mppx 0.8.15 → 0.8.18

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 (966) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/README.md +15 -0
  3. package/dist/Challenge.js +61 -39
  4. package/dist/Constants.d.ts +17 -17
  5. package/dist/Errors.d.ts +3 -3
  6. package/dist/Method.d.ts +35 -5
  7. package/dist/Method.js +7 -22
  8. package/dist/Store.d.ts +19 -0
  9. package/dist/Store.js +43 -0
  10. package/dist/attestation/Client.d.ts +17 -0
  11. package/dist/attestation/Client.js +28 -0
  12. package/dist/attestation/Constants.d.ts +15 -0
  13. package/dist/attestation/Constants.js +15 -0
  14. package/dist/attestation/Server.d.ts +4 -0
  15. package/dist/attestation/Server.js +8 -0
  16. package/dist/attestation/Types.d.ts +76 -0
  17. package/dist/attestation/Types.js +2 -0
  18. package/dist/attestation/index.d.ts +6 -0
  19. package/dist/attestation/index.js +6 -0
  20. package/dist/attestation/internal/HttpMessageSignature.d.ts +73 -0
  21. package/dist/attestation/internal/HttpMessageSignature.js +320 -0
  22. package/dist/attestation/internal/SigningContext.d.ts +4 -0
  23. package/dist/attestation/internal/SigningContext.js +11 -0
  24. package/dist/bin.js +3 -3
  25. package/dist/cli/THIRD-PARTY-LICENSES.txt +328 -0
  26. package/dist/cli/account.d.ts +14 -14
  27. package/dist/cli/cli.d.ts +6 -6
  28. package/dist/cli/cli.js +253 -1504
  29. package/dist/cli/plugins/index.js +19 -5
  30. package/dist/cli/plugins/tempo.js +7 -3
  31. package/dist/cli/sessions/Manager.js +7 -4
  32. package/dist/cli/sessions/commands.d.ts +4 -4
  33. package/dist/cli/sessions/request.d.ts +2 -0
  34. package/dist/cli/sessions/request.js +18 -0
  35. package/dist/cli/sessions/store.js +28 -14
  36. package/dist/cli/utils.d.ts +1 -1
  37. package/dist/cli/validate/index.d.ts +3 -3
  38. package/dist/client/Mppx.d.ts +3 -0
  39. package/dist/client/Mppx.js +13 -5
  40. package/dist/client/Transport.d.ts +3 -5
  41. package/dist/client/Transport.js +1 -17
  42. package/dist/client/internal/Fetch.js +2 -6
  43. package/dist/discovery/Discovery.js +2 -1
  44. package/dist/discovery/OpenApi.d.ts +3 -5
  45. package/dist/discovery/OpenApi.js +13 -34
  46. package/dist/discovery/internal/Metadata.d.ts +20 -0
  47. package/dist/discovery/internal/Metadata.js +36 -0
  48. package/dist/evm/Methods.d.ts +11 -11
  49. package/dist/evm/Types.d.ts +17 -17
  50. package/dist/evm/client/Charge.d.ts +11 -11
  51. package/dist/evm/client/Charge.js +8 -0
  52. package/dist/evm/client/Methods.d.ts +11 -11
  53. package/dist/evm/server/Charge.d.ts +1 -1
  54. package/dist/evm/server/Charge.js +2 -0
  55. package/dist/evm/server/Methods.d.ts +11 -11
  56. package/dist/internal/HeaderCodec.d.ts +2 -2
  57. package/dist/internal/types.d.ts +6 -0
  58. package/dist/proxy/Proxy.d.ts +2 -0
  59. package/dist/proxy/Proxy.js +117 -9
  60. package/dist/proxy/Service.d.ts +36 -1
  61. package/dist/proxy/Service.js +9 -8
  62. package/dist/proxy/services/anthropic.js +1 -0
  63. package/dist/proxy/services/openai.js +1 -0
  64. package/dist/proxy/services/stripe.js +1 -0
  65. package/dist/server/Mppx.d.ts +75 -13
  66. package/dist/server/Mppx.js +201 -23
  67. package/dist/server/core.d.ts +9 -0
  68. package/dist/server/core.js +9 -0
  69. package/dist/server/internal/html/config.d.ts +9 -9
  70. package/dist/server/internal/html/constants.d.ts +17 -17
  71. package/dist/stripe/Methods.d.ts +10 -10
  72. package/dist/stripe/client/Charge.d.ts +10 -10
  73. package/dist/stripe/client/Methods.d.ts +10 -10
  74. package/dist/stripe/internal/constants.d.ts +1 -1
  75. package/dist/stripe/internal/constants.js +1 -1
  76. package/dist/stripe/internal/types.d.ts +1 -0
  77. package/dist/stripe/server/Charge.d.ts +11 -11
  78. package/dist/stripe/server/Charge.js +51 -5
  79. package/dist/stripe/server/Methods.d.ts +137 -48
  80. package/dist/stripe/server/Methods.js +265 -4
  81. package/dist/stripe/server/internal/deposit-address.d.ts +13 -0
  82. package/dist/stripe/server/internal/deposit-address.js +28 -0
  83. package/dist/stripe/server/internal/html.gen.d.ts +1 -1
  84. package/dist/stripe/server/internal/html.gen.js +1 -1
  85. package/dist/stripe/server/internal/record-payment.d.ts +15 -0
  86. package/dist/stripe/server/internal/record-payment.js +42 -0
  87. package/dist/stripe/server/internal/request.d.ts +25 -0
  88. package/dist/stripe/server/internal/request.js +29 -0
  89. package/dist/stripe/server/spt.d.ts +8 -0
  90. package/dist/stripe/server/spt.js +8 -0
  91. package/dist/tap/Constants.d.ts +28 -0
  92. package/dist/tap/Constants.js +32 -0
  93. package/dist/tap/Types.d.ts +11 -0
  94. package/dist/tap/Types.js +2 -0
  95. package/dist/tap/client/index.d.ts +26 -0
  96. package/dist/tap/client/index.js +33 -0
  97. package/dist/tap/index.d.ts +5 -0
  98. package/dist/tap/index.js +5 -0
  99. package/dist/tap/server/index.d.ts +20 -0
  100. package/dist/tap/server/index.js +36 -0
  101. package/dist/tempo/Attribution.d.ts +1 -1
  102. package/dist/tempo/Methods.d.ts +73 -60
  103. package/dist/tempo/Methods.js +14 -3
  104. package/dist/tempo/Proof.d.ts +16 -16
  105. package/dist/tempo/client/Charge.d.ts +22 -19
  106. package/dist/tempo/client/Charge.js +32 -16
  107. package/dist/tempo/client/Methods.d.ts +51 -38
  108. package/dist/tempo/client/Subscription.d.ts +23 -23
  109. package/dist/tempo/internal/address.d.ts +2 -1
  110. package/dist/tempo/internal/address.js +3 -1
  111. package/dist/tempo/internal/auto-swap.js +4 -19
  112. package/dist/tempo/internal/defaults.d.ts +17 -6
  113. package/dist/tempo/internal/defaults.js +11 -0
  114. package/dist/tempo/internal/fee-payer.d.ts +12 -12
  115. package/dist/tempo/internal/machine-token-charge.d.ts +51 -0
  116. package/dist/tempo/internal/machine-token-charge.js +113 -0
  117. package/dist/tempo/internal/machine-token-session.d.ts +88 -0
  118. package/dist/tempo/internal/machine-token-session.js +173 -0
  119. package/dist/tempo/internal/proof.d.ts +17 -17
  120. package/dist/tempo/internal/signature-envelope.d.ts +14 -0
  121. package/dist/tempo/internal/signature-envelope.js +28 -0
  122. package/dist/tempo/legacy/client/ChannelOps.d.ts +2 -2
  123. package/dist/tempo/legacy/client/ChannelOps.js +11 -5
  124. package/dist/tempo/legacy/client/Session.d.ts +33 -21
  125. package/dist/tempo/legacy/client/Session.js +3 -3
  126. package/dist/tempo/legacy/client/SessionManager.d.ts +3 -1
  127. package/dist/tempo/legacy/client/SessionManager.js +2 -0
  128. package/dist/tempo/legacy/index.d.ts +1 -3
  129. package/dist/tempo/legacy/index.js +1 -3
  130. package/dist/tempo/legacy/session/escrow.abi.d.ts +374 -374
  131. package/dist/tempo/server/Charge.d.ts +28 -11
  132. package/dist/tempo/server/Charge.js +101 -55
  133. package/dist/tempo/server/Methods.d.ts +58 -56
  134. package/dist/tempo/server/Methods.js +8 -18
  135. package/dist/tempo/server/Relay.d.ts +1 -1
  136. package/dist/tempo/server/Relay.js +2 -2
  137. package/dist/tempo/server/Subscription.d.ts +25 -25
  138. package/dist/tempo/server/Subscription.js +2 -0
  139. package/dist/tempo/server/index.d.ts +1 -1
  140. package/dist/tempo/server/index.js +1 -1
  141. package/dist/tempo/server/internal/html.gen.d.ts +1 -1
  142. package/dist/tempo/server/internal/html.gen.js +1 -1
  143. package/dist/tempo/server/internal/transport.d.ts +2 -0
  144. package/dist/tempo/server/internal/transport.js +9 -2
  145. package/dist/tempo/session/client/ChannelOps.d.ts +18 -3
  146. package/dist/tempo/session/client/ChannelOps.js +35 -6
  147. package/dist/tempo/session/client/ChannelStore.d.ts +0 -5
  148. package/dist/tempo/session/client/ChannelStore.js +2 -2
  149. package/dist/tempo/session/client/CredentialState.d.ts +18 -3
  150. package/dist/tempo/session/client/CredentialState.js +77 -76
  151. package/dist/tempo/session/client/Runtime.d.ts +4 -2
  152. package/dist/tempo/session/client/Runtime.js +21 -5
  153. package/dist/tempo/session/client/Session.d.ts +34 -22
  154. package/dist/tempo/session/client/Session.js +186 -63
  155. package/dist/tempo/session/client/SessionManager.d.ts +3 -1
  156. package/dist/tempo/session/client/SessionManager.js +35 -11
  157. package/dist/tempo/session/client/Transports.d.ts +2 -0
  158. package/dist/tempo/session/client/Transports.js +12 -2
  159. package/dist/tempo/session/precompile/Chain.d.ts +37 -2
  160. package/dist/tempo/session/precompile/Chain.js +116 -15
  161. package/dist/tempo/session/precompile/Protocol.d.ts +15 -0
  162. package/dist/tempo/session/precompile/Protocol.js +7 -0
  163. package/dist/tempo/session/precompile/Voucher.d.ts +7 -5
  164. package/dist/tempo/session/precompile/Voucher.js +6 -12
  165. package/dist/tempo/session/precompile/escrow.abi.d.ts +306 -306
  166. package/dist/tempo/session/server/ChannelStore.d.ts +15 -0
  167. package/dist/tempo/session/server/ChannelStore.js +27 -12
  168. package/dist/tempo/session/server/CredentialVerification.d.ts +39 -20
  169. package/dist/tempo/session/server/CredentialVerification.js +359 -89
  170. package/dist/tempo/session/server/MeteredStream.d.ts +4 -1
  171. package/dist/tempo/session/server/MeteredStream.js +8 -5
  172. package/dist/tempo/session/server/RequestState.d.ts +19 -0
  173. package/dist/tempo/session/server/RequestState.js +61 -15
  174. package/dist/tempo/session/server/Session.d.ts +46 -23
  175. package/dist/tempo/session/server/Session.js +150 -56
  176. package/dist/tempo/session/server/Settlement.d.ts +11 -4
  177. package/dist/tempo/session/server/Settlement.js +53 -21
  178. package/dist/tempo/session/server/Sse.d.ts +3 -1
  179. package/dist/tempo/session/server/Sse.js +2 -1
  180. package/dist/tempo/session/server/Transports.d.ts +1 -1
  181. package/dist/tempo/session/server/Transports.js +1 -0
  182. package/dist/tempo/session/server/Ws.d.ts +6 -1
  183. package/dist/tempo/session/server/Ws.js +1 -0
  184. package/dist/tempo/subscription/KeyAuthorization.d.ts +39 -39
  185. package/dist/web-bot-auth/Constants.d.ts +20 -0
  186. package/dist/web-bot-auth/Constants.js +24 -0
  187. package/dist/web-bot-auth/Types.d.ts +10 -0
  188. package/dist/web-bot-auth/Types.js +2 -0
  189. package/dist/web-bot-auth/client/index.d.ts +29 -0
  190. package/dist/web-bot-auth/client/index.js +64 -0
  191. package/dist/web-bot-auth/index.d.ts +7 -0
  192. package/dist/web-bot-auth/index.js +7 -0
  193. package/dist/web-bot-auth/internal/JwkThumbprint.d.ts +5 -0
  194. package/dist/web-bot-auth/internal/JwkThumbprint.js +20 -0
  195. package/dist/web-bot-auth/internal/SignatureAgent.d.ts +3 -0
  196. package/dist/web-bot-auth/internal/SignatureAgent.js +18 -0
  197. package/dist/web-bot-auth/server/index.d.ts +35 -0
  198. package/dist/web-bot-auth/server/index.js +88 -0
  199. package/dist/x402/Types.d.ts +6 -6
  200. package/dist/x402/client/Exact.d.ts +8 -0
  201. package/dist/x402/client/Exact.js +40 -10
  202. package/dist/x402/server/EvmCharge.d.ts +22 -0
  203. package/dist/x402/server/EvmCharge.js +54 -20
  204. package/package.json +28 -34
  205. package/dist/BodyDigest.d.ts.map +0 -1
  206. package/dist/BodyDigest.js.map +0 -1
  207. package/dist/Challenge.d.ts.map +0 -1
  208. package/dist/Challenge.js.map +0 -1
  209. package/dist/Constants.d.ts.map +0 -1
  210. package/dist/Constants.js.map +0 -1
  211. package/dist/Credential.d.ts.map +0 -1
  212. package/dist/Credential.js.map +0 -1
  213. package/dist/Errors.d.ts.map +0 -1
  214. package/dist/Errors.js.map +0 -1
  215. package/dist/Expires.d.ts.map +0 -1
  216. package/dist/Expires.js.map +0 -1
  217. package/dist/Html.d.ts.map +0 -1
  218. package/dist/Html.js.map +0 -1
  219. package/dist/Mcp.d.ts.map +0 -1
  220. package/dist/Mcp.js.map +0 -1
  221. package/dist/Method.d.ts.map +0 -1
  222. package/dist/Method.js.map +0 -1
  223. package/dist/PaymentRequest.d.ts.map +0 -1
  224. package/dist/PaymentRequest.js.map +0 -1
  225. package/dist/Receipt.d.ts.map +0 -1
  226. package/dist/Receipt.js.map +0 -1
  227. package/dist/Store.d.ts.map +0 -1
  228. package/dist/Store.js.map +0 -1
  229. package/dist/bin.d.ts.map +0 -1
  230. package/dist/bin.js.map +0 -1
  231. package/dist/cli/account.d.ts.map +0 -1
  232. package/dist/cli/account.js.map +0 -1
  233. package/dist/cli/cli.d.ts.map +0 -1
  234. package/dist/cli/cli.js.map +0 -1
  235. package/dist/cli/config.d.ts.map +0 -1
  236. package/dist/cli/config.js.map +0 -1
  237. package/dist/cli/internal.d.ts.map +0 -1
  238. package/dist/cli/internal.js.map +0 -1
  239. package/dist/cli/plugins/evm.d.ts.map +0 -1
  240. package/dist/cli/plugins/evm.js.map +0 -1
  241. package/dist/cli/plugins/index.d.ts.map +0 -1
  242. package/dist/cli/plugins/index.js.map +0 -1
  243. package/dist/cli/plugins/plugin.d.ts.map +0 -1
  244. package/dist/cli/plugins/plugin.js.map +0 -1
  245. package/dist/cli/plugins/stripe.d.ts.map +0 -1
  246. package/dist/cli/plugins/stripe.js.map +0 -1
  247. package/dist/cli/plugins/tempo.d.ts.map +0 -1
  248. package/dist/cli/plugins/tempo.js.map +0 -1
  249. package/dist/cli/sessions/Manager.d.ts.map +0 -1
  250. package/dist/cli/sessions/Manager.js.map +0 -1
  251. package/dist/cli/sessions/commands.d.ts.map +0 -1
  252. package/dist/cli/sessions/commands.js.map +0 -1
  253. package/dist/cli/sessions/request.d.ts.map +0 -1
  254. package/dist/cli/sessions/request.js.map +0 -1
  255. package/dist/cli/sessions/store.d.ts.map +0 -1
  256. package/dist/cli/sessions/store.js.map +0 -1
  257. package/dist/cli/utils.d.ts.map +0 -1
  258. package/dist/cli/utils.js.map +0 -1
  259. package/dist/cli/validate/challenge.d.ts.map +0 -1
  260. package/dist/cli/validate/challenge.js.map +0 -1
  261. package/dist/cli/validate/discovery.d.ts.map +0 -1
  262. package/dist/cli/validate/discovery.js.map +0 -1
  263. package/dist/cli/validate/helpers.d.ts.map +0 -1
  264. package/dist/cli/validate/helpers.js.map +0 -1
  265. package/dist/cli/validate/index.d.ts.map +0 -1
  266. package/dist/cli/validate/index.js.map +0 -1
  267. package/dist/cli/validate/messages.d.ts.map +0 -1
  268. package/dist/cli/validate/messages.js.map +0 -1
  269. package/dist/cli/validate/payment.d.ts.map +0 -1
  270. package/dist/cli/validate/payment.js.map +0 -1
  271. package/dist/client/Methods.d.ts.map +0 -1
  272. package/dist/client/Methods.js.map +0 -1
  273. package/dist/client/Mppx.d.ts.map +0 -1
  274. package/dist/client/Mppx.js.map +0 -1
  275. package/dist/client/Transport.d.ts.map +0 -1
  276. package/dist/client/Transport.js.map +0 -1
  277. package/dist/client/index.d.ts.map +0 -1
  278. package/dist/client/index.js.map +0 -1
  279. package/dist/client/internal/Fetch.d.ts.map +0 -1
  280. package/dist/client/internal/Fetch.js.map +0 -1
  281. package/dist/client/internal/MethodChallenge.d.ts.map +0 -1
  282. package/dist/client/internal/MethodChallenge.js.map +0 -1
  283. package/dist/client/internal/MethodResponse.d.ts.map +0 -1
  284. package/dist/client/internal/MethodResponse.js.map +0 -1
  285. package/dist/client/internal/protocols/Mcp.d.ts.map +0 -1
  286. package/dist/client/internal/protocols/Mcp.js.map +0 -1
  287. package/dist/client/internal/protocols/Mpp.d.ts.map +0 -1
  288. package/dist/client/internal/protocols/Mpp.js.map +0 -1
  289. package/dist/client/internal/protocols/Protocol.d.ts.map +0 -1
  290. package/dist/client/internal/protocols/Protocol.js.map +0 -1
  291. package/dist/client/internal/protocols/Shared.d.ts.map +0 -1
  292. package/dist/client/internal/protocols/Shared.js.map +0 -1
  293. package/dist/client/internal/protocols/X402.d.ts.map +0 -1
  294. package/dist/client/internal/protocols/X402.js.map +0 -1
  295. package/dist/client/node.d.ts.map +0 -1
  296. package/dist/client/node.js.map +0 -1
  297. package/dist/discovery/Discovery.d.ts.map +0 -1
  298. package/dist/discovery/Discovery.js.map +0 -1
  299. package/dist/discovery/OpenApi.d.ts.map +0 -1
  300. package/dist/discovery/OpenApi.js.map +0 -1
  301. package/dist/discovery/Validate.d.ts.map +0 -1
  302. package/dist/discovery/Validate.js.map +0 -1
  303. package/dist/discovery/index.d.ts.map +0 -1
  304. package/dist/discovery/index.js.map +0 -1
  305. package/dist/evm/Assets.d.ts.map +0 -1
  306. package/dist/evm/Assets.js.map +0 -1
  307. package/dist/evm/Chains.d.ts.map +0 -1
  308. package/dist/evm/Chains.js.map +0 -1
  309. package/dist/evm/Methods.d.ts.map +0 -1
  310. package/dist/evm/Methods.js.map +0 -1
  311. package/dist/evm/Types.d.ts.map +0 -1
  312. package/dist/evm/Types.js.map +0 -1
  313. package/dist/evm/client/Charge.d.ts.map +0 -1
  314. package/dist/evm/client/Charge.js.map +0 -1
  315. package/dist/evm/client/Methods.d.ts.map +0 -1
  316. package/dist/evm/client/Methods.js.map +0 -1
  317. package/dist/evm/client/index.d.ts.map +0 -1
  318. package/dist/evm/client/index.js.map +0 -1
  319. package/dist/evm/index.d.ts.map +0 -1
  320. package/dist/evm/index.js.map +0 -1
  321. package/dist/evm/server/Charge.d.ts.map +0 -1
  322. package/dist/evm/server/Charge.js.map +0 -1
  323. package/dist/evm/server/Methods.d.ts.map +0 -1
  324. package/dist/evm/server/Methods.js.map +0 -1
  325. package/dist/evm/server/index.d.ts.map +0 -1
  326. package/dist/evm/server/index.js.map +0 -1
  327. package/dist/index.d.ts.map +0 -1
  328. package/dist/index.js.map +0 -1
  329. package/dist/internal/AcceptPayment.d.ts.map +0 -1
  330. package/dist/internal/AcceptPayment.js.map +0 -1
  331. package/dist/internal/HeaderCodec.d.ts.map +0 -1
  332. package/dist/internal/HeaderCodec.js.map +0 -1
  333. package/dist/internal/constantTimeEqual.d.ts.map +0 -1
  334. package/dist/internal/constantTimeEqual.js.map +0 -1
  335. package/dist/internal/env.d.ts.map +0 -1
  336. package/dist/internal/env.js.map +0 -1
  337. package/dist/internal/types.d.ts.map +0 -1
  338. package/dist/internal/types.js.map +0 -1
  339. package/dist/mcp/client/McpClient.d.ts.map +0 -1
  340. package/dist/mcp/client/McpClient.js.map +0 -1
  341. package/dist/mcp/client/index.d.ts.map +0 -1
  342. package/dist/mcp/client/index.js.map +0 -1
  343. package/dist/mcp/server/Transport.d.ts.map +0 -1
  344. package/dist/mcp/server/Transport.js.map +0 -1
  345. package/dist/mcp/server/index.d.ts.map +0 -1
  346. package/dist/mcp/server/index.js.map +0 -1
  347. package/dist/middlewares/elysia.d.ts.map +0 -1
  348. package/dist/middlewares/elysia.js.map +0 -1
  349. package/dist/middlewares/express.d.ts.map +0 -1
  350. package/dist/middlewares/express.js.map +0 -1
  351. package/dist/middlewares/hono.d.ts.map +0 -1
  352. package/dist/middlewares/hono.js.map +0 -1
  353. package/dist/middlewares/internal/mppx.d.ts.map +0 -1
  354. package/dist/middlewares/internal/mppx.js.map +0 -1
  355. package/dist/middlewares/nextjs.d.ts.map +0 -1
  356. package/dist/middlewares/nextjs.js.map +0 -1
  357. package/dist/proxy/Proxy.d.ts.map +0 -1
  358. package/dist/proxy/Proxy.js.map +0 -1
  359. package/dist/proxy/Service.d.ts.map +0 -1
  360. package/dist/proxy/Service.js.map +0 -1
  361. package/dist/proxy/index.d.ts.map +0 -1
  362. package/dist/proxy/index.js.map +0 -1
  363. package/dist/proxy/internal/Headers.d.ts.map +0 -1
  364. package/dist/proxy/internal/Headers.js.map +0 -1
  365. package/dist/proxy/internal/Route.d.ts.map +0 -1
  366. package/dist/proxy/internal/Route.js.map +0 -1
  367. package/dist/proxy/services/anthropic.d.ts.map +0 -1
  368. package/dist/proxy/services/anthropic.js.map +0 -1
  369. package/dist/proxy/services/openai.d.ts.map +0 -1
  370. package/dist/proxy/services/openai.js.map +0 -1
  371. package/dist/proxy/services/stripe.d.ts.map +0 -1
  372. package/dist/proxy/services/stripe.js.map +0 -1
  373. package/dist/server/Methods.d.ts.map +0 -1
  374. package/dist/server/Methods.js.map +0 -1
  375. package/dist/server/Mppx.d.ts.map +0 -1
  376. package/dist/server/Mppx.js.map +0 -1
  377. package/dist/server/NodeListener.d.ts.map +0 -1
  378. package/dist/server/NodeListener.js.map +0 -1
  379. package/dist/server/Request.d.ts.map +0 -1
  380. package/dist/server/Request.js.map +0 -1
  381. package/dist/server/Response.d.ts.map +0 -1
  382. package/dist/server/Response.js.map +0 -1
  383. package/dist/server/Transport.d.ts.map +0 -1
  384. package/dist/server/Transport.js.map +0 -1
  385. package/dist/server/index.d.ts.map +0 -1
  386. package/dist/server/index.js.map +0 -1
  387. package/dist/server/internal/html/compose.main.gen.d.ts.map +0 -1
  388. package/dist/server/internal/html/compose.main.gen.js.map +0 -1
  389. package/dist/server/internal/html/config.d.ts.map +0 -1
  390. package/dist/server/internal/html/config.js.map +0 -1
  391. package/dist/server/internal/html/constants.d.ts.map +0 -1
  392. package/dist/server/internal/html/constants.js.map +0 -1
  393. package/dist/server/internal/html/serviceWorker.client.d.ts.map +0 -1
  394. package/dist/server/internal/html/serviceWorker.client.js.map +0 -1
  395. package/dist/server/internal/html/serviceWorker.gen.d.ts.map +0 -1
  396. package/dist/server/internal/html/serviceWorker.gen.js.map +0 -1
  397. package/dist/server/internal/scope.d.ts.map +0 -1
  398. package/dist/server/internal/scope.js.map +0 -1
  399. package/dist/stripe/Methods.d.ts.map +0 -1
  400. package/dist/stripe/Methods.js.map +0 -1
  401. package/dist/stripe/client/Charge.d.ts.map +0 -1
  402. package/dist/stripe/client/Charge.js.map +0 -1
  403. package/dist/stripe/client/Methods.d.ts.map +0 -1
  404. package/dist/stripe/client/Methods.js.map +0 -1
  405. package/dist/stripe/client/index.d.ts.map +0 -1
  406. package/dist/stripe/client/index.js.map +0 -1
  407. package/dist/stripe/index.d.ts.map +0 -1
  408. package/dist/stripe/index.js.map +0 -1
  409. package/dist/stripe/internal/constants.d.ts.map +0 -1
  410. package/dist/stripe/internal/constants.js.map +0 -1
  411. package/dist/stripe/internal/types.d.ts.map +0 -1
  412. package/dist/stripe/internal/types.js.map +0 -1
  413. package/dist/stripe/server/Charge.d.ts.map +0 -1
  414. package/dist/stripe/server/Charge.js.map +0 -1
  415. package/dist/stripe/server/Methods.d.ts.map +0 -1
  416. package/dist/stripe/server/Methods.js.map +0 -1
  417. package/dist/stripe/server/index.d.ts.map +0 -1
  418. package/dist/stripe/server/index.js.map +0 -1
  419. package/dist/stripe/server/internal/html/types.d.ts.map +0 -1
  420. package/dist/stripe/server/internal/html/types.js.map +0 -1
  421. package/dist/stripe/server/internal/html.gen.d.ts.map +0 -1
  422. package/dist/stripe/server/internal/html.gen.js.map +0 -1
  423. package/dist/tempo/Attribution.d.ts.map +0 -1
  424. package/dist/tempo/Attribution.js.map +0 -1
  425. package/dist/tempo/Methods.d.ts.map +0 -1
  426. package/dist/tempo/Methods.js.map +0 -1
  427. package/dist/tempo/Proof.d.ts.map +0 -1
  428. package/dist/tempo/Proof.js.map +0 -1
  429. package/dist/tempo/client/Charge.d.ts.map +0 -1
  430. package/dist/tempo/client/Charge.js.map +0 -1
  431. package/dist/tempo/client/Methods.d.ts.map +0 -1
  432. package/dist/tempo/client/Methods.js.map +0 -1
  433. package/dist/tempo/client/ResolveAccount.d.ts.map +0 -1
  434. package/dist/tempo/client/ResolveAccount.js.map +0 -1
  435. package/dist/tempo/client/Subscription.d.ts.map +0 -1
  436. package/dist/tempo/client/Subscription.js.map +0 -1
  437. package/dist/tempo/client/index.d.ts.map +0 -1
  438. package/dist/tempo/client/index.js.map +0 -1
  439. package/dist/tempo/index.d.ts.map +0 -1
  440. package/dist/tempo/index.js.map +0 -1
  441. package/dist/tempo/internal/account.d.ts.map +0 -1
  442. package/dist/tempo/internal/account.js.map +0 -1
  443. package/dist/tempo/internal/address.d.ts.map +0 -1
  444. package/dist/tempo/internal/address.js.map +0 -1
  445. package/dist/tempo/internal/auto-swap.d.ts.map +0 -1
  446. package/dist/tempo/internal/auto-swap.js.map +0 -1
  447. package/dist/tempo/internal/charge.d.ts.map +0 -1
  448. package/dist/tempo/internal/charge.js.map +0 -1
  449. package/dist/tempo/internal/defaults.d.ts.map +0 -1
  450. package/dist/tempo/internal/defaults.js.map +0 -1
  451. package/dist/tempo/internal/fee-payer.d.ts.map +0 -1
  452. package/dist/tempo/internal/fee-payer.js.map +0 -1
  453. package/dist/tempo/internal/fee-token.d.ts.map +0 -1
  454. package/dist/tempo/internal/fee-token.js.map +0 -1
  455. package/dist/tempo/internal/proof.d.ts.map +0 -1
  456. package/dist/tempo/internal/proof.js.map +0 -1
  457. package/dist/tempo/internal/selectors.d.ts.map +0 -1
  458. package/dist/tempo/internal/selectors.js.map +0 -1
  459. package/dist/tempo/internal/types.d.ts.map +0 -1
  460. package/dist/tempo/internal/types.js.map +0 -1
  461. package/dist/tempo/legacy/client/ChannelOps.d.ts.map +0 -1
  462. package/dist/tempo/legacy/client/ChannelOps.js.map +0 -1
  463. package/dist/tempo/legacy/client/Session.d.ts.map +0 -1
  464. package/dist/tempo/legacy/client/Session.js.map +0 -1
  465. package/dist/tempo/legacy/client/SessionManager.d.ts.map +0 -1
  466. package/dist/tempo/legacy/client/SessionManager.js.map +0 -1
  467. package/dist/tempo/legacy/client/index.d.ts.map +0 -1
  468. package/dist/tempo/legacy/client/index.js.map +0 -1
  469. package/dist/tempo/legacy/index.d.ts.map +0 -1
  470. package/dist/tempo/legacy/index.js.map +0 -1
  471. package/dist/tempo/legacy/server/Session.d.ts +0 -208
  472. package/dist/tempo/legacy/server/Session.d.ts.map +0 -1
  473. package/dist/tempo/legacy/server/Session.js +0 -698
  474. package/dist/tempo/legacy/server/Session.js.map +0 -1
  475. package/dist/tempo/legacy/server/index.d.ts +0 -5
  476. package/dist/tempo/legacy/server/index.d.ts.map +0 -1
  477. package/dist/tempo/legacy/server/index.js +0 -5
  478. package/dist/tempo/legacy/server/index.js.map +0 -1
  479. package/dist/tempo/legacy/session/Chain.d.ts.map +0 -1
  480. package/dist/tempo/legacy/session/Chain.js.map +0 -1
  481. package/dist/tempo/legacy/session/Channel.d.ts.map +0 -1
  482. package/dist/tempo/legacy/session/Channel.js.map +0 -1
  483. package/dist/tempo/legacy/session/ChannelStore.d.ts +0 -22
  484. package/dist/tempo/legacy/session/ChannelStore.d.ts.map +0 -1
  485. package/dist/tempo/legacy/session/ChannelStore.js +0 -6
  486. package/dist/tempo/legacy/session/ChannelStore.js.map +0 -1
  487. package/dist/tempo/legacy/session/Types.d.ts.map +0 -1
  488. package/dist/tempo/legacy/session/Types.js.map +0 -1
  489. package/dist/tempo/legacy/session/Voucher.d.ts.map +0 -1
  490. package/dist/tempo/legacy/session/Voucher.js.map +0 -1
  491. package/dist/tempo/legacy/session/escrow.abi.d.ts.map +0 -1
  492. package/dist/tempo/legacy/session/escrow.abi.js.map +0 -1
  493. package/dist/tempo/legacy/session/index.d.ts.map +0 -1
  494. package/dist/tempo/legacy/session/index.js.map +0 -1
  495. package/dist/tempo/server/Charge.d.ts.map +0 -1
  496. package/dist/tempo/server/Charge.js.map +0 -1
  497. package/dist/tempo/server/Methods.d.ts.map +0 -1
  498. package/dist/tempo/server/Methods.js.map +0 -1
  499. package/dist/tempo/server/Relay.d.ts.map +0 -1
  500. package/dist/tempo/server/Relay.js.map +0 -1
  501. package/dist/tempo/server/SponsorBudget.d.ts.map +0 -1
  502. package/dist/tempo/server/SponsorBudget.js.map +0 -1
  503. package/dist/tempo/server/Subscription.d.ts.map +0 -1
  504. package/dist/tempo/server/Subscription.js.map +0 -1
  505. package/dist/tempo/server/index.d.ts.map +0 -1
  506. package/dist/tempo/server/index.js.map +0 -1
  507. package/dist/tempo/server/internal/html.gen.d.ts.map +0 -1
  508. package/dist/tempo/server/internal/html.gen.js.map +0 -1
  509. package/dist/tempo/server/internal/request-body.d.ts.map +0 -1
  510. package/dist/tempo/server/internal/request-body.js.map +0 -1
  511. package/dist/tempo/server/internal/transport.d.ts.map +0 -1
  512. package/dist/tempo/server/internal/transport.js.map +0 -1
  513. package/dist/tempo/session/Snapshot.d.ts.map +0 -1
  514. package/dist/tempo/session/Snapshot.js.map +0 -1
  515. package/dist/tempo/session/client/ChannelOps.d.ts.map +0 -1
  516. package/dist/tempo/session/client/ChannelOps.js.map +0 -1
  517. package/dist/tempo/session/client/ChannelStore.d.ts.map +0 -1
  518. package/dist/tempo/session/client/ChannelStore.js.map +0 -1
  519. package/dist/tempo/session/client/CredentialState.d.ts.map +0 -1
  520. package/dist/tempo/session/client/CredentialState.js.map +0 -1
  521. package/dist/tempo/session/client/ReceiptCoordinator.d.ts.map +0 -1
  522. package/dist/tempo/session/client/ReceiptCoordinator.js.map +0 -1
  523. package/dist/tempo/session/client/Runtime.d.ts.map +0 -1
  524. package/dist/tempo/session/client/Runtime.js.map +0 -1
  525. package/dist/tempo/session/client/Session.d.ts.map +0 -1
  526. package/dist/tempo/session/client/Session.js.map +0 -1
  527. package/dist/tempo/session/client/SessionManager.d.ts.map +0 -1
  528. package/dist/tempo/session/client/SessionManager.js.map +0 -1
  529. package/dist/tempo/session/client/Transports.d.ts.map +0 -1
  530. package/dist/tempo/session/client/Transports.js.map +0 -1
  531. package/dist/tempo/session/client/index.d.ts.map +0 -1
  532. package/dist/tempo/session/client/index.js.map +0 -1
  533. package/dist/tempo/session/client/internal/SessionManager.d.ts.map +0 -1
  534. package/dist/tempo/session/client/internal/SessionManager.js.map +0 -1
  535. package/dist/tempo/session/index.d.ts.map +0 -1
  536. package/dist/tempo/session/index.js.map +0 -1
  537. package/dist/tempo/session/precompile/Chain.d.ts.map +0 -1
  538. package/dist/tempo/session/precompile/Chain.js.map +0 -1
  539. package/dist/tempo/session/precompile/Channel.d.ts.map +0 -1
  540. package/dist/tempo/session/precompile/Channel.js.map +0 -1
  541. package/dist/tempo/session/precompile/Protocol.d.ts.map +0 -1
  542. package/dist/tempo/session/precompile/Protocol.js.map +0 -1
  543. package/dist/tempo/session/precompile/Voucher.d.ts.map +0 -1
  544. package/dist/tempo/session/precompile/Voucher.js.map +0 -1
  545. package/dist/tempo/session/precompile/escrow.abi.d.ts.map +0 -1
  546. package/dist/tempo/session/precompile/escrow.abi.js.map +0 -1
  547. package/dist/tempo/session/precompile/index.d.ts.map +0 -1
  548. package/dist/tempo/session/precompile/index.js.map +0 -1
  549. package/dist/tempo/session/server/ChannelOps.d.ts.map +0 -1
  550. package/dist/tempo/session/server/ChannelOps.js.map +0 -1
  551. package/dist/tempo/session/server/ChannelStore.d.ts.map +0 -1
  552. package/dist/tempo/session/server/ChannelStore.js.map +0 -1
  553. package/dist/tempo/session/server/CredentialVerification.d.ts.map +0 -1
  554. package/dist/tempo/session/server/CredentialVerification.js.map +0 -1
  555. package/dist/tempo/session/server/MeteredStream.d.ts.map +0 -1
  556. package/dist/tempo/session/server/MeteredStream.js.map +0 -1
  557. package/dist/tempo/session/server/RequestState.d.ts.map +0 -1
  558. package/dist/tempo/session/server/RequestState.js.map +0 -1
  559. package/dist/tempo/session/server/Session.d.ts.map +0 -1
  560. package/dist/tempo/session/server/Session.js.map +0 -1
  561. package/dist/tempo/session/server/Settlement.d.ts.map +0 -1
  562. package/dist/tempo/session/server/Settlement.js.map +0 -1
  563. package/dist/tempo/session/server/Sse.d.ts.map +0 -1
  564. package/dist/tempo/session/server/Sse.js.map +0 -1
  565. package/dist/tempo/session/server/Transports.d.ts.map +0 -1
  566. package/dist/tempo/session/server/Transports.js.map +0 -1
  567. package/dist/tempo/session/server/Ws.d.ts.map +0 -1
  568. package/dist/tempo/session/server/Ws.js.map +0 -1
  569. package/dist/tempo/session/server/index.d.ts.map +0 -1
  570. package/dist/tempo/session/server/index.js.map +0 -1
  571. package/dist/tempo/subscription/KeyAuthorization.d.ts.map +0 -1
  572. package/dist/tempo/subscription/KeyAuthorization.js.map +0 -1
  573. package/dist/tempo/subscription/Receipt.d.ts.map +0 -1
  574. package/dist/tempo/subscription/Receipt.js.map +0 -1
  575. package/dist/tempo/subscription/Store.d.ts.map +0 -1
  576. package/dist/tempo/subscription/Store.js.map +0 -1
  577. package/dist/tempo/subscription/Types.d.ts.map +0 -1
  578. package/dist/tempo/subscription/Types.js.map +0 -1
  579. package/dist/tempo/subscription/index.d.ts.map +0 -1
  580. package/dist/tempo/subscription/index.js.map +0 -1
  581. package/dist/validation/core.d.ts.map +0 -1
  582. package/dist/validation/core.js.map +0 -1
  583. package/dist/validation/index.d.ts.map +0 -1
  584. package/dist/validation/index.js.map +0 -1
  585. package/dist/viem/Account.d.ts.map +0 -1
  586. package/dist/viem/Account.js.map +0 -1
  587. package/dist/viem/Client.d.ts.map +0 -1
  588. package/dist/viem/Client.js.map +0 -1
  589. package/dist/x402/Assets.d.ts.map +0 -1
  590. package/dist/x402/Assets.js.map +0 -1
  591. package/dist/x402/Header.d.ts.map +0 -1
  592. package/dist/x402/Header.js.map +0 -1
  593. package/dist/x402/Types.d.ts.map +0 -1
  594. package/dist/x402/Types.js.map +0 -1
  595. package/dist/x402/client/Exact.d.ts.map +0 -1
  596. package/dist/x402/client/Exact.js.map +0 -1
  597. package/dist/x402/index.d.ts.map +0 -1
  598. package/dist/x402/index.js.map +0 -1
  599. package/dist/x402/internal/ChallengeBrand.d.ts.map +0 -1
  600. package/dist/x402/internal/ChallengeBrand.js.map +0 -1
  601. package/dist/x402/internal/RouteBinding.d.ts.map +0 -1
  602. package/dist/x402/internal/RouteBinding.js.map +0 -1
  603. package/dist/x402/server/EvmCharge.d.ts.map +0 -1
  604. package/dist/x402/server/EvmCharge.js.map +0 -1
  605. package/dist/x402/server/Facilitator.d.ts.map +0 -1
  606. package/dist/x402/server/Facilitator.js.map +0 -1
  607. package/dist/zod.d.ts.map +0 -1
  608. package/dist/zod.js.map +0 -1
  609. package/src/BodyDigest.test.ts +0 -43
  610. package/src/BodyDigest.ts +0 -55
  611. package/src/Challenge.fuzz.test.ts +0 -121
  612. package/src/Challenge.test-d.ts +0 -82
  613. package/src/Challenge.test.ts +0 -995
  614. package/src/Challenge.ts +0 -683
  615. package/src/Constants.ts +0 -58
  616. package/src/Credential.fuzz.test.ts +0 -62
  617. package/src/Credential.test.ts +0 -378
  618. package/src/Credential.ts +0 -217
  619. package/src/Errors.test.ts +0 -520
  620. package/src/Errors.ts +0 -448
  621. package/src/Expires.test.ts +0 -112
  622. package/src/Expires.ts +0 -59
  623. package/src/Html.ts +0 -67
  624. package/src/Mcp.ts +0 -85
  625. package/src/Method.test.ts +0 -177
  626. package/src/Method.ts +0 -617
  627. package/src/PaymentRequest.test.ts +0 -147
  628. package/src/PaymentRequest.ts +0 -108
  629. package/src/Receipt.test.ts +0 -151
  630. package/src/Receipt.ts +0 -146
  631. package/src/Store.test-d.ts +0 -195
  632. package/src/Store.test.ts +0 -357
  633. package/src/Store.ts +0 -329
  634. package/src/bin.ts +0 -4
  635. package/src/cli/account.ts +0 -269
  636. package/src/cli/cli.test.ts +0 -2221
  637. package/src/cli/cli.ts +0 -1649
  638. package/src/cli/config.test.ts +0 -89
  639. package/src/cli/config.ts +0 -50
  640. package/src/cli/internal.ts +0 -114
  641. package/src/cli/mcp.test.ts +0 -262
  642. package/src/cli/plugins/evm.ts +0 -55
  643. package/src/cli/plugins/index.ts +0 -4
  644. package/src/cli/plugins/plugin.ts +0 -84
  645. package/src/cli/plugins/stripe.ts +0 -174
  646. package/src/cli/plugins/tempo.ts +0 -1102
  647. package/src/cli/sessions/Manager.test.ts +0 -249
  648. package/src/cli/sessions/Manager.ts +0 -93
  649. package/src/cli/sessions/commands.ts +0 -444
  650. package/src/cli/sessions/request.test.ts +0 -51
  651. package/src/cli/sessions/request.ts +0 -353
  652. package/src/cli/sessions/store.test.ts +0 -581
  653. package/src/cli/sessions/store.ts +0 -940
  654. package/src/cli/utils.test.ts +0 -156
  655. package/src/cli/utils.ts +0 -394
  656. package/src/cli/validate/challenge.ts +0 -565
  657. package/src/cli/validate/discovery.test.ts +0 -435
  658. package/src/cli/validate/discovery.ts +0 -221
  659. package/src/cli/validate/helpers.ts +0 -166
  660. package/src/cli/validate/index.ts +0 -229
  661. package/src/cli/validate/messages.ts +0 -7
  662. package/src/cli/validate/payment.ts +0 -774
  663. package/src/cli/validate.test.ts +0 -843
  664. package/src/client/Methods.ts +0 -8
  665. package/src/client/Mppx.test-d.ts +0 -270
  666. package/src/client/Mppx.test.ts +0 -1065
  667. package/src/client/Mppx.ts +0 -466
  668. package/src/client/Transport.test.ts +0 -619
  669. package/src/client/Transport.ts +0 -191
  670. package/src/client/index.ts +0 -29
  671. package/src/client/internal/Fetch.browser.test.ts +0 -197
  672. package/src/client/internal/Fetch.test-d.ts +0 -109
  673. package/src/client/internal/Fetch.test.ts +0 -2336
  674. package/src/client/internal/Fetch.ts +0 -1079
  675. package/src/client/internal/MethodChallenge.ts +0 -35
  676. package/src/client/internal/MethodResponse.ts +0 -67
  677. package/src/client/internal/protocols/Mcp.test.ts +0 -220
  678. package/src/client/internal/protocols/Mcp.ts +0 -186
  679. package/src/client/internal/protocols/Mpp.ts +0 -21
  680. package/src/client/internal/protocols/Protocol.ts +0 -10
  681. package/src/client/internal/protocols/Shared.ts +0 -25
  682. package/src/client/internal/protocols/X402.ts +0 -46
  683. package/src/client/node.test.ts +0 -115
  684. package/src/client/node.ts +0 -247
  685. package/src/discovery/Discovery.test.ts +0 -214
  686. package/src/discovery/Discovery.ts +0 -105
  687. package/src/discovery/OpenApi.test.ts +0 -453
  688. package/src/discovery/OpenApi.ts +0 -224
  689. package/src/discovery/Validate.test.ts +0 -305
  690. package/src/discovery/Validate.ts +0 -77
  691. package/src/discovery/index.ts +0 -3
  692. package/src/env.d.ts +0 -12
  693. package/src/evm/Assets.ts +0 -1
  694. package/src/evm/Chains.ts +0 -11
  695. package/src/evm/Methods.ts +0 -44
  696. package/src/evm/PublicInterface.test-d.ts +0 -134
  697. package/src/evm/Types.ts +0 -140
  698. package/src/evm/client/Charge.test.ts +0 -347
  699. package/src/evm/client/Charge.ts +0 -187
  700. package/src/evm/client/Methods.ts +0 -19
  701. package/src/evm/client/index.ts +0 -6
  702. package/src/evm/index.ts +0 -16
  703. package/src/evm/server/Charge.test.ts +0 -339
  704. package/src/evm/server/Charge.ts +0 -290
  705. package/src/evm/server/Methods.ts +0 -22
  706. package/src/evm/server/index.ts +0 -6
  707. package/src/index.ts +0 -14
  708. package/src/internal/AcceptPayment.test.ts +0 -343
  709. package/src/internal/AcceptPayment.ts +0 -366
  710. package/src/internal/HeaderCodec.ts +0 -36
  711. package/src/internal/changeset.test.ts +0 -106
  712. package/src/internal/constantTimeEqual.test.ts +0 -47
  713. package/src/internal/constantTimeEqual.ts +0 -10
  714. package/src/internal/env.test.ts +0 -42
  715. package/src/internal/env.ts +0 -49
  716. package/src/internal/types.test-d.ts +0 -21
  717. package/src/internal/types.ts +0 -470
  718. package/src/mcp/client/McpClient.integration.test.ts +0 -652
  719. package/src/mcp/client/McpClient.test-d.ts +0 -144
  720. package/src/mcp/client/McpClient.test.ts +0 -463
  721. package/src/mcp/client/McpClient.ts +0 -307
  722. package/src/mcp/client/McpClient.unit.test.ts +0 -135
  723. package/src/mcp/client/index.ts +0 -2
  724. package/src/mcp/server/Transport.test.ts +0 -191
  725. package/src/mcp/server/Transport.ts +0 -111
  726. package/src/mcp/server/index.ts +0 -1
  727. package/src/middlewares/elysia.test.ts +0 -295
  728. package/src/middlewares/elysia.ts +0 -116
  729. package/src/middlewares/express.test.ts +0 -371
  730. package/src/middlewares/express.ts +0 -140
  731. package/src/middlewares/hono.test.ts +0 -476
  732. package/src/middlewares/hono.ts +0 -153
  733. package/src/middlewares/internal/mppx.test.ts +0 -177
  734. package/src/middlewares/internal/mppx.ts +0 -67
  735. package/src/middlewares/nextjs.test.ts +0 -369
  736. package/src/middlewares/nextjs.ts +0 -107
  737. package/src/proxy/Proxy.test.ts +0 -1031
  738. package/src/proxy/Proxy.ts +0 -345
  739. package/src/proxy/Service.test.ts +0 -182
  740. package/src/proxy/Service.ts +0 -253
  741. package/src/proxy/index.ts +0 -6
  742. package/src/proxy/internal/Headers.test.ts +0 -139
  743. package/src/proxy/internal/Headers.ts +0 -66
  744. package/src/proxy/internal/Route.test.ts +0 -217
  745. package/src/proxy/internal/Route.ts +0 -64
  746. package/src/proxy/services/anthropic.test.ts +0 -132
  747. package/src/proxy/services/anthropic.ts +0 -52
  748. package/src/proxy/services/openai.test.ts +0 -157
  749. package/src/proxy/services/openai.ts +0 -59
  750. package/src/proxy/services/stripe.test.ts +0 -175
  751. package/src/proxy/services/stripe.ts +0 -58
  752. package/src/server/Methods.ts +0 -3
  753. package/src/server/Mppx.authorize.test.ts +0 -210
  754. package/src/server/Mppx.test-d.ts +0 -360
  755. package/src/server/Mppx.test.ts +0 -5813
  756. package/src/server/Mppx.ts +0 -2623
  757. package/src/server/NodeListener.test.ts +0 -293
  758. package/src/server/NodeListener.ts +0 -45
  759. package/src/server/Request.test.ts +0 -255
  760. package/src/server/Request.ts +0 -155
  761. package/src/server/Response.test.ts +0 -32
  762. package/src/server/Response.ts +0 -45
  763. package/src/server/Transport.test.ts +0 -598
  764. package/src/server/Transport.ts +0 -320
  765. package/src/server/index.ts +0 -9
  766. package/src/server/internal/html/compose.main.gen.ts +0 -2
  767. package/src/server/internal/html/compose.main.ts +0 -88
  768. package/src/server/internal/html/config.ts +0 -672
  769. package/src/server/internal/html/constants.ts +0 -28
  770. package/src/server/internal/html/serviceWorker.client.ts +0 -28
  771. package/src/server/internal/html/serviceWorker.gen.ts +0 -2
  772. package/src/server/internal/html/serviceWorker.ts +0 -27
  773. package/src/server/internal/html/tsconfig.compose.json +0 -8
  774. package/src/server/internal/html/tsconfig.worker.client.json +0 -8
  775. package/src/server/internal/html/tsconfig.worker.json +0 -8
  776. package/src/server/internal/scope.ts +0 -43
  777. package/src/stripe/Charge.integration.test.ts +0 -329
  778. package/src/stripe/Methods.test.ts +0 -62
  779. package/src/stripe/Methods.ts +0 -44
  780. package/src/stripe/client/Charge.test.ts +0 -205
  781. package/src/stripe/client/Charge.ts +0 -132
  782. package/src/stripe/client/Methods.ts +0 -37
  783. package/src/stripe/client/index.ts +0 -2
  784. package/src/stripe/index.ts +0 -1
  785. package/src/stripe/internal/constants.ts +0 -7
  786. package/src/stripe/internal/types.ts +0 -46
  787. package/src/stripe/server/Charge.test-d.ts +0 -66
  788. package/src/stripe/server/Charge.test.ts +0 -621
  789. package/src/stripe/server/Charge.ts +0 -434
  790. package/src/stripe/server/Methods.ts +0 -24
  791. package/src/stripe/server/index.ts +0 -2
  792. package/src/stripe/server/internal/html/main.ts +0 -165
  793. package/src/stripe/server/internal/html/node_modules/.bin/mppx +0 -22
  794. package/src/stripe/server/internal/html/node_modules/.bin/mppx.src +0 -22
  795. package/src/stripe/server/internal/html/package.json +0 -9
  796. package/src/stripe/server/internal/html/stripe-js-pure.d.ts +0 -7
  797. package/src/stripe/server/internal/html/tsconfig.json +0 -8
  798. package/src/stripe/server/internal/html/types.ts +0 -5
  799. package/src/stripe/server/internal/html.gen.ts +0 -2
  800. package/src/tempo/AccessKeyAuthorization.test.ts +0 -141
  801. package/src/tempo/Attribution.test.ts +0 -294
  802. package/src/tempo/Attribution.ts +0 -185
  803. package/src/tempo/Methods.test.ts +0 -425
  804. package/src/tempo/Methods.ts +0 -367
  805. package/src/tempo/Proof.conformance.test.ts +0 -146
  806. package/src/tempo/Proof.test-d.ts +0 -32
  807. package/src/tempo/Proof.test.ts +0 -40
  808. package/src/tempo/Proof.ts +0 -69
  809. package/src/tempo/PublicExports.test-d.ts +0 -130
  810. package/src/tempo/Subscription.integration.test.ts +0 -591
  811. package/src/tempo/client/Charge.test.ts +0 -501
  812. package/src/tempo/client/Charge.ts +0 -289
  813. package/src/tempo/client/Methods.ts +0 -45
  814. package/src/tempo/client/ResolveAccount.ts +0 -46
  815. package/src/tempo/client/Subscription.test.ts +0 -180
  816. package/src/tempo/client/Subscription.ts +0 -156
  817. package/src/tempo/client/index.ts +0 -17
  818. package/src/tempo/index.ts +0 -5
  819. package/src/tempo/internal/account.ts +0 -56
  820. package/src/tempo/internal/address.ts +0 -6
  821. package/src/tempo/internal/auto-swap.test.ts +0 -198
  822. package/src/tempo/internal/auto-swap.ts +0 -188
  823. package/src/tempo/internal/charge.test.ts +0 -66
  824. package/src/tempo/internal/charge.ts +0 -43
  825. package/src/tempo/internal/defaults.test.ts +0 -95
  826. package/src/tempo/internal/defaults.ts +0 -53
  827. package/src/tempo/internal/fee-payer.test.ts +0 -1177
  828. package/src/tempo/internal/fee-payer.ts +0 -808
  829. package/src/tempo/internal/fee-token.test.ts +0 -165
  830. package/src/tempo/internal/fee-token.ts +0 -72
  831. package/src/tempo/internal/proof.test.ts +0 -97
  832. package/src/tempo/internal/proof.ts +0 -87
  833. package/src/tempo/internal/selectors.ts +0 -10
  834. package/src/tempo/internal/types.ts +0 -19
  835. package/src/tempo/legacy/AccessKeyAuthorization.test.ts +0 -162
  836. package/src/tempo/legacy/README.md +0 -9
  837. package/src/tempo/legacy/client/ChannelOps.test.ts +0 -379
  838. package/src/tempo/legacy/client/ChannelOps.ts +0 -271
  839. package/src/tempo/legacy/client/Session.test.ts +0 -800
  840. package/src/tempo/legacy/client/Session.ts +0 -397
  841. package/src/tempo/legacy/client/SessionManager.test.ts +0 -468
  842. package/src/tempo/legacy/client/SessionManager.ts +0 -909
  843. package/src/tempo/legacy/client/index.ts +0 -6
  844. package/src/tempo/legacy/index.ts +0 -6
  845. package/src/tempo/legacy/server/Defaults.test-d.ts +0 -9
  846. package/src/tempo/legacy/server/Session.test.ts +0 -6370
  847. package/src/tempo/legacy/server/Session.ts +0 -1024
  848. package/src/tempo/legacy/server/index.ts +0 -4
  849. package/src/tempo/legacy/session/Chain.test.ts +0 -1349
  850. package/src/tempo/legacy/session/Chain.ts +0 -830
  851. package/src/tempo/legacy/session/Channel.test.ts +0 -109
  852. package/src/tempo/legacy/session/Channel.ts +0 -51
  853. package/src/tempo/legacy/session/ChannelStore.test.ts +0 -58
  854. package/src/tempo/legacy/session/ChannelStore.ts +0 -39
  855. package/src/tempo/legacy/session/Types.ts +0 -91
  856. package/src/tempo/legacy/session/Voucher.test.ts +0 -410
  857. package/src/tempo/legacy/session/Voucher.ts +0 -183
  858. package/src/tempo/legacy/session/escrow.abi.ts +0 -760
  859. package/src/tempo/legacy/session/index.ts +0 -8
  860. package/src/tempo/server/AtomicStore.test-d.ts +0 -50
  861. package/src/tempo/server/Charge.test.ts +0 -6121
  862. package/src/tempo/server/Charge.ts +0 -1351
  863. package/src/tempo/server/Methods.ts +0 -106
  864. package/src/tempo/server/Relay.test.ts +0 -677
  865. package/src/tempo/server/Relay.ts +0 -297
  866. package/src/tempo/server/SponsorBudget.test.ts +0 -154
  867. package/src/tempo/server/SponsorBudget.ts +0 -219
  868. package/src/tempo/server/Sse.test.ts +0 -321
  869. package/src/tempo/server/Subscription.test.ts +0 -1944
  870. package/src/tempo/server/Subscription.ts +0 -1333
  871. package/src/tempo/server/index.ts +0 -12
  872. package/src/tempo/server/internal/html/main.ts +0 -115
  873. package/src/tempo/server/internal/html/node_modules/.bin/mppx +0 -22
  874. package/src/tempo/server/internal/html/node_modules/.bin/mppx.src +0 -22
  875. package/src/tempo/server/internal/html/package.json +0 -10
  876. package/src/tempo/server/internal/html/tsconfig.json +0 -8
  877. package/src/tempo/server/internal/html.gen.ts +0 -2
  878. package/src/tempo/server/internal/request-body.test.ts +0 -210
  879. package/src/tempo/server/internal/request-body.ts +0 -61
  880. package/src/tempo/server/internal/transport.test.ts +0 -903
  881. package/src/tempo/server/internal/transport.ts +0 -310
  882. package/src/tempo/session/README.md +0 -208
  883. package/src/tempo/session/Snapshot.test.ts +0 -41
  884. package/src/tempo/session/Snapshot.ts +0 -95
  885. package/src/tempo/session/client/ChannelOps.test.ts +0 -218
  886. package/src/tempo/session/client/ChannelOps.ts +0 -348
  887. package/src/tempo/session/client/ChannelStore.ts +0 -111
  888. package/src/tempo/session/client/CredentialState.test.ts +0 -789
  889. package/src/tempo/session/client/CredentialState.ts +0 -942
  890. package/src/tempo/session/client/ReceiptCoordinator.ts +0 -95
  891. package/src/tempo/session/client/Runtime.test.ts +0 -1104
  892. package/src/tempo/session/client/Runtime.ts +0 -1008
  893. package/src/tempo/session/client/Session.test.ts +0 -1355
  894. package/src/tempo/session/client/Session.ts +0 -420
  895. package/src/tempo/session/client/SessionManager.test.ts +0 -1899
  896. package/src/tempo/session/client/SessionManager.ts +0 -996
  897. package/src/tempo/session/client/Transports.test.ts +0 -1141
  898. package/src/tempo/session/client/Transports.ts +0 -1534
  899. package/src/tempo/session/client/index.ts +0 -40
  900. package/src/tempo/session/client/internal/SessionManager.ts +0 -36
  901. package/src/tempo/session/index.ts +0 -7
  902. package/src/tempo/session/precompile/Chain.integration.test.ts +0 -339
  903. package/src/tempo/session/precompile/Chain.test.ts +0 -1641
  904. package/src/tempo/session/precompile/Chain.ts +0 -1149
  905. package/src/tempo/session/precompile/Channel.test.ts +0 -147
  906. package/src/tempo/session/precompile/Channel.ts +0 -108
  907. package/src/tempo/session/precompile/Protocol.test.ts +0 -358
  908. package/src/tempo/session/precompile/Protocol.ts +0 -520
  909. package/src/tempo/session/precompile/Voucher.test.ts +0 -354
  910. package/src/tempo/session/precompile/Voucher.ts +0 -162
  911. package/src/tempo/session/precompile/escrow.abi.ts +0 -226
  912. package/src/tempo/session/precompile/index.ts +0 -33
  913. package/src/tempo/session/server/ChannelOps.test.ts +0 -129
  914. package/src/tempo/session/server/ChannelOps.ts +0 -157
  915. package/src/tempo/session/server/ChannelStore.test.ts +0 -1093
  916. package/src/tempo/session/server/ChannelStore.ts +0 -835
  917. package/src/tempo/session/server/CredentialVerification.test.ts +0 -299
  918. package/src/tempo/session/server/CredentialVerification.ts +0 -775
  919. package/src/tempo/session/server/MeteredStream.ts +0 -95
  920. package/src/tempo/session/server/RequestState.test.ts +0 -574
  921. package/src/tempo/session/server/RequestState.ts +0 -507
  922. package/src/tempo/session/server/Session.integration.test.ts +0 -449
  923. package/src/tempo/session/server/Session.test.ts +0 -3862
  924. package/src/tempo/session/server/Session.ts +0 -570
  925. package/src/tempo/session/server/Settlement.test.ts +0 -345
  926. package/src/tempo/session/server/Settlement.ts +0 -527
  927. package/src/tempo/session/server/Sse.fuzz.test.ts +0 -138
  928. package/src/tempo/session/server/Sse.test.ts +0 -557
  929. package/src/tempo/session/server/Sse.ts +0 -254
  930. package/src/tempo/session/server/Transports.test.ts +0 -346
  931. package/src/tempo/session/server/Transports.ts +0 -255
  932. package/src/tempo/session/server/Ws.test.ts +0 -594
  933. package/src/tempo/session/server/Ws.ts +0 -385
  934. package/src/tempo/session/server/index.ts +0 -12
  935. package/src/tempo/subscription/KeyAuthorization.test.ts +0 -282
  936. package/src/tempo/subscription/KeyAuthorization.ts +0 -396
  937. package/src/tempo/subscription/Receipt.ts +0 -28
  938. package/src/tempo/subscription/Store.test.ts +0 -609
  939. package/src/tempo/subscription/Store.ts +0 -449
  940. package/src/tempo/subscription/Types.ts +0 -68
  941. package/src/tempo/subscription/index.ts +0 -23
  942. package/src/tsconfig.json +0 -10
  943. package/src/validation/core.ts +0 -386
  944. package/src/validation/index.ts +0 -11
  945. package/src/viem/Account.test.ts +0 -72
  946. package/src/viem/Account.ts +0 -30
  947. package/src/viem/Client.test.ts +0 -366
  948. package/src/viem/Client.ts +0 -93
  949. package/src/x402/Assets.test.ts +0 -253
  950. package/src/x402/Assets.ts +0 -221
  951. package/src/x402/Exact.e2e.test.ts +0 -448
  952. package/src/x402/Exact.localnet.test.ts +0 -475
  953. package/src/x402/Header.test.ts +0 -73
  954. package/src/x402/Header.ts +0 -79
  955. package/src/x402/PublicInterface.test-d.ts +0 -39
  956. package/src/x402/Types.ts +0 -248
  957. package/src/x402/client/Exact.test.ts +0 -309
  958. package/src/x402/client/Exact.ts +0 -186
  959. package/src/x402/index.ts +0 -6
  960. package/src/x402/internal/ChallengeBrand.ts +0 -14
  961. package/src/x402/internal/RouteBinding.ts +0 -18
  962. package/src/x402/server/EvmCharge.ts +0 -394
  963. package/src/x402/server/Facilitator.test.ts +0 -111
  964. package/src/x402/server/Facilitator.ts +0 -56
  965. package/src/zod.test.ts +0 -169
  966. package/src/zod.ts +0 -71
@@ -1,1899 +0,0 @@
1
- import { createClient, custom, encodeFunctionResult, type Address, type Hex } from 'viem'
2
- import { privateKeyToAccount } from 'viem/accounts'
3
- import { describe, expect, test, vi } from 'vp/test'
4
-
5
- import * as Challenge from '../../../Challenge.js'
6
- import * as Constants from '../../../Constants.js'
7
- import * as Credential from '../../../Credential.js'
8
- import type { ChannelEntry } from '../client/ChannelOps.js'
9
- import { createJsonChannelStore, entryKey, type ChannelStore } from '../client/ChannelStore.js'
10
- import * as Channel from '../precompile/Channel.js'
11
- import { escrowAbi } from '../precompile/escrow.abi.js'
12
- import { tip20ChannelEscrow } from '../precompile/Protocol.js'
13
- import { createSessionReceipt, serializeSessionReceipt } from '../precompile/Protocol.js'
14
- import type { NeedVoucherEvent, SessionReceipt } from '../precompile/Protocol.js'
15
- import { formatNeedVoucherEvent, parseEvent } from '../precompile/Protocol.js'
16
- import type { SessionCredentialPayload } from '../precompile/Protocol.js'
17
- import * as Voucher from '../precompile/Voucher.js'
18
- import { computeFallbackCloseAmount, sessionManager } from './SessionManager.js'
19
-
20
- const channelId = '0x0000000000000000000000000000000000000000000000000000000000000001' as Hex
21
- const challengeId = 'test-challenge-1'
22
- const realm = 'test.example.com'
23
- const account = privateKeyToAccount(
24
- '0xac0974bec39a17e36ba6a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
25
- )
26
-
27
- const client = createClient({
28
- account,
29
- chain: { id: 4217 } as never,
30
- transport: custom({
31
- async request(args) {
32
- if (args.method === 'eth_chainId') return '0x1079'
33
- if (args.method === 'eth_getTransactionCount') return '0x0'
34
- if (args.method === 'eth_estimateGas') return '0x5208'
35
- if (args.method === 'eth_maxPriorityFeePerGas') return '0x1'
36
- if (args.method === 'eth_getBlockByNumber') return { baseFeePerGas: '0x1' }
37
- if (args.method === 'eth_call')
38
- return encodeFunctionResult({
39
- abi: escrowAbi,
40
- functionName: 'getChannelState',
41
- result: { settled: 0n, deposit: 10_000_000n, closeRequestedAt: 0 },
42
- })
43
- throw new Error(`unexpected rpc request: ${args.method}`)
44
- },
45
- }),
46
- })
47
-
48
- function channelStateClient(state: { closeRequestedAt: number; deposit: bigint; settled: bigint }) {
49
- return createClient({
50
- account,
51
- chain: { id: 4217 } as never,
52
- transport: custom({
53
- async request(args) {
54
- if (args.method === 'eth_call')
55
- return encodeFunctionResult({
56
- abi: escrowAbi,
57
- functionName: 'getChannelState',
58
- result: state,
59
- })
60
- throw new Error(`unexpected rpc request: ${args.method}`)
61
- },
62
- }),
63
- })
64
- }
65
-
66
- const storedDescriptor = {
67
- authorizedSigner: account.address,
68
- expiringNonceHash: `0x${'11'.repeat(32)}` as Hex,
69
- operator: '0x0000000000000000000000000000000000000000' as Address,
70
- payee: '0x742d35cc6634c0532925a3b844bc9e7595f8fe00' as Address,
71
- payer: account.address,
72
- salt: `0x${'22'.repeat(32)}` as Hex,
73
- token: '0x20c0000000000000000000000000000000000001' as Address,
74
- }
75
-
76
- const storedChannelId = Channel.computeId({
77
- ...storedDescriptor,
78
- chainId: 4217,
79
- escrow: tip20ChannelEscrow,
80
- })
81
-
82
- function channelEntry(overrides: Partial<ChannelEntry> = {}): ChannelEntry {
83
- return {
84
- channelId: storedChannelId,
85
- cumulativeAmount: 1_000_000n,
86
- deposit: 10_000_000n,
87
- descriptor: storedDescriptor,
88
- escrow: tip20ChannelEscrow,
89
- chainId: 4217,
90
- opened: true,
91
- ...overrides,
92
- }
93
- }
94
-
95
- /**
96
- * In-memory {@link ChannelStore} with spied `set`/`delete`, optionally seeded.
97
- * Seeded entries live in the entry index, so the plugin resumes them from
98
- * `store.get(resolved.key)` after a 402 (there is no first-request hint).
99
- */
100
- function makeChannelStore(seed: readonly ChannelEntry[] = []) {
101
- const map = new Map<string, ChannelEntry>(seed.map((entry) => [entryKey(entry), entry]))
102
- const set = vi.fn((entry: ChannelEntry) => {
103
- map.set(entryKey(entry), entry)
104
- })
105
- const remove = vi.fn((key: string) => {
106
- map.delete(key)
107
- })
108
- const store: ChannelStore = {
109
- get: (key) => map.get(key),
110
- set,
111
- delete: remove,
112
- }
113
- return { store, set, delete: remove, map }
114
- }
115
-
116
- function makeDurableChannelStore() {
117
- const backend = new Map<string, string>()
118
- const store = createJsonChannelStore({
119
- get: (key) => backend.get(key),
120
- set: (key, value) => {
121
- backend.set(key, value)
122
- },
123
- delete: (key) => {
124
- backend.delete(key)
125
- },
126
- })
127
- return { backend, store }
128
- }
129
-
130
- function makeChallenge(overrides: Record<string, unknown> = {}): Challenge.Challenge {
131
- return Challenge.from({
132
- id: challengeId,
133
- realm,
134
- method: 'tempo',
135
- intent: 'session',
136
- request: {
137
- amount: '1000000',
138
- currency: '0x20c0000000000000000000000000000000000001',
139
- recipient: '0x742d35cc6634c0532925a3b844bc9e7595f8fe00',
140
- decimals: 6,
141
- methodDetails: {
142
- escrowContract: tip20ChannelEscrow,
143
- chainId: 4217,
144
- sessionProtocol: Constants.SessionProtocols.v2,
145
- },
146
- ...overrides,
147
- },
148
- })
149
- }
150
-
151
- function makeChargeChallenge(overrides: Record<string, unknown> = {}): Challenge.Challenge {
152
- return Challenge.from({
153
- id: 'charge-bootstrap',
154
- realm,
155
- method: 'tempo',
156
- intent: 'charge',
157
- request: {
158
- amount: '0',
159
- currency: '0x20c0000000000000000000000000000000000001',
160
- recipient: '0x742d35cc6634c0532925a3b844bc9e7595f8fe00',
161
- methodDetails: { chainId: 4217 },
162
- ...overrides,
163
- },
164
- })
165
- }
166
-
167
- function make402Response(challenge?: Challenge.Challenge): Response {
168
- const c = challenge ?? makeChallenge()
169
- return new Response(null, {
170
- status: 402,
171
- headers: { 'WWW-Authenticate': Challenge.serialize(c) },
172
- })
173
- }
174
-
175
- function makeOkResponse(body?: string): Response {
176
- return new Response(body ?? 'ok', { status: 200 })
177
- }
178
-
179
- function makeSseResponse(events: string[]): Response {
180
- const body = events.join('')
181
- return new Response(body, {
182
- status: 200,
183
- headers: { 'Content-Type': 'text/event-stream' },
184
- })
185
- }
186
-
187
- describe('Session', () => {
188
- describe('computeFallbackCloseAmount', () => {
189
- test('uses matching close-ready receipt spend first', () => {
190
- const receipt = createSessionReceipt({
191
- acceptedCumulative: 100n,
192
- challengeId,
193
- channelId,
194
- spent: 80n,
195
- })
196
-
197
- expect(
198
- computeFallbackCloseAmount({
199
- challengeId,
200
- channelId,
201
- closeReadyReceipt: receipt,
202
- cumulativeAmount: 100n,
203
- deliveredChunks: 10n,
204
- socketChallengeId: challengeId,
205
- socketChannelId: channelId,
206
- spent: 50n,
207
- tickCost: 10n,
208
- }),
209
- ).toBe(80n)
210
- })
211
-
212
- test('uses matching socket delivery estimate clamped to cumulative authorization', () => {
213
- expect(
214
- computeFallbackCloseAmount({
215
- challengeId,
216
- channelId,
217
- cumulativeAmount: 90n,
218
- deliveredChunks: 10n,
219
- socketChallengeId: challengeId,
220
- socketChannelId: channelId,
221
- spent: 40n,
222
- tickCost: 10n,
223
- }),
224
- ).toBe(90n)
225
- })
226
-
227
- test('uses receipt-tracked spend when no socket estimate applies', () => {
228
- expect(
229
- computeFallbackCloseAmount({
230
- challengeId,
231
- channelId,
232
- cumulativeAmount: 100n,
233
- deliveredChunks: 10n,
234
- socketChallengeId: 'other-challenge',
235
- socketChannelId: channelId,
236
- spent: 40n,
237
- tickCost: 10n,
238
- }),
239
- ).toBe(40n)
240
- })
241
- })
242
-
243
- describe('parseEvent round-trip via SSE', () => {
244
- test('parses message events from SSE stream', () => {
245
- const raw = 'event: message\ndata: hello world\n\n'
246
- const event = parseEvent(raw)
247
- expect(event).toEqual({ type: 'message', data: 'hello world' })
248
- })
249
-
250
- test('parses payment-need-voucher events', () => {
251
- const params: NeedVoucherEvent = {
252
- channelId,
253
- requiredCumulative: '6000000',
254
- acceptedCumulative: '5000000',
255
- deposit: '10000000',
256
- }
257
- const raw = formatNeedVoucherEvent(params)
258
- const event = parseEvent(raw)
259
- expect(event).toEqual({ type: 'payment-need-voucher', data: params })
260
- })
261
- })
262
-
263
- describe('session creation', () => {
264
- test('creates session with initial state', () => {
265
- const s = sessionManager({
266
- account: '0x0000000000000000000000000000000000000001',
267
- maxDeposit: '10',
268
- })
269
-
270
- expect(s.channelId).toBeUndefined()
271
- expect(s.cumulative).toBe(0n)
272
- expect(s.opened).toBe(false)
273
- })
274
- })
275
-
276
- describe('.fetch()', () => {
277
- test('passes through non-402 responses', async () => {
278
- const mockFetch = vi.fn().mockResolvedValue(makeOkResponse('hello'))
279
-
280
- const s = sessionManager({
281
- account: '0x0000000000000000000000000000000000000001',
282
- fetch: mockFetch as typeof globalThis.fetch,
283
- })
284
-
285
- const res = await s.fetch('https://api.example.com/data')
286
- expect(res.status).toBe(200)
287
- expect(await res.text()).toBe('hello')
288
- expect(mockFetch).toHaveBeenCalledOnce()
289
- })
290
-
291
- test('rejects a concurrent request while one is in flight', async () => {
292
- let release!: () => void
293
- const gate = new Promise<void>((resolve) => {
294
- release = resolve
295
- })
296
- const mockFetch = vi.fn().mockImplementation(async () => {
297
- await gate
298
- return makeOkResponse('hello')
299
- })
300
-
301
- const s = sessionManager({
302
- account: '0x0000000000000000000000000000000000000001',
303
- fetch: mockFetch as typeof globalThis.fetch,
304
- })
305
-
306
- const first = s.fetch('https://api.example.com/data')
307
- await expect(s.fetch('https://api.example.com/data')).rejects.toThrow(
308
- 'concurrent requests on one manager are not supported',
309
- )
310
-
311
- release()
312
- expect((await first).status).toBe(200)
313
-
314
- // The guard clears after the in-flight request settles.
315
- expect((await s.fetch('https://api.example.com/data')).status).toBe(200)
316
- })
317
-
318
- test('binds the default global fetch for browser runtimes', async () => {
319
- const originalFetch = globalThis.fetch
320
- const mockFetch = vi.fn(function (this: unknown) {
321
- expect(this).toBe(globalThis)
322
- return Promise.resolve(makeOkResponse('hello'))
323
- })
324
- globalThis.fetch = mockFetch as typeof globalThis.fetch
325
- try {
326
- const s = sessionManager({
327
- account: '0x0000000000000000000000000000000000000001',
328
- })
329
-
330
- const res = await s.fetch('https://api.example.com/data')
331
-
332
- expect(res.status).toBe(200)
333
- expect(mockFetch).toHaveBeenCalledOnce()
334
- } finally {
335
- globalThis.fetch = originalFetch
336
- }
337
- })
338
-
339
- test('resumes a seeded channel after a 402 without a first-request hint', async () => {
340
- const posted: SessionCredentialPayload[] = []
341
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
342
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
343
- const payload = authorization
344
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
345
- : undefined
346
- if (payload) posted.push(payload)
347
- if (!payload) return Promise.resolve(make402Response())
348
- return Promise.resolve(makeOkResponse())
349
- })
350
- const s = sessionManager({
351
- account,
352
- client,
353
- fetch: mockFetch as typeof globalThis.fetch,
354
- channelStore: makeChannelStore([channelEntry()]).store,
355
- })
356
-
357
- await s.fetch('https://api.example.com/data')
358
-
359
- // No persisted hint: the first request carries no Payment-Session header,
360
- // and the channel is resumed from the entry index with a voucher.
361
- expect(new Headers(mockFetch.mock.calls[0]?.[1]?.headers).get('Payment-Session')).toBeNull()
362
- expect(posted[0]).toMatchObject({ action: 'voucher', channelId: storedChannelId })
363
- })
364
-
365
- test('seeds a same-route HEAD snapshot and resolves the account when resuming it', async () => {
366
- const { store, set } = makeChannelStore()
367
- const posted: SessionCredentialPayload[] = []
368
- const highestVoucher = {
369
- channelId: storedChannelId,
370
- cumulativeAmount: '1000000',
371
- signature: await Voucher.signVoucher(
372
- client,
373
- account,
374
- { channelId: storedChannelId, cumulativeAmount: 1_000_000n },
375
- tip20ChannelEscrow,
376
- 4217,
377
- ),
378
- }
379
- const resolveAccount = vi.fn(
380
- (info: Parameters<NonNullable<sessionManager.Parameters['resolveAccount']>>[0]) =>
381
- info.account,
382
- )
383
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
384
- const headers = new Headers(init?.headers)
385
- if (init?.method === 'HEAD' && !headers.get(Constants.Headers.authorization)) {
386
- expect(headers.get(Constants.Headers.acceptPayment)).toBe('tempo/charge')
387
- return Promise.resolve(make402Response(makeChargeChallenge()))
388
- }
389
- if (init?.method === 'HEAD') {
390
- const credential = Credential.deserialize(headers.get(Constants.Headers.authorization)!)
391
- expect(credential.payload).toMatchObject({ type: 'proof' })
392
- return Promise.resolve(
393
- new Response(null, {
394
- status: 204,
395
- headers: {
396
- [Constants.Headers.paymentSessionSnapshot]: sessionManager.serializeSnapshot({
397
- acceptedCumulative: '1000000',
398
- chainId: 4217,
399
- channelId: storedChannelId,
400
- deposit: '10000000',
401
- descriptor: storedDescriptor,
402
- escrow: tip20ChannelEscrow,
403
- highestVoucher,
404
- requiredCumulative: '1000000',
405
- settled: '0',
406
- spent: '0',
407
- units: 0,
408
- }),
409
- },
410
- }),
411
- )
412
- }
413
- // The seeded snapshot is not sent as a first-request hint; the content
414
- // request gets a 402 and resumes from the entry index with a voucher.
415
- const authorization = headers.get(Constants.Headers.authorization)
416
- const payload = authorization
417
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
418
- : undefined
419
- if (payload) posted.push(payload)
420
- if (!payload) {
421
- expect(s.channelId).toBe(storedChannelId)
422
- expect(s.cumulative).toBe(1_000_000n)
423
- return Promise.resolve(make402Response())
424
- }
425
- return Promise.resolve(makeOkResponse())
426
- })
427
- const s = sessionManager({
428
- account,
429
- bootstrap: true,
430
- client,
431
- fetch: mockFetch as typeof globalThis.fetch,
432
- channelStore: store,
433
- resolveAccount,
434
- })
435
-
436
- const response = await s.fetch('https://api.example.com/data')
437
-
438
- expect(response.status).toBe(200)
439
- expect(set).toHaveBeenCalledWith(expect.objectContaining({ channelId: storedChannelId }))
440
- expect(posted[0]).toMatchObject({ action: 'voucher', channelId: storedChannelId })
441
- expect(resolveAccount).toHaveBeenCalledTimes(2)
442
- expect(resolveAccount).toHaveBeenNthCalledWith(1, {
443
- account,
444
- chainId: 4217,
445
- operation: { authority: account.address, kind: 'authorizePaymentChannel' },
446
- })
447
- const contentCall = mockFetch.mock.calls.find((call) => call[1]?.method !== 'HEAD')
448
- expect(new Headers(contentCall?.[1]?.headers).get('Payment-Session')).toBeNull()
449
- })
450
-
451
- test('does not cache a server snapshot for a channel that is closed on-chain', async () => {
452
- const { store, set } = makeChannelStore()
453
- const highestVoucher = {
454
- channelId: storedChannelId,
455
- cumulativeAmount: '1000000',
456
- signature: await Voucher.signVoucher(
457
- client,
458
- account,
459
- { channelId: storedChannelId, cumulativeAmount: 1_000_000n },
460
- tip20ChannelEscrow,
461
- 4217,
462
- ),
463
- }
464
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
465
- const headers = new Headers(init?.headers)
466
- if (init?.method === 'HEAD' && !headers.get(Constants.Headers.authorization))
467
- return Promise.resolve(make402Response(makeChargeChallenge()))
468
- if (init?.method === 'HEAD')
469
- return Promise.resolve(
470
- new Response(null, {
471
- status: 204,
472
- headers: {
473
- [Constants.Headers.paymentSessionSnapshot]: sessionManager.serializeSnapshot({
474
- acceptedCumulative: '1000000',
475
- chainId: 4217,
476
- channelId: storedChannelId,
477
- deposit: '10000000',
478
- descriptor: storedDescriptor,
479
- escrow: tip20ChannelEscrow,
480
- highestVoucher,
481
- requiredCumulative: '1000000',
482
- settled: '0',
483
- spent: '0',
484
- units: 0,
485
- }),
486
- },
487
- }),
488
- )
489
- return Promise.resolve(makeOkResponse())
490
- })
491
- const s = sessionManager({
492
- account,
493
- bootstrap: true,
494
- client: channelStateClient({ closeRequestedAt: 0, deposit: 0n, settled: 0n }),
495
- fetch: mockFetch as typeof globalThis.fetch,
496
- channelStore: store,
497
- })
498
-
499
- expect((await s.fetch('https://api.example.com/data')).status).toBe(200)
500
- expect(set).not.toHaveBeenCalled()
501
- })
502
-
503
- test('does not cache a server snapshot with an invalid highest voucher signature', async () => {
504
- const { store, set } = makeChannelStore()
505
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
506
- const headers = new Headers(init?.headers)
507
- if (init?.method === 'HEAD' && !headers.get(Constants.Headers.authorization))
508
- return Promise.resolve(make402Response(makeChargeChallenge()))
509
- if (init?.method === 'HEAD')
510
- return Promise.resolve(
511
- new Response(null, {
512
- status: 204,
513
- headers: {
514
- [Constants.Headers.paymentSessionSnapshot]: sessionManager.serializeSnapshot({
515
- acceptedCumulative: '1000000',
516
- chainId: 4217,
517
- channelId: storedChannelId,
518
- deposit: '10000000',
519
- descriptor: storedDescriptor,
520
- escrow: tip20ChannelEscrow,
521
- highestVoucher: {
522
- channelId: storedChannelId,
523
- cumulativeAmount: '1000000',
524
- signature: `0x${'00'.repeat(64)}`,
525
- },
526
- requiredCumulative: '1000000',
527
- settled: '0',
528
- spent: '0',
529
- units: 0,
530
- }),
531
- },
532
- }),
533
- )
534
- return Promise.resolve(makeOkResponse())
535
- })
536
- const s = sessionManager({
537
- account,
538
- bootstrap: true,
539
- client,
540
- fetch: mockFetch as typeof globalThis.fetch,
541
- channelStore: store,
542
- })
543
-
544
- expect((await s.fetch('https://api.example.com/data')).status).toBe(200)
545
- expect(set).not.toHaveBeenCalled()
546
- })
547
-
548
- test('does not answer non-zero bootstrap charge challenges', async () => {
549
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
550
- const headers = new Headers(init?.headers)
551
- if (init?.method === 'HEAD' && !headers.get(Constants.Headers.authorization)) {
552
- return Promise.resolve(make402Response(makeChargeChallenge({ amount: '1' })))
553
- }
554
- if (init?.method === 'HEAD') throw new Error('unexpected bootstrap authorization')
555
- expect(headers.get(Constants.Headers.paymentSession)).toBeNull()
556
- return Promise.resolve(makeOkResponse())
557
- })
558
- const s = sessionManager({
559
- account,
560
- bootstrap: true,
561
- client,
562
- fetch: mockFetch as typeof globalThis.fetch,
563
- })
564
-
565
- const response = await s.fetch('https://api.example.com/data')
566
-
567
- expect(response.status).toBe(200)
568
- expect(mockFetch).toHaveBeenCalledTimes(2)
569
- })
570
-
571
- test('falls back to normal fetch when bootstrap is unsupported', async () => {
572
- const mockFetch = vi
573
- .fn()
574
- .mockResolvedValueOnce(new Response(null, { status: 404 }))
575
- .mockResolvedValueOnce(makeOkResponse())
576
- const s = sessionManager({
577
- account,
578
- bootstrap: true,
579
- client,
580
- fetch: mockFetch as typeof globalThis.fetch,
581
- })
582
-
583
- const response = await s.fetch('https://api.example.com/data')
584
-
585
- expect(response.status).toBe(200)
586
- expect(s.channelId).toBeUndefined()
587
- expect(mockFetch).toHaveBeenCalledTimes(2)
588
- expect(mockFetch.mock.calls[0]?.[1]).toMatchObject({ method: 'HEAD' })
589
- expect(new Headers(mockFetch.mock.calls[1]?.[1]?.headers).get('Payment-Session')).toBeNull()
590
- })
591
-
592
- test('drops a stale stored channel the server rejects and retries with a fresh one', async () => {
593
- const { store, delete: remove } = makeChannelStore([channelEntry()])
594
- const postedPayloads: SessionCredentialPayload[] = []
595
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
596
- const headers = new Headers(init?.headers)
597
- const authorization = headers.get(Constants.Headers.authorization)
598
- const payload = authorization
599
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
600
- : undefined
601
- if (payload) postedPayloads.push(payload)
602
-
603
- if (!payload) return Promise.resolve(make402Response())
604
- // Reject any reuse of the stale stored channel; accept a freshly opened one.
605
- if (payload.channelId === storedChannelId)
606
- return Promise.resolve(new Response('gone', { status: 500 }))
607
- return Promise.resolve(makeOkResponse())
608
- })
609
- const s = sessionManager({
610
- account,
611
- client,
612
- fetch: mockFetch as typeof globalThis.fetch,
613
- maxDeposit: '10',
614
- channelStore: store,
615
- })
616
-
617
- const response = await s.fetch('https://api.example.com/data')
618
-
619
- expect(response.status).toBe(200)
620
- expect(remove).toHaveBeenCalledOnce()
621
- expect(postedPayloads.map((payload) => payload.action)).toEqual(['voucher', 'open'])
622
- expect(s.opened).toBe(true)
623
- expect(s.channelId).not.toBe(storedChannelId)
624
- })
625
-
626
- test('keeps a persisted channel after its committed top-up when the paid retry fails', async () => {
627
- const seeded = channelEntry({ cumulativeAmount: 10_000_000n, deposit: 10_000_000n })
628
- const { store, delete: remove, map } = makeChannelStore([seeded])
629
- const postedPayloads: SessionCredentialPayload[] = []
630
- let probes = 0
631
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
632
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
633
- const payload = authorization
634
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
635
- : undefined
636
- if (!payload) {
637
- probes++
638
- if (probes > 1) throw new Error('unexpected fresh-channel retry')
639
- return Promise.resolve(make402Response())
640
- }
641
-
642
- postedPayloads.push(payload)
643
- if (payload.action === 'topUp') return Promise.resolve(new Response(null, { status: 204 }))
644
- if (payload.action === 'voucher')
645
- return Promise.resolve(new Response('upstream failed', { status: 500 }))
646
- throw new Error(`unexpected ${payload.action} credential`)
647
- })
648
- const s = sessionManager({
649
- account,
650
- client,
651
- fetch: mockFetch as typeof globalThis.fetch,
652
- maxDeposit: '20',
653
- channelStore: store,
654
- })
655
-
656
- const response = await s.fetch('https://api.example.com/data')
657
-
658
- expect(response.status).toBe(500)
659
- expect(postedPayloads.map((payload) => payload.action)).toEqual(['topUp', 'voucher'])
660
- expect(remove).not.toHaveBeenCalled()
661
- expect(map.get(entryKey(seeded))).toMatchObject({
662
- channelId: storedChannelId,
663
- cumulativeAmount: 10_000_000n,
664
- deposit: 11_000_000n,
665
- })
666
- expect(s.channelId).toBe(storedChannelId)
667
- expect(s.state).toMatchObject({
668
- status: 'active',
669
- channelId: storedChannelId,
670
- deposit: '11000000',
671
- })
672
- })
673
-
674
- test('rolls back optimistic opens across replacement challenges', async () => {
675
- const { store, delete: remove } = makeChannelStore()
676
- const postedPayloads: SessionCredentialPayload[] = []
677
- const challenge = (feePayer: boolean) =>
678
- makeChallenge({
679
- methodDetails: {
680
- escrowContract: tip20ChannelEscrow,
681
- chainId: 4217,
682
- sessionProtocol: Constants.SessionProtocols.v2,
683
- feePayer,
684
- },
685
- })
686
- const original = challenge(true)
687
- const replacement = challenge(false)
688
- let openCount = 0
689
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
690
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
691
- const payload = authorization
692
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
693
- : undefined
694
- if (payload) postedPayloads.push(payload)
695
-
696
- if (!payload) return Promise.resolve(make402Response(original))
697
- if (payload.action === 'open') {
698
- openCount++
699
- if (openCount === 1) return Promise.resolve(make402Response(replacement))
700
- if (openCount === 2) return Promise.resolve(make402Response(original))
701
- return Promise.resolve(makeOkResponse())
702
- }
703
- return Promise.resolve(new Response('unexpected voucher', { status: 500 }))
704
- })
705
- const s = sessionManager({
706
- account,
707
- client,
708
- fetch: mockFetch as typeof globalThis.fetch,
709
- maxDeposit: '10',
710
- channelStore: store,
711
- })
712
-
713
- const response = await s.fetch('https://api.example.com/data')
714
-
715
- expect(response.status).toBe(200)
716
- expect(postedPayloads.map((payload) => payload.action)).toEqual(['open', 'open', 'open'])
717
- expect(new Set(postedPayloads.map((payload) => payload.channelId)).size).toBe(3)
718
- expect(remove).toHaveBeenCalledTimes(2)
719
- expect(s.channelId).toBe(postedPayloads[2]?.channelId)
720
- })
721
-
722
- test('reuses prepared voucher state when an identical challenge succeeds', async () => {
723
- const vouchers: Extract<SessionCredentialPayload, { action: 'voucher' }>[] = []
724
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
725
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
726
- if (!authorization) return Promise.resolve(make402Response())
727
- const payload = Credential.deserialize<SessionCredentialPayload>(authorization).payload
728
- if (payload.action !== 'voucher') throw new Error('expected voucher')
729
- vouchers.push(payload)
730
- return Promise.resolve(vouchers.length === 1 ? make402Response() : makeOkResponse())
731
- })
732
- const s = sessionManager({
733
- account,
734
- client,
735
- fetch: mockFetch as typeof globalThis.fetch,
736
- channelStore: makeChannelStore([channelEntry()]).store,
737
- })
738
-
739
- expect((await s.fetch('https://api.example.com/data')).status).toBe(200)
740
- expect(vouchers.map((voucher) => voucher.cumulativeAmount)).toEqual(['2000000', '2000000'])
741
- expect(s.cumulative).toBe(2_000_000n)
742
- expect(s.state.status).toBe('active')
743
- })
744
-
745
- test('does not bootstrap when disabled', async () => {
746
- const mockFetch = vi.fn().mockResolvedValue(makeOkResponse())
747
- const s = sessionManager({
748
- account,
749
- client,
750
- fetch: mockFetch as typeof globalThis.fetch,
751
- })
752
-
753
- await s.fetch('https://api.example.com/data')
754
-
755
- expect(mockFetch).toHaveBeenCalledOnce()
756
- expect(new Headers(mockFetch.mock.calls[0]?.[1]?.headers).get('Payment-Session')).toBeNull()
757
- })
758
-
759
- test('uses stored channel details when the server does not return a snapshot', async () => {
760
- const postedPayloads: SessionCredentialPayload[] = []
761
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
762
- const authorization = new Headers(init?.headers).get('Authorization')
763
- const payload = authorization
764
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
765
- : undefined
766
- if (payload) postedPayloads.push(payload)
767
-
768
- if (!payload) return Promise.resolve(make402Response())
769
- return Promise.resolve(makeOkResponse())
770
- })
771
- const s = sessionManager({
772
- account,
773
- client,
774
- fetch: mockFetch as typeof globalThis.fetch,
775
- channelStore: makeChannelStore([channelEntry()]).store,
776
- })
777
-
778
- await s.fetch('https://api.example.com/data')
779
-
780
- expect(postedPayloads[0]).toMatchObject({
781
- action: 'voucher',
782
- channelId: storedChannelId,
783
- })
784
- })
785
-
786
- test('resumes a persisted channel across a restart via the entry index', async () => {
787
- // A shared durable KV backing two manager instances simulates a restart:
788
- // the second manager shares only what survived to disk.
789
- const backend = new Map<string, string>()
790
- const durableStore = () =>
791
- createJsonChannelStore({
792
- get: (key) => backend.get(key),
793
- set: (key, value) => {
794
- backend.set(key, value)
795
- },
796
- delete: (key) => {
797
- backend.delete(key)
798
- },
799
- })
800
-
801
- const openFetch = vi.fn((_input: RequestInfo | URL, init?: RequestInit) => {
802
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
803
- if (!authorization) return Promise.resolve(make402Response())
804
- return Promise.resolve(makeOkResponse())
805
- })
806
- const first = sessionManager({
807
- account,
808
- client,
809
- fetch: openFetch as typeof globalThis.fetch,
810
- maxDeposit: '10',
811
- channelStore: durableStore(),
812
- })
813
- await first.fetch('https://api.example.com/data')
814
- const channelId = first.channelId
815
- expect(channelId).toBeDefined()
816
-
817
- // The durable channel entry must have reached the KV.
818
- expect([...backend.keys()].some((key) => key.startsWith('chan:'))).toBe(true)
819
- // No persistent hints are written; only the durable channel entry survives.
820
- expect([...backend.keys()].some((key) => key.startsWith('hint:'))).toBe(false)
821
-
822
- const posted: SessionCredentialPayload[] = []
823
- const resumeFetch = vi.fn((_input: RequestInfo | URL, init?: RequestInit) => {
824
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
825
- const payload = authorization
826
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
827
- : undefined
828
- if (payload) posted.push(payload)
829
- if (!payload) return Promise.resolve(make402Response())
830
- return Promise.resolve(makeOkResponse())
831
- })
832
- const restarted = sessionManager({
833
- account,
834
- client,
835
- fetch: resumeFetch as typeof globalThis.fetch,
836
- maxDeposit: '10',
837
- channelStore: durableStore(),
838
- })
839
- await restarted.fetch('https://api.example.com/data')
840
-
841
- // The first request carries no hint header; after the 402 the restarted
842
- // manager tops up and resumes the full persisted channel rather than
843
- // opening a new one.
844
- expect(new Headers(resumeFetch.mock.calls[0]?.[1]?.headers).get('Payment-Session')).toBeNull()
845
- expect(posted.map((payload) => payload.action)).toEqual(['topUp', 'voucher'])
846
- expect(posted[1]).toMatchObject({ channelId })
847
- })
848
-
849
- test('persists opened channels and deletes closed channels when supported', async () => {
850
- const { store, set, delete: remove } = makeChannelStore()
851
- let callCount = 0
852
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
853
- const authorization = new Headers(init?.headers).get('Authorization')
854
- const payload = authorization
855
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
856
- : undefined
857
- callCount++
858
-
859
- if (callCount === 1) return Promise.resolve(make402Response())
860
- if (payload?.action === 'open') {
861
- return Promise.resolve(
862
- new Response('ok', {
863
- headers: {
864
- 'Payment-Receipt': serializeSessionReceipt(
865
- createSessionReceipt({
866
- acceptedCumulative: BigInt(payload.cumulativeAmount),
867
- challengeId,
868
- channelId: payload.channelId,
869
- spent: 0n,
870
- }),
871
- ),
872
- },
873
- }),
874
- )
875
- }
876
- if (payload?.action === 'close') {
877
- return Promise.resolve(
878
- new Response('ok', {
879
- headers: {
880
- 'Payment-Receipt': serializeSessionReceipt(
881
- createSessionReceipt({
882
- acceptedCumulative: BigInt(payload.cumulativeAmount),
883
- challengeId,
884
- channelId: payload.channelId,
885
- spent: BigInt(payload.cumulativeAmount),
886
- txHash: `0x${'aa'.repeat(32)}`,
887
- }),
888
- ),
889
- },
890
- }),
891
- )
892
- }
893
- return Promise.resolve(makeOkResponse())
894
- })
895
- const s = sessionManager({
896
- account,
897
- client,
898
- fetch: mockFetch as typeof globalThis.fetch,
899
- maxDeposit: '10',
900
- channelStore: store,
901
- })
902
-
903
- await s.fetch('https://api.example.com/data')
904
- expect(set).toHaveBeenCalledWith(
905
- expect.objectContaining({
906
- channelId: s.channelId,
907
- opened: true,
908
- }),
909
- )
910
-
911
- await s.close()
912
- expect(remove).toHaveBeenCalledOnce()
913
- })
914
-
915
- test('rolls back state when opening a channel throws', async () => {
916
- const failingClient = createClient({
917
- account,
918
- chain: { id: 4217 } as never,
919
- transport: custom({
920
- async request(args) {
921
- if (args.method === 'eth_chainId') return '0x1079'
922
- if (args.method === 'eth_getTransactionCount') return '0x0'
923
- if (args.method === 'eth_estimateGas') throw new Error('insufficient balance')
924
- if (args.method === 'eth_maxPriorityFeePerGas') return '0x1'
925
- if (args.method === 'eth_getBlockByNumber') return { baseFeePerGas: '0x1' }
926
- throw new Error(`unexpected rpc request: ${args.method}`)
927
- },
928
- }),
929
- })
930
- const mockFetch = vi.fn().mockResolvedValue(make402Response())
931
- const s = sessionManager({
932
- account,
933
- client: failingClient,
934
- fetch: mockFetch as typeof globalThis.fetch,
935
- maxDeposit: '10',
936
- })
937
-
938
- await expect(s.fetch('https://api.example.com/data')).rejects.toThrow(/insufficient balance/)
939
-
940
- expect(s.state).toEqual({ status: 'idle' })
941
- expect(s.opened).toBe(false)
942
- expect(s.cumulative).toBe(0n)
943
- })
944
-
945
- test('automatically top-ups and retries when an HTTP session exceeds deposit', async () => {
946
- const postedPayloads: SessionCredentialPayload[] = []
947
- let callCount = 0
948
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
949
- callCount++
950
- const authorization = new Headers(init?.headers).get('Authorization')
951
- const payload = authorization
952
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
953
- : undefined
954
- if (payload) postedPayloads.push(payload)
955
-
956
- if (callCount === 1)
957
- return Promise.resolve(make402Response(makeChallenge({ suggestedDeposit: '1000000' })))
958
-
959
- if (payload?.action === 'open') {
960
- return Promise.resolve(
961
- make402Response(
962
- makeChallenge({
963
- methodDetails: {
964
- escrowContract: tip20ChannelEscrow,
965
- chainId: 4217,
966
- sessionProtocol: Constants.SessionProtocols.v2,
967
- sessionSnapshot: {
968
- acceptedCumulative: '2000000',
969
- chainId: 4217,
970
- channelId: payload.channelId,
971
- deposit: '1000000',
972
- descriptor: payload.descriptor,
973
- escrow: tip20ChannelEscrow,
974
- requiredCumulative: '2000000',
975
- settled: '0',
976
- spent: '1000000',
977
- units: 1,
978
- },
979
- },
980
- }),
981
- ),
982
- )
983
- }
984
-
985
- if (payload?.action === 'topUp') return Promise.resolve(makeOkResponse())
986
-
987
- if (payload?.action === 'voucher') {
988
- return Promise.resolve(
989
- new Response('paid', {
990
- status: 200,
991
- headers: {
992
- 'Payment-Receipt': serializeSessionReceipt(
993
- createSessionReceipt({
994
- acceptedCumulative: 2_000_000n,
995
- challengeId,
996
- channelId: payload.channelId,
997
- spent: 2_000_000n,
998
- units: 2,
999
- }),
1000
- ),
1001
- },
1002
- }),
1003
- )
1004
- }
1005
-
1006
- return Promise.resolve(makeOkResponse())
1007
- })
1008
-
1009
- const s = sessionManager({
1010
- account,
1011
- client,
1012
- fetch: mockFetch as typeof globalThis.fetch,
1013
- maxDeposit: '10',
1014
- })
1015
-
1016
- const response = await s.fetch('https://api.example.com/data')
1017
-
1018
- expect(response.status).toBe(200)
1019
- expect(await response.text()).toBe('paid')
1020
- expect(postedPayloads.map((payload) => payload.action)).toEqual(['open', 'topUp', 'voucher'])
1021
- expect(s.state).toMatchObject({
1022
- status: 'active',
1023
- acceptedCumulative: '2000000',
1024
- deposit: '2000000',
1025
- spent: '2000000',
1026
- units: 2,
1027
- })
1028
- })
1029
-
1030
- test('preserves a snapshot-acknowledged open when its voucher fails', async () => {
1031
- const { backend, store } = makeDurableChannelStore()
1032
- const payloads: SessionCredentialPayload[] = []
1033
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1034
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
1035
- if (!authorization)
1036
- return Promise.resolve(make402Response(makeChallenge({ suggestedDeposit: '10000000' })))
1037
- const payload = Credential.deserialize<SessionCredentialPayload>(authorization).payload
1038
- payloads.push(payload)
1039
- if (payload.action !== 'open')
1040
- return Promise.resolve(new Response('failed', { status: 500 }))
1041
- return Promise.resolve(
1042
- make402Response(
1043
- makeChallenge({
1044
- methodDetails: {
1045
- escrowContract: tip20ChannelEscrow,
1046
- chainId: 4217,
1047
- sessionProtocol: Constants.SessionProtocols.v2,
1048
- sessionSnapshot: {
1049
- acceptedCumulative: '1000000',
1050
- chainId: 4217,
1051
- channelId: payload.channelId,
1052
- deposit: '10000000',
1053
- descriptor: payload.descriptor,
1054
- escrow: tip20ChannelEscrow,
1055
- requiredCumulative: '2000000',
1056
- settled: '0',
1057
- spent: '1000000',
1058
- units: 1,
1059
- },
1060
- },
1061
- }),
1062
- ),
1063
- )
1064
- })
1065
- const s = sessionManager({
1066
- account,
1067
- client,
1068
- fetch: mockFetch as typeof globalThis.fetch,
1069
- maxDeposit: '10',
1070
- channelStore: store,
1071
- })
1072
-
1073
- expect((await s.fetch('https://api.example.com/data')).status).toBe(500)
1074
- expect(payloads.map((payload) => payload.action)).toEqual(['open', 'voucher'])
1075
- expect(s.channelId).toBe(payloads[0]?.channelId)
1076
- expect(s.cumulative).toBe(1_000_000n)
1077
- expect(JSON.parse([...backend.values()][0]!)).toMatchObject({
1078
- channelId: payloads[0]?.channelId,
1079
- cumulativeAmount: '1000000',
1080
- opened: true,
1081
- })
1082
- })
1083
-
1084
- test('preemptively top-ups before signing an HTTP voucher that exceeds deposit', async () => {
1085
- const postedPayloads: SessionCredentialPayload[] = []
1086
- let challengeCount = 0
1087
- const receipt = (payload: Extract<SessionCredentialPayload, { channelId: Hex }>) =>
1088
- new Response('paid', {
1089
- status: 200,
1090
- headers: {
1091
- 'Payment-Receipt': serializeSessionReceipt(
1092
- createSessionReceipt({
1093
- acceptedCumulative: BigInt(
1094
- 'cumulativeAmount' in payload ? payload.cumulativeAmount : '1000000',
1095
- ),
1096
- challengeId,
1097
- channelId: payload.channelId,
1098
- spent: BigInt('cumulativeAmount' in payload ? payload.cumulativeAmount : '1000000'),
1099
- units:
1100
- 'cumulativeAmount' in payload && payload.cumulativeAmount === '2000000' ? 2 : 1,
1101
- }),
1102
- ),
1103
- },
1104
- })
1105
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1106
- const authorization = new Headers(init?.headers).get('Authorization')
1107
- const payload = authorization
1108
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
1109
- : undefined
1110
- if (payload) postedPayloads.push(payload)
1111
-
1112
- if (!payload) {
1113
- challengeCount++
1114
- return Promise.resolve(
1115
- make402Response(
1116
- makeChallenge(challengeCount === 1 ? { suggestedDeposit: '1000000' } : {}),
1117
- ),
1118
- )
1119
- }
1120
- if (payload.action === 'topUp') return Promise.resolve(makeOkResponse())
1121
- if (payload.action === 'open' || payload.action === 'voucher')
1122
- return Promise.resolve(receipt(payload))
1123
- return Promise.resolve(makeOkResponse())
1124
- })
1125
-
1126
- const s = sessionManager({
1127
- account,
1128
- client,
1129
- fetch: mockFetch as typeof globalThis.fetch,
1130
- maxDeposit: '10',
1131
- topUpAmount: '5',
1132
- })
1133
-
1134
- await s.fetch('https://api.example.com/data')
1135
- const response = await s.fetch('https://api.example.com/data')
1136
-
1137
- expect(response.status).toBe(200)
1138
- expect(postedPayloads.map((payload) => payload.action)).toEqual(['open', 'topUp', 'voucher'])
1139
- const topUp = postedPayloads[1]
1140
- if (topUp?.action !== 'topUp') throw new Error('expected top-up payload')
1141
- expect(topUp.additionalDeposit).toBe('5000000')
1142
- expect(s.state).toMatchObject({
1143
- status: 'active',
1144
- acceptedCumulative: '2000000',
1145
- deposit: '6000000',
1146
- spent: '2000000',
1147
- units: 2,
1148
- })
1149
- })
1150
-
1151
- test('preserves a successful automatic top-up when the paid retry fails', async () => {
1152
- const { map, store } = makeChannelStore()
1153
- const payloads: SessionCredentialPayload[] = []
1154
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1155
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
1156
- if (!authorization)
1157
- return Promise.resolve(make402Response(makeChallenge({ suggestedDeposit: '1000000' })))
1158
- const payload = Credential.deserialize<SessionCredentialPayload>(authorization).payload
1159
- payloads.push(payload)
1160
- if (payload.action === 'open')
1161
- return Promise.resolve(
1162
- new Response('ok', {
1163
- headers: {
1164
- [Constants.Headers.paymentReceipt]: serializeSessionReceipt(
1165
- createSessionReceipt({
1166
- acceptedCumulative: 1_000_000n,
1167
- challengeId,
1168
- channelId: payload.channelId,
1169
- spent: 1_000_000n,
1170
- units: 3,
1171
- }),
1172
- ),
1173
- },
1174
- }),
1175
- )
1176
- if (payload.action === 'topUp') return Promise.resolve(new Response(null, { status: 204 }))
1177
- return Promise.resolve(make402Response(makeChallenge({ suggestedDeposit: '1000000' })))
1178
- })
1179
- const s = sessionManager({
1180
- account,
1181
- client,
1182
- fetch: mockFetch as typeof globalThis.fetch,
1183
- maxDeposit: '3',
1184
- channelStore: store,
1185
- })
1186
-
1187
- await s.fetch('https://api.example.com/data')
1188
- expect((await s.fetch('https://api.example.com/data')).status).toBe(402)
1189
-
1190
- expect(payloads.map((payload) => payload.action)).toEqual([
1191
- 'open',
1192
- 'topUp',
1193
- 'voucher',
1194
- 'voucher',
1195
- 'voucher',
1196
- ])
1197
- expect(s.cumulative).toBe(1_000_000n)
1198
- expect(s.state).toMatchObject({ status: 'active', deposit: '2000000', units: 3 })
1199
- expect([...map.values()][0]).toMatchObject({
1200
- cumulativeAmount: 1_000_000n,
1201
- deposit: 2_000_000n,
1202
- })
1203
- })
1204
-
1205
- test('preserves a topped-up resumed channel in durable storage after payment fails', async () => {
1206
- const { store } = makeDurableChannelStore()
1207
- const seeded = channelEntry({ cumulativeAmount: 1_000_000n, deposit: 1_000_000n })
1208
- await store.set(seeded)
1209
- const payloads: SessionCredentialPayload[] = []
1210
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1211
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
1212
- if (!authorization)
1213
- return Promise.resolve(make402Response(makeChallenge({ suggestedDeposit: '1000000' })))
1214
- const payload = Credential.deserialize<SessionCredentialPayload>(authorization).payload
1215
- payloads.push(payload)
1216
- return Promise.resolve(
1217
- payload.action === 'topUp'
1218
- ? new Response(null, { status: 204 })
1219
- : new Response('failed', { status: 500 }),
1220
- )
1221
- })
1222
- const s = sessionManager({
1223
- account,
1224
- client,
1225
- fetch: mockFetch as typeof globalThis.fetch,
1226
- maxDeposit: '3',
1227
- channelStore: store,
1228
- })
1229
-
1230
- expect((await s.fetch('https://api.example.com/data')).status).toBe(500)
1231
-
1232
- expect(payloads.map((payload) => payload.action)).toEqual(['topUp', 'voucher'])
1233
- expect(s.cumulative).toBe(1_000_000n)
1234
- expect(s.state).toMatchObject({ status: 'active', deposit: '2000000' })
1235
- await expect(store.get(entryKey(seeded))).resolves.toMatchObject({
1236
- cumulativeAmount: 1_000_000n,
1237
- deposit: 2_000_000n,
1238
- opened: true,
1239
- })
1240
- })
1241
-
1242
- test.each([
1243
- ['new', false],
1244
- ['replacement', true],
1245
- ] as const)('removes a failed %s durable channel', async (_kind, seeded) => {
1246
- const { backend, store } = makeDurableChannelStore()
1247
- if (seeded) await store.set(channelEntry())
1248
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1249
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
1250
- return Promise.resolve(
1251
- authorization ? new Response('failed', { status: 500 }) : make402Response(),
1252
- )
1253
- })
1254
- const s = sessionManager({
1255
- account,
1256
- client,
1257
- fetch: mockFetch as typeof globalThis.fetch,
1258
- channelStore: store,
1259
- })
1260
-
1261
- expect((await s.fetch('https://api.example.com/data')).status).toBe(500)
1262
- expect(s.channelId).toBeUndefined()
1263
- expect(backend.size).toBe(0)
1264
- })
1265
- })
1266
-
1267
- describe('.topUp()', () => {
1268
- test('posts a precompile top-up credential for the active channel', async () => {
1269
- const postedPayloads: SessionCredentialPayload[] = []
1270
- let callCount = 0
1271
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1272
- callCount++
1273
- const authorization = new Headers(init?.headers).get('Authorization')
1274
- if (authorization) {
1275
- postedPayloads.push(
1276
- Credential.deserialize<SessionCredentialPayload>(authorization).payload,
1277
- )
1278
- }
1279
- if (callCount === 1)
1280
- return Promise.resolve(make402Response(makeChallenge({ suggestedDeposit: '5000000' })))
1281
- return Promise.resolve(makeOkResponse())
1282
- })
1283
-
1284
- const s = sessionManager({
1285
- account,
1286
- client,
1287
- fetch: mockFetch as typeof globalThis.fetch,
1288
- maxDeposit: '10',
1289
- })
1290
-
1291
- await s.fetch('https://api.example.com/data')
1292
- expect(s.state).toMatchObject({
1293
- status: 'active',
1294
- acceptedCumulative: '1000000',
1295
- deposit: '5000000',
1296
- })
1297
- const receipt = await s.topUp('1')
1298
-
1299
- expect(receipt).toBeUndefined()
1300
- expect(s.state).toMatchObject({
1301
- status: 'active',
1302
- acceptedCumulative: '1000000',
1303
- deposit: '6000000',
1304
- })
1305
- expect(postedPayloads[0]?.action).toBe('open')
1306
- expect(postedPayloads[1]?.action).toBe('topUp')
1307
- const openPayload = postedPayloads[0]
1308
- const topUpPayload = postedPayloads[1]
1309
- if (openPayload?.action !== 'open' || topUpPayload?.action !== 'topUp') {
1310
- throw new Error('expected open then top-up payloads')
1311
- }
1312
- expect(topUpPayload.channelId).toBe(openPayload.channelId)
1313
- expect(topUpPayload.descriptor).toEqual(openPayload.descriptor)
1314
- expect(topUpPayload.additionalDeposit).toBe('1000000')
1315
- })
1316
-
1317
- test('rejects top-up before a channel is open', async () => {
1318
- const s = sessionManager({
1319
- account,
1320
- client,
1321
- fetch: vi.fn() as typeof globalThis.fetch,
1322
- maxDeposit: '10',
1323
- })
1324
-
1325
- await expect(s.topUp('1')).rejects.toThrow('Cannot top up session: no open channel.')
1326
- })
1327
-
1328
- test('rolls back optimistic vouchers when the paid retry fails', async () => {
1329
- const postedPayloads: SessionCredentialPayload[] = []
1330
- let callCount = 0
1331
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1332
- callCount++
1333
- const authorization = new Headers(init?.headers).get('Authorization')
1334
- if (authorization) {
1335
- postedPayloads.push(
1336
- Credential.deserialize<SessionCredentialPayload>(authorization).payload,
1337
- )
1338
- }
1339
- if (callCount === 1)
1340
- return Promise.resolve(make402Response(makeChallenge({ suggestedDeposit: '3000000' })))
1341
- if (callCount >= 3 && callCount <= 6) return Promise.resolve(make402Response())
1342
- return Promise.resolve(makeOkResponse())
1343
- })
1344
-
1345
- const s = sessionManager({
1346
- account,
1347
- client,
1348
- fetch: mockFetch as typeof globalThis.fetch,
1349
- maxDeposit: '3',
1350
- })
1351
-
1352
- await s.fetch('https://api.example.com/data')
1353
- expect(s.cumulative).toBe(1000000n)
1354
-
1355
- const failed = await s.fetch('https://api.example.com/data')
1356
- expect(failed.status).toBe(402)
1357
- expect(s.cumulative).toBe(1000000n)
1358
-
1359
- await s.topUp('1')
1360
- expect(postedPayloads.map((payload) => payload.action)).toEqual([
1361
- 'open',
1362
- 'voucher',
1363
- 'voucher',
1364
- 'voucher',
1365
- 'topUp',
1366
- ])
1367
- const topUpPayload = postedPayloads[4]
1368
- if (topUpPayload?.action !== 'topUp') throw new Error('expected top-up payload')
1369
- expect(topUpPayload.additionalDeposit).toBe('1000000')
1370
- })
1371
- })
1372
-
1373
- describe('.sse() event parsing', () => {
1374
- test('yields only message data from SSE stream', async () => {
1375
- const events = [
1376
- 'event: message\ndata: chunk1\n\n',
1377
- 'event: message\ndata: chunk2\n\n',
1378
- `event: payment-receipt\ndata: ${JSON.stringify({
1379
- method: 'tempo',
1380
- intent: 'session',
1381
- status: 'success',
1382
- timestamp: '2025-01-01T00:00:00.000Z',
1383
- reference: channelId,
1384
- challengeId,
1385
- channelId,
1386
- acceptedCumulative: '2000000',
1387
- spent: '2000000',
1388
- units: 2,
1389
- } satisfies SessionReceipt)}\n\n`,
1390
- ]
1391
-
1392
- let callCount = 0
1393
- const mockFetch = vi.fn().mockImplementation(() => {
1394
- callCount++
1395
- if (callCount === 1) return Promise.resolve(makeSseResponse(events))
1396
- return Promise.resolve(makeOkResponse())
1397
- })
1398
-
1399
- const s = sessionManager({
1400
- account: '0x0000000000000000000000000000000000000001',
1401
- fetch: mockFetch as typeof globalThis.fetch,
1402
- })
1403
-
1404
- // Manually set channel state to skip auto-open flow
1405
- ;(s as any).__test_setChannel?.()
1406
-
1407
- const receiptCb = vi.fn()
1408
- const iterable = await s.sse('https://api.example.com/stream', {
1409
- onReceipt: receiptCb,
1410
- })
1411
-
1412
- const messages: string[] = []
1413
- for await (const msg of iterable) {
1414
- messages.push(msg)
1415
- }
1416
-
1417
- expect(messages).toEqual(['chunk1', 'chunk2'])
1418
- expect(receiptCb).toHaveBeenCalledOnce()
1419
- expect(receiptCb.mock.calls[0]![0].units).toBe(2)
1420
- })
1421
-
1422
- test('posts precompile SSE top-up vouchers with the channel descriptor', async () => {
1423
- const requestedUrls: string[] = []
1424
- const postedPayloads: SessionCredentialPayload[] = []
1425
- let callCount = 0
1426
- const mockFetch = vi.fn().mockImplementation((input, init?: RequestInit) => {
1427
- callCount++
1428
- requestedUrls.push(input.toString())
1429
- const authorization = new Headers(init?.headers).get('Authorization')
1430
- if (authorization) {
1431
- postedPayloads.push(
1432
- Credential.deserialize<SessionCredentialPayload>(authorization).payload,
1433
- )
1434
- }
1435
- if (callCount === 1) return Promise.resolve(make402Response())
1436
- if (callCount === 2) {
1437
- const openPayload = postedPayloads[0]
1438
- if (openPayload?.action !== 'open') throw new Error('expected open payload')
1439
- const needVoucher: NeedVoucherEvent = {
1440
- channelId: openPayload.channelId,
1441
- requiredCumulative: '2000000',
1442
- acceptedCumulative: '1000000',
1443
- deposit: '10000000',
1444
- }
1445
- return Promise.resolve(
1446
- makeSseResponse([
1447
- 'event: message\ndata: chunk1\n\n',
1448
- formatNeedVoucherEvent(needVoucher),
1449
- 'event: message\ndata: chunk2\n\n',
1450
- ]),
1451
- )
1452
- }
1453
- return Promise.resolve(makeOkResponse())
1454
- })
1455
-
1456
- const s = sessionManager({
1457
- account,
1458
- client,
1459
- fetch: mockFetch as typeof globalThis.fetch,
1460
- maxDeposit: '10',
1461
- })
1462
-
1463
- const iterable = await s.sse('https://api.example.com/stream?prompt=paid')
1464
- const messages: string[] = []
1465
- for await (const msg of iterable) messages.push(msg)
1466
-
1467
- expect(messages).toEqual(['chunk1', 'chunk2'])
1468
- expect(postedPayloads[0]?.action).toBe('open')
1469
- expect(postedPayloads[1]?.action).toBe('voucher')
1470
- const openPayload = postedPayloads[0]
1471
- const voucherPayload = postedPayloads[1]
1472
- if (openPayload?.action !== 'open' || voucherPayload?.action !== 'voucher')
1473
- throw new Error('expected open then voucher payloads')
1474
- expect(voucherPayload.channelId).toBe(openPayload.channelId)
1475
- expect(voucherPayload.descriptor).toEqual(openPayload.descriptor)
1476
- expect(voucherPayload.cumulativeAmount).toBe('2000000')
1477
- expect(requestedUrls[2]).toBe('https://api.example.com/stream?prompt=paid')
1478
- })
1479
-
1480
- test('ignores precompile SSE voucher requests for a different channel', async () => {
1481
- const mismatchedChannelId = `0x${'ff'.repeat(32)}` as Hex
1482
- const needVoucher: NeedVoucherEvent = {
1483
- channelId: mismatchedChannelId,
1484
- requiredCumulative: '2000000',
1485
- acceptedCumulative: '1000000',
1486
- deposit: '10000000',
1487
- }
1488
- const events = [
1489
- 'event: message\ndata: chunk1\n\n',
1490
- formatNeedVoucherEvent(needVoucher),
1491
- 'event: message\ndata: chunk2\n\n',
1492
- ]
1493
- const postedPayloads: SessionCredentialPayload[] = []
1494
- let callCount = 0
1495
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1496
- callCount++
1497
- const authorization = new Headers(init?.headers).get('Authorization')
1498
- if (authorization) {
1499
- postedPayloads.push(
1500
- Credential.deserialize<SessionCredentialPayload>(authorization).payload,
1501
- )
1502
- }
1503
- if (callCount === 1) return Promise.resolve(make402Response())
1504
- if (callCount === 2) return Promise.resolve(makeSseResponse(events))
1505
- return Promise.resolve(makeOkResponse())
1506
- })
1507
-
1508
- const s = sessionManager({
1509
- account,
1510
- client,
1511
- fetch: mockFetch as typeof globalThis.fetch,
1512
- maxDeposit: '10',
1513
- })
1514
-
1515
- const iterable = await s.sse('https://api.example.com/stream')
1516
- const messages: string[] = []
1517
- for await (const msg of iterable) messages.push(msg)
1518
-
1519
- expect(messages).toEqual(['chunk1', 'chunk2'])
1520
- expect(postedPayloads.map((payload) => payload.action)).toEqual(['open'])
1521
- expect(callCount).toBe(2)
1522
- })
1523
-
1524
- test('retries for the event stream after an open management response', async () => {
1525
- const postedPayloads: SessionCredentialPayload[] = []
1526
- let callCount = 0
1527
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1528
- callCount++
1529
- const authorization = new Headers(init?.headers).get('Authorization')
1530
- const payload = authorization
1531
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
1532
- : undefined
1533
- if (payload) postedPayloads.push(payload)
1534
-
1535
- if (!payload) {
1536
- return Promise.resolve(make402Response(makeChallenge({ suggestedDeposit: '5000000' })))
1537
- }
1538
-
1539
- if (payload.action === 'open') {
1540
- return Promise.resolve(
1541
- new Response(null, {
1542
- status: 200,
1543
- headers: {
1544
- 'Payment-Receipt': serializeSessionReceipt(
1545
- createSessionReceipt({
1546
- acceptedCumulative: 1_000_000n,
1547
- challengeId,
1548
- channelId: payload.channelId,
1549
- spent: 1_000_000n,
1550
- units: 1,
1551
- }),
1552
- ),
1553
- },
1554
- }),
1555
- )
1556
- }
1557
-
1558
- if (payload.action === 'voucher') {
1559
- return Promise.resolve(
1560
- makeSseResponse([
1561
- 'event: message\ndata: chunk1\n\n',
1562
- 'event: message\ndata: chunk2\n\n',
1563
- `event: payment-receipt\ndata: ${JSON.stringify(
1564
- createSessionReceipt({
1565
- acceptedCumulative: BigInt(payload.cumulativeAmount),
1566
- challengeId,
1567
- channelId: payload.channelId,
1568
- spent: BigInt(payload.cumulativeAmount),
1569
- units: 2,
1570
- }),
1571
- )}\n\n`,
1572
- ]),
1573
- )
1574
- }
1575
-
1576
- return Promise.resolve(makeOkResponse())
1577
- })
1578
-
1579
- const s = sessionManager({
1580
- account,
1581
- client,
1582
- fetch: mockFetch as typeof globalThis.fetch,
1583
- maxDeposit: '10',
1584
- })
1585
-
1586
- const iterable = await s.sse('https://api.example.com/stream')
1587
- const messages: string[] = []
1588
- for await (const msg of iterable) messages.push(msg)
1589
-
1590
- expect(messages).toEqual(['chunk1', 'chunk2'])
1591
- expect(postedPayloads.map((payload) => payload.action)).toEqual(['open', 'voucher'])
1592
- expect(callCount).toBe(4)
1593
- expect(s.state).toMatchObject({
1594
- status: 'active',
1595
- acceptedCumulative: '2000000',
1596
- deposit: '5000000',
1597
- spent: '2000000',
1598
- units: 2,
1599
- })
1600
- })
1601
- })
1602
-
1603
- describe('error handling', () => {
1604
- test('.sse() silently skips payment-need-voucher when no channel open', async () => {
1605
- const needVoucher: NeedVoucherEvent = {
1606
- channelId,
1607
- requiredCumulative: '2000000',
1608
- acceptedCumulative: '1000000',
1609
- deposit: '10000000',
1610
- }
1611
-
1612
- const events = [
1613
- 'event: message\ndata: chunk1\n\n',
1614
- formatNeedVoucherEvent(needVoucher),
1615
- 'event: message\ndata: chunk2\n\n',
1616
- ]
1617
-
1618
- const mockFetch = vi.fn().mockResolvedValue(makeSseResponse(events))
1619
-
1620
- const s = sessionManager({
1621
- account: '0x0000000000000000000000000000000000000001',
1622
- fetch: mockFetch as typeof globalThis.fetch,
1623
- })
1624
-
1625
- const iterable = await s.sse('https://api.example.com/stream')
1626
-
1627
- const messages: string[] = []
1628
- for await (const msg of iterable) {
1629
- messages.push(msg)
1630
- }
1631
-
1632
- expect(messages).toEqual(['chunk1', 'chunk2'])
1633
- expect(mockFetch).toHaveBeenCalledOnce()
1634
- })
1635
- })
1636
-
1637
- describe('.sse() headers normalization', () => {
1638
- test('preserves Headers instance properties when passed as headers', async () => {
1639
- const mockFetch = vi.fn().mockResolvedValue(makeSseResponse(['event: message\ndata: ok\n\n']))
1640
-
1641
- const s = sessionManager({
1642
- account: '0x0000000000000000000000000000000000000001',
1643
- fetch: mockFetch as typeof globalThis.fetch,
1644
- })
1645
-
1646
- const iterable = await s.sse('https://api.example.com/stream', {
1647
- headers: new Headers({ 'Content-Type': 'application/json', 'X-Custom': 'value' }),
1648
- })
1649
-
1650
- for await (const _ of iterable) {
1651
- // drain
1652
- }
1653
-
1654
- const calledHeaders = new Headers((mockFetch.mock.calls[0]![1] as RequestInit).headers)
1655
- expect(calledHeaders.get('content-type')).toBe('application/json')
1656
- expect(calledHeaders.get('x-custom')).toBe('value')
1657
- expect(calledHeaders.get('accept')).toBe('text/event-stream')
1658
- })
1659
- })
1660
-
1661
- describe('.ws()', () => {
1662
- test('tops up a full persisted channel before constructing the socket', async () => {
1663
- const events: string[] = []
1664
- const { map, set, store } = makeChannelStore([
1665
- channelEntry({ cumulativeAmount: 1_000_000n, deposit: 1_000_000n }),
1666
- ])
1667
- set.mockImplementation((entry) => {
1668
- map.set(entryKey(entry), entry)
1669
- events.push(`set:${entry.deposit}:${entry.cumulativeAmount}`)
1670
- })
1671
- const fetch = vi.fn(async (_input, init?: RequestInit) => {
1672
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
1673
- if (!authorization) {
1674
- events.push('probe')
1675
- return make402Response(makeChallenge({ suggestedDeposit: '1000000' }))
1676
- }
1677
- const payload = Credential.deserialize<SessionCredentialPayload>(authorization).payload
1678
- if (payload.action !== 'topUp') throw new Error(`unexpected ${payload.action} fetch`)
1679
- events.push('topUp')
1680
- return new Response(null, { status: 204 })
1681
- })
1682
- function WebSocket() {
1683
- events.push('socket')
1684
- throw new Error('stop after preparation')
1685
- }
1686
- const s = sessionManager({
1687
- account,
1688
- client,
1689
- fetch: fetch as typeof globalThis.fetch,
1690
- maxDeposit: '3',
1691
- channelStore: store,
1692
- webSocket: WebSocket as never,
1693
- })
1694
-
1695
- await expect(s.ws('wss://api.example.com/socket')).rejects.toThrow('stop after preparation')
1696
- expect(events).toEqual([
1697
- 'probe',
1698
- 'topUp',
1699
- 'set:2000000:1000000',
1700
- 'set:2000000:2000000',
1701
- 'socket',
1702
- ])
1703
- })
1704
- })
1705
-
1706
- describe('.close()', () => {
1707
- test('is no-op when not opened', async () => {
1708
- const mockFetch = vi.fn()
1709
-
1710
- const s = sessionManager({
1711
- account: '0x0000000000000000000000000000000000000001',
1712
- fetch: mockFetch as typeof globalThis.fetch,
1713
- })
1714
-
1715
- await s.close()
1716
- expect(mockFetch).not.toHaveBeenCalled()
1717
- })
1718
-
1719
- test('tracks spent from HTTP error receipts and closes at that amount', async () => {
1720
- const postedPayloads: SessionCredentialPayload[] = []
1721
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1722
- const authorization = new Headers(init?.headers).get('Authorization')
1723
- const payload = authorization
1724
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
1725
- : undefined
1726
- if (payload) postedPayloads.push(payload)
1727
-
1728
- if (!payload)
1729
- return Promise.resolve(
1730
- make402Response(makeChallenge({ amount: '1', suggestedDeposit: '2' })),
1731
- )
1732
- if (payload.action === 'open') {
1733
- return Promise.resolve(
1734
- new Response('upstream failed', {
1735
- status: 500,
1736
- headers: {
1737
- 'Payment-Receipt': serializeSessionReceipt(
1738
- createSessionReceipt({
1739
- acceptedCumulative: BigInt(payload.cumulativeAmount),
1740
- challengeId,
1741
- channelId: payload.channelId,
1742
- spent: 1n,
1743
- units: 1,
1744
- }),
1745
- ),
1746
- },
1747
- }),
1748
- )
1749
- }
1750
- if (payload.action === 'close') {
1751
- return Promise.resolve(
1752
- new Response(null, {
1753
- status: 200,
1754
- headers: {
1755
- 'Payment-Receipt': serializeSessionReceipt(
1756
- createSessionReceipt({
1757
- acceptedCumulative: BigInt(payload.cumulativeAmount),
1758
- challengeId,
1759
- channelId: payload.channelId,
1760
- spent: BigInt(payload.cumulativeAmount),
1761
- txHash: `0x${'aa'.repeat(32)}` as Hex,
1762
- units: 1,
1763
- }),
1764
- ),
1765
- },
1766
- }),
1767
- )
1768
- }
1769
- return Promise.resolve(makeOkResponse())
1770
- })
1771
-
1772
- const s = sessionManager({
1773
- account,
1774
- client,
1775
- decimals: 0,
1776
- fetch: mockFetch as typeof globalThis.fetch,
1777
- maxDeposit: '2',
1778
- })
1779
-
1780
- const response = await s.fetch('https://api.example.com/resource')
1781
- expect(response.status).toBe(500)
1782
- expect(response.receipt?.spent).toBe('1')
1783
-
1784
- const closeReceipt = await s.close()
1785
- expect(closeReceipt?.status).toBe('success')
1786
- expect(closeReceipt?.spent).toBe('1')
1787
- expect(s.state).toMatchObject({
1788
- status: 'closed',
1789
- channelId: closeReceipt?.channelId,
1790
- })
1791
- const closePayload = postedPayloads.find((payload) => payload.action === 'close')
1792
- expect(closePayload?.cumulativeAmount).toBe('1')
1793
- })
1794
-
1795
- test('rejects receipts that exceed the locally signed voucher', async () => {
1796
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1797
- const authorization = new Headers(init?.headers).get('Authorization')
1798
- const payload = authorization
1799
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
1800
- : undefined
1801
-
1802
- if (!payload)
1803
- return Promise.resolve(
1804
- make402Response(makeChallenge({ amount: '1', suggestedDeposit: '3' })),
1805
- )
1806
- if (payload.action === 'open') {
1807
- return Promise.resolve(
1808
- new Response('ok', {
1809
- status: 200,
1810
- headers: {
1811
- 'Payment-Receipt': serializeSessionReceipt(
1812
- createSessionReceipt({
1813
- acceptedCumulative: 3n,
1814
- challengeId,
1815
- channelId: payload.channelId,
1816
- spent: 3n,
1817
- units: 1,
1818
- }),
1819
- ),
1820
- },
1821
- }),
1822
- )
1823
- }
1824
- return Promise.resolve(makeOkResponse())
1825
- })
1826
-
1827
- const s = sessionManager({
1828
- account,
1829
- client,
1830
- decimals: 0,
1831
- fetch: mockFetch as typeof globalThis.fetch,
1832
- maxDeposit: '3',
1833
- })
1834
-
1835
- await expect(s.fetch('https://api.example.com/resource')).rejects.toThrow(
1836
- 'receipt accepted cumulative exceeds local voucher state',
1837
- )
1838
- })
1839
-
1840
- test('surfaces close failure problem details', async () => {
1841
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1842
- const authorization = new Headers(init?.headers).get('Authorization')
1843
- const payload = authorization
1844
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
1845
- : undefined
1846
-
1847
- if (!payload)
1848
- return Promise.resolve(
1849
- make402Response(makeChallenge({ amount: '1', suggestedDeposit: '2' })),
1850
- )
1851
- if (payload.action === 'open') {
1852
- return Promise.resolve(
1853
- new Response('ok', {
1854
- status: 200,
1855
- headers: {
1856
- 'Payment-Receipt': serializeSessionReceipt(
1857
- createSessionReceipt({
1858
- acceptedCumulative: BigInt(payload.cumulativeAmount),
1859
- challengeId,
1860
- channelId: payload.channelId,
1861
- spent: 1n,
1862
- units: 1,
1863
- }),
1864
- ),
1865
- },
1866
- }),
1867
- )
1868
- }
1869
- if (payload.action === 'close') {
1870
- return Promise.resolve(
1871
- new Response('close failed', {
1872
- status: 500,
1873
- headers: {
1874
- 'WWW-Authenticate': 'Payment error="close_failed"',
1875
- },
1876
- }),
1877
- )
1878
- }
1879
- return Promise.resolve(makeOkResponse())
1880
- })
1881
-
1882
- const s = sessionManager({
1883
- account,
1884
- client,
1885
- decimals: 0,
1886
- fetch: mockFetch as typeof globalThis.fetch,
1887
- maxDeposit: '2',
1888
- })
1889
-
1890
- const response = await s.fetch('https://api.example.com/resource')
1891
- expect(response.status).toBe(200)
1892
- expect(response.receipt?.spent).toBe('1')
1893
-
1894
- await expect(s.close()).rejects.toThrow(
1895
- 'Close request failed with status 500: close failed [WWW-Authenticate: Payment error="close_failed"]',
1896
- )
1897
- })
1898
- })
1899
- })