mppx 0.8.19 → 0.9.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/CHANGELOG.md +24 -0
- package/README.md +0 -6
- package/dist/Challenge.d.ts +7 -0
- package/dist/Challenge.js +32 -6
- package/dist/Constants.d.ts +1 -0
- package/dist/Constants.js +1 -0
- package/dist/Credential.d.ts +11 -5
- package/dist/Credential.js +8 -8
- package/dist/Errors.d.ts +10 -0
- package/dist/Errors.js +12 -0
- package/dist/Html.js +1 -1
- package/dist/Mcp.d.ts +9 -1
- package/dist/Mcp.js +18 -0
- package/dist/Method.d.ts +7 -0
- package/dist/cli/THIRD-PARTY-LICENSES.txt +1 -1
- package/dist/cli/cli.d.ts +2 -2
- package/dist/cli/cli.js +134 -134
- package/dist/cli/plugins/index.js +13 -13
- package/dist/cli/sessions/Manager.js +4 -6
- package/dist/cli/sessions/commands.d.ts +1 -1
- package/dist/cli/sessions/store.js +13 -19
- package/dist/cli/validate/index.d.ts +2 -2
- package/dist/client/Mppx.d.ts +39 -2
- package/dist/client/Mppx.js +102 -46
- package/dist/client/Transport.js +1 -1
- package/dist/client/internal/protocols/Mcp.js +2 -1
- package/dist/client/internal/protocols/Mpp.d.ts +1 -1
- package/dist/client/internal/protocols/Mpp.js +5 -3
- package/dist/client/internal/protocols/Protocol.d.ts +3 -1
- package/dist/client/internal/protocols/Shared.js +5 -1
- package/dist/integrations/x402/Evm.d.ts +29 -0
- package/dist/integrations/x402/Evm.js +150 -0
- package/dist/integrations/x402/Negotiator.d.ts +36 -0
- package/dist/integrations/x402/Negotiator.js +165 -0
- package/dist/mcp/client/McpClient.js +22 -10
- package/dist/mcp/internal/Credential.d.ts +9 -0
- package/dist/mcp/internal/Credential.js +16 -0
- package/dist/mcp/server/Transport.d.ts +2 -2
- package/dist/mcp/server/Transport.js +11 -6
- package/dist/middlewares/express.js +5 -12
- package/dist/middlewares/internal/express.d.ts +8 -0
- package/dist/middlewares/internal/express.js +24 -0
- package/dist/middlewares/internal/node.d.ts +10 -0
- package/dist/middlewares/internal/node.js +34 -0
- package/dist/proxy/Proxy.js +15 -9
- package/dist/server/Mppx.d.ts +8 -0
- package/dist/server/Mppx.js +92 -20
- package/dist/server/Transport.d.ts +8 -2
- package/dist/server/Transport.js +14 -18
- package/dist/server/internal/SecretKey.d.ts +3 -0
- package/dist/server/internal/SecretKey.js +9 -0
- package/dist/server/internal/html/serviceWorker.client.d.ts +1 -1
- package/dist/server/internal/html/serviceWorker.client.js +2 -2
- package/dist/server/internal/html/serviceWorker.gen.d.ts +1 -1
- package/dist/server/internal/html/serviceWorker.gen.js +1 -1
- package/dist/stripe/Methods.d.ts +6 -0
- package/dist/stripe/Methods.js +3 -1
- package/dist/stripe/client/Charge.d.ts +6 -0
- package/dist/stripe/client/Methods.d.ts +6 -0
- package/dist/stripe/internal/payment-intent.d.ts +7 -0
- package/dist/stripe/internal/payment-intent.js +6 -0
- package/dist/stripe/server/Charge.d.ts +6 -0
- package/dist/stripe/server/Charge.js +8 -3
- package/dist/stripe/server/Methods.js +62 -7
- package/dist/stripe/server/internal/html.gen.d.ts +1 -1
- package/dist/stripe/server/internal/html.gen.js +1 -1
- package/dist/tempo/Methods.d.ts +0 -10
- package/dist/tempo/Methods.js +3 -12
- package/dist/tempo/Tokens.d.ts +13 -0
- package/dist/tempo/Tokens.js +13 -0
- package/dist/tempo/client/Charge.d.ts +1 -4
- package/dist/tempo/client/Charge.js +20 -13
- package/dist/tempo/client/Methods.d.ts +0 -10
- package/dist/tempo/index.d.ts +1 -0
- package/dist/tempo/index.js +1 -0
- package/dist/tempo/internal/account.d.ts +15 -6
- package/dist/tempo/internal/account.js +17 -26
- package/dist/tempo/internal/defaults.d.ts +0 -11
- package/dist/tempo/internal/defaults.js +0 -11
- package/dist/tempo/internal/fee-payer.d.ts +22 -4
- package/dist/tempo/internal/fee-payer.js +12 -31
- package/dist/tempo/internal/fee-token.d.ts +2 -0
- package/dist/tempo/internal/fee-token.js +7 -0
- package/dist/tempo/internal/remote-fee-payer.d.ts +12 -0
- package/dist/tempo/internal/remote-fee-payer.js +17 -0
- package/dist/tempo/legacy/client/Session.d.ts +0 -7
- package/dist/tempo/server/Charge.d.ts +0 -3
- package/dist/tempo/server/Charge.js +26 -68
- package/dist/tempo/server/Methods.d.ts +4 -18
- package/dist/tempo/server/Methods.js +4 -8
- package/dist/tempo/server/internal/html.gen.d.ts +1 -1
- package/dist/tempo/server/internal/html.gen.js +1 -1
- package/dist/tempo/session/client/ChannelOps.d.ts +0 -14
- package/dist/tempo/session/client/ChannelOps.js +0 -22
- package/dist/tempo/session/client/ChannelStore.d.ts +5 -0
- package/dist/tempo/session/client/ChannelStore.js +2 -2
- package/dist/tempo/session/client/CredentialState.d.ts +2 -12
- package/dist/tempo/session/client/CredentialState.js +75 -73
- package/dist/tempo/session/client/Session.d.ts +2 -9
- package/dist/tempo/session/client/Session.js +71 -176
- package/dist/tempo/session/client/SessionManager.js +7 -27
- package/dist/tempo/session/precompile/Chain.d.ts +0 -4
- package/dist/tempo/session/precompile/Chain.js +1 -29
- package/dist/tempo/session/precompile/Protocol.d.ts +0 -13
- package/dist/tempo/session/precompile/Voucher.d.ts +1 -3
- package/dist/tempo/session/precompile/Voucher.js +12 -6
- package/dist/tempo/session/server/ChannelStore.d.ts +0 -6
- package/dist/tempo/session/server/ChannelStore.js +4 -11
- package/dist/tempo/session/server/CredentialVerification.d.ts +7 -9
- package/dist/tempo/session/server/CredentialVerification.js +118 -184
- package/dist/tempo/session/server/RequestState.d.ts +0 -17
- package/dist/tempo/session/server/RequestState.js +15 -59
- package/dist/tempo/session/server/Session.d.ts +0 -9
- package/dist/tempo/session/server/Session.js +13 -39
- package/dist/tempo/session/server/Settlement.d.ts +0 -7
- package/dist/tempo/session/server/Settlement.js +16 -50
- package/dist/viem/Client.d.ts +7 -2
- package/dist/viem/Client.js +17 -5
- package/dist/x402/Types.d.ts +2 -0
- package/dist/x402/Types.js +2 -0
- package/dist/x402/mcp.d.ts +20 -0
- package/dist/x402/mcp.js +154 -0
- package/dist/x402/middlewares/express.d.ts +23 -0
- package/dist/x402/middlewares/express.js +49 -0
- package/dist/x402/middlewares/hono.d.ts +13 -0
- package/dist/x402/middlewares/hono.js +36 -0
- package/dist/x402/middlewares/next.d.ts +17 -0
- package/dist/x402/middlewares/next.js +58 -0
- package/package.json +41 -1
- package/dist/tempo/internal/machine-token-charge.d.ts +0 -51
- package/dist/tempo/internal/machine-token-charge.js +0 -113
- package/dist/tempo/internal/machine-token-session.d.ts +0 -88
- package/dist/tempo/internal/machine-token-session.js +0 -173
- package/dist/tempo/internal/signature-envelope.d.ts +0 -14
- package/dist/tempo/internal/signature-envelope.js +0 -28
package/dist/server/Mppx.js
CHANGED
|
@@ -14,11 +14,10 @@ import * as z from '../zod.js';
|
|
|
14
14
|
import * as Html from './internal/html/config.js';
|
|
15
15
|
import { serviceWorker } from './internal/html/serviceWorker.gen.js';
|
|
16
16
|
import * as Scope from './internal/scope.js';
|
|
17
|
+
import * as SecretKey from './internal/SecretKey.js';
|
|
17
18
|
import * as NodeListener from './NodeListener.js';
|
|
18
19
|
import * as Request from './Request.js';
|
|
19
20
|
import * as Transport from './Transport.js';
|
|
20
|
-
const minimumSecretKeyBytes = 32;
|
|
21
|
-
const secretKeyGenerationCommand = 'openssl rand -base64 32';
|
|
22
21
|
const reservedMppxKeyValues = [
|
|
23
22
|
'challenge',
|
|
24
23
|
'compose',
|
|
@@ -52,11 +51,12 @@ export const reservedMppxKeys = new Set(reservedMppxKeyValues);
|
|
|
52
51
|
* ```
|
|
53
52
|
*/
|
|
54
53
|
export function create(config) {
|
|
55
|
-
const { attestation, realm = Env.get('realm'), selectOffers, secretKey = Env.get('secretKey'), transport = Transport.http(), } = config;
|
|
54
|
+
const { attestation, requiresAuth, realm = Env.get('realm'), selectOffers, secretKey = Env.get('secretKey'), transport = Transport.http({ requiresAuth }), } = config;
|
|
55
|
+
const credentialHeader = requiresAuth ? Constants.Headers.paymentAuthorization : undefined;
|
|
56
56
|
if (!secretKey) {
|
|
57
57
|
throw new Error('Missing secret key. Set the MPP_SECRET_KEY environment variable or pass `secretKey` to Mppx.create().');
|
|
58
58
|
}
|
|
59
|
-
|
|
59
|
+
SecretKey.assert(secretKey);
|
|
60
60
|
const methods = config.methods.flat();
|
|
61
61
|
const serverEvents = createServerEventDispatcher();
|
|
62
62
|
const verifyAttestation = attestation
|
|
@@ -73,6 +73,7 @@ export function create(config) {
|
|
|
73
73
|
input: ctx.input,
|
|
74
74
|
receipt: ctx.receipt,
|
|
75
75
|
request: ctx.request,
|
|
76
|
+
...(ctx.requestInput !== undefined && { requestInput: ctx.requestInput }),
|
|
76
77
|
});
|
|
77
78
|
}
|
|
78
79
|
}));
|
|
@@ -83,6 +84,7 @@ export function create(config) {
|
|
|
83
84
|
const fn = createMethodFn({
|
|
84
85
|
...(verifyAttestation && { attest: verifyAttestation }),
|
|
85
86
|
authorize: mi.authorize,
|
|
87
|
+
credentialHeader,
|
|
86
88
|
defaults: mi.defaults,
|
|
87
89
|
method: mi,
|
|
88
90
|
realm,
|
|
@@ -143,6 +145,7 @@ export function create(config) {
|
|
|
143
145
|
if (!challengeHandlers[mi.name])
|
|
144
146
|
challengeHandlers[mi.name] = {};
|
|
145
147
|
challengeHandlers[mi.name][mi.alias ?? mi.intent] = createChallengeFn({
|
|
148
|
+
credentialHeader,
|
|
146
149
|
defaults: mi.defaults,
|
|
147
150
|
method: mi,
|
|
148
151
|
realm,
|
|
@@ -235,6 +238,7 @@ export function create(config) {
|
|
|
235
238
|
credential: parsedCredential,
|
|
236
239
|
defaults: mi.defaults,
|
|
237
240
|
expires: credential.challenge.expires,
|
|
241
|
+
header: credential.challenge.header,
|
|
238
242
|
meta: expectedMeta,
|
|
239
243
|
method: mi,
|
|
240
244
|
realm: expectedRealm,
|
|
@@ -277,6 +281,7 @@ export function create(config) {
|
|
|
277
281
|
parsedCredential,
|
|
278
282
|
parsedRequest,
|
|
279
283
|
request,
|
|
284
|
+
requestInput: shouldValidateRoute ? request : undefined,
|
|
280
285
|
};
|
|
281
286
|
}
|
|
282
287
|
async function validateCredentialFn(input, options) {
|
|
@@ -290,7 +295,7 @@ export function create(config) {
|
|
|
290
295
|
// broadcastCredential: single-call end-to-end validation and broadcast
|
|
291
296
|
async function broadcastCredentialFn(input, options) {
|
|
292
297
|
const prepared = await prepareStandaloneCredential(input, options, { emitFailures: true });
|
|
293
|
-
const { method: mi, parsedCredential, parsedRequest, request, envelope } = prepared;
|
|
298
|
+
const { method: mi, parsedCredential, parsedRequest, request, requestInput, envelope, } = prepared;
|
|
294
299
|
const emitStandalonePaymentFailed = async (parameters) => {
|
|
295
300
|
await serverEvents.emit('payment.failed', createPaymentFailedContext({
|
|
296
301
|
capturedRequest: options?.capturedRequest,
|
|
@@ -310,7 +315,7 @@ export function create(config) {
|
|
|
310
315
|
receipt = await broadcast({ credential: parsedCredential, envelope, request });
|
|
311
316
|
}
|
|
312
317
|
catch (e) {
|
|
313
|
-
const error = e instanceof Errors.PaymentError ? e : new Errors.
|
|
318
|
+
const error = e instanceof Errors.PaymentError ? e : new Errors.InternalPaymentError();
|
|
314
319
|
await emitStandalonePaymentFailed({
|
|
315
320
|
challenge: prepared.credential.challenge,
|
|
316
321
|
credential: parsedCredential,
|
|
@@ -328,6 +333,7 @@ export function create(config) {
|
|
|
328
333
|
method: mi,
|
|
329
334
|
receipt,
|
|
330
335
|
request: parsedRequest,
|
|
336
|
+
...(requestInput !== undefined && { requestInput }),
|
|
331
337
|
}));
|
|
332
338
|
return receipt;
|
|
333
339
|
}
|
|
@@ -375,15 +381,9 @@ export function create(config) {
|
|
|
375
381
|
...handlers,
|
|
376
382
|
};
|
|
377
383
|
}
|
|
378
|
-
function assertSecretKey(secretKey) {
|
|
379
|
-
const byteLength = new TextEncoder().encode(secretKey).byteLength;
|
|
380
|
-
if (byteLength >= minimumSecretKeyBytes)
|
|
381
|
-
return;
|
|
382
|
-
throw new Error(`Secret key must be at least ${minimumSecretKeyBytes} bytes. Generate one with \`${secretKeyGenerationCommand}\` and set MPP_SECRET_KEY or pass it to Mppx.create().`);
|
|
383
|
-
}
|
|
384
384
|
// biome-ignore lint/correctness/noUnusedVariables: _
|
|
385
385
|
function createMethodFn(parameters) {
|
|
386
|
-
const { attest, authorize, defaults, events, method, preflight, realm, respond, secretKey, broadcast, stableBinding, transport, validate, verify, } = parameters;
|
|
386
|
+
const { attest, authorize, credentialHeader, defaults, events, method, preflight, realm, respond, secretKey, broadcast, stableBinding, transport, validate, verify, } = parameters;
|
|
387
387
|
return (options) => {
|
|
388
388
|
const { description, meta, scope, ...rest } = options;
|
|
389
389
|
const staticMeta = Scope.merge({ meta, scope });
|
|
@@ -491,6 +491,7 @@ function createMethodFn(parameters) {
|
|
|
491
491
|
defaults,
|
|
492
492
|
description,
|
|
493
493
|
expires,
|
|
494
|
+
header: credentialHeader,
|
|
494
495
|
meta: effectiveMeta,
|
|
495
496
|
method,
|
|
496
497
|
realm,
|
|
@@ -505,6 +506,7 @@ function createMethodFn(parameters) {
|
|
|
505
506
|
defaults: defaults ?? {},
|
|
506
507
|
description,
|
|
507
508
|
expires,
|
|
509
|
+
header: credentialHeader,
|
|
508
510
|
meta: effectiveMeta,
|
|
509
511
|
method,
|
|
510
512
|
realm,
|
|
@@ -549,7 +551,11 @@ function createMethodFn(parameters) {
|
|
|
549
551
|
// Credential was provided but malformed
|
|
550
552
|
if (credentialError) {
|
|
551
553
|
const reason = getSafeCredentialReason(credentialError);
|
|
552
|
-
const error =
|
|
554
|
+
const error = credentialError instanceof Errors.PaymentError
|
|
555
|
+
? credentialError
|
|
556
|
+
: reason
|
|
557
|
+
? new Errors.MalformedCredentialError({ reason })
|
|
558
|
+
: new Errors.InternalPaymentError();
|
|
553
559
|
await emitPaymentFailed({
|
|
554
560
|
challenge,
|
|
555
561
|
credential: null,
|
|
@@ -611,6 +617,7 @@ function createMethodFn(parameters) {
|
|
|
611
617
|
method,
|
|
612
618
|
receipt: authorized.receipt,
|
|
613
619
|
request: parsedRequest,
|
|
620
|
+
requestInput: request,
|
|
614
621
|
}));
|
|
615
622
|
return success(authorized.receipt, {
|
|
616
623
|
managementResponse: authorized.response,
|
|
@@ -620,7 +627,7 @@ function createMethodFn(parameters) {
|
|
|
620
627
|
catch (e) {
|
|
621
628
|
if (!(e instanceof Errors.PaymentError))
|
|
622
629
|
console.error('mppx: internal authorization error', e);
|
|
623
|
-
const error = e instanceof Errors.PaymentError ? e : new Errors.
|
|
630
|
+
const error = e instanceof Errors.PaymentError ? e : new Errors.InternalPaymentError();
|
|
624
631
|
await emitPaymentFailed({
|
|
625
632
|
challenge,
|
|
626
633
|
credential: null,
|
|
@@ -793,7 +800,7 @@ function createMethodFn(parameters) {
|
|
|
793
800
|
catch (e) {
|
|
794
801
|
if (!(e instanceof Errors.PaymentError))
|
|
795
802
|
console.error('mppx: internal verification error', e);
|
|
796
|
-
const error = e instanceof Errors.PaymentError ? e : new Errors.
|
|
803
|
+
const error = e instanceof Errors.PaymentError ? e : new Errors.InternalPaymentError();
|
|
797
804
|
await emitPaymentFailed({
|
|
798
805
|
challenge,
|
|
799
806
|
credential: parsedCredential,
|
|
@@ -833,6 +840,7 @@ function createMethodFn(parameters) {
|
|
|
833
840
|
method,
|
|
834
841
|
receipt: receiptData,
|
|
835
842
|
request: parsedRequest,
|
|
843
|
+
requestInput: request,
|
|
836
844
|
}));
|
|
837
845
|
return success(receiptData, {
|
|
838
846
|
challengeId: credential.challenge.id,
|
|
@@ -850,7 +858,7 @@ function createMethodFn(parameters) {
|
|
|
850
858
|
* but returns a Challenge object directly instead of a request handler.
|
|
851
859
|
*/
|
|
852
860
|
function createChallengeFn(parameters) {
|
|
853
|
-
const { defaults, method, realm, secretKey } = parameters;
|
|
861
|
+
const { credentialHeader, defaults, method, realm, secretKey } = parameters;
|
|
854
862
|
return async (options) => {
|
|
855
863
|
const { description, meta, scope, ...rest } = options;
|
|
856
864
|
const effectiveMeta = Scope.merge({ meta, scope });
|
|
@@ -861,6 +869,7 @@ function createChallengeFn(parameters) {
|
|
|
861
869
|
defaults,
|
|
862
870
|
description,
|
|
863
871
|
expires,
|
|
872
|
+
header: credentialHeader,
|
|
864
873
|
meta: effectiveMeta,
|
|
865
874
|
method,
|
|
866
875
|
realm,
|
|
@@ -991,6 +1000,9 @@ function createPaymentSuccessContext(parameters) {
|
|
|
991
1000
|
method: snapshotMethod(parameters.method),
|
|
992
1001
|
receipt: snapshotValue(parameters.receipt),
|
|
993
1002
|
request: snapshotValue(parameters.request),
|
|
1003
|
+
...(parameters.requestInput !== undefined && {
|
|
1004
|
+
requestInput: snapshotValue(parameters.requestInput),
|
|
1005
|
+
}),
|
|
994
1006
|
});
|
|
995
1007
|
}
|
|
996
1008
|
function snapshotMethod(method) {
|
|
@@ -1035,8 +1047,65 @@ function snapshotValue(value) {
|
|
|
1035
1047
|
return freezeSnapshot(structuredClone(value));
|
|
1036
1048
|
}
|
|
1037
1049
|
catch {
|
|
1038
|
-
return freezeSnapshot(value);
|
|
1050
|
+
return freezeSnapshot(cloneSnapshotFallback(value));
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Copies object containers when `structuredClone` rejects callable values.
|
|
1055
|
+
* Functions remain callable references, while their containing request data is
|
|
1056
|
+
* detached so snapshot freezing and nested writes cannot affect hook-owned
|
|
1057
|
+
* objects.
|
|
1058
|
+
*/
|
|
1059
|
+
function cloneSnapshotFallback(value, seen = new WeakMap()) {
|
|
1060
|
+
if (!value || typeof value !== 'object')
|
|
1061
|
+
return value;
|
|
1062
|
+
const existing = seen.get(value);
|
|
1063
|
+
if (existing)
|
|
1064
|
+
return existing;
|
|
1065
|
+
if (value instanceof Date)
|
|
1066
|
+
return new Date(value);
|
|
1067
|
+
if (value instanceof RegExp)
|
|
1068
|
+
return new RegExp(value.source, value.flags);
|
|
1069
|
+
if (value instanceof URL)
|
|
1070
|
+
return new URL(value);
|
|
1071
|
+
if (value instanceof Headers)
|
|
1072
|
+
return new Headers(value);
|
|
1073
|
+
if (value instanceof ArrayBuffer)
|
|
1074
|
+
return value.slice(0);
|
|
1075
|
+
if (ArrayBuffer.isView(value)) {
|
|
1076
|
+
const buffer = new Uint8Array(value.buffer, value.byteOffset, value.byteLength).slice().buffer;
|
|
1077
|
+
if (value instanceof DataView)
|
|
1078
|
+
return new DataView(buffer);
|
|
1079
|
+
const Constructor = value.constructor;
|
|
1080
|
+
return new Constructor(buffer);
|
|
1081
|
+
}
|
|
1082
|
+
if (value instanceof Map) {
|
|
1083
|
+
const snapshot = new Map();
|
|
1084
|
+
seen.set(value, snapshot);
|
|
1085
|
+
for (const [key, entry] of value)
|
|
1086
|
+
snapshot.set(cloneSnapshotFallback(key, seen), cloneSnapshotFallback(entry, seen));
|
|
1087
|
+
return snapshot;
|
|
1088
|
+
}
|
|
1089
|
+
if (value instanceof Set) {
|
|
1090
|
+
const snapshot = new Set();
|
|
1091
|
+
seen.set(value, snapshot);
|
|
1092
|
+
for (const entry of value)
|
|
1093
|
+
snapshot.add(cloneSnapshotFallback(entry, seen));
|
|
1094
|
+
return snapshot;
|
|
1095
|
+
}
|
|
1096
|
+
const snapshot = Array.isArray(value) ? [] : Object.create(Object.getPrototypeOf(value));
|
|
1097
|
+
seen.set(value, snapshot);
|
|
1098
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
1099
|
+
if (Array.isArray(value) && key === 'length')
|
|
1100
|
+
continue;
|
|
1101
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
1102
|
+
if (!descriptor)
|
|
1103
|
+
continue;
|
|
1104
|
+
if ('value' in descriptor)
|
|
1105
|
+
descriptor.value = cloneSnapshotFallback(descriptor.value, seen);
|
|
1106
|
+
Object.defineProperty(snapshot, key, descriptor);
|
|
1039
1107
|
}
|
|
1108
|
+
return snapshot;
|
|
1040
1109
|
}
|
|
1041
1110
|
function snapshotInputProperty(input) {
|
|
1042
1111
|
if (input === undefined)
|
|
@@ -1163,6 +1232,7 @@ async function resolveRouteChallenge(parameters) {
|
|
|
1163
1232
|
const challenge = Challenge.fromMethod(parameters.method, {
|
|
1164
1233
|
description: parameters.description,
|
|
1165
1234
|
expires: parameters.expires,
|
|
1235
|
+
header: parameters.header,
|
|
1166
1236
|
meta: parameters.meta,
|
|
1167
1237
|
realm: effectiveRealm,
|
|
1168
1238
|
request: request,
|
|
@@ -1178,6 +1248,7 @@ function createFallbackChallenge(parameters) {
|
|
|
1178
1248
|
return Challenge.fromMethod(parameters.method, {
|
|
1179
1249
|
description: parameters.description,
|
|
1180
1250
|
expires: parameters.expires,
|
|
1251
|
+
header: parameters.header,
|
|
1181
1252
|
meta: parameters.meta,
|
|
1182
1253
|
realm: parameters.realm ??
|
|
1183
1254
|
(parameters.capturedRequest
|
|
@@ -1405,8 +1476,9 @@ function composeHandlers(handlers, composeOptions, selectOffers) {
|
|
|
1405
1476
|
// Try to extract a Payment credential to decide whether to dispatch or challenge.
|
|
1406
1477
|
// Only gate on the Payment scheme — other auth schemes (Bearer, Basic, etc.)
|
|
1407
1478
|
// should fall through to the merged-402 path so all offers are presented.
|
|
1408
|
-
const
|
|
1409
|
-
|
|
1479
|
+
const paymentHeader = Array.from(input.headers.values())
|
|
1480
|
+
.map((value) => Credential.extractPaymentScheme(value))
|
|
1481
|
+
.find((value) => value !== null);
|
|
1410
1482
|
if (paymentHeader) {
|
|
1411
1483
|
// Parse the credential to find method+intent for dispatch.
|
|
1412
1484
|
let credential;
|
|
@@ -89,11 +89,17 @@ export declare function from<input = unknown, challengeOutput = unknown, receipt
|
|
|
89
89
|
/**
|
|
90
90
|
* HTTP transport for server-side payment handling.
|
|
91
91
|
*
|
|
92
|
-
* - Reads credentials from the
|
|
92
|
+
* - Reads credentials from the configured payment credential header
|
|
93
93
|
* - Issues challenges via `WWW-Authenticate` header with 402 status
|
|
94
94
|
* - Attaches receipts via `Payment-Receipt` header
|
|
95
95
|
*/
|
|
96
|
-
export declare function http(): Http;
|
|
96
|
+
export declare function http(options?: http.Options): Http;
|
|
97
|
+
export declare namespace http {
|
|
98
|
+
type Options = {
|
|
99
|
+
/** Uses `Payment-Authorization` for Payment credentials so `Authorization` remains available for application authentication. */
|
|
100
|
+
requiresAuth?: boolean | undefined;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
97
103
|
/**
|
|
98
104
|
* MCP transport for server-side payment handling with raw JSON-RPC.
|
|
99
105
|
*
|
package/dist/server/Transport.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as Challenge from '../Challenge.js';
|
|
2
2
|
import * as Constants from '../Constants.js';
|
|
3
3
|
import * as Credential from '../Credential.js';
|
|
4
|
-
import * as Errors from '../Errors.js';
|
|
5
4
|
import * as core_Mcp from '../Mcp.js';
|
|
5
|
+
import * as McpCredential from '../mcp/internal/Credential.js';
|
|
6
6
|
import * as Receipt from '../Receipt.js';
|
|
7
7
|
import * as Html from './internal/html/config.js';
|
|
8
8
|
import { serviceWorker } from './internal/html/serviceWorker.gen.js';
|
|
@@ -29,11 +29,14 @@ export function from(transport) {
|
|
|
29
29
|
/**
|
|
30
30
|
* HTTP transport for server-side payment handling.
|
|
31
31
|
*
|
|
32
|
-
* - Reads credentials from the
|
|
32
|
+
* - Reads credentials from the configured payment credential header
|
|
33
33
|
* - Issues challenges via `WWW-Authenticate` header with 402 status
|
|
34
34
|
* - Attaches receipts via `Payment-Receipt` header
|
|
35
35
|
*/
|
|
36
|
-
export function http() {
|
|
36
|
+
export function http(options = {}) {
|
|
37
|
+
const credentialHeader = options.requiresAuth
|
|
38
|
+
? Constants.Headers.paymentAuthorization
|
|
39
|
+
: Constants.Headers.authorization;
|
|
37
40
|
return from({
|
|
38
41
|
name: 'http',
|
|
39
42
|
captureRequest(request) {
|
|
@@ -45,7 +48,7 @@ export function http() {
|
|
|
45
48
|
};
|
|
46
49
|
},
|
|
47
50
|
getCredential(request) {
|
|
48
|
-
const header = request.headers.get(
|
|
51
|
+
const header = request.headers.get(credentialHeader);
|
|
49
52
|
if (!header)
|
|
50
53
|
return null;
|
|
51
54
|
const payment = Credential.extractPaymentScheme(header);
|
|
@@ -144,17 +147,20 @@ export function mcp() {
|
|
|
144
147
|
},
|
|
145
148
|
getCredential(request) {
|
|
146
149
|
const meta = request.params?._meta;
|
|
147
|
-
const
|
|
148
|
-
if (
|
|
150
|
+
const value = meta?.[core_Mcp.credentialMetaKey];
|
|
151
|
+
if (value === undefined)
|
|
149
152
|
return null;
|
|
150
|
-
|
|
153
|
+
const parsed = McpCredential.parse(value);
|
|
154
|
+
if (!parsed)
|
|
155
|
+
throw new Credential.InvalidCredentialEncodingError();
|
|
156
|
+
return parsed.value;
|
|
151
157
|
},
|
|
152
158
|
respondChallenge({ challenge, input, error }) {
|
|
153
159
|
return {
|
|
154
160
|
jsonrpc: '2.0',
|
|
155
161
|
id: input.id,
|
|
156
162
|
error: {
|
|
157
|
-
code:
|
|
163
|
+
code: core_Mcp.errorCode(error),
|
|
158
164
|
message: error?.message ?? 'Payment Required',
|
|
159
165
|
data: {
|
|
160
166
|
httpStatus: error?.status ?? 402,
|
|
@@ -184,16 +190,6 @@ export function mcp() {
|
|
|
184
190
|
},
|
|
185
191
|
});
|
|
186
192
|
}
|
|
187
|
-
/** @internal */
|
|
188
|
-
function mcpErrorCode(error) {
|
|
189
|
-
if (!error)
|
|
190
|
-
return core_Mcp.paymentRequiredCode;
|
|
191
|
-
if (error instanceof Errors.MalformedCredentialError)
|
|
192
|
-
return -32602;
|
|
193
|
-
if (error instanceof Errors.PaymentRequiredError)
|
|
194
|
-
return core_Mcp.paymentRequiredCode;
|
|
195
|
-
return core_Mcp.paymentVerificationFailedCode;
|
|
196
|
-
}
|
|
197
193
|
export function safeUrl(url) {
|
|
198
194
|
try {
|
|
199
195
|
if (url instanceof URL)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const minimumBytes = 32;
|
|
2
|
+
const generationCommand = 'openssl rand -base64 32';
|
|
3
|
+
/** Validates the minimum entropy required for HMAC-bound payment challenges. */
|
|
4
|
+
export function assert(secretKey) {
|
|
5
|
+
if (new TextEncoder().encode(secretKey).byteLength >= minimumBytes)
|
|
6
|
+
return;
|
|
7
|
+
throw new Error(`Secret key must be at least ${minimumBytes} bytes. Generate one with \`${generationCommand}\` and set MPP_SECRET_KEY or pass it to Mppx.create().`);
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=SecretKey.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function submitCredential(credential: string): Promise<void>;
|
|
1
|
+
export declare function submitCredential(credential: string, header?: string): Promise<void>;
|
|
2
2
|
//# sourceMappingURL=serviceWorker.client.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { params } from './constants.js';
|
|
2
|
-
export async function submitCredential(credential) {
|
|
2
|
+
export async function submitCredential(credential, header = 'Authorization') {
|
|
3
3
|
const url = new URL(location.href);
|
|
4
4
|
url.searchParams.set(params.serviceWorker, '');
|
|
5
5
|
const registration = await navigator.serviceWorker.register(url.pathname + url.search);
|
|
@@ -19,7 +19,7 @@ export async function submitCredential(credential) {
|
|
|
19
19
|
await new Promise((resolve) => {
|
|
20
20
|
const channel = new MessageChannel();
|
|
21
21
|
channel.port1.onmessage = () => resolve();
|
|
22
|
-
serviceWorker.postMessage({ credential }, [channel.port2]);
|
|
22
|
+
serviceWorker.postMessage({ credential, header }, [channel.port2]);
|
|
23
23
|
});
|
|
24
24
|
location.reload();
|
|
25
25
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const serviceWorker = "(function(){let e=self,t
|
|
1
|
+
export declare const serviceWorker = "(function(){let e=self,t,n=`Authorization`;e.addEventListener(`activate`,t=>{t.waitUntil(e.clients.claim())}),e.addEventListener(`message`,e=>{if(!e.source)return;let r=e.data?.credential;typeof r!=`string`||!r.startsWith(`Payment `)||(t=r,typeof e.data?.header==`string`&&(n=e.data.header),e.ports[0]?.postMessage(`ack`))}),e.addEventListener(`fetch`,r=>{if(!t||r.request.mode!==`navigate`||new URL(r.request.url).origin!==e.location.origin)return;let i=new Headers(r.request.headers);i.set(n,t),t=void 0,r.respondWith(fetch(r.request,{headers:i})),e.registration.unregister()})})();";
|
|
2
2
|
//# sourceMappingURL=serviceWorker.gen.d.ts.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// Generated — do not edit.
|
|
2
|
-
export const serviceWorker = "(function(){let e=self,t
|
|
2
|
+
export const serviceWorker = "(function(){let e=self,t,n=`Authorization`;e.addEventListener(`activate`,t=>{t.waitUntil(e.clients.claim())}),e.addEventListener(`message`,e=>{if(!e.source)return;let r=e.data?.credential;typeof r!=`string`||!r.startsWith(`Payment `)||(t=r,typeof e.data?.header==`string`&&(n=e.data.header),e.ports[0]?.postMessage(`ack`))}),e.addEventListener(`fetch`,r=>{if(!t||r.request.mode!==`navigate`||new URL(r.request.url).origin!==e.location.origin)return;let i=new Headers(r.request.headers);i.set(n,t),t=void 0,r.respondWith(fetch(r.request,{headers:i})),e.registration.unregister()})})();";
|
|
3
3
|
//# sourceMappingURL=serviceWorker.gen.js.map
|
package/dist/stripe/Methods.d.ts
CHANGED
|
@@ -22,6 +22,9 @@ export declare const charge: {
|
|
|
22
22
|
externalId: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
23
23
|
metadata: z.ZodMiniOptional<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniString<string>>>;
|
|
24
24
|
networkId: z.ZodMiniString<string>;
|
|
25
|
+
paymentIntentOptions: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
26
|
+
metadata: z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniString<string>>;
|
|
27
|
+
}, z.core.$strip>>;
|
|
25
28
|
paymentMethodTypes: z.ZodMiniArray<z.ZodMiniString<string>>;
|
|
26
29
|
recipient: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
27
30
|
}, z.core.$strip>, z.ZodMiniTransform<{
|
|
@@ -43,6 +46,9 @@ export declare const charge: {
|
|
|
43
46
|
externalId?: string | undefined;
|
|
44
47
|
metadata?: Record<string, string> | undefined;
|
|
45
48
|
networkId: string;
|
|
49
|
+
paymentIntentOptions?: {
|
|
50
|
+
metadata: Record<string, string>;
|
|
51
|
+
} | undefined;
|
|
46
52
|
paymentMethodTypes: string[];
|
|
47
53
|
recipient?: string | undefined;
|
|
48
54
|
}>>;
|
package/dist/stripe/Methods.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { parseUnits } from 'viem';
|
|
2
2
|
import * as Method from '../Method.js';
|
|
3
3
|
import * as z from '../zod.js';
|
|
4
|
+
import * as PaymentIntent from './internal/payment-intent.js';
|
|
4
5
|
/**
|
|
5
6
|
* Stripe charge intent for one-time payments via Shared Payment Tokens (SPTs).
|
|
6
7
|
*
|
|
@@ -24,9 +25,10 @@ export const charge = Method.from({
|
|
|
24
25
|
externalId: z.optional(z.string()),
|
|
25
26
|
metadata: z.optional(z.record(z.string(), z.string())),
|
|
26
27
|
networkId: z.string(),
|
|
28
|
+
paymentIntentOptions: z.optional(PaymentIntent.Schema),
|
|
27
29
|
paymentMethodTypes: z.array(z.string()).check(z.minLength(1)),
|
|
28
30
|
recipient: z.optional(z.string()),
|
|
29
|
-
}), z.transform(({ amount, decimals, metadata, networkId, paymentMethodTypes, ...rest }) => ({
|
|
31
|
+
}), z.transform(({ amount, decimals, metadata, networkId, paymentIntentOptions: _, paymentMethodTypes, ...rest }) => ({
|
|
30
32
|
...rest,
|
|
31
33
|
amount: parseUnits(amount, decimals).toString(),
|
|
32
34
|
methodDetails: {
|
|
@@ -55,6 +55,9 @@ export declare function charge(parameters: charge.Parameters): Method.Client<{
|
|
|
55
55
|
externalId: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
56
56
|
metadata: z.ZodMiniOptional<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniString<string>>>;
|
|
57
57
|
networkId: z.ZodMiniString<string>;
|
|
58
|
+
paymentIntentOptions: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
59
|
+
metadata: z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniString<string>>;
|
|
60
|
+
}, z.core.$strip>>;
|
|
58
61
|
paymentMethodTypes: z.ZodMiniArray<z.ZodMiniString<string>>;
|
|
59
62
|
recipient: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
60
63
|
}, z.core.$strip>, z.ZodMiniTransform<{
|
|
@@ -76,6 +79,9 @@ export declare function charge(parameters: charge.Parameters): Method.Client<{
|
|
|
76
79
|
externalId?: string | undefined;
|
|
77
80
|
metadata?: Record<string, string> | undefined;
|
|
78
81
|
networkId: string;
|
|
82
|
+
paymentIntentOptions?: {
|
|
83
|
+
metadata: Record<string, string>;
|
|
84
|
+
} | undefined;
|
|
79
85
|
paymentMethodTypes: string[];
|
|
80
86
|
recipient?: string | undefined;
|
|
81
87
|
}>>;
|
|
@@ -42,6 +42,9 @@ export declare function stripe(parameters: stripe.Parameters): readonly [import(
|
|
|
42
42
|
externalId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
|
|
43
43
|
metadata: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniRecord<import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniString<string>>>;
|
|
44
44
|
networkId: import("zod/mini").ZodMiniString<string>;
|
|
45
|
+
paymentIntentOptions: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
|
|
46
|
+
metadata: import("zod/mini").ZodMiniRecord<import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniString<string>>;
|
|
47
|
+
}, import("zod/v4/core").$strip>>;
|
|
45
48
|
paymentMethodTypes: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniString<string>>;
|
|
46
49
|
recipient: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
|
|
47
50
|
}, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniTransform<{
|
|
@@ -63,6 +66,9 @@ export declare function stripe(parameters: stripe.Parameters): readonly [import(
|
|
|
63
66
|
externalId?: string | undefined;
|
|
64
67
|
metadata?: Record<string, string> | undefined;
|
|
65
68
|
networkId: string;
|
|
69
|
+
paymentIntentOptions?: {
|
|
70
|
+
metadata: Record<string, string>;
|
|
71
|
+
} | undefined;
|
|
66
72
|
paymentMethodTypes: string[];
|
|
67
73
|
recipient?: string | undefined;
|
|
68
74
|
}>>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as z from '../../zod.js';
|
|
2
|
+
/** Stripe PaymentIntent options accepted only by server-side method input. */
|
|
3
|
+
export declare const Schema: z.ZodMiniObject<{
|
|
4
|
+
metadata: z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniString<string>>;
|
|
5
|
+
}, z.core.$strip>;
|
|
6
|
+
export type Options = z.infer<typeof Schema>;
|
|
7
|
+
//# sourceMappingURL=payment-intent.d.ts.map
|
|
@@ -49,6 +49,9 @@ export declare function charge<const parameters extends charge.Parameters>(param
|
|
|
49
49
|
externalId: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
50
50
|
metadata: z.ZodMiniOptional<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniString<string>>>;
|
|
51
51
|
networkId: z.ZodMiniString<string>;
|
|
52
|
+
paymentIntentOptions: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
53
|
+
metadata: z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniString<string>>;
|
|
54
|
+
}, z.core.$strip>>;
|
|
52
55
|
paymentMethodTypes: z.ZodMiniArray<z.ZodMiniString<string>>;
|
|
53
56
|
recipient: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
54
57
|
}, z.core.$strip>, z.ZodMiniTransform<{
|
|
@@ -70,6 +73,9 @@ export declare function charge<const parameters extends charge.Parameters>(param
|
|
|
70
73
|
externalId?: string | undefined;
|
|
71
74
|
metadata?: Record<string, string> | undefined;
|
|
72
75
|
networkId: string;
|
|
76
|
+
paymentIntentOptions?: {
|
|
77
|
+
metadata: Record<string, string>;
|
|
78
|
+
} | undefined;
|
|
73
79
|
paymentMethodTypes: string[];
|
|
74
80
|
recipient?: string | undefined;
|
|
75
81
|
}>>;
|
|
@@ -117,13 +117,14 @@ export function charge(parameters) {
|
|
|
117
117
|
onPaymentSuccess,
|
|
118
118
|
async verify({ credential, envelope, request }) {
|
|
119
119
|
const { challenge } = credential;
|
|
120
|
+
const { paymentIntentOptions, ...methodRequest } = request;
|
|
120
121
|
const resolvedRequest = (() => {
|
|
121
|
-
const parsed = Methods.charge.schema.request.safeParse(
|
|
122
|
+
const parsed = Methods.charge.schema.request.safeParse(methodRequest);
|
|
122
123
|
if (parsed.success)
|
|
123
124
|
return parsed.data;
|
|
124
125
|
// verifyCredential() passes the HMAC-bound challenge request, which is
|
|
125
126
|
// already in canonical output form and should not be transformed again.
|
|
126
|
-
return
|
|
127
|
+
return methodRequest;
|
|
127
128
|
})();
|
|
128
129
|
Expires.assert(challenge.expires, challenge.id);
|
|
129
130
|
const parsed = Methods.charge.schema.credential.payload.safeParse(credential.payload);
|
|
@@ -138,7 +139,11 @@ export function charge(parameters) {
|
|
|
138
139
|
});
|
|
139
140
|
}
|
|
140
141
|
const userMetadata = resolvedRequest.methodDetails?.metadata;
|
|
141
|
-
const resolvedMetadata = {
|
|
142
|
+
const resolvedMetadata = {
|
|
143
|
+
...buildAnalytics({ credential }),
|
|
144
|
+
...userMetadata,
|
|
145
|
+
...paymentIntentOptions?.metadata,
|
|
146
|
+
};
|
|
142
147
|
const settlement = validateConnectSettlement({
|
|
143
148
|
amount: resolvedRequest.amount,
|
|
144
149
|
settlement: typeof connect === 'function'
|