@tabai/sdk 0.2.0

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 (204) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +401 -0
  3. package/bin/tab.mjs +23 -0
  4. package/dist/_shared/abi.d.ts +150 -0
  5. package/dist/_shared/abi.d.ts.map +1 -0
  6. package/dist/_shared/abi.js +197 -0
  7. package/dist/_shared/abi.js.map +1 -0
  8. package/dist/_shared/chains.d.ts +118 -0
  9. package/dist/_shared/chains.d.ts.map +1 -0
  10. package/dist/_shared/chains.js +89 -0
  11. package/dist/_shared/chains.js.map +1 -0
  12. package/dist/_shared/hex.d.ts +35 -0
  13. package/dist/_shared/hex.d.ts.map +1 -0
  14. package/dist/_shared/hex.js +40 -0
  15. package/dist/_shared/hex.js.map +1 -0
  16. package/dist/_shared/index.d.ts +14 -0
  17. package/dist/_shared/index.d.ts.map +1 -0
  18. package/dist/_shared/index.js +14 -0
  19. package/dist/_shared/index.js.map +1 -0
  20. package/dist/_shared/keccak256.d.ts +29 -0
  21. package/dist/_shared/keccak256.d.ts.map +1 -0
  22. package/dist/_shared/keccak256.js +145 -0
  23. package/dist/_shared/keccak256.js.map +1 -0
  24. package/dist/_shared/result.d.ts +78 -0
  25. package/dist/_shared/result.d.ts.map +1 -0
  26. package/dist/_shared/result.js +61 -0
  27. package/dist/_shared/result.js.map +1 -0
  28. package/dist/cli/client-config.d.ts +155 -0
  29. package/dist/cli/client-config.d.ts.map +1 -0
  30. package/dist/cli/client-config.js +382 -0
  31. package/dist/cli/client-config.js.map +1 -0
  32. package/dist/cli/connect.d.ts +76 -0
  33. package/dist/cli/connect.d.ts.map +1 -0
  34. package/dist/cli/connect.js +158 -0
  35. package/dist/cli/connect.js.map +1 -0
  36. package/dist/cli/doctor.d.ts +57 -0
  37. package/dist/cli/doctor.d.ts.map +1 -0
  38. package/dist/cli/doctor.js +253 -0
  39. package/dist/cli/doctor.js.map +1 -0
  40. package/dist/cli/index.d.ts +13 -0
  41. package/dist/cli/index.d.ts.map +1 -0
  42. package/dist/cli/index.js +13 -0
  43. package/dist/cli/index.js.map +1 -0
  44. package/dist/cli/main.d.ts +45 -0
  45. package/dist/cli/main.d.ts.map +1 -0
  46. package/dist/cli/main.js +371 -0
  47. package/dist/cli/main.js.map +1 -0
  48. package/dist/errors.d.ts +29 -0
  49. package/dist/errors.d.ts.map +1 -0
  50. package/dist/errors.js +37 -0
  51. package/dist/errors.js.map +1 -0
  52. package/dist/http/client-402.d.ts +243 -0
  53. package/dist/http/client-402.d.ts.map +1 -0
  54. package/dist/http/client-402.js +515 -0
  55. package/dist/http/client-402.js.map +1 -0
  56. package/dist/http/headers.d.ts +173 -0
  57. package/dist/http/headers.d.ts.map +1 -0
  58. package/dist/http/headers.js +284 -0
  59. package/dist/http/headers.js.map +1 -0
  60. package/dist/http/index.d.ts +15 -0
  61. package/dist/http/index.d.ts.map +1 -0
  62. package/dist/http/index.js +15 -0
  63. package/dist/http/index.js.map +1 -0
  64. package/dist/http/metering-claim.d.ts +82 -0
  65. package/dist/http/metering-claim.d.ts.map +1 -0
  66. package/dist/http/metering-claim.js +99 -0
  67. package/dist/http/metering-claim.js.map +1 -0
  68. package/dist/index.d.ts +48 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +51 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/logger.d.ts +40 -0
  73. package/dist/logger.d.ts.map +1 -0
  74. package/dist/logger.js +50 -0
  75. package/dist/logger.js.map +1 -0
  76. package/dist/mcp/assets.d.ts +31 -0
  77. package/dist/mcp/assets.d.ts.map +1 -0
  78. package/dist/mcp/assets.js +78 -0
  79. package/dist/mcp/assets.js.map +1 -0
  80. package/dist/mcp/index.d.ts +19 -0
  81. package/dist/mcp/index.d.ts.map +1 -0
  82. package/dist/mcp/index.js +19 -0
  83. package/dist/mcp/index.js.map +1 -0
  84. package/dist/mcp/json-schema.d.ts +86 -0
  85. package/dist/mcp/json-schema.d.ts.map +1 -0
  86. package/dist/mcp/json-schema.js +215 -0
  87. package/dist/mcp/json-schema.js.map +1 -0
  88. package/dist/mcp/json.d.ts +43 -0
  89. package/dist/mcp/json.d.ts.map +1 -0
  90. package/dist/mcp/json.js +69 -0
  91. package/dist/mcp/json.js.map +1 -0
  92. package/dist/mcp/registry-client.d.ts +88 -0
  93. package/dist/mcp/registry-client.d.ts.map +1 -0
  94. package/dist/mcp/registry-client.js +158 -0
  95. package/dist/mcp/registry-client.js.map +1 -0
  96. package/dist/mcp/schemas.d.ts +82 -0
  97. package/dist/mcp/schemas.d.ts.map +1 -0
  98. package/dist/mcp/schemas.js +493 -0
  99. package/dist/mcp/schemas.js.map +1 -0
  100. package/dist/mcp/server.d.ts +97 -0
  101. package/dist/mcp/server.d.ts.map +1 -0
  102. package/dist/mcp/server.js +285 -0
  103. package/dist/mcp/server.js.map +1 -0
  104. package/dist/mcp/settings.d.ts +90 -0
  105. package/dist/mcp/settings.d.ts.map +1 -0
  106. package/dist/mcp/settings.js +160 -0
  107. package/dist/mcp/settings.js.map +1 -0
  108. package/dist/mcp/toolset.d.ts +231 -0
  109. package/dist/mcp/toolset.d.ts.map +1 -0
  110. package/dist/mcp/toolset.js +760 -0
  111. package/dist/mcp/toolset.js.map +1 -0
  112. package/dist/payments/abi.d.ts +9 -0
  113. package/dist/payments/abi.d.ts.map +1 -0
  114. package/dist/payments/abi.js +17 -0
  115. package/dist/payments/abi.js.map +1 -0
  116. package/dist/payments/config.d.ts +199 -0
  117. package/dist/payments/config.d.ts.map +1 -0
  118. package/dist/payments/config.js +259 -0
  119. package/dist/payments/config.js.map +1 -0
  120. package/dist/payments/index.d.ts +13 -0
  121. package/dist/payments/index.d.ts.map +1 -0
  122. package/dist/payments/index.js +13 -0
  123. package/dist/payments/index.js.map +1 -0
  124. package/dist/payments/kuru.d.ts +191 -0
  125. package/dist/payments/kuru.d.ts.map +1 -0
  126. package/dist/payments/kuru.js +377 -0
  127. package/dist/payments/kuru.js.map +1 -0
  128. package/dist/payments/monad.d.ts +69 -0
  129. package/dist/payments/monad.d.ts.map +1 -0
  130. package/dist/payments/monad.js +306 -0
  131. package/dist/payments/monad.js.map +1 -0
  132. package/dist/payments/permit2.d.ts +118 -0
  133. package/dist/payments/permit2.d.ts.map +1 -0
  134. package/dist/payments/permit2.js +366 -0
  135. package/dist/payments/permit2.js.map +1 -0
  136. package/dist/payments/registry.d.ts +119 -0
  137. package/dist/payments/registry.d.ts.map +1 -0
  138. package/dist/payments/registry.js +199 -0
  139. package/dist/payments/registry.js.map +1 -0
  140. package/dist/payments/strategy.d.ts +80 -0
  141. package/dist/payments/strategy.d.ts.map +1 -0
  142. package/dist/payments/strategy.js +103 -0
  143. package/dist/payments/strategy.js.map +1 -0
  144. package/dist/proxy/hooks.d.ts +90 -0
  145. package/dist/proxy/hooks.d.ts.map +1 -0
  146. package/dist/proxy/hooks.js +35 -0
  147. package/dist/proxy/hooks.js.map +1 -0
  148. package/dist/proxy/index.d.ts +9 -0
  149. package/dist/proxy/index.d.ts.map +1 -0
  150. package/dist/proxy/index.js +9 -0
  151. package/dist/proxy/index.js.map +1 -0
  152. package/dist/proxy/proxy.d.ts +156 -0
  153. package/dist/proxy/proxy.d.ts.map +1 -0
  154. package/dist/proxy/proxy.js +366 -0
  155. package/dist/proxy/proxy.js.map +1 -0
  156. package/dist/server/adapters/express.d.ts +89 -0
  157. package/dist/server/adapters/express.d.ts.map +1 -0
  158. package/dist/server/adapters/express.js +215 -0
  159. package/dist/server/adapters/express.js.map +1 -0
  160. package/dist/server/adapters/hono.d.ts +52 -0
  161. package/dist/server/adapters/hono.d.ts.map +1 -0
  162. package/dist/server/adapters/hono.js +61 -0
  163. package/dist/server/adapters/hono.js.map +1 -0
  164. package/dist/server/adapters/next.d.ts +52 -0
  165. package/dist/server/adapters/next.d.ts.map +1 -0
  166. package/dist/server/adapters/next.js +56 -0
  167. package/dist/server/adapters/next.js.map +1 -0
  168. package/dist/server/index.d.ts +30 -0
  169. package/dist/server/index.d.ts.map +1 -0
  170. package/dist/server/index.js +30 -0
  171. package/dist/server/index.js.map +1 -0
  172. package/dist/server/metering.d.ts +209 -0
  173. package/dist/server/metering.d.ts.map +1 -0
  174. package/dist/server/metering.js +365 -0
  175. package/dist/server/metering.js.map +1 -0
  176. package/dist/server/post-paid.d.ts +355 -0
  177. package/dist/server/post-paid.d.ts.map +1 -0
  178. package/dist/server/post-paid.js +512 -0
  179. package/dist/server/post-paid.js.map +1 -0
  180. package/dist/x402/client.d.ts +203 -0
  181. package/dist/x402/client.d.ts.map +1 -0
  182. package/dist/x402/client.js +337 -0
  183. package/dist/x402/client.js.map +1 -0
  184. package/dist/x402/hub.d.ts +79 -0
  185. package/dist/x402/hub.d.ts.map +1 -0
  186. package/dist/x402/hub.js +164 -0
  187. package/dist/x402/hub.js.map +1 -0
  188. package/dist/x402/index.d.ts +27 -0
  189. package/dist/x402/index.d.ts.map +1 -0
  190. package/dist/x402/index.js +27 -0
  191. package/dist/x402/index.js.map +1 -0
  192. package/dist/x402/proxy.d.ts +162 -0
  193. package/dist/x402/proxy.d.ts.map +1 -0
  194. package/dist/x402/proxy.js +198 -0
  195. package/dist/x402/proxy.js.map +1 -0
  196. package/dist/x402/server.d.ts +162 -0
  197. package/dist/x402/server.d.ts.map +1 -0
  198. package/dist/x402/server.js +306 -0
  199. package/dist/x402/server.js.map +1 -0
  200. package/dist/x402/wire.d.ts +104 -0
  201. package/dist/x402/wire.d.ts.map +1 -0
  202. package/dist/x402/wire.js +265 -0
  203. package/dist/x402/wire.js.map +1 -0
  204. package/package.json +61 -0
@@ -0,0 +1,306 @@
1
+ /**
2
+ * The x402 server side: build what a `402` must carry, and take a signed
3
+ * payment through a facilitator.
4
+ *
5
+ * ## The flow, and why the order is fixed
6
+ *
7
+ * x402's default `authorization` flow is verify, then resource, then settle:
8
+ * the facilitator confirms the signature and the balance before the work is
9
+ * done, and moves the funds only after the work succeeded. {@link handlePrepaidRequest}
10
+ * runs exactly that. It never settles a payment for a response that was not a
11
+ * delivery, for the same reason the post-paid plugin never meters one: an
12
+ * Agent is not charged for a call that failed.
13
+ *
14
+ * ## What a Tab Service does with this
15
+ *
16
+ * A Tab Service delivers on credit and refuses on `LimitExceeded` alone. With
17
+ * this module, that refusal can also carry a `PAYMENT-REQUIRED` naming the same
18
+ * charge as an x402 `exact` requirement, so an Agent that has no headroom and
19
+ * would rather not settle first can pay for the one call. When it does, the
20
+ * call is prepaid in full, the facilitator moves the Asset to the Service's
21
+ * Collection address, and nothing lands on the Open Tab, because nothing is
22
+ * owed.
23
+ *
24
+ * ## Official and hand-rolled
25
+ *
26
+ * The facilitator client is `@x402/core`'s `HTTPFacilitatorClient`, wrapped so
27
+ * a thrown `VerifyError` or `SettleError` comes back as a `Result` carrying the
28
+ * facilitator's reason. Requirement construction and the request handling are
29
+ * this package's own, because the reference server middleware gates every
30
+ * request on payment, which is the model Tab exists to replace.
31
+ *
32
+ * Specification: x402-specification-v2.md sections 5, 6.1 and 7, transports-v2/http.md.
33
+ */
34
+ import { HTTPFacilitatorClient } from "@x402/core/server";
35
+ import { causeOf, isAddress, ok, wrap } from "../_shared/index.js";
36
+ import { fail, tabError, validationError } from "../errors.js";
37
+ import { defaultLogger } from "../logger.js";
38
+ import { X402_HEADER, X402_SCHEME_EXACT, X402_VERSION, encodePaymentRequired, encodePaymentResponse, networkOf, } from "./wire.js";
39
+ /** Monad's facilitator, which settles `exact` and `upto` on Mainnet and Testnet. */
40
+ export const MONAD_FACILITATOR_URL = "https://x402-facilitator.molandak.org";
41
+ /** How long an authorization stays valid when the Service does not say. */
42
+ export const DEFAULT_MAX_TIMEOUT_SECONDS = 300;
43
+ /** The reference HTTP client over a facilitator's `/verify`, `/settle` and `/supported`. */
44
+ export function createX402Facilitator(options = {}) {
45
+ return new HTTPFacilitatorClient({
46
+ url: options.url ?? MONAD_FACILITATOR_URL,
47
+ ...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
48
+ });
49
+ }
50
+ /** The EIP-712 domain of the two USDC deployments Monad's facilitator settles. */
51
+ const KNOWN_DOMAINS = {
52
+ USDC: { name: "USDC", version: "2" },
53
+ // The Testnet mock's constructor names it `USDC` v2 to match Circle's; the
54
+ // rail calls it `mUSDC` so the two are never confused on a page.
55
+ MUSDC: { name: "USDC", version: "2" },
56
+ };
57
+ /** One `exact` requirement, EIP-3009, on an EVM chain. */
58
+ export function exactRequirementFor(options) {
59
+ if (typeof options.chainId !== "bigint" || options.chainId <= 0n) {
60
+ return validationError("X402_REQUIREMENTS_INVALID", "chainId must be a positive bigint");
61
+ }
62
+ if (!isAddress(options.asset.address)) {
63
+ return validationError("X402_REQUIREMENTS_INVALID", `asset \`${String(options.asset.address)}\` is not a 20-byte address`);
64
+ }
65
+ if (!isAddress(options.payTo)) {
66
+ return validationError("X402_REQUIREMENTS_INVALID", `payTo \`${String(options.payTo)}\` is not a 20-byte address`);
67
+ }
68
+ if (typeof options.amount !== "bigint" || options.amount <= 0n) {
69
+ return validationError("X402_REQUIREMENTS_INVALID", "amount must be a positive bigint of atomic units, never a number");
70
+ }
71
+ const timeout = options.maxTimeoutSeconds ?? DEFAULT_MAX_TIMEOUT_SECONDS;
72
+ if (!Number.isInteger(timeout) || timeout <= 0) {
73
+ return validationError("X402_REQUIREMENTS_INVALID", "maxTimeoutSeconds must be a positive integer");
74
+ }
75
+ const extra = options.extra ?? KNOWN_DOMAINS[options.asset.symbol.toUpperCase()];
76
+ if (extra === undefined || typeof extra["name"] !== "string" || typeof extra["version"] !== "string") {
77
+ return validationError("X402_DOMAIN_MISSING", `no EIP-712 domain is known for ${options.asset.symbol}; pass extra: { name, version } from the token contract`, { details: { asset: options.asset.address, symbol: options.asset.symbol } });
78
+ }
79
+ return ok({
80
+ scheme: X402_SCHEME_EXACT,
81
+ network: networkOf(options.chainId),
82
+ amount: options.amount.toString(10),
83
+ asset: options.asset.address,
84
+ payTo: options.payTo,
85
+ maxTimeoutSeconds: timeout,
86
+ extra: { ...extra },
87
+ });
88
+ }
89
+ /** The object a `402` carries in `PAYMENT-REQUIRED`. */
90
+ export const paymentRequiredFor = (options) => ({
91
+ x402Version: X402_VERSION,
92
+ ...(options.error === undefined ? {} : { error: options.error }),
93
+ resource: options.resource,
94
+ accepts: [...options.accepts],
95
+ });
96
+ /** The `PAYMENT-REQUIRED` header, ready to merge onto a response. */
97
+ export function paymentRequiredHeaders(required) {
98
+ const encoded = encodePaymentRequired(required);
99
+ if (!encoded.ok)
100
+ return encoded;
101
+ return ok({ [X402_HEADER.paymentRequired]: encoded.value });
102
+ }
103
+ /** The `PAYMENT-RESPONSE` header, ready to merge onto a response. */
104
+ export function paymentResponseHeaders(settlement) {
105
+ const encoded = encodePaymentResponse(settlement);
106
+ if (!encoded.ok)
107
+ return encoded;
108
+ return ok({ [X402_HEADER.paymentResponse]: encoded.value });
109
+ }
110
+ const facilitatorFailure = (what) => (error) => {
111
+ const thrown = (typeof error === "object" && error !== null ? error : {});
112
+ const reason = [thrown.invalidReason, thrown.errorReason].find((value) => typeof value === "string");
113
+ const detail = [thrown.invalidMessage, thrown.errorMessage].find((value) => typeof value === "string");
114
+ return tabError(reason === undefined ? "UPSTREAM" : "LIMIT", reason === undefined ? `X402_FACILITATOR_${what.toUpperCase()}_FAILED` : `X402_${what.toUpperCase()}_REJECTED`, reason === undefined
115
+ ? `the facilitator could not ${what} the payment`
116
+ : `the facilitator refused to ${what} the payment: ${reason}${detail === undefined ? "" : ` (${detail})`}`, {
117
+ retryable: reason === undefined,
118
+ details: {
119
+ ...(reason === undefined ? {} : { reason }),
120
+ ...(typeof thrown.payer === "string" ? { payer: thrown.payer } : {}),
121
+ ...(typeof thrown.transaction === "string" && thrown.transaction.length > 0 ? { transaction: thrown.transaction } : {}),
122
+ ...(typeof thrown.statusCode === "number" ? { statusCode: thrown.statusCode } : {}),
123
+ },
124
+ cause: causeOf(error),
125
+ });
126
+ };
127
+ /** `POST /verify`, as a `Result`. An invalid payment is a `LIMIT` error naming the facilitator's reason. */
128
+ export async function verifyPayment(facilitator, payload, requirements) {
129
+ const verified = await wrap(async () => facilitator.verify(payload, requirements), facilitatorFailure("verify"));
130
+ if (!verified.ok)
131
+ return verified;
132
+ if (verified.value.isValid !== true) {
133
+ const reason = verified.value.invalidReason ?? "invalid_payload";
134
+ return fail("LIMIT", "X402_VERIFY_REJECTED", `the facilitator refused to verify the payment: ${reason}`, {
135
+ retryable: false,
136
+ details: { reason, ...(verified.value.payer === undefined ? {} : { payer: verified.value.payer }) },
137
+ });
138
+ }
139
+ return verified;
140
+ }
141
+ /** `POST /settle`, as a `Result`. A failed settlement carries the facilitator's reason and any broadcast hash. */
142
+ export async function settlePayment(facilitator, payload, requirements) {
143
+ const settled = await wrap(async () => facilitator.settle(payload, requirements), facilitatorFailure("settle"));
144
+ if (!settled.ok)
145
+ return settled;
146
+ if (settled.value.success !== true) {
147
+ const reason = settled.value.errorReason ?? "unexpected_settle_error";
148
+ return fail(reason === "settlement_pending" ? "UNAVAILABLE" : "LIMIT", "X402_SETTLE_REJECTED", `the facilitator did not settle the payment: ${reason}`, {
149
+ retryable: reason === "settlement_pending",
150
+ details: {
151
+ reason,
152
+ transaction: settled.value.transaction,
153
+ network: settled.value.network,
154
+ ...(settled.value.payer === undefined ? {} : { payer: settled.value.payer }),
155
+ },
156
+ });
157
+ }
158
+ return settled;
159
+ }
160
+ /** `GET /supported`, as a `Result`. */
161
+ export const facilitatorSupports = (facilitator) => wrap(async () => facilitator.getSupported(), (error) => tabError("UPSTREAM", "X402_FACILITATOR_UNREACHABLE", "the facilitator did not answer /supported", {
162
+ retryable: true,
163
+ cause: causeOf(error),
164
+ }));
165
+ /**
166
+ * Checks that what the client says it accepted is what this server requires.
167
+ *
168
+ * The facilitator verifies the signature against the server's requirements, so
169
+ * a mismatch would be caught there; catching it here saves the round trip and
170
+ * names the field. `extra` and `maxTimeoutSeconds` are not compared: they are
171
+ * the server's inputs to signing and the facilitator reads them from the
172
+ * server's copy, never the client's.
173
+ */
174
+ export function matchAccepted(accepted, requirements) {
175
+ const mismatches = [];
176
+ if (accepted.scheme !== requirements.scheme)
177
+ mismatches.push(`scheme ${accepted.scheme} is not ${requirements.scheme}`);
178
+ if (accepted.network !== requirements.network)
179
+ mismatches.push(`network ${accepted.network} is not ${requirements.network}`);
180
+ if (accepted.asset.toLowerCase() !== requirements.asset.toLowerCase())
181
+ mismatches.push(`asset ${accepted.asset} is not ${requirements.asset}`);
182
+ if (accepted.payTo.toLowerCase() !== requirements.payTo.toLowerCase())
183
+ mismatches.push(`payTo ${accepted.payTo} is not ${requirements.payTo}`);
184
+ if (BigInt(accepted.amount) !== BigInt(requirements.amount))
185
+ mismatches.push(`amount ${accepted.amount} is not ${requirements.amount}`);
186
+ if (mismatches.length === 0)
187
+ return ok(undefined);
188
+ return fail("LIMIT", "X402_ACCEPTED_MISMATCH", `the signed payment does not match this call's requirement: ${mismatches.join(", ")}`, {
189
+ retryable: false,
190
+ details: { mismatches: mismatches.join("; ") },
191
+ });
192
+ }
193
+ /**
194
+ * Takes one prepaid request through verify, deliver, settle.
195
+ *
196
+ * Never throws and never rejects. A thrown handler is an outcome, not an
197
+ * exception, so a host adapter can re-raise it the way its framework expects.
198
+ */
199
+ export async function handlePrepaidRequest(options) {
200
+ const logger = options.logger ?? defaultLogger;
201
+ const billable = options.billable ?? ((response) => response.status < 400);
202
+ const required = paymentRequiredFor({ resource: options.resource, accepts: [options.requirements] });
203
+ const rejected = (error) => ({
204
+ kind: "rejected",
205
+ response: paymentRequiredResponse({ ...required, error: error.message }, error),
206
+ error,
207
+ });
208
+ const matched = matchAccepted(options.payload.accepted, options.requirements);
209
+ if (!matched.ok)
210
+ return rejected(matched.error);
211
+ const verified = await verifyPayment(options.facilitator, options.payload, options.requirements);
212
+ if (!verified.ok)
213
+ return rejected(verified.error);
214
+ let response;
215
+ try {
216
+ response = await options.deliver();
217
+ }
218
+ catch (thrown) {
219
+ logger.debug("x402 prepaid call settled nothing because the handler failed");
220
+ return {
221
+ kind: "handler-failed",
222
+ thrown,
223
+ error: tabError("INTERNAL", "HANDLER_FAILED", "the handler failed, so the verified payment was not settled", {
224
+ details: { settled: false },
225
+ cause: causeOf(thrown),
226
+ }),
227
+ };
228
+ }
229
+ let deliverable;
230
+ try {
231
+ deliverable = billable(response) === true;
232
+ }
233
+ catch (thrown) {
234
+ logger.error("x402 billable predicate threw and was read as not billable", causeOf(thrown));
235
+ deliverable = false;
236
+ }
237
+ if (!deliverable)
238
+ return { kind: "not-delivered", response };
239
+ const settled = await settlePayment(options.facilitator, options.payload, options.requirements);
240
+ if (!settled.ok) {
241
+ discard(response, logger);
242
+ const failure = {
243
+ success: false,
244
+ errorReason: String(settled.error.details?.["reason"] ?? settled.error.code),
245
+ transaction: String(settled.error.details?.["transaction"] ?? ""),
246
+ network: options.requirements.network,
247
+ ...(typeof settled.error.details?.["payer"] === "string" ? { payer: settled.error.details["payer"] } : {}),
248
+ };
249
+ return { kind: "settlement-failed", response: settlementFailedResponse(failure, settled.error), error: settled.error };
250
+ }
251
+ const headers = paymentResponseHeaders(settled.value);
252
+ if (!headers.ok) {
253
+ // The funds moved and the work is delivered; a header that will not encode
254
+ // costs the caller the receipt and nothing else.
255
+ logger.error("x402 settlement succeeded but PAYMENT-RESPONSE would not encode", { code: headers.error.code });
256
+ return { kind: "paid", response, settlement: settled.value, payer: settled.value.payer };
257
+ }
258
+ return { kind: "paid", response: withHeaders(response, headers.value, logger), settlement: settled.value, payer: settled.value.payer };
259
+ }
260
+ /** A `402` carrying `PAYMENT-REQUIRED` and a JSON body naming the error. */
261
+ export function paymentRequiredResponse(required, error, extraHeaders = {}) {
262
+ const encoded = paymentRequiredHeaders(required);
263
+ return new Response(JSON.stringify({ ok: false, error }), {
264
+ status: 402,
265
+ headers: {
266
+ ...extraHeaders,
267
+ ...(encoded.ok ? encoded.value : {}),
268
+ "Content-Type": "application/json; charset=utf-8",
269
+ },
270
+ });
271
+ }
272
+ /** A `402` carrying a failed `PAYMENT-RESPONSE`, as the HTTP transport specification shows. */
273
+ function settlementFailedResponse(failure, error) {
274
+ const encoded = paymentResponseHeaders(failure);
275
+ return new Response(JSON.stringify({ ok: false, error }), {
276
+ status: 402,
277
+ headers: { ...(encoded.ok ? encoded.value : {}), "Content-Type": "application/json; charset=utf-8" },
278
+ });
279
+ }
280
+ /** Puts headers on a response, copying it when its headers are immutable. */
281
+ function withHeaders(response, headers, logger) {
282
+ try {
283
+ for (const [name, value] of Object.entries(headers))
284
+ response.headers.set(name, value);
285
+ return response;
286
+ }
287
+ catch {
288
+ logger.debug("response headers were immutable, so PAYMENT-RESPONSE went onto a copy");
289
+ const merged = new Headers(response.headers);
290
+ for (const [name, value] of Object.entries(headers))
291
+ merged.set(name, value);
292
+ return new Response(response.body, { status: response.status, statusText: response.statusText, headers: merged });
293
+ }
294
+ }
295
+ function discard(response, logger) {
296
+ const body = response.body;
297
+ if (body === null || response.bodyUsed)
298
+ return;
299
+ try {
300
+ body.cancel().catch((error) => logger.debug("discarded response body could not be cancelled", causeOf(error)));
301
+ }
302
+ catch (error) {
303
+ logger.debug("discarded response body could not be cancelled", causeOf(error));
304
+ }
305
+ }
306
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/x402/server.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The x402 server side: build what a `402` must carry, and take a signed\n * payment through a facilitator.\n *\n * ## The flow, and why the order is fixed\n *\n * x402's default `authorization` flow is verify, then resource, then settle:\n * the facilitator confirms the signature and the balance before the work is\n * done, and moves the funds only after the work succeeded. {@link handlePrepaidRequest}\n * runs exactly that. It never settles a payment for a response that was not a\n * delivery, for the same reason the post-paid plugin never meters one: an\n * Agent is not charged for a call that failed.\n *\n * ## What a Tab Service does with this\n *\n * A Tab Service delivers on credit and refuses on `LimitExceeded` alone. With\n * this module, that refusal can also carry a `PAYMENT-REQUIRED` naming the same\n * charge as an x402 `exact` requirement, so an Agent that has no headroom and\n * would rather not settle first can pay for the one call. When it does, the\n * call is prepaid in full, the facilitator moves the Asset to the Service's\n * Collection address, and nothing lands on the Open Tab, because nothing is\n * owed.\n *\n * ## Official and hand-rolled\n *\n * The facilitator client is `@x402/core`'s `HTTPFacilitatorClient`, wrapped so\n * a thrown `VerifyError` or `SettleError` comes back as a `Result` carrying the\n * facilitator's reason. Requirement construction and the request handling are\n * this package's own, because the reference server middleware gates every\n * request on payment, which is the model Tab exists to replace.\n *\n * Specification: x402-specification-v2.md sections 5, 6.1 and 7, transports-v2/http.md.\n */\n\nimport { HTTPFacilitatorClient, type FacilitatorClient } from \"@x402/core/server\";\nimport { causeOf, isAddress, ok, wrap, type Address, type Result, type TabError } from \"../_shared/index.js\";\n\nimport { fail, tabError, validationError } from \"../errors.js\";\nimport { defaultLogger, type Logger } from \"../logger.js\";\nimport type { AssetRef } from \"../payments/strategy.js\";\nimport {\n X402_HEADER,\n X402_SCHEME_EXACT,\n X402_VERSION,\n encodePaymentRequired,\n encodePaymentResponse,\n networkOf,\n type PaymentPayload,\n type PaymentRequired,\n type PaymentRequirements,\n type ResourceInfo,\n type SettleResponse,\n type SupportedResponse,\n type VerifyResponse,\n} from \"./wire.js\";\n\n/** Monad's facilitator, which settles `exact` and `upto` on Mainnet and Testnet. */\nexport const MONAD_FACILITATOR_URL = \"https://x402-facilitator.molandak.org\";\n\n/** How long an authorization stays valid when the Service does not say. */\nexport const DEFAULT_MAX_TIMEOUT_SECONDS = 300;\n\n/**\n * What verifies and settles payments.\n *\n * The reference interface, re-exported so a fake in a test and the HTTP client\n * in production are the same type. The methods throw, as the reference does;\n * {@link verifyPayment} and {@link settlePayment} are the zero-throw doors.\n */\nexport type X402FacilitatorClient = FacilitatorClient;\n\nexport interface X402FacilitatorOptions {\n /** Defaults to {@link MONAD_FACILITATOR_URL}. */\n readonly url?: string;\n /** Per-request timeout. Defaults to the reference client's 90 seconds. */\n readonly timeoutMs?: number;\n}\n\n/** The reference HTTP client over a facilitator's `/verify`, `/settle` and `/supported`. */\nexport function createX402Facilitator(options: X402FacilitatorOptions = {}): X402FacilitatorClient {\n return new HTTPFacilitatorClient({\n url: options.url ?? MONAD_FACILITATOR_URL,\n ...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),\n });\n}\n\n/** The EIP-712 domain of the two USDC deployments Monad's facilitator settles. */\nconst KNOWN_DOMAINS: Readonly<Record<string, { readonly name: string; readonly version: string }>> = {\n USDC: { name: \"USDC\", version: \"2\" },\n // The Testnet mock's constructor names it `USDC` v2 to match Circle's; the\n // rail calls it `mUSDC` so the two are never confused on a page.\n MUSDC: { name: \"USDC\", version: \"2\" },\n};\n\nexport interface ExactRequirementOptions {\n readonly chainId: bigint;\n /** The token. `symbol` picks the EIP-712 domain when `extra` is not given. */\n readonly asset: Pick<AssetRef, \"address\" | \"symbol\">;\n /** Atomic units of the token. */\n readonly amount: bigint;\n /** Where the facilitator sends the funds: the Service's Collection address for the Asset. */\n readonly payTo: Address;\n readonly maxTimeoutSeconds?: number;\n /**\n * The requirement's `extra`. Must carry the token's EIP-712 domain `name` and\n * `version`, which EIP-3009 signing needs. Defaults to USDC's when the Asset's\n * symbol is `USDC`, and is required otherwise.\n */\n readonly extra?: Readonly<Record<string, unknown>>;\n}\n\n/** One `exact` requirement, EIP-3009, on an EVM chain. */\nexport function exactRequirementFor(options: ExactRequirementOptions): Result<PaymentRequirements> {\n if (typeof options.chainId !== \"bigint\" || options.chainId <= 0n) {\n return validationError(\"X402_REQUIREMENTS_INVALID\", \"chainId must be a positive bigint\");\n }\n if (!isAddress(options.asset.address)) {\n return validationError(\"X402_REQUIREMENTS_INVALID\", `asset \\`${String(options.asset.address)}\\` is not a 20-byte address`);\n }\n if (!isAddress(options.payTo)) {\n return validationError(\"X402_REQUIREMENTS_INVALID\", `payTo \\`${String(options.payTo)}\\` is not a 20-byte address`);\n }\n if (typeof options.amount !== \"bigint\" || options.amount <= 0n) {\n return validationError(\"X402_REQUIREMENTS_INVALID\", \"amount must be a positive bigint of atomic units, never a number\");\n }\n const timeout = options.maxTimeoutSeconds ?? DEFAULT_MAX_TIMEOUT_SECONDS;\n if (!Number.isInteger(timeout) || timeout <= 0) {\n return validationError(\"X402_REQUIREMENTS_INVALID\", \"maxTimeoutSeconds must be a positive integer\");\n }\n const extra = options.extra ?? KNOWN_DOMAINS[options.asset.symbol.toUpperCase()];\n if (extra === undefined || typeof extra[\"name\"] !== \"string\" || typeof extra[\"version\"] !== \"string\") {\n return validationError(\n \"X402_DOMAIN_MISSING\",\n `no EIP-712 domain is known for ${options.asset.symbol}; pass extra: { name, version } from the token contract`,\n { details: { asset: options.asset.address, symbol: options.asset.symbol } },\n );\n }\n return ok({\n scheme: X402_SCHEME_EXACT,\n network: networkOf(options.chainId),\n amount: options.amount.toString(10),\n asset: options.asset.address,\n payTo: options.payTo,\n maxTimeoutSeconds: timeout,\n extra: { ...extra },\n });\n}\n\nexport interface PaymentRequiredOptions {\n readonly resource: ResourceInfo;\n readonly accepts: readonly PaymentRequirements[];\n /** Why payment is being asked for, for a person reading the header. */\n readonly error?: string;\n}\n\n/** The object a `402` carries in `PAYMENT-REQUIRED`. */\nexport const paymentRequiredFor = (options: PaymentRequiredOptions): PaymentRequired => ({\n x402Version: X402_VERSION,\n ...(options.error === undefined ? {} : { error: options.error }),\n resource: options.resource,\n accepts: [...options.accepts],\n});\n\n/** The `PAYMENT-REQUIRED` header, ready to merge onto a response. */\nexport function paymentRequiredHeaders(required: PaymentRequired): Result<Record<string, string>> {\n const encoded = encodePaymentRequired(required);\n if (!encoded.ok) return encoded;\n return ok({ [X402_HEADER.paymentRequired]: encoded.value });\n}\n\n/** The `PAYMENT-RESPONSE` header, ready to merge onto a response. */\nexport function paymentResponseHeaders(settlement: SettleResponse): Result<Record<string, string>> {\n const encoded = encodePaymentResponse(settlement);\n if (!encoded.ok) return encoded;\n return ok({ [X402_HEADER.paymentResponse]: encoded.value });\n}\n\n/** What a thrown facilitator error carries, read without depending on its class. */\ninterface ThrownFacilitatorError {\n readonly invalidReason?: unknown;\n readonly errorReason?: unknown;\n readonly invalidMessage?: unknown;\n readonly errorMessage?: unknown;\n readonly payer?: unknown;\n readonly transaction?: unknown;\n readonly statusCode?: unknown;\n}\n\nconst facilitatorFailure = (what: \"verify\" | \"settle\") => (error: unknown): TabError => {\n const thrown = (typeof error === \"object\" && error !== null ? error : {}) as ThrownFacilitatorError;\n const reason = [thrown.invalidReason, thrown.errorReason].find((value) => typeof value === \"string\") as string | undefined;\n const detail = [thrown.invalidMessage, thrown.errorMessage].find((value) => typeof value === \"string\") as string | undefined;\n return tabError(\n reason === undefined ? \"UPSTREAM\" : \"LIMIT\",\n reason === undefined ? `X402_FACILITATOR_${what.toUpperCase()}_FAILED` : `X402_${what.toUpperCase()}_REJECTED`,\n reason === undefined\n ? `the facilitator could not ${what} the payment`\n : `the facilitator refused to ${what} the payment: ${reason}${detail === undefined ? \"\" : ` (${detail})`}`,\n {\n retryable: reason === undefined,\n details: {\n ...(reason === undefined ? {} : { reason }),\n ...(typeof thrown.payer === \"string\" ? { payer: thrown.payer } : {}),\n ...(typeof thrown.transaction === \"string\" && thrown.transaction.length > 0 ? { transaction: thrown.transaction } : {}),\n ...(typeof thrown.statusCode === \"number\" ? { statusCode: thrown.statusCode } : {}),\n },\n cause: causeOf(error),\n },\n );\n};\n\n/** `POST /verify`, as a `Result`. An invalid payment is a `LIMIT` error naming the facilitator's reason. */\nexport async function verifyPayment(\n facilitator: X402FacilitatorClient,\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n): Promise<Result<VerifyResponse>> {\n const verified = await wrap(async () => facilitator.verify(payload, requirements), facilitatorFailure(\"verify\"));\n if (!verified.ok) return verified;\n if (verified.value.isValid !== true) {\n const reason = verified.value.invalidReason ?? \"invalid_payload\";\n return fail(\"LIMIT\", \"X402_VERIFY_REJECTED\", `the facilitator refused to verify the payment: ${reason}`, {\n retryable: false,\n details: { reason, ...(verified.value.payer === undefined ? {} : { payer: verified.value.payer }) },\n });\n }\n return verified;\n}\n\n/** `POST /settle`, as a `Result`. A failed settlement carries the facilitator's reason and any broadcast hash. */\nexport async function settlePayment(\n facilitator: X402FacilitatorClient,\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n): Promise<Result<SettleResponse>> {\n const settled = await wrap(async () => facilitator.settle(payload, requirements), facilitatorFailure(\"settle\"));\n if (!settled.ok) return settled;\n if (settled.value.success !== true) {\n const reason = settled.value.errorReason ?? \"unexpected_settle_error\";\n return fail(\n reason === \"settlement_pending\" ? \"UNAVAILABLE\" : \"LIMIT\",\n \"X402_SETTLE_REJECTED\",\n `the facilitator did not settle the payment: ${reason}`,\n {\n retryable: reason === \"settlement_pending\",\n details: {\n reason,\n transaction: settled.value.transaction,\n network: settled.value.network,\n ...(settled.value.payer === undefined ? {} : { payer: settled.value.payer }),\n },\n },\n );\n }\n return settled;\n}\n\n/** `GET /supported`, as a `Result`. */\nexport const facilitatorSupports = (facilitator: X402FacilitatorClient): Promise<Result<SupportedResponse>> =>\n wrap(async () => facilitator.getSupported(), (error) =>\n tabError(\"UPSTREAM\", \"X402_FACILITATOR_UNREACHABLE\", \"the facilitator did not answer /supported\", {\n retryable: true,\n cause: causeOf(error),\n }),\n );\n\n/**\n * Checks that what the client says it accepted is what this server requires.\n *\n * The facilitator verifies the signature against the server's requirements, so\n * a mismatch would be caught there; catching it here saves the round trip and\n * names the field. `extra` and `maxTimeoutSeconds` are not compared: they are\n * the server's inputs to signing and the facilitator reads them from the\n * server's copy, never the client's.\n */\nexport function matchAccepted(accepted: PaymentRequirements, requirements: PaymentRequirements): Result<void> {\n const mismatches: string[] = [];\n if (accepted.scheme !== requirements.scheme) mismatches.push(`scheme ${accepted.scheme} is not ${requirements.scheme}`);\n if (accepted.network !== requirements.network) mismatches.push(`network ${accepted.network} is not ${requirements.network}`);\n if (accepted.asset.toLowerCase() !== requirements.asset.toLowerCase()) mismatches.push(`asset ${accepted.asset} is not ${requirements.asset}`);\n if (accepted.payTo.toLowerCase() !== requirements.payTo.toLowerCase()) mismatches.push(`payTo ${accepted.payTo} is not ${requirements.payTo}`);\n if (BigInt(accepted.amount) !== BigInt(requirements.amount)) mismatches.push(`amount ${accepted.amount} is not ${requirements.amount}`);\n if (mismatches.length === 0) return ok(undefined);\n return fail(\"LIMIT\", \"X402_ACCEPTED_MISMATCH\", `the signed payment does not match this call's requirement: ${mismatches.join(\", \")}`, {\n retryable: false,\n details: { mismatches: mismatches.join(\"; \") },\n });\n}\n\n/** The response, reduced to what the billability decision needs. */\nexport interface X402DeliveredResponse {\n readonly status: number;\n}\n\nexport interface PrepaidRequestOptions {\n readonly facilitator: X402FacilitatorClient;\n /** The decoded `PAYMENT-SIGNATURE`. */\n readonly payload: PaymentPayload;\n /** What this call costs, built by the server and never taken from the client. */\n readonly requirements: PaymentRequirements;\n readonly resource: ResourceInfo;\n /** The work. Runs only after the payment verified. */\n readonly deliver: () => Promise<Response> | Response;\n /** Whether a response is a delivery worth settling for. Defaults to `status < 400`. */\n readonly billable?: (response: X402DeliveredResponse) => boolean;\n readonly logger?: Logger;\n}\n\nexport type PrepaidOutcome =\n /** Verified, delivered, settled. The response carries `PAYMENT-RESPONSE`. */\n | { readonly kind: \"paid\"; readonly response: Response; readonly settlement: SettleResponse; readonly payer: string | undefined }\n /** The payment did not verify. The response is a `402` carrying `PAYMENT-REQUIRED` with the reason. */\n | { readonly kind: \"rejected\"; readonly response: Response; readonly error: TabError }\n /** The work was not a delivery, so nothing was settled and the handler's own response goes out. */\n | { readonly kind: \"not-delivered\"; readonly response: Response }\n /** The handler threw. Nothing was settled. */\n | { readonly kind: \"handler-failed\"; readonly thrown: unknown; readonly error: TabError }\n /** Delivered, but the facilitator would not settle. The response is a `402` carrying the failed `PAYMENT-RESPONSE`. */\n | { readonly kind: \"settlement-failed\"; readonly response: Response; readonly error: TabError };\n\n/**\n * Takes one prepaid request through verify, deliver, settle.\n *\n * Never throws and never rejects. A thrown handler is an outcome, not an\n * exception, so a host adapter can re-raise it the way its framework expects.\n */\nexport async function handlePrepaidRequest(options: PrepaidRequestOptions): Promise<PrepaidOutcome> {\n const logger = options.logger ?? defaultLogger;\n const billable = options.billable ?? ((response: X402DeliveredResponse) => response.status < 400);\n const required = paymentRequiredFor({ resource: options.resource, accepts: [options.requirements] });\n\n const rejected = (error: TabError): PrepaidOutcome => ({\n kind: \"rejected\",\n response: paymentRequiredResponse({ ...required, error: error.message }, error),\n error,\n });\n\n const matched = matchAccepted(options.payload.accepted, options.requirements);\n if (!matched.ok) return rejected(matched.error);\n\n const verified = await verifyPayment(options.facilitator, options.payload, options.requirements);\n if (!verified.ok) return rejected(verified.error);\n\n let response: Response;\n try {\n response = await options.deliver();\n } catch (thrown) {\n logger.debug(\"x402 prepaid call settled nothing because the handler failed\");\n return {\n kind: \"handler-failed\",\n thrown,\n error: tabError(\"INTERNAL\", \"HANDLER_FAILED\", \"the handler failed, so the verified payment was not settled\", {\n details: { settled: false },\n cause: causeOf(thrown),\n }),\n };\n }\n\n let deliverable: boolean;\n try {\n deliverable = billable(response) === true;\n } catch (thrown) {\n logger.error(\"x402 billable predicate threw and was read as not billable\", causeOf(thrown));\n deliverable = false;\n }\n if (!deliverable) return { kind: \"not-delivered\", response };\n\n const settled = await settlePayment(options.facilitator, options.payload, options.requirements);\n if (!settled.ok) {\n discard(response, logger);\n const failure: SettleResponse = {\n success: false,\n errorReason: String(settled.error.details?.[\"reason\"] ?? settled.error.code),\n transaction: String(settled.error.details?.[\"transaction\"] ?? \"\"),\n network: options.requirements.network,\n ...(typeof settled.error.details?.[\"payer\"] === \"string\" ? { payer: settled.error.details[\"payer\"] } : {}),\n };\n return { kind: \"settlement-failed\", response: settlementFailedResponse(failure, settled.error), error: settled.error };\n }\n\n const headers = paymentResponseHeaders(settled.value);\n if (!headers.ok) {\n // The funds moved and the work is delivered; a header that will not encode\n // costs the caller the receipt and nothing else.\n logger.error(\"x402 settlement succeeded but PAYMENT-RESPONSE would not encode\", { code: headers.error.code });\n return { kind: \"paid\", response, settlement: settled.value, payer: settled.value.payer };\n }\n return { kind: \"paid\", response: withHeaders(response, headers.value, logger), settlement: settled.value, payer: settled.value.payer };\n}\n\n/** A `402` carrying `PAYMENT-REQUIRED` and a JSON body naming the error. */\nexport function paymentRequiredResponse(required: PaymentRequired, error: TabError, extraHeaders: Readonly<Record<string, string>> = {}): Response {\n const encoded = paymentRequiredHeaders(required);\n return new Response(JSON.stringify({ ok: false, error }), {\n status: 402,\n headers: {\n ...extraHeaders,\n ...(encoded.ok ? encoded.value : {}),\n \"Content-Type\": \"application/json; charset=utf-8\",\n },\n });\n}\n\n/** A `402` carrying a failed `PAYMENT-RESPONSE`, as the HTTP transport specification shows. */\nfunction settlementFailedResponse(failure: SettleResponse, error: TabError): Response {\n const encoded = paymentResponseHeaders(failure);\n return new Response(JSON.stringify({ ok: false, error }), {\n status: 402,\n headers: { ...(encoded.ok ? encoded.value : {}), \"Content-Type\": \"application/json; charset=utf-8\" },\n });\n}\n\n/** Puts headers on a response, copying it when its headers are immutable. */\nfunction withHeaders(response: Response, headers: Readonly<Record<string, string>>, logger: Logger): Response {\n try {\n for (const [name, value] of Object.entries(headers)) response.headers.set(name, value);\n return response;\n } catch {\n logger.debug(\"response headers were immutable, so PAYMENT-RESPONSE went onto a copy\");\n const merged = new Headers(response.headers);\n for (const [name, value] of Object.entries(headers)) merged.set(name, value);\n return new Response(response.body, { status: response.status, statusText: response.statusText, headers: merged });\n }\n}\n\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) => logger.debug(\"discarded response body could not be cancelled\", causeOf(error)));\n } catch (error) {\n logger.debug(\"discarded response body could not be cancelled\", causeOf(error));\n }\n}\n"]}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * The x402 V2 wire format, as this package reads and writes it.
3
+ *
4
+ * x402 is the prepaid model: a resource server answers `402` with a
5
+ * `PAYMENT-REQUIRED` header naming what it accepts, the client signs a payment
6
+ * and repeats the request with `PAYMENT-SIGNATURE`, and the server returns the
7
+ * resource with `PAYMENT-RESPONSE` once a facilitator has settled it on chain.
8
+ * Tab is the opposite model, and the two meet in exactly two places: a Tab
9
+ * Service that has refused an Agent on credit can offer x402 as the way to pay
10
+ * for that one call, and a Tab Service can front an x402 upstream and buy on the
11
+ * Agent's behalf. This module is the shared vocabulary for both.
12
+ *
13
+ * ## What is official and what is not
14
+ *
15
+ * The types and the three header codecs come from `@x402/core`, the reference
16
+ * implementation, so a `PaymentRequired` built here is what an x402 client
17
+ * elsewhere decodes and a `PaymentPayload` decoded here is what one sent. The
18
+ * codecs throw on malformed input; every wrapper below turns that into a
19
+ * `Result`, because nothing exported from this package throws.
20
+ *
21
+ * {@link selectExactRequirement} is this package's own: which of a server's
22
+ * `accepts` an Agent can actually sign. It is narrow on purpose. The only
23
+ * scheme signed here is `exact` with the EIP-3009 asset transfer method, the
24
+ * default the exact EVM scheme names, and the only networks are `eip155:*`.
25
+ *
26
+ * Specification: x402-specification-v2.md sections 5 and 11.1, transports-v2/http.md.
27
+ */
28
+ import type { Network, PaymentPayload, PaymentRequired, PaymentRequirements, ResourceInfo, SettleResponse, SupportedResponse, VerifyResponse } from "@x402/core/types";
29
+ import { type Address, type Result } from "../_shared/index.js";
30
+ import { type HeaderReader, type HeaderRecord } from "../http/headers.js";
31
+ export type { Network, PaymentPayload, PaymentRequired, PaymentRequirements, ResourceInfo, SettleResponse, SupportedResponse, VerifyResponse, };
32
+ /** The protocol version this package speaks. V1 is not read and not written. */
33
+ export declare const X402_VERSION: 2;
34
+ /** The three transport headers, in the casing the HTTP transport specification uses. */
35
+ export declare const X402_HEADER: {
36
+ readonly paymentRequired: "PAYMENT-REQUIRED";
37
+ readonly paymentSignature: "PAYMENT-SIGNATURE";
38
+ readonly paymentResponse: "PAYMENT-RESPONSE";
39
+ };
40
+ /** The `exact` scheme, the only one this package signs. */
41
+ export declare const X402_SCHEME_EXACT: "exact";
42
+ /** The asset transfer method this package signs: `transferWithAuthorization`. */
43
+ export declare const X402_TRANSFER_METHOD_EIP3009: "eip3009";
44
+ /** The CAIP-2 network for an EVM chain id. */
45
+ export declare const networkOf: (chainId: bigint | number) => Network;
46
+ /** The EVM chain id a CAIP-2 network names, or an error for anything that is not `eip155:<id>`. */
47
+ export declare function chainIdOfNetwork(network: string): Result<bigint>;
48
+ /** Decodes a `PAYMENT-REQUIRED` header value. */
49
+ export declare const decodePaymentRequired: (value: string) => Result<PaymentRequired>;
50
+ /** Decodes a `PAYMENT-SIGNATURE` header value. */
51
+ export declare const decodePaymentSignature: (value: string) => Result<PaymentPayload>;
52
+ /** Decodes a `PAYMENT-RESPONSE` header value. */
53
+ export declare const decodePaymentResponse: (value: string) => Result<SettleResponse>;
54
+ /** Encodes a `PaymentRequired` as the `PAYMENT-REQUIRED` header value. */
55
+ export declare const encodePaymentRequired: (required: PaymentRequired) => Result<string>;
56
+ /** Encodes a `PaymentPayload` as the `PAYMENT-SIGNATURE` header value. */
57
+ export declare const encodePaymentSignature: (payload: PaymentPayload) => Result<string>;
58
+ /** Encodes a `SettleResponse` as the `PAYMENT-RESPONSE` header value. */
59
+ export declare const encodePaymentResponse: (settlement: SettleResponse) => Result<string>;
60
+ /**
61
+ * The `PaymentRequired` a response carries, `ok(undefined)` when it carries none.
62
+ *
63
+ * Absence is not an error: a Tab `402` without this header is an ordinary credit
64
+ * decision, and a `200` never carries one.
65
+ */
66
+ export declare function readPaymentRequired(source: HeaderReader | HeaderRecord): Result<PaymentRequired | undefined>;
67
+ /** The `PaymentPayload` a request carries, `ok(undefined)` when it carries none. */
68
+ export declare function readPaymentSignature(source: HeaderReader | HeaderRecord): Result<PaymentPayload | undefined>;
69
+ /** The `SettleResponse` a response carries, `ok(undefined)` when it carries none. */
70
+ export declare function readPaymentResponse(source: HeaderReader | HeaderRecord): Result<SettleResponse | undefined>;
71
+ /**
72
+ * The shape check the codec does not do.
73
+ *
74
+ * `@x402/core`'s decoder parses JSON and nothing more, so a header carrying
75
+ * `{"x402Version":2}` decodes without complaint. The fields checked here are
76
+ * the ones the rest of this package reads, and a document missing one is
77
+ * refused by name rather than dereferenced.
78
+ */
79
+ export declare function validatePaymentRequired(value: unknown): Result<PaymentRequired>;
80
+ /** Checks one `PaymentRequirements` object field by field. */
81
+ export declare function validatePaymentRequirements(value: unknown, label?: string): Result<PaymentRequirements>;
82
+ /** Checks a decoded `PaymentPayload` down to the EIP-3009 fields the server reads. */
83
+ export declare function validatePaymentPayload(value: unknown): Result<PaymentPayload>;
84
+ /** How {@link selectExactRequirement} narrows a server's `accepts`. */
85
+ export interface RequirementFilter {
86
+ /** Accept only this chain. Omitted accepts any `eip155:*` network. */
87
+ readonly chainId?: bigint;
88
+ /** Accept only this token, compared case-insensitively. Omitted accepts any. */
89
+ readonly asset?: Address;
90
+ /** Refuse a requirement above this many atomic units. Omitted sets no ceiling. */
91
+ readonly maxAmount?: bigint;
92
+ }
93
+ /**
94
+ * The first `accepts` entry this package can sign, in the server's order.
95
+ *
96
+ * The server's order is its preference and is kept. An entry is passed over
97
+ * when it is not `exact`, not on an EVM chain, names a transfer method other
98
+ * than EIP-3009, declares a payment flow other than `authorization`, or fails
99
+ * the caller's filter. Every reason is carried on the error when nothing
100
+ * matches, because "no usable requirement" is not actionable and "the server
101
+ * accepts Base only and this Agent signs on Monad" is.
102
+ */
103
+ export declare function selectExactRequirement(required: PaymentRequired, filter?: RequirementFilter): Result<PaymentRequirements>;
104
+ //# sourceMappingURL=wire.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../../src/x402/wire.ts"],"names":[],"mappings":"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"}