mppx 0.15.0 → 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.
Files changed (90) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/cli/cli.js +137 -131
  3. package/dist/cli/plugins/index.js +11 -11
  4. package/dist/cli/validate/payment.d.ts +12 -0
  5. package/dist/cli/validate/payment.js +113 -14
  6. package/dist/client/Mppx.d.ts +13 -3
  7. package/dist/client/Mppx.js +47 -22
  8. package/dist/client/internal/Fetch.d.ts +11 -0
  9. package/dist/client/internal/Fetch.js +46 -8
  10. package/dist/client/internal/ProofRealm.d.ts +21 -0
  11. package/dist/client/internal/ProofRealm.js +55 -0
  12. package/dist/{attestation → extensions/identity}/Constants.d.ts +2 -2
  13. package/dist/{attestation → extensions/identity}/Constants.js +2 -2
  14. package/dist/extensions/identity/Types.d.ts +21 -0
  15. package/dist/extensions/identity/index.d.ts +7 -0
  16. package/dist/extensions/identity/index.js +6 -0
  17. package/dist/{attestation → extensions/identity}/internal/HttpMessageSignature.d.ts +3 -3
  18. package/dist/{attestation → extensions/identity}/internal/HttpMessageSignature.js +10 -10
  19. package/dist/extensions/identity/internal/SigningContext.d.ts +6 -0
  20. package/dist/{attestation → extensions/identity}/internal/SigningContext.js +3 -3
  21. package/dist/extensions/identity/internal/Verification.d.ts +9 -0
  22. package/dist/extensions/identity/internal/Verification.js +10 -0
  23. package/dist/{tap → extensions/identity/tap}/Constants.js +1 -1
  24. package/dist/extensions/identity/tap/client/index.d.ts +32 -0
  25. package/dist/{tap → extensions/identity/tap}/client/index.js +13 -9
  26. package/dist/extensions/identity/tap/server/index.d.ts +27 -0
  27. package/dist/{tap → extensions/identity/tap}/server/index.js +12 -4
  28. package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/Constants.js +1 -1
  29. package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/client/index.d.ts +6 -5
  30. package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/client/index.js +5 -5
  31. package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/server/index.d.ts +6 -5
  32. package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/server/index.js +6 -4
  33. package/dist/identity/Client.d.ts +34 -0
  34. package/dist/identity/Client.js +133 -0
  35. package/dist/identity/Server.d.ts +46 -0
  36. package/dist/identity/Server.js +145 -0
  37. package/dist/identity/Types.d.ts +90 -0
  38. package/dist/identity/Types.js +2 -0
  39. package/dist/{attestation → identity}/index.d.ts +2 -2
  40. package/dist/{attestation → identity}/index.js +1 -2
  41. package/dist/identity/internal/SigningContext.d.ts +6 -0
  42. package/dist/identity/internal/SigningContext.js +11 -0
  43. package/dist/integrations/x402/Evm.d.ts +1 -0
  44. package/dist/internal/version.d.ts +2 -2
  45. package/dist/internal/version.js +1 -1
  46. package/dist/mcp/client/McpClient.d.ts +5 -0
  47. package/dist/mcp/client/McpClient.js +2 -0
  48. package/dist/proxy/Proxy.js +10 -5
  49. package/dist/proxy/Service.d.ts +42 -4
  50. package/dist/proxy/Service.js +21 -5
  51. package/dist/server/Mppx.d.ts +27 -8
  52. package/dist/server/Mppx.js +136 -51
  53. package/dist/stripe/server/internal/html.gen.js +1 -1
  54. package/dist/tempo/internal/charge.js +2 -1
  55. package/dist/tempo/internal/fee-payer.d.ts +0 -2
  56. package/dist/tempo/internal/fee-payer.js +0 -4
  57. package/dist/tempo/server/Subscription.js +0 -1
  58. package/dist/tempo/server/internal/html.gen.js +1 -1
  59. package/dist/tempo/session/client/Runtime.d.ts +2 -0
  60. package/dist/tempo/session/client/Session.js +1 -1
  61. package/dist/tempo/session/client/SessionManager.d.ts +6 -0
  62. package/dist/tempo/session/client/SessionManager.js +14 -7
  63. package/dist/tempo/session/client/Transports.d.ts +12 -3
  64. package/dist/tempo/session/client/Transports.js +37 -11
  65. package/dist/tempo/session/precompile/Chain.js +0 -3
  66. package/dist/tempo/subscription/Store.js +10 -9
  67. package/package.json +15 -11
  68. package/dist/attestation/Client.d.ts +0 -17
  69. package/dist/attestation/Client.js +0 -28
  70. package/dist/attestation/Server.d.ts +0 -4
  71. package/dist/attestation/Server.js +0 -8
  72. package/dist/attestation/Types.d.ts +0 -76
  73. package/dist/attestation/internal/SigningContext.d.ts +0 -4
  74. package/dist/tap/client/index.d.ts +0 -26
  75. package/dist/tap/server/index.d.ts +0 -20
  76. /package/dist/{attestation → extensions/identity}/Types.js +0 -0
  77. /package/dist/{tap → extensions/identity/tap}/Constants.d.ts +0 -0
  78. /package/dist/{tap → extensions/identity/tap}/Types.d.ts +0 -0
  79. /package/dist/{tap → extensions/identity/tap}/Types.js +0 -0
  80. /package/dist/{tap → extensions/identity/tap}/index.d.ts +0 -0
  81. /package/dist/{tap → extensions/identity/tap}/index.js +0 -0
  82. /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/Constants.d.ts +0 -0
  83. /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/Types.d.ts +0 -0
  84. /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/Types.js +0 -0
  85. /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/index.d.ts +0 -0
  86. /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/index.js +0 -0
  87. /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/internal/JwkThumbprint.d.ts +0 -0
  88. /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/internal/JwkThumbprint.js +0 -0
  89. /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/internal/SignatureAgent.d.ts +0 -0
  90. /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/internal/SignatureAgent.js +0 -0
@@ -0,0 +1,21 @@
1
+ import type * as Challenge from '../../Challenge.js';
2
+ /**
3
+ * Pins that let a server origin request zero-amount Tempo proofs for a realm other than its
4
+ * hostname, keyed by origin (`scheme://host[:port]`), such as
5
+ * `{ 'https://api.example.com': 'MPP Payment' }`.
6
+ */
7
+ export type TrustedRealms = Readonly<Record<string, string>>;
8
+ /**
9
+ * Refuses a zero-amount Tempo proof whose realm the HTTP server that sent the Challenge does not
10
+ * own. A proof authenticates the payer at the Challenge realm, so a foreign origin could otherwise
11
+ * relay another server's Challenge and replay the signed proof there. The server owns the realm
12
+ * when it is the request hostname, or when `trustedRealms` pins it to the request origin. Pass
13
+ * `url` as a function to resolve it only for proof Challenges.
14
+ */
15
+ export declare function assert(challenge: Challenge.Challenge, url: URL | (() => URL), trustedRealms: TrustedRealms | undefined): void;
16
+ /**
17
+ * Refuses a zero-amount Tempo proof on a transport without an origin, such as MCP, unless
18
+ * `trustedRealms` lists its realm.
19
+ */
20
+ export declare function assertWithoutOrigin(challenge: Challenge.Challenge, trustedRealms: readonly string[] | undefined): void;
21
+ //# sourceMappingURL=ProofRealm.d.ts.map
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Refuses a zero-amount Tempo proof whose realm the HTTP server that sent the Challenge does not
3
+ * own. A proof authenticates the payer at the Challenge realm, so a foreign origin could otherwise
4
+ * relay another server's Challenge and replay the signed proof there. The server owns the realm
5
+ * when it is the request hostname, or when `trustedRealms` pins it to the request origin. Pass
6
+ * `url` as a function to resolve it only for proof Challenges.
7
+ */
8
+ export function assert(challenge, url, trustedRealms) {
9
+ if (!isProof(challenge))
10
+ return;
11
+ url = typeof url === 'function' ? url() : url;
12
+ const { realm } = challenge;
13
+ if (realm.toLowerCase() === url.hostname.toLowerCase())
14
+ return;
15
+ const origin = url.origin.toLowerCase();
16
+ for (const [trustedOrigin, trustedRealm] of Object.entries(trustedRealms ?? {}))
17
+ if (trustedRealm === realm && normalizeOrigin(trustedOrigin) === origin)
18
+ return;
19
+ throw new Error(`Refusing to sign Tempo proof for realm ${JSON.stringify(realm)} from ${url.origin}. Pin the realm to this origin with \`trustedTempoProofRealms\` if this server is expected to issue it.`);
20
+ }
21
+ /**
22
+ * Refuses a zero-amount Tempo proof on a transport without an origin, such as MCP, unless
23
+ * `trustedRealms` lists its realm.
24
+ */
25
+ export function assertWithoutOrigin(challenge, trustedRealms) {
26
+ if (!isProof(challenge))
27
+ return;
28
+ if (trustedRealms?.includes(challenge.realm))
29
+ return;
30
+ throw new Error(`Refusing to sign Tempo proof for untrusted realm ${JSON.stringify(challenge.realm)}. Add it to \`trustedTempoProofRealms\` if this server is expected to issue it.`);
31
+ }
32
+ /**
33
+ * Whether `challenge` is a zero-amount `tempo/charge` Challenge, paid with a signed proof. Uses the
34
+ * same `BigInt` conversion as the Tempo charge client, so every encoding it signs a proof for
35
+ * (such as `"0x0"` or `" 0 "`) is checked.
36
+ */
37
+ function isProof(challenge) {
38
+ if (challenge.method !== 'tempo' || challenge.intent !== 'charge')
39
+ return false;
40
+ try {
41
+ return BigInt(challenge.request.amount) === 0n;
42
+ }
43
+ catch {
44
+ return false;
45
+ }
46
+ }
47
+ function normalizeOrigin(origin) {
48
+ try {
49
+ return new URL(origin).origin.toLowerCase();
50
+ }
51
+ catch {
52
+ return origin.toLowerCase();
53
+ }
54
+ }
55
+ //# sourceMappingURL=ProofRealm.js.map
@@ -1,11 +1,11 @@
1
- /** RFC 9421 signature algorithms supported by request attestation. */
1
+ /** RFC 9421 signature algorithms supported by HTTP message signatures. */
2
2
  export declare const Algorithms: {
3
3
  /** EdDSA using the Ed25519 curve. */
4
4
  readonly ed25519: 'ed25519';
5
5
  /** RSASSA-PSS using SHA-512 and a 64-byte salt. */
6
6
  readonly rsaPssSha512: 'rsa-pss-sha512';
7
7
  };
8
- /** HTTP headers defined by RFC 9421 for request-attestation signatures. */
8
+ /** HTTP headers defined by RFC 9421 for identity signatures. */
9
9
  export declare const Headers: {
10
10
  /** Carries the RFC 9421 signature bytes. */
11
11
  readonly signature: 'Signature';
@@ -1,11 +1,11 @@
1
- /** RFC 9421 signature algorithms supported by request attestation. */
1
+ /** RFC 9421 signature algorithms supported by HTTP message signatures. */
2
2
  export const Algorithms = {
3
3
  /** EdDSA using the Ed25519 curve. */
4
4
  ed25519: 'ed25519',
5
5
  /** RSASSA-PSS using SHA-512 and a 64-byte salt. */
6
6
  rsaPssSha512: 'rsa-pss-sha512',
7
7
  };
8
- /** HTTP headers defined by RFC 9421 for request-attestation signatures. */
8
+ /** HTTP headers defined by RFC 9421 for identity signatures. */
9
9
  export const Headers = {
10
10
  /** Carries the RFC 9421 signature bytes. */
11
11
  signature: 'Signature',
@@ -0,0 +1,21 @@
1
+ import type { MaybePromise } from '../../internal/types.js';
2
+ import type { Algorithms } from './Constants.js';
3
+ /** RFC 9421 algorithms implemented by the HTTP message signature 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
+ /** Values shared by every signature on one HTTP attempt. */
15
+ export type SigningContext = {
16
+ /** Unix timestamp, in seconds, at which the attempt was created. */
17
+ readonly created: number;
18
+ /** Base64url-encoded random value identifying the attempt. */
19
+ readonly nonce: string;
20
+ };
21
+ //# sourceMappingURL=Types.d.ts.map
@@ -0,0 +1,7 @@
1
+ /** Client and server adapters for the TAP agent-recognition signature profile. */
2
+ export * as Tap from './tap/index.js';
3
+ /** Client and server adapters for the Web Bot Auth HTTPS-directory profile. */
4
+ export * as WebBotAuth from './web-bot-auth/index.js';
5
+ export * from './Constants.js';
6
+ export type * from './Types.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,6 @@
1
+ /** Client and server adapters for the TAP agent-recognition signature profile. */
2
+ export * as Tap from './tap/index.js';
3
+ /** Client and server adapters for the Web Bot Auth HTTPS-directory profile. */
4
+ export * as WebBotAuth from './web-bot-auth/index.js';
5
+ export * from './Constants.js';
6
+ //# sourceMappingURL=index.js.map
@@ -1,8 +1,8 @@
1
1
  import type { BareItem } from 'structured-headers';
2
- import type { MaybePromise } from '../../internal/types.js';
3
- import * as Store from '../../Store.js';
2
+ import type { MaybePromise } from '../../../internal/types.js';
3
+ import * as Store from '../../../Store.js';
4
4
  import type { KeyResolver, SignatureAlgorithm, SigningContext } from '../Types.js';
5
- /** RFC 9421 constants used by request-attestation signature profiles. */
5
+ /** RFC 9421 constants used by identity signature profiles. */
6
6
  export declare const Constants: {
7
7
  /** Derived request components supported by this narrow request profile. */
8
8
  readonly components: {
@@ -1,8 +1,8 @@
1
1
  import { isInnerList, parseDictionary, serializeItem, serializeDictionary, serializeInnerList, serializeParameters, } from 'structured-headers';
2
- import * as Store from '../../Store.js';
3
- import { Algorithms, Headers as AttestationHeaders } from '../Constants.js';
2
+ import * as Store from '../../../Store.js';
3
+ import { Algorithms, Headers as SignatureHeaders } from '../Constants.js';
4
4
  import * as SigningContextInternal from './SigningContext.js';
5
- /** RFC 9421 constants used by request-attestation signature profiles. */
5
+ /** RFC 9421 constants used by identity signature profiles. */
6
6
  export const Constants = {
7
7
  /** Derived request components supported by this narrow request profile. */
8
8
  components: {
@@ -55,16 +55,16 @@ export async function sign(request, options) {
55
55
  };
56
56
  const signature = await crypto.subtle.sign(webCryptoAlgorithm(algorithm), options.key, toArrayBuffer(encode(signatureBase(request, input))));
57
57
  const headers = new Headers(request.headers);
58
- const inputs = parseHeaderDictionary(headers, AttestationHeaders.signatureInput);
59
- const signatures = parseHeaderDictionary(headers, AttestationHeaders.signature);
58
+ const inputs = parseHeaderDictionary(headers, SignatureHeaders.signatureInput);
59
+ const signatures = parseHeaderDictionary(headers, SignatureHeaders.signature);
60
60
  if (!haveSameKeys(inputs, signatures))
61
61
  throw new Error('Signature-Input and Signature must contain the same labels.');
62
62
  if (inputs.has(input.label) || signatures.has(input.label))
63
63
  throw new Error(`HTTP message signature label "${input.label}" already exists.`);
64
64
  inputs.set(input.label, toInnerList(input));
65
65
  signatures.set(input.label, [signature, new Map()]);
66
- headers.set(AttestationHeaders.signatureInput, serializeDictionary(inputs));
67
- headers.set(AttestationHeaders.signature, serializeDictionary(signatures));
66
+ headers.set(SignatureHeaders.signatureInput, serializeDictionary(inputs));
67
+ headers.set(SignatureHeaders.signature, serializeDictionary(signatures));
68
68
  return new Request(request, { headers });
69
69
  }
70
70
  /** Verifies a request signature, its lifetime, and optionally its nonce. */
@@ -137,8 +137,8 @@ export async function verify(request, options) {
137
137
  return { status: 'verified', input };
138
138
  }
139
139
  function parse(request, expectedTag) {
140
- const inputHeader = request.headers.get(AttestationHeaders.signatureInput);
141
- const signatureHeader = request.headers.get(AttestationHeaders.signature);
140
+ const inputHeader = request.headers.get(SignatureHeaders.signatureInput);
141
+ const signatureHeader = request.headers.get(SignatureHeaders.signature);
142
142
  if (!inputHeader && !signatureHeader)
143
143
  return undefined;
144
144
  if (!inputHeader || !signatureHeader)
@@ -219,7 +219,7 @@ function algorithmFromKey(key) {
219
219
  for (const algorithm of Object.values(Algorithms))
220
220
  if (keySupportsAlgorithm(key, algorithm))
221
221
  return algorithm;
222
- throw new TypeError('Request attestation requires an Ed25519 or RSA-PSS SHA-512 signing key.');
222
+ throw new TypeError('HTTP message signatures require an Ed25519 or RSA-PSS SHA-512 signing key.');
223
223
  }
224
224
  function isInteger(value) {
225
225
  return typeof value === 'number' && Number.isInteger(value);
@@ -0,0 +1,6 @@
1
+ /** Creates the attempt values shared by every prover on one HTTP attempt. */
2
+ export declare function create(): {
3
+ readonly created: number;
4
+ readonly nonce: string;
5
+ };
6
+ //# sourceMappingURL=SigningContext.d.ts.map
@@ -1,11 +1,11 @@
1
1
  import { Base64 } from 'ox';
2
- /** Creates the signing context for one outbound HTTP request attempt. */
2
+ /** Creates the attempt values shared by every prover on one HTTP attempt. */
3
3
  export function create() {
4
4
  const bytes = new Uint8Array(64);
5
5
  crypto.getRandomValues(bytes);
6
- return Object.freeze({
6
+ return {
7
7
  created: Math.floor(Date.now() / 1_000),
8
8
  nonce: Base64.fromBytes(bytes, { pad: false, url: true }),
9
- });
9
+ };
10
10
  }
11
11
  //# sourceMappingURL=SigningContext.js.map
@@ -0,0 +1,9 @@
1
+ import type * as Identity from '../../../identity/Types.js';
2
+ import type { VerificationResult } from './HttpMessageSignature.js';
3
+ /** Maps a non-verified HTTP message signature result to an identity verification. */
4
+ export declare function fromSignature(result: Exclude<VerificationResult, {
5
+ status: 'verified';
6
+ }>): Exclude<Identity.Verification, {
7
+ status: 'valid';
8
+ }>;
9
+ //# sourceMappingURL=Verification.d.ts.map
@@ -0,0 +1,10 @@
1
+ /** Maps a non-verified HTTP message signature result to an identity verification. */
2
+ export function fromSignature(result) {
3
+ if (result.status === 'absent')
4
+ return { status: 'missing' };
5
+ if (result.status === 'invalid')
6
+ return { status: 'invalid', reason: result.reason };
7
+ // The signature was presented but its key is not trusted or available.
8
+ return { status: 'invalid', code: 403, reason: result.reason };
9
+ }
10
+ //# sourceMappingURL=Verification.js.map
@@ -1,4 +1,4 @@
1
- import { Constants as HttpMessageSignature } from '../attestation/internal/HttpMessageSignature.js';
1
+ import { Constants as HttpMessageSignature } from '../internal/HttpMessageSignature.js';
2
2
  /** TAP values required for its RFC 9421 agent-recognition signature profile. */
3
3
  export const Constants = {
4
4
  /** Stable identifier for Trusted Agent Protocol signers and replay storage. */
@@ -0,0 +1,32 @@
1
+ import type * as Identity from '../../../../identity/Types.js';
2
+ import { Constants } from '../Constants.js';
3
+ /**
4
+ * Creates a TAP identity prover.
5
+ *
6
+ * The prover signs each in-scope attempt, including MPP payment retries, with
7
+ * an RFC 9421 HTTP message signature carrying TAP's `agent-browser-auth` or
8
+ * `agent-payer-auth` tag.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * Mppx.create({ identity: [Tap.Client.prover({ intent: 'payment', key, keyId, scope: ['https://shop.example'] })], methods })
13
+ * ```
14
+ */
15
+ export declare function prover(config: prover.Config): Identity.Prover;
16
+ export declare namespace prover {
17
+ type Config = {
18
+ /** TAP signature type for the request. */
19
+ intent: (typeof Constants.intents)[keyof typeof Constants.intents];
20
+ /** Ed25519 or RSA-PSS SHA-512 private key provisioned to the agent provider. */
21
+ key: CryptoKey;
22
+ /** Identifier the merchant uses to resolve the signing public key. */
23
+ keyId: string;
24
+ /** Origins that receive TAP signatures, or `'*'` for any origin. */
25
+ scope: Identity.Prover['scope'];
26
+ /** Signature lifetime in seconds. TAP permits at most eight minutes. @default 480 */
27
+ expiresIn?: number | undefined;
28
+ /** RFC 9421 dictionary label. @default 'tap' */
29
+ label?: string | undefined;
30
+ };
31
+ }
32
+ //# sourceMappingURL=index.d.ts.map
@@ -1,14 +1,18 @@
1
- import * as HttpMessageSignature from '../../attestation/internal/HttpMessageSignature.js';
1
+ import * as HttpMessageSignature from '../../internal/HttpMessageSignature.js';
2
2
  import { Constants } from '../Constants.js';
3
3
  /**
4
- * Creates a TAP request signer.
4
+ * Creates a TAP identity prover.
5
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.
6
+ * The prover signs each in-scope attempt, including MPP payment retries, with
7
+ * an RFC 9421 HTTP message signature carrying TAP's `agent-browser-auth` or
8
+ * `agent-payer-auth` tag.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * Mppx.create({ identity: [Tap.Client.prover({ intent: 'payment', key, keyId, scope: ['https://shop.example'] })], methods })
13
+ * ```
10
14
  */
11
- export function signer(config) {
15
+ export function prover(config) {
12
16
  const tag = config.intent === Constants.intents.payment ? Constants.tags.payment : Constants.tags.browse;
13
17
  const expiresIn = config.expiresIn ?? Constants.defaultSignatureLifetime;
14
18
  if (!Number.isInteger(expiresIn) ||
@@ -16,8 +20,8 @@ export function signer(config) {
16
20
  expiresIn > Constants.maximumSignatureLifetime)
17
21
  throw new RangeError(`TAP expiresIn must be an integer from 1 to ${Constants.maximumSignatureLifetime}.`);
18
22
  return {
19
- protocol: Constants.protocol,
20
- sign(request, context) {
23
+ scope: config.scope,
24
+ prove(request, context) {
21
25
  return HttpMessageSignature.sign(request, {
22
26
  components: Constants.requiredComponents,
23
27
  context,
@@ -0,0 +1,27 @@
1
+ import type * as Identity from '../../../../identity/Types.js';
2
+ import type * as Store from '../../../../Store.js';
3
+ import type * as SignatureTypes from '../../Types.js';
4
+ import type * as Types from '../Types.js';
5
+ /**
6
+ * Creates a request-stage identity verifier for TAP agent-recognition signatures.
7
+ *
8
+ * TAP verifies trusted agent participation and request integrity. Consumer
9
+ * recognition and payment-container verification stay protocol-specific and
10
+ * are intentionally not inferred from this header-only verifier.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * const tap = Tap.Server.verifier({ keyResolver, nonceStore })
15
+ * mppx.charge({ amount: '1', identity: [tap] })
16
+ * ```
17
+ */
18
+ export declare function verifier(config: verifier.Config): Identity.Verifier<Types.VerifiedRequest>;
19
+ export declare namespace verifier {
20
+ type Config = {
21
+ /** Resolves a TAP-approved public key by its `keyid` and signature algorithm. */
22
+ keyResolver: SignatureTypes.KeyResolver;
23
+ /** Atomically consumes each nonce in shared storage for multi-instance deployments. */
24
+ nonceStore: Store.AtomicStore;
25
+ };
26
+ }
27
+ //# sourceMappingURL=index.d.ts.map
@@ -1,14 +1,22 @@
1
- import * as HttpMessageSignature from '../../attestation/internal/HttpMessageSignature.js';
1
+ import * as HttpMessageSignature from '../../internal/HttpMessageSignature.js';
2
+ import * as Verification from '../../internal/Verification.js';
2
3
  import { Constants } from '../Constants.js';
3
4
  /**
4
- * Creates a verifier for TAP agent-recognition signatures.
5
+ * Creates a request-stage identity verifier for TAP agent-recognition signatures.
5
6
  *
6
7
  * TAP verifies trusted agent participation and request integrity. Consumer
7
8
  * recognition and payment-container verification stay protocol-specific and
8
9
  * are intentionally not inferred from this header-only verifier.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const tap = Tap.Server.verifier({ keyResolver, nonceStore })
14
+ * mppx.charge({ amount: '1', identity: [tap] })
15
+ * ```
9
16
  */
10
17
  export function verifier(config) {
11
18
  return {
19
+ stage: 'request',
12
20
  async verify(request) {
13
21
  const result = await HttpMessageSignature.verify(request, {
14
22
  keyResolver: config.keyResolver,
@@ -19,9 +27,9 @@ export function verifier(config) {
19
27
  tag: [Constants.tags.browse, Constants.tags.payment],
20
28
  });
21
29
  if (result.status !== 'verified')
22
- return result;
30
+ return Verification.fromSignature(result);
23
31
  return {
24
- status: 'verified',
32
+ status: 'valid',
25
33
  value: {
26
34
  keyId: result.input.keyId,
27
35
  nonce: result.input.nonce,
@@ -1,4 +1,4 @@
1
- import { Constants as HttpMessageSignature } from '../attestation/internal/HttpMessageSignature.js';
1
+ import { Constants as HttpMessageSignature } from '../internal/HttpMessageSignature.js';
2
2
  /** Web Bot Auth values for the supported HTTPS-directory signature profile. */
3
3
  export const Constants = {
4
4
  /** Stable identifier for Web Bot Auth signers and replay storage. */
@@ -1,7 +1,6 @@
1
- import type * as AttestationTypes from '../../attestation/Types.js';
2
- import { Constants } from '../Constants.js';
1
+ import type * as Identity from '../../../../identity/Types.js';
3
2
  /**
4
- * Creates a Web Bot Auth HTTPS-directory profile request signer.
3
+ * Creates a Web Bot Auth HTTPS-directory profile identity prover.
5
4
  *
6
5
  * The signed `Signature-Agent` header links the request to the HTTPS origin
7
6
  * of an HTTP Message Signatures Directory. This adapter does not support
@@ -9,13 +8,15 @@ import { Constants } from '../Constants.js';
9
8
  * establishes bot identity only; it does not assert consumer identity or
10
9
  * authority to make a payment.
11
10
  */
12
- export declare function signer(config: signer.Config): AttestationTypes.Signer<typeof Constants.protocol>;
13
- export declare namespace signer {
11
+ export declare function prover(config: prover.Config): Identity.Prover;
12
+ export declare namespace prover {
14
13
  type Config = {
15
14
  /** Ed25519 or RSA-PSS SHA-512 private key registered for the bot. */
16
15
  key: CryptoKey;
17
16
  /** RFC 7638 JWK thumbprint for the registered public key. */
18
17
  keyId: string;
18
+ /** Origins that receive Web Bot Auth signatures, or `'*'` for any origin. */
19
+ scope: Identity.Prover['scope'];
19
20
  /** Required HTTPS directory origin, sent with the default `directory` discovery type. */
20
21
  signatureAgent: string;
21
22
  /** Dictionary member name used for `Signature-Agent`. @default signature label */
@@ -1,10 +1,10 @@
1
1
  import { parseDictionary, serializeDictionary } from 'structured-headers';
2
- import * as HttpMessageSignature from '../../attestation/internal/HttpMessageSignature.js';
2
+ import * as HttpMessageSignature from '../../internal/HttpMessageSignature.js';
3
3
  import { Constants } from '../Constants.js';
4
4
  import * as JwkThumbprint from '../internal/JwkThumbprint.js';
5
5
  import * as SignatureAgent from '../internal/SignatureAgent.js';
6
6
  /**
7
- * Creates a Web Bot Auth HTTPS-directory profile request signer.
7
+ * Creates a Web Bot Auth HTTPS-directory profile identity prover.
8
8
  *
9
9
  * The signed `Signature-Agent` header links the request to the HTTPS origin
10
10
  * of an HTTP Message Signatures Directory. This adapter does not support
@@ -12,7 +12,7 @@ import * as SignatureAgent from '../internal/SignatureAgent.js';
12
12
  * establishes bot identity only; it does not assert consumer identity or
13
13
  * authority to make a payment.
14
14
  */
15
- export function signer(config) {
15
+ export function prover(config) {
16
16
  const label = config.label ?? Constants.label;
17
17
  const signatureAgentKey = config.signatureAgentKey ?? label;
18
18
  const expiresIn = config.expiresIn ?? Constants.defaultSignatureLifetime;
@@ -24,8 +24,8 @@ export function signer(config) {
24
24
  if (!Number.isInteger(expiresIn) || expiresIn <= 0)
25
25
  throw new RangeError('Web Bot Auth expiresIn must be a positive integer.');
26
26
  return {
27
- protocol: Constants.protocol,
28
- sign(request, context) {
27
+ scope: config.scope,
28
+ prove(request, context) {
29
29
  const headers = new Headers(request.headers);
30
30
  const signatureAgents = parseSignatureAgents(headers);
31
31
  if (signatureAgents.has(signatureAgentKey))
@@ -1,8 +1,9 @@
1
- import type * as Attestation from '../../attestation/Types.js';
2
- import type * as Store from '../../Store.js';
1
+ import type * as Identity from '../../../../identity/Types.js';
2
+ import type * as Store from '../../../../Store.js';
3
+ import type * as SignatureTypes from '../../Types.js';
3
4
  import type * as Types from '../Types.js';
4
5
  /**
5
- * Creates a verifier for the Web Bot Auth HTTPS-directory profile.
6
+ * Creates a request-stage identity verifier for the Web Bot Auth HTTPS-directory profile.
6
7
  *
7
8
  * It requires an `@authority` and signed `Signature-Agent` directory member;
8
9
  * direct key configuration and other Web Bot Auth discovery types are outside
@@ -10,7 +11,7 @@ import type * as Types from '../Types.js';
10
11
  * automated HTTP client. It must not be used on its own as user or payment
11
12
  * authorization.
12
13
  */
13
- export declare function verifier(config: verifier.Config): Attestation.Verifier<Types.VerifiedRequest>;
14
+ export declare function verifier(config: verifier.Config): Identity.Verifier<Types.VerifiedRequest>;
14
15
  export declare namespace verifier {
15
16
  type Config = {
16
17
  /**
@@ -21,7 +22,7 @@ export declare namespace verifier {
21
22
  * must be extractable so their RFC 7638 thumbprints can be verified.
22
23
  */
23
24
  keyResolver: (parameters: {
24
- algorithm: Attestation.SignatureAlgorithm;
25
+ algorithm: SignatureTypes.SignatureAlgorithm;
25
26
  keyId: string;
26
27
  request: Request;
27
28
  signatureAgent: string;
@@ -1,10 +1,11 @@
1
1
  import { isInnerList, parseDictionary, Token } from 'structured-headers';
2
- import * as HttpMessageSignature from '../../attestation/internal/HttpMessageSignature.js';
2
+ import * as HttpMessageSignature from '../../internal/HttpMessageSignature.js';
3
+ import * as Verification from '../../internal/Verification.js';
3
4
  import { Constants } from '../Constants.js';
4
5
  import * as JwkThumbprint from '../internal/JwkThumbprint.js';
5
6
  import * as SignatureAgent from '../internal/SignatureAgent.js';
6
7
  /**
7
- * Creates a verifier for the Web Bot Auth HTTPS-directory profile.
8
+ * Creates a request-stage identity verifier for the Web Bot Auth HTTPS-directory profile.
8
9
  *
9
10
  * It requires an `@authority` and signed `Signature-Agent` directory member;
10
11
  * direct key configuration and other Web Bot Auth discovery types are outside
@@ -17,6 +18,7 @@ export function verifier(config) {
17
18
  if (!Number.isInteger(maxAge) || maxAge <= 0)
18
19
  throw new RangeError('Web Bot Auth maxAge must be a positive integer.');
19
20
  return {
21
+ stage: 'request',
20
22
  async verify(request) {
21
23
  let signatureAgent;
22
24
  const result = await HttpMessageSignature.verify(request, {
@@ -73,9 +75,9 @@ export function verifier(config) {
73
75
  },
74
76
  });
75
77
  if (result.status !== 'verified')
76
- return result;
78
+ return Verification.fromSignature(result);
77
79
  return {
78
- status: 'verified',
80
+ status: 'valid',
79
81
  value: {
80
82
  keyId: result.input.keyId,
81
83
  nonce: result.input.nonce,
@@ -0,0 +1,34 @@
1
+ import type * as Types from './Types.js';
2
+ /** Sends HTTP attempts with every in-scope prover applied. */
3
+ export type Client = {
4
+ /**
5
+ * Proves and sends one request.
6
+ *
7
+ * Requests that carry proofs do not follow redirects: a redirect rejects
8
+ * (`redirect: 'error'`), so proofs never reach another URL. Requests with no
9
+ * prover in scope are sent unchanged. If a prover asks to retry a rejected
10
+ * (non-402) response, the request is proved again and resent once, except for
11
+ * paid attempts, which are never resent.
12
+ */
13
+ send: (fetch: typeof globalThis.fetch, request: Request, context?: Types.Context) => Promise<{
14
+ request: Request;
15
+ response: Response;
16
+ }>;
17
+ /** Lets in-scope provers prepare proofs for a 402 challenge from `url` before the payment retry. */
18
+ challenge: (response: Response, context: Types.Context, url: string) => Promise<void>;
19
+ };
20
+ /**
21
+ * Creates the client runner for a list of provers.
22
+ *
23
+ * Provers run in list order on every attempt, sharing one attempt context.
24
+ * List request signers last so their signatures cover headers added by
25
+ * earlier provers.
26
+ */
27
+ export declare function from(provers: readonly Types.Prover[]): Client;
28
+ /**
29
+ * Wraps a fetch implementation so every request is proved.
30
+ *
31
+ * Prefer `Mppx.create({ identity })`, which also passes the payment challenge to provers.
32
+ */
33
+ export declare function wrapFetch(fetch: typeof globalThis.fetch, client: Client, context?: Types.Context): typeof globalThis.fetch;
34
+ //# sourceMappingURL=Client.d.ts.map