mppx 0.8.15 → 0.8.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (464) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/Challenge.d.ts.map +1 -1
  3. package/dist/Challenge.js +40 -35
  4. package/dist/Challenge.js.map +1 -1
  5. package/dist/Constants.d.ts +17 -17
  6. package/dist/Constants.d.ts.map +1 -1
  7. package/dist/Credential.d.ts.map +1 -1
  8. package/dist/Errors.d.ts +3 -3
  9. package/dist/Errors.d.ts.map +1 -1
  10. package/dist/Errors.js.map +1 -1
  11. package/dist/Method.d.ts +35 -5
  12. package/dist/Method.d.ts.map +1 -1
  13. package/dist/Method.js +7 -22
  14. package/dist/Method.js.map +1 -1
  15. package/dist/Store.d.ts +19 -0
  16. package/dist/Store.d.ts.map +1 -1
  17. package/dist/Store.js +43 -0
  18. package/dist/Store.js.map +1 -1
  19. package/dist/attestation/Client.d.ts +17 -0
  20. package/dist/attestation/Client.d.ts.map +1 -0
  21. package/dist/attestation/Client.js +28 -0
  22. package/dist/attestation/Client.js.map +1 -0
  23. package/dist/attestation/Constants.d.ts +15 -0
  24. package/dist/attestation/Constants.d.ts.map +1 -0
  25. package/dist/attestation/Constants.js +15 -0
  26. package/dist/attestation/Constants.js.map +1 -0
  27. package/dist/attestation/Server.d.ts +4 -0
  28. package/dist/attestation/Server.d.ts.map +1 -0
  29. package/dist/attestation/Server.js +8 -0
  30. package/dist/attestation/Server.js.map +1 -0
  31. package/dist/attestation/Types.d.ts +76 -0
  32. package/dist/attestation/Types.d.ts.map +1 -0
  33. package/dist/attestation/Types.js +2 -0
  34. package/dist/attestation/Types.js.map +1 -0
  35. package/dist/attestation/index.d.ts +6 -0
  36. package/dist/attestation/index.d.ts.map +1 -0
  37. package/dist/attestation/index.js +6 -0
  38. package/dist/attestation/index.js.map +1 -0
  39. package/dist/attestation/internal/HttpMessageSignature.d.ts +73 -0
  40. package/dist/attestation/internal/HttpMessageSignature.d.ts.map +1 -0
  41. package/dist/attestation/internal/HttpMessageSignature.js +320 -0
  42. package/dist/attestation/internal/HttpMessageSignature.js.map +1 -0
  43. package/dist/attestation/internal/SigningContext.d.ts +4 -0
  44. package/dist/attestation/internal/SigningContext.d.ts.map +1 -0
  45. package/dist/attestation/internal/SigningContext.js +11 -0
  46. package/dist/attestation/internal/SigningContext.js.map +1 -0
  47. package/dist/cli/account.d.ts +14 -14
  48. package/dist/cli/account.d.ts.map +1 -1
  49. package/dist/cli/cli.d.ts +6 -6
  50. package/dist/cli/cli.d.ts.map +1 -1
  51. package/dist/cli/cli.js +1 -0
  52. package/dist/cli/cli.js.map +1 -1
  53. package/dist/cli/plugins/tempo.js.map +1 -1
  54. package/dist/cli/sessions/commands.d.ts +4 -4
  55. package/dist/cli/sessions/commands.d.ts.map +1 -1
  56. package/dist/cli/sessions/commands.js.map +1 -1
  57. package/dist/cli/sessions/store.d.ts.map +1 -1
  58. package/dist/cli/sessions/store.js.map +1 -1
  59. package/dist/cli/utils.d.ts +1 -1
  60. package/dist/cli/utils.d.ts.map +1 -1
  61. package/dist/cli/utils.js.map +1 -1
  62. package/dist/cli/validate/discovery.js.map +1 -1
  63. package/dist/cli/validate/index.d.ts +3 -3
  64. package/dist/cli/validate/index.d.ts.map +1 -1
  65. package/dist/client/Mppx.d.ts +3 -0
  66. package/dist/client/Mppx.d.ts.map +1 -1
  67. package/dist/client/Mppx.js +13 -5
  68. package/dist/client/Mppx.js.map +1 -1
  69. package/dist/client/Transport.d.ts +3 -5
  70. package/dist/client/Transport.d.ts.map +1 -1
  71. package/dist/client/Transport.js +1 -17
  72. package/dist/client/Transport.js.map +1 -1
  73. package/dist/client/internal/Fetch.d.ts.map +1 -1
  74. package/dist/client/internal/Fetch.js +2 -6
  75. package/dist/client/internal/Fetch.js.map +1 -1
  76. package/dist/client/node.js.map +1 -1
  77. package/dist/discovery/OpenApi.d.ts +3 -5
  78. package/dist/discovery/OpenApi.d.ts.map +1 -1
  79. package/dist/discovery/OpenApi.js +13 -34
  80. package/dist/discovery/OpenApi.js.map +1 -1
  81. package/dist/discovery/internal/Metadata.d.ts +20 -0
  82. package/dist/discovery/internal/Metadata.d.ts.map +1 -0
  83. package/dist/discovery/internal/Metadata.js +36 -0
  84. package/dist/discovery/internal/Metadata.js.map +1 -0
  85. package/dist/evm/Methods.d.ts +11 -11
  86. package/dist/evm/Methods.d.ts.map +1 -1
  87. package/dist/evm/Types.d.ts +17 -17
  88. package/dist/evm/Types.d.ts.map +1 -1
  89. package/dist/evm/client/Charge.d.ts +11 -11
  90. package/dist/evm/client/Methods.d.ts +11 -11
  91. package/dist/evm/server/Charge.d.ts +1 -1
  92. package/dist/evm/server/Charge.d.ts.map +1 -1
  93. package/dist/evm/server/Charge.js +2 -0
  94. package/dist/evm/server/Charge.js.map +1 -1
  95. package/dist/evm/server/Methods.d.ts +11 -11
  96. package/dist/internal/HeaderCodec.d.ts +2 -2
  97. package/dist/internal/HeaderCodec.d.ts.map +1 -1
  98. package/dist/internal/types.d.ts +6 -0
  99. package/dist/internal/types.d.ts.map +1 -1
  100. package/dist/middlewares/elysia.js.map +1 -1
  101. package/dist/middlewares/express.js.map +1 -1
  102. package/dist/middlewares/hono.js.map +1 -1
  103. package/dist/middlewares/nextjs.js.map +1 -1
  104. package/dist/proxy/Proxy.d.ts +2 -0
  105. package/dist/proxy/Proxy.d.ts.map +1 -1
  106. package/dist/proxy/Proxy.js +117 -9
  107. package/dist/proxy/Proxy.js.map +1 -1
  108. package/dist/proxy/Service.d.ts +36 -1
  109. package/dist/proxy/Service.d.ts.map +1 -1
  110. package/dist/proxy/Service.js +9 -8
  111. package/dist/proxy/Service.js.map +1 -1
  112. package/dist/proxy/services/anthropic.d.ts.map +1 -1
  113. package/dist/proxy/services/anthropic.js +1 -0
  114. package/dist/proxy/services/anthropic.js.map +1 -1
  115. package/dist/proxy/services/openai.d.ts.map +1 -1
  116. package/dist/proxy/services/openai.js +1 -0
  117. package/dist/proxy/services/openai.js.map +1 -1
  118. package/dist/proxy/services/stripe.d.ts.map +1 -1
  119. package/dist/proxy/services/stripe.js +1 -0
  120. package/dist/proxy/services/stripe.js.map +1 -1
  121. package/dist/server/Mppx.d.ts +75 -13
  122. package/dist/server/Mppx.d.ts.map +1 -1
  123. package/dist/server/Mppx.js +201 -23
  124. package/dist/server/Mppx.js.map +1 -1
  125. package/dist/server/internal/html/config.d.ts +9 -9
  126. package/dist/server/internal/html/config.d.ts.map +1 -1
  127. package/dist/server/internal/html/constants.d.ts +17 -17
  128. package/dist/server/internal/html/constants.d.ts.map +1 -1
  129. package/dist/stripe/Methods.d.ts +10 -10
  130. package/dist/stripe/Methods.d.ts.map +1 -1
  131. package/dist/stripe/client/Charge.d.ts +10 -10
  132. package/dist/stripe/client/Methods.d.ts +10 -10
  133. package/dist/stripe/internal/constants.d.ts +1 -1
  134. package/dist/stripe/internal/constants.js +1 -1
  135. package/dist/stripe/internal/types.d.ts +1 -0
  136. package/dist/stripe/internal/types.d.ts.map +1 -1
  137. package/dist/stripe/server/Charge.d.ts +11 -11
  138. package/dist/stripe/server/Charge.d.ts.map +1 -1
  139. package/dist/stripe/server/Charge.js +49 -1
  140. package/dist/stripe/server/Charge.js.map +1 -1
  141. package/dist/stripe/server/Methods.d.ts +137 -48
  142. package/dist/stripe/server/Methods.d.ts.map +1 -1
  143. package/dist/stripe/server/Methods.js +259 -4
  144. package/dist/stripe/server/Methods.js.map +1 -1
  145. package/dist/stripe/server/internal/deposit-address.d.ts +13 -0
  146. package/dist/stripe/server/internal/deposit-address.d.ts.map +1 -0
  147. package/dist/stripe/server/internal/deposit-address.js +28 -0
  148. package/dist/stripe/server/internal/deposit-address.js.map +1 -0
  149. package/dist/stripe/server/internal/html.gen.d.ts +1 -1
  150. package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
  151. package/dist/stripe/server/internal/html.gen.js +1 -1
  152. package/dist/stripe/server/internal/html.gen.js.map +1 -1
  153. package/dist/stripe/server/internal/record-payment.d.ts +15 -0
  154. package/dist/stripe/server/internal/record-payment.d.ts.map +1 -0
  155. package/dist/stripe/server/internal/record-payment.js +42 -0
  156. package/dist/stripe/server/internal/record-payment.js.map +1 -0
  157. package/dist/stripe/server/internal/request.d.ts +25 -0
  158. package/dist/stripe/server/internal/request.d.ts.map +1 -0
  159. package/dist/stripe/server/internal/request.js +29 -0
  160. package/dist/stripe/server/internal/request.js.map +1 -0
  161. package/dist/tap/Constants.d.ts +28 -0
  162. package/dist/tap/Constants.d.ts.map +1 -0
  163. package/dist/tap/Constants.js +32 -0
  164. package/dist/tap/Constants.js.map +1 -0
  165. package/dist/tap/Types.d.ts +11 -0
  166. package/dist/tap/Types.d.ts.map +1 -0
  167. package/dist/tap/Types.js +2 -0
  168. package/dist/tap/Types.js.map +1 -0
  169. package/dist/tap/client/index.d.ts +26 -0
  170. package/dist/tap/client/index.d.ts.map +1 -0
  171. package/dist/tap/client/index.js +33 -0
  172. package/dist/tap/client/index.js.map +1 -0
  173. package/dist/tap/index.d.ts +5 -0
  174. package/dist/tap/index.d.ts.map +1 -0
  175. package/dist/tap/index.js +5 -0
  176. package/dist/tap/index.js.map +1 -0
  177. package/dist/tap/server/index.d.ts +20 -0
  178. package/dist/tap/server/index.d.ts.map +1 -0
  179. package/dist/tap/server/index.js +36 -0
  180. package/dist/tap/server/index.js.map +1 -0
  181. package/dist/tempo/Attribution.d.ts +1 -1
  182. package/dist/tempo/Methods.d.ts +60 -60
  183. package/dist/tempo/Methods.d.ts.map +1 -1
  184. package/dist/tempo/Proof.d.ts +16 -16
  185. package/dist/tempo/client/Charge.d.ts +19 -19
  186. package/dist/tempo/client/Charge.d.ts.map +1 -1
  187. package/dist/tempo/client/Charge.js +1 -7
  188. package/dist/tempo/client/Charge.js.map +1 -1
  189. package/dist/tempo/client/Methods.d.ts +38 -38
  190. package/dist/tempo/client/Methods.js.map +1 -1
  191. package/dist/tempo/client/Subscription.d.ts +23 -23
  192. package/dist/tempo/client/Subscription.js.map +1 -1
  193. package/dist/tempo/internal/address.d.ts +2 -1
  194. package/dist/tempo/internal/address.d.ts.map +1 -1
  195. package/dist/tempo/internal/address.js +3 -1
  196. package/dist/tempo/internal/address.js.map +1 -1
  197. package/dist/tempo/internal/auto-swap.d.ts.map +1 -1
  198. package/dist/tempo/internal/auto-swap.js +4 -19
  199. package/dist/tempo/internal/auto-swap.js.map +1 -1
  200. package/dist/tempo/internal/defaults.d.ts +6 -6
  201. package/dist/tempo/internal/defaults.d.ts.map +1 -1
  202. package/dist/tempo/internal/fee-payer.d.ts +12 -12
  203. package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
  204. package/dist/tempo/internal/fee-payer.js.map +1 -1
  205. package/dist/tempo/internal/proof.d.ts +17 -17
  206. package/dist/tempo/internal/proof.d.ts.map +1 -1
  207. package/dist/tempo/legacy/client/Session.d.ts +20 -20
  208. package/dist/tempo/legacy/client/Session.js.map +1 -1
  209. package/dist/tempo/legacy/client/SessionManager.js.map +1 -1
  210. package/dist/tempo/legacy/index.d.ts +1 -3
  211. package/dist/tempo/legacy/index.d.ts.map +1 -1
  212. package/dist/tempo/legacy/index.js +1 -3
  213. package/dist/tempo/legacy/index.js.map +1 -1
  214. package/dist/tempo/legacy/session/escrow.abi.d.ts +374 -374
  215. package/dist/tempo/legacy/session/escrow.abi.d.ts.map +1 -1
  216. package/dist/tempo/server/Charge.d.ts +25 -11
  217. package/dist/tempo/server/Charge.d.ts.map +1 -1
  218. package/dist/tempo/server/Charge.js +44 -39
  219. package/dist/tempo/server/Charge.js.map +1 -1
  220. package/dist/tempo/server/Methods.d.ts +37 -52
  221. package/dist/tempo/server/Methods.d.ts.map +1 -1
  222. package/dist/tempo/server/Methods.js +0 -14
  223. package/dist/tempo/server/Methods.js.map +1 -1
  224. package/dist/tempo/server/Relay.d.ts +1 -1
  225. package/dist/tempo/server/Relay.d.ts.map +1 -1
  226. package/dist/tempo/server/Relay.js +2 -2
  227. package/dist/tempo/server/Relay.js.map +1 -1
  228. package/dist/tempo/server/Subscription.d.ts +25 -25
  229. package/dist/tempo/server/Subscription.d.ts.map +1 -1
  230. package/dist/tempo/server/Subscription.js +2 -0
  231. package/dist/tempo/server/Subscription.js.map +1 -1
  232. package/dist/tempo/server/index.d.ts +1 -1
  233. package/dist/tempo/server/index.d.ts.map +1 -1
  234. package/dist/tempo/server/index.js +1 -1
  235. package/dist/tempo/server/index.js.map +1 -1
  236. package/dist/tempo/server/internal/html.gen.d.ts +1 -1
  237. package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
  238. package/dist/tempo/server/internal/html.gen.js +1 -1
  239. package/dist/tempo/server/internal/html.gen.js.map +1 -1
  240. package/dist/tempo/server/internal/transport.d.ts +2 -0
  241. package/dist/tempo/server/internal/transport.d.ts.map +1 -1
  242. package/dist/tempo/server/internal/transport.js +9 -2
  243. package/dist/tempo/server/internal/transport.js.map +1 -1
  244. package/dist/tempo/session/client/ChannelOps.js.map +1 -1
  245. package/dist/tempo/session/client/CredentialState.d.ts +1 -1
  246. package/dist/tempo/session/client/CredentialState.js.map +1 -1
  247. package/dist/tempo/session/client/ReceiptCoordinator.js.map +1 -1
  248. package/dist/tempo/session/client/Runtime.js.map +1 -1
  249. package/dist/tempo/session/client/Session.d.ts +19 -19
  250. package/dist/tempo/session/client/Session.js.map +1 -1
  251. package/dist/tempo/session/client/SessionManager.js.map +1 -1
  252. package/dist/tempo/session/client/Transports.d.ts.map +1 -1
  253. package/dist/tempo/session/precompile/Chain.d.ts +27 -0
  254. package/dist/tempo/session/precompile/Chain.d.ts.map +1 -1
  255. package/dist/tempo/session/precompile/Chain.js +68 -7
  256. package/dist/tempo/session/precompile/Chain.js.map +1 -1
  257. package/dist/tempo/session/precompile/Protocol.js.map +1 -1
  258. package/dist/tempo/session/precompile/Voucher.d.ts +4 -4
  259. package/dist/tempo/session/precompile/Voucher.d.ts.map +1 -1
  260. package/dist/tempo/session/precompile/escrow.abi.d.ts +306 -306
  261. package/dist/tempo/session/precompile/escrow.abi.d.ts.map +1 -1
  262. package/dist/tempo/session/server/ChannelStore.d.ts +9 -0
  263. package/dist/tempo/session/server/ChannelStore.d.ts.map +1 -1
  264. package/dist/tempo/session/server/ChannelStore.js +16 -8
  265. package/dist/tempo/session/server/ChannelStore.js.map +1 -1
  266. package/dist/tempo/session/server/CredentialVerification.d.ts +30 -13
  267. package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -1
  268. package/dist/tempo/session/server/CredentialVerification.js +207 -13
  269. package/dist/tempo/session/server/CredentialVerification.js.map +1 -1
  270. package/dist/tempo/session/server/MeteredStream.d.ts +3 -0
  271. package/dist/tempo/session/server/MeteredStream.d.ts.map +1 -1
  272. package/dist/tempo/session/server/MeteredStream.js +3 -1
  273. package/dist/tempo/session/server/MeteredStream.js.map +1 -1
  274. package/dist/tempo/session/server/Session.d.ts +32 -21
  275. package/dist/tempo/session/server/Session.d.ts.map +1 -1
  276. package/dist/tempo/session/server/Session.js +116 -53
  277. package/dist/tempo/session/server/Session.js.map +1 -1
  278. package/dist/tempo/session/server/Sse.d.ts +3 -1
  279. package/dist/tempo/session/server/Sse.d.ts.map +1 -1
  280. package/dist/tempo/session/server/Sse.js +2 -1
  281. package/dist/tempo/session/server/Sse.js.map +1 -1
  282. package/dist/tempo/session/server/Transports.d.ts +1 -1
  283. package/dist/tempo/session/server/Transports.d.ts.map +1 -1
  284. package/dist/tempo/session/server/Transports.js +1 -0
  285. package/dist/tempo/session/server/Transports.js.map +1 -1
  286. package/dist/tempo/session/server/Ws.d.ts +6 -1
  287. package/dist/tempo/session/server/Ws.d.ts.map +1 -1
  288. package/dist/tempo/session/server/Ws.js +1 -0
  289. package/dist/tempo/session/server/Ws.js.map +1 -1
  290. package/dist/tempo/subscription/KeyAuthorization.d.ts +39 -39
  291. package/dist/tempo/subscription/KeyAuthorization.d.ts.map +1 -1
  292. package/dist/viem/Account.d.ts.map +1 -1
  293. package/dist/viem/Account.js.map +1 -1
  294. package/dist/web-bot-auth/Constants.d.ts +20 -0
  295. package/dist/web-bot-auth/Constants.d.ts.map +1 -0
  296. package/dist/web-bot-auth/Constants.js +24 -0
  297. package/dist/web-bot-auth/Constants.js.map +1 -0
  298. package/dist/web-bot-auth/Types.d.ts +10 -0
  299. package/dist/web-bot-auth/Types.d.ts.map +1 -0
  300. package/dist/web-bot-auth/Types.js +2 -0
  301. package/dist/web-bot-auth/Types.js.map +1 -0
  302. package/dist/web-bot-auth/client/index.d.ts +29 -0
  303. package/dist/web-bot-auth/client/index.d.ts.map +1 -0
  304. package/dist/web-bot-auth/client/index.js +64 -0
  305. package/dist/web-bot-auth/client/index.js.map +1 -0
  306. package/dist/web-bot-auth/index.d.ts +7 -0
  307. package/dist/web-bot-auth/index.d.ts.map +1 -0
  308. package/dist/web-bot-auth/index.js +7 -0
  309. package/dist/web-bot-auth/index.js.map +1 -0
  310. package/dist/web-bot-auth/internal/JwkThumbprint.d.ts +5 -0
  311. package/dist/web-bot-auth/internal/JwkThumbprint.d.ts.map +1 -0
  312. package/dist/web-bot-auth/internal/JwkThumbprint.js +20 -0
  313. package/dist/web-bot-auth/internal/JwkThumbprint.js.map +1 -0
  314. package/dist/web-bot-auth/internal/SignatureAgent.d.ts +3 -0
  315. package/dist/web-bot-auth/internal/SignatureAgent.d.ts.map +1 -0
  316. package/dist/web-bot-auth/internal/SignatureAgent.js +18 -0
  317. package/dist/web-bot-auth/internal/SignatureAgent.js.map +1 -0
  318. package/dist/web-bot-auth/server/index.d.ts +35 -0
  319. package/dist/web-bot-auth/server/index.d.ts.map +1 -0
  320. package/dist/web-bot-auth/server/index.js +88 -0
  321. package/dist/web-bot-auth/server/index.js.map +1 -0
  322. package/dist/x402/Assets.d.ts.map +1 -1
  323. package/dist/x402/Types.d.ts +6 -6
  324. package/dist/x402/Types.d.ts.map +1 -1
  325. package/dist/x402/server/EvmCharge.d.ts.map +1 -1
  326. package/dist/x402/server/EvmCharge.js +32 -20
  327. package/dist/x402/server/EvmCharge.js.map +1 -1
  328. package/package.json +19 -3
  329. package/src/Challenge.fuzz.test.ts +80 -47
  330. package/src/Challenge.test.ts +65 -0
  331. package/src/Challenge.ts +39 -35
  332. package/src/Method.ts +82 -68
  333. package/src/Store.test-d.ts +16 -0
  334. package/src/Store.test.ts +50 -0
  335. package/src/Store.ts +68 -0
  336. package/src/attestation/Attestation.integration.test.ts +208 -0
  337. package/src/attestation/Client.test.ts +83 -0
  338. package/src/attestation/Client.ts +34 -0
  339. package/src/attestation/Constants.ts +15 -0
  340. package/src/attestation/Server.test.ts +60 -0
  341. package/src/attestation/Server.ts +12 -0
  342. package/src/attestation/Types.test-d.ts +54 -0
  343. package/src/attestation/Types.ts +77 -0
  344. package/src/attestation/index.ts +5 -0
  345. package/src/attestation/internal/HttpMessageSignature.test.ts +101 -0
  346. package/src/attestation/internal/HttpMessageSignature.ts +429 -0
  347. package/src/attestation/internal/SigningContext.ts +13 -0
  348. package/src/bin.js +2 -0
  349. package/src/cli/cli.ts +1 -0
  350. package/src/client/Mppx.test-d.ts +17 -0
  351. package/src/client/Mppx.test.ts +14 -14
  352. package/src/client/Mppx.ts +25 -4
  353. package/src/client/Transport.test.ts +12 -45
  354. package/src/client/Transport.ts +3 -24
  355. package/src/client/internal/Fetch.ts +2 -6
  356. package/src/discovery/OpenApi.test.ts +170 -0
  357. package/src/discovery/OpenApi.ts +16 -48
  358. package/src/discovery/internal/Metadata.ts +51 -0
  359. package/src/evm/server/Charge.ts +6 -1
  360. package/src/internal/AcceptPayment.test.ts +12 -8
  361. package/src/internal/types.ts +9 -0
  362. package/src/mcp/client/McpClient.integration.test.ts +19 -32
  363. package/src/middlewares/elysia.test.ts +2 -12
  364. package/src/middlewares/express.test.ts +2 -12
  365. package/src/middlewares/hono.test.ts +6 -9
  366. package/src/middlewares/nextjs.test.ts +2 -12
  367. package/src/proxy/Proxy.test.ts +26 -19
  368. package/src/proxy/Proxy.ts +147 -9
  369. package/src/proxy/Proxy.upstreamError.test.ts +364 -0
  370. package/src/proxy/Service.test.ts +73 -3
  371. package/src/proxy/Service.ts +50 -23
  372. package/src/proxy/services/anthropic.ts +1 -0
  373. package/src/proxy/services/hooks.test-d.ts +14 -0
  374. package/src/proxy/services/hooks.test.ts +44 -0
  375. package/src/proxy/services/openai.ts +1 -0
  376. package/src/proxy/services/stripe.ts +1 -0
  377. package/src/server/Methods.test-d.ts +88 -0
  378. package/src/server/Methods.test.ts +69 -0
  379. package/src/server/Mppx.test-d.ts +141 -7
  380. package/src/server/Mppx.test.ts +1017 -119
  381. package/src/server/Mppx.ts +350 -54
  382. package/src/stripe/internal/constants.ts +1 -1
  383. package/src/stripe/internal/types.ts +1 -0
  384. package/src/stripe/server/Charge.test-d.ts +16 -1
  385. package/src/stripe/server/Charge.test.ts +79 -0
  386. package/src/stripe/server/Charge.ts +54 -1
  387. package/src/stripe/server/Methods.test-d.ts +157 -0
  388. package/src/stripe/server/Methods.test.ts +403 -0
  389. package/src/stripe/server/Methods.ts +423 -6
  390. package/src/stripe/server/internal/deposit-address.ts +57 -0
  391. package/src/stripe/server/internal/html/node_modules/.bin/mppx +3 -3
  392. package/src/stripe/server/internal/html/package.json +1 -1
  393. package/src/stripe/server/internal/html.gen.ts +1 -1
  394. package/src/stripe/server/internal/record-payment.ts +66 -0
  395. package/src/stripe/server/internal/request.ts +49 -0
  396. package/src/tap/Constants.ts +32 -0
  397. package/src/tap/Tap.test.ts +125 -0
  398. package/src/tap/Types.ts +11 -0
  399. package/src/tap/client/index.ts +54 -0
  400. package/src/tap/index.ts +4 -0
  401. package/src/tap/server/index.ts +48 -0
  402. package/src/tempo/PublicExports.test-d.ts +3 -3
  403. package/src/tempo/client/Charge.ts +1 -19
  404. package/src/tempo/internal/address.test.ts +42 -0
  405. package/src/tempo/internal/address.ts +3 -3
  406. package/src/tempo/internal/auto-swap.test.ts +4 -4
  407. package/src/tempo/internal/auto-swap.ts +7 -50
  408. package/src/tempo/legacy/README.md +5 -5
  409. package/src/tempo/legacy/index.ts +1 -3
  410. package/src/tempo/server/AtomicStore.test-d.ts +13 -0
  411. package/src/tempo/server/Charge.test.ts +19 -84
  412. package/src/tempo/server/Charge.ts +83 -55
  413. package/src/tempo/server/Methods.ts +0 -20
  414. package/src/tempo/server/Relay.test.ts +5 -5
  415. package/src/tempo/server/Relay.ts +2 -2
  416. package/src/tempo/server/Subscription.ts +4 -1
  417. package/src/tempo/server/index.ts +1 -1
  418. package/src/tempo/server/internal/html/node_modules/.bin/mppx +3 -3
  419. package/src/tempo/server/internal/html/package.json +1 -1
  420. package/src/tempo/server/internal/html.gen.ts +1 -1
  421. package/src/tempo/server/internal/transport.test.ts +22 -3
  422. package/src/tempo/server/internal/transport.ts +15 -3
  423. package/src/tempo/session/README.md +112 -0
  424. package/src/tempo/session/precompile/Chain.ts +131 -11
  425. package/src/tempo/session/server/ChannelStore.ts +33 -12
  426. package/src/tempo/session/server/CredentialVerification.test.ts +4 -4
  427. package/src/tempo/session/server/CredentialVerification.ts +340 -28
  428. package/src/tempo/session/server/MeteredStream.ts +5 -1
  429. package/src/tempo/session/server/Session.test.ts +428 -43
  430. package/src/tempo/session/server/Session.ts +159 -60
  431. package/src/tempo/session/server/Sse.test.ts +77 -0
  432. package/src/tempo/session/server/Sse.ts +8 -1
  433. package/src/tempo/session/server/Transports.ts +2 -1
  434. package/src/tempo/session/server/Ws.test.ts +171 -0
  435. package/src/tempo/session/server/Ws.ts +7 -1
  436. package/src/web-bot-auth/Constants.ts +24 -0
  437. package/src/web-bot-auth/Types.ts +9 -0
  438. package/src/web-bot-auth/WebBotAuth.test.ts +182 -0
  439. package/src/web-bot-auth/client/index.ts +84 -0
  440. package/src/web-bot-auth/index.ts +6 -0
  441. package/src/web-bot-auth/internal/JwkThumbprint.ts +21 -0
  442. package/src/web-bot-auth/internal/SignatureAgent.ts +18 -0
  443. package/src/web-bot-auth/server/index.ts +113 -0
  444. package/src/x402/Exact.e2e.test.ts +121 -81
  445. package/src/x402/Exact.localnet.test.ts +1 -1
  446. package/src/x402/server/EvmCharge.ts +35 -19
  447. package/dist/tempo/legacy/server/Session.d.ts +0 -208
  448. package/dist/tempo/legacy/server/Session.d.ts.map +0 -1
  449. package/dist/tempo/legacy/server/Session.js +0 -698
  450. package/dist/tempo/legacy/server/Session.js.map +0 -1
  451. package/dist/tempo/legacy/server/index.d.ts +0 -5
  452. package/dist/tempo/legacy/server/index.d.ts.map +0 -1
  453. package/dist/tempo/legacy/server/index.js +0 -5
  454. package/dist/tempo/legacy/server/index.js.map +0 -1
  455. package/dist/tempo/legacy/session/ChannelStore.d.ts +0 -22
  456. package/dist/tempo/legacy/session/ChannelStore.d.ts.map +0 -1
  457. package/dist/tempo/legacy/session/ChannelStore.js +0 -6
  458. package/dist/tempo/legacy/session/ChannelStore.js.map +0 -1
  459. package/src/tempo/legacy/server/Defaults.test-d.ts +0 -9
  460. package/src/tempo/legacy/server/Session.test.ts +0 -6370
  461. package/src/tempo/legacy/server/Session.ts +0 -1024
  462. package/src/tempo/legacy/server/index.ts +0 -4
  463. package/src/tempo/legacy/session/ChannelStore.test.ts +0 -58
  464. package/src/tempo/legacy/session/ChannelStore.ts +0 -39
@@ -738,8 +738,15 @@ describe('sse transport', () => {
738
738
 
739
739
  test('respondReceipt with non-SSE upstream Response still deducts from channel', async () => {
740
740
  const store = memoryStore()
741
+ const settled: Array<{ spent: bigint; units: number }> = []
741
742
  await seedChannel(store, 10000000n)
742
- const transport = sse({ store })
743
+ const transport = sse({
744
+ store,
745
+ async settleCharged(channel) {
746
+ settled.push({ spent: channel.spent, units: channel.units })
747
+ return undefined
748
+ },
749
+ })
743
750
  const request = new Request('https://test.example.com/session', {
744
751
  body: JSON.stringify({ prompt: 'hello' }),
745
752
  headers: makeAuthorizedRequest().headers,
@@ -768,6 +775,7 @@ describe('sse transport', () => {
768
775
  expect(channel!.units).toBe(1)
769
776
  expect(receipt.spent).toBe('1000000')
770
777
  expect(receipt.units).toBe(1)
778
+ expect(settled).toEqual([{ spent: 1000000n, units: 1 }])
771
779
 
772
780
  expect(JSON.parse(body)).toEqual({ content: 'hello' })
773
781
  expect(response.headers.get('Content-Type')).toBe('application/json')
@@ -806,8 +814,18 @@ describe('sse transport', () => {
806
814
 
807
815
  test('respondReceipt with 204 content response still deducts from channel', async () => {
808
816
  const store = memoryStore()
817
+ let resolveSettlement!: (channel: ChannelStore.State) => void
818
+ const settlement = new Promise<ChannelStore.State>((resolve) => {
819
+ resolveSettlement = resolve
820
+ })
809
821
  await seedChannel(store, 10000000n)
810
- const transport = sse({ store })
822
+ const transport = sse({
823
+ store,
824
+ async settleCharged(channel) {
825
+ resolveSettlement(channel)
826
+ return undefined
827
+ },
828
+ })
811
829
  const request = new Request('https://test.example.com/session', {
812
830
  body: JSON.stringify({ prompt: 'hello' }),
813
831
  headers: makeAuthorizedRequest().headers,
@@ -827,11 +845,12 @@ describe('sse transport', () => {
827
845
  expect(await response.text()).toBe('')
828
846
  const receipt = deserializeSessionReceipt(response.headers.get('Payment-Receipt')!)
829
847
 
830
- await Promise.resolve()
848
+ const settled = await settlement
831
849
 
832
850
  const channel = await store.getChannel(channelId)
833
851
  expect(channel!.spent).toBe(1000000n)
834
852
  expect(channel!.units).toBe(1)
853
+ expect(settled).toMatchObject({ spent: 1000000n, units: 1 })
835
854
  expect(receipt.spent).toBe('1000000')
836
855
  expect(receipt.units).toBe(1)
837
856
  })
@@ -12,6 +12,7 @@ import * as Transport from '../../../server/Transport.js'
12
12
  import type { SessionReceipt } from '../../session/precompile/Protocol.js'
13
13
  import { requireSessionCredentialContext } from '../../session/precompile/Protocol.js'
14
14
  import * as ChannelStore from '../../session/server/ChannelStore.js'
15
+ import type { SettleChargedSessionChannel } from '../../session/server/Settlement.js'
15
16
  import * as Sse_core from '../../session/server/Sse.js'
16
17
  import { captureRequestBodyProbe, shouldChargePlainResponse } from './request-body.js'
17
18
 
@@ -48,7 +49,12 @@ function hasPrepaidSessionTick(receipt: SessionReceipt): boolean {
48
49
  * - Auto-detection of upstream SSE responses
49
50
  * - Fallback to standard HTTP receipt handling for plain Response
50
51
  */
51
- export function sse(options: sse.Options & { store: ChannelStore.ChannelStore }): Sse {
52
+ export function sse(
53
+ options: sse.Options & {
54
+ settleCharged?: SettleChargedSessionChannel | undefined
55
+ store: ChannelStore.ChannelStore
56
+ },
57
+ ): Sse {
52
58
  const { pollingInterval, poll } = options
53
59
 
54
60
  // When `poll` is true, strip `waitForUpdate` so the SSE charge loop
@@ -117,6 +123,7 @@ export function sse(options: sse.Options & { store: ChannelStore.ChannelStore })
117
123
  tickCost,
118
124
  pollIntervalMs: pollingInterval,
119
125
  generate,
126
+ onChargeCommitted: options.settleCharged,
120
127
  prepaidUnits: hasPrepaidSessionTick(receipt as SessionReceipt) ? 1 : 0,
121
128
  signal: input.signal,
122
129
  })
@@ -174,20 +181,25 @@ export function sse(options: sse.Options & { store: ChannelStore.ChannelStore })
174
181
  response: response as Response,
175
182
  challengeId: verifiedChallengeId,
176
183
  })
184
+ const chargePlainResponse = async () => {
185
+ const result = await ChannelStore.deductFromChannel(store, channelId, tickCost)
186
+ if (result.ok) await options.settleCharged?.(result.channel)
187
+ return result
188
+ }
177
189
 
178
190
  // Non-SSE response (e.g. upstream returned JSON instead of event-stream).
179
191
  // Need to deduct tickCost so request isn't free.
180
192
  // For null-body statuses, the request shape determines whether the
181
193
  // response is management (no charge) or plain content (charge one tick).
182
194
  if (isNullBodyStatus(chargedResponse.status)) {
183
- void ChannelStore.deductFromChannel(store, channelId, tickCost)
195
+ void chargePlainResponse()
184
196
  return chargedResponse
185
197
  }
186
198
 
187
199
  const stream = new ReadableStream<Uint8Array>({
188
200
  async start(controller) {
189
201
  // deduction completes before consumer reads
190
- const result = await ChannelStore.deductFromChannel(store, channelId, tickCost)
202
+ const result = await chargePlainResponse()
191
203
  if (!result.ok) {
192
204
  controller.error(
193
205
  new Errors.InsufficientBalanceError({
@@ -186,6 +186,118 @@ sequenceDiagram
186
186
  The initial SSE POST is excluded from default HTTP charging to prevent double
187
187
  counting. Stream accounting remains owned by the transport driver.
188
188
 
189
+ ## Server transport configuration
190
+
191
+ A session method owns the account, channel store, verification policy, and
192
+ settlement schedule. Routes add prices and application content. HTTP and SSE
193
+ run through configured route handlers; WebSocket uses a session-bound helper
194
+ because its application messages no longer pass through HTTP.
195
+
196
+ | Server shape | Session option | Content API | Charging |
197
+ | ---------------------- | -------------- | ----------------------------------- | ----------------------------------- |
198
+ | HTTP only | Omit `sse` | `result.withReceipt(Response)` | Once per billable request |
199
+ | SSE only | `sse: true` | `result.withReceipt(AsyncIterable)` | Each `stream.charge()` |
200
+ | WebSocket only | Omit `sse` | `mppx.session.serveWebSocket(...)` | Each `stream.charge()` |
201
+ | HTTP + SSE + WebSocket | `sse: true` | All three APIs | Selected by route and response type |
202
+
203
+ All transports for one session service must share the same configured session
204
+ method and store. `serveWebSocket` is bound to both the store and settlement
205
+ policy, so callers pass neither dependency again. `tempo.Ws.serve` remains the
206
+ low-level adapter for custom integrations.
207
+
208
+ ### Shared method configuration
209
+
210
+ ```ts
211
+ const session = tempo.session({
212
+ account,
213
+ currency,
214
+ getClient: () => client,
215
+ settlementSchedule: { units: 100 },
216
+ store,
217
+ // Include when this instance serves any SSE route.
218
+ sse: true,
219
+ })
220
+
221
+ const mppx = Mppx.create({ methods: [session], secretKey })
222
+ ```
223
+
224
+ `sse: true` enables async-iterable responses without changing ordinary
225
+ `Response` handling, so a mixed server uses one session method.
226
+
227
+ ### HTTP
228
+
229
+ ```ts
230
+ const httpRoute = mppx.session({ amount: '0.01', unitType: 'request' })
231
+ const result = await httpRoute(request)
232
+
233
+ if (result.status === 402) return result.challenge
234
+ return result.withReceipt(Response.json({ ok: true }))
235
+ ```
236
+
237
+ HTTP accounting charges the configured route amount before application content
238
+ runs. A plain `Response` selects normal HTTP handling even when `sse: true`.
239
+
240
+ ### SSE
241
+
242
+ ```ts
243
+ const sseRoute = mppx.session({ amount: '0.001', unitType: 'token' })
244
+ const result = await sseRoute(request)
245
+
246
+ if (result.status === 402) return result.challenge
247
+ return result.withReceipt(async function* (stream) {
248
+ for await (const token of generateTokens()) {
249
+ await stream.charge()
250
+ yield token
251
+ }
252
+ })
253
+ ```
254
+
255
+ SSE requires `sse: true` on the shared session method. The async iterable
256
+ selects SSE framing and transport-owned metering.
257
+
258
+ ### WebSocket
259
+
260
+ ```ts
261
+ const wsRoute = mppx.session({ amount: '0.001', unitType: 'token' })
262
+
263
+ webSocketServer.on('connection', (socket, request) => {
264
+ void mppx.session.serveWebSocket({
265
+ generate: async function* (stream) {
266
+ for await (const token of generateTokens()) {
267
+ await stream.charge()
268
+ yield token
269
+ }
270
+ },
271
+ route: wsRoute,
272
+ socket,
273
+ url: new URL(request.url!, `ws://${request.headers.host}`),
274
+ })
275
+ })
276
+ ```
277
+
278
+ The application still exposes `wsRoute` over HTTP for the initial challenge
279
+ probe. The bound helper reuses the session store and automatic settlement
280
+ schedule for in-band WebSocket vouchers and charges.
281
+
282
+ ### Mixed server
283
+
284
+ ```ts
285
+ const httpRoute = mppx.session({ amount: '0.01', unitType: 'request' })
286
+ const sseRoute = mppx.session({ amount: '0.001', unitType: 'token' })
287
+ const wsRoute = mppx.session({ amount: '0.001', unitType: 'token' })
288
+
289
+ async function handler(request: Request) {
290
+ const pathname = new URL(request.url).pathname
291
+ if (pathname === '/api/data') return serveHttp(httpRoute, request)
292
+ if (pathname === '/api/events') return serveSse(sseRoute, request)
293
+ if (pathname === '/ws') return serveWebSocketProbe(wsRoute, request)
294
+ return new Response('Not found', { status: 404 })
295
+ }
296
+ ```
297
+
298
+ Each route can choose its own price and unit type. Verification, channel state,
299
+ and settlement policy remain shared through the single session method.
300
+
189
301
  ## Extension boundaries
190
302
 
191
303
  | Change | Preserve |
@@ -522,6 +522,55 @@ async function simulateTempoTransaction(client: Client, request: unknown) {
522
522
  await call(client, request as never)
523
523
  }
524
524
 
525
+ /** Simulates an unsponsored client-signed session transaction without broadcasting it. */
526
+ export async function simulateCredentialTransaction(parameters: {
527
+ /** viem client used for the read-only execution simulation. */
528
+ client: TransactionClient
529
+ /** Fee-payer configuration for the eventual broadcast. Sponsored transactions are simulated after completion. */
530
+ feePayer?: Account | true | undefined
531
+ /** Parsed client-signed Tempo transaction. */
532
+ transaction: ReturnType<(typeof Transaction)['deserialize']>
533
+ }): Promise<void> {
534
+ if (parameters.feePayer) return
535
+ await simulateTempoTransaction(
536
+ parameters.client,
537
+ FeePayer.simulationTransaction(parameters.transaction, { feePayer: false }),
538
+ )
539
+ }
540
+
541
+ function validateCredentialSponsorship(parameters: {
542
+ allowedFeeTokens: readonly Address[]
543
+ challengeExpires?: string | undefined
544
+ chainId: number
545
+ details: Record<string, string>
546
+ feePayer?: Account | true | undefined
547
+ feePayerPolicy?: Partial<FeePayer.Policy> | undefined
548
+ transaction: ReturnType<(typeof Transaction)['deserialize']>
549
+ }) {
550
+ const {
551
+ allowedFeeTokens,
552
+ challengeExpires,
553
+ chainId,
554
+ details,
555
+ feePayer,
556
+ feePayerPolicy,
557
+ transaction,
558
+ } = parameters
559
+ if (!feePayer || feePayer === true) return
560
+ FeePayer.prepareSponsoredTransaction({
561
+ account: feePayer,
562
+ allowedFeeTokens,
563
+ challengeExpires,
564
+ chainId,
565
+ details,
566
+ policy: feePayerPolicy,
567
+ transaction: {
568
+ ...transaction,
569
+ ...(allowedFeeTokens[0] ? { feeToken: transaction.feeToken ?? allowedFeeTokens[0] } : {}),
570
+ },
571
+ })
572
+ }
573
+
525
574
  async function signTempoTransaction(client: Client, transaction: unknown): Promise<Hex> {
526
575
  return (await signTransaction(client, transaction as never)) as Hex
527
576
  }
@@ -874,10 +923,25 @@ export type BroadcastOpenTransactionParameters = {
874
923
  serializedTransaction: Hex
875
924
  }
876
925
 
877
- /** Broadcast and validate a client-signed TIP-1034 open transaction. */
878
- export async function broadcastOpenTransaction(
879
- parameters: BroadcastOpenTransactionParameters,
880
- ): Promise<BroadcastOpenTransactionResult> {
926
+ /** Inputs for validating a client-signed TIP-1034 open transaction without broadcasting it. */
927
+ export type ValidateOpenCredentialTransactionParameters = Omit<
928
+ BroadcastOpenTransactionParameters,
929
+ 'beforeBroadcast' | 'client'
930
+ >
931
+
932
+ /** Validated fields recovered from a client-signed TIP-1034 open transaction. */
933
+ export type ValidatedOpenCredentialTransaction = Omit<
934
+ BroadcastOpenTransactionResult,
935
+ 'state' | 'txHash'
936
+ > & {
937
+ /** Parsed client-signed transaction, reused by simulation and broadcast. */
938
+ transaction: ReturnType<(typeof Transaction)['deserialize']>
939
+ }
940
+
941
+ /** Validates the immutable fields of a client-signed TIP-1034 open transaction. */
942
+ export function validateOpenCredentialTransaction(
943
+ parameters: ValidateOpenCredentialTransactionParameters,
944
+ ): ValidatedOpenCredentialTransaction {
881
945
  const { transaction, call, prefixCalls } = parsePrecompileCredentialTransaction({
882
946
  escrowContract: parameters.escrowContract,
883
947
  feePayer: parameters.feePayer,
@@ -909,6 +973,19 @@ export async function broadcastOpenTransaction(
909
973
  channelId: parameters.expectedChannelId,
910
974
  })
911
975
  if (parameters.feePayer) assertSenderSigned(transaction)
976
+ validateCredentialSponsorship({
977
+ allowedFeeTokens: [parameters.expectedCurrency],
978
+ challengeExpires: parameters.challengeExpires,
979
+ chainId: parameters.chainId,
980
+ details: {
981
+ channelId: parameters.expectedChannelId,
982
+ currency: parameters.expectedCurrency,
983
+ recipient: parameters.expectedPayee,
984
+ },
985
+ feePayer: parameters.feePayer,
986
+ feePayerPolicy: parameters.feePayerPolicy,
987
+ transaction,
988
+ })
912
989
  const expiringNonceHash = ChannelUtils.computeExpiringNonceHash(
913
990
  ChannelUtils.transactionForExpiringNonceHash({
914
991
  feePayer: parameters.feePayer,
@@ -920,10 +997,19 @@ export async function broadcastOpenTransaction(
920
997
  throw new VerificationFailedError({
921
998
  reason: 'credential expiringNonceHash does not match transaction',
922
999
  })
1000
+ return { descriptor, expiringNonceHash, openDeposit: open.deposit, transaction }
1001
+ }
1002
+
1003
+ /** Broadcast and validate a client-signed TIP-1034 open transaction. */
1004
+ export async function broadcastOpenTransaction(
1005
+ parameters: BroadcastOpenTransactionParameters,
1006
+ ): Promise<BroadcastOpenTransactionResult> {
1007
+ const { descriptor, expiringNonceHash, openDeposit, transaction } =
1008
+ validateOpenCredentialTransaction(parameters)
923
1009
  await parameters.beforeBroadcast?.({
924
1010
  descriptor,
925
1011
  expiringNonceHash,
926
- openDeposit: open.deposit,
1012
+ openDeposit,
927
1013
  })
928
1014
  const receipt = await sendCredentialTransaction({
929
1015
  challengeExpires: parameters.challengeExpires,
@@ -952,7 +1038,7 @@ export async function broadcastOpenTransaction(
952
1038
  emittedExpiringNonceHash: opened.expiringNonceHash,
953
1039
  escrow: parameters.escrowContract,
954
1040
  expectedChannelId: parameters.expectedChannelId,
955
- openDeposit: open.deposit,
1041
+ openDeposit,
956
1042
  })
957
1043
  const chainChannel = await readbackWithRetry(() =>
958
1044
  getChannel(parameters.client, descriptor, parameters.escrowContract, receipt.blockNumber),
@@ -964,7 +1050,7 @@ export async function broadcastOpenTransaction(
964
1050
  descriptor,
965
1051
  state,
966
1052
  expiringNonceHash: opened.expiringNonceHash,
967
- openDeposit: open.deposit,
1053
+ openDeposit,
968
1054
  }
969
1055
  }
970
1056
 
@@ -1004,10 +1090,22 @@ export type BroadcastTopUpTransactionParameters = {
1004
1090
  serializedTransaction: Hex
1005
1091
  }
1006
1092
 
1007
- /** Broadcast and validate a client-signed TIP-1034 top-up transaction. */
1008
- export async function broadcastTopUpTransaction(
1009
- parameters: BroadcastTopUpTransactionParameters,
1010
- ): Promise<BroadcastTopUpTransactionResult> {
1093
+ /** Inputs for validating a client-signed TIP-1034 top-up transaction without broadcasting it. */
1094
+ export type ValidateTopUpCredentialTransactionParameters = Omit<
1095
+ BroadcastTopUpTransactionParameters,
1096
+ 'client'
1097
+ >
1098
+
1099
+ /** Validated fields recovered from a client-signed TIP-1034 top-up transaction. */
1100
+ export type ValidatedTopUpCredentialTransaction = {
1101
+ /** Parsed client-signed transaction, reused by simulation and broadcast. */
1102
+ transaction: ReturnType<(typeof Transaction)['deserialize']>
1103
+ }
1104
+
1105
+ /** Validates the immutable fields of a client-signed TIP-1034 top-up transaction. */
1106
+ export function validateTopUpCredentialTransaction(
1107
+ parameters: ValidateTopUpCredentialTransactionParameters,
1108
+ ): ValidatedTopUpCredentialTransaction {
1011
1109
  const { transaction, call, prefixCalls } = parsePrecompileCredentialTransaction({
1012
1110
  escrowContract: parameters.escrowContract,
1013
1111
  feePayer: parameters.feePayer,
@@ -1027,6 +1125,28 @@ export async function broadcastTopUpTransaction(
1027
1125
  label: 'topUp',
1028
1126
  prefixCalls,
1029
1127
  })
1128
+ if (parameters.feePayer) assertSenderSigned(transaction)
1129
+ validateCredentialSponsorship({
1130
+ allowedFeeTokens: [parameters.expectedCurrency],
1131
+ challengeExpires: parameters.challengeExpires,
1132
+ chainId: parameters.chainId,
1133
+ details: {
1134
+ additionalDeposit: parameters.additionalDeposit.toString(),
1135
+ channelId: parameters.expectedChannelId,
1136
+ currency: parameters.expectedCurrency,
1137
+ },
1138
+ feePayer: parameters.feePayer,
1139
+ feePayerPolicy: parameters.feePayerPolicy,
1140
+ transaction,
1141
+ })
1142
+ return { transaction }
1143
+ }
1144
+
1145
+ /** Broadcast and validate a client-signed TIP-1034 top-up transaction. */
1146
+ export async function broadcastTopUpTransaction(
1147
+ parameters: BroadcastTopUpTransactionParameters,
1148
+ ): Promise<BroadcastTopUpTransactionResult> {
1149
+ const { transaction } = validateTopUpCredentialTransaction(parameters)
1030
1150
  const receipt = await sendCredentialTransaction({
1031
1151
  challengeExpires: parameters.challengeExpires,
1032
1152
  chainId: parameters.chainId,
@@ -240,6 +240,18 @@ export type VerifyAndAcceptVoucherParameters = {
240
240
  voucher: SignedVoucher
241
241
  }
242
242
 
243
+ /** Inputs for validating a cumulative voucher without recording it. */
244
+ export type ValidateVoucherParameters = Omit<
245
+ VerifyAndAcceptVoucherParameters,
246
+ 'challenge' | 'store'
247
+ >
248
+
249
+ /** Result of validating a cumulative voucher against persisted channel state. */
250
+ export type VoucherValidation = {
251
+ /** Whether the voucher was already accepted at the same cumulative amount. */
252
+ alreadyAccepted: boolean
253
+ }
254
+
243
255
  /** Channel backend-specific fields. */
244
256
  export type BackendState = CompatibilityBackendState | PrecompileBackendState
245
257
 
@@ -520,12 +532,11 @@ export async function loadPrecompileChannel(
520
532
  return channel
521
533
  }
522
534
 
523
- /** Verifies a cumulative voucher and returns a session receipt after store reconciliation. */
524
- export async function verifyAndAcceptVoucher(
525
- parameters: VerifyAndAcceptVoucherParameters,
526
- ): Promise<SessionReceipt> {
527
- const { store, minVoucherDelta, challenge, channel, voucher, channelState, methodDetails } =
528
- parameters
535
+ /** Verifies a cumulative voucher without changing persisted channel state. */
536
+ export async function validateVoucher(
537
+ parameters: ValidateVoucherParameters,
538
+ ): Promise<VoucherValidation> {
539
+ const { minVoucherDelta, channel, voucher, channelState, methodDetails } = parameters
529
540
 
530
541
  validateChannelState(channelState)
531
542
  if (voucher.cumulativeAmount > channelState.deposit)
@@ -546,7 +557,22 @@ export async function verifyAndAcceptVoucher(
546
557
  throw new VerificationFailedError({
547
558
  reason: 'voucher cumulativeAmount is below on-chain settled amount',
548
559
  })
549
- if (voucher.cumulativeAmount === channel.highestVoucherAmount)
560
+ if (voucher.cumulativeAmount === channel.highestVoucherAmount) return { alreadyAccepted: true }
561
+ const delta = voucher.cumulativeAmount - channel.highestVoucherAmount
562
+ if (delta < minVoucherDelta)
563
+ throw new DeltaTooSmallError({
564
+ reason: `voucher delta ${delta} below minimum ${minVoucherDelta}`,
565
+ })
566
+ return { alreadyAccepted: false }
567
+ }
568
+
569
+ /** Verifies a cumulative voucher and returns a session receipt after store reconciliation. */
570
+ export async function verifyAndAcceptVoucher(
571
+ parameters: VerifyAndAcceptVoucherParameters,
572
+ ): Promise<SessionReceipt> {
573
+ const { store, challenge, channel, voucher, channelState } = parameters
574
+ const validation = await validateVoucher(parameters)
575
+ if (validation.alreadyAccepted)
550
576
  return createSessionReceipt({
551
577
  challengeId: challenge.id,
552
578
  channelId: voucher.channelId,
@@ -554,11 +580,6 @@ export async function verifyAndAcceptVoucher(
554
580
  spent: channel.spent,
555
581
  units: channel.units,
556
582
  })
557
- const delta = voucher.cumulativeAmount - channel.highestVoucherAmount
558
- if (delta < minVoucherDelta)
559
- throw new DeltaTooSmallError({
560
- reason: `voucher delta ${delta} below minimum ${minVoucherDelta}`,
561
- })
562
583
  const updated = await store.updateChannel(voucher.channelId, (current) =>
563
584
  acceptVoucherStateUpdate({ channelState, current, voucher }),
564
585
  )
@@ -9,11 +9,11 @@ import * as Voucher from '../precompile/Voucher.js'
9
9
  import * as ChannelStore from './ChannelStore.js'
10
10
  import {
11
11
  assertOpenCredentialCoversRequest,
12
+ broadcastCredentialPayload,
12
13
  requireSessionCredentialAction,
13
14
  requireSessionCredentialPayload,
14
15
  requireSessionCredentialPayloadHeader,
15
16
  validateChannelDescriptor,
16
- verifyCredentialPayload,
17
17
  } from './CredentialVerification.js'
18
18
 
19
19
  describe('SessionCredentialGuards', () => {
@@ -190,7 +190,7 @@ describe('SessionCredentialGuards', () => {
190
190
  })
191
191
  })
192
192
 
193
- describe('verifyCredentialPayload', () => {
193
+ describe('broadcastCredentialPayload', () => {
194
194
  const escrow = '0x4D50500000000000000000000000000000000000' as Address
195
195
  const testChainId = chainIds.testnet
196
196
  const computedChannelId = Channel.computeId({ ...descriptor, chainId: testChainId, escrow })
@@ -246,7 +246,7 @@ describe('SessionCredentialGuards', () => {
246
246
  const verifyVoucher = vi.spyOn(Voucher, 'verifyVoucher').mockResolvedValue(true)
247
247
 
248
248
  await expect(
249
- verifyCredentialPayload({
249
+ broadcastCredentialPayload({
250
250
  challenge,
251
251
  channelStateTtl: 60_000,
252
252
  chainId: testChainId,
@@ -274,7 +274,7 @@ describe('SessionCredentialGuards', () => {
274
274
  const verifyVoucher = vi.spyOn(Voucher, 'verifyVoucher').mockResolvedValue(true)
275
275
 
276
276
  await expect(
277
- verifyCredentialPayload({
277
+ broadcastCredentialPayload({
278
278
  challenge,
279
279
  channelStateTtl: 60_000,
280
280
  chainId: testChainId,