@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":"index.js","sourceRoot":"","sources":["../../src/proxy/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC","sourcesContent":["/**\n * The proxy layer: hooks around a forwarded, metered request (R23.4), with a\n * seam for attaching the Settlement that covers it (R23.5).\n *\n * `hooks.ts` is the seam and `proxy.ts` the handler.\n */\n\nexport * from \"./hooks.js\";\nexport * from \"./proxy.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/proxy/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC","sourcesContent":["/**\n * The proxy layer: hooks around a forwarded, metered request, with a\n * seam for attaching the Settlement that covers it.\n *\n * `hooks.ts` is the seam and `proxy.ts` the handler.\n */\n\nexport * from \"./hooks.js\";\nexport * from \"./proxy.js\";\n"]}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The proxy layer: one handler that forwards a request upstream, meters the
3
- * delivery through the post-paid plugin, and runs hooks around both (R23.4).
3
+ * delivery through the post-paid plugin, and runs hooks around both.
4
4
  *
5
5
  * ## Order of operations, which is the whole contract
6
6
  *
@@ -15,7 +15,7 @@
15
15
  * delivery once the response exists, attaches the charge block, and replaces
16
16
  * the response with a 402 on `LimitExceeded` alone. Nothing about the plugin's
17
17
  * ordering guarantee changes because the handler is a network hop, and the
18
- * "never withhold pending payment" rule (R23.3) is inherited rather than
18
+ * "never withhold pending payment" rule is inherited rather than
19
19
  * re-implemented here.
20
20
  *
21
21
  * ## Streaming
@@ -42,8 +42,6 @@
42
42
  * delivery, so the plugin's default `billable` predicate does not meter it. A
43
43
  * critical hook's `err` is a response at its category's status. The handler
44
44
  * this factory returns never rejects.
45
- *
46
- * Requirements: 23.4, 23.3
47
45
  */
48
46
  import { type Result, type TabError } from "../_shared/index.js";
49
47
  import { type Logger } from "../logger.js";
@@ -97,7 +95,7 @@ export interface ProxyResult {
97
95
  readonly metering: Promise<MeteringOutcome> | undefined;
98
96
  /** The recorded charge, when the outcome was known before the hooks ran. */
99
97
  readonly charge: MeteredCharge | undefined;
100
- /** The Settlement a hook attached (R23.5). */
98
+ /** The Settlement a hook attached. */
101
99
  readonly settlement: SettlementView | undefined;
102
100
  /** Every hook failure, critical or not. */
103
101
  readonly hookFailures: readonly HookFailure[];
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/proxy/proxy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/proxy/proxy.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The proxy layer: one handler that forwards a request upstream, meters the
3
- * delivery through the post-paid plugin, and runs hooks around both (R23.4).
3
+ * delivery through the post-paid plugin, and runs hooks around both.
4
4
  *
5
5
  * ## Order of operations, which is the whole contract
6
6
  *
@@ -15,7 +15,7 @@
15
15
  * delivery once the response exists, attaches the charge block, and replaces
16
16
  * the response with a 402 on `LimitExceeded` alone. Nothing about the plugin's
17
17
  * ordering guarantee changes because the handler is a network hop, and the
18
- * "never withhold pending payment" rule (R23.3) is inherited rather than
18
+ * "never withhold pending payment" rule is inherited rather than
19
19
  * re-implemented here.
20
20
  *
21
21
  * ## Streaming
@@ -42,8 +42,6 @@
42
42
  * delivery, so the plugin's default `billable` predicate does not meter it. A
43
43
  * critical hook's `err` is a response at its category's status. The handler
44
44
  * this factory returns never rejects.
45
- *
46
- * Requirements: 23.4, 23.3
47
45
  */
48
46
  import { causeOf, httpStatusOf, ok, wrap } from "../_shared/index.js";
49
47
  import { tabError } from "../errors.js";
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/proxy/proxy.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The proxy layer: one handler that forwards a request upstream, meters the\n * delivery through the post-paid plugin, and runs hooks around both (R23.4).\n *\n * ## Order of operations, which is the whole contract\n *\n * ```text\n * before hooks, in registration order\n * -> metering.execute( forward to upstream )\n * after hooks, in reverse order\n * ```\n *\n * The forward runs *inside* the metering plugin's `execute`, so the plugin sees\n * the upstream's response exactly as it sees a local handler's: it records the\n * delivery once the response exists, attaches the charge block, and replaces\n * the response with a 402 on `LimitExceeded` alone. Nothing about the plugin's\n * ordering guarantee changes because the handler is a network hop, and the\n * \"never withhold pending payment\" rule (R23.3) is inherited rather than\n * re-implemented here.\n *\n * ## Streaming\n *\n * The upstream response body is passed through as the stream it arrived as.\n * Nothing here reads it, and the charge headers are attached by rebuilding the\n * response around the same stream. A hook that needs the body must `clone()` the\n * response and read the copy, and a hook that does so pays the buffering it\n * asked for and nobody else does. The request body is likewise forwarded as a\n * stream where the host `fetch` supports one.\n *\n * ## What is not forwarded\n *\n * Hop-by-hop request headers, `host`, and `content-length` are dropped before\n * forwarding, because they describe the connection the proxy is on rather than\n * the request. On the way back, `content-encoding`, `content-length`, and\n * `transfer-encoding` are dropped, because the host `fetch` already decoded the\n * body and the outbound server re-frames it; forwarding those headers would tell\n * the caller to decode a body that is already plain.\n *\n * ## Failures are responses, never throws\n *\n * An unreachable upstream is a 502 carrying a `TabError` body. It is not a\n * delivery, so the plugin's default `billable` predicate does not meter it. A\n * critical hook's `err` is a response at its category's status. The handler\n * this factory returns never rejects.\n *\n * Requirements: 23.4, 23.3\n */\n\nimport { causeOf, httpStatusOf, ok, wrap, type Result, type TabError } from \"../_shared/index.js\";\n\nimport { tabError } from \"../errors.js\";\nimport { defaultLogger, type Logger } from \"../logger.js\";\nimport {\n jsonResponse,\n type MeteredCharge,\n type MeteringOutcome,\n type PostPaidPlugin,\n} from \"../server/post-paid.js\";\nimport type { ProxyHook, ProxyHookContext, ProxyPhase } from \"./hooks.js\";\nimport type { SettlementView } from \"./hooks.js\";\n\n/** Request headers that describe the hop rather than the request, per RFC 9110. */\nexport const HOP_BY_HOP_HEADERS: readonly string[] = [\n \"connection\",\n \"keep-alive\",\n \"proxy-authenticate\",\n \"proxy-authorization\",\n \"proxy-connection\",\n \"te\",\n \"trailer\",\n \"transfer-encoding\",\n \"upgrade\",\n];\n\n/** Response headers the host `fetch` has already acted on and the outbound server re-frames. */\nexport const REFRAMED_RESPONSE_HEADERS: readonly string[] = [\n \"content-encoding\",\n \"content-length\",\n \"transfer-encoding\",\n \"connection\",\n \"keep-alive\",\n];\n\n/** The forward this proxy hands to its `fetch`. Structural, like `client-402.ts`. */\nexport interface ProxyForwardInit {\n readonly method: string;\n readonly headers: Readonly<Record<string, string>>;\n /** The request body stream, or undefined for a bodiless method. */\n readonly body?: unknown;\n /** Required by the host `fetch` to send a streamed request body. */\n readonly duplex?: \"half\";\n readonly signal?: AbortSignal;\n}\n\n/**\n * The `fetch` the proxy forwards with. The host's global `fetch` is the default.\n *\n * The third argument is the request as it reached the proxy, the same object\n * the metering plugin later hands to `priceOf`. A forward that learns the price\n * on the way, the x402-fronting one does, keys what it learned by it. The host\n * `fetch` and every existing two-argument `fetchImpl` ignore it.\n */\nexport type ProxyFetch = (url: string, init: ProxyForwardInit, request: Request) => Promise<Response>;\n\n/** One hook phase that returned an error or threw, in the order it happened. */\nexport interface HookFailure {\n readonly hook: string;\n readonly phase: ProxyPhase;\n readonly critical: boolean;\n readonly error: TabError;\n}\n\nexport interface ProxyResult {\n /** The response that goes out. */\n readonly response: Response;\n /**\n * `delivered`: the upstream's response, metered or not. `refused`: the metering\n * plugin replaced it, which is `LimitExceeded` and the two Agent-side refusals\n * only. `failed`: a critical hook or the forward itself failed.\n */\n readonly kind: \"delivered\" | \"refused\" | \"failed\";\n /**\n * Resolves once the delivery is recorded. Already resolved under the plugin's\n * default `after-metering`; still pending under `before-metering`, where a\n * host with a request lifetime hook passes it there.\n */\n readonly metering: Promise<MeteringOutcome> | undefined;\n /** The recorded charge, when the outcome was known before the hooks ran. */\n readonly charge: MeteredCharge | undefined;\n /** The Settlement a hook attached (R23.5). */\n readonly settlement: SettlementView | undefined;\n /** Every hook failure, critical or not. */\n readonly hookFailures: readonly HookFailure[];\n /** The error that produced a `failed` result. */\n readonly failure: TabError | undefined;\n /** The shared scratch the hooks used, for a Service that wants to log it. */\n readonly state: ReadonlyMap<string, unknown>;\n}\n\nexport interface TabProxyOptions {\n /** Absolute base URL of the service being fronted. The request path and query are appended. */\n readonly upstream: string;\n readonly hooks?: readonly ProxyHook[];\n /** The post-paid plugin of `server/post-paid.ts`. Metering runs on every request. */\n readonly metering: PostPaidPlugin;\n readonly fetchImpl?: ProxyFetch;\n readonly logger?: Logger;\n /** Aborts the forward after this long. No timeout when omitted. */\n readonly timeoutMs?: number;\n /** Request headers dropped before forwarding, on top of the hop-by-hop set and `host`. */\n readonly dropRequestHeaders?: readonly string[];\n /**\n * A leading path segment removed before the path is appended to `upstream`.\n * A proxy mounted at `/hub/nansen` in front of `https://api.nansen.ai/api/v1`\n * strips `/hub/nansen`, so `/hub/nansen/query` reaches `.../api/v1/query`.\n */\n readonly stripPrefix?: string;\n /** Called with every result, so a Service logs which Settlement covered which request. */\n readonly onResult?: (result: ProxyResult) => void;\n}\n\n/** A handler any web-standard host can mount, with the richer entry point beside it. */\nexport interface TabProxy {\n (request: Request): Promise<Response>;\n /** The same run, returning everything the handler discards. */\n proxy(request: Request): Promise<ProxyResult>;\n readonly hooks: readonly ProxyHook[];\n readonly upstream: string;\n}\n\n/**\n * Builds the proxy.\n *\n * Construction is total, as everywhere in this package. An unusable `upstream`\n * is reported by the first request as a 500 carrying a `VALIDATION` error, which\n * is the first point at which anybody is listening.\n */\nexport function createTabProxy(options: TabProxyOptions): TabProxy {\n const logger = options.logger ?? defaultLogger;\n const hooks = [...(options.hooks ?? [])];\n const dropped = new Set([\n ...HOP_BY_HOP_HEADERS,\n \"host\",\n \"content-length\",\n ...(options.dropRequestHeaders ?? []).map((name) => name.toLowerCase()),\n ]);\n\n /**\n * The forward. A failure becomes a response and is also recorded on `holder`,\n * so the result can name the error without reading it back off the response.\n */\n const forward = async (request: Request, holder: { failure?: TabError }): Promise<Response> => {\n const failed = (error: TabError): Response => {\n holder.failure = error;\n return errorResponse(error);\n };\n const target = resolveUpstream(options.upstream, request.url, options.stripPrefix);\n if (!target.ok) return failed(target.error);\n\n const send = options.fetchImpl ?? hostFetch();\n if (send === undefined) {\n return failed(\n tabError(\"UPSTREAM\", \"FETCH_UNAVAILABLE\", \"this host has no global fetch; supply fetchImpl, or run on Node 20.10 or later\"),\n );\n }\n\n const headers: Record<string, string> = {};\n request.headers.forEach((value, name) => {\n if (!dropped.has(name.toLowerCase())) headers[name] = value;\n });\n\n const bodiless = request.method === \"GET\" || request.method === \"HEAD\";\n const body = bodiless ? undefined : request.body;\n const signal = forwardSignal(request, options.timeoutMs);\n const init: ProxyForwardInit = {\n method: request.method,\n headers,\n ...(body === undefined || body === null ? {} : { body, duplex: \"half\" as const }),\n ...(signal === undefined ? {} : { signal }),\n };\n\n const sent = await wrap(\n async () => send(target.value, init, request),\n (error) =>\n tabError(\"UPSTREAM\", \"PROXY_UPSTREAM_UNREACHABLE\", `the upstream at ${target.value} did not answer`, {\n retryable: true,\n details: { upstream: target.value, method: request.method },\n cause: causeOf(error),\n }),\n );\n if (!sent.ok) return failed(sent.error);\n if (!looksLikeResponse(sent.value)) {\n return failed(\n tabError(\"UPSTREAM\", \"PROXY_UPSTREAM_INVALID\", `the fetch given to this proxy returned something that is not a response for ${target.value}`),\n );\n }\n return reframe(sent.value);\n };\n\n const proxy = async (request: Request): Promise<ProxyResult> => {\n const state = new Map<string, unknown>();\n const failures: HookFailure[] = [];\n const base = { request, state, logger } as const;\n let settlement: SettlementView | undefined;\n\n // ---- before, in registration order\n for (const hook of hooks) {\n if (hook.before === undefined) continue;\n const context: ProxyHookContext = { ...base, phase: \"before\" };\n const outcome = await runPhase(hook, \"before\", context, logger);\n if (outcome !== undefined) {\n failures.push(outcome);\n if (outcome.critical) {\n return finish({\n response: errorResponse(outcome.error),\n kind: \"failed\",\n metering: undefined,\n charge: undefined,\n settlement: context.settlement,\n hookFailures: failures,\n failure: outcome.error,\n state,\n });\n }\n }\n settlement = context.settlement ?? settlement;\n }\n\n // ---- the forward, under metering\n const holder: { failure?: TabError } = {};\n const execution = await options.metering.execute(request, () => forward(request, holder));\n\n let response: Response;\n let kind: ProxyResult[\"kind\"];\n let forwardThrew: TabError | undefined;\n let metering: Promise<MeteringOutcome> | undefined;\n let outcome: MeteringOutcome | undefined;\n if (execution.kind === \"handler-failed\") {\n // `forward` never throws, so this is a plugin invariant rather than a path,\n // and it is answered the same way a throwing hook is: as an INTERNAL error.\n forwardThrew = tabError(\"INTERNAL\", \"PROXY_FORWARD_THREW\", \"the forward threw where it should have returned a response\", {\n cause: causeOf(execution.thrown),\n });\n response = errorResponse(forwardThrew);\n kind = \"failed\";\n } else if (execution.kind === \"refused\") {\n response = execution.response;\n kind = \"refused\";\n outcome = execution.outcome;\n metering = Promise.resolve(execution.outcome);\n } else {\n response = execution.response;\n kind = holder.failure === undefined ? \"delivered\" : \"failed\";\n metering = execution.metering;\n if (options.metering.release === \"after-metering\") outcome = await execution.metering;\n }\n const charge = outcome?.kind === \"charged\" ? outcome.charge : undefined;\n\n // ---- after, in reverse order\n for (const hook of [...hooks].reverse()) {\n if (hook.after === undefined) continue;\n const context: ProxyHookContext = {\n ...base,\n phase: \"after\",\n response,\n ...(charge === undefined ? {} : { charge }),\n ...(outcome === undefined ? {} : { metering: outcome }),\n ...(settlement === undefined ? {} : { settlement }),\n };\n const failed = await runPhase(hook, \"after\", context, logger);\n settlement = context.settlement ?? settlement;\n if (failed !== undefined) {\n failures.push(failed);\n if (failed.critical) {\n discard(response, logger);\n return finish({\n response: errorResponse(failed.error),\n kind: \"failed\",\n metering,\n charge,\n settlement,\n hookFailures: failures,\n failure: failed.error,\n state,\n });\n }\n }\n }\n\n return finish({\n response,\n kind,\n metering,\n charge,\n settlement,\n hookFailures: failures,\n failure: kind === \"failed\" ? (holder.failure ?? forwardThrew) : undefined,\n state,\n });\n };\n\n const finish = (result: ProxyResult): ProxyResult => {\n if (options.onResult !== undefined) {\n try {\n options.onResult(result);\n } catch (error) {\n logger.warn(\"onResult threw and was ignored\", causeOf(error));\n }\n }\n return result;\n };\n\n const handler = async (request: Request): Promise<Response> => (await proxy(request)).response;\n return Object.assign(handler, { proxy, hooks, upstream: options.upstream });\n}\n\n/**\n * Runs one phase of one hook without letting it throw or reject into the proxy.\n * Returns the failure, or undefined when the phase succeeded.\n */\nasync function runPhase(\n hook: ProxyHook,\n phase: ProxyPhase,\n context: ProxyHookContext,\n logger: Logger,\n): Promise<HookFailure | undefined> {\n const run = phase === \"before\" ? hook.before : hook.after;\n if (run === undefined) return undefined;\n let result: Result<void>;\n try {\n result = await run.call(hook, context);\n } catch (error) {\n result = { ok: false, error: tabError(\"INTERNAL\", \"HOOK_THREW\", `hook ${hook.name} threw in its ${phase} phase`, { cause: causeOf(error) }) };\n }\n if (result.ok) return undefined;\n const critical = hook.critical === true;\n logger[critical ? \"error\" : \"warn\"](\n critical ? `hook ${hook.name} failed its ${phase} phase and the request fails with it` : `hook ${hook.name} failed its ${phase} phase and was skipped`,\n { hook: hook.name, phase, code: result.error.code, message: result.error.message },\n );\n return { hook: hook.name, phase, critical, error: result.error };\n}\n\n/**\n * The request path and query, resolved against the upstream base.\n *\n * `stripPrefix`, when given, is removed from the front of the path first, and a\n * path that does not start with it is refused rather than forwarded somewhere\n * the mount did not intend.\n */\nexport function resolveUpstream(upstream: string, requestUrl: string, stripPrefix?: string): Result<string> {\n const base = safeUrl(upstream.endsWith(\"/\") ? upstream : `${upstream}/`);\n if (base === undefined || (base.protocol !== \"http:\" && base.protocol !== \"https:\")) {\n return {\n ok: false,\n error: tabError(\"VALIDATION\", \"UPSTREAM_INVALID\", `upstream \\`${upstream}\\` is not an absolute http or https URL`),\n };\n }\n const incoming = safeUrl(requestUrl, base);\n if (incoming === undefined) {\n return {\n ok: false,\n error: tabError(\"VALIDATION\", \"REQUEST_URL_INVALID\", `the request URL \\`${requestUrl}\\` does not parse`),\n };\n }\n let pathname = incoming.pathname;\n if (stripPrefix !== undefined && stripPrefix.length > 0) {\n const prefix = `/${stripPrefix.replace(/^\\/+|\\/+$/g, \"\")}`;\n if (pathname !== prefix && !pathname.startsWith(`${prefix}/`)) {\n return {\n ok: false,\n error: tabError(\"VALIDATION\", \"REQUEST_PATH_OUTSIDE_MOUNT\", `the request path \\`${pathname}\\` does not start with the mount \\`${prefix}\\``, {\n details: { path: pathname, prefix },\n }),\n };\n }\n pathname = pathname.slice(prefix.length);\n }\n const relative = `${pathname.replace(/^\\/+/, \"\")}${incoming.search}`;\n return ok(new URL(relative, base).toString());\n}\n\nfunction safeUrl(value: string, base?: URL): URL | undefined {\n try {\n return base === undefined ? new URL(value) : new URL(value, base);\n } catch {\n return undefined;\n }\n}\n\n/** A signal that fires on the caller's abort or on the timeout, whichever comes first. */\nfunction forwardSignal(request: Request, timeoutMs: number | undefined): AbortSignal | undefined {\n const timeout = timeoutMs === undefined ? undefined : AbortSignal.timeout(timeoutMs);\n const caller = request.signal;\n if (timeout === undefined) return caller;\n const any = (AbortSignal as { any?: (signals: AbortSignal[]) => AbortSignal }).any;\n return typeof any === \"function\" ? any([caller, timeout]) : timeout;\n}\n\n/**\n * Rebuilds the upstream response around its own body stream, minus the headers\n * the host `fetch` has already consumed. No byte of the body is read here.\n */\nfunction reframe(upstream: Response): Response {\n const headers = new Headers();\n upstream.headers.forEach((value, name) => {\n if (!REFRAMED_RESPONSE_HEADERS.includes(name.toLowerCase())) headers.append(name, value);\n });\n return new Response(upstream.body, {\n status: upstream.status,\n statusText: upstream.statusText,\n headers,\n });\n}\n\n/** A `TabError` as the response it becomes: its category's status, the error as JSON. */\nexport function errorResponse(error: TabError): Response {\n return jsonResponse(httpStatusOf(error), {}, { ok: false, error });\n}\n\nfunction looksLikeResponse(value: unknown): value is Response {\n if (typeof value !== \"object\" || value === null) return false;\n const candidate = value as { status?: unknown; headers?: unknown };\n return typeof candidate.status === \"number\" && typeof candidate.headers === \"object\" && candidate.headers !== null;\n}\n\n/** Releases a response that is not going out, so its connection does not wait for the collector. */\nfunction discard(response: Response, logger: Logger): void {\n const body = response.body;\n if (body === null || response.bodyUsed) return;\n try {\n body.cancel().catch((error: unknown) => {\n logger.debug(\"discarded response body could not be cancelled\", causeOf(error));\n });\n } catch (error) {\n logger.debug(\"discarded response body could not be cancelled\", causeOf(error));\n }\n}\n\n/** The host's global `fetch`, behind a runtime check so its absence is an error and not a TypeError. */\nfunction hostFetch(): ProxyFetch | undefined {\n const candidate = (globalThis as { fetch?: unknown }).fetch;\n return typeof candidate === \"function\" ? (candidate as ProxyFetch) : undefined;\n}\n"]}
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/proxy/proxy.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The proxy layer: one handler that forwards a request upstream, meters the\n * delivery through the post-paid plugin, and runs hooks around both.\n *\n * ## Order of operations, which is the whole contract\n *\n * ```text\n * before hooks, in registration order\n * -> metering.execute( forward to upstream )\n * after hooks, in reverse order\n * ```\n *\n * The forward runs *inside* the metering plugin's `execute`, so the plugin sees\n * the upstream's response exactly as it sees a local handler's: it records the\n * delivery once the response exists, attaches the charge block, and replaces\n * the response with a 402 on `LimitExceeded` alone. Nothing about the plugin's\n * ordering guarantee changes because the handler is a network hop, and the\n * \"never withhold pending payment\" rule is inherited rather than\n * re-implemented here.\n *\n * ## Streaming\n *\n * The upstream response body is passed through as the stream it arrived as.\n * Nothing here reads it, and the charge headers are attached by rebuilding the\n * response around the same stream. A hook that needs the body must `clone()` the\n * response and read the copy, and a hook that does so pays the buffering it\n * asked for and nobody else does. The request body is likewise forwarded as a\n * stream where the host `fetch` supports one.\n *\n * ## What is not forwarded\n *\n * Hop-by-hop request headers, `host`, and `content-length` are dropped before\n * forwarding, because they describe the connection the proxy is on rather than\n * the request. On the way back, `content-encoding`, `content-length`, and\n * `transfer-encoding` are dropped, because the host `fetch` already decoded the\n * body and the outbound server re-frames it; forwarding those headers would tell\n * the caller to decode a body that is already plain.\n *\n * ## Failures are responses, never throws\n *\n * An unreachable upstream is a 502 carrying a `TabError` body. It is not a\n * delivery, so the plugin's default `billable` predicate does not meter it. A\n * critical hook's `err` is a response at its category's status. The handler\n * this factory returns never rejects.\n */\n\nimport { causeOf, httpStatusOf, ok, wrap, type Result, type TabError } from \"../_shared/index.js\";\n\nimport { tabError } from \"../errors.js\";\nimport { defaultLogger, type Logger } from \"../logger.js\";\nimport {\n jsonResponse,\n type MeteredCharge,\n type MeteringOutcome,\n type PostPaidPlugin,\n} from \"../server/post-paid.js\";\nimport type { ProxyHook, ProxyHookContext, ProxyPhase } from \"./hooks.js\";\nimport type { SettlementView } from \"./hooks.js\";\n\n/** Request headers that describe the hop rather than the request, per RFC 9110. */\nexport const HOP_BY_HOP_HEADERS: readonly string[] = [\n \"connection\",\n \"keep-alive\",\n \"proxy-authenticate\",\n \"proxy-authorization\",\n \"proxy-connection\",\n \"te\",\n \"trailer\",\n \"transfer-encoding\",\n \"upgrade\",\n];\n\n/** Response headers the host `fetch` has already acted on and the outbound server re-frames. */\nexport const REFRAMED_RESPONSE_HEADERS: readonly string[] = [\n \"content-encoding\",\n \"content-length\",\n \"transfer-encoding\",\n \"connection\",\n \"keep-alive\",\n];\n\n/** The forward this proxy hands to its `fetch`. Structural, like `client-402.ts`. */\nexport interface ProxyForwardInit {\n readonly method: string;\n readonly headers: Readonly<Record<string, string>>;\n /** The request body stream, or undefined for a bodiless method. */\n readonly body?: unknown;\n /** Required by the host `fetch` to send a streamed request body. */\n readonly duplex?: \"half\";\n readonly signal?: AbortSignal;\n}\n\n/**\n * The `fetch` the proxy forwards with. The host's global `fetch` is the default.\n *\n * The third argument is the request as it reached the proxy, the same object\n * the metering plugin later hands to `priceOf`. A forward that learns the price\n * on the way, the x402-fronting one does, keys what it learned by it. The host\n * `fetch` and every existing two-argument `fetchImpl` ignore it.\n */\nexport type ProxyFetch = (url: string, init: ProxyForwardInit, request: Request) => Promise<Response>;\n\n/** One hook phase that returned an error or threw, in the order it happened. */\nexport interface HookFailure {\n readonly hook: string;\n readonly phase: ProxyPhase;\n readonly critical: boolean;\n readonly error: TabError;\n}\n\nexport interface ProxyResult {\n /** The response that goes out. */\n readonly response: Response;\n /**\n * `delivered`: the upstream's response, metered or not. `refused`: the metering\n * plugin replaced it, which is `LimitExceeded` and the two Agent-side refusals\n * only. `failed`: a critical hook or the forward itself failed.\n */\n readonly kind: \"delivered\" | \"refused\" | \"failed\";\n /**\n * Resolves once the delivery is recorded. Already resolved under the plugin's\n * default `after-metering`; still pending under `before-metering`, where a\n * host with a request lifetime hook passes it there.\n */\n readonly metering: Promise<MeteringOutcome> | undefined;\n /** The recorded charge, when the outcome was known before the hooks ran. */\n readonly charge: MeteredCharge | undefined;\n /** The Settlement a hook attached. */\n readonly settlement: SettlementView | undefined;\n /** Every hook failure, critical or not. */\n readonly hookFailures: readonly HookFailure[];\n /** The error that produced a `failed` result. */\n readonly failure: TabError | undefined;\n /** The shared scratch the hooks used, for a Service that wants to log it. */\n readonly state: ReadonlyMap<string, unknown>;\n}\n\nexport interface TabProxyOptions {\n /** Absolute base URL of the service being fronted. The request path and query are appended. */\n readonly upstream: string;\n readonly hooks?: readonly ProxyHook[];\n /** The post-paid plugin of `server/post-paid.ts`. Metering runs on every request. */\n readonly metering: PostPaidPlugin;\n readonly fetchImpl?: ProxyFetch;\n readonly logger?: Logger;\n /** Aborts the forward after this long. No timeout when omitted. */\n readonly timeoutMs?: number;\n /** Request headers dropped before forwarding, on top of the hop-by-hop set and `host`. */\n readonly dropRequestHeaders?: readonly string[];\n /**\n * A leading path segment removed before the path is appended to `upstream`.\n * A proxy mounted at `/hub/nansen` in front of `https://api.nansen.ai/api/v1`\n * strips `/hub/nansen`, so `/hub/nansen/query` reaches `.../api/v1/query`.\n */\n readonly stripPrefix?: string;\n /** Called with every result, so a Service logs which Settlement covered which request. */\n readonly onResult?: (result: ProxyResult) => void;\n}\n\n/** A handler any web-standard host can mount, with the richer entry point beside it. */\nexport interface TabProxy {\n (request: Request): Promise<Response>;\n /** The same run, returning everything the handler discards. */\n proxy(request: Request): Promise<ProxyResult>;\n readonly hooks: readonly ProxyHook[];\n readonly upstream: string;\n}\n\n/**\n * Builds the proxy.\n *\n * Construction is total, as everywhere in this package. An unusable `upstream`\n * is reported by the first request as a 500 carrying a `VALIDATION` error, which\n * is the first point at which anybody is listening.\n */\nexport function createTabProxy(options: TabProxyOptions): TabProxy {\n const logger = options.logger ?? defaultLogger;\n const hooks = [...(options.hooks ?? [])];\n const dropped = new Set([\n ...HOP_BY_HOP_HEADERS,\n \"host\",\n \"content-length\",\n ...(options.dropRequestHeaders ?? []).map((name) => name.toLowerCase()),\n ]);\n\n /**\n * The forward. A failure becomes a response and is also recorded on `holder`,\n * so the result can name the error without reading it back off the response.\n */\n const forward = async (request: Request, holder: { failure?: TabError }): Promise<Response> => {\n const failed = (error: TabError): Response => {\n holder.failure = error;\n return errorResponse(error);\n };\n const target = resolveUpstream(options.upstream, request.url, options.stripPrefix);\n if (!target.ok) return failed(target.error);\n\n const send = options.fetchImpl ?? hostFetch();\n if (send === undefined) {\n return failed(\n tabError(\"UPSTREAM\", \"FETCH_UNAVAILABLE\", \"this host has no global fetch; supply fetchImpl, or run on Node 20.10 or later\"),\n );\n }\n\n const headers: Record<string, string> = {};\n request.headers.forEach((value, name) => {\n if (!dropped.has(name.toLowerCase())) headers[name] = value;\n });\n\n const bodiless = request.method === \"GET\" || request.method === \"HEAD\";\n const body = bodiless ? undefined : request.body;\n const signal = forwardSignal(request, options.timeoutMs);\n const init: ProxyForwardInit = {\n method: request.method,\n headers,\n ...(body === undefined || body === null ? {} : { body, duplex: \"half\" as const }),\n ...(signal === undefined ? {} : { signal }),\n };\n\n const sent = await wrap(\n async () => send(target.value, init, request),\n (error) =>\n tabError(\"UPSTREAM\", \"PROXY_UPSTREAM_UNREACHABLE\", `the upstream at ${target.value} did not answer`, {\n retryable: true,\n details: { upstream: target.value, method: request.method },\n cause: causeOf(error),\n }),\n );\n if (!sent.ok) return failed(sent.error);\n if (!looksLikeResponse(sent.value)) {\n return failed(\n tabError(\"UPSTREAM\", \"PROXY_UPSTREAM_INVALID\", `the fetch given to this proxy returned something that is not a response for ${target.value}`),\n );\n }\n return reframe(sent.value);\n };\n\n const proxy = async (request: Request): Promise<ProxyResult> => {\n const state = new Map<string, unknown>();\n const failures: HookFailure[] = [];\n const base = { request, state, logger } as const;\n let settlement: SettlementView | undefined;\n\n // ---- before, in registration order\n for (const hook of hooks) {\n if (hook.before === undefined) continue;\n const context: ProxyHookContext = { ...base, phase: \"before\" };\n const outcome = await runPhase(hook, \"before\", context, logger);\n if (outcome !== undefined) {\n failures.push(outcome);\n if (outcome.critical) {\n return finish({\n response: errorResponse(outcome.error),\n kind: \"failed\",\n metering: undefined,\n charge: undefined,\n settlement: context.settlement,\n hookFailures: failures,\n failure: outcome.error,\n state,\n });\n }\n }\n settlement = context.settlement ?? settlement;\n }\n\n // ---- the forward, under metering\n const holder: { failure?: TabError } = {};\n const execution = await options.metering.execute(request, () => forward(request, holder));\n\n let response: Response;\n let kind: ProxyResult[\"kind\"];\n let forwardThrew: TabError | undefined;\n let metering: Promise<MeteringOutcome> | undefined;\n let outcome: MeteringOutcome | undefined;\n if (execution.kind === \"handler-failed\") {\n // `forward` never throws, so this is a plugin invariant rather than a path,\n // and it is answered the same way a throwing hook is: as an INTERNAL error.\n forwardThrew = tabError(\"INTERNAL\", \"PROXY_FORWARD_THREW\", \"the forward threw where it should have returned a response\", {\n cause: causeOf(execution.thrown),\n });\n response = errorResponse(forwardThrew);\n kind = \"failed\";\n } else if (execution.kind === \"refused\") {\n response = execution.response;\n kind = \"refused\";\n outcome = execution.outcome;\n metering = Promise.resolve(execution.outcome);\n } else {\n response = execution.response;\n kind = holder.failure === undefined ? \"delivered\" : \"failed\";\n metering = execution.metering;\n if (options.metering.release === \"after-metering\") outcome = await execution.metering;\n }\n const charge = outcome?.kind === \"charged\" ? outcome.charge : undefined;\n\n // ---- after, in reverse order\n for (const hook of [...hooks].reverse()) {\n if (hook.after === undefined) continue;\n const context: ProxyHookContext = {\n ...base,\n phase: \"after\",\n response,\n ...(charge === undefined ? {} : { charge }),\n ...(outcome === undefined ? {} : { metering: outcome }),\n ...(settlement === undefined ? {} : { settlement }),\n };\n const failed = await runPhase(hook, \"after\", context, logger);\n settlement = context.settlement ?? settlement;\n if (failed !== undefined) {\n failures.push(failed);\n if (failed.critical) {\n discard(response, logger);\n return finish({\n response: errorResponse(failed.error),\n kind: \"failed\",\n metering,\n charge,\n settlement,\n hookFailures: failures,\n failure: failed.error,\n state,\n });\n }\n }\n }\n\n return finish({\n response,\n kind,\n metering,\n charge,\n settlement,\n hookFailures: failures,\n failure: kind === \"failed\" ? (holder.failure ?? forwardThrew) : undefined,\n state,\n });\n };\n\n const finish = (result: ProxyResult): ProxyResult => {\n if (options.onResult !== undefined) {\n try {\n options.onResult(result);\n } catch (error) {\n logger.warn(\"onResult threw and was ignored\", causeOf(error));\n }\n }\n return result;\n };\n\n const handler = async (request: Request): Promise<Response> => (await proxy(request)).response;\n return Object.assign(handler, { proxy, hooks, upstream: options.upstream });\n}\n\n/**\n * Runs one phase of one hook without letting it throw or reject into the proxy.\n * Returns the failure, or undefined when the phase succeeded.\n */\nasync function runPhase(\n hook: ProxyHook,\n phase: ProxyPhase,\n context: ProxyHookContext,\n logger: Logger,\n): Promise<HookFailure | undefined> {\n const run = phase === \"before\" ? hook.before : hook.after;\n if (run === undefined) return undefined;\n let result: Result<void>;\n try {\n result = await run.call(hook, context);\n } catch (error) {\n result = { ok: false, error: tabError(\"INTERNAL\", \"HOOK_THREW\", `hook ${hook.name} threw in its ${phase} phase`, { cause: causeOf(error) }) };\n }\n if (result.ok) return undefined;\n const critical = hook.critical === true;\n logger[critical ? \"error\" : \"warn\"](\n critical ? `hook ${hook.name} failed its ${phase} phase and the request fails with it` : `hook ${hook.name} failed its ${phase} phase and was skipped`,\n { hook: hook.name, phase, code: result.error.code, message: result.error.message },\n );\n return { hook: hook.name, phase, critical, error: result.error };\n}\n\n/**\n * The request path and query, resolved against the upstream base.\n *\n * `stripPrefix`, when given, is removed from the front of the path first, and a\n * path that does not start with it is refused rather than forwarded somewhere\n * the mount did not intend.\n */\nexport function resolveUpstream(upstream: string, requestUrl: string, stripPrefix?: string): Result<string> {\n const base = safeUrl(upstream.endsWith(\"/\") ? upstream : `${upstream}/`);\n if (base === undefined || (base.protocol !== \"http:\" && base.protocol !== \"https:\")) {\n return {\n ok: false,\n error: tabError(\"VALIDATION\", \"UPSTREAM_INVALID\", `upstream \\`${upstream}\\` is not an absolute http or https URL`),\n };\n }\n const incoming = safeUrl(requestUrl, base);\n if (incoming === undefined) {\n return {\n ok: false,\n error: tabError(\"VALIDATION\", \"REQUEST_URL_INVALID\", `the request URL \\`${requestUrl}\\` does not parse`),\n };\n }\n let pathname = incoming.pathname;\n if (stripPrefix !== undefined && stripPrefix.length > 0) {\n const prefix = `/${stripPrefix.replace(/^\\/+|\\/+$/g, \"\")}`;\n if (pathname !== prefix && !pathname.startsWith(`${prefix}/`)) {\n return {\n ok: false,\n error: tabError(\"VALIDATION\", \"REQUEST_PATH_OUTSIDE_MOUNT\", `the request path \\`${pathname}\\` does not start with the mount \\`${prefix}\\``, {\n details: { path: pathname, prefix },\n }),\n };\n }\n pathname = pathname.slice(prefix.length);\n }\n const relative = `${pathname.replace(/^\\/+/, \"\")}${incoming.search}`;\n return ok(new URL(relative, base).toString());\n}\n\nfunction safeUrl(value: string, base?: URL): URL | undefined {\n try {\n return base === undefined ? new URL(value) : new URL(value, base);\n } catch {\n return undefined;\n }\n}\n\n/** A signal that fires on the caller's abort or on the timeout, whichever comes first. */\nfunction forwardSignal(request: Request, timeoutMs: number | undefined): AbortSignal | undefined {\n const timeout = timeoutMs === undefined ? undefined : AbortSignal.timeout(timeoutMs);\n const caller = request.signal;\n if (timeout === undefined) return caller;\n const any = (AbortSignal as { any?: (signals: AbortSignal[]) => AbortSignal }).any;\n return typeof any === \"function\" ? any([caller, timeout]) : timeout;\n}\n\n/**\n * Rebuilds the upstream response around its own body stream, minus the headers\n * the host `fetch` has already consumed. No byte of the body is read here.\n */\nfunction reframe(upstream: Response): Response {\n const headers = new Headers();\n upstream.headers.forEach((value, name) => {\n if (!REFRAMED_RESPONSE_HEADERS.includes(name.toLowerCase())) headers.append(name, value);\n });\n return new Response(upstream.body, {\n status: upstream.status,\n statusText: upstream.statusText,\n headers,\n });\n}\n\n/** A `TabError` as the response it becomes: its category's status, the error as JSON. */\nexport function errorResponse(error: TabError): Response {\n return jsonResponse(httpStatusOf(error), {}, { ok: false, error });\n}\n\nfunction looksLikeResponse(value: unknown): value is Response {\n if (typeof value !== \"object\" || value === null) return false;\n const candidate = value as { status?: unknown; headers?: unknown };\n return typeof candidate.status === \"number\" && typeof candidate.headers === \"object\" && candidate.headers !== null;\n}\n\n/** Releases a response that is not going out, so its connection does not wait for the collector. */\nfunction discard(response: Response, logger: Logger): void {\n const body = response.body;\n if (body === null || response.bodyUsed) return;\n try {\n body.cancel().catch((error: unknown) => {\n logger.debug(\"discarded response body could not be cancelled\", causeOf(error));\n });\n } catch (error) {\n logger.debug(\"discarded response body could not be cancelled\", causeOf(error));\n }\n}\n\n/** The host's global `fetch`, behind a runtime check so its absence is an error and not a TypeError. */\nfunction hostFetch(): ProxyFetch | undefined {\n const candidate = (globalThis as { fetch?: unknown }).fetch;\n return typeof candidate === \"function\" ? (candidate as ProxyFetch) : undefined;\n}\n"]}
@@ -32,8 +32,6 @@
32
32
  * The three parameter types are structural and describe only the fields the
33
33
  * middleware touches. Nothing here imports `express`, so a consumer on Hono
34
34
  * installs nothing extra and there is no Express version to keep in step.
35
- *
36
- * Requirements: 23.3, 12.1
37
35
  */
38
36
  import type { Logger } from "../../logger.js";
39
37
  import type { MeteredRequest, MeteringOutcome, PostPaidPlugin } from "../post-paid.js";
@@ -1 +1 @@
1
- {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/express.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAG9C,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEvF,8EAA8E;AAC9E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,+EAA+E;IAC/E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,GAAG,SAAS,CAAC;CACxF;AAED,iFAAiF;AACjF,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAChD,YAAY,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACrC,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IACnC,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IACjC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;CAClD;AAED,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;AAExD,MAAM,MAAM,qBAAqB,GAAG,CAClC,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,EAAE,mBAAmB,EAC7B,IAAI,EAAE,eAAe,KAClB,IAAI,CAAC;AAEV,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IACnE,6FAA6F;IAC7F,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,yBAA8B,GACtC,qBAAqB,CAiDvB;AA0ED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,SAAqB,GAC3B,cAAc,CAOhB"}
1
+ {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/express.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAG9C,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEvF,8EAA8E;AAC9E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,+EAA+E;IAC/E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,GAAG,SAAS,CAAC;CACxF;AAED,iFAAiF;AACjF,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAChD,YAAY,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACrC,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IACnC,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IACjC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;CAClD;AAED,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;AAExD,MAAM,MAAM,qBAAqB,GAAG,CAClC,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,EAAE,mBAAmB,EAC7B,IAAI,EAAE,eAAe,KAClB,IAAI,CAAC;AAEV,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IACnE,6FAA6F;IAC7F,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,yBAA8B,GACtC,qBAAqB,CAiDvB;AA0ED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,SAAqB,GAC3B,cAAc,CAOhB"}
@@ -32,8 +32,6 @@
32
32
  * The three parameter types are structural and describe only the fields the
33
33
  * middleware touches. Nothing here imports `express`, so a consumer on Hono
34
34
  * installs nothing extra and there is no Express version to keep in step.
35
- *
36
- * Requirements: 23.3, 12.1
37
35
  */
38
36
  import { defaultLogger } from "../../logger.js";
39
37
  import { headerReaderOf } from "../../http/headers.js";
@@ -1 +1 @@
1
- {"version":3,"file":"express.js","sourceRoot":"","sources":["../../../src/server/adapters/express.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Express middleware over the post-paid plugin.\n *\n * Express is the one framework of the three that does not hand a middleware a\n * response object to inspect. A handler writes into `res` and the bytes leave as\n * they are written, so \"meter after the handler produced its response\" has to be\n * arranged rather than expressed, and the two release orderings need genuinely\n * different plumbing:\n *\n * **`before-metering` intercepts nothing.** The middleware registers a `finish`\n * listener and calls `next()`. Express writes the response exactly as it would\n * without this SDK installed, and the delivery is recorded once the bytes are\n * gone. Nothing is buffered, nothing is delayed, and a streamed endpoint keeps\n * streaming. A refusal cannot reach this request, because the response left\n * before the charge was known.\n *\n * **`after-metering` holds the body, and only the body.** `res.write` and\n * `res.end` are intercepted, the chunks are collected, and the moment the handler\n * ends the response the delivery is recorded. Then either the collected bytes go\n * out with their charge headers, or, on the one refusal an Agent must clear -\n * the refusal goes out instead. The handler is never delayed: it writes, it ends,\n * it returns. What waits is the flush, and it waits on one credit record, never on\n * a payment.\n *\n * That interception is worth naming plainly: under `after-metering` this adapter\n * buffers the response body in memory until the handler ends the response, so it\n * is the wrong choice for a streamed or long-lived response. Use\n * `before-metering` for those, and the bytes are never touched.\n *\n * ## No dependency on Express\n *\n * The three parameter types are structural and describe only the fields the\n * middleware touches. Nothing here imports `express`, so a consumer on Hono\n * installs nothing extra and there is no Express version to keep in step.\n *\n * Requirements: 23.3, 12.1\n */\n\nimport type { Logger } from \"../../logger.js\";\nimport { defaultLogger } from \"../../logger.js\";\nimport { headerReaderOf } from \"../../http/headers.js\";\nimport type { MeteredRequest, MeteringOutcome, PostPaidPlugin } from \"../post-paid.js\";\n\n/** The request fields the middleware reads. An Express `req` satisfies it. */\nexport interface ExpressLikeRequest {\n readonly method?: string | undefined;\n readonly url?: string | undefined;\n /** Express's pre-router URL. Preferred over `url`, which a router rewrites. */\n readonly originalUrl?: string | undefined;\n readonly headers?: Readonly<Record<string, string | string[] | undefined>> | undefined;\n}\n\n/** The response fields the middleware touches. An Express `res` satisfies it. */\nexport interface ExpressLikeResponse {\n statusCode: number;\n readonly headersSent?: boolean;\n setHeader(name: string, value: string): unknown;\n removeHeader?(name: string): unknown;\n write(...args: unknown[]): boolean;\n end(...args: unknown[]): unknown;\n on(event: string, listener: () => void): unknown;\n}\n\n/** Express's continuation. An argument means the handler chain failed. */\nexport type ExpressLikeNext = (error?: unknown) => void;\n\nexport type ExpressLikeMiddleware = (\n request: ExpressLikeRequest,\n response: ExpressLikeResponse,\n next: ExpressLikeNext,\n) => void;\n\nexport interface ExpressTabPostPaidOptions {\n /**\n * Receives the pending recording, so a host, or a test, can await it. Called\n * with the same promise the plugin is working on, once per metered response.\n */\n readonly onMetering?: (metering: Promise<MeteringOutcome>) => void;\n /** Base URL used to make a relative Express URL absolute. Defaults to `http://localhost`. */\n readonly baseUrl?: string;\n readonly logger?: Logger;\n}\n\n/**\n * Builds the middleware. Install it before the handlers it should meter.\n *\n * ```ts\n * app.use(expressTabPostPaid(tabPostPaid({ ... })));\n * ```\n */\nexport function expressTabPostPaid(\n plugin: PostPaidPlugin,\n options: ExpressTabPostPaidOptions = {},\n): ExpressLikeMiddleware {\n const logger = options.logger ?? defaultLogger;\n const baseUrl = options.baseUrl ?? \"http://localhost\";\n\n return (request, response, next) => {\n const metered = meteredRequestFrom(request, baseUrl);\n\n if (plugin.release === \"before-metering\") {\n // Nothing is intercepted. The bytes leave, then the charge is recorded.\n response.on(\"finish\", () => {\n const metering = plugin.meter(metered, { status: response.statusCode });\n options.onMetering?.(metering);\n });\n next();\n return;\n }\n\n const chunks: Uint8Array[] = [];\n const originalWrite = response.write.bind(response);\n const originalEnd = response.end.bind(response);\n let ended = false;\n\n response.write = (...args: unknown[]): boolean => {\n const chunk = chunkOf(args, logger);\n if (chunk !== undefined) chunks.push(chunk);\n callbackOf(args)?.();\n return true;\n };\n\n response.end = (...args: unknown[]): unknown => {\n if (ended) return response;\n ended = true;\n const chunk = chunkOf(args, logger);\n if (chunk !== undefined) chunks.push(chunk);\n const done = callbackOf(args);\n\n // Restore before anything asynchronous, so the flush below writes through\n // the real methods and a second `end` from the framework is a no-op.\n response.write = originalWrite;\n response.end = originalEnd;\n\n const metering = plugin.meter(metered, { status: response.statusCode });\n options.onMetering?.(metering);\n void flush({ plugin, response, chunks, metering, done, originalEnd, logger });\n return response;\n };\n\n next();\n };\n}\n\n/** Records the delivery, then sends either the handler's bytes or the refusal. */\nasync function flush(input: {\n readonly plugin: PostPaidPlugin;\n readonly response: ExpressLikeResponse;\n readonly chunks: readonly Uint8Array[];\n readonly metering: Promise<MeteringOutcome>;\n readonly done: (() => void) | undefined;\n readonly originalEnd: (...args: unknown[]) => unknown;\n readonly logger: Logger;\n}): Promise<void> {\n const { plugin, response, chunks, originalEnd, logger } = input;\n const body = concat(chunks);\n\n let outcome: MeteringOutcome;\n try {\n outcome = await input.metering;\n } catch (thrown) {\n // The plugin does not reject. If it somehow did, the delivered response is\n // still the delivered response.\n logger.error(\"post-paid metering rejected, and the handler's response was sent unchanged\", {\n message: String(thrown),\n });\n send(response, originalEnd, body, input.done);\n return;\n }\n\n if (response.headersSent === true) {\n // The handler flushed its own headers, so neither a status nor a header can\n // change now. The bytes go out as written and the charge is already recorded.\n logger.warn(\"post-paid could not attach charge headers because the handler had already sent them\");\n send(response, originalEnd, body, input.done);\n return;\n }\n\n if (outcome.kind === \"refused\") {\n const refusal = plugin.refusalResponseFor(outcome);\n let payload: Uint8Array;\n try {\n payload = new Uint8Array(await refusal.arrayBuffer());\n } catch (thrown) {\n logger.error(\"post-paid could not read the refusal body, so the delivered response was sent\", {\n message: String(thrown),\n });\n send(response, originalEnd, body, input.done);\n return;\n }\n response.statusCode = refusal.status;\n refusal.headers.forEach((value, name) => {\n response.setHeader(name, value);\n });\n send(response, originalEnd, payload, input.done);\n return;\n }\n\n for (const [name, value] of Object.entries(plugin.headersFor(outcome))) {\n response.setHeader(name, value);\n }\n send(response, originalEnd, body, input.done);\n}\n\n/** Writes the payload, restating `Content-Length` because the body may have changed. */\nfunction send(\n response: ExpressLikeResponse,\n originalEnd: (...args: unknown[]) => unknown,\n body: Uint8Array,\n done: (() => void) | undefined,\n): void {\n response.setHeader(\"Content-Length\", String(body.byteLength));\n if (done === undefined) originalEnd(body);\n else originalEnd(body, done);\n}\n\n/**\n * Builds the framework-free request the plugin reads, without touching the body.\n *\n * The header lookup is `headerReaderOf` from the shared header contract, so the\n * case-insensitive matching and the repeated-value handling are the same code the\n * 402 client uses rather than a second copy of the same rules. Node lower-cases\n * every incoming header name and the plugin asks in canonical casing, which is\n * exactly the mismatch that reader exists to absorb.\n */\nexport function meteredRequestFrom(\n request: ExpressLikeRequest,\n baseUrl = \"http://localhost\",\n): MeteredRequest {\n const path = request.originalUrl ?? request.url ?? \"/\";\n return {\n method: request.method ?? \"GET\",\n url: absolute(path, baseUrl),\n headers: headerReaderOf(request.headers ?? {}),\n };\n}\n\n/** Makes an Express path absolute, because a `MeteredRequest` carries a URL. */\nfunction absolute(path: string, baseUrl: string): string {\n if (/^https?:\\/\\//i.test(path)) return path;\n try {\n return new URL(path, baseUrl).toString();\n } catch {\n return `${baseUrl}${path.startsWith(\"/\") ? \"\" : \"/\"}${path}`;\n }\n}\n\n/** The chunk a `write` or `end` call carried, as bytes. */\nfunction chunkOf(args: readonly unknown[], logger: Logger): Uint8Array | undefined {\n const chunk = args[0];\n if (chunk === undefined || chunk === null || typeof chunk === \"function\") return undefined;\n if (chunk instanceof Uint8Array) return chunk;\n if (typeof chunk !== \"string\") return undefined;\n\n const declared = typeof args[1] === \"string\" ? args[1] : \"utf8\";\n try {\n return new Uint8Array(Buffer.from(chunk, declared as BufferEncoding));\n } catch {\n logger.debug(\"post-paid read a response chunk as utf8 because its encoding was not recognised\", {\n declared,\n });\n return new Uint8Array(Buffer.from(chunk, \"utf8\"));\n }\n}\n\n/** The completion callback a `write` or `end` call carried, if any. */\nfunction callbackOf(args: readonly unknown[]): (() => void) | undefined {\n const last = args[args.length - 1];\n return typeof last === \"function\" ? (last as () => void) : undefined;\n}\n\n/** Joins the collected chunks into one payload. */\nfunction concat(chunks: readonly Uint8Array[]): Uint8Array {\n if (chunks.length === 1) return chunks[0] as Uint8Array;\n const total = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);\n const joined = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n joined.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return joined;\n}\n"]}
1
+ {"version":3,"file":"express.js","sourceRoot":"","sources":["../../../src/server/adapters/express.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Express middleware over the post-paid plugin.\n *\n * Express is the one framework of the three that does not hand a middleware a\n * response object to inspect. A handler writes into `res` and the bytes leave as\n * they are written, so \"meter after the handler produced its response\" has to be\n * arranged rather than expressed, and the two release orderings need genuinely\n * different plumbing:\n *\n * **`before-metering` intercepts nothing.** The middleware registers a `finish`\n * listener and calls `next()`. Express writes the response exactly as it would\n * without this SDK installed, and the delivery is recorded once the bytes are\n * gone. Nothing is buffered, nothing is delayed, and a streamed endpoint keeps\n * streaming. A refusal cannot reach this request, because the response left\n * before the charge was known.\n *\n * **`after-metering` holds the body, and only the body.** `res.write` and\n * `res.end` are intercepted, the chunks are collected, and the moment the handler\n * ends the response the delivery is recorded. Then either the collected bytes go\n * out with their charge headers, or, on the one refusal an Agent must clear -\n * the refusal goes out instead. The handler is never delayed: it writes, it ends,\n * it returns. What waits is the flush, and it waits on one credit record, never on\n * a payment.\n *\n * That interception is worth naming plainly: under `after-metering` this adapter\n * buffers the response body in memory until the handler ends the response, so it\n * is the wrong choice for a streamed or long-lived response. Use\n * `before-metering` for those, and the bytes are never touched.\n *\n * ## No dependency on Express\n *\n * The three parameter types are structural and describe only the fields the\n * middleware touches. Nothing here imports `express`, so a consumer on Hono\n * installs nothing extra and there is no Express version to keep in step.\n */\n\nimport type { Logger } from \"../../logger.js\";\nimport { defaultLogger } from \"../../logger.js\";\nimport { headerReaderOf } from \"../../http/headers.js\";\nimport type { MeteredRequest, MeteringOutcome, PostPaidPlugin } from \"../post-paid.js\";\n\n/** The request fields the middleware reads. An Express `req` satisfies it. */\nexport interface ExpressLikeRequest {\n readonly method?: string | undefined;\n readonly url?: string | undefined;\n /** Express's pre-router URL. Preferred over `url`, which a router rewrites. */\n readonly originalUrl?: string | undefined;\n readonly headers?: Readonly<Record<string, string | string[] | undefined>> | undefined;\n}\n\n/** The response fields the middleware touches. An Express `res` satisfies it. */\nexport interface ExpressLikeResponse {\n statusCode: number;\n readonly headersSent?: boolean;\n setHeader(name: string, value: string): unknown;\n removeHeader?(name: string): unknown;\n write(...args: unknown[]): boolean;\n end(...args: unknown[]): unknown;\n on(event: string, listener: () => void): unknown;\n}\n\n/** Express's continuation. An argument means the handler chain failed. */\nexport type ExpressLikeNext = (error?: unknown) => void;\n\nexport type ExpressLikeMiddleware = (\n request: ExpressLikeRequest,\n response: ExpressLikeResponse,\n next: ExpressLikeNext,\n) => void;\n\nexport interface ExpressTabPostPaidOptions {\n /**\n * Receives the pending recording, so a host, or a test, can await it. Called\n * with the same promise the plugin is working on, once per metered response.\n */\n readonly onMetering?: (metering: Promise<MeteringOutcome>) => void;\n /** Base URL used to make a relative Express URL absolute. Defaults to `http://localhost`. */\n readonly baseUrl?: string;\n readonly logger?: Logger;\n}\n\n/**\n * Builds the middleware. Install it before the handlers it should meter.\n *\n * ```ts\n * app.use(expressTabPostPaid(tabPostPaid({ ... })));\n * ```\n */\nexport function expressTabPostPaid(\n plugin: PostPaidPlugin,\n options: ExpressTabPostPaidOptions = {},\n): ExpressLikeMiddleware {\n const logger = options.logger ?? defaultLogger;\n const baseUrl = options.baseUrl ?? \"http://localhost\";\n\n return (request, response, next) => {\n const metered = meteredRequestFrom(request, baseUrl);\n\n if (plugin.release === \"before-metering\") {\n // Nothing is intercepted. The bytes leave, then the charge is recorded.\n response.on(\"finish\", () => {\n const metering = plugin.meter(metered, { status: response.statusCode });\n options.onMetering?.(metering);\n });\n next();\n return;\n }\n\n const chunks: Uint8Array[] = [];\n const originalWrite = response.write.bind(response);\n const originalEnd = response.end.bind(response);\n let ended = false;\n\n response.write = (...args: unknown[]): boolean => {\n const chunk = chunkOf(args, logger);\n if (chunk !== undefined) chunks.push(chunk);\n callbackOf(args)?.();\n return true;\n };\n\n response.end = (...args: unknown[]): unknown => {\n if (ended) return response;\n ended = true;\n const chunk = chunkOf(args, logger);\n if (chunk !== undefined) chunks.push(chunk);\n const done = callbackOf(args);\n\n // Restore before anything asynchronous, so the flush below writes through\n // the real methods and a second `end` from the framework is a no-op.\n response.write = originalWrite;\n response.end = originalEnd;\n\n const metering = plugin.meter(metered, { status: response.statusCode });\n options.onMetering?.(metering);\n void flush({ plugin, response, chunks, metering, done, originalEnd, logger });\n return response;\n };\n\n next();\n };\n}\n\n/** Records the delivery, then sends either the handler's bytes or the refusal. */\nasync function flush(input: {\n readonly plugin: PostPaidPlugin;\n readonly response: ExpressLikeResponse;\n readonly chunks: readonly Uint8Array[];\n readonly metering: Promise<MeteringOutcome>;\n readonly done: (() => void) | undefined;\n readonly originalEnd: (...args: unknown[]) => unknown;\n readonly logger: Logger;\n}): Promise<void> {\n const { plugin, response, chunks, originalEnd, logger } = input;\n const body = concat(chunks);\n\n let outcome: MeteringOutcome;\n try {\n outcome = await input.metering;\n } catch (thrown) {\n // The plugin does not reject. If it somehow did, the delivered response is\n // still the delivered response.\n logger.error(\"post-paid metering rejected, and the handler's response was sent unchanged\", {\n message: String(thrown),\n });\n send(response, originalEnd, body, input.done);\n return;\n }\n\n if (response.headersSent === true) {\n // The handler flushed its own headers, so neither a status nor a header can\n // change now. The bytes go out as written and the charge is already recorded.\n logger.warn(\"post-paid could not attach charge headers because the handler had already sent them\");\n send(response, originalEnd, body, input.done);\n return;\n }\n\n if (outcome.kind === \"refused\") {\n const refusal = plugin.refusalResponseFor(outcome);\n let payload: Uint8Array;\n try {\n payload = new Uint8Array(await refusal.arrayBuffer());\n } catch (thrown) {\n logger.error(\"post-paid could not read the refusal body, so the delivered response was sent\", {\n message: String(thrown),\n });\n send(response, originalEnd, body, input.done);\n return;\n }\n response.statusCode = refusal.status;\n refusal.headers.forEach((value, name) => {\n response.setHeader(name, value);\n });\n send(response, originalEnd, payload, input.done);\n return;\n }\n\n for (const [name, value] of Object.entries(plugin.headersFor(outcome))) {\n response.setHeader(name, value);\n }\n send(response, originalEnd, body, input.done);\n}\n\n/** Writes the payload, restating `Content-Length` because the body may have changed. */\nfunction send(\n response: ExpressLikeResponse,\n originalEnd: (...args: unknown[]) => unknown,\n body: Uint8Array,\n done: (() => void) | undefined,\n): void {\n response.setHeader(\"Content-Length\", String(body.byteLength));\n if (done === undefined) originalEnd(body);\n else originalEnd(body, done);\n}\n\n/**\n * Builds the framework-free request the plugin reads, without touching the body.\n *\n * The header lookup is `headerReaderOf` from the shared header contract, so the\n * case-insensitive matching and the repeated-value handling are the same code the\n * 402 client uses rather than a second copy of the same rules. Node lower-cases\n * every incoming header name and the plugin asks in canonical casing, which is\n * exactly the mismatch that reader exists to absorb.\n */\nexport function meteredRequestFrom(\n request: ExpressLikeRequest,\n baseUrl = \"http://localhost\",\n): MeteredRequest {\n const path = request.originalUrl ?? request.url ?? \"/\";\n return {\n method: request.method ?? \"GET\",\n url: absolute(path, baseUrl),\n headers: headerReaderOf(request.headers ?? {}),\n };\n}\n\n/** Makes an Express path absolute, because a `MeteredRequest` carries a URL. */\nfunction absolute(path: string, baseUrl: string): string {\n if (/^https?:\\/\\//i.test(path)) return path;\n try {\n return new URL(path, baseUrl).toString();\n } catch {\n return `${baseUrl}${path.startsWith(\"/\") ? \"\" : \"/\"}${path}`;\n }\n}\n\n/** The chunk a `write` or `end` call carried, as bytes. */\nfunction chunkOf(args: readonly unknown[], logger: Logger): Uint8Array | undefined {\n const chunk = args[0];\n if (chunk === undefined || chunk === null || typeof chunk === \"function\") return undefined;\n if (chunk instanceof Uint8Array) return chunk;\n if (typeof chunk !== \"string\") return undefined;\n\n const declared = typeof args[1] === \"string\" ? args[1] : \"utf8\";\n try {\n return new Uint8Array(Buffer.from(chunk, declared as BufferEncoding));\n } catch {\n logger.debug(\"post-paid read a response chunk as utf8 because its encoding was not recognised\", {\n declared,\n });\n return new Uint8Array(Buffer.from(chunk, \"utf8\"));\n }\n}\n\n/** The completion callback a `write` or `end` call carried, if any. */\nfunction callbackOf(args: readonly unknown[]): (() => void) | undefined {\n const last = args[args.length - 1];\n return typeof last === \"function\" ? (last as () => void) : undefined;\n}\n\n/** Joins the collected chunks into one payload. */\nfunction concat(chunks: readonly Uint8Array[]): Uint8Array {\n if (chunks.length === 1) return chunks[0] as Uint8Array;\n const total = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);\n const joined = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n joined.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return joined;\n}\n"]}
@@ -20,8 +20,6 @@
20
20
  * exists, a Worker, a runtime with a request lifetime, a `before-metering`
21
21
  * recording is handed to `waitUntil` so the runtime does not tear down while the
22
22
  * charge is still in flight.
23
- *
24
- * Requirements: 23.3, 12.1
25
23
  */
26
24
  import type { PostPaidPlugin } from "../post-paid.js";
27
25
  /** The two fields of a Hono context this middleware touches, and nothing else. */
@@ -1 +1 @@
1
- {"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/hono.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAkB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtE,kFAAkF;AAClF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAC;IACxC,GAAG,EAAE,QAAQ,CAAC;IACd,0EAA0E;IAC1E,QAAQ,CAAC,YAAY,CAAC,EAAE;QAAE,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAA;KAAE,CAAC;CACxE;AAED,sCAAsC;AACtC,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;AAE/C,4CAA4C;AAC5C,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEjG;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,kBAAkB,CAmB1E"}
1
+ {"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/hono.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAkB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtE,kFAAkF;AAClF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAC;IACxC,GAAG,EAAE,QAAQ,CAAC;IACd,0EAA0E;IAC1E,QAAQ,CAAC,YAAY,CAAC,EAAE;QAAE,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAA;KAAE,CAAC;CACxE;AAED,sCAAsC;AACtC,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;AAE/C,4CAA4C;AAC5C,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEjG;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,kBAAkB,CAmB1E"}
@@ -20,8 +20,6 @@
20
20
  * exists, a Worker, a runtime with a request lifetime, a `before-metering`
21
21
  * recording is handed to `waitUntil` so the runtime does not tear down while the
22
22
  * charge is still in flight.
23
- *
24
- * Requirements: 23.3, 12.1
25
23
  */
26
24
  /**
27
25
  * Builds the middleware.
@@ -1 +1 @@
1
- {"version":3,"file":"hono.js","sourceRoot":"","sources":["../../../src/server/adapters/hono.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAkBH;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,MAAsB;IACpD,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC7B,6EAA6E;QAC7E,mCAAmC;QACnC,MAAM,OAAO,GAAmB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;QAEhD,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE;YACzD,MAAM,IAAI,EAAE,CAAC;YACb,OAAO,OAAO,CAAC,GAAG,CAAC;QACrB,CAAC,CAAC,CAAC;QAEH,IAAI,SAAS,CAAC,IAAI,KAAK,gBAAgB;YAAE,MAAM,SAAS,CAAC,MAAM,CAAC;QAEhE,OAAO,CAAC,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC;QAEjC,IAAI,SAAS,CAAC,IAAI,KAAK,WAAW,IAAI,MAAM,CAAC,OAAO,KAAK,iBAAiB,EAAE,CAAC;YAC3E,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,yFAAyF;AACzF,SAAS,SAAS,CAAC,OAAwB,EAAE,QAA0B;IACrE,IAAI,CAAC;QACH,OAAO,CAAC,YAAY,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,4EAA4E;IAC9E,CAAC;AACH,CAAC","sourcesContent":["/**\n * Hono middleware over the post-paid plugin.\n *\n * Hono already speaks the web standard, so this adapter is almost nothing: it\n * awaits `next()`, hands `c.res` to the plugin, and puts back whatever the plugin\n * says goes out. The whole of the ordering guarantee is the `await next()` on the\n * first line of the handler closure, the handler chain runs to completion, and\n * only the response it produced is metered.\n *\n * ## No dependency on Hono\n *\n * The context and next types below are structural, so this file compiles with no\n * `hono` import, no `hono` dependency, and no `hono` version to keep in step. A\n * consumer using Express should not be made to install Hono to use this SDK, and\n * the two fields the middleware touches, `c.req.raw` and `c.res`, are stable\n * across Hono 3 and 4.\n *\n * `c.executionCtx` is read through a `try`, because on a Hono context with no\n * execution context the getter throws rather than returning undefined. Where it\n * exists, a Worker, a runtime with a request lifetime, a `before-metering`\n * recording is handed to `waitUntil` so the runtime does not tear down while the\n * charge is still in flight.\n *\n * Requirements: 23.3, 12.1\n */\n\nimport type { MeteredRequest, PostPaidPlugin } from \"../post-paid.js\";\n\n/** The two fields of a Hono context this middleware touches, and nothing else. */\nexport interface HonoLikeContext {\n readonly req: { readonly raw: Request };\n res: Response;\n /** Present on a runtime with a request lifetime. Reading it may throw. */\n readonly executionCtx?: { waitUntil(promise: Promise<unknown>): void };\n}\n\n/** Hono's downstream continuation. */\nexport type HonoLikeNext = () => Promise<void>;\n\n/** What Hono expects a middleware to be. */\nexport type HonoLikeMiddleware = (context: HonoLikeContext, next: HonoLikeNext) => Promise<void>;\n\n/**\n * Builds the middleware.\n *\n * On `handler-failed` the thrown value is re-raised unchanged so Hono's own\n * `onError` sees exactly what the handler threw. That re-raise is the one place\n * this file throws, and it is the adapter boundary the zero-throw rule names: the\n * plugin returned a value, and the framework's contract for a failed handler is\n * an exception.\n */\nexport function honoTabPostPaid(plugin: PostPaidPlugin): HonoLikeMiddleware {\n return async (context, next) => {\n // A web-standard `Request` already satisfies `MeteredRequest`, so nothing is\n // rebuilt and no header is copied.\n const request: MeteredRequest = context.req.raw;\n\n const execution = await plugin.execute(request, async () => {\n await next();\n return context.res;\n });\n\n if (execution.kind === \"handler-failed\") throw execution.thrown;\n\n context.res = execution.response;\n\n if (execution.kind === \"delivered\" && plugin.release === \"before-metering\") {\n waitUntil(context, execution.metering);\n }\n };\n}\n\n/** Hands the pending recording to the runtime's request lifetime, where there is one. */\nfunction waitUntil(context: HonoLikeContext, metering: Promise<unknown>): void {\n try {\n context.executionCtx?.waitUntil(metering);\n } catch {\n // No execution context. The recording still runs; nothing is waiting on it.\n }\n}\n"]}
1
+ {"version":3,"file":"hono.js","sourceRoot":"","sources":["../../../src/server/adapters/hono.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAkBH;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,MAAsB;IACpD,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC7B,6EAA6E;QAC7E,mCAAmC;QACnC,MAAM,OAAO,GAAmB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;QAEhD,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE;YACzD,MAAM,IAAI,EAAE,CAAC;YACb,OAAO,OAAO,CAAC,GAAG,CAAC;QACrB,CAAC,CAAC,CAAC;QAEH,IAAI,SAAS,CAAC,IAAI,KAAK,gBAAgB;YAAE,MAAM,SAAS,CAAC,MAAM,CAAC;QAEhE,OAAO,CAAC,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC;QAEjC,IAAI,SAAS,CAAC,IAAI,KAAK,WAAW,IAAI,MAAM,CAAC,OAAO,KAAK,iBAAiB,EAAE,CAAC;YAC3E,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,yFAAyF;AACzF,SAAS,SAAS,CAAC,OAAwB,EAAE,QAA0B;IACrE,IAAI,CAAC;QACH,OAAO,CAAC,YAAY,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,4EAA4E;IAC9E,CAAC;AACH,CAAC","sourcesContent":["/**\n * Hono middleware over the post-paid plugin.\n *\n * Hono already speaks the web standard, so this adapter is almost nothing: it\n * awaits `next()`, hands `c.res` to the plugin, and puts back whatever the plugin\n * says goes out. The whole of the ordering guarantee is the `await next()` on the\n * first line of the handler closure, the handler chain runs to completion, and\n * only the response it produced is metered.\n *\n * ## No dependency on Hono\n *\n * The context and next types below are structural, so this file compiles with no\n * `hono` import, no `hono` dependency, and no `hono` version to keep in step. A\n * consumer using Express should not be made to install Hono to use this SDK, and\n * the two fields the middleware touches, `c.req.raw` and `c.res`, are stable\n * across Hono 3 and 4.\n *\n * `c.executionCtx` is read through a `try`, because on a Hono context with no\n * execution context the getter throws rather than returning undefined. Where it\n * exists, a Worker, a runtime with a request lifetime, a `before-metering`\n * recording is handed to `waitUntil` so the runtime does not tear down while the\n * charge is still in flight.\n */\n\nimport type { MeteredRequest, PostPaidPlugin } from \"../post-paid.js\";\n\n/** The two fields of a Hono context this middleware touches, and nothing else. */\nexport interface HonoLikeContext {\n readonly req: { readonly raw: Request };\n res: Response;\n /** Present on a runtime with a request lifetime. Reading it may throw. */\n readonly executionCtx?: { waitUntil(promise: Promise<unknown>): void };\n}\n\n/** Hono's downstream continuation. */\nexport type HonoLikeNext = () => Promise<void>;\n\n/** What Hono expects a middleware to be. */\nexport type HonoLikeMiddleware = (context: HonoLikeContext, next: HonoLikeNext) => Promise<void>;\n\n/**\n * Builds the middleware.\n *\n * On `handler-failed` the thrown value is re-raised unchanged so Hono's own\n * `onError` sees exactly what the handler threw. That re-raise is the one place\n * this file throws, and it is the adapter boundary the zero-throw rule names: the\n * plugin returned a value, and the framework's contract for a failed handler is\n * an exception.\n */\nexport function honoTabPostPaid(plugin: PostPaidPlugin): HonoLikeMiddleware {\n return async (context, next) => {\n // A web-standard `Request` already satisfies `MeteredRequest`, so nothing is\n // rebuilt and no header is copied.\n const request: MeteredRequest = context.req.raw;\n\n const execution = await plugin.execute(request, async () => {\n await next();\n return context.res;\n });\n\n if (execution.kind === \"handler-failed\") throw execution.thrown;\n\n context.res = execution.response;\n\n if (execution.kind === \"delivered\" && plugin.release === \"before-metering\") {\n waitUntil(context, execution.metering);\n }\n };\n}\n\n/** Hands the pending recording to the runtime's request lifetime, where there is one. */\nfunction waitUntil(context: HonoLikeContext, metering: Promise<unknown>): void {\n try {\n context.executionCtx?.waitUntil(metering);\n } catch {\n // No execution context. The recording still runs; nothing is waiting on it.\n }\n}\n"]}
@@ -27,8 +27,6 @@
27
27
  *
28
28
  * With no `after` and `before-metering`, the recording is best-effort, which is
29
29
  * why `after-metering` is the default the plugin ships with.
30
- *
31
- * Requirements: 23.3, 12.1
32
30
  */
33
31
  import type { PostPaidPlugin } from "../post-paid.js";
34
32
  /** A Next.js App Router route handler. `Ctx` carries the matched route parameters. */
@@ -1 +1 @@
1
- {"version":3,"file":"next.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/next.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAkB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtE,sFAAsF;AACtF,MAAM,MAAM,gBAAgB,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;AAErG,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;CACzD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,GAAG,EACjC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAAC,EAC9B,OAAO,GAAE,sBAA2B,GACnC,gBAAgB,CAAC,GAAG,CAAC,CAgBvB"}
1
+ {"version":3,"file":"next.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/next.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAkB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtE,sFAAsF;AACtF,MAAM,MAAM,gBAAgB,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;AAErG,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;CACzD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,GAAG,EACjC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAAC,EAC9B,OAAO,GAAE,sBAA2B,GACnC,gBAAgB,CAAC,GAAG,CAAC,CAgBvB"}
@@ -27,8 +27,6 @@
27
27
  *
28
28
  * With no `after` and `before-metering`, the recording is best-effort, which is
29
29
  * why `after-metering` is the default the plugin ships with.
30
- *
31
- * Requirements: 23.3, 12.1
32
30
  */
33
31
  /**
34
32
  * Wraps one route handler.
@@ -1 +1 @@
1
- {"version":3,"file":"next.js","sourceRoot":"","sources":["../../../src/server/adapters/next.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAeH;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAsB,EACtB,OAA8B,EAC9B,UAAkC,EAAE;IAEpC,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;QAChC,+DAA+D;QAC/D,MAAM,OAAO,GAAmB,OAAO,CAAC;QAExC,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAEjF,IAAI,SAAS,CAAC,IAAI,KAAK,gBAAgB;YAAE,MAAM,SAAS,CAAC,MAAM,CAAC;QAEhE,IAAI,SAAS,CAAC,IAAI,KAAK,WAAW,IAAI,MAAM,CAAC,OAAO,KAAK,iBAAiB,EAAE,CAAC;YAC3E,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC;YAChC,IAAI,SAAS,KAAK,SAAS;gBAAE,SAAS,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACnE,CAAC;QAED,OAAO,SAAS,CAAC,QAAQ,CAAC;IAC5B,CAAC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Next.js route-handler wrapper over the post-paid plugin.\n *\n * A Next.js route handler is `(request: Request, context) => Response`, which is\n * the web standard with a second argument for the matched route parameters. So\n * this adapter is a function that returns a function: the handler is called with\n * both arguments untouched, its response is metered, and the response the plugin\n * says goes out is returned.\n *\n * ## No dependency on Next.js\n *\n * Nothing here imports `next`. The handler shape is standard, and the one\n * Next-specific facility the adapter can use, a hook that keeps work alive after\n * the response has been sent, is taken as an argument rather than imported, so\n * this file has no framework version to track and a consumer on another framework\n * installs nothing.\n *\n * Under `release: \"before-metering\"` the recording is still in flight when the\n * response is returned. On a serverless runtime that is a real hazard: the\n * invocation can be frozen the moment the response is written. Pass `after` from\n * `next/server` where the Next version has it, and the recording is kept alive:\n *\n * ```ts\n * import { after } from \"next/server\";\n * export const GET = withTabPostPaid(plugin, handler, { after });\n * ```\n *\n * With no `after` and `before-metering`, the recording is best-effort, which is\n * why `after-metering` is the default the plugin ships with.\n *\n * Requirements: 23.3, 12.1\n */\n\nimport type { MeteredRequest, PostPaidPlugin } from \"../post-paid.js\";\n\n/** A Next.js App Router route handler. `Ctx` carries the matched route parameters. */\nexport type NextRouteHandler<Ctx> = (request: Request, context: Ctx) => Response | Promise<Response>;\n\nexport interface NextTabPostPaidOptions {\n /**\n * A hook that keeps work alive past the response, such as `after` from\n * `next/server`. Used under `release: \"before-metering\"` and ignored otherwise.\n */\n readonly after?: (task: () => Promise<unknown>) => void;\n}\n\n/**\n * Wraps one route handler.\n *\n * A handler that throws is re-raised unchanged, so Next's own error handling sees\n * what the handler threw and nothing is metered for a delivery that did not\n * happen. That re-raise is the adapter boundary where a returned value becomes the\n * exception the framework's contract expects.\n */\nexport function withTabPostPaid<Ctx>(\n plugin: PostPaidPlugin,\n handler: NextRouteHandler<Ctx>,\n options: NextTabPostPaidOptions = {},\n): NextRouteHandler<Ctx> {\n return async (request, context) => {\n // A web-standard `Request` already satisfies `MeteredRequest`.\n const metered: MeteredRequest = request;\n\n const execution = await plugin.execute(metered, () => handler(request, context));\n\n if (execution.kind === \"handler-failed\") throw execution.thrown;\n\n if (execution.kind === \"delivered\" && plugin.release === \"before-metering\") {\n const keepAlive = options.after;\n if (keepAlive !== undefined) keepAlive(() => execution.metering);\n }\n\n return execution.response;\n };\n}\n"]}
1
+ {"version":3,"file":"next.js","sourceRoot":"","sources":["../../../src/server/adapters/next.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAeH;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAsB,EACtB,OAA8B,EAC9B,UAAkC,EAAE;IAEpC,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;QAChC,+DAA+D;QAC/D,MAAM,OAAO,GAAmB,OAAO,CAAC;QAExC,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAEjF,IAAI,SAAS,CAAC,IAAI,KAAK,gBAAgB;YAAE,MAAM,SAAS,CAAC,MAAM,CAAC;QAEhE,IAAI,SAAS,CAAC,IAAI,KAAK,WAAW,IAAI,MAAM,CAAC,OAAO,KAAK,iBAAiB,EAAE,CAAC;YAC3E,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC;YAChC,IAAI,SAAS,KAAK,SAAS;gBAAE,SAAS,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACnE,CAAC;QAED,OAAO,SAAS,CAAC,QAAQ,CAAC;IAC5B,CAAC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Next.js route-handler wrapper over the post-paid plugin.\n *\n * A Next.js route handler is `(request: Request, context) => Response`, which is\n * the web standard with a second argument for the matched route parameters. So\n * this adapter is a function that returns a function: the handler is called with\n * both arguments untouched, its response is metered, and the response the plugin\n * says goes out is returned.\n *\n * ## No dependency on Next.js\n *\n * Nothing here imports `next`. The handler shape is standard, and the one\n * Next-specific facility the adapter can use, a hook that keeps work alive after\n * the response has been sent, is taken as an argument rather than imported, so\n * this file has no framework version to track and a consumer on another framework\n * installs nothing.\n *\n * Under `release: \"before-metering\"` the recording is still in flight when the\n * response is returned. On a serverless runtime that is a real hazard: the\n * invocation can be frozen the moment the response is written. Pass `after` from\n * `next/server` where the Next version has it, and the recording is kept alive:\n *\n * ```ts\n * import { after } from \"next/server\";\n * export const GET = withTabPostPaid(plugin, handler, { after });\n * ```\n *\n * With no `after` and `before-metering`, the recording is best-effort, which is\n * why `after-metering` is the default the plugin ships with.\n */\n\nimport type { MeteredRequest, PostPaidPlugin } from \"../post-paid.js\";\n\n/** A Next.js App Router route handler. `Ctx` carries the matched route parameters. */\nexport type NextRouteHandler<Ctx> = (request: Request, context: Ctx) => Response | Promise<Response>;\n\nexport interface NextTabPostPaidOptions {\n /**\n * A hook that keeps work alive past the response, such as `after` from\n * `next/server`. Used under `release: \"before-metering\"` and ignored otherwise.\n */\n readonly after?: (task: () => Promise<unknown>) => void;\n}\n\n/**\n * Wraps one route handler.\n *\n * A handler that throws is re-raised unchanged, so Next's own error handling sees\n * what the handler threw and nothing is metered for a delivery that did not\n * happen. That re-raise is the adapter boundary where a returned value becomes the\n * exception the framework's contract expects.\n */\nexport function withTabPostPaid<Ctx>(\n plugin: PostPaidPlugin,\n handler: NextRouteHandler<Ctx>,\n options: NextTabPostPaidOptions = {},\n): NextRouteHandler<Ctx> {\n return async (request, context) => {\n // A web-standard `Request` already satisfies `MeteredRequest`.\n const metered: MeteredRequest = request;\n\n const execution = await plugin.execute(metered, () => handler(request, context));\n\n if (execution.kind === \"handler-failed\") throw execution.thrown;\n\n if (execution.kind === \"delivered\" && plugin.release === \"before-metering\") {\n const keepAlive = options.after;\n if (keepAlive !== undefined) keepAlive(() => execution.metering);\n }\n\n return execution.response;\n };\n}\n"]}
@@ -5,17 +5,17 @@
5
5
  * `tabPostPaid` is the whole product claim in one function. A Service installs it,
6
6
  * keeps writing handlers the way it already does, and its Open Tab accrues behind
7
7
  * each delivered response. No caller prepays, no response waits on a payment, and
8
- * the one status this surface adds is a `402` on `LimitExceeded`, a credit
9
- * decision, not a prepayment demand (R23.3, R12.1).
8
+ * the one status this surface adds is a `402` on `LimitExceeded`: a credit
9
+ * decision, not a prepayment demand.
10
10
  *
11
11
  * The adapters are thin by design and carry no dependency on the framework they
12
12
  * adapt: every framework type in here is structural, so a Service on Hono installs
13
13
  * nothing for Express and nothing for Next.js.
14
14
  *
15
15
  * The wire format is not defined here. `src/http/headers.ts` owns it, this surface
16
- * is its emitting half, and the 402 client of R23.2 is its reading half, so a
17
- * disagreement about a header is a test failure in one file rather than a silent
18
- * mis-parse between two.
16
+ * is its emitting half, and the 402 client in `src/http/client-402.ts` is its
17
+ * reading half, so a disagreement about a header is a test failure in one file
18
+ * rather than a silent mis-parse between two.
19
19
  *
20
20
  * Nothing exported here throws, with one named exception: the Hono and Next.js
21
21
  * adapters re-raise a handler's own thrown value, because a framework's contract
@@ -5,17 +5,17 @@
5
5
  * `tabPostPaid` is the whole product claim in one function. A Service installs it,
6
6
  * keeps writing handlers the way it already does, and its Open Tab accrues behind
7
7
  * each delivered response. No caller prepays, no response waits on a payment, and
8
- * the one status this surface adds is a `402` on `LimitExceeded`, a credit
9
- * decision, not a prepayment demand (R23.3, R12.1).
8
+ * the one status this surface adds is a `402` on `LimitExceeded`: a credit
9
+ * decision, not a prepayment demand.
10
10
  *
11
11
  * The adapters are thin by design and carry no dependency on the framework they
12
12
  * adapt: every framework type in here is structural, so a Service on Hono installs
13
13
  * nothing for Express and nothing for Next.js.
14
14
  *
15
15
  * The wire format is not defined here. `src/http/headers.ts` owns it, this surface
16
- * is its emitting half, and the 402 client of R23.2 is its reading half, so a
17
- * disagreement about a header is a test failure in one file rather than a silent
18
- * mis-parse between two.
16
+ * is its emitting half, and the 402 client in `src/http/client-402.ts` is its
17
+ * reading half, so a disagreement about a header is a test failure in one file
18
+ * rather than a silent mis-parse between two.
19
19
  *
20
20
  * Nothing exported here throws, with one named exception: the Hono and Next.js
21
21
  * adapters re-raise a handler's own thrown value, because a framework's contract
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC","sourcesContent":["/**\n * The server-side surface: the post-paid plugin, the metering seam, and the three\n * framework adapters.\n *\n * `tabPostPaid` is the whole product claim in one function. A Service installs it,\n * keeps writing handlers the way it already does, and its Open Tab accrues behind\n * each delivered response. No caller prepays, no response waits on a payment, and\n * the one status this surface adds is a `402` on `LimitExceeded`, a credit\n * decision, not a prepayment demand (R23.3, R12.1).\n *\n * The adapters are thin by design and carry no dependency on the framework they\n * adapt: every framework type in here is structural, so a Service on Hono installs\n * nothing for Express and nothing for Next.js.\n *\n * The wire format is not defined here. `src/http/headers.ts` owns it, this surface\n * is its emitting half, and the 402 client of R23.2 is its reading half, so a\n * disagreement about a header is a test failure in one file rather than a silent\n * mis-parse between two.\n *\n * Nothing exported here throws, with one named exception: the Hono and Next.js\n * adapters re-raise a handler's own thrown value, because a framework's contract\n * for a failed handler is an exception and the adapter is the boundary where a\n * `Result` becomes whatever the host expects.\n */\n\nexport * from \"./metering.js\";\nexport * from \"./post-paid.js\";\nexport * from \"./adapters/hono.js\";\nexport * from \"./adapters/express.js\";\nexport * from \"./adapters/next.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC","sourcesContent":["/**\n * The server-side surface: the post-paid plugin, the metering seam, and the three\n * framework adapters.\n *\n * `tabPostPaid` is the whole product claim in one function. A Service installs it,\n * keeps writing handlers the way it already does, and its Open Tab accrues behind\n * each delivered response. No caller prepays, no response waits on a payment, and\n * the one status this surface adds is a `402` on `LimitExceeded`: a credit\n * decision, not a prepayment demand.\n *\n * The adapters are thin by design and carry no dependency on the framework they\n * adapt: every framework type in here is structural, so a Service on Hono installs\n * nothing for Express and nothing for Next.js.\n *\n * The wire format is not defined here. `src/http/headers.ts` owns it, this surface\n * is its emitting half, and the 402 client in `src/http/client-402.ts` is its\n * reading half, so a disagreement about a header is a test failure in one file\n * rather than a silent mis-parse between two.\n *\n * Nothing exported here throws, with one named exception: the Hono and Next.js\n * adapters re-raise a handler's own thrown value, because a framework's contract\n * for a failed handler is an exception and the adapter is the boundary where a\n * `Result` becomes whatever the host expects.\n */\n\nexport * from \"./metering.js\";\nexport * from \"./post-paid.js\";\nexport * from \"./adapters/hono.js\";\nexport * from \"./adapters/express.js\";\nexport * from \"./adapters/next.js\";\n"]}
@@ -20,8 +20,8 @@
20
20
  * the authorisation (`AuthorisationMissing`, `AuthorisationExpired`,
21
21
  * `AuthorisationExceeded`), and the headroom check (`LimitExceeded`, plus the
22
22
  * witness-validation errors the Credit Limit computation raises). Every name in
23
- * {@link RECORD_DELIVERY_REVERTS} is one of those; nothing in the table was
24
- * guessed from the design.
23
+ * {@link RECORD_DELIVERY_REVERTS} is one of those, read off the deployed
24
+ * contract's errors.
25
25
  *
26
26
  * ## Whose fault it is decides who sees it
27
27
  *
@@ -46,8 +46,6 @@
46
46
  *
47
47
  * Every amount here is an integer count of Asset base units as a `bigint`. USDC
48
48
  * is 6 decimals, and nothing in this module converts, scales, or rounds.
49
- *
50
- * Requirements: 23.3, 12.1, 12.2, 12.3, 21.5
51
49
  */
52
50
  import { type Address, type Bytes32, type ErrorCategory, type Hex, type Result, type TabError } from "../_shared/index.js";
53
51
  import type { AssetRef } from "../payments/strategy.js";
@@ -97,10 +95,10 @@ export interface DeliveryReceipt {
97
95
  *
98
96
  * Narrow on purpose: this is what lets a Service meter against a real signer in
99
97
  * production and against a stub in a test without the plugin knowing the
100
- * difference. Both methods return a `Result` and neither throws (design section
101
- * 13.1). On a revert, `recordDelivery` returns the `TabError`
102
- * {@link classifyRecordDeliveryRevert} produces, so the plugin reads the
103
- * disposition off `details.disposition` rather than re-decoding contract data.
98
+ * difference. Both methods return a `Result` and neither throws. On a revert,
99
+ * `recordDelivery` returns the `TabError` {@link classifyRecordDeliveryRevert}
100
+ * produces, so the plugin reads the disposition off `details.disposition` rather
101
+ * than re-decoding contract data.
104
102
  */
105
103
  export interface TabBookClient {
106
104
  recordDelivery(delivery: MeteredDelivery): Promise<Result<DeliveryReceipt>>;
@@ -140,7 +138,7 @@ export declare const TAB_BOOK_RECORD_DELIVERY_ABI: readonly ["function recordDel
140
138
  export type RefusalDisposition = "refuse-request" | "deliver-anyway";
141
139
  /** One row of the revert mapping table. */
142
140
  export interface RevertMapping {
143
- /** The `TabError` category, which is also what fixes the HTTP status (design section 13.1). */
141
+ /** The `TabError` category, which is also what fixes the HTTP status. */
144
142
  readonly category: ErrorCategory;
145
143
  /** Stable and machine-readable, for example `LIMIT_EXCEEDED`. */
146
144
  readonly code: string;
@@ -159,8 +157,8 @@ export interface RevertMapping {
159
157
  * Every revert `recordDelivery` can produce, and what each one becomes.
160
158
  *
161
159
  * The status each row maps to is not stored: it is `httpStatusOf(category)`, so
162
- * `LIMIT` is 402 and nothing else is, which is the whole of design section 9.5's
163
- * rule expressed as a lookup rather than as a comment.
160
+ * `LIMIT` is 402 and nothing else is, which is the whole rule expressed as a
161
+ * lookup rather than as a comment.
164
162
  */
165
163
  export declare const RECORD_DELIVERY_REVERTS: Readonly<Record<string, RevertMapping>>;
166
164
  /** The revert name and decoded arguments, as `ethers` v6 reports them. */
@@ -1 +1 @@
1
- {"version":3,"file":"metering.d.ts","sourceRoot":"","sources":["../../src/server/metering.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"metering.d.ts","sourceRoot":"","sources":["../../src/server/metering.ts"],"names":[],"mappings":"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"}