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,326 @@
1
+ import { Challenge, Credential, Receipt } from 'mppx'
2
+ import { Mppx as Mppx_client, stripe as stripe_client } from 'mppx/client'
3
+ import { Mppx as Mppx_server, stripe as stripe_server } from 'mppx/server'
4
+ import { afterEach, describe, expect, test } from 'vitest'
5
+ import * as Http from '~test/Http.js'
6
+
7
+ const stripeSecretKey = process.env.VITE_STRIPE_SECRET_KEY
8
+
9
+ const realm = 'api.example.com'
10
+ const secretKey = 'test-secret-key'
11
+
12
+ let httpServer: Awaited<ReturnType<typeof Http.createServer>> | undefined
13
+
14
+ afterEach(() => httpServer?.close())
15
+
16
+ async function createTestSpt(parameters: {
17
+ paymentMethod: string
18
+ amount: string
19
+ currency: string
20
+ networkId: string | undefined
21
+ expiresAt: number
22
+ metadata?: Record<string, string> | undefined
23
+ }) {
24
+ const body = new URLSearchParams({
25
+ payment_method: parameters.paymentMethod,
26
+ 'usage_limits[currency]': parameters.currency,
27
+ 'usage_limits[max_amount]': parameters.amount,
28
+ 'usage_limits[expires_at]': parameters.expiresAt.toString(),
29
+ })
30
+ if (parameters.networkId) body.set('seller_details[network_id]', parameters.networkId)
31
+ if (parameters.metadata) {
32
+ for (const [key, value] of Object.entries(parameters.metadata)) {
33
+ body.set(`metadata[${key}]`, value)
34
+ }
35
+ }
36
+ // Test-only endpoint; production SPT flow uses the agent-side issued_tokens API.
37
+ const createSpt = async (bodyParams: URLSearchParams) =>
38
+ fetch('https://api.stripe.com/v1/test_helpers/shared_payment/granted_tokens', {
39
+ method: 'POST',
40
+ headers: {
41
+ Authorization: `Basic ${btoa(`${stripeSecretKey!}:`)}`,
42
+ 'Content-Type': 'application/x-www-form-urlencoded',
43
+ },
44
+ body: bodyParams,
45
+ })
46
+
47
+ let response = await createSpt(body)
48
+ if (!response.ok) {
49
+ const error = (await response.json()) as { error: { message: string } }
50
+ if (
51
+ (parameters.metadata || parameters.networkId) &&
52
+ error.error.message.includes('Received unknown parameter')
53
+ ) {
54
+ const fallbackBody = new URLSearchParams({
55
+ payment_method: parameters.paymentMethod,
56
+ 'usage_limits[currency]': parameters.currency,
57
+ 'usage_limits[max_amount]': parameters.amount,
58
+ 'usage_limits[expires_at]': parameters.expiresAt.toString(),
59
+ })
60
+ response = await createSpt(fallbackBody)
61
+ } else {
62
+ throw new Error(`Failed to create SPT: ${error.error.message}`)
63
+ }
64
+ }
65
+
66
+ if (!response.ok) {
67
+ const error = (await response.json()) as { error: { message: string } }
68
+ throw new Error(`Failed to create SPT: ${error.error.message}`)
69
+ }
70
+
71
+ const { id } = (await response.json()) as { id: string }
72
+ return id
73
+ }
74
+
75
+ describe.skipIf(!stripeSecretKey)('stripe', () => {
76
+ const server = Mppx_server.create({
77
+ methods: [
78
+ stripe_server.charge({
79
+ secretKey: stripeSecretKey!,
80
+ networkId: 'internal',
81
+ paymentMethodTypes: ['card'],
82
+ metadata: { example: 'metadata' },
83
+ }),
84
+ ],
85
+ realm,
86
+ secretKey,
87
+ })
88
+
89
+ const clientCharge = stripe_client.charge({
90
+ createSpt: createTestSpt,
91
+ paymentMethod: 'pm_card_visa',
92
+ externalId: 'client_order_789',
93
+ })
94
+
95
+ describe('intent: charge; type: spt', () => {
96
+ test('default', async () => {
97
+ httpServer = await Http.createServer(async (req, res) => {
98
+ const result = await Mppx_server.toNodeListener(
99
+ server.charge({ amount: '1', currency: 'usd', decimals: 2 }),
100
+ )(req, res)
101
+ if (result.status === 402) return
102
+ res.end('OK')
103
+ })
104
+
105
+ const response = await fetch(httpServer.url)
106
+ expect(response.status).toBe(402)
107
+
108
+ const challenge = Challenge.fromResponse(response, {
109
+ methods: [clientCharge],
110
+ })
111
+ expect(challenge.method).toBe('stripe')
112
+ expect(challenge.intent).toBe('charge')
113
+ expect(challenge.request.amount).toBe('100')
114
+ expect(challenge.realm).toBe(realm)
115
+
116
+ const credential = await clientCharge.createCredential({ challenge, context: {} })
117
+
118
+ {
119
+ const response = await fetch(httpServer.url, {
120
+ headers: { Authorization: credential },
121
+ })
122
+ expect(response.status).toBe(200)
123
+
124
+ const receipt = Receipt.fromResponse(response)
125
+ expect({
126
+ ...receipt,
127
+ reference: '[reference]',
128
+ timestamp: '[timestamp]',
129
+ externalId: '[externalId]',
130
+ }).toMatchInlineSnapshot(`
131
+ {
132
+ "externalId": "[externalId]",
133
+ "method": "stripe",
134
+ "reference": "[reference]",
135
+ "status": "success",
136
+ "timestamp": "[timestamp]",
137
+ }
138
+ `)
139
+ }
140
+ })
141
+
142
+ test('behavior: rejects invalid SPT', async () => {
143
+ httpServer = await Http.createServer(async (req, res) => {
144
+ const result = await Mppx_server.toNodeListener(
145
+ server.charge({ amount: '1', currency: 'usd', decimals: 2 }),
146
+ )(req, res)
147
+ if (result.status === 402) return
148
+ res.end('OK')
149
+ })
150
+
151
+ const response = await fetch(httpServer.url)
152
+ const challenge = Challenge.fromResponse(response)
153
+
154
+ const credential = Credential.from({
155
+ challenge,
156
+ payload: { spt: 'spt_invalid_token' },
157
+ })
158
+
159
+ {
160
+ const response = await fetch(httpServer.url, {
161
+ headers: { Authorization: Credential.serialize(credential) },
162
+ })
163
+ expect(response.status).toBe(402)
164
+ const body = (await response.json()) as { detail: string }
165
+ expect(body.detail).toContain('Stripe PaymentIntent failed')
166
+ }
167
+ })
168
+
169
+ test('behavior: rejects expired challenge', async () => {
170
+ httpServer = await Http.createServer(async (req, res) => {
171
+ const result = await Mppx_server.toNodeListener(
172
+ server.charge({
173
+ amount: '1',
174
+ currency: 'usd',
175
+ decimals: 2,
176
+ expires: new Date(Date.now() - 1000).toISOString(),
177
+ }),
178
+ )(req, res)
179
+ if (result.status === 402) return
180
+ res.end('OK')
181
+ })
182
+
183
+ const response = await fetch(httpServer.url)
184
+ expect(response.status).toBe(402)
185
+
186
+ const challenge = Challenge.fromResponse(response)
187
+
188
+ const credential = Credential.from({
189
+ challenge,
190
+ payload: { spt: 'spt_does_not_matter' },
191
+ })
192
+
193
+ {
194
+ const response = await fetch(httpServer.url, {
195
+ headers: { Authorization: Credential.serialize(credential) },
196
+ })
197
+ expect(response.status).toBe(402)
198
+ const body = (await response.json()) as { detail: string }
199
+ expect(body.detail).toMatch(/^Payment expired at /)
200
+ }
201
+ })
202
+
203
+ test('behavior: rejects malformed credential payload (missing spt)', async () => {
204
+ httpServer = await Http.createServer(async (req, res) => {
205
+ const result = await Mppx_server.toNodeListener(
206
+ server.charge({ amount: '1', currency: 'usd', decimals: 2 }),
207
+ )(req, res)
208
+ if (result.status === 402) return
209
+ res.end('OK')
210
+ })
211
+
212
+ const response = await fetch(httpServer.url)
213
+ const challenge = Challenge.fromResponse(response)
214
+
215
+ const credential = Credential.from({
216
+ challenge,
217
+ payload: {},
218
+ })
219
+
220
+ {
221
+ const response = await fetch(httpServer.url, {
222
+ headers: { Authorization: Credential.serialize(credential) },
223
+ })
224
+ expect(response.status).toBe(402)
225
+ }
226
+ })
227
+
228
+ test('behavior: receipt format stability', async () => {
229
+ httpServer = await Http.createServer(async (req, res) => {
230
+ const result = await Mppx_server.toNodeListener(
231
+ server.charge({ amount: '1', currency: 'usd', decimals: 2 }),
232
+ )(req, res)
233
+ if (result.status === 402) return
234
+ res.end('OK')
235
+ })
236
+
237
+ const response = await fetch(httpServer.url)
238
+ const challenge = Challenge.fromResponse(response, {
239
+ methods: [clientCharge],
240
+ })
241
+
242
+ const credential = await clientCharge.createCredential({ challenge, context: {} })
243
+
244
+ {
245
+ const response = await fetch(httpServer.url, {
246
+ headers: { Authorization: credential },
247
+ })
248
+ expect(response.status).toBe(200)
249
+
250
+ const receipt = Receipt.fromResponse(response)
251
+ expect(receipt.status).toBe('success')
252
+ expect(receipt.method).toBe('stripe')
253
+ expect(receipt.reference).toMatch(/^pi_/)
254
+ expect(receipt.timestamp).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
255
+ }
256
+ })
257
+ })
258
+
259
+ describe('intent: charge; type: spt; via Mppx', () => {
260
+ test('default', async () => {
261
+ const mppx = Mppx_client.create({
262
+ polyfill: false,
263
+ methods: [clientCharge],
264
+ })
265
+
266
+ httpServer = await Http.createServer(async (req, res) => {
267
+ const result = await Mppx_server.toNodeListener(
268
+ server.charge({ amount: '1', currency: 'usd', decimals: 2 }),
269
+ )(req, res)
270
+ if (result.status === 402) return
271
+ res.end('OK')
272
+ })
273
+
274
+ const response = await fetch(httpServer.url)
275
+ expect(response.status).toBe(402)
276
+
277
+ const credential = await mppx.createCredential(response)
278
+
279
+ {
280
+ const response = await fetch(httpServer.url, {
281
+ headers: { Authorization: credential },
282
+ })
283
+ expect(response.status).toBe(200)
284
+
285
+ const receipt = Receipt.fromResponse(response)
286
+ expect({
287
+ ...receipt,
288
+ reference: '[reference]',
289
+ timestamp: '[timestamp]',
290
+ externalId: '[externalId]',
291
+ }).toMatchInlineSnapshot(`
292
+ {
293
+ "externalId": "[externalId]",
294
+ "method": "stripe",
295
+ "reference": "[reference]",
296
+ "status": "success",
297
+ "timestamp": "[timestamp]",
298
+ }
299
+ `)
300
+ }
301
+ })
302
+
303
+ test('behavior: full mppx.fetch() auto flow', async () => {
304
+ const mppx = Mppx_client.create({
305
+ polyfill: false,
306
+ methods: [clientCharge],
307
+ })
308
+
309
+ httpServer = await Http.createServer(async (req, res) => {
310
+ const result = await Mppx_server.toNodeListener(
311
+ server.charge({ amount: '1', currency: 'usd', decimals: 2 }),
312
+ )(req, res)
313
+ if (result.status === 402) return
314
+ res.end('OK')
315
+ })
316
+
317
+ const response = await mppx.fetch(httpServer.url)
318
+ expect(response.status).toBe(200)
319
+
320
+ const receipt = Receipt.fromResponse(response)
321
+ expect(receipt.status).toBe('success')
322
+ expect(receipt.method).toBe('stripe')
323
+ expect(receipt.reference).toMatch(/^pi_/)
324
+ })
325
+ })
326
+ })
@@ -0,0 +1,52 @@
1
+ import { MethodIntents } from 'mppx/stripe'
2
+ import { describe, expect, expectTypeOf, test } from 'vitest'
3
+
4
+ describe('charge', () => {
5
+ test('has correct name and method', () => {
6
+ expect(MethodIntents.charge.name).toBe('charge')
7
+ expect(MethodIntents.charge.method).toBe('stripe')
8
+ })
9
+
10
+ test('types: name is literal', () => {
11
+ expectTypeOf(MethodIntents.charge.name).toEqualTypeOf<'charge'>()
12
+ })
13
+
14
+ test('types: method is literal', () => {
15
+ expectTypeOf(MethodIntents.charge.method).toEqualTypeOf<'stripe'>()
16
+ })
17
+
18
+ test('schema: validates valid request', () => {
19
+ const result = MethodIntents.charge.schema.request.safeParse({
20
+ amount: '1',
21
+ currency: 'usd',
22
+ decimals: 2,
23
+ expires: '2025-02-05T12:05:00Z',
24
+ networkId: 'profile_123',
25
+ paymentMethodTypes: ['card'],
26
+ metadata: { example: 'metadata' },
27
+ })
28
+ expect(result.success).toBe(true)
29
+ })
30
+
31
+ test('schema: rejects invalid request', () => {
32
+ const result = MethodIntents.charge.schema.request.safeParse({
33
+ amount: '1',
34
+ })
35
+ expect(result.success).toBe(false)
36
+ })
37
+
38
+ test('schema: validates spt payload', () => {
39
+ const result = MethodIntents.charge.schema.credential.payload.safeParse({
40
+ spt: 'spt_test_123',
41
+ externalId: 'client_order_789',
42
+ })
43
+ expect(result.success).toBe(true)
44
+ })
45
+
46
+ test('schema: rejects invalid payload', () => {
47
+ const result = MethodIntents.charge.schema.credential.payload.safeParse({
48
+ signature: '0x...',
49
+ })
50
+ expect(result.success).toBe(false)
51
+ })
52
+ })
@@ -0,0 +1,27 @@
1
+ import * as Intent from '../Intent.js'
2
+ import * as MethodIntent from '../MethodIntent.js'
3
+ import * as z from '../zod.js'
4
+
5
+ /**
6
+ * Stripe charge intent for one-time payments via Shared Payment Tokens (SPTs).
7
+ *
8
+ * @see https://github.com/tempoxyz/payment-auth-spec/blob/main/specs/methods/stripe/draft-stripe-charge-00.md
9
+ */
10
+ export const charge = MethodIntent.fromIntent(Intent.charge, {
11
+ method: 'stripe',
12
+ schema: {
13
+ credential: {
14
+ payload: z.object({
15
+ spt: z.string(),
16
+ externalId: z.optional(z.string()),
17
+ }),
18
+ },
19
+ request: {
20
+ methodDetails: z.object({
21
+ networkId: z.string(),
22
+ paymentMethodTypes: z.array(z.string()).check(z.minLength(1)),
23
+ metadata: z.optional(z.record(z.string(), z.string())),
24
+ }),
25
+ },
26
+ },
27
+ })
@@ -0,0 +1,119 @@
1
+ import * as Credential from '../../Credential.js'
2
+ import * as MethodIntent from '../../MethodIntent.js'
3
+ import * as z from '../../zod.js'
4
+ import * as Intents from '../Intents.js'
5
+
6
+ /**
7
+ * Creates a Stripe charge method intent for usage on the client.
8
+ *
9
+ * Accepts a `createSpt` callback that handles SPT creation (requires
10
+ * a secret key, so typically proxied through a server endpoint).
11
+ *
12
+ * The `paymentMethod` (e.g. from Stripe Elements) can be provided at
13
+ * initialization or at credential-creation time via `context`.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { stripe } from 'mppx/client'
18
+ *
19
+ * const charge = stripe.charge({
20
+ * createSpt: async ({ paymentMethod, amount, currency, networkId, expiresAt, metadata }) => {
21
+ * const res = await fetch('/api/create-spt', {
22
+ * method: 'POST',
23
+ * headers: { 'Content-Type': 'application/json' },
24
+ * body: JSON.stringify({ paymentMethod, amount, currency, networkId, expiresAt, metadata }),
25
+ * })
26
+ * const { spt } = await res.json()
27
+ * return spt
28
+ * },
29
+ * })
30
+ *
31
+ * // paymentMethod comes from Stripe Elements at credential-creation time
32
+ * const credential = await charge.createCredential({
33
+ * challenge,
34
+ * context: { paymentMethod: 'pm_xxx' },
35
+ * })
36
+ * ```
37
+ */
38
+ export function charge(parameters: charge.Parameters) {
39
+ const { createSpt, externalId, paymentMethod: defaultPaymentMethod } = parameters
40
+
41
+ return MethodIntent.toClient(Intents.charge, {
42
+ context: z.object({
43
+ paymentMethod: z.optional(z.string()),
44
+ }),
45
+
46
+ async createCredential({ challenge, context }) {
47
+ const paymentMethod = context?.paymentMethod ?? defaultPaymentMethod
48
+ if (!paymentMethod)
49
+ throw new Error('paymentMethod is required (pass via context or parameters)')
50
+
51
+ const amount = challenge.request.amount as string
52
+ const currency = challenge.request.currency as string
53
+ const networkId = challenge.request.methodDetails?.networkId as string | undefined
54
+ if (!networkId) throw new Error('networkId is required in challenge.methodDetails')
55
+ const metadata = challenge.request.methodDetails?.metadata as
56
+ | Record<string, string>
57
+ | undefined
58
+ if (metadata?.externalId) {
59
+ throw new Error(
60
+ 'methodDetails.metadata.externalId is reserved; use credential externalId instead',
61
+ )
62
+ }
63
+
64
+ const expiresAt = challenge.request.expires
65
+ ? Math.floor(new Date(challenge.request.expires as string).getTime() / 1000)
66
+ : Math.floor(Date.now() / 1000) + 3600
67
+
68
+ const spt = await createSpt({
69
+ paymentMethod,
70
+ amount,
71
+ currency,
72
+ networkId,
73
+ expiresAt,
74
+ metadata,
75
+ })
76
+
77
+ return Credential.serialize({
78
+ challenge,
79
+ payload: {
80
+ spt,
81
+ ...(externalId ? { externalId } : {}),
82
+ },
83
+ })
84
+ },
85
+ })
86
+ }
87
+
88
+ export declare namespace charge {
89
+ type Parameters = {
90
+ /**
91
+ * Creates a Shared Payment Token (SPT) for the given parameters.
92
+ *
93
+ * SPT creation requires a Stripe secret key, so this typically
94
+ * proxies through a server endpoint (e.g. `POST /api/create-spt`).
95
+ * If you are running a client in an enviroment with a secret key, you can just create the
96
+ * SPT directly in this callback.
97
+ */
98
+ createSpt: (parameters: CreateSptParameters) => Promise<string>
99
+ /** Optional client-side external reference ID for the credential payload. */
100
+ externalId?: string | undefined
101
+ /** Default payment method ID. Overridden by `context.paymentMethod`. */
102
+ paymentMethod?: string | undefined
103
+ }
104
+
105
+ type CreateSptParameters = {
106
+ /** Stripe payment method ID (e.g. from Stripe Elements). */
107
+ paymentMethod: string
108
+ /** Payment amount (in smallest currency unit). */
109
+ amount: string
110
+ /** Three-letter ISO currency code. */
111
+ currency: string
112
+ /** Stripe Business Network profile ID. */
113
+ networkId: string | undefined
114
+ /** SPT expiration as a Unix timestamp (seconds). */
115
+ expiresAt: number
116
+ /** Optional metadata to associate with the SPT. */
117
+ metadata?: Record<string, string> | undefined
118
+ }
119
+ }
@@ -0,0 +1,37 @@
1
+ import { charge as charge_ } from './Charge.js'
2
+
3
+ /**
4
+ * Creates a Stripe `charge` client method intent.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { Mppx, stripe } from 'mppx/client'
9
+ *
10
+ * const mppx = Mppx.create({
11
+ * methods: [
12
+ * stripe({
13
+ * createSpt: async (params) => {
14
+ * const res = await fetch('/api/create-spt', {
15
+ * method: 'POST',
16
+ * headers: { 'Content-Type': 'application/json' },
17
+ * body: JSON.stringify(params),
18
+ * })
19
+ * const { spt } = await res.json()
20
+ * return spt
21
+ * },
22
+ * paymentMethod: 'pm_card_visa',
23
+ * }),
24
+ * ],
25
+ * })
26
+ * ```
27
+ */
28
+ export function stripe(parameters: stripe.Parameters) {
29
+ return [charge_(parameters)] as const
30
+ }
31
+
32
+ export namespace stripe {
33
+ export type Parameters = charge_.Parameters
34
+
35
+ /** Creates a Stripe `charge` client method intent for SPT-based payments. */
36
+ export const charge = charge_
37
+ }
@@ -0,0 +1,2 @@
1
+ export { charge } from './Charge.js'
2
+ export { stripe } from './MethodIntents.js'
@@ -0,0 +1 @@
1
+ export * as MethodIntents from './Intents.js'
@@ -0,0 +1,121 @@
1
+ import {
2
+ PaymentActionRequiredError,
3
+ PaymentExpiredError,
4
+ VerificationFailedError,
5
+ } from '../../Errors.js'
6
+ import type { LooseOmit } from '../../internal/types.js'
7
+ import * as MethodIntent from '../../MethodIntent.js'
8
+ import * as Intents from '../Intents.js'
9
+
10
+ /**
11
+ * Creates a Stripe charge method intent for usage on the server.
12
+ *
13
+ * Verifies payment by creating a Stripe PaymentIntent with the provided SPT.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { stripe } from 'mppx/server'
18
+ *
19
+ * const charge = stripe.charge({ secretKey: 'sk_...' })
20
+ * ```
21
+ */
22
+ export function charge<const parameters extends charge.Parameters>(parameters: parameters) {
23
+ const {
24
+ amount,
25
+ currency,
26
+ decimals,
27
+ description,
28
+ externalId,
29
+ metadata,
30
+ networkId,
31
+ paymentMethodTypes,
32
+ secretKey,
33
+ } = parameters
34
+
35
+ type Defaults = charge.DeriveDefaults<parameters>
36
+ return MethodIntent.toServer<typeof Intents.charge, Defaults>(Intents.charge, {
37
+ defaults: {
38
+ amount,
39
+ currency,
40
+ decimals,
41
+ description,
42
+ externalId,
43
+ metadata,
44
+ networkId,
45
+ paymentMethodTypes,
46
+ } as unknown as Defaults,
47
+
48
+ async verify({ credential }) {
49
+ const { challenge } = credential
50
+ const { request } = challenge
51
+
52
+ if (request.expires && new Date(request.expires) < new Date())
53
+ throw new PaymentExpiredError({ expires: request.expires })
54
+
55
+ const parsed = Intents.charge.schema.credential.payload.safeParse(credential.payload)
56
+ if (!parsed.success) throw new Error('Invalid credential payload: missing or malformed spt')
57
+ const { spt, externalId: credentialExternalId } = parsed.data as {
58
+ spt: string
59
+ externalId?: string
60
+ }
61
+
62
+ const body = new URLSearchParams({
63
+ amount: request.amount as string,
64
+ currency: request.currency as string,
65
+ shared_payment_granted_token: spt,
66
+ confirm: 'true',
67
+ 'automatic_payment_methods[enabled]': 'true',
68
+ 'automatic_payment_methods[allow_redirects]': 'never',
69
+ })
70
+ const resolvedMetadata = request.methodDetails?.metadata as Record<string, string> | undefined
71
+ if (resolvedMetadata) {
72
+ for (const [key, value] of Object.entries(resolvedMetadata)) {
73
+ body.set(`metadata[${key}]`, value)
74
+ }
75
+ }
76
+
77
+ const response = await fetch('https://api.stripe.com/v1/payment_intents', {
78
+ method: 'POST',
79
+ headers: {
80
+ Authorization: `Basic ${btoa(`${secretKey}:`)}`,
81
+ 'Content-Type': 'application/x-www-form-urlencoded',
82
+ 'Idempotency-Key': `mppx_${challenge.id}_${spt}`,
83
+ },
84
+ body,
85
+ })
86
+
87
+ if (!response.ok) throw new VerificationFailedError({ reason: 'Stripe PaymentIntent failed' })
88
+
89
+ const pi = (await response.json()) as { id: string; status: string }
90
+
91
+ if (pi.status === 'requires_action') {
92
+ throw new PaymentActionRequiredError({ reason: 'Stripe PaymentIntent requires action' })
93
+ }
94
+ if (pi.status !== 'succeeded') throw new Error(`Stripe PaymentIntent status: ${pi.status}`)
95
+
96
+ return {
97
+ method: 'stripe',
98
+ status: 'success',
99
+ timestamp: new Date().toISOString(),
100
+ reference: pi.id,
101
+ ...(credentialExternalId ? { externalId: credentialExternalId } : {}),
102
+ } as const
103
+ },
104
+ })
105
+ }
106
+
107
+ export declare namespace charge {
108
+ type Defaults = LooseOmit<MethodIntent.RequestDefaults<typeof Intents.charge>, 'recipient'>
109
+
110
+ type Parameters = {
111
+ /** Stripe secret API key. */
112
+ secretKey: string
113
+ /** Optional metadata to include in SPT creation requests. */
114
+ metadata?: Record<string, string> | undefined
115
+ } & Defaults
116
+
117
+ type DeriveDefaults<parameters extends Parameters> = Pick<
118
+ parameters,
119
+ Extract<keyof parameters, keyof Defaults>
120
+ > & { decimals: number }
121
+ }