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,1944 +0,0 @@
1
- import { Challenge, Credential, Receipt } from 'mppx'
2
- import { Mppx } from 'mppx/server'
3
- import { KeyAuthorization } from 'ox/tempo'
4
- import {
5
- createClient,
6
- custom,
7
- decodeFunctionData,
8
- encodeAbiParameters,
9
- encodeEventTopics,
10
- type Address,
11
- type Hex,
12
- } from 'viem'
13
- import { privateKeyToAccount } from 'viem/accounts'
14
- import { Abis, Transaction } from 'viem/tempo'
15
- import { tempo as tempo_chain } from 'viem/tempo/chains'
16
- import { describe, expect, test } from 'vp/test'
17
-
18
- import * as Store from '../../Store.js'
19
- import * as Methods from '../Methods.js'
20
- import { signSubscriptionKeyAuthorization } from '../subscription/KeyAuthorization.js'
21
- import * as SubscriptionStore from '../subscription/Store.js'
22
- import type { SubscriptionAccessKey } from '../subscription/Types.js'
23
- import type { SubscriptionRecord } from '../subscription/Types.js'
24
- import { renew, subscription } from './Subscription.js'
25
-
26
- const realm = 'api.example.com'
27
- const secretKey = 'test-secret-key-test-secret-key-32'
28
- const activeBillingAnchor = new Date(Math.floor(Date.now() / 1_000) * 1_000).toISOString()
29
- const activeSubscriptionExpires = new Date(
30
- Math.ceil((Date.now() + 365 * 24 * 60 * 60 * 1_000) / 1_000) * 1_000,
31
- ).toISOString()
32
- const chainId = 4217
33
- const subscriptionDefaultChainId = 42431
34
- const subscriptionAmount = '10'
35
- const subscriptionCurrency = '0x20c0000000000000000000000000000000000001'
36
- const subscriptionKey = 'user-1:plan:pro'
37
- const subscriptionPeriodCount = '1'
38
- const subscriptionPeriodUnit = 'day'
39
- const subscriptionPeriodMilliseconds = 86_400_000
40
- const subscriptionRecipient = '0x1234567890abcdef1234567890abcdef12345678'
41
- const rootAccount = privateKeyToAccount(
42
- '0x0000000000000000000000000000000000000000000000000000000000000001',
43
- )
44
- const otherRootAccount = privateKeyToAccount(
45
- '0x0000000000000000000000000000000000000000000000000000000000000004',
46
- )
47
- const accessAccount = privateKeyToAccount(
48
- '0x0000000000000000000000000000000000000000000000000000000000000002',
49
- )
50
- const otherAccessAccount = privateKeyToAccount(
51
- '0x0000000000000000000000000000000000000000000000000000000000000003',
52
- )
53
- const accessKey = {
54
- accessKeyAddress: accessAccount.address,
55
- keyType: 'secp256k1',
56
- } as const satisfies SubscriptionAccessKey
57
- const hashActivate = `0x${'a'.repeat(64)}`
58
- const hashRenewed = `0x${'b'.repeat(64)}`
59
- const hashStale = `0x${'c'.repeat(64)}`
60
- const hashBackground = `0x${'d'.repeat(64)}`
61
- const hashOld = `0x${'e'.repeat(64)}`
62
-
63
- function createReceipt(subscriptionId: string, reference = hashActivate) {
64
- return {
65
- method: 'tempo',
66
- reference,
67
- status: 'success',
68
- subscriptionId,
69
- timestamp: '2025-01-01T00:00:00.000Z',
70
- } as const
71
- }
72
-
73
- function createRecord(overrides: Partial<SubscriptionRecord> = {}): SubscriptionRecord {
74
- return {
75
- amount: '10000000',
76
- billingAnchor: activeBillingAnchor,
77
- chainId,
78
- currency: subscriptionCurrency,
79
- lastChargedPeriod: 0,
80
- lookupKey: subscriptionKey,
81
- periodCount: subscriptionPeriodCount,
82
- periodUnit: subscriptionPeriodUnit,
83
- recipient: subscriptionRecipient,
84
- reference: hashActivate,
85
- subscriptionExpires: activeSubscriptionExpires,
86
- subscriptionId: 'sub_123',
87
- timestamp: '2025-01-01T00:00:00.000Z',
88
- ...overrides,
89
- }
90
- }
91
-
92
- async function createCredential(
93
- challenge: Challenge.Challenge,
94
- source = rootAccount.address,
95
- key: SubscriptionAccessKey = accessKey,
96
- account = rootAccount,
97
- ) {
98
- const keyAuthorization = await signSubscriptionKeyAuthorization({
99
- accessKey: key,
100
- account,
101
- chainId,
102
- request: challenge.request as ReturnType<typeof Methods.subscription.schema.request.parse>,
103
- })
104
- if (!keyAuthorization) throw new Error('expected key authorization')
105
- return Credential.from({
106
- challenge,
107
- payload: {
108
- signature: KeyAuthorization.serialize(keyAuthorization),
109
- type: 'keyAuthorization',
110
- },
111
- source: `did:pkh:eip155:${chainId}:${source.toLowerCase()}`,
112
- })
113
- }
114
-
115
- function createBillingClient(
116
- hashes: readonly string[],
117
- options: { account?: typeof rootAccount; failSimulation?: number | undefined } = {},
118
- ) {
119
- const callRequests: Record<string, unknown>[] = []
120
- const rpcMethods: string[] = []
121
- let nextHash = 0
122
- let simulations = 0
123
- const client = createClient({
124
- account: options.account,
125
- chain: { ...tempo_chain, id: chainId },
126
- transport: custom({
127
- async request({ method, params }) {
128
- rpcMethods.push(method)
129
- if (method === 'eth_chainId') return `0x${chainId.toString(16)}`
130
- if (method === 'eth_getTransactionCount') return '0x0'
131
- if (method === 'eth_estimateGas') return '0x5208'
132
- if (method === 'eth_maxPriorityFeePerGas') return '0x1'
133
- if (method === 'eth_getBlockByNumber') return { baseFeePerGas: '0x1' }
134
- if (method === 'eth_call') {
135
- callRequests.push((params as [Record<string, unknown>])[0])
136
- if (options.failSimulation !== undefined && ++simulations >= options.failSimulation)
137
- throw new Error('final sponsored simulation reverted')
138
- return '0x'
139
- }
140
- if (method === 'eth_sendRawTransaction') return hashes[nextHash++] ?? hashActivate
141
- throw new Error(`unexpected rpc method: ${method}`)
142
- },
143
- }),
144
- })
145
- return { callRequests, client, rpcMethods }
146
- }
147
-
148
- async function activateFeeSponsoredSubscription(options?: { failSimulation?: number | undefined }) {
149
- const store = Store.memory()
150
- const billing = createBillingClient([hashActivate], {
151
- account: rootAccount,
152
- ...options,
153
- })
154
- const method = subscription({
155
- amount: subscriptionAmount,
156
- chainId,
157
- currency: subscriptionCurrency,
158
- feePayer: rootAccount,
159
- getClient: async () => billing.client,
160
- periodCount: subscriptionPeriodCount,
161
- periodUnit: subscriptionPeriodUnit,
162
- recipient: subscriptionRecipient,
163
- resolve: async () => ({ key: subscriptionKey }),
164
- store,
165
- subscriptionExpires: activeSubscriptionExpires,
166
- waitForConfirmation: false,
167
- })
168
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
169
- const challengeResult = await mppx.tempo.subscription({})(
170
- new Request('https://example.com/resource'),
171
- )
172
- if (challengeResult.status !== 402) throw new Error('expected activation challenge')
173
- const challenge = Challenge.fromResponse(challengeResult.challenge)
174
- const accessKey = (
175
- challenge.request as ReturnType<typeof Methods.subscription.schema.request.parse>
176
- ).methodDetails?.accessKey
177
- if (!accessKey) throw new Error('expected generated access key')
178
- const credential = await createCredential(challenge, rootAccount.address, accessKey)
179
- const result = await mppx.tempo.subscription({})(
180
- new Request('https://example.com/resource', {
181
- headers: { Authorization: Credential.serialize(credential) },
182
- }),
183
- )
184
- return { ...billing, result }
185
- }
186
-
187
- const confirmedBlockHash = `0x${'f'.repeat(64)}` as const
188
- // Canonical TIP-1028 ReceivePolicyGuard precompile address.
189
- const receivePolicyGuard = '0xB10C000000000000000000000000000000000000' as Address
190
-
191
- /**
192
- * Mock client whose `eth_sendRawTransactionSync` returns a confirmed receipt
193
- * with a `TransferWithMemo` log derived from the broadcast transaction.
194
- *
195
- * `redirectTo` simulates a T6 (TIP-1028) held transfer (credits the guard, not
196
- * the recipient); `addUnrelatedTransfer` adds a memo-less `Transfer` to the
197
- * recipient. By default only the renewal (second) broadcast is affected so
198
- * activation succeeds; `redirectActivation` also holds the first broadcast.
199
- */
200
- function createConfirmingBillingClient(options?: {
201
- addUnrelatedTransfer?: boolean
202
- redirectActivation?: boolean
203
- redirectTo?: Address
204
- }) {
205
- const rpcMethods: string[] = []
206
- let broadcastIndex = 0
207
- const client = createClient({
208
- chain: { ...tempo_chain, id: chainId },
209
- transport: custom({
210
- async request({ method, params }) {
211
- rpcMethods.push(method)
212
- if (method === 'eth_chainId') return `0x${chainId.toString(16)}`
213
- if (method === 'eth_call') return '0x'
214
- if (method === 'eth_sendRawTransactionSync') {
215
- const index = broadcastIndex++
216
- const isRenewal = index >= 1
217
- const serialized = (params as [Hex])[0]
218
- const transaction = Transaction.deserialize(
219
- serialized as Transaction.TransactionSerializedTempo,
220
- ) as unknown as {
221
- from: Address
222
- calls: readonly { data: Hex; to: Address }[]
223
- }
224
- const call = transaction.calls[0]!
225
- const { args } = decodeFunctionData({
226
- abi: Abis.tip20,
227
- data: call.data,
228
- })
229
- const [recipient, amount, memo] = args as [Address, bigint, Hex]
230
- const shouldRedirect = options?.redirectTo && (isRenewal || options?.redirectActivation)
231
- const creditedTo = shouldRedirect ? options!.redirectTo! : recipient
232
- const hash = `0x${index.toString(16).padStart(64, '0')}` as Hex
233
- const baseLog = {
234
- blockHash: confirmedBlockHash,
235
- blockNumber: '0x1',
236
- data: encodeAbiParameters([{ type: 'uint256' }], [amount]),
237
- logIndex: '0x0',
238
- removed: false,
239
- transactionHash: hash,
240
- transactionIndex: '0x0',
241
- } as const
242
- const logs: unknown[] = [
243
- {
244
- ...baseLog,
245
- address: call.to,
246
- topics: encodeEventTopics({
247
- abi: Abis.tip20,
248
- args: { from: transaction.from, memo, to: creditedTo },
249
- eventName: 'TransferWithMemo',
250
- }),
251
- },
252
- ]
253
- // Memo-less Transfer to the recipient: must not satisfy the check.
254
- if (isRenewal && options?.addUnrelatedTransfer) {
255
- logs.push({
256
- ...baseLog,
257
- address: call.to,
258
- logIndex: '0x1',
259
- topics: encodeEventTopics({
260
- abi: Abis.tip20,
261
- args: { from: transaction.from, to: recipient },
262
- eventName: 'Transfer',
263
- }),
264
- })
265
- }
266
- return {
267
- blockHash: confirmedBlockHash,
268
- blockNumber: '0x1',
269
- contractAddress: null,
270
- cumulativeGasUsed: '0x0',
271
- effectiveGasPrice: '0x0',
272
- from: transaction.from,
273
- gasUsed: '0x0',
274
- logs,
275
- logsBloom: `0x${'0'.repeat(512)}`,
276
- status: '0x1',
277
- to: call.to,
278
- transactionHash: hash,
279
- transactionIndex: '0x0',
280
- type: '0x0',
281
- }
282
- }
283
- throw new Error(`unexpected rpc method: ${method}`)
284
- },
285
- }),
286
- })
287
- return { client, rpcMethods }
288
- }
289
-
290
- describe('tempo.subscription', () => {
291
- test('preflights sender and final envelopes for fee-sponsored activation', async () => {
292
- const { callRequests, result, rpcMethods } = await activateFeeSponsoredSubscription()
293
-
294
- expect(result.status).toBe(200)
295
- expect(callRequests).toHaveLength(2)
296
- expect(callRequests[0]).not.toHaveProperty('feePayer')
297
- expect(callRequests[1]?.feePayer).toBe(rootAccount.address)
298
- expect(rpcMethods).toContain('eth_sendRawTransaction')
299
- })
300
-
301
- test('does not broadcast a fee-sponsored activation after final simulation failure', async () => {
302
- const { callRequests, result, rpcMethods } = await activateFeeSponsoredSubscription({
303
- failSimulation: 2,
304
- })
305
-
306
- expect(result.status).not.toBe(200)
307
- expect(callRequests.length).toBeGreaterThanOrEqual(2)
308
- expect(rpcMethods).not.toContain('eth_sendRawTransaction')
309
- expect(rpcMethods).not.toContain('eth_sendRawTransactionSync')
310
- })
311
-
312
- test('stores an activated subscription and reuses it on later requests', async () => {
313
- const store = Store.memory()
314
- let activationCount = 0
315
- const method = subscription({
316
- activate: async ({ request, resolved }) => {
317
- activationCount += 1
318
- return {
319
- receipt: createReceipt('sub_123', hashActivate),
320
- subscription: createRecord({
321
- amount: request.amount,
322
- chainId: request.methodDetails?.chainId,
323
- currency: request.currency,
324
- lookupKey: resolved.key,
325
- periodCount: request.periodCount,
326
- periodUnit: request.periodUnit,
327
- recipient: request.recipient,
328
- reference: hashActivate,
329
- subscriptionExpires: request.subscriptionExpires,
330
- }),
331
- }
332
- },
333
- amount: subscriptionAmount,
334
- chainId,
335
- currency: subscriptionCurrency,
336
- periodCount: subscriptionPeriodCount,
337
- periodUnit: subscriptionPeriodUnit,
338
- recipient: subscriptionRecipient,
339
- resolve: async ({ input }) => {
340
- const key = input.headers.get('X-Subscription-Key')
341
- return key ? { accessKey, key } : null
342
- },
343
- store,
344
- subscriptionExpires: activeSubscriptionExpires,
345
- })
346
-
347
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
348
- const challengeResult = await mppx.tempo.subscription({})(
349
- new Request('https://example.com/resource', {
350
- headers: { 'X-Subscription-Key': subscriptionKey },
351
- }),
352
- )
353
-
354
- expect(challengeResult.status).toBe(402)
355
- if (challengeResult.status !== 402) throw new Error('expected activation challenge')
356
-
357
- const challenge = Challenge.fromResponse(challengeResult.challenge)
358
- const challengeRequest = challenge.request as ReturnType<
359
- typeof Methods.subscription.schema.request.parse
360
- >
361
- expect(challengeRequest.methodDetails?.accessKey).toEqual({
362
- ...accessKey,
363
- accessKeyAddress: accessKey.accessKeyAddress.toLowerCase(),
364
- })
365
- const credential = await createCredential(challenge)
366
-
367
- const activated = await mppx.tempo.subscription({})(
368
- new Request('https://example.com/resource', {
369
- headers: {
370
- Authorization: Credential.serialize(credential),
371
- 'X-Subscription-Key': subscriptionKey,
372
- },
373
- }),
374
- )
375
-
376
- expect(activated.status).toBe(200)
377
- expect(activationCount).toBe(1)
378
-
379
- const replayed = await mppx.tempo.subscription({})(
380
- new Request('https://example.com/resource', {
381
- headers: {
382
- Authorization: Credential.serialize(credential),
383
- 'X-Subscription-Key': subscriptionKey,
384
- },
385
- }),
386
- )
387
-
388
- expect(replayed.status).toBe(402)
389
- expect(activationCount).toBe(1)
390
-
391
- const reused = await mppx.tempo.subscription({})(
392
- new Request('https://example.com/resource', {
393
- headers: {
394
- 'X-Subscription-Key': subscriptionKey,
395
- },
396
- }),
397
- )
398
-
399
- expect(reused.status).toBe(200)
400
- if (reused.status !== 200) throw new Error('expected authorize reuse')
401
-
402
- const response = reused.withReceipt(new Response('OK'))
403
- const receipt = response.headers.get('Payment-Receipt')
404
- expect(receipt).toBeTruthy()
405
- })
406
-
407
- test('automatically creates an access key and submits the activation payment', async () => {
408
- const store = Store.memory()
409
- const subscriptions = SubscriptionStore.fromStore(store)
410
- const { client, rpcMethods } = createBillingClient([hashActivate])
411
- const method = subscription({
412
- amount: subscriptionAmount,
413
- chainId,
414
- currency: subscriptionCurrency,
415
- getClient: async () => client,
416
- periodCount: subscriptionPeriodCount,
417
- periodUnit: subscriptionPeriodUnit,
418
- recipient: subscriptionRecipient,
419
- resolve: async () => ({ key: subscriptionKey }),
420
- store,
421
- subscriptionExpires: activeSubscriptionExpires,
422
- waitForConfirmation: false,
423
- })
424
-
425
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
426
- const challengeResult = await mppx.tempo.subscription({})(
427
- new Request('https://example.com/resource'),
428
- )
429
- expect(challengeResult.status).toBe(402)
430
- if (challengeResult.status !== 402) throw new Error('expected activation challenge')
431
-
432
- const challenge = Challenge.fromResponse(challengeResult.challenge)
433
- const challengeRequest = challenge.request as ReturnType<
434
- typeof Methods.subscription.schema.request.parse
435
- >
436
- const generatedAccessKey = challengeRequest.methodDetails?.accessKey
437
- expect(generatedAccessKey?.keyType).toBe('secp256k1')
438
- if (!generatedAccessKey) throw new Error('expected generated access key')
439
-
440
- const credential = await createCredential(challenge, rootAccount.address, generatedAccessKey)
441
- const activated = await mppx.tempo.subscription({})(
442
- new Request('https://example.com/resource', {
443
- headers: { Authorization: Credential.serialize(credential) },
444
- }),
445
- )
446
-
447
- expect(activated.status).toBe(200)
448
- if (activated.status !== 200) throw new Error('expected activation')
449
- const receipt = Receipt.fromResponse(activated.withReceipt(new Response('OK')))
450
- expect(receipt.reference).toBe(hashActivate)
451
- expect(receipt.subscriptionId).toMatch(/^[A-Za-z0-9_-]+$/)
452
- expect(rpcMethods.filter((method) => method === 'eth_sendRawTransaction')).toHaveLength(1)
453
-
454
- const record = await subscriptions.getByKey(subscriptionKey)
455
- expect(record?.accessKey).toEqual(generatedAccessKey)
456
- expect(record?.keyAuthorization).toBe(credential.payload.signature)
457
- expect(record?.payer?.address.toLowerCase()).toBe(rootAccount.address.toLowerCase())
458
- expect(record?.lastChargedPeriod).toBe(0)
459
-
460
- const reused = await mppx.tempo.subscription({})(new Request('https://example.com/resource'))
461
- expect(reused.status).toBe(200)
462
- expect(rpcMethods.filter((method) => method === 'eth_sendRawTransaction')).toHaveLength(1)
463
- })
464
-
465
- test('requires a fresh credential for active subscription reuse when configured', async () => {
466
- const store = Store.memory()
467
- const subscriptions = SubscriptionStore.fromStore(store)
468
- await subscriptions.put(
469
- createRecord({
470
- accessKey,
471
- payer: { address: rootAccount.address, chainId },
472
- }),
473
- )
474
- const method = subscription({
475
- activate: async () => {
476
- throw new Error('active subscription reuse should not activate')
477
- },
478
- amount: subscriptionAmount,
479
- chainId,
480
- currency: subscriptionCurrency,
481
- periodCount: subscriptionPeriodCount,
482
- periodUnit: subscriptionPeriodUnit,
483
- recipient: subscriptionRecipient,
484
- requireCredential: true,
485
- resolve: async () => ({ accessKey, key: subscriptionKey }),
486
- store,
487
- subscriptionExpires: activeSubscriptionExpires,
488
- })
489
-
490
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
491
- const unauthenticated = await mppx.tempo.subscription({})(
492
- new Request('https://example.com/resource'),
493
- )
494
-
495
- expect(unauthenticated.status).toBe(402)
496
- if (unauthenticated.status !== 402) throw new Error('expected reuse challenge')
497
-
498
- const challenge = Challenge.fromResponse(unauthenticated.challenge)
499
- const credential = await createCredential(challenge)
500
- const reused = await mppx.tempo.subscription({})(
501
- new Request('https://example.com/resource', {
502
- headers: { Authorization: Credential.serialize(credential) },
503
- }),
504
- )
505
-
506
- expect(reused.status).toBe(200)
507
- })
508
-
509
- test('can derive the subscription lookup key only from the signed credential source', async () => {
510
- const store = Store.memory()
511
- const subscriptions = SubscriptionStore.fromStore(store)
512
- const { client, rpcMethods } = createBillingClient([hashActivate])
513
- const sourceKey = (source: { address: string; chainId: number }) =>
514
- `payer:${source.chainId}:${source.address.toLowerCase()}:pro`
515
- const method = subscription({
516
- amount: subscriptionAmount,
517
- chainId,
518
- currency: subscriptionCurrency,
519
- getClient: async () => client,
520
- periodCount: subscriptionPeriodCount,
521
- periodUnit: subscriptionPeriodUnit,
522
- recipient: subscriptionRecipient,
523
- requireCredential: true,
524
- resolve: async ({ source }) => {
525
- if (!source) return null
526
- return { key: sourceKey(source) }
527
- },
528
- store,
529
- subscriptionExpires: activeSubscriptionExpires,
530
- waitForConfirmation: false,
531
- })
532
-
533
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
534
- const challengeResult = await mppx.tempo.subscription({})(
535
- new Request('https://example.com/resource'),
536
- )
537
-
538
- expect(challengeResult.status).toBe(402)
539
- if (challengeResult.status !== 402) throw new Error('expected source challenge')
540
-
541
- const challenge = Challenge.fromResponse(challengeResult.challenge)
542
- const challengeAccessKey = (
543
- challenge.request as ReturnType<typeof Methods.subscription.schema.request.parse>
544
- ).methodDetails?.accessKey
545
- if (!challengeAccessKey) throw new Error('expected challenge access key')
546
-
547
- const credential = await createCredential(challenge, rootAccount.address, challengeAccessKey)
548
- const activated = await mppx.tempo.subscription({})(
549
- new Request('https://example.com/resource', {
550
- headers: { Authorization: Credential.serialize(credential) },
551
- }),
552
- )
553
-
554
- expect(activated.status).toBe(200)
555
- const lookupKey = sourceKey({ address: rootAccount.address, chainId })
556
- const record = await subscriptions.getByKey(lookupKey)
557
- expect(record?.lookupKey).toBe(lookupKey)
558
- expect(record?.payer?.address.toLowerCase()).toBe(rootAccount.address.toLowerCase())
559
- expect(record?.accessKey).toEqual(challengeAccessKey)
560
- expect(rpcMethods.filter((method) => method === 'eth_sendRawTransaction')).toHaveLength(1)
561
- })
562
-
563
- test('rejects credential reuse when the signer does not match the stored payer', async () => {
564
- const store = Store.memory()
565
- const subscriptions = SubscriptionStore.fromStore(store)
566
- await subscriptions.put(
567
- createRecord({
568
- accessKey,
569
- payer: { address: rootAccount.address, chainId },
570
- }),
571
- )
572
- const method = subscription({
573
- activate: async () => {
574
- throw new Error('active subscription reuse should not activate')
575
- },
576
- amount: subscriptionAmount,
577
- chainId,
578
- currency: subscriptionCurrency,
579
- periodCount: subscriptionPeriodCount,
580
- periodUnit: subscriptionPeriodUnit,
581
- recipient: subscriptionRecipient,
582
- requireCredential: true,
583
- resolve: async () => ({ accessKey, key: subscriptionKey }),
584
- store,
585
- subscriptionExpires: activeSubscriptionExpires,
586
- })
587
-
588
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
589
- const challengeResult = await mppx.tempo.subscription({})(
590
- new Request('https://example.com/resource'),
591
- )
592
- if (challengeResult.status !== 402) throw new Error('expected reuse challenge')
593
-
594
- const challenge = Challenge.fromResponse(challengeResult.challenge)
595
- const credential = await createCredential(
596
- challenge,
597
- otherRootAccount.address,
598
- accessKey,
599
- otherRootAccount,
600
- )
601
- const rejected = await mppx.tempo.subscription({})(
602
- new Request('https://example.com/resource', {
603
- headers: { Authorization: Credential.serialize(credential) },
604
- }),
605
- )
606
-
607
- expect(rejected.status).toBe(402)
608
- if (rejected.status !== 402) throw new Error('expected payer mismatch challenge')
609
- const body = await rejected.challenge.json()
610
- expect(body.detail).toBe('Payment verification failed: subscription payer mismatch.')
611
- })
612
-
613
- test('renews an overdue active subscription after credential-required payer proof', async () => {
614
- const store = Store.memory()
615
- const subscriptions = SubscriptionStore.fromStore(store)
616
- await subscriptions.put(
617
- createRecord({
618
- accessKey,
619
- billingAnchor: new Date(Date.now() - 3 * subscriptionPeriodMilliseconds).toISOString(),
620
- lastChargedPeriod: 0,
621
- payer: { address: rootAccount.address, chainId },
622
- reference: hashStale,
623
- }),
624
- )
625
- const method = subscription({
626
- activate: async () => {
627
- throw new Error('active subscription renewal should not activate')
628
- },
629
- amount: subscriptionAmount,
630
- chainId,
631
- currency: subscriptionCurrency,
632
- periodCount: subscriptionPeriodCount,
633
- periodUnit: subscriptionPeriodUnit,
634
- recipient: subscriptionRecipient,
635
- renew: async ({ periodIndex, subscription }) => ({
636
- receipt: createReceipt(subscription.subscriptionId, hashRenewed),
637
- subscription: {
638
- ...subscription,
639
- lastChargedPeriod: periodIndex,
640
- reference: hashRenewed,
641
- },
642
- }),
643
- requireCredential: true,
644
- resolve: async () => ({ accessKey, key: subscriptionKey }),
645
- store,
646
- subscriptionExpires: activeSubscriptionExpires,
647
- })
648
-
649
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
650
- const challengeResult = await mppx.tempo.subscription({})(
651
- new Request('https://example.com/resource'),
652
- )
653
- if (challengeResult.status !== 402) throw new Error('expected reuse challenge')
654
-
655
- const challenge = Challenge.fromResponse(challengeResult.challenge)
656
- const credential = await createCredential(challenge)
657
- const renewed = await mppx.tempo.subscription({})(
658
- new Request('https://example.com/resource', {
659
- headers: { Authorization: Credential.serialize(credential) },
660
- }),
661
- )
662
-
663
- expect(renewed.status).toBe(200)
664
- if (renewed.status !== 200) throw new Error('expected credential renewal')
665
- const receipt = Receipt.fromResponse(renewed.withReceipt(new Response('OK')))
666
- expect(receipt.reference).toBe(hashRenewed)
667
- expect((await subscriptions.getByKey(subscriptionKey))?.lastChargedPeriod).toBeGreaterThan(0)
668
- })
669
-
670
- test('verifyCredential activates a subscription credential with a canonical challenge request', async () => {
671
- const store = Store.memory()
672
- const { client } = createBillingClient([hashActivate])
673
- const method = subscription({
674
- amount: subscriptionAmount,
675
- chainId,
676
- currency: subscriptionCurrency,
677
- getClient: async () => client,
678
- periodCount: subscriptionPeriodCount,
679
- periodUnit: subscriptionPeriodUnit,
680
- recipient: subscriptionRecipient,
681
- resolve: async () => ({ key: subscriptionKey }),
682
- store,
683
- subscriptionExpires: activeSubscriptionExpires,
684
- waitForConfirmation: false,
685
- })
686
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
687
- const challenge = await mppx.challenge.tempo.subscription({})
688
- const generatedAccessKey = (
689
- challenge.request as ReturnType<typeof Methods.subscription.schema.request.parse>
690
- ).methodDetails?.accessKey
691
- if (!generatedAccessKey) throw new Error('expected generated access key')
692
- const credential = await createCredential(challenge, rootAccount.address, generatedAccessKey)
693
-
694
- const receipt = await mppx.verifyCredential(credential)
695
-
696
- expect(receipt.status).toBe('success')
697
- expect(receipt.reference).toBe(hashActivate)
698
- })
699
-
700
- test('automatically renews overdue subscriptions on the request path', async () => {
701
- const store = Store.memory()
702
- const subscriptions = SubscriptionStore.fromStore(store)
703
- const { client, rpcMethods } = createBillingClient([hashActivate, hashRenewed])
704
- const method = subscription({
705
- amount: subscriptionAmount,
706
- chainId,
707
- currency: subscriptionCurrency,
708
- getClient: async () => client,
709
- periodCount: subscriptionPeriodCount,
710
- periodUnit: subscriptionPeriodUnit,
711
- recipient: subscriptionRecipient,
712
- resolve: async () => ({ key: subscriptionKey }),
713
- store,
714
- subscriptionExpires: activeSubscriptionExpires,
715
- waitForConfirmation: false,
716
- })
717
-
718
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
719
- const challengeResult = await mppx.tempo.subscription({})(
720
- new Request('https://example.com/resource'),
721
- )
722
- if (challengeResult.status !== 402) throw new Error('expected activation challenge')
723
- const challenge = Challenge.fromResponse(challengeResult.challenge)
724
- const accessKey = (
725
- challenge.request as ReturnType<typeof Methods.subscription.schema.request.parse>
726
- ).methodDetails?.accessKey
727
- if (!accessKey) throw new Error('expected generated access key')
728
- const credential = await createCredential(challenge, rootAccount.address, accessKey)
729
- const activated = await mppx.tempo.subscription({})(
730
- new Request('https://example.com/resource', {
731
- headers: { Authorization: Credential.serialize(credential) },
732
- }),
733
- )
734
- expect(activated.status).toBe(200)
735
-
736
- const record = await subscriptions.getByKey(subscriptionKey)
737
- if (!record) throw new Error('expected subscription record')
738
- await subscriptions.put({
739
- ...record,
740
- billingAnchor: new Date(Date.now() - 3 * subscriptionPeriodMilliseconds).toISOString(),
741
- keyAuthorization: undefined,
742
- lastChargedPeriod: 0,
743
- reference: hashStale,
744
- })
745
-
746
- const renewed = await mppx.tempo.subscription({})(new Request('https://example.com/resource'))
747
- expect(renewed.status).toBe(200)
748
- if (renewed.status !== 200) throw new Error('expected renewal')
749
-
750
- const receipt = Receipt.fromResponse(renewed.withReceipt(new Response('OK')))
751
- expect(receipt.reference).toBe(hashRenewed)
752
- expect(rpcMethods.filter((method) => method === 'eth_sendRawTransaction')).toHaveLength(2)
753
- expect((await subscriptions.get(record.subscriptionId))?.lastChargedPeriod).toBeGreaterThan(0)
754
- })
755
-
756
- async function activateConfirmedSubscription(parameters: {
757
- client: ReturnType<typeof createConfirmingBillingClient>['client']
758
- store: ReturnType<typeof Store.memory>
759
- }) {
760
- const { client, store } = parameters
761
- const method = subscription({
762
- amount: subscriptionAmount,
763
- chainId,
764
- currency: subscriptionCurrency,
765
- getClient: async () => client,
766
- periodCount: subscriptionPeriodCount,
767
- periodUnit: subscriptionPeriodUnit,
768
- recipient: subscriptionRecipient,
769
- resolve: async () => ({ key: subscriptionKey }),
770
- store,
771
- subscriptionExpires: activeSubscriptionExpires,
772
- })
773
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
774
- const challengeResult = await mppx.tempo.subscription({})(
775
- new Request('https://example.com/resource'),
776
- )
777
- if (challengeResult.status !== 402) throw new Error('expected activation challenge')
778
- const challenge = Challenge.fromResponse(challengeResult.challenge)
779
- const accessKey = (
780
- challenge.request as ReturnType<typeof Methods.subscription.schema.request.parse>
781
- ).methodDetails?.accessKey
782
- if (!accessKey) throw new Error('expected generated access key')
783
- const credential = await createCredential(challenge, rootAccount.address, accessKey)
784
- const activated = await mppx.tempo.subscription({})(
785
- new Request('https://example.com/resource', {
786
- headers: { Authorization: Credential.serialize(credential) },
787
- }),
788
- )
789
- expect(activated.status).toBe(200)
790
- return { mppx }
791
- }
792
-
793
- test('renews when the confirmed receipt credits the recipient', async () => {
794
- const store = Store.memory()
795
- const subscriptions = SubscriptionStore.fromStore(store)
796
- const { client } = createConfirmingBillingClient()
797
- const { mppx } = await activateConfirmedSubscription({ client, store })
798
-
799
- const record = await subscriptions.getByKey(subscriptionKey)
800
- if (!record) throw new Error('expected subscription record')
801
- await subscriptions.put({
802
- ...record,
803
- billingAnchor: new Date(Date.now() - 3 * subscriptionPeriodMilliseconds).toISOString(),
804
- lastChargedPeriod: 0,
805
- })
806
-
807
- const renewed = await mppx.tempo.subscription({})(new Request('https://example.com/resource'))
808
- expect(renewed.status).toBe(200)
809
- expect((await subscriptions.get(record.subscriptionId))?.lastChargedPeriod).toBeGreaterThan(0)
810
- })
811
-
812
- test('rejects renewal when a receive policy holds the confirmed transfer', async () => {
813
- const store = Store.memory()
814
- const subscriptions = SubscriptionStore.fromStore(store)
815
- const { client } = createConfirmingBillingClient({ redirectTo: receivePolicyGuard })
816
- const { mppx } = await activateConfirmedSubscription({ client, store })
817
-
818
- const record = await subscriptions.getByKey(subscriptionKey)
819
- if (!record) throw new Error('expected subscription record')
820
- await subscriptions.put({
821
- ...record,
822
- billingAnchor: new Date(Date.now() - 3 * subscriptionPeriodMilliseconds).toISOString(),
823
- lastChargedPeriod: 0,
824
- })
825
-
826
- const renewed = await mppx.tempo.subscription({})(new Request('https://example.com/resource'))
827
- expect(renewed.status).toBe(402)
828
- // The held renewal must not advance the billing period.
829
- expect((await subscriptions.get(record.subscriptionId))?.lastChargedPeriod).toBe(0)
830
- })
831
-
832
- test('rejects a held renewal even when a memo-less Transfer credits the recipient', async () => {
833
- const store = Store.memory()
834
- const subscriptions = SubscriptionStore.fromStore(store)
835
- // Settlement is held, but the receipt also has a memo-less Transfer to the
836
- // recipient; the memo-bound check must still reject it.
837
- const { client } = createConfirmingBillingClient({
838
- addUnrelatedTransfer: true,
839
- redirectTo: receivePolicyGuard,
840
- })
841
- const { mppx } = await activateConfirmedSubscription({ client, store })
842
-
843
- const record = await subscriptions.getByKey(subscriptionKey)
844
- if (!record) throw new Error('expected subscription record')
845
- await subscriptions.put({
846
- ...record,
847
- billingAnchor: new Date(Date.now() - 3 * subscriptionPeriodMilliseconds).toISOString(),
848
- lastChargedPeriod: 0,
849
- })
850
-
851
- const renewed = await mppx.tempo.subscription({})(new Request('https://example.com/resource'))
852
- expect(renewed.status).toBe(402)
853
- expect((await subscriptions.get(record.subscriptionId))?.lastChargedPeriod).toBe(0)
854
- })
855
-
856
- test('rejects activation when a receive policy holds the confirmed transfer', async () => {
857
- const store = Store.memory()
858
- const subscriptions = SubscriptionStore.fromStore(store)
859
- const { client } = createConfirmingBillingClient({
860
- redirectActivation: true,
861
- redirectTo: receivePolicyGuard,
862
- })
863
- const method = subscription({
864
- amount: subscriptionAmount,
865
- chainId,
866
- currency: subscriptionCurrency,
867
- getClient: async () => client,
868
- periodCount: subscriptionPeriodCount,
869
- periodUnit: subscriptionPeriodUnit,
870
- recipient: subscriptionRecipient,
871
- resolve: async () => ({ key: subscriptionKey }),
872
- store,
873
- subscriptionExpires: activeSubscriptionExpires,
874
- })
875
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
876
- const challengeResult = await mppx.tempo.subscription({})(
877
- new Request('https://example.com/resource'),
878
- )
879
- if (challengeResult.status !== 402) throw new Error('expected activation challenge')
880
- const challenge = Challenge.fromResponse(challengeResult.challenge)
881
- const generatedAccessKey = (
882
- challenge.request as ReturnType<typeof Methods.subscription.schema.request.parse>
883
- ).methodDetails?.accessKey
884
- if (!generatedAccessKey) throw new Error('expected generated access key')
885
- const credential = await createCredential(challenge, rootAccount.address, generatedAccessKey)
886
- const activated = await mppx.tempo.subscription({})(
887
- new Request('https://example.com/resource', {
888
- headers: { Authorization: Credential.serialize(credential) },
889
- }),
890
- )
891
-
892
- expect(activated.status).toBe(402)
893
- // A held activation must not persist an active subscription.
894
- expect(await subscriptions.getByKey(subscriptionKey)).toBeNull()
895
- })
896
-
897
- test('returns a management response while renewal is already in flight', async () => {
898
- const store = Store.memory()
899
- const subscriptions = SubscriptionStore.fromStore(store)
900
- const method = subscription({
901
- accessKey: async () => accessKey,
902
- activate: async () => ({
903
- receipt: createReceipt('unused'),
904
- subscription: createRecord({ subscriptionId: 'unused' }),
905
- }),
906
- amount: subscriptionAmount,
907
- chainId,
908
- currency: subscriptionCurrency,
909
- periodCount: subscriptionPeriodCount,
910
- periodUnit: subscriptionPeriodUnit,
911
- recipient: subscriptionRecipient,
912
- resolve: async () => ({ key: subscriptionKey }),
913
- renew: async () => {
914
- throw new Error('renew should not run')
915
- },
916
- store,
917
- subscriptionExpires: activeSubscriptionExpires,
918
- })
919
- await subscriptions.put(
920
- createRecord({
921
- billingAnchor: new Date(Date.now() - 3 * subscriptionPeriodMilliseconds).toISOString(),
922
- inFlightPeriod: 1,
923
- inFlightStartedAt: new Date().toISOString(),
924
- lastChargedPeriod: 0,
925
- subscriptionId: 'sub_due',
926
- }),
927
- )
928
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
929
-
930
- const result = await mppx.tempo.subscription({})(new Request('https://example.com/resource'))
931
-
932
- expect(result.status).toBe(200)
933
- if (result.status !== 200) throw new Error('expected management response')
934
- const response = (result.withReceipt as () => Response)()
935
- expect(response.status).toBe(409)
936
- expect(response.headers.get('Retry-After')).toBe('1')
937
- })
938
-
939
- test('does not authorize an active subscription whose request binding differs', async () => {
940
- const store = Store.memory()
941
- const subscriptions = SubscriptionStore.fromStore(store)
942
- await subscriptions.put(
943
- createRecord({
944
- accessKey,
945
- amount: '1000000',
946
- lookupKey: subscriptionKey,
947
- subscriptionId: 'sub_basic',
948
- }),
949
- )
950
- const method = subscription({
951
- accessKey: async () => accessKey,
952
- activate: async () => ({
953
- receipt: createReceipt('sub_unused'),
954
- subscription: createRecord({ subscriptionId: 'sub_unused' }),
955
- }),
956
- amount: subscriptionAmount,
957
- chainId,
958
- currency: subscriptionCurrency,
959
- periodCount: subscriptionPeriodCount,
960
- periodUnit: subscriptionPeriodUnit,
961
- recipient: subscriptionRecipient,
962
- resolve: async () => ({ key: subscriptionKey }),
963
- store,
964
- subscriptionExpires: activeSubscriptionExpires,
965
- })
966
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
967
-
968
- const result = await mppx.tempo.subscription({})(new Request('https://example.com/resource'))
969
-
970
- expect(result.status).toBe(402)
971
- })
972
-
973
- test('requires an access key before issuing a subscription challenge', async () => {
974
- const method = subscription({
975
- activate: async () => ({
976
- receipt: createReceipt('unused'),
977
- subscription: createRecord({ subscriptionId: 'unused' }),
978
- }),
979
- amount: subscriptionAmount,
980
- chainId,
981
- currency: subscriptionCurrency,
982
- periodCount: subscriptionPeriodCount,
983
- periodUnit: subscriptionPeriodUnit,
984
- recipient: subscriptionRecipient,
985
- resolve: async () => ({ key: subscriptionKey }),
986
- store: Store.memory(),
987
- subscriptionExpires: activeSubscriptionExpires,
988
- })
989
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
990
-
991
- const result = await mppx.tempo.subscription({})(new Request('https://example.com/resource'))
992
- expect(result.status).toBe(402)
993
- if (result.status !== 402) throw new Error('expected challenge')
994
- const body = (await result.challenge.json()) as { detail?: string }
995
- expect(body.detail).toBe('Payment verification failed: subscription accessKey is missing.')
996
- })
997
-
998
- test('defaults omitted subscription chainId to Tempo testnet', async () => {
999
- const method = subscription({
1000
- accessKey: async () => accessKey,
1001
- activate: async () => ({
1002
- receipt: createReceipt('unused'),
1003
- subscription: createRecord({ subscriptionId: 'unused' }),
1004
- }),
1005
- amount: subscriptionAmount,
1006
- currency: subscriptionCurrency,
1007
- periodCount: subscriptionPeriodCount,
1008
- periodUnit: subscriptionPeriodUnit,
1009
- recipient: subscriptionRecipient,
1010
- resolve: async () => ({ key: subscriptionKey }),
1011
- store: Store.memory(),
1012
- subscriptionExpires: activeSubscriptionExpires,
1013
- })
1014
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
1015
- const challengeResult = await mppx.tempo.subscription({})(
1016
- new Request('https://example.com/resource'),
1017
- )
1018
- if (challengeResult.status !== 402) throw new Error('expected activation challenge')
1019
-
1020
- const challenge = Challenge.fromResponse(challengeResult.challenge)
1021
- const challengeRequest = challenge.request as ReturnType<
1022
- typeof Methods.subscription.schema.request.parse
1023
- >
1024
- expect(challengeRequest.methodDetails?.chainId).toBe(subscriptionDefaultChainId)
1025
- })
1026
-
1027
- test('reuses a stored active subscription access key without a resolver callback', async () => {
1028
- const store = Store.memory()
1029
- const subscriptions = SubscriptionStore.fromStore(store)
1030
- await subscriptions.put(createRecord({ accessKey, lookupKey: subscriptionKey }))
1031
- const method = subscription({
1032
- activate: async () => ({
1033
- receipt: createReceipt('unused'),
1034
- subscription: createRecord({ subscriptionId: 'unused' }),
1035
- }),
1036
- amount: subscriptionAmount,
1037
- chainId,
1038
- currency: subscriptionCurrency,
1039
- periodCount: subscriptionPeriodCount,
1040
- periodUnit: subscriptionPeriodUnit,
1041
- recipient: subscriptionRecipient,
1042
- resolve: async () => ({ key: subscriptionKey }),
1043
- store,
1044
- subscriptionExpires: activeSubscriptionExpires,
1045
- })
1046
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
1047
-
1048
- const reused = await mppx.tempo.subscription({})(new Request('https://example.com/resource'))
1049
-
1050
- expect(reused.status).toBe(200)
1051
- })
1052
-
1053
- test('serializes concurrent fresh activations for the same lookup key', async () => {
1054
- const store = Store.memory()
1055
- let activationCount = 0
1056
- let releaseActivation!: () => void
1057
- let markActivationStarted!: () => void
1058
- const activationStarted = new Promise<void>((resolve) => {
1059
- markActivationStarted = resolve
1060
- })
1061
- const activationReleased = new Promise<void>((resolve) => {
1062
- releaseActivation = resolve
1063
- })
1064
- const method = subscription({
1065
- accessKey: async () => accessKey,
1066
- activate: async ({ request, resolved }) => {
1067
- activationCount += 1
1068
- markActivationStarted()
1069
- await activationReleased
1070
- return {
1071
- receipt: createReceipt('sub_123', hashActivate),
1072
- subscription: createRecord({
1073
- amount: request.amount,
1074
- chainId: request.methodDetails?.chainId,
1075
- currency: request.currency,
1076
- lookupKey: resolved.key,
1077
- periodCount: request.periodCount,
1078
- periodUnit: request.periodUnit,
1079
- recipient: request.recipient,
1080
- reference: hashActivate,
1081
- subscriptionExpires: request.subscriptionExpires,
1082
- }),
1083
- }
1084
- },
1085
- amount: subscriptionAmount,
1086
- chainId,
1087
- currency: subscriptionCurrency,
1088
- periodCount: subscriptionPeriodCount,
1089
- periodUnit: subscriptionPeriodUnit,
1090
- recipient: subscriptionRecipient,
1091
- resolve: async () => ({ key: subscriptionKey }),
1092
- store,
1093
- subscriptionExpires: activeSubscriptionExpires,
1094
- })
1095
-
1096
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
1097
- const firstChallengeResult = await mppx.tempo.subscription({
1098
- expires: '2027-01-01T00:01:00.000Z',
1099
- })(new Request('https://example.com/resource'))
1100
- const secondChallengeResult = await mppx.tempo.subscription({
1101
- expires: '2027-01-01T00:02:00.000Z',
1102
- })(new Request('https://example.com/resource'))
1103
- if (firstChallengeResult.status !== 402 || secondChallengeResult.status !== 402) {
1104
- throw new Error('expected activation challenges')
1105
- }
1106
-
1107
- const firstChallenge = Challenge.fromResponse(firstChallengeResult.challenge)
1108
- const secondChallenge = Challenge.fromResponse(secondChallengeResult.challenge)
1109
- expect(firstChallenge.id).not.toBe(secondChallenge.id)
1110
-
1111
- const firstCredential = await createCredential(firstChallenge)
1112
- const secondCredential = await createCredential(secondChallenge)
1113
- const firstActivation = mppx.tempo.subscription({})(
1114
- new Request('https://example.com/resource', {
1115
- headers: { Authorization: Credential.serialize(firstCredential) },
1116
- }),
1117
- )
1118
- await activationStarted
1119
-
1120
- const secondActivation = await mppx.tempo.subscription({})(
1121
- new Request('https://example.com/resource', {
1122
- headers: { Authorization: Credential.serialize(secondCredential) },
1123
- }),
1124
- )
1125
- releaseActivation()
1126
- const activated = await firstActivation
1127
-
1128
- expect(activated.status).toBe(200)
1129
- expect(secondActivation.status).toBe(402)
1130
- expect(activationCount).toBe(1)
1131
- })
1132
-
1133
- test('allows retry after a stale failed activation attempt', async () => {
1134
- const store = Store.memory()
1135
- let activationCount = 0
1136
- const method = subscription({
1137
- accessKey: async () => accessKey,
1138
- activationTimeoutMs: 0,
1139
- activate: async ({ request, resolved }) => {
1140
- activationCount += 1
1141
- if (activationCount === 1) throw new Error('activation failed before charge')
1142
- return {
1143
- receipt: createReceipt('sub_123', hashActivate),
1144
- subscription: createRecord({
1145
- amount: request.amount,
1146
- chainId: request.methodDetails?.chainId,
1147
- currency: request.currency,
1148
- lookupKey: resolved.key,
1149
- periodCount: request.periodCount,
1150
- periodUnit: request.periodUnit,
1151
- recipient: request.recipient,
1152
- reference: hashActivate,
1153
- subscriptionExpires: request.subscriptionExpires,
1154
- }),
1155
- }
1156
- },
1157
- amount: subscriptionAmount,
1158
- chainId,
1159
- currency: subscriptionCurrency,
1160
- periodCount: subscriptionPeriodCount,
1161
- periodUnit: subscriptionPeriodUnit,
1162
- recipient: subscriptionRecipient,
1163
- resolve: async () => ({ key: subscriptionKey }),
1164
- store,
1165
- subscriptionExpires: activeSubscriptionExpires,
1166
- })
1167
-
1168
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
1169
- const firstChallengeResult = await mppx.tempo.subscription({
1170
- expires: '2027-01-01T00:03:00.000Z',
1171
- })(new Request('https://example.com/resource'))
1172
- const secondChallengeResult = await mppx.tempo.subscription({
1173
- expires: '2027-01-01T00:04:00.000Z',
1174
- })(new Request('https://example.com/resource'))
1175
- if (firstChallengeResult.status !== 402 || secondChallengeResult.status !== 402) {
1176
- throw new Error('expected activation challenges')
1177
- }
1178
-
1179
- const firstCredential = await createCredential(
1180
- Challenge.fromResponse(firstChallengeResult.challenge),
1181
- )
1182
- const firstRejected = await mppx.tempo.subscription({})(
1183
- new Request('https://example.com/resource', {
1184
- headers: { Authorization: Credential.serialize(firstCredential) },
1185
- }),
1186
- )
1187
- expect(firstRejected.status).toBe(402)
1188
-
1189
- const secondCredential = await createCredential(
1190
- Challenge.fromResponse(secondChallengeResult.challenge),
1191
- )
1192
- const retried = await mppx.tempo.subscription({})(
1193
- new Request('https://example.com/resource', {
1194
- headers: { Authorization: Credential.serialize(secondCredential) },
1195
- }),
1196
- )
1197
-
1198
- expect(retried.status).toBe(200)
1199
- expect(activationCount).toBe(2)
1200
- })
1201
-
1202
- test('new activation replaces the previous subscription for the same lookup key', async () => {
1203
- const store = Store.memory()
1204
- const subscriptions = SubscriptionStore.fromStore(store)
1205
-
1206
- // Seed an expired subscription so authorize() falls through to a new challenge.
1207
- const expiredDate = new Date(Date.now() - 1_000).toISOString()
1208
- await subscriptions.put(
1209
- createRecord({
1210
- lookupKey: subscriptionKey,
1211
- subscriptionId: 'sub_old',
1212
- reference: hashOld,
1213
- subscriptionExpires: expiredDate,
1214
- }),
1215
- )
1216
-
1217
- const method = subscription({
1218
- accessKey: async () => accessKey,
1219
- activate: async ({ request, resolved }) => ({
1220
- receipt: createReceipt('sub_new', hashActivate),
1221
- subscription: createRecord({
1222
- amount: request.amount,
1223
- chainId: request.methodDetails?.chainId,
1224
- currency: request.currency,
1225
- lookupKey: resolved.key,
1226
- periodCount: request.periodCount,
1227
- periodUnit: request.periodUnit,
1228
- recipient: request.recipient,
1229
- reference: hashActivate,
1230
- subscriptionExpires: request.subscriptionExpires,
1231
- subscriptionId: 'sub_new',
1232
- }),
1233
- }),
1234
- amount: subscriptionAmount,
1235
- chainId,
1236
- currency: subscriptionCurrency,
1237
- periodCount: subscriptionPeriodCount,
1238
- periodUnit: subscriptionPeriodUnit,
1239
- recipient: subscriptionRecipient,
1240
- resolve: async () => ({ key: subscriptionKey }),
1241
- store,
1242
- subscriptionExpires: activeSubscriptionExpires,
1243
- })
1244
-
1245
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
1246
-
1247
- const challengeResult = await mppx.tempo.subscription({})(
1248
- new Request('https://example.com/resource'),
1249
- )
1250
- expect(challengeResult.status).toBe(402)
1251
- if (challengeResult.status !== 402) throw new Error('expected challenge')
1252
-
1253
- const challenge = Challenge.fromResponse(challengeResult.challenge)
1254
- const credential = await createCredential(challenge)
1255
-
1256
- const activated = await mppx.tempo.subscription({})(
1257
- new Request('https://example.com/resource', {
1258
- headers: {
1259
- Authorization: Credential.serialize(credential),
1260
- 'X-Subscription-Key': subscriptionKey,
1261
- },
1262
- }),
1263
- )
1264
- expect(activated.status).toBe(200)
1265
- if (activated.status !== 200) throw new Error('expected activation')
1266
-
1267
- const receipt = Receipt.fromResponse(activated.withReceipt(new Response('OK')))
1268
- expect(receipt.subscriptionId).toBe('sub_new')
1269
-
1270
- const current = await subscriptions.getByKey(subscriptionKey)
1271
- expect(current?.subscriptionId).toBe('sub_new')
1272
- })
1273
-
1274
- test('does not reuse an active subscription whose request binding differs during verify', async () => {
1275
- const store = Store.memory()
1276
- const subscriptions = SubscriptionStore.fromStore(store)
1277
- let activationCount = 0
1278
- await subscriptions.put(
1279
- createRecord({
1280
- accessKey,
1281
- amount: '1000000',
1282
- lookupKey: subscriptionKey,
1283
- subscriptionId: 'sub_basic',
1284
- }),
1285
- )
1286
- const method = subscription({
1287
- accessKey: async () => accessKey,
1288
- activate: async ({ request, resolved }) => {
1289
- activationCount += 1
1290
- return {
1291
- receipt: createReceipt('sub_premium'),
1292
- subscription: createRecord({
1293
- amount: request.amount,
1294
- chainId: request.methodDetails?.chainId,
1295
- currency: request.currency,
1296
- lookupKey: resolved.key,
1297
- periodCount: request.periodCount,
1298
- periodUnit: request.periodUnit,
1299
- recipient: request.recipient,
1300
- subscriptionExpires: request.subscriptionExpires,
1301
- subscriptionId: 'sub_premium',
1302
- }),
1303
- }
1304
- },
1305
- amount: subscriptionAmount,
1306
- chainId,
1307
- currency: subscriptionCurrency,
1308
- periodCount: subscriptionPeriodCount,
1309
- periodUnit: subscriptionPeriodUnit,
1310
- recipient: subscriptionRecipient,
1311
- resolve: async () => ({ key: subscriptionKey }),
1312
- store,
1313
- subscriptionExpires: activeSubscriptionExpires,
1314
- })
1315
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
1316
- const challengeResult = await mppx.tempo.subscription({})(
1317
- new Request('https://example.com/resource'),
1318
- )
1319
- if (challengeResult.status !== 402) throw new Error('expected activation challenge')
1320
-
1321
- const credential = await createCredential(Challenge.fromResponse(challengeResult.challenge))
1322
- const activated = await mppx.tempo.subscription({})(
1323
- new Request('https://example.com/resource', {
1324
- headers: { Authorization: Credential.serialize(credential) },
1325
- }),
1326
- )
1327
-
1328
- expect(activated.status).toBe(200)
1329
- expect(activationCount).toBe(1)
1330
- if (activated.status !== 200) throw new Error('expected activation')
1331
- const receipt = Receipt.fromResponse(activated.withReceipt(new Response('OK')))
1332
- expect(receipt.subscriptionId).toBe('sub_premium')
1333
- })
1334
-
1335
- test('does not reuse an overdue subscription during verify', async () => {
1336
- const store = Store.memory()
1337
- const subscriptions = SubscriptionStore.fromStore(store)
1338
- let activationCount = 0
1339
- await subscriptions.put(
1340
- createRecord({
1341
- accessKey,
1342
- billingAnchor: new Date(Date.now() - 3 * subscriptionPeriodMilliseconds).toISOString(),
1343
- lastChargedPeriod: 0,
1344
- lookupKey: subscriptionKey,
1345
- reference: hashStale,
1346
- subscriptionId: 'sub_due',
1347
- }),
1348
- )
1349
- const method = subscription({
1350
- accessKey: async () => accessKey,
1351
- activate: async () => {
1352
- activationCount += 1
1353
- throw new Error('overdue subscription must renew')
1354
- },
1355
- amount: subscriptionAmount,
1356
- chainId,
1357
- currency: subscriptionCurrency,
1358
- periodCount: subscriptionPeriodCount,
1359
- periodUnit: subscriptionPeriodUnit,
1360
- recipient: subscriptionRecipient,
1361
- resolve: async () => ({ key: subscriptionKey }),
1362
- store,
1363
- subscriptionExpires: activeSubscriptionExpires,
1364
- })
1365
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
1366
- const challengeResult = await mppx.tempo.subscription({})(
1367
- new Request('https://example.com/resource'),
1368
- )
1369
- if (challengeResult.status !== 402) throw new Error('expected activation challenge')
1370
-
1371
- const credential = await createCredential(Challenge.fromResponse(challengeResult.challenge))
1372
- const rejected = await mppx.tempo.subscription({})(
1373
- new Request('https://example.com/resource', {
1374
- headers: { Authorization: Credential.serialize(credential) },
1375
- }),
1376
- )
1377
-
1378
- expect(rejected.status).toBe(402)
1379
- expect(activationCount).toBe(1)
1380
- })
1381
-
1382
- test('rejects activation when the dynamic access key does not match the credential', async () => {
1383
- const store = Store.memory()
1384
- const activateCalls: unknown[] = []
1385
- const method = subscription({
1386
- accessKey: async () => ({
1387
- accessKeyAddress: accessAccount.address,
1388
- keyType: 'p256',
1389
- }),
1390
- activate: async (parameters) => {
1391
- activateCalls.push(parameters)
1392
- return {
1393
- receipt: createReceipt('sub_unused'),
1394
- subscription: createRecord({ subscriptionId: 'sub_unused' }),
1395
- }
1396
- },
1397
- amount: subscriptionAmount,
1398
- chainId,
1399
- currency: subscriptionCurrency,
1400
- periodCount: subscriptionPeriodCount,
1401
- periodUnit: subscriptionPeriodUnit,
1402
- recipient: subscriptionRecipient,
1403
- resolve: async () => ({ key: subscriptionKey }),
1404
- store,
1405
- subscriptionExpires: activeSubscriptionExpires,
1406
- })
1407
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
1408
- const challengeResult = await mppx.tempo.subscription({})(
1409
- new Request('https://example.com/resource'),
1410
- )
1411
- if (challengeResult.status !== 402) throw new Error('expected activation challenge')
1412
-
1413
- const challenge = Challenge.fromResponse(challengeResult.challenge)
1414
- const credential = await createCredential(challenge)
1415
- const rejected = await mppx.tempo.subscription({})(
1416
- new Request('https://example.com/resource', {
1417
- headers: { Authorization: Credential.serialize(credential) },
1418
- }),
1419
- )
1420
-
1421
- expect(rejected.status).toBe(402)
1422
- expect(activateCalls.length).toBe(0)
1423
- })
1424
-
1425
- test('rejects activation settlements that do not match the challenged request', async () => {
1426
- const store = Store.memory()
1427
- const subscriptions = SubscriptionStore.fromStore(store)
1428
- const method = subscription({
1429
- accessKey: async () => accessKey,
1430
- activate: async ({ request, resolved }) => ({
1431
- receipt: createReceipt('sub_bad', hashActivate),
1432
- subscription: createRecord({
1433
- amount: String(BigInt(request.amount) + 1n),
1434
- chainId: request.methodDetails?.chainId,
1435
- currency: request.currency,
1436
- lookupKey: resolved.key,
1437
- periodCount: request.periodCount,
1438
- periodUnit: request.periodUnit,
1439
- recipient: request.recipient,
1440
- reference: hashActivate,
1441
- subscriptionExpires: request.subscriptionExpires,
1442
- subscriptionId: 'sub_bad',
1443
- }),
1444
- }),
1445
- amount: subscriptionAmount,
1446
- chainId,
1447
- currency: subscriptionCurrency,
1448
- periodCount: subscriptionPeriodCount,
1449
- periodUnit: subscriptionPeriodUnit,
1450
- recipient: subscriptionRecipient,
1451
- resolve: async () => ({ key: subscriptionKey }),
1452
- store,
1453
- subscriptionExpires: activeSubscriptionExpires,
1454
- })
1455
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
1456
- const challengeResult = await mppx.tempo.subscription({})(
1457
- new Request('https://example.com/resource'),
1458
- )
1459
- if (challengeResult.status !== 402) throw new Error('expected activation challenge')
1460
-
1461
- const challenge = Challenge.fromResponse(challengeResult.challenge)
1462
- const credential = await createCredential(challenge)
1463
- const rejected = await mppx.tempo.subscription({})(
1464
- new Request('https://example.com/resource', {
1465
- headers: { Authorization: Credential.serialize(credential) },
1466
- }),
1467
- )
1468
-
1469
- expect(rejected.status).toBe(402)
1470
- expect(await subscriptions.getByKey(subscriptionKey)).toBe(null)
1471
- })
1472
-
1473
- test('rejects activation settlements with a mismatched chainId', async () => {
1474
- const store = Store.memory()
1475
- const subscriptions = SubscriptionStore.fromStore(store)
1476
- const method = subscription({
1477
- accessKey: async () => accessKey,
1478
- activate: async ({ request, resolved }) => ({
1479
- receipt: createReceipt('sub_bad', hashActivate),
1480
- subscription: createRecord({
1481
- amount: request.amount,
1482
- chainId: chainId + 1,
1483
- currency: request.currency,
1484
- lookupKey: resolved.key,
1485
- periodCount: request.periodCount,
1486
- periodUnit: request.periodUnit,
1487
- recipient: request.recipient,
1488
- reference: hashActivate,
1489
- subscriptionExpires: request.subscriptionExpires,
1490
- subscriptionId: 'sub_bad',
1491
- }),
1492
- }),
1493
- amount: subscriptionAmount,
1494
- chainId,
1495
- currency: subscriptionCurrency,
1496
- periodCount: subscriptionPeriodCount,
1497
- periodUnit: subscriptionPeriodUnit,
1498
- recipient: subscriptionRecipient,
1499
- resolve: async () => ({ key: subscriptionKey }),
1500
- store,
1501
- subscriptionExpires: activeSubscriptionExpires,
1502
- })
1503
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
1504
- const challengeResult = await mppx.tempo.subscription({})(
1505
- new Request('https://example.com/resource'),
1506
- )
1507
- if (challengeResult.status !== 402) throw new Error('expected activation challenge')
1508
-
1509
- const challenge = Challenge.fromResponse(challengeResult.challenge)
1510
- const credential = await createCredential(challenge)
1511
- const rejected = await mppx.tempo.subscription({})(
1512
- new Request('https://example.com/resource', {
1513
- headers: { Authorization: Credential.serialize(credential) },
1514
- }),
1515
- )
1516
-
1517
- expect(rejected.status).toBe(402)
1518
- expect(await subscriptions.getByKey(subscriptionKey)).toBe(null)
1519
- })
1520
-
1521
- test('rejects activation settlements with a mismatched externalId', async () => {
1522
- const store = Store.memory()
1523
- const subscriptions = SubscriptionStore.fromStore(store)
1524
- const method = subscription({
1525
- accessKey: async () => accessKey,
1526
- activate: async ({ request, resolved }) => ({
1527
- receipt: createReceipt('sub_bad', hashActivate),
1528
- subscription: createRecord({
1529
- amount: request.amount,
1530
- chainId: request.methodDetails?.chainId,
1531
- currency: request.currency,
1532
- externalId: 'external_2',
1533
- lookupKey: resolved.key,
1534
- periodCount: request.periodCount,
1535
- periodUnit: request.periodUnit,
1536
- recipient: request.recipient,
1537
- reference: hashActivate,
1538
- subscriptionExpires: request.subscriptionExpires,
1539
- subscriptionId: 'sub_bad',
1540
- }),
1541
- }),
1542
- amount: subscriptionAmount,
1543
- chainId,
1544
- currency: subscriptionCurrency,
1545
- externalId: 'external_1',
1546
- periodCount: subscriptionPeriodCount,
1547
- periodUnit: subscriptionPeriodUnit,
1548
- recipient: subscriptionRecipient,
1549
- resolve: async () => ({ key: subscriptionKey }),
1550
- store,
1551
- subscriptionExpires: activeSubscriptionExpires,
1552
- })
1553
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
1554
- const challengeResult = await mppx.tempo.subscription({})(
1555
- new Request('https://example.com/resource'),
1556
- )
1557
- if (challengeResult.status !== 402) throw new Error('expected activation challenge')
1558
-
1559
- const challenge = Challenge.fromResponse(challengeResult.challenge)
1560
- const credential = await createCredential(challenge)
1561
- const rejected = await mppx.tempo.subscription({})(
1562
- new Request('https://example.com/resource', {
1563
- headers: { Authorization: Credential.serialize(credential) },
1564
- }),
1565
- )
1566
-
1567
- expect(rejected.status).toBe(402)
1568
- expect(await subscriptions.getByKey(subscriptionKey)).toBe(null)
1569
- })
1570
-
1571
- test('rejects credentials when the current request externalId differs from the challenge', async () => {
1572
- const store = Store.memory()
1573
- let activationCount = 0
1574
- const method = subscription({
1575
- accessKey: async () => accessKey,
1576
- activate: async ({ request, resolved }) => {
1577
- activationCount += 1
1578
- return {
1579
- receipt: createReceipt('sub_unused'),
1580
- subscription: createRecord({
1581
- amount: request.amount,
1582
- chainId: request.methodDetails?.chainId,
1583
- currency: request.currency,
1584
- externalId: request.externalId,
1585
- lookupKey: resolved.key,
1586
- periodCount: request.periodCount,
1587
- periodUnit: request.periodUnit,
1588
- recipient: request.recipient,
1589
- subscriptionExpires: request.subscriptionExpires,
1590
- subscriptionId: 'sub_unused',
1591
- }),
1592
- }
1593
- },
1594
- amount: subscriptionAmount,
1595
- chainId,
1596
- currency: subscriptionCurrency,
1597
- periodCount: subscriptionPeriodCount,
1598
- periodUnit: subscriptionPeriodUnit,
1599
- recipient: subscriptionRecipient,
1600
- resolve: async () => ({ key: subscriptionKey }),
1601
- store,
1602
- subscriptionExpires: activeSubscriptionExpires,
1603
- })
1604
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
1605
- const challengeResult = await mppx.tempo.subscription({ externalId: 'external_1' })(
1606
- new Request('https://example.com/resource'),
1607
- )
1608
- if (challengeResult.status !== 402) throw new Error('expected activation challenge')
1609
-
1610
- const credential = await createCredential(Challenge.fromResponse(challengeResult.challenge))
1611
- const rejected = await mppx.tempo.subscription({ externalId: 'external_2' })(
1612
- new Request('https://example.com/resource', {
1613
- headers: { Authorization: Credential.serialize(credential) },
1614
- }),
1615
- )
1616
-
1617
- expect(rejected.status).toBe(402)
1618
- expect(activationCount).toBe(0)
1619
- })
1620
-
1621
- test('rejects credentials whose declared source does not match the key authorization signer', async () => {
1622
- const store = Store.memory()
1623
- const activateCalls: unknown[] = []
1624
- const method = subscription({
1625
- accessKey: async () => accessKey,
1626
- activate: async (parameters) => {
1627
- activateCalls.push(parameters)
1628
- return {
1629
- receipt: createReceipt('sub_unused'),
1630
- subscription: createRecord({ subscriptionId: 'sub_unused' }),
1631
- }
1632
- },
1633
- amount: subscriptionAmount,
1634
- chainId,
1635
- currency: subscriptionCurrency,
1636
- periodCount: subscriptionPeriodCount,
1637
- periodUnit: subscriptionPeriodUnit,
1638
- recipient: subscriptionRecipient,
1639
- resolve: async () => ({ key: subscriptionKey }),
1640
- store,
1641
- subscriptionExpires: activeSubscriptionExpires,
1642
- })
1643
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
1644
- const challengeResult = await mppx.tempo.subscription({})(
1645
- new Request('https://example.com/resource'),
1646
- )
1647
- if (challengeResult.status !== 402) throw new Error('expected activation challenge')
1648
-
1649
- const challenge = Challenge.fromResponse(challengeResult.challenge)
1650
- const credential = await createCredential(challenge, otherAccessAccount.address)
1651
- const rejected = await mppx.tempo.subscription({})(
1652
- new Request('https://example.com/resource', {
1653
- headers: { Authorization: Credential.serialize(credential) },
1654
- }),
1655
- )
1656
-
1657
- expect(rejected.status).toBe(402)
1658
- expect(activateCalls.length).toBe(0)
1659
- })
1660
-
1661
- test('renews an overdue matching subscription before falling back to 402', async () => {
1662
- const store = Store.memory()
1663
- const subscriptions = SubscriptionStore.fromStore(store)
1664
- const renewCalls: number[] = []
1665
- const renewalReferences: string[] = []
1666
- const method = subscription({
1667
- accessKey: async () => accessKey,
1668
- activate: async () => ({
1669
- receipt: createReceipt('unused'),
1670
- subscription: createRecord({ subscriptionId: 'unused' }),
1671
- }),
1672
- amount: subscriptionAmount,
1673
- chainId,
1674
- currency: subscriptionCurrency,
1675
- periodCount: subscriptionPeriodCount,
1676
- periodUnit: subscriptionPeriodUnit,
1677
- recipient: subscriptionRecipient,
1678
- resolve: async () => ({ key: subscriptionKey }),
1679
- renew: async ({ inFlightReference, periodIndex, subscription }) => {
1680
- renewCalls.push(periodIndex)
1681
- renewalReferences.push(inFlightReference)
1682
- expect(subscription.inFlightReference).toBe(inFlightReference)
1683
- return {
1684
- receipt: createReceipt(subscription.subscriptionId, hashRenewed),
1685
- subscription: {
1686
- ...subscription,
1687
- lastChargedPeriod: periodIndex,
1688
- reference: hashRenewed,
1689
- },
1690
- }
1691
- },
1692
- store,
1693
- subscriptionExpires: activeSubscriptionExpires,
1694
- })
1695
-
1696
- await subscriptions.put(
1697
- createRecord({
1698
- billingAnchor: new Date(Date.now() - 3 * subscriptionPeriodMilliseconds).toISOString(),
1699
- lastChargedPeriod: 0,
1700
- lookupKey: subscriptionKey,
1701
- reference: hashStale,
1702
- subscriptionId: 'sub_due',
1703
- }),
1704
- )
1705
-
1706
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
1707
- const result = await mppx.tempo.subscription({})(
1708
- new Request('https://example.com/resource', {
1709
- headers: { 'X-Subscription-Key': subscriptionKey },
1710
- }),
1711
- )
1712
-
1713
- expect(result.status).toBe(200)
1714
- expect(renewCalls.length).toBe(1)
1715
- expect(renewCalls[0]).toBeGreaterThan(0)
1716
- expect(renewalReferences[0]).toBe(`renewal:sub_due:${renewCalls[0]}`)
1717
- if (result.status !== 200) throw new Error('expected renewal success')
1718
-
1719
- const receipt = Receipt.fromResponse(result.withReceipt(new Response('OK')))
1720
- expect(receipt.reference).toBe(hashRenewed)
1721
- expect(receipt.subscriptionId).toBe('sub_due')
1722
- expect((await subscriptions.get('sub_due'))?.inFlightReference).toBe(undefined)
1723
- })
1724
-
1725
- test('rejects renewals that change the active subscriptionId', async () => {
1726
- const store = Store.memory()
1727
- const subscriptions = SubscriptionStore.fromStore(store)
1728
- const method = subscription({
1729
- accessKey: async () => accessKey,
1730
- activate: async () => ({
1731
- receipt: createReceipt('unused'),
1732
- subscription: createRecord({ subscriptionId: 'unused' }),
1733
- }),
1734
- amount: subscriptionAmount,
1735
- chainId,
1736
- currency: subscriptionCurrency,
1737
- periodCount: subscriptionPeriodCount,
1738
- periodUnit: subscriptionPeriodUnit,
1739
- recipient: subscriptionRecipient,
1740
- resolve: async () => ({ key: subscriptionKey }),
1741
- renew: async ({ periodIndex, subscription }) => {
1742
- const record = {
1743
- ...subscription,
1744
- lastChargedPeriod: periodIndex,
1745
- reference: hashRenewed,
1746
- subscriptionId: 'sub_other',
1747
- }
1748
- return {
1749
- receipt: createReceipt(record.subscriptionId, hashRenewed),
1750
- subscription: record,
1751
- }
1752
- },
1753
- store,
1754
- subscriptionExpires: activeSubscriptionExpires,
1755
- })
1756
-
1757
- await subscriptions.put(
1758
- createRecord({
1759
- billingAnchor: new Date(Date.now() - 3 * subscriptionPeriodMilliseconds).toISOString(),
1760
- lastChargedPeriod: 0,
1761
- lookupKey: subscriptionKey,
1762
- reference: hashStale,
1763
- subscriptionId: 'sub_due',
1764
- }),
1765
- )
1766
-
1767
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
1768
- const rejected = await mppx.tempo.subscription({})(
1769
- new Request('https://example.com/resource', {
1770
- headers: { 'X-Subscription-Key': subscriptionKey },
1771
- }),
1772
- )
1773
-
1774
- expect(rejected.status).toBe(402)
1775
- expect((await subscriptions.getByKey(subscriptionKey))?.subscriptionId).toBe('sub_due')
1776
- expect((await subscriptions.get('sub_due'))?.lastChargedPeriod).toBe(0)
1777
- })
1778
-
1779
- test('charges an overdue subscription outside the request path', async () => {
1780
- const store = Store.memory()
1781
- const subscriptions = SubscriptionStore.fromStore(store)
1782
- const renewCalls: number[] = []
1783
-
1784
- await subscriptions.put(
1785
- createRecord({
1786
- billingAnchor: new Date(Date.now() - 3 * subscriptionPeriodMilliseconds).toISOString(),
1787
- lastChargedPeriod: 0,
1788
- lookupKey: subscriptionKey,
1789
- amount: subscriptionAmount,
1790
- reference: hashStale,
1791
- subscriptionId: 'sub_background',
1792
- }),
1793
- )
1794
-
1795
- const result = await renew({
1796
- renew: async ({ periodIndex, subscription }) => {
1797
- renewCalls.push(periodIndex)
1798
- return {
1799
- receipt: createReceipt(subscription.subscriptionId, hashBackground),
1800
- subscription: {
1801
- ...subscription,
1802
- lastChargedPeriod: periodIndex,
1803
- reference: hashBackground,
1804
- },
1805
- }
1806
- },
1807
- store,
1808
- subscriptionId: 'sub_background',
1809
- })
1810
-
1811
- expect(result?.receipt.reference).toBe(hashBackground)
1812
- expect(renewCalls.length).toBe(1)
1813
- expect((await subscriptions.get('sub_background'))?.reference).toBe(hashBackground)
1814
- })
1815
-
1816
- test('rejects background renewals that mutate economic fields', async () => {
1817
- const store = Store.memory()
1818
- const subscriptions = SubscriptionStore.fromStore(store)
1819
-
1820
- await subscriptions.put(
1821
- createRecord({
1822
- billingAnchor: new Date(Date.now() - 3 * subscriptionPeriodMilliseconds).toISOString(),
1823
- lastChargedPeriod: 0,
1824
- lookupKey: subscriptionKey,
1825
- amount: subscriptionAmount,
1826
- reference: hashStale,
1827
- subscriptionId: 'sub_background',
1828
- }),
1829
- )
1830
-
1831
- await expect(
1832
- renew({
1833
- renew: async ({ periodIndex, subscription }) => {
1834
- const mutated = {
1835
- ...subscription,
1836
- amount: '999',
1837
- lastChargedPeriod: periodIndex,
1838
- reference: hashBackground,
1839
- }
1840
- return {
1841
- receipt: createReceipt(subscription.subscriptionId, hashBackground),
1842
- subscription: mutated,
1843
- }
1844
- },
1845
- store,
1846
- subscriptionId: 'sub_background',
1847
- }),
1848
- ).rejects.toThrow('subscription record does not match request')
1849
-
1850
- expect((await subscriptions.get('sub_background'))?.inFlightReference).toBe(undefined)
1851
- expect((await subscriptions.get('sub_background'))?.amount).toBe(subscriptionAmount)
1852
- })
1853
-
1854
- test('does not charge a superseded subscription outside the request path', async () => {
1855
- const store = Store.memory()
1856
- const subscriptions = SubscriptionStore.fromStore(store)
1857
- let renewCalls = 0
1858
-
1859
- await subscriptions.put(
1860
- createRecord({
1861
- billingAnchor: new Date(Date.now() - 3 * subscriptionPeriodMilliseconds).toISOString(),
1862
- lastChargedPeriod: 0,
1863
- reference: hashStale,
1864
- subscriptionId: 'sub_old',
1865
- }),
1866
- )
1867
- await subscriptions.put(
1868
- createRecord({
1869
- reference: hashBackground,
1870
- subscriptionId: 'sub_new',
1871
- }),
1872
- )
1873
-
1874
- const result = await renew({
1875
- renew: async ({ subscription }) => {
1876
- renewCalls += 1
1877
- return {
1878
- receipt: createReceipt(subscription.subscriptionId, hashBackground),
1879
- subscription,
1880
- }
1881
- },
1882
- store,
1883
- subscriptionId: 'sub_old',
1884
- })
1885
-
1886
- expect(result).toBe(null)
1887
- expect(renewCalls).toBe(0)
1888
- expect((await subscriptions.getByKey(subscriptionKey))?.subscriptionId).toBe('sub_new')
1889
- })
1890
-
1891
- test('automatically renews an overdue subscription outside the request path', async () => {
1892
- const store = Store.memory()
1893
- const subscriptions = SubscriptionStore.fromStore(store)
1894
- const { client, rpcMethods } = createBillingClient([hashActivate, hashBackground])
1895
- const method = subscription({
1896
- amount: subscriptionAmount,
1897
- chainId,
1898
- currency: subscriptionCurrency,
1899
- getClient: async () => client,
1900
- periodCount: subscriptionPeriodCount,
1901
- periodUnit: subscriptionPeriodUnit,
1902
- recipient: subscriptionRecipient,
1903
- resolve: async () => ({ key: subscriptionKey }),
1904
- store,
1905
- subscriptionExpires: activeSubscriptionExpires,
1906
- waitForConfirmation: false,
1907
- })
1908
- const mppx = Mppx.create({ methods: [method], realm, secretKey })
1909
- const challengeResult = await mppx.tempo.subscription({})(
1910
- new Request('https://example.com/resource'),
1911
- )
1912
- if (challengeResult.status !== 402) throw new Error('expected activation challenge')
1913
- const challenge = Challenge.fromResponse(challengeResult.challenge)
1914
- const accessKey = (
1915
- challenge.request as ReturnType<typeof Methods.subscription.schema.request.parse>
1916
- ).methodDetails?.accessKey
1917
- if (!accessKey) throw new Error('expected generated access key')
1918
- const credential = await createCredential(challenge, rootAccount.address, accessKey)
1919
- const activated = await mppx.tempo.subscription({})(
1920
- new Request('https://example.com/resource', {
1921
- headers: { Authorization: Credential.serialize(credential) },
1922
- }),
1923
- )
1924
- expect(activated.status).toBe(200)
1925
-
1926
- const record = await subscriptions.getByKey(subscriptionKey)
1927
- if (!record) throw new Error('expected subscription record')
1928
- await subscriptions.put({
1929
- ...record,
1930
- billingAnchor: new Date(Date.now() - 3 * subscriptionPeriodMilliseconds).toISOString(),
1931
- lastChargedPeriod: 0,
1932
- reference: hashStale,
1933
- })
1934
-
1935
- const result = await mppx.tempo.subscription.renew({
1936
- subscriptionId: record.subscriptionId,
1937
- })
1938
-
1939
- expect(result?.receipt.reference).toBe(hashBackground)
1940
- expect(rpcMethods.filter((method) => method === 'eth_sendRawTransaction')).toHaveLength(2)
1941
- const renewed = await subscriptions.get(record.subscriptionId)
1942
- expect(renewed?.reference).toBe(hashBackground)
1943
- })
1944
- })