s402 0.4.0 → 0.6.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/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createS402Error, s402Error, s402ErrorCode, s402ErrorCodeType, s402ErrorInfo } from "./errors.mjs";
2
- import { S402_HEADERS, S402_VERSION, s402Discovery, s402EscrowExtra, s402EscrowPayload, s402ExactPayload, s402Mandate, s402MandateRequirements, s402PaymentPayload, s402PaymentPayloadBase, s402PaymentRequirements, s402PaymentSession, s402PrepaidExtra, s402PrepaidPayload, s402RegistryQuery, s402Scheme, s402ServiceEntry, s402SettleResponse, s402SettlementMode, s402StreamExtra, s402StreamPayload, s402UnlockExtra, s402UnlockPayload, s402VerifyResponse } from "./types.mjs";
3
- import { S402_CONTENT_TYPE, decodePayloadBody, decodePaymentPayload, decodePaymentRequired, decodeRequirementsBody, decodeSettleBody, decodeSettleResponse, detectProtocol, detectTransport, encodePayloadBody, encodePaymentPayload, encodePaymentRequired, encodeRequirementsBody, encodeSettleBody, encodeSettleResponse, extractRequirementsFromResponse, isValidAmount, isValidU64Amount, validateRequirementsShape } from "./http.mjs";
4
- import { a as s402ServerScheme, i as s402RouteConfig, n as s402DirectScheme, o as s402SettlementVerification, r as s402FacilitatorScheme, t as s402ClientScheme } from "./scheme-tVj4sOr-.mjs";
2
+ import { S402_HEADERS, S402_VERSION, s402Discovery, s402EscrowExtra, s402EscrowPayload, s402ExactPayload, s402Mandate, s402MandateRequirements, s402PaymentPayload, s402PaymentPayloadBase, s402PaymentRequirements, s402PaymentSession, s402PrepaidExtra, s402PrepaidPayload, s402RegistryQuery, s402Scheme, s402ServiceEntry, s402SettleResponse, s402SettlementMode, s402SettlementOverrides, s402StreamExtra, s402StreamPayload, s402UnlockExtra, s402UnlockPayload, s402UptoExtra, s402UptoPayload, s402VerifyResponse } from "./types.mjs";
3
+ import { MAX_BODY_BYTES, S402_CONTENT_TYPE, decodePayloadBody, decodePaymentPayload, decodePaymentRequired, decodeRequirementsBody, decodeSettleBody, decodeSettleResponse, detectProtocol, detectTransport, encodePayloadBody, encodePaymentPayload, encodePaymentRequired, encodeRequirementsBody, encodeSettleBody, encodeSettleResponse, extractRequirementsFromResponse, isValidAmount, isValidU64Amount, validateRequirementsShape } from "./http.mjs";
4
+ import { a as s402ServerScheme, i as s402RouteConfig, n as s402DirectScheme, o as s402SettlementVerification, r as s402FacilitatorScheme, t as s402ClientScheme } from "./scheme-CKinOhyx.mjs";
5
5
  import { S402_RECEIPT_HEADER, formatReceiptHeader, parseReceiptHeader, s402Receipt, s402ReceiptSigner, s402ReceiptVerifier } from "./receipts.mjs";
6
6
 
7
7
  //#region src/client.d.ts
@@ -58,14 +58,208 @@ declare class s402Client {
58
58
  supports(network: string, scheme: s402Scheme): boolean;
59
59
  }
60
60
  //#endregion
61
+ //#region src/extensions.d.ts
62
+ /**
63
+ * Base extension interface. All three actor-specific interfaces extend this.
64
+ *
65
+ * Extensions use reverse-domain keys (per ADR-001 §4a) to avoid conflicts:
66
+ * e.g., "org.s402.discovery", "com.mycompany.ratelimit".
67
+ */
68
+ interface s402Extension {
69
+ /** Reverse-domain key: e.g., "org.s402.discovery" */
70
+ readonly key: string;
71
+ /** Semver version (per ADR-001 §4b) */
72
+ readonly version: string;
73
+ /**
74
+ * If true, failure in this extension blocks the payment flow.
75
+ * If false, failure is logged but doesn't block (advisory).
76
+ */
77
+ readonly critical: boolean;
78
+ /** Keys of extensions that must run before this one. */
79
+ readonly dependsOn?: string[];
80
+ }
81
+ /**
82
+ * Client-side extension.
83
+ * Hooks fire during payment creation and settlement verification.
84
+ */
85
+ interface s402ClientExtension extends s402Extension {
86
+ /** Enrich the payment payload before sending. */
87
+ enrichPayload?(payload: s402PaymentPayload, requirements: s402PaymentRequirements): Promise<s402PaymentPayload>;
88
+ /** Process extension data from the settle response. */
89
+ onSettlement?(response: s402SettleResponse, payload: s402PaymentPayload): Promise<void>;
90
+ }
91
+ /**
92
+ * Server-side extension (resource server).
93
+ * Hooks fire during requirements building and settlement response.
94
+ */
95
+ interface s402ServerExtension extends s402Extension {
96
+ /** Enrich payment requirements before sending the 402 response. */
97
+ enrichRequirements?(requirements: s402PaymentRequirements, config: s402RouteConfig): s402PaymentRequirements;
98
+ /** Enrich the settlement response before returning to client. */
99
+ enrichSettleResponse?(response: s402SettleResponse, payload: s402PaymentPayload): Promise<s402SettleResponse>;
100
+ }
101
+ /**
102
+ * Facilitator-side extension.
103
+ * Hooks fire during the verify→settle pipeline.
104
+ *
105
+ * Four hooks covering every phase:
106
+ * beforeVerify → verify() → afterVerify → beforeSettle → settle() → afterSettle
107
+ */
108
+ interface s402FacilitatorExtension extends s402Extension {
109
+ /** Called before verify(). Can reject by throwing. */
110
+ beforeVerify?(payload: s402PaymentPayload, requirements: s402PaymentRequirements): Promise<void>;
111
+ /** Called after successful verify(), before settle(). */
112
+ afterVerify?(payload: s402PaymentPayload, verifyResult: s402VerifyResponse): Promise<void>;
113
+ /** Called before settle(). Last chance to abort. */
114
+ beforeSettle?(payload: s402PaymentPayload, requirements: s402PaymentRequirements): Promise<void>;
115
+ /** Called after successful settle() only (not on settlement failure).
116
+ * Failures here never change the settle result — the tx is already on-chain. */
117
+ afterSettle?(payload: s402PaymentPayload, settleResult: s402SettleResponse): Promise<void>;
118
+ }
119
+ /**
120
+ * Type-safe extension data retrieval.
121
+ *
122
+ * The wire format is `Record<string, unknown>` for interop, but this helper
123
+ * provides typed access for TypeScript consumers.
124
+ *
125
+ * @example
126
+ * ```ts
127
+ * interface DiscoveryData { services: string[] }
128
+ * const data = getExtensionData<DiscoveryData>(requirements.extensions, 'org.s402.discovery');
129
+ * if (data) console.log(data.services);
130
+ * ```
131
+ */
132
+ declare function getExtensionData<T>(extensions: Record<string, unknown> | undefined, key: string): T | undefined;
133
+ /**
134
+ * Set extension data on an extensions record (creates if needed).
135
+ * Returns a new extensions object (does not mutate the input).
136
+ */
137
+ declare function setExtensionData(extensions: Record<string, unknown> | undefined, key: string, data: unknown): Record<string, unknown>;
138
+ /**
139
+ * Registry for extensions with dependency-ordered execution.
140
+ *
141
+ * Extensions are stored by key and sorted topologically based on `dependsOn`.
142
+ * Within the same dependency level, registration order is preserved.
143
+ *
144
+ * @example
145
+ * ```ts
146
+ * const registry = new s402ExtensionRegistry<s402FacilitatorExtension>();
147
+ * registry.register(rateLimitExtension);
148
+ * registry.register(analyticsExtension);
149
+ * const sorted = registry.sorted(); // dependency-ordered list
150
+ * ```
151
+ */
152
+ declare class s402ExtensionRegistry<T extends s402Extension> {
153
+ private extensions;
154
+ private sortedCache;
155
+ /**
156
+ * Register an extension. Throws on duplicate key or dependency cycle.
157
+ */
158
+ register(ext: T): void;
159
+ /** Get a registered extension by key. */
160
+ get(key: string): T | undefined;
161
+ /** Number of registered extensions. */
162
+ get size(): number;
163
+ /**
164
+ * Return extensions in topological (dependency) order.
165
+ * Cached until a new extension is registered.
166
+ */
167
+ sorted(): T[];
168
+ }
169
+ /** Callback for advisory extension failures. */
170
+ type s402ExtensionErrorHandler = (ext: s402Extension, error: unknown) => void;
171
+ /**
172
+ * Run an async hook on all extensions in order.
173
+ * Critical extensions throw on failure; advisory extensions call the error handler.
174
+ */
175
+ declare function runExtensionHooks<T extends s402Extension>(extensions: T[], hookName: string, runner: (ext: T) => Promise<void>, onError?: s402ExtensionErrorHandler): Promise<void>;
176
+ //#endregion
61
177
  //#region src/facilitator.d.ts
178
+ /**
179
+ * Options for `s402Facilitator.process()`.
180
+ *
181
+ * Callers can tune the verify→settle pipeline per-request.
182
+ */
183
+ interface s402ProcessOptions {
184
+ /**
185
+ * Skip the verify() dry-run and go straight to settle().
186
+ *
187
+ * On chains where failed transactions cost zero gas (e.g., Sui PTBs revert
188
+ * atomically with no gas charge), the dry-run is pure latency overhead — it
189
+ * adds a full RPC round-trip (~200-400ms) just to predict what settle() will
190
+ * discover anyway. Setting `skipVerify: true` eliminates that round-trip.
191
+ *
192
+ * When `true`, process() still performs: expiration checks, scheme-mismatch
193
+ * checks, deduplication, and settle timeout. Only the dry-run is skipped.
194
+ *
195
+ * **Use when:** your chain adapter knows failures are free (Sui, Aptos).
196
+ * **Don't use when:** failed settlements cost gas (EVM L1s) — the dry-run
197
+ * saves real money by catching bad txs before broadcast.
198
+ *
199
+ * @default false
200
+ */
201
+ skipVerify?: boolean;
202
+ /**
203
+ * Caller-supplied idempotency key (e.g., from an `Idempotency-Key` HTTP
204
+ * header). When present, this string becomes the dedup cache key instead of
205
+ * the auto-computed payload fingerprint.
206
+ *
207
+ * Semantics (Stripe-compatible):
208
+ * - Same key + same payload → returns the cached original result (retry dedup)
209
+ * - Same key while first call is in flight → awaits the in-flight promise (concurrent dedup)
210
+ * - Key collisions across distinct payloads are the caller's responsibility
211
+ *
212
+ * Omit this field to fall back to payload-based dedup (JSON fingerprint).
213
+ */
214
+ idempotencyKey?: string;
215
+ }
216
+ /**
217
+ * Constructor options for `s402Facilitator`.
218
+ */
219
+ interface s402FacilitatorOptions {
220
+ /**
221
+ * How long a completed result stays in the retry-dedup cache, in milliseconds.
222
+ * A retry arriving within this window returns the cached original result
223
+ * instead of re-executing. Tune based on your client's retry budget.
224
+ *
225
+ * @default 300_000 (5 minutes)
226
+ */
227
+ dedupTtlMs?: number;
228
+ /**
229
+ * Maximum entries retained in the retry-dedup cache. When the cache exceeds
230
+ * this size, the oldest entry (by insertion order) is evicted. Bound memory
231
+ * under high request volume; higher values retain more retry history.
232
+ *
233
+ * @default 10_000
234
+ */
235
+ dedupMaxEntries?: number;
236
+ }
62
237
  declare class s402Facilitator {
63
238
  private schemes;
64
239
  private inFlight;
240
+ private completed;
241
+ private dedupTtlMs;
242
+ private dedupMaxEntries;
243
+ private extensionRegistry;
244
+ private extensionErrorHandler?;
245
+ constructor(options?: s402FacilitatorOptions);
65
246
  /**
66
247
  * Register a scheme-specific facilitator for a network.
67
248
  */
68
249
  register(network: string, scheme: s402FacilitatorScheme): this;
250
+ /**
251
+ * Register a facilitator extension. Extensions fire in dependency order
252
+ * at four points in the process() pipeline: beforeVerify, afterVerify,
253
+ * beforeSettle, afterSettle.
254
+ *
255
+ * @throws {s402Error} `EXTENSION_FAILED` on duplicate key or dependency cycle
256
+ */
257
+ registerExtension(ext: s402FacilitatorExtension): this;
258
+ /**
259
+ * Set the handler for advisory (non-critical) extension failures.
260
+ * Critical extensions always throw; advisory extensions call this handler.
261
+ */
262
+ onExtensionError(handler: s402ExtensionErrorHandler): this;
69
263
  /**
70
264
  * Verify a payment payload by dispatching to the correct scheme.
71
265
  * Includes expiration guard and scheme-mismatch check.
@@ -88,6 +282,7 @@ declare class s402Facilitator {
88
282
  *
89
283
  * @param payload - Client's payment payload
90
284
  * @param requirements - Server's payment requirements
285
+ * @param options - Optional process configuration (e.g., `{ skipVerify: true }` for zero-cost-failure chains)
91
286
  * @returns Settlement result (check `result.success` and `result.errorCode`)
92
287
  *
93
288
  * @example
@@ -105,7 +300,10 @@ declare class s402Facilitator {
105
300
  * }
106
301
  * ```
107
302
  */
108
- process(payload: s402PaymentPayload, requirements: s402PaymentRequirements): Promise<s402SettleResponse>;
303
+ process(payload: s402PaymentPayload, requirements: s402PaymentRequirements, options?: s402ProcessOptions): Promise<s402SettleResponse>;
304
+ private executeProcess;
305
+ private getCached;
306
+ private cacheResult;
109
307
  /**
110
308
  * Check if a scheme is supported for a network.
111
309
  */
@@ -146,9 +344,9 @@ declare class s402ResourceServer {
146
344
  * const requirements = server.buildRequirements({
147
345
  * schemes: ['exact'],
148
346
  * price: '1000000',
149
- * network: 'sui:mainnet',
150
- * payTo: '0xYOUR_ADDRESS',
151
- * asset: '0x2::sui::SUI',
347
+ * network: 'your-chain:mainnet',
348
+ * payTo: 'YOUR_ADDRESS',
349
+ * asset: 'NATIVE_TOKEN',
152
350
  * });
153
351
  * res.status(402).setHeader('payment-required', encodePaymentRequired(requirements));
154
352
  * ```
@@ -185,4 +383,258 @@ declare class s402ResourceServer {
185
383
  process(payload: s402PaymentPayload, requirements: s402PaymentRequirements): Promise<s402SettleResponse>;
186
384
  }
187
385
  //#endregion
188
- export { S402_CONTENT_TYPE, S402_HEADERS, S402_RECEIPT_HEADER, S402_VERSION, createS402Error, decodePayloadBody, decodePaymentPayload, decodePaymentRequired, decodeRequirementsBody, decodeSettleBody, decodeSettleResponse, detectProtocol, detectTransport, encodePayloadBody, encodePaymentPayload, encodePaymentRequired, encodeRequirementsBody, encodeSettleBody, encodeSettleResponse, extractRequirementsFromResponse, formatReceiptHeader, isValidAmount, isValidU64Amount, parseReceiptHeader, s402Client, type s402ClientScheme, type s402DirectScheme, type s402Discovery, s402Error, s402ErrorCode, type s402ErrorCodeType, type s402ErrorInfo, type s402EscrowExtra, type s402EscrowPayload, type s402ExactPayload, s402Facilitator, type s402FacilitatorScheme, type s402Mandate, type s402MandateRequirements, type s402PaymentPayload, type s402PaymentPayloadBase, type s402PaymentRequirements, type s402PaymentSession, type s402PrepaidExtra, type s402PrepaidPayload, type s402Receipt, type s402ReceiptSigner, type s402ReceiptVerifier, type s402RegistryQuery, s402ResourceServer, type s402RouteConfig, type s402Scheme, type s402ServerScheme, type s402ServiceEntry, type s402SettleResponse, type s402SettlementMode, type s402SettlementVerification, type s402StreamExtra, type s402StreamPayload, type s402UnlockExtra, type s402UnlockPayload, type s402VerifyResponse, validateRequirementsShape };
386
+ //#region src/envelope.d.ts
387
+ /** Content type for the settlement envelope wire format. */
388
+ declare const S402_ENVELOPE_CONTENT_TYPE: "application/vnd.s402.envelope+json";
389
+ /** SRI-compatible digest algorithm identifiers. See ADR-007. */
390
+ type s402DigestAlg = 'sha256' | 'sha384' | 'sha512' | 'blake3';
391
+ /** Signature algorithm identifiers. See ADR-007. */
392
+ type s402SigAlg = 'ed25519' | 'ed25519ph' | 'secp256k1' | 'ml-dsa-44';
393
+ /** Algorithm identifiers carried in every envelope for crypto-agility. */
394
+ interface s402Algs {
395
+ digest: s402DigestAlg;
396
+ sig: s402SigAlg;
397
+ }
398
+ interface s402EnvelopeBase {
399
+ /** Protocol version — matches `s402-Version` header. */
400
+ s402Version: string;
401
+ /** Scheme name. */
402
+ scheme: s402Scheme;
403
+ /** Content-hash of the scheme spec this response was computed against (SRI form). */
404
+ specDigest: string;
405
+ /** Cryptographic request→response binding (SRI form). See `computeTxBinding`. */
406
+ txBinding: string;
407
+ /** Network identifier (e.g. "sui:mainnet"). Prevents cross-network replay. */
408
+ network: string;
409
+ /** Algorithm identifiers — enables migration without wire-break. */
410
+ algs: s402Algs;
411
+ /** ISO-8601 UTC millisecond timestamp. Client rejects if skew > 5 min. */
412
+ timestamp: string;
413
+ /** Facilitator identities that contributed to this envelope. */
414
+ facilitatorIds?: string[];
415
+ }
416
+ interface s402EnvelopeSettled extends s402EnvelopeBase {
417
+ status: 'settled';
418
+ settled: {
419
+ /** Chain-specific settlement blob — opaque at protocol layer. */settlement: unknown;
420
+ settledAt: string; /** Scheme-specific attestation (e.g., unlock TX2). Inline per ADR-008 S11. */
421
+ attestation?: unknown;
422
+ };
423
+ }
424
+ interface s402EnvelopeVerified extends s402EnvelopeBase {
425
+ status: 'verified';
426
+ verified: Record<string, never>;
427
+ }
428
+ interface s402EnvelopeRejected extends s402EnvelopeBase {
429
+ status: 'rejected';
430
+ rejected: {
431
+ error: {
432
+ code: s402ErrorCodeType;
433
+ message: string;
434
+ };
435
+ };
436
+ }
437
+ interface s402EnvelopePending extends s402EnvelopeBase {
438
+ status: 'pending';
439
+ pending: {
440
+ retryAfter?: number;
441
+ reason: string;
442
+ };
443
+ }
444
+ type s402Envelope = s402EnvelopeSettled | s402EnvelopeVerified | s402EnvelopeRejected | s402EnvelopePending;
445
+ /**
446
+ * Compute the `txBinding` value for a request pair.
447
+ *
448
+ * ```
449
+ * txBinding = "sha256-" || base64url_no_pad(
450
+ * sha256(
451
+ * "s402-txbinding-v1\0"
452
+ * || JCS(requirements)
453
+ * || 0x1E
454
+ * || JCS(payload)
455
+ * )
456
+ * )
457
+ * ```
458
+ *
459
+ * Clients recompute this locally from their OWN `{requirements, payload}` and
460
+ * compare to `envelope.txBinding` using a constant-time primitive. See S14.
461
+ */
462
+ declare function computeTxBinding(requirements: s402PaymentRequirements, payload: s402PaymentPayload, alg?: s402DigestAlg): Promise<string>;
463
+ interface BuildEnvelopeContext {
464
+ s402Version: string;
465
+ scheme: s402Scheme;
466
+ specDigest: string;
467
+ network: string;
468
+ requirements: s402PaymentRequirements;
469
+ payload: s402PaymentPayload;
470
+ algs?: s402Algs;
471
+ facilitatorIds?: string[];
472
+ timestamp?: string;
473
+ }
474
+ declare function buildSettledEnvelope(ctx: BuildEnvelopeContext, settled: s402EnvelopeSettled['settled']): Promise<s402EnvelopeSettled>;
475
+ declare function buildVerifiedEnvelope(ctx: BuildEnvelopeContext): Promise<s402EnvelopeVerified>;
476
+ declare function buildRejectedEnvelope(ctx: BuildEnvelopeContext, error: {
477
+ code: s402ErrorCodeType;
478
+ message: string;
479
+ }): Promise<s402EnvelopeRejected>;
480
+ declare function buildPendingEnvelope(ctx: BuildEnvelopeContext, pending: s402EnvelopePending['pending']): Promise<s402EnvelopePending>;
481
+ declare function encodeEnvelopeBody(envelope: s402Envelope): string;
482
+ declare function decodeEnvelopeBody(body: string): s402Envelope;
483
+ declare function validateEnvelopeShape(v: unknown): asserts v is s402Envelope;
484
+ interface VerifyEnvelopeOptions {
485
+ /** The original request the client sent. `txBinding` is recomputed from these. */
486
+ originalRequest: {
487
+ requirements: s402PaymentRequirements;
488
+ payload: s402PaymentPayload;
489
+ };
490
+ /** Scheme-digest the client pinned or discovered. */
491
+ expectedSpecDigest: string;
492
+ /** Digest algorithms the client accepts. Reject anything outside this set. */
493
+ acceptedDigestAlgs?: s402DigestAlg[];
494
+ /** Signature algorithms the client accepts. Reject anything outside this set. */
495
+ acceptedSigAlgs?: s402SigAlg[];
496
+ /** Max acceptable skew between envelope.timestamp and local clock, in ms. */
497
+ maxTimestampSkewMs?: number;
498
+ /** Override clock for testing. */
499
+ now?: () => number;
500
+ }
501
+ /**
502
+ * Perform the ADR-007 client-side MUST checks. Throws on any failure.
503
+ *
504
+ * Scheme-match, spec-digest, network, txBinding (constant-time), timestamp,
505
+ * and algorithm acceptance. Resource-binding and unlock-attestation checks
506
+ * live in higher layers (they need request-intent + scheme-specific context).
507
+ */
508
+ declare function verifyEnvelope(envelope: s402Envelope, options: VerifyEnvelopeOptions): Promise<void>;
509
+ /**
510
+ * Constant-time string equality — S14 invariant.
511
+ *
512
+ * Compares every character regardless of mismatches, so the time-to-answer
513
+ * does not leak digest prefix information. Lengths are compared first (their
514
+ * difference is not secret — a mismatched length means the response is
515
+ * definitely not ours).
516
+ */
517
+ declare function constantTimeStringEqual(a: string, b: string): boolean;
518
+ //#endregion
519
+ //#region src/canonicalization.d.ts
520
+ /**
521
+ * s402 canonicalization — RFC 8785 JSON Canonicalization Scheme (JCS).
522
+ *
523
+ * JCS produces a deterministic byte sequence from a JSON value. Two parsers
524
+ * that honor JCS produce identical bytes for semantically equal JSON, enabling
525
+ * content-hashing and cross-language interop.
526
+ *
527
+ * Full spec: see `spec/canonicalization.md` (project-local, normative).
528
+ * Summary applied here:
529
+ * - Object keys sorted by UTF-16 code unit order (RFC 8785 §3.2.3)
530
+ * - Numbers rendered per ECMA-404 shortest-roundtrip (RFC 8785 §3.2.2)
531
+ * - Strings escape only the minimum required (RFC 8785 §3.2.1)
532
+ * - Arrays preserve order
533
+ * - No whitespace
534
+ * - Reject non-finite numbers, BigInt, undefined, functions, symbols
535
+ *
536
+ * This module implements JCS *serialization* only. Strict parsing with
537
+ * duplicate-key rejection is deferred to a later PR — envelope txBinding
538
+ * verification never parses untrusted canonical JSON, so dup-key handling is
539
+ * not on this critical path. (Client recomputes from its own objects.)
540
+ */
541
+ /**
542
+ * JCS value type — mirrors JSON's data model.
543
+ * `unknown` arrays/objects are fine; we'll type-check at serialize time.
544
+ */
545
+ type JsonValue = null | boolean | number | string | JsonValue[] | {
546
+ [key: string]: JsonValue;
547
+ };
548
+ /**
549
+ * Serialize a JSON value to RFC 8785 canonical form.
550
+ *
551
+ * Returns a UTF-8 byte string (represented as `Uint8Array`). Callers hash the
552
+ * bytes directly; do NOT re-encode via `TextEncoder` (double-encoding risk).
553
+ *
554
+ * @throws {s402Error} INVALID_PAYLOAD on non-JSON-safe values (NaN, Infinity,
555
+ * bigint, undefined, functions, symbols, circular refs).
556
+ */
557
+ declare function canonicalize(value: unknown): Uint8Array;
558
+ /**
559
+ * Convenience: canonicalize to a UTF-8 string.
560
+ *
561
+ * Use only when a downstream API demands a string; prefer the Uint8Array form
562
+ * for digest inputs to avoid an extra encode/decode round-trip.
563
+ */
564
+ declare function canonicalizeToString(value: unknown): string;
565
+ //#endregion
566
+ //#region src/accept-payment.d.ts
567
+ /**
568
+ * `Accept-Payment` header — content negotiation for HTTP 402 protocols.
569
+ *
570
+ * Modeled on RFC 7231 `Accept` / `Accept-Language` with q-value preference.
571
+ * A client advertises which payment schemes it can produce; the server picks
572
+ * the best scheme both sides support. This lets s402, x402, and MPP
573
+ * ({@link https://machinepayments.org}) coexist on the same endpoint.
574
+ *
575
+ * Grammar (informal):
576
+ * ```
577
+ * Accept-Payment = 1#( scheme [ OWS ";" OWS "q=" qvalue ] )
578
+ * scheme = token e.g. "s402/prepaid", "tempo/charge"
579
+ * qvalue = 0.0 - 1.0 default 1.0, 3-decimal precision
580
+ * ```
581
+ *
582
+ * Entries with `q=0` are explicit rejections — they are retained in parsed
583
+ * output (callers may need to know the client named them) but {@link selectBestScheme}
584
+ * will never pick them.
585
+ *
586
+ * @packageDocumentation
587
+ */
588
+ interface AcceptPaymentEntry {
589
+ /** Scheme token, normalized to lowercase (e.g. "s402/prepaid"). */
590
+ readonly scheme: string;
591
+ /** Quality value 0.0–1.0. Default 1.0 when omitted. */
592
+ readonly q: number;
593
+ }
594
+ /**
595
+ * Parse an `Accept-Payment` header into sorted preference entries.
596
+ *
597
+ * - Entries are returned in descending q-value order; ties preserve input order
598
+ * (stable sort).
599
+ * - Malformed entries are dropped silently (robustness principle).
600
+ * - Scheme tokens are lowercased. Whitespace around `;` and `,` is tolerated.
601
+ * - Duplicate schemes: the highest-q occurrence wins.
602
+ *
603
+ * @example
604
+ * parseAcceptPayment('s402/prepaid, s402/exact;q=0.8, tempo/charge;q=0.5');
605
+ * // [
606
+ * // { scheme: 's402/prepaid', q: 1 },
607
+ * // { scheme: 's402/exact', q: 0.8 },
608
+ * // { scheme: 'tempo/charge', q: 0.5 },
609
+ * // ]
610
+ */
611
+ declare function parseAcceptPayment(header: string | null | undefined): AcceptPaymentEntry[];
612
+ /**
613
+ * Format a list of entries back into an `Accept-Payment` header string.
614
+ *
615
+ * Entries with `q=1` omit the parameter (it's the default). Other q-values
616
+ * are emitted with up to 3 decimals, trailing zeros trimmed.
617
+ *
618
+ * @example
619
+ * formatAcceptPayment([
620
+ * { scheme: 's402/prepaid', q: 1 },
621
+ * { scheme: 'tempo/charge', q: 0.5 },
622
+ * ]);
623
+ * // "s402/prepaid, tempo/charge;q=0.5"
624
+ */
625
+ declare function formatAcceptPayment(entries: readonly AcceptPaymentEntry[]): string;
626
+ /**
627
+ * Select the best scheme both sides agree on.
628
+ *
629
+ * - Walks `preferred` in order (parseAcceptPayment returns them sorted by q).
630
+ * - Returns the first scheme that appears in `supported`.
631
+ * - Entries with `q=0` are explicit rejections and are skipped.
632
+ * - Scheme comparison is case-insensitive; the returned string matches the
633
+ * casing from `supported`.
634
+ * - If `preferred` is empty (no header), falls back to the first entry in
635
+ * `supported` (server's default).
636
+ * - Returns `null` if no overlap exists.
637
+ */
638
+ declare function selectBestScheme(preferred: readonly AcceptPaymentEntry[], supported: readonly string[]): string | null;
639
+ //#endregion
640
+ export { type AcceptPaymentEntry, type BuildEnvelopeContext, type JsonValue, MAX_BODY_BYTES, S402_CONTENT_TYPE, S402_ENVELOPE_CONTENT_TYPE, S402_HEADERS, S402_RECEIPT_HEADER, S402_VERSION, type VerifyEnvelopeOptions, buildPendingEnvelope, buildRejectedEnvelope, buildSettledEnvelope, buildVerifiedEnvelope, canonicalize, canonicalizeToString, computeTxBinding, constantTimeStringEqual, createS402Error, decodeEnvelopeBody, decodePayloadBody, decodePaymentPayload, decodePaymentRequired, decodeRequirementsBody, decodeSettleBody, decodeSettleResponse, detectProtocol, detectTransport, encodeEnvelopeBody, encodePayloadBody, encodePaymentPayload, encodePaymentRequired, encodeRequirementsBody, encodeSettleBody, encodeSettleResponse, extractRequirementsFromResponse, formatAcceptPayment, formatReceiptHeader, getExtensionData, isValidAmount, isValidU64Amount, parseAcceptPayment, parseReceiptHeader, runExtensionHooks, type s402Algs, s402Client, type s402ClientExtension, type s402ClientScheme, type s402DigestAlg, type s402DirectScheme, type s402Discovery, type s402Envelope, type s402EnvelopeBase, type s402EnvelopePending, type s402EnvelopeRejected, type s402EnvelopeSettled, type s402EnvelopeVerified, s402Error, s402ErrorCode, type s402ErrorCodeType, type s402ErrorInfo, type s402EscrowExtra, type s402EscrowPayload, type s402ExactPayload, type s402Extension, type s402ExtensionErrorHandler, s402ExtensionRegistry, s402Facilitator, type s402FacilitatorExtension, type s402FacilitatorScheme, type s402Mandate, type s402MandateRequirements, type s402PaymentPayload, type s402PaymentPayloadBase, type s402PaymentRequirements, type s402PaymentSession, type s402PrepaidExtra, type s402PrepaidPayload, type s402ProcessOptions, type s402Receipt, type s402ReceiptSigner, type s402ReceiptVerifier, type s402RegistryQuery, s402ResourceServer, type s402RouteConfig, type s402Scheme, type s402ServerExtension, type s402ServerScheme, type s402ServiceEntry, type s402SettleResponse, type s402SettlementMode, type s402SettlementOverrides, type s402SettlementVerification, type s402SigAlg, type s402StreamExtra, type s402StreamPayload, type s402UnlockExtra, type s402UnlockPayload, type s402UptoExtra, type s402UptoPayload, type s402VerifyResponse, selectBestScheme, setExtensionData, validateEnvelopeShape, validateRequirementsShape, verifyEnvelope };