mppx 0.15.0 → 0.17.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 +47 -0
- package/dist/Challenge.d.ts +6 -0
- package/dist/Challenge.js +12 -0
- package/dist/Method.d.ts +2 -0
- package/dist/cli/cli.js +143 -131
- package/dist/cli/plugins/index.js +11 -11
- package/dist/cli/validate/payment.d.ts +12 -0
- package/dist/cli/validate/payment.js +137 -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/client/internal/protocols/Mpp.js +4 -1
- 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 +10 -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 +59 -0
- package/dist/identity/Server.js +194 -0
- package/dist/identity/Types.d.ts +112 -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 +1 -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/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 +27 -8
- package/dist/server/Mppx.js +164 -54
- package/dist/server/internal/challengeMeta.d.ts +6 -0
- package/dist/server/internal/challengeMeta.js +17 -1
- package/dist/stripe/server/internal/html.gen.js +1 -1
- package/dist/tempo/client/Charge.d.ts +11 -0
- package/dist/tempo/client/Charge.js +30 -1
- package/dist/tempo/internal/charge.js +2 -1
- package/dist/tempo/internal/defaults.d.ts +9 -0
- package/dist/tempo/internal/defaults.js +9 -0
- package/dist/tempo/internal/fee-payer.d.ts +0 -2
- package/dist/tempo/internal/fee-payer.js +2 -6
- package/dist/tempo/server/Charge.js +12 -1
- package/dist/tempo/server/Subscription.js +0 -1
- 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/subscription/Store.js +10 -9
- 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,
|
|
@@ -35,6 +35,14 @@ export function fromStore(store, options) {
|
|
|
35
35
|
return null;
|
|
36
36
|
return (await store.get(recordKey(subscriptionId)));
|
|
37
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
|
+
}
|
|
38
46
|
async function clearRenewalState(subscriptionId, periodIndex, attempt) {
|
|
39
47
|
await store.update(recordKey(subscriptionId), (current) => {
|
|
40
48
|
const subscription = current;
|
|
@@ -216,7 +224,7 @@ export function fromStore(store, options) {
|
|
|
216
224
|
async getOrCreateAccessKey(key) {
|
|
217
225
|
const existing = (await store.get(accessKeyKey(key)));
|
|
218
226
|
if (existing)
|
|
219
|
-
return existing;
|
|
227
|
+
return ensureAccessKeyAddressIndex(existing);
|
|
220
228
|
const privateKey = Secp256k1.randomPrivateKey();
|
|
221
229
|
const account = TempoAccount.fromSecp256k1(privateKey);
|
|
222
230
|
const candidate = {
|
|
@@ -231,14 +239,7 @@ export function fromStore(store, options) {
|
|
|
231
239
|
}
|
|
232
240
|
return { op: 'set', value: candidate, result: candidate };
|
|
233
241
|
})
|
|
234
|
-
.then(
|
|
235
|
-
await store.update(accessKeyAddressKey(record.accessKeyAddress), (current) => {
|
|
236
|
-
if (current)
|
|
237
|
-
return { op: 'noop', result: undefined };
|
|
238
|
-
return { op: 'set', value: record, result: undefined };
|
|
239
|
-
});
|
|
240
|
-
return record;
|
|
241
|
-
});
|
|
242
|
+
.then(ensureAccessKeyAddressIndex);
|
|
242
243
|
},
|
|
243
244
|
async put(record) {
|
|
244
245
|
await store.put(recordKey(record.subscriptionId), record);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mppx",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.17.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
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/** Verifies every configured request-attestation protocol. */
|
|
2
|
-
export async function verify(request, verifiers) {
|
|
3
|
-
const outcomes = {};
|
|
4
|
-
for (const [name, verifier] of Object.entries(verifiers))
|
|
5
|
-
outcomes[name] = await verifier.verify(request);
|
|
6
|
-
return outcomes;
|
|
7
|
-
}
|
|
8
|
-
//# sourceMappingURL=Server.js.map
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import type { MaybePromise } from '../internal/types.js';
|
|
2
|
-
import type { Algorithms } from './Constants.js';
|
|
3
|
-
/** RFC 9421 algorithms implemented by the request-attestation signer and verifier. */
|
|
4
|
-
export type SignatureAlgorithm = (typeof Algorithms)[keyof typeof Algorithms];
|
|
5
|
-
/** Resolves a trusted public key for a parsed request signature. */
|
|
6
|
-
export type KeyResolver = (parameters: {
|
|
7
|
-
/** RFC 9421 algorithm declared by the signature. */
|
|
8
|
-
algorithm: SignatureAlgorithm;
|
|
9
|
-
/** Key identifier declared by the signature. */
|
|
10
|
-
keyId: string;
|
|
11
|
-
/** Request carrying the signature. */
|
|
12
|
-
request: Request;
|
|
13
|
-
}) => MaybePromise<CryptoKey | undefined>;
|
|
14
|
-
/**
|
|
15
|
-
* The complete outcome of attempting one protocol verifier.
|
|
16
|
-
*
|
|
17
|
-
* `absent` means the protocol did not appear on the request. `invalid` means
|
|
18
|
-
* it appeared but failed validation and must reject the request. `unverified`
|
|
19
|
-
* means key material or another required verification dependency was unavailable.
|
|
20
|
-
* `verified` carries protocol-specific data that is safe for callers to inspect.
|
|
21
|
-
*/
|
|
22
|
-
export type Verification<value = unknown> = {
|
|
23
|
-
status: 'absent';
|
|
24
|
-
} | {
|
|
25
|
-
status: 'invalid';
|
|
26
|
-
reason: string;
|
|
27
|
-
} | {
|
|
28
|
-
status: 'unverified';
|
|
29
|
-
reason: string;
|
|
30
|
-
} | {
|
|
31
|
-
status: 'verified';
|
|
32
|
-
value: value;
|
|
33
|
-
};
|
|
34
|
-
/**
|
|
35
|
-
* Verifies one request-attestation protocol carried by an HTTP request.
|
|
36
|
-
*
|
|
37
|
-
* Verifiers are registered in a {@link VerifierMap}; each map key names the
|
|
38
|
-
* result returned to the caller.
|
|
39
|
-
*/
|
|
40
|
-
export type Verifier<value = unknown> = {
|
|
41
|
-
/** Validates the request and returns a complete protocol verification outcome. */
|
|
42
|
-
verify: (request: Request) => MaybePromise<Verification<value>>;
|
|
43
|
-
};
|
|
44
|
-
/** Maps each recognized protocol name to its verifier. */
|
|
45
|
-
export type VerifierMap = Readonly<Record<string, Verifier>>;
|
|
46
|
-
/** Preserves each configured protocol's complete verification outcome. */
|
|
47
|
-
export type VerificationsFrom<verifiers extends VerifierMap> = {
|
|
48
|
-
readonly [protocol in keyof verifiers]: Awaited<ReturnType<verifiers[protocol]['verify']>>;
|
|
49
|
-
};
|
|
50
|
-
/**
|
|
51
|
-
* Values shared by every signer contributing to one HTTP request attempt.
|
|
52
|
-
*
|
|
53
|
-
* A caller may reuse this context across independent signature protocols so
|
|
54
|
-
* they describe the same attempt. A later network retry must use a new context.
|
|
55
|
-
*/
|
|
56
|
-
export type SigningContext = {
|
|
57
|
-
/** Unix timestamp, in seconds, at which the request attempt was created. */
|
|
58
|
-
readonly created: number;
|
|
59
|
-
/** Base64url-encoded random value identifying this request attempt. */
|
|
60
|
-
readonly nonce: string;
|
|
61
|
-
};
|
|
62
|
-
/**
|
|
63
|
-
* Signs each outbound HTTP request, including MPP payment retries.
|
|
64
|
-
*
|
|
65
|
-
* The protocol type preserves which adapter produced the signer for diagnostics
|
|
66
|
-
* and composition, without asserting that the signer alone authorizes payment.
|
|
67
|
-
*/
|
|
68
|
-
export type Signer<protocol extends string = string> = {
|
|
69
|
-
/** Protocol identifier used for diagnostics. */
|
|
70
|
-
protocol: protocol;
|
|
71
|
-
/** Returns a new request containing the protocol's signature material. */
|
|
72
|
-
sign: (request: Request, context?: SigningContext | undefined) => MaybePromise<Request>;
|
|
73
|
-
};
|
|
74
|
-
/** Maps application-defined names to request-attestation signers. */
|
|
75
|
-
export type SignerMap = Readonly<Record<string, Signer>>;
|
|
76
|
-
//# sourceMappingURL=Types.d.ts.map
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type * as AttestationTypes from '../../attestation/Types.js';
|
|
2
|
-
import { Constants } from '../Constants.js';
|
|
3
|
-
/**
|
|
4
|
-
* Creates a TAP request signer.
|
|
5
|
-
*
|
|
6
|
-
* The signer emits RFC 9421 HTTP message signatures with TAP's
|
|
7
|
-
* `agent-browser-auth` or `agent-payer-auth` tag. Pass it to
|
|
8
|
-
* `Attestation.Client.wrapFetch` so MPPX signs both the initial request and
|
|
9
|
-
* its automatic paid retry.
|
|
10
|
-
*/
|
|
11
|
-
export declare function signer(config: signer.Config): AttestationTypes.Signer<typeof Constants.protocol>;
|
|
12
|
-
export declare namespace signer {
|
|
13
|
-
type Config = {
|
|
14
|
-
/** TAP signature type for the request. */
|
|
15
|
-
intent: (typeof Constants.intents)[keyof typeof Constants.intents];
|
|
16
|
-
/** Ed25519 or RSA-PSS SHA-512 private key provisioned to the agent provider. */
|
|
17
|
-
key: CryptoKey;
|
|
18
|
-
/** Identifier the merchant uses to resolve the signing public key. */
|
|
19
|
-
keyId: string;
|
|
20
|
-
/** Signature lifetime in seconds. TAP permits at most eight minutes. @default 480 */
|
|
21
|
-
expiresIn?: number | undefined;
|
|
22
|
-
/** RFC 9421 dictionary label. @default 'tap' */
|
|
23
|
-
label?: string | undefined;
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type * as Attestation from '../../attestation/Types.js';
|
|
2
|
-
import type * as Store from '../../Store.js';
|
|
3
|
-
import type * as Types from '../Types.js';
|
|
4
|
-
/**
|
|
5
|
-
* Creates a verifier for TAP agent-recognition signatures.
|
|
6
|
-
*
|
|
7
|
-
* TAP verifies trusted agent participation and request integrity. Consumer
|
|
8
|
-
* recognition and payment-container verification stay protocol-specific and
|
|
9
|
-
* are intentionally not inferred from this header-only verifier.
|
|
10
|
-
*/
|
|
11
|
-
export declare function verifier(config: verifier.Config): Attestation.Verifier<Types.VerifiedRequest>;
|
|
12
|
-
export declare namespace verifier {
|
|
13
|
-
type Config = {
|
|
14
|
-
/** Resolves a TAP-approved public key by its `keyid` and signature algorithm. */
|
|
15
|
-
keyResolver: Attestation.KeyResolver;
|
|
16
|
-
/** Atomically consumes each nonce in shared storage for multi-instance deployments. */
|
|
17
|
-
nonceStore: Store.AtomicStore;
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
//# sourceMappingURL=index.d.ts.map
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/internal/SignatureAgent.d.ts
RENAMED
|
File without changes
|
|
File without changes
|