Skip to content

Commit 911b9a2

Browse files
committed
Fix docs: buildGateFromPolicy name, drop non-existent ReceiptNextSteps, correct file paths
- /identity/policy helper is buildGateFromPolicy, not buildGateOptionsFromPolicy (README, CLAUDE, examples) - /challenge exports only Receipt; ReceiptNextSteps does not exist (examples) - CLAUDE.md file refs: src/address.ts and src/_response.ts (not under src/identity/)
1 parent c6ebf55 commit 911b9a2

3 files changed

Lines changed: 7 additions & 7 deletions

File tree

CLAUDE.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Every helper is extracted from a real consumer, not speculated.
1010
|---|---|
1111
| `@agent-score/commerce` (top-level) | `Checkout` orchestrator (the 2.0 high-level surface) for fixed-price one-shot endpoints: one config object + hooks (preValidate, computePricing, mintRecipients, composeMppx, onSettled, gate), auto-derived x402+mppx servers, per-framework adapters `handleHono`/`handleExpress`/`handleFastify`/`handleNextjs`/`handleWeb`, signed UCP routes via `mountUcpRoutes{Hono,Express,Fastify}`, optional `discoveryProbe` config for x402-crawler auto-routing. Plus `computeFirstCheckout` — variable-cost pay-per-result helper (compute-first + exact-x402). Scope is exact-mode rails only (x402-exact Base, tempo/charge, solana/charge, Stripe SPT); does NOT use x402-upto (Permit2) or Settlement-Overrides — variable cost is captured by running the work pre-settle and emitting a 402 at the exact computed price. `createQuoteCache` — content-hash quote cache used by the compute-first helper (in-memory by default; pass `redisUrl` for distributed deployments). `createDefaultOnDenied` — canonical `onDenied(reason)` factory matching `Checkout`'s gate hook (handles `wallet_signer_mismatch`, `wallet_not_trusted` unfixable fallback, `payment_required`, `token_expired`/`invalid_credential`/`api_error`); merchants pass `merchantName` + `supportEmail` and override `walletNotTrustedMessage` / `paymentRequiredMessage` / `supportContext` for vendor-specific copy. `hasPaymentHeader` — discriminator that splits discovery legs (no payment credential → 402) from settle legs (`payment-signature` / `x-payment` / `Authorization: Payment <jwt>`); `hasX402Header` / `hasMppxHeader` — granular dispatch helpers (x402 vs MPP credential present) for routes that branch on rail. `defaultReadOnlyOnDenied(reason)` — canonical `onDenied` for read-only resource gates (`GET /orders/:id`): collapses every denial to 401 `unauthorized` + `Cache-Control: no-store` while still spreading `denialReasonToBody` so `agent_instructions` / `verify_url` ride through. `extractOwnerScope(headers) → { walletAddress?, operatorTokenHash? }` — pull canonical owner identity from `X-Wallet-Address` / `X-Operator-Token` with safe token hashing; pair with a wallet-or-token-scoped resource query so plaintext tokens never leave the request. Plus factories: `pricingResult` (cents → typed PricingResult with optional `decimals` for sub-cent precision), `validationResponse{Hono,Express,Fastify,Nextjs,Web}` (4xx envelope per framework) |
1212
| `@agent-score/commerce/identity/{hono,express,fastify,nextjs,web}` | Trust gate middleware (KYC, age, sanctions, jurisdiction). Each adapter exports a `conditionalAgentscoreGate(options)` variant (Next.js / Web Fetch use the wrapper form `withConditionalAgentScoreGate(opts, handler)` / `createConditionalAgentScoreGate(opts) => guard(req)`) that fires only on settle legs — discovery legs (no payment credential) flow through and the handler emits a 402 with all rails. Adapters export ONLY framework-specific surface (gate fns, accessors, `captureWallet`); shared helpers like `hasPaymentHeader` / `denialReasonToBody` import from their canonical home (`@agent-score/commerce/payment` and `@agent-score/commerce` respectively). |
13-
| `@agent-score/commerce/identity/policy` | Framework-agnostic per-product / per-tier compliance policy helpers: `PolicyBlock`, `buildGateOptionsFromPolicy`, `runGateWithEnforcement`, `shippingCountryAllowed`, `shippingStateAllowed`, `validateShippingAgainstPolicy` (one-call country+state validator that raises `CheckoutValidationError` with the canonical envelope on miss) |
13+
| `@agent-score/commerce/identity/policy` | Framework-agnostic per-product / per-tier compliance policy helpers: `PolicyBlock`, `buildGateFromPolicy`, `runGateWithEnforcement`, `shippingCountryAllowed`, `shippingStateAllowed`, `validateShippingAgainstPolicy` (one-call country+state validator that raises `CheckoutValidationError` with the canonical envelope on miss) |
1414
| `@agent-score/commerce/payment` | Networks/USDC/rails registries, paymentauth.org directive builders, `createX402Server` (peer-dep `@x402/core` + `@coinbase/x402` for the Coinbase facilitator), `buildX402AcceptsFor402` (one-call helper for the 402-emit path: builds the requirements via the registered scheme so `extra.name` matches the on-chain USDC contract per network), `buildDefaultCheckoutRails({tempo?, x402Base?, solanaMpp?, stripe?})` (canonical 4-rail `rails` dict factory: merchants pass per-rail overrides instead of redeclaring the recipient sentinel + network/chainId/token boilerplate. When a caller overrides `network` without pinning `token` / `chainId`, the helper derives them from the network: Base Sepolia → Sepolia USDC + chainId 84532, Solana devnet → devnet USDC mint. Explicit overrides always win. Solana's `network` field accepts both CAIP-2 (`solana:5eykt4UsFv8…` / `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1`) AND the raw `@solana/mpp` form (`mainnet-beta` / `devnet` / `localnet`)), `buildMppxComposeRails({amountUsd, tempoRecipient?, solanaRecipient?, ...})` (per-call intent factory replacing the hand-rolled `[['tempo/charge',{...}],['solana/charge',{...}],['stripe/charge',{...}]]` array; auto-handles USD→atomic conversion for Solana; auto-drops the `stripe/charge` rail with a one-time `console.warn` when `amountUsd < 0.50` since Stripe's fixed ~$0.30 fee makes sub-50-cent charges unprofitable — many Stripe accounts also reject PI creation below the floor with `amount_too_small`; sub-50-cent APIs pass `includeStripe: false` explicitly to silence the warning), `createMppxServer` (peer-dep `mppx`; the solana rail's `ataCreationRequired` defaults to `true` so Solana settles work zero-config on `@solana/mpp >= 0.6.0` — the SDK propagates it as a self-referential split so the validator's `allowedAtaOwners` accepts the configured recipient; opt out only when every recipient's ATA pre-exists out-of-band), `composeMppxRequest` (typed wrapper around `mppx.compose(...intents)(request)`; replaces the `(mppx as any).compose(...)` cast in custom `composeMppx` hooks), `mppxChallengeHeaders` (one-call extractor for the 402 path's `Object.fromEntries(challenge.headers)`), `processX402Settle` (verify+settle in one call), `isEvmNetwork`/`isSolanaNetwork` (CAIP-2 discriminators that hide the `startsWith('eip155:')` / `startsWith('solana:')` prefix matching), dispatch-by-network, signer extraction, WWW-Authenticate header, Settlement-Overrides header |
1515
| `@agent-score/commerce/discovery` | Discovery probe middleware (`isDiscoveryProbeRequest`, `buildDiscoveryProbeResponse`), Bazaar wrapper, `/.well-known/mpp.json` builder, `llms.txt` builder, `skill.md` builder (Claude-Skill-compatible agent-discovery manifest), `buildRedemptionSkillMd` (delivery-neutral; printed/emailed/API-trial codes all covered via `deliveryIntro`/`bodyShape`/`bodyRules`/`extraRecoveryRows` overrides), `buildMerchantIndexJson` + `standardEndpointDescriptions({kind})` (canonical `/` discovery body for goods or API merchants), `buildSuccessNextSteps` (universal Passport-active success block), `buildAgentscoreOnboardingSteps`, OpenAPI snippets, `noindexNonDiscoveryPaths` Hono middleware. Plus the UCP/JWKS publish surface: `buildSignedUcpResponse`, `buildSignedJwksResponse`, `wellKnownPreflightResponse`, `defaultA2aServices`, `bootstrapUcpSigningKey`, framework-neutral `SignedDiscoveryResponse` + per-framework wrappers `signedResponse{Hono,Express,Fastify,Nextjs,Web}` |
1616
| `@agent-score/commerce/challenge` | 402-body builders: accepted_methods, identity metadata (auto-attached by `Checkout` when wallet header present), how_to_pay, agent_instructions, build402Body, pricing, agent_memory, `buildValidationError` (4xx body builder), `Receipt` (canonical 200-receipt shape) |
@@ -48,7 +48,7 @@ Peer-dep pattern: payment/x402/mppx/stripe modules `dynamic import` at runtime,
4848
| `stripe-multichain-merchant.ts` | Stripe-anchored multichain (PaymentIntent → tempo/base/solana deposit addresses) |
4949
| `compute-first-merchant.ts` | Pay-per-result variable-cost merchant via the compute-first + exact-x402 helper (`computeFirstCheckout`). Exact-mode rails only (x402-exact Base, tempo/charge, solana/charge, Stripe SPT); deliberately scoped out of x402-upto (Permit2) and Settlement-Overrides. Probe runs the work + caches by body content-hash; settle replays the cached result at the computed exact price. Pairs with `rateLimitHono` since the probe leg runs work pre-payment. |
5050
| `compliance-merchant.ts` | Regulated-goods merchant: full compliance gate + custom `onDenied` composing the denial helpers (`verificationAgentInstructions`, `isFixableDenial`, `buildSignerMismatchBody`, `buildContactSupportNextSteps`, `denialReasonToBody`/`denialReasonStatus`) |
51-
| `per-product-policy-merchant.ts` | Multi-product merchant where each product carries its own compliance policy: wine has hard gate (KYC + 21 + state allowlist), tee has none (anonymous), limited print uses `enforcement: 'soft'` (request KYC, accept anonymous, stamp `identity_status: 'unverified'`). Demonstrates `PolicyBlock`, `buildGateOptionsFromPolicy`, `runGateWithEnforcement`, `shippingCountryAllowed`, `shippingStateAllowed`. |
51+
| `per-product-policy-merchant.ts` | Multi-product merchant where each product carries its own compliance policy: wine has hard gate (KYC + 21 + state allowlist), tee has none (anonymous), limited print uses `enforcement: 'soft'` (request KYC, accept anonymous, stamp `identity_status: 'unverified'`). Demonstrates `PolicyBlock`, `buildGateFromPolicy`, `runGateWithEnforcement`, `shippingCountryAllowed`, `shippingStateAllowed`. |
5252
| `signed-ucp-merchant.ts` | Signed UCP profile (`/.well-known/ucp`) + JWKS endpoint (`/.well-known/jwks.json`). AgentScore's `agentscore-profile+jws` is a vendor extension on top of UCP for trust-mode verifiers (regulated-commerce, AP2-aware) that opt into auditable cryptographic provenance — UCP §6 itself does NOT mandate signing; production UCP merchants commonly ship unsigned. Wires ephemeral-for-dev / env-JWK-for-prod signing, kid rotation, and `Cache-Control` posture. Uses `generateUCPSigningKey`, `signUCPProfile`, `buildJWKSResponse`, `UCPSigningKey.fromJWK`, `UCPVerificationError`. Demonstrates the payment-handler builders (`mppPaymentHandler`, `x402PaymentHandler`, `stripeSptPaymentHandler` — see "Payment-handler builders" below). |
5353

5454
## Payment-handler builders
@@ -72,9 +72,9 @@ Each helper returns `{ [reverse-DNS-key]: [binding] }` so spreading composes the
7272

7373
## Identity model
7474

75-
Two identity types: wallet (`X-Wallet-Address`) and operator-token (`X-Operator-Token`). Default checks operator-token first, then wallet. Address normalization is network-aware via `src/identity/address.ts`: EVM lowercased, Solana base58 preserved verbatim. Used for cache keys, wallet→operator resolves, and signer-match comparisons.
75+
Two identity types: wallet (`X-Wallet-Address`) and operator-token (`X-Operator-Token`). Default checks operator-token first, then wallet. Address normalization is network-aware via `src/address.ts`: EVM lowercased, Solana base58 preserved verbatim. Used for cache keys, wallet→operator resolves, and signer-match comparisons.
7676

77-
Denial reason codes: `missing_identity`, `identity_verification_required`, `token_expired`, `invalid_credential`, `wallet_signer_mismatch`, `wallet_auth_requires_wallet_signing`, `wallet_not_trusted`, `api_error`, `payment_required`. Each carries a structured `agent_instructions` JSON block describing concrete recovery actions. See `src/identity/_response.ts` and `src/core.ts` for the canned action copy.
77+
Denial reason codes: `missing_identity`, `identity_verification_required`, `token_expired`, `invalid_credential`, `wallet_signer_mismatch`, `wallet_auth_requires_wallet_signing`, `wallet_not_trusted`, `api_error`, `payment_required`. Each carries a structured `agent_instructions` JSON block describing concrete recovery actions. See `src/_response.ts` and `src/core.ts` for the canned action copy.
7878

7979
`createSessionOnMissing` auto-mints a verification session when no identity is present AND when `wallet_not_trusted` carries fixable reasons (`kyc_required` / `kyc_pending` / `kyc_failed`) — both paths rewrite the denial to `identity_verification_required` before reaching `onDenied`, so merchants only need to handle one code. When the merchant omits `createSessionOnMissing` from the gate config, `Checkout` auto-defaults it from `gate.apiKey` + `gate.baseUrl` + `gate.context` + `gate.merchantName` — every gated route gets the bootstrap UX out of the box. Merchants that need per-request session context or `onBeforeSession` side effects (goods merchants pre-minting an order_id) supply their own config to override.
8080

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ npm install hono mppx @x402/core @x402/evm @solana/mpp @solana/kit stripe # wh
2424
| Subpath | What it provides |
2525
|---|---|
2626
| `/identity/{hono,express,fastify}` | Trust gate middleware: KYC, sanctions (account name + signer wallet), age, jurisdiction. Context-getter pattern: `agentscoreGate(opts)` middleware + `getAgentScoreData(ctx)` / `getGateDegradedState(ctx)` / `getGateQuotaInfo(ctx)` / `getSignerVerdict(ctx)` accessors, `captureWallet(...)`. The denial helpers (`denialReasonStatus`, `denialReasonToBody`, `buildSignerMismatchBody`, `buildContactSupportNextSteps`, `verificationAgentInstructions`, `isFixableDenial`, `FIXABLE_DENIAL_REASONS`) are exported from the top-level `@agent-score/commerce`, not the adapters. |
27-
| `/identity/policy` | Per-product compliance helpers for multi-product merchants (each product carries its own policy: hard gate vs soft vs none, per-product shipping allowlists): `PolicyBlock`, `GateResult`, `EnforcementMode`, `IdentityStatus`, `buildGateOptionsFromPolicy`, `runGateWithEnforcement`, `shippingCountryAllowed`, `shippingStateAllowed`, `validateShippingAgainstPolicy` (one-call country+state validator that raises `CheckoutValidationError` with the canonical envelope on miss). |
27+
| `/identity/policy` | Per-product compliance helpers for multi-product merchants (each product carries its own policy: hard gate vs soft vs none, per-product shipping allowlists): `PolicyBlock`, `GateResult`, `EnforcementMode`, `IdentityStatus`, `buildGateFromPolicy`, `runGateWithEnforcement`, `shippingCountryAllowed`, `shippingStateAllowed`, `validateShippingAgainstPolicy` (one-call country+state validator that raises `CheckoutValidationError` with the canonical envelope on miss). |
2828
| `/identity/{nextjs,web}` | Same gate, wrapper pattern: `withAgentScoreGate(opts, handler)` / `createAgentScoreGate(opts) => guard(req)`. The `data` + `degraded` + `infraReason` + `getSignerVerdict` fields land directly on the handler arg / guard result (no separate getter). Plus shared `captureWallet`. |
2929
| `/payment` | `networks`, `USDC`, `rails` registries; `paymentDirective`, `buildPaymentDirective`, `wwwAuthenticateHeader`, `paymentRequiredHeader`, `aliasAmountFields` (opt-in v1↔v2 amount-field shim: adds both `amount` and `maxAmountRequired` to an entry. The 402 builders do NOT apply it by default — strict x402 v2 settlement matches the agent's echoed requirement by exact comparison, so an extra field the server's rebuilt requirement lacks breaks settle; use only when you know a client is hardcoded to read `maxAmountRequired`), `settlementOverrideHeader`, `dispatchSettlementByNetwork`, `extractPaymentSigner` (Request-based; recovers signer from x402 EIP-3009 `payload.authorization.from` OR MPP `Authorization: Payment <base64>` `did:pkh:eip155:<chain>:<addr>` / `did:pkh:solana:<genesis>:<addr>` source DID, including Solana `TransferChecked` authority fallback when `@solana/kit` is installed), `extractPaymentSignerFromAuth` (header-string variant for callers that already have the `Authorization` value in hand), `detectRailFromHeaders` (returns `"x402"` / `"mpp"` / `null` from inbound headers); `createX402Server`, `createMppxServer` (the solana rail's `ataCreationRequired` defaults to `true` so Solana settles work on `@solana/mpp >= 0.6.0` out of the box — opt out only if every recipient's ATA is guaranteed to pre-exist; see `SolanaMppRailSpec.ataCreationRequired` for economics), `buildDefaultCheckoutRails({tempo?, x402Base?, solanaMpp?, stripe?})` (canonical 4-rail `rails` dict factory: flipping `network` alone derives the right `token` + `chainId` — Base Sepolia → Sepolia USDC + chainId 84532, Solana devnet → devnet USDC mint. Solana's `network` accepts both CAIP-2 and the raw `@solana/mpp` form `mainnet-beta` / `devnet` / `localnet`. Explicit overrides always win), `buildMppxComposeRails({amountUsd, tempoRecipient?, solanaRecipient?, ...})` (per-call intent factory replacing the hand-rolled `[['tempo/charge',{...}],['solana/charge',{...}],['stripe/charge',{...}]]` array; auto-handles USD→atomic conversion for Solana; auto-drops `stripe/charge` when `amountUsd < 0.50` since Stripe's fixed ~$0.30 fee makes sub-50-cent charges unprofitable — sub-50-cent APIs pass `includeStripe: false` explicitly to silence the warning); drop-in x402 helpers: `validateX402NetworkConfig` (boot-time guard), `verifyX402Request` (parse + validate inbound X-Payment), `processX402Settle` (verify-then-settle with one call), `classifyX402SettleResult` (maps the tagged settle result to a recommended HTTP status / code / nextSteps so merchants get a controlled envelope without coupling to facilitator-specific error text), `classifyOrchestrationError` (same `ClassifiedX402Error` shape but for uncaught exceptions thrown elsewhere in the orchestration; returns `null` for unknown errors so merchants rethrow instead of swallowing); `zeroAmountCarveOut` (skip CDP / mppx upstream verify+settle for $0 settles where the upstream rejects value=0 payloads; parses the credential, lifts signer + network, returns a `ZeroSettleResult` shaped identically to the success path so callers branch on rail, not on result shape); `usdToAtomic` (BigInt-based USD → atomic value, ROUND_HALF_UP — for Tempo / Solana / Base USDC amount construction). |
3030
| `/discovery` | `isDiscoveryProbeRequest`, `buildDiscoveryProbeResponse` (with optional `x402Sample` for x402-aware crawlers, e.g. `awal x402 details`), `sampleX402AcceptForNetwork` (USDC sample-accept builder for known CAIP-2 networks), `buildWellKnownMpp`, `buildLlmsTxt` + `llmsTxtIdentitySection` + `llmsTxtPaymentSection` (compact + verbose modes), `buildSkillMd` (Claude-Skill-compatible `/skill.md` agent-discovery manifest; strictly agent-facing data only, no internal posture), `buildRedemptionSkillMd` (delivery-neutral redemption-code template — printed mailers, emailed codes, API trial credits all covered; `endpointPath`/`deliveryIntro`/`bodyShape`/`bodyRules`/`extraRecoveryRows` overrides for non-goods shapes), `agentscoreOpenApiSnippets`, `createBazaarDiscovery`, `noindexNonDiscoveryPaths` (Hono middleware emitting `X-Robots-Tag: noindex` on every path except the agent-discovery surfaces; pure helpers `isDiscoveryPath` + `defaultDiscoveryPaths` for non-Hono frameworks), `buildMerchantIndexJson` (canonical `/` discovery body), `standardEndpointDescriptions({kind})` (canonical method+path → description map for goods vs api merchants; optional `includeOrderStatusRoute` for goods), `buildSuccessNextSteps` (universal Passport-active success block), `buildAgentscoreOnboardingSteps` (canonical skill.md onboarding for goods or API merchants). Plus the UCP/JWKS publish surface: `buildSignedUcpResponse`, `buildSignedJwksResponse`, `wellKnownPreflightResponse`, `defaultA2aServices`, `bootstrapUcpSigningKey`, and the framework-neutral `SignedDiscoveryResponse` + per-framework wrappers `signedResponse{Hono,Express,Fastify,Nextjs,Web}`. |

0 commit comments

Comments
 (0)