mppx 0.8.14 → 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 (507) hide show
  1. package/CHANGELOG.md +57 -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/cli/validate/payment.d.ts.map +1 -1
  66. package/dist/cli/validate/payment.js +18 -4
  67. package/dist/cli/validate/payment.js.map +1 -1
  68. package/dist/client/Mppx.d.ts +3 -0
  69. package/dist/client/Mppx.d.ts.map +1 -1
  70. package/dist/client/Mppx.js +13 -5
  71. package/dist/client/Mppx.js.map +1 -1
  72. package/dist/client/Transport.d.ts +3 -5
  73. package/dist/client/Transport.d.ts.map +1 -1
  74. package/dist/client/Transport.js +1 -17
  75. package/dist/client/Transport.js.map +1 -1
  76. package/dist/client/internal/Fetch.d.ts.map +1 -1
  77. package/dist/client/internal/Fetch.js +92 -13
  78. package/dist/client/internal/Fetch.js.map +1 -1
  79. package/dist/client/internal/MethodChallenge.d.ts +2 -0
  80. package/dist/client/internal/MethodChallenge.d.ts.map +1 -1
  81. package/dist/client/internal/MethodChallenge.js +4 -0
  82. package/dist/client/internal/MethodChallenge.js.map +1 -1
  83. package/dist/client/internal/MethodResponse.d.ts +15 -0
  84. package/dist/client/internal/MethodResponse.d.ts.map +1 -1
  85. package/dist/client/internal/MethodResponse.js +10 -0
  86. package/dist/client/internal/MethodResponse.js.map +1 -1
  87. package/dist/client/node.js.map +1 -1
  88. package/dist/discovery/OpenApi.d.ts +3 -5
  89. package/dist/discovery/OpenApi.d.ts.map +1 -1
  90. package/dist/discovery/OpenApi.js +13 -34
  91. package/dist/discovery/OpenApi.js.map +1 -1
  92. package/dist/discovery/internal/Metadata.d.ts +20 -0
  93. package/dist/discovery/internal/Metadata.d.ts.map +1 -0
  94. package/dist/discovery/internal/Metadata.js +36 -0
  95. package/dist/discovery/internal/Metadata.js.map +1 -0
  96. package/dist/evm/Methods.d.ts +11 -11
  97. package/dist/evm/Methods.d.ts.map +1 -1
  98. package/dist/evm/Types.d.ts +17 -17
  99. package/dist/evm/Types.d.ts.map +1 -1
  100. package/dist/evm/client/Charge.d.ts +11 -11
  101. package/dist/evm/client/Methods.d.ts +11 -11
  102. package/dist/evm/server/Charge.d.ts +1 -1
  103. package/dist/evm/server/Charge.d.ts.map +1 -1
  104. package/dist/evm/server/Charge.js +2 -0
  105. package/dist/evm/server/Charge.js.map +1 -1
  106. package/dist/evm/server/Methods.d.ts +11 -11
  107. package/dist/internal/HeaderCodec.d.ts +2 -2
  108. package/dist/internal/HeaderCodec.d.ts.map +1 -1
  109. package/dist/internal/types.d.ts +6 -0
  110. package/dist/internal/types.d.ts.map +1 -1
  111. package/dist/middlewares/elysia.js.map +1 -1
  112. package/dist/middlewares/express.js.map +1 -1
  113. package/dist/middlewares/hono.js.map +1 -1
  114. package/dist/middlewares/nextjs.js.map +1 -1
  115. package/dist/proxy/Proxy.d.ts +2 -0
  116. package/dist/proxy/Proxy.d.ts.map +1 -1
  117. package/dist/proxy/Proxy.js +117 -9
  118. package/dist/proxy/Proxy.js.map +1 -1
  119. package/dist/proxy/Service.d.ts +36 -1
  120. package/dist/proxy/Service.d.ts.map +1 -1
  121. package/dist/proxy/Service.js +9 -8
  122. package/dist/proxy/Service.js.map +1 -1
  123. package/dist/proxy/services/anthropic.d.ts.map +1 -1
  124. package/dist/proxy/services/anthropic.js +1 -0
  125. package/dist/proxy/services/anthropic.js.map +1 -1
  126. package/dist/proxy/services/openai.d.ts.map +1 -1
  127. package/dist/proxy/services/openai.js +1 -0
  128. package/dist/proxy/services/openai.js.map +1 -1
  129. package/dist/proxy/services/stripe.d.ts.map +1 -1
  130. package/dist/proxy/services/stripe.js +1 -0
  131. package/dist/proxy/services/stripe.js.map +1 -1
  132. package/dist/server/Mppx.d.ts +75 -13
  133. package/dist/server/Mppx.d.ts.map +1 -1
  134. package/dist/server/Mppx.js +201 -23
  135. package/dist/server/Mppx.js.map +1 -1
  136. package/dist/server/internal/html/config.d.ts +9 -9
  137. package/dist/server/internal/html/config.d.ts.map +1 -1
  138. package/dist/server/internal/html/constants.d.ts +17 -17
  139. package/dist/server/internal/html/constants.d.ts.map +1 -1
  140. package/dist/stripe/Methods.d.ts +10 -10
  141. package/dist/stripe/Methods.d.ts.map +1 -1
  142. package/dist/stripe/client/Charge.d.ts +10 -10
  143. package/dist/stripe/client/Methods.d.ts +10 -10
  144. package/dist/stripe/internal/constants.d.ts +1 -1
  145. package/dist/stripe/internal/constants.js +1 -1
  146. package/dist/stripe/internal/types.d.ts +1 -0
  147. package/dist/stripe/internal/types.d.ts.map +1 -1
  148. package/dist/stripe/server/Charge.d.ts +11 -11
  149. package/dist/stripe/server/Charge.d.ts.map +1 -1
  150. package/dist/stripe/server/Charge.js +49 -1
  151. package/dist/stripe/server/Charge.js.map +1 -1
  152. package/dist/stripe/server/Methods.d.ts +137 -48
  153. package/dist/stripe/server/Methods.d.ts.map +1 -1
  154. package/dist/stripe/server/Methods.js +259 -4
  155. package/dist/stripe/server/Methods.js.map +1 -1
  156. package/dist/stripe/server/internal/deposit-address.d.ts +13 -0
  157. package/dist/stripe/server/internal/deposit-address.d.ts.map +1 -0
  158. package/dist/stripe/server/internal/deposit-address.js +28 -0
  159. package/dist/stripe/server/internal/deposit-address.js.map +1 -0
  160. package/dist/stripe/server/internal/html.gen.d.ts +1 -1
  161. package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
  162. package/dist/stripe/server/internal/html.gen.js +1 -1
  163. package/dist/stripe/server/internal/html.gen.js.map +1 -1
  164. package/dist/stripe/server/internal/record-payment.d.ts +15 -0
  165. package/dist/stripe/server/internal/record-payment.d.ts.map +1 -0
  166. package/dist/stripe/server/internal/record-payment.js +42 -0
  167. package/dist/stripe/server/internal/record-payment.js.map +1 -0
  168. package/dist/stripe/server/internal/request.d.ts +25 -0
  169. package/dist/stripe/server/internal/request.d.ts.map +1 -0
  170. package/dist/stripe/server/internal/request.js +29 -0
  171. package/dist/stripe/server/internal/request.js.map +1 -0
  172. package/dist/tap/Constants.d.ts +28 -0
  173. package/dist/tap/Constants.d.ts.map +1 -0
  174. package/dist/tap/Constants.js +32 -0
  175. package/dist/tap/Constants.js.map +1 -0
  176. package/dist/tap/Types.d.ts +11 -0
  177. package/dist/tap/Types.d.ts.map +1 -0
  178. package/dist/tap/Types.js +2 -0
  179. package/dist/tap/Types.js.map +1 -0
  180. package/dist/tap/client/index.d.ts +26 -0
  181. package/dist/tap/client/index.d.ts.map +1 -0
  182. package/dist/tap/client/index.js +33 -0
  183. package/dist/tap/client/index.js.map +1 -0
  184. package/dist/tap/index.d.ts +5 -0
  185. package/dist/tap/index.d.ts.map +1 -0
  186. package/dist/tap/index.js +5 -0
  187. package/dist/tap/index.js.map +1 -0
  188. package/dist/tap/server/index.d.ts +20 -0
  189. package/dist/tap/server/index.d.ts.map +1 -0
  190. package/dist/tap/server/index.js +36 -0
  191. package/dist/tap/server/index.js.map +1 -0
  192. package/dist/tempo/Attribution.d.ts +1 -1
  193. package/dist/tempo/Methods.d.ts +60 -60
  194. package/dist/tempo/Methods.d.ts.map +1 -1
  195. package/dist/tempo/Proof.d.ts +16 -16
  196. package/dist/tempo/client/Charge.d.ts +19 -19
  197. package/dist/tempo/client/Charge.d.ts.map +1 -1
  198. package/dist/tempo/client/Charge.js +1 -7
  199. package/dist/tempo/client/Charge.js.map +1 -1
  200. package/dist/tempo/client/Methods.d.ts +38 -38
  201. package/dist/tempo/client/Methods.js.map +1 -1
  202. package/dist/tempo/client/Subscription.d.ts +23 -23
  203. package/dist/tempo/client/Subscription.js.map +1 -1
  204. package/dist/tempo/internal/address.d.ts +2 -1
  205. package/dist/tempo/internal/address.d.ts.map +1 -1
  206. package/dist/tempo/internal/address.js +3 -1
  207. package/dist/tempo/internal/address.js.map +1 -1
  208. package/dist/tempo/internal/auto-swap.d.ts.map +1 -1
  209. package/dist/tempo/internal/auto-swap.js +4 -19
  210. package/dist/tempo/internal/auto-swap.js.map +1 -1
  211. package/dist/tempo/internal/defaults.d.ts +6 -6
  212. package/dist/tempo/internal/defaults.d.ts.map +1 -1
  213. package/dist/tempo/internal/fee-payer.d.ts +12 -12
  214. package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
  215. package/dist/tempo/internal/fee-payer.js.map +1 -1
  216. package/dist/tempo/internal/proof.d.ts +17 -17
  217. package/dist/tempo/internal/proof.d.ts.map +1 -1
  218. package/dist/tempo/legacy/client/Session.d.ts +20 -20
  219. package/dist/tempo/legacy/client/Session.js.map +1 -1
  220. package/dist/tempo/legacy/client/SessionManager.js.map +1 -1
  221. package/dist/tempo/legacy/index.d.ts +1 -3
  222. package/dist/tempo/legacy/index.d.ts.map +1 -1
  223. package/dist/tempo/legacy/index.js +1 -3
  224. package/dist/tempo/legacy/index.js.map +1 -1
  225. package/dist/tempo/legacy/session/escrow.abi.d.ts +374 -374
  226. package/dist/tempo/legacy/session/escrow.abi.d.ts.map +1 -1
  227. package/dist/tempo/server/Charge.d.ts +34 -12
  228. package/dist/tempo/server/Charge.d.ts.map +1 -1
  229. package/dist/tempo/server/Charge.js +44 -39
  230. package/dist/tempo/server/Charge.js.map +1 -1
  231. package/dist/tempo/server/Methods.d.ts +37 -52
  232. package/dist/tempo/server/Methods.d.ts.map +1 -1
  233. package/dist/tempo/server/Methods.js +0 -14
  234. package/dist/tempo/server/Methods.js.map +1 -1
  235. package/dist/tempo/server/Relay.d.ts +14 -5
  236. package/dist/tempo/server/Relay.d.ts.map +1 -1
  237. package/dist/tempo/server/Relay.js +6 -4
  238. package/dist/tempo/server/Relay.js.map +1 -1
  239. package/dist/tempo/server/SponsorBudget.d.ts.map +1 -1
  240. package/dist/tempo/server/SponsorBudget.js +7 -1
  241. package/dist/tempo/server/SponsorBudget.js.map +1 -1
  242. package/dist/tempo/server/Subscription.d.ts +25 -25
  243. package/dist/tempo/server/Subscription.d.ts.map +1 -1
  244. package/dist/tempo/server/Subscription.js +2 -0
  245. package/dist/tempo/server/Subscription.js.map +1 -1
  246. package/dist/tempo/server/index.d.ts +1 -1
  247. package/dist/tempo/server/index.d.ts.map +1 -1
  248. package/dist/tempo/server/index.js +1 -1
  249. package/dist/tempo/server/index.js.map +1 -1
  250. package/dist/tempo/server/internal/html.gen.d.ts +1 -1
  251. package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
  252. package/dist/tempo/server/internal/html.gen.js +1 -1
  253. package/dist/tempo/server/internal/html.gen.js.map +1 -1
  254. package/dist/tempo/server/internal/transport.d.ts +2 -0
  255. package/dist/tempo/server/internal/transport.d.ts.map +1 -1
  256. package/dist/tempo/server/internal/transport.js +9 -2
  257. package/dist/tempo/server/internal/transport.js.map +1 -1
  258. package/dist/tempo/session/client/ChannelOps.js.map +1 -1
  259. package/dist/tempo/session/client/CredentialState.d.ts +1 -1
  260. package/dist/tempo/session/client/CredentialState.js.map +1 -1
  261. package/dist/tempo/session/client/ReceiptCoordinator.js.map +1 -1
  262. package/dist/tempo/session/client/Runtime.js.map +1 -1
  263. package/dist/tempo/session/client/Session.d.ts +19 -19
  264. package/dist/tempo/session/client/Session.d.ts.map +1 -1
  265. package/dist/tempo/session/client/Session.js +128 -14
  266. package/dist/tempo/session/client/Session.js.map +1 -1
  267. package/dist/tempo/session/client/SessionManager.d.ts.map +1 -1
  268. package/dist/tempo/session/client/SessionManager.js +62 -20
  269. package/dist/tempo/session/client/SessionManager.js.map +1 -1
  270. package/dist/tempo/session/client/Transports.d.ts +9 -1
  271. package/dist/tempo/session/client/Transports.d.ts.map +1 -1
  272. package/dist/tempo/session/client/Transports.js +36 -13
  273. package/dist/tempo/session/client/Transports.js.map +1 -1
  274. package/dist/tempo/session/precompile/Chain.d.ts +27 -0
  275. package/dist/tempo/session/precompile/Chain.d.ts.map +1 -1
  276. package/dist/tempo/session/precompile/Chain.js +68 -7
  277. package/dist/tempo/session/precompile/Chain.js.map +1 -1
  278. package/dist/tempo/session/precompile/Protocol.js.map +1 -1
  279. package/dist/tempo/session/precompile/Voucher.d.ts +4 -4
  280. package/dist/tempo/session/precompile/Voucher.d.ts.map +1 -1
  281. package/dist/tempo/session/precompile/escrow.abi.d.ts +306 -306
  282. package/dist/tempo/session/precompile/escrow.abi.d.ts.map +1 -1
  283. package/dist/tempo/session/server/ChannelStore.d.ts +9 -0
  284. package/dist/tempo/session/server/ChannelStore.d.ts.map +1 -1
  285. package/dist/tempo/session/server/ChannelStore.js +16 -8
  286. package/dist/tempo/session/server/ChannelStore.js.map +1 -1
  287. package/dist/tempo/session/server/CredentialVerification.d.ts +30 -13
  288. package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -1
  289. package/dist/tempo/session/server/CredentialVerification.js +207 -13
  290. package/dist/tempo/session/server/CredentialVerification.js.map +1 -1
  291. package/dist/tempo/session/server/MeteredStream.d.ts +3 -0
  292. package/dist/tempo/session/server/MeteredStream.d.ts.map +1 -1
  293. package/dist/tempo/session/server/MeteredStream.js +3 -1
  294. package/dist/tempo/session/server/MeteredStream.js.map +1 -1
  295. package/dist/tempo/session/server/Session.d.ts +32 -21
  296. package/dist/tempo/session/server/Session.d.ts.map +1 -1
  297. package/dist/tempo/session/server/Session.js +116 -53
  298. package/dist/tempo/session/server/Session.js.map +1 -1
  299. package/dist/tempo/session/server/Sse.d.ts +3 -1
  300. package/dist/tempo/session/server/Sse.d.ts.map +1 -1
  301. package/dist/tempo/session/server/Sse.js +2 -1
  302. package/dist/tempo/session/server/Sse.js.map +1 -1
  303. package/dist/tempo/session/server/Transports.d.ts +1 -1
  304. package/dist/tempo/session/server/Transports.d.ts.map +1 -1
  305. package/dist/tempo/session/server/Transports.js +1 -0
  306. package/dist/tempo/session/server/Transports.js.map +1 -1
  307. package/dist/tempo/session/server/Ws.d.ts +6 -1
  308. package/dist/tempo/session/server/Ws.d.ts.map +1 -1
  309. package/dist/tempo/session/server/Ws.js +4 -0
  310. package/dist/tempo/session/server/Ws.js.map +1 -1
  311. package/dist/tempo/subscription/KeyAuthorization.d.ts +38 -866
  312. package/dist/tempo/subscription/KeyAuthorization.d.ts.map +1 -1
  313. package/dist/tempo/subscription/KeyAuthorization.js +14 -3
  314. package/dist/tempo/subscription/KeyAuthorization.js.map +1 -1
  315. package/dist/viem/Account.d.ts.map +1 -1
  316. package/dist/viem/Account.js.map +1 -1
  317. package/dist/viem/Client.d.ts.map +1 -1
  318. package/dist/viem/Client.js +6 -1
  319. package/dist/viem/Client.js.map +1 -1
  320. package/dist/web-bot-auth/Constants.d.ts +20 -0
  321. package/dist/web-bot-auth/Constants.d.ts.map +1 -0
  322. package/dist/web-bot-auth/Constants.js +24 -0
  323. package/dist/web-bot-auth/Constants.js.map +1 -0
  324. package/dist/web-bot-auth/Types.d.ts +10 -0
  325. package/dist/web-bot-auth/Types.d.ts.map +1 -0
  326. package/dist/web-bot-auth/Types.js +2 -0
  327. package/dist/web-bot-auth/Types.js.map +1 -0
  328. package/dist/web-bot-auth/client/index.d.ts +29 -0
  329. package/dist/web-bot-auth/client/index.d.ts.map +1 -0
  330. package/dist/web-bot-auth/client/index.js +64 -0
  331. package/dist/web-bot-auth/client/index.js.map +1 -0
  332. package/dist/web-bot-auth/index.d.ts +7 -0
  333. package/dist/web-bot-auth/index.d.ts.map +1 -0
  334. package/dist/web-bot-auth/index.js +7 -0
  335. package/dist/web-bot-auth/index.js.map +1 -0
  336. package/dist/web-bot-auth/internal/JwkThumbprint.d.ts +5 -0
  337. package/dist/web-bot-auth/internal/JwkThumbprint.d.ts.map +1 -0
  338. package/dist/web-bot-auth/internal/JwkThumbprint.js +20 -0
  339. package/dist/web-bot-auth/internal/JwkThumbprint.js.map +1 -0
  340. package/dist/web-bot-auth/internal/SignatureAgent.d.ts +3 -0
  341. package/dist/web-bot-auth/internal/SignatureAgent.d.ts.map +1 -0
  342. package/dist/web-bot-auth/internal/SignatureAgent.js +18 -0
  343. package/dist/web-bot-auth/internal/SignatureAgent.js.map +1 -0
  344. package/dist/web-bot-auth/server/index.d.ts +35 -0
  345. package/dist/web-bot-auth/server/index.d.ts.map +1 -0
  346. package/dist/web-bot-auth/server/index.js +88 -0
  347. package/dist/web-bot-auth/server/index.js.map +1 -0
  348. package/dist/x402/Assets.d.ts.map +1 -1
  349. package/dist/x402/Types.d.ts +6 -6
  350. package/dist/x402/Types.d.ts.map +1 -1
  351. package/dist/x402/server/EvmCharge.d.ts.map +1 -1
  352. package/dist/x402/server/EvmCharge.js +32 -20
  353. package/dist/x402/server/EvmCharge.js.map +1 -1
  354. package/package.json +20 -4
  355. package/src/Challenge.fuzz.test.ts +80 -47
  356. package/src/Challenge.test.ts +65 -0
  357. package/src/Challenge.ts +39 -35
  358. package/src/Method.ts +82 -68
  359. package/src/Store.test-d.ts +16 -0
  360. package/src/Store.test.ts +50 -0
  361. package/src/Store.ts +68 -0
  362. package/src/attestation/Attestation.integration.test.ts +208 -0
  363. package/src/attestation/Client.test.ts +83 -0
  364. package/src/attestation/Client.ts +34 -0
  365. package/src/attestation/Constants.ts +15 -0
  366. package/src/attestation/Server.test.ts +60 -0
  367. package/src/attestation/Server.ts +12 -0
  368. package/src/attestation/Types.test-d.ts +54 -0
  369. package/src/attestation/Types.ts +77 -0
  370. package/src/attestation/index.ts +5 -0
  371. package/src/attestation/internal/HttpMessageSignature.test.ts +101 -0
  372. package/src/attestation/internal/HttpMessageSignature.ts +429 -0
  373. package/src/attestation/internal/SigningContext.ts +13 -0
  374. package/src/bin.js +2 -0
  375. package/src/cli/cli.ts +1 -0
  376. package/src/cli/validate/payment.ts +18 -4
  377. package/src/cli/validate.test.ts +16 -0
  378. package/src/client/Mppx.test-d.ts +17 -0
  379. package/src/client/Mppx.test.ts +14 -14
  380. package/src/client/Mppx.ts +25 -4
  381. package/src/client/Transport.test.ts +12 -45
  382. package/src/client/Transport.ts +3 -24
  383. package/src/client/internal/Fetch.test.ts +77 -0
  384. package/src/client/internal/Fetch.ts +112 -14
  385. package/src/client/internal/MethodChallenge.ts +5 -0
  386. package/src/client/internal/MethodResponse.ts +28 -0
  387. package/src/discovery/OpenApi.test.ts +170 -0
  388. package/src/discovery/OpenApi.ts +16 -48
  389. package/src/discovery/internal/Metadata.ts +51 -0
  390. package/src/evm/server/Charge.ts +6 -1
  391. package/src/internal/AcceptPayment.test.ts +12 -8
  392. package/src/internal/types.ts +9 -0
  393. package/src/mcp/client/McpClient.integration.test.ts +19 -32
  394. package/src/middlewares/elysia.test.ts +2 -12
  395. package/src/middlewares/express.test.ts +2 -12
  396. package/src/middlewares/hono.test.ts +6 -9
  397. package/src/middlewares/nextjs.test.ts +2 -12
  398. package/src/proxy/Proxy.test.ts +26 -19
  399. package/src/proxy/Proxy.ts +147 -9
  400. package/src/proxy/Proxy.upstreamError.test.ts +364 -0
  401. package/src/proxy/Service.test.ts +73 -3
  402. package/src/proxy/Service.ts +50 -23
  403. package/src/proxy/services/anthropic.ts +1 -0
  404. package/src/proxy/services/hooks.test-d.ts +14 -0
  405. package/src/proxy/services/hooks.test.ts +44 -0
  406. package/src/proxy/services/openai.ts +1 -0
  407. package/src/proxy/services/stripe.ts +1 -0
  408. package/src/server/Methods.test-d.ts +88 -0
  409. package/src/server/Methods.test.ts +69 -0
  410. package/src/server/Mppx.test-d.ts +141 -7
  411. package/src/server/Mppx.test.ts +1017 -119
  412. package/src/server/Mppx.ts +350 -54
  413. package/src/stripe/internal/constants.ts +1 -1
  414. package/src/stripe/internal/types.ts +1 -0
  415. package/src/stripe/server/Charge.test-d.ts +16 -1
  416. package/src/stripe/server/Charge.test.ts +79 -0
  417. package/src/stripe/server/Charge.ts +54 -1
  418. package/src/stripe/server/Methods.test-d.ts +157 -0
  419. package/src/stripe/server/Methods.test.ts +403 -0
  420. package/src/stripe/server/Methods.ts +423 -6
  421. package/src/stripe/server/internal/deposit-address.ts +57 -0
  422. package/src/stripe/server/internal/html/node_modules/.bin/mppx +3 -3
  423. package/src/stripe/server/internal/html/package.json +1 -1
  424. package/src/stripe/server/internal/html.gen.ts +1 -1
  425. package/src/stripe/server/internal/record-payment.ts +66 -0
  426. package/src/stripe/server/internal/request.ts +49 -0
  427. package/src/tap/Constants.ts +32 -0
  428. package/src/tap/Tap.test.ts +125 -0
  429. package/src/tap/Types.ts +11 -0
  430. package/src/tap/client/index.ts +54 -0
  431. package/src/tap/index.ts +4 -0
  432. package/src/tap/server/index.ts +48 -0
  433. package/src/tempo/PublicExports.test-d.ts +3 -3
  434. package/src/tempo/client/Charge.ts +1 -19
  435. package/src/tempo/internal/address.test.ts +42 -0
  436. package/src/tempo/internal/address.ts +3 -3
  437. package/src/tempo/internal/auto-swap.test.ts +4 -4
  438. package/src/tempo/internal/auto-swap.ts +7 -50
  439. package/src/tempo/legacy/README.md +5 -5
  440. package/src/tempo/legacy/index.ts +1 -3
  441. package/src/tempo/server/AtomicStore.test-d.ts +13 -0
  442. package/src/tempo/server/Charge.test.ts +19 -84
  443. package/src/tempo/server/Charge.ts +92 -56
  444. package/src/tempo/server/Methods.ts +0 -20
  445. package/src/tempo/server/Relay.test.ts +161 -7
  446. package/src/tempo/server/Relay.ts +15 -6
  447. package/src/tempo/server/SponsorBudget.test.ts +29 -0
  448. package/src/tempo/server/SponsorBudget.ts +7 -1
  449. package/src/tempo/server/Subscription.ts +4 -1
  450. package/src/tempo/server/index.ts +1 -1
  451. package/src/tempo/server/internal/html/node_modules/.bin/mppx +3 -3
  452. package/src/tempo/server/internal/html/package.json +1 -1
  453. package/src/tempo/server/internal/html.gen.ts +1 -1
  454. package/src/tempo/server/internal/transport.test.ts +22 -3
  455. package/src/tempo/server/internal/transport.ts +15 -3
  456. package/src/tempo/session/README.md +119 -0
  457. package/src/tempo/session/client/Session.test.ts +299 -33
  458. package/src/tempo/session/client/Session.ts +152 -16
  459. package/src/tempo/session/client/SessionManager.test.ts +216 -9
  460. package/src/tempo/session/client/SessionManager.ts +63 -17
  461. package/src/tempo/session/client/Transports.test.ts +22 -0
  462. package/src/tempo/session/client/Transports.ts +58 -22
  463. package/src/tempo/session/precompile/Chain.ts +131 -11
  464. package/src/tempo/session/server/ChannelStore.ts +33 -12
  465. package/src/tempo/session/server/CredentialVerification.test.ts +4 -4
  466. package/src/tempo/session/server/CredentialVerification.ts +340 -28
  467. package/src/tempo/session/server/MeteredStream.ts +5 -1
  468. package/src/tempo/session/server/Session.test.ts +483 -36
  469. package/src/tempo/session/server/Session.ts +159 -60
  470. package/src/tempo/session/server/Sse.test.ts +77 -0
  471. package/src/tempo/session/server/Sse.ts +8 -1
  472. package/src/tempo/session/server/Transports.ts +2 -1
  473. package/src/tempo/session/server/Ws.test.ts +171 -0
  474. package/src/tempo/session/server/Ws.ts +10 -1
  475. package/src/tempo/subscription/KeyAuthorization.test.ts +70 -1
  476. package/src/tempo/subscription/KeyAuthorization.ts +14 -3
  477. package/src/viem/Client.test.ts +18 -1
  478. package/src/viem/Client.ts +7 -1
  479. package/src/web-bot-auth/Constants.ts +24 -0
  480. package/src/web-bot-auth/Types.ts +9 -0
  481. package/src/web-bot-auth/WebBotAuth.test.ts +182 -0
  482. package/src/web-bot-auth/client/index.ts +84 -0
  483. package/src/web-bot-auth/index.ts +6 -0
  484. package/src/web-bot-auth/internal/JwkThumbprint.ts +21 -0
  485. package/src/web-bot-auth/internal/SignatureAgent.ts +18 -0
  486. package/src/web-bot-auth/server/index.ts +113 -0
  487. package/src/x402/Exact.e2e.test.ts +121 -81
  488. package/src/x402/Exact.localnet.test.ts +1 -1
  489. package/src/x402/server/EvmCharge.ts +35 -19
  490. package/dist/tempo/legacy/server/Session.d.ts +0 -208
  491. package/dist/tempo/legacy/server/Session.d.ts.map +0 -1
  492. package/dist/tempo/legacy/server/Session.js +0 -698
  493. package/dist/tempo/legacy/server/Session.js.map +0 -1
  494. package/dist/tempo/legacy/server/index.d.ts +0 -5
  495. package/dist/tempo/legacy/server/index.d.ts.map +0 -1
  496. package/dist/tempo/legacy/server/index.js +0 -5
  497. package/dist/tempo/legacy/server/index.js.map +0 -1
  498. package/dist/tempo/legacy/session/ChannelStore.d.ts +0 -22
  499. package/dist/tempo/legacy/session/ChannelStore.d.ts.map +0 -1
  500. package/dist/tempo/legacy/session/ChannelStore.js +0 -6
  501. package/dist/tempo/legacy/session/ChannelStore.js.map +0 -1
  502. package/src/tempo/legacy/server/Defaults.test-d.ts +0 -9
  503. package/src/tempo/legacy/server/Session.test.ts +0 -6370
  504. package/src/tempo/legacy/server/Session.ts +0 -1024
  505. package/src/tempo/legacy/server/index.ts +0 -4
  506. package/src/tempo/legacy/session/ChannelStore.test.ts +0 -58
  507. 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 {
@@ -10,6 +10,7 @@ import { rpcUrl } from '~test/tempo/rpc.js'
10
10
  import { accounts, asset, chain, client, http } from '~test/tempo/viem.js'
11
11
 
12
12
  import * as Fetch from './Fetch.js'
13
+ import * as MethodChallenge from './MethodChallenge.js'
13
14
  import * as MethodResponse from './MethodResponse.js'
14
15
 
15
16
  const realm = 'api.example.com'
@@ -337,6 +338,23 @@ const noopMethod = {
337
338
  createCredential: async () => 'credential',
338
339
  } as any
339
340
 
341
+ function trackedMethod(settlements: MethodResponse.AttemptOutcome['status'][]) {
342
+ const method = {
343
+ ...noopMethod,
344
+ async createCredential(parameters: object) {
345
+ const attempt = MethodResponse.getAttempt(parameters)
346
+ if (attempt)
347
+ attempt.settle = (outcome) => {
348
+ settlements.push(outcome.status)
349
+ return outcome.status !== 'pending'
350
+ }
351
+ return 'credential'
352
+ },
353
+ }
354
+ MethodChallenge.register(method, () => undefined)
355
+ return MethodResponse.register(method, ({ response }) => response)
356
+ }
357
+
340
358
  const x402PaymentRequired = {
341
359
  accepts: [
342
360
  {
@@ -418,6 +436,30 @@ describe('Fetch.from: method responses', () => {
418
436
  expect(handle).toHaveBeenCalledWith(expect.objectContaining({ credential: 'credential' }))
419
437
  expect(paidResponse?.clone).not.toHaveBeenCalled()
420
438
  })
439
+
440
+ test.each([
441
+ ['a rejected paid response', () => new Response('rejected', { status: 500 }), 500, undefined],
442
+ ['the final payment retry', () => make402(), 402, 1],
443
+ [
444
+ 'the paid request throwing',
445
+ () => Promise.reject(new Error('paid request failed')),
446
+ undefined,
447
+ undefined,
448
+ ],
449
+ ])('settles credential state after %s', async (_name, paidRequest, status, maxPaymentRetries) => {
450
+ const settlements: MethodResponse.AttemptOutcome['status'][] = []
451
+ let calls = 0
452
+ const fetch = Fetch.from({
453
+ fetch: async () => (++calls === 1 ? make402() : paidRequest()),
454
+ maxPaymentRetries,
455
+ methods: [trackedMethod(settlements)],
456
+ })
457
+
458
+ const result = fetch('https://example.com/paid')
459
+ if (status) expect((await result).status).toBe(status)
460
+ else await expect(result).rejects.toThrow('paid request failed')
461
+ expect(settlements).toEqual(['rejected'])
462
+ })
421
463
  })
422
464
 
423
465
  describe('Fetch.from: init passthrough (non-402)', () => {
@@ -1873,6 +1915,41 @@ describe('Fetch.from: 402 retry path', () => {
1873
1915
  ).toEqual(['credential-first', 'credential-second', 'credential-third'])
1874
1916
  })
1875
1917
 
1918
+ test('invalidates a prepared credential across a generic challenge', async () => {
1919
+ const firstCredential = vi.fn(async () => 'first')
1920
+ const first = { ...noopMethod, name: 'first', createCredential: firstCredential }
1921
+ const second = { ...noopMethod, name: 'second', createCredential: async () => 'second' }
1922
+ MethodChallenge.register(first, () => undefined)
1923
+ const responses = [
1924
+ make402({ id: 'first', method: 'first' }),
1925
+ make402({ id: 'second', method: 'second' }),
1926
+ make402({ id: 'first', method: 'first' }),
1927
+ new Response('OK'),
1928
+ ]
1929
+ const mockFetch = vi.fn(async () => responses.shift()!)
1930
+ const fetch = Fetch.from({ fetch: mockFetch, methods: [first, second] })
1931
+
1932
+ expect((await fetch('https://example.com/api')).status).toBe(200)
1933
+ expect(firstCredential).toHaveBeenCalledTimes(2)
1934
+ })
1935
+
1936
+ test('invalidates a prepared credential after an explicit context', async () => {
1937
+ const createCredential = vi.fn(async () => 'credential')
1938
+ const method = { ...noopMethod, createCredential }
1939
+ MethodChallenge.register(method, () => undefined)
1940
+ let challenges = 0
1941
+ const mockFetch = vi.fn(async () => (++challenges <= 3 ? make402() : new Response('OK')))
1942
+ const fetch = Fetch.from({
1943
+ fetch: mockFetch as typeof globalThis.fetch,
1944
+ methods: [method],
1945
+ onChallenge: async (_challenge, { createCredential: create }) =>
1946
+ challenges === 2 ? create({ override: true } as never) : undefined,
1947
+ })
1948
+
1949
+ expect((await fetch('https://example.com/api')).status).toBe(200)
1950
+ expect(createCredential).toHaveBeenCalledTimes(3)
1951
+ })
1952
+
1876
1953
  test('caps repeated 402 retries at three', async () => {
1877
1954
  let callCount = 0
1878
1955
  const createCredential = vi.fn(async () => 'credential')
@@ -19,9 +19,33 @@ type WrappedFetch = typeof globalThis.fetch & {
19
19
  [MPPX_FETCH_WRAPPER]?: typeof globalThis.fetch
20
20
  }
21
21
 
22
+ /** Credential state retained between payment retries until its method settles it. */
23
+ type PreparedCredential = {
24
+ /** Method-owned preparation and settlement hooks. */
25
+ attempt: MethodResponse.Attempt
26
+ /** Serialized challenge used to recognize the same retry. */
27
+ key?: string | undefined
28
+ /** Method that prepared the credential. */
29
+ method: Method.AnyClient
30
+ /** Memoized credential reused for the same retry. */
31
+ promise: Promise<string>
32
+ }
33
+
22
34
  let originalFetch: typeof globalThis.fetch | undefined
23
35
  const eventObserverChecks = new WeakMap<object, (name: keyof ClientEventMap) => boolean>()
24
36
 
37
+ async function settleAttempt(
38
+ prepared: PreparedCredential | undefined,
39
+ outcome: MethodResponse.AttemptOutcome,
40
+ ): Promise<boolean> {
41
+ const settle = prepared?.attempt.settle
42
+ if (!settle) return outcome.status !== 'pending'
43
+ prepared.attempt.settle = undefined
44
+ const settled = await settle(outcome)
45
+ if (!settled) prepared.attempt.settle = settle
46
+ return settled
47
+ }
48
+
25
49
  export type ClientEventMap<
26
50
  methods extends readonly Method.AnyClient[] = readonly Method.AnyClient[],
27
51
  response = Response,
@@ -210,12 +234,11 @@ export function from<const methods extends readonly Method.AnyClient[]>(
210
234
  let challenge: Challenge.Challenge | undefined
211
235
  let challenges: readonly Challenge.Challenge[] | undefined
212
236
  let mi: methods[number] | undefined
237
+ let preparedCredential: PreparedCredential | undefined
213
238
 
214
239
  try {
215
240
  for (let retry = 0; retry < maxPaymentRetries; retry++) {
216
- challenges = transport.getChallenges
217
- ? await transport.getChallenges(response, transportRequest as never)
218
- : [await transport.getChallenge(response, transportRequest as never)]
241
+ challenges = await transport.getChallenges(response, transportRequest as never)
219
242
 
220
243
  const candidates = AcceptPayment.selectChallengeCandidates(
221
244
  challenges,
@@ -229,6 +252,11 @@ export function from<const methods extends readonly Method.AnyClient[]>(
229
252
  )
230
253
  const selected = orderedCandidates[0]
231
254
  if (!selected) {
255
+ await settleAttempt(preparedCredential, {
256
+ challenges,
257
+ response,
258
+ status: 'rejected',
259
+ })
232
260
  // A post-payment 402 with no actionable challenge (e.g. rejected credential)
233
261
  // is the server's final answer, not a new challenge round.
234
262
  if (retry > 0) return response
@@ -247,16 +275,54 @@ export function from<const methods extends readonly Method.AnyClient[]>(
247
275
  initialRequest.input,
248
276
  initialRequest.input,
249
277
  )
278
+ const previousCredential = preparedCredential
279
+ const key = Challenge.serialize(selectedChallenge)
280
+ const sameAttempt =
281
+ previousCredential?.method === selected.method && previousCredential?.key === key
282
+ let canReusePrevious = false
283
+ if (previousCredential) {
284
+ const settled = await settleAttempt(previousCredential, {
285
+ challenges,
286
+ response,
287
+ status: sameAttempt ? 'pending' : 'rejected',
288
+ })
289
+ canReusePrevious = sameAttempt && !settled
290
+ }
291
+ preparedCredential = canReusePrevious ? previousCredential : undefined
250
292
  const createCredential = memoizeCreateCredential(
251
293
  async (overrideContext?: AnyContextFor<methods>) => {
294
+ if (overrideContext === undefined && canReusePrevious && previousCredential) {
295
+ return previousCredential.promise
296
+ }
297
+ if (canReusePrevious && previousCredential) {
298
+ await settleAttempt(previousCredential, { status: 'rejected' })
299
+ preparedCredential = undefined
300
+ }
301
+
252
302
  const credentialContext = overrideContext ?? context
253
- await MethodChallenge.handle(selected.method, {
254
- challenge: selectedChallenge,
255
- context: credentialContext,
256
- fetch: baseFetch,
257
- input: paymentInput,
258
- })
259
- return resolveCredential(selectedChallenge, selected.method, credentialContext)
303
+ if (!MethodChallenge.has(selected.method))
304
+ return resolveCredential(selectedChallenge, selected.method, credentialContext)
305
+ const attempt: MethodResponse.Attempt = {
306
+ prepare: () =>
307
+ MethodChallenge.handle(selected.method, {
308
+ challenge: selectedChallenge,
309
+ context: credentialContext,
310
+ fetch: baseFetch,
311
+ input: paymentInput,
312
+ }),
313
+ }
314
+ const promise = attempt
315
+ .prepare()
316
+ .then(() =>
317
+ resolveCredential(selectedChallenge, selected.method, credentialContext, attempt),
318
+ )
319
+ preparedCredential = {
320
+ attempt,
321
+ key: overrideContext === undefined ? key : undefined,
322
+ method: selected.method,
323
+ promise,
324
+ }
325
+ return promise
260
326
  },
261
327
  )
262
328
  const eventCredential = await events.emit(
@@ -279,6 +345,11 @@ export function from<const methods extends readonly Method.AnyClient[]>(
279
345
  })
280
346
  : undefined)
281
347
  const credential = onChallengeCredential ?? (await createCredential())
348
+ const prepared = preparedCredential
349
+ if (prepared && (await prepared.promise.catch(() => undefined)) !== credential) {
350
+ await settleAttempt(prepared, { status: 'rejected' })
351
+ preparedCredential = undefined
352
+ }
282
353
  validateCredentialHeaderValue(credential)
283
354
  await events.emit(
284
355
  'credential.created',
@@ -303,6 +374,17 @@ export function from<const methods extends readonly Method.AnyClient[]>(
303
374
  { challenge: selectedChallenge },
304
375
  ),
305
376
  )
377
+ const paymentRequired = await transport.isPaymentRequired(
378
+ response,
379
+ transportRequest as never,
380
+ )
381
+ if (!paymentRequired) {
382
+ await settleAttempt(prepared, {
383
+ response,
384
+ status: response.ok ? 'accepted' : 'rejected',
385
+ })
386
+ preparedCredential = undefined
387
+ }
306
388
  // Cloning an unobserved stream would tee and buffer it indefinitely.
307
389
  if (response.ok && hasEventObservers(events, 'payment.response'))
308
390
  await events.emit(
@@ -316,7 +398,7 @@ export function from<const methods extends readonly Method.AnyClient[]>(
316
398
  response,
317
399
  }),
318
400
  )
319
- if (!(await transport.isPaymentRequired(response, transportRequest as never))) {
401
+ if (!paymentRequired) {
320
402
  if (!response.ok) return response
321
403
  return MethodResponse.handle(selected.method, {
322
404
  challenge: selectedChallenge,
@@ -334,8 +416,22 @@ export function from<const methods extends readonly Method.AnyClient[]>(
334
416
  })
335
417
  }
336
418
  }
419
+ challenges = undefined
420
+ try {
421
+ challenges = await transport.getChallenges(response, transportRequest as never)
422
+ } catch {}
423
+ await settleAttempt(preparedCredential, {
424
+ challenges,
425
+ response,
426
+ status: 'rejected',
427
+ })
337
428
  return response
338
429
  } catch (error) {
430
+ await settleAttempt(preparedCredential, {
431
+ challenges,
432
+ response,
433
+ status: 'rejected',
434
+ })
339
435
  await events.emit(
340
436
  'payment.failed',
341
437
  createPaymentFailedPayload({
@@ -884,11 +980,13 @@ async function resolveCredential(
884
980
  challenge: Challenge.Challenge,
885
981
  mi: Method.AnyClient,
886
982
  context: unknown,
983
+ attempt?: MethodResponse.Attempt | undefined,
887
984
  ): Promise<string> {
888
985
  const parsedContext = mi.context && context !== undefined ? mi.context.parse(context) : undefined
889
- return mi.createCredential(
890
- parsedContext !== undefined ? { challenge, context: parsedContext } : ({ challenge } as never),
891
- )
986
+ const parameters =
987
+ parsedContext !== undefined ? { challenge, context: parsedContext } : { challenge }
988
+ if (attempt) MethodResponse.attachAttempt(mi, parameters, attempt)
989
+ return mi.createCredential(parameters as never)
892
990
  }
893
991
 
894
992
  function resolvePaymentPreferences<methods extends readonly Method.AnyClient[]>(
@@ -24,6 +24,11 @@ export function register<const method extends Method.AnyClient>(
24
24
  return method
25
25
  }
26
26
 
27
+ /** Returns whether a method registered pre-credential work. */
28
+ export function has(method: Method.AnyClient): boolean {
29
+ return handlers.has(method)
30
+ }
31
+
27
32
  /** Runs method-specific work before creating a challenge credential. */
28
33
  export function handle(method: Method.AnyClient, parameters: HandlerParameters): Promise<void> {
29
34
  return Promise.resolve(handlers.get(method)?.(parameters))
@@ -3,6 +3,20 @@ import type { MaybePromise } from '../../internal/types.js'
3
3
  import type * as Method from '../../Method.js'
4
4
 
5
5
  const handlers = new WeakMap<Method.AnyClient, Handler>()
6
+ const attempts = new WeakMap<object, Attempt>()
7
+
8
+ export type AttemptOutcome = {
9
+ challenges?: readonly Challenge.Challenge[] | undefined
10
+ response?: Response | undefined
11
+ status: 'accepted' | 'pending' | 'rejected'
12
+ }
13
+
14
+ export type Attempt = {
15
+ /** Re-runs method preparation when serialized state changed before signing. */
16
+ prepare: () => Promise<void>
17
+ /** Settles state created for one credential attempt. */
18
+ settle?: ((outcome: AttemptOutcome) => MaybePromise<boolean>) | undefined
19
+ }
6
20
 
7
21
  /** Inputs available when a client method handles a successful paid response. */
8
22
  export type HandlerParameters = {
@@ -33,6 +47,20 @@ export function unregister(method: Method.AnyClient): void {
33
47
  handlers.delete(method)
34
48
  }
35
49
 
50
+ /** Adds response lifecycle state to internal credential parameters. */
51
+ export function attachAttempt(
52
+ method: Method.AnyClient,
53
+ parameters: object,
54
+ attempt: Attempt,
55
+ ): void {
56
+ if (handlers.has(method)) attempts.set(parameters, attempt)
57
+ }
58
+
59
+ /** Reads response lifecycle state when Fetch owns this credential. */
60
+ export function getAttempt(parameters: object): Attempt | undefined {
61
+ return attempts.get(parameters)
62
+ }
63
+
36
64
  /** Lets the selected client method handle a successful paid response. */
37
65
  export function handle(method: Method.AnyClient, parameters: HandlerParameters): Promise<Response> {
38
66
  return Promise.resolve(handlers.get(method)?.(parameters) ?? parameters.response)