@devlab.group/agent-commerce 1.2.0 → 1.4.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/authorization/ap2/errors.ts","../src/authorization/ap2/profile.ts","../src/authorization/ap2/checkout-signer.ts","../src/authorization/ap2/descriptor.ts","../src/authorization/ap2/replay-store.ts","../src/authorization/ap2/checkout-jwt.ts","../src/authorization/ap2/sd-jwt.ts","../src/authorization/ap2/trust.ts","../src/authorization/ap2/verifier.ts","../src/authorization/ap2/provider.ts"],"names":["asRecord","jwtVerify"],"mappings":"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","file":"ap2.js","sourcesContent":["/**\n * Every failure the AP2 verifier can report.\n *\n * `CommerceError.message` reaches the client, and a mandate carries the\n * buyer's purchase and often personal data, so messages are fixed phrases from\n * the list below. The machine-readable code goes in `details.reason` and the\n * original exception on `cause`, which is never serialised.\n *\n * Three codes: AUTHORIZATION_INVALID when the buyer's mandate is bad,\n * AUTHORIZATION_REPLAYED when it is good but spent, and\n * AUTHORIZATION_PROVIDER_UNAVAILABLE when our verifier never reached a\n * verdict. Blaming the buyer for our outage refuses a good mandate.\n */\nimport { CommerceError } from '../../core/index.js';\n\n/**\n * Coarse on purpose: a client learns roughly where its mandate was refused,\n * not which check failed. Finer detail is an oracle for probing trust policy.\n */\nexport const AP2_REJECTION_REASONS = [\n 'malformed_presentation',\n 'untrusted_issuer',\n 'unknown_key',\n 'invalid_signature',\n 'unsupported_algorithm',\n 'invalid_claims',\n 'expired',\n 'wrong_audience',\n 'unsupported_mandate_type',\n 'checkout_binding_failed',\n 'purchase_mismatch',\n] as const;\n\nexport type Ap2RejectionReason = (typeof AP2_REJECTION_REASONS)[number];\n\nconst MESSAGES: Readonly<Record<Ap2RejectionReason, string>> = {\n malformed_presentation: 'The authorization is not a well-formed SD-JWT presentation.',\n untrusted_issuer: 'The mandate was issued by a party this merchant does not trust.',\n unknown_key: 'The mandate names a signing key this merchant does not trust.',\n invalid_signature: 'The mandate signature did not verify.',\n unsupported_algorithm: 'The mandate uses a signature or digest algorithm that is not accepted.',\n invalid_claims: 'The mandate is missing required claims or they are malformed.',\n expired: 'The mandate is expired or not yet valid.',\n wrong_audience: 'The mandate is addressed to a different audience.',\n unsupported_mandate_type: 'The mandate is not a closed Direct Checkout Mandate.',\n checkout_binding_failed: 'The merchant checkout document bound to the mandate did not verify.',\n purchase_mismatch: 'The mandate does not authorize this purchase.',\n};\n\nexport interface Ap2ErrorContext {\n readonly requestId?: string;\n readonly resourceId?: string;\n readonly cause?: unknown;\n}\n\n/** The buyer's mandate is bad. Fail closed */\nexport function ap2Rejected(\n reason: Ap2RejectionReason,\n context: Ap2ErrorContext = {},\n): CommerceError {\n return new CommerceError('AUTHORIZATION_INVALID', MESSAGES[reason], {\n details: { method: 'ap2', reason },\n ...(context.requestId !== undefined ? { requestId: context.requestId } : {}),\n ...(context.resourceId !== undefined ? { resourceId: context.resourceId } : {}),\n ...(context.cause !== undefined ? { cause: context.cause } : {}),\n });\n}\n\n/**\n * The mandate verified but has already been presented. A separate code from\n * a bad mandate: nothing is wrong with this proof except that it is spent\n */\nexport function ap2Replayed(state: string, context: Ap2ErrorContext = {}): CommerceError {\n return new CommerceError(\n 'AUTHORIZATION_REPLAYED',\n 'This mandate has already been presented and cannot authorize another purchase.',\n {\n details: { method: 'ap2', reason: 'replayed', state },\n ...(context.requestId !== undefined ? { requestId: context.requestId } : {}),\n ...(context.resourceId !== undefined ? { resourceId: context.resourceId } : {}),\n },\n );\n}\n\n/**\n * The check never ran (a configured key that will not import, say). Retryable,\n * and never recorded against the payer: the mandate may be perfectly good.\n */\nexport function ap2Unavailable(detail: string, context: Ap2ErrorContext = {}): CommerceError {\n return new CommerceError(\n 'AUTHORIZATION_PROVIDER_UNAVAILABLE',\n 'Authorization could not be verified right now. This is a merchant-side fault, not a problem with the presented mandate.',\n {\n details: { method: 'ap2', reason: 'verifier_unavailable', detail },\n ...(context.requestId !== undefined ? { requestId: context.requestId } : {}),\n ...(context.resourceId !== undefined ? { resourceId: context.resourceId } : {}),\n ...(context.cause !== undefined ? { cause: context.cause } : {}),\n },\n );\n}\n","/**\n * Binds a verified mandate to the purchase in front of us.\n *\n * A perfect mandate authorises exactly one purchase; without this comparison a\n * mandate approved for a $0.01 report would settle a $500 one.\n *\n * Everything is compared against the ALREADY RESOLVED request. Nothing is\n * taken from the mandate and used to shape the purchase, which would invert\n * the control.\n */\nimport canonicalize from 'canonicalize';\nimport type { AuthorizationVerificationContext } from '../../core/index.js';\nimport { AP2_CHECKOUT_PROFILE } from './constants.js';\nimport { type Ap2ErrorContext, ap2Rejected } from './errors.js';\nimport type { VerifiedCheckoutMandate } from './types.js';\n\n/**\n * All required. Absent is a mismatch, never a skipped check: a mandate that\n * will not say which resource or how much authorises nothing in particular.\n */\nconst REQUIRED_PROFILE_CLAIMS = [\n 'profile',\n 'resource_id',\n 'input_hash',\n 'amount',\n 'currency',\n 'payment_method',\n] as const;\n\n/**\n * RFC 8785 (JCS) digest of the validated resource input.\n *\n * Binds a mandate to the exact request, not just to a resource and a price:\n * without it, one mandate for `translate` would authorise any translation.\n *\n * `canonicalize` rather than a sorted-key `JSON.stringify`, which differs\n * exactly where it matters. The merchant's signer computes this same digest,\n * probably in another language, and the two agree only if both follow RFC\n * 8785's number formatting and UTF-16 key ordering.\n *\n * The caller passes what the backend will receive: validated, reserved fields\n * stripped, no request id or transport metadata (the buyer could not have\n * known those when they approved).\n */\nexport async function computeInputHash(input: unknown): Promise<string> {\n const canonical = canonicalize(input ?? {});\n // undefined means JSON cannot represent it. Input has already passed schema\n // validation, so this is something exotic getting past it, not a buyer error.\n if (canonical === undefined) {\n throw new TypeError('resource input is not canonicalizable JSON');\n }\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(canonical));\n return Buffer.from(digest).toString('base64url');\n}\n\n/** What the mandate turned out to authorise, once it matched */\nexport interface BoundPurchase {\n readonly resourceId: string;\n readonly amount: string;\n readonly currency: string;\n readonly paymentMethod: string;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/**\n * Throws on the first mismatch with one coarse reason. Which field disagreed\n * is not reported: a caller able to ask about one field at a time can read a\n * mandate's contents out of the gateway by elimination.\n */\nexport async function bindMandateToPurchase(\n mandate: VerifiedCheckoutMandate,\n context: AuthorizationVerificationContext,\n errorContext: Ap2ErrorContext,\n): Promise<BoundPurchase> {\n const profile = asRecord(mandate.checkoutClaims['agent_commerce']);\n if (profile === undefined) throw ap2Rejected('purchase_mismatch', errorContext);\n\n for (const claim of REQUIRED_PROFILE_CLAIMS) {\n const value = profile[claim];\n if (typeof value !== 'string' || value.length === 0) {\n throw ap2Rejected('purchase_mismatch', errorContext);\n }\n }\n\n const requirement = context.requirement;\n const expectedInputHash = await computeInputHash(context.input);\n\n const mustMatch: readonly (readonly [string, unknown])[] = [\n ['profile', AP2_CHECKOUT_PROFILE],\n ['resource_id', context.resourceId],\n ['input_hash', expectedInputHash],\n // Decimal strings on both sides. Comparing numerically would make \"0.10\"\n // and \"0.1\" equal, and a mandate says what it says.\n ['amount', requirement.amount],\n ['currency', requirement.currency],\n ['payment_method', requirement.provider],\n ];\n\n for (const [claim, expected] of mustMatch) {\n if (profile[claim] !== expected) throw ap2Rejected('purchase_mismatch', errorContext);\n }\n\n // Checked whenever EITHER side names one, which is the fail-closed reading.\n // A mandate silent about the chain must not unlock a mainnet settlement, and\n // one naming a chain the requirement lacks was approved for another rail.\n for (const [claim, expected] of [\n ['destination', requirement.destination],\n ['network', requirement.network],\n ['asset', requirement.asset],\n ] as const) {\n const declared = profile[claim];\n if (declared === undefined && expected === undefined) continue;\n if (declared !== expected) throw ap2Rejected('purchase_mismatch', errorContext);\n }\n\n return {\n resourceId: profile['resource_id'] as string,\n amount: profile['amount'] as string,\n currency: profile['currency'] as string,\n paymentMethod: profile['payment_method'] as string,\n };\n}\n","/**\n * Merchant-side helper: mint the checkout JWT a Checkout Mandate binds.\n *\n * The gateway only verifies. This is what a merchant runs in their own\n * process, with their own key, to produce the document the buyer approves. It\n * never calls the gateway and the gateway never calls it - the mirror of\n * `createPaymentProof`, which a buyer runs to produce a payment proof.\n *\n * It exists for `input_hash`, an RFC 8785 digest. A signer reaching for a\n * sorted-key `JSON.stringify` agrees on most inputs and disagrees on floats\n * and non-ASCII keys, and the mandate is then refused with a reason that does\n * not say which field disagreed.\n */\nimport { importPKCS8, type JWK, SignJWT } from 'jose';\nimport {\n AP2_CHECKOUT_PROFILE,\n AP2_JWK_CURVE,\n AP2_KEY_TYPE,\n AP2_SIGNING_ALGORITHM,\n} from './constants.js';\nimport { computeInputHash } from './profile.js';\n\n/**\n * A private ES256 key: either a private JWK (the pair of the public one in the\n * gateway's `checkoutIssuers`) or a PKCS#8 PEM, as `openssl` emits it.\n */\nexport type Ap2SigningKey = Readonly<Record<string, unknown>> | string;\n\nexport interface CreateCheckoutJwtOptions {\n readonly privateKey: Ap2SigningKey;\n /** Must match a `kid` configured under the gateway's `checkoutIssuers` */\n readonly kid: string;\n /** Must match that issuer's configured `issuer` */\n readonly issuer: string;\n /** Must match that issuer's configured `audience` */\n readonly audience: string;\n\n readonly resourceId: string;\n /**\n * The resource input this purchase is for, exactly as the buyer will send\n * it: no reserved fields, no request id, no transport metadata.\n */\n readonly input: unknown;\n\n /**\n * Decimal string, never a number, and compared as a string: `0.10` and `0.1`\n * are different mandates. Take it from your own catalogue rather than from\n * whatever the agent asked for.\n */\n readonly amount: string;\n readonly currency: string;\n /** The rail that will settle, e.g. `x402` */\n readonly paymentMethod: string;\n\n /**\n * Settlement coordinates. Required whenever the gateway's requirement names\n * them, which under x402 is always. A mandate silent about the chain will\n * not unlock a settlement on one.\n */\n readonly destination?: string;\n readonly network?: string;\n readonly asset?: string;\n\n /** Defaults to a random UUID. Recorded on the receipt and used for replay defence */\n readonly jwtId?: string;\n /** Defaults to 900: a human approval sits inside this window */\n readonly expiresInSeconds?: number;\n /** Injectable so a test need not move the wall clock */\n readonly now?: Date;\n}\n\nconst DEFAULT_EXPIRES_IN_SECONDS = 900;\n\nfunction requireText(value: unknown, field: string): string {\n if (typeof value !== 'string' || value.length === 0) {\n throw new TypeError(\n `createCheckoutJwt: ${field} must be a non-empty string, received ${describe(value)}`,\n );\n }\n return value;\n}\n\nfunction describe(value: unknown): string {\n return value === null ? 'null' : typeof value;\n}\n\n/**\n * Every rejection here is a mistake that would otherwise surface as an opaque\n * verification failure much later: the public half of the pair, the wrong key\n * type, or a PEM that is not PKCS#8.\n */\nasync function resolveKey(\n key: Ap2SigningKey,\n): Promise<JWK | Awaited<ReturnType<typeof importPKCS8>>> {\n if (typeof key === 'string') {\n if (!key.includes('BEGIN PRIVATE KEY')) {\n throw new TypeError(\n 'createCheckoutJwt: a string privateKey must be a PKCS#8 PEM beginning \"-----BEGIN PRIVATE KEY-----\"',\n );\n }\n return importPKCS8(key, AP2_SIGNING_ALGORITHM);\n }\n if (typeof key !== 'object' || key === null) {\n throw new TypeError('createCheckoutJwt: privateKey must be a private JWK or a PKCS#8 PEM');\n }\n if (key['d'] === undefined) {\n throw new TypeError(\n 'createCheckoutJwt: privateKey is a public JWK (no \"d\"). Use the private half of the pair whose public key is configured under checkoutIssuers',\n );\n }\n if (key['kty'] !== AP2_KEY_TYPE || key['crv'] !== AP2_JWK_CURVE) {\n throw new TypeError(\n `createCheckoutJwt: privateKey must be ${AP2_KEY_TYPE}/${AP2_JWK_CURVE}, the pair ${AP2_SIGNING_ALGORITHM} implies`,\n );\n }\n return key as JWK;\n}\n\n/**\n * Returns the compact JWT to hand to the agent, which wraps it in the Checkout\n * Mandate the buyer signs.\n */\nexport async function createCheckoutJwt(options: CreateCheckoutJwtOptions): Promise<string> {\n const kid = requireText(options.kid, 'kid');\n const issuer = requireText(options.issuer, 'issuer');\n const audience = requireText(options.audience, 'audience');\n const resourceId = requireText(options.resourceId, 'resourceId');\n const currency = requireText(options.currency, 'currency');\n const paymentMethod = requireText(options.paymentMethod, 'paymentMethod');\n\n if (typeof options.amount === 'number') {\n throw new TypeError(\n 'createCheckoutJwt: amount must be a decimal string, not a number. It is compared as a string, so 0.1 and \"0.10\" are different mandates',\n );\n }\n const amount = requireText(options.amount, 'amount');\n\n const key = await resolveKey(options.privateKey);\n const issuedAt = Math.floor((options.now ?? new Date()).getTime() / 1000);\n const expiresIn = options.expiresInSeconds ?? DEFAULT_EXPIRES_IN_SECONDS;\n if (!Number.isInteger(expiresIn) || expiresIn <= 0) {\n throw new TypeError('createCheckoutJwt: expiresInSeconds must be a positive whole number');\n }\n\n const agentCommerce: Record<string, string> = {\n profile: AP2_CHECKOUT_PROFILE,\n resource_id: resourceId,\n input_hash: await computeInputHash(options.input),\n amount,\n currency,\n payment_method: paymentMethod,\n ...(options.destination !== undefined ? { destination: options.destination } : {}),\n ...(options.network !== undefined ? { network: options.network } : {}),\n ...(options.asset !== undefined ? { asset: options.asset } : {}),\n };\n\n return new SignJWT({ agent_commerce: agentCommerce })\n .setProtectedHeader({ alg: AP2_SIGNING_ALGORITHM, kid, typ: 'JWT' })\n .setIssuer(issuer)\n .setAudience(audience)\n .setIssuedAt(issuedAt)\n .setExpirationTime(issuedAt + expiresIn)\n .setJti(options.jwtId ?? crypto.randomUUID())\n .sign(key);\n}\n","/**\n * Adapter self-description.\n *\n * Imports nothing but core types and the pins, so `doctor` can report AP2\n * without pulling `jose` or `@sd-jwt/core` into the CLI bundle.\n */\nimport type { AdapterDescriptor } from '../../core/index.js';\nimport {\n AP2_CHECKOUT_MANDATE_VCT,\n AP2_CHECKOUT_PROFILE,\n AP2_DIGEST_ALGORITHM,\n AP2_SIGNING_ALGORITHM,\n AP2_SPEC_VERSION,\n} from './constants.js';\n\n/** What this provider actually verifies */\nexport const AP2_CAPABILITIES: readonly string[] = [\n 'direct-mode',\n AP2_CHECKOUT_MANDATE_VCT,\n 'sd-jwt-presentation',\n AP2_SIGNING_ALGORITHM,\n AP2_DIGEST_ALGORITHM,\n 'static-inline-trust',\n 'merchant-checkout-jwt-binding',\n AP2_CHECKOUT_PROFILE,\n 'purchase-binding',\n 'replay-defence',\n];\n\n/**\n * Everything an AP2 client may reasonably expect and will not get here.\n * Complete on purpose: a short list reads as \"mostly compatible\", which is the\n * blanket claim alpha honesty forbids.\n */\nexport const AP2_UNSUPPORTED: readonly string[] = [\n // Mandate kinds. Open mandates carry spending constraints nothing here\n // evaluates, so accepting one would tell a buyer their limits were checked.\n 'autonomous mode',\n 'open checkout mandates (mandate.checkout.open.1)',\n 'intent mandates',\n 'cart mandates',\n 'spending constraint evaluation',\n 'cnf-bound agent keys',\n // Key handling. Every key is written into config by an operator\n 'JWKS and any key discovery by URL (jku, x5u)',\n 'issuer metadata fetching',\n 'key rotation without a config change',\n // Algorithms\n 'signature algorithms other than ES256',\n 'digest algorithms other than sha-256',\n // Roles this gateway does not play\n 'mandate issuance',\n 'merchant checkout JWT issuance',\n 'AP2 over the ACP checkout adapter',\n];\n\nexport function buildAp2Descriptor(implementationVersion: string): AdapterDescriptor {\n return {\n name: 'ap2',\n kind: 'authorization',\n implementationVersion,\n supportedSpec: `ap2/v${AP2_SPEC_VERSION} mode=direct`,\n capabilities: AP2_CAPABILITIES,\n status: 'experimental',\n unsupported: AP2_UNSUPPORTED,\n };\n}\n","/**\n * Durable record of which mandates have been spent.\n *\n * Its own table in its own file: an x402 payment replay key expires with its\n * on-chain authorisation, while a consumed mandate must stay consumed for as\n * long as the merchant can be asked what they delivered. Hence no retention\n * sweep here, unlike the ACP idempotency store next door - deleting a\n * `consumed` row makes that mandate spendable again. If the table ever needs\n * bounding, archive `released` rows and leave the rest.\n *\n * Settlement and a local commit are not one transaction. If the process dies\n * between them the row stays `reserved` and that mandate is refused from then\n * on: a refused retry costs a round trip, the other direction costs a second\n * payment.\n */\nimport type { Database } from 'better-sqlite3';\nimport { type Logger, NOOP_LOGGER } from '../../core/index.js';\nimport { openSqliteDatabase } from '../../storage/sqlite.js';\n\n/**\n * `released` is \"nothing happened\" and the only state a mandate can be\n * presented from again. `uncertain` is a settlement whose outcome we never\n * learned: not reusable, but findable by an operator reconciling by hand.\n */\nexport type Ap2AuthorizationState = 'reserved' | 'consumed' | 'released' | 'uncertain';\n\n/**\n * A digest and a few identifiers: everything replay defence needs, and nothing\n * a leaked database would hand an attacker\n */\nexport interface Ap2ReservationRequest {\n /**\n * Digest of the ISSUER-SIGNED TOKEN, not of the presentation. Selective\n * disclosure gives one mandate many presentation strings, so keying on the\n * presentation would let it be spent once per disclosed subset.\n */\n readonly reference: string;\n /** `jti` of the merchant checkout JWT the mandate binds */\n readonly checkoutJti: string;\n readonly mandateIssuer: string;\n readonly checkoutIssuer: string;\n readonly resourceId: string;\n readonly requestId: string;\n}\n\nexport type Ap2ReservationResult =\n | { readonly kind: 'reserved' }\n /** Already reserved, consumed, or of uncertain outcome. Never re-spendable */\n | { readonly kind: 'replayed'; readonly state: Ap2AuthorizationState };\n\nexport interface Ap2ReplayStore {\n /** Atomically claim a mandate, or report that something already holds it */\n reserve(request: Ap2ReservationRequest): Ap2ReservationResult;\n /** Settlement succeeded: spend it permanently */\n consume(reference: string): void;\n /** Nothing happened: hand it back so a corrected retry can use it */\n release(reference: string): void;\n /** Settlement outcome unknown. Not reusable, and flagged for a human */\n markUncertain(reference: string): void;\n /** Current state, for tests and diagnostics */\n stateOf(reference: string): Ap2AuthorizationState | undefined;\n close(): void;\n}\n\nexport interface Ap2ReplayStoreOptions {\n /** File path, or ':memory:' for tests */\n readonly path: string;\n readonly logger?: Logger;\n /** Injectable so tests need not move the wall clock */\n readonly now?: () => number;\n}\n\ninterface StateRow {\n state: string;\n}\n\nexport function createAp2ReplayStore(options: Ap2ReplayStoreOptions): Ap2ReplayStore {\n const logger = options.logger ?? NOOP_LOGGER;\n const now = options.now ?? (() => Date.now());\n\n const db: Database = openSqliteDatabase({\n path: options.path,\n label: 'AP2 authorization database',\n logger,\n });\n migrate(db);\n\n const selectByReference = db.prepare<[string], StateRow>(\n 'SELECT state FROM ap2_authorizations WHERE reference = ?',\n );\n // Two mandates can bind one checkout document, giving two references, so\n // the reference alone would not catch the second one\n const selectLiveByJti = db.prepare<[string, string], StateRow>(\n `SELECT state FROM ap2_authorizations\n WHERE checkout_jti = ? AND reference != ? AND state != 'released'`,\n );\n const insert = db.prepare(\n `INSERT INTO ap2_authorizations\n (reference, checkout_jti, mandate_issuer, checkout_issuer, resource_id, request_id,\n state, created_at, updated_at)\n VALUES (@reference, @checkout_jti, @mandate_issuer, @checkout_issuer, @resource_id,\n @request_id, 'reserved', @at, @at)`,\n );\n const reReserve = db.prepare(\n `UPDATE ap2_authorizations\n SET state = 'reserved', request_id = @request_id, updated_at = @at\n WHERE reference = @reference AND state = 'released'`,\n );\n // Guarded on `reserved`: releasing a `consumed` row would hand back a\n // mandate whose money has already moved\n const transition = db.prepare(\n `UPDATE ap2_authorizations SET state = @state, updated_at = @at\n WHERE reference = @reference AND state = 'reserved'`,\n );\n\n const reserveTx = db.transaction((request: Ap2ReservationRequest): Ap2ReservationResult => {\n const at = new Date(now()).toISOString();\n\n const existing = selectByReference.get(request.reference);\n if (existing !== undefined) {\n if (existing.state !== 'released') {\n return { kind: 'replayed', state: existing.state as Ap2AuthorizationState };\n }\n reReserve.run({ reference: request.reference, request_id: request.requestId, at });\n return { kind: 'reserved' };\n }\n\n const sameCheckout = selectLiveByJti.get(request.checkoutJti, request.reference);\n if (sameCheckout !== undefined) {\n return { kind: 'replayed', state: sameCheckout.state as Ap2AuthorizationState };\n }\n\n insert.run({\n reference: request.reference,\n checkout_jti: request.checkoutJti,\n mandate_issuer: request.mandateIssuer,\n checkout_issuer: request.checkoutIssuer,\n resource_id: request.resourceId,\n request_id: request.requestId,\n at,\n });\n return { kind: 'reserved' };\n });\n\n const move = (reference: string, state: Ap2AuthorizationState): void => {\n transition.run({ reference, state, at: new Date(now()).toISOString() });\n };\n\n let closed = false;\n return {\n reserve(request) {\n return reserveTx(request);\n },\n consume(reference) {\n move(reference, 'consumed');\n },\n release(reference) {\n move(reference, 'released');\n },\n markUncertain(reference) {\n move(reference, 'uncertain');\n },\n stateOf(reference) {\n return selectByReference.get(reference)?.state as Ap2AuthorizationState | undefined;\n },\n close() {\n if (closed) return;\n closed = true;\n db.close();\n },\n };\n}\n\n// `PRAGMA user_version`, so reopening an existing file is a no-op check\nfunction migrate(db: Database): void {\n const current = db.pragma('user_version', { simple: true }) as number;\n if (current >= 1) return;\n const apply = db.transaction(() => {\n db.exec(`\n CREATE TABLE IF NOT EXISTS ap2_authorizations (\n reference TEXT PRIMARY KEY,\n checkout_jti TEXT NOT NULL,\n mandate_issuer TEXT NOT NULL,\n checkout_issuer TEXT NOT NULL,\n resource_id TEXT NOT NULL,\n request_id TEXT NOT NULL,\n state TEXT NOT NULL\n CHECK (state IN ('reserved', 'consumed', 'released', 'uncertain')),\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n );\n CREATE INDEX IF NOT EXISTS idx_ap2_authorizations_checkout_jti\n ON ap2_authorizations(checkout_jti);\n `);\n db.pragma('user_version = 1');\n });\n apply();\n}\n","/**\n * Stage two: the merchant checkout JWT the mandate binds.\n *\n * Two things have to hold. The hash proves the buyer approved *this* document;\n * the signature proves the merchant issued it. Hash alone accepts a document\n * the buyer wrote themselves; signature alone accepts a genuine merchant\n * document this mandate never covered.\n */\nimport { type JWTVerifyOptions, jwtVerify } from 'jose';\nimport type { Clock } from '../../core/index.js';\nimport { AP2_SIGNING_ALGORITHM } from './constants.js';\nimport { type Ap2ErrorContext, ap2Rejected } from './errors.js';\nimport type { TrustStore } from './trust.js';\n\nexport interface VerifiedCheckoutJwt {\n readonly issuer: string;\n readonly jwtId: string;\n readonly claims: Readonly<Record<string, unknown>>;\n}\n\nfunction decodeSegment(jwt: string, index: 0 | 1): Record<string, unknown> | undefined {\n const segment = jwt.split('.')[index];\n if (segment === undefined) return undefined;\n try {\n const parsed: unknown = JSON.parse(Buffer.from(segment, 'base64url').toString('utf8'));\n return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * `mandateClaims` must come from an already-verified mandate: `checkout_hash`\n * is worth nothing unless the issuer signed it\n */\nexport async function verifyCheckoutJwt(\n mandateClaims: Readonly<Record<string, unknown>>,\n deps: { readonly trust: TrustStore; readonly clock: Clock; readonly clockSkewSeconds: number },\n context: Ap2ErrorContext,\n): Promise<VerifiedCheckoutJwt> {\n const compact = mandateClaims['checkout_jwt'];\n const expectedHash = mandateClaims['checkout_hash'];\n if (typeof compact !== 'string' || compact.length === 0) {\n throw ap2Rejected('invalid_claims', context);\n }\n if (typeof expectedHash !== 'string' || expectedHash.length === 0) {\n throw ap2Rejected('invalid_claims', context);\n }\n\n await requireMatchingHash(compact, expectedHash, context);\n\n const header = decodeSegment(compact, 0);\n const unverifiedPayload = decodeSegment(compact, 1);\n if (header === undefined || unverifiedPayload === undefined) {\n throw ap2Rejected('checkout_binding_failed', context);\n }\n\n const { issuer, key } = await deps.trust.resolve(\n unverifiedPayload['iss'],\n header['kid'],\n context,\n );\n\n const options: JWTVerifyOptions = {\n algorithms: [AP2_SIGNING_ALGORITHM],\n issuer: issuer.issuer,\n audience: issuer.audience,\n clockTolerance: deps.clockSkewSeconds,\n currentDate: deps.clock.now(),\n };\n\n let claims: Record<string, unknown>;\n try {\n const result = await jwtVerify(compact, key, options);\n claims = result.payload as Record<string, unknown>;\n } catch (cause) {\n throw ap2Rejected('checkout_binding_failed', { ...context, cause });\n }\n\n const exp = claims['exp'];\n const iat = claims['iat'];\n const jti = claims['jti'];\n // jose validates a time claim only when present, so requiring them is ours\n if (typeof exp !== 'number' || typeof iat !== 'number') {\n throw ap2Rejected('invalid_claims', context);\n }\n // `jti` is what replay defence and the receipt record, so it is required\n if (typeof jti !== 'string' || jti.length === 0) {\n throw ap2Rejected('invalid_claims', context);\n }\n const nowSeconds = Math.floor(deps.clock.now().getTime() / 1000);\n if (iat > nowSeconds + deps.clockSkewSeconds) throw ap2Rejected('expired', context);\n\n return { issuer: issuer.issuer, jwtId: jti, claims };\n}\n\n/**\n * Hashed as the bytes that arrived, never re-encoded from parsed claims: a\n * re-serialised payload has a different digest, and normalising first would\n * hash a document other than the one being verified\n */\nasync function requireMatchingHash(\n compact: string,\n expected: string,\n context: Ap2ErrorContext,\n): Promise<void> {\n // sha-256 only: `_sd_alg` was already pinned to it upstream\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(compact));\n const actual = Buffer.from(digest).toString('base64url');\n // Plain comparison: both sides are public to anyone holding the\n // presentation, so there is no secret for timing to leak\n if (actual !== expected) throw ap2Rejected('checkout_binding_failed', context);\n}\n","/**\n * Stage one: parse the presentation, verify the issuer's signature, resolve\n * the disclosures.\n *\n * Disclosure mechanics come from `@sd-jwt/core`, which refuses the three\n * attacks that live in that algorithm: an appended disclosure nothing\n * references, the same disclosure twice, and one that will not decode.\n * Cryptography is `jose`'s. This file supplies the policy: which key, which\n * algorithm, which audience, what counts as fresh.\n */\nimport { decodeSdJwt, getClaims, splitSdJwt } from '@sd-jwt/core';\nimport { type JWTVerifyOptions, jwtVerify } from 'jose';\nimport type { Clock } from '../../core/index.js';\nimport {\n AP2_CHECKOUT_MANDATE_VCT,\n AP2_DIGEST_ALGORITHM,\n AP2_SIGNING_ALGORITHM,\n} from './constants.js';\nimport { type Ap2ErrorContext, ap2Rejected } from './errors.js';\nimport type { TrustStore } from './trust.js';\n\nexport interface VerifiedMandate {\n readonly issuer: string;\n /** Every claim, with the presented disclosures resolved into place */\n readonly claims: Readonly<Record<string, unknown>>;\n /**\n * The issuer-signed token on its own, without the disclosures.\n *\n * This, not the presentation string, is the stable identity of a mandate:\n * disclosing or withholding an optional claim rewrites the presentation and\n * leaves the signed token untouched. Replay defence keys on a digest of it.\n */\n readonly signedToken: string;\n}\n\n/**\n * `@sd-jwt/core` passes the algorithm it read from `_sd_alg`, so this is also\n * where a presentation declaring anything but sha-256 is refused\n */\nasync function hasher(data: string | ArrayBuffer, algorithm: string): Promise<Uint8Array> {\n if (algorithm.toLowerCase() !== AP2_DIGEST_ALGORITHM) {\n throw new Error(`unsupported digest algorithm ${algorithm}`);\n }\n const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : new Uint8Array(data);\n return new Uint8Array(await crypto.subtle.digest('SHA-256', bytes));\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/**\n * Order is the security boundary here: nothing is trusted until `jwtVerify`\n * returns. `kid` and `iss` are read before that only to pick which configured\n * key to try, and picking wrong just makes the signature fail.\n */\nexport async function verifyMandate(\n presentation: string,\n deps: { readonly trust: TrustStore; readonly clock: Clock; readonly clockSkewSeconds: number },\n context: Ap2ErrorContext,\n): Promise<VerifiedMandate> {\n let decoded: Awaited<ReturnType<typeof decodeSdJwt>>;\n let encodedJws: string;\n try {\n // Covers a malformed base JWT, a disclosure that will not decode, a\n // duplicate digest, and an `_sd_alg` this release does not implement\n decoded = await decodeSdJwt(presentation, hasher);\n encodedJws = splitSdJwt(presentation).jwt;\n } catch (cause) {\n throw ap2Rejected('malformed_presentation', { ...context, cause });\n }\n\n // Direct mode issues no key-bound mandates, so one arriving here belongs to\n // a flow we do not verify. Ignoring it would mean silently not checking a\n // proof that was sent.\n if (decoded.kbJwt !== undefined) {\n throw ap2Rejected('unsupported_mandate_type', context);\n }\n\n const rawPayload = asRecord(decoded.jwt.payload);\n const header = asRecord(decoded.jwt.header);\n if (rawPayload === undefined || header === undefined) {\n throw ap2Rejected('malformed_presentation', context);\n }\n\n const { issuer, key } = await deps.trust.resolve(rawPayload['iss'], header['kid'], context);\n\n const options: JWTVerifyOptions = {\n // Redundant today (the key is EC, so jose already refuses `alg: none` and\n // a forged HMAC) and kept for the day this resolves a key set instead of\n // one key, where the header would get to pick\n algorithms: [AP2_SIGNING_ALGORITHM],\n // Also redundant, and for the same reason: the key was resolved *from*\n // `iss` against the configured allowlist, so nothing reaching here can\n // carry a different one. It backstops a future resolver that matches on\n // something else. `audience` below is not redundant - `aud` is the\n // presenter's claim, checked against what the operator configured.\n issuer: issuer.issuer,\n audience: issuer.audience,\n clockTolerance: deps.clockSkewSeconds,\n // Injected clock, not jose's `Date.now()`, so expiry tests are tests\n currentDate: deps.clock.now(),\n };\n\n let verifiedPayload: Record<string, unknown>;\n try {\n const result = await jwtVerify(encodedJws, key, options);\n verifiedPayload = result.payload as Record<string, unknown>;\n } catch (cause) {\n throw ap2Rejected(classifyJoseFailure(cause), { ...context, cause });\n }\n\n requireFreshness(verifiedPayload, deps, context);\n\n let claims: Record<string, unknown>;\n try {\n // Against the VERIFIED payload: the decoded one would match disclosures\n // against digests nobody signed\n claims = (await getClaims(verifiedPayload, decoded.disclosures, hasher)) as Record<\n string,\n unknown\n >;\n } catch (cause) {\n // Where an appended disclosure that no digest references is refused\n throw ap2Rejected('malformed_presentation', { ...context, cause });\n }\n\n requireClosedCheckoutMandate(claims, context);\n\n return { issuer: issuer.issuer, claims, signedToken: encodedJws };\n}\n\n/**\n * Matched on jose's stable error `code`, not its message. A client is owed\n * \"expired\" versus \"did not verify\"; anything finer describes our checks back\n * to whoever is probing them.\n */\nfunction classifyJoseFailure(cause: unknown): 'expired' | 'wrong_audience' | 'invalid_signature' {\n const code = (cause as { code?: unknown })?.code;\n if (code === 'ERR_JWT_EXPIRED') return 'expired';\n if (code === 'ERR_JWT_CLAIM_VALIDATION_FAILED') {\n const claim = (cause as { claim?: unknown }).claim;\n if (claim === 'aud') return 'wrong_audience';\n if (claim === 'nbf' || claim === 'exp') return 'expired';\n }\n return 'invalid_signature';\n}\n\n/**\n * Required, not merely checked when present: jose validates a time claim only\n * if it is there, so a mandate omitting `exp` would verify and never expire\n */\nfunction requireFreshness(\n payload: Record<string, unknown>,\n deps: { readonly clock: Clock; readonly clockSkewSeconds: number },\n context: Ap2ErrorContext,\n): void {\n const exp = payload['exp'];\n const iat = payload['iat'];\n if (typeof exp !== 'number' || typeof iat !== 'number') {\n throw ap2Rejected('invalid_claims', context);\n }\n const nowSeconds = Math.floor(deps.clock.now().getTime() / 1000);\n // A future `iat` is a broken signer, or a mandate minted to outlive its own\n // expiry window\n if (iat > nowSeconds + deps.clockSkewSeconds) throw ap2Rejected('expired', context);\n}\n\n// Exactly `mandate.checkout.1`; see AP2_CHECKOUT_MANDATE_VCT for why\nfunction requireClosedCheckoutMandate(\n claims: Record<string, unknown>,\n context: Ap2ErrorContext,\n): void {\n if (claims['vct'] !== AP2_CHECKOUT_MANDATE_VCT) {\n throw ap2Rejected('unsupported_mandate_type', context);\n }\n}\n","/**\n * Static key resolution.\n *\n * Every key was written into `config.yaml` by an operator. No JWKS fetch, no\n * `jku`, no `x5u`. A mandate's `iss` and `kid` only choose *which* trusted key\n * verifies it; an unrecognised pair is refused, so a mandate can never\n * nominate its own signer.\n *\n * Not a \"try every key\" loop: that would make `kid` advisory and accept a\n * mandate that named a key it was not signed with.\n */\nimport { importJWK, type JWK } from 'jose';\nimport { AP2_SIGNING_ALGORITHM } from './constants.js';\nimport { type Ap2ErrorContext, ap2Rejected, ap2Unavailable } from './errors.js';\nimport type { Ap2TrustedIssuer } from './types.js';\n\n/** Named off `importJWK` because `CryptoKey` is a DOM type we do not load */\nexport type VerificationKey = Awaited<ReturnType<typeof importJWK>>;\n\nexport interface ResolvedKey {\n readonly issuer: Ap2TrustedIssuer;\n readonly key: VerificationKey;\n}\n\n/**\n * Resolves `(iss, kid)` against one configured issuer list. Caches the import\n * promise, not the key, so concurrent requests for a cold key share one import.\n */\nexport function createTrustStore(issuers: readonly Ap2TrustedIssuer[]) {\n const byIssuer = new Map(issuers.map((entry) => [entry.issuer, entry]));\n const imported = new Map<string, Promise<VerificationKey>>();\n\n return {\n /** Every trusted issuer id, for diagnostics. Never the keys themselves */\n issuerIds(): readonly string[] {\n return [...byIssuer.keys()];\n },\n\n async resolve(iss: unknown, kid: unknown, context: Ap2ErrorContext): Promise<ResolvedKey> {\n if (typeof iss !== 'string' || iss.length === 0) {\n throw ap2Rejected('invalid_claims', context);\n }\n const issuer = byIssuer.get(iss);\n if (issuer === undefined) throw ap2Rejected('untrusted_issuer', context);\n\n // Not defaulted to the issuer's only key: mid-rotation there are two,\n // and the gateway should not guess which one signed this\n if (typeof kid !== 'string' || kid.length === 0) {\n throw ap2Rejected('unknown_key', context);\n }\n const trusted = issuer.keys.find((candidate) => candidate.kid === kid);\n if (trusted === undefined) throw ap2Rejected('unknown_key', context);\n\n // JSON, not a joined string: both halves are operator-chosen and could\n // contain whatever separator we picked\n const cacheKey = JSON.stringify([iss, kid]);\n let pending = imported.get(cacheKey);\n if (pending === undefined) {\n pending = importJWK(trusted.jwk as JWK, AP2_SIGNING_ALGORITHM);\n imported.set(cacheKey, pending);\n }\n\n try {\n return { issuer, key: await pending };\n } catch (cause) {\n // Config already checked this JWK member by member, so reaching here\n // means our config is broken, not the mandate. Drop the cached\n // rejection so a fixed config is not still failing against it.\n imported.delete(cacheKey);\n throw ap2Unavailable('configured verification key could not be imported', {\n ...context,\n cause,\n });\n }\n },\n };\n}\n\nexport type TrustStore = ReturnType<typeof createTrustStore>;\n","/**\n * The Direct Checkout Mandate verifier: mandate signature first, then the\n * merchant checkout JWT it binds. Either stage failing is a refusal.\n *\n * What this proves is narrow. A trusted issuer signed this mandate, it has not\n * expired, it is addressed to us, and it binds a checkout document the\n * merchant signed. It does NOT prove the mandate authorises the purchase in\n * front of us: that is profile.ts, and a caller treating this as permission to\n * settle has skipped it.\n */\nimport type { Clock } from '../../core/index.js';\nimport { verifyCheckoutJwt } from './checkout-jwt.js';\nimport { type Ap2ErrorContext, ap2Rejected } from './errors.js';\nimport { verifyMandate } from './sd-jwt.js';\nimport { createTrustStore } from './trust.js';\nimport type { EnabledAp2Config, VerifiedCheckoutMandate } from './types.js';\n\nexport interface Ap2VerifierOptions {\n readonly config: EnabledAp2Config;\n readonly clock: Clock;\n}\n\nexport interface Ap2MandateVerifier {\n verify(presentation: string, context?: Ap2ErrorContext): Promise<VerifiedCheckoutMandate>;\n /** Trusted issuer ids, for `doctor`. Counts and names only, never keys */\n trustedIssuers(): { readonly mandate: readonly string[]; readonly checkout: readonly string[] };\n}\n\n/**\n * Algorithm-prefixed so a future digest change is visible in stored references\n * rather than silently producing unequal values for one mandate\n */\nasync function mandateReference(signedToken: string): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(signedToken));\n return `sha256:${Buffer.from(digest).toString('base64url')}`;\n}\n\nexport function createAp2MandateVerifier(options: Ap2VerifierOptions): Ap2MandateVerifier {\n // Two stores, not one list: signing the merchant's checkout documents must\n // not confer the power to issue mandates\n const mandateTrust = createTrustStore(options.config.trust.mandateIssuers);\n const checkoutTrust = createTrustStore(options.config.trust.checkoutIssuers);\n const deps = { clock: options.clock, clockSkewSeconds: options.config.clockSkewSeconds };\n\n return {\n async verify(\n presentation: string,\n context: Ap2ErrorContext = {},\n ): Promise<VerifiedCheckoutMandate> {\n if (typeof presentation !== 'string' || presentation.length === 0) {\n throw ap2Rejected('malformed_presentation', context);\n }\n\n const mandate = await verifyMandate(presentation, { ...deps, trust: mandateTrust }, context);\n const checkout = await verifyCheckoutJwt(\n mandate.claims,\n { ...deps, trust: checkoutTrust },\n context,\n );\n\n return {\n reference: await mandateReference(mandate.signedToken),\n mandateIssuer: mandate.issuer,\n checkoutIssuer: checkout.issuer,\n checkoutJwtId: checkout.jwtId,\n checkoutClaims: checkout.claims,\n mandateClaims: mandate.claims,\n };\n },\n\n trustedIssuers() {\n return { mandate: mandateTrust.issuerIds(), checkout: checkoutTrust.issuerIds() };\n },\n };\n}\n","/**\n * The AP2 authorization provider: the seam between core's generic contract and\n * the mandate machinery.\n *\n * Owns the replay database, so the gateway owns this object's lifetime and\n * closes it on shutdown.\n */\nimport type {\n AdapterHealth,\n AuthorizationFinalizeContext,\n AuthorizationProvider,\n AuthorizationRequirement,\n AuthorizationVerification,\n AuthorizationVerificationContext,\n Clock,\n Logger,\n} from '../../core/index.js';\nimport { NOOP_LOGGER, systemClock } from '../../core/index.js';\nimport { PACKAGE_VERSION } from '../../version.js';\nimport { AP2_CHECKOUT_PROFILE, AP2_SPEC_VERSION } from './constants.js';\nimport { buildAp2Descriptor } from './descriptor.js';\nimport { type Ap2ErrorContext, ap2Replayed, ap2Unavailable } from './errors.js';\nimport { bindMandateToPurchase } from './profile.js';\nimport { type Ap2ReplayStore, createAp2ReplayStore } from './replay-store.js';\nimport type { EnabledAp2Config } from './types.js';\nimport { createAp2MandateVerifier } from './verifier.js';\n\nexport interface Ap2AuthorizationProviderOptions {\n readonly config: EnabledAp2Config;\n readonly clock?: Clock;\n readonly logger?: Logger;\n /** Injectable so tests need not touch the filesystem */\n readonly replayStore?: Ap2ReplayStore;\n}\n\nexport interface Ap2AuthorizationProvider extends AuthorizationProvider {\n /** Closes the replay database */\n close(): void;\n}\n\n/**\n * A reservation is keyed by the mandate reference, so the handle and the\n * receipt's identity are the same digest. Kept as one name rather than two\n * fields that must never disagree.\n */\nexport function createAp2AuthorizationProvider(\n options: Ap2AuthorizationProviderOptions,\n): Ap2AuthorizationProvider {\n const clock = options.clock ?? systemClock;\n const logger = options.logger ?? NOOP_LOGGER;\n\n const verifier = createAp2MandateVerifier({ config: options.config, clock });\n const replay =\n options.replayStore ?? createAp2ReplayStore({ path: options.config.replay.path, logger });\n\n const requirement: AuthorizationRequirement = {\n method: 'ap2',\n version: AP2_SPEC_VERSION,\n profile: AP2_CHECKOUT_PROFILE,\n };\n\n async function verifyAndReserve(\n context: AuthorizationVerificationContext,\n ): Promise<AuthorizationVerification> {\n const errorContext: Ap2ErrorContext = {\n requestId: context.requestId,\n resourceId: context.resourceId,\n };\n\n const mandate = await verifier.verify(context.submission.payload, errorContext);\n // Before reserving, not after: a mandate that does not authorize this\n // purchase must stay spendable on the purchase it does authorize\n await bindMandateToPurchase(mandate, context, errorContext);\n\n let reservation: ReturnType<Ap2ReplayStore['reserve']>;\n try {\n reservation = replay.reserve({\n reference: mandate.reference,\n checkoutJti: mandate.checkoutJwtId,\n mandateIssuer: mandate.mandateIssuer,\n checkoutIssuer: mandate.checkoutIssuer,\n resourceId: context.resourceId,\n requestId: context.requestId,\n });\n } catch (cause) {\n throw ap2Unavailable('replay store could not be written', { ...errorContext, cause });\n }\n\n if (reservation.kind === 'replayed') {\n throw ap2Replayed(reservation.state, errorContext);\n }\n\n return {\n status: 'verified',\n method: 'ap2',\n reference: mandate.reference,\n reservationId: mandate.reference,\n // Opaque identifiers an operator can reconcile with. Never a claim from\n // the mandate: those carry the buyer's purchase and their personal data.\n // `checkoutId`, not `checkoutJwtId` - the receipt store redacts any key\n // that reads as secret-shaped, and \"jwt\" is on that list.\n metadata: {\n mandateIssuer: mandate.mandateIssuer,\n checkoutIssuer: mandate.checkoutIssuer,\n checkoutId: mandate.checkoutJwtId,\n },\n };\n }\n\n const finalize = (\n action: 'consume' | 'release' | 'markUncertain',\n reservationId: string,\n context: AuthorizationFinalizeContext,\n ): void => {\n try {\n replay[action](reservationId);\n } catch (cause) {\n throw ap2Unavailable(`replay store could not record ${action}`, { ...context, cause });\n }\n };\n\n return {\n name: 'ap2',\n descriptor: buildAp2Descriptor(PACKAGE_VERSION),\n requirement,\n verifyAndReserve,\n\n async consume(reservationId, context) {\n finalize('consume', reservationId, context);\n },\n async release(reservationId, context) {\n finalize('release', reservationId, context);\n },\n async markUncertain(reservationId, context) {\n finalize('markUncertain', reservationId, context);\n },\n\n async health(): Promise<AdapterHealth> {\n const startedAt = clock.monotonicMs();\n const trusted = verifier.trustedIssuers();\n const checkedAt = clock.nowIso();\n const durationMs = Math.round(clock.monotonicMs() - startedAt);\n try {\n // A read against the real table, so a database that opened but cannot\n // be queried is caught here rather than on the first purchase\n replay.stateOf('health-probe');\n } catch {\n // A fixed token, never a sentence built from the caught error\n return { status: 'fail', checkedAt, durationMs, detail: 'replay-store-unavailable' };\n }\n return {\n status: 'pass',\n checkedAt,\n durationMs,\n detail: `mandate-issuers=${trusted.mandate.length} checkout-issuers=${trusted.checkout.length}`,\n };\n },\n\n close() {\n replay.close();\n },\n };\n}\n"]}
@@ -0,0 +1,123 @@
1
+ import { f as AuthorizationMethodName, A as AdapterDescriptor, l as PaymentRequirement, c as AdapterHealth } from './runtime-CKq3d_3K.js';
2
+
3
+ /**
4
+ * Canonical authorization model.
5
+ *
6
+ * FROZEN CONTRACT.
7
+ *
8
+ * Authorization answers a different question from payment. Payment proves
9
+ * that funds moved; authorization proves that the human behind the agent
10
+ * approved *this exact purchase*. A valid authorization never unlocks a paid
11
+ * resource on its own and never moves money. It gates settlement, and a
12
+ * resource that requires one still needs a real payment proof as well.
13
+ *
14
+ * Core decides *that* a resource requires authorization and *when* in the
15
+ * pipeline it is checked. Authorization providers decide how a submission is
16
+ * parsed, verified and bound to the purchase. No AP2, SD-JWT or JWT type may
17
+ * appear in this file.
18
+ */
19
+
20
+ /**
21
+ * Opaque authorization proof supplied by the buyer's client.
22
+ *
23
+ * Over HTTP this arrives base64url-JSON-encoded in the `Agent-Authorization`
24
+ * header; over MCP and A2A it is the same `{ method, payload }` object carried
25
+ * in the reserved `_authorization` input field.
26
+ *
27
+ * `payload` is preserved byte-for-byte from the wire. Providers derive replay
28
+ * identities by hashing it, so decoding and reserialising it before it reaches
29
+ * the provider would change the identity of an otherwise identical proof.
30
+ */
31
+ interface AuthorizationSubmission {
32
+ readonly method: AuthorizationMethodName;
33
+ readonly payload: string;
34
+ }
35
+ /**
36
+ * What a buyer must present, advertised alongside the payment challenge so a
37
+ * client learns before it pays that a proof of payment alone will not do.
38
+ *
39
+ * The gateway never issues the authorization itself. It states the method,
40
+ * the spec version it verifies against, and the payload profile it expects.
41
+ */
42
+ interface AuthorizationRequirement {
43
+ readonly method: AuthorizationMethodName;
44
+ readonly version: string;
45
+ readonly profile?: string;
46
+ }
47
+ /**
48
+ * Safe audit identity of an authorization, fit for a receipt. `reference` is a
49
+ * digest: a receipt outlives its request, and a stored proof would be a
50
+ * spendable secret at rest.
51
+ */
52
+ interface AuthorizationRecord {
53
+ readonly method: AuthorizationMethodName;
54
+ readonly reference: string;
55
+ /** Safe audit summary only. Never the proof, its disclosures, or PII */
56
+ readonly metadata?: Readonly<Record<string, unknown>>;
57
+ }
58
+ /**
59
+ * A verified, reserved authorization. `reservationId` is the live handle the
60
+ * pipeline consumes, releases or marks uncertain once settlement resolves; it
61
+ * stays out of the record above because a handle is not an audit fact.
62
+ */
63
+ interface AuthorizationVerification extends AuthorizationRecord {
64
+ readonly status: 'verified';
65
+ readonly reservationId: string;
66
+ }
67
+ /** Input to {@link AuthorizationProvider.verifyAndReserve}. */
68
+ interface AuthorizationVerificationContext {
69
+ readonly requestId: string;
70
+ readonly resourceId: string;
71
+ /**
72
+ * The validated resource input, reserved fields already stripped: the same
73
+ * bytes the merchant backend will be called with. A provider that binds a
74
+ * proof to the request hashes this, so it must not include `_payment`,
75
+ * `_authorization`, the request id or any transport metadata.
76
+ */
77
+ readonly input: unknown;
78
+ readonly submission: AuthorizationSubmission;
79
+ /** The resolved price and destination the proof must match. */
80
+ readonly requirement: PaymentRequirement;
81
+ }
82
+ /** Input to {@link AuthorizationProvider.consume} and `release`. */
83
+ interface AuthorizationFinalizeContext {
84
+ readonly requestId: string;
85
+ readonly resourceId: string;
86
+ }
87
+ /**
88
+ * Contract every authorization method implements.
89
+ *
90
+ * The lifecycle straddles settlement: a proof must be reserved *before* funds
91
+ * move so a replay cannot race one, and its fate is only known *after*.
92
+ *
93
+ * Release only for a failure that provably moved no money. Anything ambiguous
94
+ * is marked uncertain: a proof handed back after a settlement that may have
95
+ * landed can be spent twice.
96
+ */
97
+ interface AuthorizationProvider {
98
+ readonly name: AuthorizationMethodName;
99
+ readonly descriptor: AdapterDescriptor;
100
+ /** What a buyer must present, advertised beside the payment challenge */
101
+ readonly requirement: AuthorizationRequirement;
102
+ /**
103
+ * Verify a submission against the resolved purchase and atomically reserve
104
+ * it against reuse.
105
+ *
106
+ * Throws a `CommerceError` with an `AUTHORIZATION_*` code, never a payment
107
+ * code. A verifier or store outage is
108
+ * `AUTHORIZATION_PROVIDER_UNAVAILABLE`, not the buyer's fault.
109
+ */
110
+ verifyAndReserve(context: AuthorizationVerificationContext): Promise<AuthorizationVerification>;
111
+ /** Mark a reservation permanently spent. Called after settlement succeeds. */
112
+ consume(reservationId: string, context: AuthorizationFinalizeContext): Promise<void>;
113
+ /** Return a reservation to unused. Only for failures that moved no funds. */
114
+ release(reservationId: string, context: AuthorizationFinalizeContext): Promise<void>;
115
+ /**
116
+ * Settlement broadcast but never confirmed: neither spend the reservation
117
+ * nor hand it back, and flag it for an operator
118
+ */
119
+ markUncertain(reservationId: string, context: AuthorizationFinalizeContext): Promise<void>;
120
+ health(): Promise<AdapterHealth>;
121
+ }
122
+
123
+ export type { AuthorizationProvider as A, AuthorizationRequirement as a, AuthorizationSubmission as b, AuthorizationFinalizeContext as c, AuthorizationRecord as d, AuthorizationVerification as e, AuthorizationVerificationContext as f };
@@ -0,0 +1,68 @@
1
+ import { CommerceError } from './chunk-ZDVJ7EVL.js';
2
+ import { existsSync, mkdirSync, accessSync, constants, closeSync, openSync, chmodSync } from 'fs';
3
+ import { dirname } from 'path';
4
+ import Database from 'better-sqlite3';
5
+
6
+ // src/authorization/ap2/constants.ts
7
+ var AP2_SPEC_VERSION = "0.2.0";
8
+ var AP2_MODES = ["direct"];
9
+ var AP2_SIGNING_ALGORITHM = "ES256";
10
+ var AP2_KEY_TYPE = "EC";
11
+ var AP2_JWK_CURVE = "P-256";
12
+ var AP2_JWK_COORDINATE_BYTES = 32;
13
+ var AP2_JWK_MEMBERS = ["kty", "crv", "x", "y", "kid", "alg", "use"];
14
+ var AP2_CHECKOUT_MANDATE_VCT = "mandate.checkout.1";
15
+ var AP2_CHECKOUT_PROFILE = "agent-commerce/ap2/checkout/v1";
16
+ var AP2_DIGEST_ALGORITHM = "sha-256";
17
+ var AP2_DEFAULT_CLOCK_SKEW_SECONDS = 60;
18
+ var AP2_MAX_CLOCK_SKEW_SECONDS = 300;
19
+ function openSqliteDatabase(options) {
20
+ const { path, label, logger } = options;
21
+ const isFileBacked = path !== ":memory:";
22
+ if (isFileBacked) {
23
+ const dir = dirname(path);
24
+ if (dir !== "" && dir !== "." && !existsSync(dir)) {
25
+ mkdirSync(dir, { recursive: true, mode: 448 });
26
+ }
27
+ }
28
+ if (isFileBacked && existsSync(path)) {
29
+ try {
30
+ accessSync(path, constants.W_OK);
31
+ } catch {
32
+ throw new CommerceError(
33
+ "STORAGE_ERROR",
34
+ `${label} "${path}" exists but is not writable by this process (uid ${typeof process.getuid === "function" ? process.getuid() : "unknown"}). If this is a container that recently changed user, an existing volume may still be owned by the previous one - recreate it (docker compose down -v) or fix its ownership.`,
35
+ { details: { path } }
36
+ );
37
+ }
38
+ }
39
+ if (isFileBacked) {
40
+ try {
41
+ closeSync(openSync(path, "a", 384));
42
+ } catch {
43
+ }
44
+ }
45
+ const db = new Database(path);
46
+ db.pragma("journal_mode = WAL");
47
+ db.pragma("foreign_keys = ON");
48
+ if (isFileBacked) restrictDatabasePermissions(path, label, logger);
49
+ return db;
50
+ }
51
+ function restrictDatabasePermissions(path, label, logger) {
52
+ for (const file of [path, `${path}-wal`, `${path}-shm`]) {
53
+ try {
54
+ chmodSync(file, 384);
55
+ } catch (error) {
56
+ const code = error.code;
57
+ if (code === "ENOENT") continue;
58
+ logger.warn(
59
+ { file, label, error: code ?? "unknown" },
60
+ "could not restrict database permissions to owner-only"
61
+ );
62
+ }
63
+ }
64
+ }
65
+
66
+ export { AP2_CHECKOUT_MANDATE_VCT, AP2_CHECKOUT_PROFILE, AP2_DEFAULT_CLOCK_SKEW_SECONDS, AP2_DIGEST_ALGORITHM, AP2_JWK_COORDINATE_BYTES, AP2_JWK_CURVE, AP2_JWK_MEMBERS, AP2_KEY_TYPE, AP2_MAX_CLOCK_SKEW_SECONDS, AP2_MODES, AP2_SIGNING_ALGORITHM, AP2_SPEC_VERSION, openSqliteDatabase };
67
+ //# sourceMappingURL=chunk-7NKWFGBY.js.map
68
+ //# sourceMappingURL=chunk-7NKWFGBY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/authorization/ap2/constants.ts","../src/storage/sqlite.ts"],"names":["fsConstants"],"mappings":";;;;;;AAQO,IAAM,gBAAA,GAAmB;AAOzB,IAAM,SAAA,GAAY,CAAC,QAAQ;AAO3B,IAAM,qBAAA,GAAwB;AAG9B,IAAM,YAAA,GAAe;AACrB,IAAM,aAAA,GAAgB;AAGtB,IAAM,wBAAA,GAA2B;AASjC,IAAM,eAAA,GAAkB,CAAC,KAAA,EAAO,KAAA,EAAO,KAAK,GAAA,EAAK,KAAA,EAAO,OAAO,KAAK;AAOpE,IAAM,wBAAA,GAA2B;AAajC,IAAM,oBAAA,GAAuB;AAO7B,IAAM,oBAAA,GAAuB;AAG7B,IAAM,8BAAA,GAAiC;AAMvC,IAAM,0BAAA,GAA6B;ACzCnC,SAAS,mBAAmB,OAAA,EAA+C;AAChF,EAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAO,GAAI,OAAA;AAChC,EAAA,MAAM,eAAe,IAAA,KAAS,UAAA;AAE9B,EAAA,IAAI,YAAA,EAAc;AAChB,IAAA,MAAM,GAAA,GAAM,QAAQ,IAAI,CAAA;AACxB,IAAA,IAAI,QAAQ,EAAA,IAAM,GAAA,KAAQ,OAAO,CAAC,UAAA,CAAW,GAAG,CAAA,EAAG;AAGjD,MAAA,SAAA,CAAU,KAAK,EAAE,SAAA,EAAW,IAAA,EAAM,IAAA,EAAM,KAAO,CAAA;AAAA,IACjD;AAAA,EACF;AAUA,EAAA,IAAI,YAAA,IAAgB,UAAA,CAAW,IAAI,CAAA,EAAG;AACpC,IAAA,IAAI;AACF,MAAA,UAAA,CAAW,IAAA,EAAMA,UAAY,IAAI,CAAA;AAAA,IACnC,CAAA,CAAA,MAAQ;AACN,MAAA,MAAM,IAAI,aAAA;AAAA,QACR,eAAA;AAAA,QACA,CAAA,EAAG,KAAK,CAAA,EAAA,EAAK,IAAI,CAAA,kDAAA,EAAqD,OAAO,OAAA,CAAQ,MAAA,KAAW,UAAA,GAAa,OAAA,CAAQ,MAAA,EAAO,GAAI,SAAS,CAAA,4KAAA,CAAA;AAAA,QACzI,EAAE,OAAA,EAAS,EAAE,IAAA,EAAK;AAAE,OACtB;AAAA,IACF;AAAA,EACF;AASA,EAAA,IAAI,YAAA,EAAc;AAChB,IAAA,IAAI;AACF,MAAA,SAAA,CAAU,QAAA,CAAS,IAAA,EAAM,GAAA,EAAK,GAAK,CAAC,CAAA;AAAA,IACtC,CAAA,CAAA,MAAQ;AAAA,IAIR;AAAA,EACF;AAEA,EAAA,MAAM,EAAA,GAAK,IAAI,QAAA,CAAS,IAAI,CAAA;AAC5B,EAAA,EAAA,CAAG,OAAO,oBAAoB,CAAA;AAC9B,EAAA,EAAA,CAAG,OAAO,mBAAmB,CAAA;AAC7B,EAAA,IAAI,YAAA,EAAc,2BAAA,CAA4B,IAAA,EAAM,KAAA,EAAO,MAAM,CAAA;AACjE,EAAA,OAAO,EAAA;AACT;AAkBA,SAAS,2BAAA,CAA4B,IAAA,EAAc,KAAA,EAAe,MAAA,EAAsB;AACtF,EAAA,KAAA,MAAW,IAAA,IAAQ,CAAC,IAAA,EAAM,CAAA,EAAG,IAAI,CAAA,IAAA,CAAA,EAAQ,CAAA,EAAG,IAAI,CAAA,IAAA,CAAM,CAAA,EAAG;AACvD,IAAA,IAAI;AACF,MAAA,SAAA,CAAU,MAAM,GAAK,CAAA;AAAA,IACvB,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,OAAQ,KAAA,CAAgC,IAAA;AAC9C,MAAA,IAAI,SAAS,QAAA,EAAU;AACvB,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,EAAE,IAAA,EAAM,KAAA,EAAO,KAAA,EAAO,QAAQ,SAAA,EAAU;AAAA,QACxC;AAAA,OACF;AAAA,IACF;AAAA,EACF;AACF","file":"chunk-7NKWFGBY.js","sourcesContent":["/**\n * Pinned AP2 identifiers and key policy.\n *\n * AP2 v0.2.0 (2026-04-28, commit b4587ac) is the tagged release this gateway\n * verifies against; unversioned `main` is never implemented against. Config,\n * the verifier and `doctor` all read these, so a bump lands in one place.\n */\n\nexport const AP2_SPEC_VERSION = '0.2.0';\n\n/**\n * Autonomous mode needs open mandates, cnf-bound agent keys and constraint\n * evaluation over `checkout.line_items`. Half of that would be worse than a\n * declared Direct-only profile, so it is refused rather than partly served.\n */\nexport const AP2_MODES = ['direct'] as const;\nexport type Ap2Mode = (typeof AP2_MODES)[number];\n\n/**\n * One entry, so `alg=none` and the HMAC family are excluded by construction\n * rather than by a check that has to remember them\n */\nexport const AP2_SIGNING_ALGORITHM = 'ES256';\n\n/** The key type and curve ES256 implies. Any other pair is refused at load */\nexport const AP2_KEY_TYPE = 'EC';\nexport const AP2_JWK_CURVE = 'P-256';\n\n/** Byte length of a P-256 coordinate, before base64url encoding */\nexport const AP2_JWK_COORDINATE_BYTES = 32;\n\n/**\n * JWK members a verification key may carry.\n *\n * An allowlist, so private material (`d`) and anything naming a URL (`x5u`,\n * or a smuggled `jku`) is refused without this list having to name it. Keys\n * are configured inline and never fetched; see docs/security.md.\n */\nexport const AP2_JWK_MEMBERS = ['kty', 'crv', 'x', 'y', 'kid', 'alg', 'use'] as const;\n\n/**\n * Compared against this literal, never as a prefix. `mandate.checkout.open.1`\n * carries spending constraints this release does not evaluate, so accepting it\n * would tell a buyer their limits were checked when nothing read them.\n */\nexport const AP2_CHECKOUT_MANDATE_VCT = 'mandate.checkout.1';\n\n/**\n * The checkout profile every merchant checkout JWT must declare.\n *\n * Ours, not AP2's: AP2 leaves the checkout payload outside its scope, so the\n * claims a paid-resource invocation needs had to be specified somewhere.\n *\n * A bare name, matching the gateway's other wire identifiers\n * (`agent-commerce/delivery`, `agent-commerce/v1.0.0`). A profile id is a\n * namespace and is never dereferenced, so a URL would only tie the wire format\n * to a domain. Frozen once released: merchants sign it into every checkout JWT.\n */\nexport const AP2_CHECKOUT_PROFILE = 'agent-commerce/ap2/checkout/v1';\n\n/**\n * Taken from the SD-JWT `_sd_alg`, which defaults to sha-256 when absent.\n * Anything else is refused rather than hashed as sha-256 anyway, which would\n * check a presentation under an algorithm it never claimed.\n */\nexport const AP2_DIGEST_ALGORITHM = 'sha-256';\n\n/** Seconds of clock skew tolerated on mandate and checkout time claims */\nexport const AP2_DEFAULT_CLOCK_SKEW_SECONDS = 60;\n\n/**\n * Skew wide enough to cover a mandate's validity window stops `exp` rejecting\n * anything. An operator needing more than five minutes has a clock to fix.\n */\nexport const AP2_MAX_CLOCK_SKEW_SECONDS = 300;\n","/**\n * Opening a SQLite file safely.\n *\n * One definition, because every rule below was learned once and must not be\n * re-learned per store: the file is pre-created at 0600 before SQLite can\n * create it at `0666 & ~umask`, the WAL sidecars are narrowed after WAL is\n * enabled (they do not exist until then), and an existing but unwritable file\n * fails at startup instead of on the first write.\n *\n * Callers own their schema. This function opens and hardens; it migrates\n * nothing.\n */\nimport {\n accessSync,\n chmodSync,\n closeSync,\n existsSync,\n constants as fsConstants,\n mkdirSync,\n openSync,\n} from 'node:fs';\nimport { dirname } from 'node:path';\nimport Database from 'better-sqlite3';\nimport { CommerceError, type Logger } from '../core/index.js';\n\nexport interface OpenSqliteOptions {\n /** File path, or ':memory:' for tests. Parent directory is created if missing. */\n readonly path: string;\n /** Names the database in operator-facing errors, e.g. \"Receipt database\". */\n readonly label: string;\n readonly logger: Logger;\n}\n\nexport function openSqliteDatabase(options: OpenSqliteOptions): Database.Database {\n const { path, label, logger } = options;\n const isFileBacked = path !== ':memory:';\n\n if (isFileBacked) {\n const dir = dirname(path);\n if (dir !== '' && dir !== '.' && !existsSync(dir)) {\n // 0700 on directories we create ourselves. An existing directory is the\n // operator's to own and is deliberately left alone.\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n }\n\n // Fail at startup, not on the first write. `new Database(path)` happily opens\n // a file the process cannot write, and SQLite only says \"attempt to write a\n // readonly database\" once a write is attempted - which on a paid resource is\n // *after* the payment attempt reservation, surfacing as an opaque\n // STORAGE_ERROR per request. Readiness does catch it (503), but the operator\n // is left guessing. This is not hypothetical: switching the demo containers\n // to a non-root user left an existing named volume root-owned, and that is\n // exactly how it presented.\n if (isFileBacked && existsSync(path)) {\n try {\n accessSync(path, fsConstants.W_OK);\n } catch {\n throw new CommerceError(\n 'STORAGE_ERROR',\n `${label} \"${path}\" exists but is not writable by this process (uid ${typeof process.getuid === 'function' ? process.getuid() : 'unknown'}). If this is a container that recently changed user, an existing volume may still be owned by the previous one - recreate it (docker compose down -v) or fix its ownership.`,\n { details: { path } },\n );\n }\n }\n\n // Create the file ourselves, at 0600, *before* SQLite can create it at\n // `0666 & ~umask`. The chmod below only narrows the mode after the fact: a\n // local co-tenant who opens the file inside that window keeps a readable\n // descriptor across the chmod and reads everything written afterwards.\n // SQLite copies the main file's mode onto the -wal/-shm sidecars, so this one\n // call covers all three. `mode` applies on creation only, so an existing file\n // is untouched here and left to the chmod.\n if (isFileBacked) {\n try {\n closeSync(openSync(path, 'a', 0o600));\n } catch {\n // Deliberately silent: whatever stopped us (unwritable directory, exotic\n // filesystem) is about to be reported by `new Database` with a better\n // message, or is harmless and covered by the chmod below.\n }\n }\n\n const db = new Database(path);\n db.pragma('journal_mode = WAL');\n db.pragma('foreign_keys = ON');\n if (isFileBacked) restrictDatabasePermissions(path, label, logger);\n return db;\n}\n\n/**\n * Narrow the database and its WAL sidecars to owner-only.\n *\n * `new Database(path)` opens with `0666 & ~umask`, so on a standard host the\n * `.sqlite`, `-wal` and `-shm` files landed at 0644 - any other local user\n * could read the whole commerce ledger: payer and payee addresses, amounts,\n * settlement transaction hashes, replay keys and the entire event stream. No\n * key material (the gateway is non-custodial and `redact.ts` is recursive), but\n * business metadata all the same.\n *\n * Called *after* `journal_mode = WAL`, because the sidecars do not exist until\n * then. Belt-and-braces since the main file is pre-created at 0600 above: this\n * still tightens a database that already existed with a looser mode.\n * Best-effort by design: a filesystem without POSIX modes must not stop the\n * gateway from starting, so a failure warns rather than throws.\n */\nfunction restrictDatabasePermissions(path: string, label: string, logger: Logger): void {\n for (const file of [path, `${path}-wal`, `${path}-shm`]) {\n try {\n chmodSync(file, 0o600);\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code === 'ENOENT') continue;\n logger.warn(\n { file, label, error: code ?? 'unknown' },\n 'could not restrict database permissions to owner-only',\n );\n }\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { CommerceError } from './chunk-EIACECVM.js';
1
+ import { CommerceError } from './chunk-ZDVJ7EVL.js';
2
2
 
3
3
  // src/payments/x402/networks.ts
4
4
  var PROFILES = [
@@ -251,5 +251,5 @@ function sameAddress(a, b) {
251
251
  }
252
252
 
253
253
  export { SUPPORTED_NETWORK_IDS, assertDevKeyIsLocalOnly, assertPayToIsNotDevAddress, describeDeploymentMode, requireNetworkProfile, resolveDeploymentMode, resolveX402Deployment };
254
- //# sourceMappingURL=chunk-5TKNTWMC.js.map
255
- //# sourceMappingURL=chunk-5TKNTWMC.js.map
254
+ //# sourceMappingURL=chunk-IUR3Q7DE.js.map
255
+ //# sourceMappingURL=chunk-IUR3Q7DE.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/payments/x402/networks.ts","../src/payments/x402/local-chain/accounts.ts","../src/payments/x402/dev-key-guard.ts","../src/payments/x402/guardrails.ts"],"names":[],"mappings":"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","file":"chunk-5TKNTWMC.js","sourcesContent":["/**\n * The networks this gateway will settle on, as data.\n *\n * x402 v2 identifies a network by its CAIP-2 id, so the only thing an\n * operator has to change to move between environments is that string. What\n * the code needs on top of it — the chain id to sign against, a name a human\n * recognises, and whether real money is involved — lives here rather than\n * being derived at each call site.\n *\n * A registry rather than \"parse any `eip155:*`\" on purpose. The chain id is\n * parseable from any such string, but `mainnet` is not, and every guardrail in\n * `guardrails.ts` keys off it. An unknown id is refused at startup instead of\n * being quietly treated as a testnet.\n *\n * Base Sepolia and the local dev chain share the id `eip155:84532`: the local\n * chain deliberately reuses Base Sepolia's chain id so the unmodified x402 SDK\n * can talk to it. Nothing may infer \"public network\" from the network id alone\n * — that is what `resolveDeploymentMode` and the Anvil probe in `provider.ts`\n * are for.\n */\nimport { CommerceError } from '../../core/index.js';\n\nexport interface NetworkProfile {\n /** CAIP-2 identifier, e.g. `eip155:84532`. */\n readonly id: string;\n /** Signed into the buyer's EIP-712 domain. */\n readonly chainId: number;\n readonly displayName: string;\n readonly kind: 'testnet' | 'mainnet';\n /**\n * The USDC deployment this network is expected to settle in, with the EIP-712\n * domain the token actually reports. Enforced only on mainnet (see\n * `guardrails.ts`) — a testnet is where a mock token is a legitimate thing to\n * point at.\n *\n * `name` is not decorative and is not the symbol: it is signed into every\n * buyer's EIP-712 domain, and the two USDC deployments disagree. Base Sepolia\n * reports `\"USDC\"`; Base mainnet reports `\"USD Coin\"`. Configure the wrong\n * one and every payment is refused `invalid_exact_evm_token_name_mismatch`\n * after the buyer has signed. Read back from the contracts, not assumed.\n */\n readonly canonicalAsset?: {\n readonly symbol: string;\n readonly address: string;\n readonly name: string;\n readonly version: string;\n };\n}\n\nconst PROFILES: readonly NetworkProfile[] = [\n {\n id: 'eip155:84532',\n chainId: 84532,\n displayName: 'Base Sepolia',\n kind: 'testnet',\n canonicalAsset: {\n symbol: 'USDC',\n address: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n name: 'USDC',\n version: '2',\n },\n },\n {\n id: 'eip155:8453',\n chainId: 8453,\n displayName: 'Base',\n kind: 'mainnet',\n canonicalAsset: {\n symbol: 'USDC',\n address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n name: 'USD Coin',\n version: '2',\n },\n },\n];\n\nconst BY_ID = new Map(PROFILES.map((profile) => [profile.id, profile]));\n\nexport const SUPPORTED_NETWORK_IDS: readonly string[] = PROFILES.map((p) => p.id);\n\nexport function findNetworkProfile(id: string): NetworkProfile | undefined {\n return BY_ID.get(id);\n}\n\nexport function requireNetworkProfile(id: string, path: string): NetworkProfile {\n const profile = BY_ID.get(id);\n if (!profile) {\n throw new CommerceError(\n 'CONFIG_INVALID',\n `${path}: \"${id}\" is not a supported network. Supported CAIP-2 identifiers: ${SUPPORTED_NETWORK_IDS.join(', ')}`,\n { details: { path, network: id } },\n );\n }\n return profile;\n}\n\n/**\n * What this deployment actually is, as opposed to what it is called.\n *\n * `local` is a property of the *facilitator*, not the network: settling\n * through the in-process facilitator against a dev node is local regardless of\n * the CAIP-2 id that node answers to. This distinction is the whole reason\n * diagnostics can say `eip155:84532` without claiming to be on public Base\n * Sepolia.\n */\nexport type DeploymentMode = 'local' | 'testnet' | 'mainnet';\n\nexport function resolveDeploymentMode(\n profile: NetworkProfile,\n facilitatorMode: 'local' | 'remote',\n): DeploymentMode {\n if (facilitatorMode === 'local') return 'local';\n return profile.kind;\n}\n\n/** The banner an operator must not be able to miss. Never printed for anything else. */\nexport const LIVE_MAINNET_BANNER = 'LIVE MAINNET MODE — REAL FUNDS';\n\nexport function describeDeploymentMode(mode: DeploymentMode): string {\n return mode === 'mainnet' ? LIVE_MAINNET_BANNER : mode.toUpperCase();\n}\n","/**\n * Anvil's well-known development accounts.\n *\n * LOCAL DEVELOPMENT ONLY — DO NOT FUND. These addresses and private keys are\n * derived from Foundry's public, well-documented default test mnemonic\n * (\"test test test test test test test test test test test junk\") and are\n * known to everyone who has ever run `anvil`. Anyone who sends real value to\n * one of these addresses on a real network will lose it.\n *\n * Index layout used by the local demo chain (see docs/contracts.md):\n * 0 — deployer / local facilitator signer (pays gas, broadcasts settlement)\n * 1 — merchant settlement destination (`payTo`)\n * 2 — buyer (signs EIP-3009 authorisations; never held by the gateway)\n */\nexport interface AnvilWellKnownAccount {\n readonly address: `0x${string}`;\n readonly privateKey: `0x${string}`;\n}\n\n/** Fixed-length tuple (not a bare array) so indexing by the documented layout above is fully typed. */\nexport const ANVIL_WELL_KNOWN_ACCOUNTS: readonly [\n AnvilWellKnownAccount,\n AnvilWellKnownAccount,\n AnvilWellKnownAccount,\n] = [\n {\n address: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',\n privateKey: '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',\n },\n {\n address: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',\n privateKey: '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d',\n },\n {\n address: '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',\n privateKey: '0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a',\n },\n];\n\nexport const LOCAL_FACILITATOR_ACCOUNT = ANVIL_WELL_KNOWN_ACCOUNTS[0];\nexport const LOCAL_MERCHANT_ACCOUNT = ANVIL_WELL_KNOWN_ACCOUNTS[1];\nexport const LOCAL_BUYER_ACCOUNT = ANVIL_WELL_KNOWN_ACCOUNTS[2];\n\n/** Safe label used everywhere a dev key appears in output, logs or manifests. */\nexport const DEV_KEY_LABEL = 'LOCAL DEVELOPMENT ONLY - DO NOT FUND';\n","/**\n * Prevents a well-known Anvil development private key — or a well-known\n * Anvil development *address* — from ever being used against anything other\n * than a loopback/private/dev RPC. Two symmetric mistakes, both covered:\n * signing settlement with a dev key (`assertDevKeyIsLocalOnly`), and routing\n * settlement revenue to a dev address (`assertPayToIsNotDevAddress`). The\n * second is the more consequential of the two — a wrong key merely fails to\n * sign, a wrong payTo silently succeeds and gives the money away, since the\n * private key behind every well-known Anvil address is public knowledge.\n *\n * Chain id alone cannot tell a real network from this project's local dev\n * chain: Base Sepolia's own chain id is 84532, the same id this project\n * deliberately reuses for the local chain so the unmodified x402 SDK can talk\n * to it. A dev key or dev payTo pointed at a real RPC by a config mistake is\n * instantly drainable — this is checked once at provider construction, not per\n * payment.\n */\nimport { CommerceError } from '../../core/index.js';\nimport { ANVIL_WELL_KNOWN_ACCOUNTS } from './local-chain/accounts.js';\n\nconst WELL_KNOWN_DEV_KEYS: ReadonlySet<string> = new Set(\n ANVIL_WELL_KNOWN_ACCOUNTS.map((a) => a.privateKey.toLowerCase()),\n);\n\nconst WELL_KNOWN_DEV_ADDRESSES: ReadonlySet<string> = new Set(\n ANVIL_WELL_KNOWN_ACCOUNTS.map((a) => a.address.toLowerCase()),\n);\n\n/** `0x` + 64 hex chars — the only shape `privateKeyToAccount` accepts. */\nconst PRIVATE_KEY_SHAPE = /^0x[0-9a-fA-F]{64}$/;\n\nexport function isWellKnownDevKey(privateKey: string): boolean {\n return WELL_KNOWN_DEV_KEYS.has(privateKey.toLowerCase());\n}\n\nexport function isWellKnownDevAddress(address: string): boolean {\n return WELL_KNOWN_DEV_ADDRESSES.has(address.toLowerCase());\n}\n\n/**\n * True for loopback addresses, RFC1918 private ranges, and bare (dot-free)\n * hostnames — the shape of a docker-compose/k8s service name (e.g.\n * \"anvil\"), which a real public DNS name essentially never has.\n *\n * ASSUMPTION, and the loosest edge of this guard: every dot-free, colon-free\n * hostname is treated as private, with no exceptions. A single-label *public* hostname (no dots) is\n * essentially nonexistent in practice — ICANN does not delegate bare\n * gTLDs/TLDs as public A/AAAA records — but this function cannot tell \"no\n * dots because it's a compose service name\" from \"no dots because it's an\n * unusual real host\" if one somehow existed. If that assumption ever stops\n * holding, this is the line to revisit.\n */\nexport function isLikelyLocalOrPrivateHost(hostname: string): boolean {\n const h = hostname.toLowerCase().replace(/^\\[|\\]$/g, '');\n if (h === 'localhost' || h === '127.0.0.1' || h === '::1') return true;\n if (/^127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/.test(h)) return true;\n if (/^10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/.test(h)) return true;\n if (/^192\\.168\\.\\d{1,3}\\.\\d{1,3}$/.test(h)) return true;\n if (/^172\\.(1[6-9]|2\\d|3[01])\\.\\d{1,3}\\.\\d{1,3}$/.test(h)) return true;\n if (!h.includes('.') && !h.includes(':')) return true; // bare hostname\n return false;\n}\n\nfunction parseHostnameOrThrow(rpcUrl: string): string {\n try {\n return new URL(rpcUrl).hostname;\n } catch (cause) {\n // Not the URL itself: every commercial EVM RPC provider embeds an API key\n // in the path, and these messages reach `validate`, `doctor`, startup\n // output and CI logs.\n throw new CommerceError('CONFIG_INVALID', 'x402 provider: rpcUrl is not a valid URL', {\n cause,\n });\n }\n}\n\n/** Host only, for diagnostics. An RPC URL's path routinely carries a key. */\nfunction describeRpc(rpcUrl: string): string {\n try {\n return new URL(rpcUrl).origin;\n } catch {\n return '[unparseable rpcUrl]';\n }\n}\n\n/**\n * Throws CONFIG_INVALID if a well-known dev key would sign against a non-local\n * RPC — or if `signerPrivateKey` isn't shaped like a private key at all.\n *\n * The shape check runs first and unconditionally. \"Not a key I recognise\"\n * (falls through `isWellKnownDevKey`, silently treated as someone's own real\n * facilitator key) and \"not a key at all\" (e.g. a truncated 63-char string)\n * must never share a code path: a malformed key that slips past this guard\n * only fails later, inside `settle()`, after the buyer's replayKey is already\n * reserved.\n */\nexport function assertDevKeyIsLocalOnly(rpcUrl: string, signerPrivateKey: string): void {\n if (!PRIVATE_KEY_SHAPE.test(signerPrivateKey)) {\n throw new CommerceError(\n 'CONFIG_INVALID',\n 'x402 provider: facilitator.signerPrivateKey is not a well-formed private key ' +\n '(expected \"0x\" followed by exactly 64 hex characters).',\n );\n }\n\n if (!isWellKnownDevKey(signerPrivateKey)) return; // a real facilitator key: not our business\n\n const hostname = parseHostnameOrThrow(rpcUrl);\n\n if (!isLikelyLocalOrPrivateHost(hostname)) {\n throw new CommerceError(\n 'CONFIG_INVALID',\n 'x402 provider: facilitator.signerPrivateKey is a well-known Anvil development key, but rpcUrl ' +\n `${describeRpc(rpcUrl)} does not look like a local/private chain. A public dev key must never sign against ` +\n 'a public network — it is instantly drainable and can grief real settlements via nonce exhaustion. ' +\n 'Use a real facilitator key for any non-local RPC, or point rpcUrl at your local/dev chain.',\n );\n }\n}\n\n/**\n * Throws CONFIG_INVALID if `payTo` (the settlement destination) is a\n * well-known Anvil development address and `rpcUrl` doesn't look\n * local/private.\n *\n * Mirrors `assertDevKeyIsLocalOnly`, but guards the *receiving* side of the\n * payment instead of the signing side, and — unlike the key guard — applies\n * regardless of facilitator mode: which account signs the settlement\n * transaction has no bearing on whether the destination address is one whose\n * private key is public knowledge. `agent-commerce init` defaults `payTo` to\n * a well-known Anvil address as a local-demo convenience; on a real network\n * that default routes every payment to an address anyone on earth can sweep.\n */\nexport function assertPayToIsNotDevAddress(rpcUrl: string, payTo: string): void {\n if (!isWellKnownDevAddress(payTo)) return; // not a dev address: not our business\n\n const hostname = parseHostnameOrThrow(rpcUrl);\n\n if (!isLikelyLocalOrPrivateHost(hostname)) {\n throw new CommerceError(\n 'CONFIG_INVALID',\n `x402 provider: \"payTo\" (${payTo}) is a well-known Anvil development address, but rpcUrl ` +\n `${describeRpc(rpcUrl)} does not look like a local/private chain. The private key behind that address ` +\n 'is public knowledge, so any revenue settled to it is immediately spendable by anyone. Set ' +\n '\"payTo\" to your own merchant wallet for any non-local RPC, or point rpcUrl at your ' +\n 'local/dev chain.',\n );\n }\n}\n","/**\n * Everything that must be true before this gateway is allowed to settle a\n * payment on the configured network.\n *\n * One definition, two callers: the provider runs it at construction so a\n * library consumer who never touches our config loader still gets the checks,\n * and `doctor` runs it against the parsed config so an operator sees the same\n * verdict without starting the gateway. Sharing a *call* is not sharing a\n * definition — the checks live here, and nothing re-implements them.\n *\n * Every failure is a startup failure. None of these are request-time\n * decisions: a deployment that is unsafe is unsafe before the first buyer\n * arrives, and finding out during `settle()` means the buyer's authorisation\n * is already burned.\n *\n * Peer-free by construction (no viem, no `@x402/*`) so the CLI can import it.\n */\nimport { CommerceError } from '../../core/index.js';\nimport { isLikelyLocalOrPrivateHost, isWellKnownDevAddress } from './dev-key-guard.js';\nimport {\n type DeploymentMode,\n type NetworkProfile,\n requireNetworkProfile,\n resolveDeploymentMode,\n} from './networks.js';\n\n/**\n * How the gateway authenticates to a remote facilitator.\n *\n * Deliberately a list, not a vendor: x402 facilitators are not a Coinbase-only\n * category, and a scheme that only fitted one vendor's credentials would make\n * the abstraction a fiction.\n *\n * - `none` — the facilitator takes no credential (the public testnet one).\n * - `bearer` — a static token. Covers most self-hosted and third-party\n * facilitators, and needs nothing installed.\n * - `cdp` — Coinbase Developer Platform, which signs a fresh JWT per request\n * over method + host + path, so a static header cannot express it. Handled by\n * the optional peer `@coinbase/x402`, imported only when this type is\n * configured. Anyone not using CDP never installs it.\n *\n * A facilitator whose scheme is none of these is refused at config load rather\n * than sent nothing.\n */\nexport type FacilitatorAuth =\n | { readonly type: 'none' }\n | { readonly type: 'bearer'; readonly token: string }\n | { readonly type: 'cdp'; readonly apiKeyId: string; readonly apiKeySecret: string };\n\nexport type X402FacilitatorConfig =\n | { readonly mode: 'local'; readonly signerPrivateKey: string }\n | { readonly mode: 'remote'; readonly url: string; readonly auth: FacilitatorAuth };\n\nexport interface X402DeploymentInput {\n readonly network: string;\n readonly payTo: string;\n readonly asset: string;\n /** EIP-712 domain of the asset, as the token itself reports it. */\n readonly assetName?: string;\n readonly assetVersion?: string;\n readonly facilitator: X402FacilitatorConfig;\n /** Required, and required to be `true`, before anything settles on a mainnet. */\n readonly allowMainnet?: boolean;\n /**\n * Required, and required to be `true`, to settle on a mainnet through a\n * facilitator that takes no credential.\n *\n * Separate from `allowMainnet` because it names a different decision: not\n * \"I meant to use real money\" but \"I accept this particular counterparty\n * without an account, terms, or anyone to call\".\n */\n readonly allowUnauthenticatedFacilitator?: boolean;\n}\n\nexport interface X402Deployment {\n readonly profile: NetworkProfile;\n readonly mode: DeploymentMode;\n}\n\nfunction invalid(message: string, path: string): CommerceError {\n return new CommerceError('CONFIG_INVALID', message, { details: { path } });\n}\n\n/**\n * Resolves the deployment and refuses every combination that could move real\n * money by accident. Order matters only in that the network must resolve\n * first; the rest are independent.\n */\nexport function resolveX402Deployment(input: X402DeploymentInput): X402Deployment {\n const profile = requireNetworkProfile(input.network, 'payments.x402.network');\n const mode = resolveDeploymentMode(profile, input.facilitator.mode);\n\n // The in-process facilitator signs with a key this process holds. Not a\n // custody problem — that signer never holds buyer or merchant funds, it pays\n // gas and broadcasts `transferWithAuthorization`, and the money moves buyer\n // to merchant directly on-chain. What it *is*, on a mainnet, is a funded key\n // inside the resource server: compromise that process and an attacker drains\n // the gas wallet and broadcasts from it. Separate processes, separate blast\n // radius — so it is refused, not warned about.\n if (profile.kind === 'mainnet' && input.facilitator.mode === 'local') {\n throw invalid(\n `payments.x402: network \"${profile.id}\" (${profile.displayName}) is a mainnet and cannot be served by facilitator.mode \"local\". A mainnet deployment must settle through a remote facilitator.`,\n 'payments.x402.facilitator.mode',\n );\n }\n\n if (mode === 'mainnet' && input.allowMainnet !== true) {\n throw invalid(\n `payments.x402: network \"${profile.id}\" (${profile.displayName}) settles real funds. Set payments.x402.allowMainnet: true to acknowledge this explicitly — it is never the default.`,\n 'payments.x402.allowMainnet',\n );\n }\n\n if (input.facilitator.mode === 'remote') {\n assertFacilitatorUrlIsSafe(input.facilitator.url, mode);\n // Not a funds check. An EIP-3009 authorisation names its recipient, its\n // amount and its chain, so a facilitator can broadcast exactly that\n // transfer or nothing — it cannot redirect the money. What a credential\n // buys is a *relationship*: rate limits, terms, someone to call when\n // settlement stops. Running production payments through a counterparty you\n // have none of that with is a real choice, and this is where it gets made\n // explicitly rather than by omission.\n if (\n mode === 'mainnet' &&\n input.facilitator.auth.type === 'none' &&\n input.allowUnauthenticatedFacilitator !== true\n ) {\n throw invalid(\n `payments.x402: facilitator ${describeOrigin(input.facilitator.url)} takes no credential, and this is a mainnet deployment. It will see every payment authorisation you handle, with no account, terms or support behind it. Set payments.x402.allowUnauthenticatedFacilitator: true to accept that, or configure facilitator.auth.`,\n 'payments.x402.allowUnauthenticatedFacilitator',\n );\n }\n // An empty credential is refused rather than sent: a blank token or key\n // reaches the facilitator as \"unauthenticated\" and fails every payment\n // after the buyer has already signed. `${VAR:- }` resolving to whitespace\n // is the realistic way this happens.\n for (const [field, value] of credentialFields(input.facilitator.auth)) {\n if (value.trim() === '') {\n throw invalid(\n `payments.x402: facilitator.auth.type is \"${input.facilitator.auth.type}\" but ${field} is empty. An empty credential is refused rather than sent.`,\n `payments.x402.facilitator.auth.${field}`,\n );\n }\n }\n }\n\n // The private key behind every well-known Anvil address is public knowledge.\n // `dev-key-guard` already refuses one against a public *RPC*; this refuses\n // one on any non-local *deployment*, which is the case a remote facilitator\n // creates — there the RPC host says nothing about where settlement lands.\n // The zero address lived only in the config loader, so a library consumer\n // calling `createX402PaymentProvider` directly — the path this shared\n // definition exists to cover — could boot a mainnet provider whose every\n // payment burns — sharing a *call* is not sharing a definition, and this\n // check had drifted out of the shared one.\n if (/^0x0{40}$/i.test(input.payTo)) {\n throw invalid(\n 'payments.x402: \"payTo\" is the zero address. Every payment settled there is destroyed.',\n 'payments.x402.payTo',\n );\n }\n\n if (mode !== 'local' && isWellKnownDevAddress(input.payTo)) {\n throw invalid(\n `payments.x402: \"payTo\" (${input.payTo}) is a well-known Anvil development address and this is a ${mode} deployment. Anyone can spend what settles there. Set payTo to your own merchant wallet.`,\n 'payments.x402.payTo',\n );\n }\n\n // Mainnet only. A testnet is exactly where pointing at a mock token is the\n // right thing to do, so the same check there would block the normal case.\n const canonical = profile.canonicalAsset;\n if (mode === 'mainnet' && canonical) {\n if (!sameAddress(input.asset, canonical.address)) {\n throw invalid(\n `payments.x402: asset ${input.asset} is not ${canonical.symbol} on ${profile.displayName} (expected ${canonical.address}). Settling a mainnet payment in an unintended token is refused.`,\n 'payments.x402.asset',\n );\n }\n // The EIP-712 domain is signed by the buyer and checked by the scheme. Get\n // it wrong and every payment is refused `invalid_exact_evm_token_name_mismatch`\n // *after* the buyer signed — a config error charged to the buyer's patience.\n // Caught here instead, before the gateway starts.\n if (input.assetName !== undefined && input.assetName !== canonical.name) {\n throw invalid(\n `payments.x402: assetName \"${input.assetName}\" is not the EIP-712 domain name ${canonical.symbol} reports on ${profile.displayName} (expected \"${canonical.name}\"). Every payment would be refused after the buyer signed.`,\n 'payments.x402.assetName',\n );\n }\n if (input.assetVersion !== undefined && input.assetVersion !== canonical.version) {\n throw invalid(\n `payments.x402: assetVersion \"${input.assetVersion}\" is not the EIP-712 domain version ${canonical.symbol} reports on ${profile.displayName} (expected \"${canonical.version}\").`,\n 'payments.x402.assetVersion',\n );\n }\n }\n\n return { profile, mode };\n}\n\n/**\n * A facilitator sees every payment authorisation this gateway handles. Plain\n * HTTP to one on a public network puts those on the wire in the clear and\n * lets anyone in the path rewrite a settlement result, so it is allowed only\n * where the endpoint cannot leave the host — a local or private address.\n */\nfunction assertFacilitatorUrlIsSafe(url: string, mode: DeploymentMode): void {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch (cause) {\n throw new CommerceError('CONFIG_INVALID', `payments.x402: facilitator.url is not a valid URL`, {\n cause,\n details: { path: 'payments.x402.facilitator.url' },\n });\n }\n\n if (parsed.protocol === 'https:') return;\n if (parsed.protocol !== 'http:') {\n throw invalid(\n `payments.x402: facilitator ${describeOrigin(url)} must be reached over https (or http on a local/private host); got \"${parsed.protocol}//\"`,\n 'payments.x402.facilitator.url',\n );\n }\n if (mode !== 'mainnet' && isLikelyLocalOrPrivateHost(parsed.hostname)) return;\n\n // The origin, never the whole URL: the path can carry a tenant or an API\n // key, which is why `/.well-known` withholds this field entirely. A refusal\n // message goes to `validate`, `doctor`, startup output and CI logs.\n throw invalid(\n `payments.x402: facilitator ${describeOrigin(url)} is reached over plain HTTP. Payment authorisations and settlement results would travel unencrypted. Use https, or point at a local/private host on a non-mainnet deployment.`,\n 'payments.x402.facilitator.url',\n );\n}\n\n/** Host only — a facilitator URL can carry a tenant path or an API key. */\nfunction describeOrigin(url: string): string {\n try {\n return new URL(url).origin;\n } catch {\n return '[unparseable facilitator.url]';\n }\n}\n\n/** The secret-bearing fields of an auth block, for emptiness checks only. Never logged. */\nfunction credentialFields(auth: FacilitatorAuth): readonly (readonly [string, string])[] {\n switch (auth.type) {\n case 'bearer':\n return [['token', auth.token]];\n case 'cdp':\n return [\n ['apiKeyId', auth.apiKeyId],\n ['apiKeySecret', auth.apiKeySecret],\n ];\n default:\n return [];\n }\n}\n\nfunction sameAddress(a: string, b: string): boolean {\n return a.toLowerCase() === b.toLowerCase();\n}\n"]}
1
+ {"version":3,"sources":["../src/payments/x402/networks.ts","../src/payments/x402/local-chain/accounts.ts","../src/payments/x402/dev-key-guard.ts","../src/payments/x402/guardrails.ts"],"names":[],"mappings":"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","file":"chunk-IUR3Q7DE.js","sourcesContent":["/**\n * The networks this gateway will settle on, as data.\n *\n * x402 v2 identifies a network by its CAIP-2 id, so the only thing an\n * operator has to change to move between environments is that string. What\n * the code needs on top of it — the chain id to sign against, a name a human\n * recognises, and whether real money is involved — lives here rather than\n * being derived at each call site.\n *\n * A registry rather than \"parse any `eip155:*`\" on purpose. The chain id is\n * parseable from any such string, but `mainnet` is not, and every guardrail in\n * `guardrails.ts` keys off it. An unknown id is refused at startup instead of\n * being quietly treated as a testnet.\n *\n * Base Sepolia and the local dev chain share the id `eip155:84532`: the local\n * chain deliberately reuses Base Sepolia's chain id so the unmodified x402 SDK\n * can talk to it. Nothing may infer \"public network\" from the network id alone\n * — that is what `resolveDeploymentMode` and the Anvil probe in `provider.ts`\n * are for.\n */\nimport { CommerceError } from '../../core/index.js';\n\nexport interface NetworkProfile {\n /** CAIP-2 identifier, e.g. `eip155:84532`. */\n readonly id: string;\n /** Signed into the buyer's EIP-712 domain. */\n readonly chainId: number;\n readonly displayName: string;\n readonly kind: 'testnet' | 'mainnet';\n /**\n * The USDC deployment this network is expected to settle in, with the EIP-712\n * domain the token actually reports. Enforced only on mainnet (see\n * `guardrails.ts`) — a testnet is where a mock token is a legitimate thing to\n * point at.\n *\n * `name` is not decorative and is not the symbol: it is signed into every\n * buyer's EIP-712 domain, and the two USDC deployments disagree. Base Sepolia\n * reports `\"USDC\"`; Base mainnet reports `\"USD Coin\"`. Configure the wrong\n * one and every payment is refused `invalid_exact_evm_token_name_mismatch`\n * after the buyer has signed. Read back from the contracts, not assumed.\n */\n readonly canonicalAsset?: {\n readonly symbol: string;\n readonly address: string;\n readonly name: string;\n readonly version: string;\n };\n}\n\nconst PROFILES: readonly NetworkProfile[] = [\n {\n id: 'eip155:84532',\n chainId: 84532,\n displayName: 'Base Sepolia',\n kind: 'testnet',\n canonicalAsset: {\n symbol: 'USDC',\n address: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n name: 'USDC',\n version: '2',\n },\n },\n {\n id: 'eip155:8453',\n chainId: 8453,\n displayName: 'Base',\n kind: 'mainnet',\n canonicalAsset: {\n symbol: 'USDC',\n address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n name: 'USD Coin',\n version: '2',\n },\n },\n];\n\nconst BY_ID = new Map(PROFILES.map((profile) => [profile.id, profile]));\n\nexport const SUPPORTED_NETWORK_IDS: readonly string[] = PROFILES.map((p) => p.id);\n\nexport function findNetworkProfile(id: string): NetworkProfile | undefined {\n return BY_ID.get(id);\n}\n\nexport function requireNetworkProfile(id: string, path: string): NetworkProfile {\n const profile = BY_ID.get(id);\n if (!profile) {\n throw new CommerceError(\n 'CONFIG_INVALID',\n `${path}: \"${id}\" is not a supported network. Supported CAIP-2 identifiers: ${SUPPORTED_NETWORK_IDS.join(', ')}`,\n { details: { path, network: id } },\n );\n }\n return profile;\n}\n\n/**\n * What this deployment actually is, as opposed to what it is called.\n *\n * `local` is a property of the *facilitator*, not the network: settling\n * through the in-process facilitator against a dev node is local regardless of\n * the CAIP-2 id that node answers to. This distinction is the whole reason\n * diagnostics can say `eip155:84532` without claiming to be on public Base\n * Sepolia.\n */\nexport type DeploymentMode = 'local' | 'testnet' | 'mainnet';\n\nexport function resolveDeploymentMode(\n profile: NetworkProfile,\n facilitatorMode: 'local' | 'remote',\n): DeploymentMode {\n if (facilitatorMode === 'local') return 'local';\n return profile.kind;\n}\n\n/** The banner an operator must not be able to miss. Never printed for anything else. */\nexport const LIVE_MAINNET_BANNER = 'LIVE MAINNET MODE — REAL FUNDS';\n\nexport function describeDeploymentMode(mode: DeploymentMode): string {\n return mode === 'mainnet' ? LIVE_MAINNET_BANNER : mode.toUpperCase();\n}\n","/**\n * Anvil's well-known development accounts.\n *\n * LOCAL DEVELOPMENT ONLY — DO NOT FUND. These addresses and private keys are\n * derived from Foundry's public, well-documented default test mnemonic\n * (\"test test test test test test test test test test test junk\") and are\n * known to everyone who has ever run `anvil`. Anyone who sends real value to\n * one of these addresses on a real network will lose it.\n *\n * Index layout used by the local demo chain (see docs/contracts.md):\n * 0 — deployer / local facilitator signer (pays gas, broadcasts settlement)\n * 1 — merchant settlement destination (`payTo`)\n * 2 — buyer (signs EIP-3009 authorisations; never held by the gateway)\n */\nexport interface AnvilWellKnownAccount {\n readonly address: `0x${string}`;\n readonly privateKey: `0x${string}`;\n}\n\n/** Fixed-length tuple (not a bare array) so indexing by the documented layout above is fully typed. */\nexport const ANVIL_WELL_KNOWN_ACCOUNTS: readonly [\n AnvilWellKnownAccount,\n AnvilWellKnownAccount,\n AnvilWellKnownAccount,\n] = [\n {\n address: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',\n privateKey: '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',\n },\n {\n address: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',\n privateKey: '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d',\n },\n {\n address: '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',\n privateKey: '0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a',\n },\n];\n\nexport const LOCAL_FACILITATOR_ACCOUNT = ANVIL_WELL_KNOWN_ACCOUNTS[0];\nexport const LOCAL_MERCHANT_ACCOUNT = ANVIL_WELL_KNOWN_ACCOUNTS[1];\nexport const LOCAL_BUYER_ACCOUNT = ANVIL_WELL_KNOWN_ACCOUNTS[2];\n\n/** Safe label used everywhere a dev key appears in output, logs or manifests. */\nexport const DEV_KEY_LABEL = 'LOCAL DEVELOPMENT ONLY - DO NOT FUND';\n","/**\n * Prevents a well-known Anvil development private key — or a well-known\n * Anvil development *address* — from ever being used against anything other\n * than a loopback/private/dev RPC. Two symmetric mistakes, both covered:\n * signing settlement with a dev key (`assertDevKeyIsLocalOnly`), and routing\n * settlement revenue to a dev address (`assertPayToIsNotDevAddress`). The\n * second is the more consequential of the two — a wrong key merely fails to\n * sign, a wrong payTo silently succeeds and gives the money away, since the\n * private key behind every well-known Anvil address is public knowledge.\n *\n * Chain id alone cannot tell a real network from this project's local dev\n * chain: Base Sepolia's own chain id is 84532, the same id this project\n * deliberately reuses for the local chain so the unmodified x402 SDK can talk\n * to it. A dev key or dev payTo pointed at a real RPC by a config mistake is\n * instantly drainable — this is checked once at provider construction, not per\n * payment.\n */\nimport { CommerceError } from '../../core/index.js';\nimport { ANVIL_WELL_KNOWN_ACCOUNTS } from './local-chain/accounts.js';\n\nconst WELL_KNOWN_DEV_KEYS: ReadonlySet<string> = new Set(\n ANVIL_WELL_KNOWN_ACCOUNTS.map((a) => a.privateKey.toLowerCase()),\n);\n\nconst WELL_KNOWN_DEV_ADDRESSES: ReadonlySet<string> = new Set(\n ANVIL_WELL_KNOWN_ACCOUNTS.map((a) => a.address.toLowerCase()),\n);\n\n/** `0x` + 64 hex chars — the only shape `privateKeyToAccount` accepts. */\nconst PRIVATE_KEY_SHAPE = /^0x[0-9a-fA-F]{64}$/;\n\nexport function isWellKnownDevKey(privateKey: string): boolean {\n return WELL_KNOWN_DEV_KEYS.has(privateKey.toLowerCase());\n}\n\nexport function isWellKnownDevAddress(address: string): boolean {\n return WELL_KNOWN_DEV_ADDRESSES.has(address.toLowerCase());\n}\n\n/**\n * True for loopback addresses, RFC1918 private ranges, and bare (dot-free)\n * hostnames — the shape of a docker-compose/k8s service name (e.g.\n * \"anvil\"), which a real public DNS name essentially never has.\n *\n * ASSUMPTION, and the loosest edge of this guard: every dot-free, colon-free\n * hostname is treated as private, with no exceptions. A single-label *public* hostname (no dots) is\n * essentially nonexistent in practice — ICANN does not delegate bare\n * gTLDs/TLDs as public A/AAAA records — but this function cannot tell \"no\n * dots because it's a compose service name\" from \"no dots because it's an\n * unusual real host\" if one somehow existed. If that assumption ever stops\n * holding, this is the line to revisit.\n */\nexport function isLikelyLocalOrPrivateHost(hostname: string): boolean {\n const h = hostname.toLowerCase().replace(/^\\[|\\]$/g, '');\n if (h === 'localhost' || h === '127.0.0.1' || h === '::1') return true;\n if (/^127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/.test(h)) return true;\n if (/^10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/.test(h)) return true;\n if (/^192\\.168\\.\\d{1,3}\\.\\d{1,3}$/.test(h)) return true;\n if (/^172\\.(1[6-9]|2\\d|3[01])\\.\\d{1,3}\\.\\d{1,3}$/.test(h)) return true;\n if (!h.includes('.') && !h.includes(':')) return true; // bare hostname\n return false;\n}\n\nfunction parseHostnameOrThrow(rpcUrl: string): string {\n try {\n return new URL(rpcUrl).hostname;\n } catch (cause) {\n // Not the URL itself: every commercial EVM RPC provider embeds an API key\n // in the path, and these messages reach `validate`, `doctor`, startup\n // output and CI logs.\n throw new CommerceError('CONFIG_INVALID', 'x402 provider: rpcUrl is not a valid URL', {\n cause,\n });\n }\n}\n\n/** Host only, for diagnostics. An RPC URL's path routinely carries a key. */\nfunction describeRpc(rpcUrl: string): string {\n try {\n return new URL(rpcUrl).origin;\n } catch {\n return '[unparseable rpcUrl]';\n }\n}\n\n/**\n * Throws CONFIG_INVALID if a well-known dev key would sign against a non-local\n * RPC — or if `signerPrivateKey` isn't shaped like a private key at all.\n *\n * The shape check runs first and unconditionally. \"Not a key I recognise\"\n * (falls through `isWellKnownDevKey`, silently treated as someone's own real\n * facilitator key) and \"not a key at all\" (e.g. a truncated 63-char string)\n * must never share a code path: a malformed key that slips past this guard\n * only fails later, inside `settle()`, after the buyer's replayKey is already\n * reserved.\n */\nexport function assertDevKeyIsLocalOnly(rpcUrl: string, signerPrivateKey: string): void {\n if (!PRIVATE_KEY_SHAPE.test(signerPrivateKey)) {\n throw new CommerceError(\n 'CONFIG_INVALID',\n 'x402 provider: facilitator.signerPrivateKey is not a well-formed private key ' +\n '(expected \"0x\" followed by exactly 64 hex characters).',\n );\n }\n\n if (!isWellKnownDevKey(signerPrivateKey)) return; // a real facilitator key: not our business\n\n const hostname = parseHostnameOrThrow(rpcUrl);\n\n if (!isLikelyLocalOrPrivateHost(hostname)) {\n throw new CommerceError(\n 'CONFIG_INVALID',\n 'x402 provider: facilitator.signerPrivateKey is a well-known Anvil development key, but rpcUrl ' +\n `${describeRpc(rpcUrl)} does not look like a local/private chain. A public dev key must never sign against ` +\n 'a public network — it is instantly drainable and can grief real settlements via nonce exhaustion. ' +\n 'Use a real facilitator key for any non-local RPC, or point rpcUrl at your local/dev chain.',\n );\n }\n}\n\n/**\n * Throws CONFIG_INVALID if `payTo` (the settlement destination) is a\n * well-known Anvil development address and `rpcUrl` doesn't look\n * local/private.\n *\n * Mirrors `assertDevKeyIsLocalOnly`, but guards the *receiving* side of the\n * payment instead of the signing side, and — unlike the key guard — applies\n * regardless of facilitator mode: which account signs the settlement\n * transaction has no bearing on whether the destination address is one whose\n * private key is public knowledge. `agent-commerce init` defaults `payTo` to\n * a well-known Anvil address as a local-demo convenience; on a real network\n * that default routes every payment to an address anyone on earth can sweep.\n */\nexport function assertPayToIsNotDevAddress(rpcUrl: string, payTo: string): void {\n if (!isWellKnownDevAddress(payTo)) return; // not a dev address: not our business\n\n const hostname = parseHostnameOrThrow(rpcUrl);\n\n if (!isLikelyLocalOrPrivateHost(hostname)) {\n throw new CommerceError(\n 'CONFIG_INVALID',\n `x402 provider: \"payTo\" (${payTo}) is a well-known Anvil development address, but rpcUrl ` +\n `${describeRpc(rpcUrl)} does not look like a local/private chain. The private key behind that address ` +\n 'is public knowledge, so any revenue settled to it is immediately spendable by anyone. Set ' +\n '\"payTo\" to your own merchant wallet for any non-local RPC, or point rpcUrl at your ' +\n 'local/dev chain.',\n );\n }\n}\n","/**\n * Everything that must be true before this gateway is allowed to settle a\n * payment on the configured network.\n *\n * One definition, two callers: the provider runs it at construction so a\n * library consumer who never touches our config loader still gets the checks,\n * and `doctor` runs it against the parsed config so an operator sees the same\n * verdict without starting the gateway. Sharing a *call* is not sharing a\n * definition — the checks live here, and nothing re-implements them.\n *\n * Every failure is a startup failure. None of these are request-time\n * decisions: a deployment that is unsafe is unsafe before the first buyer\n * arrives, and finding out during `settle()` means the buyer's authorisation\n * is already burned.\n *\n * Peer-free by construction (no viem, no `@x402/*`) so the CLI can import it.\n */\nimport { CommerceError } from '../../core/index.js';\nimport { isLikelyLocalOrPrivateHost, isWellKnownDevAddress } from './dev-key-guard.js';\nimport {\n type DeploymentMode,\n type NetworkProfile,\n requireNetworkProfile,\n resolveDeploymentMode,\n} from './networks.js';\n\n/**\n * How the gateway authenticates to a remote facilitator.\n *\n * Deliberately a list, not a vendor: x402 facilitators are not a Coinbase-only\n * category, and a scheme that only fitted one vendor's credentials would make\n * the abstraction a fiction.\n *\n * - `none` — the facilitator takes no credential (the public testnet one).\n * - `bearer` — a static token. Covers most self-hosted and third-party\n * facilitators, and needs nothing installed.\n * - `cdp` — Coinbase Developer Platform, which signs a fresh JWT per request\n * over method + host + path, so a static header cannot express it. Handled by\n * the optional peer `@coinbase/x402`, imported only when this type is\n * configured. Anyone not using CDP never installs it.\n *\n * A facilitator whose scheme is none of these is refused at config load rather\n * than sent nothing.\n */\nexport type FacilitatorAuth =\n | { readonly type: 'none' }\n | { readonly type: 'bearer'; readonly token: string }\n | { readonly type: 'cdp'; readonly apiKeyId: string; readonly apiKeySecret: string };\n\nexport type X402FacilitatorConfig =\n | { readonly mode: 'local'; readonly signerPrivateKey: string }\n | { readonly mode: 'remote'; readonly url: string; readonly auth: FacilitatorAuth };\n\nexport interface X402DeploymentInput {\n readonly network: string;\n readonly payTo: string;\n readonly asset: string;\n /** EIP-712 domain of the asset, as the token itself reports it. */\n readonly assetName?: string;\n readonly assetVersion?: string;\n readonly facilitator: X402FacilitatorConfig;\n /** Required, and required to be `true`, before anything settles on a mainnet. */\n readonly allowMainnet?: boolean;\n /**\n * Required, and required to be `true`, to settle on a mainnet through a\n * facilitator that takes no credential.\n *\n * Separate from `allowMainnet` because it names a different decision: not\n * \"I meant to use real money\" but \"I accept this particular counterparty\n * without an account, terms, or anyone to call\".\n */\n readonly allowUnauthenticatedFacilitator?: boolean;\n}\n\nexport interface X402Deployment {\n readonly profile: NetworkProfile;\n readonly mode: DeploymentMode;\n}\n\nfunction invalid(message: string, path: string): CommerceError {\n return new CommerceError('CONFIG_INVALID', message, { details: { path } });\n}\n\n/**\n * Resolves the deployment and refuses every combination that could move real\n * money by accident. Order matters only in that the network must resolve\n * first; the rest are independent.\n */\nexport function resolveX402Deployment(input: X402DeploymentInput): X402Deployment {\n const profile = requireNetworkProfile(input.network, 'payments.x402.network');\n const mode = resolveDeploymentMode(profile, input.facilitator.mode);\n\n // The in-process facilitator signs with a key this process holds. Not a\n // custody problem — that signer never holds buyer or merchant funds, it pays\n // gas and broadcasts `transferWithAuthorization`, and the money moves buyer\n // to merchant directly on-chain. What it *is*, on a mainnet, is a funded key\n // inside the resource server: compromise that process and an attacker drains\n // the gas wallet and broadcasts from it. Separate processes, separate blast\n // radius — so it is refused, not warned about.\n if (profile.kind === 'mainnet' && input.facilitator.mode === 'local') {\n throw invalid(\n `payments.x402: network \"${profile.id}\" (${profile.displayName}) is a mainnet and cannot be served by facilitator.mode \"local\". A mainnet deployment must settle through a remote facilitator.`,\n 'payments.x402.facilitator.mode',\n );\n }\n\n if (mode === 'mainnet' && input.allowMainnet !== true) {\n throw invalid(\n `payments.x402: network \"${profile.id}\" (${profile.displayName}) settles real funds. Set payments.x402.allowMainnet: true to acknowledge this explicitly — it is never the default.`,\n 'payments.x402.allowMainnet',\n );\n }\n\n if (input.facilitator.mode === 'remote') {\n assertFacilitatorUrlIsSafe(input.facilitator.url, mode);\n // Not a funds check. An EIP-3009 authorisation names its recipient, its\n // amount and its chain, so a facilitator can broadcast exactly that\n // transfer or nothing — it cannot redirect the money. What a credential\n // buys is a *relationship*: rate limits, terms, someone to call when\n // settlement stops. Running production payments through a counterparty you\n // have none of that with is a real choice, and this is where it gets made\n // explicitly rather than by omission.\n if (\n mode === 'mainnet' &&\n input.facilitator.auth.type === 'none' &&\n input.allowUnauthenticatedFacilitator !== true\n ) {\n throw invalid(\n `payments.x402: facilitator ${describeOrigin(input.facilitator.url)} takes no credential, and this is a mainnet deployment. It will see every payment authorisation you handle, with no account, terms or support behind it. Set payments.x402.allowUnauthenticatedFacilitator: true to accept that, or configure facilitator.auth.`,\n 'payments.x402.allowUnauthenticatedFacilitator',\n );\n }\n // An empty credential is refused rather than sent: a blank token or key\n // reaches the facilitator as \"unauthenticated\" and fails every payment\n // after the buyer has already signed. `${VAR:- }` resolving to whitespace\n // is the realistic way this happens.\n for (const [field, value] of credentialFields(input.facilitator.auth)) {\n if (value.trim() === '') {\n throw invalid(\n `payments.x402: facilitator.auth.type is \"${input.facilitator.auth.type}\" but ${field} is empty. An empty credential is refused rather than sent.`,\n `payments.x402.facilitator.auth.${field}`,\n );\n }\n }\n }\n\n // The private key behind every well-known Anvil address is public knowledge.\n // `dev-key-guard` already refuses one against a public *RPC*; this refuses\n // one on any non-local *deployment*, which is the case a remote facilitator\n // creates — there the RPC host says nothing about where settlement lands.\n // The zero address lived only in the config loader, so a library consumer\n // calling `createX402PaymentProvider` directly — the path this shared\n // definition exists to cover — could boot a mainnet provider whose every\n // payment burns — sharing a *call* is not sharing a definition, and this\n // check had drifted out of the shared one.\n if (/^0x0{40}$/i.test(input.payTo)) {\n throw invalid(\n 'payments.x402: \"payTo\" is the zero address. Every payment settled there is destroyed.',\n 'payments.x402.payTo',\n );\n }\n\n if (mode !== 'local' && isWellKnownDevAddress(input.payTo)) {\n throw invalid(\n `payments.x402: \"payTo\" (${input.payTo}) is a well-known Anvil development address and this is a ${mode} deployment. Anyone can spend what settles there. Set payTo to your own merchant wallet.`,\n 'payments.x402.payTo',\n );\n }\n\n // Mainnet only. A testnet is exactly where pointing at a mock token is the\n // right thing to do, so the same check there would block the normal case.\n const canonical = profile.canonicalAsset;\n if (mode === 'mainnet' && canonical) {\n if (!sameAddress(input.asset, canonical.address)) {\n throw invalid(\n `payments.x402: asset ${input.asset} is not ${canonical.symbol} on ${profile.displayName} (expected ${canonical.address}). Settling a mainnet payment in an unintended token is refused.`,\n 'payments.x402.asset',\n );\n }\n // The EIP-712 domain is signed by the buyer and checked by the scheme. Get\n // it wrong and every payment is refused `invalid_exact_evm_token_name_mismatch`\n // *after* the buyer signed — a config error charged to the buyer's patience.\n // Caught here instead, before the gateway starts.\n if (input.assetName !== undefined && input.assetName !== canonical.name) {\n throw invalid(\n `payments.x402: assetName \"${input.assetName}\" is not the EIP-712 domain name ${canonical.symbol} reports on ${profile.displayName} (expected \"${canonical.name}\"). Every payment would be refused after the buyer signed.`,\n 'payments.x402.assetName',\n );\n }\n if (input.assetVersion !== undefined && input.assetVersion !== canonical.version) {\n throw invalid(\n `payments.x402: assetVersion \"${input.assetVersion}\" is not the EIP-712 domain version ${canonical.symbol} reports on ${profile.displayName} (expected \"${canonical.version}\").`,\n 'payments.x402.assetVersion',\n );\n }\n }\n\n return { profile, mode };\n}\n\n/**\n * A facilitator sees every payment authorisation this gateway handles. Plain\n * HTTP to one on a public network puts those on the wire in the clear and\n * lets anyone in the path rewrite a settlement result, so it is allowed only\n * where the endpoint cannot leave the host — a local or private address.\n */\nfunction assertFacilitatorUrlIsSafe(url: string, mode: DeploymentMode): void {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch (cause) {\n throw new CommerceError('CONFIG_INVALID', `payments.x402: facilitator.url is not a valid URL`, {\n cause,\n details: { path: 'payments.x402.facilitator.url' },\n });\n }\n\n if (parsed.protocol === 'https:') return;\n if (parsed.protocol !== 'http:') {\n throw invalid(\n `payments.x402: facilitator ${describeOrigin(url)} must be reached over https (or http on a local/private host); got \"${parsed.protocol}//\"`,\n 'payments.x402.facilitator.url',\n );\n }\n if (mode !== 'mainnet' && isLikelyLocalOrPrivateHost(parsed.hostname)) return;\n\n // The origin, never the whole URL: the path can carry a tenant or an API\n // key, which is why `/.well-known` withholds this field entirely. A refusal\n // message goes to `validate`, `doctor`, startup output and CI logs.\n throw invalid(\n `payments.x402: facilitator ${describeOrigin(url)} is reached over plain HTTP. Payment authorisations and settlement results would travel unencrypted. Use https, or point at a local/private host on a non-mainnet deployment.`,\n 'payments.x402.facilitator.url',\n );\n}\n\n/** Host only — a facilitator URL can carry a tenant path or an API key. */\nfunction describeOrigin(url: string): string {\n try {\n return new URL(url).origin;\n } catch {\n return '[unparseable facilitator.url]';\n }\n}\n\n/** The secret-bearing fields of an auth block, for emptiness checks only. Never logged. */\nfunction credentialFields(auth: FacilitatorAuth): readonly (readonly [string, string])[] {\n switch (auth.type) {\n case 'bearer':\n return [['token', auth.token]];\n case 'cdp':\n return [\n ['apiKeyId', auth.apiKeyId],\n ['apiKeySecret', auth.apiKeySecret],\n ];\n default:\n return [];\n }\n}\n\nfunction sameAddress(a: string, b: string): boolean {\n return a.toLowerCase() === b.toLowerCase();\n}\n"]}