#!/usr/bin/env node /** Sales department: per-customer multiplier / tier. Writes through zappier-edge. */ import fs from 'node:fs'; import http from 'node:http'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { SUBJECTS, billingRequest } from './nats-billing.js'; import { listCustomers, withCustomerName } from './names.js'; const PUBLIC = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'public'); const PORT = Number(process.env.PORT || 3012); const EDGE = (process.env.ZAPPIER_ADMIN_URL || 'http://127.0.0.1:3000').replace(/\/$/, ''); const KEY = process.env.ZAPPIER_ADMIN_KEY || 'admin-dev-key'; const BOOKS = (process.env.ACCOUNT_BALANCE_URL || 'http://127.0.0.1:3010').replace(/\/$/, ''); async function edge(pathname, { method = 'GET', body } = {}) { const r = await fetch(`${EDGE}${pathname}`, { method, headers: { 'content-type': 'application/json', 'x-admin-key': KEY }, body: body ? JSON.stringify(body) : undefined, }); const text = await r.text(); try { return { status: r.status, body: JSON.parse(text) }; } catch { return { status: r.status, body: text }; } } const server = http.createServer(async (req, res) => { const url = new URL(req.url || '/', `http://127.0.0.1:${PORT}`); const json = (code, obj) => { res.writeHead(code, { 'content-type': 'application/json' }); res.end(JSON.stringify(obj)); }; try { if (req.method === 'GET' && (url.pathname === '/' || url.pathname === '/index.html')) { if (process.env.STAFF_AUTH === '1') { const login = (process.env.STAFF_SESSION_URL || 'http://127.0.0.1:3027').replace(/\/$/, ''); const chk = await fetch(`${login}/check`, { headers: { cookie: req.headers.cookie || '' } }).catch(() => null); if (!chk || !chk.ok) { res.writeHead(302, { location: `${login}/login?next=${encodeURIComponent('http://' + (req.headers.host || '127.0.0.1') + '/')}` }); res.end(); return; } } res.writeHead(200, { 'content-type': 'text/html; charset=utf-8' }); res.end(fs.readFileSync(path.join(PUBLIC, 'index.html'))); return; } if (req.method === 'GET' && url.pathname === '/health') { return json(200, { ok: true, role: 'zappier-sales-pricing' }); } if (req.method === 'GET' && url.pathname === '/customers') { return json(200, { customers: await listCustomers(EDGE, KEY) }); } const review = url.pathname.match(/^\/review\/([^/]+)$/); if (req.method === 'GET' && review) { const id = decodeURIComponent(review[1]); const nats = await billingRequest(SUBJECTS.STATEMENT_GET, { customerId: id }); if (nats) return json(200, await withCustomerName({ ...nats, source: 'nats' }, id, EDGE, KEY)); const r = await fetch(`${BOOKS}/statement/${encodeURIComponent(id)}`); if (r.ok) return json(200, await withCustomerName({ ...(await r.json()), source: 'account-balance' }, id, EDGE, KEY)); const e = await edge(`/admin/api/statement/${encodeURIComponent(id)}`); return json(e.status, await withCustomerName(e.body, id, EDGE, KEY)); } const quote = url.pathname.match(/^\/quotes\/([^/]+)$/); if (req.method === 'GET' && quote) { const forwarded = await edge(`/admin/api/sales/quote/${quote[1]}`); return json(forwarded.status, forwarded.body); } const price = url.pathname.match(/^\/customers\/([^/]+)\/pricing$/); if (req.method === 'PUT' && price) { const chunks = []; for await (const c of req) chunks.push(c); const payload = JSON.parse(Buffer.concat(chunks).toString('utf8') || '{}'); const forwarded = await edge(`/admin/api/customers/${price[1]}`, { method: 'PUT', body: payload }); return json(forwarded.status, forwarded.body); } json(404, { error: 'not found' }); } catch (err) { json(err.status === 403 ? 403 : 502, { error: err.message }); } }); server.listen(PORT, '0.0.0.0', () => { process.stdout.write(`zappier-sales-pricing http://127.0.0.1:${PORT}/\n`); });