mppx 0.6.31 → 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 (477) hide show
  1. package/CHANGELOG.md +17 -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/Response.d.ts.map +1 -1
  62. package/dist/server/Response.js +2 -1
  63. package/dist/server/Response.js.map +1 -1
  64. package/dist/server/Transport.d.ts.map +1 -1
  65. package/dist/server/Transport.js +4 -3
  66. package/dist/server/Transport.js.map +1 -1
  67. package/dist/server/index.d.ts +1 -0
  68. package/dist/server/index.d.ts.map +1 -1
  69. package/dist/server/index.js +1 -0
  70. package/dist/server/index.js.map +1 -1
  71. package/dist/stripe/client/Charge.d.ts +1 -1
  72. package/dist/stripe/client/Charge.d.ts.map +1 -1
  73. package/dist/stripe/client/Charge.js +3 -1
  74. package/dist/stripe/client/Charge.js.map +1 -1
  75. package/dist/stripe/server/Charge.d.ts +1 -1
  76. package/dist/stripe/server/Charge.d.ts.map +1 -1
  77. package/dist/stripe/server/Charge.js +9 -2
  78. package/dist/stripe/server/Charge.js.map +1 -1
  79. package/dist/stripe/server/Methods.d.ts +1 -1
  80. package/dist/stripe/server/Methods.d.ts.map +1 -1
  81. package/dist/stripe/server/internal/html.gen.d.ts +1 -1
  82. package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
  83. package/dist/stripe/server/internal/html.gen.js +1 -1
  84. package/dist/stripe/server/internal/html.gen.js.map +1 -1
  85. package/dist/tempo/Methods.d.ts +18 -0
  86. package/dist/tempo/Methods.d.ts.map +1 -1
  87. package/dist/tempo/Methods.js +16 -1
  88. package/dist/tempo/Methods.js.map +1 -1
  89. package/dist/tempo/client/Charge.d.ts +6 -0
  90. package/dist/tempo/client/Charge.d.ts.map +1 -1
  91. package/dist/tempo/client/Charge.js +9 -2
  92. package/dist/tempo/client/Charge.js.map +1 -1
  93. package/dist/tempo/client/Methods.d.ts +36 -7
  94. package/dist/tempo/client/Methods.d.ts.map +1 -1
  95. package/dist/tempo/client/Methods.js +12 -5
  96. package/dist/tempo/client/Methods.js.map +1 -1
  97. package/dist/tempo/client/index.d.ts +7 -4
  98. package/dist/tempo/client/index.d.ts.map +1 -1
  99. package/dist/tempo/client/index.js +5 -3
  100. package/dist/tempo/client/index.js.map +1 -1
  101. package/dist/tempo/index.d.ts +1 -0
  102. package/dist/tempo/index.d.ts.map +1 -1
  103. package/dist/tempo/index.js +1 -0
  104. package/dist/tempo/index.js.map +1 -1
  105. package/dist/tempo/internal/fee-payer.d.ts +21 -1
  106. package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
  107. package/dist/tempo/internal/fee-payer.js +109 -4
  108. package/dist/tempo/internal/fee-payer.js.map +1 -1
  109. package/dist/tempo/{client → legacy/client}/ChannelOps.d.ts +19 -6
  110. package/dist/tempo/legacy/client/ChannelOps.d.ts.map +1 -0
  111. package/dist/tempo/{client → legacy/client}/ChannelOps.js +9 -3
  112. package/dist/tempo/legacy/client/ChannelOps.js.map +1 -0
  113. package/dist/tempo/{client → legacy/client}/Session.d.ts +23 -4
  114. package/dist/tempo/legacy/client/Session.d.ts.map +1 -0
  115. package/dist/tempo/{client → legacy/client}/Session.js +14 -7
  116. package/dist/tempo/legacy/client/Session.js.map +1 -0
  117. package/dist/tempo/{client → legacy/client}/SessionManager.d.ts +20 -5
  118. package/dist/tempo/legacy/client/SessionManager.d.ts.map +1 -0
  119. package/dist/tempo/{client → legacy/client}/SessionManager.js +20 -16
  120. package/dist/tempo/legacy/client/SessionManager.js.map +1 -0
  121. package/dist/tempo/legacy/client/index.d.ts +7 -0
  122. package/dist/tempo/legacy/client/index.d.ts.map +1 -0
  123. package/dist/tempo/legacy/client/index.js +5 -0
  124. package/dist/tempo/legacy/client/index.js.map +1 -0
  125. package/dist/tempo/legacy/index.d.ts +7 -0
  126. package/dist/tempo/legacy/index.d.ts.map +1 -0
  127. package/dist/tempo/legacy/index.js +7 -0
  128. package/dist/tempo/legacy/index.js.map +1 -0
  129. package/dist/tempo/{server → legacy/server}/Session.d.ts +28 -11
  130. package/dist/tempo/legacy/server/Session.d.ts.map +1 -0
  131. package/dist/tempo/{server → legacy/server}/Session.js +12 -10
  132. package/dist/tempo/legacy/server/Session.js.map +1 -0
  133. package/dist/tempo/legacy/server/index.d.ts +5 -0
  134. package/dist/tempo/legacy/server/index.d.ts.map +1 -0
  135. package/dist/tempo/legacy/server/index.js +5 -0
  136. package/dist/tempo/legacy/server/index.js.map +1 -0
  137. package/dist/tempo/{session → legacy/session}/Chain.d.ts +30 -23
  138. package/dist/tempo/legacy/session/Chain.d.ts.map +1 -0
  139. package/dist/tempo/{session → legacy/session}/Chain.js +12 -11
  140. package/dist/tempo/legacy/session/Chain.js.map +1 -0
  141. package/dist/tempo/{session → legacy/session}/Channel.d.ts +1 -0
  142. package/dist/tempo/legacy/session/Channel.d.ts.map +1 -0
  143. package/dist/tempo/legacy/session/Channel.js.map +1 -0
  144. package/dist/tempo/legacy/session/ChannelStore.d.ts +22 -0
  145. package/dist/tempo/legacy/session/ChannelStore.d.ts.map +1 -0
  146. package/dist/tempo/legacy/session/ChannelStore.js +6 -0
  147. package/dist/tempo/legacy/session/ChannelStore.js.map +1 -0
  148. package/dist/tempo/legacy/session/Types.d.ts +73 -0
  149. package/dist/tempo/legacy/session/Types.d.ts.map +1 -0
  150. package/dist/tempo/legacy/session/Types.js.map +1 -0
  151. package/dist/tempo/{session → legacy/session}/Voucher.d.ts +4 -4
  152. package/dist/tempo/legacy/session/Voucher.d.ts.map +1 -0
  153. package/dist/tempo/{session → legacy/session}/Voucher.js +1 -1
  154. package/dist/tempo/legacy/session/Voucher.js.map +1 -0
  155. package/dist/tempo/{session → legacy/session}/escrow.abi.d.ts +1 -0
  156. package/dist/tempo/{session → legacy/session}/escrow.abi.d.ts.map +1 -1
  157. package/dist/tempo/{session → legacy/session}/escrow.abi.js +1 -0
  158. package/dist/tempo/legacy/session/escrow.abi.js.map +1 -0
  159. package/dist/tempo/legacy/session/index.d.ts +9 -0
  160. package/dist/tempo/legacy/session/index.d.ts.map +1 -0
  161. package/dist/tempo/legacy/session/index.js +9 -0
  162. package/dist/tempo/legacy/session/index.js.map +1 -0
  163. package/dist/tempo/server/Charge.d.ts +1 -1
  164. package/dist/tempo/server/Charge.d.ts.map +1 -1
  165. package/dist/tempo/server/Charge.js +13 -16
  166. package/dist/tempo/server/Charge.js.map +1 -1
  167. package/dist/tempo/server/Methods.d.ts +63 -6
  168. package/dist/tempo/server/Methods.d.ts.map +1 -1
  169. package/dist/tempo/server/Methods.js +36 -8
  170. package/dist/tempo/server/Methods.js.map +1 -1
  171. package/dist/tempo/server/Subscription.d.ts +1 -1
  172. package/dist/tempo/server/Subscription.d.ts.map +1 -1
  173. package/dist/tempo/server/index.d.ts +6 -5
  174. package/dist/tempo/server/index.d.ts.map +1 -1
  175. package/dist/tempo/server/index.js +5 -5
  176. package/dist/tempo/server/index.js.map +1 -1
  177. package/dist/tempo/server/internal/html.gen.d.ts +1 -1
  178. package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
  179. package/dist/tempo/server/internal/html.gen.js +1 -1
  180. package/dist/tempo/server/internal/html.gen.js.map +1 -1
  181. package/dist/tempo/server/internal/request-body.d.ts +7 -2
  182. package/dist/tempo/server/internal/request-body.d.ts.map +1 -1
  183. package/dist/tempo/server/internal/request-body.js +20 -3
  184. package/dist/tempo/server/internal/request-body.js.map +1 -1
  185. package/dist/tempo/server/internal/transport.d.ts +8 -4
  186. package/dist/tempo/server/internal/transport.d.ts.map +1 -1
  187. package/dist/tempo/server/internal/transport.js +8 -7
  188. package/dist/tempo/server/internal/transport.js.map +1 -1
  189. package/dist/tempo/session/Snapshot.d.ts +32 -0
  190. package/dist/tempo/session/Snapshot.d.ts.map +1 -0
  191. package/dist/tempo/session/Snapshot.js +37 -0
  192. package/dist/tempo/session/Snapshot.js.map +1 -0
  193. package/dist/tempo/session/client/ChannelOps.d.ts +82 -0
  194. package/dist/tempo/session/client/ChannelOps.d.ts.map +1 -0
  195. package/dist/tempo/session/client/ChannelOps.js +204 -0
  196. package/dist/tempo/session/client/ChannelOps.js.map +1 -0
  197. package/dist/tempo/session/client/CredentialState.d.ts +262 -0
  198. package/dist/tempo/session/client/CredentialState.d.ts.map +1 -0
  199. package/dist/tempo/session/client/CredentialState.js +417 -0
  200. package/dist/tempo/session/client/CredentialState.js.map +1 -0
  201. package/dist/tempo/session/client/ReceiptCoordinator.d.ts +26 -0
  202. package/dist/tempo/session/client/ReceiptCoordinator.d.ts.map +1 -0
  203. package/dist/tempo/session/client/ReceiptCoordinator.js +61 -0
  204. package/dist/tempo/session/client/ReceiptCoordinator.js.map +1 -0
  205. package/dist/tempo/session/client/Runtime.d.ts +464 -0
  206. package/dist/tempo/session/client/Runtime.d.ts.map +1 -0
  207. package/dist/tempo/session/client/Runtime.js +499 -0
  208. package/dist/tempo/session/client/Runtime.js.map +1 -0
  209. package/dist/tempo/session/client/Session.d.ts +132 -0
  210. package/dist/tempo/session/client/Session.d.ts.map +1 -0
  211. package/dist/tempo/session/client/Session.js +55 -0
  212. package/dist/tempo/session/client/Session.js.map +1 -0
  213. package/dist/tempo/session/client/SessionManager.d.ts +120 -0
  214. package/dist/tempo/session/client/SessionManager.d.ts.map +1 -0
  215. package/dist/tempo/session/client/SessionManager.js +627 -0
  216. package/dist/tempo/session/client/SessionManager.js.map +1 -0
  217. package/dist/tempo/session/client/Transports.d.ts +449 -0
  218. package/dist/tempo/session/client/Transports.d.ts.map +1 -0
  219. package/dist/tempo/session/client/Transports.js +721 -0
  220. package/dist/tempo/session/client/Transports.js.map +1 -0
  221. package/dist/tempo/session/client/index.d.ts +12 -0
  222. package/dist/tempo/session/client/index.d.ts.map +1 -0
  223. package/dist/tempo/session/client/index.js +5 -0
  224. package/dist/tempo/session/client/index.js.map +1 -0
  225. package/dist/tempo/session/index.d.ts +7 -8
  226. package/dist/tempo/session/index.d.ts.map +1 -1
  227. package/dist/tempo/session/index.js +7 -8
  228. package/dist/tempo/session/index.js.map +1 -1
  229. package/dist/tempo/session/precompile/Chain.d.ts +319 -0
  230. package/dist/tempo/session/precompile/Chain.d.ts.map +1 -0
  231. package/dist/tempo/session/precompile/Chain.js +492 -0
  232. package/dist/tempo/session/precompile/Chain.js.map +1 -0
  233. package/dist/tempo/session/precompile/Channel.d.ts +46 -0
  234. package/dist/tempo/session/precompile/Channel.d.ts.map +1 -0
  235. package/dist/tempo/session/precompile/Channel.js +56 -0
  236. package/dist/tempo/session/precompile/Channel.js.map +1 -0
  237. package/dist/tempo/session/precompile/Protocol.d.ts +308 -0
  238. package/dist/tempo/session/precompile/Protocol.d.ts.map +1 -0
  239. package/dist/tempo/session/precompile/Protocol.js +264 -0
  240. package/dist/tempo/session/precompile/Protocol.js.map +1 -0
  241. package/dist/tempo/session/precompile/Voucher.d.ts +40 -0
  242. package/dist/tempo/session/precompile/Voucher.d.ts.map +1 -0
  243. package/dist/tempo/session/precompile/Voucher.js +126 -0
  244. package/dist/tempo/session/precompile/Voucher.js.map +1 -0
  245. package/dist/tempo/session/precompile/escrow.abi.d.ts +522 -0
  246. package/dist/tempo/session/precompile/escrow.abi.d.ts.map +1 -0
  247. package/dist/tempo/session/precompile/escrow.abi.js +224 -0
  248. package/dist/tempo/session/precompile/escrow.abi.js.map +1 -0
  249. package/dist/tempo/session/precompile/index.d.ts +24 -0
  250. package/dist/tempo/session/precompile/index.d.ts.map +1 -0
  251. package/dist/tempo/session/precompile/index.js +22 -0
  252. package/dist/tempo/session/precompile/index.js.map +1 -0
  253. package/dist/tempo/session/server/ChannelOps.d.ts +56 -0
  254. package/dist/tempo/session/server/ChannelOps.d.ts.map +1 -0
  255. package/dist/tempo/session/server/ChannelOps.js +91 -0
  256. package/dist/tempo/session/server/ChannelOps.js.map +1 -0
  257. package/dist/tempo/session/server/ChannelStore.d.ts +347 -0
  258. package/dist/tempo/session/server/ChannelStore.d.ts.map +1 -0
  259. package/dist/tempo/session/server/ChannelStore.js +404 -0
  260. package/dist/tempo/session/server/ChannelStore.js.map +1 -0
  261. package/dist/tempo/session/server/CredentialVerification.d.ts +85 -0
  262. package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -0
  263. package/dist/tempo/session/server/CredentialVerification.js +494 -0
  264. package/dist/tempo/session/server/CredentialVerification.js.map +1 -0
  265. package/dist/tempo/session/server/MeteredStream.d.ts +40 -0
  266. package/dist/tempo/session/server/MeteredStream.d.ts.map +1 -0
  267. package/dist/tempo/session/server/MeteredStream.js +42 -0
  268. package/dist/tempo/session/server/MeteredStream.js.map +1 -0
  269. package/dist/tempo/session/server/RequestState.d.ts +208 -0
  270. package/dist/tempo/session/server/RequestState.d.ts.map +1 -0
  271. package/dist/tempo/session/server/RequestState.js +252 -0
  272. package/dist/tempo/session/server/RequestState.js.map +1 -0
  273. package/dist/tempo/session/server/Session.d.ts +169 -0
  274. package/dist/tempo/session/server/Session.d.ts.map +1 -0
  275. package/dist/tempo/session/server/Session.js +351 -0
  276. package/dist/tempo/session/server/Session.js.map +1 -0
  277. package/dist/tempo/session/server/Settlement.d.ts +185 -0
  278. package/dist/tempo/session/server/Settlement.d.ts.map +1 -0
  279. package/dist/tempo/session/server/Settlement.js +250 -0
  280. package/dist/tempo/session/server/Settlement.js.map +1 -0
  281. package/dist/tempo/session/{Sse.d.ts → server/Sse.d.ts} +9 -56
  282. package/dist/tempo/session/server/Sse.d.ts.map +1 -0
  283. package/dist/tempo/session/server/Sse.js +184 -0
  284. package/dist/tempo/session/server/Sse.js.map +1 -0
  285. package/dist/tempo/session/server/Transports.d.ts +89 -0
  286. package/dist/tempo/session/server/Transports.d.ts.map +1 -0
  287. package/dist/tempo/session/server/Transports.js +149 -0
  288. package/dist/tempo/session/server/Transports.js.map +1 -0
  289. package/dist/tempo/session/server/Ws.d.ts +48 -0
  290. package/dist/tempo/session/server/Ws.d.ts.map +1 -0
  291. package/dist/tempo/session/server/Ws.js +244 -0
  292. package/dist/tempo/session/server/Ws.js.map +1 -0
  293. package/dist/tempo/session/server/index.d.ts +4 -0
  294. package/dist/tempo/session/server/index.d.ts.map +1 -0
  295. package/dist/tempo/session/server/index.js +2 -0
  296. package/dist/tempo/session/server/index.js.map +1 -0
  297. package/package.json +6 -1
  298. package/src/Challenge.ts +9 -7
  299. package/src/Constants.ts +58 -0
  300. package/src/Credential.ts +5 -4
  301. package/src/Method.ts +46 -5
  302. package/src/Receipt.ts +3 -2
  303. package/src/cli/cli.test.ts +23 -28
  304. package/src/cli/cli.ts +23 -10
  305. package/src/cli/mcp.test.ts +21 -7
  306. package/src/cli/plugins/tempo.ts +21 -8
  307. package/src/cli/utils.test.ts +25 -1
  308. package/src/cli/utils.ts +10 -0
  309. package/src/client/Methods.ts +5 -2
  310. package/src/client/Mppx.test-d.ts +10 -0
  311. package/src/client/Mppx.test.ts +75 -0
  312. package/src/client/Transport.ts +4 -5
  313. package/src/client/index.ts +11 -1
  314. package/src/client/internal/Fetch.test.ts +29 -4
  315. package/src/client/internal/Fetch.ts +17 -5
  316. package/src/env.d.ts +1 -1
  317. package/src/index.ts +1 -0
  318. package/src/internal/AcceptPayment.test.ts +61 -0
  319. package/src/internal/AcceptPayment.ts +21 -14
  320. package/src/mcp-sdk/client/McpClient.integration.test.ts +8 -7
  321. package/src/mcp-sdk/client/McpClient.test-d.ts +7 -0
  322. package/src/mcp-sdk/client/McpClient.ts +99 -67
  323. package/src/mcp-sdk/client/McpClient.unit.test.ts +131 -0
  324. package/src/middlewares/elysia.test.ts +8 -4
  325. package/src/middlewares/express.test.ts +8 -4
  326. package/src/middlewares/hono.test.ts +4 -4
  327. package/src/middlewares/nextjs.test.ts +8 -4
  328. package/src/proxy/Proxy.test.ts +8 -8
  329. package/src/server/Mppx.test-d.ts +54 -0
  330. package/src/server/Mppx.test.ts +200 -7
  331. package/src/server/Mppx.ts +487 -406
  332. package/src/server/Response.ts +2 -1
  333. package/src/server/Transport.ts +4 -3
  334. package/src/server/index.ts +1 -0
  335. package/src/stripe/client/Charge.test.ts +20 -5
  336. package/src/stripe/client/Charge.ts +6 -2
  337. package/src/stripe/server/Charge.test.ts +114 -1
  338. package/src/stripe/server/Charge.ts +13 -2
  339. package/src/stripe/server/internal/html.gen.ts +1 -1
  340. package/src/tempo/AccessKeyAuthorization.test.ts +4 -94
  341. package/src/tempo/Methods.test.ts +45 -17
  342. package/src/tempo/Methods.ts +22 -0
  343. package/src/tempo/PublicExports.test-d.ts +105 -0
  344. package/src/tempo/client/Charge.test.ts +85 -0
  345. package/src/tempo/client/Charge.ts +19 -2
  346. package/src/tempo/client/Methods.ts +18 -6
  347. package/src/tempo/client/index.ts +15 -4
  348. package/src/tempo/index.ts +1 -0
  349. package/src/tempo/internal/fee-payer.test.ts +241 -17
  350. package/src/tempo/internal/fee-payer.ts +150 -4
  351. package/src/tempo/internal/fee-token.test.ts +14 -9
  352. package/src/tempo/legacy/AccessKeyAuthorization.test.ts +162 -0
  353. package/src/tempo/legacy/README.md +9 -0
  354. package/src/tempo/{client → legacy/client}/ChannelOps.test.ts +6 -7
  355. package/src/tempo/{client → legacy/client}/ChannelOps.ts +22 -9
  356. package/src/tempo/{client → legacy/client}/Session.test.ts +51 -9
  357. package/src/tempo/{client → legacy/client}/Session.ts +25 -11
  358. package/src/tempo/{client → legacy/client}/SessionManager.test.ts +81 -9
  359. package/src/tempo/{client → legacy/client}/SessionManager.ts +41 -20
  360. package/src/tempo/legacy/client/index.ts +6 -0
  361. package/src/tempo/legacy/index.ts +6 -0
  362. package/src/tempo/{server → legacy/server}/Session.test.ts +45 -45
  363. package/src/tempo/{server → legacy/server}/Session.ts +32 -23
  364. package/src/tempo/legacy/server/index.ts +4 -0
  365. package/src/tempo/{session → legacy/session}/Chain.test.ts +3 -4
  366. package/src/tempo/{session → legacy/session}/Chain.ts +94 -63
  367. package/src/tempo/{session → legacy/session}/Channel.ts +1 -0
  368. package/src/tempo/legacy/session/ChannelStore.test.ts +58 -0
  369. package/src/tempo/legacy/session/ChannelStore.ts +39 -0
  370. package/src/tempo/legacy/session/Types.ts +91 -0
  371. package/src/tempo/{session → legacy/session}/Voucher.ts +12 -8
  372. package/src/tempo/{session → legacy/session}/escrow.abi.ts +1 -0
  373. package/src/tempo/legacy/session/index.ts +8 -0
  374. package/src/tempo/server/AtomicStore.test-d.ts +16 -11
  375. package/src/tempo/server/Charge.test.ts +92 -14
  376. package/src/tempo/server/Charge.ts +18 -16
  377. package/src/tempo/server/Methods.ts +54 -8
  378. package/src/tempo/server/Sse.test.ts +2 -2
  379. package/src/tempo/server/index.ts +6 -5
  380. package/src/tempo/server/internal/html.gen.ts +1 -1
  381. package/src/tempo/server/internal/request-body.test.ts +37 -4
  382. package/src/tempo/server/internal/request-body.ts +25 -6
  383. package/src/tempo/server/internal/transport.test.ts +4 -4
  384. package/src/tempo/server/internal/transport.ts +19 -10
  385. package/src/tempo/session/Snapshot.test.ts +41 -0
  386. package/src/tempo/session/Snapshot.ts +74 -0
  387. package/src/tempo/session/client/ChannelOps.test.ts +163 -0
  388. package/src/tempo/session/client/ChannelOps.ts +344 -0
  389. package/src/tempo/session/client/CredentialState.test.ts +645 -0
  390. package/src/tempo/session/client/CredentialState.ts +814 -0
  391. package/src/tempo/session/client/ReceiptCoordinator.ts +95 -0
  392. package/src/tempo/session/client/Runtime.test.ts +1092 -0
  393. package/src/tempo/session/client/Runtime.ts +986 -0
  394. package/src/tempo/session/client/Session.test.ts +734 -0
  395. package/src/tempo/session/client/Session.ts +97 -0
  396. package/src/tempo/session/client/SessionManager.test.ts +1308 -0
  397. package/src/tempo/session/client/SessionManager.ts +845 -0
  398. package/src/tempo/session/client/Transports.test.ts +837 -0
  399. package/src/tempo/session/client/Transports.ts +1292 -0
  400. package/src/tempo/session/client/index.ts +37 -0
  401. package/src/tempo/session/index.ts +7 -8
  402. package/src/tempo/session/precompile/Chain.integration.test.ts +321 -0
  403. package/src/tempo/session/precompile/Chain.test.ts +1258 -0
  404. package/src/tempo/session/precompile/Chain.ts +979 -0
  405. package/src/tempo/session/precompile/Channel.test.ts +138 -0
  406. package/src/tempo/session/precompile/Channel.ts +103 -0
  407. package/src/tempo/session/precompile/Protocol.test.ts +358 -0
  408. package/src/tempo/session/precompile/Protocol.ts +520 -0
  409. package/src/tempo/session/precompile/Voucher.test.ts +316 -0
  410. package/src/tempo/session/precompile/Voucher.ts +160 -0
  411. package/src/tempo/session/precompile/escrow.abi.ts +226 -0
  412. package/src/tempo/session/precompile/index.ts +33 -0
  413. package/src/tempo/session/server/ChannelOps.test.ts +129 -0
  414. package/src/tempo/session/server/ChannelOps.ts +157 -0
  415. package/src/tempo/session/{ChannelStore.test.ts → server/ChannelStore.test.ts} +536 -29
  416. package/src/tempo/session/server/ChannelStore.ts +835 -0
  417. package/src/tempo/session/server/CredentialVerification.test.ts +146 -0
  418. package/src/tempo/session/server/CredentialVerification.ts +710 -0
  419. package/src/tempo/session/server/MeteredStream.ts +88 -0
  420. package/src/tempo/session/server/RequestState.test.ts +531 -0
  421. package/src/tempo/session/server/RequestState.ts +499 -0
  422. package/src/tempo/session/server/Session.integration.test.ts +444 -0
  423. package/src/tempo/session/server/Session.test.ts +3253 -0
  424. package/src/tempo/session/server/Session.ts +543 -0
  425. package/src/tempo/session/server/Settlement.test.ts +242 -0
  426. package/src/tempo/session/server/Settlement.ts +470 -0
  427. package/src/tempo/session/{Sse.test.ts → server/Sse.test.ts} +37 -3
  428. package/src/tempo/session/server/Sse.ts +256 -0
  429. package/src/tempo/session/server/Transports.test.ts +346 -0
  430. package/src/tempo/session/server/Transports.ts +255 -0
  431. package/src/tempo/session/{Ws.test.ts → server/Ws.test.ts} +4 -4
  432. package/src/tempo/session/server/Ws.ts +384 -0
  433. package/src/tempo/session/server/index.ts +8 -0
  434. package/dist/tempo/client/ChannelOps.d.ts.map +0 -1
  435. package/dist/tempo/client/ChannelOps.js.map +0 -1
  436. package/dist/tempo/client/Session.d.ts.map +0 -1
  437. package/dist/tempo/client/Session.js.map +0 -1
  438. package/dist/tempo/client/SessionManager.d.ts.map +0 -1
  439. package/dist/tempo/client/SessionManager.js.map +0 -1
  440. package/dist/tempo/server/Session.d.ts.map +0 -1
  441. package/dist/tempo/server/Session.js.map +0 -1
  442. package/dist/tempo/session/Chain.d.ts.map +0 -1
  443. package/dist/tempo/session/Chain.js.map +0 -1
  444. package/dist/tempo/session/Channel.d.ts.map +0 -1
  445. package/dist/tempo/session/Channel.js.map +0 -1
  446. package/dist/tempo/session/ChannelStore.d.ts +0 -117
  447. package/dist/tempo/session/ChannelStore.d.ts.map +0 -1
  448. package/dist/tempo/session/ChannelStore.js +0 -172
  449. package/dist/tempo/session/ChannelStore.js.map +0 -1
  450. package/dist/tempo/session/Receipt.d.ts +0 -22
  451. package/dist/tempo/session/Receipt.d.ts.map +0 -1
  452. package/dist/tempo/session/Receipt.js +0 -34
  453. package/dist/tempo/session/Receipt.js.map +0 -1
  454. package/dist/tempo/session/Sse.d.ts.map +0 -1
  455. package/dist/tempo/session/Sse.js +0 -363
  456. package/dist/tempo/session/Sse.js.map +0 -1
  457. package/dist/tempo/session/Types.d.ts +0 -78
  458. package/dist/tempo/session/Types.d.ts.map +0 -1
  459. package/dist/tempo/session/Types.js.map +0 -1
  460. package/dist/tempo/session/Voucher.d.ts.map +0 -1
  461. package/dist/tempo/session/Voucher.js.map +0 -1
  462. package/dist/tempo/session/Ws.d.ts +0 -87
  463. package/dist/tempo/session/Ws.d.ts.map +0 -1
  464. package/dist/tempo/session/Ws.js +0 -443
  465. package/dist/tempo/session/Ws.js.map +0 -1
  466. package/dist/tempo/session/escrow.abi.js.map +0 -1
  467. package/src/tempo/session/ChannelStore.ts +0 -308
  468. package/src/tempo/session/Receipt.test.ts +0 -89
  469. package/src/tempo/session/Receipt.ts +0 -46
  470. package/src/tempo/session/Sse.ts +0 -462
  471. package/src/tempo/session/Types.ts +0 -86
  472. package/src/tempo/session/Ws.ts +0 -576
  473. /package/dist/tempo/{session → legacy/session}/Channel.js +0 -0
  474. /package/dist/tempo/{session → legacy/session}/Types.js +0 -0
  475. /package/src/tempo/{session → legacy/session}/Channel.test.ts +0 -0
  476. /package/src/tempo/{session → legacy/session}/Voucher.test.ts +0 -0
  477. /package/src/tempo/session/{Sse.fuzz.test.ts → server/Sse.fuzz.test.ts} +0 -0
@@ -0,0 +1,138 @@
1
+ import { AbiParameters, Hash } from 'ox'
2
+ import { describe, expect, test } from 'vp/test'
3
+
4
+ import * as Channel from './Channel.js'
5
+ import { tip20ChannelEscrow } from './Protocol.js'
6
+
7
+ const descriptor = {
8
+ payer: '0x1111111111111111111111111111111111111111',
9
+ payee: '0x2222222222222222222222222222222222222222',
10
+ operator: '0x3333333333333333333333333333333333333333',
11
+ token: '0x4444444444444444444444444444444444444444',
12
+ salt: '0x0000000000000000000000000000000000000000000000000000000000000001',
13
+ authorizedSigner: '0x5555555555555555555555555555555555555555',
14
+ expiringNonceHash: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
15
+ } as const satisfies Channel.ChannelDescriptor
16
+
17
+ const chainId = 42431
18
+ const transaction = {
19
+ chainId,
20
+ calls: [],
21
+ feePayerSignature: {
22
+ r: `0x${'01'.repeat(32)}`,
23
+ s: `0x${'02'.repeat(32)}`,
24
+ yParity: 0,
25
+ },
26
+ nonce: 1,
27
+ } as const satisfies Channel.ExpiringNonceTransaction
28
+
29
+ describe('precompile Channel.computeId', () => {
30
+ test('returns deterministic 32-byte hash for fixed inputs', () => {
31
+ const id = Channel.computeId({ ...descriptor, chainId })
32
+ expect(Channel.computeId({ ...descriptor, chainId })).toBe(id)
33
+ expect(id).toMatch(/^0x[0-9a-f]{64}$/)
34
+ })
35
+
36
+ test('matches manual keccak256(abi.encode(...))', () => {
37
+ const encoded = AbiParameters.encode(
38
+ AbiParameters.from([
39
+ 'address payer',
40
+ 'address payee',
41
+ 'address operator',
42
+ 'address token',
43
+ 'bytes32 salt',
44
+ 'address authorizedSigner',
45
+ 'bytes32 expiringNonceHash',
46
+ 'address escrow',
47
+ 'uint256 chainId',
48
+ ]),
49
+ [
50
+ descriptor.payer,
51
+ descriptor.payee,
52
+ descriptor.operator,
53
+ descriptor.token,
54
+ descriptor.salt,
55
+ descriptor.authorizedSigner,
56
+ descriptor.expiringNonceHash,
57
+ tip20ChannelEscrow,
58
+ BigInt(chainId),
59
+ ],
60
+ )
61
+ expect(Channel.computeId({ ...descriptor, chainId })).toBe(Hash.keccak256(encoded))
62
+ })
63
+
64
+ test.each([
65
+ ['payer', '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'],
66
+ ['payee', '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'],
67
+ ['operator', '0xcccccccccccccccccccccccccccccccccccccccc'],
68
+ ['token', '0xdddddddddddddddddddddddddddddddddddddddd'],
69
+ ['salt', '0x0000000000000000000000000000000000000000000000000000000000000002'],
70
+ ['authorizedSigner', '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'],
71
+ ['expiringNonceHash', '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'],
72
+ ] as const)('changes when %s changes', (key, value) => {
73
+ expect(Channel.computeId({ ...descriptor, [key]: value, chainId })).not.toBe(
74
+ Channel.computeId({ ...descriptor, chainId }),
75
+ )
76
+ })
77
+
78
+ test('changes when escrow or chainId changes', () => {
79
+ expect(
80
+ Channel.computeId({
81
+ ...descriptor,
82
+ chainId,
83
+ escrow: '0xffffffffffffffffffffffffffffffffffffffff',
84
+ }),
85
+ ).not.toBe(Channel.computeId({ ...descriptor, chainId }))
86
+ expect(Channel.computeId({ ...descriptor, chainId: 1 })).not.toBe(
87
+ Channel.computeId({ ...descriptor, chainId }),
88
+ )
89
+ })
90
+
91
+ test('encodes chainId as uint256', () => {
92
+ const largeChainId = 2 ** 32
93
+ const id = Channel.computeId({ ...descriptor, chainId: largeChainId })
94
+ const encoded = AbiParameters.encode(
95
+ AbiParameters.from([
96
+ 'address payer',
97
+ 'address payee',
98
+ 'address operator',
99
+ 'address token',
100
+ 'bytes32 salt',
101
+ 'address authorizedSigner',
102
+ 'bytes32 expiringNonceHash',
103
+ 'address escrow',
104
+ 'uint256 chainId',
105
+ ]),
106
+ [
107
+ descriptor.payer,
108
+ descriptor.payee,
109
+ descriptor.operator,
110
+ descriptor.token,
111
+ descriptor.salt,
112
+ descriptor.authorizedSigner,
113
+ descriptor.expiringNonceHash,
114
+ tip20ChannelEscrow,
115
+ BigInt(largeChainId),
116
+ ],
117
+ )
118
+ expect(id).toBe(Hash.keccak256(encoded))
119
+ })
120
+ })
121
+
122
+ describe('precompile Channel.transactionForExpiringNonceHash', () => {
123
+ test('returns transaction unchanged when no fee payer is used', () => {
124
+ expect(Channel.transactionForExpiringNonceHash({ transaction })).toBe(transaction)
125
+ })
126
+
127
+ test('strips fee-payer signature from the hash preimage transaction', () => {
128
+ expect(
129
+ Channel.transactionForExpiringNonceHash({
130
+ feePayer: true,
131
+ transaction,
132
+ }),
133
+ ).toEqual({
134
+ ...transaction,
135
+ feePayerSignature: null,
136
+ })
137
+ })
138
+ })
@@ -0,0 +1,103 @@
1
+ import { AbiParameters, Hash, Hex as OxHex } from 'ox'
2
+ import { TxEnvelopeTempo } from 'ox/tempo'
3
+ import type { Account, Address, Hex } from 'viem'
4
+ import type { z_TransactionRequestTempo, z_TransactionSerializableTempo } from 'viem/tempo'
5
+
6
+ import { tip20ChannelEscrow } from './Protocol.js'
7
+ import type { ChannelDescriptor } from './Protocol.js'
8
+
9
+ /** Re-export of the TIP-1034 channel descriptor shape. */
10
+ export type { ChannelDescriptor } from './Protocol.js'
11
+
12
+ /** Tempo transaction shape used to derive the TIP-1034 `expiringNonceHash`. */
13
+ export type ExpiringNonceTransaction = (
14
+ | z_TransactionSerializableTempo
15
+ | z_TransactionRequestTempo
16
+ ) & {
17
+ /** Fee-payer metadata may be present on fee-sponsored open transactions. */
18
+ feePayer?: Account | true | undefined
19
+ }
20
+
21
+ /** Computes the TIP-1034 channel ID for a precompile channel descriptor. */
22
+ export function computeId(parameters: computeId.Parameters): Hex {
23
+ const encoded = AbiParameters.encode(
24
+ AbiParameters.from([
25
+ 'address payer',
26
+ 'address payee',
27
+ 'address operator',
28
+ 'address token',
29
+ 'bytes32 salt',
30
+ 'address authorizedSigner',
31
+ 'bytes32 expiringNonceHash',
32
+ 'address escrow',
33
+ 'uint256 chainId',
34
+ ]),
35
+ [
36
+ parameters.payer,
37
+ parameters.payee,
38
+ parameters.operator,
39
+ parameters.token,
40
+ parameters.salt,
41
+ parameters.authorizedSigner,
42
+ parameters.expiringNonceHash,
43
+ parameters.escrow ?? tip20ChannelEscrow,
44
+ BigInt(parameters.chainId),
45
+ ],
46
+ )
47
+ return Hash.keccak256(encoded)
48
+ }
49
+
50
+ /** Type helpers for `computeId()`. */
51
+ export declare namespace computeId {
52
+ /** Parameters that uniquely identify a TIP-1034 precompile channel. */
53
+ type Parameters = ChannelDescriptor & {
54
+ /** Chain ID included in the channel ID preimage. */
55
+ chainId: number
56
+ /** Escrow contract/precompile address. Defaults to the canonical TIP-1034 address. */
57
+ escrow?: Address | undefined
58
+ }
59
+ }
60
+
61
+ function encodeTempoTransactionForSigning(transaction: ExpiringNonceTransaction) {
62
+ // ox exposes the exact Tempo signing encoder we need, but its public type
63
+ // does not include viem's request-time fee-payer fields. Keep the bridge at
64
+ // the encoder boundary so channel ID derivation stays explicit.
65
+ return TxEnvelopeTempo.encodeForSigning(transaction as never)
66
+ }
67
+
68
+ /** Input for deriving the transaction body used by TIP-1034 channel identity hashing. */
69
+ export type ExpiringNonceHashTransactionParameters = {
70
+ /** Deserialized Tempo transaction that opened the channel. */
71
+ transaction: ExpiringNonceTransaction
72
+ /** Whether the transaction will receive a fee-payer co-signature after payer signing. */
73
+ feePayer?: Account | true | undefined
74
+ }
75
+
76
+ /**
77
+ * Returns the sender-signed transaction body used for TIP-1034 `expiringNonceHash`.
78
+ *
79
+ * Fee-payer co-signing happens after payer signing and must not affect the channel ID preimage.
80
+ */
81
+ export function transactionForExpiringNonceHash(
82
+ parameters: ExpiringNonceHashTransactionParameters,
83
+ ): ExpiringNonceTransaction {
84
+ const { feePayer, transaction } = parameters
85
+ if (!feePayer) return transaction
86
+ return { ...transaction, feePayerSignature: null } as ExpiringNonceTransaction
87
+ }
88
+
89
+ /**
90
+ * Computes the TIP-1034 `expiringNonceHash` for a channel-opening Tempo transaction.
91
+ *
92
+ * This delegates to viem's Tempo sender-scoped hash helper, which matches the node's
93
+ * `keccak256(encodeForSigning || sender)` consensus preimage. mppx intentionally does
94
+ * not duplicate Tempo transaction encoding logic here.
95
+ */
96
+ export function computeExpiringNonceHash(
97
+ transaction: ExpiringNonceTransaction,
98
+ parameters: { sender: Address },
99
+ ): Hex {
100
+ return Hash.keccak256(
101
+ OxHex.concat(encodeTempoTransactionForSigning(transaction), parameters.sender),
102
+ ) as Hex
103
+ }
@@ -0,0 +1,358 @@
1
+ import { Base64 } from 'ox'
2
+ import type { Hex } from 'viem'
3
+ import { describe, expect, test } from 'vp/test'
4
+
5
+ import {
6
+ createSessionReceipt,
7
+ deserializeSessionReceipt,
8
+ extractData,
9
+ formatApplicationMessage,
10
+ formatAuthorizationMessage,
11
+ formatCloseReadyMessage,
12
+ formatCloseRequestMessage,
13
+ formatErrorMessage,
14
+ formatMessageEvent,
15
+ formatNeedVoucherEvent,
16
+ formatNeedVoucherMessage,
17
+ formatReceiptEvent,
18
+ formatReceiptMessage,
19
+ isNeedVoucherEvent,
20
+ isSessionCredentialAction,
21
+ isSessionCredentialContext,
22
+ isSessionReceipt,
23
+ parseEvent,
24
+ parseMessage,
25
+ readSessionChallengeAmount,
26
+ requireSessionCredentialContext,
27
+ serializeSessionReceipt,
28
+ type NeedVoucherEvent,
29
+ type SessionReceipt,
30
+ } from './Protocol.js'
31
+ import * as Types from './Protocol.js'
32
+
33
+ const maxUint96 = (1n << 96n) - 1n
34
+
35
+ describe('precompile Uint96', () => {
36
+ test('accepts lower and upper bounds', () => {
37
+ expect(Types.uint96(0n)).toBe(0n)
38
+ expect(Types.uint96(maxUint96)).toBe(maxUint96)
39
+ expect(Types.isUint96(0n)).toBe(true)
40
+ expect(Types.isUint96(maxUint96)).toBe(true)
41
+ })
42
+
43
+ test('rejects values outside uint96 bounds', () => {
44
+ expect(() => Types.uint96(-1n)).toThrow('outside uint96 bounds')
45
+ expect(() => Types.uint96(maxUint96 + 1n)).toThrow('outside uint96 bounds')
46
+ expect(Types.isUint96(-1n)).toBe(false)
47
+ expect(Types.isUint96(maxUint96 + 1n)).toBe(false)
48
+ })
49
+
50
+ test('assertUint96 validates valid values and throws for invalid values', () => {
51
+ const amount: bigint = 1n
52
+ Types.assertUint96(amount)
53
+ expect(amount).toBe(1n)
54
+ expect(() => Types.assertUint96(maxUint96 + 1n)).toThrow('outside uint96 bounds')
55
+ })
56
+ })
57
+
58
+ const credentialContextChannelId = `0x${'11'.repeat(32)}` as const
59
+
60
+ describe('session credential context guards', () => {
61
+ test('accepts transport context with a channel ID and known action', () => {
62
+ expect(isSessionCredentialContext({ channelId: credentialContextChannelId })).toBe(true)
63
+ expect(
64
+ isSessionCredentialContext({ action: 'voucher', channelId: credentialContextChannelId }),
65
+ ).toBe(true)
66
+ })
67
+
68
+ test('rejects missing channel IDs and unknown actions', () => {
69
+ expect(isSessionCredentialContext({ action: 'voucher' })).toBe(false)
70
+ expect(
71
+ isSessionCredentialContext({ action: 'refund', channelId: credentialContextChannelId }),
72
+ ).toBe(false)
73
+ expect(isSessionCredentialContext(null)).toBe(false)
74
+ })
75
+
76
+ test('narrows supported action names', () => {
77
+ expect(isSessionCredentialAction('open')).toBe(true)
78
+ expect(isSessionCredentialAction('topUp')).toBe(true)
79
+ expect(isSessionCredentialAction('voucher')).toBe(true)
80
+ expect(isSessionCredentialAction('close')).toBe(true)
81
+ expect(isSessionCredentialAction('refund')).toBe(false)
82
+ })
83
+
84
+ test('requires context with custom error message', () => {
85
+ expect(requireSessionCredentialContext({ channelId: credentialContextChannelId })).toEqual({
86
+ channelId: credentialContextChannelId,
87
+ })
88
+ expect(() => requireSessionCredentialContext({}, 'missing context')).toThrow('missing context')
89
+ })
90
+
91
+ test('reads raw session challenge amount', () => {
92
+ expect(
93
+ readSessionChallengeAmount({
94
+ id: 'challenge-1',
95
+ realm: 'test',
96
+ method: 'tempo',
97
+ intent: 'session',
98
+ request: { amount: '25' },
99
+ }),
100
+ ).toBe(25n)
101
+ })
102
+
103
+ test('rejects missing session challenge amount', () => {
104
+ expect(() =>
105
+ readSessionChallengeAmount({
106
+ id: 'challenge-1',
107
+ realm: 'test',
108
+ method: 'tempo',
109
+ intent: 'session',
110
+ request: {},
111
+ }),
112
+ ).toThrow('Session challenge is missing amount.')
113
+ })
114
+ })
115
+
116
+ describe('session transport payload guards', () => {
117
+ test('accepts complete need-voucher events', () => {
118
+ expect(
119
+ isNeedVoucherEvent({
120
+ channelId: credentialContextChannelId,
121
+ requiredCumulative: '200',
122
+ acceptedCumulative: '100',
123
+ deposit: '1000',
124
+ }),
125
+ ).toBe(true)
126
+ })
127
+
128
+ test('rejects incomplete need-voucher events', () => {
129
+ expect(
130
+ isNeedVoucherEvent({ channelId: credentialContextChannelId, requiredCumulative: '200' }),
131
+ ).toBe(false)
132
+ })
133
+
134
+ test('accepts complete session receipts', () => {
135
+ expect(
136
+ isSessionReceipt({
137
+ method: 'tempo',
138
+ intent: 'session',
139
+ status: 'success',
140
+ timestamp: '2026-01-01T00:00:00.000Z',
141
+ reference: credentialContextChannelId,
142
+ challengeId: 'challenge-1',
143
+ channelId: credentialContextChannelId,
144
+ acceptedCumulative: '100',
145
+ spent: '50',
146
+ units: 1,
147
+ }),
148
+ ).toBe(true)
149
+ })
150
+
151
+ test('rejects incomplete session receipts', () => {
152
+ expect(
153
+ isSessionReceipt({
154
+ challengeId: 'challenge-1',
155
+ channelId: credentialContextChannelId,
156
+ }),
157
+ ).toBe(false)
158
+ })
159
+ })
160
+
161
+ const receiptChannelId = '0x0000000000000000000000000000000000000000000000000000000000000001' as Hex
162
+
163
+ describe('Receipt', () => {
164
+ test('createSessionReceipt', () => {
165
+ const receipt = createSessionReceipt({
166
+ challengeId: 'test-challenge-id',
167
+ channelId: receiptChannelId,
168
+ acceptedCumulative: 5000000n,
169
+ spent: 3000000n,
170
+ units: 42,
171
+ })
172
+
173
+ expect(receipt.method).toBe('tempo')
174
+ expect(receipt.intent).toBe('session')
175
+ expect(receipt.status).toBe('success')
176
+ expect(receipt.reference).toBe(receiptChannelId)
177
+ expect(receipt.challengeId).toBe('test-challenge-id')
178
+ expect(receipt.channelId).toBe(receiptChannelId)
179
+ expect(receipt.acceptedCumulative).toBe('5000000')
180
+ expect(receipt.spent).toBe('3000000')
181
+ expect(receipt.units).toBe(42)
182
+ expect(receipt.timestamp).toBeTruthy()
183
+ expect(receipt.txHash).toBeUndefined()
184
+ })
185
+
186
+ test('createSessionReceipt with txHash', () => {
187
+ const txHash = '0xabcdef' as Hex
188
+ const receipt = createSessionReceipt({
189
+ challengeId: 'test-challenge-id',
190
+ channelId: receiptChannelId,
191
+ acceptedCumulative: 5000000n,
192
+ spent: 3000000n,
193
+ txHash,
194
+ })
195
+
196
+ expect(receipt.txHash).toBe(txHash)
197
+ expect(receipt.units).toBeUndefined()
198
+ })
199
+
200
+ test('createSessionReceipt omits optional fields when undefined', () => {
201
+ const receipt = createSessionReceipt({
202
+ challengeId: 'test-challenge-id',
203
+ channelId: receiptChannelId,
204
+ acceptedCumulative: 1000n,
205
+ spent: 0n,
206
+ })
207
+
208
+ expect('units' in receipt).toBe(false)
209
+ expect('txHash' in receipt).toBe(false)
210
+ })
211
+
212
+ test('serialize and deserialize round-trip', () => {
213
+ const receipt = createSessionReceipt({
214
+ challengeId: 'test-challenge-id',
215
+ channelId: receiptChannelId,
216
+ acceptedCumulative: 5000000n,
217
+ spent: 3000000n,
218
+ units: 42,
219
+ })
220
+
221
+ const encoded = serializeSessionReceipt(receipt)
222
+ expect(typeof encoded).toBe('string')
223
+
224
+ const decoded = deserializeSessionReceipt(encoded)
225
+ expect(decoded).toEqual(receipt)
226
+ })
227
+
228
+ test('serialize produces base64url without padding', () => {
229
+ const receipt = createSessionReceipt({
230
+ challengeId: 'test-challenge-id',
231
+ channelId: receiptChannelId,
232
+ acceptedCumulative: 1n,
233
+ spent: 0n,
234
+ })
235
+
236
+ const encoded = serializeSessionReceipt(receipt)
237
+ // base64url uses - and _ instead of + and /, no = padding
238
+ expect(encoded).not.toMatch(/[+/=]/)
239
+ })
240
+
241
+ test('deserialize rejects incomplete receipts', () => {
242
+ const malformed = Base64.fromString(JSON.stringify({ channelId: receiptChannelId }), {
243
+ pad: false,
244
+ url: true,
245
+ })
246
+
247
+ expect(() => deserializeSessionReceipt(malformed)).toThrow('Invalid session receipt.')
248
+ })
249
+ })
250
+
251
+ const sseChannelId = '0x0000000000000000000000000000000000000000000000000000000000000001' as Hex
252
+
253
+ const sseReceipt: SessionReceipt = {
254
+ method: 'tempo',
255
+ intent: 'session',
256
+ status: 'success',
257
+ timestamp: '2026-01-01T00:00:00.000Z',
258
+ reference: sseChannelId,
259
+ challengeId: 'challenge-1',
260
+ channelId: sseChannelId,
261
+ acceptedCumulative: '100',
262
+ spent: '50',
263
+ units: 2,
264
+ }
265
+
266
+ const sseNeedVoucher: NeedVoucherEvent = {
267
+ channelId: sseChannelId,
268
+ requiredCumulative: '200',
269
+ acceptedCumulative: '100',
270
+ deposit: '1000',
271
+ }
272
+
273
+ describe('SseProtocol', () => {
274
+ test('round-trips built-in payment events', () => {
275
+ expect(parseEvent(formatReceiptEvent(sseReceipt))).toEqual({
276
+ type: 'payment-receipt',
277
+ data: sseReceipt,
278
+ })
279
+ expect(parseEvent(formatNeedVoucherEvent(sseNeedVoucher))).toEqual({
280
+ type: 'payment-need-voucher',
281
+ data: sseNeedVoucher,
282
+ })
283
+ })
284
+
285
+ test('formats multiline application messages as one event', () => {
286
+ const formatted = formatMessageEvent('first\n\nthird')
287
+
288
+ expect(formatted).toBe('event: message\ndata: first\ndata: \ndata: third\n\n')
289
+ expect(parseEvent(formatted)).toEqual({ type: 'message', data: 'first\n\nthird' })
290
+ })
291
+
292
+ test('treats unknown event types as application messages', () => {
293
+ expect(parseEvent('event: custom\ndata: payload\n\n')).toEqual({
294
+ type: 'message',
295
+ data: 'payload',
296
+ })
297
+ })
298
+
299
+ test('extractData returns joined data lines or null', () => {
300
+ expect(extractData('event: message\ndata: a\ndata: b\n')).toBe('a\nb')
301
+ expect(extractData(': comment only')).toBeNull()
302
+ })
303
+
304
+ test('rejects malformed payment events', () => {
305
+ expect(parseEvent('event: payment-receipt\ndata: {"channelId":"0x01"}\n\n')).toBeNull()
306
+ expect(parseEvent('event: payment-need-voucher\ndata: not json\n\n')).toBeNull()
307
+ })
308
+ })
309
+
310
+ const wsReceipt: SessionReceipt = {
311
+ method: 'tempo',
312
+ intent: 'session',
313
+ status: 'success',
314
+ timestamp: '2026-01-01T00:00:00.000Z',
315
+ reference: '0x01',
316
+ challengeId: 'challenge-1',
317
+ channelId: '0x02',
318
+ acceptedCumulative: '100',
319
+ spent: '50',
320
+ units: 1,
321
+ }
322
+
323
+ const wsNeedVoucher: NeedVoucherEvent = {
324
+ channelId: '0x01',
325
+ requiredCumulative: '200',
326
+ acceptedCumulative: '100',
327
+ deposit: '1000',
328
+ }
329
+
330
+ describe('WsProtocol', () => {
331
+ test.each([
332
+ ['authorization', formatAuthorizationMessage('credential'), { mpp: 'authorization' }],
333
+ ['message', formatApplicationMessage('payload'), { mpp: 'message', data: 'payload' }],
334
+ ['close request', formatCloseRequestMessage(), { mpp: 'payment-close-request' }],
335
+ [
336
+ 'close ready',
337
+ formatCloseReadyMessage(wsReceipt),
338
+ { mpp: 'payment-close-ready', data: wsReceipt },
339
+ ],
340
+ ['error', formatErrorMessage({ status: 402, message: 'pay' }), { mpp: 'payment-error' }],
341
+ [
342
+ 'need voucher',
343
+ formatNeedVoucherMessage(wsNeedVoucher),
344
+ { mpp: 'payment-need-voucher', data: wsNeedVoucher },
345
+ ],
346
+ ['receipt', formatReceiptMessage(wsReceipt), { mpp: 'payment-receipt', data: wsReceipt }],
347
+ ])('round-trips %s frames', (_name, raw, expected) => {
348
+ expect(parseMessage(raw)).toMatchObject(expected)
349
+ })
350
+
351
+ test('rejects malformed or application-only frames', () => {
352
+ expect(parseMessage('not json')).toBeNull()
353
+ expect(parseMessage('{"hello":"world"}')).toBeNull()
354
+ expect(parseMessage('{"mpp":"payment-receipt","data":true}')).toBeNull()
355
+ expect(parseMessage('{"mpp":"payment-receipt","data":{"channelId":"0x01"}}')).toBeNull()
356
+ expect(parseMessage('{"mpp":"payment-need-voucher","data":{"channelId":"0x01"}}')).toBeNull()
357
+ })
358
+ })