/** * Public checkout vocabulary shared by the low-level `claim` and the recommended * `gatedCheckout`. Isomorphic (no React) so the package root can export it. * * The two Shopify identifiers a gated line carries are BOTH opaque * `gid://shopify/...` strings, so they are branded to make a transposition a * compile error rather than a silent admission-authority mismatch: * - `shopifyProductId` (a `ProductGID`) is the gate's policy anchor. * - `merchandiseId` (a `VariantGID`) is Shopify's Storefront `cartLinesAdd` id. */ declare const gidBrand: unique symbol; /** A Shopify Product GID, e.g. `gid://shopify/Product/123`. Construct via `productGid`. */ export type ProductGID = string & { readonly [gidBrand]: "Product"; }; /** A Shopify ProductVariant GID, e.g. `gid://shopify/ProductVariant/456`. Construct via `variantGid`. */ export type VariantGID = string & { readonly [gidBrand]: "ProductVariant"; }; export declare function productGid(gid: string): ProductGID; export declare function variantGid(gid: string): VariantGID; /** * One purchase intent the gate evaluates. `shopifyProductId` drives the gate's * (currently server-deferred) product policy; `merchandiseId` is the variant the * integrator's `cartLinesAdd` consumes. Both required — the admission authority * keys on the product and has no variant→product derivation path. */ export interface GatedLine { shopifyProductId: ProductGID; merchandiseId: VariantGID; quantity: number; } /** * The intended-purchase payload relayed to the app proxy. INTERNAL wire shape: * `merchandiseId` maps to the authority's `variantId`. The fields stay branded so * the mapping below cannot transpose them. */ export interface ShopifyRequestedPurchase { productId: ProductGID; variantId: VariantGID; quantity: number; } /** Map a `GatedLine` to the authority's requested-purchase wire shape. */ export declare function gatedLineToRequestedPurchase(line: GatedLine): ShopifyRequestedPurchase; /** * Closed refusal vocabulary for `gatedCheckout`. The load-bearing distinction is * whether a fresh `gatedCheckout` is safe (nothing reserved) or would * double-reserve (a slot is already held) — see `kind` + the docs on * `FanfareGatedCheckoutResult`. * * - `cart_create_failed` — `createCart` threw; nothing claimed, safe to restart. * - `no_claim_context` — not yet ready (no grant/distribution, or demo mode). * - `cart_not_materialized` — the proxy could not find a real cart; safe to restart. * - `DISTRIBUTION_ORDER_LIMIT` — purchase allowance exceeded; not retryable. * - `dedicated_cart_required` — the admission is priced and the cart `createCart` * returned is not dedicated to it (it holds other lines, is in a market whose * currency is not the shop currency, or carries another admission's token). Not * retryable as-is: have `createCart` return the cart `createDedicatedCart()` * creates, then start a fresh `gatedCheckout`. * - `admission_bound_to_other_cart` — the admission is already bound to another * cart; not retryable on this cart. When `boundCart` is present, claim again on * that cart (its `cartId` AND `checkoutUrl`) and redirect to it. Without it the * server could not name the bound cart; surface the refusal. * - `claim_failed` — the claim was refused/unreachable; nothing reserved, safe to restart. * - `add_line_failed` — RESERVED. The token is minted and the slot held; resume the * add via `retry()`, never re-claim (that double-reserves). * - `reservation_expired` — the reservation lapsed mid-add; a fresh `gatedCheckout` is required. * - `cart_id_mismatch` — the cart `addLine` returned is not the one claimed (adapter bug). * - `checkout_url_missing` — the cart exposed no checkout URL when the claim/redirect needed it (adapter bug). * - `checkout_url_mismatch` — the cart checkout URL changed after the claim was signed (adapter bug). * - `busy` — a `gatedCheckout` is already in flight; disable the buy button on `pending`. * * Only `add_line_failed` carries a `retry()`; branch on `retryable` (or the presence * of `retry`), never on `code` alone, to decide whether to retry. */ export type FanfareCheckoutCode = "cart_create_failed" | "no_claim_context" | "cart_not_materialized" | "DISTRIBUTION_ORDER_LIMIT" | "dedicated_cart_required" | "admission_bound_to_other_cart" | "claim_failed" | "add_line_failed" | "reservation_expired" | "cart_id_mismatch" | "checkout_url_missing" | "checkout_url_mismatch" | "busy"; /** Which phase the failure came from, for coarse UI/metric bucketing. */ export type FanfareCheckoutFailureKind = "create_cart" | "claim" | "add_line" | "busy"; /** * The closed result of `gatedCheckout`. Never rejects. On `{ ok: true }` the cart * carries the gate token plus every line, and `checkoutUrl` is ready to redirect. * * On `{ ok: false }`, branch on `code`. The only RESUMABLE failure is * `add_line_failed`: the claim already minted the token and reserved the slot, so * `retry()` re-runs the remaining `addLine`s on the SAME cart — it never re-claims. * `cart` is the half-built cart and `expDate` the reservation expiry, so a caller * can decide to `retry()` or, once expired (`reservation_expired`), start fresh. */ export type FanfareGatedCheckoutResult = { ok: true; cart: TCart; checkoutUrl: string; expDate: string; } | { ok: false; code: FanfareCheckoutCode; retryable: boolean; kind: FanfareCheckoutFailureKind; /** The reservation expiry, when a claim succeeded before the failure. */ expDate?: string; /** The index into `[gatedLine, ...ungatedLines]` whose `addLine` failed. */ failedLineIndex?: number; /** The claimed (possibly half-built) cart, when one exists. */ cart?: TCart; /** Present only on `admission_bound_to_other_cart`, when the server named the cart the admission is bound to. */ boundCart?: { cartId: string; checkoutUrl: string; }; /** Present only on `add_line_failed`: resume the remaining adds on the same cart. */ retry?: () => Promise>; }; export {};