@tabai/sdk 0.2.3 → 0.2.4

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 (155) hide show
  1. package/README.md +8 -7
  2. package/dist/_shared/abi.d.ts.map +1 -1
  3. package/dist/_shared/abi.js +6 -3
  4. package/dist/_shared/abi.js.map +1 -1
  5. package/dist/_shared/chains.d.ts +4 -6
  6. package/dist/_shared/chains.d.ts.map +1 -1
  7. package/dist/_shared/chains.js +1 -2
  8. package/dist/_shared/chains.js.map +1 -1
  9. package/dist/_shared/keccak256.d.ts +6 -6
  10. package/dist/_shared/keccak256.js +6 -6
  11. package/dist/_shared/keccak256.js.map +1 -1
  12. package/dist/_shared/result.d.ts +5 -6
  13. package/dist/_shared/result.d.ts.map +1 -1
  14. package/dist/_shared/result.js +5 -6
  15. package/dist/_shared/result.js.map +1 -1
  16. package/dist/cli/client-config.d.ts +4 -5
  17. package/dist/cli/client-config.d.ts.map +1 -1
  18. package/dist/cli/client-config.js +4 -5
  19. package/dist/cli/client-config.js.map +1 -1
  20. package/dist/cli/connect.d.ts +1 -3
  21. package/dist/cli/connect.d.ts.map +1 -1
  22. package/dist/cli/connect.js +1 -3
  23. package/dist/cli/connect.js.map +1 -1
  24. package/dist/cli/doctor.d.ts +1 -3
  25. package/dist/cli/doctor.d.ts.map +1 -1
  26. package/dist/cli/doctor.js +1 -3
  27. package/dist/cli/doctor.js.map +1 -1
  28. package/dist/cli/index.d.ts +1 -1
  29. package/dist/cli/index.js +1 -1
  30. package/dist/cli/index.js.map +1 -1
  31. package/dist/cli/main.d.ts +1 -3
  32. package/dist/cli/main.d.ts.map +1 -1
  33. package/dist/cli/main.js +2 -4
  34. package/dist/cli/main.js.map +1 -1
  35. package/dist/errors.d.ts +2 -4
  36. package/dist/errors.d.ts.map +1 -1
  37. package/dist/errors.js +2 -4
  38. package/dist/errors.js.map +1 -1
  39. package/dist/http/client-402.d.ts +11 -13
  40. package/dist/http/client-402.d.ts.map +1 -1
  41. package/dist/http/client-402.js +12 -14
  42. package/dist/http/client-402.js.map +1 -1
  43. package/dist/http/headers.d.ts +9 -11
  44. package/dist/http/headers.d.ts.map +1 -1
  45. package/dist/http/headers.js +9 -11
  46. package/dist/http/headers.js.map +1 -1
  47. package/dist/http/index.d.ts +0 -2
  48. package/dist/http/index.d.ts.map +1 -1
  49. package/dist/http/index.js +0 -2
  50. package/dist/http/index.js.map +1 -1
  51. package/dist/http/metering-claim.d.ts +0 -2
  52. package/dist/http/metering-claim.d.ts.map +1 -1
  53. package/dist/http/metering-claim.js +0 -2
  54. package/dist/http/metering-claim.js.map +1 -1
  55. package/dist/index.d.ts +15 -12
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +15 -12
  58. package/dist/index.js.map +1 -1
  59. package/dist/logger.d.ts +1 -4
  60. package/dist/logger.d.ts.map +1 -1
  61. package/dist/logger.js +1 -4
  62. package/dist/logger.js.map +1 -1
  63. package/dist/mcp/index.d.ts +1 -1
  64. package/dist/mcp/index.js +1 -1
  65. package/dist/mcp/index.js.map +1 -1
  66. package/dist/mcp/json-schema.d.ts +1 -3
  67. package/dist/mcp/json-schema.d.ts.map +1 -1
  68. package/dist/mcp/json-schema.js +1 -3
  69. package/dist/mcp/json-schema.js.map +1 -1
  70. package/dist/mcp/json.d.ts +0 -2
  71. package/dist/mcp/json.d.ts.map +1 -1
  72. package/dist/mcp/json.js +0 -2
  73. package/dist/mcp/json.js.map +1 -1
  74. package/dist/mcp/registry-client.d.ts +0 -2
  75. package/dist/mcp/registry-client.d.ts.map +1 -1
  76. package/dist/mcp/registry-client.js +3 -4
  77. package/dist/mcp/registry-client.js.map +1 -1
  78. package/dist/mcp/schemas.d.ts +10 -8
  79. package/dist/mcp/schemas.d.ts.map +1 -1
  80. package/dist/mcp/schemas.js +5 -7
  81. package/dist/mcp/schemas.js.map +1 -1
  82. package/dist/mcp/server.d.ts +0 -2
  83. package/dist/mcp/server.d.ts.map +1 -1
  84. package/dist/mcp/server.js +4 -7
  85. package/dist/mcp/server.js.map +1 -1
  86. package/dist/mcp/settings.d.ts +0 -2
  87. package/dist/mcp/settings.d.ts.map +1 -1
  88. package/dist/mcp/settings.js +0 -2
  89. package/dist/mcp/settings.js.map +1 -1
  90. package/dist/mcp/toolset.d.ts +2 -5
  91. package/dist/mcp/toolset.d.ts.map +1 -1
  92. package/dist/mcp/toolset.js +3 -6
  93. package/dist/mcp/toolset.js.map +1 -1
  94. package/dist/payments/config.d.ts +6 -8
  95. package/dist/payments/config.d.ts.map +1 -1
  96. package/dist/payments/config.js +5 -7
  97. package/dist/payments/config.js.map +1 -1
  98. package/dist/payments/index.d.ts +0 -2
  99. package/dist/payments/index.d.ts.map +1 -1
  100. package/dist/payments/index.js +0 -2
  101. package/dist/payments/index.js.map +1 -1
  102. package/dist/payments/registry.d.ts +11 -12
  103. package/dist/payments/registry.d.ts.map +1 -1
  104. package/dist/payments/registry.js +11 -12
  105. package/dist/payments/registry.js.map +1 -1
  106. package/dist/payments/strategy.d.ts +9 -5
  107. package/dist/payments/strategy.d.ts.map +1 -1
  108. package/dist/payments/strategy.js +9 -5
  109. package/dist/payments/strategy.js.map +1 -1
  110. package/dist/proxy/hooks.d.ts +3 -5
  111. package/dist/proxy/hooks.d.ts.map +1 -1
  112. package/dist/proxy/hooks.js +2 -4
  113. package/dist/proxy/hooks.js.map +1 -1
  114. package/dist/proxy/index.d.ts +2 -2
  115. package/dist/proxy/index.js +2 -2
  116. package/dist/proxy/index.js.map +1 -1
  117. package/dist/proxy/proxy.d.ts +3 -5
  118. package/dist/proxy/proxy.d.ts.map +1 -1
  119. package/dist/proxy/proxy.js +2 -4
  120. package/dist/proxy/proxy.js.map +1 -1
  121. package/dist/server/adapters/express.d.ts +0 -2
  122. package/dist/server/adapters/express.d.ts.map +1 -1
  123. package/dist/server/adapters/express.js +0 -2
  124. package/dist/server/adapters/express.js.map +1 -1
  125. package/dist/server/adapters/hono.d.ts +0 -2
  126. package/dist/server/adapters/hono.d.ts.map +1 -1
  127. package/dist/server/adapters/hono.js +0 -2
  128. package/dist/server/adapters/hono.js.map +1 -1
  129. package/dist/server/adapters/next.d.ts +0 -2
  130. package/dist/server/adapters/next.d.ts.map +1 -1
  131. package/dist/server/adapters/next.js +0 -2
  132. package/dist/server/adapters/next.js.map +1 -1
  133. package/dist/server/index.d.ts +5 -5
  134. package/dist/server/index.js +5 -5
  135. package/dist/server/index.js.map +1 -1
  136. package/dist/server/metering.d.ts +9 -11
  137. package/dist/server/metering.d.ts.map +1 -1
  138. package/dist/server/metering.js +6 -8
  139. package/dist/server/metering.js.map +1 -1
  140. package/dist/server/post-paid.d.ts +8 -10
  141. package/dist/server/post-paid.d.ts.map +1 -1
  142. package/dist/server/post-paid.js +7 -9
  143. package/dist/server/post-paid.js.map +1 -1
  144. package/dist/x402/client.d.ts +5 -6
  145. package/dist/x402/client.d.ts.map +1 -1
  146. package/dist/x402/client.js +6 -7
  147. package/dist/x402/client.js.map +1 -1
  148. package/dist/x402/server.d.ts +5 -5
  149. package/dist/x402/server.d.ts.map +1 -1
  150. package/dist/x402/server.js +2 -2
  151. package/dist/x402/server.js.map +1 -1
  152. package/dist/x402/wire.d.ts +1 -1
  153. package/dist/x402/wire.js +1 -1
  154. package/dist/x402/wire.js.map +1 -1
  155. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"client-402.js","sourceRoot":"","sources":["../../src/http/client-402.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The HTTP 402 client wrapper (R23.2).\n *\n * ## Tab is post-paid, so a 402 is not a demand for prepayment\n *\n * This is the one thing to understand about this file. A `402` from a Tab Service\n * does not mean \"pay now and I will then serve you\". Work is delivered first and\n * metered after (R23.3); the charge lands on the Open Tab as an accrual, and the\n * Agent settles later, asynchronously, on Ethereum, with its own keys, through\n * the payment-strategy seam. So:\n *\n * - the **normal** metered response is a `200` carrying the charge block, and\n * this client records the accrual and hands the response straight back;\n * - a `402` is issued on `LimitExceeded` alone, the Agent has no headroom left\n * for that Asset. It is a credit decision, not an invoice;\n * - on a `402` the client records what the Service says the call requires, sends\n * the original request **once** more carrying `Tab-Agent` and\n * `Tab-Authorisation`, and stops. Not a retry loop, and not a backoff.\n *\n * **Nothing in this file settles.** There is no signer here, no strategy call, no\n * transaction, and no allowance. A settlement step inside the 402 handler would\n * be the prepay model Tab exists to replace. Settling is the Agent's decision,\n * taken through `tab_settle`, not something a transport does on its own.\n *\n * ## Why a repeat at all, if the charge already landed\n *\n * Two cases, and the repeat serves both. On the ordinary path the first attempt\n * may have reached a Service that could not identify the Agent, a caller that\n * built its own headers or a proxy that dropped them, and the repeat carries the\n * identity headers explicitly. On the `LimitExceeded` path a Settlement may have\n * landed between the two attempts: `TabSettlement` restores headroom in the\n * same block it moves the Asset (R15.1), so the second attempt is genuinely a\n * different question rather than the same one asked louder. Exactly one repeat,\n * because a second `402` means the\n * headroom is not coming back within the life of this request, and looping would\n * only meter the Service's rejection path.\n *\n * ## x402, the one exception, and why it is not settlement\n *\n * A `402` from a Tab Service that also carries `PAYMENT-REQUIRED` is a credit\n * refusal with an offer attached: pay for this one call, prepaid, through x402.\n * When the caller configured an x402 signer, and only then, a `402` that still\n * stands after the repeat is answered by signing that offer and sending the\n * request once more with `PAYMENT-SIGNATURE`. That is a prepayment for one\n * call and touches no tab. It is not a Settlement, it restores no headroom,\n * and it is off unless a signer was given, because an Agent that would rather\n * settle than prepay should get the `LIMIT_EXCEEDED` it can act on.\n *\n * ## Zero-throw, everywhere\n *\n * Every fallible call returns a `Result` (R21.5, design section 13.1). A transport\n * failure, a response object that is not one, a malformed header, a partial charge\n * block, an unreplayable request body, a `402` that stands after the repeat: all\n * of them are `err` values carrying an error category. Nothing here throws,\n * including the consumer's own `onCharge` callback, which is called inside a guard\n * so a consumer's bug cannot fail a request that succeeded.\n *\n * Requirements: 23.2, 21.5\n */\n\nimport { causeOf, isAddress, isBytes32, ok, wrap, type Address, type Bytes32, type Result } from \"../_shared/index.js\";\nimport { defaultLogger, type Logger } from \"../logger.js\";\nimport { fail, upstreamError, validationError } from \"../errors.js\";\nimport {\n agentRequestHeaders,\n chargedAssetKey,\n headerReaderOf,\n parseChargeHeaders,\n type ChargeBlock,\n type ChargedAsset,\n type HeaderReader,\n type HeaderRecord,\n} from \"./headers.js\";\nimport { createX402Client, resolveX402Signer, type X402PaymentReceipt, type X402SignerSource } from \"../x402/client.js\";\nimport { readPaymentRequired } from \"../x402/wire.js\";\n\n/**\n * What the caller may put on a request.\n *\n * A near-mirror of the standard `RequestInit` rather than an import of it, because\n * `@tabai/sdk` compiles against the ES2023 library alone and must not acquire a DOM\n * or `undici` type dependency to describe a request. The index signature carries\n * every option this client does not read, `signal`, `redirect`, `cache`,\n * `keepalive`, a dispatcher, through to the host `fetch` untouched.\n */\nexport interface Tab402RequestInit {\n readonly method?: string;\n /** A plain object, a `Headers`, or an array of pairs. Merged with the Tab headers. */\n readonly headers?: HeaderReader | HeaderRecord | readonly (readonly [string, string])[];\n readonly body?: unknown;\n readonly [option: string]: unknown;\n}\n\n/** The request this client hands to its `fetch`: the caller's options, with headers resolved. */\nexport interface Tab402FetchInit {\n readonly headers: Readonly<Record<string, string>>;\n readonly [option: string]: unknown;\n}\n\n/**\n * The little of a response this client reads.\n *\n * Structural for the same reason as {@link Tab402RequestInit}, and loose on\n * purpose: `body` and `bodyUsed` are `unknown` and duck-checked at runtime, so a\n * real `Response` from any host satisfies this without the two type worlds having\n * to agree. Widen it through the type parameter of {@link createTab402Client} when\n * the caller supplies a typed `fetch`, and `client.fetch` then returns\n * `Result<Response>` with every method of the real thing intact.\n */\nexport interface Tab402Response {\n readonly status: number;\n readonly headers: HeaderReader | HeaderRecord;\n readonly body?: unknown;\n readonly bodyUsed?: unknown;\n}\n\n/** The `fetch` this client calls. The host's global `fetch` is the default. */\nexport type Tab402Fetch<Res extends Tab402Response> = (\n url: string,\n init: Tab402FetchInit,\n) => Promise<Res>;\n\n/** Whether the charge the Service reported landed on the Open Tab. */\nexport type ChargeOutcome =\n /** The call was served and metered. The Open Tab now carries this amount. */\n | \"accrued\"\n /**\n * `LimitExceeded`: the amount is what the call *requires* and it did not land,\n * because the Agent's headroom for the Asset does not cover it.\n */\n | \"declined\";\n\n/** One charge block, read off one response, in the client's own terms. */\nexport interface ChargeAccrued {\n /** The Agent this call was metered against. */\n readonly agent: Address;\n /** The absolute URL that was called. */\n readonly url: string;\n /** The HTTP status the charge block arrived on. */\n readonly status: number;\n readonly outcome: ChargeOutcome;\n /** Integer Asset base units: charged on `accrued`, required on `declined`. */\n readonly amount: bigint;\n readonly asset: ChargedAsset;\n readonly serviceId: Bytes32;\n readonly tool: Bytes32;\n /** The Open Tab the Service reported after this call. */\n readonly openTab: bigint;\n /** The headroom the Service reported for this Agent and Asset. */\n readonly headroom: bigint;\n readonly authorisation?: Bytes32;\n /**\n * The strategy the Agent intends to settle this Asset through, if the client was\n * given one. Carried for the later, separate settlement path and used by nothing\n * here.\n */\n readonly strategyId?: string;\n /** `1` for the original request, `2` for the repeat. */\n readonly attempt: 1 | 2;\n /** Milliseconds since the epoch, when the header was read. */\n readonly observedAt: number;\n}\n\n/** What this client believes about one Asset's tab, from headers alone. */\nexport interface TabSnapshot {\n readonly asset: ChargedAsset;\n /** The Open Tab most recently reported for this Asset. */\n readonly openTab: bigint;\n /** The headroom most recently reported for this Asset. */\n readonly headroom: bigint;\n /** Sum of every charge that landed, across the client's lifetime. */\n readonly accrued: bigint;\n /** Sum of every charge refused for want of headroom. Never part of {@link accrued}. */\n readonly declined: bigint;\n readonly accruedCount: number;\n readonly declinedCount: number;\n readonly observedAt: number;\n}\n\nexport interface Tab402ClientOptions<Res extends Tab402Response = Tab402Response> {\n /** Absolute base URL. A relative path handed to `fetch` resolves against it. */\n readonly baseUrl: string;\n /** The Agent's Monad address, sent as `Tab-Agent`. */\n readonly agent: Address;\n /** The authKey to meter against, sent as `Tab-Authorisation` when supplied. */\n readonly authorisation?: Bytes32;\n /** Called for every charge block read, on the 200 path and the 402 path alike. */\n readonly onCharge?: (charge: ChargeAccrued) => void;\n /**\n * `1` repeats the original request once after a `402`; `0` repeats nothing.\n *\n * Typed as the two values it can hold rather than as a `number`, because \"repeat\n * once\" is the semantics rather than a default: a caller who wrote `5` would be\n * asking for a retry loop against a credit decision, and a number that silently\n * clamped to `1` would leave them believing they had one.\n */\n readonly maxRetries?: 0 | 1;\n /** Recorded on each accrual for the later settlement path. Never used to settle here. */\n readonly strategyId?: string;\n /**\n * The prepaid fallback. With a signer here, a `402` that still stands after\n * the repeat and carries `PAYMENT-REQUIRED` is paid through x402 and the\n * request sent once more. Without one, that `402` is the `LIMIT_EXCEEDED`\n * it always was. See the module note.\n */\n readonly x402?: Tab402X402Options;\n /** Defaults to the host's global `fetch`. */\n readonly fetchImpl?: Tab402Fetch<Res>;\n readonly logger?: Logger;\n /** Injectable clock, so `observedAt` is testable. Defaults to `Date.now`. */\n readonly now?: () => number;\n /**\n * How many accruals {@link Tab402Client.charges} keeps. Defaults to 128.\n *\n * Trimming the list never touches the totals in {@link TabSnapshot}, which are\n * running sums, so a long-lived client keeps exact accounting on bounded memory.\n */\n readonly maxChargeHistory?: number;\n}\n\n/** How the client pays when it pays. */\nexport interface Tab402X402Options {\n /**\n * The signer, or a factory called only when an offer is about to be taken. A\n * factory returning `undefined` declines, and the `402` stands as the credit\n * decision it was.\n */\n readonly signer: X402SignerSource;\n /** Sign only on this chain. Defaults to any `eip155:*` the Service offers. */\n readonly chainId?: bigint;\n /** Sign only for this token. Defaults to any the Service offers. */\n readonly asset?: Address;\n /** Refuse an offer above this many atomic units. Omitted sets no ceiling. */\n readonly maxAmount?: bigint;\n readonly onPayment?: (receipt: X402PaymentReceipt) => void;\n}\n\nexport interface Tab402Client<Res extends Tab402Response = Tab402Response> {\n /**\n * Sends a request, records whatever charge the response reports, and repeats\n * once on a `402`.\n *\n * `input` may be absolute or relative to `baseUrl`. Returns the response the\n * Service produced, this client never rewrites a status, so a `500` from the\n * Service comes back as `ok(response)` for the caller to read. The `err` cases\n * are this client's own: a bad URL, a malformed charge block, a transport\n * failure, or a `402` that still stands after the repeat.\n */\n fetch(input: string, init?: Tab402RequestInit): Promise<Result<Res>>;\n /** Every charge block read, oldest first, up to `maxChargeHistory`. */\n charges(): readonly ChargeAccrued[];\n /** One snapshot per Asset seen, in first-seen order. */\n tabs(): readonly TabSnapshot[];\n tabOf(asset: ChargedAsset): TabSnapshot | undefined;\n /** Every x402 payment made, oldest first. Empty unless `x402` was configured. */\n payments(): readonly X402PaymentReceipt[];\n}\n\ninterface LedgerEntry {\n asset: ChargedAsset;\n openTab: bigint;\n headroom: bigint;\n accrued: bigint;\n declined: bigint;\n accruedCount: number;\n declinedCount: number;\n observedAt: number;\n}\n\n/**\n * Builds the client.\n *\n * Construction is total: it cannot fail and returns a client, not a `Result`.\n * Every fallible thing, an unusable `baseUrl`, an `agent` that is not an\n * address, a host with no `fetch`, is reported by the call that needs it, which\n * is the only place a caller can act on it. This matches\n * `createEthereumUsdcStrategy` and keeps the SDK's two factories the same shape.\n */\nexport function createTab402Client<Res extends Tab402Response = Tab402Response>(\n options: Tab402ClientOptions<Res>,\n): Tab402Client<Res> {\n const logger = options.logger ?? defaultLogger;\n const now = options.now ?? (() => Date.now());\n const maxRetries = options.maxRetries ?? 1;\n const historyLimit = options.maxChargeHistory ?? 128;\n\n const history: ChargeAccrued[] = [];\n const ledger = new Map<string, LedgerEntry>();\n const payments: X402PaymentReceipt[] = [];\n\n const record = (\n block: ChargeBlock,\n outcome: ChargeOutcome,\n url: string,\n status: number,\n attempt: 1 | 2,\n ): ChargeAccrued => {\n const observedAt = now();\n const charge: ChargeAccrued = {\n agent: options.agent,\n url,\n status,\n outcome,\n amount: block.amount,\n asset: block.asset,\n serviceId: block.serviceId,\n tool: block.tool,\n openTab: block.openTab,\n headroom: block.headroom,\n ...(options.authorisation === undefined ? {} : { authorisation: options.authorisation }),\n ...(options.strategyId === undefined ? {} : { strategyId: options.strategyId }),\n attempt,\n observedAt,\n };\n\n const key = chargedAssetKey(block.asset);\n const entry = ledger.get(key) ?? {\n asset: block.asset,\n openTab: 0n,\n headroom: 0n,\n accrued: 0n,\n declined: 0n,\n accruedCount: 0,\n declinedCount: 0,\n observedAt,\n };\n // The Open Tab and the headroom are the Service's figures, not sums of ours:\n // a Settlement moves both without this client seeing a request, so the\n // latest report replaces rather than adds.\n entry.openTab = block.openTab;\n entry.headroom = block.headroom;\n entry.observedAt = observedAt;\n if (outcome === \"accrued\") {\n entry.accrued += block.amount;\n entry.accruedCount += 1;\n } else {\n entry.declined += block.amount;\n entry.declinedCount += 1;\n }\n ledger.set(key, entry);\n\n history.push(charge);\n if (history.length > historyLimit && historyLimit >= 0) {\n history.splice(0, history.length - historyLimit);\n }\n\n if (options.onCharge !== undefined) {\n // A consumer callback is code this package did not write, and a throw from\n // it must not fail a call that otherwise succeeded.\n try {\n options.onCharge(charge);\n } catch (error) {\n logger.warn(\"onCharge threw and the charge was recorded anyway\", {\n url,\n outcome,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n return charge;\n };\n\n const attempt = async (\n url: string,\n init: Tab402FetchInit,\n send: Tab402Fetch<Res>,\n ordinal: 1 | 2,\n ): Promise<Result<{ readonly response: Res; readonly charge?: ChargeAccrued }>> => {\n const sent = await wrap(\n async () => send(url, init),\n (error) => ({\n category: \"UPSTREAM\",\n code: \"FETCH_FAILED\",\n message: `the request to ${url} did not complete`,\n retryable: true,\n details: { url, attempt: ordinal },\n cause: causeOf(error),\n }),\n );\n if (!sent.ok) return sent;\n\n const response = sent.value;\n if (!looksLikeResponse(response)) {\n return upstreamError(\n \"FETCH_RESPONSE_INVALID\",\n `the fetch given to this client returned something that is not a response for ${url}`,\n { details: { url, attempt: ordinal } },\n );\n }\n\n const block = parseChargeHeaders(headerReaderOf(response.headers));\n if (!block.ok) {\n discard(response, logger);\n return block;\n }\n\n if (block.value === undefined) {\n if (response.status === 402) {\n // A 402 with no charge block is not a Tab credit decision. With an x402\n // signer it may still be an offer this client can take, so it is handed\n // back for the payment path to read; without one it is malformed.\n if (options.x402 !== undefined && hasPaymentRequired(response.headers)) return ok({ response });\n discard(response, logger);\n return validationError(\n \"CHARGE_HEADERS_MISSING\",\n `${url} answered 402 with no Tab charge headers; a 402 on this rail is a LimitExceeded credit decision and must name the required amount and the current headroom`,\n { details: { url, attempt: ordinal, status: 402 } },\n );\n }\n return ok({ response });\n }\n\n const charge = record(\n block.value,\n response.status === 402 ? \"declined\" : \"accrued\",\n url,\n response.status,\n ordinal,\n );\n return ok({ response, charge });\n };\n\n /**\n * The standing 402, resolved: paid through x402 when a signer and an offer are\n * both present, and the `LIMIT_EXCEEDED` it always was otherwise.\n */\n const prepay = async (\n url: string,\n init: Tab402FetchInit,\n send: Tab402Fetch<Res>,\n standing: Res,\n declined: ChargeAccrued | undefined,\n attempts: 1 | 2,\n ): Promise<Result<Res>> => {\n const x402 = options.x402;\n if (x402 === undefined) {\n discard(standing, logger);\n return limitExceeded(url, declined, attempts);\n }\n const offer = readPaymentRequired(headerReaderOf(standing.headers));\n discard(standing, logger);\n if (!offer.ok) return offer;\n if (offer.value === undefined) return limitExceeded(url, declined, attempts);\n const signer = await resolveX402Signer(x402.signer);\n if (!signer.ok) return signer;\n if (signer.value === undefined) {\n logger.debug(\"the x402 signer declined, so the standing 402 is reported as the credit decision it is\", { url });\n return limitExceeded(url, declined, attempts);\n }\n if (!isReplayable(init[\"body\"])) {\n return validationError(\n \"REQUEST_BODY_NOT_REPLAYABLE\",\n `${url} offered an x402 payment and the request body is a stream, which cannot be sent a second time; buffer the body before calling`,\n { details: { url } },\n );\n }\n const payer = createX402Client<Res>({\n signer: signer.value,\n ...(x402.chainId === undefined ? {} : { chainId: x402.chainId }),\n ...(x402.asset === undefined ? {} : { asset: x402.asset }),\n ...(x402.maxAmount === undefined ? {} : { maxAmount: x402.maxAmount }),\n fetchImpl: send,\n logger,\n now,\n });\n const paid = await payer.pay(url, init, offer.value);\n if (!paid.ok) {\n logger.warn(\"the x402 offer on a standing 402 could not be taken\", { url, code: paid.error.code });\n return paid;\n }\n if (paid.value.payment !== undefined) {\n payments.push(paid.value.payment);\n if (x402.onPayment !== undefined) {\n try {\n x402.onPayment(paid.value.payment);\n } catch (error) {\n logger.warn(\"onPayment threw and the payment was recorded anyway\", { url, error: causeOf(error).message });\n }\n }\n }\n return ok(paid.value.response);\n };\n\n return {\n async fetch(input: string, init: Tab402RequestInit = {}): Promise<Result<Res>> {\n if (maxRetries !== 0 && maxRetries !== 1) {\n return validationError(\n \"MAX_RETRIES_UNSUPPORTED\",\n `maxRetries is ${String(maxRetries)}; this client repeats a 402 exactly once or not at all, because a 402 here is a credit decision and no number of immediate retries clears it`,\n );\n }\n if (!isAddress(options.agent)) {\n return validationError(\n \"AGENT_INVALID\",\n `agent must be the Agent's 20-byte 0x Monad address, received \\`${String(options.agent)}\\``,\n );\n }\n if (options.authorisation !== undefined && !isBytes32(options.authorisation)) {\n return validationError(\n \"AUTHORISATION_INVALID\",\n `authorisation must be a 32-byte 0x authKey, received \\`${String(options.authorisation)}\\``,\n );\n }\n\n const url = resolveUrl(options.baseUrl, input);\n if (!url.ok) return url;\n\n const identity = agentRequestHeaders(options.agent, options.authorisation);\n if (!identity.ok) return identity;\n\n const supplied = normaliseHeaders(init.headers);\n if (!supplied.ok) return supplied;\n\n const send = options.fetchImpl ?? hostFetch<Res>();\n if (typeof send !== \"function\") {\n return upstreamError(\n \"FETCH_UNAVAILABLE\",\n \"this host has no global fetch; supply fetchImpl, or run on Node 20.10 or later\",\n );\n }\n\n // The caller's own headers win over the Tab headers: a caller metering a\n // second Agent on one call said so deliberately, and silently overriding it\n // would charge the wrong tab.\n const headers = { ...identity.value, ...supplied.value };\n const requestInit: Tab402FetchInit = { ...init, headers };\n\n const first = await attempt(url.value, requestInit, send, 1);\n if (!first.ok) return first;\n if (first.value.response.status !== 402) return ok(first.value.response);\n\n const declined = first.value.charge;\n if (maxRetries === 0) {\n return prepay(url.value, requestInit, send, first.value.response, declined, 1);\n }\n\n if (!isReplayable(init.body)) {\n discard(first.value.response, logger);\n return validationError(\n \"REQUEST_BODY_NOT_REPLAYABLE\",\n `${url.value} answered 402 and the request body is a stream, which cannot be sent a second time; buffer the body before calling, or set maxRetries to 0 and handle the credit decision yourself`,\n { details: { url: url.value } },\n );\n }\n\n // The 402's body is of no use to anyone and would otherwise hold a socket.\n discard(first.value.response, logger);\n\n const second = await attempt(url.value, requestInit, send, 2);\n if (!second.ok) return second;\n if (second.value.response.status !== 402) return ok(second.value.response);\n\n return prepay(url.value, requestInit, send, second.value.response, second.value.charge ?? declined, 2);\n },\n\n charges: () => [...history],\n\n payments: () => [...payments],\n\n tabs: () => [...ledger.values()].map(snapshotOf),\n\n tabOf(asset: ChargedAsset): TabSnapshot | undefined {\n const entry = ledger.get(chargedAssetKey(asset));\n return entry === undefined ? undefined : snapshotOf(entry);\n },\n };\n}\n\n/** The read-only view of one ledger entry. */\nconst snapshotOf = (entry: LedgerEntry): TabSnapshot => ({\n asset: entry.asset,\n openTab: entry.openTab,\n headroom: entry.headroom,\n accrued: entry.accrued,\n declined: entry.declined,\n accruedCount: entry.accruedCount,\n declinedCount: entry.declinedCount,\n observedAt: entry.observedAt,\n});\n\n/**\n * Whether what the `fetch` returned is a response at all.\n *\n * A duck check rather than an `instanceof`: a caller's `fetch` may come from\n * `undici`, from a test double, or from a runtime whose `Response` is a different\n * class than this process's, and none of those should be refused. Only `status`\n * and `headers` are checked, because they are the only two fields this client\n * reads.\n */\nfunction looksLikeResponse(value: unknown): boolean {\n if (typeof value !== \"object\" || value === null) return false;\n const candidate = value as { status?: unknown; headers?: unknown };\n return (\n typeof candidate.status === \"number\" &&\n typeof candidate.headers === \"object\" &&\n candidate.headers !== null\n );\n}\n\n/** Whether a response carries an x402 offer, without decoding it yet. */\nfunction hasPaymentRequired(headers: HeaderReader | HeaderRecord): boolean {\n try {\n const value = headerReaderOf(headers).get(\"PAYMENT-REQUIRED\");\n return typeof value === \"string\" && value.trim().length > 0;\n } catch {\n return false;\n }\n}\n\n/**\n * The `LIMIT` failure a standing `402` becomes.\n *\n * `retryable` is false, and deliberately: the condition does clear, but it clears\n * when the Agent settles and the registry indexes it, not after an interval. A\n * caller told to retry would spin against a Service that is answering correctly.\n * The detail keys are the ones the MCP tools report on `LIMIT_EXCEEDED` (R21.5).\n */\nfunction limitExceeded(url: string, charge: ChargeAccrued | undefined, attempts: 1 | 2): Result<never> {\n const detail =\n charge === undefined\n ? {}\n : {\n requiredBaseUnits: charge.amount.toString(10),\n headroomBaseUnits: charge.headroom.toString(10),\n openTabBaseUnits: charge.openTab.toString(10),\n asset: chargedAssetKey(charge.asset),\n serviceId: charge.serviceId,\n tool: charge.tool,\n };\n const shortfall =\n charge === undefined\n ? \"\"\n : ` It requires ${charge.amount.toString(10)} base units of ${chargedAssetKey(charge.asset)} and the Agent has ${charge.headroom.toString(10)} of headroom left.`;\n return fail(\n \"LIMIT\",\n \"LIMIT_EXCEEDED\",\n `${url} answered 402 after ${attempts === 1 ? \"one attempt with no repeat requested\" : \"both attempts\"}.${shortfall} Settle an Open Tab to restore headroom; repeating the request will not.`,\n { retryable: false, details: { url, attempts, ...detail } },\n );\n}\n\n/** Resolves `input` against `baseUrl`, accepting an absolute `input` unchanged. */\nfunction resolveUrl(baseUrl: string, input: string): Result<string> {\n if (typeof baseUrl !== \"string\" || baseUrl.trim().length === 0) {\n return validationError(\"BASE_URL_INVALID\", \"baseUrl must be a non-empty absolute URL\");\n }\n if (typeof input !== \"string\" || input.length === 0) {\n return validationError(\"REQUEST_URL_INVALID\", \"fetch() needs a URL or a path relative to baseUrl\");\n }\n const base = safeUrl(baseUrl, undefined);\n if (base === undefined) {\n return validationError(\n \"BASE_URL_INVALID\",\n `baseUrl \\`${baseUrl}\\` is not an absolute URL; it needs a scheme and a host`,\n { details: { baseUrl } },\n );\n }\n const resolved = safeUrl(input, base);\n if (resolved === undefined) {\n return validationError(\n \"REQUEST_URL_INVALID\",\n `\\`${input}\\` does not resolve to a URL against baseUrl \\`${baseUrl}\\``,\n { details: { baseUrl, input } },\n );\n }\n return ok(resolved);\n}\n\n/** The one place a `URL` constructor's throw is contained. */\nfunction safeUrl(value: string, base: string | undefined): string | undefined {\n try {\n return base === undefined ? new URL(value).toString() : new URL(value, base).toString();\n } catch {\n return undefined;\n }\n}\n\n/**\n * Flattens whatever header shape the caller passed into a plain object.\n *\n * Three shapes are accepted because all three are what a caller already holds: a\n * plain object, a `Headers` instance, and an array of pairs. Anything else is a\n * `VALIDATION` error rather than a silent drop, because a dropped `Content-Type`\n * turns a working request into a puzzling one.\n */\nfunction normaliseHeaders(value: unknown): Result<Record<string, string>> {\n if (value === undefined || value === null) return ok({});\n\n const flat: Record<string, string> = {};\n\n if (Array.isArray(value)) {\n for (const [index, pair] of (value as readonly unknown[]).entries()) {\n if (!Array.isArray(pair) || pair.length !== 2) {\n return validationError(\n \"REQUEST_HEADERS_INVALID\",\n `init.headers[${index}] is not a [name, value] pair`,\n { details: { index } },\n );\n }\n const name: unknown = pair[0];\n const headerValue: unknown = pair[1];\n if (typeof name !== \"string\" || typeof headerValue !== \"string\") {\n return validationError(\n \"REQUEST_HEADERS_INVALID\",\n `init.headers[${index}] must be a pair of strings`,\n { details: { index } },\n );\n }\n flat[name] = headerValue;\n }\n return ok(flat);\n }\n\n if (typeof value !== \"object\") {\n return validationError(\n \"REQUEST_HEADERS_INVALID\",\n `init.headers must be an object, a Headers, or an array of [name, value] pairs, received ${typeof value}`,\n );\n }\n\n const iterable = value as { forEach?: unknown };\n if (typeof iterable.forEach === \"function\") {\n // A `Headers`: iteration yields (value, name), in that order.\n const failed = collectHeaders(value as HeadersLike, flat);\n if (failed !== undefined) return failed;\n return ok(flat);\n }\n\n for (const [name, headerValue] of Object.entries(value as Record<string, unknown>)) {\n if (headerValue === undefined || headerValue === null) continue;\n if (Array.isArray(headerValue)) {\n flat[name] = headerValue.join(\", \");\n continue;\n }\n if (typeof headerValue !== \"string\" && typeof headerValue !== \"number\" && typeof headerValue !== \"bigint\") {\n return validationError(\n \"REQUEST_HEADERS_INVALID\",\n `init.headers[${JSON.stringify(name)}] must be a string, received ${typeof headerValue}`,\n { details: { header: name } },\n );\n }\n flat[name] = String(headerValue);\n }\n return ok(flat);\n}\n\ninterface HeadersLike {\n forEach(callback: (value: string, name: string) => void): void;\n}\n\n/** Drains a `Headers`-like into `flat`, returning an error result if it throws. */\nfunction collectHeaders(headers: HeadersLike, flat: Record<string, string>): Result<never> | undefined {\n try {\n headers.forEach((headerValue, name) => {\n flat[name] = headerValue;\n });\n return undefined;\n } catch (error) {\n return upstreamError(\"REQUEST_HEADERS_INVALID\", \"init.headers could not be read\", {\n cause: causeOf(error),\n });\n }\n}\n\n/**\n * Whether a body can be sent a second time.\n *\n * A string, a byte view, a `URLSearchParams`, a `Blob`, a `FormData`, and nothing\n * at all all replay. A `ReadableStream` and an async iterable do not: the first\n * attempt consumed them, and a repeat would send an empty body while the Service\n * answered as if the caller had meant it. So the repeat is refused with a reason\n * instead.\n */\nfunction isReplayable(body: unknown): boolean {\n if (body === undefined || body === null) return true;\n if (typeof body !== \"object\") return true;\n const candidate = body as { getReader?: unknown; [Symbol.asyncIterator]?: unknown };\n if (typeof candidate.getReader === \"function\") return false;\n if (typeof candidate[Symbol.asyncIterator] === \"function\") return false;\n return true;\n}\n\n/**\n * Releases a response this client is not handing back.\n *\n * A discarded response with an unread body holds its connection open until the\n * runtime collects it, which on a busy Agent is a socket leak rather than an\n * inconvenience. Failure to cancel is logged and swallowed: the request already\n * has its answer.\n */\nfunction discard(response: Tab402Response, logger: Logger): void {\n const body = response.body as { cancel?: unknown } | null | undefined;\n if (body === null || body === undefined || typeof body.cancel !== \"function\") return;\n if (response.bodyUsed === true) return;\n try {\n const cancelled = (body.cancel as () => unknown)();\n if (typeof (cancelled as { catch?: unknown })?.catch === \"function\") {\n (cancelled as Promise<unknown>).catch((error: unknown) => {\n logger.debug(\"discarded response body could not be cancelled\", {\n error: error instanceof Error ? error.message : String(error),\n });\n });\n }\n } catch (error) {\n logger.debug(\"discarded response body could not be cancelled\", {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n}\n\n/**\n * The host's global `fetch`.\n *\n * The single cast in this module, and the reason it is needed: this package\n * compiles against the ES2023 library alone, so the global `fetch` has no type\n * here to line up with {@link Tab402Fetch}. The runtime check above the cast is\n * what makes it safe, and a host without `fetch` becomes an `UPSTREAM` error\n * rather than a `TypeError`.\n */\nfunction hostFetch<Res extends Tab402Response>(): Tab402Fetch<Res> | undefined {\n const candidate = (globalThis as { fetch?: unknown }).fetch;\n if (typeof candidate !== \"function\") return undefined;\n return candidate as Tab402Fetch<Res>;\n}\n"]}
1
+ {"version":3,"file":"client-402.js","sourceRoot":"","sources":["../../src/http/client-402.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The HTTP 402 client wrapper.\n *\n * ## Tab is post-paid, so a 402 is not a demand for prepayment\n *\n * This is the one thing to understand about this file. A `402` from a Tab Service\n * does not mean \"pay now and I will then serve you\". Work is delivered first and\n * metered after; the charge lands on the Open Tab as an accrual, and the\n * Agent settles later, asynchronously, on Monad, with its own keys, through\n * the payment-strategy seam. So:\n *\n * - the **normal** metered response is a `200` carrying the charge block, and\n * this client records the accrual and hands the response straight back;\n * - a `402` is issued on `LimitExceeded` alone: the Agent has no headroom left\n * for that Asset. It is a credit decision, not an invoice;\n * - on a `402` the client records what the Service says the call requires, sends\n * the original request **once** more carrying `Tab-Agent` and\n * `Tab-Authorisation`, and stops. Not a retry loop, and not a backoff.\n *\n * **Nothing in this file settles.** There is no signer here, no strategy call, no\n * transaction, and no allowance. A settlement step inside the 402 handler would\n * be the prepay model Tab exists to replace. Settling is the Agent's decision,\n * taken through `tab_settle`, not something a transport does on its own.\n *\n * ## Why a repeat at all, if the charge already landed\n *\n * Two cases, and the repeat serves both. On the ordinary path the first attempt\n * may have reached a Service that could not identify the Agent (a caller that\n * built its own headers, or a proxy that dropped them), and the repeat carries the\n * identity headers explicitly. On the `LimitExceeded` path a Settlement may have\n * landed between the two attempts: `TabSettlement` restores headroom in the\n * same block it moves the Asset, so the second attempt is genuinely a\n * different question rather than the same one asked louder. Exactly one repeat,\n * because a second `402` means the\n * headroom is not coming back within the life of this request, and looping would\n * only meter the Service's rejection path.\n *\n * ## x402, the one exception, and why it is not settlement\n *\n * A `402` from a Tab Service that also carries `PAYMENT-REQUIRED` is a credit\n * refusal with an offer attached: pay for this one call, prepaid, through x402.\n * When the caller configured an x402 signer, and only then, a `402` that still\n * stands after the repeat is answered by signing that offer and sending the\n * request once more with `PAYMENT-SIGNATURE`. That is a prepayment for one\n * call and touches no tab. It is not a Settlement, it restores no headroom,\n * and it is off unless a signer was given, because an Agent that would rather\n * settle than prepay should get the `LIMIT_EXCEEDED` it can act on.\n *\n * ## Zero-throw, everywhere\n *\n * Every fallible call returns a `Result`. A transport\n * failure, a response object that is not one, a malformed header, a partial charge\n * block, an unreplayable request body, a `402` that stands after the repeat: all\n * of them are `err` values carrying an error category. Nothing here throws,\n * including the consumer's own `onCharge` callback, which is called inside a guard\n * so a consumer's bug cannot fail a request that succeeded.\n */\n\nimport { causeOf, isAddress, isBytes32, ok, wrap, type Address, type Bytes32, type Result } from \"../_shared/index.js\";\nimport { defaultLogger, type Logger } from \"../logger.js\";\nimport { fail, upstreamError, validationError } from \"../errors.js\";\nimport {\n agentRequestHeaders,\n chargedAssetKey,\n headerReaderOf,\n parseChargeHeaders,\n type ChargeBlock,\n type ChargedAsset,\n type HeaderReader,\n type HeaderRecord,\n} from \"./headers.js\";\nimport { createX402Client, resolveX402Signer, type X402PaymentReceipt, type X402SignerSource } from \"../x402/client.js\";\nimport { readPaymentRequired } from \"../x402/wire.js\";\n\n/**\n * What the caller may put on a request.\n *\n * A near-mirror of the standard `RequestInit` rather than an import of it, because\n * `@tabai/sdk` compiles against the ES2023 library alone and must not acquire a DOM\n * or `undici` type dependency to describe a request. The index signature carries\n * every option this client does not read, `signal`, `redirect`, `cache`,\n * `keepalive`, a dispatcher, through to the host `fetch` untouched.\n */\nexport interface Tab402RequestInit {\n readonly method?: string;\n /** A plain object, a `Headers`, or an array of pairs. Merged with the Tab headers. */\n readonly headers?: HeaderReader | HeaderRecord | readonly (readonly [string, string])[];\n readonly body?: unknown;\n readonly [option: string]: unknown;\n}\n\n/** The request this client hands to its `fetch`: the caller's options, with headers resolved. */\nexport interface Tab402FetchInit {\n readonly headers: Readonly<Record<string, string>>;\n readonly [option: string]: unknown;\n}\n\n/**\n * The little of a response this client reads.\n *\n * Structural for the same reason as {@link Tab402RequestInit}, and loose on\n * purpose: `body` and `bodyUsed` are `unknown` and duck-checked at runtime, so a\n * real `Response` from any host satisfies this without the two type worlds having\n * to agree. Widen it through the type parameter of {@link createTab402Client} when\n * the caller supplies a typed `fetch`, and `client.fetch` then returns\n * `Result<Response>` with every method of the real thing intact.\n */\nexport interface Tab402Response {\n readonly status: number;\n readonly headers: HeaderReader | HeaderRecord;\n readonly body?: unknown;\n readonly bodyUsed?: unknown;\n}\n\n/** The `fetch` this client calls. The host's global `fetch` is the default. */\nexport type Tab402Fetch<Res extends Tab402Response> = (\n url: string,\n init: Tab402FetchInit,\n) => Promise<Res>;\n\n/** Whether the charge the Service reported landed on the Open Tab. */\nexport type ChargeOutcome =\n /** The call was served and metered. The Open Tab now carries this amount. */\n | \"accrued\"\n /**\n * `LimitExceeded`: the amount is what the call *requires* and it did not land,\n * because the Agent's headroom for the Asset does not cover it.\n */\n | \"declined\";\n\n/** One charge block, read off one response, in the client's own terms. */\nexport interface ChargeAccrued {\n /** The Agent this call was metered against. */\n readonly agent: Address;\n /** The absolute URL that was called. */\n readonly url: string;\n /** The HTTP status the charge block arrived on. */\n readonly status: number;\n readonly outcome: ChargeOutcome;\n /** Integer Asset base units: charged on `accrued`, required on `declined`. */\n readonly amount: bigint;\n readonly asset: ChargedAsset;\n readonly serviceId: Bytes32;\n readonly tool: Bytes32;\n /** The Open Tab the Service reported after this call. */\n readonly openTab: bigint;\n /** The headroom the Service reported for this Agent and Asset. */\n readonly headroom: bigint;\n readonly authorisation?: Bytes32;\n /**\n * The strategy the Agent intends to settle this Asset through, if the client was\n * given one. Carried for the later, separate settlement path and used by nothing\n * here.\n */\n readonly strategyId?: string;\n /** `1` for the original request, `2` for the repeat. */\n readonly attempt: 1 | 2;\n /** Milliseconds since the epoch, when the header was read. */\n readonly observedAt: number;\n}\n\n/** What this client believes about one Asset's tab, from headers alone. */\nexport interface TabSnapshot {\n readonly asset: ChargedAsset;\n /** The Open Tab most recently reported for this Asset. */\n readonly openTab: bigint;\n /** The headroom most recently reported for this Asset. */\n readonly headroom: bigint;\n /** Sum of every charge that landed, across the client's lifetime. */\n readonly accrued: bigint;\n /** Sum of every charge refused for want of headroom. Never part of {@link accrued}. */\n readonly declined: bigint;\n readonly accruedCount: number;\n readonly declinedCount: number;\n readonly observedAt: number;\n}\n\nexport interface Tab402ClientOptions<Res extends Tab402Response = Tab402Response> {\n /** Absolute base URL. A relative path handed to `fetch` resolves against it. */\n readonly baseUrl: string;\n /** The Agent's Monad address, sent as `Tab-Agent`. */\n readonly agent: Address;\n /** The authKey to meter against, sent as `Tab-Authorisation` when supplied. */\n readonly authorisation?: Bytes32;\n /** Called for every charge block read, on the 200 path and the 402 path alike. */\n readonly onCharge?: (charge: ChargeAccrued) => void;\n /**\n * `1` repeats the original request once after a `402`; `0` repeats nothing.\n *\n * Typed as the two values it can hold rather than as a `number`, because \"repeat\n * once\" is the semantics rather than a default: a caller who wrote `5` would be\n * asking for a retry loop against a credit decision, and a number that silently\n * clamped to `1` would leave them believing they had one.\n */\n readonly maxRetries?: 0 | 1;\n /** Recorded on each accrual for the later settlement path. Never used to settle here. */\n readonly strategyId?: string;\n /**\n * The prepaid fallback. With a signer here, a `402` that still stands after\n * the repeat and carries `PAYMENT-REQUIRED` is paid through x402 and the\n * request sent once more. Without one, that `402` is the `LIMIT_EXCEEDED`\n * it always was. See the module note.\n */\n readonly x402?: Tab402X402Options;\n /** Defaults to the host's global `fetch`. */\n readonly fetchImpl?: Tab402Fetch<Res>;\n readonly logger?: Logger;\n /** Injectable clock, so `observedAt` is testable. Defaults to `Date.now`. */\n readonly now?: () => number;\n /**\n * How many accruals {@link Tab402Client.charges} keeps. Defaults to 128.\n *\n * Trimming the list never touches the totals in {@link TabSnapshot}, which are\n * running sums, so a long-lived client keeps exact accounting on bounded memory.\n */\n readonly maxChargeHistory?: number;\n}\n\n/** How the client pays when it pays. */\nexport interface Tab402X402Options {\n /**\n * The signer, or a factory called only when an offer is about to be taken. A\n * factory returning `undefined` declines, and the `402` stands as the credit\n * decision it was.\n */\n readonly signer: X402SignerSource;\n /** Sign only on this chain. Defaults to any `eip155:*` the Service offers. */\n readonly chainId?: bigint;\n /** Sign only for this token. Defaults to any the Service offers. */\n readonly asset?: Address;\n /** Refuse an offer above this many atomic units. Omitted sets no ceiling. */\n readonly maxAmount?: bigint;\n readonly onPayment?: (receipt: X402PaymentReceipt) => void;\n}\n\nexport interface Tab402Client<Res extends Tab402Response = Tab402Response> {\n /**\n * Sends a request, records whatever charge the response reports, and repeats\n * once on a `402`.\n *\n * `input` may be absolute or relative to `baseUrl`. Returns the response the\n * Service produced, this client never rewrites a status, so a `500` from the\n * Service comes back as `ok(response)` for the caller to read. The `err` cases\n * are this client's own: a bad URL, a malformed charge block, a transport\n * failure, or a `402` that still stands after the repeat.\n */\n fetch(input: string, init?: Tab402RequestInit): Promise<Result<Res>>;\n /** Every charge block read, oldest first, up to `maxChargeHistory`. */\n charges(): readonly ChargeAccrued[];\n /** One snapshot per Asset seen, in first-seen order. */\n tabs(): readonly TabSnapshot[];\n tabOf(asset: ChargedAsset): TabSnapshot | undefined;\n /** Every x402 payment made, oldest first. Empty unless `x402` was configured. */\n payments(): readonly X402PaymentReceipt[];\n}\n\ninterface LedgerEntry {\n asset: ChargedAsset;\n openTab: bigint;\n headroom: bigint;\n accrued: bigint;\n declined: bigint;\n accruedCount: number;\n declinedCount: number;\n observedAt: number;\n}\n\n/**\n * Builds the client.\n *\n * Construction is total: it cannot fail and returns a client, not a `Result`.\n * Every fallible thing (an unusable `baseUrl`, an `agent` that is not an\n * address, a host with no `fetch`) is reported by the call that needs it, which\n * is the only place a caller can act on it. This matches\n * `createMonadStrategy` and keeps the SDK's two factories the same shape.\n */\nexport function createTab402Client<Res extends Tab402Response = Tab402Response>(\n options: Tab402ClientOptions<Res>,\n): Tab402Client<Res> {\n const logger = options.logger ?? defaultLogger;\n const now = options.now ?? (() => Date.now());\n const maxRetries = options.maxRetries ?? 1;\n const historyLimit = options.maxChargeHistory ?? 128;\n\n const history: ChargeAccrued[] = [];\n const ledger = new Map<string, LedgerEntry>();\n const payments: X402PaymentReceipt[] = [];\n\n const record = (\n block: ChargeBlock,\n outcome: ChargeOutcome,\n url: string,\n status: number,\n attempt: 1 | 2,\n ): ChargeAccrued => {\n const observedAt = now();\n const charge: ChargeAccrued = {\n agent: options.agent,\n url,\n status,\n outcome,\n amount: block.amount,\n asset: block.asset,\n serviceId: block.serviceId,\n tool: block.tool,\n openTab: block.openTab,\n headroom: block.headroom,\n ...(options.authorisation === undefined ? {} : { authorisation: options.authorisation }),\n ...(options.strategyId === undefined ? {} : { strategyId: options.strategyId }),\n attempt,\n observedAt,\n };\n\n const key = chargedAssetKey(block.asset);\n const entry = ledger.get(key) ?? {\n asset: block.asset,\n openTab: 0n,\n headroom: 0n,\n accrued: 0n,\n declined: 0n,\n accruedCount: 0,\n declinedCount: 0,\n observedAt,\n };\n // The Open Tab and the headroom are the Service's figures, not sums of ours:\n // a Settlement moves both without this client seeing a request, so the\n // latest report replaces rather than adds.\n entry.openTab = block.openTab;\n entry.headroom = block.headroom;\n entry.observedAt = observedAt;\n if (outcome === \"accrued\") {\n entry.accrued += block.amount;\n entry.accruedCount += 1;\n } else {\n entry.declined += block.amount;\n entry.declinedCount += 1;\n }\n ledger.set(key, entry);\n\n history.push(charge);\n if (history.length > historyLimit && historyLimit >= 0) {\n history.splice(0, history.length - historyLimit);\n }\n\n if (options.onCharge !== undefined) {\n // A consumer callback is code this package did not write, and a throw from\n // it must not fail a call that otherwise succeeded.\n try {\n options.onCharge(charge);\n } catch (error) {\n logger.warn(\"onCharge threw and the charge was recorded anyway\", {\n url,\n outcome,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n return charge;\n };\n\n const attempt = async (\n url: string,\n init: Tab402FetchInit,\n send: Tab402Fetch<Res>,\n ordinal: 1 | 2,\n ): Promise<Result<{ readonly response: Res; readonly charge?: ChargeAccrued }>> => {\n const sent = await wrap(\n async () => send(url, init),\n (error) => ({\n category: \"UPSTREAM\",\n code: \"FETCH_FAILED\",\n message: `the request to ${url} did not complete`,\n retryable: true,\n details: { url, attempt: ordinal },\n cause: causeOf(error),\n }),\n );\n if (!sent.ok) return sent;\n\n const response = sent.value;\n if (!looksLikeResponse(response)) {\n return upstreamError(\n \"FETCH_RESPONSE_INVALID\",\n `the fetch given to this client returned something that is not a response for ${url}`,\n { details: { url, attempt: ordinal } },\n );\n }\n\n const block = parseChargeHeaders(headerReaderOf(response.headers));\n if (!block.ok) {\n discard(response, logger);\n return block;\n }\n\n if (block.value === undefined) {\n if (response.status === 402) {\n // A 402 with no charge block is not a Tab credit decision. With an x402\n // signer it may still be an offer this client can take, so it is handed\n // back for the payment path to read; without one it is malformed.\n if (options.x402 !== undefined && hasPaymentRequired(response.headers)) return ok({ response });\n discard(response, logger);\n return validationError(\n \"CHARGE_HEADERS_MISSING\",\n `${url} answered 402 with no Tab charge headers; a 402 on this rail is a LimitExceeded credit decision and must name the required amount and the current headroom`,\n { details: { url, attempt: ordinal, status: 402 } },\n );\n }\n return ok({ response });\n }\n\n const charge = record(\n block.value,\n response.status === 402 ? \"declined\" : \"accrued\",\n url,\n response.status,\n ordinal,\n );\n return ok({ response, charge });\n };\n\n /**\n * The standing 402, resolved: paid through x402 when a signer and an offer are\n * both present, and the `LIMIT_EXCEEDED` it always was otherwise.\n */\n const prepay = async (\n url: string,\n init: Tab402FetchInit,\n send: Tab402Fetch<Res>,\n standing: Res,\n declined: ChargeAccrued | undefined,\n attempts: 1 | 2,\n ): Promise<Result<Res>> => {\n const x402 = options.x402;\n if (x402 === undefined) {\n discard(standing, logger);\n return limitExceeded(url, declined, attempts);\n }\n const offer = readPaymentRequired(headerReaderOf(standing.headers));\n discard(standing, logger);\n if (!offer.ok) return offer;\n if (offer.value === undefined) return limitExceeded(url, declined, attempts);\n const signer = await resolveX402Signer(x402.signer);\n if (!signer.ok) return signer;\n if (signer.value === undefined) {\n logger.debug(\"the x402 signer declined, so the standing 402 is reported as the credit decision it is\", { url });\n return limitExceeded(url, declined, attempts);\n }\n if (!isReplayable(init[\"body\"])) {\n return validationError(\n \"REQUEST_BODY_NOT_REPLAYABLE\",\n `${url} offered an x402 payment and the request body is a stream, which cannot be sent a second time; buffer the body before calling`,\n { details: { url } },\n );\n }\n const payer = createX402Client<Res>({\n signer: signer.value,\n ...(x402.chainId === undefined ? {} : { chainId: x402.chainId }),\n ...(x402.asset === undefined ? {} : { asset: x402.asset }),\n ...(x402.maxAmount === undefined ? {} : { maxAmount: x402.maxAmount }),\n fetchImpl: send,\n logger,\n now,\n });\n const paid = await payer.pay(url, init, offer.value);\n if (!paid.ok) {\n logger.warn(\"the x402 offer on a standing 402 could not be taken\", { url, code: paid.error.code });\n return paid;\n }\n if (paid.value.payment !== undefined) {\n payments.push(paid.value.payment);\n if (x402.onPayment !== undefined) {\n try {\n x402.onPayment(paid.value.payment);\n } catch (error) {\n logger.warn(\"onPayment threw and the payment was recorded anyway\", { url, error: causeOf(error).message });\n }\n }\n }\n return ok(paid.value.response);\n };\n\n return {\n async fetch(input: string, init: Tab402RequestInit = {}): Promise<Result<Res>> {\n if (maxRetries !== 0 && maxRetries !== 1) {\n return validationError(\n \"MAX_RETRIES_UNSUPPORTED\",\n `maxRetries is ${String(maxRetries)}; this client repeats a 402 exactly once or not at all, because a 402 here is a credit decision and no number of immediate retries clears it`,\n );\n }\n if (!isAddress(options.agent)) {\n return validationError(\n \"AGENT_INVALID\",\n `agent must be the Agent's 20-byte 0x Monad address, received \\`${String(options.agent)}\\``,\n );\n }\n if (options.authorisation !== undefined && !isBytes32(options.authorisation)) {\n return validationError(\n \"AUTHORISATION_INVALID\",\n `authorisation must be a 32-byte 0x authKey, received \\`${String(options.authorisation)}\\``,\n );\n }\n\n const url = resolveUrl(options.baseUrl, input);\n if (!url.ok) return url;\n\n const identity = agentRequestHeaders(options.agent, options.authorisation);\n if (!identity.ok) return identity;\n\n const supplied = normaliseHeaders(init.headers);\n if (!supplied.ok) return supplied;\n\n const send = options.fetchImpl ?? hostFetch<Res>();\n if (typeof send !== \"function\") {\n return upstreamError(\n \"FETCH_UNAVAILABLE\",\n \"this host has no global fetch; supply fetchImpl, or run on Node 20.10 or later\",\n );\n }\n\n // The caller's own headers win over the Tab headers: a caller metering a\n // second Agent on one call said so deliberately, and silently overriding it\n // would charge the wrong tab.\n const headers = { ...identity.value, ...supplied.value };\n const requestInit: Tab402FetchInit = { ...init, headers };\n\n const first = await attempt(url.value, requestInit, send, 1);\n if (!first.ok) return first;\n if (first.value.response.status !== 402) return ok(first.value.response);\n\n const declined = first.value.charge;\n if (maxRetries === 0) {\n return prepay(url.value, requestInit, send, first.value.response, declined, 1);\n }\n\n if (!isReplayable(init.body)) {\n discard(first.value.response, logger);\n return validationError(\n \"REQUEST_BODY_NOT_REPLAYABLE\",\n `${url.value} answered 402 and the request body is a stream, which cannot be sent a second time; buffer the body before calling, or set maxRetries to 0 and handle the credit decision yourself`,\n { details: { url: url.value } },\n );\n }\n\n // The 402's body is of no use to anyone and would otherwise hold a socket.\n discard(first.value.response, logger);\n\n const second = await attempt(url.value, requestInit, send, 2);\n if (!second.ok) return second;\n if (second.value.response.status !== 402) return ok(second.value.response);\n\n return prepay(url.value, requestInit, send, second.value.response, second.value.charge ?? declined, 2);\n },\n\n charges: () => [...history],\n\n payments: () => [...payments],\n\n tabs: () => [...ledger.values()].map(snapshotOf),\n\n tabOf(asset: ChargedAsset): TabSnapshot | undefined {\n const entry = ledger.get(chargedAssetKey(asset));\n return entry === undefined ? undefined : snapshotOf(entry);\n },\n };\n}\n\n/** The read-only view of one ledger entry. */\nconst snapshotOf = (entry: LedgerEntry): TabSnapshot => ({\n asset: entry.asset,\n openTab: entry.openTab,\n headroom: entry.headroom,\n accrued: entry.accrued,\n declined: entry.declined,\n accruedCount: entry.accruedCount,\n declinedCount: entry.declinedCount,\n observedAt: entry.observedAt,\n});\n\n/**\n * Whether what the `fetch` returned is a response at all.\n *\n * A duck check rather than an `instanceof`: a caller's `fetch` may come from\n * `undici`, from a test double, or from a runtime whose `Response` is a different\n * class than this process's, and none of those should be refused. Only `status`\n * and `headers` are checked, because they are the only two fields this client\n * reads.\n */\nfunction looksLikeResponse(value: unknown): boolean {\n if (typeof value !== \"object\" || value === null) return false;\n const candidate = value as { status?: unknown; headers?: unknown };\n return (\n typeof candidate.status === \"number\" &&\n typeof candidate.headers === \"object\" &&\n candidate.headers !== null\n );\n}\n\n/** Whether a response carries an x402 offer, without decoding it yet. */\nfunction hasPaymentRequired(headers: HeaderReader | HeaderRecord): boolean {\n try {\n const value = headerReaderOf(headers).get(\"PAYMENT-REQUIRED\");\n return typeof value === \"string\" && value.trim().length > 0;\n } catch {\n return false;\n }\n}\n\n/**\n * The `LIMIT` failure a standing `402` becomes.\n *\n * `retryable` is false, and deliberately: the condition does clear, but it clears\n * when the Agent settles and the registry indexes it, not after an interval. A\n * caller told to retry would spin against a Service that is answering correctly.\n * The detail keys are the ones the MCP tools report on `LIMIT_EXCEEDED`.\n */\nfunction limitExceeded(url: string, charge: ChargeAccrued | undefined, attempts: 1 | 2): Result<never> {\n const detail =\n charge === undefined\n ? {}\n : {\n requiredBaseUnits: charge.amount.toString(10),\n headroomBaseUnits: charge.headroom.toString(10),\n openTabBaseUnits: charge.openTab.toString(10),\n asset: chargedAssetKey(charge.asset),\n serviceId: charge.serviceId,\n tool: charge.tool,\n };\n const shortfall =\n charge === undefined\n ? \"\"\n : ` It requires ${charge.amount.toString(10)} base units of ${chargedAssetKey(charge.asset)} and the Agent has ${charge.headroom.toString(10)} of headroom left.`;\n return fail(\n \"LIMIT\",\n \"LIMIT_EXCEEDED\",\n `${url} answered 402 after ${attempts === 1 ? \"one attempt with no repeat requested\" : \"both attempts\"}.${shortfall} Settle an Open Tab to restore headroom; repeating the request will not.`,\n { retryable: false, details: { url, attempts, ...detail } },\n );\n}\n\n/** Resolves `input` against `baseUrl`, accepting an absolute `input` unchanged. */\nfunction resolveUrl(baseUrl: string, input: string): Result<string> {\n if (typeof baseUrl !== \"string\" || baseUrl.trim().length === 0) {\n return validationError(\"BASE_URL_INVALID\", \"baseUrl must be a non-empty absolute URL\");\n }\n if (typeof input !== \"string\" || input.length === 0) {\n return validationError(\"REQUEST_URL_INVALID\", \"fetch() needs a URL or a path relative to baseUrl\");\n }\n const base = safeUrl(baseUrl, undefined);\n if (base === undefined) {\n return validationError(\n \"BASE_URL_INVALID\",\n `baseUrl \\`${baseUrl}\\` is not an absolute URL; it needs a scheme and a host`,\n { details: { baseUrl } },\n );\n }\n const resolved = safeUrl(input, base);\n if (resolved === undefined) {\n return validationError(\n \"REQUEST_URL_INVALID\",\n `\\`${input}\\` does not resolve to a URL against baseUrl \\`${baseUrl}\\``,\n { details: { baseUrl, input } },\n );\n }\n return ok(resolved);\n}\n\n/** The one place a `URL` constructor's throw is contained. */\nfunction safeUrl(value: string, base: string | undefined): string | undefined {\n try {\n return base === undefined ? new URL(value).toString() : new URL(value, base).toString();\n } catch {\n return undefined;\n }\n}\n\n/**\n * Flattens whatever header shape the caller passed into a plain object.\n *\n * Three shapes are accepted because all three are what a caller already holds: a\n * plain object, a `Headers` instance, and an array of pairs. Anything else is a\n * `VALIDATION` error rather than a silent drop, because a dropped `Content-Type`\n * turns a working request into a puzzling one.\n */\nfunction normaliseHeaders(value: unknown): Result<Record<string, string>> {\n if (value === undefined || value === null) return ok({});\n\n const flat: Record<string, string> = {};\n\n if (Array.isArray(value)) {\n for (const [index, pair] of (value as readonly unknown[]).entries()) {\n if (!Array.isArray(pair) || pair.length !== 2) {\n return validationError(\n \"REQUEST_HEADERS_INVALID\",\n `init.headers[${index}] is not a [name, value] pair`,\n { details: { index } },\n );\n }\n const name: unknown = pair[0];\n const headerValue: unknown = pair[1];\n if (typeof name !== \"string\" || typeof headerValue !== \"string\") {\n return validationError(\n \"REQUEST_HEADERS_INVALID\",\n `init.headers[${index}] must be a pair of strings`,\n { details: { index } },\n );\n }\n flat[name] = headerValue;\n }\n return ok(flat);\n }\n\n if (typeof value !== \"object\") {\n return validationError(\n \"REQUEST_HEADERS_INVALID\",\n `init.headers must be an object, a Headers, or an array of [name, value] pairs, received ${typeof value}`,\n );\n }\n\n const iterable = value as { forEach?: unknown };\n if (typeof iterable.forEach === \"function\") {\n // A `Headers`: iteration yields (value, name), in that order.\n const failed = collectHeaders(value as HeadersLike, flat);\n if (failed !== undefined) return failed;\n return ok(flat);\n }\n\n for (const [name, headerValue] of Object.entries(value as Record<string, unknown>)) {\n if (headerValue === undefined || headerValue === null) continue;\n if (Array.isArray(headerValue)) {\n flat[name] = headerValue.join(\", \");\n continue;\n }\n if (typeof headerValue !== \"string\" && typeof headerValue !== \"number\" && typeof headerValue !== \"bigint\") {\n return validationError(\n \"REQUEST_HEADERS_INVALID\",\n `init.headers[${JSON.stringify(name)}] must be a string, received ${typeof headerValue}`,\n { details: { header: name } },\n );\n }\n flat[name] = String(headerValue);\n }\n return ok(flat);\n}\n\ninterface HeadersLike {\n forEach(callback: (value: string, name: string) => void): void;\n}\n\n/** Drains a `Headers`-like into `flat`, returning an error result if it throws. */\nfunction collectHeaders(headers: HeadersLike, flat: Record<string, string>): Result<never> | undefined {\n try {\n headers.forEach((headerValue, name) => {\n flat[name] = headerValue;\n });\n return undefined;\n } catch (error) {\n return upstreamError(\"REQUEST_HEADERS_INVALID\", \"init.headers could not be read\", {\n cause: causeOf(error),\n });\n }\n}\n\n/**\n * Whether a body can be sent a second time.\n *\n * A string, a byte view, a `URLSearchParams`, a `Blob`, a `FormData`, and nothing\n * at all all replay. A `ReadableStream` and an async iterable do not: the first\n * attempt consumed them, and a repeat would send an empty body while the Service\n * answered as if the caller had meant it. So the repeat is refused with a reason\n * instead.\n */\nfunction isReplayable(body: unknown): boolean {\n if (body === undefined || body === null) return true;\n if (typeof body !== \"object\") return true;\n const candidate = body as { getReader?: unknown; [Symbol.asyncIterator]?: unknown };\n if (typeof candidate.getReader === \"function\") return false;\n if (typeof candidate[Symbol.asyncIterator] === \"function\") return false;\n return true;\n}\n\n/**\n * Releases a response this client is not handing back.\n *\n * A discarded response with an unread body holds its connection open until the\n * runtime collects it, which on a busy Agent is a socket leak rather than an\n * inconvenience. Failure to cancel is logged and swallowed: the request already\n * has its answer.\n */\nfunction discard(response: Tab402Response, logger: Logger): void {\n const body = response.body as { cancel?: unknown } | null | undefined;\n if (body === null || body === undefined || typeof body.cancel !== \"function\") return;\n if (response.bodyUsed === true) return;\n try {\n const cancelled = (body.cancel as () => unknown)();\n if (typeof (cancelled as { catch?: unknown })?.catch === \"function\") {\n (cancelled as Promise<unknown>).catch((error: unknown) => {\n logger.debug(\"discarded response body could not be cancelled\", {\n error: error instanceof Error ? error.message : String(error),\n });\n });\n }\n } catch (error) {\n logger.debug(\"discarded response body could not be cancelled\", {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n}\n\n/**\n * The host's global `fetch`.\n *\n * The single cast in this module, and the reason it is needed: this package\n * compiles against the ES2023 library alone, so the global `fetch` has no type\n * here to line up with {@link Tab402Fetch}. The runtime check above the cast is\n * what makes it safe, and a host without `fetch` becomes an `UPSTREAM` error\n * rather than a `TypeError`.\n */\nfunction hostFetch<Res extends Tab402Response>(): Tab402Fetch<Res> | undefined {\n const candidate = (globalThis as { fetch?: unknown }).fetch;\n if (typeof candidate !== \"function\") return undefined;\n return candidate as Tab402Fetch<Res>;\n}\n"]}
@@ -2,7 +2,7 @@
2
2
  * The Tab HTTP header contract, and the only parser and formatter for it.
3
3
  *
4
4
  * This module is the reconciliation point between the two halves of the wire
5
- * protocol: the client wrapper in `client-402.ts` (R23.2) reads these headers off
5
+ * protocol: the client wrapper in `client-402.ts` reads these headers off
6
6
  * a Service response, and the server-side post-paid plugin writes them. Both
7
7
  * halves go through the functions here rather than through their own string
8
8
  * handling, so a disagreement about a format is a compile or test failure in one
@@ -21,11 +21,11 @@
21
21
  * | `Tab-Agent` | request | yes on a metered call | `0x` 20-byte address: the Agent's Monad address, its identity on the rail |
22
22
  * | `Tab-Authorisation` | request | optional | `0x` 32-byte word: the `authKey` the Service should meter against |
23
23
  *
24
- * ## Five decisions the table does not show, each of which 15.3 must match
24
+ * ## Five decisions the table does not show, which both halves hold to
25
25
  *
26
26
  * **1. The six response headers are one all-or-nothing block.** A response
27
27
  * carrying none of them is simply not a metered response, and
28
- * {@link parseChargeHeaders} returns `ok(undefined)` for it, an unmetered health
28
+ * {@link parseChargeHeaders} returns `ok(undefined)` for it: an unmetered health
29
29
  * endpoint behind the same client must not become an error. A response carrying
30
30
  * *some* of them is a malformed metered response and is an `err`, because the
31
31
  * alternative is a client that silently records a charge against the wrong Asset
@@ -37,7 +37,7 @@
37
37
  * decimals, so `10_000` is one cent, and an Open Tab routinely exceeds the range
38
38
  * a float represents exactly. `Number.parseInt` would round a large Open Tab into
39
39
  * something that still looks plausible, which is worse than failing. The grammar
40
- * is deliberately narrow, `/^[0-9]+$/`, so `1e6`, `1.0`, `1_000`, `+1`, `-1`,
40
+ * is deliberately narrow (`/^[0-9]+$/`), so `1e6`, `1.0`, `1_000`, `+1`, `-1`,
41
41
  * `0x10`, and `1,000` are all rejected rather than coerced.
42
42
  *
43
43
  * **3. `Tab-Charge-Asset` carries the chain id and the Asset address and nothing
@@ -49,7 +49,7 @@
49
49
  *
50
50
  * **4. The chain id is bounded as a `uint64` and not narrowed to Monad's two
51
51
  * networks.** Refusing an unknown chain id here would close a set the
52
- * payment-strategy seam deliberately leaves open (R23.6): a strategy settling on a
52
+ * payment-strategy seam deliberately leaves open: a strategy settling on a
53
53
  * network this release has never heard of should still be able to read its own
54
54
  * charge headers.
55
55
  *
@@ -59,12 +59,10 @@
59
59
  * client that reports two Open Tabs where there is one. A `bytes32` word has no
60
60
  * checksum convention to normalise, so it is carried through byte-for-byte.
61
61
  *
62
- * A `bytes32` tool key is usually a short name right-padded with zero bytes -
63
- * `0x7461622e64656d6f…` is `tab.demo`, but nothing
64
- * here decodes it. The key is what `ServiceRegistry.priceOf` is keyed on, and it
65
- * is carried as the word it is so it round-trips into a contract call unchanged.
66
- *
67
- * Requirements: 23.2, 21.5
62
+ * A `bytes32` tool key is usually a short name right-padded with zero bytes
63
+ * (`0x7461622e64656d6f…` is `tab.demo`), but nothing here decodes it. The key
64
+ * is what `ServiceRegistry.priceOf` is keyed on, and it is carried as the word it
65
+ * is so it round-trips into a contract call unchanged.
68
66
  */
69
67
  import { type Address, type Bytes32, type Result } from "../_shared/index.js";
70
68
  /** Every Tab header name, in the casing this SDK writes. */
@@ -1 +1 @@
1
- {"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../../src/http/headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AAEH,OAAO,EAKL,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,KAAK,MAAM,EACZ,MAAM,eAAe,CAAC;AAGvB,4DAA4D;AAC5D,eAAO,MAAM,UAAU;;;;;;;;;CASb,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,uBAAuB,6HAO1B,CAAC;AAEX;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,2FAA2F;IAC3F,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mFAAmF;IACnF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,uFAAuF;AACvF,MAAM,WAAW,WAAW;IAC1B,8CAA8C;IAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CAC9C;AAED,8EAA8E;AAC9E,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC;AAE5F,kFAAkF;AAClF,eAAO,MAAM,eAAe,GAAI,OAAO,YAAY,KAAG,MACU,CAAC;AAEjE,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,GAAI,GAAG,YAAY,EAAE,GAAG,YAAY,KAAG,OACzB,CAAC;AAE5C;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,GAAG,YAAY,CAQhF;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAexF;AAED,yDAAyD;AACzD,eAAO,MAAM,kBAAkB,GAAI,OAAO,YAAY,KAAG,MACO,CAAC;AAEjE,iCAAiC;AACjC,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,CA6BnE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,YAAY,GAAG,YAAY,GAClC,MAAM,CAAC,WAAW,GAAG,SAAS,CAAC,CAwEjC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAiDtF;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,EACd,aAAa,CAAC,EAAE,OAAO,GACtB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAiBhC"}
1
+ {"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../../src/http/headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AAEH,OAAO,EAKL,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,KAAK,MAAM,EACZ,MAAM,eAAe,CAAC;AAGvB,4DAA4D;AAC5D,eAAO,MAAM,UAAU;;;;;;;;;CASb,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,uBAAuB,6HAO1B,CAAC;AAEX;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,2FAA2F;IAC3F,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mFAAmF;IACnF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,uFAAuF;AACvF,MAAM,WAAW,WAAW;IAC1B,8CAA8C;IAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CAC9C;AAED,8EAA8E;AAC9E,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC;AAE5F,kFAAkF;AAClF,eAAO,MAAM,eAAe,GAAI,OAAO,YAAY,KAAG,MACU,CAAC;AAEjE,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,GAAI,GAAG,YAAY,EAAE,GAAG,YAAY,KAAG,OACzB,CAAC;AAE5C;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,GAAG,YAAY,CAQhF;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAexF;AAED,yDAAyD;AACzD,eAAO,MAAM,kBAAkB,GAAI,OAAO,YAAY,KAAG,MACO,CAAC;AAEjE,iCAAiC;AACjC,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,CA6BnE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,YAAY,GAAG,YAAY,GAClC,MAAM,CAAC,WAAW,GAAG,SAAS,CAAC,CAwEjC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAiDtF;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,EACd,aAAa,CAAC,EAAE,OAAO,GACtB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAiBhC"}
@@ -2,7 +2,7 @@
2
2
  * The Tab HTTP header contract, and the only parser and formatter for it.
3
3
  *
4
4
  * This module is the reconciliation point between the two halves of the wire
5
- * protocol: the client wrapper in `client-402.ts` (R23.2) reads these headers off
5
+ * protocol: the client wrapper in `client-402.ts` reads these headers off
6
6
  * a Service response, and the server-side post-paid plugin writes them. Both
7
7
  * halves go through the functions here rather than through their own string
8
8
  * handling, so a disagreement about a format is a compile or test failure in one
@@ -21,11 +21,11 @@
21
21
  * | `Tab-Agent` | request | yes on a metered call | `0x` 20-byte address: the Agent's Monad address, its identity on the rail |
22
22
  * | `Tab-Authorisation` | request | optional | `0x` 32-byte word: the `authKey` the Service should meter against |
23
23
  *
24
- * ## Five decisions the table does not show, each of which 15.3 must match
24
+ * ## Five decisions the table does not show, which both halves hold to
25
25
  *
26
26
  * **1. The six response headers are one all-or-nothing block.** A response
27
27
  * carrying none of them is simply not a metered response, and
28
- * {@link parseChargeHeaders} returns `ok(undefined)` for it, an unmetered health
28
+ * {@link parseChargeHeaders} returns `ok(undefined)` for it: an unmetered health
29
29
  * endpoint behind the same client must not become an error. A response carrying
30
30
  * *some* of them is a malformed metered response and is an `err`, because the
31
31
  * alternative is a client that silently records a charge against the wrong Asset
@@ -37,7 +37,7 @@
37
37
  * decimals, so `10_000` is one cent, and an Open Tab routinely exceeds the range
38
38
  * a float represents exactly. `Number.parseInt` would round a large Open Tab into
39
39
  * something that still looks plausible, which is worse than failing. The grammar
40
- * is deliberately narrow, `/^[0-9]+$/`, so `1e6`, `1.0`, `1_000`, `+1`, `-1`,
40
+ * is deliberately narrow (`/^[0-9]+$/`), so `1e6`, `1.0`, `1_000`, `+1`, `-1`,
41
41
  * `0x10`, and `1,000` are all rejected rather than coerced.
42
42
  *
43
43
  * **3. `Tab-Charge-Asset` carries the chain id and the Asset address and nothing
@@ -49,7 +49,7 @@
49
49
  *
50
50
  * **4. The chain id is bounded as a `uint64` and not narrowed to Monad's two
51
51
  * networks.** Refusing an unknown chain id here would close a set the
52
- * payment-strategy seam deliberately leaves open (R23.6): a strategy settling on a
52
+ * payment-strategy seam deliberately leaves open: a strategy settling on a
53
53
  * network this release has never heard of should still be able to read its own
54
54
  * charge headers.
55
55
  *
@@ -59,12 +59,10 @@
59
59
  * client that reports two Open Tabs where there is one. A `bytes32` word has no
60
60
  * checksum convention to normalise, so it is carried through byte-for-byte.
61
61
  *
62
- * A `bytes32` tool key is usually a short name right-padded with zero bytes -
63
- * `0x7461622e64656d6f…` is `tab.demo`, but nothing
64
- * here decodes it. The key is what `ServiceRegistry.priceOf` is keyed on, and it
65
- * is carried as the word it is so it round-trips into a contract call unchanged.
66
- *
67
- * Requirements: 23.2, 21.5
62
+ * A `bytes32` tool key is usually a short name right-padded with zero bytes
63
+ * (`0x7461622e64656d6f…` is `tab.demo`), but nothing here decodes it. The key
64
+ * is what `ServiceRegistry.priceOf` is keyed on, and it is carried as the word it
65
+ * is so it round-trips into a contract call unchanged.
68
66
  */
69
67
  import { UINT64_MAX, isAddress, isBytes32, ok, } from "../_shared/index.js";
70
68
  import { validationError } from "../errors.js";
@@ -1 +1 @@
1
- {"version":3,"file":"headers.js","sourceRoot":"","sources":["../../src/http/headers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Tab HTTP header contract, and the only parser and formatter for it.\n *\n * This module is the reconciliation point between the two halves of the wire\n * protocol: the client wrapper in `client-402.ts` (R23.2) reads these headers off\n * a Service response, and the server-side post-paid plugin writes them. Both\n * halves go through the functions here rather than through their own string\n * handling, so a disagreement about a format is a compile or test failure in one\n * file instead of a silent mis-parse in production.\n *\n * ## The contract\n *\n * | Header | Direction | Required | Value format |\n * | --- | --- | --- | --- |\n * | `Tab-Charge-Amount` | response | yes, within the block | decimal integer Asset base units, no sign, no separators, no exponent |\n * | `Tab-Charge-Asset` | response | yes, within the block | `<chainId>:<address>`: the decimal EVM chain id, a colon, then a `0x` 20-byte address |\n * | `Tab-Charge-Service` | response | yes, within the block | `0x` 32-byte word: the `serviceId` |\n * | `Tab-Charge-Tool` | response | yes, within the block | `0x` 32-byte word: the `bytes32` tool key from the applied price list |\n * | `Tab-Open-Tab` | response | yes, within the block | decimal integer base units: the Open Tab for that Agent, Service, and Asset after this call |\n * | `Tab-Headroom` | response | yes, within the block | decimal integer base units: headroom remaining for that Agent and Asset |\n * | `Tab-Agent` | request | yes on a metered call | `0x` 20-byte address: the Agent's Monad address, its identity on the rail |\n * | `Tab-Authorisation` | request | optional | `0x` 32-byte word: the `authKey` the Service should meter against |\n *\n * ## Five decisions the table does not show, each of which 15.3 must match\n *\n * **1. The six response headers are one all-or-nothing block.** A response\n * carrying none of them is simply not a metered response, and\n * {@link parseChargeHeaders} returns `ok(undefined)` for it, an unmetered health\n * endpoint behind the same client must not become an error. A response carrying\n * *some* of them is a malformed metered response and is an `err`, because the\n * alternative is a client that silently records a charge against the wrong Asset\n * or against no Asset at all. There is no partial block and no default value: a\n * missing `Tab-Headroom` does not mean zero headroom.\n *\n * **2. Every amount is an integer count of Asset base units, parsed to\n * `bigint`.** Never a `number`, never a decimal, never a rate. USDC is 6\n * decimals, so `10_000` is one cent, and an Open Tab routinely exceeds the range\n * a float represents exactly. `Number.parseInt` would round a large Open Tab into\n * something that still looks plausible, which is worse than failing. The grammar\n * is deliberately narrow, `/^[0-9]+$/`, so `1e6`, `1.0`, `1_000`, `+1`, `-1`,\n * `0x10`, and `1,000` are all rejected rather than coerced.\n *\n * **3. `Tab-Charge-Asset` carries the chain id and the Asset address and nothing\n * else.** Decimals and symbol are deliberately absent: they are registry facts,\n * not per-call facts, and a Service that could restate an Asset's decimals on\n * every response could restate what a base unit means. So the parsed\n * {@link ChargedAsset} is a two-field reference rather than an `AssetRef`, and a\n * caller that needs decimals resolves them from its own configuration.\n *\n * **4. The chain id is bounded as a `uint64` and not narrowed to Monad's two\n * networks.** Refusing an unknown chain id here would close a set the\n * payment-strategy seam deliberately leaves open (R23.6): a strategy settling on a\n * network this release has never heard of should still be able to read its own\n * charge headers.\n *\n * **5. The Asset address is lower-cased on parse, and `serviceId` and the tool\n * key are not.** An address arrives checksummed from one source and lower-case\n * from another, and two spellings of one Asset in a ledger keyed by Asset is a\n * client that reports two Open Tabs where there is one. A `bytes32` word has no\n * checksum convention to normalise, so it is carried through byte-for-byte.\n *\n * A `bytes32` tool key is usually a short name right-padded with zero bytes -\n * `0x7461622e64656d6f…` is `tab.demo`, but nothing\n * here decodes it. The key is what `ServiceRegistry.priceOf` is keyed on, and it\n * is carried as the word it is so it round-trips into a contract call unchanged.\n *\n * Requirements: 23.2, 21.5\n */\n\nimport {\n UINT64_MAX,\n isAddress,\n isBytes32,\n ok,\n type Address,\n type Bytes32,\n type Result,\n} from \"../_shared/index.js\";\nimport { validationError } from \"../errors.js\";\n\n/** Every Tab header name, in the casing this SDK writes. */\nexport const TAB_HEADER = {\n chargeAmount: \"Tab-Charge-Amount\",\n chargeAsset: \"Tab-Charge-Asset\",\n chargeService: \"Tab-Charge-Service\",\n chargeTool: \"Tab-Charge-Tool\",\n openTab: \"Tab-Open-Tab\",\n headroom: \"Tab-Headroom\",\n agent: \"Tab-Agent\",\n authorisation: \"Tab-Authorisation\",\n} as const;\n\n/**\n * The six response headers that form the charge block, all six required whenever\n * any one of them is present.\n */\nexport const CHARGE_RESPONSE_HEADERS = [\n TAB_HEADER.chargeAmount,\n TAB_HEADER.chargeAsset,\n TAB_HEADER.chargeService,\n TAB_HEADER.chargeTool,\n TAB_HEADER.openTab,\n TAB_HEADER.headroom,\n] as const;\n\n/**\n * The Asset a charge is denominated in, exactly as `Tab-Charge-Asset` carries it:\n * a chain id and an address, with no decimals and no symbol.\n */\nexport interface ChargedAsset {\n /** The EVM chain id the Asset lives on: 143 for Monad Mainnet, 10143 for Monad Testnet. */\n readonly chainId: bigint;\n /** Lower-cased on parse, so one Asset has one spelling in a ledger keyed by it. */\n readonly address: Address;\n}\n\n/** One decoded charge block: what the Service says this call cost and what it left. */\nexport interface ChargeBlock {\n /** Integer Asset base units for this call. */\n readonly amount: bigint;\n readonly asset: ChargedAsset;\n readonly serviceId: Bytes32;\n /** The `bytes32` tool key from the applied price list. */\n readonly tool: Bytes32;\n /** The Open Tab for this Agent, Service, and Asset after this call. */\n readonly openTab: bigint;\n /** Headroom remaining for this Agent and Asset. */\n readonly headroom: bigint;\n}\n\n/**\n * Anything that answers a case-insensitive header lookup. A `Headers` instance\n * satisfies it, and so does {@link headerReaderOf} over a plain object.\n */\nexport interface HeaderReader {\n get(name: string): string | null | undefined;\n}\n\n/** A header bag as a framework hands one over: values, or repeated values. */\nexport type HeaderRecord = Readonly<Record<string, string | readonly string[] | undefined>>;\n\n/** The registry key for a charged Asset: `${chainId}:${address}`, lower-cased. */\nexport const chargedAssetKey = (asset: ChargedAsset): string =>\n `${asset.chainId.toString(10)}:${asset.address.toLowerCase()}`;\n\n/** True when both refs name the same Asset on the same chain, spelling aside. */\nexport const sameChargedAsset = (a: ChargedAsset, b: ChargedAsset): boolean =>\n chargedAssetKey(a) === chargedAssetKey(b);\n\n/**\n * Wraps a plain header object as a {@link HeaderReader}, matching names\n * case-insensitively.\n *\n * Repeated values are joined with `, ` rather than resolved to one of them. Every\n * Tab header is single-valued, so a repeat is a bug on the emitting side, and\n * joining makes it fail the format check loudly instead of picking a winner.\n */\nexport function headerReaderOf(source: HeaderReader | HeaderRecord): HeaderReader {\n if (typeof (source as HeaderReader).get === \"function\") return source as HeaderReader;\n const indexed = new Map<string, string>();\n for (const [name, value] of Object.entries(source as HeaderRecord)) {\n if (value === undefined) continue;\n indexed.set(name.toLowerCase(), Array.isArray(value) ? value.join(\", \") : (value as string));\n }\n return { get: (name) => indexed.get(name.toLowerCase()) ?? null };\n}\n\n/**\n * Parses a decimal integer count of Asset base units.\n *\n * `bigint` because base units are exact integers of arbitrary size, and a narrow\n * grammar because every rejected spelling is a spelling that would otherwise be\n * silently rounded or silently truncated.\n */\nexport function parseBaseUnits(raw: string, header: string, code: string): Result<bigint> {\n const value = raw.trim();\n if (value.length === 0) {\n return validationError(code, `${header} is empty; it must carry a decimal integer of base units`, {\n details: { header },\n });\n }\n if (!/^[0-9]+$/.test(value)) {\n return validationError(\n code,\n `${header} carries \\`${value}\\`, which is not a decimal integer of base units; no sign, separator, decimal point, exponent, or 0x prefix is accepted`,\n { details: { header, value } },\n );\n }\n return ok(BigInt(value));\n}\n\n/** Renders `Tab-Charge-Asset`: `<chainId>:<address>`. */\nexport const formatChargedAsset = (asset: ChargedAsset): string =>\n `${asset.chainId.toString(10)}:${asset.address.toLowerCase()}`;\n\n/** Parses `Tab-Charge-Asset`. */\nexport function parseChargedAsset(raw: string): Result<ChargedAsset> {\n const value = raw.trim();\n const parts = value.split(\":\");\n const [chainIdPart, addressPart] = parts;\n if (parts.length !== 2 || chainIdPart === undefined || addressPart === undefined) {\n return validationError(\n \"CHARGE_ASSET_INVALID\",\n `${TAB_HEADER.chargeAsset} carries \\`${value}\\`; it must be exactly \\`<chainId>:<address>\\``,\n { details: { header: TAB_HEADER.chargeAsset, value } },\n );\n }\n const chainId = parseBaseUnits(chainIdPart, `${TAB_HEADER.chargeAsset} chainId`, \"CHARGE_ASSET_INVALID\");\n if (!chainId.ok) return chainId;\n if (chainId.value > UINT64_MAX) {\n return validationError(\n \"CHARGE_ASSET_INVALID\",\n `${TAB_HEADER.chargeAsset} names chain id ${chainId.value.toString(10)}, which exceeds uint64`,\n { details: { header: TAB_HEADER.chargeAsset, value } },\n );\n }\n const address = addressPart.trim();\n if (!isAddress(address)) {\n return validationError(\n \"CHARGE_ASSET_INVALID\",\n `${TAB_HEADER.chargeAsset} names \\`${address}\\` as its Asset, which is not a 20-byte 0x address`,\n { details: { header: TAB_HEADER.chargeAsset, value } },\n );\n }\n return ok({ chainId: chainId.value, address: address.toLowerCase() as Address });\n}\n\n/**\n * Reads the charge block off a response.\n *\n * Three outcomes, and the middle one is the reason this returns\n * `Result<ChargeBlock | undefined>` rather than `Result<ChargeBlock>`:\n *\n * - all six headers present and well-formed, `ok(block)`;\n * - none of the six present, `ok(undefined)`, an unmetered response;\n * - some present, or one malformed, `err`, because a partial block cannot be\n * completed by guessing and a zero is not a safe stand-in for an absent amount.\n */\nexport function parseChargeHeaders(\n source: HeaderReader | HeaderRecord,\n): Result<ChargeBlock | undefined> {\n const headers = headerReaderOf(source);\n const raw = new Map<string, string>();\n const absent: string[] = [];\n for (const name of CHARGE_RESPONSE_HEADERS) {\n const value = headers.get(name);\n if (value === null || value === undefined || value.trim().length === 0) {\n absent.push(name);\n continue;\n }\n raw.set(name, value);\n }\n\n if (absent.length === CHARGE_RESPONSE_HEADERS.length) return ok(undefined);\n if (absent.length > 0) {\n return validationError(\n \"CHARGE_HEADERS_INCOMPLETE\",\n `the response carries part of a Tab charge block and is missing ${absent.join(\", \")}; the ${CHARGE_RESPONSE_HEADERS.length} charge headers are all-or-nothing, because a missing header is not a zero`,\n { details: { missing: absent.join(\", \"), present: [...raw.keys()].join(\", \") } },\n );\n }\n\n const amount = parseBaseUnits(\n raw.get(TAB_HEADER.chargeAmount) ?? \"\",\n TAB_HEADER.chargeAmount,\n \"CHARGE_AMOUNT_INVALID\",\n );\n if (!amount.ok) return amount;\n\n const asset = parseChargedAsset(raw.get(TAB_HEADER.chargeAsset) ?? \"\");\n if (!asset.ok) return asset;\n\n const serviceId = (raw.get(TAB_HEADER.chargeService) ?? \"\").trim();\n if (!isBytes32(serviceId)) {\n return validationError(\n \"CHARGE_SERVICE_INVALID\",\n `${TAB_HEADER.chargeService} carries \\`${serviceId}\\`, which is not a 32-byte 0x word`,\n { details: { header: TAB_HEADER.chargeService, value: serviceId } },\n );\n }\n\n const tool = (raw.get(TAB_HEADER.chargeTool) ?? \"\").trim();\n if (!isBytes32(tool)) {\n return validationError(\n \"CHARGE_TOOL_INVALID\",\n `${TAB_HEADER.chargeTool} carries \\`${tool}\\`, which is not a 32-byte 0x word; the tool key is the bytes32 the price list is keyed on, not its decoded name`,\n { details: { header: TAB_HEADER.chargeTool, value: tool } },\n );\n }\n\n const openTab = parseBaseUnits(\n raw.get(TAB_HEADER.openTab) ?? \"\",\n TAB_HEADER.openTab,\n \"OPEN_TAB_INVALID\",\n );\n if (!openTab.ok) return openTab;\n\n const headroom = parseBaseUnits(\n raw.get(TAB_HEADER.headroom) ?? \"\",\n TAB_HEADER.headroom,\n \"HEADROOM_INVALID\",\n );\n if (!headroom.ok) return headroom;\n\n return ok({\n amount: amount.value,\n asset: asset.value,\n serviceId,\n tool,\n openTab: openTab.value,\n headroom: headroom.value,\n });\n}\n\n/**\n * Renders a charge block as the six response headers.\n *\n * Exported for the emitting side, so the server plugin writes what this module's\n * parser reads rather than what a second string-building routine believes. The\n * round trip through {@link parseChargeHeaders} is asserted in the tests.\n */\nexport function formatChargeHeaders(block: ChargeBlock): Result<Record<string, string>> {\n for (const [label, value, code] of [\n [TAB_HEADER.chargeAmount, block.amount, \"CHARGE_AMOUNT_INVALID\"],\n [TAB_HEADER.openTab, block.openTab, \"OPEN_TAB_INVALID\"],\n [TAB_HEADER.headroom, block.headroom, \"HEADROOM_INVALID\"],\n ] as const) {\n if (typeof value !== \"bigint\") {\n return validationError(code, `${label} must be a bigint count of base units, never a number`, {\n details: { header: label },\n });\n }\n if (value < 0n) {\n return validationError(code, `${label} must not be negative, received ${value.toString(10)}`, {\n details: { header: label },\n });\n }\n }\n if (typeof block.asset.chainId !== \"bigint\" || block.asset.chainId < 0n) {\n return validationError(\n \"CHARGE_ASSET_INVALID\",\n `${TAB_HEADER.chargeAsset} needs a non-negative bigint chain id`,\n );\n }\n if (block.asset.chainId > UINT64_MAX) {\n return validationError(\n \"CHARGE_ASSET_INVALID\",\n `${TAB_HEADER.chargeAsset} chain id exceeds uint64: ${block.asset.chainId.toString(10)}`,\n );\n }\n if (!isAddress(block.asset.address)) {\n return validationError(\n \"CHARGE_ASSET_INVALID\",\n `${TAB_HEADER.chargeAsset} needs a 20-byte 0x Asset address`,\n );\n }\n if (!isBytes32(block.serviceId)) {\n return validationError(\"CHARGE_SERVICE_INVALID\", `${TAB_HEADER.chargeService} needs a 32-byte 0x word`);\n }\n if (!isBytes32(block.tool)) {\n return validationError(\"CHARGE_TOOL_INVALID\", `${TAB_HEADER.chargeTool} needs a 32-byte 0x word`);\n }\n return ok({\n [TAB_HEADER.chargeAmount]: block.amount.toString(10),\n [TAB_HEADER.chargeAsset]: formatChargedAsset(block.asset),\n [TAB_HEADER.chargeService]: block.serviceId,\n [TAB_HEADER.chargeTool]: block.tool,\n [TAB_HEADER.openTab]: block.openTab.toString(10),\n [TAB_HEADER.headroom]: block.headroom.toString(10),\n });\n}\n\n/**\n * Builds the request headers that identify the Agent being metered.\n *\n * `Tab-Agent` is the Agent's Monad address, its identity on the rail, and\n * the only thing that tells a Service which tab to charge. `Tab-Authorisation` is\n * optional here because the authKey is a per-Service arrangement a caller may not\n * hold; a Service that requires one answers 403 through the ordinary error path\n * rather than through this function.\n */\nexport function agentRequestHeaders(\n agent: Address,\n authorisation?: Bytes32,\n): Result<Record<string, string>> {\n if (!isAddress(agent)) {\n return validationError(\n \"AGENT_INVALID\",\n `${TAB_HEADER.agent} must be the Agent's 20-byte 0x Monad address, received \\`${String(agent)}\\``,\n );\n }\n if (authorisation !== undefined && !isBytes32(authorisation)) {\n return validationError(\n \"AUTHORISATION_INVALID\",\n `${TAB_HEADER.authorisation} must be a 32-byte 0x authKey, received \\`${String(authorisation)}\\``,\n );\n }\n return ok({\n [TAB_HEADER.agent]: agent,\n ...(authorisation === undefined ? {} : { [TAB_HEADER.authorisation]: authorisation }),\n });\n}\n"]}
1
+ {"version":3,"file":"headers.js","sourceRoot":"","sources":["../../src/http/headers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Tab HTTP header contract, and the only parser and formatter for it.\n *\n * This module is the reconciliation point between the two halves of the wire\n * protocol: the client wrapper in `client-402.ts` reads these headers off\n * a Service response, and the server-side post-paid plugin writes them. Both\n * halves go through the functions here rather than through their own string\n * handling, so a disagreement about a format is a compile or test failure in one\n * file instead of a silent mis-parse in production.\n *\n * ## The contract\n *\n * | Header | Direction | Required | Value format |\n * | --- | --- | --- | --- |\n * | `Tab-Charge-Amount` | response | yes, within the block | decimal integer Asset base units, no sign, no separators, no exponent |\n * | `Tab-Charge-Asset` | response | yes, within the block | `<chainId>:<address>`: the decimal EVM chain id, a colon, then a `0x` 20-byte address |\n * | `Tab-Charge-Service` | response | yes, within the block | `0x` 32-byte word: the `serviceId` |\n * | `Tab-Charge-Tool` | response | yes, within the block | `0x` 32-byte word: the `bytes32` tool key from the applied price list |\n * | `Tab-Open-Tab` | response | yes, within the block | decimal integer base units: the Open Tab for that Agent, Service, and Asset after this call |\n * | `Tab-Headroom` | response | yes, within the block | decimal integer base units: headroom remaining for that Agent and Asset |\n * | `Tab-Agent` | request | yes on a metered call | `0x` 20-byte address: the Agent's Monad address, its identity on the rail |\n * | `Tab-Authorisation` | request | optional | `0x` 32-byte word: the `authKey` the Service should meter against |\n *\n * ## Five decisions the table does not show, which both halves hold to\n *\n * **1. The six response headers are one all-or-nothing block.** A response\n * carrying none of them is simply not a metered response, and\n * {@link parseChargeHeaders} returns `ok(undefined)` for it: an unmetered health\n * endpoint behind the same client must not become an error. A response carrying\n * *some* of them is a malformed metered response and is an `err`, because the\n * alternative is a client that silently records a charge against the wrong Asset\n * or against no Asset at all. There is no partial block and no default value: a\n * missing `Tab-Headroom` does not mean zero headroom.\n *\n * **2. Every amount is an integer count of Asset base units, parsed to\n * `bigint`.** Never a `number`, never a decimal, never a rate. USDC is 6\n * decimals, so `10_000` is one cent, and an Open Tab routinely exceeds the range\n * a float represents exactly. `Number.parseInt` would round a large Open Tab into\n * something that still looks plausible, which is worse than failing. The grammar\n * is deliberately narrow (`/^[0-9]+$/`), so `1e6`, `1.0`, `1_000`, `+1`, `-1`,\n * `0x10`, and `1,000` are all rejected rather than coerced.\n *\n * **3. `Tab-Charge-Asset` carries the chain id and the Asset address and nothing\n * else.** Decimals and symbol are deliberately absent: they are registry facts,\n * not per-call facts, and a Service that could restate an Asset's decimals on\n * every response could restate what a base unit means. So the parsed\n * {@link ChargedAsset} is a two-field reference rather than an `AssetRef`, and a\n * caller that needs decimals resolves them from its own configuration.\n *\n * **4. The chain id is bounded as a `uint64` and not narrowed to Monad's two\n * networks.** Refusing an unknown chain id here would close a set the\n * payment-strategy seam deliberately leaves open: a strategy settling on a\n * network this release has never heard of should still be able to read its own\n * charge headers.\n *\n * **5. The Asset address is lower-cased on parse, and `serviceId` and the tool\n * key are not.** An address arrives checksummed from one source and lower-case\n * from another, and two spellings of one Asset in a ledger keyed by Asset is a\n * client that reports two Open Tabs where there is one. A `bytes32` word has no\n * checksum convention to normalise, so it is carried through byte-for-byte.\n *\n * A `bytes32` tool key is usually a short name right-padded with zero bytes\n * (`0x7461622e64656d6f…` is `tab.demo`), but nothing here decodes it. The key\n * is what `ServiceRegistry.priceOf` is keyed on, and it is carried as the word it\n * is so it round-trips into a contract call unchanged.\n */\n\nimport {\n UINT64_MAX,\n isAddress,\n isBytes32,\n ok,\n type Address,\n type Bytes32,\n type Result,\n} from \"../_shared/index.js\";\nimport { validationError } from \"../errors.js\";\n\n/** Every Tab header name, in the casing this SDK writes. */\nexport const TAB_HEADER = {\n chargeAmount: \"Tab-Charge-Amount\",\n chargeAsset: \"Tab-Charge-Asset\",\n chargeService: \"Tab-Charge-Service\",\n chargeTool: \"Tab-Charge-Tool\",\n openTab: \"Tab-Open-Tab\",\n headroom: \"Tab-Headroom\",\n agent: \"Tab-Agent\",\n authorisation: \"Tab-Authorisation\",\n} as const;\n\n/**\n * The six response headers that form the charge block, all six required whenever\n * any one of them is present.\n */\nexport const CHARGE_RESPONSE_HEADERS = [\n TAB_HEADER.chargeAmount,\n TAB_HEADER.chargeAsset,\n TAB_HEADER.chargeService,\n TAB_HEADER.chargeTool,\n TAB_HEADER.openTab,\n TAB_HEADER.headroom,\n] as const;\n\n/**\n * The Asset a charge is denominated in, exactly as `Tab-Charge-Asset` carries it:\n * a chain id and an address, with no decimals and no symbol.\n */\nexport interface ChargedAsset {\n /** The EVM chain id the Asset lives on: 143 for Monad Mainnet, 10143 for Monad Testnet. */\n readonly chainId: bigint;\n /** Lower-cased on parse, so one Asset has one spelling in a ledger keyed by it. */\n readonly address: Address;\n}\n\n/** One decoded charge block: what the Service says this call cost and what it left. */\nexport interface ChargeBlock {\n /** Integer Asset base units for this call. */\n readonly amount: bigint;\n readonly asset: ChargedAsset;\n readonly serviceId: Bytes32;\n /** The `bytes32` tool key from the applied price list. */\n readonly tool: Bytes32;\n /** The Open Tab for this Agent, Service, and Asset after this call. */\n readonly openTab: bigint;\n /** Headroom remaining for this Agent and Asset. */\n readonly headroom: bigint;\n}\n\n/**\n * Anything that answers a case-insensitive header lookup. A `Headers` instance\n * satisfies it, and so does {@link headerReaderOf} over a plain object.\n */\nexport interface HeaderReader {\n get(name: string): string | null | undefined;\n}\n\n/** A header bag as a framework hands one over: values, or repeated values. */\nexport type HeaderRecord = Readonly<Record<string, string | readonly string[] | undefined>>;\n\n/** The registry key for a charged Asset: `${chainId}:${address}`, lower-cased. */\nexport const chargedAssetKey = (asset: ChargedAsset): string =>\n `${asset.chainId.toString(10)}:${asset.address.toLowerCase()}`;\n\n/** True when both refs name the same Asset on the same chain, spelling aside. */\nexport const sameChargedAsset = (a: ChargedAsset, b: ChargedAsset): boolean =>\n chargedAssetKey(a) === chargedAssetKey(b);\n\n/**\n * Wraps a plain header object as a {@link HeaderReader}, matching names\n * case-insensitively.\n *\n * Repeated values are joined with `, ` rather than resolved to one of them. Every\n * Tab header is single-valued, so a repeat is a bug on the emitting side, and\n * joining makes it fail the format check loudly instead of picking a winner.\n */\nexport function headerReaderOf(source: HeaderReader | HeaderRecord): HeaderReader {\n if (typeof (source as HeaderReader).get === \"function\") return source as HeaderReader;\n const indexed = new Map<string, string>();\n for (const [name, value] of Object.entries(source as HeaderRecord)) {\n if (value === undefined) continue;\n indexed.set(name.toLowerCase(), Array.isArray(value) ? value.join(\", \") : (value as string));\n }\n return { get: (name) => indexed.get(name.toLowerCase()) ?? null };\n}\n\n/**\n * Parses a decimal integer count of Asset base units.\n *\n * `bigint` because base units are exact integers of arbitrary size, and a narrow\n * grammar because every rejected spelling is a spelling that would otherwise be\n * silently rounded or silently truncated.\n */\nexport function parseBaseUnits(raw: string, header: string, code: string): Result<bigint> {\n const value = raw.trim();\n if (value.length === 0) {\n return validationError(code, `${header} is empty; it must carry a decimal integer of base units`, {\n details: { header },\n });\n }\n if (!/^[0-9]+$/.test(value)) {\n return validationError(\n code,\n `${header} carries \\`${value}\\`, which is not a decimal integer of base units; no sign, separator, decimal point, exponent, or 0x prefix is accepted`,\n { details: { header, value } },\n );\n }\n return ok(BigInt(value));\n}\n\n/** Renders `Tab-Charge-Asset`: `<chainId>:<address>`. */\nexport const formatChargedAsset = (asset: ChargedAsset): string =>\n `${asset.chainId.toString(10)}:${asset.address.toLowerCase()}`;\n\n/** Parses `Tab-Charge-Asset`. */\nexport function parseChargedAsset(raw: string): Result<ChargedAsset> {\n const value = raw.trim();\n const parts = value.split(\":\");\n const [chainIdPart, addressPart] = parts;\n if (parts.length !== 2 || chainIdPart === undefined || addressPart === undefined) {\n return validationError(\n \"CHARGE_ASSET_INVALID\",\n `${TAB_HEADER.chargeAsset} carries \\`${value}\\`; it must be exactly \\`<chainId>:<address>\\``,\n { details: { header: TAB_HEADER.chargeAsset, value } },\n );\n }\n const chainId = parseBaseUnits(chainIdPart, `${TAB_HEADER.chargeAsset} chainId`, \"CHARGE_ASSET_INVALID\");\n if (!chainId.ok) return chainId;\n if (chainId.value > UINT64_MAX) {\n return validationError(\n \"CHARGE_ASSET_INVALID\",\n `${TAB_HEADER.chargeAsset} names chain id ${chainId.value.toString(10)}, which exceeds uint64`,\n { details: { header: TAB_HEADER.chargeAsset, value } },\n );\n }\n const address = addressPart.trim();\n if (!isAddress(address)) {\n return validationError(\n \"CHARGE_ASSET_INVALID\",\n `${TAB_HEADER.chargeAsset} names \\`${address}\\` as its Asset, which is not a 20-byte 0x address`,\n { details: { header: TAB_HEADER.chargeAsset, value } },\n );\n }\n return ok({ chainId: chainId.value, address: address.toLowerCase() as Address });\n}\n\n/**\n * Reads the charge block off a response.\n *\n * Three outcomes, and the middle one is the reason this returns\n * `Result<ChargeBlock | undefined>` rather than `Result<ChargeBlock>`:\n *\n * - all six headers present and well-formed, `ok(block)`;\n * - none of the six present, `ok(undefined)`, an unmetered response;\n * - some present, or one malformed, `err`, because a partial block cannot be\n * completed by guessing and a zero is not a safe stand-in for an absent amount.\n */\nexport function parseChargeHeaders(\n source: HeaderReader | HeaderRecord,\n): Result<ChargeBlock | undefined> {\n const headers = headerReaderOf(source);\n const raw = new Map<string, string>();\n const absent: string[] = [];\n for (const name of CHARGE_RESPONSE_HEADERS) {\n const value = headers.get(name);\n if (value === null || value === undefined || value.trim().length === 0) {\n absent.push(name);\n continue;\n }\n raw.set(name, value);\n }\n\n if (absent.length === CHARGE_RESPONSE_HEADERS.length) return ok(undefined);\n if (absent.length > 0) {\n return validationError(\n \"CHARGE_HEADERS_INCOMPLETE\",\n `the response carries part of a Tab charge block and is missing ${absent.join(\", \")}; the ${CHARGE_RESPONSE_HEADERS.length} charge headers are all-or-nothing, because a missing header is not a zero`,\n { details: { missing: absent.join(\", \"), present: [...raw.keys()].join(\", \") } },\n );\n }\n\n const amount = parseBaseUnits(\n raw.get(TAB_HEADER.chargeAmount) ?? \"\",\n TAB_HEADER.chargeAmount,\n \"CHARGE_AMOUNT_INVALID\",\n );\n if (!amount.ok) return amount;\n\n const asset = parseChargedAsset(raw.get(TAB_HEADER.chargeAsset) ?? \"\");\n if (!asset.ok) return asset;\n\n const serviceId = (raw.get(TAB_HEADER.chargeService) ?? \"\").trim();\n if (!isBytes32(serviceId)) {\n return validationError(\n \"CHARGE_SERVICE_INVALID\",\n `${TAB_HEADER.chargeService} carries \\`${serviceId}\\`, which is not a 32-byte 0x word`,\n { details: { header: TAB_HEADER.chargeService, value: serviceId } },\n );\n }\n\n const tool = (raw.get(TAB_HEADER.chargeTool) ?? \"\").trim();\n if (!isBytes32(tool)) {\n return validationError(\n \"CHARGE_TOOL_INVALID\",\n `${TAB_HEADER.chargeTool} carries \\`${tool}\\`, which is not a 32-byte 0x word; the tool key is the bytes32 the price list is keyed on, not its decoded name`,\n { details: { header: TAB_HEADER.chargeTool, value: tool } },\n );\n }\n\n const openTab = parseBaseUnits(\n raw.get(TAB_HEADER.openTab) ?? \"\",\n TAB_HEADER.openTab,\n \"OPEN_TAB_INVALID\",\n );\n if (!openTab.ok) return openTab;\n\n const headroom = parseBaseUnits(\n raw.get(TAB_HEADER.headroom) ?? \"\",\n TAB_HEADER.headroom,\n \"HEADROOM_INVALID\",\n );\n if (!headroom.ok) return headroom;\n\n return ok({\n amount: amount.value,\n asset: asset.value,\n serviceId,\n tool,\n openTab: openTab.value,\n headroom: headroom.value,\n });\n}\n\n/**\n * Renders a charge block as the six response headers.\n *\n * Exported for the emitting side, so the server plugin writes what this module's\n * parser reads rather than what a second string-building routine believes. The\n * round trip through {@link parseChargeHeaders} is asserted in the tests.\n */\nexport function formatChargeHeaders(block: ChargeBlock): Result<Record<string, string>> {\n for (const [label, value, code] of [\n [TAB_HEADER.chargeAmount, block.amount, \"CHARGE_AMOUNT_INVALID\"],\n [TAB_HEADER.openTab, block.openTab, \"OPEN_TAB_INVALID\"],\n [TAB_HEADER.headroom, block.headroom, \"HEADROOM_INVALID\"],\n ] as const) {\n if (typeof value !== \"bigint\") {\n return validationError(code, `${label} must be a bigint count of base units, never a number`, {\n details: { header: label },\n });\n }\n if (value < 0n) {\n return validationError(code, `${label} must not be negative, received ${value.toString(10)}`, {\n details: { header: label },\n });\n }\n }\n if (typeof block.asset.chainId !== \"bigint\" || block.asset.chainId < 0n) {\n return validationError(\n \"CHARGE_ASSET_INVALID\",\n `${TAB_HEADER.chargeAsset} needs a non-negative bigint chain id`,\n );\n }\n if (block.asset.chainId > UINT64_MAX) {\n return validationError(\n \"CHARGE_ASSET_INVALID\",\n `${TAB_HEADER.chargeAsset} chain id exceeds uint64: ${block.asset.chainId.toString(10)}`,\n );\n }\n if (!isAddress(block.asset.address)) {\n return validationError(\n \"CHARGE_ASSET_INVALID\",\n `${TAB_HEADER.chargeAsset} needs a 20-byte 0x Asset address`,\n );\n }\n if (!isBytes32(block.serviceId)) {\n return validationError(\"CHARGE_SERVICE_INVALID\", `${TAB_HEADER.chargeService} needs a 32-byte 0x word`);\n }\n if (!isBytes32(block.tool)) {\n return validationError(\"CHARGE_TOOL_INVALID\", `${TAB_HEADER.chargeTool} needs a 32-byte 0x word`);\n }\n return ok({\n [TAB_HEADER.chargeAmount]: block.amount.toString(10),\n [TAB_HEADER.chargeAsset]: formatChargedAsset(block.asset),\n [TAB_HEADER.chargeService]: block.serviceId,\n [TAB_HEADER.chargeTool]: block.tool,\n [TAB_HEADER.openTab]: block.openTab.toString(10),\n [TAB_HEADER.headroom]: block.headroom.toString(10),\n });\n}\n\n/**\n * Builds the request headers that identify the Agent being metered.\n *\n * `Tab-Agent` is the Agent's Monad address, its identity on the rail, and\n * the only thing that tells a Service which tab to charge. `Tab-Authorisation` is\n * optional here because the authKey is a per-Service arrangement a caller may not\n * hold; a Service that requires one answers 403 through the ordinary error path\n * rather than through this function.\n */\nexport function agentRequestHeaders(\n agent: Address,\n authorisation?: Bytes32,\n): Result<Record<string, string>> {\n if (!isAddress(agent)) {\n return validationError(\n \"AGENT_INVALID\",\n `${TAB_HEADER.agent} must be the Agent's 20-byte 0x Monad address, received \\`${String(agent)}\\``,\n );\n }\n if (authorisation !== undefined && !isBytes32(authorisation)) {\n return validationError(\n \"AUTHORISATION_INVALID\",\n `${TAB_HEADER.authorisation} must be a 32-byte 0x authKey, received \\`${String(authorisation)}\\``,\n );\n }\n return ok({\n [TAB_HEADER.agent]: agent,\n ...(authorisation === undefined ? {} : { [TAB_HEADER.authorisation]: authorisation }),\n });\n}\n"]}
@@ -6,8 +6,6 @@
6
6
  * format, and both directions go through it, the client here parses with it, and
7
7
  * the server-side post-paid plugin formats with it, so the two halves cannot
8
8
  * drift apart without a test failing.
9
- *
10
- * Requirements: 23.2, 21.5
11
9
  */
12
10
  export * from "./headers.js";
13
11
  export * from "./client-402.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC"}
@@ -6,8 +6,6 @@
6
6
  * format, and both directions go through it, the client here parses with it, and
7
7
  * the server-side post-paid plugin formats with it, so the two halves cannot
8
8
  * drift apart without a test failing.
9
- *
10
- * Requirements: 23.2, 21.5
11
9
  */
12
10
  export * from "./headers.js";
13
11
  export * from "./client-402.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC","sourcesContent":["/**\n * The HTTP surface of the SDK: the header contract, and the post-paid 402 client\n * that reads it.\n *\n * `headers.ts` is the shared half. It is the only definition of the `Tab-*` wire\n * format, and both directions go through it, the client here parses with it, and\n * the server-side post-paid plugin formats with it, so the two halves cannot\n * drift apart without a test failing.\n *\n * Requirements: 23.2, 21.5\n */\n\nexport * from \"./headers.js\";\nexport * from \"./client-402.js\";\nexport * from \"./metering-claim.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC","sourcesContent":["/**\n * The HTTP surface of the SDK: the header contract, and the post-paid 402 client\n * that reads it.\n *\n * `headers.ts` is the shared half. It is the only definition of the `Tab-*` wire\n * format, and both directions go through it, the client here parses with it, and\n * the server-side post-paid plugin formats with it, so the two halves cannot\n * drift apart without a test failing.\n */\n\nexport * from \"./headers.js\";\nexport * from \"./client-402.js\";\nexport * from \"./metering-claim.js\";\n"]}
@@ -26,8 +26,6 @@
26
26
  * produce one digest. JSON key order is not guaranteed across
27
27
  * implementations, and a signature over a reordered object would fail for a
28
28
  * caller who did nothing wrong.
29
- *
30
- * Requirements: 12.1, 12.2, 21.5
31
29
  */
32
30
  import type { ServiceHeaderProvider } from "../payments/config.js";
33
31
  /** The headers a signed metering request carries, by who signed it. */
@@ -1 +1 @@
1
- {"version":3,"file":"metering-claim.d.ts","sourceRoot":"","sources":["../../src/http/metering-claim.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAIH,OAAO,KAAK,EAAE,qBAAqB,EAAwB,MAAM,uBAAuB,CAAC;AAEzF,uEAAuE;AACvE,eAAO,MAAM,eAAe;;;;;CAKlB,CAAC;AAEX,qDAAqD;AACrD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,qEAAqE;AACrE,wBAAgB,cAAc,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAUlE;AAED,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9B,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC/C;AAED,2GAA2G;AAC3G,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,cAAc,GAAG,SAAS,EACxC,OAAO,GAAE;IAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAAO,GAC5C,qBAAqB,CAqBvB"}
1
+ {"version":3,"file":"metering-claim.d.ts","sourceRoot":"","sources":["../../src/http/metering-claim.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH,OAAO,KAAK,EAAE,qBAAqB,EAAwB,MAAM,uBAAuB,CAAC;AAEzF,uEAAuE;AACvE,eAAO,MAAM,eAAe;;;;;CAKlB,CAAC;AAEX,qDAAqD;AACrD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,qEAAqE;AACrE,wBAAgB,cAAc,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAUlE;AAED,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9B,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC/C;AAED,2GAA2G;AAC3G,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,cAAc,GAAG,SAAS,EACxC,OAAO,GAAE;IAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAAO,GAC5C,qBAAqB,CAqBvB"}
@@ -26,8 +26,6 @@
26
26
  * produce one digest. JSON key order is not guaranteed across
27
27
  * implementations, and a signature over a reordered object would fail for a
28
28
  * caller who did nothing wrong.
29
- *
30
- * Requirements: 12.1, 12.2, 21.5
31
29
  */
32
30
  import { encodeBytes32String } from "ethers";
33
31
  /** The headers a signed metering request carries, by who signed it. */
@@ -1 +1 @@
1
- {"version":3,"file":"metering-claim.js","sourceRoot":"","sources":["../../src/http/metering-claim.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAI7C,uEAAuE;AACvE,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,iBAAiB,EAAE,wBAAwB;IAC3C,gBAAgB,EAAE,wBAAwB;IAC1C,cAAc,EAAE,qBAAqB;IACrC,aAAa,EAAE,qBAAqB;CAC5B,CAAC;AAcX,qEAAqE;AACrE,MAAM,UAAU,cAAc,CAAC,KAA2B;IACxD,OAAO;QACL,sBAAsB;QACtB,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE;QAC1B,KAAK,CAAC,IAAI;QACV,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE;QACzB,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE;QACxB,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;QACnB,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;KACvB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAQD,2GAA2G;AAC3G,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;AAC7F,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAwC,EACxC,UAA2C,EAAE;IAE7C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC9C,OAAO,KAAK,EAAE,OAA6B,EAAE,EAAE;QAC7C,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;QACxB,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,CAAC,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAC1D,IAAI,OAAO,KAAK,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE;YAAE,OAAO,EAAE,CAAC;QACvD,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,cAAc,CAAC;YAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,IAAI,EAAE,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ;YACnC,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;YAC7B,KAAK,EAAE,CAAC;YACR,QAAQ;SACT,CAAC,CAAC;QACH,OAAO;YACL,CAAC,eAAe,CAAC,cAAc,CAAC,EAAE,MAAM,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC;YAClE,CAAC,eAAe,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;SAClD,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The metering claim: what a signed metered request binds, and who may sign it.\n *\n * ## Two signers, one digest\n *\n * A metered call records a delivery on chain and spends the Service operator's\n * gas, so a metering endpoint anyone can reach must know the call was meant.\n * Two parties can say so, and the digest they sign is the same string:\n *\n * - **The operator**, from the Service's own front, which has authenticated\n * its caller however it likes. `Tab-Operator-Signature` carries it.\n * - **The Agent**, whose Open Tab the charge lands on. `Tab-Agent-Signature`\n * carries it, recovered against the address in `Tab-Agent`, so the one\n * party that pays for the call is the one that asked for it, and a\n * stranger who knows an Agent's address can put nothing on its tab.\n *\n * The digest binds the method, the path, the Agent, the tool, the unit count\n * and a timestamp. Binding the Agent and the units is the point: a signature\n * over the path alone would be a bearer token that replays against a\n * different Agent for a different amount. The timestamp bounds replay to a\n * window the gateway checks.\n *\n * ## Why it is written out and not JSON\n *\n * Newline-separated and fully ordered, so two different claims can never\n * produce one digest. JSON key order is not guaranteed across\n * implementations, and a signature over a reordered object would fail for a\n * caller who did nothing wrong.\n *\n * Requirements: 12.1, 12.2, 21.5\n */\n\nimport { encodeBytes32String } from \"ethers\";\n\nimport type { ServiceHeaderProvider, ServiceHeaderRequest } from \"../payments/config.js\";\n\n/** The headers a signed metering request carries, by who signed it. */\nexport const METERING_HEADER = {\n operatorSignature: \"Tab-Operator-Signature\",\n operatorIssuedAt: \"Tab-Operator-Issued-At\",\n agentSignature: \"Tab-Agent-Signature\",\n agentIssuedAt: \"Tab-Agent-Issued-At\",\n} as const;\n\n/** The fields a metering request signature binds. */\nexport interface MeteringRequestClaim {\n readonly method: string;\n readonly path: string;\n readonly agent: string;\n /** The 32-byte tool key the price list is keyed by, never the label. */\n readonly tool: string;\n readonly units: number;\n /** Milliseconds since the epoch, as the caller stated it. */\n readonly issuedAt: number;\n}\n\n/** The exact string a signer signs, with EIP-191 `personal_sign`. */\nexport function meteringDigest(claim: MeteringRequestClaim): string {\n return [\n \"tab-metering-request\",\n claim.method.toUpperCase(),\n claim.path,\n claim.agent.toLowerCase(),\n claim.tool.toLowerCase(),\n String(claim.units),\n String(claim.issuedAt),\n ].join(\"\\n\");\n}\n\n/** A signer that can `personal_sign`. An ethers `Wallet` satisfies it. */\nexport interface MeteringSigner {\n getAddress(): Promise<string>;\n signMessage(message: string): Promise<string>;\n}\n\n/** A tool name as the caller gave it, packed to the key the price list holds, unless it already is one. */\nexport function toolKeyOf(tool: string): string {\n return (/^0x[0-9a-fA-F]{64}$/.test(tool) ? tool : encodeBytes32String(tool)).toLowerCase();\n}\n\n/**\n * A header provider that signs every metered call as the Agent.\n *\n * Put it on a Service entry in `tab.config` and `tab_call` sends\n * `Tab-Agent-Signature` and `Tab-Agent-Issued-At` with each call, signed by\n * the key the factory returns. A factory, like the strategies, so the key is\n * built only when a call is made and every read stays keyless; one that\n * returns nothing sends the call unsigned, and a gateway that requires a\n * signature says so in its refusal.\n *\n * It signs only when the key it is given is the Agent the call is metered\n * against, because that is what the gateway recovers the signature against.\n * A key for anyone else adds nothing and the Service decides: one that\n * requires a signature refuses by name, and one that does not is unaffected.\n * That is the case where the Agent comes from somewhere other than this\n * config, such as a wallet the MetaMask Agent Wallet plugin reads, and it is\n * an honest \"this key is not that Agent\" rather than a signature that could\n * only be rejected.\n */\nexport function agentSignedMetering(\n signer: () => MeteringSigner | undefined,\n options: { readonly now?: () => number } = {},\n): ServiceHeaderProvider {\n const now = options.now ?? (() => Date.now());\n return async (request: ServiceHeaderRequest) => {\n const wallet = signer();\n if (wallet === undefined) return {};\n const address = (await wallet.getAddress()).toLowerCase();\n if (address !== request.agent.toLowerCase()) return {};\n const issuedAt = now();\n const digest = meteringDigest({\n method: request.method,\n path: new URL(request.url).pathname,\n agent: address,\n tool: toolKeyOf(request.tool),\n units: 1,\n issuedAt,\n });\n return {\n [METERING_HEADER.agentSignature]: await wallet.signMessage(digest),\n [METERING_HEADER.agentIssuedAt]: String(issuedAt),\n };\n };\n}\n"]}
1
+ {"version":3,"file":"metering-claim.js","sourceRoot":"","sources":["../../src/http/metering-claim.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAI7C,uEAAuE;AACvE,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,iBAAiB,EAAE,wBAAwB;IAC3C,gBAAgB,EAAE,wBAAwB;IAC1C,cAAc,EAAE,qBAAqB;IACrC,aAAa,EAAE,qBAAqB;CAC5B,CAAC;AAcX,qEAAqE;AACrE,MAAM,UAAU,cAAc,CAAC,KAA2B;IACxD,OAAO;QACL,sBAAsB;QACtB,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE;QAC1B,KAAK,CAAC,IAAI;QACV,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE;QACzB,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE;QACxB,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;QACnB,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;KACvB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAQD,2GAA2G;AAC3G,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;AAC7F,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAwC,EACxC,UAA2C,EAAE;IAE7C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC9C,OAAO,KAAK,EAAE,OAA6B,EAAE,EAAE;QAC7C,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;QACxB,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,CAAC,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAC1D,IAAI,OAAO,KAAK,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE;YAAE,OAAO,EAAE,CAAC;QACvD,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,cAAc,CAAC;YAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,IAAI,EAAE,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ;YACnC,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;YAC7B,KAAK,EAAE,CAAC;YACR,QAAQ;SACT,CAAC,CAAC;QACH,OAAO;YACL,CAAC,eAAe,CAAC,cAAc,CAAC,EAAE,MAAM,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC;YAClE,CAAC,eAAe,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;SAClD,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The metering claim: what a signed metered request binds, and who may sign it.\n *\n * ## Two signers, one digest\n *\n * A metered call records a delivery on chain and spends the Service operator's\n * gas, so a metering endpoint anyone can reach must know the call was meant.\n * Two parties can say so, and the digest they sign is the same string:\n *\n * - **The operator**, from the Service's own front, which has authenticated\n * its caller however it likes. `Tab-Operator-Signature` carries it.\n * - **The Agent**, whose Open Tab the charge lands on. `Tab-Agent-Signature`\n * carries it, recovered against the address in `Tab-Agent`, so the one\n * party that pays for the call is the one that asked for it, and a\n * stranger who knows an Agent's address can put nothing on its tab.\n *\n * The digest binds the method, the path, the Agent, the tool, the unit count\n * and a timestamp. Binding the Agent and the units is the point: a signature\n * over the path alone would be a bearer token that replays against a\n * different Agent for a different amount. The timestamp bounds replay to a\n * window the gateway checks.\n *\n * ## Why it is written out and not JSON\n *\n * Newline-separated and fully ordered, so two different claims can never\n * produce one digest. JSON key order is not guaranteed across\n * implementations, and a signature over a reordered object would fail for a\n * caller who did nothing wrong.\n */\n\nimport { encodeBytes32String } from \"ethers\";\n\nimport type { ServiceHeaderProvider, ServiceHeaderRequest } from \"../payments/config.js\";\n\n/** The headers a signed metering request carries, by who signed it. */\nexport const METERING_HEADER = {\n operatorSignature: \"Tab-Operator-Signature\",\n operatorIssuedAt: \"Tab-Operator-Issued-At\",\n agentSignature: \"Tab-Agent-Signature\",\n agentIssuedAt: \"Tab-Agent-Issued-At\",\n} as const;\n\n/** The fields a metering request signature binds. */\nexport interface MeteringRequestClaim {\n readonly method: string;\n readonly path: string;\n readonly agent: string;\n /** The 32-byte tool key the price list is keyed by, never the label. */\n readonly tool: string;\n readonly units: number;\n /** Milliseconds since the epoch, as the caller stated it. */\n readonly issuedAt: number;\n}\n\n/** The exact string a signer signs, with EIP-191 `personal_sign`. */\nexport function meteringDigest(claim: MeteringRequestClaim): string {\n return [\n \"tab-metering-request\",\n claim.method.toUpperCase(),\n claim.path,\n claim.agent.toLowerCase(),\n claim.tool.toLowerCase(),\n String(claim.units),\n String(claim.issuedAt),\n ].join(\"\\n\");\n}\n\n/** A signer that can `personal_sign`. An ethers `Wallet` satisfies it. */\nexport interface MeteringSigner {\n getAddress(): Promise<string>;\n signMessage(message: string): Promise<string>;\n}\n\n/** A tool name as the caller gave it, packed to the key the price list holds, unless it already is one. */\nexport function toolKeyOf(tool: string): string {\n return (/^0x[0-9a-fA-F]{64}$/.test(tool) ? tool : encodeBytes32String(tool)).toLowerCase();\n}\n\n/**\n * A header provider that signs every metered call as the Agent.\n *\n * Put it on a Service entry in `tab.config` and `tab_call` sends\n * `Tab-Agent-Signature` and `Tab-Agent-Issued-At` with each call, signed by\n * the key the factory returns. A factory, like the strategies, so the key is\n * built only when a call is made and every read stays keyless; one that\n * returns nothing sends the call unsigned, and a gateway that requires a\n * signature says so in its refusal.\n *\n * It signs only when the key it is given is the Agent the call is metered\n * against, because that is what the gateway recovers the signature against.\n * A key for anyone else adds nothing and the Service decides: one that\n * requires a signature refuses by name, and one that does not is unaffected.\n * That is the case where the Agent comes from somewhere other than this\n * config, such as a wallet the MetaMask Agent Wallet plugin reads, and it is\n * an honest \"this key is not that Agent\" rather than a signature that could\n * only be rejected.\n */\nexport function agentSignedMetering(\n signer: () => MeteringSigner | undefined,\n options: { readonly now?: () => number } = {},\n): ServiceHeaderProvider {\n const now = options.now ?? (() => Date.now());\n return async (request: ServiceHeaderRequest) => {\n const wallet = signer();\n if (wallet === undefined) return {};\n const address = (await wallet.getAddress()).toLowerCase();\n if (address !== request.agent.toLowerCase()) return {};\n const issuedAt = now();\n const digest = meteringDigest({\n method: request.method,\n path: new URL(request.url).pathname,\n agent: address,\n tool: toolKeyOf(request.tool),\n units: 1,\n issuedAt,\n });\n return {\n [METERING_HEADER.agentSignature]: await wallet.signMessage(digest),\n [METERING_HEADER.agentIssuedAt]: String(issuedAt),\n };\n };\n}\n"]}