mppx 0.8.17 → 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 (914) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +15 -0
  3. package/dist/Challenge.js +21 -4
  4. package/dist/bin.js +3 -3
  5. package/dist/cli/THIRD-PARTY-LICENSES.txt +328 -0
  6. package/dist/cli/cli.js +253 -1505
  7. package/dist/cli/plugins/index.js +19 -5
  8. package/dist/cli/plugins/tempo.js +7 -3
  9. package/dist/cli/sessions/Manager.js +7 -4
  10. package/dist/cli/sessions/request.d.ts +2 -0
  11. package/dist/cli/sessions/request.js +18 -0
  12. package/dist/cli/sessions/store.js +28 -14
  13. package/dist/discovery/Discovery.js +2 -1
  14. package/dist/evm/client/Charge.js +8 -0
  15. package/dist/server/core.d.ts +9 -0
  16. package/dist/server/core.js +9 -0
  17. package/dist/stripe/server/Charge.js +2 -4
  18. package/dist/stripe/server/Methods.d.ts +2 -2
  19. package/dist/stripe/server/Methods.js +17 -11
  20. package/dist/stripe/server/internal/html.gen.d.ts +1 -1
  21. package/dist/stripe/server/internal/html.gen.js +1 -1
  22. package/dist/stripe/server/spt.d.ts +8 -0
  23. package/dist/stripe/server/spt.js +8 -0
  24. package/dist/tempo/Methods.d.ts +13 -0
  25. package/dist/tempo/Methods.js +14 -3
  26. package/dist/tempo/client/Charge.d.ts +3 -0
  27. package/dist/tempo/client/Charge.js +31 -9
  28. package/dist/tempo/client/Methods.d.ts +13 -0
  29. package/dist/tempo/internal/defaults.d.ts +11 -0
  30. package/dist/tempo/internal/defaults.js +11 -0
  31. package/dist/tempo/internal/machine-token-charge.d.ts +51 -0
  32. package/dist/tempo/internal/machine-token-charge.js +113 -0
  33. package/dist/tempo/internal/machine-token-session.d.ts +88 -0
  34. package/dist/tempo/internal/machine-token-session.js +173 -0
  35. package/dist/tempo/internal/signature-envelope.d.ts +14 -0
  36. package/dist/tempo/internal/signature-envelope.js +28 -0
  37. package/dist/tempo/legacy/client/ChannelOps.d.ts +2 -2
  38. package/dist/tempo/legacy/client/ChannelOps.js +11 -5
  39. package/dist/tempo/legacy/client/Session.d.ts +13 -1
  40. package/dist/tempo/legacy/client/Session.js +3 -3
  41. package/dist/tempo/legacy/client/SessionManager.d.ts +3 -1
  42. package/dist/tempo/legacy/client/SessionManager.js +2 -0
  43. package/dist/tempo/server/Charge.d.ts +3 -0
  44. package/dist/tempo/server/Charge.js +58 -17
  45. package/dist/tempo/server/Methods.d.ts +21 -4
  46. package/dist/tempo/server/Methods.js +8 -4
  47. package/dist/tempo/server/internal/html.gen.d.ts +1 -1
  48. package/dist/tempo/server/internal/html.gen.js +1 -1
  49. package/dist/tempo/session/client/ChannelOps.d.ts +18 -3
  50. package/dist/tempo/session/client/ChannelOps.js +35 -6
  51. package/dist/tempo/session/client/ChannelStore.d.ts +0 -5
  52. package/dist/tempo/session/client/ChannelStore.js +2 -2
  53. package/dist/tempo/session/client/CredentialState.d.ts +17 -2
  54. package/dist/tempo/session/client/CredentialState.js +77 -76
  55. package/dist/tempo/session/client/Runtime.d.ts +4 -2
  56. package/dist/tempo/session/client/Runtime.js +21 -5
  57. package/dist/tempo/session/client/Session.d.ts +15 -3
  58. package/dist/tempo/session/client/Session.js +186 -63
  59. package/dist/tempo/session/client/SessionManager.d.ts +3 -1
  60. package/dist/tempo/session/client/SessionManager.js +35 -11
  61. package/dist/tempo/session/client/Transports.d.ts +2 -0
  62. package/dist/tempo/session/client/Transports.js +12 -2
  63. package/dist/tempo/session/precompile/Chain.d.ts +10 -2
  64. package/dist/tempo/session/precompile/Chain.js +50 -10
  65. package/dist/tempo/session/precompile/Protocol.d.ts +15 -0
  66. package/dist/tempo/session/precompile/Protocol.js +7 -0
  67. package/dist/tempo/session/precompile/Voucher.d.ts +3 -1
  68. package/dist/tempo/session/precompile/Voucher.js +6 -12
  69. package/dist/tempo/session/server/ChannelStore.d.ts +6 -0
  70. package/dist/tempo/session/server/ChannelStore.js +11 -4
  71. package/dist/tempo/session/server/CredentialVerification.d.ts +11 -9
  72. package/dist/tempo/session/server/CredentialVerification.js +185 -109
  73. package/dist/tempo/session/server/MeteredStream.d.ts +1 -1
  74. package/dist/tempo/session/server/MeteredStream.js +5 -4
  75. package/dist/tempo/session/server/RequestState.d.ts +19 -0
  76. package/dist/tempo/session/server/RequestState.js +61 -15
  77. package/dist/tempo/session/server/Session.d.ts +14 -2
  78. package/dist/tempo/session/server/Session.js +37 -6
  79. package/dist/tempo/session/server/Settlement.d.ts +11 -4
  80. package/dist/tempo/session/server/Settlement.js +53 -21
  81. package/dist/x402/client/Exact.d.ts +8 -0
  82. package/dist/x402/client/Exact.js +40 -10
  83. package/dist/x402/server/EvmCharge.d.ts +22 -0
  84. package/dist/x402/server/EvmCharge.js +23 -1
  85. package/package.json +15 -37
  86. package/dist/BodyDigest.d.ts.map +0 -1
  87. package/dist/BodyDigest.js.map +0 -1
  88. package/dist/Challenge.d.ts.map +0 -1
  89. package/dist/Challenge.js.map +0 -1
  90. package/dist/Constants.d.ts.map +0 -1
  91. package/dist/Constants.js.map +0 -1
  92. package/dist/Credential.d.ts.map +0 -1
  93. package/dist/Credential.js.map +0 -1
  94. package/dist/Errors.d.ts.map +0 -1
  95. package/dist/Errors.js.map +0 -1
  96. package/dist/Expires.d.ts.map +0 -1
  97. package/dist/Expires.js.map +0 -1
  98. package/dist/Html.d.ts.map +0 -1
  99. package/dist/Html.js.map +0 -1
  100. package/dist/Mcp.d.ts.map +0 -1
  101. package/dist/Mcp.js.map +0 -1
  102. package/dist/Method.d.ts.map +0 -1
  103. package/dist/Method.js.map +0 -1
  104. package/dist/PaymentRequest.d.ts.map +0 -1
  105. package/dist/PaymentRequest.js.map +0 -1
  106. package/dist/Receipt.d.ts.map +0 -1
  107. package/dist/Receipt.js.map +0 -1
  108. package/dist/Store.d.ts.map +0 -1
  109. package/dist/Store.js.map +0 -1
  110. package/dist/attestation/Client.d.ts.map +0 -1
  111. package/dist/attestation/Client.js.map +0 -1
  112. package/dist/attestation/Constants.d.ts.map +0 -1
  113. package/dist/attestation/Constants.js.map +0 -1
  114. package/dist/attestation/Server.d.ts.map +0 -1
  115. package/dist/attestation/Server.js.map +0 -1
  116. package/dist/attestation/Types.d.ts.map +0 -1
  117. package/dist/attestation/Types.js.map +0 -1
  118. package/dist/attestation/index.d.ts.map +0 -1
  119. package/dist/attestation/index.js.map +0 -1
  120. package/dist/attestation/internal/HttpMessageSignature.d.ts.map +0 -1
  121. package/dist/attestation/internal/HttpMessageSignature.js.map +0 -1
  122. package/dist/attestation/internal/SigningContext.d.ts.map +0 -1
  123. package/dist/attestation/internal/SigningContext.js.map +0 -1
  124. package/dist/bin.d.ts.map +0 -1
  125. package/dist/bin.js.map +0 -1
  126. package/dist/cli/account.d.ts.map +0 -1
  127. package/dist/cli/account.js.map +0 -1
  128. package/dist/cli/cli.d.ts.map +0 -1
  129. package/dist/cli/cli.js.map +0 -1
  130. package/dist/cli/config.d.ts.map +0 -1
  131. package/dist/cli/config.js.map +0 -1
  132. package/dist/cli/internal.d.ts.map +0 -1
  133. package/dist/cli/internal.js.map +0 -1
  134. package/dist/cli/plugins/evm.d.ts.map +0 -1
  135. package/dist/cli/plugins/evm.js.map +0 -1
  136. package/dist/cli/plugins/index.d.ts.map +0 -1
  137. package/dist/cli/plugins/index.js.map +0 -1
  138. package/dist/cli/plugins/plugin.d.ts.map +0 -1
  139. package/dist/cli/plugins/plugin.js.map +0 -1
  140. package/dist/cli/plugins/stripe.d.ts.map +0 -1
  141. package/dist/cli/plugins/stripe.js.map +0 -1
  142. package/dist/cli/plugins/tempo.d.ts.map +0 -1
  143. package/dist/cli/plugins/tempo.js.map +0 -1
  144. package/dist/cli/sessions/Manager.d.ts.map +0 -1
  145. package/dist/cli/sessions/Manager.js.map +0 -1
  146. package/dist/cli/sessions/commands.d.ts.map +0 -1
  147. package/dist/cli/sessions/commands.js.map +0 -1
  148. package/dist/cli/sessions/request.d.ts.map +0 -1
  149. package/dist/cli/sessions/request.js.map +0 -1
  150. package/dist/cli/sessions/store.d.ts.map +0 -1
  151. package/dist/cli/sessions/store.js.map +0 -1
  152. package/dist/cli/utils.d.ts.map +0 -1
  153. package/dist/cli/utils.js.map +0 -1
  154. package/dist/cli/validate/challenge.d.ts.map +0 -1
  155. package/dist/cli/validate/challenge.js.map +0 -1
  156. package/dist/cli/validate/discovery.d.ts.map +0 -1
  157. package/dist/cli/validate/discovery.js.map +0 -1
  158. package/dist/cli/validate/helpers.d.ts.map +0 -1
  159. package/dist/cli/validate/helpers.js.map +0 -1
  160. package/dist/cli/validate/index.d.ts.map +0 -1
  161. package/dist/cli/validate/index.js.map +0 -1
  162. package/dist/cli/validate/messages.d.ts.map +0 -1
  163. package/dist/cli/validate/messages.js.map +0 -1
  164. package/dist/cli/validate/payment.d.ts.map +0 -1
  165. package/dist/cli/validate/payment.js.map +0 -1
  166. package/dist/client/Methods.d.ts.map +0 -1
  167. package/dist/client/Methods.js.map +0 -1
  168. package/dist/client/Mppx.d.ts.map +0 -1
  169. package/dist/client/Mppx.js.map +0 -1
  170. package/dist/client/Transport.d.ts.map +0 -1
  171. package/dist/client/Transport.js.map +0 -1
  172. package/dist/client/index.d.ts.map +0 -1
  173. package/dist/client/index.js.map +0 -1
  174. package/dist/client/internal/Fetch.d.ts.map +0 -1
  175. package/dist/client/internal/Fetch.js.map +0 -1
  176. package/dist/client/internal/MethodChallenge.d.ts.map +0 -1
  177. package/dist/client/internal/MethodChallenge.js.map +0 -1
  178. package/dist/client/internal/MethodResponse.d.ts.map +0 -1
  179. package/dist/client/internal/MethodResponse.js.map +0 -1
  180. package/dist/client/internal/protocols/Mcp.d.ts.map +0 -1
  181. package/dist/client/internal/protocols/Mcp.js.map +0 -1
  182. package/dist/client/internal/protocols/Mpp.d.ts.map +0 -1
  183. package/dist/client/internal/protocols/Mpp.js.map +0 -1
  184. package/dist/client/internal/protocols/Protocol.d.ts.map +0 -1
  185. package/dist/client/internal/protocols/Protocol.js.map +0 -1
  186. package/dist/client/internal/protocols/Shared.d.ts.map +0 -1
  187. package/dist/client/internal/protocols/Shared.js.map +0 -1
  188. package/dist/client/internal/protocols/X402.d.ts.map +0 -1
  189. package/dist/client/internal/protocols/X402.js.map +0 -1
  190. package/dist/client/node.d.ts.map +0 -1
  191. package/dist/client/node.js.map +0 -1
  192. package/dist/discovery/Discovery.d.ts.map +0 -1
  193. package/dist/discovery/Discovery.js.map +0 -1
  194. package/dist/discovery/OpenApi.d.ts.map +0 -1
  195. package/dist/discovery/OpenApi.js.map +0 -1
  196. package/dist/discovery/Validate.d.ts.map +0 -1
  197. package/dist/discovery/Validate.js.map +0 -1
  198. package/dist/discovery/index.d.ts.map +0 -1
  199. package/dist/discovery/index.js.map +0 -1
  200. package/dist/discovery/internal/Metadata.d.ts.map +0 -1
  201. package/dist/discovery/internal/Metadata.js.map +0 -1
  202. package/dist/evm/Assets.d.ts.map +0 -1
  203. package/dist/evm/Assets.js.map +0 -1
  204. package/dist/evm/Chains.d.ts.map +0 -1
  205. package/dist/evm/Chains.js.map +0 -1
  206. package/dist/evm/Methods.d.ts.map +0 -1
  207. package/dist/evm/Methods.js.map +0 -1
  208. package/dist/evm/Types.d.ts.map +0 -1
  209. package/dist/evm/Types.js.map +0 -1
  210. package/dist/evm/client/Charge.d.ts.map +0 -1
  211. package/dist/evm/client/Charge.js.map +0 -1
  212. package/dist/evm/client/Methods.d.ts.map +0 -1
  213. package/dist/evm/client/Methods.js.map +0 -1
  214. package/dist/evm/client/index.d.ts.map +0 -1
  215. package/dist/evm/client/index.js.map +0 -1
  216. package/dist/evm/index.d.ts.map +0 -1
  217. package/dist/evm/index.js.map +0 -1
  218. package/dist/evm/server/Charge.d.ts.map +0 -1
  219. package/dist/evm/server/Charge.js.map +0 -1
  220. package/dist/evm/server/Methods.d.ts.map +0 -1
  221. package/dist/evm/server/Methods.js.map +0 -1
  222. package/dist/evm/server/index.d.ts.map +0 -1
  223. package/dist/evm/server/index.js.map +0 -1
  224. package/dist/index.d.ts.map +0 -1
  225. package/dist/index.js.map +0 -1
  226. package/dist/internal/AcceptPayment.d.ts.map +0 -1
  227. package/dist/internal/AcceptPayment.js.map +0 -1
  228. package/dist/internal/HeaderCodec.d.ts.map +0 -1
  229. package/dist/internal/HeaderCodec.js.map +0 -1
  230. package/dist/internal/constantTimeEqual.d.ts.map +0 -1
  231. package/dist/internal/constantTimeEqual.js.map +0 -1
  232. package/dist/internal/env.d.ts.map +0 -1
  233. package/dist/internal/env.js.map +0 -1
  234. package/dist/internal/types.d.ts.map +0 -1
  235. package/dist/internal/types.js.map +0 -1
  236. package/dist/mcp/client/McpClient.d.ts.map +0 -1
  237. package/dist/mcp/client/McpClient.js.map +0 -1
  238. package/dist/mcp/client/index.d.ts.map +0 -1
  239. package/dist/mcp/client/index.js.map +0 -1
  240. package/dist/mcp/server/Transport.d.ts.map +0 -1
  241. package/dist/mcp/server/Transport.js.map +0 -1
  242. package/dist/mcp/server/index.d.ts.map +0 -1
  243. package/dist/mcp/server/index.js.map +0 -1
  244. package/dist/middlewares/elysia.d.ts.map +0 -1
  245. package/dist/middlewares/elysia.js.map +0 -1
  246. package/dist/middlewares/express.d.ts.map +0 -1
  247. package/dist/middlewares/express.js.map +0 -1
  248. package/dist/middlewares/hono.d.ts.map +0 -1
  249. package/dist/middlewares/hono.js.map +0 -1
  250. package/dist/middlewares/internal/mppx.d.ts.map +0 -1
  251. package/dist/middlewares/internal/mppx.js.map +0 -1
  252. package/dist/middlewares/nextjs.d.ts.map +0 -1
  253. package/dist/middlewares/nextjs.js.map +0 -1
  254. package/dist/proxy/Proxy.d.ts.map +0 -1
  255. package/dist/proxy/Proxy.js.map +0 -1
  256. package/dist/proxy/Service.d.ts.map +0 -1
  257. package/dist/proxy/Service.js.map +0 -1
  258. package/dist/proxy/index.d.ts.map +0 -1
  259. package/dist/proxy/index.js.map +0 -1
  260. package/dist/proxy/internal/Headers.d.ts.map +0 -1
  261. package/dist/proxy/internal/Headers.js.map +0 -1
  262. package/dist/proxy/internal/Route.d.ts.map +0 -1
  263. package/dist/proxy/internal/Route.js.map +0 -1
  264. package/dist/proxy/services/anthropic.d.ts.map +0 -1
  265. package/dist/proxy/services/anthropic.js.map +0 -1
  266. package/dist/proxy/services/openai.d.ts.map +0 -1
  267. package/dist/proxy/services/openai.js.map +0 -1
  268. package/dist/proxy/services/stripe.d.ts.map +0 -1
  269. package/dist/proxy/services/stripe.js.map +0 -1
  270. package/dist/server/Methods.d.ts.map +0 -1
  271. package/dist/server/Methods.js.map +0 -1
  272. package/dist/server/Mppx.d.ts.map +0 -1
  273. package/dist/server/Mppx.js.map +0 -1
  274. package/dist/server/NodeListener.d.ts.map +0 -1
  275. package/dist/server/NodeListener.js.map +0 -1
  276. package/dist/server/Request.d.ts.map +0 -1
  277. package/dist/server/Request.js.map +0 -1
  278. package/dist/server/Response.d.ts.map +0 -1
  279. package/dist/server/Response.js.map +0 -1
  280. package/dist/server/Transport.d.ts.map +0 -1
  281. package/dist/server/Transport.js.map +0 -1
  282. package/dist/server/index.d.ts.map +0 -1
  283. package/dist/server/index.js.map +0 -1
  284. package/dist/server/internal/html/compose.main.gen.d.ts.map +0 -1
  285. package/dist/server/internal/html/compose.main.gen.js.map +0 -1
  286. package/dist/server/internal/html/config.d.ts.map +0 -1
  287. package/dist/server/internal/html/config.js.map +0 -1
  288. package/dist/server/internal/html/constants.d.ts.map +0 -1
  289. package/dist/server/internal/html/constants.js.map +0 -1
  290. package/dist/server/internal/html/serviceWorker.client.d.ts.map +0 -1
  291. package/dist/server/internal/html/serviceWorker.client.js.map +0 -1
  292. package/dist/server/internal/html/serviceWorker.gen.d.ts.map +0 -1
  293. package/dist/server/internal/html/serviceWorker.gen.js.map +0 -1
  294. package/dist/server/internal/scope.d.ts.map +0 -1
  295. package/dist/server/internal/scope.js.map +0 -1
  296. package/dist/stripe/Methods.d.ts.map +0 -1
  297. package/dist/stripe/Methods.js.map +0 -1
  298. package/dist/stripe/client/Charge.d.ts.map +0 -1
  299. package/dist/stripe/client/Charge.js.map +0 -1
  300. package/dist/stripe/client/Methods.d.ts.map +0 -1
  301. package/dist/stripe/client/Methods.js.map +0 -1
  302. package/dist/stripe/client/index.d.ts.map +0 -1
  303. package/dist/stripe/client/index.js.map +0 -1
  304. package/dist/stripe/index.d.ts.map +0 -1
  305. package/dist/stripe/index.js.map +0 -1
  306. package/dist/stripe/internal/constants.d.ts.map +0 -1
  307. package/dist/stripe/internal/constants.js.map +0 -1
  308. package/dist/stripe/internal/types.d.ts.map +0 -1
  309. package/dist/stripe/internal/types.js.map +0 -1
  310. package/dist/stripe/server/Charge.d.ts.map +0 -1
  311. package/dist/stripe/server/Charge.js.map +0 -1
  312. package/dist/stripe/server/Methods.d.ts.map +0 -1
  313. package/dist/stripe/server/Methods.js.map +0 -1
  314. package/dist/stripe/server/index.d.ts.map +0 -1
  315. package/dist/stripe/server/index.js.map +0 -1
  316. package/dist/stripe/server/internal/deposit-address.d.ts.map +0 -1
  317. package/dist/stripe/server/internal/deposit-address.js.map +0 -1
  318. package/dist/stripe/server/internal/html/types.d.ts.map +0 -1
  319. package/dist/stripe/server/internal/html/types.js.map +0 -1
  320. package/dist/stripe/server/internal/html.gen.d.ts.map +0 -1
  321. package/dist/stripe/server/internal/html.gen.js.map +0 -1
  322. package/dist/stripe/server/internal/record-payment.d.ts.map +0 -1
  323. package/dist/stripe/server/internal/record-payment.js.map +0 -1
  324. package/dist/stripe/server/internal/request.d.ts.map +0 -1
  325. package/dist/stripe/server/internal/request.js.map +0 -1
  326. package/dist/tap/Constants.d.ts.map +0 -1
  327. package/dist/tap/Constants.js.map +0 -1
  328. package/dist/tap/Types.d.ts.map +0 -1
  329. package/dist/tap/Types.js.map +0 -1
  330. package/dist/tap/client/index.d.ts.map +0 -1
  331. package/dist/tap/client/index.js.map +0 -1
  332. package/dist/tap/index.d.ts.map +0 -1
  333. package/dist/tap/index.js.map +0 -1
  334. package/dist/tap/server/index.d.ts.map +0 -1
  335. package/dist/tap/server/index.js.map +0 -1
  336. package/dist/tempo/Attribution.d.ts.map +0 -1
  337. package/dist/tempo/Attribution.js.map +0 -1
  338. package/dist/tempo/Methods.d.ts.map +0 -1
  339. package/dist/tempo/Methods.js.map +0 -1
  340. package/dist/tempo/Proof.d.ts.map +0 -1
  341. package/dist/tempo/Proof.js.map +0 -1
  342. package/dist/tempo/client/Charge.d.ts.map +0 -1
  343. package/dist/tempo/client/Charge.js.map +0 -1
  344. package/dist/tempo/client/Methods.d.ts.map +0 -1
  345. package/dist/tempo/client/Methods.js.map +0 -1
  346. package/dist/tempo/client/ResolveAccount.d.ts.map +0 -1
  347. package/dist/tempo/client/ResolveAccount.js.map +0 -1
  348. package/dist/tempo/client/Subscription.d.ts.map +0 -1
  349. package/dist/tempo/client/Subscription.js.map +0 -1
  350. package/dist/tempo/client/index.d.ts.map +0 -1
  351. package/dist/tempo/client/index.js.map +0 -1
  352. package/dist/tempo/index.d.ts.map +0 -1
  353. package/dist/tempo/index.js.map +0 -1
  354. package/dist/tempo/internal/account.d.ts.map +0 -1
  355. package/dist/tempo/internal/account.js.map +0 -1
  356. package/dist/tempo/internal/address.d.ts.map +0 -1
  357. package/dist/tempo/internal/address.js.map +0 -1
  358. package/dist/tempo/internal/auto-swap.d.ts.map +0 -1
  359. package/dist/tempo/internal/auto-swap.js.map +0 -1
  360. package/dist/tempo/internal/charge.d.ts.map +0 -1
  361. package/dist/tempo/internal/charge.js.map +0 -1
  362. package/dist/tempo/internal/defaults.d.ts.map +0 -1
  363. package/dist/tempo/internal/defaults.js.map +0 -1
  364. package/dist/tempo/internal/fee-payer.d.ts.map +0 -1
  365. package/dist/tempo/internal/fee-payer.js.map +0 -1
  366. package/dist/tempo/internal/fee-token.d.ts.map +0 -1
  367. package/dist/tempo/internal/fee-token.js.map +0 -1
  368. package/dist/tempo/internal/proof.d.ts.map +0 -1
  369. package/dist/tempo/internal/proof.js.map +0 -1
  370. package/dist/tempo/internal/selectors.d.ts.map +0 -1
  371. package/dist/tempo/internal/selectors.js.map +0 -1
  372. package/dist/tempo/internal/types.d.ts.map +0 -1
  373. package/dist/tempo/internal/types.js.map +0 -1
  374. package/dist/tempo/legacy/client/ChannelOps.d.ts.map +0 -1
  375. package/dist/tempo/legacy/client/ChannelOps.js.map +0 -1
  376. package/dist/tempo/legacy/client/Session.d.ts.map +0 -1
  377. package/dist/tempo/legacy/client/Session.js.map +0 -1
  378. package/dist/tempo/legacy/client/SessionManager.d.ts.map +0 -1
  379. package/dist/tempo/legacy/client/SessionManager.js.map +0 -1
  380. package/dist/tempo/legacy/client/index.d.ts.map +0 -1
  381. package/dist/tempo/legacy/client/index.js.map +0 -1
  382. package/dist/tempo/legacy/index.d.ts.map +0 -1
  383. package/dist/tempo/legacy/index.js.map +0 -1
  384. package/dist/tempo/legacy/session/Chain.d.ts.map +0 -1
  385. package/dist/tempo/legacy/session/Chain.js.map +0 -1
  386. package/dist/tempo/legacy/session/Channel.d.ts.map +0 -1
  387. package/dist/tempo/legacy/session/Channel.js.map +0 -1
  388. package/dist/tempo/legacy/session/Types.d.ts.map +0 -1
  389. package/dist/tempo/legacy/session/Types.js.map +0 -1
  390. package/dist/tempo/legacy/session/Voucher.d.ts.map +0 -1
  391. package/dist/tempo/legacy/session/Voucher.js.map +0 -1
  392. package/dist/tempo/legacy/session/escrow.abi.d.ts.map +0 -1
  393. package/dist/tempo/legacy/session/escrow.abi.js.map +0 -1
  394. package/dist/tempo/legacy/session/index.d.ts.map +0 -1
  395. package/dist/tempo/legacy/session/index.js.map +0 -1
  396. package/dist/tempo/server/Charge.d.ts.map +0 -1
  397. package/dist/tempo/server/Charge.js.map +0 -1
  398. package/dist/tempo/server/Methods.d.ts.map +0 -1
  399. package/dist/tempo/server/Methods.js.map +0 -1
  400. package/dist/tempo/server/Relay.d.ts.map +0 -1
  401. package/dist/tempo/server/Relay.js.map +0 -1
  402. package/dist/tempo/server/SponsorBudget.d.ts.map +0 -1
  403. package/dist/tempo/server/SponsorBudget.js.map +0 -1
  404. package/dist/tempo/server/Subscription.d.ts.map +0 -1
  405. package/dist/tempo/server/Subscription.js.map +0 -1
  406. package/dist/tempo/server/index.d.ts.map +0 -1
  407. package/dist/tempo/server/index.js.map +0 -1
  408. package/dist/tempo/server/internal/html.gen.d.ts.map +0 -1
  409. package/dist/tempo/server/internal/html.gen.js.map +0 -1
  410. package/dist/tempo/server/internal/request-body.d.ts.map +0 -1
  411. package/dist/tempo/server/internal/request-body.js.map +0 -1
  412. package/dist/tempo/server/internal/transport.d.ts.map +0 -1
  413. package/dist/tempo/server/internal/transport.js.map +0 -1
  414. package/dist/tempo/session/Snapshot.d.ts.map +0 -1
  415. package/dist/tempo/session/Snapshot.js.map +0 -1
  416. package/dist/tempo/session/client/ChannelOps.d.ts.map +0 -1
  417. package/dist/tempo/session/client/ChannelOps.js.map +0 -1
  418. package/dist/tempo/session/client/ChannelStore.d.ts.map +0 -1
  419. package/dist/tempo/session/client/ChannelStore.js.map +0 -1
  420. package/dist/tempo/session/client/CredentialState.d.ts.map +0 -1
  421. package/dist/tempo/session/client/CredentialState.js.map +0 -1
  422. package/dist/tempo/session/client/ReceiptCoordinator.d.ts.map +0 -1
  423. package/dist/tempo/session/client/ReceiptCoordinator.js.map +0 -1
  424. package/dist/tempo/session/client/Runtime.d.ts.map +0 -1
  425. package/dist/tempo/session/client/Runtime.js.map +0 -1
  426. package/dist/tempo/session/client/Session.d.ts.map +0 -1
  427. package/dist/tempo/session/client/Session.js.map +0 -1
  428. package/dist/tempo/session/client/SessionManager.d.ts.map +0 -1
  429. package/dist/tempo/session/client/SessionManager.js.map +0 -1
  430. package/dist/tempo/session/client/Transports.d.ts.map +0 -1
  431. package/dist/tempo/session/client/Transports.js.map +0 -1
  432. package/dist/tempo/session/client/index.d.ts.map +0 -1
  433. package/dist/tempo/session/client/index.js.map +0 -1
  434. package/dist/tempo/session/client/internal/SessionManager.d.ts.map +0 -1
  435. package/dist/tempo/session/client/internal/SessionManager.js.map +0 -1
  436. package/dist/tempo/session/index.d.ts.map +0 -1
  437. package/dist/tempo/session/index.js.map +0 -1
  438. package/dist/tempo/session/precompile/Chain.d.ts.map +0 -1
  439. package/dist/tempo/session/precompile/Chain.js.map +0 -1
  440. package/dist/tempo/session/precompile/Channel.d.ts.map +0 -1
  441. package/dist/tempo/session/precompile/Channel.js.map +0 -1
  442. package/dist/tempo/session/precompile/Protocol.d.ts.map +0 -1
  443. package/dist/tempo/session/precompile/Protocol.js.map +0 -1
  444. package/dist/tempo/session/precompile/Voucher.d.ts.map +0 -1
  445. package/dist/tempo/session/precompile/Voucher.js.map +0 -1
  446. package/dist/tempo/session/precompile/escrow.abi.d.ts.map +0 -1
  447. package/dist/tempo/session/precompile/escrow.abi.js.map +0 -1
  448. package/dist/tempo/session/precompile/index.d.ts.map +0 -1
  449. package/dist/tempo/session/precompile/index.js.map +0 -1
  450. package/dist/tempo/session/server/ChannelOps.d.ts.map +0 -1
  451. package/dist/tempo/session/server/ChannelOps.js.map +0 -1
  452. package/dist/tempo/session/server/ChannelStore.d.ts.map +0 -1
  453. package/dist/tempo/session/server/ChannelStore.js.map +0 -1
  454. package/dist/tempo/session/server/CredentialVerification.d.ts.map +0 -1
  455. package/dist/tempo/session/server/CredentialVerification.js.map +0 -1
  456. package/dist/tempo/session/server/MeteredStream.d.ts.map +0 -1
  457. package/dist/tempo/session/server/MeteredStream.js.map +0 -1
  458. package/dist/tempo/session/server/RequestState.d.ts.map +0 -1
  459. package/dist/tempo/session/server/RequestState.js.map +0 -1
  460. package/dist/tempo/session/server/Session.d.ts.map +0 -1
  461. package/dist/tempo/session/server/Session.js.map +0 -1
  462. package/dist/tempo/session/server/Settlement.d.ts.map +0 -1
  463. package/dist/tempo/session/server/Settlement.js.map +0 -1
  464. package/dist/tempo/session/server/Sse.d.ts.map +0 -1
  465. package/dist/tempo/session/server/Sse.js.map +0 -1
  466. package/dist/tempo/session/server/Transports.d.ts.map +0 -1
  467. package/dist/tempo/session/server/Transports.js.map +0 -1
  468. package/dist/tempo/session/server/Ws.d.ts.map +0 -1
  469. package/dist/tempo/session/server/Ws.js.map +0 -1
  470. package/dist/tempo/session/server/index.d.ts.map +0 -1
  471. package/dist/tempo/session/server/index.js.map +0 -1
  472. package/dist/tempo/subscription/KeyAuthorization.d.ts.map +0 -1
  473. package/dist/tempo/subscription/KeyAuthorization.js.map +0 -1
  474. package/dist/tempo/subscription/Receipt.d.ts.map +0 -1
  475. package/dist/tempo/subscription/Receipt.js.map +0 -1
  476. package/dist/tempo/subscription/Store.d.ts.map +0 -1
  477. package/dist/tempo/subscription/Store.js.map +0 -1
  478. package/dist/tempo/subscription/Types.d.ts.map +0 -1
  479. package/dist/tempo/subscription/Types.js.map +0 -1
  480. package/dist/tempo/subscription/index.d.ts.map +0 -1
  481. package/dist/tempo/subscription/index.js.map +0 -1
  482. package/dist/validation/core.d.ts.map +0 -1
  483. package/dist/validation/core.js.map +0 -1
  484. package/dist/validation/index.d.ts.map +0 -1
  485. package/dist/validation/index.js.map +0 -1
  486. package/dist/viem/Account.d.ts.map +0 -1
  487. package/dist/viem/Account.js.map +0 -1
  488. package/dist/viem/Client.d.ts.map +0 -1
  489. package/dist/viem/Client.js.map +0 -1
  490. package/dist/web-bot-auth/Constants.d.ts.map +0 -1
  491. package/dist/web-bot-auth/Constants.js.map +0 -1
  492. package/dist/web-bot-auth/Types.d.ts.map +0 -1
  493. package/dist/web-bot-auth/Types.js.map +0 -1
  494. package/dist/web-bot-auth/client/index.d.ts.map +0 -1
  495. package/dist/web-bot-auth/client/index.js.map +0 -1
  496. package/dist/web-bot-auth/index.d.ts.map +0 -1
  497. package/dist/web-bot-auth/index.js.map +0 -1
  498. package/dist/web-bot-auth/internal/JwkThumbprint.d.ts.map +0 -1
  499. package/dist/web-bot-auth/internal/JwkThumbprint.js.map +0 -1
  500. package/dist/web-bot-auth/internal/SignatureAgent.d.ts.map +0 -1
  501. package/dist/web-bot-auth/internal/SignatureAgent.js.map +0 -1
  502. package/dist/web-bot-auth/server/index.d.ts.map +0 -1
  503. package/dist/web-bot-auth/server/index.js.map +0 -1
  504. package/dist/x402/Assets.d.ts.map +0 -1
  505. package/dist/x402/Assets.js.map +0 -1
  506. package/dist/x402/Header.d.ts.map +0 -1
  507. package/dist/x402/Header.js.map +0 -1
  508. package/dist/x402/Types.d.ts.map +0 -1
  509. package/dist/x402/Types.js.map +0 -1
  510. package/dist/x402/client/Exact.d.ts.map +0 -1
  511. package/dist/x402/client/Exact.js.map +0 -1
  512. package/dist/x402/index.d.ts.map +0 -1
  513. package/dist/x402/index.js.map +0 -1
  514. package/dist/x402/internal/ChallengeBrand.d.ts.map +0 -1
  515. package/dist/x402/internal/ChallengeBrand.js.map +0 -1
  516. package/dist/x402/internal/RouteBinding.d.ts.map +0 -1
  517. package/dist/x402/internal/RouteBinding.js.map +0 -1
  518. package/dist/x402/server/EvmCharge.d.ts.map +0 -1
  519. package/dist/x402/server/EvmCharge.js.map +0 -1
  520. package/dist/x402/server/Facilitator.d.ts.map +0 -1
  521. package/dist/x402/server/Facilitator.js.map +0 -1
  522. package/dist/zod.d.ts.map +0 -1
  523. package/dist/zod.js.map +0 -1
  524. package/src/BodyDigest.test.ts +0 -43
  525. package/src/BodyDigest.ts +0 -55
  526. package/src/Challenge.fuzz.test.ts +0 -154
  527. package/src/Challenge.test-d.ts +0 -82
  528. package/src/Challenge.test.ts +0 -1060
  529. package/src/Challenge.ts +0 -687
  530. package/src/Constants.ts +0 -58
  531. package/src/Credential.fuzz.test.ts +0 -62
  532. package/src/Credential.test.ts +0 -378
  533. package/src/Credential.ts +0 -217
  534. package/src/Errors.test.ts +0 -520
  535. package/src/Errors.ts +0 -448
  536. package/src/Expires.test.ts +0 -112
  537. package/src/Expires.ts +0 -59
  538. package/src/Html.ts +0 -67
  539. package/src/Mcp.ts +0 -85
  540. package/src/Method.test.ts +0 -177
  541. package/src/Method.ts +0 -631
  542. package/src/PaymentRequest.test.ts +0 -147
  543. package/src/PaymentRequest.ts +0 -108
  544. package/src/Receipt.test.ts +0 -151
  545. package/src/Receipt.ts +0 -146
  546. package/src/Store.test-d.ts +0 -211
  547. package/src/Store.test.ts +0 -407
  548. package/src/Store.ts +0 -397
  549. package/src/attestation/Attestation.integration.test.ts +0 -208
  550. package/src/attestation/Client.test.ts +0 -83
  551. package/src/attestation/Client.ts +0 -34
  552. package/src/attestation/Constants.ts +0 -15
  553. package/src/attestation/Server.test.ts +0 -60
  554. package/src/attestation/Server.ts +0 -12
  555. package/src/attestation/Types.test-d.ts +0 -54
  556. package/src/attestation/Types.ts +0 -77
  557. package/src/attestation/index.ts +0 -5
  558. package/src/attestation/internal/HttpMessageSignature.test.ts +0 -101
  559. package/src/attestation/internal/HttpMessageSignature.ts +0 -429
  560. package/src/attestation/internal/SigningContext.ts +0 -13
  561. package/src/bin.js +0 -2
  562. package/src/bin.ts +0 -4
  563. package/src/cli/account.ts +0 -269
  564. package/src/cli/cli.test.ts +0 -2221
  565. package/src/cli/cli.ts +0 -1650
  566. package/src/cli/config.test.ts +0 -89
  567. package/src/cli/config.ts +0 -50
  568. package/src/cli/internal.ts +0 -114
  569. package/src/cli/mcp.test.ts +0 -262
  570. package/src/cli/plugins/evm.ts +0 -55
  571. package/src/cli/plugins/index.ts +0 -4
  572. package/src/cli/plugins/plugin.ts +0 -84
  573. package/src/cli/plugins/stripe.ts +0 -174
  574. package/src/cli/plugins/tempo.ts +0 -1102
  575. package/src/cli/sessions/Manager.test.ts +0 -249
  576. package/src/cli/sessions/Manager.ts +0 -93
  577. package/src/cli/sessions/commands.ts +0 -444
  578. package/src/cli/sessions/request.test.ts +0 -51
  579. package/src/cli/sessions/request.ts +0 -353
  580. package/src/cli/sessions/store.test.ts +0 -581
  581. package/src/cli/sessions/store.ts +0 -940
  582. package/src/cli/utils.test.ts +0 -156
  583. package/src/cli/utils.ts +0 -394
  584. package/src/cli/validate/challenge.ts +0 -565
  585. package/src/cli/validate/discovery.test.ts +0 -435
  586. package/src/cli/validate/discovery.ts +0 -221
  587. package/src/cli/validate/helpers.ts +0 -166
  588. package/src/cli/validate/index.ts +0 -229
  589. package/src/cli/validate/messages.ts +0 -7
  590. package/src/cli/validate/payment.ts +0 -774
  591. package/src/cli/validate.test.ts +0 -843
  592. package/src/client/Methods.ts +0 -8
  593. package/src/client/Mppx.test-d.ts +0 -287
  594. package/src/client/Mppx.test.ts +0 -1065
  595. package/src/client/Mppx.ts +0 -487
  596. package/src/client/Transport.test.ts +0 -586
  597. package/src/client/Transport.ts +0 -170
  598. package/src/client/index.ts +0 -29
  599. package/src/client/internal/Fetch.browser.test.ts +0 -197
  600. package/src/client/internal/Fetch.test-d.ts +0 -109
  601. package/src/client/internal/Fetch.test.ts +0 -2336
  602. package/src/client/internal/Fetch.ts +0 -1075
  603. package/src/client/internal/MethodChallenge.ts +0 -35
  604. package/src/client/internal/MethodResponse.ts +0 -67
  605. package/src/client/internal/protocols/Mcp.test.ts +0 -220
  606. package/src/client/internal/protocols/Mcp.ts +0 -186
  607. package/src/client/internal/protocols/Mpp.ts +0 -21
  608. package/src/client/internal/protocols/Protocol.ts +0 -10
  609. package/src/client/internal/protocols/Shared.ts +0 -25
  610. package/src/client/internal/protocols/X402.ts +0 -46
  611. package/src/client/node.test.ts +0 -115
  612. package/src/client/node.ts +0 -247
  613. package/src/discovery/Discovery.test.ts +0 -214
  614. package/src/discovery/Discovery.ts +0 -105
  615. package/src/discovery/OpenApi.test.ts +0 -623
  616. package/src/discovery/OpenApi.ts +0 -192
  617. package/src/discovery/Validate.test.ts +0 -305
  618. package/src/discovery/Validate.ts +0 -77
  619. package/src/discovery/index.ts +0 -3
  620. package/src/discovery/internal/Metadata.ts +0 -51
  621. package/src/env.d.ts +0 -12
  622. package/src/evm/Assets.ts +0 -1
  623. package/src/evm/Chains.ts +0 -11
  624. package/src/evm/Methods.ts +0 -44
  625. package/src/evm/PublicInterface.test-d.ts +0 -134
  626. package/src/evm/Types.ts +0 -140
  627. package/src/evm/client/Charge.test.ts +0 -347
  628. package/src/evm/client/Charge.ts +0 -187
  629. package/src/evm/client/Methods.ts +0 -19
  630. package/src/evm/client/index.ts +0 -6
  631. package/src/evm/index.ts +0 -16
  632. package/src/evm/server/Charge.test.ts +0 -339
  633. package/src/evm/server/Charge.ts +0 -295
  634. package/src/evm/server/Methods.ts +0 -22
  635. package/src/evm/server/index.ts +0 -6
  636. package/src/index.ts +0 -14
  637. package/src/internal/AcceptPayment.test.ts +0 -347
  638. package/src/internal/AcceptPayment.ts +0 -366
  639. package/src/internal/HeaderCodec.ts +0 -36
  640. package/src/internal/changeset.test.ts +0 -106
  641. package/src/internal/constantTimeEqual.test.ts +0 -47
  642. package/src/internal/constantTimeEqual.ts +0 -10
  643. package/src/internal/env.test.ts +0 -42
  644. package/src/internal/env.ts +0 -49
  645. package/src/internal/types.test-d.ts +0 -21
  646. package/src/internal/types.ts +0 -479
  647. package/src/mcp/client/McpClient.integration.test.ts +0 -639
  648. package/src/mcp/client/McpClient.test-d.ts +0 -144
  649. package/src/mcp/client/McpClient.test.ts +0 -463
  650. package/src/mcp/client/McpClient.ts +0 -307
  651. package/src/mcp/client/McpClient.unit.test.ts +0 -135
  652. package/src/mcp/client/index.ts +0 -2
  653. package/src/mcp/server/Transport.test.ts +0 -191
  654. package/src/mcp/server/Transport.ts +0 -111
  655. package/src/mcp/server/index.ts +0 -1
  656. package/src/middlewares/elysia.test.ts +0 -285
  657. package/src/middlewares/elysia.ts +0 -116
  658. package/src/middlewares/express.test.ts +0 -361
  659. package/src/middlewares/express.ts +0 -140
  660. package/src/middlewares/hono.test.ts +0 -473
  661. package/src/middlewares/hono.ts +0 -153
  662. package/src/middlewares/internal/mppx.test.ts +0 -177
  663. package/src/middlewares/internal/mppx.ts +0 -67
  664. package/src/middlewares/nextjs.test.ts +0 -359
  665. package/src/middlewares/nextjs.ts +0 -107
  666. package/src/proxy/Proxy.test.ts +0 -1038
  667. package/src/proxy/Proxy.ts +0 -483
  668. package/src/proxy/Proxy.upstreamError.test.ts +0 -364
  669. package/src/proxy/Service.test.ts +0 -252
  670. package/src/proxy/Service.ts +0 -280
  671. package/src/proxy/index.ts +0 -6
  672. package/src/proxy/internal/Headers.test.ts +0 -139
  673. package/src/proxy/internal/Headers.ts +0 -66
  674. package/src/proxy/internal/Route.test.ts +0 -217
  675. package/src/proxy/internal/Route.ts +0 -64
  676. package/src/proxy/services/anthropic.test.ts +0 -132
  677. package/src/proxy/services/anthropic.ts +0 -53
  678. package/src/proxy/services/hooks.test-d.ts +0 -14
  679. package/src/proxy/services/hooks.test.ts +0 -44
  680. package/src/proxy/services/openai.test.ts +0 -157
  681. package/src/proxy/services/openai.ts +0 -60
  682. package/src/proxy/services/stripe.test.ts +0 -175
  683. package/src/proxy/services/stripe.ts +0 -59
  684. package/src/server/Methods.test-d.ts +0 -88
  685. package/src/server/Methods.test.ts +0 -69
  686. package/src/server/Methods.ts +0 -3
  687. package/src/server/Mppx.authorize.test.ts +0 -210
  688. package/src/server/Mppx.test-d.ts +0 -494
  689. package/src/server/Mppx.test.ts +0 -6711
  690. package/src/server/Mppx.ts +0 -2919
  691. package/src/server/NodeListener.test.ts +0 -293
  692. package/src/server/NodeListener.ts +0 -45
  693. package/src/server/Request.test.ts +0 -255
  694. package/src/server/Request.ts +0 -155
  695. package/src/server/Response.test.ts +0 -32
  696. package/src/server/Response.ts +0 -45
  697. package/src/server/Transport.test.ts +0 -598
  698. package/src/server/Transport.ts +0 -320
  699. package/src/server/index.ts +0 -9
  700. package/src/server/internal/html/compose.main.gen.ts +0 -2
  701. package/src/server/internal/html/compose.main.ts +0 -88
  702. package/src/server/internal/html/config.ts +0 -672
  703. package/src/server/internal/html/constants.ts +0 -28
  704. package/src/server/internal/html/serviceWorker.client.ts +0 -28
  705. package/src/server/internal/html/serviceWorker.gen.ts +0 -2
  706. package/src/server/internal/html/serviceWorker.ts +0 -27
  707. package/src/server/internal/html/tsconfig.compose.json +0 -8
  708. package/src/server/internal/html/tsconfig.worker.client.json +0 -8
  709. package/src/server/internal/html/tsconfig.worker.json +0 -8
  710. package/src/server/internal/scope.ts +0 -43
  711. package/src/stripe/Charge.integration.test.ts +0 -329
  712. package/src/stripe/Methods.test.ts +0 -62
  713. package/src/stripe/Methods.ts +0 -44
  714. package/src/stripe/client/Charge.test.ts +0 -205
  715. package/src/stripe/client/Charge.ts +0 -132
  716. package/src/stripe/client/Methods.ts +0 -37
  717. package/src/stripe/client/index.ts +0 -2
  718. package/src/stripe/index.ts +0 -1
  719. package/src/stripe/internal/constants.ts +0 -7
  720. package/src/stripe/internal/types.ts +0 -47
  721. package/src/stripe/server/Charge.test-d.ts +0 -81
  722. package/src/stripe/server/Charge.test.ts +0 -700
  723. package/src/stripe/server/Charge.ts +0 -487
  724. package/src/stripe/server/Methods.test-d.ts +0 -157
  725. package/src/stripe/server/Methods.test.ts +0 -403
  726. package/src/stripe/server/Methods.ts +0 -441
  727. package/src/stripe/server/index.ts +0 -2
  728. package/src/stripe/server/internal/deposit-address.ts +0 -57
  729. package/src/stripe/server/internal/html/main.ts +0 -165
  730. package/src/stripe/server/internal/html/node_modules/.bin/mppx +0 -22
  731. package/src/stripe/server/internal/html/node_modules/.bin/mppx.src +0 -22
  732. package/src/stripe/server/internal/html/package.json +0 -9
  733. package/src/stripe/server/internal/html/stripe-js-pure.d.ts +0 -7
  734. package/src/stripe/server/internal/html/tsconfig.json +0 -8
  735. package/src/stripe/server/internal/html/types.ts +0 -5
  736. package/src/stripe/server/internal/html.gen.ts +0 -2
  737. package/src/stripe/server/internal/record-payment.ts +0 -66
  738. package/src/stripe/server/internal/request.ts +0 -49
  739. package/src/tap/Constants.ts +0 -32
  740. package/src/tap/Tap.test.ts +0 -125
  741. package/src/tap/Types.ts +0 -11
  742. package/src/tap/client/index.ts +0 -54
  743. package/src/tap/index.ts +0 -4
  744. package/src/tap/server/index.ts +0 -48
  745. package/src/tempo/AccessKeyAuthorization.test.ts +0 -141
  746. package/src/tempo/Attribution.test.ts +0 -294
  747. package/src/tempo/Attribution.ts +0 -185
  748. package/src/tempo/Methods.test.ts +0 -425
  749. package/src/tempo/Methods.ts +0 -367
  750. package/src/tempo/Proof.conformance.test.ts +0 -146
  751. package/src/tempo/Proof.test-d.ts +0 -32
  752. package/src/tempo/Proof.test.ts +0 -40
  753. package/src/tempo/Proof.ts +0 -69
  754. package/src/tempo/PublicExports.test-d.ts +0 -130
  755. package/src/tempo/Subscription.integration.test.ts +0 -591
  756. package/src/tempo/client/Charge.test.ts +0 -501
  757. package/src/tempo/client/Charge.ts +0 -271
  758. package/src/tempo/client/Methods.ts +0 -45
  759. package/src/tempo/client/ResolveAccount.ts +0 -46
  760. package/src/tempo/client/Subscription.test.ts +0 -180
  761. package/src/tempo/client/Subscription.ts +0 -156
  762. package/src/tempo/client/index.ts +0 -17
  763. package/src/tempo/index.ts +0 -5
  764. package/src/tempo/internal/account.ts +0 -56
  765. package/src/tempo/internal/address.test.ts +0 -42
  766. package/src/tempo/internal/address.ts +0 -6
  767. package/src/tempo/internal/auto-swap.test.ts +0 -198
  768. package/src/tempo/internal/auto-swap.ts +0 -145
  769. package/src/tempo/internal/charge.test.ts +0 -66
  770. package/src/tempo/internal/charge.ts +0 -43
  771. package/src/tempo/internal/defaults.test.ts +0 -95
  772. package/src/tempo/internal/defaults.ts +0 -53
  773. package/src/tempo/internal/fee-payer.test.ts +0 -1177
  774. package/src/tempo/internal/fee-payer.ts +0 -808
  775. package/src/tempo/internal/fee-token.test.ts +0 -165
  776. package/src/tempo/internal/fee-token.ts +0 -72
  777. package/src/tempo/internal/proof.test.ts +0 -97
  778. package/src/tempo/internal/proof.ts +0 -87
  779. package/src/tempo/internal/selectors.ts +0 -10
  780. package/src/tempo/internal/types.ts +0 -19
  781. package/src/tempo/legacy/AccessKeyAuthorization.test.ts +0 -162
  782. package/src/tempo/legacy/README.md +0 -9
  783. package/src/tempo/legacy/client/ChannelOps.test.ts +0 -379
  784. package/src/tempo/legacy/client/ChannelOps.ts +0 -271
  785. package/src/tempo/legacy/client/Session.test.ts +0 -800
  786. package/src/tempo/legacy/client/Session.ts +0 -397
  787. package/src/tempo/legacy/client/SessionManager.test.ts +0 -468
  788. package/src/tempo/legacy/client/SessionManager.ts +0 -909
  789. package/src/tempo/legacy/client/index.ts +0 -6
  790. package/src/tempo/legacy/index.ts +0 -4
  791. package/src/tempo/legacy/session/Chain.test.ts +0 -1349
  792. package/src/tempo/legacy/session/Chain.ts +0 -830
  793. package/src/tempo/legacy/session/Channel.test.ts +0 -109
  794. package/src/tempo/legacy/session/Channel.ts +0 -51
  795. package/src/tempo/legacy/session/Types.ts +0 -91
  796. package/src/tempo/legacy/session/Voucher.test.ts +0 -410
  797. package/src/tempo/legacy/session/Voucher.ts +0 -183
  798. package/src/tempo/legacy/session/escrow.abi.ts +0 -760
  799. package/src/tempo/legacy/session/index.ts +0 -8
  800. package/src/tempo/server/AtomicStore.test-d.ts +0 -63
  801. package/src/tempo/server/Charge.test.ts +0 -6056
  802. package/src/tempo/server/Charge.ts +0 -1379
  803. package/src/tempo/server/Methods.ts +0 -86
  804. package/src/tempo/server/Relay.test.ts +0 -677
  805. package/src/tempo/server/Relay.ts +0 -297
  806. package/src/tempo/server/SponsorBudget.test.ts +0 -154
  807. package/src/tempo/server/SponsorBudget.ts +0 -219
  808. package/src/tempo/server/Sse.test.ts +0 -321
  809. package/src/tempo/server/Subscription.test.ts +0 -1944
  810. package/src/tempo/server/Subscription.ts +0 -1336
  811. package/src/tempo/server/index.ts +0 -12
  812. package/src/tempo/server/internal/html/main.ts +0 -115
  813. package/src/tempo/server/internal/html/node_modules/.bin/mppx +0 -22
  814. package/src/tempo/server/internal/html/node_modules/.bin/mppx.src +0 -22
  815. package/src/tempo/server/internal/html/package.json +0 -10
  816. package/src/tempo/server/internal/html/tsconfig.json +0 -8
  817. package/src/tempo/server/internal/html.gen.ts +0 -2
  818. package/src/tempo/server/internal/request-body.test.ts +0 -210
  819. package/src/tempo/server/internal/request-body.ts +0 -61
  820. package/src/tempo/server/internal/transport.test.ts +0 -922
  821. package/src/tempo/server/internal/transport.ts +0 -322
  822. package/src/tempo/session/README.md +0 -320
  823. package/src/tempo/session/Snapshot.test.ts +0 -41
  824. package/src/tempo/session/Snapshot.ts +0 -95
  825. package/src/tempo/session/client/ChannelOps.test.ts +0 -218
  826. package/src/tempo/session/client/ChannelOps.ts +0 -348
  827. package/src/tempo/session/client/ChannelStore.ts +0 -111
  828. package/src/tempo/session/client/CredentialState.test.ts +0 -789
  829. package/src/tempo/session/client/CredentialState.ts +0 -942
  830. package/src/tempo/session/client/ReceiptCoordinator.ts +0 -95
  831. package/src/tempo/session/client/Runtime.test.ts +0 -1104
  832. package/src/tempo/session/client/Runtime.ts +0 -1008
  833. package/src/tempo/session/client/Session.test.ts +0 -1355
  834. package/src/tempo/session/client/Session.ts +0 -420
  835. package/src/tempo/session/client/SessionManager.test.ts +0 -1899
  836. package/src/tempo/session/client/SessionManager.ts +0 -996
  837. package/src/tempo/session/client/Transports.test.ts +0 -1141
  838. package/src/tempo/session/client/Transports.ts +0 -1534
  839. package/src/tempo/session/client/index.ts +0 -40
  840. package/src/tempo/session/client/internal/SessionManager.ts +0 -36
  841. package/src/tempo/session/index.ts +0 -7
  842. package/src/tempo/session/precompile/Chain.integration.test.ts +0 -339
  843. package/src/tempo/session/precompile/Chain.test.ts +0 -1641
  844. package/src/tempo/session/precompile/Chain.ts +0 -1269
  845. package/src/tempo/session/precompile/Channel.test.ts +0 -147
  846. package/src/tempo/session/precompile/Channel.ts +0 -108
  847. package/src/tempo/session/precompile/Protocol.test.ts +0 -358
  848. package/src/tempo/session/precompile/Protocol.ts +0 -520
  849. package/src/tempo/session/precompile/Voucher.test.ts +0 -354
  850. package/src/tempo/session/precompile/Voucher.ts +0 -162
  851. package/src/tempo/session/precompile/escrow.abi.ts +0 -226
  852. package/src/tempo/session/precompile/index.ts +0 -33
  853. package/src/tempo/session/server/ChannelOps.test.ts +0 -129
  854. package/src/tempo/session/server/ChannelOps.ts +0 -157
  855. package/src/tempo/session/server/ChannelStore.test.ts +0 -1093
  856. package/src/tempo/session/server/ChannelStore.ts +0 -856
  857. package/src/tempo/session/server/CredentialVerification.test.ts +0 -299
  858. package/src/tempo/session/server/CredentialVerification.ts +0 -1087
  859. package/src/tempo/session/server/MeteredStream.ts +0 -99
  860. package/src/tempo/session/server/RequestState.test.ts +0 -574
  861. package/src/tempo/session/server/RequestState.ts +0 -507
  862. package/src/tempo/session/server/Session.integration.test.ts +0 -449
  863. package/src/tempo/session/server/Session.test.ts +0 -4247
  864. package/src/tempo/session/server/Session.ts +0 -669
  865. package/src/tempo/session/server/Settlement.test.ts +0 -345
  866. package/src/tempo/session/server/Settlement.ts +0 -527
  867. package/src/tempo/session/server/Sse.fuzz.test.ts +0 -138
  868. package/src/tempo/session/server/Sse.test.ts +0 -634
  869. package/src/tempo/session/server/Sse.ts +0 -261
  870. package/src/tempo/session/server/Transports.test.ts +0 -346
  871. package/src/tempo/session/server/Transports.ts +0 -256
  872. package/src/tempo/session/server/Ws.test.ts +0 -765
  873. package/src/tempo/session/server/Ws.ts +0 -391
  874. package/src/tempo/session/server/index.ts +0 -12
  875. package/src/tempo/subscription/KeyAuthorization.test.ts +0 -282
  876. package/src/tempo/subscription/KeyAuthorization.ts +0 -396
  877. package/src/tempo/subscription/Receipt.ts +0 -28
  878. package/src/tempo/subscription/Store.test.ts +0 -609
  879. package/src/tempo/subscription/Store.ts +0 -449
  880. package/src/tempo/subscription/Types.ts +0 -68
  881. package/src/tempo/subscription/index.ts +0 -23
  882. package/src/tsconfig.json +0 -10
  883. package/src/validation/core.ts +0 -386
  884. package/src/validation/index.ts +0 -11
  885. package/src/viem/Account.test.ts +0 -72
  886. package/src/viem/Account.ts +0 -30
  887. package/src/viem/Client.test.ts +0 -366
  888. package/src/viem/Client.ts +0 -93
  889. package/src/web-bot-auth/Constants.ts +0 -24
  890. package/src/web-bot-auth/Types.ts +0 -9
  891. package/src/web-bot-auth/WebBotAuth.test.ts +0 -182
  892. package/src/web-bot-auth/client/index.ts +0 -84
  893. package/src/web-bot-auth/index.ts +0 -6
  894. package/src/web-bot-auth/internal/JwkThumbprint.ts +0 -21
  895. package/src/web-bot-auth/internal/SignatureAgent.ts +0 -18
  896. package/src/web-bot-auth/server/index.ts +0 -113
  897. package/src/x402/Assets.test.ts +0 -253
  898. package/src/x402/Assets.ts +0 -221
  899. package/src/x402/Exact.e2e.test.ts +0 -488
  900. package/src/x402/Exact.localnet.test.ts +0 -475
  901. package/src/x402/Header.test.ts +0 -73
  902. package/src/x402/Header.ts +0 -79
  903. package/src/x402/PublicInterface.test-d.ts +0 -39
  904. package/src/x402/Types.ts +0 -248
  905. package/src/x402/client/Exact.test.ts +0 -309
  906. package/src/x402/client/Exact.ts +0 -186
  907. package/src/x402/index.ts +0 -6
  908. package/src/x402/internal/ChallengeBrand.ts +0 -14
  909. package/src/x402/internal/RouteBinding.ts +0 -18
  910. package/src/x402/server/EvmCharge.ts +0 -410
  911. package/src/x402/server/Facilitator.test.ts +0 -111
  912. package/src/x402/server/Facilitator.ts +0 -56
  913. package/src/zod.test.ts +0 -169
  914. 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
- })