import { CheckoutVerifier, GrantRecord, VerificationResult } from '@fanfare-io/fanfare-sdk-core/storefront'; import { ShopifyRequestedPurchase } from './checkout-types'; /** * Shopify checkout verifier. Called at checkout entry with the grant the adapter * recorded when the shopper cleared the drop. * * Never throws — it always resolves to a result for every grant (the checkout * gate consumes it with `.then()` only, so a thrown failure would strand the gate * in "checking" or surface as an unhandled rejection). An expired grant resolves * { ok:false, reason:"grant_expired" }; any unexpected throw is caught and * resolves { ok:false, reason:"verify_failed" }. * * This zero-config default enforces only client-side grant expiry, so a * storefront can render the gate without any server wiring. For server-side * enforcement, use `createShopifyCheckoutVerifier(config)` below, which drives * the Fanfare Shopify app proxy. */ export declare const shopifyCheckoutVerifier: CheckoutVerifier; /** * The live checkout context the `verify(grant)` seam does not itself carry. The * `CheckoutVerifier.verify` contract receives only a `GrantRecord` (UX/continuity * state), but driving the proxy needs the consumer's admission credential, the * distribution being checked out, and the cart to gate. The integration supplies * these from its own journey state via `config.getCheckoutContext` — keeping the * credential out of `GrantRecord` and the published surface minimal. */ export interface ShopifyCheckoutContext { /** The consumer's admission credential (the `admissionGrant` from the * consumer-me snapshot). Proof of admission — relayed to the proxy, never * persisted in Shopify. */ credential: string; distributionId: string; /** Ajax cart token (including `?key=`) for Liquid themes, or the Storefront * cart GID for headless. The proxy/cart-bridge resolves it to a cart GID. */ cartId: string; /** * The Shopify cart checkout URL. When present, the SDK signs the relayed DPoP * proof over this URL so the app proxy can ask the admission authority to * verify possession for the eventual checkout target. */ checkoutUrl?: string; } /** * The context the reserve verifier relays: the checkout context plus the purchase * being checked out. The reserve route refuses a body that names no purchase. */ export interface ShopifyVerifierContext extends ShopifyCheckoutContext { /** The product, variant and quantity being bought, checked against the remaining allowance. */ requestedPurchase: ShopifyRequestedPurchase; } export interface ShopifyCheckoutVerifierConfig { /** App-proxy base, e.g. "/apps/fanfare/api". `verify` POSTs to * `${proxyBaseUrl}/${endpoint}`. */ proxyBaseUrl: string; /** * Supplies the live checkout context the grant seam omits. Returns `null` when * the storefront is not ready to check out (no credential/cart yet), which * `verify` surfaces as a denied result rather than a thrown error. */ getCheckoutContext: () => ShopifyVerifierContext | null | Promise; /** * Proxy path under `proxyBaseUrl`. Defaults to the checkout-entry reserve * endpoint (validate + reserve + gate-token re-mint). A pre-reservation * eligibility check can point this at the non-consuming claim/validate path. */ endpoint?: string; /** Injectable for SSR/test. Defaults to `globalThis.fetch`. */ fetchImpl?: typeof fetch; /** * Abort the proxy request after this many ms. Without it, a proxy that accepts * the connection but stalls (never responds) leaves `verify()` pending forever * — and the consumer is stuck in `checking`. The abort surfaces as a denied * result so `verify()` always resolves. Defaults to 10s. */ timeoutMs?: number; } /** A verification result that, on `admission_bound_to_other_cart`, may name the bound cart. */ export type ShopifyVerificationResult = VerificationResult & { boundCart?: { cartId: string; checkoutUrl: string; }; }; /** A `CheckoutVerifier` whose denials can carry the cart a priced admission is bound to. */ export interface ShopifyCheckoutVerifier extends CheckoutVerifier { verify(grant: GrantRecord): Promise; } /** * Build a Shopify `CheckoutVerifier` that drives the Fanfare app proxy at * checkout entry: it relays the admission credential, cart and requested purchase * to the proxy, which * validates against the admission authority, reserves the admission, and * re-mints the platform gate token into the cart metafield. The proxy — not this * client — is the trust boundary; a positive result means "the authority * currently accepts this admission for this cart", never a client assertion. * * Never throws — it always resolves to a result: client-side expiry is a cheap * pre-check; a missing context, a non-2xx proxy response, and any transport throw * all resolve to a denied `{ ok:false, reason }`. A priced admission's 409 * `dedicated_cart_required` / `admission_bound_to_other_cart` surfaces as that * reason (the latter with `boundCart` when the server named the bound cart); any * other non-2xx as `proxy_`. */ export declare function createShopifyCheckoutVerifier(config: ShopifyCheckoutVerifierConfig): ShopifyCheckoutVerifier;