mppx 0.6.30 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/dist/Challenge.d.ts.map +1 -1
- package/dist/Challenge.js +9 -7
- package/dist/Challenge.js.map +1 -1
- package/dist/Constants.d.ts +46 -0
- package/dist/Constants.d.ts.map +1 -0
- package/dist/Constants.js +46 -0
- package/dist/Constants.js.map +1 -0
- package/dist/Credential.d.ts.map +1 -1
- package/dist/Credential.js +5 -4
- package/dist/Credential.js.map +1 -1
- package/dist/Method.d.ts +32 -4
- package/dist/Method.d.ts.map +1 -1
- package/dist/Method.js +5 -2
- package/dist/Method.js.map +1 -1
- package/dist/Receipt.d.ts.map +1 -1
- package/dist/Receipt.js +3 -2
- package/dist/Receipt.js.map +1 -1
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +19 -11
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/plugins/tempo.d.ts.map +1 -1
- package/dist/cli/plugins/tempo.js +17 -6
- package/dist/cli/plugins/tempo.js.map +1 -1
- package/dist/cli/utils.d.ts +5 -0
- package/dist/cli/utils.d.ts.map +1 -1
- package/dist/cli/utils.js +10 -0
- package/dist/cli/utils.js.map +1 -1
- package/dist/client/Methods.d.ts +5 -2
- package/dist/client/Methods.d.ts.map +1 -1
- package/dist/client/Methods.js +5 -2
- package/dist/client/Methods.js.map +1 -1
- package/dist/client/Transport.d.ts.map +1 -1
- package/dist/client/Transport.js +4 -5
- package/dist/client/Transport.js.map +1 -1
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal/Fetch.d.ts.map +1 -1
- package/dist/client/internal/Fetch.js +14 -6
- package/dist/client/internal/Fetch.js.map +1 -1
- package/dist/evm/server/Methods.d.ts +1 -1
- package/dist/evm/server/Methods.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/AcceptPayment.d.ts +3 -0
- package/dist/internal/AcceptPayment.d.ts.map +1 -1
- package/dist/internal/AcceptPayment.js +15 -11
- package/dist/internal/AcceptPayment.js.map +1 -1
- package/dist/mcp-sdk/client/McpClient.d.ts +12 -5
- package/dist/mcp-sdk/client/McpClient.d.ts.map +1 -1
- package/dist/mcp-sdk/client/McpClient.js +55 -42
- package/dist/mcp-sdk/client/McpClient.js.map +1 -1
- package/dist/server/Mppx.d.ts +11 -3
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +76 -27
- package/dist/server/Mppx.js.map +1 -1
- package/dist/server/Request.js +24 -10
- package/dist/server/Request.js.map +1 -1
- package/dist/server/Response.d.ts.map +1 -1
- package/dist/server/Response.js +2 -1
- package/dist/server/Response.js.map +1 -1
- package/dist/server/Transport.d.ts.map +1 -1
- package/dist/server/Transport.js +4 -3
- package/dist/server/Transport.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/stripe/client/Charge.d.ts +1 -1
- package/dist/stripe/client/Charge.d.ts.map +1 -1
- package/dist/stripe/client/Charge.js +3 -1
- package/dist/stripe/client/Charge.js.map +1 -1
- package/dist/stripe/server/Charge.d.ts +1 -1
- package/dist/stripe/server/Charge.d.ts.map +1 -1
- package/dist/stripe/server/Charge.js +9 -2
- package/dist/stripe/server/Charge.js.map +1 -1
- package/dist/stripe/server/Methods.d.ts +1 -1
- package/dist/stripe/server/Methods.d.ts.map +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
- package/dist/stripe/server/internal/html.gen.js +1 -1
- package/dist/stripe/server/internal/html.gen.js.map +1 -1
- package/dist/tempo/Methods.d.ts +18 -0
- package/dist/tempo/Methods.d.ts.map +1 -1
- package/dist/tempo/Methods.js +16 -1
- package/dist/tempo/Methods.js.map +1 -1
- package/dist/tempo/client/Charge.d.ts +6 -0
- package/dist/tempo/client/Charge.d.ts.map +1 -1
- package/dist/tempo/client/Charge.js +9 -2
- package/dist/tempo/client/Charge.js.map +1 -1
- package/dist/tempo/client/Methods.d.ts +36 -7
- package/dist/tempo/client/Methods.d.ts.map +1 -1
- package/dist/tempo/client/Methods.js +12 -5
- package/dist/tempo/client/Methods.js.map +1 -1
- package/dist/tempo/client/index.d.ts +7 -4
- package/dist/tempo/client/index.d.ts.map +1 -1
- package/dist/tempo/client/index.js +5 -3
- package/dist/tempo/client/index.js.map +1 -1
- package/dist/tempo/index.d.ts +1 -0
- package/dist/tempo/index.d.ts.map +1 -1
- package/dist/tempo/index.js +1 -0
- package/dist/tempo/index.js.map +1 -1
- package/dist/tempo/internal/fee-payer.d.ts +21 -1
- package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
- package/dist/tempo/internal/fee-payer.js +109 -4
- package/dist/tempo/internal/fee-payer.js.map +1 -1
- package/dist/tempo/{client → legacy/client}/ChannelOps.d.ts +19 -6
- package/dist/tempo/legacy/client/ChannelOps.d.ts.map +1 -0
- package/dist/tempo/{client → legacy/client}/ChannelOps.js +9 -3
- package/dist/tempo/legacy/client/ChannelOps.js.map +1 -0
- package/dist/tempo/{client → legacy/client}/Session.d.ts +23 -4
- package/dist/tempo/legacy/client/Session.d.ts.map +1 -0
- package/dist/tempo/{client → legacy/client}/Session.js +14 -7
- package/dist/tempo/legacy/client/Session.js.map +1 -0
- package/dist/tempo/{client → legacy/client}/SessionManager.d.ts +20 -5
- package/dist/tempo/legacy/client/SessionManager.d.ts.map +1 -0
- package/dist/tempo/{client → legacy/client}/SessionManager.js +20 -16
- package/dist/tempo/legacy/client/SessionManager.js.map +1 -0
- package/dist/tempo/legacy/client/index.d.ts +7 -0
- package/dist/tempo/legacy/client/index.d.ts.map +1 -0
- package/dist/tempo/legacy/client/index.js +5 -0
- package/dist/tempo/legacy/client/index.js.map +1 -0
- package/dist/tempo/legacy/index.d.ts +7 -0
- package/dist/tempo/legacy/index.d.ts.map +1 -0
- package/dist/tempo/legacy/index.js +7 -0
- package/dist/tempo/legacy/index.js.map +1 -0
- package/dist/tempo/{server → legacy/server}/Session.d.ts +28 -11
- package/dist/tempo/legacy/server/Session.d.ts.map +1 -0
- package/dist/tempo/{server → legacy/server}/Session.js +28 -23
- package/dist/tempo/legacy/server/Session.js.map +1 -0
- package/dist/tempo/legacy/server/index.d.ts +5 -0
- package/dist/tempo/legacy/server/index.d.ts.map +1 -0
- package/dist/tempo/legacy/server/index.js +5 -0
- package/dist/tempo/legacy/server/index.js.map +1 -0
- package/dist/tempo/{session → legacy/session}/Chain.d.ts +30 -23
- package/dist/tempo/legacy/session/Chain.d.ts.map +1 -0
- package/dist/tempo/{session → legacy/session}/Chain.js +12 -11
- package/dist/tempo/legacy/session/Chain.js.map +1 -0
- package/dist/tempo/{session → legacy/session}/Channel.d.ts +1 -0
- package/dist/tempo/legacy/session/Channel.d.ts.map +1 -0
- package/dist/tempo/legacy/session/Channel.js.map +1 -0
- package/dist/tempo/legacy/session/ChannelStore.d.ts +22 -0
- package/dist/tempo/legacy/session/ChannelStore.d.ts.map +1 -0
- package/dist/tempo/legacy/session/ChannelStore.js +6 -0
- package/dist/tempo/legacy/session/ChannelStore.js.map +1 -0
- package/dist/tempo/legacy/session/Types.d.ts +73 -0
- package/dist/tempo/legacy/session/Types.d.ts.map +1 -0
- package/dist/tempo/legacy/session/Types.js.map +1 -0
- package/dist/tempo/{session → legacy/session}/Voucher.d.ts +4 -4
- package/dist/tempo/legacy/session/Voucher.d.ts.map +1 -0
- package/dist/tempo/{session → legacy/session}/Voucher.js +1 -1
- package/dist/tempo/legacy/session/Voucher.js.map +1 -0
- package/dist/tempo/{session → legacy/session}/escrow.abi.d.ts +1 -0
- package/dist/tempo/{session → legacy/session}/escrow.abi.d.ts.map +1 -1
- package/dist/tempo/{session → legacy/session}/escrow.abi.js +1 -0
- package/dist/tempo/legacy/session/escrow.abi.js.map +1 -0
- package/dist/tempo/legacy/session/index.d.ts +9 -0
- package/dist/tempo/legacy/session/index.d.ts.map +1 -0
- package/dist/tempo/legacy/session/index.js +9 -0
- package/dist/tempo/legacy/session/index.js.map +1 -0
- package/dist/tempo/server/Charge.d.ts +1 -1
- package/dist/tempo/server/Charge.d.ts.map +1 -1
- package/dist/tempo/server/Charge.js +13 -16
- package/dist/tempo/server/Charge.js.map +1 -1
- package/dist/tempo/server/Methods.d.ts +63 -6
- package/dist/tempo/server/Methods.d.ts.map +1 -1
- package/dist/tempo/server/Methods.js +36 -8
- package/dist/tempo/server/Methods.js.map +1 -1
- package/dist/tempo/server/Subscription.d.ts +1 -1
- package/dist/tempo/server/Subscription.d.ts.map +1 -1
- package/dist/tempo/server/index.d.ts +6 -5
- package/dist/tempo/server/index.d.ts.map +1 -1
- package/dist/tempo/server/index.js +5 -5
- package/dist/tempo/server/index.js.map +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
- package/dist/tempo/server/internal/html.gen.js +1 -1
- package/dist/tempo/server/internal/html.gen.js.map +1 -1
- package/dist/tempo/server/internal/request-body.d.ts +7 -2
- package/dist/tempo/server/internal/request-body.d.ts.map +1 -1
- package/dist/tempo/server/internal/request-body.js +20 -3
- package/dist/tempo/server/internal/request-body.js.map +1 -1
- package/dist/tempo/server/internal/transport.d.ts +8 -4
- package/dist/tempo/server/internal/transport.d.ts.map +1 -1
- package/dist/tempo/server/internal/transport.js +8 -7
- package/dist/tempo/server/internal/transport.js.map +1 -1
- package/dist/tempo/session/Snapshot.d.ts +32 -0
- package/dist/tempo/session/Snapshot.d.ts.map +1 -0
- package/dist/tempo/session/Snapshot.js +37 -0
- package/dist/tempo/session/Snapshot.js.map +1 -0
- package/dist/tempo/session/client/ChannelOps.d.ts +82 -0
- package/dist/tempo/session/client/ChannelOps.d.ts.map +1 -0
- package/dist/tempo/session/client/ChannelOps.js +204 -0
- package/dist/tempo/session/client/ChannelOps.js.map +1 -0
- package/dist/tempo/session/client/CredentialState.d.ts +262 -0
- package/dist/tempo/session/client/CredentialState.d.ts.map +1 -0
- package/dist/tempo/session/client/CredentialState.js +417 -0
- package/dist/tempo/session/client/CredentialState.js.map +1 -0
- package/dist/tempo/session/client/ReceiptCoordinator.d.ts +26 -0
- package/dist/tempo/session/client/ReceiptCoordinator.d.ts.map +1 -0
- package/dist/tempo/session/client/ReceiptCoordinator.js +61 -0
- package/dist/tempo/session/client/ReceiptCoordinator.js.map +1 -0
- package/dist/tempo/session/client/Runtime.d.ts +464 -0
- package/dist/tempo/session/client/Runtime.d.ts.map +1 -0
- package/dist/tempo/session/client/Runtime.js +499 -0
- package/dist/tempo/session/client/Runtime.js.map +1 -0
- package/dist/tempo/session/client/Session.d.ts +132 -0
- package/dist/tempo/session/client/Session.d.ts.map +1 -0
- package/dist/tempo/session/client/Session.js +55 -0
- package/dist/tempo/session/client/Session.js.map +1 -0
- package/dist/tempo/session/client/SessionManager.d.ts +120 -0
- package/dist/tempo/session/client/SessionManager.d.ts.map +1 -0
- package/dist/tempo/session/client/SessionManager.js +627 -0
- package/dist/tempo/session/client/SessionManager.js.map +1 -0
- package/dist/tempo/session/client/Transports.d.ts +449 -0
- package/dist/tempo/session/client/Transports.d.ts.map +1 -0
- package/dist/tempo/session/client/Transports.js +721 -0
- package/dist/tempo/session/client/Transports.js.map +1 -0
- package/dist/tempo/session/client/index.d.ts +12 -0
- package/dist/tempo/session/client/index.d.ts.map +1 -0
- package/dist/tempo/session/client/index.js +5 -0
- package/dist/tempo/session/client/index.js.map +1 -0
- package/dist/tempo/session/index.d.ts +7 -8
- package/dist/tempo/session/index.d.ts.map +1 -1
- package/dist/tempo/session/index.js +7 -8
- package/dist/tempo/session/index.js.map +1 -1
- package/dist/tempo/session/precompile/Chain.d.ts +319 -0
- package/dist/tempo/session/precompile/Chain.d.ts.map +1 -0
- package/dist/tempo/session/precompile/Chain.js +492 -0
- package/dist/tempo/session/precompile/Chain.js.map +1 -0
- package/dist/tempo/session/precompile/Channel.d.ts +46 -0
- package/dist/tempo/session/precompile/Channel.d.ts.map +1 -0
- package/dist/tempo/session/precompile/Channel.js +56 -0
- package/dist/tempo/session/precompile/Channel.js.map +1 -0
- package/dist/tempo/session/precompile/Protocol.d.ts +308 -0
- package/dist/tempo/session/precompile/Protocol.d.ts.map +1 -0
- package/dist/tempo/session/precompile/Protocol.js +264 -0
- package/dist/tempo/session/precompile/Protocol.js.map +1 -0
- package/dist/tempo/session/precompile/Voucher.d.ts +40 -0
- package/dist/tempo/session/precompile/Voucher.d.ts.map +1 -0
- package/dist/tempo/session/precompile/Voucher.js +126 -0
- package/dist/tempo/session/precompile/Voucher.js.map +1 -0
- package/dist/tempo/session/precompile/escrow.abi.d.ts +522 -0
- package/dist/tempo/session/precompile/escrow.abi.d.ts.map +1 -0
- package/dist/tempo/session/precompile/escrow.abi.js +224 -0
- package/dist/tempo/session/precompile/escrow.abi.js.map +1 -0
- package/dist/tempo/session/precompile/index.d.ts +24 -0
- package/dist/tempo/session/precompile/index.d.ts.map +1 -0
- package/dist/tempo/session/precompile/index.js +22 -0
- package/dist/tempo/session/precompile/index.js.map +1 -0
- package/dist/tempo/session/server/ChannelOps.d.ts +56 -0
- package/dist/tempo/session/server/ChannelOps.d.ts.map +1 -0
- package/dist/tempo/session/server/ChannelOps.js +91 -0
- package/dist/tempo/session/server/ChannelOps.js.map +1 -0
- package/dist/tempo/session/server/ChannelStore.d.ts +347 -0
- package/dist/tempo/session/server/ChannelStore.d.ts.map +1 -0
- package/dist/tempo/session/server/ChannelStore.js +404 -0
- package/dist/tempo/session/server/ChannelStore.js.map +1 -0
- package/dist/tempo/session/server/CredentialVerification.d.ts +85 -0
- package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -0
- package/dist/tempo/session/server/CredentialVerification.js +494 -0
- package/dist/tempo/session/server/CredentialVerification.js.map +1 -0
- package/dist/tempo/session/server/MeteredStream.d.ts +40 -0
- package/dist/tempo/session/server/MeteredStream.d.ts.map +1 -0
- package/dist/tempo/session/server/MeteredStream.js +42 -0
- package/dist/tempo/session/server/MeteredStream.js.map +1 -0
- package/dist/tempo/session/server/RequestState.d.ts +208 -0
- package/dist/tempo/session/server/RequestState.d.ts.map +1 -0
- package/dist/tempo/session/server/RequestState.js +252 -0
- package/dist/tempo/session/server/RequestState.js.map +1 -0
- package/dist/tempo/session/server/Session.d.ts +169 -0
- package/dist/tempo/session/server/Session.d.ts.map +1 -0
- package/dist/tempo/session/server/Session.js +351 -0
- package/dist/tempo/session/server/Session.js.map +1 -0
- package/dist/tempo/session/server/Settlement.d.ts +185 -0
- package/dist/tempo/session/server/Settlement.d.ts.map +1 -0
- package/dist/tempo/session/server/Settlement.js +250 -0
- package/dist/tempo/session/server/Settlement.js.map +1 -0
- package/dist/tempo/session/{Sse.d.ts → server/Sse.d.ts} +9 -56
- package/dist/tempo/session/server/Sse.d.ts.map +1 -0
- package/dist/tempo/session/server/Sse.js +184 -0
- package/dist/tempo/session/server/Sse.js.map +1 -0
- package/dist/tempo/session/server/Transports.d.ts +89 -0
- package/dist/tempo/session/server/Transports.d.ts.map +1 -0
- package/dist/tempo/session/server/Transports.js +149 -0
- package/dist/tempo/session/server/Transports.js.map +1 -0
- package/dist/tempo/session/server/Ws.d.ts +48 -0
- package/dist/tempo/session/server/Ws.d.ts.map +1 -0
- package/dist/tempo/session/server/Ws.js +244 -0
- package/dist/tempo/session/server/Ws.js.map +1 -0
- package/dist/tempo/session/server/index.d.ts +4 -0
- package/dist/tempo/session/server/index.d.ts.map +1 -0
- package/dist/tempo/session/server/index.js +2 -0
- package/dist/tempo/session/server/index.js.map +1 -0
- package/package.json +8 -3
- package/src/Challenge.ts +9 -7
- package/src/Constants.ts +58 -0
- package/src/Credential.ts +5 -4
- package/src/Method.ts +46 -5
- package/src/Receipt.ts +3 -2
- package/src/cli/cli.test.ts +23 -28
- package/src/cli/cli.ts +23 -10
- package/src/cli/mcp.test.ts +21 -7
- package/src/cli/plugins/tempo.ts +21 -8
- package/src/cli/utils.test.ts +25 -1
- package/src/cli/utils.ts +10 -0
- package/src/client/Methods.ts +5 -2
- package/src/client/Mppx.test-d.ts +10 -0
- package/src/client/Mppx.test.ts +75 -0
- package/src/client/Transport.ts +4 -5
- package/src/client/index.ts +11 -1
- package/src/client/internal/Fetch.test.ts +29 -4
- package/src/client/internal/Fetch.ts +17 -5
- package/src/env.d.ts +1 -1
- package/src/index.ts +1 -0
- package/src/internal/AcceptPayment.test.ts +61 -0
- package/src/internal/AcceptPayment.ts +21 -14
- package/src/mcp-sdk/client/McpClient.integration.test.ts +8 -7
- package/src/mcp-sdk/client/McpClient.test-d.ts +7 -0
- package/src/mcp-sdk/client/McpClient.ts +99 -67
- package/src/mcp-sdk/client/McpClient.unit.test.ts +131 -0
- package/src/middlewares/elysia.test.ts +8 -4
- package/src/middlewares/express.test.ts +8 -4
- package/src/middlewares/hono.test.ts +4 -4
- package/src/middlewares/nextjs.test.ts +8 -4
- package/src/proxy/Proxy.test.ts +8 -8
- package/src/server/Mppx.test-d.ts +54 -0
- package/src/server/Mppx.test.ts +274 -7
- package/src/server/Mppx.ts +487 -406
- package/src/server/Request.test.ts +81 -0
- package/src/server/Request.ts +23 -9
- package/src/server/Response.ts +2 -1
- package/src/server/Transport.ts +4 -3
- package/src/server/index.ts +1 -0
- package/src/stripe/client/Charge.test.ts +20 -5
- package/src/stripe/client/Charge.ts +6 -2
- package/src/stripe/server/Charge.test.ts +114 -1
- package/src/stripe/server/Charge.ts +13 -2
- package/src/stripe/server/internal/html/package.json +1 -1
- package/src/stripe/server/internal/html.gen.ts +1 -1
- package/src/tempo/AccessKeyAuthorization.test.ts +4 -94
- package/src/tempo/Methods.test.ts +45 -17
- package/src/tempo/Methods.ts +22 -0
- package/src/tempo/PublicExports.test-d.ts +105 -0
- package/src/tempo/client/Charge.test.ts +85 -0
- package/src/tempo/client/Charge.ts +19 -2
- package/src/tempo/client/Methods.ts +18 -6
- package/src/tempo/client/index.ts +15 -4
- package/src/tempo/index.ts +1 -0
- package/src/tempo/internal/fee-payer.test.ts +241 -17
- package/src/tempo/internal/fee-payer.ts +150 -4
- package/src/tempo/internal/fee-token.test.ts +14 -9
- package/src/tempo/legacy/AccessKeyAuthorization.test.ts +162 -0
- package/src/tempo/legacy/README.md +9 -0
- package/src/tempo/{client → legacy/client}/ChannelOps.test.ts +6 -7
- package/src/tempo/{client → legacy/client}/ChannelOps.ts +22 -9
- package/src/tempo/{client → legacy/client}/Session.test.ts +51 -9
- package/src/tempo/{client → legacy/client}/Session.ts +25 -11
- package/src/tempo/{client → legacy/client}/SessionManager.test.ts +81 -9
- package/src/tempo/{client → legacy/client}/SessionManager.ts +41 -20
- package/src/tempo/legacy/client/index.ts +6 -0
- package/src/tempo/legacy/index.ts +6 -0
- package/src/tempo/{server → legacy/server}/Session.test.ts +162 -63
- package/src/tempo/{server → legacy/server}/Session.ts +49 -37
- package/src/tempo/legacy/server/index.ts +4 -0
- package/src/tempo/{session → legacy/session}/Chain.test.ts +3 -4
- package/src/tempo/{session → legacy/session}/Chain.ts +94 -63
- package/src/tempo/{session → legacy/session}/Channel.ts +1 -0
- package/src/tempo/legacy/session/ChannelStore.test.ts +58 -0
- package/src/tempo/legacy/session/ChannelStore.ts +39 -0
- package/src/tempo/legacy/session/Types.ts +91 -0
- package/src/tempo/{session → legacy/session}/Voucher.ts +12 -8
- package/src/tempo/{session → legacy/session}/escrow.abi.ts +1 -0
- package/src/tempo/legacy/session/index.ts +8 -0
- package/src/tempo/server/AtomicStore.test-d.ts +16 -11
- package/src/tempo/server/Charge.test.ts +92 -14
- package/src/tempo/server/Charge.ts +18 -16
- package/src/tempo/server/Methods.ts +54 -8
- package/src/tempo/server/Sse.test.ts +2 -2
- package/src/tempo/server/index.ts +6 -5
- package/src/tempo/server/internal/html/package.json +1 -1
- package/src/tempo/server/internal/html.gen.ts +1 -1
- package/src/tempo/server/internal/request-body.test.ts +37 -4
- package/src/tempo/server/internal/request-body.ts +25 -6
- package/src/tempo/server/internal/transport.test.ts +4 -4
- package/src/tempo/server/internal/transport.ts +19 -10
- package/src/tempo/session/Snapshot.test.ts +41 -0
- package/src/tempo/session/Snapshot.ts +74 -0
- package/src/tempo/session/client/ChannelOps.test.ts +163 -0
- package/src/tempo/session/client/ChannelOps.ts +344 -0
- package/src/tempo/session/client/CredentialState.test.ts +645 -0
- package/src/tempo/session/client/CredentialState.ts +814 -0
- package/src/tempo/session/client/ReceiptCoordinator.ts +95 -0
- package/src/tempo/session/client/Runtime.test.ts +1092 -0
- package/src/tempo/session/client/Runtime.ts +986 -0
- package/src/tempo/session/client/Session.test.ts +734 -0
- package/src/tempo/session/client/Session.ts +97 -0
- package/src/tempo/session/client/SessionManager.test.ts +1308 -0
- package/src/tempo/session/client/SessionManager.ts +845 -0
- package/src/tempo/session/client/Transports.test.ts +837 -0
- package/src/tempo/session/client/Transports.ts +1292 -0
- package/src/tempo/session/client/index.ts +37 -0
- package/src/tempo/session/index.ts +7 -8
- package/src/tempo/session/precompile/Chain.integration.test.ts +321 -0
- package/src/tempo/session/precompile/Chain.test.ts +1258 -0
- package/src/tempo/session/precompile/Chain.ts +979 -0
- package/src/tempo/session/precompile/Channel.test.ts +138 -0
- package/src/tempo/session/precompile/Channel.ts +103 -0
- package/src/tempo/session/precompile/Protocol.test.ts +358 -0
- package/src/tempo/session/precompile/Protocol.ts +520 -0
- package/src/tempo/session/precompile/Voucher.test.ts +316 -0
- package/src/tempo/session/precompile/Voucher.ts +160 -0
- package/src/tempo/session/precompile/escrow.abi.ts +226 -0
- package/src/tempo/session/precompile/index.ts +33 -0
- package/src/tempo/session/server/ChannelOps.test.ts +129 -0
- package/src/tempo/session/server/ChannelOps.ts +157 -0
- package/src/tempo/session/{ChannelStore.test.ts → server/ChannelStore.test.ts} +536 -29
- package/src/tempo/session/server/ChannelStore.ts +835 -0
- package/src/tempo/session/server/CredentialVerification.test.ts +146 -0
- package/src/tempo/session/server/CredentialVerification.ts +710 -0
- package/src/tempo/session/server/MeteredStream.ts +88 -0
- package/src/tempo/session/server/RequestState.test.ts +531 -0
- package/src/tempo/session/server/RequestState.ts +499 -0
- package/src/tempo/session/server/Session.integration.test.ts +444 -0
- package/src/tempo/session/server/Session.test.ts +3253 -0
- package/src/tempo/session/server/Session.ts +543 -0
- package/src/tempo/session/server/Settlement.test.ts +242 -0
- package/src/tempo/session/server/Settlement.ts +470 -0
- package/src/tempo/session/{Sse.test.ts → server/Sse.test.ts} +37 -3
- package/src/tempo/session/server/Sse.ts +256 -0
- package/src/tempo/session/server/Transports.test.ts +346 -0
- package/src/tempo/session/server/Transports.ts +255 -0
- package/src/tempo/session/{Ws.test.ts → server/Ws.test.ts} +4 -4
- package/src/tempo/session/server/Ws.ts +384 -0
- package/src/tempo/session/server/index.ts +8 -0
- package/dist/tempo/client/ChannelOps.d.ts.map +0 -1
- package/dist/tempo/client/ChannelOps.js.map +0 -1
- package/dist/tempo/client/Session.d.ts.map +0 -1
- package/dist/tempo/client/Session.js.map +0 -1
- package/dist/tempo/client/SessionManager.d.ts.map +0 -1
- package/dist/tempo/client/SessionManager.js.map +0 -1
- package/dist/tempo/server/Session.d.ts.map +0 -1
- package/dist/tempo/server/Session.js.map +0 -1
- package/dist/tempo/session/Chain.d.ts.map +0 -1
- package/dist/tempo/session/Chain.js.map +0 -1
- package/dist/tempo/session/Channel.d.ts.map +0 -1
- package/dist/tempo/session/Channel.js.map +0 -1
- package/dist/tempo/session/ChannelStore.d.ts +0 -117
- package/dist/tempo/session/ChannelStore.d.ts.map +0 -1
- package/dist/tempo/session/ChannelStore.js +0 -172
- package/dist/tempo/session/ChannelStore.js.map +0 -1
- package/dist/tempo/session/Receipt.d.ts +0 -22
- package/dist/tempo/session/Receipt.d.ts.map +0 -1
- package/dist/tempo/session/Receipt.js +0 -34
- package/dist/tempo/session/Receipt.js.map +0 -1
- package/dist/tempo/session/Sse.d.ts.map +0 -1
- package/dist/tempo/session/Sse.js +0 -363
- package/dist/tempo/session/Sse.js.map +0 -1
- package/dist/tempo/session/Types.d.ts +0 -78
- package/dist/tempo/session/Types.d.ts.map +0 -1
- package/dist/tempo/session/Types.js.map +0 -1
- package/dist/tempo/session/Voucher.d.ts.map +0 -1
- package/dist/tempo/session/Voucher.js.map +0 -1
- package/dist/tempo/session/Ws.d.ts +0 -87
- package/dist/tempo/session/Ws.d.ts.map +0 -1
- package/dist/tempo/session/Ws.js +0 -443
- package/dist/tempo/session/Ws.js.map +0 -1
- package/dist/tempo/session/escrow.abi.js.map +0 -1
- package/src/tempo/session/ChannelStore.ts +0 -308
- package/src/tempo/session/Receipt.test.ts +0 -89
- package/src/tempo/session/Receipt.ts +0 -46
- package/src/tempo/session/Sse.ts +0 -462
- package/src/tempo/session/Types.ts +0 -86
- package/src/tempo/session/Ws.ts +0 -576
- /package/dist/tempo/{session → legacy/session}/Channel.js +0 -0
- /package/dist/tempo/{session → legacy/session}/Types.js +0 -0
- /package/src/tempo/{session → legacy/session}/Channel.test.ts +0 -0
- /package/src/tempo/{session → legacy/session}/Voucher.test.ts +0 -0
- /package/src/tempo/session/{Sse.fuzz.test.ts → server/Sse.fuzz.test.ts} +0 -0
package/src/server/Mppx.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { IncomingMessage, ServerResponse } from 'node:http'
|
|
|
2
2
|
import { isDeepStrictEqual } from 'node:util'
|
|
3
3
|
|
|
4
4
|
import * as Challenge from '../Challenge.js'
|
|
5
|
+
import * as Constants from '../Constants.js'
|
|
5
6
|
import * as Credential from '../Credential.js'
|
|
6
7
|
import * as Errors from '../Errors.js'
|
|
7
8
|
import * as Expires from '../Expires.js'
|
|
@@ -326,12 +327,30 @@ type UniqueIntentHandlers<
|
|
|
326
327
|
}
|
|
327
328
|
|
|
328
329
|
/** Nested handlers: `mppx.tempo.charge(...)`, grouped by method name then intent. */
|
|
330
|
+
type PublicAlias<method extends Method.AnyServer> = method extends {
|
|
331
|
+
alias?: infer alias
|
|
332
|
+
}
|
|
333
|
+
? Exclude<alias, undefined> extends infer definedAlias
|
|
334
|
+
? definedAlias extends string
|
|
335
|
+
? string extends definedAlias
|
|
336
|
+
? never
|
|
337
|
+
: definedAlias
|
|
338
|
+
: never
|
|
339
|
+
: never
|
|
340
|
+
: never
|
|
341
|
+
|
|
342
|
+
type PublicIntent<method extends Method.AnyServer> = [PublicAlias<method>] extends [never]
|
|
343
|
+
? method extends { intent: infer intent extends string }
|
|
344
|
+
? intent
|
|
345
|
+
: never
|
|
346
|
+
: PublicAlias<method>
|
|
347
|
+
|
|
329
348
|
type NestedHandlers<
|
|
330
349
|
methods extends readonly Method.AnyServer[],
|
|
331
350
|
transport extends Transport.AnyTransport,
|
|
332
351
|
> = {
|
|
333
352
|
[name in methods[number]['name'] as name extends ReservedKey ? never : name]: {
|
|
334
|
-
[mi in Extract<methods[number], { name: name }> as mi
|
|
353
|
+
[mi in Extract<methods[number], { name: name }> as PublicIntent<mi>]: MethodFn<
|
|
335
354
|
mi,
|
|
336
355
|
EffectiveTransportOf<mi, transport>,
|
|
337
356
|
NonNullable<mi['defaults']>
|
|
@@ -351,7 +370,12 @@ type Handlers<
|
|
|
351
370
|
> &
|
|
352
371
|
MethodExtensions<mi>
|
|
353
372
|
} & UniqueIntentHandlers<methods, transport> &
|
|
354
|
-
NestedHandlers<methods, transport>
|
|
373
|
+
NestedHandlers<methods, transport> & {
|
|
374
|
+
[mi in methods[number] as PublicAlias<mi> extends string
|
|
375
|
+
? `${mi['name']}/${PublicAlias<mi>}`
|
|
376
|
+
: never]: MethodFn<mi, EffectiveTransportOf<mi, transport>, NonNullable<mi['defaults']>> &
|
|
377
|
+
MethodExtensions<mi>
|
|
378
|
+
}
|
|
355
379
|
|
|
356
380
|
type MethodExtensions<method extends Method.AnyServer> = method extends {
|
|
357
381
|
extensions?: (infer extensions) | undefined
|
|
@@ -364,7 +388,7 @@ type MethodExtensions<method extends Method.AnyServer> = method extends {
|
|
|
364
388
|
/** Nested challenge generators: `mppx.challenge.tempo.charge(...)`. */
|
|
365
389
|
type ChallengeHandlers<methods extends readonly Method.AnyServer[]> = {
|
|
366
390
|
[name in methods[number]['name']]: {
|
|
367
|
-
[mi in Extract<methods[number], { name: name }> as mi
|
|
391
|
+
[mi in Extract<methods[number], { name: name }> as PublicIntent<mi>]: ChallengeFn<
|
|
368
392
|
mi,
|
|
369
393
|
NonNullable<mi['defaults']>
|
|
370
394
|
>
|
|
@@ -426,6 +450,7 @@ export function create<
|
|
|
426
450
|
method: mi,
|
|
427
451
|
realm,
|
|
428
452
|
events: serverEvents as never,
|
|
453
|
+
preflight: mi.preflight as never,
|
|
429
454
|
request: mi.request as never,
|
|
430
455
|
respond: mi.respond as never,
|
|
431
456
|
secretKey,
|
|
@@ -433,8 +458,11 @@ export function create<
|
|
|
433
458
|
transport: (mi.transport ?? transport) as never,
|
|
434
459
|
verify: mi.verify as never,
|
|
435
460
|
})
|
|
461
|
+
const wireKey = `${mi.name}/${mi.intent}`
|
|
462
|
+
const aliasKey = mi.alias ? `${mi.name}/${mi.alias}` : undefined
|
|
436
463
|
if (mi.extensions) Object.assign(fn, mi.extensions)
|
|
437
|
-
handlers[
|
|
464
|
+
if (!aliasKey || !handlers[wireKey]) handlers[wireKey] = fn
|
|
465
|
+
if (aliasKey) handlers[aliasKey] = fn
|
|
438
466
|
}
|
|
439
467
|
|
|
440
468
|
// Also set shorthand intent key when there's no collision
|
|
@@ -445,16 +473,17 @@ export function create<
|
|
|
445
473
|
// Build nested handlers: mppx.tempo.charge(...)
|
|
446
474
|
for (const mi of methods) {
|
|
447
475
|
if (!handlers[mi.name]) handlers[mi.name] = {}
|
|
448
|
-
const
|
|
476
|
+
const key = mi.alias ? `${mi.name}/${mi.alias}` : `${mi.name}/${mi.intent}`
|
|
477
|
+
const fn = handlers[key] as AnyMethodFn & { _method?: Method.AnyServer }
|
|
449
478
|
fn._method = mi
|
|
450
|
-
;(handlers[mi.name] as Record<string, unknown>)[mi.intent] = fn
|
|
479
|
+
;(handlers[mi.name] as Record<string, unknown>)[mi.alias ?? mi.intent] = fn
|
|
451
480
|
}
|
|
452
481
|
|
|
453
482
|
// Build challenge generators: mppx.challenge.tempo.charge(...)
|
|
454
483
|
const challengeHandlers: Record<string, Record<string, unknown>> = {}
|
|
455
484
|
for (const mi of methods) {
|
|
456
485
|
if (!challengeHandlers[mi.name]) challengeHandlers[mi.name] = {}
|
|
457
|
-
challengeHandlers[mi.name]![mi.intent] = createChallengeFn({
|
|
486
|
+
challengeHandlers[mi.name]![mi.alias ?? mi.intent] = createChallengeFn({
|
|
458
487
|
defaults: mi.defaults,
|
|
459
488
|
method: mi,
|
|
460
489
|
realm,
|
|
@@ -472,11 +501,13 @@ export function create<
|
|
|
472
501
|
typeof input === 'string' ? Credential.deserialize(input) : input,
|
|
473
502
|
)
|
|
474
503
|
|
|
475
|
-
// Find matching method by name + intent
|
|
504
|
+
// Find matching method by name + intent, then use method-details markers
|
|
505
|
+
// when multiple handlers intentionally share the same wire identity.
|
|
476
506
|
const { method: credMethod, intent: credIntent } = credential.challenge
|
|
477
|
-
const
|
|
507
|
+
const methodCandidates = (methods as readonly Method.AnyServer[]).filter(
|
|
478
508
|
(m) => m.name === credMethod && m.intent === credIntent,
|
|
479
509
|
)
|
|
510
|
+
const mi = selectVerificationMethod(methodCandidates, credential.challenge)
|
|
480
511
|
const eventMethod =
|
|
481
512
|
mi ?? ({ intent: credIntent, name: credMethod } satisfies ServerMethodDescriptor)
|
|
482
513
|
|
|
@@ -688,8 +719,8 @@ export function create<
|
|
|
688
719
|
typeof methodOrKey === 'string'
|
|
689
720
|
? methodOrKey
|
|
690
721
|
: typeof methodOrKey === 'function' && '_method' in methodOrKey
|
|
691
|
-
? `${(methodOrKey._method as Method.AnyServer).name}/${(methodOrKey._method as Method.AnyServer).intent}`
|
|
692
|
-
: `${(methodOrKey as Method.AnyServer).name}/${(methodOrKey as Method.AnyServer).intent}`
|
|
722
|
+
? `${(methodOrKey._method as Method.AnyServer).name}/${(methodOrKey._method as Method.AnyServer).alias ?? (methodOrKey._method as Method.AnyServer).intent}`
|
|
723
|
+
: `${(methodOrKey as Method.AnyServer).name}/${(methodOrKey as Method.AnyServer).alias ?? (methodOrKey as Method.AnyServer).intent}`
|
|
693
724
|
const handlerFn = handlers[key] as AnyMethodFn | undefined
|
|
694
725
|
if (!handlerFn)
|
|
695
726
|
throw new Error(`No handler for "${key}". Is this method in your methods array?`)
|
|
@@ -761,6 +792,7 @@ function createMethodFn(parameters: createMethodFn.Parameters): createMethodFn.R
|
|
|
761
792
|
defaults,
|
|
762
793
|
events,
|
|
763
794
|
method,
|
|
795
|
+
preflight,
|
|
764
796
|
realm,
|
|
765
797
|
respond,
|
|
766
798
|
secretKey,
|
|
@@ -772,75 +804,83 @@ function createMethodFn(parameters: createMethodFn.Parameters): createMethodFn.R
|
|
|
772
804
|
return (options) => {
|
|
773
805
|
const { description, meta, scope, ...rest } = options
|
|
774
806
|
const staticMeta = Scope.merge({ meta, scope })
|
|
807
|
+
const internal: ConfiguredHandler['_internal'] = {
|
|
808
|
+
...method,
|
|
809
|
+
...defaults,
|
|
810
|
+
...options,
|
|
811
|
+
...(staticMeta !== undefined ? { meta: staticMeta } : {}),
|
|
812
|
+
name: method.name,
|
|
813
|
+
intent: method.intent,
|
|
814
|
+
html: method.html,
|
|
815
|
+
_canonicalRequest: PaymentRequest.fromMethod(method, { ...defaults, ...rest }),
|
|
816
|
+
_stableBinding: stableBinding as never,
|
|
817
|
+
}
|
|
775
818
|
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
} as MethodFn.Response<Transport.Http>
|
|
783
|
-
|
|
784
|
-
const expires =
|
|
785
|
-
'expires' in options
|
|
786
|
-
? normalizeExpires(options.expires as z.DatetimeInput | undefined)
|
|
787
|
-
: Expires.minutes(5)
|
|
788
|
-
const capturedRequest = await captureRequest(transport, input)
|
|
789
|
-
const effectiveMeta =
|
|
790
|
-
scope === undefined && input instanceof globalThis.Request
|
|
791
|
-
? Scope.merge({ meta: staticMeta, scope: Scope.get(input) })
|
|
792
|
-
: staticMeta
|
|
793
|
-
|
|
794
|
-
// Extract credential once — getCredential may have side effects (e.g. SSE transports).
|
|
795
|
-
let [credential, credentialError] = (() => {
|
|
796
|
-
try {
|
|
797
|
-
const credential = transport.getCredential(input) as Credential.Credential | null
|
|
798
|
-
return [credential ? hydrateCredentialMeta(credential) : null, undefined] as const
|
|
799
|
-
} catch (e) {
|
|
800
|
-
return [null, e as Error] as const
|
|
801
|
-
}
|
|
802
|
-
})()
|
|
819
|
+
const handler = async (input: Transport.InputOf): Promise<MethodFn.Response> => {
|
|
820
|
+
if (method.html && isServiceWorkerRequest(input))
|
|
821
|
+
return {
|
|
822
|
+
status: 402,
|
|
823
|
+
challenge: createServiceWorkerResponse(),
|
|
824
|
+
} as MethodFn.Response<Transport.Http>
|
|
803
825
|
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
826
|
+
const expires =
|
|
827
|
+
'expires' in options
|
|
828
|
+
? normalizeExpires(options.expires as z.DatetimeInput | undefined)
|
|
829
|
+
: Expires.minutes(5)
|
|
830
|
+
const capturedRequest = await captureRequest(transport, input)
|
|
831
|
+
const effectiveMeta =
|
|
832
|
+
scope === undefined && input instanceof globalThis.Request
|
|
833
|
+
? Scope.merge({ meta: staticMeta, scope: Scope.get(input) })
|
|
834
|
+
: staticMeta
|
|
835
|
+
|
|
836
|
+
// Extract credential once — getCredential may have side effects (e.g. SSE transports).
|
|
837
|
+
let [credential, credentialError] = (() => {
|
|
838
|
+
try {
|
|
839
|
+
const credential = transport.getCredential(input) as Credential.Credential | null
|
|
840
|
+
return [credential ? hydrateCredentialMeta(credential) : null, undefined] as const
|
|
841
|
+
} catch (e) {
|
|
842
|
+
return [null, e as Error] as const
|
|
843
|
+
}
|
|
844
|
+
})()
|
|
845
|
+
|
|
846
|
+
if (preflight && input instanceof globalThis.Request) {
|
|
847
|
+
const response = await preflight({
|
|
848
|
+
capturedRequest,
|
|
849
|
+
credential,
|
|
850
|
+
expires,
|
|
851
|
+
input,
|
|
852
|
+
options: { ...defaults, ...rest },
|
|
853
|
+
realm: realm ?? new URL(input.url).hostname ?? 'MPP Payment',
|
|
854
|
+
secretKey,
|
|
855
|
+
} as never)
|
|
856
|
+
if (response) {
|
|
857
|
+
if (response.status === 402) return { challenge: response, status: 402 }
|
|
858
|
+
return {
|
|
859
|
+
status: 200,
|
|
860
|
+
withReceipt() {
|
|
861
|
+
return response
|
|
862
|
+
},
|
|
863
|
+
} as MethodFn.Response
|
|
831
864
|
}
|
|
865
|
+
}
|
|
832
866
|
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
867
|
+
const emitChallenge = async (parameters: {
|
|
868
|
+
challenge: Challenge.Challenge
|
|
869
|
+
credential?: Credential.Credential | null | undefined
|
|
870
|
+
error?: Errors.PaymentError | undefined
|
|
871
|
+
html?: Method.Method['html'] | undefined
|
|
872
|
+
request: Record<string, unknown>
|
|
873
|
+
}) => {
|
|
874
|
+
const response = await transport.respondChallenge({
|
|
875
|
+
challenge: parameters.challenge,
|
|
876
|
+
input,
|
|
877
|
+
...(parameters.error && { error: parameters.error }),
|
|
878
|
+
...(parameters.html && { html: parameters.html }),
|
|
879
|
+
})
|
|
880
|
+
if (isIssuedChallengeResponse(response))
|
|
841
881
|
await events.emit(
|
|
842
|
-
'
|
|
843
|
-
|
|
882
|
+
'challenge.created',
|
|
883
|
+
createChallengeContext({
|
|
844
884
|
capturedRequest,
|
|
845
885
|
challenge: parameters.challenge,
|
|
846
886
|
credential: parameters.credential,
|
|
@@ -848,272 +888,199 @@ function createMethodFn(parameters: createMethodFn.Parameters): createMethodFn.R
|
|
|
848
888
|
input,
|
|
849
889
|
method,
|
|
850
890
|
request: parameters.request,
|
|
851
|
-
retryChallenge: parameters.retryChallenge,
|
|
852
|
-
submittedChallenge: parameters.submittedChallenge,
|
|
853
891
|
}) as never,
|
|
854
892
|
)
|
|
855
|
-
|
|
893
|
+
return response
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
const emitPaymentFailed = async (parameters: {
|
|
897
|
+
challenge: Challenge.Challenge
|
|
898
|
+
credential: Credential.Credential | null
|
|
899
|
+
error: Errors.PaymentError
|
|
900
|
+
request: Record<string, unknown>
|
|
901
|
+
retryChallenge?: Challenge.Challenge | undefined
|
|
902
|
+
submittedChallenge?: Challenge.Challenge | undefined
|
|
903
|
+
}) => {
|
|
904
|
+
await events.emit(
|
|
905
|
+
'payment.failed',
|
|
906
|
+
createPaymentFailedContext({
|
|
907
|
+
capturedRequest,
|
|
908
|
+
challenge: parameters.challenge,
|
|
909
|
+
credential: parameters.credential,
|
|
910
|
+
error: parameters.error,
|
|
911
|
+
input,
|
|
912
|
+
method,
|
|
913
|
+
request: parameters.request,
|
|
914
|
+
retryChallenge: parameters.retryChallenge,
|
|
915
|
+
submittedChallenge: parameters.submittedChallenge,
|
|
916
|
+
}) as never,
|
|
917
|
+
)
|
|
918
|
+
}
|
|
856
919
|
|
|
857
|
-
|
|
920
|
+
const routeChallenge = await resolveRouteChallenge({
|
|
921
|
+
capturedRequest,
|
|
922
|
+
credential,
|
|
923
|
+
defaults,
|
|
924
|
+
description,
|
|
925
|
+
expires,
|
|
926
|
+
meta: effectiveMeta,
|
|
927
|
+
method,
|
|
928
|
+
realm,
|
|
929
|
+
request: parameters.request,
|
|
930
|
+
routeRequest: rest,
|
|
931
|
+
secretKey,
|
|
932
|
+
}).catch(async (e) => {
|
|
933
|
+
if (!(e instanceof Errors.PaymentError)) throw e
|
|
934
|
+
const challenge = createFallbackChallenge({
|
|
858
935
|
capturedRequest,
|
|
859
|
-
|
|
860
|
-
defaults,
|
|
936
|
+
defaults: defaults ?? {},
|
|
861
937
|
description,
|
|
862
938
|
expires,
|
|
863
939
|
meta: effectiveMeta,
|
|
864
940
|
method,
|
|
865
941
|
realm,
|
|
866
|
-
request: parameters.request,
|
|
867
942
|
routeRequest: rest,
|
|
868
943
|
secretKey,
|
|
869
|
-
})
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
capturedRequest,
|
|
873
|
-
defaults: defaults ?? {},
|
|
874
|
-
description,
|
|
875
|
-
expires,
|
|
876
|
-
meta: effectiveMeta,
|
|
877
|
-
method,
|
|
878
|
-
realm,
|
|
879
|
-
routeRequest: rest,
|
|
880
|
-
secretKey,
|
|
881
|
-
})
|
|
882
|
-
if (credential)
|
|
883
|
-
await emitPaymentFailed({
|
|
884
|
-
challenge,
|
|
885
|
-
credential,
|
|
886
|
-
error: e,
|
|
887
|
-
request: challenge.request,
|
|
888
|
-
retryChallenge: challenge,
|
|
889
|
-
submittedChallenge: credential.challenge,
|
|
890
|
-
})
|
|
891
|
-
const response = await emitChallenge({
|
|
944
|
+
})
|
|
945
|
+
if (credential)
|
|
946
|
+
await emitPaymentFailed({
|
|
892
947
|
challenge,
|
|
893
948
|
credential,
|
|
894
|
-
request: challenge.request,
|
|
895
949
|
error: e,
|
|
896
|
-
|
|
950
|
+
request: challenge.request,
|
|
951
|
+
retryChallenge: challenge,
|
|
952
|
+
submittedChallenge: credential.challenge,
|
|
897
953
|
})
|
|
898
|
-
|
|
954
|
+
const response = await emitChallenge({
|
|
955
|
+
challenge,
|
|
956
|
+
credential,
|
|
957
|
+
request: challenge.request,
|
|
958
|
+
error: e,
|
|
959
|
+
html: method.html,
|
|
899
960
|
})
|
|
900
|
-
|
|
901
|
-
|
|
961
|
+
return { response }
|
|
962
|
+
})
|
|
963
|
+
if ('response' in routeChallenge) return { challenge: routeChallenge.response, status: 402 }
|
|
964
|
+
const { challenge, parsedRequest, request } = routeChallenge
|
|
965
|
+
internal._canonicalRequest = parsedRequest
|
|
902
966
|
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
}
|
|
967
|
+
if (credential && transport.bindCredential) {
|
|
968
|
+
try {
|
|
969
|
+
credential = hydrateCredentialMeta(
|
|
970
|
+
(await transport.bindCredential({
|
|
971
|
+
challenge,
|
|
972
|
+
credential,
|
|
973
|
+
input,
|
|
974
|
+
})) as Credential.Credential,
|
|
975
|
+
)
|
|
976
|
+
} catch (e) {
|
|
977
|
+
credential = null
|
|
978
|
+
credentialError = e as Error
|
|
916
979
|
}
|
|
980
|
+
}
|
|
917
981
|
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
982
|
+
// Credential was provided but malformed
|
|
983
|
+
if (credentialError) {
|
|
984
|
+
const reason = getSafeCredentialReason(credentialError)
|
|
985
|
+
const error = new Errors.MalformedCredentialError(reason ? { reason } : {})
|
|
986
|
+
await emitPaymentFailed({
|
|
987
|
+
challenge,
|
|
988
|
+
credential: null,
|
|
989
|
+
error,
|
|
990
|
+
request: parsedRequest,
|
|
991
|
+
retryChallenge: challenge,
|
|
992
|
+
})
|
|
993
|
+
const response = await emitChallenge({
|
|
994
|
+
challenge,
|
|
995
|
+
credential: null,
|
|
996
|
+
request: parsedRequest,
|
|
997
|
+
error,
|
|
998
|
+
html: method.html,
|
|
999
|
+
})
|
|
1000
|
+
return { challenge: response, status: 402 }
|
|
1001
|
+
}
|
|
938
1002
|
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
1003
|
+
const success = (
|
|
1004
|
+
receiptData: Receipt.Receipt,
|
|
1005
|
+
options: {
|
|
1006
|
+
challengeId?: string | undefined
|
|
1007
|
+
credentialForReceipt?: Credential.Credential | undefined
|
|
1008
|
+
envelopeForReceipt?: Method.VerifiedChallengeEnvelope | undefined
|
|
1009
|
+
managementResponse?: globalThis.Response | undefined
|
|
1010
|
+
} = {},
|
|
1011
|
+
): MethodFn.Response => {
|
|
1012
|
+
const {
|
|
1013
|
+
challengeId = challenge.id,
|
|
1014
|
+
credentialForReceipt = { challenge, payload: {} } as Credential.Credential,
|
|
1015
|
+
envelopeForReceipt,
|
|
1016
|
+
managementResponse,
|
|
1017
|
+
} = options
|
|
954
1018
|
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
return transport.respondReceipt({
|
|
960
|
-
challengeId,
|
|
961
|
-
credential: credentialForReceipt,
|
|
962
|
-
...(envelopeForReceipt ? { envelope: envelopeForReceipt } : {}),
|
|
963
|
-
input,
|
|
964
|
-
receipt: receiptData,
|
|
965
|
-
response: managementResponse as never,
|
|
966
|
-
}) as response
|
|
967
|
-
}
|
|
968
|
-
if (!response) throw new MissingReceiptResponseError()
|
|
1019
|
+
return {
|
|
1020
|
+
status: 200,
|
|
1021
|
+
withReceipt<response>(response?: response) {
|
|
1022
|
+
if (managementResponse) {
|
|
969
1023
|
return transport.respondReceipt({
|
|
970
1024
|
challengeId,
|
|
971
1025
|
credential: credentialForReceipt,
|
|
972
1026
|
...(envelopeForReceipt ? { envelope: envelopeForReceipt } : {}),
|
|
973
1027
|
input,
|
|
974
1028
|
receipt: receiptData,
|
|
975
|
-
response:
|
|
1029
|
+
response: managementResponse as never,
|
|
976
1030
|
}) as response
|
|
977
|
-
}
|
|
978
|
-
|
|
1031
|
+
}
|
|
1032
|
+
if (!response) throw new MissingReceiptResponseError()
|
|
1033
|
+
return transport.respondReceipt({
|
|
1034
|
+
challengeId,
|
|
1035
|
+
credential: credentialForReceipt,
|
|
1036
|
+
...(envelopeForReceipt ? { envelope: envelopeForReceipt } : {}),
|
|
1037
|
+
input,
|
|
1038
|
+
receipt: receiptData,
|
|
1039
|
+
response: response as never,
|
|
1040
|
+
}) as response
|
|
1041
|
+
},
|
|
979
1042
|
}
|
|
1043
|
+
}
|
|
980
1044
|
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
})
|
|
1005
|
-
}
|
|
1006
|
-
} catch (e) {
|
|
1007
|
-
if (!(e instanceof Errors.PaymentError))
|
|
1008
|
-
console.error('mppx: internal authorization error', e)
|
|
1009
|
-
const error =
|
|
1010
|
-
e instanceof Errors.PaymentError ? e : new Errors.VerificationFailedError()
|
|
1011
|
-
await emitPaymentFailed({
|
|
1012
|
-
challenge,
|
|
1013
|
-
credential: null,
|
|
1014
|
-
error,
|
|
1015
|
-
request: parsedRequest,
|
|
1016
|
-
retryChallenge: challenge,
|
|
1017
|
-
})
|
|
1018
|
-
const response = await emitChallenge({
|
|
1019
|
-
challenge,
|
|
1020
|
-
request: parsedRequest,
|
|
1021
|
-
error,
|
|
1022
|
-
html: method.html,
|
|
1045
|
+
// No credential provided—issue challenge
|
|
1046
|
+
if (!credential) {
|
|
1047
|
+
if (authorize && input instanceof globalThis.Request) {
|
|
1048
|
+
try {
|
|
1049
|
+
const authorized = await authorize({
|
|
1050
|
+
challenge,
|
|
1051
|
+
input,
|
|
1052
|
+
request: challenge.request,
|
|
1053
|
+
} as never)
|
|
1054
|
+
if (authorized) {
|
|
1055
|
+
await events.emit(
|
|
1056
|
+
'payment.success',
|
|
1057
|
+
createPaymentSuccessContext({
|
|
1058
|
+
capturedRequest,
|
|
1059
|
+
challenge,
|
|
1060
|
+
input,
|
|
1061
|
+
method,
|
|
1062
|
+
receipt: authorized.receipt,
|
|
1063
|
+
request: parsedRequest,
|
|
1064
|
+
}) as never,
|
|
1065
|
+
)
|
|
1066
|
+
return success(authorized.receipt, {
|
|
1067
|
+
managementResponse: authorized.response,
|
|
1023
1068
|
})
|
|
1024
|
-
return { challenge: response, status: 402 }
|
|
1025
1069
|
}
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
credential: null,
|
|
1032
|
-
request: parsedRequest,
|
|
1033
|
-
error,
|
|
1034
|
-
html: method.html,
|
|
1035
|
-
})
|
|
1036
|
-
return { challenge: response, status: 402 }
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
// ── Tier 1: HMAC provenance check (primary gate) ──────────────────
|
|
1040
|
-
//
|
|
1041
|
-
// Recompute the HMAC-SHA256 over the credential's echoed challenge
|
|
1042
|
-
// parameters (realm|method|intent|request|expires|digest|opaque) and
|
|
1043
|
-
// compare to the echoed `id`. This proves the challenge was issued by
|
|
1044
|
-
// this server with these exact parameters — including opaque/meta,
|
|
1045
|
-
// expires, and the full serialized request blob.
|
|
1046
|
-
//
|
|
1047
|
-
// This is the authoritative binding per §5.1.2.1.1 of the spec
|
|
1048
|
-
// (https://paymentauth.org/draft-httpauth-payment-00.html#section-5.1.2.1.1).
|
|
1049
|
-
// No database lookup is needed; the HMAC is stateless verification.
|
|
1050
|
-
if (!Challenge.verify(credential.challenge, { secretKey })) {
|
|
1051
|
-
const error = new Errors.InvalidChallengeError({
|
|
1052
|
-
id: credential.challenge.id,
|
|
1053
|
-
reason: 'challenge was not issued by this server',
|
|
1054
|
-
})
|
|
1055
|
-
await emitPaymentFailed({
|
|
1056
|
-
challenge,
|
|
1057
|
-
credential,
|
|
1058
|
-
error,
|
|
1059
|
-
request: parsedRequest,
|
|
1060
|
-
retryChallenge: challenge,
|
|
1061
|
-
submittedChallenge: credential.challenge,
|
|
1062
|
-
})
|
|
1063
|
-
const response = await emitChallenge({
|
|
1064
|
-
challenge,
|
|
1065
|
-
credential,
|
|
1066
|
-
request: parsedRequest,
|
|
1067
|
-
error,
|
|
1068
|
-
html: method.html,
|
|
1069
|
-
})
|
|
1070
|
-
return { challenge: response, status: 402 }
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
|
-
// ── Tier 2: Pinned field safety net ──────────────────────────────
|
|
1074
|
-
//
|
|
1075
|
-
// The HMAC check above (Tier 1) is the primary gate — it already
|
|
1076
|
-
// covers ALL challenge fields including opaque, digest, and the full
|
|
1077
|
-
// serialized request. So why this second check?
|
|
1078
|
-
//
|
|
1079
|
-
// The `request()` hook can produce credential-dependent output: for
|
|
1080
|
-
// example, `feePayer` may differ between the 402 challenge call (no
|
|
1081
|
-
// credential) and the credential-bearing call. This means the
|
|
1082
|
-
// recomputed challenge here has a different `request` blob — and
|
|
1083
|
-
// thus a different HMAC — than the original challenge the client
|
|
1084
|
-
// echoes back. The HMAC check above verifies the *echoed* challenge
|
|
1085
|
-
// was signed by us, but it cannot verify that the echoed challenge
|
|
1086
|
-
// matches *this route's current configuration* when the request
|
|
1087
|
-
// hook transforms fields between calls.
|
|
1088
|
-
//
|
|
1089
|
-
// This check compares the fields that MUST be stable across both
|
|
1090
|
-
// calls. That includes the economically significant request fields
|
|
1091
|
-
// plus `opaque`, which can carry route-scoping metadata (for example,
|
|
1092
|
-
// sibling route identity) that must not be replayable across handlers.
|
|
1093
|
-
// `expires` still is not pinned here because its default is generated
|
|
1094
|
-
// per invocation, and `digest` is already bound by the echoed HMAC.
|
|
1095
|
-
{
|
|
1096
|
-
const mismatch = getChallengeBindingMismatch(
|
|
1097
|
-
challenge,
|
|
1098
|
-
credential.challenge,
|
|
1099
|
-
stableBinding as never,
|
|
1100
|
-
)
|
|
1101
|
-
if (mismatch) {
|
|
1102
|
-
const error = new Errors.InvalidChallengeError({
|
|
1103
|
-
id: credential.challenge.id,
|
|
1104
|
-
reason: `credential ${mismatch} does not match this route's requirements`,
|
|
1105
|
-
})
|
|
1070
|
+
} catch (e) {
|
|
1071
|
+
if (!(e instanceof Errors.PaymentError))
|
|
1072
|
+
console.error('mppx: internal authorization error', e)
|
|
1073
|
+
const error =
|
|
1074
|
+
e instanceof Errors.PaymentError ? e : new Errors.VerificationFailedError()
|
|
1106
1075
|
await emitPaymentFailed({
|
|
1107
1076
|
challenge,
|
|
1108
|
-
credential,
|
|
1077
|
+
credential: null,
|
|
1109
1078
|
error,
|
|
1110
1079
|
request: parsedRequest,
|
|
1111
1080
|
retryChallenge: challenge,
|
|
1112
|
-
submittedChallenge: credential.challenge,
|
|
1113
1081
|
})
|
|
1114
1082
|
const response = await emitChallenge({
|
|
1115
1083
|
challenge,
|
|
1116
|
-
credential,
|
|
1117
1084
|
request: parsedRequest,
|
|
1118
1085
|
error,
|
|
1119
1086
|
html: method.html,
|
|
@@ -1122,35 +1089,84 @@ function createMethodFn(parameters: createMethodFn.Parameters): createMethodFn.R
|
|
|
1122
1089
|
}
|
|
1123
1090
|
}
|
|
1124
1091
|
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1092
|
+
const error = new Errors.PaymentRequiredError({ description })
|
|
1093
|
+
const response = await emitChallenge({
|
|
1094
|
+
challenge,
|
|
1095
|
+
credential: null,
|
|
1096
|
+
request: parsedRequest,
|
|
1097
|
+
error,
|
|
1098
|
+
html: method.html,
|
|
1099
|
+
})
|
|
1100
|
+
return { challenge: response, status: 402 }
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
// ── Tier 1: HMAC provenance check (primary gate) ──────────────────
|
|
1104
|
+
//
|
|
1105
|
+
// Recompute the HMAC-SHA256 over the credential's echoed challenge
|
|
1106
|
+
// parameters (realm|method|intent|request|expires|digest|opaque) and
|
|
1107
|
+
// compare to the echoed `id`. This proves the challenge was issued by
|
|
1108
|
+
// this server with these exact parameters — including opaque/meta,
|
|
1109
|
+
// expires, and the full serialized request blob.
|
|
1110
|
+
//
|
|
1111
|
+
// This is the authoritative binding per §5.1.2.1.1 of the spec
|
|
1112
|
+
// (https://paymentauth.org/draft-httpauth-payment-00.html#section-5.1.2.1.1).
|
|
1113
|
+
// No database lookup is needed; the HMAC is stateless verification.
|
|
1114
|
+
if (!Challenge.verify(credential.challenge, { secretKey })) {
|
|
1115
|
+
const error = new Errors.InvalidChallengeError({
|
|
1116
|
+
id: credential.challenge.id,
|
|
1117
|
+
reason: 'challenge was not issued by this server',
|
|
1118
|
+
})
|
|
1119
|
+
await emitPaymentFailed({
|
|
1120
|
+
challenge,
|
|
1121
|
+
credential,
|
|
1122
|
+
error,
|
|
1123
|
+
request: parsedRequest,
|
|
1124
|
+
retryChallenge: challenge,
|
|
1125
|
+
submittedChallenge: credential.challenge,
|
|
1126
|
+
})
|
|
1127
|
+
const response = await emitChallenge({
|
|
1128
|
+
challenge,
|
|
1129
|
+
credential,
|
|
1130
|
+
request: parsedRequest,
|
|
1131
|
+
error,
|
|
1132
|
+
html: method.html,
|
|
1133
|
+
})
|
|
1134
|
+
return { challenge: response, status: 402 }
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
// ── Tier 2: Pinned field safety net ──────────────────────────────
|
|
1138
|
+
//
|
|
1139
|
+
// The HMAC check above (Tier 1) is the primary gate — it already
|
|
1140
|
+
// covers ALL challenge fields including opaque, digest, and the full
|
|
1141
|
+
// serialized request. So why this second check?
|
|
1142
|
+
//
|
|
1143
|
+
// The `request()` hook can produce credential-dependent output: for
|
|
1144
|
+
// example, `feePayer` may differ between the 402 challenge call (no
|
|
1145
|
+
// credential) and the credential-bearing call. This means the
|
|
1146
|
+
// recomputed challenge here has a different `request` blob — and
|
|
1147
|
+
// thus a different HMAC — than the original challenge the client
|
|
1148
|
+
// echoes back. The HMAC check above verifies the *echoed* challenge
|
|
1149
|
+
// was signed by us, but it cannot verify that the echoed challenge
|
|
1150
|
+
// matches *this route's current configuration* when the request
|
|
1151
|
+
// hook transforms fields between calls.
|
|
1152
|
+
//
|
|
1153
|
+
// This check compares the fields that MUST be stable across both
|
|
1154
|
+
// calls. That includes the economically significant request fields
|
|
1155
|
+
// plus `opaque`, which can carry route-scoping metadata (for example,
|
|
1156
|
+
// sibling route identity) that must not be replayable across handlers.
|
|
1157
|
+
// `expires` still is not pinned here because its default is generated
|
|
1158
|
+
// per invocation, and `digest` is already bound by the echoed HMAC.
|
|
1159
|
+
{
|
|
1160
|
+
const mismatch = getChallengeBindingMismatch(
|
|
1161
|
+
challenge,
|
|
1162
|
+
credential.challenge,
|
|
1163
|
+
stableBinding as never,
|
|
1164
|
+
)
|
|
1165
|
+
if (mismatch) {
|
|
1166
|
+
const error = new Errors.InvalidChallengeError({
|
|
1167
|
+
id: credential.challenge.id,
|
|
1168
|
+
reason: `credential ${mismatch} does not match this route's requirements`,
|
|
1142
1169
|
})
|
|
1143
|
-
return { challenge: response, status: 402 }
|
|
1144
|
-
}
|
|
1145
|
-
// Validate payload structure against method schema
|
|
1146
|
-
let parsedCredential: Credential.Credential
|
|
1147
|
-
try {
|
|
1148
|
-
parsedCredential = withParsedCredentialPayload(
|
|
1149
|
-
credential,
|
|
1150
|
-
method.schema.credential.payload.parse(credential.payload),
|
|
1151
|
-
)
|
|
1152
|
-
} catch {
|
|
1153
|
-
const error = new Errors.InvalidPayloadError()
|
|
1154
1170
|
await emitPaymentFailed({
|
|
1155
1171
|
challenge,
|
|
1156
1172
|
credential,
|
|
@@ -1164,92 +1180,129 @@ function createMethodFn(parameters: createMethodFn.Parameters): createMethodFn.R
|
|
|
1164
1180
|
credential,
|
|
1165
1181
|
request: parsedRequest,
|
|
1166
1182
|
error,
|
|
1183
|
+
html: method.html,
|
|
1167
1184
|
})
|
|
1168
1185
|
return { challenge: response, status: 402 }
|
|
1169
1186
|
}
|
|
1187
|
+
}
|
|
1170
1188
|
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1189
|
+
// Reject credentials without expires (fail-closed) or with expired timestamp
|
|
1190
|
+
try {
|
|
1191
|
+
Expires.assert(credential.challenge.expires, credential.challenge.id)
|
|
1192
|
+
} catch (error) {
|
|
1193
|
+
await emitPaymentFailed({
|
|
1194
|
+
challenge,
|
|
1195
|
+
credential,
|
|
1196
|
+
error: error as Errors.PaymentError,
|
|
1197
|
+
request: parsedRequest,
|
|
1198
|
+
retryChallenge: challenge,
|
|
1199
|
+
submittedChallenge: credential.challenge,
|
|
1200
|
+
})
|
|
1201
|
+
const response = await emitChallenge({
|
|
1202
|
+
challenge,
|
|
1203
|
+
credential,
|
|
1204
|
+
request: parsedRequest,
|
|
1205
|
+
error: error as Errors.PaymentError,
|
|
1206
|
+
})
|
|
1207
|
+
return { challenge: response, status: 402 }
|
|
1208
|
+
}
|
|
1209
|
+
// Validate payload structure against method schema
|
|
1210
|
+
let parsedCredential: Credential.Credential
|
|
1211
|
+
try {
|
|
1212
|
+
parsedCredential = withParsedCredentialPayload(
|
|
1213
|
+
credential,
|
|
1214
|
+
method.schema.credential.payload.parse(credential.payload),
|
|
1215
|
+
)
|
|
1216
|
+
} catch {
|
|
1217
|
+
const error = new Errors.InvalidPayloadError()
|
|
1218
|
+
await emitPaymentFailed({
|
|
1219
|
+
challenge,
|
|
1220
|
+
credential,
|
|
1221
|
+
error,
|
|
1175
1222
|
request: parsedRequest,
|
|
1223
|
+
retryChallenge: challenge,
|
|
1224
|
+
submittedChallenge: credential.challenge,
|
|
1176
1225
|
})
|
|
1226
|
+
const response = await emitChallenge({
|
|
1227
|
+
challenge,
|
|
1228
|
+
credential,
|
|
1229
|
+
request: parsedRequest,
|
|
1230
|
+
error,
|
|
1231
|
+
})
|
|
1232
|
+
return { challenge: response, status: 402 }
|
|
1233
|
+
}
|
|
1177
1234
|
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
if (!(e instanceof Errors.PaymentError))
|
|
1185
|
-
console.error('mppx: internal verification error', e)
|
|
1186
|
-
const error = e instanceof Errors.PaymentError ? e : new Errors.VerificationFailedError()
|
|
1187
|
-
await emitPaymentFailed({
|
|
1188
|
-
challenge,
|
|
1189
|
-
credential: parsedCredential,
|
|
1190
|
-
error,
|
|
1191
|
-
request: parsedRequest,
|
|
1192
|
-
retryChallenge: challenge,
|
|
1193
|
-
submittedChallenge: credential.challenge,
|
|
1194
|
-
})
|
|
1195
|
-
const response = await emitChallenge({
|
|
1196
|
-
challenge,
|
|
1197
|
-
credential: parsedCredential,
|
|
1198
|
-
request: parsedRequest,
|
|
1199
|
-
error,
|
|
1200
|
-
})
|
|
1201
|
-
return { challenge: response, status: 402 }
|
|
1202
|
-
}
|
|
1235
|
+
const envelope: Method.VerifiedChallengeEnvelope = Object.freeze({
|
|
1236
|
+
capturedRequest,
|
|
1237
|
+
challenge: credential.challenge,
|
|
1238
|
+
credential: parsedCredential,
|
|
1239
|
+
request: parsedRequest,
|
|
1240
|
+
})
|
|
1203
1241
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
:
|
|
1242
|
+
// User-provided verification (e.g., check signature, submit tx, verify payment).
|
|
1243
|
+
// If verification fails, re-issue the challenge so the client can retry.
|
|
1244
|
+
let receiptData: Receipt.Receipt
|
|
1245
|
+
try {
|
|
1246
|
+
receiptData = await verify({ credential: parsedCredential, envelope, request } as never)
|
|
1247
|
+
} catch (e) {
|
|
1248
|
+
if (!(e instanceof Errors.PaymentError))
|
|
1249
|
+
console.error('mppx: internal verification error', e)
|
|
1250
|
+
const error = e instanceof Errors.PaymentError ? e : new Errors.VerificationFailedError()
|
|
1251
|
+
await emitPaymentFailed({
|
|
1252
|
+
challenge,
|
|
1253
|
+
credential: parsedCredential,
|
|
1254
|
+
error,
|
|
1255
|
+
request: parsedRequest,
|
|
1256
|
+
retryChallenge: challenge,
|
|
1257
|
+
submittedChallenge: credential.challenge,
|
|
1258
|
+
})
|
|
1259
|
+
const response = await emitChallenge({
|
|
1260
|
+
challenge,
|
|
1261
|
+
credential: parsedCredential,
|
|
1262
|
+
request: parsedRequest,
|
|
1263
|
+
error,
|
|
1264
|
+
})
|
|
1265
|
+
return { challenge: response, status: 402 }
|
|
1266
|
+
}
|
|
1218
1267
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1268
|
+
// If the method's `respond` hook returns a Response, it means this
|
|
1269
|
+
// request is a management action (e.g. channel open, voucher POST)
|
|
1270
|
+
// and the user's route handler should NOT run. `withReceipt()` will
|
|
1271
|
+
// return the management response directly. If undefined, `withReceipt()`
|
|
1272
|
+
// expects the caller to pass the user handler's response instead.
|
|
1273
|
+
const managementResponse = respond
|
|
1274
|
+
? await respond({
|
|
1224
1275
|
credential: parsedCredential,
|
|
1225
1276
|
envelope,
|
|
1226
1277
|
input,
|
|
1227
|
-
method,
|
|
1228
1278
|
receipt: receiptData,
|
|
1229
|
-
request
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1279
|
+
request,
|
|
1280
|
+
} as never)
|
|
1281
|
+
: undefined
|
|
1232
1282
|
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1283
|
+
await events.emit(
|
|
1284
|
+
'payment.success',
|
|
1285
|
+
createPaymentSuccessContext({
|
|
1286
|
+
capturedRequest,
|
|
1287
|
+
challenge: credential.challenge,
|
|
1288
|
+
credential: parsedCredential,
|
|
1289
|
+
envelope,
|
|
1290
|
+
input,
|
|
1291
|
+
method,
|
|
1292
|
+
receipt: receiptData,
|
|
1293
|
+
request: parsedRequest,
|
|
1294
|
+
}) as never,
|
|
1295
|
+
)
|
|
1296
|
+
|
|
1297
|
+
return success(receiptData, {
|
|
1298
|
+
challengeId: credential.challenge.id,
|
|
1299
|
+
credentialForReceipt: parsedCredential,
|
|
1300
|
+
envelopeForReceipt: envelope,
|
|
1301
|
+
managementResponse,
|
|
1302
|
+
})
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
return Object.assign(handler, { _internal: internal })
|
|
1253
1306
|
}
|
|
1254
1307
|
}
|
|
1255
1308
|
|
|
@@ -1305,6 +1358,7 @@ declare namespace createMethodFn {
|
|
|
1305
1358
|
defaults?: defaults
|
|
1306
1359
|
method: method
|
|
1307
1360
|
events: ServerEventDispatcher<readonly [method], transport>
|
|
1361
|
+
preflight?: Method.PreflightFn<method>
|
|
1308
1362
|
realm: string | undefined
|
|
1309
1363
|
request?: Method.RequestFn<method>
|
|
1310
1364
|
respond?: Method.RespondFn<method>
|
|
@@ -1767,7 +1821,7 @@ function captureRequestFromInput(input: unknown): Method.CapturedRequest {
|
|
|
1767
1821
|
}
|
|
1768
1822
|
|
|
1769
1823
|
const coreBindingFields = ['amount', 'currency', 'recipient'] as const
|
|
1770
|
-
const methodBindingFields = ['chainId', 'memo', 'splits', 'unitType'] as const
|
|
1824
|
+
const methodBindingFields = ['chainId', 'memo', 'sessionProtocol', 'splits', 'unitType'] as const
|
|
1771
1825
|
const pinnedRequestBindingFields = [...coreBindingFields, ...methodBindingFields] as const
|
|
1772
1826
|
|
|
1773
1827
|
type CoreBindingField = (typeof coreBindingFields)[number]
|
|
@@ -1776,6 +1830,31 @@ type PinnedRequestBindingField = (typeof pinnedRequestBindingFields)[number]
|
|
|
1776
1830
|
type PinnedChallengeField = 'method' | 'intent' | 'realm' | 'opaque' | PinnedRequestBindingField
|
|
1777
1831
|
type StableBinding = Record<string, unknown>
|
|
1778
1832
|
|
|
1833
|
+
function selectVerificationMethod(
|
|
1834
|
+
methods: readonly Method.AnyServer[],
|
|
1835
|
+
challenge: Challenge.Challenge,
|
|
1836
|
+
): Method.AnyServer | undefined {
|
|
1837
|
+
if (methods.length <= 1) return methods[0]
|
|
1838
|
+
if (
|
|
1839
|
+
challenge.method !== Constants.Methods.tempo ||
|
|
1840
|
+
challenge.intent !== Constants.Intents.session
|
|
1841
|
+
)
|
|
1842
|
+
return methods[0]
|
|
1843
|
+
|
|
1844
|
+
const sessionProtocolMarker = Constants.getMethodDetail(
|
|
1845
|
+
challenge.request.methodDetails,
|
|
1846
|
+
Constants.MethodDetailKeys.sessionProtocol,
|
|
1847
|
+
)
|
|
1848
|
+
if (
|
|
1849
|
+
sessionProtocolMarker === undefined ||
|
|
1850
|
+
sessionProtocolMarker === Constants.SessionProtocols.v1
|
|
1851
|
+
)
|
|
1852
|
+
return methods.find((method) => method.alias === 'sessionLegacy') ?? methods[0]
|
|
1853
|
+
if (sessionProtocolMarker === Constants.SessionProtocols.v2)
|
|
1854
|
+
return methods.find((method) => method.alias === undefined) ?? methods[0]
|
|
1855
|
+
return undefined
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1779
1858
|
function getChallengeBindingMismatch(
|
|
1780
1859
|
expectedChallenge: Challenge.Challenge,
|
|
1781
1860
|
actualChallenge: Challenge.Challenge,
|
|
@@ -1856,6 +1935,7 @@ function getPinnedRequestBinding(request: Record<string, unknown>): PinnedReques
|
|
|
1856
1935
|
const currency = normalizeScalar(request.currency ?? methodDetails.currency)
|
|
1857
1936
|
const memo = normalizeHex(methodDetails.memo)
|
|
1858
1937
|
const recipient = normalizeScalar(request.recipient ?? methodDetails.recipient)
|
|
1938
|
+
const sessionProtocol = normalizeScalar(methodDetails.sessionProtocol)
|
|
1859
1939
|
const splits = normalizeComparable(methodDetails.splits)
|
|
1860
1940
|
const unitType = normalizeScalar(request.unitType ?? methodDetails.unitType)
|
|
1861
1941
|
|
|
@@ -1868,6 +1948,7 @@ function getPinnedRequestBinding(request: Record<string, unknown>): PinnedReques
|
|
|
1868
1948
|
methodBinding: {
|
|
1869
1949
|
...(chainId !== undefined ? { chainId } : {}),
|
|
1870
1950
|
...(memo !== undefined ? { memo } : {}),
|
|
1951
|
+
...(sessionProtocol !== undefined ? { sessionProtocol } : {}),
|
|
1871
1952
|
...(splits !== undefined ? { splits } : {}),
|
|
1872
1953
|
...(unitType !== undefined ? { unitType } : {}),
|
|
1873
1954
|
},
|
|
@@ -2021,7 +2102,7 @@ type ConfiguredHandler = ((input: Request) => Promise<MethodFn.Response<Transpor
|
|
|
2021
2102
|
}
|
|
2022
2103
|
}
|
|
2023
2104
|
|
|
2024
|
-
const paymentAuthChallengeHeader =
|
|
2105
|
+
const paymentAuthChallengeHeader = Constants.Headers.wwwAuthenticate
|
|
2025
2106
|
|
|
2026
2107
|
const challengeHeaderMerges = [
|
|
2027
2108
|
{
|
|
@@ -2141,7 +2222,7 @@ export function compose(
|
|
|
2141
2222
|
// Try to extract a Payment credential to decide whether to dispatch or challenge.
|
|
2142
2223
|
// Only gate on the Payment scheme — other auth schemes (Bearer, Basic, etc.)
|
|
2143
2224
|
// should fall through to the merged-402 path so all offers are presented.
|
|
2144
|
-
const header = input.headers.get(
|
|
2225
|
+
const header = input.headers.get(Constants.Headers.authorization)
|
|
2145
2226
|
const paymentHeader = header ? Credential.extractPaymentScheme(header) : null
|
|
2146
2227
|
|
|
2147
2228
|
if (paymentHeader) {
|
|
@@ -2222,7 +2303,7 @@ export function compose(
|
|
|
2222
2303
|
})
|
|
2223
2304
|
}
|
|
2224
2305
|
|
|
2225
|
-
const acceptPayment = input.headers.get(
|
|
2306
|
+
const acceptPayment = input.headers.get(Constants.Headers.acceptPayment)
|
|
2226
2307
|
if (!acceptPayment) return entries
|
|
2227
2308
|
|
|
2228
2309
|
try {
|
|
@@ -2243,7 +2324,7 @@ export function compose(
|
|
|
2243
2324
|
result.status === 402 ? [result.challenge as Response] : [],
|
|
2244
2325
|
)
|
|
2245
2326
|
const unnegotiatedX402Responses =
|
|
2246
|
-
input.headers.has(
|
|
2327
|
+
input.headers.has(Constants.Headers.acceptPayment) || challengeEntries.length === 0
|
|
2247
2328
|
? []
|
|
2248
2329
|
: challengeResponses.filter(
|
|
2249
2330
|
(response) =>
|