mppx 0.9.0 → 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 +8 -0
- package/dist/Errors.d.ts +10 -0
- package/dist/Errors.js +12 -0
- package/dist/Mcp.d.ts +9 -1
- package/dist/Mcp.js +18 -0
- package/dist/Method.d.ts +7 -0
- package/dist/cli/cli.js +134 -134
- package/dist/cli/plugins/index.js +12 -12
- package/dist/client/internal/protocols/Mcp.js +2 -1
- package/dist/mcp/client/McpClient.js +22 -10
- package/dist/mcp/server/Transport.d.ts +2 -2
- package/dist/mcp/server/Transport.js +11 -4
- package/dist/server/Mppx.d.ts +6 -0
- package/dist/server/Mppx.js +75 -6
- package/dist/server/Transport.js +8 -15
- 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/Tokens.d.ts +13 -0
- package/dist/tempo/Tokens.js +13 -0
- package/dist/tempo/client/Charge.d.ts +1 -1
- package/dist/tempo/client/Charge.js +17 -0
- package/dist/tempo/index.d.ts +1 -0
- package/dist/tempo/index.js +1 -0
- package/dist/tempo/internal/fee-payer.d.ts +1 -1
- package/dist/tempo/internal/fee-payer.js +2 -12
- package/dist/tempo/internal/fee-token.d.ts +2 -0
- package/dist/tempo/internal/fee-token.js +7 -0
- 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/SessionManager.js +1 -2
- package/dist/tempo/session/server/Session.js +5 -2
- package/dist/x402/mcp.js +4 -3
- package/package.json +1 -1
|
@@ -77,7 +77,8 @@ export function paymentRequiredData(message) {
|
|
|
77
77
|
if (!message)
|
|
78
78
|
return undefined;
|
|
79
79
|
if ('error' in message) {
|
|
80
|
-
if (message.error?.code !== Mcp.paymentRequiredCode
|
|
80
|
+
if (message.error?.code !== Mcp.paymentRequiredCode &&
|
|
81
|
+
message.error?.code !== Mcp.paymentVerificationFailedCode)
|
|
81
82
|
return undefined;
|
|
82
83
|
return paymentRequiredDataFromValue(message.error.data);
|
|
83
84
|
}
|
|
@@ -5,6 +5,7 @@ import * as AcceptPayment from '../../internal/AcceptPayment.js';
|
|
|
5
5
|
import * as core_Mcp from '../../Mcp.js';
|
|
6
6
|
import * as z from '../../zod.js';
|
|
7
7
|
const MPPX_MCP_CLIENT_WRAPPER = Symbol.for('mppx.mcp.client.wrapper');
|
|
8
|
+
const maxPaymentAttempts = 3;
|
|
8
9
|
/**
|
|
9
10
|
* Adds automatic payment handling to an MCP SDK client.
|
|
10
11
|
*
|
|
@@ -80,7 +81,8 @@ export function isPaymentRequiredError(error) {
|
|
|
80
81
|
return false;
|
|
81
82
|
if (!('code' in error) || !('message' in error))
|
|
82
83
|
return false;
|
|
83
|
-
|
|
84
|
+
const code = error.code;
|
|
85
|
+
if (code !== core_Mcp.paymentRequiredCode && code !== core_Mcp.paymentVerificationFailedCode)
|
|
84
86
|
return false;
|
|
85
87
|
return isPaymentRequiredData(error.data);
|
|
86
88
|
}
|
|
@@ -98,7 +100,7 @@ async function createCredential(challenge, config) {
|
|
|
98
100
|
function createPaymentAwareCallTool(callTool, config) {
|
|
99
101
|
const methods = config.methods.flat();
|
|
100
102
|
const paymentPreferences = AcceptPayment.resolve(methods, config.paymentPreferences);
|
|
101
|
-
const retryWithPayment = async (params, call, paymentRequired, cause) => {
|
|
103
|
+
const retryWithPayment = async (params, call, paymentRequired, cause, attemptsRemaining = maxPaymentAttempts) => {
|
|
102
104
|
const challenges = paymentRequired.challenges;
|
|
103
105
|
const candidates = AcceptPayment.selectChallengeCandidates(challenges, methods, paymentPreferences.entries);
|
|
104
106
|
const orderedCandidates = config.orderChallenges
|
|
@@ -122,14 +124,24 @@ function createPaymentAwareCallTool(callTool, config) {
|
|
|
122
124
|
methods,
|
|
123
125
|
});
|
|
124
126
|
const parsed = Credential.deserialize(credential);
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
127
|
+
try {
|
|
128
|
+
const retryResult = await callTool({
|
|
129
|
+
...params,
|
|
130
|
+
_meta: {
|
|
131
|
+
...params._meta,
|
|
132
|
+
[core_Mcp.credentialMetaKey]: parsed,
|
|
133
|
+
},
|
|
134
|
+
}, call.resultSchema, call.requestOptions);
|
|
135
|
+
const nextPaymentRequired = getPaymentRequiredMeta(retryResult);
|
|
136
|
+
if (nextPaymentRequired && attemptsRemaining > 1)
|
|
137
|
+
return retryWithPayment(params, call, nextPaymentRequired, retryResult, attemptsRemaining - 1);
|
|
138
|
+
return withReceipt(retryResult);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
if (!isPaymentRequiredError(error) || attemptsRemaining <= 1)
|
|
142
|
+
throw error;
|
|
143
|
+
return retryWithPayment(params, call, error.data, error, attemptsRemaining - 1);
|
|
144
|
+
}
|
|
133
145
|
};
|
|
134
146
|
return async (params, call) => {
|
|
135
147
|
try {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CallToolResult, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
-
import
|
|
2
|
+
import * as Credential from '../../Credential.js';
|
|
3
3
|
import * as core_Mcp from '../../Mcp.js';
|
|
4
4
|
import * as Transport from '../../server/Transport.js';
|
|
5
5
|
/**
|
|
@@ -18,7 +18,7 @@ export type McpSdk = Transport.Transport<Extra, McpError, CallToolResult>;
|
|
|
18
18
|
* MCP SDK transport for server-side payment handling with `@modelcontextprotocol/sdk`.
|
|
19
19
|
*
|
|
20
20
|
* - Reads credentials from `_meta["org.paymentauth/credential"]`
|
|
21
|
-
* -
|
|
21
|
+
* - Maps payment errors to their specification-defined JSON-RPC codes
|
|
22
22
|
* - Attaches receipts via `_meta["org.paymentauth/receipt"]` on tool results
|
|
23
23
|
*
|
|
24
24
|
* @example
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as Credential from '../../Credential.js';
|
|
1
2
|
import * as core_Mcp from '../../Mcp.js';
|
|
2
3
|
import * as Transport from '../../server/Transport.js';
|
|
3
4
|
import * as McpCredential from '../internal/Credential.js';
|
|
@@ -5,7 +6,7 @@ import * as McpCredential from '../internal/Credential.js';
|
|
|
5
6
|
* MCP SDK transport for server-side payment handling with `@modelcontextprotocol/sdk`.
|
|
6
7
|
*
|
|
7
8
|
* - Reads credentials from `_meta["org.paymentauth/credential"]`
|
|
8
|
-
* -
|
|
9
|
+
* - Maps payment errors to their specification-defined JSON-RPC codes
|
|
9
10
|
* - Attaches receipts via `_meta["org.paymentauth/receipt"]` on tool results
|
|
10
11
|
*
|
|
11
12
|
* @example
|
|
@@ -41,7 +42,13 @@ export function mcpSdk() {
|
|
|
41
42
|
};
|
|
42
43
|
},
|
|
43
44
|
getCredential(extra) {
|
|
44
|
-
|
|
45
|
+
const value = extra._meta?.[core_Mcp.credentialMetaKey];
|
|
46
|
+
if (value === undefined)
|
|
47
|
+
return null;
|
|
48
|
+
const parsed = McpCredential.parse(value);
|
|
49
|
+
if (!parsed)
|
|
50
|
+
throw new Credential.InvalidCredentialEncodingError();
|
|
51
|
+
return parsed.value;
|
|
45
52
|
},
|
|
46
53
|
async respondChallenge({ challenge, error }) {
|
|
47
54
|
if (!McpErrorClass) {
|
|
@@ -55,8 +62,8 @@ export function mcpSdk() {
|
|
|
55
62
|
throw err;
|
|
56
63
|
}
|
|
57
64
|
}
|
|
58
|
-
return new McpErrorClass(core_Mcp.
|
|
59
|
-
httpStatus: 402,
|
|
65
|
+
return new McpErrorClass(core_Mcp.errorCode(error), error?.message ?? 'Payment Required', {
|
|
66
|
+
httpStatus: error?.status ?? 402,
|
|
60
67
|
challenges: [challenge],
|
|
61
68
|
...(error && { problem: error.toProblemDetails(challenge.id) }),
|
|
62
69
|
});
|
package/dist/server/Mppx.d.ts
CHANGED
|
@@ -99,7 +99,13 @@ export type PaymentSuccessContext<method extends Method.Method = Method.Method,
|
|
|
99
99
|
input?: Transport.InputOf<transport> | undefined;
|
|
100
100
|
method: ServerMethodDescriptor<method>;
|
|
101
101
|
receipt: Receipt.Receipt;
|
|
102
|
+
/** Canonical request represented by the challenge. */
|
|
102
103
|
request: z.output<method['schema']['request']>;
|
|
104
|
+
/**
|
|
105
|
+
* Resolved method input before request-schema output transforms. Absent during
|
|
106
|
+
* standalone credential verification when no route options are supplied.
|
|
107
|
+
*/
|
|
108
|
+
requestInput?: z.input<method['schema']['request']> | undefined;
|
|
103
109
|
}>;
|
|
104
110
|
/** Options for standalone credential verification. */
|
|
105
111
|
export type VerifyCredentialOptions = {
|
package/dist/server/Mppx.js
CHANGED
|
@@ -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
|
}));
|
|
@@ -280,6 +281,7 @@ export function create(config) {
|
|
|
280
281
|
parsedCredential,
|
|
281
282
|
parsedRequest,
|
|
282
283
|
request,
|
|
284
|
+
requestInput: shouldValidateRoute ? request : undefined,
|
|
283
285
|
};
|
|
284
286
|
}
|
|
285
287
|
async function validateCredentialFn(input, options) {
|
|
@@ -293,7 +295,7 @@ export function create(config) {
|
|
|
293
295
|
// broadcastCredential: single-call end-to-end validation and broadcast
|
|
294
296
|
async function broadcastCredentialFn(input, options) {
|
|
295
297
|
const prepared = await prepareStandaloneCredential(input, options, { emitFailures: true });
|
|
296
|
-
const { method: mi, parsedCredential, parsedRequest, request, envelope } = prepared;
|
|
298
|
+
const { method: mi, parsedCredential, parsedRequest, request, requestInput, envelope, } = prepared;
|
|
297
299
|
const emitStandalonePaymentFailed = async (parameters) => {
|
|
298
300
|
await serverEvents.emit('payment.failed', createPaymentFailedContext({
|
|
299
301
|
capturedRequest: options?.capturedRequest,
|
|
@@ -313,7 +315,7 @@ export function create(config) {
|
|
|
313
315
|
receipt = await broadcast({ credential: parsedCredential, envelope, request });
|
|
314
316
|
}
|
|
315
317
|
catch (e) {
|
|
316
|
-
const error = e instanceof Errors.PaymentError ? e : new Errors.
|
|
318
|
+
const error = e instanceof Errors.PaymentError ? e : new Errors.InternalPaymentError();
|
|
317
319
|
await emitStandalonePaymentFailed({
|
|
318
320
|
challenge: prepared.credential.challenge,
|
|
319
321
|
credential: parsedCredential,
|
|
@@ -331,6 +333,7 @@ export function create(config) {
|
|
|
331
333
|
method: mi,
|
|
332
334
|
receipt,
|
|
333
335
|
request: parsedRequest,
|
|
336
|
+
...(requestInput !== undefined && { requestInput }),
|
|
334
337
|
}));
|
|
335
338
|
return receipt;
|
|
336
339
|
}
|
|
@@ -548,7 +551,11 @@ function createMethodFn(parameters) {
|
|
|
548
551
|
// Credential was provided but malformed
|
|
549
552
|
if (credentialError) {
|
|
550
553
|
const reason = getSafeCredentialReason(credentialError);
|
|
551
|
-
const error =
|
|
554
|
+
const error = credentialError instanceof Errors.PaymentError
|
|
555
|
+
? credentialError
|
|
556
|
+
: reason
|
|
557
|
+
? new Errors.MalformedCredentialError({ reason })
|
|
558
|
+
: new Errors.InternalPaymentError();
|
|
552
559
|
await emitPaymentFailed({
|
|
553
560
|
challenge,
|
|
554
561
|
credential: null,
|
|
@@ -610,6 +617,7 @@ function createMethodFn(parameters) {
|
|
|
610
617
|
method,
|
|
611
618
|
receipt: authorized.receipt,
|
|
612
619
|
request: parsedRequest,
|
|
620
|
+
requestInput: request,
|
|
613
621
|
}));
|
|
614
622
|
return success(authorized.receipt, {
|
|
615
623
|
managementResponse: authorized.response,
|
|
@@ -619,7 +627,7 @@ function createMethodFn(parameters) {
|
|
|
619
627
|
catch (e) {
|
|
620
628
|
if (!(e instanceof Errors.PaymentError))
|
|
621
629
|
console.error('mppx: internal authorization error', e);
|
|
622
|
-
const error = e instanceof Errors.PaymentError ? e : new Errors.
|
|
630
|
+
const error = e instanceof Errors.PaymentError ? e : new Errors.InternalPaymentError();
|
|
623
631
|
await emitPaymentFailed({
|
|
624
632
|
challenge,
|
|
625
633
|
credential: null,
|
|
@@ -792,7 +800,7 @@ function createMethodFn(parameters) {
|
|
|
792
800
|
catch (e) {
|
|
793
801
|
if (!(e instanceof Errors.PaymentError))
|
|
794
802
|
console.error('mppx: internal verification error', e);
|
|
795
|
-
const error = e instanceof Errors.PaymentError ? e : new Errors.
|
|
803
|
+
const error = e instanceof Errors.PaymentError ? e : new Errors.InternalPaymentError();
|
|
796
804
|
await emitPaymentFailed({
|
|
797
805
|
challenge,
|
|
798
806
|
credential: parsedCredential,
|
|
@@ -832,6 +840,7 @@ function createMethodFn(parameters) {
|
|
|
832
840
|
method,
|
|
833
841
|
receipt: receiptData,
|
|
834
842
|
request: parsedRequest,
|
|
843
|
+
requestInput: request,
|
|
835
844
|
}));
|
|
836
845
|
return success(receiptData, {
|
|
837
846
|
challengeId: credential.challenge.id,
|
|
@@ -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)
|
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';
|
|
@@ -147,17 +147,20 @@ export function mcp() {
|
|
|
147
147
|
},
|
|
148
148
|
getCredential(request) {
|
|
149
149
|
const meta = request.params?._meta;
|
|
150
|
-
const
|
|
151
|
-
if (
|
|
150
|
+
const value = meta?.[core_Mcp.credentialMetaKey];
|
|
151
|
+
if (value === undefined)
|
|
152
152
|
return null;
|
|
153
|
-
|
|
153
|
+
const parsed = McpCredential.parse(value);
|
|
154
|
+
if (!parsed)
|
|
155
|
+
throw new Credential.InvalidCredentialEncodingError();
|
|
156
|
+
return parsed.value;
|
|
154
157
|
},
|
|
155
158
|
respondChallenge({ challenge, input, error }) {
|
|
156
159
|
return {
|
|
157
160
|
jsonrpc: '2.0',
|
|
158
161
|
id: input.id,
|
|
159
162
|
error: {
|
|
160
|
-
code:
|
|
163
|
+
code: core_Mcp.errorCode(error),
|
|
161
164
|
message: error?.message ?? 'Payment Required',
|
|
162
165
|
data: {
|
|
163
166
|
httpStatus: error?.status ?? 402,
|
|
@@ -187,16 +190,6 @@ export function mcp() {
|
|
|
187
190
|
},
|
|
188
191
|
});
|
|
189
192
|
}
|
|
190
|
-
/** @internal */
|
|
191
|
-
function mcpErrorCode(error) {
|
|
192
|
-
if (!error)
|
|
193
|
-
return core_Mcp.paymentRequiredCode;
|
|
194
|
-
if (error instanceof Errors.MalformedCredentialError)
|
|
195
|
-
return -32602;
|
|
196
|
-
if (error instanceof Errors.PaymentRequiredError)
|
|
197
|
-
return core_Mcp.paymentRequiredCode;
|
|
198
|
-
return core_Mcp.paymentVerificationFailedCode;
|
|
199
|
-
}
|
|
200
193
|
export function safeUrl(url) {
|
|
201
194
|
try {
|
|
202
195
|
if (url instanceof URL)
|
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'
|
|
@@ -3,6 +3,8 @@ import { charge as evmCharge } from '../../evm/server/Charge.js';
|
|
|
3
3
|
import * as tempoDefaults from '../../tempo/internal/defaults.js';
|
|
4
4
|
import { charge as tempoCharge } from '../../tempo/server/Charge.js';
|
|
5
5
|
import { session as tempoSession } from '../../tempo/session/server/Session.js';
|
|
6
|
+
import * as z from '../../zod.js';
|
|
7
|
+
import * as PaymentIntent from '../internal/payment-intent.js';
|
|
6
8
|
import { charge as charge_ } from './Charge.js';
|
|
7
9
|
import { findOrCreateDepositAddress as _findOrCreateDepositAddress } from './internal/deposit-address.js';
|
|
8
10
|
import { recordCryptoPayment } from './internal/record-payment.js';
|
|
@@ -96,14 +98,14 @@ export function stripe(parameters) {
|
|
|
96
98
|
const handler = callMetadata
|
|
97
99
|
? createPaymentSuccessHandler(client, 'tempo', connect, { ...metadata, ...callMetadata })
|
|
98
100
|
: tempoPaymentHandler;
|
|
99
|
-
return tempoCharge({
|
|
101
|
+
return withPaymentIntentInput(tempoCharge({
|
|
100
102
|
currency: tempoCurrency,
|
|
101
103
|
recipient,
|
|
102
104
|
...(!livemode && { testnet: true }),
|
|
103
105
|
canOffer: cryptoCanOffer,
|
|
104
106
|
onPaymentSuccess: handler,
|
|
105
107
|
...rest,
|
|
106
|
-
});
|
|
108
|
+
}));
|
|
107
109
|
}
|
|
108
110
|
function makeTempoSession(params) {
|
|
109
111
|
const { recipient, ...rest } = params;
|
|
@@ -119,14 +121,14 @@ export function stripe(parameters) {
|
|
|
119
121
|
const handler = callMetadata
|
|
120
122
|
? createPaymentSuccessHandler(client, 'base', connect, { ...metadata, ...callMetadata })
|
|
121
123
|
: basePaymentHandler;
|
|
122
|
-
return evmCharge({
|
|
124
|
+
return withPaymentIntentInput(evmCharge({
|
|
123
125
|
currency: livemode ? EvmAssets.base.USDC : EvmAssets.baseSepolia.USDC,
|
|
124
126
|
recipient,
|
|
125
127
|
x402,
|
|
126
128
|
canOffer: cryptoCanOffer,
|
|
127
129
|
onPaymentSuccess: handler,
|
|
128
130
|
...rest,
|
|
129
|
-
});
|
|
131
|
+
}));
|
|
130
132
|
}
|
|
131
133
|
const defaultMethodBuilders = {
|
|
132
134
|
tempo: (addresses) => {
|
|
@@ -180,7 +182,7 @@ export function stripe(parameters) {
|
|
|
180
182
|
const canOffer = m.canOffer
|
|
181
183
|
? (params) => cryptoCanOffer(params) && m.canOffer(params)
|
|
182
184
|
: cryptoCanOffer;
|
|
183
|
-
result.push({ ...m, canOffer, onPaymentSuccess });
|
|
185
|
+
result.push(withPaymentIntentInput({ ...m, canOffer, onPaymentSuccess }));
|
|
184
186
|
}
|
|
185
187
|
}
|
|
186
188
|
}
|
|
@@ -267,16 +269,69 @@ function customRails(additional) {
|
|
|
267
269
|
}
|
|
268
270
|
function createPaymentSuccessHandler(client, network, connect, metadata) {
|
|
269
271
|
return (params) => {
|
|
270
|
-
const { receipt, request } = params;
|
|
272
|
+
const { receipt, request, requestInput } = params;
|
|
271
273
|
if (receipt?.reference && request?.amount) {
|
|
274
|
+
const resolvedMetadata = {
|
|
275
|
+
...metadata,
|
|
276
|
+
...requestInput?.paymentIntentOptions?.metadata,
|
|
277
|
+
};
|
|
272
278
|
return recordCryptoPayment(client, {
|
|
273
279
|
network,
|
|
274
280
|
reference: receipt.reference,
|
|
275
281
|
amount: String(request.amount),
|
|
276
282
|
...(connect && { connect }),
|
|
277
|
-
...(
|
|
283
|
+
...(Object.keys(resolvedMetadata).length > 0 && { metadata: resolvedMetadata }),
|
|
278
284
|
});
|
|
279
285
|
}
|
|
280
286
|
};
|
|
281
287
|
}
|
|
288
|
+
/**
|
|
289
|
+
* Extends a rail's server-only input with Stripe PaymentIntent options while
|
|
290
|
+
* keeping its canonical request unchanged. The schema strips the options
|
|
291
|
+
* before challenge serialization, and delegated lifecycle hooks receive the
|
|
292
|
+
* underlying rail request without Stripe-only fields. The wrapper retains the
|
|
293
|
+
* options only in `requestInput` for payment-success recording.
|
|
294
|
+
*/
|
|
295
|
+
function withPaymentIntentInput(method) {
|
|
296
|
+
const baseSchema = method.schema.request;
|
|
297
|
+
const baseRequest = method.request;
|
|
298
|
+
const baseRespond = method.respond;
|
|
299
|
+
const baseBroadcast = method.broadcast;
|
|
300
|
+
const baseValidate = method.validate;
|
|
301
|
+
const baseVerify = method.verify;
|
|
302
|
+
return {
|
|
303
|
+
...method,
|
|
304
|
+
// Accept Stripe-only options without changing the canonical rail schema.
|
|
305
|
+
schema: {
|
|
306
|
+
...method.schema,
|
|
307
|
+
request: z.pipe(z.custom(), z.transform((input) => {
|
|
308
|
+
const { paymentIntentOptions, ...request } = input;
|
|
309
|
+
z.optional(PaymentIntent.Schema).parse(paymentIntentOptions);
|
|
310
|
+
// Only the base schema's output is included in the challenge.
|
|
311
|
+
return baseSchema.parse(request);
|
|
312
|
+
})),
|
|
313
|
+
},
|
|
314
|
+
async request(context) {
|
|
315
|
+
const { paymentIntentOptions, ...request } = context.request;
|
|
316
|
+
const resolved = baseRequest ? await baseRequest({ ...context, request }) : request;
|
|
317
|
+
return { ...resolved, paymentIntentOptions };
|
|
318
|
+
},
|
|
319
|
+
...(baseRespond && {
|
|
320
|
+
respond: (context) => baseRespond(withoutPaymentIntentOptions(context)),
|
|
321
|
+
}),
|
|
322
|
+
...(baseBroadcast && {
|
|
323
|
+
broadcast: (context) => baseBroadcast(withoutPaymentIntentOptions(context)),
|
|
324
|
+
}),
|
|
325
|
+
...(baseValidate && {
|
|
326
|
+
validate: (context) => baseValidate(withoutPaymentIntentOptions(context)),
|
|
327
|
+
}),
|
|
328
|
+
...(baseVerify && {
|
|
329
|
+
verify: (context) => baseVerify(withoutPaymentIntentOptions(context)),
|
|
330
|
+
}),
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
function withoutPaymentIntentOptions(context) {
|
|
334
|
+
const { paymentIntentOptions: _, ...request } = context.request;
|
|
335
|
+
return { ...context, request };
|
|
336
|
+
}
|
|
282
337
|
//# sourceMappingURL=Methods.js.map
|