const AUTHZ = (process.env.AUTHZ_URL || 'http://127.0.0.1:3020').replace(/\/$/, ''); const BOOKS = (process.env.ACCOUNT_BALANCE_URL || 'http://127.0.0.1:3010').replace(/\/$/, ''); export const PLANE = 'web'; export const AUTHZ_CHECK = 'verae.access.authz.check'; export async function check(subject, { principal, kind, payload } = {}) { const r = await fetch(`${AUTHZ}/check`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ plane: PLANE, subject, principal, kind, payload }), }); return { status: r.status, body: await r.json().catch(() => ({ allow: false })) }; } export async function statement(customerId, principal) { const gate = await check('verae.billing.statement.get', { principal }); if (!gate.body.allow) return { status: 403, body: gate.body }; const url = process.env.NATS_URL; if (url) { try { const { connect, StringCodec } = await import('nats'); const nc = await connect({ servers: url.split(','), name: 'verae-access-web' }); const sc = StringCodec(); const m = await nc.request( 'verae.billing.statement.get', sc.encode(JSON.stringify({ customerId, plane: PLANE, principal })), { timeout: 2000 }, ); const out = JSON.parse(sc.decode(m.data) || '{}'); await nc.close(); return { status: 200, body: { ...out, source: 'nats', plane: PLANE } }; } catch { /* HTTP fallback */ } } const r = await fetch(`${BOOKS}/statement/${customerId}`); return { status: r.status, body: { ...(await r.json().catch(() => ({}))), source: 'account-balance', plane: PLANE } }; } export async function reload(customerId, cents, principal) { const gate = await check('verae.billing.balance.adjust', { principal, kind: 'reload' }); if (!gate.body.allow) return { status: 403, body: gate.body }; const r = await fetch(`${BOOKS}/adjust`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ customerId, cents, reason: 'reload', agent: principal || 'web', kind: 'reload' }), }); return { status: r.status, body: { ...(await r.json().catch(() => ({}))), plane: PLANE } }; }