mppx 0.8.15 → 0.8.17

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 (464) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/Challenge.d.ts.map +1 -1
  3. package/dist/Challenge.js +40 -35
  4. package/dist/Challenge.js.map +1 -1
  5. package/dist/Constants.d.ts +17 -17
  6. package/dist/Constants.d.ts.map +1 -1
  7. package/dist/Credential.d.ts.map +1 -1
  8. package/dist/Errors.d.ts +3 -3
  9. package/dist/Errors.d.ts.map +1 -1
  10. package/dist/Errors.js.map +1 -1
  11. package/dist/Method.d.ts +35 -5
  12. package/dist/Method.d.ts.map +1 -1
  13. package/dist/Method.js +7 -22
  14. package/dist/Method.js.map +1 -1
  15. package/dist/Store.d.ts +19 -0
  16. package/dist/Store.d.ts.map +1 -1
  17. package/dist/Store.js +43 -0
  18. package/dist/Store.js.map +1 -1
  19. package/dist/attestation/Client.d.ts +17 -0
  20. package/dist/attestation/Client.d.ts.map +1 -0
  21. package/dist/attestation/Client.js +28 -0
  22. package/dist/attestation/Client.js.map +1 -0
  23. package/dist/attestation/Constants.d.ts +15 -0
  24. package/dist/attestation/Constants.d.ts.map +1 -0
  25. package/dist/attestation/Constants.js +15 -0
  26. package/dist/attestation/Constants.js.map +1 -0
  27. package/dist/attestation/Server.d.ts +4 -0
  28. package/dist/attestation/Server.d.ts.map +1 -0
  29. package/dist/attestation/Server.js +8 -0
  30. package/dist/attestation/Server.js.map +1 -0
  31. package/dist/attestation/Types.d.ts +76 -0
  32. package/dist/attestation/Types.d.ts.map +1 -0
  33. package/dist/attestation/Types.js +2 -0
  34. package/dist/attestation/Types.js.map +1 -0
  35. package/dist/attestation/index.d.ts +6 -0
  36. package/dist/attestation/index.d.ts.map +1 -0
  37. package/dist/attestation/index.js +6 -0
  38. package/dist/attestation/index.js.map +1 -0
  39. package/dist/attestation/internal/HttpMessageSignature.d.ts +73 -0
  40. package/dist/attestation/internal/HttpMessageSignature.d.ts.map +1 -0
  41. package/dist/attestation/internal/HttpMessageSignature.js +320 -0
  42. package/dist/attestation/internal/HttpMessageSignature.js.map +1 -0
  43. package/dist/attestation/internal/SigningContext.d.ts +4 -0
  44. package/dist/attestation/internal/SigningContext.d.ts.map +1 -0
  45. package/dist/attestation/internal/SigningContext.js +11 -0
  46. package/dist/attestation/internal/SigningContext.js.map +1 -0
  47. package/dist/cli/account.d.ts +14 -14
  48. package/dist/cli/account.d.ts.map +1 -1
  49. package/dist/cli/cli.d.ts +6 -6
  50. package/dist/cli/cli.d.ts.map +1 -1
  51. package/dist/cli/cli.js +1 -0
  52. package/dist/cli/cli.js.map +1 -1
  53. package/dist/cli/plugins/tempo.js.map +1 -1
  54. package/dist/cli/sessions/commands.d.ts +4 -4
  55. package/dist/cli/sessions/commands.d.ts.map +1 -1
  56. package/dist/cli/sessions/commands.js.map +1 -1
  57. package/dist/cli/sessions/store.d.ts.map +1 -1
  58. package/dist/cli/sessions/store.js.map +1 -1
  59. package/dist/cli/utils.d.ts +1 -1
  60. package/dist/cli/utils.d.ts.map +1 -1
  61. package/dist/cli/utils.js.map +1 -1
  62. package/dist/cli/validate/discovery.js.map +1 -1
  63. package/dist/cli/validate/index.d.ts +3 -3
  64. package/dist/cli/validate/index.d.ts.map +1 -1
  65. package/dist/client/Mppx.d.ts +3 -0
  66. package/dist/client/Mppx.d.ts.map +1 -1
  67. package/dist/client/Mppx.js +13 -5
  68. package/dist/client/Mppx.js.map +1 -1
  69. package/dist/client/Transport.d.ts +3 -5
  70. package/dist/client/Transport.d.ts.map +1 -1
  71. package/dist/client/Transport.js +1 -17
  72. package/dist/client/Transport.js.map +1 -1
  73. package/dist/client/internal/Fetch.d.ts.map +1 -1
  74. package/dist/client/internal/Fetch.js +2 -6
  75. package/dist/client/internal/Fetch.js.map +1 -1
  76. package/dist/client/node.js.map +1 -1
  77. package/dist/discovery/OpenApi.d.ts +3 -5
  78. package/dist/discovery/OpenApi.d.ts.map +1 -1
  79. package/dist/discovery/OpenApi.js +13 -34
  80. package/dist/discovery/OpenApi.js.map +1 -1
  81. package/dist/discovery/internal/Metadata.d.ts +20 -0
  82. package/dist/discovery/internal/Metadata.d.ts.map +1 -0
  83. package/dist/discovery/internal/Metadata.js +36 -0
  84. package/dist/discovery/internal/Metadata.js.map +1 -0
  85. package/dist/evm/Methods.d.ts +11 -11
  86. package/dist/evm/Methods.d.ts.map +1 -1
  87. package/dist/evm/Types.d.ts +17 -17
  88. package/dist/evm/Types.d.ts.map +1 -1
  89. package/dist/evm/client/Charge.d.ts +11 -11
  90. package/dist/evm/client/Methods.d.ts +11 -11
  91. package/dist/evm/server/Charge.d.ts +1 -1
  92. package/dist/evm/server/Charge.d.ts.map +1 -1
  93. package/dist/evm/server/Charge.js +2 -0
  94. package/dist/evm/server/Charge.js.map +1 -1
  95. package/dist/evm/server/Methods.d.ts +11 -11
  96. package/dist/internal/HeaderCodec.d.ts +2 -2
  97. package/dist/internal/HeaderCodec.d.ts.map +1 -1
  98. package/dist/internal/types.d.ts +6 -0
  99. package/dist/internal/types.d.ts.map +1 -1
  100. package/dist/middlewares/elysia.js.map +1 -1
  101. package/dist/middlewares/express.js.map +1 -1
  102. package/dist/middlewares/hono.js.map +1 -1
  103. package/dist/middlewares/nextjs.js.map +1 -1
  104. package/dist/proxy/Proxy.d.ts +2 -0
  105. package/dist/proxy/Proxy.d.ts.map +1 -1
  106. package/dist/proxy/Proxy.js +117 -9
  107. package/dist/proxy/Proxy.js.map +1 -1
  108. package/dist/proxy/Service.d.ts +36 -1
  109. package/dist/proxy/Service.d.ts.map +1 -1
  110. package/dist/proxy/Service.js +9 -8
  111. package/dist/proxy/Service.js.map +1 -1
  112. package/dist/proxy/services/anthropic.d.ts.map +1 -1
  113. package/dist/proxy/services/anthropic.js +1 -0
  114. package/dist/proxy/services/anthropic.js.map +1 -1
  115. package/dist/proxy/services/openai.d.ts.map +1 -1
  116. package/dist/proxy/services/openai.js +1 -0
  117. package/dist/proxy/services/openai.js.map +1 -1
  118. package/dist/proxy/services/stripe.d.ts.map +1 -1
  119. package/dist/proxy/services/stripe.js +1 -0
  120. package/dist/proxy/services/stripe.js.map +1 -1
  121. package/dist/server/Mppx.d.ts +75 -13
  122. package/dist/server/Mppx.d.ts.map +1 -1
  123. package/dist/server/Mppx.js +201 -23
  124. package/dist/server/Mppx.js.map +1 -1
  125. package/dist/server/internal/html/config.d.ts +9 -9
  126. package/dist/server/internal/html/config.d.ts.map +1 -1
  127. package/dist/server/internal/html/constants.d.ts +17 -17
  128. package/dist/server/internal/html/constants.d.ts.map +1 -1
  129. package/dist/stripe/Methods.d.ts +10 -10
  130. package/dist/stripe/Methods.d.ts.map +1 -1
  131. package/dist/stripe/client/Charge.d.ts +10 -10
  132. package/dist/stripe/client/Methods.d.ts +10 -10
  133. package/dist/stripe/internal/constants.d.ts +1 -1
  134. package/dist/stripe/internal/constants.js +1 -1
  135. package/dist/stripe/internal/types.d.ts +1 -0
  136. package/dist/stripe/internal/types.d.ts.map +1 -1
  137. package/dist/stripe/server/Charge.d.ts +11 -11
  138. package/dist/stripe/server/Charge.d.ts.map +1 -1
  139. package/dist/stripe/server/Charge.js +49 -1
  140. package/dist/stripe/server/Charge.js.map +1 -1
  141. package/dist/stripe/server/Methods.d.ts +137 -48
  142. package/dist/stripe/server/Methods.d.ts.map +1 -1
  143. package/dist/stripe/server/Methods.js +259 -4
  144. package/dist/stripe/server/Methods.js.map +1 -1
  145. package/dist/stripe/server/internal/deposit-address.d.ts +13 -0
  146. package/dist/stripe/server/internal/deposit-address.d.ts.map +1 -0
  147. package/dist/stripe/server/internal/deposit-address.js +28 -0
  148. package/dist/stripe/server/internal/deposit-address.js.map +1 -0
  149. package/dist/stripe/server/internal/html.gen.d.ts +1 -1
  150. package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
  151. package/dist/stripe/server/internal/html.gen.js +1 -1
  152. package/dist/stripe/server/internal/html.gen.js.map +1 -1
  153. package/dist/stripe/server/internal/record-payment.d.ts +15 -0
  154. package/dist/stripe/server/internal/record-payment.d.ts.map +1 -0
  155. package/dist/stripe/server/internal/record-payment.js +42 -0
  156. package/dist/stripe/server/internal/record-payment.js.map +1 -0
  157. package/dist/stripe/server/internal/request.d.ts +25 -0
  158. package/dist/stripe/server/internal/request.d.ts.map +1 -0
  159. package/dist/stripe/server/internal/request.js +29 -0
  160. package/dist/stripe/server/internal/request.js.map +1 -0
  161. package/dist/tap/Constants.d.ts +28 -0
  162. package/dist/tap/Constants.d.ts.map +1 -0
  163. package/dist/tap/Constants.js +32 -0
  164. package/dist/tap/Constants.js.map +1 -0
  165. package/dist/tap/Types.d.ts +11 -0
  166. package/dist/tap/Types.d.ts.map +1 -0
  167. package/dist/tap/Types.js +2 -0
  168. package/dist/tap/Types.js.map +1 -0
  169. package/dist/tap/client/index.d.ts +26 -0
  170. package/dist/tap/client/index.d.ts.map +1 -0
  171. package/dist/tap/client/index.js +33 -0
  172. package/dist/tap/client/index.js.map +1 -0
  173. package/dist/tap/index.d.ts +5 -0
  174. package/dist/tap/index.d.ts.map +1 -0
  175. package/dist/tap/index.js +5 -0
  176. package/dist/tap/index.js.map +1 -0
  177. package/dist/tap/server/index.d.ts +20 -0
  178. package/dist/tap/server/index.d.ts.map +1 -0
  179. package/dist/tap/server/index.js +36 -0
  180. package/dist/tap/server/index.js.map +1 -0
  181. package/dist/tempo/Attribution.d.ts +1 -1
  182. package/dist/tempo/Methods.d.ts +60 -60
  183. package/dist/tempo/Methods.d.ts.map +1 -1
  184. package/dist/tempo/Proof.d.ts +16 -16
  185. package/dist/tempo/client/Charge.d.ts +19 -19
  186. package/dist/tempo/client/Charge.d.ts.map +1 -1
  187. package/dist/tempo/client/Charge.js +1 -7
  188. package/dist/tempo/client/Charge.js.map +1 -1
  189. package/dist/tempo/client/Methods.d.ts +38 -38
  190. package/dist/tempo/client/Methods.js.map +1 -1
  191. package/dist/tempo/client/Subscription.d.ts +23 -23
  192. package/dist/tempo/client/Subscription.js.map +1 -1
  193. package/dist/tempo/internal/address.d.ts +2 -1
  194. package/dist/tempo/internal/address.d.ts.map +1 -1
  195. package/dist/tempo/internal/address.js +3 -1
  196. package/dist/tempo/internal/address.js.map +1 -1
  197. package/dist/tempo/internal/auto-swap.d.ts.map +1 -1
  198. package/dist/tempo/internal/auto-swap.js +4 -19
  199. package/dist/tempo/internal/auto-swap.js.map +1 -1
  200. package/dist/tempo/internal/defaults.d.ts +6 -6
  201. package/dist/tempo/internal/defaults.d.ts.map +1 -1
  202. package/dist/tempo/internal/fee-payer.d.ts +12 -12
  203. package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
  204. package/dist/tempo/internal/fee-payer.js.map +1 -1
  205. package/dist/tempo/internal/proof.d.ts +17 -17
  206. package/dist/tempo/internal/proof.d.ts.map +1 -1
  207. package/dist/tempo/legacy/client/Session.d.ts +20 -20
  208. package/dist/tempo/legacy/client/Session.js.map +1 -1
  209. package/dist/tempo/legacy/client/SessionManager.js.map +1 -1
  210. package/dist/tempo/legacy/index.d.ts +1 -3
  211. package/dist/tempo/legacy/index.d.ts.map +1 -1
  212. package/dist/tempo/legacy/index.js +1 -3
  213. package/dist/tempo/legacy/index.js.map +1 -1
  214. package/dist/tempo/legacy/session/escrow.abi.d.ts +374 -374
  215. package/dist/tempo/legacy/session/escrow.abi.d.ts.map +1 -1
  216. package/dist/tempo/server/Charge.d.ts +25 -11
  217. package/dist/tempo/server/Charge.d.ts.map +1 -1
  218. package/dist/tempo/server/Charge.js +44 -39
  219. package/dist/tempo/server/Charge.js.map +1 -1
  220. package/dist/tempo/server/Methods.d.ts +37 -52
  221. package/dist/tempo/server/Methods.d.ts.map +1 -1
  222. package/dist/tempo/server/Methods.js +0 -14
  223. package/dist/tempo/server/Methods.js.map +1 -1
  224. package/dist/tempo/server/Relay.d.ts +1 -1
  225. package/dist/tempo/server/Relay.d.ts.map +1 -1
  226. package/dist/tempo/server/Relay.js +2 -2
  227. package/dist/tempo/server/Relay.js.map +1 -1
  228. package/dist/tempo/server/Subscription.d.ts +25 -25
  229. package/dist/tempo/server/Subscription.d.ts.map +1 -1
  230. package/dist/tempo/server/Subscription.js +2 -0
  231. package/dist/tempo/server/Subscription.js.map +1 -1
  232. package/dist/tempo/server/index.d.ts +1 -1
  233. package/dist/tempo/server/index.d.ts.map +1 -1
  234. package/dist/tempo/server/index.js +1 -1
  235. package/dist/tempo/server/index.js.map +1 -1
  236. package/dist/tempo/server/internal/html.gen.d.ts +1 -1
  237. package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
  238. package/dist/tempo/server/internal/html.gen.js +1 -1
  239. package/dist/tempo/server/internal/html.gen.js.map +1 -1
  240. package/dist/tempo/server/internal/transport.d.ts +2 -0
  241. package/dist/tempo/server/internal/transport.d.ts.map +1 -1
  242. package/dist/tempo/server/internal/transport.js +9 -2
  243. package/dist/tempo/server/internal/transport.js.map +1 -1
  244. package/dist/tempo/session/client/ChannelOps.js.map +1 -1
  245. package/dist/tempo/session/client/CredentialState.d.ts +1 -1
  246. package/dist/tempo/session/client/CredentialState.js.map +1 -1
  247. package/dist/tempo/session/client/ReceiptCoordinator.js.map +1 -1
  248. package/dist/tempo/session/client/Runtime.js.map +1 -1
  249. package/dist/tempo/session/client/Session.d.ts +19 -19
  250. package/dist/tempo/session/client/Session.js.map +1 -1
  251. package/dist/tempo/session/client/SessionManager.js.map +1 -1
  252. package/dist/tempo/session/client/Transports.d.ts.map +1 -1
  253. package/dist/tempo/session/precompile/Chain.d.ts +27 -0
  254. package/dist/tempo/session/precompile/Chain.d.ts.map +1 -1
  255. package/dist/tempo/session/precompile/Chain.js +68 -7
  256. package/dist/tempo/session/precompile/Chain.js.map +1 -1
  257. package/dist/tempo/session/precompile/Protocol.js.map +1 -1
  258. package/dist/tempo/session/precompile/Voucher.d.ts +4 -4
  259. package/dist/tempo/session/precompile/Voucher.d.ts.map +1 -1
  260. package/dist/tempo/session/precompile/escrow.abi.d.ts +306 -306
  261. package/dist/tempo/session/precompile/escrow.abi.d.ts.map +1 -1
  262. package/dist/tempo/session/server/ChannelStore.d.ts +9 -0
  263. package/dist/tempo/session/server/ChannelStore.d.ts.map +1 -1
  264. package/dist/tempo/session/server/ChannelStore.js +16 -8
  265. package/dist/tempo/session/server/ChannelStore.js.map +1 -1
  266. package/dist/tempo/session/server/CredentialVerification.d.ts +30 -13
  267. package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -1
  268. package/dist/tempo/session/server/CredentialVerification.js +207 -13
  269. package/dist/tempo/session/server/CredentialVerification.js.map +1 -1
  270. package/dist/tempo/session/server/MeteredStream.d.ts +3 -0
  271. package/dist/tempo/session/server/MeteredStream.d.ts.map +1 -1
  272. package/dist/tempo/session/server/MeteredStream.js +3 -1
  273. package/dist/tempo/session/server/MeteredStream.js.map +1 -1
  274. package/dist/tempo/session/server/Session.d.ts +32 -21
  275. package/dist/tempo/session/server/Session.d.ts.map +1 -1
  276. package/dist/tempo/session/server/Session.js +116 -53
  277. package/dist/tempo/session/server/Session.js.map +1 -1
  278. package/dist/tempo/session/server/Sse.d.ts +3 -1
  279. package/dist/tempo/session/server/Sse.d.ts.map +1 -1
  280. package/dist/tempo/session/server/Sse.js +2 -1
  281. package/dist/tempo/session/server/Sse.js.map +1 -1
  282. package/dist/tempo/session/server/Transports.d.ts +1 -1
  283. package/dist/tempo/session/server/Transports.d.ts.map +1 -1
  284. package/dist/tempo/session/server/Transports.js +1 -0
  285. package/dist/tempo/session/server/Transports.js.map +1 -1
  286. package/dist/tempo/session/server/Ws.d.ts +6 -1
  287. package/dist/tempo/session/server/Ws.d.ts.map +1 -1
  288. package/dist/tempo/session/server/Ws.js +1 -0
  289. package/dist/tempo/session/server/Ws.js.map +1 -1
  290. package/dist/tempo/subscription/KeyAuthorization.d.ts +39 -39
  291. package/dist/tempo/subscription/KeyAuthorization.d.ts.map +1 -1
  292. package/dist/viem/Account.d.ts.map +1 -1
  293. package/dist/viem/Account.js.map +1 -1
  294. package/dist/web-bot-auth/Constants.d.ts +20 -0
  295. package/dist/web-bot-auth/Constants.d.ts.map +1 -0
  296. package/dist/web-bot-auth/Constants.js +24 -0
  297. package/dist/web-bot-auth/Constants.js.map +1 -0
  298. package/dist/web-bot-auth/Types.d.ts +10 -0
  299. package/dist/web-bot-auth/Types.d.ts.map +1 -0
  300. package/dist/web-bot-auth/Types.js +2 -0
  301. package/dist/web-bot-auth/Types.js.map +1 -0
  302. package/dist/web-bot-auth/client/index.d.ts +29 -0
  303. package/dist/web-bot-auth/client/index.d.ts.map +1 -0
  304. package/dist/web-bot-auth/client/index.js +64 -0
  305. package/dist/web-bot-auth/client/index.js.map +1 -0
  306. package/dist/web-bot-auth/index.d.ts +7 -0
  307. package/dist/web-bot-auth/index.d.ts.map +1 -0
  308. package/dist/web-bot-auth/index.js +7 -0
  309. package/dist/web-bot-auth/index.js.map +1 -0
  310. package/dist/web-bot-auth/internal/JwkThumbprint.d.ts +5 -0
  311. package/dist/web-bot-auth/internal/JwkThumbprint.d.ts.map +1 -0
  312. package/dist/web-bot-auth/internal/JwkThumbprint.js +20 -0
  313. package/dist/web-bot-auth/internal/JwkThumbprint.js.map +1 -0
  314. package/dist/web-bot-auth/internal/SignatureAgent.d.ts +3 -0
  315. package/dist/web-bot-auth/internal/SignatureAgent.d.ts.map +1 -0
  316. package/dist/web-bot-auth/internal/SignatureAgent.js +18 -0
  317. package/dist/web-bot-auth/internal/SignatureAgent.js.map +1 -0
  318. package/dist/web-bot-auth/server/index.d.ts +35 -0
  319. package/dist/web-bot-auth/server/index.d.ts.map +1 -0
  320. package/dist/web-bot-auth/server/index.js +88 -0
  321. package/dist/web-bot-auth/server/index.js.map +1 -0
  322. package/dist/x402/Assets.d.ts.map +1 -1
  323. package/dist/x402/Types.d.ts +6 -6
  324. package/dist/x402/Types.d.ts.map +1 -1
  325. package/dist/x402/server/EvmCharge.d.ts.map +1 -1
  326. package/dist/x402/server/EvmCharge.js +32 -20
  327. package/dist/x402/server/EvmCharge.js.map +1 -1
  328. package/package.json +19 -3
  329. package/src/Challenge.fuzz.test.ts +80 -47
  330. package/src/Challenge.test.ts +65 -0
  331. package/src/Challenge.ts +39 -35
  332. package/src/Method.ts +82 -68
  333. package/src/Store.test-d.ts +16 -0
  334. package/src/Store.test.ts +50 -0
  335. package/src/Store.ts +68 -0
  336. package/src/attestation/Attestation.integration.test.ts +208 -0
  337. package/src/attestation/Client.test.ts +83 -0
  338. package/src/attestation/Client.ts +34 -0
  339. package/src/attestation/Constants.ts +15 -0
  340. package/src/attestation/Server.test.ts +60 -0
  341. package/src/attestation/Server.ts +12 -0
  342. package/src/attestation/Types.test-d.ts +54 -0
  343. package/src/attestation/Types.ts +77 -0
  344. package/src/attestation/index.ts +5 -0
  345. package/src/attestation/internal/HttpMessageSignature.test.ts +101 -0
  346. package/src/attestation/internal/HttpMessageSignature.ts +429 -0
  347. package/src/attestation/internal/SigningContext.ts +13 -0
  348. package/src/bin.js +2 -0
  349. package/src/cli/cli.ts +1 -0
  350. package/src/client/Mppx.test-d.ts +17 -0
  351. package/src/client/Mppx.test.ts +14 -14
  352. package/src/client/Mppx.ts +25 -4
  353. package/src/client/Transport.test.ts +12 -45
  354. package/src/client/Transport.ts +3 -24
  355. package/src/client/internal/Fetch.ts +2 -6
  356. package/src/discovery/OpenApi.test.ts +170 -0
  357. package/src/discovery/OpenApi.ts +16 -48
  358. package/src/discovery/internal/Metadata.ts +51 -0
  359. package/src/evm/server/Charge.ts +6 -1
  360. package/src/internal/AcceptPayment.test.ts +12 -8
  361. package/src/internal/types.ts +9 -0
  362. package/src/mcp/client/McpClient.integration.test.ts +19 -32
  363. package/src/middlewares/elysia.test.ts +2 -12
  364. package/src/middlewares/express.test.ts +2 -12
  365. package/src/middlewares/hono.test.ts +6 -9
  366. package/src/middlewares/nextjs.test.ts +2 -12
  367. package/src/proxy/Proxy.test.ts +26 -19
  368. package/src/proxy/Proxy.ts +147 -9
  369. package/src/proxy/Proxy.upstreamError.test.ts +364 -0
  370. package/src/proxy/Service.test.ts +73 -3
  371. package/src/proxy/Service.ts +50 -23
  372. package/src/proxy/services/anthropic.ts +1 -0
  373. package/src/proxy/services/hooks.test-d.ts +14 -0
  374. package/src/proxy/services/hooks.test.ts +44 -0
  375. package/src/proxy/services/openai.ts +1 -0
  376. package/src/proxy/services/stripe.ts +1 -0
  377. package/src/server/Methods.test-d.ts +88 -0
  378. package/src/server/Methods.test.ts +69 -0
  379. package/src/server/Mppx.test-d.ts +141 -7
  380. package/src/server/Mppx.test.ts +1017 -119
  381. package/src/server/Mppx.ts +350 -54
  382. package/src/stripe/internal/constants.ts +1 -1
  383. package/src/stripe/internal/types.ts +1 -0
  384. package/src/stripe/server/Charge.test-d.ts +16 -1
  385. package/src/stripe/server/Charge.test.ts +79 -0
  386. package/src/stripe/server/Charge.ts +54 -1
  387. package/src/stripe/server/Methods.test-d.ts +157 -0
  388. package/src/stripe/server/Methods.test.ts +403 -0
  389. package/src/stripe/server/Methods.ts +423 -6
  390. package/src/stripe/server/internal/deposit-address.ts +57 -0
  391. package/src/stripe/server/internal/html/node_modules/.bin/mppx +3 -3
  392. package/src/stripe/server/internal/html/package.json +1 -1
  393. package/src/stripe/server/internal/html.gen.ts +1 -1
  394. package/src/stripe/server/internal/record-payment.ts +66 -0
  395. package/src/stripe/server/internal/request.ts +49 -0
  396. package/src/tap/Constants.ts +32 -0
  397. package/src/tap/Tap.test.ts +125 -0
  398. package/src/tap/Types.ts +11 -0
  399. package/src/tap/client/index.ts +54 -0
  400. package/src/tap/index.ts +4 -0
  401. package/src/tap/server/index.ts +48 -0
  402. package/src/tempo/PublicExports.test-d.ts +3 -3
  403. package/src/tempo/client/Charge.ts +1 -19
  404. package/src/tempo/internal/address.test.ts +42 -0
  405. package/src/tempo/internal/address.ts +3 -3
  406. package/src/tempo/internal/auto-swap.test.ts +4 -4
  407. package/src/tempo/internal/auto-swap.ts +7 -50
  408. package/src/tempo/legacy/README.md +5 -5
  409. package/src/tempo/legacy/index.ts +1 -3
  410. package/src/tempo/server/AtomicStore.test-d.ts +13 -0
  411. package/src/tempo/server/Charge.test.ts +19 -84
  412. package/src/tempo/server/Charge.ts +83 -55
  413. package/src/tempo/server/Methods.ts +0 -20
  414. package/src/tempo/server/Relay.test.ts +5 -5
  415. package/src/tempo/server/Relay.ts +2 -2
  416. package/src/tempo/server/Subscription.ts +4 -1
  417. package/src/tempo/server/index.ts +1 -1
  418. package/src/tempo/server/internal/html/node_modules/.bin/mppx +3 -3
  419. package/src/tempo/server/internal/html/package.json +1 -1
  420. package/src/tempo/server/internal/html.gen.ts +1 -1
  421. package/src/tempo/server/internal/transport.test.ts +22 -3
  422. package/src/tempo/server/internal/transport.ts +15 -3
  423. package/src/tempo/session/README.md +112 -0
  424. package/src/tempo/session/precompile/Chain.ts +131 -11
  425. package/src/tempo/session/server/ChannelStore.ts +33 -12
  426. package/src/tempo/session/server/CredentialVerification.test.ts +4 -4
  427. package/src/tempo/session/server/CredentialVerification.ts +340 -28
  428. package/src/tempo/session/server/MeteredStream.ts +5 -1
  429. package/src/tempo/session/server/Session.test.ts +428 -43
  430. package/src/tempo/session/server/Session.ts +159 -60
  431. package/src/tempo/session/server/Sse.test.ts +77 -0
  432. package/src/tempo/session/server/Sse.ts +8 -1
  433. package/src/tempo/session/server/Transports.ts +2 -1
  434. package/src/tempo/session/server/Ws.test.ts +171 -0
  435. package/src/tempo/session/server/Ws.ts +7 -1
  436. package/src/web-bot-auth/Constants.ts +24 -0
  437. package/src/web-bot-auth/Types.ts +9 -0
  438. package/src/web-bot-auth/WebBotAuth.test.ts +182 -0
  439. package/src/web-bot-auth/client/index.ts +84 -0
  440. package/src/web-bot-auth/index.ts +6 -0
  441. package/src/web-bot-auth/internal/JwkThumbprint.ts +21 -0
  442. package/src/web-bot-auth/internal/SignatureAgent.ts +18 -0
  443. package/src/web-bot-auth/server/index.ts +113 -0
  444. package/src/x402/Exact.e2e.test.ts +121 -81
  445. package/src/x402/Exact.localnet.test.ts +1 -1
  446. package/src/x402/server/EvmCharge.ts +35 -19
  447. package/dist/tempo/legacy/server/Session.d.ts +0 -208
  448. package/dist/tempo/legacy/server/Session.d.ts.map +0 -1
  449. package/dist/tempo/legacy/server/Session.js +0 -698
  450. package/dist/tempo/legacy/server/Session.js.map +0 -1
  451. package/dist/tempo/legacy/server/index.d.ts +0 -5
  452. package/dist/tempo/legacy/server/index.d.ts.map +0 -1
  453. package/dist/tempo/legacy/server/index.js +0 -5
  454. package/dist/tempo/legacy/server/index.js.map +0 -1
  455. package/dist/tempo/legacy/session/ChannelStore.d.ts +0 -22
  456. package/dist/tempo/legacy/session/ChannelStore.d.ts.map +0 -1
  457. package/dist/tempo/legacy/session/ChannelStore.js +0 -6
  458. package/dist/tempo/legacy/session/ChannelStore.js.map +0 -1
  459. package/src/tempo/legacy/server/Defaults.test-d.ts +0 -9
  460. package/src/tempo/legacy/server/Session.test.ts +0 -6370
  461. package/src/tempo/legacy/server/Session.ts +0 -1024
  462. package/src/tempo/legacy/server/index.ts +0 -4
  463. package/src/tempo/legacy/session/ChannelStore.test.ts +0 -58
  464. package/src/tempo/legacy/session/ChannelStore.ts +0 -39
@@ -77,38 +77,6 @@ describe('http', () => {
77
77
  })
78
78
  })
79
79
 
80
- describe('getChallenge', () => {
81
- test('default', () => {
82
- const transport = Transport.http()
83
- const response = new Response(null, {
84
- status: 402,
85
- headers: {
86
- 'WWW-Authenticate': Challenge.serialize(challenge),
87
- },
88
- })
89
-
90
- expect(transport.getChallenge(response)).toMatchObject({
91
- expires: '2025-01-01T00:00:00.000Z',
92
- id: expect.any(String),
93
- intent: 'charge',
94
- method: 'tempo',
95
- realm: 'api.example.com',
96
- request: {
97
- amount: '1000',
98
- currency: '0x20c0000000000000000000000000000000000001',
99
- recipient: '0x742d35Cc6634C0532925a3b844Bc9e7595f8fE00',
100
- },
101
- })
102
- })
103
-
104
- test('throws for non-402 response', () => {
105
- const transport = Transport.http()
106
- const response = new Response(null, { status: 200 })
107
-
108
- expect(() => transport.getChallenge(response)).toThrow()
109
- })
110
- })
111
-
112
80
  describe('getChallenges', () => {
113
81
  test.each([
114
82
  {
@@ -188,7 +156,7 @@ describe('http', () => {
188
156
  status: 402,
189
157
  headers: headers(),
190
158
  })
191
- const challenges = (await transport.getChallenges?.(response)) ?? []
159
+ const challenges = await transport.getChallenges(response)
192
160
 
193
161
  expect(challenges.map((entry) => entry.id)).toEqual(expectedIds)
194
162
  expect(challenges.map((entry) => entry.method)).toEqual(expectedMethods)
@@ -207,7 +175,7 @@ describe('http', () => {
207
175
  },
208
176
  })
209
177
 
210
- const challenges = (await transport.getChallenges?.(response)) ?? []
178
+ const challenges = await transport.getChallenges(response)
211
179
 
212
180
  expect(challenges.map((entry) => entry.id)).toEqual([challenge.id])
213
181
  expect(challenges.map((entry) => entry.method)).toEqual(['tempo'])
@@ -225,9 +193,8 @@ describe('http', () => {
225
193
  },
226
194
  })
227
195
 
228
- const challenges = (await transport.getChallenges?.(response)) ?? []
196
+ const challenges = await transport.getChallenges(response)
229
197
  expect(challenges).toEqual([])
230
- expect(() => transport.getChallenge(response)).toThrow('No challenge in response.')
231
198
  })
232
199
  })
233
200
 
@@ -265,7 +232,7 @@ describe('http', () => {
265
232
 
266
233
  test('writes x402 credentials for x402 challenges from the same transport', () => {
267
234
  const transport = Transport.http()
268
- const [x402Challenge] = transport.getChallenges!(
235
+ const [x402Challenge] = transport.getChallenges(
269
236
  new Response(null, {
270
237
  status: 402,
271
238
  headers: {
@@ -306,7 +273,7 @@ describe('http', () => {
306
273
  method: 'POST',
307
274
  body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'tools/call', params: {} }),
308
275
  } satisfies RequestInit
309
- const [nativeChallenge] = transport.getChallenges!(
276
+ const [nativeChallenge] = transport.getChallenges(
310
277
  new Response(null, {
311
278
  status: 402,
312
279
  headers: { 'WWW-Authenticate': Challenge.serialize(challenge) },
@@ -326,7 +293,7 @@ describe('http', () => {
326
293
  test('marks x402 challenges with the brand the evm charge client reads', async () => {
327
294
  // Provenance guard: `evm/client/Charge.ts` recognizes x402 challenges via the same
328
295
  // brand the x402 adapter stamps. If the marking site drifts, EVM x402 charges misroute.
329
- const [x402Challenge] = await Transport.http().getChallenges!(
296
+ const [x402Challenge] = await Transport.http().getChallenges(
330
297
  new Response(null, {
331
298
  status: 402,
332
299
  headers: {
@@ -339,7 +306,7 @@ describe('http', () => {
339
306
 
340
307
  test('removes stale credential headers before setting the retry credential', async () => {
341
308
  const transport = Transport.http()
342
- const [x402Challenge] = await transport.getChallenges!(
309
+ const [x402Challenge] = await transport.getChallenges(
343
310
  new Response(null, {
344
311
  status: 402,
345
312
  headers: {
@@ -497,16 +464,16 @@ describe('http (MCP-over-HTTP)', () => {
497
464
  expect(await Transport.http().isPaymentRequired(ok, jsonRpcRequest)).toBe(false)
498
465
  })
499
466
  test('getChallenges extracts the MCP challenge (via the mcp protocol)', async () => {
500
- const challenges = await Transport.http().getChallenges!(sseBody(), jsonRpcRequest)
467
+ const challenges = await Transport.http().getChallenges(sseBody(), jsonRpcRequest)
501
468
  expect(challenges.map((entry) => entry.id)).toEqual([challenge.id])
502
469
  })
503
470
  test('getChallenges extracts an MCP result metadata challenge', async () => {
504
- const challenges = await Transport.http().getChallenges!(jsonResultBody(), jsonRpcRequest)
471
+ const challenges = await Transport.http().getChallenges(jsonResultBody(), jsonRpcRequest)
505
472
  expect(challenges.map((entry) => entry.id)).toEqual([challenge.id])
506
473
  })
507
474
  test('setCredential routes the MCP challenge into the JSON-RPC _meta', async () => {
508
475
  const transport = Transport.http()
509
- const [mcpChallenge] = await transport.getChallenges!(sseBody(), jsonRpcRequest)
476
+ const [mcpChallenge] = await transport.getChallenges(sseBody(), jsonRpcRequest)
510
477
  const result = transport.setCredential(jsonRpcRequest, Credential.serialize(credential), {
511
478
  challenge: mcpChallenge,
512
479
  }) as RequestInit
@@ -593,7 +560,7 @@ describe('mcp', () => {
593
560
  const transport = Transport.mcp()
594
561
 
595
562
  expect(await transport.isPaymentRequired(mcpResponse)).toBe(true)
596
- expect((await transport.getChallenges?.(mcpResponse))?.map((entry) => entry.id)).toEqual([
563
+ expect((await transport.getChallenges(mcpResponse)).map((entry) => entry.id)).toEqual([
597
564
  challenge.id,
598
565
  ])
599
566
  })
@@ -602,7 +569,7 @@ describe('mcp', () => {
602
569
  const transport = Transport.mcp()
603
570
 
604
571
  expect(await transport.isPaymentRequired(mcpResult)).toBe(true)
605
- expect((await transport.getChallenges?.(mcpResult))?.map((entry) => entry.id)).toEqual([
572
+ expect((await transport.getChallenges(mcpResult)).map((entry) => entry.id)).toEqual([
606
573
  challenge.id,
607
574
  ])
608
575
  })
@@ -21,16 +21,11 @@ export type Transport<in out request = unknown, in out response = unknown> = {
21
21
  * body reads) and be async (to read a response body).
22
22
  */
23
23
  isPaymentRequired: (response: response, request?: request) => boolean | Promise<boolean>
24
- /** Extracts all challenges from a payment-required response, when the transport supports multiple offers. */
25
- getChallenges?: (
24
+ /** Extracts all challenges from a payment-required response. */
25
+ getChallenges: (
26
26
  response: response,
27
27
  request?: request,
28
28
  ) => Challenge.Challenge[] | Promise<Challenge.Challenge[]>
29
- /** Extracts the challenge from a payment-required response. */
30
- getChallenge: (
31
- response: response,
32
- request?: request,
33
- ) => Challenge.Challenge | Promise<Challenge.Challenge>
34
29
  /** Attaches a credential to a request. */
35
30
  setCredential: (
36
31
  request: request,
@@ -65,7 +60,7 @@ export type RequestOf<transport extends Transport> =
65
60
  * const custom = Transport.from({
66
61
  * name: 'custom',
67
62
  * isPaymentRequired(response) { ... },
68
- * getChallenge(response) { ... },
63
+ * getChallenges(response) { ... },
69
64
  * setCredential(request, credential) { ... },
70
65
  * })
71
66
  * ```
@@ -125,16 +120,6 @@ export function http(): Transport<RequestInit, Response> {
125
120
  return collect(response, request)
126
121
  },
127
122
 
128
- getChallenge(response, request) {
129
- const pick = (challenges: Challenge.Challenge[]): Challenge.Challenge => {
130
- const challenge = challenges[0]
131
- if (!challenge) throw new Error('No challenge in response.')
132
- return challenge
133
- }
134
- const challenges = collect(response, request)
135
- return challenges instanceof Promise ? challenges.then(pick) : pick(challenges)
136
- },
137
-
138
123
  setCredential(request, credential, options) {
139
124
  const protocol = options?.challenge ? protocolForChallenge.get(options.challenge) : undefined
140
125
  const fallback = protocols[0]
@@ -168,12 +153,6 @@ export function mcp() {
168
153
  return mcpPaymentRequiredChallenges(response)
169
154
  },
170
155
 
171
- getChallenge(response) {
172
- const challenge = mcpPaymentRequiredChallenges(response)[0]
173
- if (!challenge) throw new Error('No challenge in response.')
174
- return challenge
175
- },
176
-
177
156
  setCredential(request, credential) {
178
157
  const parsed = Credential.deserialize(credential)
179
158
  return {
@@ -238,9 +238,7 @@ export function from<const methods extends readonly Method.AnyClient[]>(
238
238
 
239
239
  try {
240
240
  for (let retry = 0; retry < maxPaymentRetries; retry++) {
241
- challenges = transport.getChallenges
242
- ? await transport.getChallenges(response, transportRequest as never)
243
- : [await transport.getChallenge(response, transportRequest as never)]
241
+ challenges = await transport.getChallenges(response, transportRequest as never)
244
242
 
245
243
  const candidates = AcceptPayment.selectChallengeCandidates(
246
244
  challenges,
@@ -420,9 +418,7 @@ export function from<const methods extends readonly Method.AnyClient[]>(
420
418
  }
421
419
  challenges = undefined
422
420
  try {
423
- challenges = transport.getChallenges
424
- ? await transport.getChallenges(response, transportRequest as never)
425
- : [await transport.getChallenge(response, transportRequest as never)]
421
+ challenges = await transport.getChallenges(response, transportRequest as never)
426
422
  } catch {}
427
423
  await settleAttempt(preparedCredential, {
428
424
  challenges,
@@ -1,3 +1,4 @@
1
+ import * as Challenge from '../Challenge.js'
1
2
  import * as Method from '../Method.js'
2
3
  import * as Mppx from '../server/Mppx.js'
3
4
  import * as z from '../zod.js'
@@ -56,6 +57,8 @@ const subscribe = Method.toServer(
56
57
  credential: { payload: z.object({ signature: z.string() }) },
57
58
  request: z.object({
58
59
  amount: z.string(),
60
+ interval: z.string(),
61
+ recipient: z.string(),
59
62
  }),
60
63
  },
61
64
  }),
@@ -69,6 +72,38 @@ const subscribe = Method.toServer(
69
72
  },
70
73
  )
71
74
 
75
+ const transformedCharge = Method.toServer(
76
+ Method.from({
77
+ intent: 'charge',
78
+ name: 'transformed',
79
+ schema: {
80
+ credential: { payload: z.object({ signature: z.string() }) },
81
+ request: z.pipe(
82
+ z.object({
83
+ amount: z.string(),
84
+ asset: z.string(),
85
+ decimals: z.number(),
86
+ recipient: z.string(),
87
+ }),
88
+ z.transform(({ amount, asset, decimals, recipient }) => ({
89
+ amount: String(Number(amount) * 10 ** decimals),
90
+ currency: asset,
91
+ methodDetails: { decimals },
92
+ recipient,
93
+ })),
94
+ ),
95
+ },
96
+ }),
97
+ {
98
+ verify: async () => ({
99
+ method: 'transformed',
100
+ reference: '',
101
+ status: 'success' as const,
102
+ timestamp: '',
103
+ }),
104
+ },
105
+ )
106
+
72
107
  function createMppx<const methods extends Mppx.Methods>(methods: methods) {
73
108
  return Mppx.create({
74
109
  methods,
@@ -169,6 +204,7 @@ describe('generate', () => {
169
204
  {
170
205
  "amount": "50",
171
206
  "currency": "usd",
207
+ "description": "Search credits",
172
208
  "intent": "charge",
173
209
  "method": "tempo",
174
210
  "recipient": "0x1",
@@ -182,6 +218,140 @@ describe('generate', () => {
182
218
  `)
183
219
  })
184
220
 
221
+ test('matches handler discovery to its canonical runtime challenge', async () => {
222
+ const mppx = createMppx([transformedCharge])
223
+ const handler = mppx.charge({
224
+ amount: '2',
225
+ asset: '0xUSDC',
226
+ decimals: 6,
227
+ description: 'Canonical price',
228
+ recipient: '0x1',
229
+ })
230
+
231
+ const doc = generate(mppx, {
232
+ routes: [{ handler, method: 'post', path: '/api/resource' }],
233
+ }) as any
234
+ const result = await handler(new Request('https://example.com/api/resource'))
235
+ if (result.status !== 402) throw new Error('Expected payment challenge')
236
+ const challenge = Challenge.fromResponse(result.challenge)
237
+
238
+ expect(doc.paths['/api/resource'].post['x-payment-info'].offers[0]).toEqual({
239
+ amount: challenge.request.amount,
240
+ currency: challenge.request.currency,
241
+ description: challenge.description,
242
+ intent: challenge.intent,
243
+ method: challenge.method,
244
+ recipient: challenge.request.recipient,
245
+ })
246
+ })
247
+
248
+ test('applies method schema transforms to legacy route discovery', () => {
249
+ const mppx = createMppx([transformedCharge])
250
+ const doc = generate(mppx, {
251
+ routes: [
252
+ {
253
+ intent: 'charge',
254
+ method: 'post',
255
+ options: {
256
+ amount: '2',
257
+ asset: '0xUSDC',
258
+ decimals: 6,
259
+ description: 'Canonical price',
260
+ recipient: '0x1',
261
+ },
262
+ path: '/api/resource',
263
+ },
264
+ ],
265
+ }) as any
266
+
267
+ expect(doc.paths['/api/resource'].post['x-payment-info'].offers[0]).toEqual({
268
+ amount: '2000000',
269
+ currency: '0xUSDC',
270
+ description: 'Canonical price',
271
+ intent: 'charge',
272
+ method: 'transformed',
273
+ recipient: '0x1',
274
+ })
275
+ })
276
+
277
+ test('derives only explicitly composed payment offers from a handler', () => {
278
+ const mppx = createMppx([charge, session])
279
+ const handler = mppx.compose(
280
+ ['tempo/charge', { amount: '50', currency: '0xUSDC', description: 'USDC', recipient: '0x1' }],
281
+ [
282
+ 'tempo/charge',
283
+ { amount: '50', currency: '0xNANOUSD', description: 'NANOUSD', recipient: '0x1' },
284
+ ],
285
+ )
286
+
287
+ const doc = generate(mppx, {
288
+ routes: [{ handler, method: 'post', path: '/api/search' }],
289
+ }) as any
290
+
291
+ expect(doc.paths['/api/search'].post['x-payment-info'].offers).toEqual([
292
+ {
293
+ amount: '50',
294
+ currency: '0xUSDC',
295
+ description: 'USDC',
296
+ intent: 'charge',
297
+ method: 'tempo',
298
+ recipient: '0x1',
299
+ },
300
+ {
301
+ amount: '50',
302
+ currency: '0xNANOUSD',
303
+ description: 'NANOUSD',
304
+ intent: 'charge',
305
+ method: 'tempo',
306
+ recipient: '0x1',
307
+ },
308
+ ])
309
+ })
310
+
311
+ test('keeps nested composed discovery in runtime challenge order', async () => {
312
+ const mppx = createMppx([charge])
313
+ const handler = Mppx.compose(
314
+ mppx.charge({
315
+ amount: '1',
316
+ currency: '0xUSDC',
317
+ description: 'USDC',
318
+ recipient: '0x1',
319
+ }),
320
+ Mppx.compose(
321
+ mppx.charge({
322
+ amount: '2',
323
+ currency: '0xNANOUSD',
324
+ description: 'NANOUSD',
325
+ recipient: '0x1',
326
+ }),
327
+ mppx.charge({
328
+ amount: '3',
329
+ currency: 'usd',
330
+ description: 'Card',
331
+ recipient: '0x1',
332
+ }),
333
+ ),
334
+ )
335
+
336
+ const doc = generate(mppx, {
337
+ routes: [{ handler, method: 'post', path: '/api/search' }],
338
+ }) as any
339
+ const result = await handler(new Request('https://example.com/api/search'))
340
+ if (result.status !== 402) throw new Error('Expected payment challenge')
341
+
342
+ const discovered = doc.paths['/api/search'].post['x-payment-info'].offers
343
+ const challenged = Challenge.fromResponseList(result.challenge).map((challenge) => ({
344
+ amount: challenge.request.amount,
345
+ currency: challenge.request.currency,
346
+ description: challenge.description,
347
+ intent: challenge.intent,
348
+ method: challenge.method,
349
+ recipient: challenge.request.recipient,
350
+ }))
351
+
352
+ expect(discovered).toEqual(challenged)
353
+ })
354
+
185
355
  test('handles null amount for session intent', () => {
186
356
  const mppx = createMppx([session])
187
357
  const doc = generate(mppx, {
@@ -1,12 +1,11 @@
1
1
  import type * as Method from '../Method.js'
2
+ import * as PaymentRequest from '../PaymentRequest.js'
2
3
  import { PaymentInfo, type ServiceInfo } from './Discovery.js'
4
+ import * as Metadata from './internal/Metadata.js'
3
5
 
6
+ /** Payment handler carrying metadata used to generate discovery documents. */
4
7
  export type DiscoveryHandler = ((...args: any[]) => unknown) & {
5
- _internal?: {
6
- _canonicalRequest: Record<string, unknown>
7
- intent: string
8
- name: string
9
- }
8
+ _internal?: Metadata.Metadata
10
9
  }
11
10
 
12
11
  export type LegacyRouteConfig = {
@@ -151,11 +150,9 @@ function resolveRoute(
151
150
  return {
152
151
  method: route.method,
153
152
  path: route.path,
154
- payment: paymentInfoFromCanonical({
155
- canonicalRequest: internal._canonicalRequest,
156
- intent: internal.intent,
157
- method: internal.name,
158
- }),
153
+ payment: {
154
+ offers: Metadata.offers(internal).map(Metadata.paymentOffer),
155
+ },
159
156
  ...(route.requestBody ? { requestBody: route.requestBody } : {}),
160
157
  ...(route.summary ? { summary: route.summary } : {}),
161
158
  }
@@ -168,52 +165,23 @@ function resolveRoute(
168
165
  )
169
166
  }
170
167
 
168
+ const { description, ...options } = route.options
169
+ const metadata: Metadata.Offer = {
170
+ _canonicalRequest: PaymentRequest.fromMethod(mi, options as never),
171
+ ...(typeof description === 'string' ? { description } : {}),
172
+ intent: mi.intent,
173
+ name: mi.name,
174
+ }
175
+
171
176
  return {
172
177
  method: route.method,
173
178
  path: route.path,
174
- payment: paymentInfoFromCanonical({
175
- canonicalRequest: route.options,
176
- intent: mi.intent,
177
- method: mi.name,
178
- }),
179
+ payment: Metadata.paymentOffer(metadata),
179
180
  ...(route.requestBody ? { requestBody: route.requestBody } : {}),
180
181
  ...(route.summary ? { summary: route.summary } : {}),
181
182
  }
182
183
  }
183
184
 
184
- function paymentInfoFromCanonical(route: {
185
- canonicalRequest: Record<string, unknown>
186
- intent: string
187
- method: string
188
- }) {
189
- const { canonicalRequest, intent, method } = route
190
- const methodDetails = (canonicalRequest.methodDetails ?? {}) as Record<string, unknown>
191
-
192
- const amount = pickString(canonicalRequest.amount) ?? pickString(methodDetails.amount) ?? null
193
- const currency = pickString(canonicalRequest.currency) ?? pickString(methodDetails.currency)
194
- const description = pickString(canonicalRequest.description)
195
-
196
- const base: Record<string, unknown> = {
197
- amount,
198
- ...(currency ? { currency } : {}),
199
- ...(description ? { description } : {}),
200
- intent,
201
- method,
202
- }
203
-
204
- // Forward any extra canonical params that aren't already covered.
205
- const reserved = new Set(['amount', 'currency', 'description', 'methodDetails'])
206
- for (const [key, value] of Object.entries(canonicalRequest)) {
207
- if (!reserved.has(key) && value !== undefined) base[key] = value
208
- }
209
-
210
- return base
211
- }
212
-
213
- function pickString(value: unknown) {
214
- return typeof value === 'string' ? value : undefined
215
- }
216
-
217
185
  function withBasePath(basePath: string | undefined, path: string) {
218
186
  if (!basePath) return path
219
187
  const normalizedBasePath = basePath.startsWith('/') ? basePath : `/${basePath}`
@@ -0,0 +1,51 @@
1
+ /** Metadata retained by one explicitly configured payment handler. */
2
+ export type Offer = {
3
+ _canonicalRequest: Record<string, unknown>
4
+ description?: string | undefined
5
+ intent: string
6
+ name: string
7
+ }
8
+
9
+ /** Metadata retained by a single or composed payment handler. */
10
+ export type Metadata = Offer | { offers: readonly Offer[] }
11
+
12
+ /** Returns every explicitly configured offer from discovery metadata. */
13
+ export function offers(metadata: Metadata): readonly Offer[] {
14
+ if (isComposed(metadata)) return metadata.offers
15
+ return [metadata]
16
+ }
17
+
18
+ /** Converts configured handler metadata into a discovery payment offer. */
19
+ export function paymentOffer(metadata: Offer): Record<string, unknown> {
20
+ const { _canonicalRequest: request, intent, name: method } = metadata
21
+ const methodDetails = (request.methodDetails ?? {}) as Record<string, unknown>
22
+
23
+ const amount = pickString(request.amount) ?? pickString(methodDetails.amount) ?? null
24
+ const currency = pickString(request.currency) ?? pickString(methodDetails.currency)
25
+ const description = pickString(metadata.description) ?? pickString(request.description)
26
+
27
+ const offer: Record<string, unknown> = {
28
+ amount,
29
+ ...(currency ? { currency } : {}),
30
+ ...(description ? { description } : {}),
31
+ intent,
32
+ method,
33
+ }
34
+
35
+ // Preserve extension fields emitted by method request schemas.
36
+ const reserved = new Set(['amount', 'currency', 'description', 'methodDetails'])
37
+ for (const [key, value] of Object.entries(request)) {
38
+ if (!reserved.has(key) && value !== undefined) offer[key] = value
39
+ }
40
+
41
+ return offer
42
+ }
43
+
44
+ /** Returns whether metadata represents a composed handler. */
45
+ export function isComposed(metadata: Metadata): metadata is Extract<Metadata, { offers: unknown }> {
46
+ return 'offers' in metadata && !('_canonicalRequest' in metadata)
47
+ }
48
+
49
+ function pickString(value: unknown) {
50
+ return typeof value === 'string' ? value : undefined
51
+ }
@@ -24,6 +24,8 @@ export function charge(parameters: charge.NativeConfig): Method.AnyServer {
24
24
  const transport = httpTransport(paths)
25
25
 
26
26
  return Method.toServer<typeof Methods.charge, charge.Defaults, typeof transport>(Methods.charge, {
27
+ canOffer: parameters.canOffer,
28
+ onPaymentSuccess: parameters.onPaymentSuccess,
27
29
  defaults: {
28
30
  chainId: config.chainId,
29
31
  currency: config.currency,
@@ -107,7 +109,10 @@ export declare namespace charge {
107
109
  type Parameters = NativeConfig
108
110
  type Native = Method.Server<typeof Methods.charge, Defaults>
109
111
 
110
- type NativeConfig = BaseConfig & CurrencyConfig & RecipientConfig
112
+ type NativeConfig = BaseConfig &
113
+ CurrencyConfig &
114
+ RecipientConfig &
115
+ Method.ComposableHooks<typeof Methods.charge>
111
116
 
112
117
  type BaseConfig = {
113
118
  /** EIP-3009 token domain metadata. Required for raw addresses and viem tokens; inferred for known assets. */
@@ -226,21 +226,21 @@ describe('AcceptPayment', () => {
226
226
  test('selectChallengeCandidates supports duplicate method keys with challenge predicates', () => {
227
227
  const challenges = [
228
228
  {
229
- id: 'v2',
229
+ id: 'primary',
230
230
  intent: 'session',
231
231
  method: 'tempo',
232
232
  realm: 'test',
233
- request: { methodDetails: { sessionProtocol: 'v2' } },
233
+ request: { methodDetails: { sessionProtocol: 'primary' } },
234
234
  },
235
235
  {
236
- id: 'v1',
236
+ id: 'fallback',
237
237
  intent: 'session',
238
238
  method: 'tempo',
239
239
  realm: 'test',
240
- request: { methodDetails: { sessionProtocol: 'v1' } },
240
+ request: { methodDetails: { sessionProtocol: 'fallback' } },
241
241
  },
242
242
  {
243
- id: 'old-server',
243
+ id: 'unmarked',
244
244
  intent: 'session',
245
245
  method: 'tempo',
246
246
  realm: 'test',
@@ -257,7 +257,7 @@ describe('AcceptPayment', () => {
257
257
  challenge: AcceptPayment.ChallengeCandidate['challenge']
258
258
  }) =>
259
259
  (challenge.request.methodDetails as { sessionProtocol?: string } | undefined)
260
- ?.sessionProtocol === 'v2',
260
+ ?.sessionProtocol === 'primary',
261
261
  },
262
262
  {
263
263
  name: 'tempo',
@@ -270,7 +270,7 @@ describe('AcceptPayment', () => {
270
270
  const sessionProtocol = (
271
271
  challenge.request.methodDetails as { sessionProtocol?: string } | undefined
272
272
  )?.sessionProtocol
273
- return sessionProtocol === undefined || sessionProtocol === 'v1'
273
+ return sessionProtocol === undefined || sessionProtocol === 'fallback'
274
274
  },
275
275
  },
276
276
  ] as const
@@ -281,7 +281,11 @@ describe('AcceptPayment', () => {
281
281
  AcceptPayment.parse('tempo/session'),
282
282
  )
283
283
 
284
- expect(candidates.map(({ challenge }) => challenge.id)).toEqual(['v2', 'v1', 'old-server'])
284
+ expect(candidates.map(({ challenge }) => challenge.id)).toEqual([
285
+ 'primary',
286
+ 'fallback',
287
+ 'unmarked',
288
+ ])
285
289
  })
286
290
 
287
291
  test('selectChallenge honors a specific opt-out over a broader wildcard', () => {
@@ -2,6 +2,15 @@
2
2
  // https://twitter.com/mattpocockuk/status/1622730173446557697?s=20&t=NdpAcmEFXY01xkqU3KO0Mg
3
3
  export type Compute<type> = { [key in keyof type]: type[key] } & unknown
4
4
 
5
+ /** Recursively makes every property of a value readonly. */
6
+ export type DeepReadonly<type> = type extends (...args: infer _arguments) => infer _return
7
+ ? type
8
+ : type extends readonly unknown[]
9
+ ? { readonly [key in keyof type]: DeepReadonly<type[key]> }
10
+ : type extends object
11
+ ? { readonly [key in keyof type]: DeepReadonly<type[key]> }
12
+ : type
13
+
5
14
  declare const symbol: unique symbol
6
15
 
7
16
  /**