import { Request, Response } from 'express'; export type UpstreamFetch = typeof fetch; /** * After zappier meters the call, forward Verae operations to middleware. * When ZAPPIER_UPSTREAM is unset, callers keep the local mock. */ export async function proxyVerae( req: Request, res: Response, pathname: string, fetchImpl: UpstreamFetch = fetch, ): Promise { const base = (process.env.ZAPPIER_UPSTREAM || '').replace(/\/$/, ''); if (!base) return false; const url = new URL(pathname, `${base}/`); for (const [k, v] of Object.entries(req.query)) { if (typeof v === 'string') url.searchParams.set(k, v); } const headers: Record = { accept: 'application/json' }; const key = req.header('x-api-key'); if (key) headers['x-api-key'] = key; const auth = req.header('authorization'); if (auth) headers.authorization = auth; const veraeUserId = req.customer?.veraeUserId; if (veraeUserId) headers['x-verae-user-id'] = veraeUserId; const method = req.method.toUpperCase(); const init: RequestInit = { method, headers }; if (method !== 'GET' && method !== 'HEAD') { headers['content-type'] = 'application/json'; init.body = JSON.stringify(req.body ?? {}); } const r = await fetchImpl(url.toString(), init); const text = await r.text(); let body: unknown = text; try { body = text ? JSON.parse(text) : {}; } catch { /* keep text */ } if (body && typeof body === 'object' && !Array.isArray(body) && res.locals.quote) { (body as Record).quote = res.locals.quote; } res.status(r.status).json(body); return true; }