mppx 0.0.1 → 0.1.1
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 +89 -0
- package/dist/client/Mppx.d.ts.map +1 -0
- package/dist/client/Mppx.js +69 -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 +87 -0
- package/dist/client/internal/Fetch.d.ts.map +1 -0
- package/dist/client/internal/Fetch.js +99 -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 +105 -0
- package/dist/stripe/client/Charge.d.ts.map +1 -0
- package/dist/stripe/client/Charge.js +74 -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 +201 -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 +119 -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 +165 -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 +315 -0
- package/src/client/internal/Fetch.ts +169 -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 +329 -0
- package/src/stripe/Intents.test.ts +52 -0
- package/src/stripe/Intents.ts +27 -0
- package/src/stripe/client/Charge.ts +115 -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 +276 -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 +154 -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,165 @@
|
|
|
1
|
+
import type * as Challenge from '../Challenge.js'
|
|
2
|
+
import type * as MethodIntent from '../MethodIntent.js'
|
|
3
|
+
import type * as z from '../zod.js'
|
|
4
|
+
import * as Fetch from './internal/Fetch.js'
|
|
5
|
+
import * as Transport from './Transport.js'
|
|
6
|
+
|
|
7
|
+
export type Methods = readonly (MethodIntent.AnyClient | readonly MethodIntent.AnyClient[])[]
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Client-side payment handler.
|
|
11
|
+
*/
|
|
12
|
+
export type Mppx<
|
|
13
|
+
methods extends Methods = Methods,
|
|
14
|
+
transport extends Transport.Transport = Transport.Transport,
|
|
15
|
+
> = {
|
|
16
|
+
/** Payment-aware fetch function that automatically handles 402 responses. */
|
|
17
|
+
fetch: Fetch.from.Fetch<FlattenMethods<methods>>
|
|
18
|
+
/** Methods to configure. */
|
|
19
|
+
methods: FlattenMethods<methods>
|
|
20
|
+
/** The transport used. */
|
|
21
|
+
transport: transport
|
|
22
|
+
/** Creates a credential from a payment-required response by routing to the correct method. */
|
|
23
|
+
createCredential: (
|
|
24
|
+
response: Transport.ResponseOf<transport>,
|
|
25
|
+
context?: AnyContextFor<FlattenMethods<methods>> | undefined,
|
|
26
|
+
) => Promise<string>
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Creates a client-side payment handler from an array of method intents.
|
|
31
|
+
*
|
|
32
|
+
* Returns a payment handler with a `fetch` function that automatically handles
|
|
33
|
+
* 402 Payment Required responses. By default, also polyfills `globalThis.fetch`.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { Mppx, tempo } from 'mppx/client'
|
|
38
|
+
*
|
|
39
|
+
* const mppx = Mppx.create({
|
|
40
|
+
* methods: [tempo({ account })],
|
|
41
|
+
* })
|
|
42
|
+
*
|
|
43
|
+
* // Use the returned fetch — handles 402 automatically
|
|
44
|
+
* const res = await mppx.fetch('/resource')
|
|
45
|
+
*
|
|
46
|
+
* // Or use globalThis.fetch (polyfilled by default)
|
|
47
|
+
* const res2 = await fetch('/resource')
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function create<
|
|
51
|
+
const methods extends Methods,
|
|
52
|
+
const transport extends Transport.Transport<any, any> = Transport.Transport<
|
|
53
|
+
RequestInit,
|
|
54
|
+
Response
|
|
55
|
+
>,
|
|
56
|
+
>(config: create.Config<methods, transport>): Mppx<methods, transport> {
|
|
57
|
+
const { onChallenge, polyfill = true, transport = Transport.http() as transport } = config
|
|
58
|
+
|
|
59
|
+
const methods = config.methods.flat() as unknown as FlattenMethods<methods>
|
|
60
|
+
|
|
61
|
+
const resolvedOnChallenge = onChallenge as Fetch.from.Config<
|
|
62
|
+
FlattenMethods<methods>
|
|
63
|
+
>['onChallenge']
|
|
64
|
+
const config_fetch = {
|
|
65
|
+
...(config.fetch && { fetch: config.fetch }),
|
|
66
|
+
...(resolvedOnChallenge && { onChallenge: resolvedOnChallenge }),
|
|
67
|
+
methods,
|
|
68
|
+
} satisfies Fetch.from.Config<FlattenMethods<methods>>
|
|
69
|
+
const fetch = Fetch.from<FlattenMethods<methods>>(config_fetch)
|
|
70
|
+
|
|
71
|
+
if (polyfill) Fetch.polyfill(config_fetch)
|
|
72
|
+
return {
|
|
73
|
+
fetch,
|
|
74
|
+
methods,
|
|
75
|
+
transport,
|
|
76
|
+
async createCredential(response: Transport.ResponseOf<transport>, context?: unknown) {
|
|
77
|
+
const challenge = transport.getChallenge(response as never) as Challenge.Challenge
|
|
78
|
+
|
|
79
|
+
const mi = methods.find((m) => m.method === challenge.method && m.name === challenge.intent)
|
|
80
|
+
if (!mi)
|
|
81
|
+
throw new Error(
|
|
82
|
+
`No method intent found for "${challenge.method}.${challenge.intent}". Available: ${methods.map((m) => `${m.method}.${m.name}`).join(', ')}`,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
const parsedContext =
|
|
86
|
+
mi.context && context !== undefined ? mi.context.parse(context) : undefined
|
|
87
|
+
|
|
88
|
+
return mi.createCredential(
|
|
89
|
+
parsedContext !== undefined
|
|
90
|
+
? { challenge, context: parsedContext }
|
|
91
|
+
: ({ challenge } as never),
|
|
92
|
+
)
|
|
93
|
+
},
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Restores the original `fetch` after `create()` polyfilled it.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* import { Mppx, tempo } from 'mppx/client'
|
|
103
|
+
*
|
|
104
|
+
* Mppx.create({ methods: [tempo({ account })] })
|
|
105
|
+
*
|
|
106
|
+
* // ... use payment-aware fetch ...
|
|
107
|
+
*
|
|
108
|
+
* Mppx.restore()
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export function restore(): void {
|
|
112
|
+
Fetch.restore()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export declare namespace create {
|
|
116
|
+
type Config<
|
|
117
|
+
methods extends Methods = Methods,
|
|
118
|
+
transport extends Transport.Transport = Transport.Transport,
|
|
119
|
+
> = {
|
|
120
|
+
/** Custom fetch function to wrap. Defaults to `globalThis.fetch`. */
|
|
121
|
+
fetch?: typeof globalThis.fetch
|
|
122
|
+
/** Called when a 402 challenge is received, before credential creation. */
|
|
123
|
+
onChallenge?:
|
|
124
|
+
| ((
|
|
125
|
+
challenge: Challenge.Challenge,
|
|
126
|
+
helpers: {
|
|
127
|
+
createCredential: (context?: AnyContextFor<FlattenMethods<methods>>) => Promise<string>
|
|
128
|
+
},
|
|
129
|
+
) => Promise<string | undefined>)
|
|
130
|
+
| undefined
|
|
131
|
+
/** Array of method intents to use. Accepts individual clients or tuples (e.g. from `tempo()`). */
|
|
132
|
+
methods: methods
|
|
133
|
+
/** Whether to polyfill `globalThis.fetch` with the payment-aware wrapper. @default true */
|
|
134
|
+
polyfill?: boolean | undefined
|
|
135
|
+
/** Transport to use (defaults to HTTP). */
|
|
136
|
+
transport?: transport | undefined
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Union of all context types from all methods that have context schemas.
|
|
142
|
+
* @internal
|
|
143
|
+
*/
|
|
144
|
+
type AnyContextFor<methods extends readonly MethodIntent.AnyClient[]> = {
|
|
145
|
+
[method in keyof methods]: methods[method] extends MethodIntent.Client<any, infer context>
|
|
146
|
+
? context extends z.ZodMiniType
|
|
147
|
+
? z.input<context>
|
|
148
|
+
: undefined
|
|
149
|
+
: undefined
|
|
150
|
+
}[number]
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Flattens a methods config tuple, preserving positional types.
|
|
154
|
+
* @internal
|
|
155
|
+
*/
|
|
156
|
+
type FlattenMethods<methods extends Methods> = methods extends readonly [
|
|
157
|
+
infer head,
|
|
158
|
+
...infer tail extends Methods,
|
|
159
|
+
]
|
|
160
|
+
? head extends readonly MethodIntent.AnyClient[]
|
|
161
|
+
? readonly [...head, ...FlattenMethods<tail>]
|
|
162
|
+
: head extends MethodIntent.AnyClient
|
|
163
|
+
? readonly [head, ...FlattenMethods<tail>]
|
|
164
|
+
: never
|
|
165
|
+
: readonly []
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { Challenge, Credential, Mcp } from 'mppx'
|
|
2
|
+
import { Transport } from 'mppx/client'
|
|
3
|
+
import { MethodIntents as Intents } from 'mppx/tempo'
|
|
4
|
+
import { describe, expect, test } from 'vitest'
|
|
5
|
+
|
|
6
|
+
const realm = 'api.example.com'
|
|
7
|
+
const secretKey = 'test-secret-key'
|
|
8
|
+
|
|
9
|
+
const challenge = Challenge.fromIntent(Intents.charge, {
|
|
10
|
+
realm,
|
|
11
|
+
secretKey,
|
|
12
|
+
request: {
|
|
13
|
+
amount: '0.001',
|
|
14
|
+
currency: '0x20c0000000000000000000000000000000000001',
|
|
15
|
+
decimals: 6,
|
|
16
|
+
recipient: '0x742d35Cc6634C0532925a3b844Bc9e7595f8fE00',
|
|
17
|
+
expires: '2025-01-01T00:00:00.000Z',
|
|
18
|
+
},
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const credential = Credential.from({
|
|
22
|
+
challenge,
|
|
23
|
+
payload: { signature: '0xabc123', type: 'transaction' },
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
describe('http', () => {
|
|
27
|
+
describe('isPaymentRequired', () => {
|
|
28
|
+
test('returns true for 402 response', () => {
|
|
29
|
+
const transport = Transport.http()
|
|
30
|
+
const response = new Response(null, { status: 402 })
|
|
31
|
+
|
|
32
|
+
expect(transport.isPaymentRequired(response)).toBe(true)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
test('returns false for 200 response', () => {
|
|
36
|
+
const transport = Transport.http()
|
|
37
|
+
const response = new Response(null, { status: 200 })
|
|
38
|
+
|
|
39
|
+
expect(transport.isPaymentRequired(response)).toBe(false)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
test('returns false for other error responses', () => {
|
|
43
|
+
const transport = Transport.http()
|
|
44
|
+
const response = new Response(null, { status: 401 })
|
|
45
|
+
|
|
46
|
+
expect(transport.isPaymentRequired(response)).toBe(false)
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
describe('getChallenge', () => {
|
|
51
|
+
test('default', () => {
|
|
52
|
+
const transport = Transport.http()
|
|
53
|
+
const response = new Response(null, {
|
|
54
|
+
status: 402,
|
|
55
|
+
headers: {
|
|
56
|
+
'WWW-Authenticate': Challenge.serialize(challenge),
|
|
57
|
+
},
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
expect(transport.getChallenge(response)).toMatchInlineSnapshot(`
|
|
61
|
+
{
|
|
62
|
+
"expires": "2025-01-01T00:00:00.000Z",
|
|
63
|
+
"id": "EUAHxZRCSFB29SAs5TEcB4cQDS0uVDzl8uSYuA58aVs",
|
|
64
|
+
"intent": "charge",
|
|
65
|
+
"method": "tempo",
|
|
66
|
+
"realm": "api.example.com",
|
|
67
|
+
"request": {
|
|
68
|
+
"amount": "1000",
|
|
69
|
+
"currency": "0x20c0000000000000000000000000000000000001",
|
|
70
|
+
"expires": "2025-01-01T00:00:00.000Z",
|
|
71
|
+
"recipient": "0x742d35Cc6634C0532925a3b844Bc9e7595f8fE00",
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
`)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
test('throws for non-402 response', () => {
|
|
78
|
+
const transport = Transport.http()
|
|
79
|
+
const response = new Response(null, { status: 200 })
|
|
80
|
+
|
|
81
|
+
expect(() => transport.getChallenge(response)).toThrow()
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
describe('setCredential', () => {
|
|
86
|
+
test('default', () => {
|
|
87
|
+
const transport = Transport.http()
|
|
88
|
+
const serialized = Credential.serialize(credential)
|
|
89
|
+
|
|
90
|
+
const result = transport.setCredential({}, serialized)
|
|
91
|
+
const headers = result.headers as Headers
|
|
92
|
+
|
|
93
|
+
expect(headers.get('Authorization')).toMatchInlineSnapshot(
|
|
94
|
+
`"Payment eyJjaGFsbGVuZ2UiOnsiZXhwaXJlcyI6IjIwMjUtMDEtMDFUMDA6MDA6MDAuMDAwWiIsImlkIjoiRVVBSHhaUkNTRkIyOVNBczVURWNCNGNRRFMwdVZEemw4dVNZdUE1OGFWcyIsImludGVudCI6ImNoYXJnZSIsIm1ldGhvZCI6InRlbXBvIiwicmVhbG0iOiJhcGkuZXhhbXBsZS5jb20iLCJyZXF1ZXN0IjoiZXlKamRYSnlaVzVqZVNJNklqQjRNakJqTURBd01EQXdNREF3TURBd01EQXdNREF3TURBd01EQXdNREF3TURBd01EQXdNREF3TVNJc0ltVjRjR2x5WlhNaU9pSXlNREkxTFRBeExUQXhWREF3T2pBd09qQXdMakF3TUZvaUxDSnlaV05wY0dsbGJuUWlPaUl3ZURjME1tUXpOVU5qTmpZek5FTXdOVE15T1RJMVlUTmlPRFEwUW1NNVpUYzFPVFZtT0daRk1EQWlMQ0poYlc5MWJuUWlPaUl4TURBd0luMCJ9LCJwYXlsb2FkIjp7InNpZ25hdHVyZSI6IjB4YWJjMTIzIiwidHlwZSI6InRyYW5zYWN0aW9uIn19"`,
|
|
95
|
+
)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test('preserves existing headers', () => {
|
|
99
|
+
const transport = Transport.http()
|
|
100
|
+
const serialized = Credential.serialize(credential)
|
|
101
|
+
|
|
102
|
+
const result = transport.setCredential(
|
|
103
|
+
{ headers: { 'Content-Type': 'application/json' } },
|
|
104
|
+
serialized,
|
|
105
|
+
)
|
|
106
|
+
const headers = result.headers as Headers
|
|
107
|
+
|
|
108
|
+
expect(headers.get('Content-Type')).toBe('application/json')
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
describe('mcp', () => {
|
|
114
|
+
const mcpRequest: Mcp.Request = {
|
|
115
|
+
method: 'tools/call',
|
|
116
|
+
params: {
|
|
117
|
+
name: 'test-tool',
|
|
118
|
+
},
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
describe('isPaymentRequired', () => {
|
|
122
|
+
test('returns true for payment required error', () => {
|
|
123
|
+
const transport = Transport.mcp()
|
|
124
|
+
const response: Mcp.Response = {
|
|
125
|
+
jsonrpc: '2.0',
|
|
126
|
+
id: 1,
|
|
127
|
+
error: {
|
|
128
|
+
code: Mcp.paymentRequiredCode,
|
|
129
|
+
message: 'Payment Required',
|
|
130
|
+
data: {
|
|
131
|
+
httpStatus: 402,
|
|
132
|
+
challenges: [challenge],
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
expect(transport.isPaymentRequired(response)).toBe(true)
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
test('returns false for success response', () => {
|
|
141
|
+
const transport = Transport.mcp()
|
|
142
|
+
const response: Mcp.Response = {
|
|
143
|
+
jsonrpc: '2.0',
|
|
144
|
+
id: 1,
|
|
145
|
+
result: { content: [] },
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
expect(transport.isPaymentRequired(response)).toBe(false)
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
test('returns false for other error codes', () => {
|
|
152
|
+
const transport = Transport.mcp()
|
|
153
|
+
const response: Mcp.Response = {
|
|
154
|
+
jsonrpc: '2.0',
|
|
155
|
+
id: 1,
|
|
156
|
+
error: {
|
|
157
|
+
code: -32600,
|
|
158
|
+
message: 'Invalid Request',
|
|
159
|
+
},
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
expect(transport.isPaymentRequired(response)).toBe(false)
|
|
163
|
+
})
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
describe('getChallenge', () => {
|
|
167
|
+
test('default', () => {
|
|
168
|
+
const transport = Transport.mcp()
|
|
169
|
+
const response: Mcp.Response = {
|
|
170
|
+
jsonrpc: '2.0',
|
|
171
|
+
id: 1,
|
|
172
|
+
error: {
|
|
173
|
+
code: Mcp.paymentRequiredCode,
|
|
174
|
+
message: 'Payment Required',
|
|
175
|
+
data: {
|
|
176
|
+
httpStatus: 402,
|
|
177
|
+
challenges: [challenge],
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
expect(transport.getChallenge(response)).toMatchInlineSnapshot(`
|
|
183
|
+
{
|
|
184
|
+
"expires": "2025-01-01T00:00:00.000Z",
|
|
185
|
+
"id": "EUAHxZRCSFB29SAs5TEcB4cQDS0uVDzl8uSYuA58aVs",
|
|
186
|
+
"intent": "charge",
|
|
187
|
+
"method": "tempo",
|
|
188
|
+
"realm": "api.example.com",
|
|
189
|
+
"request": {
|
|
190
|
+
"amount": "1000",
|
|
191
|
+
"currency": "0x20c0000000000000000000000000000000000001",
|
|
192
|
+
"expires": "2025-01-01T00:00:00.000Z",
|
|
193
|
+
"recipient": "0x742d35Cc6634C0532925a3b844Bc9e7595f8fE00",
|
|
194
|
+
},
|
|
195
|
+
}
|
|
196
|
+
`)
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
test('throws for success response', () => {
|
|
200
|
+
const transport = Transport.mcp()
|
|
201
|
+
const response: Mcp.Response = {
|
|
202
|
+
jsonrpc: '2.0',
|
|
203
|
+
id: 1,
|
|
204
|
+
result: { content: [] },
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
expect(() => transport.getChallenge(response)).toThrow('Response is not an error')
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
test('throws when no challenges in error', () => {
|
|
211
|
+
const transport = Transport.mcp()
|
|
212
|
+
const response: Mcp.Response = {
|
|
213
|
+
jsonrpc: '2.0',
|
|
214
|
+
id: 1,
|
|
215
|
+
error: {
|
|
216
|
+
code: Mcp.paymentRequiredCode,
|
|
217
|
+
message: 'Payment Required',
|
|
218
|
+
data: {
|
|
219
|
+
httpStatus: 402,
|
|
220
|
+
challenges: [],
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
expect(() => transport.getChallenge(response)).toThrow('No challenge in error response')
|
|
226
|
+
})
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
describe('setCredential', () => {
|
|
230
|
+
test('default', () => {
|
|
231
|
+
const transport = Transport.mcp()
|
|
232
|
+
const serialized = Credential.serialize(credential)
|
|
233
|
+
|
|
234
|
+
expect(transport.setCredential(mcpRequest, serialized)).toMatchInlineSnapshot(`
|
|
235
|
+
{
|
|
236
|
+
"method": "tools/call",
|
|
237
|
+
"params": {
|
|
238
|
+
"_meta": {
|
|
239
|
+
"org.paymentauth/credential": {
|
|
240
|
+
"challenge": {
|
|
241
|
+
"expires": "2025-01-01T00:00:00.000Z",
|
|
242
|
+
"id": "EUAHxZRCSFB29SAs5TEcB4cQDS0uVDzl8uSYuA58aVs",
|
|
243
|
+
"intent": "charge",
|
|
244
|
+
"method": "tempo",
|
|
245
|
+
"realm": "api.example.com",
|
|
246
|
+
"request": {
|
|
247
|
+
"amount": "1000",
|
|
248
|
+
"currency": "0x20c0000000000000000000000000000000000001",
|
|
249
|
+
"expires": "2025-01-01T00:00:00.000Z",
|
|
250
|
+
"recipient": "0x742d35Cc6634C0532925a3b844Bc9e7595f8fE00",
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
"payload": {
|
|
254
|
+
"signature": "0xabc123",
|
|
255
|
+
"type": "transaction",
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
"name": "test-tool",
|
|
260
|
+
},
|
|
261
|
+
}
|
|
262
|
+
`)
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
test('preserves existing _meta', () => {
|
|
266
|
+
const transport = Transport.mcp()
|
|
267
|
+
const serialized = Credential.serialize(credential)
|
|
268
|
+
const requestWithMeta: Mcp.Request = {
|
|
269
|
+
...mcpRequest,
|
|
270
|
+
params: {
|
|
271
|
+
...mcpRequest.params,
|
|
272
|
+
_meta: {
|
|
273
|
+
existingKey: 'existingValue',
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const result = transport.setCredential(requestWithMeta, serialized)
|
|
279
|
+
|
|
280
|
+
expect(result.params?._meta?.existingKey).toBe('existingValue')
|
|
281
|
+
})
|
|
282
|
+
})
|
|
283
|
+
})
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import * as Challenge from '../Challenge.js'
|
|
2
|
+
import * as Credential from '../Credential.js'
|
|
3
|
+
import * as Mcp from '../Mcp.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Client-side transport adapter.
|
|
7
|
+
*
|
|
8
|
+
* Abstracts how challenges are received and credentials are sent
|
|
9
|
+
* across different transport protocols (HTTP, MCP, etc.).
|
|
10
|
+
*/
|
|
11
|
+
export type Transport<in out request = unknown, in out response = unknown> = {
|
|
12
|
+
/** Transport name for identification. */
|
|
13
|
+
name: string
|
|
14
|
+
/** Checks if a response indicates payment is required. */
|
|
15
|
+
isPaymentRequired: (response: response) => boolean
|
|
16
|
+
/** Extracts the challenge from a payment-required response. */
|
|
17
|
+
getChallenge: (response: response) => Challenge.Challenge
|
|
18
|
+
/** Attaches a credential to a request. */
|
|
19
|
+
setCredential: (request: request, credential: string) => request
|
|
20
|
+
}
|
|
21
|
+
export type AnyTransport = Transport<any, any>
|
|
22
|
+
|
|
23
|
+
/** Extracts the response type from a transport. */
|
|
24
|
+
export type ResponseOf<transport extends Transport> =
|
|
25
|
+
transport extends Transport<any, infer response> ? response : never
|
|
26
|
+
|
|
27
|
+
/** Extracts the request type from a transport. */
|
|
28
|
+
export type RequestOf<transport extends Transport> =
|
|
29
|
+
transport extends Transport<infer request, any> ? request : never
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Creates a custom client-side transport.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* import { Transport } from 'mppx/client'
|
|
37
|
+
*
|
|
38
|
+
* const custom = Transport.from({
|
|
39
|
+
* name: 'custom',
|
|
40
|
+
* isPaymentRequired(response) { ... },
|
|
41
|
+
* getChallenge(response) { ... },
|
|
42
|
+
* setCredential(request, credential) { ... },
|
|
43
|
+
* })
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function from<request, response>(
|
|
47
|
+
transport: Transport<request, response>,
|
|
48
|
+
): Transport<request, response> {
|
|
49
|
+
return transport
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* HTTP transport for client-side payment handling.
|
|
54
|
+
*
|
|
55
|
+
* - Detects payment required via 402 status
|
|
56
|
+
* - Extracts challenges from `WWW-Authenticate` header
|
|
57
|
+
* - Sends credentials via `Authorization` header
|
|
58
|
+
*/
|
|
59
|
+
export function http() {
|
|
60
|
+
return from<RequestInit, Response>({
|
|
61
|
+
name: 'http',
|
|
62
|
+
|
|
63
|
+
isPaymentRequired(response) {
|
|
64
|
+
return response.status === 402
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
getChallenge(response) {
|
|
68
|
+
return Challenge.fromResponse(response)
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
setCredential(request, credential) {
|
|
72
|
+
const headers = new Headers(request.headers)
|
|
73
|
+
headers.set('Authorization', credential)
|
|
74
|
+
return { ...request, headers }
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* MCP transport for client-side payment handling.
|
|
81
|
+
*
|
|
82
|
+
* - Detects payment required via error code -32042
|
|
83
|
+
* - Extracts challenges from `error.data.challenges[0]`
|
|
84
|
+
* - Sends credentials via `_meta["org.paymentauth/credential"]`
|
|
85
|
+
*/
|
|
86
|
+
export function mcp() {
|
|
87
|
+
return from<Mcp.Request, Mcp.Response>({
|
|
88
|
+
name: 'mcp',
|
|
89
|
+
|
|
90
|
+
isPaymentRequired(response) {
|
|
91
|
+
return 'error' in response && response.error?.code === Mcp.paymentRequiredCode
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
getChallenge(response) {
|
|
95
|
+
if (!('error' in response) || !response.error) throw new Error('Response is not an error.')
|
|
96
|
+
const challenge = response.error.data?.challenges[0]
|
|
97
|
+
if (!challenge) throw new Error('No challenge in error response.')
|
|
98
|
+
return challenge
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
setCredential(request, credential) {
|
|
102
|
+
const parsed = Credential.deserialize(credential)
|
|
103
|
+
return {
|
|
104
|
+
...request,
|
|
105
|
+
params: {
|
|
106
|
+
...request.params,
|
|
107
|
+
_meta: {
|
|
108
|
+
...request.params?._meta,
|
|
109
|
+
[Mcp.credentialMetaKey]: parsed,
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
})
|
|
115
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Account } from 'viem'
|
|
2
|
+
import { describe, expectTypeOf, test } from 'vitest'
|
|
3
|
+
import { charge } from '../../tempo/client/Charge.js'
|
|
4
|
+
import * as Fetch from './Fetch.js'
|
|
5
|
+
|
|
6
|
+
describe('Fetch.from', () => {
|
|
7
|
+
test('default', () => {
|
|
8
|
+
const fetch = Fetch.from({
|
|
9
|
+
methods: [charge()],
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
expectTypeOf(fetch).toBeFunction()
|
|
13
|
+
expectTypeOf(fetch).returns.toMatchTypeOf<Promise<Response>>()
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test('behavior: accepts context in RequestInit when method has context', () => {
|
|
17
|
+
const fetch = Fetch.from({
|
|
18
|
+
methods: [charge()],
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
expectTypeOf(fetch).toBeCallableWith('https://example.com', {
|
|
22
|
+
context: { account: {} as Account },
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('behavior: context is optional in RequestInit', () => {
|
|
27
|
+
const fetch = Fetch.from({
|
|
28
|
+
methods: [charge()],
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
expectTypeOf(fetch).toBeCallableWith('https://example.com')
|
|
32
|
+
expectTypeOf(fetch).toBeCallableWith('https://example.com', {})
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
test('behavior: RequestInit extends standard RequestInit', () => {
|
|
36
|
+
const fetch = Fetch.from({
|
|
37
|
+
methods: [charge()],
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
expectTypeOf(fetch).toBeCallableWith('https://example.com', {
|
|
41
|
+
method: 'POST',
|
|
42
|
+
headers: { 'Content-Type': 'application/json' },
|
|
43
|
+
body: JSON.stringify({ foo: 'bar' }),
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
describe('Fetch.from.RequestInit', () => {
|
|
49
|
+
test('behavior: has context property typed to method context', () => {
|
|
50
|
+
const method = charge()
|
|
51
|
+
|
|
52
|
+
type Methods = [typeof method]
|
|
53
|
+
type Init = Fetch.from.RequestInit<Methods>
|
|
54
|
+
|
|
55
|
+
expectTypeOf<Init>().toHaveProperty('context')
|
|
56
|
+
})
|
|
57
|
+
})
|