mppx 0.6.30 → 0.7.0

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 (483) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/Challenge.d.ts.map +1 -1
  3. package/dist/Challenge.js +9 -7
  4. package/dist/Challenge.js.map +1 -1
  5. package/dist/Constants.d.ts +46 -0
  6. package/dist/Constants.d.ts.map +1 -0
  7. package/dist/Constants.js +46 -0
  8. package/dist/Constants.js.map +1 -0
  9. package/dist/Credential.d.ts.map +1 -1
  10. package/dist/Credential.js +5 -4
  11. package/dist/Credential.js.map +1 -1
  12. package/dist/Method.d.ts +32 -4
  13. package/dist/Method.d.ts.map +1 -1
  14. package/dist/Method.js +5 -2
  15. package/dist/Method.js.map +1 -1
  16. package/dist/Receipt.d.ts.map +1 -1
  17. package/dist/Receipt.js +3 -2
  18. package/dist/Receipt.js.map +1 -1
  19. package/dist/cli/cli.d.ts.map +1 -1
  20. package/dist/cli/cli.js +19 -11
  21. package/dist/cli/cli.js.map +1 -1
  22. package/dist/cli/plugins/tempo.d.ts.map +1 -1
  23. package/dist/cli/plugins/tempo.js +17 -6
  24. package/dist/cli/plugins/tempo.js.map +1 -1
  25. package/dist/cli/utils.d.ts +5 -0
  26. package/dist/cli/utils.d.ts.map +1 -1
  27. package/dist/cli/utils.js +10 -0
  28. package/dist/cli/utils.js.map +1 -1
  29. package/dist/client/Methods.d.ts +5 -2
  30. package/dist/client/Methods.d.ts.map +1 -1
  31. package/dist/client/Methods.js +5 -2
  32. package/dist/client/Methods.js.map +1 -1
  33. package/dist/client/Transport.d.ts.map +1 -1
  34. package/dist/client/Transport.js +4 -5
  35. package/dist/client/Transport.js.map +1 -1
  36. package/dist/client/index.d.ts +2 -1
  37. package/dist/client/index.d.ts.map +1 -1
  38. package/dist/client/index.js +2 -1
  39. package/dist/client/index.js.map +1 -1
  40. package/dist/client/internal/Fetch.d.ts.map +1 -1
  41. package/dist/client/internal/Fetch.js +14 -6
  42. package/dist/client/internal/Fetch.js.map +1 -1
  43. package/dist/evm/server/Methods.d.ts +1 -1
  44. package/dist/evm/server/Methods.d.ts.map +1 -1
  45. package/dist/index.d.ts +1 -0
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +1 -0
  48. package/dist/index.js.map +1 -1
  49. package/dist/internal/AcceptPayment.d.ts +3 -0
  50. package/dist/internal/AcceptPayment.d.ts.map +1 -1
  51. package/dist/internal/AcceptPayment.js +15 -11
  52. package/dist/internal/AcceptPayment.js.map +1 -1
  53. package/dist/mcp-sdk/client/McpClient.d.ts +12 -5
  54. package/dist/mcp-sdk/client/McpClient.d.ts.map +1 -1
  55. package/dist/mcp-sdk/client/McpClient.js +55 -42
  56. package/dist/mcp-sdk/client/McpClient.js.map +1 -1
  57. package/dist/server/Mppx.d.ts +11 -3
  58. package/dist/server/Mppx.d.ts.map +1 -1
  59. package/dist/server/Mppx.js +76 -27
  60. package/dist/server/Mppx.js.map +1 -1
  61. package/dist/server/Request.js +24 -10
  62. package/dist/server/Request.js.map +1 -1
  63. package/dist/server/Response.d.ts.map +1 -1
  64. package/dist/server/Response.js +2 -1
  65. package/dist/server/Response.js.map +1 -1
  66. package/dist/server/Transport.d.ts.map +1 -1
  67. package/dist/server/Transport.js +4 -3
  68. package/dist/server/Transport.js.map +1 -1
  69. package/dist/server/index.d.ts +1 -0
  70. package/dist/server/index.d.ts.map +1 -1
  71. package/dist/server/index.js +1 -0
  72. package/dist/server/index.js.map +1 -1
  73. package/dist/stripe/client/Charge.d.ts +1 -1
  74. package/dist/stripe/client/Charge.d.ts.map +1 -1
  75. package/dist/stripe/client/Charge.js +3 -1
  76. package/dist/stripe/client/Charge.js.map +1 -1
  77. package/dist/stripe/server/Charge.d.ts +1 -1
  78. package/dist/stripe/server/Charge.d.ts.map +1 -1
  79. package/dist/stripe/server/Charge.js +9 -2
  80. package/dist/stripe/server/Charge.js.map +1 -1
  81. package/dist/stripe/server/Methods.d.ts +1 -1
  82. package/dist/stripe/server/Methods.d.ts.map +1 -1
  83. package/dist/stripe/server/internal/html.gen.d.ts +1 -1
  84. package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
  85. package/dist/stripe/server/internal/html.gen.js +1 -1
  86. package/dist/stripe/server/internal/html.gen.js.map +1 -1
  87. package/dist/tempo/Methods.d.ts +18 -0
  88. package/dist/tempo/Methods.d.ts.map +1 -1
  89. package/dist/tempo/Methods.js +16 -1
  90. package/dist/tempo/Methods.js.map +1 -1
  91. package/dist/tempo/client/Charge.d.ts +6 -0
  92. package/dist/tempo/client/Charge.d.ts.map +1 -1
  93. package/dist/tempo/client/Charge.js +9 -2
  94. package/dist/tempo/client/Charge.js.map +1 -1
  95. package/dist/tempo/client/Methods.d.ts +36 -7
  96. package/dist/tempo/client/Methods.d.ts.map +1 -1
  97. package/dist/tempo/client/Methods.js +12 -5
  98. package/dist/tempo/client/Methods.js.map +1 -1
  99. package/dist/tempo/client/index.d.ts +7 -4
  100. package/dist/tempo/client/index.d.ts.map +1 -1
  101. package/dist/tempo/client/index.js +5 -3
  102. package/dist/tempo/client/index.js.map +1 -1
  103. package/dist/tempo/index.d.ts +1 -0
  104. package/dist/tempo/index.d.ts.map +1 -1
  105. package/dist/tempo/index.js +1 -0
  106. package/dist/tempo/index.js.map +1 -1
  107. package/dist/tempo/internal/fee-payer.d.ts +21 -1
  108. package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
  109. package/dist/tempo/internal/fee-payer.js +109 -4
  110. package/dist/tempo/internal/fee-payer.js.map +1 -1
  111. package/dist/tempo/{client → legacy/client}/ChannelOps.d.ts +19 -6
  112. package/dist/tempo/legacy/client/ChannelOps.d.ts.map +1 -0
  113. package/dist/tempo/{client → legacy/client}/ChannelOps.js +9 -3
  114. package/dist/tempo/legacy/client/ChannelOps.js.map +1 -0
  115. package/dist/tempo/{client → legacy/client}/Session.d.ts +23 -4
  116. package/dist/tempo/legacy/client/Session.d.ts.map +1 -0
  117. package/dist/tempo/{client → legacy/client}/Session.js +14 -7
  118. package/dist/tempo/legacy/client/Session.js.map +1 -0
  119. package/dist/tempo/{client → legacy/client}/SessionManager.d.ts +20 -5
  120. package/dist/tempo/legacy/client/SessionManager.d.ts.map +1 -0
  121. package/dist/tempo/{client → legacy/client}/SessionManager.js +20 -16
  122. package/dist/tempo/legacy/client/SessionManager.js.map +1 -0
  123. package/dist/tempo/legacy/client/index.d.ts +7 -0
  124. package/dist/tempo/legacy/client/index.d.ts.map +1 -0
  125. package/dist/tempo/legacy/client/index.js +5 -0
  126. package/dist/tempo/legacy/client/index.js.map +1 -0
  127. package/dist/tempo/legacy/index.d.ts +7 -0
  128. package/dist/tempo/legacy/index.d.ts.map +1 -0
  129. package/dist/tempo/legacy/index.js +7 -0
  130. package/dist/tempo/legacy/index.js.map +1 -0
  131. package/dist/tempo/{server → legacy/server}/Session.d.ts +28 -11
  132. package/dist/tempo/legacy/server/Session.d.ts.map +1 -0
  133. package/dist/tempo/{server → legacy/server}/Session.js +28 -23
  134. package/dist/tempo/legacy/server/Session.js.map +1 -0
  135. package/dist/tempo/legacy/server/index.d.ts +5 -0
  136. package/dist/tempo/legacy/server/index.d.ts.map +1 -0
  137. package/dist/tempo/legacy/server/index.js +5 -0
  138. package/dist/tempo/legacy/server/index.js.map +1 -0
  139. package/dist/tempo/{session → legacy/session}/Chain.d.ts +30 -23
  140. package/dist/tempo/legacy/session/Chain.d.ts.map +1 -0
  141. package/dist/tempo/{session → legacy/session}/Chain.js +12 -11
  142. package/dist/tempo/legacy/session/Chain.js.map +1 -0
  143. package/dist/tempo/{session → legacy/session}/Channel.d.ts +1 -0
  144. package/dist/tempo/legacy/session/Channel.d.ts.map +1 -0
  145. package/dist/tempo/legacy/session/Channel.js.map +1 -0
  146. package/dist/tempo/legacy/session/ChannelStore.d.ts +22 -0
  147. package/dist/tempo/legacy/session/ChannelStore.d.ts.map +1 -0
  148. package/dist/tempo/legacy/session/ChannelStore.js +6 -0
  149. package/dist/tempo/legacy/session/ChannelStore.js.map +1 -0
  150. package/dist/tempo/legacy/session/Types.d.ts +73 -0
  151. package/dist/tempo/legacy/session/Types.d.ts.map +1 -0
  152. package/dist/tempo/legacy/session/Types.js.map +1 -0
  153. package/dist/tempo/{session → legacy/session}/Voucher.d.ts +4 -4
  154. package/dist/tempo/legacy/session/Voucher.d.ts.map +1 -0
  155. package/dist/tempo/{session → legacy/session}/Voucher.js +1 -1
  156. package/dist/tempo/legacy/session/Voucher.js.map +1 -0
  157. package/dist/tempo/{session → legacy/session}/escrow.abi.d.ts +1 -0
  158. package/dist/tempo/{session → legacy/session}/escrow.abi.d.ts.map +1 -1
  159. package/dist/tempo/{session → legacy/session}/escrow.abi.js +1 -0
  160. package/dist/tempo/legacy/session/escrow.abi.js.map +1 -0
  161. package/dist/tempo/legacy/session/index.d.ts +9 -0
  162. package/dist/tempo/legacy/session/index.d.ts.map +1 -0
  163. package/dist/tempo/legacy/session/index.js +9 -0
  164. package/dist/tempo/legacy/session/index.js.map +1 -0
  165. package/dist/tempo/server/Charge.d.ts +1 -1
  166. package/dist/tempo/server/Charge.d.ts.map +1 -1
  167. package/dist/tempo/server/Charge.js +13 -16
  168. package/dist/tempo/server/Charge.js.map +1 -1
  169. package/dist/tempo/server/Methods.d.ts +63 -6
  170. package/dist/tempo/server/Methods.d.ts.map +1 -1
  171. package/dist/tempo/server/Methods.js +36 -8
  172. package/dist/tempo/server/Methods.js.map +1 -1
  173. package/dist/tempo/server/Subscription.d.ts +1 -1
  174. package/dist/tempo/server/Subscription.d.ts.map +1 -1
  175. package/dist/tempo/server/index.d.ts +6 -5
  176. package/dist/tempo/server/index.d.ts.map +1 -1
  177. package/dist/tempo/server/index.js +5 -5
  178. package/dist/tempo/server/index.js.map +1 -1
  179. package/dist/tempo/server/internal/html.gen.d.ts +1 -1
  180. package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
  181. package/dist/tempo/server/internal/html.gen.js +1 -1
  182. package/dist/tempo/server/internal/html.gen.js.map +1 -1
  183. package/dist/tempo/server/internal/request-body.d.ts +7 -2
  184. package/dist/tempo/server/internal/request-body.d.ts.map +1 -1
  185. package/dist/tempo/server/internal/request-body.js +20 -3
  186. package/dist/tempo/server/internal/request-body.js.map +1 -1
  187. package/dist/tempo/server/internal/transport.d.ts +8 -4
  188. package/dist/tempo/server/internal/transport.d.ts.map +1 -1
  189. package/dist/tempo/server/internal/transport.js +8 -7
  190. package/dist/tempo/server/internal/transport.js.map +1 -1
  191. package/dist/tempo/session/Snapshot.d.ts +32 -0
  192. package/dist/tempo/session/Snapshot.d.ts.map +1 -0
  193. package/dist/tempo/session/Snapshot.js +37 -0
  194. package/dist/tempo/session/Snapshot.js.map +1 -0
  195. package/dist/tempo/session/client/ChannelOps.d.ts +82 -0
  196. package/dist/tempo/session/client/ChannelOps.d.ts.map +1 -0
  197. package/dist/tempo/session/client/ChannelOps.js +204 -0
  198. package/dist/tempo/session/client/ChannelOps.js.map +1 -0
  199. package/dist/tempo/session/client/CredentialState.d.ts +262 -0
  200. package/dist/tempo/session/client/CredentialState.d.ts.map +1 -0
  201. package/dist/tempo/session/client/CredentialState.js +417 -0
  202. package/dist/tempo/session/client/CredentialState.js.map +1 -0
  203. package/dist/tempo/session/client/ReceiptCoordinator.d.ts +26 -0
  204. package/dist/tempo/session/client/ReceiptCoordinator.d.ts.map +1 -0
  205. package/dist/tempo/session/client/ReceiptCoordinator.js +61 -0
  206. package/dist/tempo/session/client/ReceiptCoordinator.js.map +1 -0
  207. package/dist/tempo/session/client/Runtime.d.ts +464 -0
  208. package/dist/tempo/session/client/Runtime.d.ts.map +1 -0
  209. package/dist/tempo/session/client/Runtime.js +499 -0
  210. package/dist/tempo/session/client/Runtime.js.map +1 -0
  211. package/dist/tempo/session/client/Session.d.ts +132 -0
  212. package/dist/tempo/session/client/Session.d.ts.map +1 -0
  213. package/dist/tempo/session/client/Session.js +55 -0
  214. package/dist/tempo/session/client/Session.js.map +1 -0
  215. package/dist/tempo/session/client/SessionManager.d.ts +120 -0
  216. package/dist/tempo/session/client/SessionManager.d.ts.map +1 -0
  217. package/dist/tempo/session/client/SessionManager.js +627 -0
  218. package/dist/tempo/session/client/SessionManager.js.map +1 -0
  219. package/dist/tempo/session/client/Transports.d.ts +449 -0
  220. package/dist/tempo/session/client/Transports.d.ts.map +1 -0
  221. package/dist/tempo/session/client/Transports.js +721 -0
  222. package/dist/tempo/session/client/Transports.js.map +1 -0
  223. package/dist/tempo/session/client/index.d.ts +12 -0
  224. package/dist/tempo/session/client/index.d.ts.map +1 -0
  225. package/dist/tempo/session/client/index.js +5 -0
  226. package/dist/tempo/session/client/index.js.map +1 -0
  227. package/dist/tempo/session/index.d.ts +7 -8
  228. package/dist/tempo/session/index.d.ts.map +1 -1
  229. package/dist/tempo/session/index.js +7 -8
  230. package/dist/tempo/session/index.js.map +1 -1
  231. package/dist/tempo/session/precompile/Chain.d.ts +319 -0
  232. package/dist/tempo/session/precompile/Chain.d.ts.map +1 -0
  233. package/dist/tempo/session/precompile/Chain.js +492 -0
  234. package/dist/tempo/session/precompile/Chain.js.map +1 -0
  235. package/dist/tempo/session/precompile/Channel.d.ts +46 -0
  236. package/dist/tempo/session/precompile/Channel.d.ts.map +1 -0
  237. package/dist/tempo/session/precompile/Channel.js +56 -0
  238. package/dist/tempo/session/precompile/Channel.js.map +1 -0
  239. package/dist/tempo/session/precompile/Protocol.d.ts +308 -0
  240. package/dist/tempo/session/precompile/Protocol.d.ts.map +1 -0
  241. package/dist/tempo/session/precompile/Protocol.js +264 -0
  242. package/dist/tempo/session/precompile/Protocol.js.map +1 -0
  243. package/dist/tempo/session/precompile/Voucher.d.ts +40 -0
  244. package/dist/tempo/session/precompile/Voucher.d.ts.map +1 -0
  245. package/dist/tempo/session/precompile/Voucher.js +126 -0
  246. package/dist/tempo/session/precompile/Voucher.js.map +1 -0
  247. package/dist/tempo/session/precompile/escrow.abi.d.ts +522 -0
  248. package/dist/tempo/session/precompile/escrow.abi.d.ts.map +1 -0
  249. package/dist/tempo/session/precompile/escrow.abi.js +224 -0
  250. package/dist/tempo/session/precompile/escrow.abi.js.map +1 -0
  251. package/dist/tempo/session/precompile/index.d.ts +24 -0
  252. package/dist/tempo/session/precompile/index.d.ts.map +1 -0
  253. package/dist/tempo/session/precompile/index.js +22 -0
  254. package/dist/tempo/session/precompile/index.js.map +1 -0
  255. package/dist/tempo/session/server/ChannelOps.d.ts +56 -0
  256. package/dist/tempo/session/server/ChannelOps.d.ts.map +1 -0
  257. package/dist/tempo/session/server/ChannelOps.js +91 -0
  258. package/dist/tempo/session/server/ChannelOps.js.map +1 -0
  259. package/dist/tempo/session/server/ChannelStore.d.ts +347 -0
  260. package/dist/tempo/session/server/ChannelStore.d.ts.map +1 -0
  261. package/dist/tempo/session/server/ChannelStore.js +404 -0
  262. package/dist/tempo/session/server/ChannelStore.js.map +1 -0
  263. package/dist/tempo/session/server/CredentialVerification.d.ts +85 -0
  264. package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -0
  265. package/dist/tempo/session/server/CredentialVerification.js +494 -0
  266. package/dist/tempo/session/server/CredentialVerification.js.map +1 -0
  267. package/dist/tempo/session/server/MeteredStream.d.ts +40 -0
  268. package/dist/tempo/session/server/MeteredStream.d.ts.map +1 -0
  269. package/dist/tempo/session/server/MeteredStream.js +42 -0
  270. package/dist/tempo/session/server/MeteredStream.js.map +1 -0
  271. package/dist/tempo/session/server/RequestState.d.ts +208 -0
  272. package/dist/tempo/session/server/RequestState.d.ts.map +1 -0
  273. package/dist/tempo/session/server/RequestState.js +252 -0
  274. package/dist/tempo/session/server/RequestState.js.map +1 -0
  275. package/dist/tempo/session/server/Session.d.ts +169 -0
  276. package/dist/tempo/session/server/Session.d.ts.map +1 -0
  277. package/dist/tempo/session/server/Session.js +351 -0
  278. package/dist/tempo/session/server/Session.js.map +1 -0
  279. package/dist/tempo/session/server/Settlement.d.ts +185 -0
  280. package/dist/tempo/session/server/Settlement.d.ts.map +1 -0
  281. package/dist/tempo/session/server/Settlement.js +250 -0
  282. package/dist/tempo/session/server/Settlement.js.map +1 -0
  283. package/dist/tempo/session/{Sse.d.ts → server/Sse.d.ts} +9 -56
  284. package/dist/tempo/session/server/Sse.d.ts.map +1 -0
  285. package/dist/tempo/session/server/Sse.js +184 -0
  286. package/dist/tempo/session/server/Sse.js.map +1 -0
  287. package/dist/tempo/session/server/Transports.d.ts +89 -0
  288. package/dist/tempo/session/server/Transports.d.ts.map +1 -0
  289. package/dist/tempo/session/server/Transports.js +149 -0
  290. package/dist/tempo/session/server/Transports.js.map +1 -0
  291. package/dist/tempo/session/server/Ws.d.ts +48 -0
  292. package/dist/tempo/session/server/Ws.d.ts.map +1 -0
  293. package/dist/tempo/session/server/Ws.js +244 -0
  294. package/dist/tempo/session/server/Ws.js.map +1 -0
  295. package/dist/tempo/session/server/index.d.ts +4 -0
  296. package/dist/tempo/session/server/index.d.ts.map +1 -0
  297. package/dist/tempo/session/server/index.js +2 -0
  298. package/dist/tempo/session/server/index.js.map +1 -0
  299. package/package.json +8 -3
  300. package/src/Challenge.ts +9 -7
  301. package/src/Constants.ts +58 -0
  302. package/src/Credential.ts +5 -4
  303. package/src/Method.ts +46 -5
  304. package/src/Receipt.ts +3 -2
  305. package/src/cli/cli.test.ts +23 -28
  306. package/src/cli/cli.ts +23 -10
  307. package/src/cli/mcp.test.ts +21 -7
  308. package/src/cli/plugins/tempo.ts +21 -8
  309. package/src/cli/utils.test.ts +25 -1
  310. package/src/cli/utils.ts +10 -0
  311. package/src/client/Methods.ts +5 -2
  312. package/src/client/Mppx.test-d.ts +10 -0
  313. package/src/client/Mppx.test.ts +75 -0
  314. package/src/client/Transport.ts +4 -5
  315. package/src/client/index.ts +11 -1
  316. package/src/client/internal/Fetch.test.ts +29 -4
  317. package/src/client/internal/Fetch.ts +17 -5
  318. package/src/env.d.ts +1 -1
  319. package/src/index.ts +1 -0
  320. package/src/internal/AcceptPayment.test.ts +61 -0
  321. package/src/internal/AcceptPayment.ts +21 -14
  322. package/src/mcp-sdk/client/McpClient.integration.test.ts +8 -7
  323. package/src/mcp-sdk/client/McpClient.test-d.ts +7 -0
  324. package/src/mcp-sdk/client/McpClient.ts +99 -67
  325. package/src/mcp-sdk/client/McpClient.unit.test.ts +131 -0
  326. package/src/middlewares/elysia.test.ts +8 -4
  327. package/src/middlewares/express.test.ts +8 -4
  328. package/src/middlewares/hono.test.ts +4 -4
  329. package/src/middlewares/nextjs.test.ts +8 -4
  330. package/src/proxy/Proxy.test.ts +8 -8
  331. package/src/server/Mppx.test-d.ts +54 -0
  332. package/src/server/Mppx.test.ts +274 -7
  333. package/src/server/Mppx.ts +487 -406
  334. package/src/server/Request.test.ts +81 -0
  335. package/src/server/Request.ts +23 -9
  336. package/src/server/Response.ts +2 -1
  337. package/src/server/Transport.ts +4 -3
  338. package/src/server/index.ts +1 -0
  339. package/src/stripe/client/Charge.test.ts +20 -5
  340. package/src/stripe/client/Charge.ts +6 -2
  341. package/src/stripe/server/Charge.test.ts +114 -1
  342. package/src/stripe/server/Charge.ts +13 -2
  343. package/src/stripe/server/internal/html/package.json +1 -1
  344. package/src/stripe/server/internal/html.gen.ts +1 -1
  345. package/src/tempo/AccessKeyAuthorization.test.ts +4 -94
  346. package/src/tempo/Methods.test.ts +45 -17
  347. package/src/tempo/Methods.ts +22 -0
  348. package/src/tempo/PublicExports.test-d.ts +105 -0
  349. package/src/tempo/client/Charge.test.ts +85 -0
  350. package/src/tempo/client/Charge.ts +19 -2
  351. package/src/tempo/client/Methods.ts +18 -6
  352. package/src/tempo/client/index.ts +15 -4
  353. package/src/tempo/index.ts +1 -0
  354. package/src/tempo/internal/fee-payer.test.ts +241 -17
  355. package/src/tempo/internal/fee-payer.ts +150 -4
  356. package/src/tempo/internal/fee-token.test.ts +14 -9
  357. package/src/tempo/legacy/AccessKeyAuthorization.test.ts +162 -0
  358. package/src/tempo/legacy/README.md +9 -0
  359. package/src/tempo/{client → legacy/client}/ChannelOps.test.ts +6 -7
  360. package/src/tempo/{client → legacy/client}/ChannelOps.ts +22 -9
  361. package/src/tempo/{client → legacy/client}/Session.test.ts +51 -9
  362. package/src/tempo/{client → legacy/client}/Session.ts +25 -11
  363. package/src/tempo/{client → legacy/client}/SessionManager.test.ts +81 -9
  364. package/src/tempo/{client → legacy/client}/SessionManager.ts +41 -20
  365. package/src/tempo/legacy/client/index.ts +6 -0
  366. package/src/tempo/legacy/index.ts +6 -0
  367. package/src/tempo/{server → legacy/server}/Session.test.ts +162 -63
  368. package/src/tempo/{server → legacy/server}/Session.ts +49 -37
  369. package/src/tempo/legacy/server/index.ts +4 -0
  370. package/src/tempo/{session → legacy/session}/Chain.test.ts +3 -4
  371. package/src/tempo/{session → legacy/session}/Chain.ts +94 -63
  372. package/src/tempo/{session → legacy/session}/Channel.ts +1 -0
  373. package/src/tempo/legacy/session/ChannelStore.test.ts +58 -0
  374. package/src/tempo/legacy/session/ChannelStore.ts +39 -0
  375. package/src/tempo/legacy/session/Types.ts +91 -0
  376. package/src/tempo/{session → legacy/session}/Voucher.ts +12 -8
  377. package/src/tempo/{session → legacy/session}/escrow.abi.ts +1 -0
  378. package/src/tempo/legacy/session/index.ts +8 -0
  379. package/src/tempo/server/AtomicStore.test-d.ts +16 -11
  380. package/src/tempo/server/Charge.test.ts +92 -14
  381. package/src/tempo/server/Charge.ts +18 -16
  382. package/src/tempo/server/Methods.ts +54 -8
  383. package/src/tempo/server/Sse.test.ts +2 -2
  384. package/src/tempo/server/index.ts +6 -5
  385. package/src/tempo/server/internal/html/package.json +1 -1
  386. package/src/tempo/server/internal/html.gen.ts +1 -1
  387. package/src/tempo/server/internal/request-body.test.ts +37 -4
  388. package/src/tempo/server/internal/request-body.ts +25 -6
  389. package/src/tempo/server/internal/transport.test.ts +4 -4
  390. package/src/tempo/server/internal/transport.ts +19 -10
  391. package/src/tempo/session/Snapshot.test.ts +41 -0
  392. package/src/tempo/session/Snapshot.ts +74 -0
  393. package/src/tempo/session/client/ChannelOps.test.ts +163 -0
  394. package/src/tempo/session/client/ChannelOps.ts +344 -0
  395. package/src/tempo/session/client/CredentialState.test.ts +645 -0
  396. package/src/tempo/session/client/CredentialState.ts +814 -0
  397. package/src/tempo/session/client/ReceiptCoordinator.ts +95 -0
  398. package/src/tempo/session/client/Runtime.test.ts +1092 -0
  399. package/src/tempo/session/client/Runtime.ts +986 -0
  400. package/src/tempo/session/client/Session.test.ts +734 -0
  401. package/src/tempo/session/client/Session.ts +97 -0
  402. package/src/tempo/session/client/SessionManager.test.ts +1308 -0
  403. package/src/tempo/session/client/SessionManager.ts +845 -0
  404. package/src/tempo/session/client/Transports.test.ts +837 -0
  405. package/src/tempo/session/client/Transports.ts +1292 -0
  406. package/src/tempo/session/client/index.ts +37 -0
  407. package/src/tempo/session/index.ts +7 -8
  408. package/src/tempo/session/precompile/Chain.integration.test.ts +321 -0
  409. package/src/tempo/session/precompile/Chain.test.ts +1258 -0
  410. package/src/tempo/session/precompile/Chain.ts +979 -0
  411. package/src/tempo/session/precompile/Channel.test.ts +138 -0
  412. package/src/tempo/session/precompile/Channel.ts +103 -0
  413. package/src/tempo/session/precompile/Protocol.test.ts +358 -0
  414. package/src/tempo/session/precompile/Protocol.ts +520 -0
  415. package/src/tempo/session/precompile/Voucher.test.ts +316 -0
  416. package/src/tempo/session/precompile/Voucher.ts +160 -0
  417. package/src/tempo/session/precompile/escrow.abi.ts +226 -0
  418. package/src/tempo/session/precompile/index.ts +33 -0
  419. package/src/tempo/session/server/ChannelOps.test.ts +129 -0
  420. package/src/tempo/session/server/ChannelOps.ts +157 -0
  421. package/src/tempo/session/{ChannelStore.test.ts → server/ChannelStore.test.ts} +536 -29
  422. package/src/tempo/session/server/ChannelStore.ts +835 -0
  423. package/src/tempo/session/server/CredentialVerification.test.ts +146 -0
  424. package/src/tempo/session/server/CredentialVerification.ts +710 -0
  425. package/src/tempo/session/server/MeteredStream.ts +88 -0
  426. package/src/tempo/session/server/RequestState.test.ts +531 -0
  427. package/src/tempo/session/server/RequestState.ts +499 -0
  428. package/src/tempo/session/server/Session.integration.test.ts +444 -0
  429. package/src/tempo/session/server/Session.test.ts +3253 -0
  430. package/src/tempo/session/server/Session.ts +543 -0
  431. package/src/tempo/session/server/Settlement.test.ts +242 -0
  432. package/src/tempo/session/server/Settlement.ts +470 -0
  433. package/src/tempo/session/{Sse.test.ts → server/Sse.test.ts} +37 -3
  434. package/src/tempo/session/server/Sse.ts +256 -0
  435. package/src/tempo/session/server/Transports.test.ts +346 -0
  436. package/src/tempo/session/server/Transports.ts +255 -0
  437. package/src/tempo/session/{Ws.test.ts → server/Ws.test.ts} +4 -4
  438. package/src/tempo/session/server/Ws.ts +384 -0
  439. package/src/tempo/session/server/index.ts +8 -0
  440. package/dist/tempo/client/ChannelOps.d.ts.map +0 -1
  441. package/dist/tempo/client/ChannelOps.js.map +0 -1
  442. package/dist/tempo/client/Session.d.ts.map +0 -1
  443. package/dist/tempo/client/Session.js.map +0 -1
  444. package/dist/tempo/client/SessionManager.d.ts.map +0 -1
  445. package/dist/tempo/client/SessionManager.js.map +0 -1
  446. package/dist/tempo/server/Session.d.ts.map +0 -1
  447. package/dist/tempo/server/Session.js.map +0 -1
  448. package/dist/tempo/session/Chain.d.ts.map +0 -1
  449. package/dist/tempo/session/Chain.js.map +0 -1
  450. package/dist/tempo/session/Channel.d.ts.map +0 -1
  451. package/dist/tempo/session/Channel.js.map +0 -1
  452. package/dist/tempo/session/ChannelStore.d.ts +0 -117
  453. package/dist/tempo/session/ChannelStore.d.ts.map +0 -1
  454. package/dist/tempo/session/ChannelStore.js +0 -172
  455. package/dist/tempo/session/ChannelStore.js.map +0 -1
  456. package/dist/tempo/session/Receipt.d.ts +0 -22
  457. package/dist/tempo/session/Receipt.d.ts.map +0 -1
  458. package/dist/tempo/session/Receipt.js +0 -34
  459. package/dist/tempo/session/Receipt.js.map +0 -1
  460. package/dist/tempo/session/Sse.d.ts.map +0 -1
  461. package/dist/tempo/session/Sse.js +0 -363
  462. package/dist/tempo/session/Sse.js.map +0 -1
  463. package/dist/tempo/session/Types.d.ts +0 -78
  464. package/dist/tempo/session/Types.d.ts.map +0 -1
  465. package/dist/tempo/session/Types.js.map +0 -1
  466. package/dist/tempo/session/Voucher.d.ts.map +0 -1
  467. package/dist/tempo/session/Voucher.js.map +0 -1
  468. package/dist/tempo/session/Ws.d.ts +0 -87
  469. package/dist/tempo/session/Ws.d.ts.map +0 -1
  470. package/dist/tempo/session/Ws.js +0 -443
  471. package/dist/tempo/session/Ws.js.map +0 -1
  472. package/dist/tempo/session/escrow.abi.js.map +0 -1
  473. package/src/tempo/session/ChannelStore.ts +0 -308
  474. package/src/tempo/session/Receipt.test.ts +0 -89
  475. package/src/tempo/session/Receipt.ts +0 -46
  476. package/src/tempo/session/Sse.ts +0 -462
  477. package/src/tempo/session/Types.ts +0 -86
  478. package/src/tempo/session/Ws.ts +0 -576
  479. /package/dist/tempo/{session → legacy/session}/Channel.js +0 -0
  480. /package/dist/tempo/{session → legacy/session}/Types.js +0 -0
  481. /package/src/tempo/{session → legacy/session}/Channel.test.ts +0 -0
  482. /package/src/tempo/{session → legacy/session}/Voucher.test.ts +0 -0
  483. /package/src/tempo/session/{Sse.fuzz.test.ts → server/Sse.fuzz.test.ts} +0 -0
@@ -9,7 +9,16 @@ import {
9
9
 
10
10
  describe('request-body', () => {
11
11
  describe('hasCapturedRequestBody', () => {
12
- test('returns true when the captured request recorded a body stream', () => {
12
+ test('returns true when the captured request recorded a typed body stream', () => {
13
+ expect(
14
+ hasCapturedRequestBody({
15
+ hasBody: true,
16
+ headers: new Headers({ 'content-type': 'application/json' }),
17
+ }),
18
+ ).toBe(true)
19
+ })
20
+
21
+ test('returns true for captured body streams without body headers', () => {
13
22
  expect(
14
23
  hasCapturedRequestBody({
15
24
  hasBody: true,
@@ -63,7 +72,17 @@ describe('request-body', () => {
63
72
  ).toBe(false)
64
73
  })
65
74
 
66
- test('treats POST requests with a body stream and no content-length as content requests', () => {
75
+ test('treats POST requests with a typed body stream and no content-length as content requests', () => {
76
+ expect(
77
+ isSessionContentRequest({
78
+ hasBody: true,
79
+ headers: new Headers({ 'content-type': 'application/json' }),
80
+ method: 'POST',
81
+ }),
82
+ ).toBe(true)
83
+ })
84
+
85
+ test('treats POST body streams without body headers as content requests', () => {
67
86
  expect(
68
87
  isSessionContentRequest({
69
88
  hasBody: true,
@@ -107,12 +126,12 @@ describe('request-body', () => {
107
126
  expect(shouldChargePlainResponse(input, { action: 'topUp' })).toBe(false)
108
127
  })
109
128
 
110
- test('charges POST content requests detected via the body stream', () => {
129
+ test('charges POST content requests detected via the typed body stream', () => {
111
130
  expect(
112
131
  shouldChargePlainResponse(
113
132
  {
114
133
  hasBody: true,
115
- headers: new Headers(),
134
+ headers: new Headers({ 'content-type': 'application/json' }),
116
135
  method: 'POST',
117
136
  },
118
137
  { action: 'voucher' },
@@ -133,6 +152,20 @@ describe('request-body', () => {
133
152
  ).toBe(false)
134
153
  })
135
154
 
155
+ test('charges voucher POSTs when runtime reports a body stream', () => {
156
+ expect(
157
+ shouldChargePlainResponse(
158
+ {
159
+ hasBody: true,
160
+ headers: new Headers(),
161
+ method: 'POST',
162
+ url: new URL('https://api.example.com/session'),
163
+ },
164
+ { action: 'voucher' },
165
+ ),
166
+ ).toBe(true)
167
+ })
168
+
136
169
  test('charges bodyless POST query requests', () => {
137
170
  expect(
138
171
  shouldChargePlainResponse(
@@ -1,9 +1,11 @@
1
1
  import type * as Method from '../../../Method.js'
2
- import type { SessionCredentialPayload } from '../../session/Types.js'
2
+ import type { SessionCredentialContext } from '../../session/precompile/Protocol.js'
3
3
 
4
+ /** Minimal immutable request shape used to decide whether a session request serves billable content. */
4
5
  export type RequestBodyProbe = Pick<Method.CapturedRequest, 'headers' | 'hasBody' | 'method'> &
5
6
  Partial<Pick<Method.CapturedRequest, 'url'>>
6
7
 
8
+ /** Captures the request fields needed by the session content/management classifier. */
7
9
  export function captureRequestBodyProbe(input: Request): RequestBodyProbe {
8
10
  return {
9
11
  headers: input.headers,
@@ -13,17 +15,25 @@ export function captureRequestBodyProbe(input: Request): RequestBodyProbe {
13
15
  }
14
16
  }
15
17
 
18
+ /** Returns whether request metadata indicates a meaningful body is present. */
16
19
  export function hasCapturedRequestBody(
17
20
  input: Pick<RequestBodyProbe, 'headers' | 'hasBody'>,
18
21
  ): boolean {
22
+ if (hasBodyFramingHeaders(input)) return true
23
+ if (input.hasBody === true) return true
24
+ return false
25
+ }
26
+
27
+ function hasBodyFramingHeaders(input: Pick<RequestBodyProbe, 'headers'>): boolean {
19
28
  const contentLength = input.headers.get('content-length')
20
- const headerIndicatesBody =
21
- (contentLength !== null && contentLength !== '0') || input.headers.has('transfer-encoding')
29
+ return (contentLength !== null && contentLength !== '0') || input.headers.has('transfer-encoding')
30
+ }
22
31
 
23
- if (input.hasBody === true) return true
24
- return headerIndicatesBody
32
+ function hasBodyIntentHeaders(input: Pick<RequestBodyProbe, 'headers'>): boolean {
33
+ return hasBodyFramingHeaders(input) || input.headers.has('content-type')
25
34
  }
26
35
 
36
+ /** Returns whether a verified session credential should let the application handler serve content. */
27
37
  export function isSessionContentRequest(input: RequestBodyProbe): boolean {
28
38
  if (input.method === 'HEAD') return false
29
39
  if (input.method !== 'POST') return true
@@ -31,10 +41,19 @@ export function isSessionContentRequest(input: RequestBodyProbe): boolean {
31
41
  return hasCapturedRequestBody(input)
32
42
  }
33
43
 
44
+ /** Returns whether a plain non-streaming response should be charged after verification. */
34
45
  export function shouldChargePlainResponse(
35
46
  input: RequestBodyProbe,
36
- payload: Partial<SessionCredentialPayload>,
47
+ payload: Partial<SessionCredentialContext>,
37
48
  ): boolean {
38
49
  if (payload.action === 'close' || payload.action === 'topUp') return false
50
+ if (
51
+ (payload.action === 'open' || payload.action === 'voucher') &&
52
+ input.method === 'POST' &&
53
+ !input.url?.search &&
54
+ input.hasBody !== true &&
55
+ !hasBodyIntentHeaders(input)
56
+ )
57
+ return false
39
58
  return isSessionContentRequest(input)
40
59
  }
@@ -4,10 +4,10 @@ import { describe, expect, test } from 'vp/test'
4
4
 
5
5
  import * as Store from '../../../Store.js'
6
6
  import { chainId, escrowContract as escrowContractDefaults } from '../../internal/defaults.js'
7
- import * as ChannelStore from '../../session/ChannelStore.js'
8
- import { deserializeSessionReceipt } from '../../session/Receipt.js'
9
- import { parseEvent } from '../../session/Sse.js'
10
- import type { SessionReceipt } from '../../session/Types.js'
7
+ import { deserializeSessionReceipt } from '../../session/precompile/Protocol.js'
8
+ import type { SessionReceipt } from '../../session/precompile/Protocol.js'
9
+ import * as ChannelStore from '../../session/server/ChannelStore.js'
10
+ import { parseEvent } from '../../session/server/Sse.js'
11
11
  import { markPrepaidSessionTick, sse } from './transport.js'
12
12
 
13
13
  const channelId = '0x0000000000000000000000000000000000000000000000000000000000000001' as Hex
@@ -6,11 +6,13 @@
6
6
  * @internal
7
7
  */
8
8
  import * as Challenge from '../../../Challenge.js'
9
+ import * as Constants from '../../../Constants.js'
9
10
  import * as Errors from '../../../Errors.js'
10
11
  import * as Transport from '../../../server/Transport.js'
11
- import * as ChannelStore from '../../session/ChannelStore.js'
12
- import * as Sse_core from '../../session/Sse.js'
13
- import type { SessionCredentialPayload, SessionReceipt } from '../../session/Types.js'
12
+ import type { SessionReceipt } from '../../session/precompile/Protocol.js'
13
+ import { requireSessionCredentialContext } from '../../session/precompile/Protocol.js'
14
+ import * as ChannelStore from '../../session/server/ChannelStore.js'
15
+ import * as Sse_core from '../../session/server/Sse.js'
14
16
  import { captureRequestBodyProbe, shouldChargePlainResponse } from './request-body.js'
15
17
 
16
18
  const prepaidSessionTick = Symbol('mppx.prepaidSessionTick')
@@ -18,10 +20,12 @@ const prepaidSessionTick = Symbol('mppx.prepaidSessionTick')
18
20
  /** SSE transport with Tempo session controller. */
19
21
  export type Sse = Transport.Sse<Sse_core.SessionController>
20
22
 
23
+ /** Receipt marker used to avoid double-charging a request already charged during verification. */
21
24
  export type PrepaidSessionReceipt = SessionReceipt & {
22
25
  [prepaidSessionTick]?: true | undefined
23
26
  }
24
27
 
28
+ /** Marks a session receipt as already charged for the current request. */
25
29
  export function markPrepaidSessionTick(receipt: SessionReceipt): SessionReceipt {
26
30
  Object.defineProperty(receipt, prepaidSessionTick, {
27
31
  configurable: false,
@@ -83,9 +87,10 @@ export function sse(options: sse.Options & { store: ChannelStore.ChannelStore })
83
87
  const verifiedCredential = envelope?.credential ?? credential
84
88
  const verifiedChallengeId = envelope?.challenge.id ?? challengeId
85
89
  const verifiedRequest = envelope?.request ?? verifiedCredential.challenge.request
86
- const payload = verifiedCredential.payload as Partial<SessionCredentialPayload>
87
- if (!payload.channelId) throw new Error('No SSE context available')
88
-
90
+ const payload = requireSessionCredentialContext(
91
+ verifiedCredential.payload,
92
+ 'No SSE context available',
93
+ )
89
94
  const channelId = payload.channelId
90
95
  const tickCost = BigInt(verifiedCredential.challenge.request.amount as string)
91
96
  const unitType =
@@ -146,7 +151,9 @@ export function sse(options: sse.Options & { store: ChannelStore.ChannelStore })
146
151
  {
147
152
  status: error.status,
148
153
  headers: {
149
- 'WWW-Authenticate': Challenge.serialize(verifiedCredential.challenge),
154
+ [Constants.Headers.wwwAuthenticate]: Challenge.serialize(
155
+ verifiedCredential.challenge,
156
+ ),
150
157
  'Cache-Control': 'no-store',
151
158
  'Content-Type': 'application/problem+json',
152
159
  },
@@ -217,6 +224,7 @@ export function sse(options: sse.Options & { store: ChannelStore.ChannelStore })
217
224
  })
218
225
  }
219
226
 
227
+ /** Type helpers for the Tempo SSE transport adapter. */
220
228
  export declare namespace sse {
221
229
  type Options = {
222
230
  /**
@@ -235,13 +243,14 @@ export declare namespace sse {
235
243
  }
236
244
  }
237
245
 
246
+ type DefaultServeGenerate = AsyncIterable<string> | (() => AsyncIterable<string>)
247
+
238
248
  /** Default SSE serve: iterates values and emits `event: message` per value. */
239
249
  export function defaultServe(options: {
240
- generate: AsyncIterable<string> | ((...args: any[]) => AsyncIterable<string>)
250
+ generate: DefaultServeGenerate
241
251
  challengeId: string
242
252
  }): Response {
243
- const iterable =
244
- typeof options.generate === 'function' ? options.generate(undefined as any) : options.generate
253
+ const iterable = typeof options.generate === 'function' ? options.generate() : options.generate
245
254
  const encoder = new TextEncoder()
246
255
  const stream = new ReadableStream<Uint8Array>({
247
256
  async start(controller) {
@@ -0,0 +1,41 @@
1
+ import { Base64 } from 'ox'
2
+ import { describe, expect, test } from 'vp/test'
3
+
4
+ import { deserializeSnapshot, serializeSnapshot, type SessionSnapshot } from './Snapshot.js'
5
+
6
+ const descriptor = {
7
+ authorizedSigner: '0x0000000000000000000000000000000000000001',
8
+ expiringNonceHash: `0x${'11'.repeat(32)}`,
9
+ operator: '0x0000000000000000000000000000000000000000',
10
+ payee: '0x0000000000000000000000000000000000000002',
11
+ payer: '0x0000000000000000000000000000000000000003',
12
+ salt: `0x${'22'.repeat(32)}`,
13
+ token: '0x20c0000000000000000000000000000000000001',
14
+ } as const
15
+
16
+ const snapshot = {
17
+ acceptedCumulative: '100',
18
+ chainId: 4217,
19
+ channelId: `0x${'aa'.repeat(32)}`,
20
+ deposit: '1000',
21
+ descriptor,
22
+ escrow: '0x4d50500000000000000000000000000000000000',
23
+ requiredCumulative: '100',
24
+ settled: '0',
25
+ spent: '50',
26
+ units: 5,
27
+ } satisfies SessionSnapshot
28
+
29
+ describe('SessionSnapshot', () => {
30
+ test('round-trips a valid snapshot header', () => {
31
+ expect(deserializeSnapshot(serializeSnapshot(snapshot))).toEqual(snapshot)
32
+ })
33
+
34
+ test('rejects malformed channel descriptors', () => {
35
+ const value = serializeSnapshot(snapshot)
36
+ const encoded = JSON.parse(Base64.toString(value)) as SessionSnapshot
37
+ encoded.descriptor = { ...descriptor, payee: 'not-an-address' as never }
38
+
39
+ expect(() => deserializeSnapshot(Base64.fromString(JSON.stringify(encoded)))).toThrow()
40
+ })
41
+ })
@@ -0,0 +1,74 @@
1
+ import { isAddress, type Address, type Hex } from 'viem'
2
+
3
+ import * as HeaderCodec from '../../internal/HeaderCodec.js'
4
+ import * as z from '../../zod.js'
5
+ import type { ChannelDescriptor, RawAmountString } from './precompile/Protocol.js'
6
+
7
+ /** Server-provided reusable channel state used to bootstrap a client session. */
8
+ export type SessionSnapshot = {
9
+ /** Highest cumulative voucher amount the server has accepted for this channel. */
10
+ acceptedCumulative: RawAmountString
11
+ /** Tempo chain ID used to derive the channel ID and voucher domain. */
12
+ chainId: number
13
+ /** TIP-1034 channel ID derived from descriptor, escrow address, and chain ID. */
14
+ channelId: Hex
15
+ /** Timestamp when unilateral close was requested, when the channel is closing. */
16
+ closeRequestedAt?: RawAmountString | undefined
17
+ /** Current on-chain deposit ceiling for cumulative voucher authorization. */
18
+ deposit: RawAmountString
19
+ /** Full descriptor needed to recover the channel without client-side persistence. */
20
+ descriptor: ChannelDescriptor
21
+ /** Escrow precompile address used to derive the channel ID. */
22
+ escrow: Address
23
+ /** Minimum cumulative authorization needed for the challenged request or stream continuation. */
24
+ requiredCumulative: RawAmountString
25
+ /** Amount already settled on-chain. */
26
+ settled: RawAmountString
27
+ /** Amount consumed by delivered content according to server accounting. */
28
+ spent: RawAmountString
29
+ /** Paid units delivered by the server, when the transport reports them. */
30
+ units?: number | undefined
31
+ }
32
+
33
+ const addressSchema = z.custom<Address>(
34
+ (value) => typeof value === 'string' && isAddress(value, { strict: false }),
35
+ )
36
+ const hashSchema = z.custom<Hex>(
37
+ (value) => typeof value === 'string' && /^0x[0-9a-fA-F]{64}$/.test(value),
38
+ )
39
+
40
+ const channelDescriptorSchema = z.object({
41
+ authorizedSigner: addressSchema,
42
+ expiringNonceHash: hashSchema,
43
+ operator: addressSchema,
44
+ payee: addressSchema,
45
+ payer: addressSchema,
46
+ salt: hashSchema,
47
+ token: addressSchema,
48
+ })
49
+
50
+ const sessionSnapshotSchema = z.object({
51
+ acceptedCumulative: z.string(),
52
+ chainId: z.number(),
53
+ channelId: hashSchema,
54
+ closeRequestedAt: z.optional(z.string()),
55
+ deposit: z.string(),
56
+ descriptor: channelDescriptorSchema,
57
+ escrow: addressSchema,
58
+ requiredCumulative: z.string(),
59
+ settled: z.string(),
60
+ spent: z.string(),
61
+ units: z.optional(z.number()),
62
+ })
63
+
64
+ const sessionSnapshotHeader = HeaderCodec.createJson(sessionSnapshotSchema)
65
+
66
+ /** Serializes a session snapshot for the `Payment-Session-Snapshot` header. */
67
+ export function serializeSnapshot(snapshot: SessionSnapshot): string {
68
+ return sessionSnapshotHeader.encode(snapshot)
69
+ }
70
+
71
+ /** Deserializes a session snapshot from the `Payment-Session-Snapshot` header. */
72
+ export function deserializeSnapshot(value: string): SessionSnapshot {
73
+ return sessionSnapshotHeader.decode(value) as SessionSnapshot
74
+ }
@@ -0,0 +1,163 @@
1
+ import { Hex } from 'ox'
2
+ import { type Address, createClient, custom, zeroAddress } from 'viem'
3
+ import { privateKeyToAccount } from 'viem/accounts'
4
+ import { describe, expect, test } from 'vp/test'
5
+
6
+ import * as Channel from '../precompile/Channel.js'
7
+ import { tip20ChannelEscrow } from '../precompile/Protocol.js'
8
+ import * as Types from '../precompile/Protocol.js'
9
+ import * as Voucher from '../precompile/Voucher.js'
10
+ import * as ChannelOps from './ChannelOps.js'
11
+
12
+ const account = privateKeyToAccount(
13
+ '0xac0974bec39a17e36ba6a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
14
+ )
15
+ const client = createClient({
16
+ account,
17
+ transport: custom({
18
+ async request() {
19
+ throw new Error('unexpected rpc request')
20
+ },
21
+ }),
22
+ })
23
+ const chainId = 42431
24
+
25
+ const descriptor = {
26
+ payer: account.address,
27
+ payee: '0x0000000000000000000000000000000000000002' as Address,
28
+ operator: '0x0000000000000000000000000000000000000000' as Address,
29
+ token: '0x0000000000000000000000000000000000000003' as Address,
30
+ salt: `0x${'11'.repeat(32)}` as Hex.Hex,
31
+ authorizedSigner: account.address,
32
+ expiringNonceHash: `0x${'22'.repeat(32)}` as Hex.Hex,
33
+ } satisfies Channel.ChannelDescriptor
34
+
35
+ const channelId = Channel.computeId({ ...descriptor, chainId, escrow: tip20ChannelEscrow })
36
+
37
+ describe('precompile client ChannelOps credential builders', () => {
38
+ test('resolves escrow from override, challenge hint, or canonical default', () => {
39
+ const override = '0x0000000000000000000000000000000000000005' as Address
40
+ const hinted = '0x0000000000000000000000000000000000000006' as Address
41
+
42
+ expect(
43
+ ChannelOps.resolveEscrow(
44
+ { request: { methodDetails: { escrowContract: hinted } } },
45
+ override,
46
+ ),
47
+ ).toBe(override)
48
+ expect(
49
+ ChannelOps.resolveEscrow({ request: { methodDetails: { escrowContract: hinted } } }),
50
+ ).toBe(hinted)
51
+ expect(ChannelOps.resolveEscrow({ request: { methodDetails: { escrow: hinted } } })).toBe(
52
+ hinted,
53
+ )
54
+ expect(
55
+ ChannelOps.resolveEscrow({
56
+ request: { methodDetails: { escrowContract: 'not-an-address' } },
57
+ }),
58
+ ).toBe(tip20ChannelEscrow)
59
+ expect(ChannelOps.resolveEscrow({ request: { methodDetails: {} } })).toBe(tip20ChannelEscrow)
60
+ })
61
+
62
+ test('creates a verifiable voucher credential for an existing precompile channel', async () => {
63
+ const cumulativeAmount = Types.uint96(250n)
64
+ const payload = await ChannelOps.createVoucherPayload(
65
+ client,
66
+ account,
67
+ descriptor,
68
+ cumulativeAmount,
69
+ chainId,
70
+ )
71
+ if (payload.action !== 'voucher') throw new Error('expected voucher payload')
72
+
73
+ expect(payload.channelId).toBe(channelId)
74
+ expect(payload.descriptor).toEqual(descriptor)
75
+ expect(payload.cumulativeAmount).toBe('250')
76
+ expect(
77
+ Voucher.verifyVoucher(
78
+ tip20ChannelEscrow,
79
+ chainId,
80
+ { channelId, cumulativeAmount, signature: payload.signature },
81
+ descriptor.authorizedSigner,
82
+ ),
83
+ ).toBe(true)
84
+ })
85
+
86
+ test('binds voucher channel ID and signature domain to the provided escrow', async () => {
87
+ const escrow = '0x0000000000000000000000000000000000000005' as Address
88
+ const cumulativeAmount = Types.uint96(260n)
89
+ const expectedChannelId = Channel.computeId({ ...descriptor, chainId, escrow })
90
+ const payload = await ChannelOps.createVoucherPayload(
91
+ client,
92
+ account,
93
+ descriptor,
94
+ cumulativeAmount,
95
+ chainId,
96
+ escrow,
97
+ )
98
+
99
+ expect(payload.channelId).toBe(expectedChannelId)
100
+ expect(
101
+ Voucher.verifyVoucher(
102
+ escrow,
103
+ chainId,
104
+ { channelId: expectedChannelId, cumulativeAmount, signature: payload.signature },
105
+ descriptor.authorizedSigner,
106
+ ),
107
+ ).toBe(true)
108
+ })
109
+
110
+ test('uses the payer as voucher signer when descriptor authorizedSigner is zero', async () => {
111
+ const zeroSignerDescriptor = {
112
+ ...descriptor,
113
+ authorizedSigner: zeroAddress,
114
+ }
115
+ const zeroSignerChannelId = Channel.computeId({
116
+ ...zeroSignerDescriptor,
117
+ chainId,
118
+ escrow: tip20ChannelEscrow,
119
+ })
120
+ const cumulativeAmount = Types.uint96(275n)
121
+ const payload = await ChannelOps.createVoucherPayload(
122
+ client,
123
+ account,
124
+ zeroSignerDescriptor,
125
+ cumulativeAmount,
126
+ chainId,
127
+ )
128
+ if (payload.action !== 'voucher') throw new Error('expected voucher payload')
129
+
130
+ expect(payload.channelId).toBe(zeroSignerChannelId)
131
+ expect(
132
+ Voucher.verifyVoucher(
133
+ tip20ChannelEscrow,
134
+ chainId,
135
+ { channelId: zeroSignerChannelId, cumulativeAmount, signature: payload.signature },
136
+ descriptor.payer,
137
+ ),
138
+ ).toBe(true)
139
+ })
140
+
141
+ test('creates a close credential with a verifiable voucher signature', async () => {
142
+ const cumulativeAmount = Types.uint96(300n)
143
+ const payload = await ChannelOps.createClosePayload(
144
+ client,
145
+ account,
146
+ descriptor,
147
+ cumulativeAmount,
148
+ chainId,
149
+ )
150
+ if (payload.action !== 'close') throw new Error('expected close payload')
151
+
152
+ expect(payload.channelId).toBe(channelId)
153
+ expect(payload.cumulativeAmount).toBe('300')
154
+ expect(
155
+ Voucher.verifyVoucher(
156
+ tip20ChannelEscrow,
157
+ chainId,
158
+ { channelId, cumulativeAmount, signature: payload.signature },
159
+ descriptor.authorizedSigner,
160
+ ),
161
+ ).toBe(true)
162
+ })
163
+ })