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
@@ -4,6 +4,8 @@ import { serve } from '@hono/node-server'
4
4
  import { Hono } from 'hono'
5
5
  import { Challenge, Constants, Credential } from 'mppx'
6
6
  import { Mppx as Mppx_server, tempo as tempo_server } from 'mppx/server'
7
+ import { Secp256k1 } from 'ox'
8
+ import { TxEnvelopeTempo } from 'ox/tempo'
7
9
  import {
8
10
  type Address,
9
11
  createClient,
@@ -14,6 +16,7 @@ import {
14
16
  encodeFunctionData,
15
17
  encodeFunctionResult,
16
18
  type Hex,
19
+ maxUint256,
17
20
  zeroAddress,
18
21
  } from 'viem'
19
22
  import { privateKeyToAccount } from 'viem/accounts'
@@ -40,9 +43,8 @@ import * as ChannelStore from './ChannelStore.js'
40
43
  import { charge, session, type ResolveSessionChannelId } from './Session.js'
41
44
  import * as TempoWs from './Ws.js'
42
45
 
43
- const payer = privateKeyToAccount(
44
- '0xac0974bec39a17e36ba6a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
45
- )
46
+ const payerPrivateKey = '0xac0974bec39a17e36ba6a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
47
+ const payer = privateKeyToAccount(payerPrivateKey)
46
48
  const wrongPayer = privateKeyToAccount(
47
49
  '0x59c6995e998f97a5a0044966f094538a009d74290f5811cfba6a6b4d238ff944',
48
50
  )
@@ -88,10 +90,16 @@ function createServerClient(
88
90
  _eventChannelId: Hex = `0x${'00'.repeat(32)}` as Hex,
89
91
  options: {
90
92
  descriptor?: Channel.ChannelDescriptor
91
- receipt?: Record<string, unknown>
92
- state?: ChainState
93
+ receipt?:
94
+ | Record<string, unknown>
95
+ | (() => Record<string, unknown> | Promise<Record<string, unknown>>)
96
+ sentReceipt?:
97
+ | Record<string, unknown>
98
+ | (() => Record<string, unknown> | Promise<Record<string, unknown>>)
99
+ state?: ChainState | (() => ChainState | Promise<ChainState>)
93
100
  } = {},
94
101
  ) {
102
+ let sentTransaction = false
95
103
  return createClient({
96
104
  ...(account ? { account } : {}),
97
105
  chain: testChain,
@@ -103,11 +111,24 @@ function createServerClient(
103
111
  if (args.method === 'eth_estimateGas') return '0x5208'
104
112
  if (args.method === 'eth_maxPriorityFeePerGas') return '0x1'
105
113
  if (args.method === 'eth_getBlockByNumber') return { baseFeePerGas: '0x1' }
106
- if (args.method === 'eth_sendRawTransaction') return `0x${'aa'.repeat(32)}`
107
- if (args.method === 'eth_getTransactionReceipt') return options.receipt ?? null
108
- if (args.method === 'eth_sendTransaction') return `0x${'bb'.repeat(32)}`
114
+ if (args.method === 'eth_sendRawTransaction') {
115
+ sentTransaction = true
116
+ return `0x${'aa'.repeat(32)}`
117
+ }
118
+ if (args.method === 'eth_getTransactionReceipt') {
119
+ const receipt = sentTransaction
120
+ ? (options.sentReceipt ?? options.receipt)
121
+ : options.receipt
122
+ return typeof receipt === 'function' ? receipt() : (receipt ?? null)
123
+ }
124
+ if (args.method === 'eth_sendTransaction') {
125
+ sentTransaction = true
126
+ return `0x${'bb'.repeat(32)}`
127
+ }
109
128
  if (args.method === 'eth_call') {
110
- const state = options.state ?? { settled: 100n, deposit: 1_000n, closeRequestedAt: 0 }
129
+ const configuredState =
130
+ typeof options.state === 'function' ? await options.state() : options.state
131
+ const state = configuredState ?? { settled: 100n, deposit: 1_000n, closeRequestedAt: 0 }
111
132
  const data = (args.params as [{ data?: Hex }])[0].data
112
133
  const getChannelSelector = options.descriptor
113
134
  ? encodeFunctionData({
@@ -315,6 +336,52 @@ async function createOpenPayload(
315
336
  }
316
337
  }
317
338
 
339
+ function sponsorTransaction(
340
+ serializedTransaction: Hex,
341
+ options: { gas?: bigint | undefined } = {},
342
+ ): Hex {
343
+ const transaction = Transaction.deserialize(
344
+ serializedTransaction as Transaction.TransactionSerializedTempo,
345
+ )
346
+ const envelope = TxEnvelopeTempo.from({
347
+ ...transaction,
348
+ feePayerSignature: null,
349
+ gas: options.gas ?? 100_000n,
350
+ maxFeePerGas: 1n,
351
+ maxPriorityFeePerGas: 1n,
352
+ nonceKey: maxUint256,
353
+ validBefore: Math.floor(Date.now() / 1_000) + 600,
354
+ } as never)
355
+ return TxEnvelopeTempo.serialize(envelope, {
356
+ signature: Secp256k1.sign({
357
+ payload: TxEnvelopeTempo.getSignPayload(envelope),
358
+ privateKey: payerPrivateKey,
359
+ }),
360
+ }) as Hex
361
+ }
362
+
363
+ async function createSponsoredOpenPayload(): Promise<
364
+ Extract<SessionCredentialPayload, { action: 'open' }>
365
+ > {
366
+ const payload = await createOpenPayload()
367
+ const transaction = sponsorTransaction(payload.transaction)
368
+ const signed = Transaction.deserialize(transaction as Transaction.TransactionSerializedTempo)
369
+ const expiringNonceHash = Channel.computeExpiringNonceHash(
370
+ Channel.transactionForExpiringNonceHash({ feePayer: true, transaction: signed }),
371
+ { sender: payer.address },
372
+ )
373
+ const descriptor = { ...payload.descriptor, expiringNonceHash }
374
+ const channelId = Channel.computeId({ ...descriptor, chainId, escrow: tip20ChannelEscrow })
375
+ const signature = await Voucher.signVoucher(
376
+ createSigningClient(),
377
+ payer,
378
+ { channelId, cumulativeAmount: BigInt(payload.cumulativeAmount) },
379
+ tip20ChannelEscrow,
380
+ chainId,
381
+ )
382
+ return { ...payload, channelId, transaction, signature, descriptor }
383
+ }
384
+
318
385
  function transactionReceipt(logs: readonly Record<string, unknown>[]) {
319
386
  return {
320
387
  blockHash: `0x${'01'.repeat(32)}`,
@@ -757,6 +824,133 @@ describe('precompile server session unit guardrails', () => {
757
824
  ).rejects.toThrow('Client not configured with chainId 1.')
758
825
  })
759
826
 
827
+ test('fully validates a session credential without broadcasting or changing channel state', async () => {
828
+ const { method, rpcCalls, store } = createServer()
829
+ const openPayload = await createOpenPayload()
830
+ await persistPrecompileChannel(store, openPayload)
831
+ const payload = await ClientOps.createVoucherPayload(
832
+ createSigningClient(),
833
+ payer,
834
+ openPayload.descriptor,
835
+ Types.uint96(200n),
836
+ chainId,
837
+ )
838
+
839
+ const validation = await method.validate!({
840
+ credential: {
841
+ challenge: makeChallenge(openPayload.channelId),
842
+ payload,
843
+ source: sourceFor(),
844
+ },
845
+ request: verifyRequest(openPayload.channelId),
846
+ })
847
+
848
+ await method.validate!({
849
+ credential: {
850
+ challenge: makeChallenge(openPayload.channelId),
851
+ payload,
852
+ source: sourceFor(),
853
+ },
854
+ request: verifyRequest(openPayload.channelId),
855
+ })
856
+
857
+ expect(validation.details).toEqual({ action: 'voucher', channelId: openPayload.channelId })
858
+ expect(await store.getChannel(openPayload.channelId)).toMatchObject({
859
+ highestVoucherAmount: 100n,
860
+ spent: 0n,
861
+ units: 0,
862
+ })
863
+ expect(rpcCalls.map(({ method }) => method)).toEqual(['eth_call'])
864
+ expect(rpcCalls.map(({ method }) => method)).not.toContain('eth_sendRawTransaction')
865
+ expect(rpcCalls.map(({ method }) => method)).not.toContain('eth_sendRawTransactionSync')
866
+ })
867
+
868
+ test('simulates unsponsored open and top-up credentials during validation', async () => {
869
+ const { method, rpcCalls, store } = createServer()
870
+ const openPayload = await createOpenPayload()
871
+
872
+ await method.validate!({
873
+ credential: { challenge: makeChallenge(openPayload.channelId), payload: openPayload },
874
+ request: verifyRequest(openPayload.channelId),
875
+ })
876
+ await persistPrecompileChannel(store, openPayload)
877
+ const topUpPayload = await createTopUpPayload(openPayload.descriptor, 100n)
878
+
879
+ await method.validate!({
880
+ credential: { challenge: makeChallenge(topUpPayload.channelId), payload: topUpPayload },
881
+ request: verifyRequest(topUpPayload.channelId),
882
+ })
883
+
884
+ expect(rpcCalls.map(({ method }) => method)).toEqual(['eth_call', 'eth_call', 'eth_call'])
885
+ expect(await store.getChannel(openPayload.channelId)).toMatchObject({
886
+ deposit: 1_000n,
887
+ highestVoucherAmount: 100n,
888
+ })
889
+ })
890
+
891
+ test('does not simulate sponsored credentials during validation but checks top-up state', async () => {
892
+ const { method, rpcCalls, store } = createServer({ feePayer: payer })
893
+ const openPayload = await createSponsoredOpenPayload()
894
+
895
+ await method.validate!({
896
+ credential: { challenge: makeChallenge(openPayload.channelId), payload: openPayload },
897
+ request: verifyRequestWithFeePayer(openPayload.channelId, payer),
898
+ })
899
+ await persistPrecompileChannel(store, openPayload)
900
+ const topUpPayload = await createTopUpPayload(openPayload.descriptor, 100n)
901
+ topUpPayload.transaction = sponsorTransaction(topUpPayload.transaction)
902
+
903
+ await method.validate!({
904
+ credential: { challenge: makeChallenge(topUpPayload.channelId), payload: topUpPayload },
905
+ request: verifyRequestWithFeePayer(topUpPayload.channelId, payer),
906
+ })
907
+
908
+ expect(rpcCalls.map(({ method }) => method)).toEqual(['eth_call'])
909
+ expect(await store.getChannel(openPayload.channelId)).toMatchObject({
910
+ deposit: 1_000n,
911
+ highestVoucherAmount: 100n,
912
+ })
913
+ })
914
+
915
+ test('rejects sponsored credentials that exceed the fee-payer policy during validation', async () => {
916
+ const { method, rpcCalls } = createServer({
917
+ feePayer: payer,
918
+ feePayerPolicy: { maxGas: 1n },
919
+ })
920
+ const payload = await createSponsoredOpenPayload()
921
+
922
+ payload.transaction = sponsorTransaction(payload.transaction, { gas: 2n })
923
+
924
+ await expect(
925
+ method.validate!({
926
+ credential: { challenge: makeChallenge(payload.channelId), payload },
927
+ request: verifyRequestWithFeePayer(payload.channelId, payer),
928
+ }),
929
+ ).rejects.toThrow(/fee-sponsored transaction gas exceeds sponsor policy/)
930
+ expect(rpcCalls).toEqual([])
931
+ })
932
+
933
+ test('validates close credentials without marking the channel pending', async () => {
934
+ const { method, rpcCalls, store } = createServer()
935
+ const openPayload = await createOpenPayload()
936
+ await persistPrecompileChannel(store, openPayload, { payee: payer.address })
937
+ const payload = await ClientOps.createClosePayload(
938
+ createSigningClient(),
939
+ payer,
940
+ openPayload.descriptor,
941
+ Types.uint96(100n),
942
+ chainId,
943
+ )
944
+
945
+ await method.validate!({
946
+ credential: { challenge: makeChallenge(openPayload.channelId), payload },
947
+ request: verifyRequest(openPayload.channelId),
948
+ })
949
+
950
+ expect((await store.getChannel(openPayload.channelId))?.closeRequestedAt).toBe(0n)
951
+ expect(rpcCalls.map(({ method }) => method)).toEqual(['eth_call'])
952
+ })
953
+
760
954
  test('rejects open transactions targeting the wrong address', async () => {
761
955
  const { method } = createServer()
762
956
  const payload = await createOpenPayload({ escrow: wrongTarget })
@@ -1409,7 +1603,7 @@ describe('precompile server session unit guardrails', () => {
1409
1603
  expect(stored?.units).toBe(4)
1410
1604
  })
1411
1605
 
1412
- test('rejects precompile top-up when on-chain state has pending close', async () => {
1606
+ test('rejects top-up validation when on-chain state has pending close', async () => {
1413
1607
  const rawStore = Store.memory()
1414
1608
  const store = channelStore(rawStore)
1415
1609
  const openPayload = await createOpenPayload({ initialAmount: 100n })
@@ -1431,7 +1625,7 @@ describe('precompile server session unit guardrails', () => {
1431
1625
  })
1432
1626
 
1433
1627
  await expect(
1434
- method.verify({
1628
+ method.validate!({
1435
1629
  credential: {
1436
1630
  challenge: makeChallenge(openPayload.channelId),
1437
1631
  payload: topUpPayload,
@@ -2172,14 +2366,23 @@ describe('precompile server session unit guardrails', () => {
2172
2366
 
2173
2367
  describe('SSE parity', () => {
2174
2368
  function createManagedSseFetch(
2175
- options: { amount?: string; maxDeposit?: bigint; unitType?: 'request' | 'token' } = {},
2369
+ options: {
2370
+ amount?: string
2371
+ chunkDelayMs?: number
2372
+ maxDeposit?: bigint
2373
+ onSessionSettlement?: session.Parameters['onSessionSettlement']
2374
+ settlementSchedule?: session.Parameters['settlementSchedule']
2375
+ unitType?: 'request' | 'token'
2376
+ } = {},
2176
2377
  ) {
2177
2378
  const rawStore = Store.memory()
2379
+ let activeChannelId: Hex | undefined
2178
2380
  let currentPayload: SessionCredentialPayload | undefined
2179
2381
  let voucherPosts = 0
2180
2382
  const amount = options.amount ?? '1'
2181
2383
  const maxDeposit = options.maxDeposit ?? 3n
2182
2384
  let deposit = maxDeposit
2385
+ let settled = 0n
2183
2386
  const unitType = options.unitType ?? 'token'
2184
2387
  const route = Mppx_server.create({
2185
2388
  methods: [
@@ -2189,6 +2392,8 @@ describe('precompile server session unit guardrails', () => {
2189
2392
  currency: token,
2190
2393
  decimals: 0,
2191
2394
  recipient: payer.address,
2395
+ onSessionSettlement: options.onSessionSettlement,
2396
+ settlementSchedule: options.settlementSchedule,
2192
2397
  sse: true,
2193
2398
  store: rawStore,
2194
2399
  unitType,
@@ -2206,20 +2411,24 @@ describe('precompile server session unit guardrails', () => {
2206
2411
  receipt: transactionReceipt([
2207
2412
  closedLog(payload.channelId, BigInt(payload.cumulativeAmount), 0n),
2208
2413
  ]),
2209
- state: { settled: 0n, deposit, closeRequestedAt: 0 },
2414
+ state: { settled, deposit, closeRequestedAt: 0 },
2210
2415
  })
2211
2416
  }
2212
2417
  if (payload?.action === 'topUp') {
2213
2418
  deposit += BigInt(payload.additionalDeposit)
2214
2419
  return createServerClient([], payer, payload.channelId, {
2215
2420
  receipt: transactionReceipt([topUpLog(payload, deposit)]),
2216
- state: { settled: 0n, deposit, closeRequestedAt: 0 },
2421
+ state: { settled, deposit, closeRequestedAt: 0 },
2217
2422
  })
2218
2423
  }
2219
- return createStateClient(payer, {
2220
- settled: 0n,
2221
- deposit,
2222
- closeRequestedAt: 0,
2424
+ return createServerClient([], payer, undefined, {
2425
+ sentReceipt: async () => {
2426
+ if (!activeChannelId) throw new Error('missing channel context')
2427
+ const channel = await channelStore(rawStore).getChannel(activeChannelId)
2428
+ settled = channel?.highestVoucherAmount ?? settled
2429
+ return transactionReceipt([settledLog(activeChannelId, settled)])
2430
+ },
2431
+ state: () => ({ settled, deposit, closeRequestedAt: 0 }),
2223
2432
  })
2224
2433
  },
2225
2434
  }),
@@ -2233,6 +2442,7 @@ describe('precompile server session unit guardrails', () => {
2233
2442
  if (request.headers.has('Authorization')) {
2234
2443
  try {
2235
2444
  currentPayload = Credential.fromRequest<SessionCredentialPayload>(request).payload
2445
+ activeChannelId = currentPayload.channelId
2236
2446
  if (currentPayload.action === 'voucher') voucherPosts++
2237
2447
  } catch {}
2238
2448
  }
@@ -2259,9 +2469,12 @@ describe('precompile server session unit guardrails', () => {
2259
2469
  )
2260
2470
  }
2261
2471
 
2472
+ currentPayload = undefined
2262
2473
  return result.withReceipt(async function* (stream) {
2263
2474
  await stream.charge()
2264
2475
  yield 'chunk-1'
2476
+ if (options.chunkDelayMs)
2477
+ await new Promise((resolve) => setTimeout(resolve, options.chunkDelayMs))
2265
2478
  await stream.charge()
2266
2479
  yield 'chunk-2'
2267
2480
  await stream.charge()
@@ -2312,6 +2525,49 @@ describe('precompile server session unit guardrails', () => {
2312
2525
  expect(persisted?.finalized).toBe(true)
2313
2526
  })
2314
2527
 
2528
+ test.each([
2529
+ ['unit', { units: 2 }, 0],
2530
+ ['amount', { amount: '2' }, 0],
2531
+ ['interval', { intervalMs: 500 }, 750],
2532
+ ] as const)(
2533
+ 'applies the %s settlement schedule after SSE charges',
2534
+ async (_label, settlementSchedule, chunkDelayMs) => {
2535
+ const settlements: Array<{ delta: bigint; trigger: string }> = []
2536
+ const harness = createManagedSseFetch({
2537
+ chunkDelayMs,
2538
+ maxDeposit: 3n,
2539
+ settlementSchedule,
2540
+ onSessionSettlement(context) {
2541
+ settlements.push({ delta: context.delta, trigger: context.trigger })
2542
+ },
2543
+ })
2544
+ const manager = precompileSessionManager({
2545
+ account: payer,
2546
+ client: createSigningClient(),
2547
+ decimals: 0,
2548
+ fetch: harness.fetch,
2549
+ maxDeposit: '3',
2550
+ })
2551
+
2552
+ const chunks: string[] = []
2553
+ for await (const chunk of await manager.sse('https://api.example.com/stream')) {
2554
+ chunks.push(chunk)
2555
+ }
2556
+
2557
+ expect(chunks).toEqual(['chunk-1', 'chunk-2', 'chunk-3'])
2558
+ expect(harness.voucherPosts).toBeGreaterThan(0)
2559
+ expect(settlements).toEqual([{ delta: 2n, trigger: 'scheduled' }])
2560
+ const persisted = await channelStore(harness.rawStore).getChannel(manager.channelId!)
2561
+ expect(persisted?.lastSettlementUnits).toBe(2)
2562
+
2563
+ await manager.close()
2564
+ expect(settlements).toEqual([
2565
+ { delta: 2n, trigger: 'scheduled' },
2566
+ { delta: 1n, trigger: 'close' },
2567
+ ])
2568
+ },
2569
+ )
2570
+
2315
2571
  test('handles empty management POST streams through a Node adapter', async () => {
2316
2572
  const harness = createManagedSseFetch({ maxDeposit: 1n })
2317
2573
  const managementPosts: Array<{
@@ -2421,19 +2677,31 @@ describe('precompile server session unit guardrails', () => {
2421
2677
  })
2422
2678
 
2423
2679
  describe('WebSocket parity', () => {
2424
- async function createManagedWsHarness(options: { maxDeposit?: bigint } = {}) {
2680
+ async function createManagedWsHarness(
2681
+ options: {
2682
+ challengeTtlMs?: number
2683
+ maxDeposit?: bigint
2684
+ onSessionSettlement?: session.Parameters['onSessionSettlement']
2685
+ settlementSchedule?: session.Parameters['settlementSchedule']
2686
+ } = {},
2687
+ ) {
2425
2688
  const rawStore = Store.memory()
2689
+ let activeChannelId: Hex | undefined
2690
+ let challengeRequests = 0
2426
2691
  let currentPayload: SessionCredentialPayload | undefined
2692
+ let settled = 0n
2427
2693
  let voucherPosts = 0
2428
2694
  const maxDeposit = options.maxDeposit ?? 3n
2429
- const routeHandler = Mppx_server.create({
2695
+ const payment = Mppx_server.create({
2430
2696
  methods: [
2431
2697
  tempo_server.session({
2432
2698
  amount: '1',
2433
2699
  chainId,
2434
2700
  currency: token,
2435
2701
  decimals: 0,
2702
+ onSessionSettlement: options.onSessionSettlement,
2436
2703
  recipient: payer.address,
2704
+ settlementSchedule: options.settlementSchedule,
2437
2705
  store: rawStore,
2438
2706
  unitType: 'token',
2439
2707
  getClient: () => {
@@ -2450,30 +2718,45 @@ describe('precompile server session unit guardrails', () => {
2450
2718
  receipt: transactionReceipt([
2451
2719
  closedLog(payload.channelId, BigInt(payload.cumulativeAmount), 0n),
2452
2720
  ]),
2453
- state: { settled: 0n, deposit: maxDeposit, closeRequestedAt: 0 },
2721
+ state: { settled, deposit: maxDeposit, closeRequestedAt: 0 },
2454
2722
  })
2455
2723
  }
2456
- return createStateClient(payer, {
2457
- settled: 0n,
2458
- deposit: maxDeposit,
2459
- closeRequestedAt: 0,
2724
+ return createServerClient([], payer, undefined, {
2725
+ sentReceipt: async () => {
2726
+ if (!activeChannelId) throw new Error('missing channel context')
2727
+ const channel = await channelStore(rawStore).getChannel(activeChannelId)
2728
+ settled = channel?.highestVoucherAmount ?? settled
2729
+ return transactionReceipt([settledLog(activeChannelId, settled)])
2730
+ },
2731
+ state: () => ({ settled, deposit: maxDeposit, closeRequestedAt: 0 }),
2460
2732
  })
2461
2733
  },
2462
2734
  }),
2463
2735
  ],
2464
2736
  realm: 'api.example.com',
2465
2737
  secretKey: 'test-secret-key-test-secret-key-32',
2466
- }).session({ amount: '1', decimals: 0, suggestedDeposit: maxDeposit.toString() })
2738
+ })
2467
2739
 
2740
+ const routeOptions = () => ({
2741
+ amount: '1',
2742
+ decimals: 0,
2743
+ suggestedDeposit: maxDeposit.toString(),
2744
+ ...(options.challengeTtlMs === undefined
2745
+ ? {}
2746
+ : { expires: new Date(Date.now() + options.challengeTtlMs) }),
2747
+ })
2468
2748
  const route = async (request: Request) => {
2469
2749
  currentPayload = undefined
2470
2750
  if (request.headers.has('Authorization')) {
2471
2751
  try {
2472
2752
  currentPayload = Credential.fromRequest<SessionCredentialPayload>(request).payload
2753
+ activeChannelId = currentPayload.channelId
2473
2754
  if (currentPayload.action === 'voucher') voucherPosts++
2474
2755
  } catch {}
2475
- }
2476
- return routeHandler(request)
2756
+ } else challengeRequests++
2757
+ const result = await payment.session(routeOptions())(request)
2758
+ currentPayload = undefined
2759
+ return result
2477
2760
  }
2478
2761
 
2479
2762
  const httpHandler = NodeRequest.toNodeListener(async (request) => {
@@ -2505,11 +2788,15 @@ describe('precompile server session unit guardrails', () => {
2505
2788
  return {
2506
2789
  rawStore,
2507
2790
  route,
2791
+ serveWebSocket: payment.session.serveWebSocket,
2508
2792
  server,
2509
2793
  wsServer,
2510
2794
  get port() {
2511
2795
  return port
2512
2796
  },
2797
+ get challengeRequests() {
2798
+ return challengeRequests
2799
+ },
2513
2800
  get voucherPosts() {
2514
2801
  return voucherPosts
2515
2802
  },
@@ -2520,12 +2807,58 @@ describe('precompile server session unit guardrails', () => {
2520
2807
  }
2521
2808
  }
2522
2809
 
2810
+ test('refreshes an expired challenge before sending a later websocket voucher', async () => {
2811
+ const harness = await createManagedWsHarness({ challengeTtlMs: 2_000, maxDeposit: 2n })
2812
+ harness.wsServer.on('connection', (socket: import('ws').WebSocket) => {
2813
+ void harness.serveWebSocket({
2814
+ socket,
2815
+ url: `${harness.server.url}/ws`,
2816
+ route: harness.route,
2817
+ generate: async function* (stream: TempoWs.SessionController) {
2818
+ await stream.charge()
2819
+ yield 'chunk-1'
2820
+ await new Promise((resolve) => setTimeout(resolve, 2_200))
2821
+ await stream.charge()
2822
+ yield 'chunk-2'
2823
+ },
2824
+ })
2825
+ })
2826
+
2827
+ try {
2828
+ const manager = precompileSessionManager({
2829
+ account: payer,
2830
+ client: createSigningClient(),
2831
+ decimals: 0,
2832
+ fetch: globalThis.fetch,
2833
+ maxDeposit: '2',
2834
+ webSocket: WebSocket as never,
2835
+ })
2836
+ const ws = await manager.ws(`ws://localhost:${harness.port}/ws`)
2837
+ const chunks: string[] = []
2838
+
2839
+ await new Promise<void>((resolve, reject) => {
2840
+ ws.addEventListener('message', (event) => {
2841
+ if (typeof event.data === 'string') chunks.push(event.data)
2842
+ })
2843
+ ws.addEventListener('close', () => resolve(), { once: true })
2844
+ ws.addEventListener('error', () => reject(new Error('websocket stream failed')), {
2845
+ once: true,
2846
+ })
2847
+ })
2848
+
2849
+ expect(chunks).toEqual(['chunk-1', 'chunk-2'])
2850
+ expect(harness.challengeRequests).toBeGreaterThan(1)
2851
+ expect(harness.voucherPosts).toBe(1)
2852
+ } finally {
2853
+ harness.close()
2854
+ }
2855
+ })
2856
+
2523
2857
  test('open -> stream -> need-voucher -> resume -> close', async () => {
2524
2858
  const harness = await createManagedWsHarness({ maxDeposit: 3n })
2525
2859
  harness.wsServer.on('connection', (socket: import('ws').WebSocket) => {
2526
- void TempoWs.serve({
2860
+ void harness.serveWebSocket({
2527
2861
  socket,
2528
- store: harness.rawStore,
2529
2862
  url: `${harness.server.url}/ws`,
2530
2863
  route: harness.route,
2531
2864
  generate: async function* (stream: TempoWs.SessionController) {
@@ -2579,6 +2912,75 @@ describe('precompile server session unit guardrails', () => {
2579
2912
  }
2580
2913
  })
2581
2914
 
2915
+ test.each([
2916
+ ['unit', { units: 2 }, 0],
2917
+ ['amount', { amount: '2' }, 0],
2918
+ ['interval', { intervalMs: 500 }, 750],
2919
+ ] as const)(
2920
+ 'applies the %s settlement schedule after websocket charges',
2921
+ async (_label, settlementSchedule, chunkDelayMs) => {
2922
+ const settlements: Array<{ delta: bigint; trigger: string }> = []
2923
+ const harness = await createManagedWsHarness({
2924
+ maxDeposit: 3n,
2925
+ settlementSchedule,
2926
+ onSessionSettlement(context) {
2927
+ settlements.push({ delta: context.delta, trigger: context.trigger })
2928
+ },
2929
+ })
2930
+ harness.wsServer.on('connection', (socket: import('ws').WebSocket) => {
2931
+ void harness.serveWebSocket({
2932
+ socket,
2933
+ url: `${harness.server.url}/ws`,
2934
+ route: harness.route,
2935
+ generate: async function* (stream: TempoWs.SessionController) {
2936
+ for (const chunk of ['chunk-1', 'chunk-2', 'chunk-3']) {
2937
+ if (chunk === 'chunk-2' && chunkDelayMs)
2938
+ await new Promise((resolve) => setTimeout(resolve, chunkDelayMs))
2939
+ await stream.charge()
2940
+ yield chunk
2941
+ }
2942
+ },
2943
+ })
2944
+ })
2945
+
2946
+ try {
2947
+ const manager = precompileSessionManager({
2948
+ account: payer,
2949
+ client: createSigningClient(),
2950
+ decimals: 0,
2951
+ fetch: globalThis.fetch,
2952
+ maxDeposit: '3',
2953
+ webSocket: WebSocket as never,
2954
+ })
2955
+ const ws = await manager.ws(`ws://localhost:${harness.port}/ws`)
2956
+ const chunks: string[] = []
2957
+
2958
+ await new Promise<void>((resolve, reject) => {
2959
+ ws.addEventListener('message', (event) => {
2960
+ if (typeof event.data === 'string') chunks.push(event.data)
2961
+ })
2962
+ ws.addEventListener('close', () => resolve(), { once: true })
2963
+ ws.addEventListener('error', () => reject(new Error('websocket stream failed')), {
2964
+ once: true,
2965
+ })
2966
+ })
2967
+
2968
+ expect(chunks).toEqual(['chunk-1', 'chunk-2', 'chunk-3'])
2969
+ expect(harness.voucherPosts).toBeGreaterThan(0)
2970
+ expect(settlements).toEqual([{ delta: 2n, trigger: 'scheduled' }])
2971
+ await manager.close()
2972
+ expect(settlements).toEqual([
2973
+ { delta: 2n, trigger: 'scheduled' },
2974
+ { delta: 1n, trigger: 'close' },
2975
+ ])
2976
+ const persisted = await channelStore(harness.rawStore).getChannel(manager.channelId!)
2977
+ expect(persisted?.lastSettlementUnits).toBe(2)
2978
+ } finally {
2979
+ harness.close()
2980
+ }
2981
+ },
2982
+ )
2983
+
2582
2984
  test('treats control-shaped application payloads as content', async () => {
2583
2985
  const harness = await createManagedWsHarness({ maxDeposit: 1n })
2584
2986
  const controlLookingChunk = JSON.stringify({
@@ -2591,9 +2993,8 @@ describe('precompile server session unit guardrails', () => {
2591
2993
  },
2592
2994
  })
2593
2995
  harness.wsServer.on('connection', (socket: import('ws').WebSocket) => {
2594
- void TempoWs.serve({
2996
+ void harness.serveWebSocket({
2595
2997
  socket,
2596
- store: harness.rawStore,
2597
2998
  url: `${harness.server.url}/ws`,
2598
2999
  route: harness.route,
2599
3000
  generate: async function* (stream: TempoWs.SessionController) {
@@ -2641,9 +3042,8 @@ describe('precompile server session unit guardrails', () => {
2641
3042
  test('refuses websocket voucher requests beyond local maxDeposit', async () => {
2642
3043
  const harness = await createManagedWsHarness({ maxDeposit: 1n })
2643
3044
  harness.wsServer.on('connection', (socket: import('ws').WebSocket) => {
2644
- void TempoWs.serve({
3045
+ void harness.serveWebSocket({
2645
3046
  socket,
2646
- store: harness.rawStore,
2647
3047
  url: `${harness.server.url}/ws`,
2648
3048
  route: harness.route,
2649
3049
  generate: async function* (stream: TempoWs.SessionController) {
@@ -2803,9 +3203,8 @@ describe('precompile server session unit guardrails', () => {
2803
3203
  let serverSocket: import('ws').WebSocket | null = null
2804
3204
  harness.wsServer.on('connection', (socket: import('ws').WebSocket) => {
2805
3205
  serverSocket = socket
2806
- void TempoWs.serve({
3206
+ void harness.serveWebSocket({
2807
3207
  socket,
2808
- store: harness.rawStore,
2809
3208
  url: `${harness.server.url}/ws`,
2810
3209
  route: harness.route,
2811
3210
  generate: async function* (stream: TempoWs.SessionController) {
@@ -3399,6 +3798,54 @@ describe('precompile server session unit guardrails', () => {
3399
3798
  })
3400
3799
  })
3401
3800
 
3801
+ describe('session settlement extensions', () => {
3802
+ test.each([
3803
+ ['no schedule is configured', undefined],
3804
+ ['the configured threshold is not due', { units: 11 }],
3805
+ ] as const)('does not resolve a client when %s', async (_label, settlementSchedule) => {
3806
+ const rawStore = Store.memory()
3807
+ const store = channelStore(rawStore)
3808
+ const openPayload = await createOpenPayload()
3809
+ let clientResolutions = 0
3810
+ await persistPrecompileChannel(store, openPayload, {
3811
+ highestVoucherAmount: 500n,
3812
+ highestVoucher: {
3813
+ channelId: openPayload.channelId,
3814
+ cumulativeAmount: 500n,
3815
+ signature: '0x1234',
3816
+ },
3817
+ spent: 500n,
3818
+ units: 10,
3819
+ })
3820
+
3821
+ const payment = Mppx_server.create({
3822
+ methods: [
3823
+ tempo_server.session({
3824
+ account: payer,
3825
+ amount: '1',
3826
+ chainId,
3827
+ currency: token,
3828
+ decimals: 0,
3829
+ getClient() {
3830
+ clientResolutions++
3831
+ throw new Error('client should not be resolved')
3832
+ },
3833
+ recipient: payee,
3834
+ settlementSchedule,
3835
+ store: rawStore,
3836
+ unitType: 'token',
3837
+ }),
3838
+ ],
3839
+ realm: 'api.example.com',
3840
+ secretKey: 'test-secret-key-test-secret-key-32',
3841
+ })
3842
+ const channel = await store.getChannel(openPayload.channelId)
3843
+
3844
+ await expect(payment.session.settleScheduled(channel!)).resolves.toBeUndefined()
3845
+ expect(clientResolutions).toBe(0)
3846
+ })
3847
+ })
3848
+
3402
3849
  describe('onSessionSettlement', () => {
3403
3850
  function createSettleClient(channelId: Hex, settledAmount: bigint) {
3404
3851
  return createClient({