/** * `@tiledev/sdk-apptile-cart-sync` — public types. (Cart Sync is the platform's "Cart Assist".) * * Cart Sync is the shopper's cart, *shared*. Apptile keeps a pointer to a customer's cart on the * customer record, so the same cart can be seen and edited elsewhere — a support agent in the * dashboard, or the shopper on the web store. This SDK reconciles the two directions: * * up — report which cart this device is on (which makes the backend write the pointer) * down — when the pointer names a different cart, adopt it, folding this device's cart in first * * Signed-in shoppers only: the shared cart hangs off the customer. Every step degrades to "keep the * local cart" — this is a convenience layer, and a shopper losing their cart to a failed sync is a far * worse outcome than a sync that quietly did nothing. * * `@tiledev/sdk-shopify` is a required peer: Cart Sync coordinates with the same cart Cart Hold * guards. The client imports only its pure attribution functions; the Shopify host (`./shopifyHost`) * reads its hooks and `shopify.cart`, and needs 0.10 for the Customer Account sign-in. */ /** Minimal key/value store, satisfied by AsyncStorage/localStorage as-is. Holds the "spent carts" * list so this device never re-adopts one the shopper has already checked out. */ export interface KeyValueStorage { getItem(key: string): Promise; setItem(key: string, value: string): Promise; } /** `fetch`, injectable for tests or a non-global runtime. Defaults to the ambient `fetch`. */ export type FetchLike = typeof fetch; /** * Cart Sync's runtime configuration — the `cartAssist` block of the app config. * * `apiUrl` is the app-proxy route on apptile-server (`/update`, `/clear`), NOT the storefront's * `/a/apptile-app-proxy/...` path, which is only reachable from the shop's own domain. `mergeApiUrl` * is the server-side cart-merge endpoint. */ export interface CartSyncConfig { enabled: boolean; apiUrl: string; mergeApiUrl: string; } /** The customer's shared-cart pointer, as read from the Customer Account metafields. */ export interface SharedCart { /** Cart token (not a GID) Apptile has on file for this customer, if any. */ activeToken: string | null; /** Tokens of carts already converted to orders. */ spentTokens: string[]; } /** A cart or line attribute, as Shopify stores it. */ export type CartAttribute = { key: string; value: string; }; /** A cart line as `readLines` returns it — structurally `@tiledev/sdk-shopify`'s `CartLineSnapshot`. */ export interface CarriedLine { merchandiseId: string; quantity: number; sellingPlanId: string | null; attributes: CartAttribute[]; } /** What `addLines` receives: a `CarriedLine` minus a null selling plan, i.e. sdk-shopify's `CartLineInput`. */ export interface CarriedLineInput { merchandiseId: string; quantity: number; sellingPlanId?: string; attributes: CartAttribute[]; } /** * The reconciliation inputs for one sync run. Assembled by the host from its cart + session — the SDK * stays decoupled from `@tiledev/sdk-shopify`'s hooks by receiving these rather than importing them. */ export interface SyncCartArgs { /** * The cart this device is on, as a GID — or a function that returns it. Pass the function: the * sync calls it when it decides, after the customer id and the shared pointer have been read, so a * cart the app restored in the meantime is the one it sees. A plain value is used as given (older * hosts); a value captured before the app restored its cart is null, and a null cart adopts the * shared one outright. */ cartId: string | null | (() => string | null); /** * Resolves the numeric customer id, awaited *inside* the run — the sync fires the moment the * session resolves, typically before the profile has loaded, so reading it synchronously up front * makes every sign-in sync a silent no-op. Null means a guest (a real no-op: the shared cart hangs * off a customer). */ resolveCustomerId: () => Promise; /** Switches this device to the shared cart. Resolves null when that cart no longer exists. */ adopt: (cartGid: string) => Promise; /** Re-reads the cart in place, for a shared cart edited elsewhere without its id changing. */ refresh: () => Promise; /** Abandons a spent cart and starts a fresh one. */ reset: () => Promise; /** Shown to the shopper when their cart changes under them. */ notify?: (message: string) => void; /** * Reads a cart's lines by id. Resolve null when the cart does not exist; throw when you can't tell * (a network error) — a throw keeps the local cart and changes nothing. * * With it, the sync decides by what each cart holds (the README's decision table): an empty local * cart adopts the shared one, an empty or missing shared cart keeps the local one and makes it the * shared one, and two carts with lines are folded together before switching. Without it, the sync * behaves as 0.5 did: merge when it can, then adopt — except that a failed merge keeps the local cart. */ readLines?: (cartGid: string) => Promise; /** * Adds lines to a cart by id (not the current one). Carries this device's lines into the shared * cart, attributes verbatim, when the merge service can't take the cart or the merge failed. Only * used together with `readLines`. */ addLines?: (cartGid: string, lines: CarriedLineInput[]) => Promise; /** * Read and write a cart's attributes by id. With both, the local cart's `_apptile_attribution` * counts are merged into the shared cart's once its lines are carried; the write is the whole set. */ readAttributes?: (cartGid: string) => Promise; writeAttributes?: (cartGid: string, attributes: CartAttribute[]) => Promise; } /** Runs a Customer Account API GraphQL query with the host's authed transport. The SDK owns the * query text (`POINTER_QUERY`); the host owns the credentials. */ export type CustomerAccountRequest = (query: string, variables: Record) => Promise; /** * Everything a `CartSyncClient` needs from its host. `config`, `appId`, `shop` and * `customerAccountRequest` are required; the rest degrade (no storage → the shared pointer still * guards re-adoption; no `getAccessToken` → the report omits the customer-token header). */ export interface CartSyncOptions { config: CartSyncConfig; /** The Apptile engine app id — the `x-shopify-app-id` header (shared with Cart Hold). */ appId: string; /** Shopify store domain, e.g. `acme.myshopify.com` — required by `/clear` and the merge endpoint. */ shop: string; /** Reads the shared-cart pointer from the Customer Account metafields. */ customerAccountRequest: CustomerAccountRequest; /** Persists the locally-recorded spent carts. Omit to rely on the remote pointer alone. */ storage?: KeyValueStorage; /** The customer access token, sent as a header on the report. */ getAccessToken?: () => Promise; /** Non-fatal error sink. Defaults to a silent no-op. */ onError?: (error: unknown, context?: Record) => void; /** Injectable fetch. Defaults to the global. */ fetch?: FetchLike; /** Request timeout (ms). Default 8000. */ timeoutMs?: number; /** Verbose sync tracing (mirrors the app's `__DEV__` logs). Defaults off. */ debug?: boolean; } /** Shopper-facing copy for the two things a sync can announce. Exported so the host stays consistent. */ export declare const DEFAULT_MESSAGES: { readonly ADOPTED: "We found your saved cart and synced it."; readonly SPENT: "That cart was already checked out. Started a fresh one."; }; /** The Customer Account metafield namespace + keys the pointer lives under. */ export declare const CART_SYNC_NAMESPACE = "Apptile-CartAssist"; export declare const ACTIVE_CART_KEY = "smart_cart_id"; export declare const CHECKED_OUT_CARTS_KEY = "smart_cart_checkedout_ids"; /** * `metafields(identifiers:)` leaves a slot null when the metafield has no value — or errors the whole * query when the definition is not readable by the Customer Account API. Both mean "nothing to sync". */ export declare const POINTER_QUERY = "\n query CartAssistMetafields($identifiers: [HasMetafieldsIdentifier!]!) {\n customer {\n metafields(identifiers: $identifiers) {\n key\n value\n }\n }\n }\n"; //# sourceMappingURL=types.d.ts.map