@fatstack/x402 0.1.0 → 0.1.1

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.
package/dist/client.js CHANGED
@@ -1,15 +1,17 @@
1
1
  import {
2
2
  evaluateGuards,
3
3
  payFetch,
4
- quoteUsdOf
5
- } from "./chunk-HCN75CTX.js";
4
+ quoteUsdOf,
5
+ readQuotedRequirements
6
+ } from "./chunk-ZGVPNFNS.js";
6
7
  import {
7
8
  PAYMENT_REF_HEADER
8
- } from "./chunk-6LSPHKJ7.js";
9
+ } from "./chunk-C4BASAUA.js";
9
10
  export {
10
11
  PAYMENT_REF_HEADER,
11
12
  evaluateGuards,
12
13
  payFetch,
13
- quoteUsdOf
14
+ quoteUsdOf,
15
+ readQuotedRequirements
14
16
  };
15
17
  //# sourceMappingURL=client.js.map
package/dist/index.cjs CHANGED
@@ -27,9 +27,13 @@ __export(index_exports, {
27
27
  NO_REFUNDS_NOTICE: () => NO_REFUNDS_NOTICE,
28
28
  NotImplementedError: () => NotImplementedError,
29
29
  PAYMENT_REF_HEADER: () => PAYMENT_REF_HEADER,
30
+ PAYMENT_SIGNATURE_HEADERS: () => PAYMENT_SIGNATURE_HEADERS,
31
+ SETTLEMENT_HEADERS: () => SETTLEMENT_HEADERS,
30
32
  SpendGuardError: () => SpendGuardError,
31
33
  USDC_DECIMALS: () => USDC_DECIMALS,
34
+ UnreadableQuoteError: () => UnreadableQuoteError,
32
35
  createMemorySpendStore: () => createMemorySpendStore,
36
+ decodePaymentResponseHeader: () => import_http3.decodePaymentResponseHeader,
33
37
  evaluateGuards: () => evaluateGuards,
34
38
  formatUsdc: () => formatUsdc,
35
39
  parseUsdc: () => parseUsdc,
@@ -39,13 +43,18 @@ __export(index_exports, {
39
43
  quoteToUsd: () => quoteToUsd,
40
44
  quoteUsdOf: () => quoteUsdOf,
41
45
  readPaywallEnv: () => readPaywallEnv,
46
+ readSettlementHeader: () => readSettlementHeader,
42
47
  resolvePayee: () => resolvePayee
43
48
  });
44
49
  module.exports = __toCommonJS(index_exports);
45
50
 
46
51
  // src/constants.ts
47
52
  var NETWORKS = {
48
- base: { caip2: "eip155:8453", chainId: 8453, usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" },
53
+ base: {
54
+ caip2: "eip155:8453",
55
+ chainId: 8453,
56
+ usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
57
+ },
49
58
  "base-sepolia": {
50
59
  caip2: "eip155:84532",
51
60
  chainId: 84532,
@@ -56,6 +65,15 @@ var USDC_DECIMALS = 6;
56
65
  var NO_REFUNDS_NOTICE = "Payments are final. Once settled on-chain the transfer cannot be reversed, and there are no refunds.";
57
66
  var DOCS_URL = "https://fatstack.net/docs/payments";
58
67
  var PAYMENT_REF_HEADER = "X-Fatstack-Payment-Ref";
68
+ var SETTLEMENT_HEADERS = ["payment-response", "x-payment-response"];
69
+ var PAYMENT_SIGNATURE_HEADERS = ["payment-signature", "x-payment"];
70
+ function readSettlementHeader(headers) {
71
+ for (const name of SETTLEMENT_HEADERS) {
72
+ const value = headers.get(name);
73
+ if (value) return value;
74
+ }
75
+ return null;
76
+ }
59
77
  var DEFAULT_FACILITATOR_URL = "https://x402.org/facilitator";
60
78
 
61
79
  // src/errors.ts
@@ -81,6 +99,12 @@ var MissingAdapterError = class extends Error {
81
99
  super(`${pkg} is not installed. Add it to use this adapter: pnpm add ${pkg}`);
82
100
  }
83
101
  };
102
+ var UnreadableQuoteError = class extends Error {
103
+ name = "UnreadableQuoteError";
104
+ constructor(message) {
105
+ super(message);
106
+ }
107
+ };
84
108
 
85
109
  // src/fee-mode.ts
86
110
  function resolvePayee(mode, providerWallet) {
@@ -222,7 +246,11 @@ function paywall(options) {
222
246
  payTo,
223
247
  // An explicit asset+amount pins USDC and the exact atomic amount, rather than
224
248
  // leaving the quote to a price feed.
225
- price: { asset: network.usdc, amount: amountAtomic },
249
+ // A dollar price, not an explicit { asset, amount }: the EVM scheme resolves the
250
+ // network's default asset (USDC) and publishes its EIP-712 domain in `extra`, which
251
+ // the payer needs to sign the EIP-3009 authorisation. Naming the asset directly
252
+ // skips that lookup and emits `extra: {}`, which nobody can pay against.
253
+ price: `$${priceUsdc}`,
226
254
  maxTimeoutSeconds: config.maxTimeoutSeconds
227
255
  },
228
256
  description: config.description ?? `Fatstack tool ${config.toolId}`,
@@ -265,7 +293,7 @@ function paywall(options) {
265
293
  const middleware = cached;
266
294
  const result = await middleware(c, next);
267
295
  const carrier = result instanceof Response ? result : c.res;
268
- const ref = paymentRef(carrier?.headers?.get("x-payment-response"));
296
+ const ref = paymentRef(carrier ? readSettlementHeader(carrier.headers) : null);
269
297
  if (ref) carrier.headers.set(PAYMENT_REF_HEADER, ref);
270
298
  return result;
271
299
  };
@@ -285,7 +313,7 @@ function paywall(options) {
285
313
  const originalSetHeader = response.setHeader.bind(response);
286
314
  response.setHeader = (name, value) => {
287
315
  const out = originalSetHeader(name, value);
288
- if (String(name).toLowerCase() === "x-payment-response") {
316
+ if (SETTLEMENT_HEADERS.includes(String(name).toLowerCase())) {
289
317
  const ref = paymentRef(String(value));
290
318
  if (ref) originalSetHeader(PAYMENT_REF_HEADER, ref);
291
319
  }
@@ -308,7 +336,7 @@ function paywall(options) {
308
336
  const wrapped = cached;
309
337
  const result = await wrapped(request);
310
338
  if (result instanceof Response) {
311
- const ref = paymentRef(result.headers.get("x-payment-response"));
339
+ const ref = paymentRef(readSettlementHeader(result.headers));
312
340
  if (ref) result.headers.set(PAYMENT_REF_HEADER, ref);
313
341
  }
314
342
  return result;
@@ -329,6 +357,7 @@ async function importOptional(specifier) {
329
357
 
330
358
  // src/client.ts
331
359
  var import_client = require("@x402/core/client");
360
+ var import_http2 = require("@x402/core/http");
332
361
  var import_client2 = require("@x402/evm/exact/client");
333
362
  var import_fetch = require("@x402/fetch");
334
363
  var HOUR_MS = 60 * 60 * 1e3;
@@ -376,6 +405,19 @@ async function evaluateGuards(quoteUsd, guards, store, now) {
376
405
  }
377
406
  }
378
407
  }
408
+ async function readQuotedRequirements(response) {
409
+ const header = response.headers.get("payment-required");
410
+ if (header) {
411
+ try {
412
+ const decoded = (0, import_http2.decodePaymentRequiredHeader)(header);
413
+ if (Array.isArray(decoded.accepts) && decoded.accepts.length > 0) return decoded.accepts;
414
+ } catch {
415
+ }
416
+ }
417
+ const body = await response.clone().json().catch(() => null);
418
+ const accepts = body?.accepts;
419
+ return Array.isArray(accepts) ? accepts : [];
420
+ }
379
421
  function quoteUsdOf(requirements) {
380
422
  const asRecord = requirements;
381
423
  const amountAtomic = asRecord.maxAmountRequired ?? asRecord.amount;
@@ -421,23 +463,28 @@ async function payFetch(url, init, options) {
421
463
  const guarded = async (input, requestInit) => {
422
464
  const response2 = await baseFetch(input, requestInit);
423
465
  if (response2.status !== 402) return response2;
424
- const body = await response2.clone().json().catch(() => null);
425
- const accepts = body?.accepts;
426
- if (Array.isArray(accepts) && accepts.length > 0) {
427
- const cheapest = accepts.map((requirement) => quoteUsdOf(requirement)).sort((a, b) => a - b)[0];
428
- if (cheapest !== void 0) {
429
- await evaluateGuards(cheapest, guards, store, now());
430
- }
466
+ const accepts = await readQuotedRequirements(response2);
467
+ if (accepts.length === 0) {
468
+ throw new UnreadableQuoteError(
469
+ "Received a 402 with no readable payment requirements (no payment-required header, no accepts body). Refusing to pay blind."
470
+ );
471
+ }
472
+ const cheapest = accepts.map((requirement) => quoteUsdOf(requirement)).sort((a, b) => a - b)[0];
473
+ if (cheapest !== void 0) {
474
+ await evaluateGuards(cheapest, guards, store, now());
431
475
  }
432
476
  return response2;
433
477
  };
434
478
  const paying = (0, import_fetch.wrapFetchWithPayment)(guarded, client);
435
479
  const response = await paying(url, init);
436
- if (response.headers.get("x-payment-response") && quotedUsd !== null) {
480
+ if (readSettlementHeader(response.headers) && quotedUsd !== null) {
437
481
  await store.record({ at: now(), usd: quotedUsd });
438
482
  }
439
483
  return response;
440
484
  }
485
+
486
+ // src/index.ts
487
+ var import_http3 = require("@x402/core/http");
441
488
  // Annotate the CommonJS export names for ESM import in node:
442
489
  0 && (module.exports = {
443
490
  DEFAULT_FACILITATOR_URL,
@@ -447,9 +494,13 @@ async function payFetch(url, init, options) {
447
494
  NO_REFUNDS_NOTICE,
448
495
  NotImplementedError,
449
496
  PAYMENT_REF_HEADER,
497
+ PAYMENT_SIGNATURE_HEADERS,
498
+ SETTLEMENT_HEADERS,
450
499
  SpendGuardError,
451
500
  USDC_DECIMALS,
501
+ UnreadableQuoteError,
452
502
  createMemorySpendStore,
503
+ decodePaymentResponseHeader,
453
504
  evaluateGuards,
454
505
  formatUsdc,
455
506
  parseUsdc,
@@ -459,6 +510,7 @@ async function payFetch(url, init, options) {
459
510
  quoteToUsd,
460
511
  quoteUsdOf,
461
512
  readPaywallEnv,
513
+ readSettlementHeader,
462
514
  resolvePayee
463
515
  });
464
516
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/errors.ts","../src/fee-mode.ts","../src/money.ts","../src/store.ts","../src/provider.ts","../src/env.ts","../src/client.ts"],"sourcesContent":["export * from './constants.js';\nexport * from './errors.js';\nexport * from './fee-mode.js';\nexport * from './money.js';\nexport * from './store.js';\nexport { paywall } from './provider.js';\nexport type {\n Paywall,\n PaywallOptions,\n UnpaidBody,\n HonoMiddleware,\n HonoContextLike,\n ExpressMiddleware,\n ExpressResponseLike,\n FacilitatorClient,\n RouteConfig,\n} from './provider.js';\nexport { payFetch, evaluateGuards, quoteUsdOf } from './client.js';\nexport type { EvmWallet, PayFetchOptions, SpendGuards } from './client.js';\nexport { readPaywallEnv, paywallEnvSchema } from './env.js';\nexport type { PaywallEnv } from './env.js';\n","/** Base networks in CAIP-2 form, which is what x402 v2 speaks. */\nexport const NETWORKS = {\n base: { caip2: 'eip155:8453', chainId: 8453, usdc: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' },\n 'base-sepolia': {\n caip2: 'eip155:84532',\n chainId: 84532,\n usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n },\n} as const;\n\nexport type NetworkName = keyof typeof NETWORKS;\n\n/** USDC is 6 decimals on Base. */\nexport const USDC_DECIMALS = 6;\n\n/**\n * Required on every 402 body and every payment-facing doc page. A payment is a direct\n * on-chain transfer between two wallets: once settled nobody, Fatstack included, can\n * reverse it.\n */\nexport const NO_REFUNDS_NOTICE =\n 'Payments are final. Once settled on-chain the transfer cannot be reversed, and there are no refunds.';\n\nexport const DOCS_URL = 'https://fatstack.net/docs/payments';\n\n/** Correlates a settled payment with the indexer's view of the on-chain transfer. */\nexport const PAYMENT_REF_HEADER = 'X-Fatstack-Payment-Ref';\n\nexport const DEFAULT_FACILITATOR_URL = 'https://x402.org/facilitator';\n","/** Names of the spend guards an agent can set. */\nexport type GuardName = 'maxPerCall' | 'maxPerHour' | 'maxPerDay' | 'allowedHosts';\n\n/**\n * Thrown before anything is signed when a call would breach a spend guard.\n *\n * Payments are final, so the only place to stop an unwanted spend is before the\n * signature exists. Every guard raises this, and it is never thrown after a payment\n * payload has been created.\n */\nexport class SpendGuardError extends Error {\n override readonly name = 'SpendGuardError';\n\n constructor(\n readonly guard: GuardName,\n message: string,\n readonly detail: { limitUsd?: number; attemptedUsd?: number; host?: string } = {},\n ) {\n super(message);\n }\n}\n\n/** Thrown by seams that are typed and reachable but deliberately not built yet. */\nexport class NotImplementedError extends Error {\n override readonly name = 'NotImplementedError';\n\n constructor(feature: string) {\n super(`${feature} is not implemented in this build.`);\n }\n}\n\n/** Thrown when an optional framework adapter is used without its package installed. */\nexport class MissingAdapterError extends Error {\n override readonly name = 'MissingAdapterError';\n\n constructor(pkg: string) {\n super(`${pkg} is not installed. Add it to use this adapter: pnpm add ${pkg}`);\n }\n}\n","import { NotImplementedError } from './errors.js';\n\nexport type FeeMode = 'direct' | 'splitter';\n\nexport interface PayeeResolution {\n /** The single address that receives the transfer. */\n payTo: string;\n /** Platform fee in basis points. Always 0 while FEE_MODE=direct. */\n feeBps: number;\n}\n\n/**\n * Resolves who is paid for a call. Under `direct` this is always, and only, the\n * provider's own wallet — the platform is never a payee and never custodies funds.\n *\n * `splitter` is a reserved seam for the fee-splitting contract. It is typed and reachable\n * so the shape is settled, but it throws: there is no splitter contract in this build.\n */\nexport function resolvePayee(mode: FeeMode, providerWallet: string): PayeeResolution {\n switch (mode) {\n case 'direct':\n return { payTo: providerWallet, feeBps: 0 };\n case 'splitter':\n throw new NotImplementedError(\n 'FEE_MODE=splitter (no splitter contract ships in the launch build)',\n );\n }\n}\n","import { NETWORKS, USDC_DECIMALS } from './constants.js';\n\nconst UNITS_PER_USDC = 10n ** BigInt(USDC_DECIMALS);\n\n/** \"1.25\" -> 1250000n. Rejects anything that is not a plain non-negative decimal. */\nexport function parseUsdc(input: string): bigint {\n const match = /^(\\d+)(?:\\.(\\d{1,6}))?$/.exec(input.trim());\n if (!match) {\n throw new RangeError(`Not a USDC amount with at most ${USDC_DECIMALS} decimals: ${input}`);\n }\n const whole = BigInt(match[1] ?? '0');\n const fraction = BigInt((match[2] ?? '').padEnd(USDC_DECIMALS, '0') || '0');\n return whole * UNITS_PER_USDC + fraction;\n}\n\n/** 1250000n -> \"1.25\". Trailing zeros trimmed. */\nexport function formatUsdc(atomic: bigint): string {\n if (atomic < 0n) throw new RangeError('USDC amounts are never negative');\n const whole = atomic / UNITS_PER_USDC;\n const fraction = (atomic % UNITS_PER_USDC).toString().padStart(USDC_DECIMALS, '0');\n const trimmed = fraction.replace(/0+$/, '');\n return trimmed ? `${whole}.${trimmed}` : whole.toString();\n}\n\nconst USDC_ADDRESSES = new Set(\n Object.values(NETWORKS).map((network) => network.usdc.toLowerCase()),\n);\n\n/**\n * Converts a quoted amount to USD for guard evaluation.\n *\n * Fails closed: if the asset is not a USDC contract we recognise and the quote carries no\n * usable `decimals`, this throws rather than guessing. Guessing here would let an\n * unrecognised token slip past a spend cap, and the payment is irreversible.\n */\nexport function quoteToUsd(quote: {\n amountAtomic: string;\n asset: string;\n decimals?: number | undefined;\n}): number {\n const decimals = USDC_ADDRESSES.has(quote.asset.toLowerCase()) ? USDC_DECIMALS : quote.decimals;\n\n if (decimals === undefined || !Number.isInteger(decimals) || decimals < 0 || decimals > 36) {\n throw new RangeError(\n `Cannot price asset ${quote.asset}: unknown decimals. Refusing to evaluate spend guards against an unpriceable quote.`,\n );\n }\n\n if (!/^\\d+$/.test(quote.amountAtomic)) {\n throw new RangeError(`Quoted amount is not an integer atomic value: ${quote.amountAtomic}`);\n }\n\n return Number(quote.amountAtomic) / 10 ** decimals;\n}\n","/** One recorded spend, in USD, at a wall-clock millisecond. */\nexport interface SpendRecord {\n at: number;\n usd: number;\n}\n\n/**\n * Where rolling spend totals live. The default is in-memory and per-process; swap in a\n * shared implementation (Redis, Durable Object, Postgres) when an agent runs as more\n * than one process, otherwise each process enforces its own separate budget.\n */\nexport interface SpendStore {\n record(entry: SpendRecord): Promise<void> | void;\n /** Total USD recorded at or after `sinceMs`. */\n totalSince(sinceMs: number): Promise<number> | number;\n}\n\n/** Process-local store. Entries older than the longest window are dropped on write. */\nexport function createMemorySpendStore(retentionMs = 24 * 60 * 60 * 1000): SpendStore {\n let entries: SpendRecord[] = [];\n\n return {\n record(entry) {\n entries.push(entry);\n const cutoff = entry.at - retentionMs;\n if (entries.length > 64) entries = entries.filter((e) => e.at >= cutoff);\n },\n totalSince(sinceMs) {\n let total = 0;\n for (const entry of entries) if (entry.at >= sinceMs) total += entry.usd;\n return total;\n },\n };\n}\n","import { decodePaymentResponseHeader } from '@x402/core/http';\nimport { HTTPFacilitatorClient, x402ResourceServer } from '@x402/core/server';\nimport type { FacilitatorClient, RouteConfig } from '@x402/core/server';\nimport { ExactEvmScheme } from '@x402/evm/exact/server';\nimport { z } from 'zod';\n\nimport { DOCS_URL, NETWORKS, NO_REFUNDS_NOTICE, PAYMENT_REF_HEADER } from './constants.js';\nimport type { NetworkName } from './constants.js';\nimport { readPaywallEnv } from './env.js';\nimport { MissingAdapterError } from './errors.js';\nimport { resolvePayee } from './fee-mode.js';\nimport { formatUsdc, parseUsdc } from './money.js';\n\nconst optionsSchema = z.object({\n /** Price per call in USD, as a decimal string: \"0.002\". */\n price: z.string().regex(/^\\d+(?:\\.\\d{1,6})?$/, 'price must be USD with at most 6 decimals'),\n /** The provider's own wallet. Under FEE_MODE=direct this is the sole payee. */\n wallet: z.string().regex(/^0x[0-9a-fA-F]{40}$/, 'wallet must be a 20-byte address'),\n toolId: z.string().min(1).max(128),\n network: z.enum(['base', 'base-sepolia']).default('base'),\n description: z.string().optional(),\n docsUrl: z.string().url().default(DOCS_URL),\n mimeType: z.string().default('application/json'),\n maxTimeoutSeconds: z.number().int().positive().default(60),\n});\n\nexport interface PaywallOptions extends z.input<typeof optionsSchema> {\n /** Defaults to process.env. */\n env?: Record<string, string | undefined>;\n /** Injects a facilitator instead of building an HTTP one. Used by tests. */\n facilitator?: FacilitatorClient;\n}\n\n/** The 402 body an agent reads before deciding to pay. */\nexport interface UnpaidBody {\n error: 'payment_required';\n tool: string;\n price: { usdc: string; amountAtomic: string; asset: string; network: string };\n payTo: string;\n terms: { refundable: false; notice: string };\n docs: string;\n message: string;\n}\n\n/** Structurally compatible with Hono's `MiddlewareHandler`, without importing hono. */\nexport interface HonoContextLike {\n json: (body: unknown, status?: number) => Response;\n res: Response;\n req: { raw: Request };\n}\nexport type HonoMiddleware = (\n c: HonoContextLike,\n next: () => Promise<void>,\n) => Promise<Response | void>;\n\n/** Structurally compatible with an Express request handler. */\nexport interface ExpressResponseLike {\n status: (code: number) => { json: (body: unknown) => void };\n setHeader: (name: string, value: string | number | readonly string[]) => unknown;\n}\nexport type ExpressMiddleware = (\n req: unknown,\n res: ExpressResponseLike,\n next: (err?: unknown) => void,\n) => Promise<void>;\n\nexport interface Paywall {\n /** Hono middleware. Requires @x402/hono. */\n hono(): HonoMiddleware;\n /** Express middleware. Requires @x402/express. */\n express(): ExpressMiddleware;\n /** Wraps a Next.js route handler. Requires @x402/next (which needs Next >= 16.2.6). */\n next<T>(handler: (request: never) => Promise<T>): (request: never) => Promise<T>;\n /** The x402 route config, for advanced use with the official adapters directly. */\n routeConfig: RouteConfig;\n /** Resolved payee. Always the provider wallet while FEE_MODE=direct. */\n payTo: string;\n}\n\n/** Minimal shapes of the optional adapter packages, so their types are not required. */\ninterface HonoAdapterModule {\n paymentMiddleware: (routes: RouteConfig, server: x402ResourceServer) => unknown;\n}\ninterface ExpressAdapterModule {\n paymentMiddleware: (routes: RouteConfig, server: x402ResourceServer) => unknown;\n}\ninterface NextAdapterModule {\n withX402: (handler: unknown, routeConfig: RouteConfig, server: x402ResourceServer) => unknown;\n}\n\nconst KILLSWITCH_BODY = {\n error: 'service_unavailable',\n message:\n 'This tool is temporarily disabled by its operator (KILLSWITCH). No payment was taken. Try again later.',\n} as const;\n\n/**\n * Paywalls a route with x402: USDC on Base, paid directly to the provider's wallet.\n *\n * Verification and settlement are delegated to the official x402 packages against the\n * hosted facilitator — this module does not sign or verify anything itself.\n *\n * Throws immediately when FEE_MODE=splitter: there is no splitter contract in this build,\n * and silently falling back to `direct` would pay the wrong party.\n */\nexport function paywall(options: PaywallOptions): Paywall {\n const config = optionsSchema.parse(options);\n const env = readPaywallEnv(options.env);\n const network = NETWORKS[config.network as NetworkName];\n\n // Throws for FEE_MODE=splitter, at construction time rather than mid-request.\n const { payTo } = resolvePayee(env.FEE_MODE, config.wallet);\n\n const amountAtomic = parseUsdc(config.price).toString();\n const priceUsdc = formatUsdc(parseUsdc(config.price));\n\n const unpaidBody: UnpaidBody = {\n error: 'payment_required',\n tool: config.toolId,\n price: {\n usdc: priceUsdc,\n amountAtomic,\n asset: network.usdc,\n network: network.caip2,\n },\n payTo,\n terms: { refundable: false, notice: NO_REFUNDS_NOTICE },\n docs: config.docsUrl,\n message: `This call costs ${priceUsdc} USDC on ${config.network}, paid directly to the provider. ${NO_REFUNDS_NOTICE} See ${config.docsUrl}`,\n };\n\n const routeConfig: RouteConfig = {\n accepts: {\n scheme: 'exact',\n network: network.caip2,\n payTo,\n // An explicit asset+amount pins USDC and the exact atomic amount, rather than\n // leaving the quote to a price feed.\n price: { asset: network.usdc, amount: amountAtomic },\n maxTimeoutSeconds: config.maxTimeoutSeconds,\n },\n description: config.description ?? `Fatstack tool ${config.toolId}`,\n mimeType: config.mimeType,\n unpaidResponseBody: () => ({ contentType: 'application/json', body: unpaidBody }),\n };\n\n const facilitator: FacilitatorClient =\n options.facilitator ??\n new HTTPFacilitatorClient({\n url: env.FACILITATOR_URL,\n ...(env.FACILITATOR_API_KEY\n ? {\n createAuthHeaders: async () => ({\n verify: { authorization: `Bearer ${env.FACILITATOR_API_KEY}` },\n settle: { authorization: `Bearer ${env.FACILITATOR_API_KEY}` },\n supported: { authorization: `Bearer ${env.FACILITATOR_API_KEY}` },\n }),\n }\n : {}),\n });\n\n const server = new x402ResourceServer(facilitator).register(network.caip2, new ExactEvmScheme());\n\n const killed = env.KILLSWITCH === '1';\n\n /** Derives the indexing reference from the settlement receipt the adapter emitted. */\n function paymentRef(paymentResponseHeader: string | null | undefined): string | null {\n if (!paymentResponseHeader) return null;\n try {\n const settled = decodePaymentResponseHeader(paymentResponseHeader);\n const transaction = (settled as { transaction?: string }).transaction;\n return transaction ? `${config.toolId}:${network.caip2}:${transaction}` : null;\n } catch {\n return null;\n }\n }\n\n return {\n routeConfig,\n payTo,\n\n hono(): HonoMiddleware {\n let cached: unknown;\n return async (c, next) => {\n if (killed) return c.json(KILLSWITCH_BODY, 503);\n\n if (!cached) {\n const mod = await importOptional<HonoAdapterModule>('@x402/hono');\n cached = mod.paymentMiddleware(routeConfig, server);\n }\n const middleware = cached as (\n ctx: HonoContextLike,\n n: () => Promise<void>,\n ) => Promise<Response | void>;\n const result = await middleware(c, next);\n\n // c.res carries the response Hono will send, whether the middleware set it or\n // the downstream handler did.\n const carrier = result instanceof Response ? result : c.res;\n const ref = paymentRef(carrier?.headers?.get('x-payment-response'));\n if (ref) carrier.headers.set(PAYMENT_REF_HEADER, ref);\n return result;\n };\n },\n\n express(): ExpressMiddleware {\n let cached: unknown;\n return async (req, res, next) => {\n const response = res;\n if (killed) {\n response.status(503).json(KILLSWITCH_BODY);\n return;\n }\n\n if (!cached) {\n const mod = await importOptional<ExpressAdapterModule>('@x402/express');\n cached = mod.paymentMiddleware(routeConfig, server);\n }\n\n // Headers must be attached before the response flushes, so mirror the settlement\n // receipt onto the ref header the moment the adapter sets it.\n const originalSetHeader = response.setHeader.bind(response);\n response.setHeader = (name, value) => {\n const out = originalSetHeader(name, value);\n if (String(name).toLowerCase() === 'x-payment-response') {\n const ref = paymentRef(String(value));\n if (ref) originalSetHeader(PAYMENT_REF_HEADER, ref);\n }\n return out;\n };\n\n const middleware = cached as (\n q: unknown,\n s: unknown,\n n: (err?: unknown) => void,\n ) => Promise<void>;\n await middleware(req, res, next);\n };\n },\n\n next<T>(handler: (request: never) => Promise<T>) {\n let cached: unknown;\n return async (request: never): Promise<T> => {\n if (killed) {\n return Response.json(KILLSWITCH_BODY, { status: 503 }) as T;\n }\n\n if (!cached) {\n const mod = await importOptional<NextAdapterModule>('@x402/next');\n cached = mod.withX402(handler as never, routeConfig, server);\n }\n const wrapped = cached as (r: never) => Promise<T>;\n const result = await wrapped(request);\n\n if (result instanceof Response) {\n const ref = paymentRef(result.headers.get('x-payment-response'));\n if (ref) result.headers.set(PAYMENT_REF_HEADER, ref);\n }\n return result;\n };\n },\n };\n}\n\nasync function importOptional<T>(specifier: string): Promise<T> {\n try {\n return (await import(/* @vite-ignore */ specifier)) as T;\n } catch {\n throw new MissingAdapterError(specifier);\n }\n}\n\nexport type { FacilitatorClient, RouteConfig } from '@x402/core/server';\n","import { z } from 'zod';\n\nimport { DEFAULT_FACILITATOR_URL } from './constants.js';\n\n/**\n * Environment the paywall reads. Parsed lazily inside `paywall()`, never at module load,\n * so importing this package never throws in a build step.\n */\nexport const paywallEnvSchema = z.object({\n /** Hosted facilitator (Coinbase CDP). Fatstack does not run its own. */\n FACILITATOR_URL: z.string().url().default(DEFAULT_FACILITATOR_URL),\n FACILITATOR_API_KEY: z.string().min(1).optional(),\n /**\n * `1` takes every paywalled route offline with a 503. Intended for an incident where\n * continuing to take irreversible payments would be worse than being down.\n */\n KILLSWITCH: z.enum(['0', '1']).default('0'),\n /**\n * direct = agent pays the provider wallet, 0% platform fee (the launch build)\n * splitter = reserved for the fee-splitting contract; not implemented\n */\n FEE_MODE: z.enum(['direct', 'splitter']).default('direct'),\n});\n\nexport type PaywallEnv = z.infer<typeof paywallEnvSchema>;\n\nexport function readPaywallEnv(\n source: Record<string, string | undefined> = process.env,\n): PaywallEnv {\n return paywallEnvSchema.parse({\n FACILITATOR_URL: source.FACILITATOR_URL,\n FACILITATOR_API_KEY: source.FACILITATOR_API_KEY,\n KILLSWITCH: source.KILLSWITCH,\n FEE_MODE: source.FEE_MODE,\n });\n}\n","import { x402Client } from '@x402/core/client';\nimport type { PaymentRequirements } from '@x402/core/types';\nimport { ExactEvmScheme } from '@x402/evm/exact/client';\nimport { wrapFetchWithPayment } from '@x402/fetch';\n\nimport { NETWORKS, PAYMENT_REF_HEADER } from './constants.js';\nimport type { NetworkName } from './constants.js';\nimport { SpendGuardError } from './errors.js';\nimport { quoteToUsd } from './money.js';\nimport { createMemorySpendStore } from './store.js';\nimport type { SpendStore } from './store.js';\n\n/** The signer the official EVM scheme expects: address + signTypedData, no key handling. */\nexport type EvmWallet = ConstructorParameters<typeof ExactEvmScheme>[0];\n\nexport interface SpendGuards {\n /** Hard USD ceiling for a single call. */\n maxPerCall?: number;\n /** Rolling 60-minute USD ceiling. */\n maxPerHour?: number;\n /** Rolling 24-hour USD ceiling. */\n maxPerDay?: number;\n /** Hostnames this agent may pay. Checked before any network call. */\n allowedHosts?: string[];\n}\n\nexport interface PayFetchOptions {\n wallet: EvmWallet;\n guards?: SpendGuards;\n /** Defaults to a process-local in-memory store. */\n store?: SpendStore;\n networks?: NetworkName[];\n fetch?: typeof globalThis.fetch;\n now?: () => number;\n}\n\nconst HOUR_MS = 60 * 60 * 1000;\nconst DAY_MS = 24 * HOUR_MS;\n\nfunction hostOf(input: RequestInfo | URL): string | null {\n try {\n const raw =\n typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.toString()\n : (input as Request).url;\n return new URL(raw).hostname.toLowerCase();\n } catch {\n return null;\n }\n}\n\n/** `example.com` in allowedHosts also authorises `tool.example.com`. */\nfunction hostAllowed(host: string, allowed: readonly string[]): boolean {\n return allowed.some((entry) => {\n const candidate = entry.trim().toLowerCase().replace(/^\\*\\./, '');\n return host === candidate || host.endsWith(`.${candidate}`);\n });\n}\n\n/**\n * Checks every guard against a quote. Returns the USD value if the call may proceed,\n * throws SpendGuardError otherwise. Called before a payment payload exists.\n */\nexport async function evaluateGuards(\n quoteUsd: number,\n guards: SpendGuards,\n store: SpendStore,\n now: number,\n): Promise<void> {\n if (guards.maxPerCall !== undefined && quoteUsd > guards.maxPerCall) {\n throw new SpendGuardError(\n 'maxPerCall',\n `Call costs $${quoteUsd} which exceeds the maxPerCall limit of $${guards.maxPerCall}`,\n { limitUsd: guards.maxPerCall, attemptedUsd: quoteUsd },\n );\n }\n\n if (guards.maxPerHour !== undefined) {\n const spent = await store.totalSince(now - HOUR_MS);\n if (spent + quoteUsd > guards.maxPerHour) {\n throw new SpendGuardError(\n 'maxPerHour',\n `Call costs $${quoteUsd} and $${spent} was already spent this hour, exceeding the maxPerHour limit of $${guards.maxPerHour}`,\n { limitUsd: guards.maxPerHour, attemptedUsd: spent + quoteUsd },\n );\n }\n }\n\n if (guards.maxPerDay !== undefined) {\n const spent = await store.totalSince(now - DAY_MS);\n if (spent + quoteUsd > guards.maxPerDay) {\n throw new SpendGuardError(\n 'maxPerDay',\n `Call costs $${quoteUsd} and $${spent} was already spent today, exceeding the maxPerDay limit of $${guards.maxPerDay}`,\n { limitUsd: guards.maxPerDay, attemptedUsd: spent + quoteUsd },\n );\n }\n }\n}\n\n/** Reads the quoted amount out of x402 payment requirements. */\ninterface PriceableRequirement {\n maxAmountRequired?: string;\n amount?: string;\n asset?: string;\n extra?: { decimals?: number };\n}\n\nexport function quoteUsdOf(requirements: PaymentRequirements): number {\n const asRecord: PriceableRequirement = requirements;\n const amountAtomic = asRecord.maxAmountRequired ?? asRecord.amount;\n if (!amountAtomic || !asRecord.asset) {\n throw new RangeError('Payment requirements carry no priceable amount; refusing to pay.');\n }\n return quoteToUsd({\n amountAtomic,\n asset: asRecord.asset,\n decimals: asRecord.extra?.decimals,\n });\n}\n\n/**\n * A `fetch` that pays for 402 responses, under spend guards.\n *\n * The 402 handling, signing and retry are the official x402 packages' work. What this adds\n * is refusal: guards are evaluated inside the payment-policy hook, which runs after the\n * quote is known and before any payload is signed, so exceeding a guard throws\n * SpendGuardError with nothing signed and nothing spent.\n */\nexport async function payFetch(\n url: RequestInfo | URL,\n init: RequestInit | undefined,\n options: PayFetchOptions,\n): Promise<Response> {\n const guards = options.guards ?? {};\n const store = options.store ?? createMemorySpendStore();\n const now = options.now ?? Date.now;\n const baseFetch = options.fetch ?? globalThis.fetch;\n const networks = options.networks ?? (['base'] as NetworkName[]);\n\n // Host allowlist is checked first: an unauthorised host should cost no request at all.\n if (guards.allowedHosts) {\n const host = hostOf(url);\n if (!host || !hostAllowed(host, guards.allowedHosts)) {\n throw new SpendGuardError(\n 'allowedHosts',\n `Host ${host ?? '<unparseable>'} is not in allowedHosts`,\n { host: host ?? undefined },\n );\n }\n }\n\n let quotedUsd: number | null = null;\n\n const client = new x402Client((_version, requirements) => {\n // Runs before the payment payload is created. Throwing here means no signature.\n const affordable = requirements.filter((requirement) => {\n const usd = quoteUsdOf(requirement);\n return guards.maxPerCall === undefined || usd <= guards.maxPerCall;\n });\n\n const chosen = (affordable.length > 0 ? affordable : requirements)[0];\n if (!chosen) throw new RangeError('Resource offered no payment requirements');\n\n quotedUsd = quoteUsdOf(chosen);\n return chosen;\n });\n\n for (const name of networks) {\n client.register(NETWORKS[name].caip2, new ExactEvmScheme(options.wallet));\n }\n\n const guarded: typeof globalThis.fetch = async (input, requestInit) => {\n const response = await baseFetch(input, requestInit);\n if (response.status !== 402) return response;\n\n // Peek at the quote and apply guards before the wrapper signs anything.\n const body = await response\n .clone()\n .json()\n .catch(() => null);\n const accepts = (body as { accepts?: PaymentRequirements[] } | null)?.accepts;\n if (Array.isArray(accepts) && accepts.length > 0) {\n const cheapest = accepts\n .map((requirement) => quoteUsdOf(requirement))\n .sort((a, b) => a - b)[0];\n if (cheapest !== undefined) {\n await evaluateGuards(cheapest, guards, store, now());\n }\n }\n return response;\n };\n\n const paying = wrapFetchWithPayment(guarded, client);\n const response = await paying(url as RequestInfo, init);\n\n // Record the spend only once a payment actually settled.\n if (response.headers.get('x-payment-response') && quotedUsd !== null) {\n await store.record({ at: now(), usd: quotedUsd });\n }\n\n return response;\n}\n\nexport { PAYMENT_REF_HEADER };\n"],"mappings":"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","names":["import_server","import_zod","import_client","response"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/errors.ts","../src/fee-mode.ts","../src/money.ts","../src/store.ts","../src/provider.ts","../src/env.ts","../src/client.ts"],"sourcesContent":["export * from './constants.js';\nexport * from './errors.js';\nexport * from './fee-mode.js';\nexport * from './money.js';\nexport * from './store.js';\nexport { paywall } from './provider.js';\nexport type {\n Paywall,\n PaywallOptions,\n UnpaidBody,\n HonoMiddleware,\n HonoContextLike,\n ExpressMiddleware,\n ExpressResponseLike,\n FacilitatorClient,\n RouteConfig,\n} from './provider.js';\nexport { payFetch, evaluateGuards, quoteUsdOf } from './client.js';\nexport type { EvmWallet, PayFetchOptions, SpendGuards } from './client.js';\nexport { readPaywallEnv, paywallEnvSchema } from './env.js';\nexport type { PaywallEnv } from './env.js';\nexport { decodePaymentResponseHeader } from '@x402/core/http';\n","/** Base networks in CAIP-2 form, which is what x402 v2 speaks. */\n/**\n * The EIP-712 domain a payer signs the EIP-3009 authorisation against is **not** listed\n * here on purpose: it differs per network (mainnet USDC is \"USD Coin\", the Sepolia\n * deployment is \"USDC\"), and the EVM scheme owns the authoritative table. Quoting a\n * dollar price lets it resolve the asset and publish that domain in the 402; naming an\n * explicit asset bypasses the lookup and emits `extra: {}`, which no payer can sign\n * against.\n */\nexport const NETWORKS = {\n base: {\n caip2: 'eip155:8453',\n chainId: 8453,\n usdc: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n },\n 'base-sepolia': {\n caip2: 'eip155:84532',\n chainId: 84532,\n usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n },\n} as const;\n\nexport type NetworkName = keyof typeof NETWORKS;\n\n/** USDC is 6 decimals on Base. */\nexport const USDC_DECIMALS = 6;\n\n/**\n * Required on every 402 body and every payment-facing doc page. A payment is a direct\n * on-chain transfer between two wallets: once settled nobody, Fatstack included, can\n * reverse it.\n */\nexport const NO_REFUNDS_NOTICE =\n 'Payments are final. Once settled on-chain the transfer cannot be reversed, and there are no refunds.';\n\nexport const DOCS_URL = 'https://fatstack.net/docs/payments';\n\n/** Correlates a settled payment with the indexer's view of the on-chain transfer. */\nexport const PAYMENT_REF_HEADER = 'X-Fatstack-Payment-Ref';\n\n/**\n * x402 v2 dropped the `X-` prefix: the settlement receipt is `PAYMENT-RESPONSE` and the\n * payer's payload is `PAYMENT-SIGNATURE`. The v1 spellings are still read so a v1 payer\n * or resource keeps working. Header names are case-insensitive; these are lowercase\n * because `Headers.get` normalises.\n */\nexport const SETTLEMENT_HEADERS = ['payment-response', 'x-payment-response'] as const;\nexport const PAYMENT_SIGNATURE_HEADERS = ['payment-signature', 'x-payment'] as const;\n\n/** First settlement receipt present on a response, in either spelling. */\nexport function readSettlementHeader(headers: Headers): string | null {\n for (const name of SETTLEMENT_HEADERS) {\n const value = headers.get(name);\n if (value) return value;\n }\n return null;\n}\n\nexport const DEFAULT_FACILITATOR_URL = 'https://x402.org/facilitator';\n","/** Names of the spend guards an agent can set. */\nexport type GuardName = 'maxPerCall' | 'maxPerHour' | 'maxPerDay' | 'allowedHosts';\n\n/**\n * Thrown before anything is signed when a call would breach a spend guard.\n *\n * Payments are final, so the only place to stop an unwanted spend is before the\n * signature exists. Every guard raises this, and it is never thrown after a payment\n * payload has been created.\n */\nexport class SpendGuardError extends Error {\n override readonly name = 'SpendGuardError';\n\n constructor(\n readonly guard: GuardName,\n message: string,\n readonly detail: { limitUsd?: number; attemptedUsd?: number; host?: string } = {},\n ) {\n super(message);\n }\n}\n\n/** Thrown by seams that are typed and reachable but deliberately not built yet. */\nexport class NotImplementedError extends Error {\n override readonly name = 'NotImplementedError';\n\n constructor(feature: string) {\n super(`${feature} is not implemented in this build.`);\n }\n}\n\n/** Thrown when an optional framework adapter is used without its package installed. */\nexport class MissingAdapterError extends Error {\n override readonly name = 'MissingAdapterError';\n\n constructor(pkg: string) {\n super(`${pkg} is not installed. Add it to use this adapter: pnpm add ${pkg}`);\n }\n}\n\n/**\n * A 402 arrived whose payment requirements could not be read, so the call cannot be\n * priced and therefore cannot be checked against a spend cap. Refusing is the safe\n * outcome: paying blind is irreversible.\n */\nexport class UnreadableQuoteError extends Error {\n override readonly name = 'UnreadableQuoteError';\n\n constructor(message: string) {\n super(message);\n }\n}\n","import { NotImplementedError } from './errors.js';\n\nexport type FeeMode = 'direct' | 'splitter';\n\nexport interface PayeeResolution {\n /** The single address that receives the transfer. */\n payTo: string;\n /** Platform fee in basis points. Always 0 while FEE_MODE=direct. */\n feeBps: number;\n}\n\n/**\n * Resolves who is paid for a call. Under `direct` this is always, and only, the\n * provider's own wallet — the platform is never a payee and never custodies funds.\n *\n * `splitter` is a reserved seam for the fee-splitting contract. It is typed and reachable\n * so the shape is settled, but it throws: there is no splitter contract in this build.\n */\nexport function resolvePayee(mode: FeeMode, providerWallet: string): PayeeResolution {\n switch (mode) {\n case 'direct':\n return { payTo: providerWallet, feeBps: 0 };\n case 'splitter':\n throw new NotImplementedError(\n 'FEE_MODE=splitter (no splitter contract ships in the launch build)',\n );\n }\n}\n","import { NETWORKS, USDC_DECIMALS } from './constants.js';\n\nconst UNITS_PER_USDC = 10n ** BigInt(USDC_DECIMALS);\n\n/** \"1.25\" -> 1250000n. Rejects anything that is not a plain non-negative decimal. */\nexport function parseUsdc(input: string): bigint {\n const match = /^(\\d+)(?:\\.(\\d{1,6}))?$/.exec(input.trim());\n if (!match) {\n throw new RangeError(`Not a USDC amount with at most ${USDC_DECIMALS} decimals: ${input}`);\n }\n const whole = BigInt(match[1] ?? '0');\n const fraction = BigInt((match[2] ?? '').padEnd(USDC_DECIMALS, '0') || '0');\n return whole * UNITS_PER_USDC + fraction;\n}\n\n/** 1250000n -> \"1.25\". Trailing zeros trimmed. */\nexport function formatUsdc(atomic: bigint): string {\n if (atomic < 0n) throw new RangeError('USDC amounts are never negative');\n const whole = atomic / UNITS_PER_USDC;\n const fraction = (atomic % UNITS_PER_USDC).toString().padStart(USDC_DECIMALS, '0');\n const trimmed = fraction.replace(/0+$/, '');\n return trimmed ? `${whole}.${trimmed}` : whole.toString();\n}\n\nconst USDC_ADDRESSES = new Set(\n Object.values(NETWORKS).map((network) => network.usdc.toLowerCase()),\n);\n\n/**\n * Converts a quoted amount to USD for guard evaluation.\n *\n * Fails closed: if the asset is not a USDC contract we recognise and the quote carries no\n * usable `decimals`, this throws rather than guessing. Guessing here would let an\n * unrecognised token slip past a spend cap, and the payment is irreversible.\n */\nexport function quoteToUsd(quote: {\n amountAtomic: string;\n asset: string;\n decimals?: number | undefined;\n}): number {\n const decimals = USDC_ADDRESSES.has(quote.asset.toLowerCase()) ? USDC_DECIMALS : quote.decimals;\n\n if (decimals === undefined || !Number.isInteger(decimals) || decimals < 0 || decimals > 36) {\n throw new RangeError(\n `Cannot price asset ${quote.asset}: unknown decimals. Refusing to evaluate spend guards against an unpriceable quote.`,\n );\n }\n\n if (!/^\\d+$/.test(quote.amountAtomic)) {\n throw new RangeError(`Quoted amount is not an integer atomic value: ${quote.amountAtomic}`);\n }\n\n return Number(quote.amountAtomic) / 10 ** decimals;\n}\n","/** One recorded spend, in USD, at a wall-clock millisecond. */\nexport interface SpendRecord {\n at: number;\n usd: number;\n}\n\n/**\n * Where rolling spend totals live. The default is in-memory and per-process; swap in a\n * shared implementation (Redis, Durable Object, Postgres) when an agent runs as more\n * than one process, otherwise each process enforces its own separate budget.\n */\nexport interface SpendStore {\n record(entry: SpendRecord): Promise<void> | void;\n /** Total USD recorded at or after `sinceMs`. */\n totalSince(sinceMs: number): Promise<number> | number;\n}\n\n/** Process-local store. Entries older than the longest window are dropped on write. */\nexport function createMemorySpendStore(retentionMs = 24 * 60 * 60 * 1000): SpendStore {\n let entries: SpendRecord[] = [];\n\n return {\n record(entry) {\n entries.push(entry);\n const cutoff = entry.at - retentionMs;\n if (entries.length > 64) entries = entries.filter((e) => e.at >= cutoff);\n },\n totalSince(sinceMs) {\n let total = 0;\n for (const entry of entries) if (entry.at >= sinceMs) total += entry.usd;\n return total;\n },\n };\n}\n","import { decodePaymentResponseHeader } from '@x402/core/http';\nimport { HTTPFacilitatorClient, x402ResourceServer } from '@x402/core/server';\nimport type { FacilitatorClient, RouteConfig } from '@x402/core/server';\nimport { ExactEvmScheme } from '@x402/evm/exact/server';\nimport { z } from 'zod';\n\nimport {\n DOCS_URL,\n NETWORKS,\n NO_REFUNDS_NOTICE,\n PAYMENT_REF_HEADER,\n readSettlementHeader,\n} from './constants.js';\nimport type { NetworkName } from './constants.js';\nimport { readPaywallEnv } from './env.js';\nimport { SETTLEMENT_HEADERS } from './constants.js';\nimport { MissingAdapterError } from './errors.js';\nimport { resolvePayee } from './fee-mode.js';\nimport { formatUsdc, parseUsdc } from './money.js';\n\nconst optionsSchema = z.object({\n /** Price per call in USD, as a decimal string: \"0.002\". */\n price: z.string().regex(/^\\d+(?:\\.\\d{1,6})?$/, 'price must be USD with at most 6 decimals'),\n /** The provider's own wallet. Under FEE_MODE=direct this is the sole payee. */\n wallet: z.string().regex(/^0x[0-9a-fA-F]{40}$/, 'wallet must be a 20-byte address'),\n toolId: z.string().min(1).max(128),\n network: z.enum(['base', 'base-sepolia']).default('base'),\n description: z.string().optional(),\n docsUrl: z.string().url().default(DOCS_URL),\n mimeType: z.string().default('application/json'),\n maxTimeoutSeconds: z.number().int().positive().default(60),\n});\n\nexport interface PaywallOptions extends z.input<typeof optionsSchema> {\n /** Defaults to process.env. */\n env?: Record<string, string | undefined>;\n /** Injects a facilitator instead of building an HTTP one. Used by tests. */\n facilitator?: FacilitatorClient;\n}\n\n/** The 402 body an agent reads before deciding to pay. */\nexport interface UnpaidBody {\n error: 'payment_required';\n tool: string;\n price: { usdc: string; amountAtomic: string; asset: string; network: string };\n payTo: string;\n terms: { refundable: false; notice: string };\n docs: string;\n message: string;\n}\n\n/** Structurally compatible with Hono's `MiddlewareHandler`, without importing hono. */\nexport interface HonoContextLike {\n json: (body: unknown, status?: number) => Response;\n res: Response;\n req: { raw: Request };\n}\nexport type HonoMiddleware = (\n c: HonoContextLike,\n next: () => Promise<void>,\n) => Promise<Response | void>;\n\n/** Structurally compatible with an Express request handler. */\nexport interface ExpressResponseLike {\n status: (code: number) => { json: (body: unknown) => void };\n setHeader: (name: string, value: string | number | readonly string[]) => unknown;\n}\nexport type ExpressMiddleware = (\n req: unknown,\n res: ExpressResponseLike,\n next: (err?: unknown) => void,\n) => Promise<void>;\n\nexport interface Paywall {\n /** Hono middleware. Requires @x402/hono. */\n hono(): HonoMiddleware;\n /** Express middleware. Requires @x402/express. */\n express(): ExpressMiddleware;\n /** Wraps a Next.js route handler. Requires @x402/next (which needs Next >= 16.2.6). */\n next<T>(handler: (request: never) => Promise<T>): (request: never) => Promise<T>;\n /** The x402 route config, for advanced use with the official adapters directly. */\n routeConfig: RouteConfig;\n /** Resolved payee. Always the provider wallet while FEE_MODE=direct. */\n payTo: string;\n}\n\n/** Minimal shapes of the optional adapter packages, so their types are not required. */\ninterface HonoAdapterModule {\n paymentMiddleware: (routes: RouteConfig, server: x402ResourceServer) => unknown;\n}\ninterface ExpressAdapterModule {\n paymentMiddleware: (routes: RouteConfig, server: x402ResourceServer) => unknown;\n}\ninterface NextAdapterModule {\n withX402: (handler: unknown, routeConfig: RouteConfig, server: x402ResourceServer) => unknown;\n}\n\nconst KILLSWITCH_BODY = {\n error: 'service_unavailable',\n message:\n 'This tool is temporarily disabled by its operator (KILLSWITCH). No payment was taken. Try again later.',\n} as const;\n\n/**\n * Paywalls a route with x402: USDC on Base, paid directly to the provider's wallet.\n *\n * Verification and settlement are delegated to the official x402 packages against the\n * hosted facilitator — this module does not sign or verify anything itself.\n *\n * Throws immediately when FEE_MODE=splitter: there is no splitter contract in this build,\n * and silently falling back to `direct` would pay the wrong party.\n */\nexport function paywall(options: PaywallOptions): Paywall {\n const config = optionsSchema.parse(options);\n const env = readPaywallEnv(options.env);\n const network = NETWORKS[config.network as NetworkName];\n\n // Throws for FEE_MODE=splitter, at construction time rather than mid-request.\n const { payTo } = resolvePayee(env.FEE_MODE, config.wallet);\n\n const amountAtomic = parseUsdc(config.price).toString();\n const priceUsdc = formatUsdc(parseUsdc(config.price));\n\n const unpaidBody: UnpaidBody = {\n error: 'payment_required',\n tool: config.toolId,\n price: {\n usdc: priceUsdc,\n amountAtomic,\n asset: network.usdc,\n network: network.caip2,\n },\n payTo,\n terms: { refundable: false, notice: NO_REFUNDS_NOTICE },\n docs: config.docsUrl,\n message: `This call costs ${priceUsdc} USDC on ${config.network}, paid directly to the provider. ${NO_REFUNDS_NOTICE} See ${config.docsUrl}`,\n };\n\n const routeConfig: RouteConfig = {\n accepts: {\n scheme: 'exact',\n network: network.caip2,\n payTo,\n // An explicit asset+amount pins USDC and the exact atomic amount, rather than\n // leaving the quote to a price feed.\n // A dollar price, not an explicit { asset, amount }: the EVM scheme resolves the\n // network's default asset (USDC) and publishes its EIP-712 domain in `extra`, which\n // the payer needs to sign the EIP-3009 authorisation. Naming the asset directly\n // skips that lookup and emits `extra: {}`, which nobody can pay against.\n price: `$${priceUsdc}`,\n maxTimeoutSeconds: config.maxTimeoutSeconds,\n },\n description: config.description ?? `Fatstack tool ${config.toolId}`,\n mimeType: config.mimeType,\n unpaidResponseBody: () => ({ contentType: 'application/json', body: unpaidBody }),\n };\n\n const facilitator: FacilitatorClient =\n options.facilitator ??\n new HTTPFacilitatorClient({\n url: env.FACILITATOR_URL,\n ...(env.FACILITATOR_API_KEY\n ? {\n createAuthHeaders: async () => ({\n verify: { authorization: `Bearer ${env.FACILITATOR_API_KEY}` },\n settle: { authorization: `Bearer ${env.FACILITATOR_API_KEY}` },\n supported: { authorization: `Bearer ${env.FACILITATOR_API_KEY}` },\n }),\n }\n : {}),\n });\n\n const server = new x402ResourceServer(facilitator).register(network.caip2, new ExactEvmScheme());\n\n const killed = env.KILLSWITCH === '1';\n\n /** Derives the indexing reference from the settlement receipt the adapter emitted. */\n function paymentRef(paymentResponseHeader: string | null | undefined): string | null {\n if (!paymentResponseHeader) return null;\n try {\n const settled = decodePaymentResponseHeader(paymentResponseHeader);\n const transaction = (settled as { transaction?: string }).transaction;\n return transaction ? `${config.toolId}:${network.caip2}:${transaction}` : null;\n } catch {\n return null;\n }\n }\n\n return {\n routeConfig,\n payTo,\n\n hono(): HonoMiddleware {\n let cached: unknown;\n return async (c, next) => {\n if (killed) return c.json(KILLSWITCH_BODY, 503);\n\n if (!cached) {\n const mod = await importOptional<HonoAdapterModule>('@x402/hono');\n cached = mod.paymentMiddleware(routeConfig, server);\n }\n const middleware = cached as (\n ctx: HonoContextLike,\n n: () => Promise<void>,\n ) => Promise<Response | void>;\n const result = await middleware(c, next);\n\n // c.res carries the response Hono will send, whether the middleware set it or\n // the downstream handler did.\n const carrier = result instanceof Response ? result : c.res;\n const ref = paymentRef(carrier ? readSettlementHeader(carrier.headers) : null);\n if (ref) carrier.headers.set(PAYMENT_REF_HEADER, ref);\n return result;\n };\n },\n\n express(): ExpressMiddleware {\n let cached: unknown;\n return async (req, res, next) => {\n const response = res;\n if (killed) {\n response.status(503).json(KILLSWITCH_BODY);\n return;\n }\n\n if (!cached) {\n const mod = await importOptional<ExpressAdapterModule>('@x402/express');\n cached = mod.paymentMiddleware(routeConfig, server);\n }\n\n // Headers must be attached before the response flushes, so mirror the settlement\n // receipt onto the ref header the moment the adapter sets it.\n const originalSetHeader = response.setHeader.bind(response);\n response.setHeader = (name, value) => {\n const out = originalSetHeader(name, value);\n if (SETTLEMENT_HEADERS.includes(String(name).toLowerCase() as never)) {\n const ref = paymentRef(String(value));\n if (ref) originalSetHeader(PAYMENT_REF_HEADER, ref);\n }\n return out;\n };\n\n const middleware = cached as (\n q: unknown,\n s: unknown,\n n: (err?: unknown) => void,\n ) => Promise<void>;\n await middleware(req, res, next);\n };\n },\n\n next<T>(handler: (request: never) => Promise<T>) {\n let cached: unknown;\n return async (request: never): Promise<T> => {\n if (killed) {\n return Response.json(KILLSWITCH_BODY, { status: 503 }) as T;\n }\n\n if (!cached) {\n const mod = await importOptional<NextAdapterModule>('@x402/next');\n cached = mod.withX402(handler as never, routeConfig, server);\n }\n const wrapped = cached as (r: never) => Promise<T>;\n const result = await wrapped(request);\n\n if (result instanceof Response) {\n const ref = paymentRef(readSettlementHeader(result.headers));\n if (ref) result.headers.set(PAYMENT_REF_HEADER, ref);\n }\n return result;\n };\n },\n };\n}\n\nasync function importOptional<T>(specifier: string): Promise<T> {\n try {\n return (await import(/* @vite-ignore */ specifier)) as T;\n } catch {\n throw new MissingAdapterError(specifier);\n }\n}\n\nexport type { FacilitatorClient, RouteConfig } from '@x402/core/server';\n","import { z } from 'zod';\n\nimport { DEFAULT_FACILITATOR_URL } from './constants.js';\n\n/**\n * Environment the paywall reads. Parsed lazily inside `paywall()`, never at module load,\n * so importing this package never throws in a build step.\n */\nexport const paywallEnvSchema = z.object({\n /** Hosted facilitator (Coinbase CDP). Fatstack does not run its own. */\n FACILITATOR_URL: z.string().url().default(DEFAULT_FACILITATOR_URL),\n FACILITATOR_API_KEY: z.string().min(1).optional(),\n /**\n * `1` takes every paywalled route offline with a 503. Intended for an incident where\n * continuing to take irreversible payments would be worse than being down.\n */\n KILLSWITCH: z.enum(['0', '1']).default('0'),\n /**\n * direct = agent pays the provider wallet, 0% platform fee (the launch build)\n * splitter = reserved for the fee-splitting contract; not implemented\n */\n FEE_MODE: z.enum(['direct', 'splitter']).default('direct'),\n});\n\nexport type PaywallEnv = z.infer<typeof paywallEnvSchema>;\n\nexport function readPaywallEnv(\n source: Record<string, string | undefined> = process.env,\n): PaywallEnv {\n return paywallEnvSchema.parse({\n FACILITATOR_URL: source.FACILITATOR_URL,\n FACILITATOR_API_KEY: source.FACILITATOR_API_KEY,\n KILLSWITCH: source.KILLSWITCH,\n FEE_MODE: source.FEE_MODE,\n });\n}\n","import { x402Client } from '@x402/core/client';\nimport { decodePaymentRequiredHeader } from '@x402/core/http';\nimport type { PaymentRequirements } from '@x402/core/types';\nimport { ExactEvmScheme } from '@x402/evm/exact/client';\nimport { wrapFetchWithPayment } from '@x402/fetch';\n\nimport { NETWORKS, PAYMENT_REF_HEADER, readSettlementHeader } from './constants.js';\nimport type { NetworkName } from './constants.js';\nimport { SpendGuardError, UnreadableQuoteError } from './errors.js';\nimport { quoteToUsd } from './money.js';\nimport { createMemorySpendStore } from './store.js';\nimport type { SpendStore } from './store.js';\n\n/** The signer the official EVM scheme expects: address + signTypedData, no key handling. */\nexport type EvmWallet = ConstructorParameters<typeof ExactEvmScheme>[0];\n\nexport interface SpendGuards {\n /** Hard USD ceiling for a single call. */\n maxPerCall?: number;\n /** Rolling 60-minute USD ceiling. */\n maxPerHour?: number;\n /** Rolling 24-hour USD ceiling. */\n maxPerDay?: number;\n /** Hostnames this agent may pay. Checked before any network call. */\n allowedHosts?: string[];\n}\n\nexport interface PayFetchOptions {\n wallet: EvmWallet;\n guards?: SpendGuards;\n /** Defaults to a process-local in-memory store. */\n store?: SpendStore;\n networks?: NetworkName[];\n fetch?: typeof globalThis.fetch;\n now?: () => number;\n}\n\nconst HOUR_MS = 60 * 60 * 1000;\nconst DAY_MS = 24 * HOUR_MS;\n\nfunction hostOf(input: RequestInfo | URL): string | null {\n try {\n const raw =\n typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.toString()\n : (input as Request).url;\n return new URL(raw).hostname.toLowerCase();\n } catch {\n return null;\n }\n}\n\n/** `example.com` in allowedHosts also authorises `tool.example.com`. */\nfunction hostAllowed(host: string, allowed: readonly string[]): boolean {\n return allowed.some((entry) => {\n const candidate = entry.trim().toLowerCase().replace(/^\\*\\./, '');\n return host === candidate || host.endsWith(`.${candidate}`);\n });\n}\n\n/**\n * Checks every guard against a quote. Returns the USD value if the call may proceed,\n * throws SpendGuardError otherwise. Called before a payment payload exists.\n */\nexport async function evaluateGuards(\n quoteUsd: number,\n guards: SpendGuards,\n store: SpendStore,\n now: number,\n): Promise<void> {\n if (guards.maxPerCall !== undefined && quoteUsd > guards.maxPerCall) {\n throw new SpendGuardError(\n 'maxPerCall',\n `Call costs $${quoteUsd} which exceeds the maxPerCall limit of $${guards.maxPerCall}`,\n { limitUsd: guards.maxPerCall, attemptedUsd: quoteUsd },\n );\n }\n\n if (guards.maxPerHour !== undefined) {\n const spent = await store.totalSince(now - HOUR_MS);\n if (spent + quoteUsd > guards.maxPerHour) {\n throw new SpendGuardError(\n 'maxPerHour',\n `Call costs $${quoteUsd} and $${spent} was already spent this hour, exceeding the maxPerHour limit of $${guards.maxPerHour}`,\n { limitUsd: guards.maxPerHour, attemptedUsd: spent + quoteUsd },\n );\n }\n }\n\n if (guards.maxPerDay !== undefined) {\n const spent = await store.totalSince(now - DAY_MS);\n if (spent + quoteUsd > guards.maxPerDay) {\n throw new SpendGuardError(\n 'maxPerDay',\n `Call costs $${quoteUsd} and $${spent} was already spent today, exceeding the maxPerDay limit of $${guards.maxPerDay}`,\n { limitUsd: guards.maxPerDay, attemptedUsd: spent + quoteUsd },\n );\n }\n }\n}\n\n/**\n * Reads the offered requirements from a 402.\n *\n * x402 v2 carries them in the base64 `payment-required` header, not the body — the body\n * is the resource's own, and may be anything. v1 put them in the body, so both are read.\n */\nexport async function readQuotedRequirements(response: Response): Promise<PaymentRequirements[]> {\n const header = response.headers.get('payment-required');\n if (header) {\n try {\n const decoded = decodePaymentRequiredHeader(header);\n if (Array.isArray(decoded.accepts) && decoded.accepts.length > 0) return decoded.accepts;\n } catch {\n // Fall through to the body form.\n }\n }\n\n const body: unknown = await response\n .clone()\n .json()\n .catch(() => null);\n const accepts = (body as { accepts?: PaymentRequirements[] } | null)?.accepts;\n return Array.isArray(accepts) ? accepts : [];\n}\n\n/** Reads the quoted amount out of x402 payment requirements. */\ninterface PriceableRequirement {\n maxAmountRequired?: string;\n amount?: string;\n asset?: string;\n extra?: { decimals?: number };\n}\n\nexport function quoteUsdOf(requirements: PaymentRequirements): number {\n const asRecord: PriceableRequirement = requirements;\n const amountAtomic = asRecord.maxAmountRequired ?? asRecord.amount;\n if (!amountAtomic || !asRecord.asset) {\n throw new RangeError('Payment requirements carry no priceable amount; refusing to pay.');\n }\n return quoteToUsd({\n amountAtomic,\n asset: asRecord.asset,\n decimals: asRecord.extra?.decimals,\n });\n}\n\n/**\n * A `fetch` that pays for 402 responses, under spend guards.\n *\n * The 402 handling, signing and retry are the official x402 packages' work. What this adds\n * is refusal: guards are evaluated inside the payment-policy hook, which runs after the\n * quote is known and before any payload is signed, so exceeding a guard throws\n * SpendGuardError with nothing signed and nothing spent.\n */\nexport async function payFetch(\n url: RequestInfo | URL,\n init: RequestInit | undefined,\n options: PayFetchOptions,\n): Promise<Response> {\n const guards = options.guards ?? {};\n const store = options.store ?? createMemorySpendStore();\n const now = options.now ?? Date.now;\n const baseFetch = options.fetch ?? globalThis.fetch;\n const networks = options.networks ?? (['base'] as NetworkName[]);\n\n // Host allowlist is checked first: an unauthorised host should cost no request at all.\n if (guards.allowedHosts) {\n const host = hostOf(url);\n if (!host || !hostAllowed(host, guards.allowedHosts)) {\n throw new SpendGuardError(\n 'allowedHosts',\n `Host ${host ?? '<unparseable>'} is not in allowedHosts`,\n { host: host ?? undefined },\n );\n }\n }\n\n let quotedUsd: number | null = null;\n\n const client = new x402Client((_version, requirements) => {\n // Runs before the payment payload is created. Throwing here means no signature.\n const affordable = requirements.filter((requirement) => {\n const usd = quoteUsdOf(requirement);\n return guards.maxPerCall === undefined || usd <= guards.maxPerCall;\n });\n\n const chosen = (affordable.length > 0 ? affordable : requirements)[0];\n if (!chosen) throw new RangeError('Resource offered no payment requirements');\n\n quotedUsd = quoteUsdOf(chosen);\n return chosen;\n });\n\n for (const name of networks) {\n client.register(NETWORKS[name].caip2, new ExactEvmScheme(options.wallet));\n }\n\n const guarded: typeof globalThis.fetch = async (input, requestInit) => {\n const response = await baseFetch(input, requestInit);\n if (response.status !== 402) return response;\n\n // Peek at the quote and apply guards before the wrapper signs anything.\n const accepts = await readQuotedRequirements(response);\n if (accepts.length === 0) {\n // A 402 whose requirements we cannot read is a 402 we cannot price, and an\n // unpriced call cannot be checked against a spend cap. Refuse rather than let it\n // through unguarded.\n throw new UnreadableQuoteError(\n 'Received a 402 with no readable payment requirements (no payment-required header, no accepts body). Refusing to pay blind.',\n );\n }\n\n const cheapest = accepts.map((requirement) => quoteUsdOf(requirement)).sort((a, b) => a - b)[0];\n if (cheapest !== undefined) {\n await evaluateGuards(cheapest, guards, store, now());\n }\n return response;\n };\n\n const paying = wrapFetchWithPayment(guarded, client);\n const response = await paying(url as RequestInfo, init);\n\n // Record the spend only once a payment actually settled.\n if (readSettlementHeader(response.headers) && quotedUsd !== null) {\n await store.record({ at: now(), usd: quotedUsd });\n }\n\n return response;\n}\n\nexport { PAYMENT_REF_HEADER };\n"],"mappings":"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","names":["import_server","import_zod","import_http","import_client","response","import_http"]}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,7 @@
1
- export { D as DEFAULT_FACILITATOR_URL, a as DOCS_URL, E as EvmWallet, N as NETWORKS, b as NO_REFUNDS_NOTICE, c as NetworkName, P as PAYMENT_REF_HEADER, d as PayFetchOptions, S as SpendGuards, e as SpendRecord, f as SpendStore, U as USDC_DECIMALS, g as createMemorySpendStore, h as evaluateGuards, p as payFetch, q as quoteUsdOf } from './client-C8_arVa4.cjs';
1
+ export { D as DEFAULT_FACILITATOR_URL, a as DOCS_URL, E as EvmWallet, N as NETWORKS, b as NO_REFUNDS_NOTICE, c as NetworkName, P as PAYMENT_REF_HEADER, d as PAYMENT_SIGNATURE_HEADERS, e as PayFetchOptions, S as SETTLEMENT_HEADERS, f as SpendGuards, g as SpendRecord, h as SpendStore, U as USDC_DECIMALS, i as createMemorySpendStore, j as evaluateGuards, p as payFetch, q as quoteUsdOf, r as readSettlementHeader } from './client-BBsrY6gC.cjs';
2
2
  export { ExpressMiddleware, ExpressResponseLike, HonoContextLike, HonoMiddleware, Paywall, PaywallOptions, UnpaidBody, paywall } from './provider.cjs';
3
3
  import { z } from 'zod';
4
+ export { decodePaymentResponseHeader } from '@x402/core/http';
4
5
  export { FacilitatorClient, RouteConfig } from '@x402/core/server';
5
6
  import '@x402/core/types';
6
7
  import '@x402/evm/exact/client';
@@ -38,6 +39,15 @@ declare class MissingAdapterError extends Error {
38
39
  readonly name = "MissingAdapterError";
39
40
  constructor(pkg: string);
40
41
  }
42
+ /**
43
+ * A 402 arrived whose payment requirements could not be read, so the call cannot be
44
+ * priced and therefore cannot be checked against a spend cap. Refusing is the safe
45
+ * outcome: paying blind is irreversible.
46
+ */
47
+ declare class UnreadableQuoteError extends Error {
48
+ readonly name = "UnreadableQuoteError";
49
+ constructor(message: string);
50
+ }
41
51
 
42
52
  type FeeMode = 'direct' | 'splitter';
43
53
  interface PayeeResolution {
@@ -104,4 +114,4 @@ declare const paywallEnvSchema: z.ZodObject<{
104
114
  type PaywallEnv = z.infer<typeof paywallEnvSchema>;
105
115
  declare function readPaywallEnv(source?: Record<string, string | undefined>): PaywallEnv;
106
116
 
107
- export { type FeeMode, type GuardName, MissingAdapterError, NotImplementedError, type PayeeResolution, type PaywallEnv, SpendGuardError, formatUsdc, parseUsdc, paywallEnvSchema, quoteToUsd, readPaywallEnv, resolvePayee };
117
+ export { type FeeMode, type GuardName, MissingAdapterError, NotImplementedError, type PayeeResolution, type PaywallEnv, SpendGuardError, UnreadableQuoteError, formatUsdc, parseUsdc, paywallEnvSchema, quoteToUsd, readPaywallEnv, resolvePayee };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- export { D as DEFAULT_FACILITATOR_URL, a as DOCS_URL, E as EvmWallet, N as NETWORKS, b as NO_REFUNDS_NOTICE, c as NetworkName, P as PAYMENT_REF_HEADER, d as PayFetchOptions, S as SpendGuards, e as SpendRecord, f as SpendStore, U as USDC_DECIMALS, g as createMemorySpendStore, h as evaluateGuards, p as payFetch, q as quoteUsdOf } from './client-C8_arVa4.js';
1
+ export { D as DEFAULT_FACILITATOR_URL, a as DOCS_URL, E as EvmWallet, N as NETWORKS, b as NO_REFUNDS_NOTICE, c as NetworkName, P as PAYMENT_REF_HEADER, d as PAYMENT_SIGNATURE_HEADERS, e as PayFetchOptions, S as SETTLEMENT_HEADERS, f as SpendGuards, g as SpendRecord, h as SpendStore, U as USDC_DECIMALS, i as createMemorySpendStore, j as evaluateGuards, p as payFetch, q as quoteUsdOf, r as readSettlementHeader } from './client-BBsrY6gC.js';
2
2
  export { ExpressMiddleware, ExpressResponseLike, HonoContextLike, HonoMiddleware, Paywall, PaywallOptions, UnpaidBody, paywall } from './provider.js';
3
3
  import { z } from 'zod';
4
+ export { decodePaymentResponseHeader } from '@x402/core/http';
4
5
  export { FacilitatorClient, RouteConfig } from '@x402/core/server';
5
6
  import '@x402/core/types';
6
7
  import '@x402/evm/exact/client';
@@ -38,6 +39,15 @@ declare class MissingAdapterError extends Error {
38
39
  readonly name = "MissingAdapterError";
39
40
  constructor(pkg: string);
40
41
  }
42
+ /**
43
+ * A 402 arrived whose payment requirements could not be read, so the call cannot be
44
+ * priced and therefore cannot be checked against a spend cap. Refusing is the safe
45
+ * outcome: paying blind is irreversible.
46
+ */
47
+ declare class UnreadableQuoteError extends Error {
48
+ readonly name = "UnreadableQuoteError";
49
+ constructor(message: string);
50
+ }
41
51
 
42
52
  type FeeMode = 'direct' | 'splitter';
43
53
  interface PayeeResolution {
@@ -104,4 +114,4 @@ declare const paywallEnvSchema: z.ZodObject<{
104
114
  type PaywallEnv = z.infer<typeof paywallEnvSchema>;
105
115
  declare function readPaywallEnv(source?: Record<string, string | undefined>): PaywallEnv;
106
116
 
107
- export { type FeeMode, type GuardName, MissingAdapterError, NotImplementedError, type PayeeResolution, type PaywallEnv, SpendGuardError, formatUsdc, parseUsdc, paywallEnvSchema, quoteToUsd, readPaywallEnv, resolvePayee };
117
+ export { type FeeMode, type GuardName, MissingAdapterError, NotImplementedError, type PayeeResolution, type PaywallEnv, SpendGuardError, UnreadableQuoteError, formatUsdc, parseUsdc, paywallEnvSchema, quoteToUsd, readPaywallEnv, resolvePayee };
package/dist/index.js CHANGED
@@ -3,13 +3,13 @@ import {
3
3
  evaluateGuards,
4
4
  payFetch,
5
5
  quoteUsdOf
6
- } from "./chunk-HCN75CTX.js";
6
+ } from "./chunk-ZGVPNFNS.js";
7
7
  import {
8
8
  paywall,
9
9
  paywallEnvSchema,
10
10
  readPaywallEnv,
11
11
  resolvePayee
12
- } from "./chunk-7DVR574O.js";
12
+ } from "./chunk-PY25VKHS.js";
13
13
  import {
14
14
  DEFAULT_FACILITATOR_URL,
15
15
  DOCS_URL,
@@ -18,12 +18,19 @@ import {
18
18
  NO_REFUNDS_NOTICE,
19
19
  NotImplementedError,
20
20
  PAYMENT_REF_HEADER,
21
+ PAYMENT_SIGNATURE_HEADERS,
22
+ SETTLEMENT_HEADERS,
21
23
  SpendGuardError,
22
24
  USDC_DECIMALS,
25
+ UnreadableQuoteError,
23
26
  formatUsdc,
24
27
  parseUsdc,
25
- quoteToUsd
26
- } from "./chunk-6LSPHKJ7.js";
28
+ quoteToUsd,
29
+ readSettlementHeader
30
+ } from "./chunk-C4BASAUA.js";
31
+
32
+ // src/index.ts
33
+ import { decodePaymentResponseHeader } from "@x402/core/http";
27
34
  export {
28
35
  DEFAULT_FACILITATOR_URL,
29
36
  DOCS_URL,
@@ -32,9 +39,13 @@ export {
32
39
  NO_REFUNDS_NOTICE,
33
40
  NotImplementedError,
34
41
  PAYMENT_REF_HEADER,
42
+ PAYMENT_SIGNATURE_HEADERS,
43
+ SETTLEMENT_HEADERS,
35
44
  SpendGuardError,
36
45
  USDC_DECIMALS,
46
+ UnreadableQuoteError,
37
47
  createMemorySpendStore,
48
+ decodePaymentResponseHeader,
38
49
  evaluateGuards,
39
50
  formatUsdc,
40
51
  parseUsdc,
@@ -44,6 +55,7 @@ export {
44
55
  quoteToUsd,
45
56
  quoteUsdOf,
46
57
  readPaywallEnv,
58
+ readSettlementHeader,
47
59
  resolvePayee
48
60
  };
49
61
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './constants.js';\nexport * from './errors.js';\nexport * from './fee-mode.js';\nexport * from './money.js';\nexport * from './store.js';\nexport { paywall } from './provider.js';\nexport type {\n Paywall,\n PaywallOptions,\n UnpaidBody,\n HonoMiddleware,\n HonoContextLike,\n ExpressMiddleware,\n ExpressResponseLike,\n FacilitatorClient,\n RouteConfig,\n} from './provider.js';\nexport { payFetch, evaluateGuards, quoteUsdOf } from './client.js';\nexport type { EvmWallet, PayFetchOptions, SpendGuards } from './client.js';\nexport { readPaywallEnv, paywallEnvSchema } from './env.js';\nexport type { PaywallEnv } from './env.js';\nexport { decodePaymentResponseHeader } from '@x402/core/http';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqBA,SAAS,mCAAmC;","names":[]}
package/dist/provider.cjs CHANGED
@@ -30,7 +30,11 @@ var import_zod2 = require("zod");
30
30
 
31
31
  // src/constants.ts
32
32
  var NETWORKS = {
33
- base: { caip2: "eip155:8453", chainId: 8453, usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" },
33
+ base: {
34
+ caip2: "eip155:8453",
35
+ chainId: 8453,
36
+ usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
37
+ },
34
38
  "base-sepolia": {
35
39
  caip2: "eip155:84532",
36
40
  chainId: 84532,
@@ -41,6 +45,14 @@ var USDC_DECIMALS = 6;
41
45
  var NO_REFUNDS_NOTICE = "Payments are final. Once settled on-chain the transfer cannot be reversed, and there are no refunds.";
42
46
  var DOCS_URL = "https://fatstack.net/docs/payments";
43
47
  var PAYMENT_REF_HEADER = "X-Fatstack-Payment-Ref";
48
+ var SETTLEMENT_HEADERS = ["payment-response", "x-payment-response"];
49
+ function readSettlementHeader(headers) {
50
+ for (const name of SETTLEMENT_HEADERS) {
51
+ const value = headers.get(name);
52
+ if (value) return value;
53
+ }
54
+ return null;
55
+ }
44
56
  var DEFAULT_FACILITATOR_URL = "https://x402.org/facilitator";
45
57
 
46
58
  // src/env.ts
@@ -162,7 +174,11 @@ function paywall(options) {
162
174
  payTo,
163
175
  // An explicit asset+amount pins USDC and the exact atomic amount, rather than
164
176
  // leaving the quote to a price feed.
165
- price: { asset: network.usdc, amount: amountAtomic },
177
+ // A dollar price, not an explicit { asset, amount }: the EVM scheme resolves the
178
+ // network's default asset (USDC) and publishes its EIP-712 domain in `extra`, which
179
+ // the payer needs to sign the EIP-3009 authorisation. Naming the asset directly
180
+ // skips that lookup and emits `extra: {}`, which nobody can pay against.
181
+ price: `$${priceUsdc}`,
166
182
  maxTimeoutSeconds: config.maxTimeoutSeconds
167
183
  },
168
184
  description: config.description ?? `Fatstack tool ${config.toolId}`,
@@ -205,7 +221,7 @@ function paywall(options) {
205
221
  const middleware = cached;
206
222
  const result = await middleware(c, next);
207
223
  const carrier = result instanceof Response ? result : c.res;
208
- const ref = paymentRef(carrier?.headers?.get("x-payment-response"));
224
+ const ref = paymentRef(carrier ? readSettlementHeader(carrier.headers) : null);
209
225
  if (ref) carrier.headers.set(PAYMENT_REF_HEADER, ref);
210
226
  return result;
211
227
  };
@@ -225,7 +241,7 @@ function paywall(options) {
225
241
  const originalSetHeader = response.setHeader.bind(response);
226
242
  response.setHeader = (name, value) => {
227
243
  const out = originalSetHeader(name, value);
228
- if (String(name).toLowerCase() === "x-payment-response") {
244
+ if (SETTLEMENT_HEADERS.includes(String(name).toLowerCase())) {
229
245
  const ref = paymentRef(String(value));
230
246
  if (ref) originalSetHeader(PAYMENT_REF_HEADER, ref);
231
247
  }
@@ -248,7 +264,7 @@ function paywall(options) {
248
264
  const wrapped = cached;
249
265
  const result = await wrapped(request);
250
266
  if (result instanceof Response) {
251
- const ref = paymentRef(result.headers.get("x-payment-response"));
267
+ const ref = paymentRef(readSettlementHeader(result.headers));
252
268
  if (ref) result.headers.set(PAYMENT_REF_HEADER, ref);
253
269
  }
254
270
  return result;