mppx 0.14.1 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/README.md +1 -1
- package/dist/Expires.js +1 -1
- package/dist/Store.d.ts +2 -2
- package/dist/Store.js +13 -3
- package/dist/cli/cli.js +137 -131
- package/dist/cli/plugins/index.js +11 -11
- package/dist/cli/validate/payment.d.ts +12 -0
- package/dist/cli/validate/payment.js +113 -14
- package/dist/client/Mppx.d.ts +13 -3
- package/dist/client/Mppx.js +47 -22
- package/dist/client/internal/Fetch.d.ts +11 -0
- package/dist/client/internal/Fetch.js +46 -8
- package/dist/client/internal/ProofRealm.d.ts +21 -0
- package/dist/client/internal/ProofRealm.js +55 -0
- package/dist/{attestation → extensions/identity}/Constants.d.ts +2 -2
- package/dist/{attestation → extensions/identity}/Constants.js +2 -2
- package/dist/extensions/identity/Types.d.ts +21 -0
- package/dist/extensions/identity/index.d.ts +7 -0
- package/dist/extensions/identity/index.js +6 -0
- package/dist/{attestation → extensions/identity}/internal/HttpMessageSignature.d.ts +3 -3
- package/dist/{attestation → extensions/identity}/internal/HttpMessageSignature.js +12 -10
- package/dist/extensions/identity/internal/SigningContext.d.ts +6 -0
- package/dist/{attestation → extensions/identity}/internal/SigningContext.js +3 -3
- package/dist/extensions/identity/internal/Verification.d.ts +9 -0
- package/dist/extensions/identity/internal/Verification.js +10 -0
- package/dist/{tap → extensions/identity/tap}/Constants.js +1 -1
- package/dist/extensions/identity/tap/client/index.d.ts +32 -0
- package/dist/{tap → extensions/identity/tap}/client/index.js +13 -9
- package/dist/extensions/identity/tap/server/index.d.ts +27 -0
- package/dist/{tap → extensions/identity/tap}/server/index.js +12 -4
- package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/Constants.js +1 -1
- package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/client/index.d.ts +6 -5
- package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/client/index.js +5 -5
- package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/server/index.d.ts +6 -5
- package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/server/index.js +6 -4
- package/dist/identity/Client.d.ts +34 -0
- package/dist/identity/Client.js +133 -0
- package/dist/identity/Server.d.ts +46 -0
- package/dist/identity/Server.js +145 -0
- package/dist/identity/Types.d.ts +90 -0
- package/dist/identity/Types.js +2 -0
- package/dist/{attestation → identity}/index.d.ts +2 -2
- package/dist/{attestation → identity}/index.js +1 -2
- package/dist/identity/internal/SigningContext.d.ts +6 -0
- package/dist/identity/internal/SigningContext.js +11 -0
- package/dist/integrations/x402/Evm.d.ts +2 -0
- package/dist/internal/version.d.ts +2 -2
- package/dist/internal/version.js +1 -1
- package/dist/mcp/client/McpClient.d.ts +5 -0
- package/dist/mcp/client/McpClient.js +2 -0
- package/dist/middlewares/express.js +18 -6
- package/dist/proxy/Proxy.js +10 -5
- package/dist/proxy/Service.d.ts +42 -4
- package/dist/proxy/Service.js +21 -5
- package/dist/server/Mppx.d.ts +32 -8
- package/dist/server/Mppx.js +144 -54
- package/dist/stripe/server/internal/html.gen.js +1 -1
- package/dist/tempo/Methods.d.ts +5 -0
- package/dist/tempo/Methods.js +1 -0
- package/dist/tempo/client/Subscription.d.ts +5 -0
- package/dist/tempo/internal/charge.js +2 -1
- package/dist/tempo/internal/fee-payer.d.ts +0 -2
- package/dist/tempo/internal/fee-payer.js +0 -4
- package/dist/tempo/server/Charge.js +4 -0
- package/dist/tempo/server/Methods.d.ts +26 -0
- package/dist/tempo/server/Subscription.d.ts +5 -0
- package/dist/tempo/server/Subscription.js +8 -5
- package/dist/tempo/server/internal/html.gen.js +1 -1
- package/dist/tempo/session/client/Runtime.d.ts +2 -0
- package/dist/tempo/session/client/Session.js +1 -1
- package/dist/tempo/session/client/SessionManager.d.ts +6 -0
- package/dist/tempo/session/client/SessionManager.js +14 -7
- package/dist/tempo/session/client/Transports.d.ts +12 -3
- package/dist/tempo/session/client/Transports.js +37 -11
- package/dist/tempo/session/precompile/Chain.js +0 -3
- package/dist/tempo/session/server/Ws.d.ts +5 -2
- package/dist/tempo/session/server/Ws.js +11 -2
- package/dist/tempo/subscription/Store.d.ts +7 -1
- package/dist/tempo/subscription/Store.js +66 -13
- package/dist/tempo/subscription/Types.d.ts +2 -0
- package/package.json +15 -11
- package/dist/attestation/Client.d.ts +0 -17
- package/dist/attestation/Client.js +0 -28
- package/dist/attestation/Server.d.ts +0 -4
- package/dist/attestation/Server.js +0 -8
- package/dist/attestation/Types.d.ts +0 -76
- package/dist/attestation/internal/SigningContext.d.ts +0 -4
- package/dist/tap/client/index.d.ts +0 -26
- package/dist/tap/server/index.d.ts +0 -20
- /package/dist/{attestation → extensions/identity}/Types.js +0 -0
- /package/dist/{tap → extensions/identity/tap}/Constants.d.ts +0 -0
- /package/dist/{tap → extensions/identity/tap}/Types.d.ts +0 -0
- /package/dist/{tap → extensions/identity/tap}/Types.js +0 -0
- /package/dist/{tap → extensions/identity/tap}/index.d.ts +0 -0
- /package/dist/{tap → extensions/identity/tap}/index.js +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/Constants.d.ts +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/Types.d.ts +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/Types.js +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/index.d.ts +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/index.js +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/internal/JwkThumbprint.d.ts +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/internal/JwkThumbprint.js +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/internal/SignatureAgent.d.ts +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/internal/SignatureAgent.js +0 -0
|
@@ -377,6 +377,8 @@ export type SessionManagerRuntime = RuntimeState & {
|
|
|
377
377
|
lastChallenge: TempoSessionChallenge | null;
|
|
378
378
|
/** Last HTTP resource URL usable for management POSTs. */
|
|
379
379
|
lastUrl: RequestInfo | URL | null;
|
|
380
|
+
/** Headers of the last HTTP request, whose application Authorization management POSTs keep. */
|
|
381
|
+
lastHeaders?: HeadersInit | undefined;
|
|
380
382
|
/** Active WebSocket payment session bookkeeping, when a socket is open. */
|
|
381
383
|
socketSession: ActiveSocketSession | null;
|
|
382
384
|
};
|
|
@@ -323,7 +323,7 @@ export function session(parameters = {}) {
|
|
|
323
323
|
},
|
|
324
324
|
};
|
|
325
325
|
return wrapSseResponse({
|
|
326
|
-
onNeedVoucher: (event, streamSignal) => handleSseNeedVoucher({ challenge, driver, input, signal: streamSignal }, event),
|
|
326
|
+
onNeedVoucher: (event, streamSignal) => handleSseNeedVoucher({ challenge, driver, headers, input, signal: streamSignal }, event),
|
|
327
327
|
onReceipt() { },
|
|
328
328
|
response,
|
|
329
329
|
signal,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Hex } from 'ox';
|
|
2
2
|
import { type Address } from 'viem';
|
|
3
|
+
import * as ProofRealm from '../../../client/internal/ProofRealm.js';
|
|
3
4
|
import * as Account from '../../../viem/Account.js';
|
|
4
5
|
import * as Client from '../../../viem/Client.js';
|
|
5
6
|
import { type ChannelStore } from '../client/ChannelStore.js';
|
|
@@ -73,6 +74,11 @@ export declare namespace sessionManager {
|
|
|
73
74
|
autoSwap?: sessionPlugin.Parameters['autoSwap'];
|
|
74
75
|
/** Enables same-route HEAD bootstrap from a server session snapshot before opening a new channel. */
|
|
75
76
|
bootstrap?: boolean | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Server origins allowed to request bootstrap proofs for a realm other than their hostname,
|
|
79
|
+
* mapped to that realm, such as `{ 'https://api.example.com': 'MPP Payment' }`.
|
|
80
|
+
*/
|
|
81
|
+
trustedTempoProofRealms?: ProofRealm.TrustedRealms | undefined;
|
|
76
82
|
/** Viem client instance. Shorthand for `getClient: () => client`. */
|
|
77
83
|
client?: import('viem').Client | undefined;
|
|
78
84
|
/** Token decimals used to convert `maxDeposit` to raw units. Defaults to `6`. */
|
|
@@ -4,6 +4,8 @@ import * as Challenge from '../../../Challenge.js';
|
|
|
4
4
|
import * as Fetch from '../../../client/internal/Fetch.js';
|
|
5
5
|
import * as MethodChallenge from '../../../client/internal/MethodChallenge.js';
|
|
6
6
|
import * as MethodResponse from '../../../client/internal/MethodResponse.js';
|
|
7
|
+
import * as ProofRealm from '../../../client/internal/ProofRealm.js';
|
|
8
|
+
import { setCredentialHeader } from '../../../client/internal/protocols/Shared.js';
|
|
7
9
|
import * as Constants from '../../../Constants.js';
|
|
8
10
|
import * as Account from '../../../viem/Account.js';
|
|
9
11
|
import * as Client from '../../../viem/Client.js';
|
|
@@ -353,17 +355,19 @@ export function sessionManager(parameters) {
|
|
|
353
355
|
return undefined;
|
|
354
356
|
if (!isZeroAmountChargeChallenge(challenge))
|
|
355
357
|
return undefined;
|
|
358
|
+
// The proof authenticates the payer at the challenge realm: sign only for the server it is
|
|
359
|
+
// sent to, and never after a redirect to another origin.
|
|
360
|
+
const target = new URL(String(bootstrapInput), typeof location !== 'undefined' ? location.href : undefined);
|
|
361
|
+
if (challengeResponse.url && new URL(challengeResponse.url).origin !== target.origin)
|
|
362
|
+
return undefined;
|
|
363
|
+
ProofRealm.assert(challenge, target, parameters.trustedTempoProofRealms);
|
|
356
364
|
const credential = await chargeMethod.createCredential({
|
|
357
365
|
challenge: challenge,
|
|
358
366
|
context: {},
|
|
359
367
|
});
|
|
360
|
-
const response = await config.fetch(bootstrapInput,
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
...Fetch.normalizeHeaders(headInit.headers),
|
|
364
|
-
[Constants.Headers.authorization]: credential,
|
|
365
|
-
},
|
|
366
|
-
});
|
|
368
|
+
const response = await config.fetch(bootstrapInput,
|
|
369
|
+
// Runtimes do not strip custom payment headers on cross-origin redirects.
|
|
370
|
+
setCredentialHeader({ ...headInit, redirect: 'manual' }, Challenge.credentialHeader(challenge), credential));
|
|
367
371
|
if (response.ok)
|
|
368
372
|
return await storeSnapshotHeader(response);
|
|
369
373
|
return undefined;
|
|
@@ -643,6 +647,7 @@ export function sessionManager(parameters) {
|
|
|
643
647
|
if (channelUse)
|
|
644
648
|
throw new Error('SessionManager: a request is already in flight; concurrent requests on one manager are not supported');
|
|
645
649
|
runtime.lastUrl = input;
|
|
650
|
+
runtime.lastHeaders = init?.headers;
|
|
646
651
|
const previous = captureRuntimeStateSnapshot({
|
|
647
652
|
channel: runtime.channel,
|
|
648
653
|
spent: runtime.spent,
|
|
@@ -732,6 +737,7 @@ export function sessionManager(parameters) {
|
|
|
732
737
|
createSessionCredential,
|
|
733
738
|
fetch: config.fetch,
|
|
734
739
|
getMinimumSpent: () => runtime.spent,
|
|
740
|
+
headers: runtime.lastHeaders,
|
|
735
741
|
lastUrl: runtime.lastUrl,
|
|
736
742
|
resolveSignedCloseAmount: (challenge) => getValidatedFallbackCloseAmount(target, challenge, true),
|
|
737
743
|
signedCloseAmount: getValidatedFallbackCloseAmount(target),
|
|
@@ -799,6 +805,7 @@ export function sessionManager(parameters) {
|
|
|
799
805
|
additionalDeposit: target.additionalDeposit,
|
|
800
806
|
challenge: target.challenge,
|
|
801
807
|
channelId: target.channelId,
|
|
808
|
+
headers: runtime.lastHeaders,
|
|
802
809
|
input: target.input,
|
|
803
810
|
});
|
|
804
811
|
});
|
|
@@ -78,6 +78,8 @@ export type TopUpRequirement = {
|
|
|
78
78
|
deposit: bigint;
|
|
79
79
|
/** Original paid resource URL; converted to a management URL by the caller. */
|
|
80
80
|
input: RequestInfo | URL;
|
|
81
|
+
/** Headers of the paid request; management posts keep its application `Authorization`. */
|
|
82
|
+
headers?: HeadersInit | undefined;
|
|
81
83
|
/** Minimum cumulative voucher amount the server needs. */
|
|
82
84
|
requiredCumulative: bigint;
|
|
83
85
|
/** Cancels nested management requests for this top-up. */
|
|
@@ -158,6 +160,8 @@ export type ResolveNeedVoucherContextParameters = {
|
|
|
158
160
|
getChannel(): ChannelEntry | null;
|
|
159
161
|
/** Original paid resource URL; converted to management URL by the caller. */
|
|
160
162
|
input: RequestInfo | URL;
|
|
163
|
+
/** Headers of the paid request; management posts keep its application `Authorization`. */
|
|
164
|
+
headers?: HeadersInit | undefined;
|
|
161
165
|
/** Cancels top-up work triggered by this event. */
|
|
162
166
|
signal?: AbortSignal | undefined;
|
|
163
167
|
/** Performs the deposit top-up when server-required cumulative exceeds deposit. */
|
|
@@ -211,6 +215,8 @@ export type PostTopUpParameters = {
|
|
|
211
215
|
fetch: typeof globalThis.fetch;
|
|
212
216
|
/** Original paid resource URL; normalized to a management URL before posting. */
|
|
213
217
|
input: RequestInfo | URL;
|
|
218
|
+
/** Headers of the paid request; management posts keep its application `Authorization`. */
|
|
219
|
+
headers?: HeadersInit | undefined;
|
|
214
220
|
/** Cancels the top-up management request. */
|
|
215
221
|
signal?: AbortSignal | undefined;
|
|
216
222
|
/** Persists an unresolved funding outcome before another caller can reuse the channel. */
|
|
@@ -254,6 +260,8 @@ export type CloseHttpSessionParameters = {
|
|
|
254
260
|
fetch: typeof globalThis.fetch;
|
|
255
261
|
/** Last paid resource URL; used as the management endpoint base. */
|
|
256
262
|
lastUrl: RequestInfo | URL | null;
|
|
263
|
+
/** Headers of the last paid request; the close post keeps its application `Authorization`. */
|
|
264
|
+
headers?: HeadersInit | undefined;
|
|
257
265
|
/** Returns the latest cumulative spend already confirmed by the client. */
|
|
258
266
|
getMinimumSpent?: (() => bigint) | undefined;
|
|
259
267
|
/** Resolves the close amount again when the server refreshes the challenge. */
|
|
@@ -271,8 +279,8 @@ export declare function isTempoSessionChallenge(challenge: Challenge.Challenge):
|
|
|
271
279
|
export declare function isTip1034SessionChallenge(challenge: Challenge.Challenge): challenge is TempoSessionChallenge;
|
|
272
280
|
/** Reads a server-provided session snapshot from challenge method details. */
|
|
273
281
|
export declare function getSessionSnapshot(challenge: TempoSessionChallenge): SessionSnapshot | undefined;
|
|
274
|
-
/** Merges request headers and sets the
|
|
275
|
-
export declare function requestInitWithAuthorization(input: RequestInfo | URL, init: RequestInit | undefined, credential: string): RequestInit;
|
|
282
|
+
/** Merges request headers and sets the challenge's credential header for a retry. */
|
|
283
|
+
export declare function requestInitWithAuthorization(input: RequestInfo | URL, init: RequestInit | undefined, credential: string, challenge: TempoSessionChallenge): RequestInit;
|
|
276
284
|
/** Returns the exact resource URL used for out-of-band management POSTs, without its fragment. */
|
|
277
285
|
export declare function managementInput(input: RequestInfo | URL): RequestInfo | URL;
|
|
278
286
|
/** Converts a WebSocket URL into the HTTP URL used for its payment challenge probe. */
|
|
@@ -335,7 +343,7 @@ export type SsePaymentDriver = Pick<OpenSseSessionParameters, 'assertVoucherWith
|
|
|
335
343
|
*/
|
|
336
344
|
export declare function openSseSession(input: RequestInfo | URL, init: SseDriverOptions | undefined, driver: OpenSseSessionParameters): Promise<AsyncIterable<string>>;
|
|
337
345
|
/** @internal Consumes an already-paid SSE response with the session transport driver. */
|
|
338
|
-
export declare function consumeSseSessionResponse(input: RequestInfo | URL, response: Response, options: SseResponseOptions | undefined, driver: OpenSseSessionParameters): AsyncIterable<string>;
|
|
346
|
+
export declare function consumeSseSessionResponse(input: RequestInfo | URL, response: Response, options: SseResponseOptions | undefined, driver: OpenSseSessionParameters, headers?: HeadersInit | undefined): AsyncIterable<string>;
|
|
339
347
|
/** Application SSE frame emitted after session payment events are handled. */
|
|
340
348
|
export type SseResponseFrame = {
|
|
341
349
|
/** Parsed application data, when present. */
|
|
@@ -362,6 +370,7 @@ export declare function wrapSseResponse(parameters: DriveSseResponseParameters):
|
|
|
362
370
|
export declare function handleSseNeedVoucher(parameters: {
|
|
363
371
|
challenge: TempoSessionChallenge | null;
|
|
364
372
|
driver: SsePaymentDriver;
|
|
373
|
+
headers?: HeadersInit | undefined;
|
|
365
374
|
input: RequestInfo | URL;
|
|
366
375
|
signal?: AbortSignal | undefined;
|
|
367
376
|
}, event: NeedVoucherEvent): Promise<void>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Hex } from 'ox';
|
|
2
2
|
import * as Challenge from '../../../Challenge.js';
|
|
3
3
|
import * as Fetch from '../../../client/internal/Fetch.js';
|
|
4
|
+
import { setCredentialHeader } from '../../../client/internal/protocols/Shared.js';
|
|
4
5
|
import * as Constants from '../../../Constants.js';
|
|
5
6
|
import * as PaymentCredential from '../../../Credential.js';
|
|
6
7
|
import { deserializeSessionReceipt, isEventStream, parseEvent, readSessionChallengeAmount, uint96, } from '../precompile/Protocol.js';
|
|
@@ -211,6 +212,7 @@ export async function resolveNeedVoucherContext(parameters) {
|
|
|
211
212
|
await parameters.topUpIfNeeded({
|
|
212
213
|
challenge: parameters.challenge,
|
|
213
214
|
input: parameters.input,
|
|
215
|
+
headers: parameters.headers,
|
|
214
216
|
channelId: parameters.expectedChannelId,
|
|
215
217
|
deposit: eventAmounts.deposit,
|
|
216
218
|
requiredCumulative: eventAmounts.requiredCumulative,
|
|
@@ -246,17 +248,18 @@ export function isTip1034SessionChallenge(challenge) {
|
|
|
246
248
|
export function getSessionSnapshot(challenge) {
|
|
247
249
|
return Constants.getMethodDetail(challenge.request.methodDetails, Constants.MethodDetailKeys.sessionSnapshot);
|
|
248
250
|
}
|
|
249
|
-
/** Merges request headers and sets the
|
|
250
|
-
export function requestInitWithAuthorization(input, init, credential) {
|
|
251
|
+
/** Merges request headers and sets the challenge's credential header for a retry. */
|
|
252
|
+
export function requestInitWithAuthorization(input, init, credential, challenge) {
|
|
251
253
|
const requestHeaders = input instanceof Request ? input.headers : undefined;
|
|
252
|
-
return {
|
|
254
|
+
return setCredentialHeader({
|
|
253
255
|
...init,
|
|
256
|
+
// Runtimes do not strip custom payment headers on cross-origin redirects.
|
|
257
|
+
redirect: 'manual',
|
|
254
258
|
headers: {
|
|
255
259
|
...Fetch.normalizeHeaders(requestHeaders),
|
|
256
260
|
...Fetch.normalizeHeaders(init?.headers),
|
|
257
|
-
[Constants.Headers.authorization]: credential,
|
|
258
261
|
},
|
|
259
|
-
};
|
|
262
|
+
}, Challenge.credentialHeader(challenge), credential);
|
|
260
263
|
}
|
|
261
264
|
/** Returns the exact resource URL used for out-of-band management POSTs, without its fragment. */
|
|
262
265
|
export function managementInput(input) {
|
|
@@ -324,6 +327,7 @@ export async function postTopUp(parameters) {
|
|
|
324
327
|
},
|
|
325
328
|
createSessionCredential: parameters.createSessionCredential,
|
|
326
329
|
fetch: parameters.fetch,
|
|
330
|
+
headers: parameters.headers,
|
|
327
331
|
input: parameters.input,
|
|
328
332
|
signal: parameters.signal,
|
|
329
333
|
}).catch(async (error) => {
|
|
@@ -360,7 +364,8 @@ async function postManagementCredential(parameters) {
|
|
|
360
364
|
parameters.fetch(managementInput(parameters.input), {
|
|
361
365
|
method: 'POST',
|
|
362
366
|
signal: controller.signal,
|
|
363
|
-
|
|
367
|
+
redirect: 'manual',
|
|
368
|
+
headers: managementHeaders(challenge, authorization, parameters.input, parameters.headers),
|
|
364
369
|
}),
|
|
365
370
|
aborted,
|
|
366
371
|
]);
|
|
@@ -397,6 +402,7 @@ export async function retryHttpPaymentRequired(parameters) {
|
|
|
397
402
|
await parameters.topUpIfNeeded({
|
|
398
403
|
challenge,
|
|
399
404
|
input: parameters.input,
|
|
405
|
+
headers: parameters.init?.headers,
|
|
400
406
|
channelId: snapshot.channelId,
|
|
401
407
|
deposit: BigInt(snapshot.deposit),
|
|
402
408
|
requiredCumulative,
|
|
@@ -419,7 +425,7 @@ export async function retryHttpPaymentRequired(parameters) {
|
|
|
419
425
|
descriptor: currentChannel.descriptor,
|
|
420
426
|
cumulativeAmountRaw: cumulativeAmount.toString(),
|
|
421
427
|
});
|
|
422
|
-
retry = await parameters.fetch(parameters.input, requestInitWithAuthorization(parameters.input, parameters.init, credential));
|
|
428
|
+
retry = await parameters.fetch(parameters.input, requestInitWithAuthorization(parameters.input, parameters.init, credential, challenge));
|
|
423
429
|
}
|
|
424
430
|
catch (error) {
|
|
425
431
|
await restore();
|
|
@@ -463,7 +469,8 @@ export async function closeHttpSession(parameters) {
|
|
|
463
469
|
});
|
|
464
470
|
return parameters.fetch(parameters.lastUrl, {
|
|
465
471
|
method: 'POST',
|
|
466
|
-
|
|
472
|
+
redirect: 'manual',
|
|
473
|
+
headers: managementHeaders(challenge, credential, parameters.lastUrl, parameters.headers),
|
|
467
474
|
});
|
|
468
475
|
};
|
|
469
476
|
let response = await postClose(parameters.target.challenge);
|
|
@@ -516,17 +523,17 @@ export async function openSseSession(input, init, driver) {
|
|
|
516
523
|
let response = await driver.doFetch(input, sseInit);
|
|
517
524
|
if (!isEventStream(response) && driver.getChannel()?.opened)
|
|
518
525
|
response = await driver.doFetch(input, sseInit);
|
|
519
|
-
return consumeSseSessionResponse(input, response, { onReceipt, signal }, driver);
|
|
526
|
+
return consumeSseSessionResponse(input, response, { onReceipt, signal }, driver, sseInit.headers);
|
|
520
527
|
}
|
|
521
528
|
/** @internal Consumes an already-paid SSE response with the session transport driver. */
|
|
522
|
-
export function consumeSseSessionResponse(input, response, options, driver) {
|
|
529
|
+
export function consumeSseSessionResponse(input, response, options, driver, headers) {
|
|
523
530
|
if (!isEventStream(response))
|
|
524
531
|
throw new Error('SSE response is not an event stream.');
|
|
525
532
|
if (!response.body)
|
|
526
533
|
throw new Error('Response has no body.');
|
|
527
534
|
const challenge = driver.getChallenge();
|
|
528
535
|
return iterateSseMessages({
|
|
529
|
-
onNeedVoucher: (event) => handleSseNeedVoucher({ challenge, driver, input, signal: options?.signal }, event),
|
|
536
|
+
onNeedVoucher: (event) => handleSseNeedVoucher({ challenge, driver, headers, input, signal: options?.signal }, event),
|
|
530
537
|
onReceipt(receipt) {
|
|
531
538
|
driver.acceptReceipt(receipt);
|
|
532
539
|
options?.onReceipt?.(receipt);
|
|
@@ -682,6 +689,7 @@ export async function handleSseNeedVoucher(parameters, event) {
|
|
|
682
689
|
event,
|
|
683
690
|
expectedChannelId: channel.channelId,
|
|
684
691
|
getChannel: parameters.driver.getChannel,
|
|
692
|
+
headers: parameters.headers,
|
|
685
693
|
input: parameters.input,
|
|
686
694
|
signal: parameters.signal,
|
|
687
695
|
topUpIfNeeded: parameters.driver.topUpIfNeeded,
|
|
@@ -693,6 +701,7 @@ export async function handleSseNeedVoucher(parameters, event) {
|
|
|
693
701
|
context: resolution.context,
|
|
694
702
|
createSessionCredential: parameters.driver.createSessionCredential,
|
|
695
703
|
fetch: parameters.driver.fetch,
|
|
704
|
+
headers: parameters.headers,
|
|
696
705
|
input: parameters.input,
|
|
697
706
|
signal: parameters.signal,
|
|
698
707
|
});
|
|
@@ -979,4 +988,21 @@ function handleReceipt(parameters, receipt) {
|
|
|
979
988
|
parameters.driver.options?.onReceipt?.(receipt);
|
|
980
989
|
parameters.driver.settleReceipt(receipt);
|
|
981
990
|
}
|
|
991
|
+
/**
|
|
992
|
+
* Builds the headers of a management or close post: the session credential in the header the
|
|
993
|
+
* challenge selects, plus the paid request's application `Authorization` when the credential
|
|
994
|
+
* goes elsewhere (`requiresAuth`), so the post passes the same application authentication.
|
|
995
|
+
*/
|
|
996
|
+
function managementHeaders(challenge, credential, input, headers) {
|
|
997
|
+
const header = Challenge.credentialHeader(challenge);
|
|
998
|
+
const result = new Headers();
|
|
999
|
+
if (header.toLowerCase() !== Constants.Headers.authorization.toLowerCase()) {
|
|
1000
|
+
const authorization = new Headers(headers).get(Constants.Headers.authorization) ??
|
|
1001
|
+
(input instanceof Request ? input.headers.get(Constants.Headers.authorization) : null);
|
|
1002
|
+
if (authorization && !authorization.startsWith(`${Constants.Schemes.payment} `))
|
|
1003
|
+
result.set(Constants.Headers.authorization, authorization);
|
|
1004
|
+
}
|
|
1005
|
+
result.set(header, credential);
|
|
1006
|
+
return result;
|
|
1007
|
+
}
|
|
982
1008
|
//# sourceMappingURL=Transports.js.map
|
|
@@ -300,9 +300,6 @@ function validateCredentialSponsorship(parameters) {
|
|
|
300
300
|
return;
|
|
301
301
|
if (feePayer === true) {
|
|
302
302
|
assertPrecompileFeePayerPolicy({ prepared: transaction, policy: feePayerPolicy });
|
|
303
|
-
if (feePayerPolicy?.allowKeyAuthorization === false &&
|
|
304
|
-
transaction.keyAuthorization !== undefined)
|
|
305
|
-
throw new BadRequestError({ reason: 'fee-payer policy keyAuthorization is not allowed' });
|
|
306
303
|
FeePayer.assertAllowedFeeToken(transaction, allowedFeeTokens);
|
|
307
304
|
FeePayer.assertTransactionPolicy({
|
|
308
305
|
challengeExpires,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type * as Challenge from '../../../Challenge.js';
|
|
1
2
|
import { type SessionCredentialContext } from '../precompile/Protocol.js';
|
|
2
3
|
import * as ChannelStore from './ChannelStore.js';
|
|
3
4
|
import type { MeteredStreamOptions, SessionController } from './MeteredStream.js';
|
|
@@ -13,6 +14,7 @@ export type SessionRouteResult = {
|
|
|
13
14
|
challenge: Response;
|
|
14
15
|
} | {
|
|
15
16
|
status: 200;
|
|
17
|
+
challenge?: Challenge.Challenge | undefined;
|
|
16
18
|
withReceipt(response?: Response): Response | Promise<Response>;
|
|
17
19
|
};
|
|
18
20
|
/** HTTP route used to perform a WebSocket payment probe. */
|
|
@@ -36,14 +38,15 @@ export declare function serve(options: serve.Options): Promise<void>;
|
|
|
36
38
|
/** Type helpers for {@link serve}. */
|
|
37
39
|
export declare namespace serve {
|
|
38
40
|
type Options = {
|
|
39
|
-
/** Expected per-tick amount in raw units.
|
|
41
|
+
/** Expected per-tick amount in raw units. Required for custom routes that
|
|
42
|
+
* do not return their canonical challenge. When set, credentials whose
|
|
40
43
|
* challenge `request.amount` does not match are rejected. Use this to
|
|
41
44
|
* pin the price when the route is backed by `Mppx.compose()` with
|
|
42
45
|
* multiple offers — otherwise a client can select the cheapest offer
|
|
43
46
|
* and still receive the same stream. */
|
|
44
47
|
amount?: string | undefined;
|
|
45
48
|
/** Application stream. A manual stream can call `charge(amount)` with a
|
|
46
|
-
* per-message raw-unit amount; omitting it uses the
|
|
49
|
+
* per-message raw-unit amount; omitting it uses the canonical route tick cost. */
|
|
47
50
|
generate: AsyncIterable<string> | ((stream: SessionController) => AsyncIterable<string>);
|
|
48
51
|
/** Maximum accepted inbound WebSocket frame size in bytes. @default 65536 */
|
|
49
52
|
maxIncomingMessageBytes?: number | undefined;
|
|
@@ -133,6 +133,11 @@ export async function serve(options) {
|
|
|
133
133
|
return;
|
|
134
134
|
}
|
|
135
135
|
const { receipt } = authorizationResult;
|
|
136
|
+
const tickCost = expectedAmount !== undefined ? BigInt(expectedAmount) : authorizationResult.amount;
|
|
137
|
+
if (tickCost === undefined) {
|
|
138
|
+
await close(1008, 'WebSocket route must provide canonical pricing or an explicit amount');
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
136
141
|
if (payload.action === 'voucher' && runtime.streamContext) {
|
|
137
142
|
runtime.streamContext.challengeId = credential.challenge.id;
|
|
138
143
|
}
|
|
@@ -149,7 +154,7 @@ export async function serve(options) {
|
|
|
149
154
|
runtime.streamContext = {
|
|
150
155
|
challengeId: credential.challenge.id,
|
|
151
156
|
channelId: payload.channelId,
|
|
152
|
-
tickCost
|
|
157
|
+
tickCost,
|
|
153
158
|
};
|
|
154
159
|
// Defer the first application frame until after the client receives the
|
|
155
160
|
// auth receipt and has a chance to install its own message listeners.
|
|
@@ -299,6 +304,10 @@ async function authorizePaymentFrame(parameters) {
|
|
|
299
304
|
const receiptHeader = response.headers.get(Constants.Headers.paymentReceipt);
|
|
300
305
|
if (!receiptHeader)
|
|
301
306
|
throw new Error('management response missing Payment-Receipt header');
|
|
302
|
-
return {
|
|
307
|
+
return {
|
|
308
|
+
status: 'accepted',
|
|
309
|
+
amount: result.challenge ? readSessionChallengeAmount(result.challenge) : undefined,
|
|
310
|
+
receipt: deserializeSessionReceipt(receiptHeader),
|
|
311
|
+
};
|
|
303
312
|
}
|
|
304
313
|
//# sourceMappingURL=Ws.js.map
|
|
@@ -13,9 +13,13 @@ export type SubscriptionStore = {
|
|
|
13
13
|
/** Looks up a generated access key for a resolved request key. */
|
|
14
14
|
getAccessKey(key: string): Promise<SubscriptionAccessKeyRecord | null>;
|
|
15
15
|
/** Looks up a generated access key by its public access key address. */
|
|
16
|
-
getAccessKeyByAddress(address: string): Promise<SubscriptionAccessKeyRecord | null>;
|
|
16
|
+
getAccessKeyByAddress(address: string, keyToken?: `0x${string}`): Promise<SubscriptionAccessKeyRecord | null>;
|
|
17
17
|
/** Looks up the active subscription for a resolved request key. */
|
|
18
18
|
getByKey(key: string): Promise<SubscriptionRecord | null>;
|
|
19
|
+
/** Creates a key sealed in a client-carried token, without retaining per-challenge state. */
|
|
20
|
+
createChallengeAccessKey(): Promise<SubscriptionAccessKeyRecord>;
|
|
21
|
+
/** Retains a key after verified payment submission for subsequent subscription billing. */
|
|
22
|
+
retainAccessKey(key: string, record: SubscriptionAccessKeyRecord): Promise<void>;
|
|
19
23
|
/** Gets or creates the server-owned access key for a resolved request key. */
|
|
20
24
|
getOrCreateAccessKey(key: string): Promise<SubscriptionAccessKeyRecord>;
|
|
21
25
|
/** Upserts a subscription record and marks it as active for its lookup key. */
|
|
@@ -85,6 +89,8 @@ export declare namespace fromStore {
|
|
|
85
89
|
type Options = {
|
|
86
90
|
/** Key prefix for server-owned subscription access keys. @default `'tempo:subscription:access-key:'` */
|
|
87
91
|
accessKeyPrefix?: string | undefined;
|
|
92
|
+
/** Namespace for the persistent anonymous-challenge sealing key. */
|
|
93
|
+
pendingAccessKeyPrefix?: string | undefined;
|
|
88
94
|
/** Key prefix for resolved subscription activation locks. @default `'tempo:subscription:activation:'` */
|
|
89
95
|
activationPrefix?: string | undefined;
|
|
90
96
|
/** Milliseconds before a stuck activation lock can be replaced. @default `900000` */
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { Secp256k1 } from 'ox';
|
|
1
|
+
import { Hex, Secp256k1 } from 'ox';
|
|
2
2
|
import { Account as TempoAccount } from 'viem/tempo';
|
|
3
3
|
const defaultRecordPrefix = 'tempo:subscription:record:';
|
|
4
4
|
const defaultKeyPrefix = 'tempo:subscription:key:';
|
|
5
5
|
const defaultActivationPrefix = 'tempo:subscription:activation:';
|
|
6
6
|
const defaultAccessKeyPrefix = 'tempo:subscription:access-key:';
|
|
7
|
+
const defaultPendingAccessKeyPrefix = 'tempo:subscription:pending-access-key:';
|
|
7
8
|
const defaultCredentialPrefix = 'tempo:subscription:credential:';
|
|
8
9
|
const defaultActivationTimeoutMs = 15 * 60 * 1_000;
|
|
9
10
|
const defaultRenewalTimeoutMs = 15 * 60 * 1_000;
|
|
10
11
|
/** Wraps a generic key-value {@link Store.Store} with subscription-specific accessors. */
|
|
11
12
|
export function fromStore(store, options) {
|
|
12
|
-
const { accessKeyPrefix = defaultAccessKeyPrefix, activationPrefix = defaultActivationPrefix, activationTimeoutMs = defaultActivationTimeoutMs, credentialPrefix = defaultCredentialPrefix, keyPrefix = defaultKeyPrefix, recordPrefix = defaultRecordPrefix, renewalTimeoutMs = defaultRenewalTimeoutMs, } = options ?? {};
|
|
13
|
+
const { accessKeyPrefix = defaultAccessKeyPrefix, activationPrefix = defaultActivationPrefix, activationTimeoutMs = defaultActivationTimeoutMs, credentialPrefix = defaultCredentialPrefix, keyPrefix = defaultKeyPrefix, recordPrefix = defaultRecordPrefix, pendingAccessKeyPrefix = defaultPendingAccessKeyPrefix, renewalTimeoutMs = defaultRenewalTimeoutMs, } = options ?? {};
|
|
13
14
|
function recordKey(subscriptionId) {
|
|
14
15
|
return `${recordPrefix}${subscriptionId}`;
|
|
15
16
|
}
|
|
@@ -34,6 +35,14 @@ export function fromStore(store, options) {
|
|
|
34
35
|
return null;
|
|
35
36
|
return (await store.get(recordKey(subscriptionId)));
|
|
36
37
|
}
|
|
38
|
+
async function ensureAccessKeyAddressIndex(record) {
|
|
39
|
+
await store.update(accessKeyAddressKey(record.accessKeyAddress), (current) => {
|
|
40
|
+
if (current)
|
|
41
|
+
return { op: 'noop', result: undefined };
|
|
42
|
+
return { op: 'set', value: record, result: undefined };
|
|
43
|
+
});
|
|
44
|
+
return record;
|
|
45
|
+
}
|
|
37
46
|
async function clearRenewalState(subscriptionId, periodIndex, attempt) {
|
|
38
47
|
await store.update(recordKey(subscriptionId), (current) => {
|
|
39
48
|
const subscription = current;
|
|
@@ -61,7 +70,35 @@ export function fromStore(store, options) {
|
|
|
61
70
|
const marker = (await store.get(activationKey(lookupKey)));
|
|
62
71
|
return marker?.challengeId === challengeId;
|
|
63
72
|
}
|
|
73
|
+
const sealingKey = `${pendingAccessKeyPrefix}sealing-key`;
|
|
74
|
+
// One shared secret survives across workers; anonymous issuance never grows the store.
|
|
75
|
+
async function getSealingKey() {
|
|
76
|
+
const candidate = Hex.fromBytes(crypto.getRandomValues(new Uint8Array(32)));
|
|
77
|
+
const secret = await store.update(sealingKey, (current) => current
|
|
78
|
+
? { op: 'noop', result: current }
|
|
79
|
+
: { op: 'set', value: candidate, result: candidate });
|
|
80
|
+
return crypto.subtle.importKey('raw', new Uint8Array(Hex.toBytes(secret)), 'AES-GCM', false, [
|
|
81
|
+
'encrypt',
|
|
82
|
+
'decrypt',
|
|
83
|
+
]);
|
|
84
|
+
}
|
|
64
85
|
return {
|
|
86
|
+
async createChallengeAccessKey() {
|
|
87
|
+
const privateKey = Secp256k1.randomPrivateKey();
|
|
88
|
+
const account = TempoAccount.fromSecp256k1(privateKey);
|
|
89
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
90
|
+
const sealed = new Uint8Array(await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, await getSealingKey(), new Uint8Array(Hex.toBytes(privateKey))));
|
|
91
|
+
return {
|
|
92
|
+
accessKeyAddress: account.address.toLowerCase(),
|
|
93
|
+
keyType: account.keyType,
|
|
94
|
+
privateKey,
|
|
95
|
+
keyToken: Hex.fromBytes(new Uint8Array([...iv, ...sealed])),
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
async retainAccessKey(key, record) {
|
|
99
|
+
await store.put(accessKeyKey(key), record);
|
|
100
|
+
await store.put(accessKeyAddressKey(record.accessKeyAddress), record);
|
|
101
|
+
},
|
|
65
102
|
async activate({ challengeId, create, isReusable, lookupKey }) {
|
|
66
103
|
const claimed = await store.update(credentialKey(challengeId), (current) => {
|
|
67
104
|
if (current)
|
|
@@ -155,8 +192,31 @@ export function fromStore(store, options) {
|
|
|
155
192
|
async getAccessKey(key) {
|
|
156
193
|
return (await store.get(accessKeyKey(key)));
|
|
157
194
|
},
|
|
158
|
-
async getAccessKeyByAddress(address) {
|
|
159
|
-
|
|
195
|
+
async getAccessKeyByAddress(address, keyToken) {
|
|
196
|
+
const stored = (await store.get(accessKeyAddressKey(address)));
|
|
197
|
+
if (stored)
|
|
198
|
+
return stored;
|
|
199
|
+
if (!keyToken)
|
|
200
|
+
return null;
|
|
201
|
+
try {
|
|
202
|
+
const bytes = Hex.toBytes(keyToken);
|
|
203
|
+
// 12-byte nonce, 32-byte private key, and 16-byte authentication tag.
|
|
204
|
+
if (bytes.length !== 60)
|
|
205
|
+
return null;
|
|
206
|
+
const privateKey = Hex.fromBytes(new Uint8Array(await crypto.subtle.decrypt({ name: 'AES-GCM', iv: bytes.slice(0, 12) }, await getSealingKey(), bytes.slice(12))));
|
|
207
|
+
const account = TempoAccount.fromSecp256k1(privateKey);
|
|
208
|
+
if (account.address.toLowerCase() !== address.toLowerCase())
|
|
209
|
+
return null;
|
|
210
|
+
return {
|
|
211
|
+
accessKeyAddress: account.address.toLowerCase(),
|
|
212
|
+
keyType: account.keyType,
|
|
213
|
+
privateKey,
|
|
214
|
+
keyToken,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
160
220
|
},
|
|
161
221
|
async getByKey(key) {
|
|
162
222
|
return getByLookupKey(key);
|
|
@@ -164,7 +224,7 @@ export function fromStore(store, options) {
|
|
|
164
224
|
async getOrCreateAccessKey(key) {
|
|
165
225
|
const existing = (await store.get(accessKeyKey(key)));
|
|
166
226
|
if (existing)
|
|
167
|
-
return existing;
|
|
227
|
+
return ensureAccessKeyAddressIndex(existing);
|
|
168
228
|
const privateKey = Secp256k1.randomPrivateKey();
|
|
169
229
|
const account = TempoAccount.fromSecp256k1(privateKey);
|
|
170
230
|
const candidate = {
|
|
@@ -179,14 +239,7 @@ export function fromStore(store, options) {
|
|
|
179
239
|
}
|
|
180
240
|
return { op: 'set', value: candidate, result: candidate };
|
|
181
241
|
})
|
|
182
|
-
.then(
|
|
183
|
-
await store.update(accessKeyAddressKey(record.accessKeyAddress), (current) => {
|
|
184
|
-
if (current)
|
|
185
|
-
return { op: 'noop', result: undefined };
|
|
186
|
-
return { op: 'set', value: record, result: undefined };
|
|
187
|
-
});
|
|
188
|
-
return record;
|
|
189
|
-
});
|
|
242
|
+
.then(ensureAccessKeyAddressIndex);
|
|
190
243
|
},
|
|
191
244
|
async put(record) {
|
|
192
245
|
await store.put(recordKey(record.subscriptionId), record);
|
|
@@ -5,6 +5,8 @@ export type SubscriptionPeriodUnit = 'dev_second' | 'day' | 'week';
|
|
|
5
5
|
export type SubscriptionAccessKey = {
|
|
6
6
|
accessKeyAddress: Address;
|
|
7
7
|
keyType: 'p256' | 'secp256k1' | 'webAuthn';
|
|
8
|
+
/** Opaque server-sealed key for stateless anonymous setup. */
|
|
9
|
+
keyToken?: `0x${string}` | undefined;
|
|
8
10
|
};
|
|
9
11
|
/** Server-owned subscription access key persisted for automatic billing. */
|
|
10
12
|
export type SubscriptionAccessKeyRecord = SubscriptionAccessKey & {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mppx",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.16.0",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://github.com/wevm/mppx#readme",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"types": "./dist/client/node.d.ts",
|
|
36
36
|
"default": "./dist/client/node.js"
|
|
37
37
|
},
|
|
38
|
-
"./
|
|
39
|
-
"types": "./dist/
|
|
40
|
-
"default": "./dist/
|
|
38
|
+
"./identity": {
|
|
39
|
+
"types": "./dist/identity/index.d.ts",
|
|
40
|
+
"default": "./dist/identity/index.js"
|
|
41
41
|
},
|
|
42
42
|
"./discovery": {
|
|
43
43
|
"types": "./dist/discovery/index.d.ts",
|
|
@@ -123,13 +123,17 @@
|
|
|
123
123
|
"types": "./dist/tempo/index.d.ts",
|
|
124
124
|
"default": "./dist/tempo/index.js"
|
|
125
125
|
},
|
|
126
|
-
"./
|
|
127
|
-
"types": "./dist/
|
|
128
|
-
"default": "./dist/
|
|
126
|
+
"./extensions/identity": {
|
|
127
|
+
"types": "./dist/extensions/identity/index.d.ts",
|
|
128
|
+
"default": "./dist/extensions/identity/index.js"
|
|
129
129
|
},
|
|
130
|
-
"./
|
|
131
|
-
"types": "./dist/
|
|
132
|
-
"default": "./dist/
|
|
130
|
+
"./extensions/identity/tap": {
|
|
131
|
+
"types": "./dist/extensions/identity/tap/index.d.ts",
|
|
132
|
+
"default": "./dist/extensions/identity/tap/index.js"
|
|
133
|
+
},
|
|
134
|
+
"./extensions/identity/web-bot-auth": {
|
|
135
|
+
"types": "./dist/extensions/identity/web-bot-auth/index.d.ts",
|
|
136
|
+
"default": "./dist/extensions/identity/web-bot-auth/index.js"
|
|
133
137
|
},
|
|
134
138
|
"./html": {
|
|
135
139
|
"types": "./dist/Html.d.ts",
|
|
@@ -206,7 +210,7 @@
|
|
|
206
210
|
"eventsource-parser": "4.1.1",
|
|
207
211
|
"ox": "0.14.45",
|
|
208
212
|
"structured-headers": "2.1.0",
|
|
209
|
-
"zod": "^4.6.
|
|
213
|
+
"zod": "^4.6.7"
|
|
210
214
|
},
|
|
211
215
|
"repository": {
|
|
212
216
|
"type": "git",
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type * as Types from './Types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Combines request signers using one shared context per call.
|
|
4
|
-
*
|
|
5
|
-
* The returned signer creates a fresh context unless its caller supplies one,
|
|
6
|
-
* allowing every signature on one HTTP attempt to share a nonce and timestamp.
|
|
7
|
-
*/
|
|
8
|
-
export declare function composeSigners(...signers: readonly [Types.Signer, ...Types.Signer[]]): Types.Signer<'composed'>;
|
|
9
|
-
/**
|
|
10
|
-
* Wraps a fetch implementation so every outbound request is attested.
|
|
11
|
-
*
|
|
12
|
-
* Configure this wrapper as the underlying `fetch` passed to `mppx/client`
|
|
13
|
-
* `Fetch.from()`. MPPX then uses it for both the initial request and its
|
|
14
|
-
* automatic request containing an `Authorization: Payment` credential.
|
|
15
|
-
*/
|
|
16
|
-
export declare function wrapFetch(fetch: typeof globalThis.fetch, signer: Types.Signer): typeof globalThis.fetch;
|
|
17
|
-
//# sourceMappingURL=Client.d.ts.map
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import * as SigningContext from './internal/SigningContext.js';
|
|
2
|
-
/**
|
|
3
|
-
* Combines request signers using one shared context per call.
|
|
4
|
-
*
|
|
5
|
-
* The returned signer creates a fresh context unless its caller supplies one,
|
|
6
|
-
* allowing every signature on one HTTP attempt to share a nonce and timestamp.
|
|
7
|
-
*/
|
|
8
|
-
export function composeSigners(...signers) {
|
|
9
|
-
return {
|
|
10
|
-
protocol: 'composed',
|
|
11
|
-
async sign(request, context = SigningContext.create()) {
|
|
12
|
-
for (const signer of signers)
|
|
13
|
-
request = await signer.sign(request, context);
|
|
14
|
-
return request;
|
|
15
|
-
},
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Wraps a fetch implementation so every outbound request is attested.
|
|
20
|
-
*
|
|
21
|
-
* Configure this wrapper as the underlying `fetch` passed to `mppx/client`
|
|
22
|
-
* `Fetch.from()`. MPPX then uses it for both the initial request and its
|
|
23
|
-
* automatic request containing an `Authorization: Payment` credential.
|
|
24
|
-
*/
|
|
25
|
-
export function wrapFetch(fetch, signer) {
|
|
26
|
-
return async (input, init) => fetch(await signer.sign(new Request(input, init)));
|
|
27
|
-
}
|
|
28
|
-
//# sourceMappingURL=Client.js.map
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type * as Types from './Types.js';
|
|
2
|
-
/** Verifies every configured request-attestation protocol. */
|
|
3
|
-
export declare function verify<const verifiers extends Types.VerifierMap>(request: Request, verifiers: verifiers): Promise<Types.VerificationsFrom<verifiers>>;
|
|
4
|
-
//# sourceMappingURL=Server.d.ts.map
|