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.
- package/LICENSE +21 -0
- package/README.md +195 -0
- package/dist/BodyDigest.d.ts +42 -0
- package/dist/BodyDigest.d.ts.map +1 -0
- package/dist/BodyDigest.js +40 -0
- package/dist/BodyDigest.js.map +1 -0
- package/dist/Challenge.d.ts +271 -0
- package/dist/Challenge.d.ts.map +1 -0
- package/dist/Challenge.js +291 -0
- package/dist/Challenge.js.map +1 -0
- package/dist/Credential.d.ts +91 -0
- package/dist/Credential.d.ts.map +1 -0
- package/dist/Credential.js +122 -0
- package/dist/Credential.js.map +1 -0
- package/dist/Errors.d.ts +243 -0
- package/dist/Errors.d.ts.map +1 -0
- package/dist/Errors.js +201 -0
- package/dist/Errors.js.map +1 -0
- package/dist/Expires.d.ts +15 -0
- package/dist/Expires.d.ts.map +1 -0
- package/dist/Expires.js +29 -0
- package/dist/Expires.js.map +1 -0
- package/dist/Intent.d.ts +101 -0
- package/dist/Intent.d.ts.map +1 -0
- package/dist/Intent.js +83 -0
- package/dist/Intent.js.map +1 -0
- package/dist/Mcp.d.ts +74 -0
- package/dist/Mcp.d.ts.map +1 -0
- package/dist/Mcp.js +9 -0
- package/dist/Mcp.js.map +1 -0
- package/dist/MethodIntent.d.ts +225 -0
- package/dist/MethodIntent.d.ts.map +1 -0
- package/dist/MethodIntent.js +156 -0
- package/dist/MethodIntent.js.map +1 -0
- package/dist/PaymentRequest.d.ts +88 -0
- package/dist/PaymentRequest.d.ts.map +1 -0
- package/dist/PaymentRequest.js +81 -0
- package/dist/PaymentRequest.js.map +1 -0
- package/dist/Receipt.d.ts +110 -0
- package/dist/Receipt.d.ts.map +1 -0
- package/dist/Receipt.js +105 -0
- package/dist/Receipt.js.map +1 -0
- package/dist/Store.d.ts +28 -0
- package/dist/Store.d.ts.map +1 -0
- package/dist/Store.js +61 -0
- package/dist/Store.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1219 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/Methods.d.ts +4 -0
- package/dist/client/Methods.d.ts.map +1 -0
- package/dist/client/Methods.js +4 -0
- package/dist/client/Methods.js.map +1 -0
- package/dist/client/Mppx.d.ts +84 -0
- package/dist/client/Mppx.d.ts.map +1 -0
- package/dist/client/Mppx.js +64 -0
- package/dist/client/Mppx.js.map +1 -0
- package/dist/client/Transport.d.ts +56 -0
- package/dist/client/Transport.d.ts.map +1 -0
- package/dist/client/Transport.js +81 -0
- package/dist/client/Transport.js.map +1 -0
- package/dist/client/index.d.ts +5 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +5 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/internal/Fetch.d.ts +85 -0
- package/dist/client/internal/Fetch.d.ts.map +1 -0
- package/dist/client/internal/Fetch.js +95 -0
- package/dist/client/internal/Fetch.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/types.d.ts +302 -0
- package/dist/internal/types.d.ts.map +1 -0
- package/dist/internal/types.js +2 -0
- package/dist/internal/types.js.map +1 -0
- package/dist/mcp-sdk/client/McpClient.d.ts +78 -0
- package/dist/mcp-sdk/client/McpClient.d.ts.map +1 -0
- package/dist/mcp-sdk/client/McpClient.js +98 -0
- package/dist/mcp-sdk/client/McpClient.js.map +1 -0
- package/dist/mcp-sdk/client/index.d.ts +3 -0
- package/dist/mcp-sdk/client/index.d.ts.map +1 -0
- package/dist/mcp-sdk/client/index.js +3 -0
- package/dist/mcp-sdk/client/index.js.map +1 -0
- package/dist/mcp-sdk/server/Transport.d.ts +43 -0
- package/dist/mcp-sdk/server/Transport.d.ts.map +1 -0
- package/dist/mcp-sdk/server/Transport.js +71 -0
- package/dist/mcp-sdk/server/Transport.js.map +1 -0
- package/dist/mcp-sdk/server/index.d.ts +2 -0
- package/dist/mcp-sdk/server/index.d.ts.map +1 -0
- package/dist/mcp-sdk/server/index.js +2 -0
- package/dist/mcp-sdk/server/index.js.map +1 -0
- package/dist/middlewares/elysia.d.ts +51 -0
- package/dist/middlewares/elysia.d.ts.map +1 -0
- package/dist/middlewares/elysia.js +59 -0
- package/dist/middlewares/elysia.js.map +1 -0
- package/dist/middlewares/express.d.ts +46 -0
- package/dist/middlewares/express.d.ts.map +1 -0
- package/dist/middlewares/express.js +69 -0
- package/dist/middlewares/express.js.map +1 -0
- package/dist/middlewares/hono.d.ts +46 -0
- package/dist/middlewares/hono.d.ts.map +1 -0
- package/dist/middlewares/hono.js +57 -0
- package/dist/middlewares/hono.js.map +1 -0
- package/dist/middlewares/internal/mppx.d.ts +16 -0
- package/dist/middlewares/internal/mppx.d.ts.map +1 -0
- package/dist/middlewares/internal/mppx.js +16 -0
- package/dist/middlewares/internal/mppx.js.map +1 -0
- package/dist/middlewares/nextjs.d.ts +45 -0
- package/dist/middlewares/nextjs.d.ts.map +1 -0
- package/dist/middlewares/nextjs.js +57 -0
- package/dist/middlewares/nextjs.js.map +1 -0
- package/dist/proxy/Proxy.d.ts +47 -0
- package/dist/proxy/Proxy.d.ts.map +1 -0
- package/dist/proxy/Proxy.js +126 -0
- package/dist/proxy/Proxy.js.map +1 -0
- package/dist/proxy/Service.d.ts +100 -0
- package/dist/proxy/Service.d.ts.map +1 -0
- package/dist/proxy/Service.js +147 -0
- package/dist/proxy/Service.js.map +1 -0
- package/dist/proxy/index.d.ts +7 -0
- package/dist/proxy/index.d.ts.map +1 -0
- package/dist/proxy/index.js +7 -0
- package/dist/proxy/index.js.map +1 -0
- package/dist/proxy/internal/Headers.d.ts +3 -0
- package/dist/proxy/internal/Headers.d.ts.map +1 -0
- package/dist/proxy/internal/Headers.js +41 -0
- package/dist/proxy/internal/Headers.js.map +1 -0
- package/dist/proxy/internal/Route.d.ts +14 -0
- package/dist/proxy/internal/Route.d.ts.map +1 -0
- package/dist/proxy/internal/Route.js +47 -0
- package/dist/proxy/internal/Route.js.map +1 -0
- package/dist/proxy/services/anthropic.d.ts +29 -0
- package/dist/proxy/services/anthropic.d.ts.map +1 -0
- package/dist/proxy/services/anthropic.js +30 -0
- package/dist/proxy/services/anthropic.js.map +1 -0
- package/dist/proxy/services/openai.d.ts +29 -0
- package/dist/proxy/services/openai.d.ts.map +1 -0
- package/dist/proxy/services/openai.js +30 -0
- package/dist/proxy/services/openai.js.map +1 -0
- package/dist/proxy/services/stripe.d.ts +29 -0
- package/dist/proxy/services/stripe.d.ts.map +1 -0
- package/dist/proxy/services/stripe.js +30 -0
- package/dist/proxy/services/stripe.js.map +1 -0
- package/dist/server/Methods.d.ts +3 -0
- package/dist/server/Methods.d.ts.map +1 -0
- package/dist/server/Methods.js +3 -0
- package/dist/server/Methods.js.map +1 -0
- package/dist/server/Mppx.d.ts +116 -0
- package/dist/server/Mppx.d.ts.map +1 -0
- package/dist/server/Mppx.js +207 -0
- package/dist/server/Mppx.js.map +1 -0
- package/dist/server/NodeListener.d.ts +3 -0
- package/dist/server/NodeListener.d.ts.map +1 -0
- package/dist/server/NodeListener.js +3 -0
- package/dist/server/NodeListener.js.map +1 -0
- package/dist/server/Request.d.ts +24 -0
- package/dist/server/Request.d.ts.map +1 -0
- package/dist/server/Request.js +26 -0
- package/dist/server/Request.js.map +1 -0
- package/dist/server/Response.d.ts +10 -0
- package/dist/server/Response.d.ts.map +1 -0
- package/dist/server/Response.js +15 -0
- package/dist/server/Response.js.map +1 -0
- package/dist/server/Transport.d.ts +93 -0
- package/dist/server/Transport.d.ts.map +1 -0
- package/dist/server/Transport.js +132 -0
- package/dist/server/Transport.js.map +1 -0
- package/dist/server/index.d.ts +9 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +9 -0
- package/dist/server/index.js.map +1 -0
- package/dist/stripe/Intents.d.ts +54 -0
- package/dist/stripe/Intents.d.ts.map +1 -0
- package/dist/stripe/Intents.js +27 -0
- package/dist/stripe/Intents.js.map +1 -0
- package/dist/stripe/client/Charge.d.ts +114 -0
- package/dist/stripe/client/Charge.d.ts.map +1 -0
- package/dist/stripe/client/Charge.js +77 -0
- package/dist/stripe/client/Charge.js.map +1 -0
- package/dist/stripe/client/MethodIntents.d.ts +80 -0
- package/dist/stripe/client/MethodIntents.d.ts.map +1 -0
- package/dist/stripe/client/MethodIntents.js +34 -0
- package/dist/stripe/client/MethodIntents.js.map +1 -0
- package/dist/stripe/client/index.d.ts +3 -0
- package/dist/stripe/client/index.d.ts.map +1 -0
- package/dist/stripe/client/index.js +3 -0
- package/dist/stripe/client/index.js.map +1 -0
- package/dist/stripe/index.d.ts +2 -0
- package/dist/stripe/index.d.ts.map +1 -0
- package/dist/stripe/index.js +2 -0
- package/dist/stripe/index.js.map +1 -0
- package/dist/stripe/server/Charge.d.ts +74 -0
- package/dist/stripe/server/Charge.d.ts.map +1 -0
- package/dist/stripe/server/Charge.js +79 -0
- package/dist/stripe/server/Charge.js.map +1 -0
- package/dist/stripe/server/MethodIntents.d.ts +65 -0
- package/dist/stripe/server/MethodIntents.d.ts.map +1 -0
- package/dist/stripe/server/MethodIntents.js +21 -0
- package/dist/stripe/server/MethodIntents.js.map +1 -0
- package/dist/stripe/server/index.d.ts +3 -0
- package/dist/stripe/server/index.d.ts.map +1 -0
- package/dist/stripe/server/index.js +3 -0
- package/dist/stripe/server/index.js.map +1 -0
- package/dist/tempo/Attribution.d.ts +101 -0
- package/dist/tempo/Attribution.d.ts.map +1 -0
- package/dist/tempo/Attribution.js +124 -0
- package/dist/tempo/Attribution.js.map +1 -0
- package/dist/tempo/Intents.d.ts +132 -0
- package/dist/tempo/Intents.d.ts.map +1 -0
- package/dist/tempo/Intents.js +81 -0
- package/dist/tempo/Intents.js.map +1 -0
- package/dist/tempo/client/ChannelOps.d.ts +54 -0
- package/dist/tempo/client/ChannelOps.d.ts.map +1 -0
- package/dist/tempo/client/ChannelOps.js +138 -0
- package/dist/tempo/client/ChannelOps.js.map +1 -0
- package/dist/tempo/client/Charge.d.ts +76 -0
- package/dist/tempo/client/Charge.d.ts.map +1 -0
- package/dist/tempo/client/Charge.js +69 -0
- package/dist/tempo/client/Charge.js.map +1 -0
- package/dist/tempo/client/MethodIntents.d.ts +157 -0
- package/dist/tempo/client/MethodIntents.d.ts.map +1 -0
- package/dist/tempo/client/MethodIntents.js +25 -0
- package/dist/tempo/client/MethodIntents.js.map +1 -0
- package/dist/tempo/client/Session.d.ts +159 -0
- package/dist/tempo/client/Session.d.ts.map +1 -0
- package/dist/tempo/client/Session.js +263 -0
- package/dist/tempo/client/Session.js.map +1 -0
- package/dist/tempo/client/SessionManager.d.ts +62 -0
- package/dist/tempo/client/SessionManager.d.ts.map +1 -0
- package/dist/tempo/client/SessionManager.js +196 -0
- package/dist/tempo/client/SessionManager.js.map +1 -0
- package/dist/tempo/client/index.d.ts +6 -0
- package/dist/tempo/client/index.d.ts.map +1 -0
- package/dist/tempo/client/index.js +5 -0
- package/dist/tempo/client/index.js.map +1 -0
- package/dist/tempo/index.d.ts +3 -0
- package/dist/tempo/index.d.ts.map +1 -0
- package/dist/tempo/index.js +3 -0
- package/dist/tempo/index.js.map +1 -0
- package/dist/tempo/internal/account.d.ts +32 -0
- package/dist/tempo/internal/account.d.ts.map +1 -0
- package/dist/tempo/internal/account.js +33 -0
- package/dist/tempo/internal/account.js.map +1 -0
- package/dist/tempo/internal/defaults.d.ts +18 -0
- package/dist/tempo/internal/defaults.d.ts.map +1 -0
- package/dist/tempo/internal/defaults.js +18 -0
- package/dist/tempo/internal/defaults.js.map +1 -0
- package/dist/tempo/internal/types.d.ts +11 -0
- package/dist/tempo/internal/types.d.ts.map +1 -0
- package/dist/tempo/internal/types.js +2 -0
- package/dist/tempo/internal/types.js.map +1 -0
- package/dist/tempo/server/Charge.d.ts +77 -0
- package/dist/tempo/server/Charge.d.ts.map +1 -0
- package/dist/tempo/server/Charge.js +228 -0
- package/dist/tempo/server/Charge.js.map +1 -0
- package/dist/tempo/server/MethodIntents.d.ts +140 -0
- package/dist/tempo/server/MethodIntents.d.ts.map +1 -0
- package/dist/tempo/server/MethodIntents.js +26 -0
- package/dist/tempo/server/MethodIntents.js.map +1 -0
- package/dist/tempo/server/Session.d.ts +148 -0
- package/dist/tempo/server/Session.d.ts.map +1 -0
- package/dist/tempo/server/Session.js +529 -0
- package/dist/tempo/server/Session.js.map +1 -0
- package/dist/tempo/server/internal/transport.d.ts +47 -0
- package/dist/tempo/server/internal/transport.d.ts.map +1 -0
- package/dist/tempo/server/internal/transport.js +118 -0
- package/dist/tempo/server/internal/transport.js.map +1 -0
- package/dist/tempo/stream/Chain.d.ts +52 -0
- package/dist/tempo/stream/Chain.d.ts.map +1 -0
- package/dist/tempo/stream/Chain.js +215 -0
- package/dist/tempo/stream/Chain.js.map +1 -0
- package/dist/tempo/stream/Channel.d.ts +26 -0
- package/dist/tempo/stream/Channel.d.ts.map +1 -0
- package/dist/tempo/stream/Channel.js +27 -0
- package/dist/tempo/stream/Channel.js.map +1 -0
- package/dist/tempo/stream/ChannelStore.d.ts +103 -0
- package/dist/tempo/stream/ChannelStore.d.ts.map +1 -0
- package/dist/tempo/stream/ChannelStore.js +100 -0
- package/dist/tempo/stream/ChannelStore.js.map +1 -0
- package/dist/tempo/stream/Receipt.d.ts +22 -0
- package/dist/tempo/stream/Receipt.d.ts.map +1 -0
- package/dist/tempo/stream/Receipt.js +34 -0
- package/dist/tempo/stream/Receipt.js.map +1 -0
- package/dist/tempo/stream/Sse.d.ts +134 -0
- package/dist/tempo/stream/Sse.d.ts.map +1 -0
- package/dist/tempo/stream/Sse.js +288 -0
- package/dist/tempo/stream/Sse.js.map +1 -0
- package/dist/tempo/stream/Types.d.ts +78 -0
- package/dist/tempo/stream/Types.d.ts.map +1 -0
- package/dist/tempo/stream/Types.js +2 -0
- package/dist/tempo/stream/Types.js.map +1 -0
- package/dist/tempo/stream/Voucher.d.ts +20 -0
- package/dist/tempo/stream/Voucher.d.ts.map +1 -0
- package/dist/tempo/stream/Voucher.js +98 -0
- package/dist/tempo/stream/Voucher.js.map +1 -0
- package/dist/tempo/stream/escrow.abi.d.ts +598 -0
- package/dist/tempo/stream/escrow.abi.d.ts.map +1 -0
- package/dist/tempo/stream/escrow.abi.js +760 -0
- package/dist/tempo/stream/escrow.abi.js.map +1 -0
- package/dist/tempo/stream/index.d.ts +8 -0
- package/dist/tempo/stream/index.d.ts.map +1 -0
- package/dist/tempo/stream/index.js +8 -0
- package/dist/tempo/stream/index.js.map +1 -0
- package/dist/viem/Account.d.ts +12 -0
- package/dist/viem/Account.d.ts.map +1 -0
- package/dist/viem/Account.js +14 -0
- package/dist/viem/Account.js.map +1 -0
- package/dist/viem/Client.d.ts +21 -0
- package/dist/viem/Client.d.ts.map +1 -0
- package/dist/viem/Client.js +19 -0
- package/dist/viem/Client.js.map +1 -0
- package/dist/zod.d.ts +17 -0
- package/dist/zod.d.ts.map +1 -0
- package/dist/zod.js +35 -0
- package/dist/zod.js.map +1 -0
- package/package.json +117 -4
- package/src/BodyDigest.test.ts +43 -0
- package/src/BodyDigest.ts +53 -0
- package/src/Challenge.test-d.ts +81 -0
- package/src/Challenge.test.ts +414 -0
- package/src/Challenge.ts +429 -0
- package/src/Credential.test.ts +227 -0
- package/src/Credential.ts +154 -0
- package/src/Errors.test.ts +402 -0
- package/src/Errors.ts +348 -0
- package/src/Expires.ts +34 -0
- package/src/Intent.test.ts +180 -0
- package/src/Intent.ts +109 -0
- package/src/Mcp.ts +81 -0
- package/src/MethodIntent.test.ts +303 -0
- package/src/MethodIntent.ts +388 -0
- package/src/PaymentRequest.test.ts +152 -0
- package/src/PaymentRequest.ts +107 -0
- package/src/Receipt.test.ts +98 -0
- package/src/Receipt.ts +129 -0
- package/src/Store.ts +84 -0
- package/src/cli.test.ts +542 -0
- package/src/cli.ts +1319 -0
- package/src/client/Methods.ts +3 -0
- package/src/client/Mppx.test-d.ts +90 -0
- package/src/client/Mppx.test.ts +468 -0
- package/src/client/Mppx.ts +149 -0
- package/src/client/Transport.test.ts +283 -0
- package/src/client/Transport.ts +115 -0
- package/src/client/index.ts +4 -0
- package/src/client/internal/Fetch.test-d.ts +57 -0
- package/src/client/internal/Fetch.test.ts +281 -0
- package/src/client/internal/Fetch.ts +157 -0
- package/src/env.d.ts +11 -0
- package/src/index.ts +12 -0
- package/src/internal/types.ts +403 -0
- package/src/mcp-sdk/client/McpClient.test-d.ts +109 -0
- package/src/mcp-sdk/client/McpClient.test.ts +219 -0
- package/src/mcp-sdk/client/McpClient.ts +187 -0
- package/src/mcp-sdk/client/index.ts +2 -0
- package/src/mcp-sdk/server/Transport.ts +94 -0
- package/src/mcp-sdk/server/index.ts +1 -0
- package/src/middlewares/elysia.ts +66 -0
- package/src/middlewares/express.test.ts +155 -0
- package/src/middlewares/express.ts +82 -0
- package/src/middlewares/hono.test.ts +148 -0
- package/src/middlewares/hono.ts +62 -0
- package/src/middlewares/internal/mppx.ts +30 -0
- package/src/middlewares/nextjs.test.ts +164 -0
- package/src/middlewares/nextjs.ts +66 -0
- package/src/proxy/Proxy.test.ts +472 -0
- package/src/proxy/Proxy.ts +175 -0
- package/src/proxy/Service.test.ts +125 -0
- package/src/proxy/Service.ts +227 -0
- package/src/proxy/index.ts +6 -0
- package/src/proxy/internal/Headers.test.ts +100 -0
- package/src/proxy/internal/Headers.ts +40 -0
- package/src/proxy/internal/Route.test.ts +143 -0
- package/src/proxy/internal/Route.ts +54 -0
- package/src/proxy/services/anthropic.ts +45 -0
- package/src/proxy/services/openai.test.ts +97 -0
- package/src/proxy/services/openai.ts +48 -0
- package/src/proxy/services/stripe.ts +49 -0
- package/src/server/Methods.ts +2 -0
- package/src/server/Mppx.test-d.ts +343 -0
- package/src/server/Mppx.test.ts +342 -0
- package/src/server/Mppx.ts +378 -0
- package/src/server/NodeListener.test.ts +188 -0
- package/src/server/NodeListener.ts +3 -0
- package/src/server/Request.test.ts +102 -0
- package/src/server/Request.ts +33 -0
- package/src/server/Response.test.ts +31 -0
- package/src/server/Response.ts +27 -0
- package/src/server/Transport.test.ts +294 -0
- package/src/server/Transport.ts +222 -0
- package/src/server/index.ts +8 -0
- package/src/stripe/Charge.integration.test.ts +326 -0
- package/src/stripe/Intents.test.ts +52 -0
- package/src/stripe/Intents.ts +27 -0
- package/src/stripe/client/Charge.ts +119 -0
- package/src/stripe/client/MethodIntents.ts +37 -0
- package/src/stripe/client/index.ts +2 -0
- package/src/stripe/index.ts +1 -0
- package/src/stripe/server/Charge.ts +121 -0
- package/src/stripe/server/MethodIntents.ts +24 -0
- package/src/stripe/server/index.ts +2 -0
- package/src/tempo/Attribution.test.ts +187 -0
- package/src/tempo/Attribution.ts +156 -0
- package/src/tempo/Intents.test.ts +84 -0
- package/src/tempo/Intents.ts +93 -0
- package/src/tempo/client/ChannelOps.ts +233 -0
- package/src/tempo/client/Charge.ts +84 -0
- package/src/tempo/client/MethodIntents.ts +28 -0
- package/src/tempo/client/Session.ts +369 -0
- package/src/tempo/client/SessionManager.test.ts +223 -0
- package/src/tempo/client/SessionManager.ts +270 -0
- package/src/tempo/client/index.ts +5 -0
- package/src/tempo/index.ts +2 -0
- package/src/tempo/internal/account.ts +47 -0
- package/src/tempo/internal/defaults.ts +20 -0
- package/src/tempo/internal/types.ts +8 -0
- package/src/tempo/server/Charge.test.ts +847 -0
- package/src/tempo/server/Charge.ts +309 -0
- package/src/tempo/server/MethodIntents.ts +29 -0
- package/src/tempo/server/Session.test.ts +1349 -0
- package/src/tempo/server/Session.ts +773 -0
- package/src/tempo/server/Sse.test.ts +289 -0
- package/src/tempo/server/index.ts +5 -0
- package/src/tempo/server/internal/transport.ts +153 -0
- package/src/tempo/stream/Chain.ts +333 -0
- package/src/tempo/stream/Channel.ts +50 -0
- package/src/tempo/stream/ChannelStore.test.ts +473 -0
- package/src/tempo/stream/ChannelStore.ts +202 -0
- package/src/tempo/stream/Receipt.test.ts +84 -0
- package/src/tempo/stream/Receipt.ts +45 -0
- package/src/tempo/stream/Sse.test.ts +401 -0
- package/src/tempo/stream/Sse.ts +375 -0
- package/src/tempo/stream/Types.ts +86 -0
- package/src/tempo/stream/Voucher.test.ts +134 -0
- package/src/tempo/stream/Voucher.ts +123 -0
- package/src/tempo/stream/escrow.abi.ts +759 -0
- package/src/tempo/stream/index.ts +7 -0
- package/src/tsconfig.json +10 -0
- package/src/viem/Account.test.ts +71 -0
- package/src/viem/Account.ts +30 -0
- package/src/viem/Client.test.ts +58 -0
- package/src/viem/Client.ts +33 -0
- 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 @@
|
|
|
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
|
+
}
|