mppx 0.0.1 → 0.1.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 (446) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +195 -0
  3. package/dist/BodyDigest.d.ts +42 -0
  4. package/dist/BodyDigest.d.ts.map +1 -0
  5. package/dist/BodyDigest.js +40 -0
  6. package/dist/BodyDigest.js.map +1 -0
  7. package/dist/Challenge.d.ts +271 -0
  8. package/dist/Challenge.d.ts.map +1 -0
  9. package/dist/Challenge.js +291 -0
  10. package/dist/Challenge.js.map +1 -0
  11. package/dist/Credential.d.ts +91 -0
  12. package/dist/Credential.d.ts.map +1 -0
  13. package/dist/Credential.js +122 -0
  14. package/dist/Credential.js.map +1 -0
  15. package/dist/Errors.d.ts +243 -0
  16. package/dist/Errors.d.ts.map +1 -0
  17. package/dist/Errors.js +201 -0
  18. package/dist/Errors.js.map +1 -0
  19. package/dist/Expires.d.ts +15 -0
  20. package/dist/Expires.d.ts.map +1 -0
  21. package/dist/Expires.js +29 -0
  22. package/dist/Expires.js.map +1 -0
  23. package/dist/Intent.d.ts +101 -0
  24. package/dist/Intent.d.ts.map +1 -0
  25. package/dist/Intent.js +83 -0
  26. package/dist/Intent.js.map +1 -0
  27. package/dist/Mcp.d.ts +74 -0
  28. package/dist/Mcp.d.ts.map +1 -0
  29. package/dist/Mcp.js +9 -0
  30. package/dist/Mcp.js.map +1 -0
  31. package/dist/MethodIntent.d.ts +225 -0
  32. package/dist/MethodIntent.d.ts.map +1 -0
  33. package/dist/MethodIntent.js +156 -0
  34. package/dist/MethodIntent.js.map +1 -0
  35. package/dist/PaymentRequest.d.ts +88 -0
  36. package/dist/PaymentRequest.d.ts.map +1 -0
  37. package/dist/PaymentRequest.js +81 -0
  38. package/dist/PaymentRequest.js.map +1 -0
  39. package/dist/Receipt.d.ts +110 -0
  40. package/dist/Receipt.d.ts.map +1 -0
  41. package/dist/Receipt.js +105 -0
  42. package/dist/Receipt.js.map +1 -0
  43. package/dist/Store.d.ts +28 -0
  44. package/dist/Store.d.ts.map +1 -0
  45. package/dist/Store.js +61 -0
  46. package/dist/Store.js.map +1 -0
  47. package/dist/cli.d.ts +3 -0
  48. package/dist/cli.d.ts.map +1 -0
  49. package/dist/cli.js +1219 -0
  50. package/dist/cli.js.map +1 -0
  51. package/dist/client/Methods.d.ts +4 -0
  52. package/dist/client/Methods.d.ts.map +1 -0
  53. package/dist/client/Methods.js +4 -0
  54. package/dist/client/Methods.js.map +1 -0
  55. package/dist/client/Mppx.d.ts +84 -0
  56. package/dist/client/Mppx.d.ts.map +1 -0
  57. package/dist/client/Mppx.js +64 -0
  58. package/dist/client/Mppx.js.map +1 -0
  59. package/dist/client/Transport.d.ts +56 -0
  60. package/dist/client/Transport.d.ts.map +1 -0
  61. package/dist/client/Transport.js +81 -0
  62. package/dist/client/Transport.js.map +1 -0
  63. package/dist/client/index.d.ts +5 -0
  64. package/dist/client/index.d.ts.map +1 -0
  65. package/dist/client/index.js +5 -0
  66. package/dist/client/index.js.map +1 -0
  67. package/dist/client/internal/Fetch.d.ts +85 -0
  68. package/dist/client/internal/Fetch.d.ts.map +1 -0
  69. package/dist/client/internal/Fetch.js +95 -0
  70. package/dist/client/internal/Fetch.js.map +1 -0
  71. package/dist/index.d.ts +13 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +13 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/internal/types.d.ts +302 -0
  76. package/dist/internal/types.d.ts.map +1 -0
  77. package/dist/internal/types.js +2 -0
  78. package/dist/internal/types.js.map +1 -0
  79. package/dist/mcp-sdk/client/McpClient.d.ts +78 -0
  80. package/dist/mcp-sdk/client/McpClient.d.ts.map +1 -0
  81. package/dist/mcp-sdk/client/McpClient.js +98 -0
  82. package/dist/mcp-sdk/client/McpClient.js.map +1 -0
  83. package/dist/mcp-sdk/client/index.d.ts +3 -0
  84. package/dist/mcp-sdk/client/index.d.ts.map +1 -0
  85. package/dist/mcp-sdk/client/index.js +3 -0
  86. package/dist/mcp-sdk/client/index.js.map +1 -0
  87. package/dist/mcp-sdk/server/Transport.d.ts +43 -0
  88. package/dist/mcp-sdk/server/Transport.d.ts.map +1 -0
  89. package/dist/mcp-sdk/server/Transport.js +71 -0
  90. package/dist/mcp-sdk/server/Transport.js.map +1 -0
  91. package/dist/mcp-sdk/server/index.d.ts +2 -0
  92. package/dist/mcp-sdk/server/index.d.ts.map +1 -0
  93. package/dist/mcp-sdk/server/index.js +2 -0
  94. package/dist/mcp-sdk/server/index.js.map +1 -0
  95. package/dist/middlewares/elysia.d.ts +51 -0
  96. package/dist/middlewares/elysia.d.ts.map +1 -0
  97. package/dist/middlewares/elysia.js +59 -0
  98. package/dist/middlewares/elysia.js.map +1 -0
  99. package/dist/middlewares/express.d.ts +46 -0
  100. package/dist/middlewares/express.d.ts.map +1 -0
  101. package/dist/middlewares/express.js +69 -0
  102. package/dist/middlewares/express.js.map +1 -0
  103. package/dist/middlewares/hono.d.ts +46 -0
  104. package/dist/middlewares/hono.d.ts.map +1 -0
  105. package/dist/middlewares/hono.js +57 -0
  106. package/dist/middlewares/hono.js.map +1 -0
  107. package/dist/middlewares/internal/mppx.d.ts +16 -0
  108. package/dist/middlewares/internal/mppx.d.ts.map +1 -0
  109. package/dist/middlewares/internal/mppx.js +16 -0
  110. package/dist/middlewares/internal/mppx.js.map +1 -0
  111. package/dist/middlewares/nextjs.d.ts +45 -0
  112. package/dist/middlewares/nextjs.d.ts.map +1 -0
  113. package/dist/middlewares/nextjs.js +57 -0
  114. package/dist/middlewares/nextjs.js.map +1 -0
  115. package/dist/proxy/Proxy.d.ts +47 -0
  116. package/dist/proxy/Proxy.d.ts.map +1 -0
  117. package/dist/proxy/Proxy.js +126 -0
  118. package/dist/proxy/Proxy.js.map +1 -0
  119. package/dist/proxy/Service.d.ts +100 -0
  120. package/dist/proxy/Service.d.ts.map +1 -0
  121. package/dist/proxy/Service.js +147 -0
  122. package/dist/proxy/Service.js.map +1 -0
  123. package/dist/proxy/index.d.ts +7 -0
  124. package/dist/proxy/index.d.ts.map +1 -0
  125. package/dist/proxy/index.js +7 -0
  126. package/dist/proxy/index.js.map +1 -0
  127. package/dist/proxy/internal/Headers.d.ts +3 -0
  128. package/dist/proxy/internal/Headers.d.ts.map +1 -0
  129. package/dist/proxy/internal/Headers.js +41 -0
  130. package/dist/proxy/internal/Headers.js.map +1 -0
  131. package/dist/proxy/internal/Route.d.ts +14 -0
  132. package/dist/proxy/internal/Route.d.ts.map +1 -0
  133. package/dist/proxy/internal/Route.js +47 -0
  134. package/dist/proxy/internal/Route.js.map +1 -0
  135. package/dist/proxy/services/anthropic.d.ts +29 -0
  136. package/dist/proxy/services/anthropic.d.ts.map +1 -0
  137. package/dist/proxy/services/anthropic.js +30 -0
  138. package/dist/proxy/services/anthropic.js.map +1 -0
  139. package/dist/proxy/services/openai.d.ts +29 -0
  140. package/dist/proxy/services/openai.d.ts.map +1 -0
  141. package/dist/proxy/services/openai.js +30 -0
  142. package/dist/proxy/services/openai.js.map +1 -0
  143. package/dist/proxy/services/stripe.d.ts +29 -0
  144. package/dist/proxy/services/stripe.d.ts.map +1 -0
  145. package/dist/proxy/services/stripe.js +30 -0
  146. package/dist/proxy/services/stripe.js.map +1 -0
  147. package/dist/server/Methods.d.ts +3 -0
  148. package/dist/server/Methods.d.ts.map +1 -0
  149. package/dist/server/Methods.js +3 -0
  150. package/dist/server/Methods.js.map +1 -0
  151. package/dist/server/Mppx.d.ts +116 -0
  152. package/dist/server/Mppx.d.ts.map +1 -0
  153. package/dist/server/Mppx.js +207 -0
  154. package/dist/server/Mppx.js.map +1 -0
  155. package/dist/server/NodeListener.d.ts +3 -0
  156. package/dist/server/NodeListener.d.ts.map +1 -0
  157. package/dist/server/NodeListener.js +3 -0
  158. package/dist/server/NodeListener.js.map +1 -0
  159. package/dist/server/Request.d.ts +24 -0
  160. package/dist/server/Request.d.ts.map +1 -0
  161. package/dist/server/Request.js +26 -0
  162. package/dist/server/Request.js.map +1 -0
  163. package/dist/server/Response.d.ts +10 -0
  164. package/dist/server/Response.d.ts.map +1 -0
  165. package/dist/server/Response.js +15 -0
  166. package/dist/server/Response.js.map +1 -0
  167. package/dist/server/Transport.d.ts +93 -0
  168. package/dist/server/Transport.d.ts.map +1 -0
  169. package/dist/server/Transport.js +132 -0
  170. package/dist/server/Transport.js.map +1 -0
  171. package/dist/server/index.d.ts +9 -0
  172. package/dist/server/index.d.ts.map +1 -0
  173. package/dist/server/index.js +9 -0
  174. package/dist/server/index.js.map +1 -0
  175. package/dist/stripe/Intents.d.ts +54 -0
  176. package/dist/stripe/Intents.d.ts.map +1 -0
  177. package/dist/stripe/Intents.js +27 -0
  178. package/dist/stripe/Intents.js.map +1 -0
  179. package/dist/stripe/client/Charge.d.ts +114 -0
  180. package/dist/stripe/client/Charge.d.ts.map +1 -0
  181. package/dist/stripe/client/Charge.js +77 -0
  182. package/dist/stripe/client/Charge.js.map +1 -0
  183. package/dist/stripe/client/MethodIntents.d.ts +80 -0
  184. package/dist/stripe/client/MethodIntents.d.ts.map +1 -0
  185. package/dist/stripe/client/MethodIntents.js +34 -0
  186. package/dist/stripe/client/MethodIntents.js.map +1 -0
  187. package/dist/stripe/client/index.d.ts +3 -0
  188. package/dist/stripe/client/index.d.ts.map +1 -0
  189. package/dist/stripe/client/index.js +3 -0
  190. package/dist/stripe/client/index.js.map +1 -0
  191. package/dist/stripe/index.d.ts +2 -0
  192. package/dist/stripe/index.d.ts.map +1 -0
  193. package/dist/stripe/index.js +2 -0
  194. package/dist/stripe/index.js.map +1 -0
  195. package/dist/stripe/server/Charge.d.ts +74 -0
  196. package/dist/stripe/server/Charge.d.ts.map +1 -0
  197. package/dist/stripe/server/Charge.js +79 -0
  198. package/dist/stripe/server/Charge.js.map +1 -0
  199. package/dist/stripe/server/MethodIntents.d.ts +65 -0
  200. package/dist/stripe/server/MethodIntents.d.ts.map +1 -0
  201. package/dist/stripe/server/MethodIntents.js +21 -0
  202. package/dist/stripe/server/MethodIntents.js.map +1 -0
  203. package/dist/stripe/server/index.d.ts +3 -0
  204. package/dist/stripe/server/index.d.ts.map +1 -0
  205. package/dist/stripe/server/index.js +3 -0
  206. package/dist/stripe/server/index.js.map +1 -0
  207. package/dist/tempo/Attribution.d.ts +101 -0
  208. package/dist/tempo/Attribution.d.ts.map +1 -0
  209. package/dist/tempo/Attribution.js +124 -0
  210. package/dist/tempo/Attribution.js.map +1 -0
  211. package/dist/tempo/Intents.d.ts +132 -0
  212. package/dist/tempo/Intents.d.ts.map +1 -0
  213. package/dist/tempo/Intents.js +81 -0
  214. package/dist/tempo/Intents.js.map +1 -0
  215. package/dist/tempo/client/ChannelOps.d.ts +54 -0
  216. package/dist/tempo/client/ChannelOps.d.ts.map +1 -0
  217. package/dist/tempo/client/ChannelOps.js +138 -0
  218. package/dist/tempo/client/ChannelOps.js.map +1 -0
  219. package/dist/tempo/client/Charge.d.ts +76 -0
  220. package/dist/tempo/client/Charge.d.ts.map +1 -0
  221. package/dist/tempo/client/Charge.js +69 -0
  222. package/dist/tempo/client/Charge.js.map +1 -0
  223. package/dist/tempo/client/MethodIntents.d.ts +157 -0
  224. package/dist/tempo/client/MethodIntents.d.ts.map +1 -0
  225. package/dist/tempo/client/MethodIntents.js +25 -0
  226. package/dist/tempo/client/MethodIntents.js.map +1 -0
  227. package/dist/tempo/client/Session.d.ts +159 -0
  228. package/dist/tempo/client/Session.d.ts.map +1 -0
  229. package/dist/tempo/client/Session.js +263 -0
  230. package/dist/tempo/client/Session.js.map +1 -0
  231. package/dist/tempo/client/SessionManager.d.ts +62 -0
  232. package/dist/tempo/client/SessionManager.d.ts.map +1 -0
  233. package/dist/tempo/client/SessionManager.js +196 -0
  234. package/dist/tempo/client/SessionManager.js.map +1 -0
  235. package/dist/tempo/client/index.d.ts +6 -0
  236. package/dist/tempo/client/index.d.ts.map +1 -0
  237. package/dist/tempo/client/index.js +5 -0
  238. package/dist/tempo/client/index.js.map +1 -0
  239. package/dist/tempo/index.d.ts +3 -0
  240. package/dist/tempo/index.d.ts.map +1 -0
  241. package/dist/tempo/index.js +3 -0
  242. package/dist/tempo/index.js.map +1 -0
  243. package/dist/tempo/internal/account.d.ts +32 -0
  244. package/dist/tempo/internal/account.d.ts.map +1 -0
  245. package/dist/tempo/internal/account.js +33 -0
  246. package/dist/tempo/internal/account.js.map +1 -0
  247. package/dist/tempo/internal/defaults.d.ts +18 -0
  248. package/dist/tempo/internal/defaults.d.ts.map +1 -0
  249. package/dist/tempo/internal/defaults.js +18 -0
  250. package/dist/tempo/internal/defaults.js.map +1 -0
  251. package/dist/tempo/internal/types.d.ts +11 -0
  252. package/dist/tempo/internal/types.d.ts.map +1 -0
  253. package/dist/tempo/internal/types.js +2 -0
  254. package/dist/tempo/internal/types.js.map +1 -0
  255. package/dist/tempo/server/Charge.d.ts +77 -0
  256. package/dist/tempo/server/Charge.d.ts.map +1 -0
  257. package/dist/tempo/server/Charge.js +228 -0
  258. package/dist/tempo/server/Charge.js.map +1 -0
  259. package/dist/tempo/server/MethodIntents.d.ts +140 -0
  260. package/dist/tempo/server/MethodIntents.d.ts.map +1 -0
  261. package/dist/tempo/server/MethodIntents.js +26 -0
  262. package/dist/tempo/server/MethodIntents.js.map +1 -0
  263. package/dist/tempo/server/Session.d.ts +148 -0
  264. package/dist/tempo/server/Session.d.ts.map +1 -0
  265. package/dist/tempo/server/Session.js +529 -0
  266. package/dist/tempo/server/Session.js.map +1 -0
  267. package/dist/tempo/server/internal/transport.d.ts +47 -0
  268. package/dist/tempo/server/internal/transport.d.ts.map +1 -0
  269. package/dist/tempo/server/internal/transport.js +118 -0
  270. package/dist/tempo/server/internal/transport.js.map +1 -0
  271. package/dist/tempo/stream/Chain.d.ts +52 -0
  272. package/dist/tempo/stream/Chain.d.ts.map +1 -0
  273. package/dist/tempo/stream/Chain.js +215 -0
  274. package/dist/tempo/stream/Chain.js.map +1 -0
  275. package/dist/tempo/stream/Channel.d.ts +26 -0
  276. package/dist/tempo/stream/Channel.d.ts.map +1 -0
  277. package/dist/tempo/stream/Channel.js +27 -0
  278. package/dist/tempo/stream/Channel.js.map +1 -0
  279. package/dist/tempo/stream/ChannelStore.d.ts +103 -0
  280. package/dist/tempo/stream/ChannelStore.d.ts.map +1 -0
  281. package/dist/tempo/stream/ChannelStore.js +100 -0
  282. package/dist/tempo/stream/ChannelStore.js.map +1 -0
  283. package/dist/tempo/stream/Receipt.d.ts +22 -0
  284. package/dist/tempo/stream/Receipt.d.ts.map +1 -0
  285. package/dist/tempo/stream/Receipt.js +34 -0
  286. package/dist/tempo/stream/Receipt.js.map +1 -0
  287. package/dist/tempo/stream/Sse.d.ts +134 -0
  288. package/dist/tempo/stream/Sse.d.ts.map +1 -0
  289. package/dist/tempo/stream/Sse.js +288 -0
  290. package/dist/tempo/stream/Sse.js.map +1 -0
  291. package/dist/tempo/stream/Types.d.ts +78 -0
  292. package/dist/tempo/stream/Types.d.ts.map +1 -0
  293. package/dist/tempo/stream/Types.js +2 -0
  294. package/dist/tempo/stream/Types.js.map +1 -0
  295. package/dist/tempo/stream/Voucher.d.ts +20 -0
  296. package/dist/tempo/stream/Voucher.d.ts.map +1 -0
  297. package/dist/tempo/stream/Voucher.js +98 -0
  298. package/dist/tempo/stream/Voucher.js.map +1 -0
  299. package/dist/tempo/stream/escrow.abi.d.ts +598 -0
  300. package/dist/tempo/stream/escrow.abi.d.ts.map +1 -0
  301. package/dist/tempo/stream/escrow.abi.js +760 -0
  302. package/dist/tempo/stream/escrow.abi.js.map +1 -0
  303. package/dist/tempo/stream/index.d.ts +8 -0
  304. package/dist/tempo/stream/index.d.ts.map +1 -0
  305. package/dist/tempo/stream/index.js +8 -0
  306. package/dist/tempo/stream/index.js.map +1 -0
  307. package/dist/viem/Account.d.ts +12 -0
  308. package/dist/viem/Account.d.ts.map +1 -0
  309. package/dist/viem/Account.js +14 -0
  310. package/dist/viem/Account.js.map +1 -0
  311. package/dist/viem/Client.d.ts +21 -0
  312. package/dist/viem/Client.d.ts.map +1 -0
  313. package/dist/viem/Client.js +19 -0
  314. package/dist/viem/Client.js.map +1 -0
  315. package/dist/zod.d.ts +17 -0
  316. package/dist/zod.d.ts.map +1 -0
  317. package/dist/zod.js +35 -0
  318. package/dist/zod.js.map +1 -0
  319. package/package.json +117 -4
  320. package/src/BodyDigest.test.ts +43 -0
  321. package/src/BodyDigest.ts +53 -0
  322. package/src/Challenge.test-d.ts +81 -0
  323. package/src/Challenge.test.ts +414 -0
  324. package/src/Challenge.ts +429 -0
  325. package/src/Credential.test.ts +227 -0
  326. package/src/Credential.ts +154 -0
  327. package/src/Errors.test.ts +402 -0
  328. package/src/Errors.ts +348 -0
  329. package/src/Expires.ts +34 -0
  330. package/src/Intent.test.ts +180 -0
  331. package/src/Intent.ts +109 -0
  332. package/src/Mcp.ts +81 -0
  333. package/src/MethodIntent.test.ts +303 -0
  334. package/src/MethodIntent.ts +388 -0
  335. package/src/PaymentRequest.test.ts +152 -0
  336. package/src/PaymentRequest.ts +107 -0
  337. package/src/Receipt.test.ts +98 -0
  338. package/src/Receipt.ts +129 -0
  339. package/src/Store.ts +84 -0
  340. package/src/cli.test.ts +542 -0
  341. package/src/cli.ts +1319 -0
  342. package/src/client/Methods.ts +3 -0
  343. package/src/client/Mppx.test-d.ts +90 -0
  344. package/src/client/Mppx.test.ts +468 -0
  345. package/src/client/Mppx.ts +149 -0
  346. package/src/client/Transport.test.ts +283 -0
  347. package/src/client/Transport.ts +115 -0
  348. package/src/client/index.ts +4 -0
  349. package/src/client/internal/Fetch.test-d.ts +57 -0
  350. package/src/client/internal/Fetch.test.ts +281 -0
  351. package/src/client/internal/Fetch.ts +157 -0
  352. package/src/env.d.ts +11 -0
  353. package/src/index.ts +12 -0
  354. package/src/internal/types.ts +403 -0
  355. package/src/mcp-sdk/client/McpClient.test-d.ts +109 -0
  356. package/src/mcp-sdk/client/McpClient.test.ts +219 -0
  357. package/src/mcp-sdk/client/McpClient.ts +187 -0
  358. package/src/mcp-sdk/client/index.ts +2 -0
  359. package/src/mcp-sdk/server/Transport.ts +94 -0
  360. package/src/mcp-sdk/server/index.ts +1 -0
  361. package/src/middlewares/elysia.ts +66 -0
  362. package/src/middlewares/express.test.ts +155 -0
  363. package/src/middlewares/express.ts +82 -0
  364. package/src/middlewares/hono.test.ts +148 -0
  365. package/src/middlewares/hono.ts +62 -0
  366. package/src/middlewares/internal/mppx.ts +30 -0
  367. package/src/middlewares/nextjs.test.ts +164 -0
  368. package/src/middlewares/nextjs.ts +66 -0
  369. package/src/proxy/Proxy.test.ts +472 -0
  370. package/src/proxy/Proxy.ts +175 -0
  371. package/src/proxy/Service.test.ts +125 -0
  372. package/src/proxy/Service.ts +227 -0
  373. package/src/proxy/index.ts +6 -0
  374. package/src/proxy/internal/Headers.test.ts +100 -0
  375. package/src/proxy/internal/Headers.ts +40 -0
  376. package/src/proxy/internal/Route.test.ts +143 -0
  377. package/src/proxy/internal/Route.ts +54 -0
  378. package/src/proxy/services/anthropic.ts +45 -0
  379. package/src/proxy/services/openai.test.ts +97 -0
  380. package/src/proxy/services/openai.ts +48 -0
  381. package/src/proxy/services/stripe.ts +49 -0
  382. package/src/server/Methods.ts +2 -0
  383. package/src/server/Mppx.test-d.ts +343 -0
  384. package/src/server/Mppx.test.ts +342 -0
  385. package/src/server/Mppx.ts +378 -0
  386. package/src/server/NodeListener.test.ts +188 -0
  387. package/src/server/NodeListener.ts +3 -0
  388. package/src/server/Request.test.ts +102 -0
  389. package/src/server/Request.ts +33 -0
  390. package/src/server/Response.test.ts +31 -0
  391. package/src/server/Response.ts +27 -0
  392. package/src/server/Transport.test.ts +294 -0
  393. package/src/server/Transport.ts +222 -0
  394. package/src/server/index.ts +8 -0
  395. package/src/stripe/Charge.integration.test.ts +326 -0
  396. package/src/stripe/Intents.test.ts +52 -0
  397. package/src/stripe/Intents.ts +27 -0
  398. package/src/stripe/client/Charge.ts +119 -0
  399. package/src/stripe/client/MethodIntents.ts +37 -0
  400. package/src/stripe/client/index.ts +2 -0
  401. package/src/stripe/index.ts +1 -0
  402. package/src/stripe/server/Charge.ts +121 -0
  403. package/src/stripe/server/MethodIntents.ts +24 -0
  404. package/src/stripe/server/index.ts +2 -0
  405. package/src/tempo/Attribution.test.ts +187 -0
  406. package/src/tempo/Attribution.ts +156 -0
  407. package/src/tempo/Intents.test.ts +84 -0
  408. package/src/tempo/Intents.ts +93 -0
  409. package/src/tempo/client/ChannelOps.ts +233 -0
  410. package/src/tempo/client/Charge.ts +84 -0
  411. package/src/tempo/client/MethodIntents.ts +28 -0
  412. package/src/tempo/client/Session.ts +369 -0
  413. package/src/tempo/client/SessionManager.test.ts +223 -0
  414. package/src/tempo/client/SessionManager.ts +270 -0
  415. package/src/tempo/client/index.ts +5 -0
  416. package/src/tempo/index.ts +2 -0
  417. package/src/tempo/internal/account.ts +47 -0
  418. package/src/tempo/internal/defaults.ts +20 -0
  419. package/src/tempo/internal/types.ts +8 -0
  420. package/src/tempo/server/Charge.test.ts +847 -0
  421. package/src/tempo/server/Charge.ts +309 -0
  422. package/src/tempo/server/MethodIntents.ts +29 -0
  423. package/src/tempo/server/Session.test.ts +1349 -0
  424. package/src/tempo/server/Session.ts +773 -0
  425. package/src/tempo/server/Sse.test.ts +289 -0
  426. package/src/tempo/server/index.ts +5 -0
  427. package/src/tempo/server/internal/transport.ts +153 -0
  428. package/src/tempo/stream/Chain.ts +333 -0
  429. package/src/tempo/stream/Channel.ts +50 -0
  430. package/src/tempo/stream/ChannelStore.test.ts +473 -0
  431. package/src/tempo/stream/ChannelStore.ts +202 -0
  432. package/src/tempo/stream/Receipt.test.ts +84 -0
  433. package/src/tempo/stream/Receipt.ts +45 -0
  434. package/src/tempo/stream/Sse.test.ts +401 -0
  435. package/src/tempo/stream/Sse.ts +375 -0
  436. package/src/tempo/stream/Types.ts +86 -0
  437. package/src/tempo/stream/Voucher.test.ts +134 -0
  438. package/src/tempo/stream/Voucher.ts +123 -0
  439. package/src/tempo/stream/escrow.abi.ts +759 -0
  440. package/src/tempo/stream/index.ts +7 -0
  441. package/src/tsconfig.json +10 -0
  442. package/src/viem/Account.test.ts +71 -0
  443. package/src/viem/Account.ts +30 -0
  444. package/src/viem/Client.test.ts +58 -0
  445. package/src/viem/Client.ts +33 -0
  446. package/src/zod.ts +47 -0
@@ -0,0 +1,369 @@
1
+ import type { Hex } from 'ox'
2
+ import { type Address, parseUnits, type Account as viem_Account } from 'viem'
3
+ import { tempo as tempo_chain } from 'viem/chains'
4
+ import type * as Challenge from '../../Challenge.js'
5
+ import * as MethodIntent from '../../MethodIntent.js'
6
+ import * as Account from '../../viem/Account.js'
7
+ import * as Client from '../../viem/Client.js'
8
+ import * as z from '../../zod.js'
9
+ import * as Intents from '../Intents.js'
10
+ import * as defaults from '../internal/defaults.js'
11
+ import type { StreamCredentialPayload } from '../stream/Types.js'
12
+ import { signVoucher } from '../stream/Voucher.js'
13
+ import {
14
+ type ChannelEntry,
15
+ createOpenPayload,
16
+ createVoucherPayload,
17
+ resolveEscrow,
18
+ serializeCredential,
19
+ tryRecoverChannel,
20
+ } from './ChannelOps.js'
21
+
22
+ export const streamContextSchema = z.object({
23
+ account: z.optional(z.custom<Account.getResolver.Parameters['account']>()),
24
+ action: z.optional(z.enum(['open', 'topUp', 'voucher', 'close'])),
25
+ channelId: z.optional(z.string()),
26
+ cumulativeAmount: z.optional(z.amount()),
27
+ cumulativeAmountRaw: z.optional(z.string()),
28
+ transaction: z.optional(z.string()),
29
+ authorizedSigner: z.optional(z.string()),
30
+ additionalDeposit: z.optional(z.amount()),
31
+ additionalDepositRaw: z.optional(z.string()),
32
+ depositRaw: z.optional(z.string()),
33
+ })
34
+
35
+ export type StreamContext = z.infer<typeof streamContextSchema>
36
+
37
+ /**
38
+ * Creates a session payment MethodIntent plugin for use with `Mppx.create()`.
39
+ *
40
+ * Supports both auto mode (set `deposit` to manage channels automatically)
41
+ * and manual mode (pass `context.action` to control each step).
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * // Auto mode
46
+ * import { Mppx, tempo } from 'mppx/client'
47
+ *
48
+ * const mppx = Mppx.create({
49
+ * methods: [tempo({
50
+ * account: privateKeyToAccount('0x...'),
51
+ * deposit: '10',
52
+ * })],
53
+ * })
54
+ *
55
+ * const res = await mppx.fetch('/api/chat?prompt=hello')
56
+ * ```
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * // Manual mode
61
+ * const mppx = Mppx.create({
62
+ * methods: [tempo({ account })],
63
+ * })
64
+ *
65
+ * const credential = await mppx.createCredential(response, {
66
+ * action: 'voucher',
67
+ * channelId: '0x...',
68
+ * cumulativeAmount: '1',
69
+ * })
70
+ * ```
71
+ */
72
+ export function session(parameters: session.Parameters = {}) {
73
+ const { decimals = defaults.decimals } = parameters
74
+
75
+ const getClient = Client.getResolver({
76
+ chain: tempo_chain,
77
+ getClient: parameters.getClient,
78
+ rpcUrl: defaults.rpcUrl,
79
+ })
80
+ const getAccount = Account.getResolver({ account: parameters.account })
81
+
82
+ const maxDeposit =
83
+ parameters.maxDeposit !== undefined ? parseUnits(parameters.maxDeposit, decimals) : undefined
84
+
85
+ const escrowContractMap = new Map<string, Address>()
86
+ const channels = new Map<string, ChannelEntry>()
87
+ const channelIdToKey = new Map<string, string>()
88
+
89
+ function notifyUpdate(entry: ChannelEntry) {
90
+ parameters.onChannelUpdate?.(entry)
91
+ }
92
+
93
+ function channelKey(payee: Address, currency: Address, escrow: Address): string {
94
+ return `${payee.toLowerCase()}:${currency.toLowerCase()}:${escrow.toLowerCase()}`
95
+ }
96
+
97
+ function resolveEscrowCached(
98
+ challenge: { request: { methodDetails?: unknown } },
99
+ chainId: number,
100
+ channelId?: string,
101
+ ): Address {
102
+ if (channelId) {
103
+ const cached = escrowContractMap.get(channelId)
104
+ if (cached) return cached
105
+ }
106
+ return resolveEscrow(challenge, chainId, parameters.escrowContract)
107
+ }
108
+
109
+ async function autoManageCredential(
110
+ challenge: Challenge.Challenge,
111
+ account: viem_Account,
112
+ context?: StreamContext,
113
+ ): Promise<string> {
114
+ const md = challenge.request.methodDetails as
115
+ | { chainId?: number; escrowContract?: string; channelId?: string; feePayer?: boolean }
116
+ | undefined
117
+ const chainId = md?.chainId ?? 0
118
+ const client = await getClient({ chainId })
119
+ const escrowContract = resolveEscrowCached(challenge, chainId)
120
+ const payee = challenge.request.recipient as Address
121
+ const currency = challenge.request.currency as Address
122
+ const amount = BigInt(challenge.request.amount as string)
123
+
124
+ const suggestedDepositRaw = (challenge.request as { suggestedDeposit?: string })
125
+ .suggestedDeposit
126
+ const suggestedDeposit = suggestedDepositRaw ? BigInt(suggestedDepositRaw) : undefined
127
+
128
+ const deposit = (() => {
129
+ if (context?.depositRaw) return BigInt(context.depositRaw)
130
+ if (suggestedDeposit !== undefined && maxDeposit !== undefined)
131
+ return suggestedDeposit < maxDeposit ? suggestedDeposit : maxDeposit
132
+ if (suggestedDeposit !== undefined) return suggestedDeposit
133
+ if (maxDeposit !== undefined) return maxDeposit
134
+ if (parameters.deposit !== undefined) return parseUnits(parameters.deposit, decimals)
135
+ throw new Error(
136
+ 'No deposit amount available. Set `deposit`, `maxDeposit`, or ensure the server challenge includes `suggestedDeposit`.',
137
+ )
138
+ })()
139
+
140
+ const key = channelKey(payee, currency, escrowContract)
141
+ let entry = channels.get(key)
142
+
143
+ if (!entry) {
144
+ const suggestedChannelId = (context?.channelId ?? md?.channelId) as Hex.Hex | undefined
145
+ if (suggestedChannelId) {
146
+ const recovered = await tryRecoverChannel(
147
+ client,
148
+ escrowContract,
149
+ suggestedChannelId,
150
+ chainId,
151
+ )
152
+ if (recovered) {
153
+ const contextCumulative = context?.cumulativeAmountRaw
154
+ ? BigInt(context.cumulativeAmountRaw)
155
+ : context?.cumulativeAmount
156
+ ? parseUnits(context.cumulativeAmount, decimals)
157
+ : undefined
158
+ if (contextCumulative !== undefined) recovered.cumulativeAmount = contextCumulative
159
+ channels.set(key, recovered)
160
+ channelIdToKey.set(recovered.channelId, key)
161
+ escrowContractMap.set(recovered.channelId, escrowContract)
162
+ entry = recovered
163
+ notifyUpdate(entry)
164
+ } else if (context?.channelId) {
165
+ throw new Error(
166
+ `Channel ${context.channelId} cannot be reused (closed or not found on-chain).`,
167
+ )
168
+ }
169
+ }
170
+ }
171
+
172
+ let payload: StreamCredentialPayload
173
+
174
+ if (entry?.opened) {
175
+ entry.cumulativeAmount += amount
176
+ payload = await createVoucherPayload(
177
+ client,
178
+ account,
179
+ entry.channelId,
180
+ entry.cumulativeAmount,
181
+ escrowContract,
182
+ chainId,
183
+ parameters.authorizedSigner,
184
+ )
185
+ notifyUpdate(entry)
186
+ } else {
187
+ const result = await createOpenPayload(client, account, {
188
+ authorizedSigner: parameters.authorizedSigner,
189
+ escrowContract,
190
+ payee,
191
+ currency,
192
+ deposit,
193
+ initialAmount: amount,
194
+ chainId,
195
+ feePayer: md?.feePayer,
196
+ })
197
+ channels.set(key, result.entry)
198
+ channelIdToKey.set(result.entry.channelId, key)
199
+ escrowContractMap.set(result.entry.channelId, escrowContract)
200
+ payload = result.payload
201
+ notifyUpdate(result.entry)
202
+ }
203
+
204
+ return serializeCredential(challenge, payload, chainId, account)
205
+ }
206
+
207
+ async function manualCredential(
208
+ challenge: Challenge.Challenge,
209
+ account: viem_Account,
210
+ context: StreamContext,
211
+ ): Promise<string> {
212
+ const md = challenge.request.methodDetails as
213
+ | { chainId?: number; escrowContract?: string; channelId?: string }
214
+ | undefined
215
+ const chainId = md?.chainId ?? 0
216
+ const client = await getClient({ chainId })
217
+
218
+ const action = context.action!
219
+ const { channelId: channelIdRaw, transaction, authorizedSigner } = context
220
+ const channelId = channelIdRaw as Hex.Hex
221
+ const cumulativeAmount = context.cumulativeAmountRaw
222
+ ? BigInt(context.cumulativeAmountRaw)
223
+ : context.cumulativeAmount
224
+ ? parseUnits(context.cumulativeAmount, decimals)
225
+ : undefined
226
+ const resolvedAdditionalDeposit = context.additionalDepositRaw
227
+ ? BigInt(context.additionalDepositRaw)
228
+ : context.additionalDeposit
229
+ ? parseUnits(context.additionalDeposit, decimals)
230
+ : undefined
231
+
232
+ const escrowContract = resolveEscrowCached(challenge, chainId, channelId)
233
+ escrowContractMap.set(channelId, escrowContract)
234
+
235
+ let payload: StreamCredentialPayload
236
+
237
+ switch (action) {
238
+ case 'open': {
239
+ if (!transaction) throw new Error('transaction required for open action')
240
+ if (cumulativeAmount === undefined)
241
+ throw new Error('cumulativeAmount required for open action')
242
+ const signature = await signVoucher(
243
+ client,
244
+ account,
245
+ { channelId, cumulativeAmount },
246
+ escrowContract,
247
+ chainId,
248
+ parameters.authorizedSigner,
249
+ )
250
+ payload = {
251
+ action: 'open',
252
+ type: 'transaction',
253
+ channelId,
254
+ transaction: transaction as Hex.Hex,
255
+ authorizedSigner: (authorizedSigner as Address) ?? account.address,
256
+ cumulativeAmount: cumulativeAmount.toString(),
257
+ signature,
258
+ }
259
+ break
260
+ }
261
+
262
+ case 'topUp':
263
+ if (!transaction) throw new Error('transaction required for topUp action')
264
+ if (resolvedAdditionalDeposit === undefined)
265
+ throw new Error('additionalDeposit required for topUp action')
266
+ payload = {
267
+ action: 'topUp',
268
+ type: 'transaction',
269
+ channelId,
270
+ transaction: transaction as Hex.Hex,
271
+ additionalDeposit: resolvedAdditionalDeposit.toString(),
272
+ }
273
+ break
274
+
275
+ case 'voucher': {
276
+ if (cumulativeAmount === undefined)
277
+ throw new Error('cumulativeAmount required for voucher action')
278
+ payload = await createVoucherPayload(
279
+ client,
280
+ account,
281
+ channelId,
282
+ cumulativeAmount,
283
+ escrowContract,
284
+ chainId,
285
+ parameters.authorizedSigner,
286
+ )
287
+ const key = channelIdToKey.get(channelId)
288
+ if (key) {
289
+ const entry = channels.get(key)
290
+ if (entry) {
291
+ entry.cumulativeAmount =
292
+ entry.cumulativeAmount > cumulativeAmount ? entry.cumulativeAmount : cumulativeAmount
293
+ notifyUpdate(entry)
294
+ }
295
+ }
296
+ break
297
+ }
298
+
299
+ case 'close': {
300
+ if (cumulativeAmount === undefined)
301
+ throw new Error('cumulativeAmount required for close action')
302
+ const signature = await signVoucher(
303
+ client,
304
+ account,
305
+ { channelId, cumulativeAmount },
306
+ escrowContract,
307
+ chainId,
308
+ parameters.authorizedSigner,
309
+ )
310
+ payload = {
311
+ action: 'close',
312
+ channelId,
313
+ cumulativeAmount: cumulativeAmount.toString(),
314
+ signature,
315
+ }
316
+ const closeKey = channelIdToKey.get(channelId)
317
+ if (closeKey) {
318
+ const entry = channels.get(closeKey)
319
+ if (entry) {
320
+ entry.opened = false
321
+ entry.cumulativeAmount =
322
+ entry.cumulativeAmount > cumulativeAmount ? entry.cumulativeAmount : cumulativeAmount
323
+ notifyUpdate(entry)
324
+ }
325
+ }
326
+ break
327
+ }
328
+ }
329
+
330
+ return serializeCredential(challenge, payload, chainId, account)
331
+ }
332
+
333
+ return MethodIntent.toClient(Intents.session, {
334
+ context: streamContextSchema,
335
+
336
+ async createCredential({ challenge, context }) {
337
+ const chainId = challenge.request.methodDetails?.chainId ?? 0
338
+ const client = await getClient({ chainId })
339
+ const account = getAccount(client, context)
340
+
341
+ if (!context?.action && (parameters.deposit !== undefined || maxDeposit !== undefined))
342
+ return autoManageCredential(challenge, account, context)
343
+
344
+ if (context?.action) return manualCredential(challenge, account, context)
345
+
346
+ throw new Error(
347
+ 'No `action` in context and no `deposit` or `maxDeposit` configured. Either provide context with action/channelId/cumulativeAmount, or configure `deposit`/`maxDeposit` for auto-management.',
348
+ )
349
+ },
350
+ })
351
+ }
352
+
353
+ export declare namespace session {
354
+ type Parameters = Account.getResolver.Parameters &
355
+ Client.getResolver.Parameters & {
356
+ /** Address authorized to sign vouchers. Defaults to the account address. Use when a separate access key (e.g. secp256k1) signs vouchers while the root account funds the channel. */
357
+ authorizedSigner?: Address | undefined
358
+ /** Token decimals for parsing human-readable amounts (default: 6). */
359
+ decimals?: number | undefined
360
+ /** Initial deposit amount in human-readable units (e.g. "10" for 10 tokens). When set, the method handles the full channel lifecycle (open, voucher, cumulative tracking) automatically. */
361
+ deposit?: string | undefined
362
+ /** Escrow contract address override. Derived from challenge or defaults if not provided. */
363
+ escrowContract?: Address | undefined
364
+ /** Maximum deposit in human-readable units (e.g. "10"). Caps the server's `suggestedDeposit`. Enables auto-management like `deposit`. */
365
+ maxDeposit?: string | undefined
366
+ /** Called whenever channel state changes (open, voucher, close, recovery). */
367
+ onChannelUpdate?: ((entry: ChannelEntry) => void) | undefined
368
+ }
369
+ }
@@ -0,0 +1,223 @@
1
+ import type { Hex } from 'viem'
2
+ import { describe, expect, test, vi } from 'vitest'
3
+ import * as Challenge from '../../Challenge.js'
4
+ import { formatNeedVoucherEvent, parseEvent } from '../stream/Sse.js'
5
+ import type { NeedVoucherEvent, StreamReceipt } from '../stream/Types.js'
6
+ import { sessionManager } from './SessionManager.js'
7
+
8
+ const channelId = '0x0000000000000000000000000000000000000000000000000000000000000001' as Hex
9
+ const challengeId = 'test-challenge-1'
10
+ const realm = 'test.example.com'
11
+
12
+ function makeChallenge(overrides: Record<string, unknown> = {}): Challenge.Challenge {
13
+ return Challenge.from({
14
+ id: challengeId,
15
+ realm,
16
+ method: 'tempo',
17
+ intent: 'session',
18
+ request: {
19
+ amount: '1000000',
20
+ currency: '0x20c0000000000000000000000000000000000001',
21
+ recipient: '0x742d35Cc6634C0532925a3b844Bc9e7595f8fE00',
22
+ decimals: 6,
23
+ methodDetails: {
24
+ escrowContract: '0x9d136eEa063eDE5418A6BC7bEafF009bBb6CFa70',
25
+ chainId: 4217,
26
+ },
27
+ ...overrides,
28
+ },
29
+ })
30
+ }
31
+
32
+ function make402Response(challenge?: Challenge.Challenge): Response {
33
+ const c = challenge ?? makeChallenge()
34
+ return new Response(null, {
35
+ status: 402,
36
+ headers: { 'WWW-Authenticate': Challenge.serialize(c) },
37
+ })
38
+ }
39
+
40
+ function makeOkResponse(body?: string): Response {
41
+ return new Response(body ?? 'ok', { status: 200 })
42
+ }
43
+
44
+ function makeSseResponse(events: string[]): Response {
45
+ const body = events.join('')
46
+ return new Response(body, {
47
+ status: 200,
48
+ headers: { 'Content-Type': 'text/event-stream' },
49
+ })
50
+ }
51
+
52
+ describe('Session', () => {
53
+ describe('parseEvent round-trip via SSE', () => {
54
+ test('parses message events from SSE stream', () => {
55
+ const raw = 'event: message\ndata: hello world\n\n'
56
+ const event = parseEvent(raw)
57
+ expect(event).toEqual({ type: 'message', data: 'hello world' })
58
+ })
59
+
60
+ test('parses payment-need-voucher events', () => {
61
+ const params: NeedVoucherEvent = {
62
+ channelId,
63
+ requiredCumulative: '6000000',
64
+ acceptedCumulative: '5000000',
65
+ deposit: '10000000',
66
+ }
67
+ const raw = formatNeedVoucherEvent(params)
68
+ const event = parseEvent(raw)
69
+ expect(event).toEqual({ type: 'payment-need-voucher', data: params })
70
+ })
71
+ })
72
+
73
+ describe('session creation', () => {
74
+ test('creates session with initial state', () => {
75
+ const s = sessionManager({
76
+ account: '0x0000000000000000000000000000000000000001',
77
+ maxDeposit: '10',
78
+ })
79
+
80
+ expect(s.channelId).toBeUndefined()
81
+ expect(s.cumulative).toBe(0n)
82
+ expect(s.opened).toBe(false)
83
+ })
84
+ })
85
+
86
+ describe('.fetch()', () => {
87
+ test('passes through non-402 responses', async () => {
88
+ const mockFetch = vi.fn().mockResolvedValue(makeOkResponse('hello'))
89
+
90
+ const s = sessionManager({
91
+ account: '0x0000000000000000000000000000000000000001',
92
+ fetch: mockFetch as typeof globalThis.fetch,
93
+ })
94
+
95
+ const res = await s.fetch('https://api.example.com/data')
96
+ expect(res.status).toBe(200)
97
+ expect(await res.text()).toBe('hello')
98
+ expect(mockFetch).toHaveBeenCalledOnce()
99
+ })
100
+
101
+ test('throws on 402 without maxDeposit or open channel', async () => {
102
+ const mockFetch = vi.fn().mockResolvedValue(make402Response())
103
+
104
+ const s = sessionManager({
105
+ account: '0x0000000000000000000000000000000000000001',
106
+ fetch: mockFetch as typeof globalThis.fetch,
107
+ })
108
+
109
+ await expect(s.fetch('https://api.example.com/data')).rejects.toThrow(
110
+ 'no `deposit` or `maxDeposit` configured',
111
+ )
112
+ })
113
+ })
114
+
115
+ describe('.open()', () => {
116
+ test('throws when no challenge is available', async () => {
117
+ const s = sessionManager({
118
+ account: '0x0000000000000000000000000000000000000001',
119
+ maxDeposit: '10',
120
+ })
121
+
122
+ await expect(s.open()).rejects.toThrow('No challenge available')
123
+ })
124
+ })
125
+
126
+ describe('.sse() event parsing', () => {
127
+ test('yields only message data from SSE stream', async () => {
128
+ const events = [
129
+ 'event: message\ndata: chunk1\n\n',
130
+ 'event: message\ndata: chunk2\n\n',
131
+ `event: payment-receipt\ndata: ${JSON.stringify({
132
+ method: 'tempo',
133
+ intent: 'session',
134
+ status: 'success',
135
+ timestamp: '2025-01-01T00:00:00.000Z',
136
+ reference: channelId,
137
+ challengeId,
138
+ channelId,
139
+ acceptedCumulative: '2000000',
140
+ spent: '2000000',
141
+ units: 2,
142
+ } satisfies StreamReceipt)}\n\n`,
143
+ ]
144
+
145
+ let callCount = 0
146
+ const mockFetch = vi.fn().mockImplementation(() => {
147
+ callCount++
148
+ if (callCount === 1) return Promise.resolve(makeSseResponse(events))
149
+ return Promise.resolve(makeOkResponse())
150
+ })
151
+
152
+ const s = sessionManager({
153
+ account: '0x0000000000000000000000000000000000000001',
154
+ fetch: mockFetch as typeof globalThis.fetch,
155
+ })
156
+
157
+ // Manually set channel state to skip auto-open flow
158
+ ;(s as any).__test_setChannel?.()
159
+
160
+ const receiptCb = vi.fn()
161
+ const iterable = await s.sse('https://api.example.com/stream', {
162
+ onReceipt: receiptCb,
163
+ })
164
+
165
+ const messages: string[] = []
166
+ for await (const msg of iterable) {
167
+ messages.push(msg)
168
+ }
169
+
170
+ expect(messages).toEqual(['chunk1', 'chunk2'])
171
+ expect(receiptCb).toHaveBeenCalledOnce()
172
+ expect(receiptCb.mock.calls[0]![0].units).toBe(2)
173
+ })
174
+ })
175
+
176
+ describe('error handling', () => {
177
+ test('.sse() silently skips payment-need-voucher when no channel open', async () => {
178
+ const needVoucher: NeedVoucherEvent = {
179
+ channelId,
180
+ requiredCumulative: '2000000',
181
+ acceptedCumulative: '1000000',
182
+ deposit: '10000000',
183
+ }
184
+
185
+ const events = [
186
+ 'event: message\ndata: chunk1\n\n',
187
+ formatNeedVoucherEvent(needVoucher),
188
+ 'event: message\ndata: chunk2\n\n',
189
+ ]
190
+
191
+ const mockFetch = vi.fn().mockResolvedValue(makeSseResponse(events))
192
+
193
+ const s = sessionManager({
194
+ account: '0x0000000000000000000000000000000000000001',
195
+ fetch: mockFetch as typeof globalThis.fetch,
196
+ })
197
+
198
+ const iterable = await s.sse('https://api.example.com/stream')
199
+
200
+ const messages: string[] = []
201
+ for await (const msg of iterable) {
202
+ messages.push(msg)
203
+ }
204
+
205
+ expect(messages).toEqual(['chunk1', 'chunk2'])
206
+ expect(mockFetch).toHaveBeenCalledOnce()
207
+ })
208
+ })
209
+
210
+ describe('.close()', () => {
211
+ test('is no-op when not opened', async () => {
212
+ const mockFetch = vi.fn()
213
+
214
+ const s = sessionManager({
215
+ account: '0x0000000000000000000000000000000000000001',
216
+ fetch: mockFetch as typeof globalThis.fetch,
217
+ })
218
+
219
+ await s.close()
220
+ expect(mockFetch).not.toHaveBeenCalled()
221
+ })
222
+ })
223
+ })