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
@@ -0,0 +1,364 @@
1
+ import { describe, expect, test, vi } from 'vp/test'
2
+
3
+ import * as Mppx from '../server/Mppx.js'
4
+ import * as Proxy from './Proxy.js'
5
+ import * as Service from './Service.js'
6
+
7
+ type CreatePaidProxyParameters = {
8
+ fetch: typeof globalThis.fetch
9
+ method?: 'GET' | 'POST' | undefined
10
+ onPayment?: (() => void) | undefined
11
+ onProxyError?: Service.UpstreamErrorHandler | undefined
12
+ onServiceError?: Service.UpstreamErrorHandler | undefined
13
+ rewriteRequest?: Service.Service['rewriteRequest']
14
+ rewriteResponse?: Service.Service['rewriteResponse']
15
+ }
16
+
17
+ function createPaidProxy(parameters: CreatePaidProxyParameters): Proxy.Proxy {
18
+ const method = parameters.method ?? 'GET'
19
+ const service = Service.from('api', {
20
+ baseUrl: 'https://upstream.example',
21
+ onUpstreamError: parameters.onServiceError,
22
+ rewriteRequest: parameters.rewriteRequest,
23
+ routes: {
24
+ [`${method} /resource`]: createPaidHandler(parameters.onPayment),
25
+ },
26
+ })
27
+ service.rewriteResponse = parameters.rewriteResponse
28
+ return Proxy.create({
29
+ fetch: parameters.fetch,
30
+ onUpstreamError: parameters.onProxyError,
31
+ services: [service],
32
+ })
33
+ }
34
+
35
+ function createPaidHandler(onPayment?: () => void): Service.IntentHandler {
36
+ return async () => {
37
+ onPayment?.()
38
+ return {
39
+ status: 200,
40
+ withReceipt<response>(response: response): response {
41
+ if (!(response instanceof Response)) throw new Mppx.MissingReceiptResponseError()
42
+ const headers = new Headers(response.headers)
43
+ headers.set('Payment-Receipt', 'test-receipt')
44
+ return new Response(response.body, {
45
+ headers,
46
+ status: response.status,
47
+ statusText: response.statusText,
48
+ }) as response
49
+ },
50
+ }
51
+ }
52
+ }
53
+
54
+ function paidRequest(init?: RequestInit): Request {
55
+ const headers = new Headers(init?.headers)
56
+ headers.set('Authorization', 'Payment test-credential')
57
+ return new Request('https://proxy.example/api/resource', {
58
+ ...init,
59
+ headers,
60
+ })
61
+ }
62
+
63
+ describe('onUpstreamError', () => {
64
+ test('retries upstream without verifying payment again', async () => {
65
+ const onPayment = vi.fn()
66
+ const onUpstreamError = vi.fn((context: Service.UpstreamErrorContext) => ({
67
+ retry: context.attempt < 3,
68
+ })) as Service.UpstreamErrorHandler
69
+ let attempts = 0
70
+ const fetch = vi.fn(async () => {
71
+ attempts++
72
+ if (attempts < 3) return new Response('unavailable', { status: 503 })
73
+ return Response.json({ ok: true })
74
+ }) as typeof globalThis.fetch
75
+ const proxy = createPaidProxy({ fetch, onPayment, onServiceError: onUpstreamError })
76
+
77
+ const response = await proxy.fetch(paidRequest())
78
+
79
+ expect(response.status).toBe(200)
80
+ expect(response.headers.get('Payment-Receipt')).toBe('test-receipt')
81
+ expect(await response.json()).toEqual({ ok: true })
82
+ expect(fetch).toHaveBeenCalledTimes(3)
83
+ expect(onPayment).toHaveBeenCalledTimes(1)
84
+ expect(onUpstreamError).toHaveBeenCalledTimes(2)
85
+ expect(onUpstreamError).toHaveBeenCalledWith(
86
+ expect.objectContaining({
87
+ attempt: 1,
88
+ error: undefined,
89
+ response: expect.objectContaining({ status: 503 }),
90
+ service: expect.objectContaining({ id: 'api' }),
91
+ upstreamPath: '/resource',
92
+ upstreamRequest: expect.objectContaining({ url: 'https://upstream.example/resource' }),
93
+ }),
94
+ )
95
+ })
96
+
97
+ test('uses the proxy handler when the service has no override', async () => {
98
+ const upstreamError = new Error('connection reset')
99
+ const onProxyError = vi.fn((context: Service.UpstreamErrorContext) => ({
100
+ retry: context.attempt < 2,
101
+ })) as Service.UpstreamErrorHandler
102
+ let attempts = 0
103
+ const fetch = vi.fn(async () => {
104
+ attempts++
105
+ if (attempts === 1) throw upstreamError
106
+ return new Response('recovered')
107
+ }) as typeof globalThis.fetch
108
+ const proxy = createPaidProxy({ fetch, onProxyError })
109
+
110
+ const response = await proxy.fetch(paidRequest())
111
+
112
+ expect(response.status).toBe(200)
113
+ expect(await response.text()).toBe('recovered')
114
+ expect(response.headers.get('Payment-Receipt')).toBe('test-receipt')
115
+ expect(onProxyError).toHaveBeenCalledWith(
116
+ expect.objectContaining({
117
+ attempt: 1,
118
+ error: upstreamError,
119
+ response: undefined,
120
+ }),
121
+ )
122
+ })
123
+
124
+ test('prefers the service handler over the proxy default', async () => {
125
+ const onProxyError = vi.fn(() => ({ retry: true as const }))
126
+ const onServiceError = vi.fn(() => ({ retry: false as const }))
127
+ const fetch = vi.fn(
128
+ async () => new Response('rate limited', { status: 429 }),
129
+ ) as typeof globalThis.fetch
130
+ const proxy = createPaidProxy({ fetch, onProxyError, onServiceError })
131
+
132
+ const response = await proxy.fetch(paidRequest())
133
+
134
+ expect(response.status).toBe(429)
135
+ expect(response.headers.get('Payment-Receipt')).toBe('test-receipt')
136
+ expect(fetch).toHaveBeenCalledTimes(1)
137
+ expect(onServiceError).toHaveBeenCalledTimes(1)
138
+ expect(onProxyError).not.toHaveBeenCalled()
139
+ })
140
+
141
+ test('returns a handler fallback and attaches a receipt when it succeeds', async () => {
142
+ const onServiceError = vi.fn(() => ({
143
+ response: Response.json({ cached: true }),
144
+ retry: false as const,
145
+ }))
146
+ const fetch = vi.fn(
147
+ async () => new Response('unavailable', { status: 503 }),
148
+ ) as typeof globalThis.fetch
149
+ const proxy = createPaidProxy({ fetch, onServiceError })
150
+
151
+ const response = await proxy.fetch(paidRequest())
152
+
153
+ expect(response.status).toBe(200)
154
+ expect(response.headers.get('Payment-Receipt')).toBe('test-receipt')
155
+ expect(await response.json()).toEqual({ cached: true })
156
+ })
157
+
158
+ test('attaches a receipt when an upstream error is returned', async () => {
159
+ const fetch = vi.fn(
160
+ async () => new Response('upstream failed', { status: 500 }),
161
+ ) as typeof globalThis.fetch
162
+ const proxy = createPaidProxy({ fetch })
163
+
164
+ const response = await proxy.fetch(paidRequest())
165
+
166
+ expect(response.status).toBe(500)
167
+ expect(response.headers.get('Payment-Receipt')).toBe('test-receipt')
168
+ expect(await response.text()).toBe('upstream failed')
169
+ })
170
+
171
+ test('preserves streaming when error recovery is disabled', async () => {
172
+ const clone = vi.spyOn(Request.prototype, 'clone')
173
+ const fetch = vi.fn(async (input: URL | RequestInfo, init?: RequestInit) => {
174
+ expect(await new Request(input, init).text()).toBe('streamed body')
175
+ return new Response('ok')
176
+ }) as typeof globalThis.fetch
177
+ const proxy = Proxy.create({
178
+ fetch,
179
+ services: [
180
+ Service.from('api', {
181
+ baseUrl: 'https://upstream.example',
182
+ routes: { 'POST /resource': true },
183
+ }),
184
+ ],
185
+ })
186
+
187
+ try {
188
+ const response = await proxy.fetch(
189
+ new Request('https://proxy.example/api/resource', {
190
+ body: 'streamed body',
191
+ method: 'POST',
192
+ }),
193
+ )
194
+
195
+ expect(response.status).toBe(200)
196
+ expect(clone).not.toHaveBeenCalled()
197
+ } finally {
198
+ clone.mockRestore()
199
+ }
200
+ })
201
+
202
+ test('preserves a failed response body read by the handler', async () => {
203
+ const onServiceError = vi.fn(async ({ response }: Service.UpstreamErrorContext) => {
204
+ expect(await response?.text()).toBe('upstream failed')
205
+ return { retry: false as const }
206
+ })
207
+ const fetch = vi.fn(
208
+ async () => new Response('upstream failed', { status: 503 }),
209
+ ) as typeof globalThis.fetch
210
+ const proxy = createPaidProxy({ fetch, onServiceError })
211
+
212
+ const response = await proxy.fetch(paidRequest())
213
+
214
+ expect(response.status).toBe(503)
215
+ expect(await response.text()).toBe('upstream failed')
216
+ })
217
+
218
+ test('preserves a recovery response derived from the failed body', async () => {
219
+ const onServiceError = vi.fn(({ response }: Service.UpstreamErrorContext) => ({
220
+ response: new Response(response?.body, { status: 200 }),
221
+ retry: false as const,
222
+ }))
223
+ const fetch = vi.fn(
224
+ async () => new Response('recovered body', { status: 503 }),
225
+ ) as typeof globalThis.fetch
226
+ const proxy = createPaidProxy({ fetch, onServiceError })
227
+
228
+ const response = await proxy.fetch(paidRequest())
229
+
230
+ expect(response.status).toBe(200)
231
+ expect(response.headers.get('Payment-Receipt')).toBe('test-receipt')
232
+ expect(await response.text()).toBe('recovered body')
233
+ })
234
+
235
+ test('does not block a retry when the handler partially reads the failed body', async () => {
236
+ const onServiceError = vi.fn(async ({ response }: Service.UpstreamErrorContext) => {
237
+ await response?.body?.getReader().read()
238
+ return { retry: true as const }
239
+ })
240
+ let attempts = 0
241
+ const fetch = vi.fn(async () => {
242
+ attempts++
243
+ if (attempts > 1) return new Response('recovered')
244
+ return new Response(
245
+ new ReadableStream({
246
+ start(controller) {
247
+ controller.enqueue(new TextEncoder().encode('partial failure'))
248
+ },
249
+ }),
250
+ { status: 503 },
251
+ )
252
+ }) as typeof globalThis.fetch
253
+ const proxy = createPaidProxy({ fetch, onServiceError })
254
+
255
+ const response = await proxy.fetch(paidRequest())
256
+
257
+ expect(response.status).toBe(200)
258
+ expect(await response.text()).toBe('recovered')
259
+ expect(fetch).toHaveBeenCalledTimes(2)
260
+ })
261
+
262
+ test('does not retry response rewrite failures', async () => {
263
+ const rewriteError = new Error('invalid upstream response')
264
+ const onServiceError = vi.fn(() => ({ retry: true as const }))
265
+ const rewriteResponse = vi.fn(() => {
266
+ throw rewriteError
267
+ })
268
+ const fetch = vi.fn(async () => new Response('created')) as typeof globalThis.fetch
269
+ const proxy = createPaidProxy({
270
+ fetch,
271
+ method: 'POST',
272
+ onServiceError,
273
+ rewriteResponse,
274
+ })
275
+
276
+ await expect(
277
+ proxy.fetch(paidRequest({ body: 'create resource', method: 'POST' })),
278
+ ).rejects.toBe(rewriteError)
279
+ expect(fetch).toHaveBeenCalledTimes(1)
280
+ expect(onServiceError).not.toHaveBeenCalled()
281
+ })
282
+
283
+ test('preserves a POST body across delayed retries', async () => {
284
+ const bodies: string[] = []
285
+ const rewriteRequest = vi.fn((request: Request) => request)
286
+ const onServiceError = vi.fn(() => ({ delay: 1, retry: true as const }))
287
+ const fetch = vi.fn(async (input: URL | RequestInfo, init?: RequestInit) => {
288
+ const request = new Request(input, init)
289
+ bodies.push(await request.text())
290
+ if (bodies.length === 1) return new Response('rate limited', { status: 429 })
291
+ return Response.json({ ok: true })
292
+ }) as typeof globalThis.fetch
293
+ const proxy = createPaidProxy({
294
+ fetch,
295
+ method: 'POST',
296
+ onServiceError,
297
+ rewriteRequest,
298
+ })
299
+
300
+ const response = await proxy.fetch(
301
+ paidRequest({
302
+ body: JSON.stringify({ prompt: 'hello' }),
303
+ headers: { 'Content-Type': 'application/json' },
304
+ method: 'POST',
305
+ }),
306
+ )
307
+
308
+ expect(response.status).toBe(200)
309
+ expect(bodies).toEqual(['{"prompt":"hello"}', '{"prompt":"hello"}'])
310
+ expect(rewriteRequest).toHaveBeenCalledTimes(2)
311
+ expect(onServiceError).toHaveBeenCalledTimes(1)
312
+ })
313
+
314
+ test('stops a delayed retry when the client aborts', async () => {
315
+ const controller = new AbortController()
316
+ let handlerCalled: (() => void) | undefined
317
+ const called = new Promise<void>((resolve) => {
318
+ handlerCalled = resolve
319
+ })
320
+ const onServiceError: Service.UpstreamErrorHandler = () => {
321
+ handlerCalled?.()
322
+ return { delay: 60_000, retry: true }
323
+ }
324
+ const fetch = vi.fn(
325
+ async () => new Response('unavailable', { status: 503 }),
326
+ ) as typeof globalThis.fetch
327
+ const proxy = createPaidProxy({ fetch, onServiceError })
328
+ const response = proxy.fetch(paidRequest({ signal: controller.signal }))
329
+ const assertion = expect(response).rejects.toThrow('stop retrying')
330
+
331
+ await called
332
+ controller.abort(new Error('stop retrying'))
333
+
334
+ await assertion
335
+ expect(fetch).toHaveBeenCalledTimes(1)
336
+ })
337
+
338
+ test('also recovers free upstream routes without adding a receipt', async () => {
339
+ const onUpstreamError = vi.fn(() => ({ retry: true as const }))
340
+ let attempts = 0
341
+ const fetch = vi.fn(async () => {
342
+ attempts++
343
+ if (attempts === 1) return new Response('unavailable', { status: 503 })
344
+ return new Response('public resource')
345
+ }) as typeof globalThis.fetch
346
+ const proxy = Proxy.create({
347
+ fetch,
348
+ services: [
349
+ Service.from('api', {
350
+ baseUrl: 'https://upstream.example',
351
+ onUpstreamError,
352
+ routes: { 'GET /resource': true },
353
+ }),
354
+ ],
355
+ })
356
+
357
+ const response = await proxy.fetch(new Request('https://proxy.example/api/resource'))
358
+
359
+ expect(response.status).toBe(200)
360
+ expect(await response.text()).toBe('public resource')
361
+ expect(response.headers.get('Payment-Receipt')).toBeNull()
362
+ expect(fetch).toHaveBeenCalledTimes(2)
363
+ })
364
+ })
@@ -12,6 +12,17 @@ describe('from', () => {
12
12
  expect(service.baseUrl).toBe('https://api.example.com')
13
13
  })
14
14
 
15
+ test('behavior: preserves upstream error hook', () => {
16
+ const onUpstreamError: Service.UpstreamErrorHandler = () => ({ retry: false })
17
+ const service = Service.from('api', {
18
+ baseUrl: 'https://api.example.com',
19
+ onUpstreamError,
20
+ routes: { 'GET /v1/status': true },
21
+ })
22
+
23
+ expect(service.onUpstreamError).toBe(onUpstreamError)
24
+ })
25
+
15
26
  test('behavior: bearer sets Authorization header', async () => {
16
27
  const service = Service.from('api', {
17
28
  baseUrl: 'https://api.example.com',
@@ -123,7 +134,7 @@ describe('paymentOf', () => {
123
134
  expect(Service.paymentOf({ pay: handler, options: {} })).toBeNull()
124
135
  })
125
136
 
126
- test('behavior: strips function internals from payment metadata', () => {
137
+ test('behavior: derives payment metadata from the canonical request', () => {
127
138
  const handler = Object.assign(
128
139
  async () => ({
129
140
  status: 200 as const,
@@ -131,11 +142,18 @@ describe('paymentOf', () => {
131
142
  }),
132
143
  {
133
144
  _internal: {
134
- _canonicalRequest: () => ({}),
145
+ _canonicalRequest: {
146
+ amount: '1000000',
147
+ currency: '0xUSDC',
148
+ recipient: '0x1',
149
+ },
135
150
  _stableBinding: () => ({}),
136
151
  amount: '1',
152
+ asset: 'raw-asset',
137
153
  authorize: () => undefined,
154
+ client: { apiKey: 'secret' },
138
155
  decimals: 6,
156
+ description: 'Generate text',
139
157
  defaults: {},
140
158
  intent: 'charge',
141
159
  name: 'mock',
@@ -151,9 +169,61 @@ describe('paymentOf', () => {
151
169
 
152
170
  expect(Service.paymentOf(handler as never)).toEqual({
153
171
  amount: '1000000',
154
- decimals: 6,
172
+ currency: '0xUSDC',
173
+ description: 'Generate text',
155
174
  intent: 'charge',
156
175
  method: 'mock',
176
+ recipient: '0x1',
177
+ })
178
+ })
179
+
180
+ test('behavior: derives every explicitly composed payment offer', () => {
181
+ const handler = Object.assign(
182
+ async () => ({
183
+ status: 200 as const,
184
+ withReceipt: <T>(r: T) => r,
185
+ }),
186
+ {
187
+ _internal: {
188
+ offers: [
189
+ {
190
+ _canonicalRequest: { amount: '1000000', currency: '0xUSDC' },
191
+ amount: '1',
192
+ decimals: 6,
193
+ description: 'USDC',
194
+ intent: 'charge',
195
+ name: 'tempo',
196
+ },
197
+ {
198
+ _canonicalRequest: { amount: '2000000', currency: '0xNANOUSD' },
199
+ amount: '2',
200
+ decimals: 6,
201
+ description: 'NANOUSD',
202
+ intent: 'charge',
203
+ name: 'tempo',
204
+ },
205
+ ],
206
+ },
207
+ },
208
+ )
209
+
210
+ expect(Service.paymentOf(handler as never)).toEqual({
211
+ offers: [
212
+ {
213
+ amount: '1000000',
214
+ currency: '0xUSDC',
215
+ description: 'USDC',
216
+ intent: 'charge',
217
+ method: 'tempo',
218
+ },
219
+ {
220
+ amount: '2000000',
221
+ currency: '0xNANOUSD',
222
+ description: 'NANOUSD',
223
+ intent: 'charge',
224
+ method: 'tempo',
225
+ },
226
+ ],
157
227
  })
158
228
  })
159
229
  })
@@ -1,4 +1,4 @@
1
- import { Value } from 'ox'
1
+ import * as Metadata from '../discovery/internal/Metadata.js'
2
2
 
3
3
  /** A proxied upstream service with route definitions and optional request/response hooks. */
4
4
  export type Service = {
@@ -12,6 +12,8 @@ export type Service = {
12
12
  docs?: Docs | undefined
13
13
  /** Unique identifier used as the URL prefix (e.g. `'openai'` → `/{id}/...`). */
14
14
  id: string
15
+ /** Handles failed upstream attempts before the proxy returns a response. Retries do not re-verify payment. */
16
+ onUpstreamError?: UpstreamErrorHandler | undefined
15
17
  /** Hook to modify the upstream request before sending (e.g. inject auth headers). */
16
18
  rewriteRequest?: ((req: Request, ctx: Context) => Request | Promise<Request>) | undefined
17
19
  /** Hook to modify the upstream response before returning to the client. */
@@ -61,13 +63,50 @@ export type Context = {
61
63
  upstreamPath: string
62
64
  } & EndpointOptions
63
65
 
66
+ /** Context passed to an upstream error handler after a failed proxy attempt. */
67
+ export type UpstreamErrorContext = Context & {
68
+ /** One-based upstream attempt number. */
69
+ attempt: number
70
+ /** Error thrown while preparing or sending the request. Undefined for HTTP error responses. */
71
+ error: unknown | undefined
72
+ /** Non-2xx upstream response. Undefined when the attempt threw. */
73
+ response: Response | undefined
74
+ /** Rewritten request sent to the upstream service. */
75
+ upstreamRequest: Request
76
+ }
77
+
78
+ /** Action returned by an upstream error handler. */
79
+ export type UpstreamErrorAction =
80
+ | {
81
+ /** Wait this many milliseconds before retrying. */
82
+ delay?: number | undefined
83
+ retry: true
84
+ }
85
+ | {
86
+ /** Optional response to return instead of the original failure. */
87
+ response?: Response | undefined
88
+ retry: false
89
+ }
90
+
91
+ /**
92
+ * Handles a non-2xx upstream response or thrown request error.
93
+ *
94
+ * This hook runs before the response is returned. It cannot observe failures
95
+ * from a streaming body after response headers have been sent.
96
+ */
97
+ export type UpstreamErrorHandler<options = unknown> = (
98
+ context: UpstreamErrorContext & Partial<Omit<options & {}, 'onUpstreamError' | 'routes'>>,
99
+ ) => UpstreamErrorAction | Promise<UpstreamErrorAction>
100
+
64
101
  export type From<
65
102
  options extends {
66
103
  routes: string
67
104
  },
68
105
  > = {
69
106
  routes: EndpointMap<options['routes']>
70
- } & Omit<options, 'routes'>
107
+ } & Omit<options, 'onUpstreamError' | 'routes'> & {
108
+ onUpstreamError?: UpstreamErrorHandler<options> | undefined
109
+ }
71
110
 
72
111
  /**
73
112
  * Creates a service definition.
@@ -92,6 +131,7 @@ export function from<options = unknown>(id: string, config: from.Config<options>
92
131
  description: config.description,
93
132
  docs: resolveDocs(config),
94
133
  id,
134
+ onUpstreamError: config.onUpstreamError as Service['onUpstreamError'],
95
135
  routes: config.routes,
96
136
  title: config.title,
97
137
  rewriteRequest: config.rewriteRequest
@@ -126,6 +166,8 @@ export declare namespace from {
126
166
  | undefined
127
167
  /** Shorthand: full request mutation function. Takes priority over `bearer`/`headers`. */
128
168
  mutate?: ((req: Request) => Request | Promise<Request>) | undefined
169
+ /** Handles failed upstream attempts before the proxy returns a response. Retries do not re-verify payment. */
170
+ onUpstreamError?: UpstreamErrorHandler<options> | undefined
129
171
  /** Hook to modify the upstream request. Receives typed per-endpoint options via `ctx`. */
130
172
  rewriteRequest?:
131
173
  | ((req: Request, ctx: Context & Partial<options & {}>) => Request | Promise<Request>)
@@ -206,31 +248,16 @@ export function getOptions(endpoint: Endpoint): EndpointOptions | undefined {
206
248
  return undefined
207
249
  }
208
250
 
251
+ /** Derives discovery payment metadata from an explicitly priced endpoint handler. */
209
252
  export function paymentOf(endpoint: Endpoint): Record<string, unknown> | null {
210
253
  if (endpoint === true) return null
211
254
  const handler = typeof endpoint === 'function' ? endpoint : endpoint.pay
212
255
  if (!('_internal' in handler)) return null
213
- const {
214
- name,
215
- intent,
216
- defaults: _,
217
- schema: _s,
218
- _canonicalRequest,
219
- _stableBinding: _sb,
220
- authorize: _a,
221
- request: _r,
222
- respond: _re,
223
- stableBinding: _st,
224
- transport: _t,
225
- verify: _v,
226
- ...rest
227
- } = handler._internal as Record<string, unknown>
228
- const amount = (() => {
229
- if (typeof rest.amount === 'string' && typeof rest.decimals === 'number')
230
- return String(Value.from(rest.amount, rest.decimals))
231
- return rest.amount
232
- })()
233
- return { intent, method: name, ...rest, ...(amount !== undefined && { amount }) }
256
+ const metadata = handler._internal as Metadata.Metadata | undefined
257
+ if (!metadata) return null
258
+ if (Metadata.isComposed(metadata))
259
+ return { offers: Metadata.offers(metadata).map(Metadata.paymentOffer) }
260
+ return Metadata.paymentOffer(metadata)
234
261
  }
235
262
 
236
263
  function resolveDocs(config: from.Config): Docs | undefined {
@@ -26,6 +26,7 @@ export function anthropic(config: anthropic.Config) {
26
26
  apiReference: 'https://docs.anthropic.com/en/api/getting-started',
27
27
  homepage: 'https://docs.anthropic.com/en/docs/intro-to-claude',
28
28
  },
29
+ onUpstreamError: config.onUpstreamError,
29
30
  rewriteRequest(request, ctx) {
30
31
  const apiKey = ctx.apiKey ?? config.apiKey
31
32
  request.headers.set('x-api-key', apiKey)
@@ -0,0 +1,14 @@
1
+ import { expectTypeOf, test } from 'vp/test'
2
+
3
+ import { openai } from './openai.js'
4
+
5
+ test('upstream error hooks preserve service-specific context', () => {
6
+ openai({
7
+ apiKey: 'test',
8
+ onUpstreamError(context) {
9
+ expectTypeOf(context.apiKey).toEqualTypeOf<string | undefined>()
10
+ return { retry: false }
11
+ },
12
+ routes: { 'POST /v1/chat/completions': true },
13
+ })
14
+ })
@@ -0,0 +1,44 @@
1
+ import { describe, expect, test } from 'vp/test'
2
+
3
+ import type * as Service from '../Service.js'
4
+ import { anthropic } from './anthropic.js'
5
+ import { openai } from './openai.js'
6
+ import { stripe } from './stripe.js'
7
+
8
+ describe('service hooks', () => {
9
+ const onUpstreamError: Service.UpstreamErrorHandler = () => ({ retry: false })
10
+
11
+ test.each([
12
+ [
13
+ 'openai',
14
+ () =>
15
+ openai({
16
+ apiKey: 'test',
17
+ onUpstreamError,
18
+ routes: { 'POST /v1/chat/completions': true },
19
+ }),
20
+ ],
21
+ [
22
+ 'anthropic',
23
+ () =>
24
+ anthropic({
25
+ apiKey: 'test',
26
+ onUpstreamError,
27
+ routes: { 'POST /v1/messages': true },
28
+ }),
29
+ ],
30
+ [
31
+ 'stripe',
32
+ () =>
33
+ stripe({
34
+ apiKey: 'test',
35
+ onUpstreamError,
36
+ routes: { 'POST /v1/charges': true },
37
+ }),
38
+ ],
39
+ ] as const)('preserves hooks for %s', (_name, createService) => {
40
+ const service = createService()
41
+
42
+ expect(service.onUpstreamError).toBe(onUpstreamError)
43
+ })
44
+ })
@@ -27,6 +27,7 @@ export function openai(config: openai.Config) {
27
27
  homepage: 'https://platform.openai.com/docs',
28
28
  llms: 'https://context7.com/websites/platform_openai/llms.txt',
29
29
  },
30
+ onUpstreamError: config.onUpstreamError,
30
31
  rewriteRequest(request, ctx) {
31
32
  const apiKey = ctx.apiKey ?? config.apiKey
32
33
  request.headers.delete('OpenAI-Organization')
@@ -27,6 +27,7 @@ export function stripe(config: stripe.Config) {
27
27
  homepage: 'https://docs.stripe.com',
28
28
  llms: 'https://docs.stripe.com/llms.txt',
29
29
  },
30
+ onUpstreamError: config.onUpstreamError,
30
31
  rewriteRequest(request, ctx) {
31
32
  const apiKey = ctx.apiKey ?? config.apiKey
32
33
  request.headers.delete('Stripe-Account')