const fs = require('node:fs'); const https = require('node:https'); const path = require('node:path'); const { createStore, createJtlPosServer, createAdminServer } = require('./lib/src'); const actions = require('./lib/src/actions'); const PORT = Number(process.env.PORT) || 8086; const ADMIN_PORT = Number(process.env.ADMIN_PORT) || 8087; const AUTH_TOKEN = process.env.AUTH_TOKEN || '9a2e3036ed9c47e389741d9dbb7590e9'; const PAIRING_CODE = process.env.PAIRING_CODE || '307018'; const certsDir = path.join(__dirname, 'certs'); const keyPath = path.join(certsDir, 'key.pem'); const certPath = path.join(certsDir, 'cert.pem'); if (!fs.existsSync(keyPath) || !fs.existsSync(certPath)) { console.error('Missing TLS certificate. Run: npm run cert'); process.exit(1); } function serverTimestamp() { const d = new Date(); const pad = (n) => String(n).padStart(2, '0'); return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`; } function formatBody(buffer) { if (!buffer.length) { return '(empty)'; } const text = buffer.toString('utf8'); if (/^[\x09\x0A\x0D\x20-\x7E\u0080-\uFFFF]*$/.test(text)) { return text; } return `[binary ${buffer.length} bytes]\n${buffer.toString('hex')}`; } const store = createStore(); // Pre-register the fixed pairing code so the POS can pair out of the box. store.dispatch(actions.setPairingCode(PAIRING_CODE, 'JTL-POS')); // Treat the fixed auth token as a pre-paired device for display in the admin UI. store.dispatch(actions.registerDevice(AUTH_TOKEN, 'JTL-POS')); const jtlHandler = createJtlPosServer(store, { authToken: AUTH_TOKEN }); const loggedJtlHandler = async (req, res) => { const started = Date.now(); const originalEnd = res.end.bind(res); console.log('\n--- incoming POS request ---'); console.log(`${req.method} ${req.url}`); console.log('remote:', req.socket.remoteAddress, req.socket.remotePort); console.log('headers:', JSON.stringify(req.headers, null, 2)); await jtlHandler(req, res); // req.rawBody is attached by jtlHandler's body reader console.log('body:', formatBody(req.rawBody ?? Buffer.alloc(0))); console.log(`responded ${res.statusCode} in ${Date.now() - started}ms`); }; const httpsServer = https.createServer( { key: fs.readFileSync(keyPath), cert: fs.readFileSync(certPath), }, loggedJtlHandler ); httpsServer.listen(PORT, '0.0.0.0', () => { console.log(`HTTPS POS server listening on https://0.0.0.0:${PORT}`); console.log(`Certificate: ${certPath}`); console.log('Import cert.pem into JTL POS / Windows trust store if required.'); }); const { server: adminServer } = createAdminServer(store, { adminPort: ADMIN_PORT, staticDir: path.join(__dirname, 'web', 'dist'), }); function shutdown() { console.log('\nShutting down...'); httpsServer.close(); adminServer.close(); } process.on('SIGINT', shutdown); process.on('SIGTERM', shutdown);