@antseed/cli 0.1.168 → 0.1.169

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/dist/buyer-identities/loader.d.ts +28 -0
  2. package/dist/buyer-identities/loader.d.ts.map +1 -0
  3. package/dist/buyer-identities/loader.js +58 -0
  4. package/dist/buyer-identities/loader.js.map +1 -0
  5. package/dist/buyer-identities/store.d.ts +41 -0
  6. package/dist/buyer-identities/store.d.ts.map +1 -0
  7. package/dist/buyer-identities/store.js +171 -0
  8. package/dist/buyer-identities/store.js.map +1 -0
  9. package/dist/buyer-identities/store.test.d.ts +2 -0
  10. package/dist/buyer-identities/store.test.d.ts.map +1 -0
  11. package/dist/buyer-identities/store.test.js +122 -0
  12. package/dist/buyer-identities/store.test.js.map +1 -0
  13. package/dist/cli/commands/buyer/identity.d.ts +3 -0
  14. package/dist/cli/commands/buyer/identity.d.ts.map +1 -0
  15. package/dist/cli/commands/buyer/identity.js +115 -0
  16. package/dist/cli/commands/buyer/identity.js.map +1 -0
  17. package/dist/cli/commands/buyer/index.d.ts.map +1 -1
  18. package/dist/cli/commands/buyer/index.js +2 -0
  19. package/dist/cli/commands/buyer/index.js.map +1 -1
  20. package/dist/cli/commands/buyer/start.d.ts.map +1 -1
  21. package/dist/cli/commands/buyer/start.js +30 -2
  22. package/dist/cli/commands/buyer/start.js.map +1 -1
  23. package/dist/cli/commands/gateway/index.d.ts +3 -0
  24. package/dist/cli/commands/gateway/index.d.ts.map +1 -0
  25. package/dist/cli/commands/gateway/index.js +43 -0
  26. package/dist/cli/commands/gateway/index.js.map +1 -0
  27. package/dist/cli/commands/gateway/key.d.ts +3 -0
  28. package/dist/cli/commands/gateway/key.d.ts.map +1 -0
  29. package/dist/cli/commands/gateway/key.js +240 -0
  30. package/dist/cli/commands/gateway/key.js.map +1 -0
  31. package/dist/cli/commands/gateway/shared.d.ts +29 -0
  32. package/dist/cli/commands/gateway/shared.d.ts.map +1 -0
  33. package/dist/cli/commands/gateway/shared.js +90 -0
  34. package/dist/cli/commands/gateway/shared.js.map +1 -0
  35. package/dist/cli/commands/tunnel/start.d.ts.map +1 -1
  36. package/dist/cli/commands/tunnel/start.js +25 -14
  37. package/dist/cli/commands/tunnel/start.js.map +1 -1
  38. package/dist/cli/index.js +2 -0
  39. package/dist/cli/index.js.map +1 -1
  40. package/dist/gateway/accounting.d.ts +45 -0
  41. package/dist/gateway/accounting.d.ts.map +1 -0
  42. package/dist/gateway/accounting.js +94 -0
  43. package/dist/gateway/accounting.js.map +1 -0
  44. package/dist/gateway/cdp-auth.d.ts +12 -0
  45. package/dist/gateway/cdp-auth.d.ts.map +1 -0
  46. package/dist/gateway/cdp-auth.js +53 -0
  47. package/dist/gateway/cdp-auth.js.map +1 -0
  48. package/dist/gateway/cdp-auth.test.d.ts +2 -0
  49. package/dist/gateway/cdp-auth.test.d.ts.map +1 -0
  50. package/dist/gateway/cdp-auth.test.js +96 -0
  51. package/dist/gateway/cdp-auth.test.js.map +1 -0
  52. package/dist/gateway/gateway.test.d.ts.map +1 -0
  53. package/dist/gateway/gateway.test.js +709 -0
  54. package/dist/gateway/gateway.test.js.map +1 -0
  55. package/dist/gateway/keys.d.ts +13 -0
  56. package/dist/gateway/keys.d.ts.map +1 -0
  57. package/dist/gateway/keys.js +24 -0
  58. package/dist/gateway/keys.js.map +1 -0
  59. package/dist/gateway/limits.d.ts +25 -0
  60. package/dist/gateway/limits.d.ts.map +1 -0
  61. package/dist/gateway/limits.js +45 -0
  62. package/dist/gateway/limits.js.map +1 -0
  63. package/dist/gateway/money.d.ts +9 -0
  64. package/dist/gateway/money.d.ts.map +1 -0
  65. package/dist/gateway/money.js +37 -0
  66. package/dist/gateway/money.js.map +1 -0
  67. package/dist/gateway/runtime.d.ts +38 -0
  68. package/dist/gateway/runtime.d.ts.map +1 -0
  69. package/dist/gateway/runtime.js +144 -0
  70. package/dist/gateway/runtime.js.map +1 -0
  71. package/dist/gateway/server.d.ts +49 -0
  72. package/dist/gateway/server.d.ts.map +1 -0
  73. package/dist/gateway/server.js +460 -0
  74. package/dist/gateway/server.js.map +1 -0
  75. package/dist/gateway/spend-feed.d.ts +32 -0
  76. package/dist/gateway/spend-feed.d.ts.map +1 -0
  77. package/dist/gateway/spend-feed.js +86 -0
  78. package/dist/gateway/spend-feed.js.map +1 -0
  79. package/dist/gateway/store.d.ts +114 -0
  80. package/dist/gateway/store.d.ts.map +1 -0
  81. package/dist/gateway/store.js +253 -0
  82. package/dist/gateway/store.js.map +1 -0
  83. package/dist/gateway/x402.d.ts +95 -0
  84. package/dist/gateway/x402.d.ts.map +1 -0
  85. package/dist/gateway/x402.js +120 -0
  86. package/dist/gateway/x402.js.map +1 -0
  87. package/dist/proxy/buyer-proxy.d.ts +13 -0
  88. package/dist/proxy/buyer-proxy.d.ts.map +1 -1
  89. package/dist/proxy/buyer-proxy.js +99 -11
  90. package/dist/proxy/buyer-proxy.js.map +1 -1
  91. package/dist/proxy/request-utils.d.ts +3 -0
  92. package/dist/proxy/request-utils.d.ts.map +1 -1
  93. package/dist/proxy/request-utils.js +3 -0
  94. package/dist/proxy/request-utils.js.map +1 -1
  95. package/dist/proxy/spend-attribution.d.ts +63 -0
  96. package/dist/proxy/spend-attribution.d.ts.map +1 -0
  97. package/dist/proxy/spend-attribution.js +97 -0
  98. package/dist/proxy/spend-attribution.js.map +1 -0
  99. package/package.json +8 -6
  100. package/dist/tunnel/gateway.d.ts +0 -16
  101. package/dist/tunnel/gateway.d.ts.map +0 -1
  102. package/dist/tunnel/gateway.js +0 -146
  103. package/dist/tunnel/gateway.js.map +0 -1
  104. package/dist/tunnel/gateway.test.d.ts.map +0 -1
  105. package/dist/tunnel/gateway.test.js +0 -89
  106. package/dist/tunnel/gateway.test.js.map +0 -1
  107. /package/dist/{tunnel → gateway}/gateway.test.d.ts +0 -0
@@ -0,0 +1,460 @@
1
+ import * as http from 'node:http';
2
+ import { DEFAULT_BUYER_IDENTITY } from '@antseed/node';
3
+ import { SPEND_ATTRIBUTION_HEADER } from '../proxy/spend-attribution.js';
4
+ import { BUYER_IDENTITY_HEADER } from '../proxy/request-utils.js';
5
+ import { newRequestTag } from './accounting.js';
6
+ import { parseBearerToken } from './keys.js';
7
+ import { hasSpendLimits, LIMIT_PERIODS } from './limits.js';
8
+ import { formatUsdc, optionalUsdcToDecimalString, parseUsdToUsdc, usdcToDecimalString } from './money.js';
9
+ import { PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, PAYMENT_SIGNATURE_HEADER, X402_VERSION, buildPaymentRequirements, checkPaymentPayload, decodeHeaderJson, encodeHeaderJson, } from './x402.js';
10
+ const HOP_BY_HOP = new Set([
11
+ 'connection',
12
+ 'keep-alive',
13
+ 'proxy-authenticate',
14
+ 'proxy-authorization',
15
+ 'te',
16
+ 'trailers',
17
+ 'transfer-encoding',
18
+ 'upgrade',
19
+ ]);
20
+ /** Bodies are buffered to read the model for metrics; the buyer buffers them too. */
21
+ const MAX_MODEL_SNIFF_BYTES = 4 * 1024 * 1024;
22
+ /** Largest request body the gateway accepts, matching the buyer's default upload limit. */
23
+ const MAX_BODY_BYTES = 64 * 1024 * 1024;
24
+ const KEY_INFO_PATH = '/v1/key';
25
+ const TOPUP_PATH = '/v1/key/topup';
26
+ /**
27
+ * `paid` routes reach a seller; the others are answered by the buyer for
28
+ * free, or (`local`) by the gateway itself.
29
+ */
30
+ const ALLOWED_ROUTES = [
31
+ { method: 'GET', prefix: KEY_INFO_PATH, paid: false, local: true },
32
+ { method: 'POST', prefix: TOPUP_PATH, paid: false, local: true },
33
+ { method: 'GET', prefix: '/v1/models', paid: false },
34
+ { method: 'POST', prefix: '/v1/messages', paid: true },
35
+ { method: 'POST', prefix: '/v1/messages/count_tokens', paid: false },
36
+ { method: 'POST', prefix: '/v1/chat/completions', paid: true },
37
+ { method: 'POST', prefix: '/v1/responses', paid: true },
38
+ { method: 'POST', prefix: '/v1/images/generations', paid: true },
39
+ { method: 'POST', prefix: '/v1/images/edits', paid: true },
40
+ ];
41
+ /**
42
+ * Authenticated front door to a buyer. Each API key names the buyer identity
43
+ * (wallet) that pays for it, carries optional spend caps, and gets its signed
44
+ * spend attributed back through the buyer's spend feed.
45
+ */
46
+ export class GatewayServer {
47
+ _options;
48
+ _server = null;
49
+ _port = 0;
50
+ constructor(_options) {
51
+ this._options = _options;
52
+ }
53
+ get port() {
54
+ return this._port;
55
+ }
56
+ async start() {
57
+ if (this._server)
58
+ return this._port;
59
+ this._server = http.createServer((req, res) => {
60
+ this._handle(req, res).catch((error) => {
61
+ this._log(`gateway error: ${error instanceof Error ? error.message : String(error)}`);
62
+ if (!res.headersSent)
63
+ sendError(res, 500, 'api_error', 'internal_error', 'Gateway error');
64
+ else
65
+ res.destroy();
66
+ });
67
+ });
68
+ await new Promise((resolve, reject) => {
69
+ this._server.once('error', reject);
70
+ this._server.listen(this._options.listenPort ?? 0, this._options.listenHost ?? '127.0.0.1', () => resolve());
71
+ });
72
+ this._port = this._server.address().port;
73
+ return this._port;
74
+ }
75
+ async stop() {
76
+ const server = this._server;
77
+ this._server = null;
78
+ this._port = 0;
79
+ if (!server)
80
+ return;
81
+ await new Promise((resolve) => server.close(() => resolve()));
82
+ }
83
+ _log(message) {
84
+ this._options.onLog?.(message);
85
+ }
86
+ async _handle(req, res) {
87
+ const method = req.method ?? 'GET';
88
+ const path = req.url ?? '/';
89
+ const route = canonicalizeRoute(method, path);
90
+ if (!route) {
91
+ this._log(`gateway rejected route: ${method} ${path}`);
92
+ sendError(res, 404, 'invalid_request_error', 'not_found', 'Not found');
93
+ return;
94
+ }
95
+ const canonicalPath = route.path;
96
+ const secret = parseBearerToken(req.headers.authorization);
97
+ const key = secret ? this._options.store.findKeyBySecret(secret) : null;
98
+ if (!key || key.status !== 'active') {
99
+ this._log(`gateway rejected authentication: ${method} ${path}`);
100
+ res.setHeader('www-authenticate', 'Bearer');
101
+ sendError(res, 401, 'authentication_error', key ? 'key_revoked' : 'invalid_api_key', key ? 'API key has been revoked' : 'Invalid API key');
102
+ return;
103
+ }
104
+ if (key.expiresAt !== null && key.expiresAt <= Date.now()) {
105
+ res.setHeader('www-authenticate', 'Bearer');
106
+ sendError(res, 401, 'authentication_error', 'key_expired', 'API key has expired');
107
+ return;
108
+ }
109
+ if (route.local) {
110
+ if (route.prefix === TOPUP_PATH)
111
+ await this._topup(req, res, key);
112
+ else
113
+ sendJson(res, 200, { data: await this._keyInfo(key) });
114
+ return;
115
+ }
116
+ const buyerPort = this._options.buyerPort;
117
+ // Caps are only as good as the spend that reaches the ledger, so a key
118
+ // with caps fails closed while its buyer is not reporting spend.
119
+ if (route.paid && hasSpendLimits(key.limits) && this._options.spendFeedState() !== 'reporting') {
120
+ await this._options.refreshSpendFeed();
121
+ const state = this._options.spendFeedState();
122
+ if (state !== 'reporting') {
123
+ sendError(res, 503, 'api_error', 'spend_tracking_unavailable', state === 'unsupported'
124
+ ? 'The buyer for this API key does not report spend; upgrade it to enforce spend limits'
125
+ : 'The buyer for this API key is not reachable');
126
+ return;
127
+ }
128
+ }
129
+ const body = await readBody(req);
130
+ if (!body)
131
+ return sendBodyTooLarge(res);
132
+ let tag;
133
+ if (route.paid) {
134
+ const admission = this._options.accounting.admit(key);
135
+ if (!admission.ok) {
136
+ this._log(`gateway spend limit reached: key=${key.id} period=${admission.breach.period}`);
137
+ sendJson(res, 402, { error: spendLimitError(admission.breach) });
138
+ return;
139
+ }
140
+ tag = admission.tag;
141
+ }
142
+ else {
143
+ tag = newRequestTag();
144
+ }
145
+ this._options.store.startRequest({
146
+ tag,
147
+ keyId: key.id,
148
+ buyerIdentity: key.buyerIdentity,
149
+ method,
150
+ path: canonicalPath.split('?')[0],
151
+ model: sniffModel(body, req.headers['content-type']),
152
+ startedAt: Date.now(),
153
+ });
154
+ this._options.store.touchKey(key.id);
155
+ this._log(`gateway request: key=${key.id} identity=${key.buyerIdentity} ${method} ${path} -> ${canonicalPath}`);
156
+ let finished = false;
157
+ const finish = (status, buyerRequestId) => {
158
+ if (finished)
159
+ return;
160
+ finished = true;
161
+ this._options.store.finishRequest(tag, { status, buyerRequestId });
162
+ this._options.accounting.finish(tag);
163
+ };
164
+ const headers = {};
165
+ for (const [name, value] of Object.entries(req.headers)) {
166
+ const normalized = name.toLowerCase();
167
+ if (normalized === 'host' || normalized === 'authorization' || normalized === 'cookie')
168
+ continue;
169
+ // The key decides who pays and how spend is tagged, never the client.
170
+ if (normalized === 'content-length' || normalized === SPEND_ATTRIBUTION_HEADER || normalized === BUYER_IDENTITY_HEADER)
171
+ continue;
172
+ if (normalized.startsWith('x-forwarded-') || HOP_BY_HOP.has(normalized))
173
+ continue;
174
+ headers[name] = value;
175
+ }
176
+ headers.host = `127.0.0.1:${buyerPort}`;
177
+ headers.connection = 'close';
178
+ headers['content-length'] = String(body.length);
179
+ headers['x-antseed-system-proxy-source'] = tunnelRequestSource(req.headers);
180
+ headers[SPEND_ATTRIBUTION_HEADER] = tag;
181
+ if (key.buyerIdentity !== DEFAULT_BUYER_IDENTITY)
182
+ headers[BUYER_IDENTITY_HEADER] = key.buyerIdentity;
183
+ const upstream = http.request({
184
+ hostname: '127.0.0.1',
185
+ port: buyerPort,
186
+ method,
187
+ path: canonicalPath,
188
+ headers,
189
+ }, (upstreamRes) => {
190
+ const status = upstreamRes.statusCode ?? 502;
191
+ const buyerRequestId = firstHeader(upstreamRes.headers['x-antseed-request-id']) || null;
192
+ const responseHeaders = {};
193
+ for (const [name, value] of Object.entries(upstreamRes.headers)) {
194
+ if (!HOP_BY_HOP.has(name.toLowerCase()) && value !== undefined)
195
+ responseHeaders[name] = value;
196
+ }
197
+ responseHeaders.connection = 'close';
198
+ res.writeHead(status, responseHeaders);
199
+ upstreamRes.pipe(res);
200
+ upstreamRes.once('end', () => finish(status, buyerRequestId));
201
+ upstreamRes.once('error', () => finish(status, buyerRequestId));
202
+ res.once('close', () => finish(status, buyerRequestId));
203
+ });
204
+ upstream.on('error', (error) => {
205
+ this._log(`gateway upstream error: ${error.message}`);
206
+ finish(502, null);
207
+ if (!res.headersSent) {
208
+ sendError(res, 502, 'api_error', 'buyer_unavailable', 'Antseed buyer proxy is unavailable');
209
+ }
210
+ else {
211
+ res.destroy();
212
+ }
213
+ });
214
+ // A client that disconnects mid-stream should stop the paid request too.
215
+ res.once('close', () => {
216
+ if (!res.writableFinished)
217
+ upstream.destroy();
218
+ });
219
+ upstream.end(body);
220
+ }
221
+ /**
222
+ * x402 top-up: the key holder pays USDC straight to the key's buyer wallet.
223
+ * The buyer's deposit watcher then sweeps it into that identity's credits.
224
+ * Without a PAYMENT-SIGNATURE the answer is the 402 an x402 client pays.
225
+ */
226
+ async _topup(req, res, key) {
227
+ const topup = this._options.topup;
228
+ if (!topup) {
229
+ sendError(res, 501, 'invalid_request_error', 'topup_unavailable', 'This gateway does not accept top-ups');
230
+ return;
231
+ }
232
+ if (key.buyerIdentity === DEFAULT_BUYER_IDENTITY) {
233
+ sendError(res, 403, 'invalid_request_error', 'topup_not_available', 'This key is paid from the operator\'s wallet and cannot be topped up');
234
+ return;
235
+ }
236
+ if (!key.topupEnabled) {
237
+ sendError(res, 403, 'invalid_request_error', 'topup_not_allowed', 'Top-ups are not enabled for this API key');
238
+ return;
239
+ }
240
+ const payTo = await this._options.identityAddress(key.buyerIdentity).catch(() => null);
241
+ if (!payTo) {
242
+ sendError(res, 503, 'api_error', 'buyer_wallet_unknown', 'The wallet behind this API key is not available');
243
+ return;
244
+ }
245
+ const raw = await readBody(req);
246
+ if (!raw)
247
+ return sendBodyTooLarge(res);
248
+ let amountUsdc;
249
+ try {
250
+ const body = JSON.parse(raw.toString('utf8') || '{}');
251
+ amountUsdc = parseUsdToUsdc(String(body.amount_usd ?? ''));
252
+ }
253
+ catch {
254
+ sendError(res, 400, 'invalid_request_error', 'invalid_amount', 'Send {"amount_usd": "<USD amount>"}');
255
+ return;
256
+ }
257
+ if (amountUsdc < topup.minUsdc || amountUsdc > topup.maxUsdc) {
258
+ sendError(res, 400, 'invalid_request_error', 'invalid_amount', `Top-ups must be between ${formatUsdc(topup.minUsdc)} and ${formatUsdc(topup.maxUsdc)}`);
259
+ return;
260
+ }
261
+ const asset = await topup.asset();
262
+ const requirements = buildPaymentRequirements(asset, payTo, amountUsdc);
263
+ const proto = firstHeader(req.headers['x-forwarded-proto']) || 'http';
264
+ const resource = {
265
+ url: `${proto}://${req.headers.host ?? 'localhost'}${TOPUP_PATH}`,
266
+ description: `Add ${formatUsdc(amountUsdc)} of credits to API key ${key.id}`,
267
+ mimeType: 'application/json',
268
+ };
269
+ const paymentRequired = (error) => {
270
+ const body = { x402Version: X402_VERSION, error, resource, accepts: [requirements] };
271
+ res.setHeader(PAYMENT_REQUIRED_HEADER, encodeHeaderJson(body));
272
+ sendJson(res, 402, body);
273
+ };
274
+ const signature = firstHeader(req.headers[PAYMENT_SIGNATURE_HEADER]);
275
+ if (!signature) {
276
+ paymentRequired('PAYMENT-SIGNATURE header is required');
277
+ return;
278
+ }
279
+ const payment = decodeHeaderJson(signature);
280
+ if (!payment) {
281
+ sendError(res, 400, 'invalid_request_error', 'invalid_payload', 'PAYMENT-SIGNATURE is not base64-encoded JSON');
282
+ return;
283
+ }
284
+ const localError = checkPaymentPayload(payment, requirements, asset, Math.floor(Date.now() / 1000));
285
+ if (localError) {
286
+ paymentRequired(localError);
287
+ return;
288
+ }
289
+ const settled = await this._settleTopup(topup, payment, requirements);
290
+ if (!settled.success) {
291
+ this._log(`gateway top-up failed: key=${key.id} reason=${settled.errorReason ?? 'unknown'}`);
292
+ res.setHeader(PAYMENT_RESPONSE_HEADER, encodeHeaderJson(settled));
293
+ paymentRequired(settled.errorReason ?? 'unexpected_settle_error');
294
+ return;
295
+ }
296
+ const authorization = payment.payload.authorization;
297
+ // The USDC has already moved; a failed bookkeeping write must not turn
298
+ // the settled payment into an error the client would retry.
299
+ try {
300
+ this._options.store.recordLedgerEntry({
301
+ kind: 'credit',
302
+ keyId: key.id,
303
+ buyerIdentity: key.buyerIdentity,
304
+ amountUsdc,
305
+ externalRef: `x402:${requirements.network}:${authorization.nonce.toLowerCase()}`,
306
+ note: `x402 top-up from ${settled.payer || authorization.from}, tx ${settled.transaction}`,
307
+ createdAt: Date.now(),
308
+ });
309
+ }
310
+ catch (error) {
311
+ this._log(`gateway top-up settled but NOT recorded in the ledger: key=${key.id} amount=${formatUsdc(amountUsdc)} tx=${settled.transaction}: ${error instanceof Error ? error.message : String(error)}`);
312
+ }
313
+ this._log(`gateway top-up: key=${key.id} identity=${key.buyerIdentity} amount=${formatUsdc(amountUsdc)} tx=${settled.transaction}`);
314
+ res.setHeader(PAYMENT_RESPONSE_HEADER, encodeHeaderJson(settled));
315
+ sendJson(res, 200, {
316
+ data: {
317
+ topped_up_usd: usdcToDecimalString(amountUsdc),
318
+ buyer_address: requirements.payTo,
319
+ transaction: settled.transaction,
320
+ network: settled.network,
321
+ payer: settled.payer || authorization.from,
322
+ // The buyer sweeps the wallet into its deposits on its next check.
323
+ credits_available: 'within about a minute',
324
+ },
325
+ });
326
+ }
327
+ async _settleTopup(topup, payment, requirements) {
328
+ const failure = (errorReason) => ({
329
+ success: false, errorReason, transaction: '', network: requirements.network, payer: payment.payload.authorization.from,
330
+ });
331
+ try {
332
+ const verified = await topup.facilitator.verify(payment, requirements);
333
+ if (!verified.isValid)
334
+ return failure(verified.invalidReason ?? 'unexpected_verify_error');
335
+ return await topup.facilitator.settle(payment, requirements);
336
+ }
337
+ catch (error) {
338
+ this._log(`gateway facilitator error: ${error instanceof Error ? error.message : String(error)}`);
339
+ return failure('unexpected_settle_error');
340
+ }
341
+ }
342
+ async _keyInfo(key) {
343
+ const spent = this._options.store.periodSpend(key.id);
344
+ const usage = this._options.store.usageStats(key.id);
345
+ const buyerAddress = await this._options.identityAddress(key.buyerIdentity).catch(() => null);
346
+ const limits = Object.fromEntries(LIMIT_PERIODS.map((period) => {
347
+ const limit = key.limits[period];
348
+ return [period, {
349
+ limit_usd: optionalUsdcToDecimalString(limit),
350
+ spent_usd: usdcToDecimalString(spent[period]),
351
+ remaining_usd: optionalUsdcToDecimalString(limit === null ? null : Math.max(0, limit - spent[period])),
352
+ }];
353
+ }));
354
+ return {
355
+ id: key.id,
356
+ label: key.label,
357
+ created_at: new Date(key.createdAt).toISOString(),
358
+ expires_at: key.expiresAt === null ? null : new Date(key.expiresAt).toISOString(),
359
+ // Whether POST /v1/key/topup accepts payments for this key.
360
+ topup_enabled: key.topupEnabled && key.buyerIdentity !== DEFAULT_BUYER_IDENTITY && Boolean(this._options.topup),
361
+ // The wallet that pays sellers for this key's requests.
362
+ buyer_address: buyerAddress,
363
+ usage: {
364
+ requests: usage.requests,
365
+ spent_usd: usdcToDecimalString(usage.spentUsdc),
366
+ topped_up_usd: usdcToDecimalString(usage.creditedUsdc),
367
+ input_tokens: usage.inputTokens,
368
+ cached_input_tokens: usage.cachedInputTokens,
369
+ output_tokens: usage.outputTokens,
370
+ },
371
+ limits,
372
+ };
373
+ }
374
+ }
375
+ /**
376
+ * 402 is the status a client-facing payment flow will answer with, so a key
377
+ * that hits its cap already gets the shape a top-up offer can extend.
378
+ */
379
+ function spendLimitError(breach) {
380
+ const label = breach.period === 'total' ? 'lifetime' : breach.period;
381
+ return {
382
+ type: 'insufficient_quota',
383
+ code: 'spend_limit_reached',
384
+ message: `This API key reached its ${label} spend limit of ${formatUsdc(breach.limitUsdc)}.`,
385
+ limit: {
386
+ period: breach.period,
387
+ limit_usd: usdcToDecimalString(breach.limitUsdc),
388
+ spent_usd: usdcToDecimalString(breach.spentUsdc),
389
+ resets_at: breach.resetsAt === null ? null : new Date(breach.resetsAt).toISOString(),
390
+ },
391
+ };
392
+ }
393
+ function sendJson(res, status, payload) {
394
+ res.writeHead(status, { 'content-type': 'application/json' });
395
+ res.end(JSON.stringify(payload));
396
+ }
397
+ function sendError(res, status, type, code, message) {
398
+ sendJson(res, status, { error: { message, type, code } });
399
+ }
400
+ /** The request body, or null once it exceeds MAX_BODY_BYTES (the rest is drained, not kept). */
401
+ async function readBody(req) {
402
+ if (Number(req.headers['content-length']) > MAX_BODY_BYTES) {
403
+ req.resume();
404
+ return null;
405
+ }
406
+ const chunks = [];
407
+ let size = 0;
408
+ for await (const chunk of req) {
409
+ size += chunk.length;
410
+ if (size <= MAX_BODY_BYTES)
411
+ chunks.push(chunk);
412
+ }
413
+ return size > MAX_BODY_BYTES ? null : Buffer.concat(chunks);
414
+ }
415
+ function sendBodyTooLarge(res) {
416
+ sendError(res, 413, 'invalid_request_error', 'request_too_large', `Request bodies are limited to ${MAX_BODY_BYTES / 1024 / 1024} MiB`);
417
+ }
418
+ function sniffModel(body, contentType) {
419
+ if (body.length === 0 || body.length > MAX_MODEL_SNIFF_BYTES)
420
+ return null;
421
+ if (contentType && !contentType.includes('json'))
422
+ return null;
423
+ try {
424
+ const parsed = JSON.parse(body.toString('utf8'));
425
+ return typeof parsed.model === 'string' ? parsed.model.slice(0, 200) : null;
426
+ }
427
+ catch {
428
+ return null;
429
+ }
430
+ }
431
+ function tunnelRequestSource(headers) {
432
+ const originator = normalizeSource(firstHeader(headers.originator));
433
+ if (originator)
434
+ return originator.startsWith('cursor') ? 'cursor' : originator;
435
+ if (Object.keys(headers).some((name) => name.toLowerCase().startsWith('x-cursor-'))) {
436
+ return 'cursor';
437
+ }
438
+ const userAgent = firstHeader(headers['user-agent']).trim();
439
+ const product = normalizeSource(userAgent.split(/[/\s]/, 1)[0] ?? '');
440
+ return product.startsWith('cursor') ? 'cursor' : 'public-tunnel';
441
+ }
442
+ function firstHeader(value) {
443
+ return Array.isArray(value) ? value[0] ?? '' : value ?? '';
444
+ }
445
+ function normalizeSource(value) {
446
+ return value.trim().toLowerCase().replace(/[^a-z0-9.]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 64);
447
+ }
448
+ function canonicalizeRoute(method, path) {
449
+ const queryIndex = path.indexOf('?');
450
+ const pathname = (queryIndex === -1 ? path : path.slice(0, queryIndex)).toLowerCase();
451
+ const query = queryIndex === -1 ? '' : path.slice(queryIndex);
452
+ const candidates = new Set([pathname]);
453
+ if (!pathname.startsWith('/v1/'))
454
+ candidates.add(`/v1${pathname}`);
455
+ if (pathname.startsWith('/v1/v1/'))
456
+ candidates.add(pathname.slice(3));
457
+ const route = ALLOWED_ROUTES.find((allowed) => allowed.method === method && candidates.has(allowed.prefix));
458
+ return route ? { path: `${route.prefix}${query}`, prefix: route.prefix, paid: route.paid, local: route.local ?? false } : null;
459
+ }
460
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/gateway/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { AttributedSpendPage } from '../proxy/spend-attribution.js';
2
+ /**
3
+ * - `reporting`: the buyer answers and reports attributed spend.
4
+ * - `unsupported`: a buyer answers but predates spend attribution.
5
+ * - `unreachable`: nothing answered on the buyer port.
6
+ */
7
+ export type SpendFeedState = 'reporting' | 'unsupported' | 'unreachable';
8
+ export interface SpendFeedOptions {
9
+ buyerPort: number;
10
+ onPage: (page: AttributedSpendPage) => void;
11
+ onLog?: (message: string) => void;
12
+ intervalMs?: number;
13
+ fetchImpl?: typeof fetch;
14
+ }
15
+ /** Polls the buyer for the signed spend of gateway-tagged requests. */
16
+ export declare class SpendFeedPoller {
17
+ private readonly _options;
18
+ private _bootId;
19
+ private _after;
20
+ private _state;
21
+ private _timer;
22
+ private _polling;
23
+ constructor(_options: SpendFeedOptions);
24
+ get state(): SpendFeedState;
25
+ start(): void;
26
+ stop(): Promise<void>;
27
+ /** Concurrent callers share the poll already in flight. */
28
+ pollOnce(): Promise<void>;
29
+ private _drain;
30
+ private _setState;
31
+ }
32
+ //# sourceMappingURL=spend-feed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spend-feed.d.ts","sourceRoot":"","sources":["../../src/gateway/spend-feed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AAKxE;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,aAAa,GAAG,aAAa,CAAA;AAExE,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAA;IAC3C,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB;AAED,uEAAuE;AACvE,qBAAa,eAAe;IAOd,OAAO,CAAC,QAAQ,CAAC,QAAQ;IANrC,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,MAAM,CAA8C;IAC5D,OAAO,CAAC,QAAQ,CAA6B;gBAEhB,QAAQ,EAAE,gBAAgB;IAEvD,IAAI,KAAK,IAAI,cAAc,CAE1B;IAED,KAAK,IAAI,IAAI;IAOP,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3B,2DAA2D;IAC3D,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YAKX,MAAM;IA8CpB,OAAO,CAAC,SAAS;CAIlB"}
@@ -0,0 +1,86 @@
1
+ const DEFAULT_POLL_INTERVAL_MS = 2_000;
2
+ const POLL_TIMEOUT_MS = 3_000;
3
+ /** Polls the buyer for the signed spend of gateway-tagged requests. */
4
+ export class SpendFeedPoller {
5
+ _options;
6
+ _bootId = null;
7
+ _after = 0;
8
+ _state = 'unreachable';
9
+ _timer = null;
10
+ _polling = null;
11
+ constructor(_options) {
12
+ this._options = _options;
13
+ }
14
+ get state() {
15
+ return this._state;
16
+ }
17
+ start() {
18
+ if (this._timer)
19
+ return;
20
+ void this.pollOnce();
21
+ this._timer = setInterval(() => void this.pollOnce(), this._options.intervalMs ?? DEFAULT_POLL_INTERVAL_MS);
22
+ this._timer.unref?.();
23
+ }
24
+ async stop() {
25
+ if (this._timer)
26
+ clearInterval(this._timer);
27
+ this._timer = null;
28
+ // Drain spend signed during shutdown so it reaches the ledger.
29
+ await this.pollOnce();
30
+ }
31
+ /** Concurrent callers share the poll already in flight. */
32
+ pollOnce() {
33
+ this._polling ??= this._drain().finally(() => { this._polling = null; });
34
+ return this._polling;
35
+ }
36
+ async _drain() {
37
+ const fetchImpl = this._options.fetchImpl ?? fetch;
38
+ for (;;) {
39
+ let response;
40
+ try {
41
+ response = await fetchImpl(`http://127.0.0.1:${this._options.buyerPort}/_antseed/attributed-spend?after=${this._after}`, { signal: AbortSignal.timeout(POLL_TIMEOUT_MS) });
42
+ }
43
+ catch {
44
+ this._setState('unreachable');
45
+ return;
46
+ }
47
+ if (response.status === 404) {
48
+ this._setState('unsupported');
49
+ return;
50
+ }
51
+ if (!response.ok) {
52
+ this._setState('unreachable');
53
+ return;
54
+ }
55
+ const page = await response.json().catch(() => null);
56
+ if (!page || typeof page.bootId !== 'string' || !Array.isArray(page.events)) {
57
+ this._setState('unsupported');
58
+ return;
59
+ }
60
+ this._setState('reporting');
61
+ if (page.bootId !== this._bootId) {
62
+ // A restarted buyer numbers its events from 1 again.
63
+ const restarted = this._bootId !== null;
64
+ this._bootId = page.bootId;
65
+ if (restarted || this._after > 0) {
66
+ this._after = 0;
67
+ continue;
68
+ }
69
+ }
70
+ if (this._after > 0 && page.oldestSeq > this._after + 1) {
71
+ this._options.onLog?.(`spend feed dropped events ${this._after + 1}-${page.oldestSeq - 1}`);
72
+ }
73
+ this._options.onPage(page);
74
+ const advanced = page.cursor > this._after;
75
+ this._after = page.cursor;
76
+ if (!advanced || page.events.length === 0)
77
+ return;
78
+ }
79
+ }
80
+ _setState(state) {
81
+ if (this._state !== state)
82
+ this._options.onLog?.(`spend feed: ${state}`);
83
+ this._state = state;
84
+ }
85
+ }
86
+ //# sourceMappingURL=spend-feed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spend-feed.js","sourceRoot":"","sources":["../../src/gateway/spend-feed.ts"],"names":[],"mappings":"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"}