mppx 0.17.0 → 0.17.3
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 +45 -0
- package/dist/BodyDigest.js +13 -1
- package/dist/Method.d.ts +5 -0
- package/dist/Store.d.ts +225 -0
- package/dist/Store.js +358 -0
- package/dist/cli/cli.js +136 -135
- package/dist/cli/plugins/index.js +12 -11
- package/dist/cli/sessions/Manager.js +12 -1
- package/dist/cli/sessions/store.js +7 -1
- package/dist/cli/utils.d.ts +2 -0
- package/dist/cli/utils.js +6 -0
- package/dist/cli/validate/helpers.d.ts +1 -1
- package/dist/cli/validate/helpers.js +14 -2
- package/dist/client/Mppx.d.ts +1 -1
- package/dist/client/Mppx.js +18 -6
- package/dist/client/internal/Fetch.d.ts +3 -1
- package/dist/client/internal/Fetch.js +68 -3
- package/dist/client/internal/MethodResponse.d.ts +8 -0
- package/dist/client/internal/MethodResponse.js +9 -0
- package/dist/client/internal/ProofRealm.d.ts +3 -3
- package/dist/client/internal/ProofRealm.js +4 -4
- package/dist/client/internal/protocols/Mcp.d.ts +4 -0
- package/dist/client/internal/protocols/Mcp.js +27 -14
- package/dist/identity/Client.js +7 -1
- package/dist/internal/AcceptPayment.d.ts +12 -2
- package/dist/internal/AcceptPayment.js +12 -3
- package/dist/internal/sse.d.ts +21 -0
- package/dist/internal/sse.js +65 -0
- package/dist/internal/version.d.ts +2 -2
- package/dist/internal/version.js +1 -1
- package/dist/mcp/client/McpClient.d.ts +2 -2
- package/dist/mcp/client/McpClient.js +6 -3
- package/dist/proxy/Proxy.d.ts +17 -0
- package/dist/proxy/Proxy.js +116 -3
- package/dist/proxy/internal/Replay.d.ts +105 -0
- package/dist/proxy/internal/Replay.js +257 -0
- package/dist/server/Mppx.d.ts +2 -0
- package/dist/server/Mppx.js +7 -5
- package/dist/server/Transport.js +1 -1
- package/dist/server/internal/html/config.d.ts +7 -1
- package/dist/server/internal/html/config.js +4 -0
- package/dist/stripe/internal/types.d.ts +82 -6
- package/dist/stripe/server/Charge.js +1 -2
- package/dist/stripe/server/internal/html.gen.js +1 -1
- package/dist/tempo/client/Charge.d.ts +9 -0
- package/dist/tempo/client/Charge.js +13 -9
- package/dist/tempo/client/Methods.d.ts +2 -0
- package/dist/tempo/internal/fee-payer.d.ts +85 -10
- package/dist/tempo/internal/fee-payer.js +183 -19
- package/dist/tempo/legacy/session/Chain.js +2 -0
- package/dist/tempo/server/Charge.js +6 -3
- package/dist/tempo/server/Subscription.js +1 -0
- package/dist/tempo/server/internal/html.gen.js +1 -1
- package/dist/tempo/server/internal/transport.d.ts +6 -0
- package/dist/tempo/server/internal/transport.js +21 -21
- package/dist/tempo/session/client/ChannelOps.d.ts +2 -0
- package/dist/tempo/session/client/ChannelStore.d.ts +2 -0
- package/dist/tempo/session/client/ChannelStore.js +5 -0
- package/dist/tempo/session/client/CredentialState.js +2 -0
- package/dist/tempo/session/client/Session.d.ts +37 -2
- package/dist/tempo/session/client/Session.js +111 -7
- package/dist/tempo/session/client/SessionManager.d.ts +2 -1
- package/dist/tempo/session/client/SessionManager.js +60 -9
- package/dist/tempo/session/client/Transports.d.ts +4 -0
- package/dist/tempo/session/client/Transports.js +35 -3
- package/dist/tempo/session/precompile/Chain.js +1 -0
- package/dist/tempo/session/precompile/Voucher.js +20 -7
- package/dist/tempo/session/server/ChannelStore.d.ts +9 -0
- package/dist/tempo/session/server/ChannelStore.js +8 -1
- package/dist/tempo/session/server/MeteredStream.d.ts +4 -0
- package/dist/tempo/session/server/MeteredStream.js +6 -1
- package/dist/tempo/session/server/Session.d.ts +2 -1
- package/dist/tempo/session/server/Session.js +2 -1
- package/dist/tempo/session/server/Settlement.d.ts +4 -2
- package/dist/tempo/session/server/Settlement.js +2 -2
- package/dist/tempo/session/server/Sse.d.ts +59 -0
- package/dist/tempo/session/server/Sse.js +175 -10
- package/dist/tempo/session/server/Ws.js +29 -12
- package/dist/zod.d.ts +2 -1
- package/dist/zod.js +1 -1
- package/package.json +1 -3
- package/dist/stripe/server/internal/html/types.d.ts +0 -2
- package/dist/stripe/server/internal/html/types.js +0 -2
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { Base64, Bytes, Hash } from 'ox';
|
|
2
|
+
import * as Credential from '../../Credential.js';
|
|
3
|
+
const keyPrefix = 'mppx:proxy:replay:';
|
|
4
|
+
/** Applies defaults to replay options. */
|
|
5
|
+
export function resolve(options) {
|
|
6
|
+
const ttl = options.ttl ?? 900_000;
|
|
7
|
+
// AbortSignal.timeout needs a positive integer that fits a 32-bit timer.
|
|
8
|
+
if (!Number.isSafeInteger(ttl) || ttl <= 0 || ttl > 2_147_483_647)
|
|
9
|
+
throw new RangeError('replay.ttl must be a positive integer number of milliseconds up to 2147483647.');
|
|
10
|
+
return {
|
|
11
|
+
maxAttempts: options.maxAttempts ?? 3,
|
|
12
|
+
maxBodySize: options.maxBodySize ?? 1_048_576,
|
|
13
|
+
maxRequestBodySize: options.maxRequestBodySize ?? 1_048_576,
|
|
14
|
+
retryAfter: options.retryAfter ?? 5,
|
|
15
|
+
store: options.store,
|
|
16
|
+
ttl,
|
|
17
|
+
waitUntil: options.waitUntil,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** Returns the request's Payment credential header value, if it carries one. */
|
|
21
|
+
export function credentialOf(request, headerNames = ['authorization']) {
|
|
22
|
+
// Only the headers the route's payment handler verifies can name a replay.
|
|
23
|
+
for (const name of headerNames) {
|
|
24
|
+
const header = request.headers.get(name);
|
|
25
|
+
const payment = header ? Credential.extractPaymentScheme(header) : null;
|
|
26
|
+
if (payment)
|
|
27
|
+
return payment;
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
/** Reads a request body, or returns null when it is larger than maxRequestBodySize. */
|
|
32
|
+
export async function readBody(request, maxRequestBodySize) {
|
|
33
|
+
const length = Number(request.headers.get('content-length'));
|
|
34
|
+
if (Number.isFinite(length) && length > maxRequestBodySize)
|
|
35
|
+
return null;
|
|
36
|
+
if (!request.body)
|
|
37
|
+
return new Uint8Array();
|
|
38
|
+
return keep(request.body, maxRequestBodySize);
|
|
39
|
+
}
|
|
40
|
+
/** Derives the replay key from the credential and the exact request (origin, path, query, method, body) it paid for. */
|
|
41
|
+
export function key(parameters) {
|
|
42
|
+
const bodyHash = Hash.sha256(parameters.body, { as: 'Hex' });
|
|
43
|
+
const input = JSON.stringify([
|
|
44
|
+
parameters.credential,
|
|
45
|
+
parameters.method.toUpperCase(),
|
|
46
|
+
parameters.target,
|
|
47
|
+
bodyHash,
|
|
48
|
+
]);
|
|
49
|
+
return keyPrefix + Hash.sha256(Bytes.fromString(input), { as: 'Hex' }).slice(2);
|
|
50
|
+
}
|
|
51
|
+
/** Rebuilds a request around an already-read body, optionally with another abort signal. */
|
|
52
|
+
export function withBody(request, body, signal, headers) {
|
|
53
|
+
const method = request.method.toUpperCase();
|
|
54
|
+
const hasBody = method !== 'GET' && method !== 'HEAD';
|
|
55
|
+
return new globalThis.Request(request.url, {
|
|
56
|
+
// An empty body stays absent, as on the original request: payment
|
|
57
|
+
// transports tell management requests apart by a missing body.
|
|
58
|
+
body: hasBody && body.byteLength > 0 ? body : null,
|
|
59
|
+
headers: headers ?? request.headers,
|
|
60
|
+
method: request.method,
|
|
61
|
+
redirect: request.redirect,
|
|
62
|
+
signal: signal ?? request.signal,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/** Looks up a delivery and, for a failed one, claims the next upstream attempt. */
|
|
66
|
+
export async function lookup(replay, replayKey) {
|
|
67
|
+
const now = Date.now();
|
|
68
|
+
// Read first: only a failed delivery needs an atomic claim, so unknown
|
|
69
|
+
// credentials never cause a store write.
|
|
70
|
+
const seen = (await replay.store.get(replayKey));
|
|
71
|
+
if (!seen)
|
|
72
|
+
return { type: 'none' };
|
|
73
|
+
if (seen.expires > now && seen.status !== 'failed')
|
|
74
|
+
return { response: respond(replay, seen), type: 'respond' };
|
|
75
|
+
const result = await replay.store.update(replayKey, (current) => {
|
|
76
|
+
const record = current;
|
|
77
|
+
if (!record)
|
|
78
|
+
return { op: 'noop', result: { type: 'none' } };
|
|
79
|
+
if (record.expires <= now)
|
|
80
|
+
return { op: 'delete', result: { type: 'none' } };
|
|
81
|
+
if (record.status !== 'failed' || record.attempts >= replay.maxAttempts)
|
|
82
|
+
return { op: 'noop', result: record };
|
|
83
|
+
const attempts = record.attempts + 1;
|
|
84
|
+
return {
|
|
85
|
+
op: 'set',
|
|
86
|
+
value: { ...record, attempts, status: 'pending' },
|
|
87
|
+
result: {
|
|
88
|
+
attempts,
|
|
89
|
+
receipt: record.receipt,
|
|
90
|
+
requestHeaders: record.requestHeaders,
|
|
91
|
+
type: 'retry',
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
if ('type' in result)
|
|
96
|
+
return result;
|
|
97
|
+
return { response: respond(replay, result), type: 'respond' };
|
|
98
|
+
}
|
|
99
|
+
/** Builds the response for a recorded delivery that is not retried. */
|
|
100
|
+
function respond(replay, record) {
|
|
101
|
+
if (record.status === 'complete')
|
|
102
|
+
return fromRecord(record);
|
|
103
|
+
if (record.status === 'delivered')
|
|
104
|
+
return Response.json({ error: 'The paid response was delivered and is not stored for replay.' }, { status: 410 });
|
|
105
|
+
if (record.status === 'pending')
|
|
106
|
+
return new Response(null, {
|
|
107
|
+
headers: { 'Retry-After': String(replay.retryAfter) },
|
|
108
|
+
status: 202,
|
|
109
|
+
});
|
|
110
|
+
return withReceiptHeader(Response.json({ error: 'The paid upstream request failed.' }, { status: 502 }), record.receipt);
|
|
111
|
+
}
|
|
112
|
+
/** Runs a paid upstream delivery detached from the client and records its outcome. */
|
|
113
|
+
export async function deliver(parameters) {
|
|
114
|
+
const { applyReceipt, attempts, replay, replayKey, requestHeaders } = parameters;
|
|
115
|
+
// Outcomes are kept for ttl from when they are recorded, not from the start.
|
|
116
|
+
const expires = () => Date.now() + replay.ttl;
|
|
117
|
+
await record(replay, replayKey, {
|
|
118
|
+
attempts,
|
|
119
|
+
expires: expires(),
|
|
120
|
+
receipt: null,
|
|
121
|
+
requestHeaders,
|
|
122
|
+
status: 'pending',
|
|
123
|
+
});
|
|
124
|
+
let response;
|
|
125
|
+
try {
|
|
126
|
+
// ttl bounds the wait for the upstream to respond, not how long its body
|
|
127
|
+
// streams: a paid stream keeps going once it has started.
|
|
128
|
+
const controller = new AbortController();
|
|
129
|
+
const timer = setTimeout(() => controller.abort(new DOMException('Replay ttl elapsed.', 'TimeoutError')), replay.ttl);
|
|
130
|
+
let upstream;
|
|
131
|
+
try {
|
|
132
|
+
upstream = await parameters.run(controller.signal);
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
clearTimeout(timer);
|
|
136
|
+
}
|
|
137
|
+
response = await applyReceipt(upstream);
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
const failed = await applyReceipt(Response.json({ error: 'The paid upstream request failed.' }, { status: 502 }));
|
|
141
|
+
await recordFailure(replay, replayKey, attempts, requestHeaders, expires(), failed.headers.get('Payment-Receipt'));
|
|
142
|
+
return failed;
|
|
143
|
+
}
|
|
144
|
+
const receipt = response.headers.get('Payment-Receipt');
|
|
145
|
+
if (response.status >= 500) {
|
|
146
|
+
await recordFailure(replay, replayKey, attempts, requestHeaders, expires(), receipt);
|
|
147
|
+
return response;
|
|
148
|
+
}
|
|
149
|
+
if (!response.body) {
|
|
150
|
+
await record(replay, replayKey, toRecord(response, new Uint8Array(), expires()));
|
|
151
|
+
return response;
|
|
152
|
+
}
|
|
153
|
+
if (/^text\/event-stream/i.test(response.headers.get('content-type') ?? '')) {
|
|
154
|
+
await record(replay, replayKey, { expires: expires(), status: 'delivered' });
|
|
155
|
+
return response;
|
|
156
|
+
}
|
|
157
|
+
// Keep a copy while the client reads the other branch, so a client that
|
|
158
|
+
// disconnects mid-body can still collect the response on retry.
|
|
159
|
+
const [client, kept] = response.body.tee();
|
|
160
|
+
const stored = keep(kept, replay.maxBodySize)
|
|
161
|
+
.then((body) => replay.store.put(replayKey, body
|
|
162
|
+
? toRecord(response, body, expires())
|
|
163
|
+
: { expires: expires(), status: 'delivered' }),
|
|
164
|
+
// The upstream body broke off: let the payer retry the delivery.
|
|
165
|
+
() => recordFailure(replay, replayKey, attempts, requestHeaders, expires(), receipt))
|
|
166
|
+
// A failed background write leaves the record pending until it expires.
|
|
167
|
+
.catch(() => { });
|
|
168
|
+
replay.waitUntil?.(stored);
|
|
169
|
+
return new Response(client, {
|
|
170
|
+
headers: response.headers,
|
|
171
|
+
status: response.status,
|
|
172
|
+
statusText: response.statusText,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
/** Reads a body branch up to maxBodySize, or returns null when it is larger. */
|
|
176
|
+
async function keep(stream, maxBodySize) {
|
|
177
|
+
const reader = stream.getReader();
|
|
178
|
+
const chunks = [];
|
|
179
|
+
let size = 0;
|
|
180
|
+
for (;;) {
|
|
181
|
+
const { done, value } = await reader.read();
|
|
182
|
+
if (done)
|
|
183
|
+
break;
|
|
184
|
+
size += value.byteLength;
|
|
185
|
+
if (size > maxBodySize) {
|
|
186
|
+
void reader.cancel().catch(() => { });
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
chunks.push(value);
|
|
190
|
+
}
|
|
191
|
+
const body = new Uint8Array(size);
|
|
192
|
+
let offset = 0;
|
|
193
|
+
for (const chunk of chunks) {
|
|
194
|
+
body.set(chunk, offset);
|
|
195
|
+
offset += chunk.byteLength;
|
|
196
|
+
}
|
|
197
|
+
return body;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Writes a replay record without letting a store failure break the paid
|
|
201
|
+
* delivery: the payer still gets the upstream response, only replay is lost.
|
|
202
|
+
*/
|
|
203
|
+
async function record(replay, replayKey, value) {
|
|
204
|
+
try {
|
|
205
|
+
await replay.store.put(replayKey, value);
|
|
206
|
+
}
|
|
207
|
+
catch { }
|
|
208
|
+
}
|
|
209
|
+
async function recordFailure(replay, replayKey, attempts, requestHeaders, expires, receipt) {
|
|
210
|
+
await record(replay, replayKey, {
|
|
211
|
+
attempts,
|
|
212
|
+
expires,
|
|
213
|
+
receipt,
|
|
214
|
+
requestHeaders,
|
|
215
|
+
status: 'failed',
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
/** Adds a stored receipt to a response built for a retried delivery. */
|
|
219
|
+
export function withReceiptHeader(response, receipt) {
|
|
220
|
+
if (!receipt)
|
|
221
|
+
return response;
|
|
222
|
+
const headers = new Headers(response.headers);
|
|
223
|
+
headers.set('Payment-Receipt', receipt);
|
|
224
|
+
headers.set('Cache-Control', withPrivateCacheControl(headers.get('Cache-Control')));
|
|
225
|
+
return new Response(response.body, {
|
|
226
|
+
headers,
|
|
227
|
+
status: response.status,
|
|
228
|
+
statusText: response.statusText,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
function withPrivateCacheControl(value) {
|
|
232
|
+
if (!value)
|
|
233
|
+
return 'private';
|
|
234
|
+
const directives = value.split(',').map((directive) => directive.trim().toLowerCase());
|
|
235
|
+
if (directives.includes('private'))
|
|
236
|
+
return value;
|
|
237
|
+
return `${value}, private`;
|
|
238
|
+
}
|
|
239
|
+
function toRecord(response, body, expires) {
|
|
240
|
+
return {
|
|
241
|
+
body: Base64.fromBytes(body),
|
|
242
|
+
expires,
|
|
243
|
+
headers: [...response.headers.entries()],
|
|
244
|
+
responseStatus: response.status,
|
|
245
|
+
status: 'complete',
|
|
246
|
+
statusText: response.statusText,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
function fromRecord(record) {
|
|
250
|
+
const nullBody = [101, 204, 205, 304].includes(record.responseStatus);
|
|
251
|
+
return new Response(nullBody ? null : Base64.toBytes(record.body), {
|
|
252
|
+
headers: record.headers,
|
|
253
|
+
status: record.responseStatus,
|
|
254
|
+
statusText: record.statusText,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=Replay.js.map
|
package/dist/server/Mppx.d.ts
CHANGED
|
@@ -414,6 +414,8 @@ type ConfiguredHandler<transport extends Transport.AnyTransport = Transport.Http
|
|
|
414
414
|
_stableBinding?: Method.StableBindingFn<Method.Method> | undefined;
|
|
415
415
|
/** The offer's payment-stage identity verifiers, if any. */
|
|
416
416
|
_paymentIdentity?: readonly Identity.Verifier[] | undefined;
|
|
417
|
+
/** Whether the route requires identity verifiers (request or payment stage). */
|
|
418
|
+
_identity?: boolean | undefined;
|
|
417
419
|
_transport: Transport.AnyTransport;
|
|
418
420
|
};
|
|
419
421
|
};
|
package/dist/server/Mppx.js
CHANGED
|
@@ -468,6 +468,7 @@ function createMethodFn(parameters) {
|
|
|
468
468
|
],
|
|
469
469
|
_canonicalRequest: PaymentRequest.fromMethod(method, { ...defaults, ...rest }),
|
|
470
470
|
_paymentIdentity: paymentVerifiers.length > 0 ? paymentVerifiers : undefined,
|
|
471
|
+
_identity: identity.length > 0,
|
|
471
472
|
_stableBinding: stableBinding,
|
|
472
473
|
_transport: transport,
|
|
473
474
|
};
|
|
@@ -1875,11 +1876,12 @@ function composeHandlers(handlers, composeOptions, selectOffers) {
|
|
|
1875
1876
|
}
|
|
1876
1877
|
mergedHeaders.set('Content-Type', 'text/html; charset=utf-8');
|
|
1877
1878
|
const firstData = Object.values(dataMap)[0];
|
|
1879
|
+
const entries = await Promise.all(htmlEntries.map(async (entry) => ({
|
|
1880
|
+
challenge: entry.challenge,
|
|
1881
|
+
content: await Html.resolveContent(entry.handler._internal.html.content),
|
|
1882
|
+
})));
|
|
1878
1883
|
const body = Html.render({
|
|
1879
|
-
entries
|
|
1880
|
-
challenge: entry.challenge,
|
|
1881
|
-
content: entry.handler._internal.html.content,
|
|
1882
|
-
})),
|
|
1884
|
+
entries,
|
|
1883
1885
|
dataMap,
|
|
1884
1886
|
formattedAmount: firstData.formattedAmount,
|
|
1885
1887
|
panels: true,
|
|
@@ -1916,11 +1918,11 @@ function composeHandlers(handlers, composeOptions, selectOffers) {
|
|
|
1916
1918
|
composed._internal = { offers, handlers: handlers, selectOffers };
|
|
1917
1919
|
return composed;
|
|
1918
1920
|
}
|
|
1919
|
-
/** Returns the flattened configured offers accepted by a handler. */
|
|
1920
1921
|
/** Whether two verifier lists hold the same verifiers in the same order. */
|
|
1921
1922
|
function sameVerifiers(a, b) {
|
|
1922
1923
|
return a.length === b.length && a.every((verifier, i) => verifier === b[i]);
|
|
1923
1924
|
}
|
|
1925
|
+
/** Returns the flattened configured offers accepted by a handler. */
|
|
1924
1926
|
function getConfiguredOffers(handler) {
|
|
1925
1927
|
const internal = handler._internal;
|
|
1926
1928
|
if (!internal)
|
package/dist/server/Transport.js
CHANGED
|
@@ -98,7 +98,7 @@ export function http(options = {}) {
|
|
|
98
98
|
},
|
|
99
99
|
};
|
|
100
100
|
return Html.render({
|
|
101
|
-
entries: [{ challenge, content: options.html.content }],
|
|
101
|
+
entries: [{ challenge, content: await Html.resolveContent(options.html.content) }],
|
|
102
102
|
dataMap,
|
|
103
103
|
formattedAmount: amount,
|
|
104
104
|
text,
|
|
@@ -2,7 +2,11 @@ import type * as Challenge from '../../../Challenge.js';
|
|
|
2
2
|
import type * as Method from '../../../Method.js';
|
|
3
3
|
export type Options = {
|
|
4
4
|
config: Record<string, unknown>;
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* The payment page's script, or a function that loads it. A loader lets a
|
|
7
|
+
* method import its (large) page bundle only when a page is rendered.
|
|
8
|
+
*/
|
|
9
|
+
content: string | (() => Promise<string>);
|
|
6
10
|
formatAmount: (request: any) => string | Promise<string>;
|
|
7
11
|
text: Text | undefined;
|
|
8
12
|
theme: Theme | undefined;
|
|
@@ -21,6 +25,8 @@ export type Data<method extends Method.Method = Method.Method, config extends Re
|
|
|
21
25
|
};
|
|
22
26
|
};
|
|
23
27
|
export { attrs, classNames, ids, params } from './constants.js';
|
|
28
|
+
/** Resolves {@link Options.content}, loading it when it is a loader function. */
|
|
29
|
+
export declare function resolveContent(content: Options['content']): Promise<string>;
|
|
24
30
|
declare class CssVar {
|
|
25
31
|
readonly name: string;
|
|
26
32
|
constructor(token: string);
|
|
@@ -2,6 +2,10 @@ import { Json } from 'ox';
|
|
|
2
2
|
import { tabScript } from './compose.main.gen.js';
|
|
3
3
|
export { attrs, classNames, ids, params } from './constants.js';
|
|
4
4
|
import { attrs, classNames, ids } from './constants.js';
|
|
5
|
+
/** Resolves {@link Options.content}, loading it when it is a loader function. */
|
|
6
|
+
export async function resolveContent(content) {
|
|
7
|
+
return typeof content === 'function' ? content() : content;
|
|
8
|
+
}
|
|
5
9
|
function logoColorScheme(colorScheme) {
|
|
6
10
|
return colorScheme === 'dark' || colorScheme === 'light'
|
|
7
11
|
? `${classNames.logo}--${colorScheme}`
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as StripeJsTypes from '../../stripe/server/internal/html/types.js';
|
|
2
1
|
/**
|
|
3
2
|
* Duck-typed interface for the Stripe Node SDK (`stripe` npm package).
|
|
4
3
|
* Matches the subset of the API used by mppx for server-side payment verification.
|
|
@@ -31,9 +30,86 @@ export type StripeJs = {
|
|
|
31
30
|
createPaymentMethod(...args: any[]): Promise<Record<string, unknown>>;
|
|
32
31
|
elements(...args: any[]): unknown;
|
|
33
32
|
};
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
33
|
+
/** A nested Stripe.js option object, passed through to Stripe.js as is. */
|
|
34
|
+
type StripeJsObject = {
|
|
35
|
+
readonly [key: string]: any;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Stripe.js Elements appearance (`Appearance` in `@stripe/stripe-js`).
|
|
39
|
+
*
|
|
40
|
+
* @see https://docs.stripe.com/elements/appearance-api
|
|
41
|
+
*/
|
|
42
|
+
export type StripeAppearance = {
|
|
43
|
+
disableAnimations?: boolean | undefined;
|
|
44
|
+
theme?: 'stripe' | 'night' | 'flat' | undefined;
|
|
45
|
+
variables?: StripeJsObject | undefined;
|
|
46
|
+
rules?: StripeJsObject | undefined;
|
|
47
|
+
labels?: 'auto' | 'above' | 'floating' | undefined;
|
|
48
|
+
inputs?: 'spaced' | 'condensed' | undefined;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Options for `stripe.createPaymentMethod` with Elements, without `elements`
|
|
52
|
+
* (`CreatePaymentMethodFromElements` in `@stripe/stripe-js`).
|
|
53
|
+
*
|
|
54
|
+
* Structural so mppx's types don't depend on `@stripe/stripe-js`; its values stay assignable.
|
|
55
|
+
*/
|
|
56
|
+
export type CreatePaymentMethodFromElements = {
|
|
57
|
+
/** Payment method parameters (`PaymentMethodCreateParams`). */
|
|
58
|
+
params?: StripeJsObject | undefined;
|
|
59
|
+
metadata?: {
|
|
60
|
+
readonly [name: string]: string | number | null;
|
|
61
|
+
} | undefined;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Options for `stripe.elements` in payment mode, without the fields mppx sets from the
|
|
65
|
+
* Challenge (`StripeElementsOptionsMode` in `@stripe/stripe-js`).
|
|
66
|
+
*
|
|
67
|
+
* Structural so mppx's types don't depend on `@stripe/stripe-js`; its values stay assignable.
|
|
68
|
+
*/
|
|
69
|
+
export type StripeElementsOptionsMode = {
|
|
70
|
+
adaptivePricing?: {
|
|
71
|
+
allowed?: boolean | undefined;
|
|
72
|
+
} | undefined;
|
|
73
|
+
allowedPaymentMethodTypes?: readonly string[] | undefined;
|
|
74
|
+
appearance?: StripeAppearance | undefined;
|
|
75
|
+
captureMethod?: 'manual' | 'automatic' | 'automatic_async' | undefined;
|
|
76
|
+
capture_method?: 'manual' | 'automatic' | 'automatic_async' | undefined;
|
|
77
|
+
clientSecret?: undefined;
|
|
78
|
+
customPaymentMethods?: readonly StripeJsObject[] | undefined;
|
|
79
|
+
customerOptions?: StripeJsObject | undefined;
|
|
80
|
+
customerSessionClientSecret?: string | undefined;
|
|
81
|
+
externalPaymentMethodTypes?: readonly string[] | undefined;
|
|
82
|
+
fonts?: readonly StripeJsObject[] | undefined;
|
|
83
|
+
loader?: 'auto' | 'always' | 'never' | undefined;
|
|
84
|
+
locale?: string | undefined;
|
|
85
|
+
onBehalfOf?: string | undefined;
|
|
86
|
+
on_behalf_of?: string | undefined;
|
|
87
|
+
paymentMethodConfiguration?: string | undefined;
|
|
88
|
+
payment_method_configuration?: string | undefined;
|
|
89
|
+
paymentMethodOptions?: StripeJsObject | undefined;
|
|
90
|
+
payment_method_options?: StripeJsObject | undefined;
|
|
91
|
+
setupFutureUsage?: 'off_session' | 'on_session' | null | undefined;
|
|
92
|
+
setup_future_usage?: 'off_session' | 'on_session' | null | undefined;
|
|
93
|
+
syncAddressCheckbox?: 'billing' | 'shipping' | 'none' | undefined;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Options for the Stripe.js Payment Element (`StripePaymentElementOptions` in `@stripe/stripe-js`).
|
|
97
|
+
*
|
|
98
|
+
* Structural so mppx's types don't depend on `@stripe/stripe-js`; its values stay assignable.
|
|
99
|
+
*/
|
|
100
|
+
export type StripePaymentElementOptions = {
|
|
101
|
+
applePay?: StripeJsObject | undefined;
|
|
102
|
+
business?: {
|
|
103
|
+
name: string;
|
|
104
|
+
} | undefined;
|
|
105
|
+
defaultValues?: StripeJsObject | undefined;
|
|
106
|
+
fields?: StripeJsObject | undefined;
|
|
107
|
+
layout?: string | StripeJsObject | undefined;
|
|
108
|
+
paymentMethodOrder?: readonly string[] | undefined;
|
|
109
|
+
readOnly?: boolean | undefined;
|
|
110
|
+
terms?: StripeJsObject | undefined;
|
|
111
|
+
walletOptions?: StripeJsObject | undefined;
|
|
112
|
+
wallets?: StripeJsObject | undefined;
|
|
113
|
+
};
|
|
114
|
+
export {};
|
|
39
115
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -5,7 +5,6 @@ import { stripePreviewVersion } from '../internal/constants.js';
|
|
|
5
5
|
import * as PaymentIntent from '../internal/payment-intent.js';
|
|
6
6
|
import * as Methods from '../Methods.js';
|
|
7
7
|
import { buildAnalytics } from './internal/analytics.js';
|
|
8
|
-
import { html as htmlContent } from './internal/html.gen.js';
|
|
9
8
|
/**
|
|
10
9
|
* Stripe's general minimum charge amounts in each currency's smallest unit.
|
|
11
10
|
* Payment methods with lower provider-specific exceptions remain conservatively
|
|
@@ -91,7 +90,7 @@ export function charge(parameters) {
|
|
|
91
90
|
html: 'publishableKey' in htmlConfig && htmlConfig.publishableKey && htmlConfig.createTokenUrl
|
|
92
91
|
? {
|
|
93
92
|
config: htmlConfig,
|
|
94
|
-
content:
|
|
93
|
+
content: async () => (await import('./internal/html.gen.js')).html,
|
|
95
94
|
formatAmount: (request) => {
|
|
96
95
|
try {
|
|
97
96
|
const formatter = new Intl.NumberFormat('en', {
|