@agent-score/commerce 2.3.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/challenge/index.d.mts +9 -5
- package/dist/challenge/index.d.ts +9 -5
- package/dist/challenge/index.js +11 -4
- package/dist/challenge/index.js.map +1 -1
- package/dist/challenge/index.mjs +11 -4
- package/dist/challenge/index.mjs.map +1 -1
- package/dist/{checkout-ChyOi7aU.d.ts → checkout-McfNpZJf.d.ts} +80 -12
- package/dist/{checkout-Ceo1_rVJ.d.mts → checkout-o17dIxHi.d.mts} +80 -12
- package/dist/core.d.mts +27 -7
- package/dist/core.d.ts +27 -7
- package/dist/core.js +25 -11
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +25 -11
- package/dist/core.mjs.map +1 -1
- package/dist/discovery/index.d.mts +26 -10
- package/dist/discovery/index.d.ts +26 -10
- package/dist/discovery/index.js +58 -10
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/index.mjs +58 -10
- package/dist/discovery/index.mjs.map +1 -1
- package/dist/gate-CWP10xPQ.d.mts +339 -0
- package/dist/gate-CWP10xPQ.d.ts +339 -0
- package/dist/identity/express.d.mts +26 -1
- package/dist/identity/express.d.ts +26 -1
- package/dist/identity/express.js +599 -25
- package/dist/identity/express.js.map +1 -1
- package/dist/identity/express.mjs +595 -24
- package/dist/identity/express.mjs.map +1 -1
- package/dist/identity/fastify.d.mts +12 -2
- package/dist/identity/fastify.d.ts +12 -2
- package/dist/identity/fastify.js +607 -25
- package/dist/identity/fastify.js.map +1 -1
- package/dist/identity/fastify.mjs +603 -24
- package/dist/identity/fastify.mjs.map +1 -1
- package/dist/identity/hono.d.mts +26 -1
- package/dist/identity/hono.d.ts +26 -1
- package/dist/identity/hono.js +588 -25
- package/dist/identity/hono.js.map +1 -1
- package/dist/identity/hono.mjs +584 -24
- package/dist/identity/hono.mjs.map +1 -1
- package/dist/identity/nextjs.d.mts +3 -0
- package/dist/identity/nextjs.d.ts +3 -0
- package/dist/identity/nextjs.js +593 -25
- package/dist/identity/nextjs.js.map +1 -1
- package/dist/identity/nextjs.mjs +589 -24
- package/dist/identity/nextjs.mjs.map +1 -1
- package/dist/identity/policy.js.map +1 -1
- package/dist/identity/policy.mjs.map +1 -1
- package/dist/identity/web.d.mts +24 -1
- package/dist/identity/web.d.ts +24 -1
- package/dist/identity/web.js +593 -25
- package/dist/identity/web.js.map +1 -1
- package/dist/identity/web.mjs +589 -24
- package/dist/identity/web.mjs.map +1 -1
- package/dist/index.d.mts +129 -14
- package/dist/index.d.ts +129 -14
- package/dist/index.js +978 -99
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +956 -99
- package/dist/index.mjs.map +1 -1
- package/dist/{default_rails-DtR_E9N9.d.ts → network_kind-BIJM2peR.d.ts} +22 -8
- package/dist/{default_rails-K25PtWrL.d.mts → network_kind-C0EMkdzz.d.mts} +22 -8
- package/dist/payment/index.d.mts +16 -26
- package/dist/payment/index.d.ts +16 -26
- package/dist/payment/index.js +62 -57
- package/dist/payment/index.js.map +1 -1
- package/dist/payment/index.mjs +62 -57
- package/dist/payment/index.mjs.map +1 -1
- package/dist/{pricing-B3-aKxSz.d.ts → pricing-CytRwhC2.d.ts} +1 -1
- package/dist/{pricing-BReyZiqN.d.mts → pricing-KHDqMLd7.d.mts} +1 -1
- package/dist/{rail_spec-B1239jPp.d.mts → rail_spec-BFZmW9RN.d.mts} +3 -4
- package/dist/{rail_spec-B1239jPp.d.ts → rail_spec-BFZmW9RN.d.ts} +3 -4
- package/dist/stripe-multichain/index.d.mts +2 -9
- package/dist/stripe-multichain/index.d.ts +2 -9
- package/dist/stripe-multichain/index.js.map +1 -1
- package/dist/stripe-multichain/index.mjs.map +1 -1
- package/dist/{wwwauthenticate-D_FMnPgU.d.mts → wwwauthenticate-CVaGUMjU.d.mts} +8 -6
- package/dist/{wwwauthenticate-D_FMnPgU.d.ts → wwwauthenticate-CVaGUMjU.d.ts} +8 -6
- package/package.json +14 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/identity/policy.ts","../../src/errors.ts"],"sourcesContent":["/**\n * Per-product / per-tier compliance policy helpers.\n *\n * A *policy* is a small bag of fields describing what identity the merchant wants\n * verified for a given resource:\n *\n * - `enforcement`: `\"hard\"` (today's wine path — 403 on miss) or `\"soft\"` (gate\n * denial is swallowed; the order completes with a degraded `identity_status`).\n * `null` / absent = no gate at all.\n * - `requireKyc` / `requireSanctionsClear` / `minAge`: passed through to the\n * per-framework `agentscoreGate(...)` factory.\n * - `allowedJurisdictions`: buyer-verified country list (`[\"US\", \"CA\", ...]`).\n * - `allowedShippingCountries` / `allowedShippingStates`: optional shipping\n * allowlists. State list is only enforced for US shipments.\n *\n * This module ships three primitives:\n *\n * 1. {@link PolicyBlock} — the typed shape.\n * 2. {@link buildGateFromPolicy} — translate a block into the options object the\n * per-framework `agentscoreGate(...)` accepts. Returns `null` when the policy\n * has no enforcement (treat as \"no gate; anonymous OK\").\n * 3. {@link runGateWithEnforcement} — wrap a per-framework middleware in the\n * hard/soft enforcement runner. The middleware is given an `onDenied` shim\n * that captures the denial body and status; the runner returns a structured\n * {@link GateResult} so the vendor decides how to surface it.\n *\n * All three are additive — vendors using `agentscoreGate(...)` directly are\n * unaffected.\n */\n\nimport { CheckoutValidationError } from '../errors';\nimport type { AgentScoreCoreOptions, DenialReason } from '../core.js';\n\n/** Hard = 403 propagates; soft = swallowed + identity_status=\"unverified\". */\nexport type EnforcementMode = 'hard' | 'soft';\n\n/** Per-order trust level captured at settle time. */\nexport type IdentityStatus = 'verified' | 'unverified' | 'anonymous' | 'denied';\n\n/** Compliance fields a merchant attaches per product / per tier. All optional. */\nexport interface PolicyBlock {\n enforcement?: EnforcementMode;\n requireKyc?: boolean;\n requireSanctionsClear?: boolean;\n minAge?: number;\n allowedJurisdictions?: readonly string[];\n allowedShippingCountries?: readonly string[];\n allowedShippingStates?: readonly string[];\n}\n\n/**\n * Outcome of running a gate under an enforcement mode.\n *\n * - `verified`: gate accepted; identity is fully verified for the policy.\n * - `unverified`: soft mode swallowed a gate denial; the agent had *some*\n * identity but didn't meet the policy. Stamp this on the order so\n * ops/analytics can tell apart soft passes from hard passes.\n * - `anonymous`: no gate ran (policy was null / no enforcement).\n * - `denied`: hard mode rejected; the caller must propagate the 403. The\n * `denialBody` and `denialStatus` carry the original gate response so the\n * caller can return it as-is.\n */\nexport interface GateResult {\n status: IdentityStatus;\n denialStatus?: number;\n denialBody?: Record<string, unknown>;\n denialReason?: DenialReason;\n}\n\n/**\n * Translate a {@link PolicyBlock} into the options the per-framework\n * `agentscoreGate(...)` expects. Returns `null` when the block has no\n * `enforcement` set — the caller should treat that as \"no gate; anonymous OK\".\n *\n * Use a fresh gate per request rather than constructing once at module scope\n * when the policy varies per resource (e.g. per product). Each adapter's gate\n * is cheap to instantiate.\n */\nexport function buildGateFromPolicy(\n policy: PolicyBlock | null | undefined,\n base: { apiKey: string; baseUrl?: string },\n): AgentScoreCoreOptions | null {\n if (!policy || !policy.enforcement) return null;\n return {\n apiKey: base.apiKey,\n ...(base.baseUrl !== undefined && { baseUrl: base.baseUrl }),\n ...(policy.requireKyc !== undefined && { requireKyc: policy.requireKyc }),\n ...(policy.requireSanctionsClear !== undefined && {\n requireSanctionsClear: policy.requireSanctionsClear,\n }),\n ...(policy.minAge !== undefined && { minAge: policy.minAge }),\n ...(policy.allowedJurisdictions !== undefined && {\n allowedJurisdictions: [...policy.allowedJurisdictions],\n }),\n };\n}\n\n/**\n * Run a per-framework gate middleware respecting the enforcement mode.\n *\n * The vendor passes:\n * - `gate`: their framework's middleware (Hono `MiddlewareHandler`, Express\n * `(req, res, next) => void`, etc.) — anything that resolves on accept and\n * throws or returns a `Response` on deny.\n * - `runGate`: a thin adapter that calls the middleware with the framework\n * context and returns either `{ ok: true }` (gate accepted) or\n * `{ ok: false, status, body, reason? }` (gate denied with details).\n *\n * `runGateWithEnforcement` wraps that in the hard/soft split:\n *\n * - `gate=null` or `enforcement=null`: no gate fires; status=\"anonymous\".\n * - `enforcement=\"hard\"` + denied: status=\"denied\"; caller propagates denialStatus + denialBody.\n * - `enforcement=\"soft\"` + denied: swallow; status=\"unverified\".\n * - accepted: status=\"verified\".\n */\nexport async function runGateWithEnforcement(\n enforcement: EnforcementMode | undefined,\n runGate: (() => Promise<{ ok: true } | { ok: false; status: number; body: Record<string, unknown>; reason?: DenialReason }>) | null,\n): Promise<GateResult> {\n if (!runGate || !enforcement) return { status: 'anonymous' };\n\n const outcome = await runGate();\n if (outcome.ok) return { status: 'verified' };\n\n if (enforcement === 'hard') {\n return {\n status: 'denied',\n denialStatus: outcome.status,\n denialBody: outcome.body,\n ...(outcome.reason !== undefined && { denialReason: outcome.reason }),\n };\n }\n return {\n status: 'unverified',\n denialStatus: outcome.status,\n denialBody: outcome.body,\n ...(outcome.reason !== undefined && { denialReason: outcome.reason }),\n };\n}\n\n/** NULL policy / NULL allowlist → ship anywhere. Otherwise country must be in the list. */\nexport function shippingCountryAllowed(country: string, policy: PolicyBlock | null | undefined): boolean {\n if (!policy?.allowedShippingCountries || policy.allowedShippingCountries.length === 0) return true;\n const allowed = new Set(policy.allowedShippingCountries.map((c) => c.toUpperCase()));\n return allowed.has(country.toUpperCase());\n}\n\n/**\n * US-state allowlist (e.g. wine).\n *\n * Only enforced for US shipments — non-US shipments are governed by\n * {@link shippingCountryAllowed} independently.\n */\nexport function shippingStateAllowed(\n state: string,\n country: string,\n policy: PolicyBlock | null | undefined,\n): boolean {\n if (!policy?.allowedShippingStates || policy.allowedShippingStates.length === 0) return true;\n if (country.toUpperCase() !== 'US') return true;\n const allowed = new Set(policy.allowedShippingStates.map((s) => s.toUpperCase()));\n return allowed.has(state.toUpperCase());\n}\n\n/**\n * Throw {@link CheckoutValidationError} when shipping isn't allowed by the policy.\n *\n * One-call replacement for the\n *\n * if (!shippingCountryAllowed(...)) throw new CheckoutValidationError(...);\n * if (!shippingStateAllowed(...)) throw new CheckoutValidationError(...);\n *\n * boilerplate every goods merchant writes in their `preValidate` hook.\n *\n * `policy` is a {@link PolicyBlock} (or `null`/`undefined`); NULL policy means\n * \"ship anywhere\" and the function is a no-op. The reason a location is\n * excluded is **merchant-defined**: it might be regulatory (regulated goods\n * + state allowlist), operational (no fulfillment partner), or commercial\n * (fragility, fraud-rate-by-region, etc.) — the helper doesn't assume.\n *\n * `productName` is the user-facing item name surfaced in the error message\n * (\"Cannot ship 'Wine 2020' to NY ...\"). Omit for a generic message.\n *\n * `errorCode` and `errorAction` let merchants override the canonical denial\n * codes if their consumer agents expect different shapes.\n *\n * `countryMessage` / `stateMessage` override the default messages verbatim\n * (use these when the default phrasing isn't right for your consumer agents\n * — e.g. you want to surface the regulatory reason explicitly, or you want\n * the message in a different language).\n */\nexport function validateShippingAgainstPolicy(opts: {\n country: string;\n state: string;\n policy: PolicyBlock | null | undefined;\n productName?: string;\n errorCode?: string;\n errorAction?: string;\n countryMessage?: string;\n stateMessage?: string;\n}): void {\n const code = opts.errorCode ?? 'unsupported_jurisdiction';\n const action = opts.errorAction ?? 'change_shipping_state';\n const item = opts.productName ? `'${opts.productName}'` : 'this item';\n if (!shippingCountryAllowed(opts.country, opts.policy)) {\n throw new CheckoutValidationError({\n code,\n message:\n opts.countryMessage ??\n `We can't ship ${item} to ${opts.country.toUpperCase() || '<unset>'}.`,\n action,\n });\n }\n if (!shippingStateAllowed(opts.state, opts.country, opts.policy)) {\n throw new CheckoutValidationError({\n code,\n message:\n opts.stateMessage ??\n `We can't ship ${item} to ${opts.state.toUpperCase() || '<unset>'}.`,\n action,\n });\n }\n}\n","/**\n * Cross-module typed errors.\n *\n * Lives in its own module so `payment/` and `stripe-multichain/` helpers can\n * throw `CheckoutValidationError` without importing from `checkout.ts`. (In\n * the python sibling this avoids a checkout → payment → checkout cycle; in\n * node it sidesteps tsup's per-entry class duplication.)\n *\n * Re-exported from `checkout.ts` and the top-level entry to preserve the\n * public import path.\n */\n\n/**\n * Raised to short-circuit a Checkout flow with a 4xx/5xx envelope. The\n * framework catches this at request-flow boundaries (`preValidate`, recipient\n * minting, settlement dispatch) and emits `{ error, next_steps }` via\n * `buildValidationError` so merchants don't construct response bodies\n * themselves.\n */\nexport class CheckoutValidationError extends Error {\n readonly code: string;\n readonly action: string;\n readonly status: number;\n readonly extra: Record<string, unknown> | undefined;\n constructor(opts: {\n code: string;\n message: string;\n action?: string;\n status?: number;\n extra?: Record<string, unknown>;\n }) {\n super(opts.message);\n this.name = 'CheckoutValidationError';\n this.code = opts.code;\n this.action = opts.action ?? 'fix_request';\n this.status = opts.status ?? 400;\n this.extra = opts.extra;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACmBO,IAAM,0BAAN,cAAsC,MAAM;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT,YAAY,MAMT;AACD,UAAM,KAAK,OAAO;AAClB,SAAK,OAAO;AACZ,SAAK,OAAO,KAAK;AACjB,SAAK,SAAS,KAAK,UAAU;AAC7B,SAAK,SAAS,KAAK,UAAU;AAC7B,SAAK,QAAQ,KAAK;AAAA,EACpB;AACF;;;ADwCO,SAAS,oBACd,QACA,MAC8B;AAC9B,MAAI,CAAC,UAAU,CAAC,OAAO,YAAa,QAAO;AAC3C,SAAO;AAAA,IACL,QAAQ,KAAK;AAAA,IACb,GAAI,KAAK,YAAY,UAAa,EAAE,SAAS,KAAK,QAAQ;AAAA,IAC1D,GAAI,OAAO,eAAe,UAAa,EAAE,YAAY,OAAO,WAAW;AAAA,IACvE,GAAI,OAAO,0BAA0B,UAAa;AAAA,MAChD,uBAAuB,OAAO;AAAA,IAChC;AAAA,IACA,GAAI,OAAO,WAAW,UAAa,EAAE,QAAQ,OAAO,OAAO;AAAA,IAC3D,GAAI,OAAO,yBAAyB,UAAa;AAAA,MAC/C,sBAAsB,CAAC,GAAG,OAAO,oBAAoB;AAAA,IACvD;AAAA,EACF;AACF;AAoBA,eAAsB,uBACpB,aACA,SACqB;AACrB,MAAI,CAAC,WAAW,CAAC,YAAa,QAAO,EAAE,QAAQ,YAAY;AAE3D,QAAM,UAAU,MAAM,QAAQ;AAC9B,MAAI,QAAQ,GAAI,QAAO,EAAE,QAAQ,WAAW;AAE5C,MAAI,gBAAgB,QAAQ;AAC1B,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,cAAc,QAAQ;AAAA,MACtB,YAAY,QAAQ;AAAA,MACpB,GAAI,QAAQ,WAAW,UAAa,EAAE,cAAc,QAAQ,OAAO;AAAA,IACrE;AAAA,EACF;AACA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,cAAc,QAAQ;AAAA,IACtB,YAAY,QAAQ;AAAA,IACpB,GAAI,QAAQ,WAAW,UAAa,EAAE,cAAc,QAAQ,OAAO;AAAA,EACrE;AACF;AAGO,SAAS,uBAAuB,SAAiB,QAAiD;AACvG,MAAI,CAAC,QAAQ,4BAA4B,OAAO,yBAAyB,WAAW,EAAG,QAAO;AAC9F,QAAM,UAAU,IAAI,IAAI,OAAO,yBAAyB,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AACnF,SAAO,QAAQ,IAAI,QAAQ,YAAY,CAAC;AAC1C;AAQO,SAAS,qBACd,OACA,SACA,QACS;AACT,MAAI,CAAC,QAAQ,yBAAyB,OAAO,sBAAsB,WAAW,EAAG,QAAO;AACxF,MAAI,QAAQ,YAAY,MAAM,KAAM,QAAO;AAC3C,QAAM,UAAU,IAAI,IAAI,OAAO,sBAAsB,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAChF,SAAO,QAAQ,IAAI,MAAM,YAAY,CAAC;AACxC;AA6BO,SAAS,8BAA8B,MASrC;AACP,QAAM,OAAO,KAAK,aAAa;AAC/B,QAAM,SAAS,KAAK,eAAe;AACnC,QAAM,OAAO,KAAK,cAAc,IAAI,KAAK,WAAW,MAAM;AAC1D,MAAI,CAAC,uBAAuB,KAAK,SAAS,KAAK,MAAM,GAAG;AACtD,UAAM,IAAI,wBAAwB;AAAA,MAChC;AAAA,MACA,SACE,KAAK,kBACL,iBAAiB,IAAI,OAAO,KAAK,QAAQ,YAAY,KAAK,SAAS;AAAA,MACrE;AAAA,IACF,CAAC;AAAA,EACH;AACA,MAAI,CAAC,qBAAqB,KAAK,OAAO,KAAK,SAAS,KAAK,MAAM,GAAG;AAChE,UAAM,IAAI,wBAAwB;AAAA,MAChC;AAAA,MACA,SACE,KAAK,gBACL,iBAAiB,IAAI,OAAO,KAAK,MAAM,YAAY,KAAK,SAAS;AAAA,MACnE;AAAA,IACF,CAAC;AAAA,EACH;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/identity/policy.ts","../../src/errors.ts"],"sourcesContent":["/**\n * Per-product / per-tier compliance policy helpers.\n *\n * A *policy* is a small bag of fields describing what identity the merchant wants\n * verified for a given resource:\n *\n * - `enforcement`: `\"hard\"` (today's wine path — 403 on miss) or `\"soft\"` (gate\n * denial is swallowed; the order completes with a degraded `identity_status`).\n * `null` / absent = no gate at all.\n * - `requireKyc` / `requireSanctionsClear` / `minAge`: passed through to the\n * per-framework `agentscoreGate(...)` factory.\n * - `allowedJurisdictions`: buyer-verified country list (`[\"US\", \"CA\", ...]`).\n * - `allowedShippingCountries` / `allowedShippingStates`: optional shipping\n * allowlists. State list is only enforced for US shipments.\n *\n * This module ships three primitives:\n *\n * 1. {@link PolicyBlock} — the typed shape.\n * 2. {@link buildGateFromPolicy} — translate a block into the options object the\n * per-framework `agentscoreGate(...)` accepts. Returns `null` when the policy\n * has no enforcement (treat as \"no gate; anonymous OK\").\n * 3. {@link runGateWithEnforcement} — wrap a per-framework middleware in the\n * hard/soft enforcement runner. The middleware is given an `onDenied` shim\n * that captures the denial body and status; the runner returns a structured\n * {@link GateResult} so the vendor decides how to surface it.\n *\n * All three are additive — vendors using `agentscoreGate(...)` directly are\n * unaffected.\n */\n\nimport { CheckoutValidationError } from '../errors';\nimport type { AgentScoreCoreOptions, DenialReason } from '../core.js';\n\n/** Hard = 403 propagates; soft = swallowed + identity_status=\"unverified\". */\nexport type EnforcementMode = 'hard' | 'soft';\n\n/** Per-order trust level captured at settle time. */\nexport type IdentityStatus = 'verified' | 'unverified' | 'anonymous' | 'denied';\n\n/** Compliance fields a merchant attaches per product / per tier. All optional. */\nexport interface PolicyBlock {\n enforcement?: EnforcementMode;\n requireKyc?: boolean;\n requireSanctionsClear?: boolean;\n minAge?: number;\n allowedJurisdictions?: readonly string[];\n allowedShippingCountries?: readonly string[];\n allowedShippingStates?: readonly string[];\n}\n\n/**\n * Outcome of running a gate under an enforcement mode.\n *\n * - `verified`: gate accepted; identity is fully verified for the policy.\n * - `unverified`: soft mode swallowed a gate denial; the agent had *some*\n * identity but didn't meet the policy. Stamp this on the order so\n * ops/analytics can tell apart soft passes from hard passes.\n * - `anonymous`: no gate ran (policy was null / no enforcement).\n * - `denied`: hard mode rejected; the caller must propagate the 403. The\n * `denialBody` and `denialStatus` carry the original gate response so the\n * caller can return it as-is.\n */\nexport interface GateResult {\n status: IdentityStatus;\n denialStatus?: number;\n denialBody?: Record<string, unknown>;\n denialReason?: DenialReason;\n}\n\n/**\n * Translate a {@link PolicyBlock} into the options the per-framework\n * `agentscoreGate(...)` expects. Returns `null` when the block has no\n * `enforcement` set — the caller should treat that as \"no gate; anonymous OK\".\n *\n * Use a fresh gate per request rather than constructing once at module scope\n * when the policy varies per resource (e.g. per product). Each adapter's gate\n * is cheap to instantiate.\n */\nexport function buildGateFromPolicy(\n policy: PolicyBlock | null | undefined,\n base: { apiKey: string; baseUrl?: string },\n): AgentScoreCoreOptions | null {\n if (!policy || !policy.enforcement) return null;\n return {\n apiKey: base.apiKey,\n ...(base.baseUrl !== undefined && { baseUrl: base.baseUrl }),\n ...(policy.requireKyc !== undefined && { requireKyc: policy.requireKyc }),\n ...(policy.requireSanctionsClear !== undefined && {\n requireSanctionsClear: policy.requireSanctionsClear,\n }),\n ...(policy.minAge !== undefined && { minAge: policy.minAge }),\n ...(policy.allowedJurisdictions !== undefined && {\n allowedJurisdictions: [...policy.allowedJurisdictions],\n }),\n };\n}\n\n/**\n * Run a per-framework gate middleware respecting the enforcement mode.\n *\n * The vendor passes:\n * - `gate`: their framework's middleware (Hono `MiddlewareHandler`, Express\n * `(req, res, next) => void`, etc.) — anything that resolves on accept and\n * throws or returns a `Response` on deny.\n * - `runGate`: a thin adapter that calls the middleware with the framework\n * context and returns either `{ ok: true }` (gate accepted) or\n * `{ ok: false, status, body, reason? }` (gate denied with details).\n *\n * `runGateWithEnforcement` wraps that in the hard/soft split:\n *\n * - `gate=null` or `enforcement=null`: no gate fires; status=\"anonymous\".\n * - `enforcement=\"hard\"` + denied: status=\"denied\"; caller propagates denialStatus + denialBody.\n * - `enforcement=\"soft\"` + denied: swallow; status=\"unverified\".\n * - accepted: status=\"verified\".\n */\nexport async function runGateWithEnforcement(\n enforcement: EnforcementMode | undefined,\n runGate: (() => Promise<{ ok: true } | { ok: false; status: number; body: Record<string, unknown>; reason?: DenialReason }>) | null,\n): Promise<GateResult> {\n if (!runGate || !enforcement) return { status: 'anonymous' };\n\n const outcome = await runGate();\n if (outcome.ok) return { status: 'verified' };\n\n if (enforcement === 'hard') {\n return {\n status: 'denied',\n denialStatus: outcome.status,\n denialBody: outcome.body,\n ...(outcome.reason !== undefined && { denialReason: outcome.reason }),\n };\n }\n return {\n status: 'unverified',\n denialStatus: outcome.status,\n denialBody: outcome.body,\n ...(outcome.reason !== undefined && { denialReason: outcome.reason }),\n };\n}\n\n/** NULL policy / NULL allowlist → ship anywhere. Otherwise country must be in the list. */\nexport function shippingCountryAllowed(country: string, policy: PolicyBlock | null | undefined): boolean {\n if (!policy?.allowedShippingCountries || policy.allowedShippingCountries.length === 0) return true;\n const allowed = new Set(policy.allowedShippingCountries.map((c) => c.toUpperCase()));\n return allowed.has(country.toUpperCase());\n}\n\n/**\n * US-state allowlist (e.g. wine).\n *\n * Only enforced for US shipments — non-US shipments are governed by\n * {@link shippingCountryAllowed} independently.\n */\nexport function shippingStateAllowed(\n state: string,\n country: string,\n policy: PolicyBlock | null | undefined,\n): boolean {\n if (!policy?.allowedShippingStates || policy.allowedShippingStates.length === 0) return true;\n if (country.toUpperCase() !== 'US') return true;\n const allowed = new Set(policy.allowedShippingStates.map((s) => s.toUpperCase()));\n return allowed.has(state.toUpperCase());\n}\n\n/**\n * Throw {@link CheckoutValidationError} when shipping isn't allowed by the policy.\n *\n * One-call replacement for the\n *\n * if (!shippingCountryAllowed(...)) throw new CheckoutValidationError(...);\n * if (!shippingStateAllowed(...)) throw new CheckoutValidationError(...);\n *\n * boilerplate every goods merchant writes in their `preValidate` hook.\n *\n * `policy` is a {@link PolicyBlock} (or `null`/`undefined`); NULL policy means\n * \"ship anywhere\" and the function is a no-op. The reason a location is\n * excluded is **merchant-defined**: it might be regulatory (regulated goods\n * + state allowlist), operational (no fulfillment partner), or commercial\n * (fragility, fraud-rate-by-region, etc.) — the helper doesn't assume.\n *\n * `productName` is the user-facing item name surfaced in the error message\n * (\"Cannot ship 'Wine 2020' to NY ...\"). Omit for a generic message.\n *\n * `errorCode` and `errorAction` let merchants override the canonical denial\n * codes if their consumer agents expect different shapes.\n *\n * `countryMessage` / `stateMessage` override the default messages verbatim\n * (use these when the default phrasing isn't right for your consumer agents\n * — e.g. you want to surface the regulatory reason explicitly, or you want\n * the message in a different language).\n */\nexport function validateShippingAgainstPolicy(opts: {\n country: string;\n state: string;\n policy: PolicyBlock | null | undefined;\n productName?: string;\n errorCode?: string;\n errorAction?: string;\n countryMessage?: string;\n stateMessage?: string;\n}): void {\n const code = opts.errorCode ?? 'unsupported_jurisdiction';\n const action = opts.errorAction ?? 'change_shipping_state';\n const item = opts.productName ? `'${opts.productName}'` : 'this item';\n if (!shippingCountryAllowed(opts.country, opts.policy)) {\n throw new CheckoutValidationError({\n code,\n message:\n opts.countryMessage ??\n `We can't ship ${item} to ${opts.country.toUpperCase() || '<unset>'}.`,\n action,\n });\n }\n if (!shippingStateAllowed(opts.state, opts.country, opts.policy)) {\n throw new CheckoutValidationError({\n code,\n message:\n opts.stateMessage ??\n `We can't ship ${item} to ${opts.state.toUpperCase() || '<unset>'}.`,\n action,\n });\n }\n}\n","/**\n * Cross-module typed errors.\n *\n * Lives in its own module so `payment/` and `stripe-multichain/` helpers can\n * throw `CheckoutValidationError` without importing from `checkout.ts` — this\n * also sidesteps tsup's per-entry class duplication.\n *\n * Re-exported from `checkout.ts` and the top-level entry to preserve the\n * public import path.\n */\n\n/**\n * Raised to short-circuit a Checkout flow with a 4xx/5xx envelope. The\n * framework catches this at request-flow boundaries (`preValidate`, recipient\n * minting, settlement dispatch) and emits `{ error, next_steps }` via\n * `buildValidationError` so merchants don't construct response bodies\n * themselves.\n */\nexport class CheckoutValidationError extends Error {\n readonly code: string;\n readonly action: string;\n readonly status: number;\n readonly extra: Record<string, unknown> | undefined;\n constructor(opts: {\n code: string;\n message: string;\n action?: string;\n status?: number;\n extra?: Record<string, unknown>;\n }) {\n super(opts.message);\n this.name = 'CheckoutValidationError';\n this.code = opts.code;\n this.action = opts.action ?? 'fix_request';\n this.status = opts.status ?? 400;\n this.extra = opts.extra;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/errors.ts","../../src/identity/policy.ts"],"sourcesContent":["/**\n * Cross-module typed errors.\n *\n * Lives in its own module so `payment/` and `stripe-multichain/` helpers can\n * throw `CheckoutValidationError` without importing from `checkout.ts`. (In\n * the python sibling this avoids a checkout → payment → checkout cycle; in\n * node it sidesteps tsup's per-entry class duplication.)\n *\n * Re-exported from `checkout.ts` and the top-level entry to preserve the\n * public import path.\n */\n\n/**\n * Raised to short-circuit a Checkout flow with a 4xx/5xx envelope. The\n * framework catches this at request-flow boundaries (`preValidate`, recipient\n * minting, settlement dispatch) and emits `{ error, next_steps }` via\n * `buildValidationError` so merchants don't construct response bodies\n * themselves.\n */\nexport class CheckoutValidationError extends Error {\n readonly code: string;\n readonly action: string;\n readonly status: number;\n readonly extra: Record<string, unknown> | undefined;\n constructor(opts: {\n code: string;\n message: string;\n action?: string;\n status?: number;\n extra?: Record<string, unknown>;\n }) {\n super(opts.message);\n this.name = 'CheckoutValidationError';\n this.code = opts.code;\n this.action = opts.action ?? 'fix_request';\n this.status = opts.status ?? 400;\n this.extra = opts.extra;\n }\n}\n","/**\n * Per-product / per-tier compliance policy helpers.\n *\n * A *policy* is a small bag of fields describing what identity the merchant wants\n * verified for a given resource:\n *\n * - `enforcement`: `\"hard\"` (today's wine path — 403 on miss) or `\"soft\"` (gate\n * denial is swallowed; the order completes with a degraded `identity_status`).\n * `null` / absent = no gate at all.\n * - `requireKyc` / `requireSanctionsClear` / `minAge`: passed through to the\n * per-framework `agentscoreGate(...)` factory.\n * - `allowedJurisdictions`: buyer-verified country list (`[\"US\", \"CA\", ...]`).\n * - `allowedShippingCountries` / `allowedShippingStates`: optional shipping\n * allowlists. State list is only enforced for US shipments.\n *\n * This module ships three primitives:\n *\n * 1. {@link PolicyBlock} — the typed shape.\n * 2. {@link buildGateFromPolicy} — translate a block into the options object the\n * per-framework `agentscoreGate(...)` accepts. Returns `null` when the policy\n * has no enforcement (treat as \"no gate; anonymous OK\").\n * 3. {@link runGateWithEnforcement} — wrap a per-framework middleware in the\n * hard/soft enforcement runner. The middleware is given an `onDenied` shim\n * that captures the denial body and status; the runner returns a structured\n * {@link GateResult} so the vendor decides how to surface it.\n *\n * All three are additive — vendors using `agentscoreGate(...)` directly are\n * unaffected.\n */\n\nimport { CheckoutValidationError } from '../errors';\nimport type { AgentScoreCoreOptions, DenialReason } from '../core.js';\n\n/** Hard = 403 propagates; soft = swallowed + identity_status=\"unverified\". */\nexport type EnforcementMode = 'hard' | 'soft';\n\n/** Per-order trust level captured at settle time. */\nexport type IdentityStatus = 'verified' | 'unverified' | 'anonymous' | 'denied';\n\n/** Compliance fields a merchant attaches per product / per tier. All optional. */\nexport interface PolicyBlock {\n enforcement?: EnforcementMode;\n requireKyc?: boolean;\n requireSanctionsClear?: boolean;\n minAge?: number;\n allowedJurisdictions?: readonly string[];\n allowedShippingCountries?: readonly string[];\n allowedShippingStates?: readonly string[];\n}\n\n/**\n * Outcome of running a gate under an enforcement mode.\n *\n * - `verified`: gate accepted; identity is fully verified for the policy.\n * - `unverified`: soft mode swallowed a gate denial; the agent had *some*\n * identity but didn't meet the policy. Stamp this on the order so\n * ops/analytics can tell apart soft passes from hard passes.\n * - `anonymous`: no gate ran (policy was null / no enforcement).\n * - `denied`: hard mode rejected; the caller must propagate the 403. The\n * `denialBody` and `denialStatus` carry the original gate response so the\n * caller can return it as-is.\n */\nexport interface GateResult {\n status: IdentityStatus;\n denialStatus?: number;\n denialBody?: Record<string, unknown>;\n denialReason?: DenialReason;\n}\n\n/**\n * Translate a {@link PolicyBlock} into the options the per-framework\n * `agentscoreGate(...)` expects. Returns `null` when the block has no\n * `enforcement` set — the caller should treat that as \"no gate; anonymous OK\".\n *\n * Use a fresh gate per request rather than constructing once at module scope\n * when the policy varies per resource (e.g. per product). Each adapter's gate\n * is cheap to instantiate.\n */\nexport function buildGateFromPolicy(\n policy: PolicyBlock | null | undefined,\n base: { apiKey: string; baseUrl?: string },\n): AgentScoreCoreOptions | null {\n if (!policy || !policy.enforcement) return null;\n return {\n apiKey: base.apiKey,\n ...(base.baseUrl !== undefined && { baseUrl: base.baseUrl }),\n ...(policy.requireKyc !== undefined && { requireKyc: policy.requireKyc }),\n ...(policy.requireSanctionsClear !== undefined && {\n requireSanctionsClear: policy.requireSanctionsClear,\n }),\n ...(policy.minAge !== undefined && { minAge: policy.minAge }),\n ...(policy.allowedJurisdictions !== undefined && {\n allowedJurisdictions: [...policy.allowedJurisdictions],\n }),\n };\n}\n\n/**\n * Run a per-framework gate middleware respecting the enforcement mode.\n *\n * The vendor passes:\n * - `gate`: their framework's middleware (Hono `MiddlewareHandler`, Express\n * `(req, res, next) => void`, etc.) — anything that resolves on accept and\n * throws or returns a `Response` on deny.\n * - `runGate`: a thin adapter that calls the middleware with the framework\n * context and returns either `{ ok: true }` (gate accepted) or\n * `{ ok: false, status, body, reason? }` (gate denied with details).\n *\n * `runGateWithEnforcement` wraps that in the hard/soft split:\n *\n * - `gate=null` or `enforcement=null`: no gate fires; status=\"anonymous\".\n * - `enforcement=\"hard\"` + denied: status=\"denied\"; caller propagates denialStatus + denialBody.\n * - `enforcement=\"soft\"` + denied: swallow; status=\"unverified\".\n * - accepted: status=\"verified\".\n */\nexport async function runGateWithEnforcement(\n enforcement: EnforcementMode | undefined,\n runGate: (() => Promise<{ ok: true } | { ok: false; status: number; body: Record<string, unknown>; reason?: DenialReason }>) | null,\n): Promise<GateResult> {\n if (!runGate || !enforcement) return { status: 'anonymous' };\n\n const outcome = await runGate();\n if (outcome.ok) return { status: 'verified' };\n\n if (enforcement === 'hard') {\n return {\n status: 'denied',\n denialStatus: outcome.status,\n denialBody: outcome.body,\n ...(outcome.reason !== undefined && { denialReason: outcome.reason }),\n };\n }\n return {\n status: 'unverified',\n denialStatus: outcome.status,\n denialBody: outcome.body,\n ...(outcome.reason !== undefined && { denialReason: outcome.reason }),\n };\n}\n\n/** NULL policy / NULL allowlist → ship anywhere. Otherwise country must be in the list. */\nexport function shippingCountryAllowed(country: string, policy: PolicyBlock | null | undefined): boolean {\n if (!policy?.allowedShippingCountries || policy.allowedShippingCountries.length === 0) return true;\n const allowed = new Set(policy.allowedShippingCountries.map((c) => c.toUpperCase()));\n return allowed.has(country.toUpperCase());\n}\n\n/**\n * US-state allowlist (e.g. wine).\n *\n * Only enforced for US shipments — non-US shipments are governed by\n * {@link shippingCountryAllowed} independently.\n */\nexport function shippingStateAllowed(\n state: string,\n country: string,\n policy: PolicyBlock | null | undefined,\n): boolean {\n if (!policy?.allowedShippingStates || policy.allowedShippingStates.length === 0) return true;\n if (country.toUpperCase() !== 'US') return true;\n const allowed = new Set(policy.allowedShippingStates.map((s) => s.toUpperCase()));\n return allowed.has(state.toUpperCase());\n}\n\n/**\n * Throw {@link CheckoutValidationError} when shipping isn't allowed by the policy.\n *\n * One-call replacement for the\n *\n * if (!shippingCountryAllowed(...)) throw new CheckoutValidationError(...);\n * if (!shippingStateAllowed(...)) throw new CheckoutValidationError(...);\n *\n * boilerplate every goods merchant writes in their `preValidate` hook.\n *\n * `policy` is a {@link PolicyBlock} (or `null`/`undefined`); NULL policy means\n * \"ship anywhere\" and the function is a no-op. The reason a location is\n * excluded is **merchant-defined**: it might be regulatory (regulated goods\n * + state allowlist), operational (no fulfillment partner), or commercial\n * (fragility, fraud-rate-by-region, etc.) — the helper doesn't assume.\n *\n * `productName` is the user-facing item name surfaced in the error message\n * (\"Cannot ship 'Wine 2020' to NY ...\"). Omit for a generic message.\n *\n * `errorCode` and `errorAction` let merchants override the canonical denial\n * codes if their consumer agents expect different shapes.\n *\n * `countryMessage` / `stateMessage` override the default messages verbatim\n * (use these when the default phrasing isn't right for your consumer agents\n * — e.g. you want to surface the regulatory reason explicitly, or you want\n * the message in a different language).\n */\nexport function validateShippingAgainstPolicy(opts: {\n country: string;\n state: string;\n policy: PolicyBlock | null | undefined;\n productName?: string;\n errorCode?: string;\n errorAction?: string;\n countryMessage?: string;\n stateMessage?: string;\n}): void {\n const code = opts.errorCode ?? 'unsupported_jurisdiction';\n const action = opts.errorAction ?? 'change_shipping_state';\n const item = opts.productName ? `'${opts.productName}'` : 'this item';\n if (!shippingCountryAllowed(opts.country, opts.policy)) {\n throw new CheckoutValidationError({\n code,\n message:\n opts.countryMessage ??\n `We can't ship ${item} to ${opts.country.toUpperCase() || '<unset>'}.`,\n action,\n });\n }\n if (!shippingStateAllowed(opts.state, opts.country, opts.policy)) {\n throw new CheckoutValidationError({\n code,\n message:\n opts.stateMessage ??\n `We can't ship ${item} to ${opts.state.toUpperCase() || '<unset>'}.`,\n action,\n });\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/errors.ts","../../src/identity/policy.ts"],"sourcesContent":["/**\n * Cross-module typed errors.\n *\n * Lives in its own module so `payment/` and `stripe-multichain/` helpers can\n * throw `CheckoutValidationError` without importing from `checkout.ts` — this\n * also sidesteps tsup's per-entry class duplication.\n *\n * Re-exported from `checkout.ts` and the top-level entry to preserve the\n * public import path.\n */\n\n/**\n * Raised to short-circuit a Checkout flow with a 4xx/5xx envelope. The\n * framework catches this at request-flow boundaries (`preValidate`, recipient\n * minting, settlement dispatch) and emits `{ error, next_steps }` via\n * `buildValidationError` so merchants don't construct response bodies\n * themselves.\n */\nexport class CheckoutValidationError extends Error {\n readonly code: string;\n readonly action: string;\n readonly status: number;\n readonly extra: Record<string, unknown> | undefined;\n constructor(opts: {\n code: string;\n message: string;\n action?: string;\n status?: number;\n extra?: Record<string, unknown>;\n }) {\n super(opts.message);\n this.name = 'CheckoutValidationError';\n this.code = opts.code;\n this.action = opts.action ?? 'fix_request';\n this.status = opts.status ?? 400;\n this.extra = opts.extra;\n }\n}\n","/**\n * Per-product / per-tier compliance policy helpers.\n *\n * A *policy* is a small bag of fields describing what identity the merchant wants\n * verified for a given resource:\n *\n * - `enforcement`: `\"hard\"` (today's wine path — 403 on miss) or `\"soft\"` (gate\n * denial is swallowed; the order completes with a degraded `identity_status`).\n * `null` / absent = no gate at all.\n * - `requireKyc` / `requireSanctionsClear` / `minAge`: passed through to the\n * per-framework `agentscoreGate(...)` factory.\n * - `allowedJurisdictions`: buyer-verified country list (`[\"US\", \"CA\", ...]`).\n * - `allowedShippingCountries` / `allowedShippingStates`: optional shipping\n * allowlists. State list is only enforced for US shipments.\n *\n * This module ships three primitives:\n *\n * 1. {@link PolicyBlock} — the typed shape.\n * 2. {@link buildGateFromPolicy} — translate a block into the options object the\n * per-framework `agentscoreGate(...)` accepts. Returns `null` when the policy\n * has no enforcement (treat as \"no gate; anonymous OK\").\n * 3. {@link runGateWithEnforcement} — wrap a per-framework middleware in the\n * hard/soft enforcement runner. The middleware is given an `onDenied` shim\n * that captures the denial body and status; the runner returns a structured\n * {@link GateResult} so the vendor decides how to surface it.\n *\n * All three are additive — vendors using `agentscoreGate(...)` directly are\n * unaffected.\n */\n\nimport { CheckoutValidationError } from '../errors';\nimport type { AgentScoreCoreOptions, DenialReason } from '../core.js';\n\n/** Hard = 403 propagates; soft = swallowed + identity_status=\"unverified\". */\nexport type EnforcementMode = 'hard' | 'soft';\n\n/** Per-order trust level captured at settle time. */\nexport type IdentityStatus = 'verified' | 'unverified' | 'anonymous' | 'denied';\n\n/** Compliance fields a merchant attaches per product / per tier. All optional. */\nexport interface PolicyBlock {\n enforcement?: EnforcementMode;\n requireKyc?: boolean;\n requireSanctionsClear?: boolean;\n minAge?: number;\n allowedJurisdictions?: readonly string[];\n allowedShippingCountries?: readonly string[];\n allowedShippingStates?: readonly string[];\n}\n\n/**\n * Outcome of running a gate under an enforcement mode.\n *\n * - `verified`: gate accepted; identity is fully verified for the policy.\n * - `unverified`: soft mode swallowed a gate denial; the agent had *some*\n * identity but didn't meet the policy. Stamp this on the order so\n * ops/analytics can tell apart soft passes from hard passes.\n * - `anonymous`: no gate ran (policy was null / no enforcement).\n * - `denied`: hard mode rejected; the caller must propagate the 403. The\n * `denialBody` and `denialStatus` carry the original gate response so the\n * caller can return it as-is.\n */\nexport interface GateResult {\n status: IdentityStatus;\n denialStatus?: number;\n denialBody?: Record<string, unknown>;\n denialReason?: DenialReason;\n}\n\n/**\n * Translate a {@link PolicyBlock} into the options the per-framework\n * `agentscoreGate(...)` expects. Returns `null` when the block has no\n * `enforcement` set — the caller should treat that as \"no gate; anonymous OK\".\n *\n * Use a fresh gate per request rather than constructing once at module scope\n * when the policy varies per resource (e.g. per product). Each adapter's gate\n * is cheap to instantiate.\n */\nexport function buildGateFromPolicy(\n policy: PolicyBlock | null | undefined,\n base: { apiKey: string; baseUrl?: string },\n): AgentScoreCoreOptions | null {\n if (!policy || !policy.enforcement) return null;\n return {\n apiKey: base.apiKey,\n ...(base.baseUrl !== undefined && { baseUrl: base.baseUrl }),\n ...(policy.requireKyc !== undefined && { requireKyc: policy.requireKyc }),\n ...(policy.requireSanctionsClear !== undefined && {\n requireSanctionsClear: policy.requireSanctionsClear,\n }),\n ...(policy.minAge !== undefined && { minAge: policy.minAge }),\n ...(policy.allowedJurisdictions !== undefined && {\n allowedJurisdictions: [...policy.allowedJurisdictions],\n }),\n };\n}\n\n/**\n * Run a per-framework gate middleware respecting the enforcement mode.\n *\n * The vendor passes:\n * - `gate`: their framework's middleware (Hono `MiddlewareHandler`, Express\n * `(req, res, next) => void`, etc.) — anything that resolves on accept and\n * throws or returns a `Response` on deny.\n * - `runGate`: a thin adapter that calls the middleware with the framework\n * context and returns either `{ ok: true }` (gate accepted) or\n * `{ ok: false, status, body, reason? }` (gate denied with details).\n *\n * `runGateWithEnforcement` wraps that in the hard/soft split:\n *\n * - `gate=null` or `enforcement=null`: no gate fires; status=\"anonymous\".\n * - `enforcement=\"hard\"` + denied: status=\"denied\"; caller propagates denialStatus + denialBody.\n * - `enforcement=\"soft\"` + denied: swallow; status=\"unverified\".\n * - accepted: status=\"verified\".\n */\nexport async function runGateWithEnforcement(\n enforcement: EnforcementMode | undefined,\n runGate: (() => Promise<{ ok: true } | { ok: false; status: number; body: Record<string, unknown>; reason?: DenialReason }>) | null,\n): Promise<GateResult> {\n if (!runGate || !enforcement) return { status: 'anonymous' };\n\n const outcome = await runGate();\n if (outcome.ok) return { status: 'verified' };\n\n if (enforcement === 'hard') {\n return {\n status: 'denied',\n denialStatus: outcome.status,\n denialBody: outcome.body,\n ...(outcome.reason !== undefined && { denialReason: outcome.reason }),\n };\n }\n return {\n status: 'unverified',\n denialStatus: outcome.status,\n denialBody: outcome.body,\n ...(outcome.reason !== undefined && { denialReason: outcome.reason }),\n };\n}\n\n/** NULL policy / NULL allowlist → ship anywhere. Otherwise country must be in the list. */\nexport function shippingCountryAllowed(country: string, policy: PolicyBlock | null | undefined): boolean {\n if (!policy?.allowedShippingCountries || policy.allowedShippingCountries.length === 0) return true;\n const allowed = new Set(policy.allowedShippingCountries.map((c) => c.toUpperCase()));\n return allowed.has(country.toUpperCase());\n}\n\n/**\n * US-state allowlist (e.g. wine).\n *\n * Only enforced for US shipments — non-US shipments are governed by\n * {@link shippingCountryAllowed} independently.\n */\nexport function shippingStateAllowed(\n state: string,\n country: string,\n policy: PolicyBlock | null | undefined,\n): boolean {\n if (!policy?.allowedShippingStates || policy.allowedShippingStates.length === 0) return true;\n if (country.toUpperCase() !== 'US') return true;\n const allowed = new Set(policy.allowedShippingStates.map((s) => s.toUpperCase()));\n return allowed.has(state.toUpperCase());\n}\n\n/**\n * Throw {@link CheckoutValidationError} when shipping isn't allowed by the policy.\n *\n * One-call replacement for the\n *\n * if (!shippingCountryAllowed(...)) throw new CheckoutValidationError(...);\n * if (!shippingStateAllowed(...)) throw new CheckoutValidationError(...);\n *\n * boilerplate every goods merchant writes in their `preValidate` hook.\n *\n * `policy` is a {@link PolicyBlock} (or `null`/`undefined`); NULL policy means\n * \"ship anywhere\" and the function is a no-op. The reason a location is\n * excluded is **merchant-defined**: it might be regulatory (regulated goods\n * + state allowlist), operational (no fulfillment partner), or commercial\n * (fragility, fraud-rate-by-region, etc.) — the helper doesn't assume.\n *\n * `productName` is the user-facing item name surfaced in the error message\n * (\"Cannot ship 'Wine 2020' to NY ...\"). Omit for a generic message.\n *\n * `errorCode` and `errorAction` let merchants override the canonical denial\n * codes if their consumer agents expect different shapes.\n *\n * `countryMessage` / `stateMessage` override the default messages verbatim\n * (use these when the default phrasing isn't right for your consumer agents\n * — e.g. you want to surface the regulatory reason explicitly, or you want\n * the message in a different language).\n */\nexport function validateShippingAgainstPolicy(opts: {\n country: string;\n state: string;\n policy: PolicyBlock | null | undefined;\n productName?: string;\n errorCode?: string;\n errorAction?: string;\n countryMessage?: string;\n stateMessage?: string;\n}): void {\n const code = opts.errorCode ?? 'unsupported_jurisdiction';\n const action = opts.errorAction ?? 'change_shipping_state';\n const item = opts.productName ? `'${opts.productName}'` : 'this item';\n if (!shippingCountryAllowed(opts.country, opts.policy)) {\n throw new CheckoutValidationError({\n code,\n message:\n opts.countryMessage ??\n `We can't ship ${item} to ${opts.country.toUpperCase() || '<unset>'}.`,\n action,\n });\n }\n if (!shippingStateAllowed(opts.state, opts.country, opts.policy)) {\n throw new CheckoutValidationError({\n code,\n message:\n opts.stateMessage ??\n `We can't ship ${item} to ${opts.state.toUpperCase() || '<unset>'}.`,\n action,\n });\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/identity/web.d.mts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { b as AipGateOptions, r as buildAipErrorBody, V as VerifiedAit } from '../gate-CWP10xPQ.mjs';
|
|
1
2
|
import { AgentScoreCoreOptions, AgentIdentity, DenialReason, CreateSessionOnMissing, AssessResult, SignerVerdict, FailOpenInfraReason, GateQuotaInfo } from '../core.mjs';
|
|
3
|
+
import 'jose';
|
|
2
4
|
import '../signer-3FAit11j.mjs';
|
|
3
5
|
|
|
4
6
|
interface AgentScoreGateOptions extends Omit<AgentScoreCoreOptions, 'createSessionOnMissing'> {
|
|
@@ -96,5 +98,26 @@ declare function createConditionalAgentScoreGate(options: AgentScoreGateOptions)
|
|
|
96
98
|
/** Wrapper variant matching `withAgentScoreGate(opts, handler)` that only
|
|
97
99
|
* invokes the gate when a payment credential is attached. */
|
|
98
100
|
declare function withConditionalAgentScoreGate<TCtx = unknown>(options: AgentScoreGateOptions, handler: Parameters<typeof withAgentScoreGate<TCtx>>[1]): (req: Request, ctx: TCtx) => Promise<Response>;
|
|
101
|
+
type AipGuardResult = {
|
|
102
|
+
allowed: true;
|
|
103
|
+
ait: VerifiedAit;
|
|
104
|
+
} | {
|
|
105
|
+
allowed: false;
|
|
106
|
+
response: Response;
|
|
107
|
+
};
|
|
108
|
+
interface AipGateWebOptions extends AipGateOptions {
|
|
109
|
+
/** Custom denial responder. Defaults to a 401/403 `application/problem+json` Response. */
|
|
110
|
+
onDenied?: (req: Request, body: ReturnType<typeof buildAipErrorBody>) => Response | Promise<Response>;
|
|
111
|
+
}
|
|
112
|
+
/** Create a Web Fetch AIP guard: returns `{ allowed, ait }` or `{ allowed: false, response }`. */
|
|
113
|
+
declare function createAipGate(options: AipGateWebOptions): (req: Request) => Promise<AipGuardResult>;
|
|
114
|
+
/** Wrap a Web Fetch handler with the AIP gate. Denied requests return the problem+json Response. */
|
|
115
|
+
declare function withAipGate<TCtx = unknown>(options: AipGateWebOptions, handler: (req: Request, gate: {
|
|
116
|
+
ait: VerifiedAit;
|
|
117
|
+
}, ctx?: TCtx) => Response | Promise<Response>): (req: Request, ctx?: TCtx) => Promise<Response>;
|
|
118
|
+
/** Conditional variant: only runs the AIP gate when an `Agent-Identity` header is present. */
|
|
119
|
+
declare function withConditionalAipGate<TCtx = unknown>(options: AipGateWebOptions, handler: (req: Request, gate: {
|
|
120
|
+
ait?: VerifiedAit;
|
|
121
|
+
}, ctx?: TCtx) => Response | Promise<Response>): (req: Request, ctx?: TCtx) => Promise<Response>;
|
|
99
122
|
|
|
100
|
-
export { type GuardResult, createAgentScoreGate, createConditionalAgentScoreGate, withAgentScoreGate, withConditionalAgentScoreGate };
|
|
123
|
+
export { type AipGateWebOptions, type AipGuardResult, type GuardResult, createAgentScoreGate, createAipGate, createConditionalAgentScoreGate, withAgentScoreGate, withAipGate, withConditionalAgentScoreGate, withConditionalAipGate };
|
package/dist/identity/web.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { b as AipGateOptions, r as buildAipErrorBody, V as VerifiedAit } from '../gate-CWP10xPQ.js';
|
|
1
2
|
import { AgentScoreCoreOptions, AgentIdentity, DenialReason, CreateSessionOnMissing, AssessResult, SignerVerdict, FailOpenInfraReason, GateQuotaInfo } from '../core.js';
|
|
3
|
+
import 'jose';
|
|
2
4
|
import '../signer-3FAit11j.js';
|
|
3
5
|
|
|
4
6
|
interface AgentScoreGateOptions extends Omit<AgentScoreCoreOptions, 'createSessionOnMissing'> {
|
|
@@ -96,5 +98,26 @@ declare function createConditionalAgentScoreGate(options: AgentScoreGateOptions)
|
|
|
96
98
|
/** Wrapper variant matching `withAgentScoreGate(opts, handler)` that only
|
|
97
99
|
* invokes the gate when a payment credential is attached. */
|
|
98
100
|
declare function withConditionalAgentScoreGate<TCtx = unknown>(options: AgentScoreGateOptions, handler: Parameters<typeof withAgentScoreGate<TCtx>>[1]): (req: Request, ctx: TCtx) => Promise<Response>;
|
|
101
|
+
type AipGuardResult = {
|
|
102
|
+
allowed: true;
|
|
103
|
+
ait: VerifiedAit;
|
|
104
|
+
} | {
|
|
105
|
+
allowed: false;
|
|
106
|
+
response: Response;
|
|
107
|
+
};
|
|
108
|
+
interface AipGateWebOptions extends AipGateOptions {
|
|
109
|
+
/** Custom denial responder. Defaults to a 401/403 `application/problem+json` Response. */
|
|
110
|
+
onDenied?: (req: Request, body: ReturnType<typeof buildAipErrorBody>) => Response | Promise<Response>;
|
|
111
|
+
}
|
|
112
|
+
/** Create a Web Fetch AIP guard: returns `{ allowed, ait }` or `{ allowed: false, response }`. */
|
|
113
|
+
declare function createAipGate(options: AipGateWebOptions): (req: Request) => Promise<AipGuardResult>;
|
|
114
|
+
/** Wrap a Web Fetch handler with the AIP gate. Denied requests return the problem+json Response. */
|
|
115
|
+
declare function withAipGate<TCtx = unknown>(options: AipGateWebOptions, handler: (req: Request, gate: {
|
|
116
|
+
ait: VerifiedAit;
|
|
117
|
+
}, ctx?: TCtx) => Response | Promise<Response>): (req: Request, ctx?: TCtx) => Promise<Response>;
|
|
118
|
+
/** Conditional variant: only runs the AIP gate when an `Agent-Identity` header is present. */
|
|
119
|
+
declare function withConditionalAipGate<TCtx = unknown>(options: AipGateWebOptions, handler: (req: Request, gate: {
|
|
120
|
+
ait?: VerifiedAit;
|
|
121
|
+
}, ctx?: TCtx) => Response | Promise<Response>): (req: Request, ctx?: TCtx) => Promise<Response>;
|
|
99
122
|
|
|
100
|
-
export { type GuardResult, createAgentScoreGate, createConditionalAgentScoreGate, withAgentScoreGate, withConditionalAgentScoreGate };
|
|
123
|
+
export { type AipGateWebOptions, type AipGuardResult, type GuardResult, createAgentScoreGate, createAipGate, createConditionalAgentScoreGate, withAgentScoreGate, withAipGate, withConditionalAgentScoreGate, withConditionalAipGate };
|