@shoppexio/storefront 1.0.106 → 1.0.107
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/CHANGELOG.md +4 -0
- package/dist/{chunk-INBEHRZN.js → chunk-P7MN6RXP.js} +22 -3
- package/dist/{chunk-INBEHRZN.js.map → chunk-P7MN6RXP.js.map} +1 -1
- package/dist/customer.cjs +27 -4
- package/dist/customer.cjs.map +1 -1
- package/dist/customer.d.cts +12 -2
- package/dist/customer.d.ts +12 -2
- package/dist/customer.js +7 -3
- package/dist/customer.js.map +1 -1
- package/dist/index.cjs +26 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -2
- package/dist/index.d.ts +12 -2
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../sdk/src/core/errors.ts","../../sdk/src/utils/requested-currency.ts","../../sdk/src/core/config.ts","../../sdk/src/utils/storage.ts","../../sdk/src/core/cache.ts","../../sdk/src/core/endpoint.ts","../../sdk/src/core/telemetry.ts","../../sdk/src/core/client.ts","../../sdk/src/modules/affiliates.ts","../../contracts/src/storefront-consent-choice.ts","../../sdk/src/core/analytics-session.ts","../../sdk/src/core/attribution.ts","../../sdk/src/core/page-path.ts","../../sdk/src/core/page-tracker.ts","../../sdk/src/modules/analytics.ts","../../sdk/src/utils/cart-line-id.ts","../../contracts/src/catalog-unit-price.ts","../../sdk/src/modules/cart.ts","../../sdk/src/storefront-storage-sdk.ts","../../../node_modules/.bun/openapi-fetch@0.17.0/node_modules/openapi-fetch/src/index.js","../../contracts/src/api-client.ts","../../sdk/src/core/typed-client.ts","../../sdk/src/modules/store.ts","../../sdk/src/utils/storefront-catalog.ts","../../sdk/src/modules/products.ts","../../contracts/src/redirect-link-template.ts","../../sdk/src/modules/checkout.ts","../../sdk/src/modules/coupons.ts","../../sdk/src/modules/reviews.ts","../../sdk/src/utils/storefront-stock.ts","../../sdk/src/utils/storefront-search.ts","../../sdk/src/modules/search.ts","../../sdk/src/modules/invoices.ts","../../sdk/src/modules/pages.ts","../../contracts/src/navigation.ts","../../sdk/src/modules/navigation.ts","../../sdk/src/modules/presence.ts","../../sdk/src/utils/format.ts","../../sdk/src/modules/theme.ts","../../sdk/src/storefront-sdk.ts","../../contracts/src/product-custom-fields.ts","../../sdk/src/utils/storefront-custom-fields.ts","../../sdk/src/utils/storefront-contact.ts","../../sdk/src/modules/customer.ts","../../sdk/src/index.ts"],"sourcesContent":["/**\n * SDK Error Classes\n */\n\n/**\n * `SDKResponse.code` of a priced read that asked for a currency the shop does\n * not sell in (ADR-0066). `errorParams.requested` names the currency,\n * `errorParams.available` lists the enabled ones.\n */\nexport const CURRENCY_UNAVAILABLE_ERROR_CODE = 'errors.storefront.currency_unavailable';\n\nexport class ShoppexError extends Error {\n public readonly code: string;\n public readonly statusCode?: number;\n\n constructor(message: string, code: string, statusCode?: number) {\n super(message);\n this.name = 'ShoppexError';\n this.code = code;\n this.statusCode = statusCode;\n Object.setPrototypeOf(this, ShoppexError.prototype);\n }\n}\n\nexport class NotInitializedError extends ShoppexError {\n constructor() {\n super(\n 'SDK not initialized. Call shoppex.init() first.',\n 'NOT_INITIALIZED'\n );\n this.name = 'NotInitializedError';\n Object.setPrototypeOf(this, NotInitializedError.prototype);\n }\n}\n\nexport class NetworkError extends ShoppexError {\n constructor(message: string, statusCode?: number) {\n super(message, 'NETWORK_ERROR', statusCode);\n this.name = 'NetworkError';\n Object.setPrototypeOf(this, NetworkError.prototype);\n }\n}\n\n/**\n * A refusal the SERVER made and named. `code` is the backend's `error_code`\n * (e.g. `errors.checkout.coupon_no_longer_valid`) — the branchable identity of\n * the refusal, stable across locales, unlike the localized `message`.\n *\n * Distinct from {@link NetworkError}, whose `code` is always `NETWORK_ERROR`:\n * that one means \"the request did not produce a named answer\".\n */\nexport class ApiError extends ShoppexError {\n public readonly errorParams?: Record<string, unknown>;\n\n constructor(\n message: string,\n code: string,\n statusCode?: number,\n errorParams?: Record<string, unknown>,\n ) {\n super(message, code, statusCode);\n this.name = 'ApiError';\n this.errorParams = errorParams;\n Object.setPrototypeOf(this, ApiError.prototype);\n }\n}\n\nexport class ValidationError extends ShoppexError {\n public readonly invalidFields?: string[];\n\n constructor(message: string, invalidFields?: string[]) {\n super(message, 'VALIDATION_ERROR');\n this.name = 'ValidationError';\n this.invalidFields = invalidFields;\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\nexport class CartError extends ShoppexError {\n constructor(message: string) {\n super(message, 'BASKET_ERROR');\n this.name = 'CartError';\n Object.setPrototypeOf(this, CartError.prototype);\n }\n}\n","export function normalizeRequestedCurrency(value: string | null | undefined): string | null {\n const normalized = value?.trim().toUpperCase();\n return normalized && /^[A-Z]{3}$/.test(normalized) ? normalized : null;\n}\n\n/**\n * The buyer currency every priced SDK call uses (ADR-0066): an explicit\n * `?currency=` on the page wins, then the currency from `init()`. One rule for\n * catalog reads, cart quotes and checkout, so they can never disagree.\n */\nexport function resolveBuyerCurrency(configCurrency: string | null | undefined): string | null {\n return getRequestedCurrencyFromLocation() ?? normalizeRequestedCurrency(configCurrency);\n}\n\nexport function getRequestedCurrencyFromLocation(): string | null {\n if (typeof window === 'undefined' || !window.location) {\n return null;\n }\n\n const search = typeof window.location.search === 'string' ? window.location.search : '';\n if (search) {\n return normalizeRequestedCurrency(new URLSearchParams(search).get('currency'));\n }\n\n const href = typeof window.location.href === 'string' ? window.location.href : '';\n if (!href) {\n return null;\n }\n\n try {\n return normalizeRequestedCurrency(\n new URL(href, 'https://storefront.shoppex.local').searchParams.get('currency'),\n );\n } catch {\n return null;\n }\n}\n","/**\n * SDK Configuration Management\n */\n\nimport type { ShoppexConfig, ShoppexInitOptions } from '../types';\nimport { NotInitializedError, ValidationError } from './errors';\nimport { normalizeRequestedCurrency } from '../utils/requested-currency';\n\nexport const DEFAULT_API_BASE_URL = 'https://api.shoppex.io';\n\nlet currentConfig: ShoppexConfig | null = null;\nlet cachedShopId: string | null = null;\n\nexport const DEFAULT_CHECKOUT_BASE_URL = 'https://checkout.shoppex.io';\n\nexport function initConfig(\n storeSlug: string,\n options?: ShoppexInitOptions\n): ShoppexConfig {\n // Validate before touching any module state: a rejected init must leave\n // the previous configuration fully intact, not half of it.\n const currency = normalizeInitCurrency(options?.currency);\n const normalizedShopId = options?.shopId?.trim();\n\n // Reset cached shop id on every init to avoid cross-store leakage\n // when the SDK is re-initialized with a different slug.\n cachedShopId = normalizedShopId ? normalizedShopId : null;\n\n currentConfig = {\n storeSlug,\n locale: options?.locale,\n currency,\n apiBaseUrl: options?.apiBaseUrl ?? DEFAULT_API_BASE_URL,\n checkoutBaseUrl: options?.checkoutBaseUrl ?? DEFAULT_CHECKOUT_BASE_URL,\n preview: options?.preview === true,\n };\n // Response cache keys carry the locale and buyer currency (client.ts), so a\n // re-init with another audience reads its own entries instead of the\n // previous audience's payloads. The typed client is keyed on this object\n // (typed-client.ts), so it is rebuilt too.\n return currentConfig;\n}\n\n/**\n * The init currency is a contract input (ADR-0066): it is sent on every priced\n * read and refused by the API when the shop does not sell in it. A value that\n * cannot be a currency code is a programming error worth failing at init, not\n * a request the backend should have to reject on every call.\n */\nfunction normalizeInitCurrency(value: string | undefined): string | undefined {\n if (value === undefined || value.trim() === '') {\n return undefined;\n }\n const normalized = normalizeRequestedCurrency(value);\n if (!normalized) {\n throw new ValidationError(\n `Invalid currency \"${value}\": pass an ISO 4217 code such as \"EUR\".`,\n ['currency'],\n );\n }\n return normalized;\n}\n\nexport function getConfig(): ShoppexConfig {\n if (!currentConfig) {\n throw new NotInitializedError();\n }\n return currentConfig;\n}\n\nexport function isInitialized(): boolean {\n return currentConfig !== null;\n}\n\nexport function resetConfig(): void {\n currentConfig = null;\n cachedShopId = null;\n}\n\nexport function setShopId(shopId: string): void {\n cachedShopId = shopId;\n}\n\nexport function getShopId(): string | null {\n return cachedShopId;\n}\n","/**\n * Web Storage Wrapper\n *\n * Handles localStorage (default) and sessionStorage access with error handling\n * for environments where storage is not available.\n */\n\nimport { storefrontStorageKey } from '@shoppex/contracts/storefront-storage-key';\n\nconst STORAGE_PREFIX = 'shoppex_';\n\nexport type StorageArea = 'localStorage' | 'sessionStorage';\n\nfunction getKey(key: string): string {\n return `${STORAGE_PREFIX}${key}`;\n}\n\nexport function getItem<T>(key: string, area: StorageArea = 'localStorage'): T | null {\n try {\n const item = globalThis[area].getItem(storefrontStorageKey(getKey(key)));\n if (!item) return null;\n return JSON.parse(item) as T;\n } catch {\n return null;\n }\n}\n\nexport function setItem<T>(key: string, value: T, area: StorageArea = 'localStorage'): void {\n try {\n globalThis[area].setItem(storefrontStorageKey(getKey(key)), JSON.stringify(value));\n } catch {\n console.warn(`[shoppex] Failed to save to ${area}`);\n }\n}\n\nexport function removeItem(key: string, area: StorageArea = 'localStorage'): void {\n try {\n globalThis[area].removeItem(storefrontStorageKey(getKey(key)));\n } catch {\n // Ignore errors\n }\n}\n","/**\n * In-memory cache with pending request deduplication.\n */\n\nexport interface CacheEntry<T> {\n data: T;\n expiresAt: number;\n updatedAt: number;\n ttl: number;\n}\n\nexport interface CacheOptions {\n ttl: number;\n staleWhileRevalidate?: boolean;\n}\n\nexport interface CacheStats {\n hits: number;\n misses: number;\n pendingRequests: number;\n entries: number;\n}\n\nconst cache = new Map<string, CacheEntry<unknown>>();\nconst pending = new Map<string, Promise<unknown>>();\n\nconst stats = {\n hits: 0,\n misses: 0,\n};\n\nfunction isExpired(entry: CacheEntry<unknown>): boolean {\n return Date.now() > entry.expiresAt;\n}\n\nexport function getCacheStats(): CacheStats {\n return {\n hits: stats.hits,\n misses: stats.misses,\n pendingRequests: pending.size,\n entries: cache.size,\n };\n}\n\nexport function clearCache(): void {\n cache.clear();\n pending.clear();\n}\n\n// Keys written through the client carry the audience they were fetched for\n// as `<locale>|<currency>|<key>`. Callers invalidate by the bare key or\n// prefix (`products:my-store`) and mean every audience's copy of it.\nconst AUDIENCE_PREFIX = /^[^|]*\\|[^|]*\\|/;\n\nexport function invalidateCache(prefixOrKey: string): void {\n for (const key of cache.keys()) {\n const bareKey = key.replace(AUDIENCE_PREFIX, '');\n if (\n key === prefixOrKey\n || key.startsWith(prefixOrKey)\n || bareKey === prefixOrKey\n || bareKey.startsWith(prefixOrKey)\n ) {\n cache.delete(key);\n }\n }\n}\n\nexport function setCacheEntry<T>(key: string, data: T, ttl: number): void {\n const now = Date.now();\n cache.set(key, {\n data,\n ttl,\n updatedAt: now,\n expiresAt: now + ttl,\n });\n}\n\nexport function getCacheEntry<T>(key: string): CacheEntry<T> | null {\n const entry = cache.get(key) as CacheEntry<T> | undefined;\n if (!entry) return null;\n return entry;\n}\n\nexport async function getOrFetch<T>(\n key: string,\n fetcher: () => Promise<T>,\n options: CacheOptions,\n shouldCache: (value: T) => boolean = () => true\n): Promise<T> {\n const entry = getCacheEntry<T>(key);\n\n if (entry && !isExpired(entry)) {\n stats.hits += 1;\n return entry.data;\n }\n\n if (entry && options.staleWhileRevalidate) {\n stats.hits += 1;\n if (!pending.has(key)) {\n const refreshPromise = (async () => {\n try {\n const data = await fetcher();\n if (shouldCache(data)) {\n setCacheEntry(key, data, options.ttl);\n }\n return data;\n } finally {\n pending.delete(key);\n }\n })();\n pending.set(key, refreshPromise as Promise<unknown>);\n }\n return entry.data;\n }\n\n if (pending.has(key)) {\n return pending.get(key) as Promise<T>;\n }\n\n stats.misses += 1;\n const promise = (async () => {\n try {\n const data = await fetcher();\n if (shouldCache(data)) {\n setCacheEntry(key, data, options.ttl);\n }\n return data;\n } finally {\n pending.delete(key);\n }\n })();\n\n pending.set(key, promise as Promise<unknown>);\n return promise;\n}\n","const PARAM_PATTERN = /:([A-Za-z0-9_]+)/g;\n\nexport function buildEndpoint(\n template: string,\n params: Record<string, string | number | null | undefined>\n): string {\n return template.replace(PARAM_PATTERN, (_, key: string) => {\n const rawValue = params[key];\n if (rawValue === null || rawValue === undefined) {\n throw new Error(`Missing endpoint param: ${key}`);\n }\n\n const value = String(rawValue).trim();\n if (!value) {\n throw new Error(`Endpoint param \"${key}\" must not be empty`);\n }\n\n return encodeURIComponent(value);\n });\n}\n","import { getConfig, getShopId, isInitialized } from './config';\nimport { buildEndpoint } from './endpoint';\nimport { getItem, setItem } from '../utils/storage';\n\nconst CLIENT_ERROR_DEDUPE_WINDOW_MS = 15_000;\n// The ping endpoint rejects longer values (422); the report is cut to fit\n// instead of being lost.\nconst CLIENT_ERROR_TEXT_MAX_LENGTH = 500;\nconst CLIENT_ERROR_URL_MAX_LENGTH = 2000;\n\ntype VisibilityStateValue = 'hidden' | 'visible' | 'prerender' | 'unloaded';\ntype RequestMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';\n\nexport interface StorefrontClientErrorPayload {\n endpoint: string;\n method: RequestMethod;\n message: string;\n statusCode?: number;\n source?: 'sdk';\n phase?: 'request';\n attemptCount?: number;\n responseReceived?: boolean;\n pageUrl?: string;\n requestUrl?: string;\n online?: boolean;\n visibilityState?: VisibilityStateValue;\n}\n\nfunction getRecentClientErrorKey(payload: StorefrontClientErrorPayload): string {\n return [\n payload.method,\n payload.endpoint,\n payload.statusCode ?? 'none',\n payload.message.trim().toLowerCase(),\n payload.responseReceived ? 'response' : 'no-response',\n ].join('|');\n}\n\nfunction shouldSkipDuplicateClientError(payload: StorefrontClientErrorPayload): boolean {\n const dedupeKey = `client_error_${getRecentClientErrorKey(payload)}`;\n const now = Date.now();\n const lastSeenAt = getItem<number>(dedupeKey);\n if (typeof lastSeenAt === 'number' && now - lastSeenAt < CLIENT_ERROR_DEDUPE_WINDOW_MS) {\n return true;\n }\n\n setItem(dedupeKey, now);\n return false;\n}\n\nexport async function reportStorefrontClientError(payload: StorefrontClientErrorPayload): Promise<void> {\n if (!isInitialized()) return;\n if (typeof window === 'undefined') return;\n if (shouldSkipDuplicateClientError(payload)) return;\n\n const config = getConfig();\n const shopId = getShopId();\n const endpoint = shopId\n ? buildEndpoint('/v1/storefront/shops/id/:id/ping', { id: shopId })\n : buildEndpoint('/v1/storefront/shops/:storeSlug/ping', { storeSlug: config.storeSlug });\n const body = JSON.stringify({\n event_type: 'client_error',\n referer: document.referrer || undefined,\n client_error: {\n source: payload.source ?? 'sdk',\n phase: payload.phase ?? 'request',\n endpoint: payload.endpoint.slice(0, CLIENT_ERROR_TEXT_MAX_LENGTH),\n method: payload.method,\n message: payload.message.slice(0, CLIENT_ERROR_TEXT_MAX_LENGTH),\n status_code: payload.statusCode,\n attempt_count: payload.attemptCount,\n response_received: payload.responseReceived ?? false,\n page_url: (payload.pageUrl ?? window.location.href).slice(0, CLIENT_ERROR_URL_MAX_LENGTH),\n request_url: payload.requestUrl?.slice(0, CLIENT_ERROR_URL_MAX_LENGTH),\n online: payload.online ?? (typeof navigator !== 'undefined' ? navigator.onLine : undefined),\n visibility_state:\n payload.visibilityState ??\n (typeof document !== 'undefined'\n ? (document.visibilityState as VisibilityStateValue)\n : undefined),\n },\n });\n\n const targetUrl = `${config.apiBaseUrl}${endpoint}`;\n\n try {\n if (typeof navigator !== 'undefined' && typeof navigator.sendBeacon === 'function') {\n const beaconBody = new Blob([body], { type: 'application/json' });\n if (navigator.sendBeacon(targetUrl, beaconBody)) {\n return;\n }\n }\n\n await fetch(targetUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body,\n keepalive: true,\n });\n } catch {\n // Telemetry must never break storefront usage.\n }\n}\n","/**\n * HTTP Client for SDK\n *\n * IMPORTANT: No credentials! SDK runs on external domains,\n * and CORS with wildcard origin doesn't allow credentials.\n * All endpoints are public storefront endpoints.\n */\n\nimport type { ApiResponse, SDKResponse } from '../types';\nimport { getConfig, isInitialized } from './config';\nimport { ApiError, NetworkError, ShoppexError } from './errors';\nimport { getOrFetch, type CacheOptions } from './cache';\nimport { reportStorefrontClientError } from './telemetry';\nimport { resolveBuyerCurrency } from '../utils/requested-currency';\n\nconst DEFAULT_TIMEOUT = 10000;\nconst MAX_RETRIES = 2;\n\ninterface RequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\n body?: unknown;\n timeout?: number;\n retries?: number;\n baseUrl?: string;\n headers?: Record<string, string>;\n cache?: (CacheOptions & { key?: string }) | false;\n /**\n * This read prices its payload, so it travels with the buyer currency from\n * `init({ currency })` as `?currency=` (ADR-0066). The API prices the\n * response in that currency or refuses with\n * `errors.storefront.currency_unavailable`; it never silently serves the\n * shop default. Leave unset for reads that carry no prices.\n */\n buyerCurrency?: boolean;\n}\n\ninterface ParsedResponsePayload {\n data: unknown | null;\n rawText: string | null;\n}\n\ninterface FailureInfo {\n message: string;\n statusCode?: number;\n isTransport: boolean;\n responseReceived: boolean;\n responseDefinitive: boolean;\n /** The server's `error_code`, when the failure was a named refusal. */\n code?: string;\n errorParams?: Record<string, unknown>;\n}\n\nasync function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction appendQueryParam(url: string, key: string, value: string): string {\n const separator = url.includes('?') ? '&' : '?';\n return `${url}${separator}${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n}\n\n/**\n * Re-shape a failed response for a module's own return type without losing\n * the failure contract: `code` / `errorParams` are what callers branch on\n * (`errors.storefront.currency_unavailable`), `status` / `responseReceived` /\n * `responseDefinitive` are what mutation helpers and retries read. A wrapper\n * that rebuilds `{ success: false, message }` by hand silently drops them.\n */\nexport function forwardFailure<T>(\n response: SDKResponse<unknown>,\n overrides: { message?: string; data?: T } = {},\n): SDKResponse<T> {\n const { success: _success, data: _data, ...failure } = response;\n return {\n ...failure,\n success: false,\n message: overrides.message ?? response.message,\n ...(overrides.data !== undefined ? { data: overrides.data } : {}),\n };\n}\n\nexport async function request<T>(\n endpoint: string,\n options: RequestOptions = {}\n): Promise<SDKResponse<T>> {\n const config = options.baseUrl ? null : getConfig();\n // The audience (locale, buyer currency) travels with EVERY request of an\n // initialized SDK — a baseUrl override (e.g. resolveStoreByDomain) must not\n // silently drop it back to server-side negotiation (Codex P2).\n const audience = config ?? (isInitialized() ? getConfig() : null);\n const {\n method = 'GET',\n body,\n timeout = DEFAULT_TIMEOUT,\n retries,\n baseUrl,\n headers: requestHeaders,\n cache,\n buyerCurrency: pricesInBuyerCurrency = false,\n } = options;\n const retryCount =\n retries ?? (method === 'GET' ? MAX_RETRIES : 0);\n\n const apiBaseUrl = baseUrl ?? config?.apiBaseUrl ?? '';\n // One place knows the transport: currency is a query parameter, not a\n // header, because the storefront API keys its HTTP cache on the URL. The\n // value follows the same rule as cart quotes and checkout (page URL, then\n // init config), so the catalog is never priced differently from the cart.\n const buyerCurrency = pricesInBuyerCurrency ? resolveBuyerCurrency(audience?.currency) : null;\n const url = buyerCurrency\n ? appendQueryParam(`${apiBaseUrl}${endpoint}`, 'currency', buyerCurrency)\n : `${apiBaseUrl}${endpoint}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n ...requestHeaders,\n };\n // Explicit request locale (ADR-0055): without it the backend would fall\n // back to Accept-Language, detaching catalog content from the page locale.\n const locale = typeof audience?.locale === 'string' && audience.locale.trim() ? audience.locale.trim() : null;\n if (locale) {\n headers['x-shoppex-locale'] = locale;\n }\n\n let lastFailure: FailureInfo | null = null;\n\n const executeRequest = async (): Promise<SDKResponse<T>> => {\n for (let attempt = 0; attempt <= retryCount; attempt++) {\n let responseReceived = false;\n let responseDefinitive = false;\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n responseReceived = true;\n\n clearTimeout(timeoutId);\n\n const payload = await parseResponsePayload(response);\n if (!response.ok) {\n responseDefinitive = isDefinitiveHttpRefusal(payload.data)\n && response.status >= 400\n && response.status < 500\n && response.status !== 408;\n const fallbackHttpMessage = response.statusText\n ? `HTTP ${response.status}: ${response.statusText}`\n : `HTTP ${response.status}`;\n const message =\n (payload.data && typeof payload.data === 'object' && 'error' in payload.data && typeof payload.data.error === 'string'\n ? payload.data.error\n : null) ??\n (payload.data && typeof payload.data === 'object' && 'message' in payload.data && typeof payload.data.message === 'string'\n ? payload.data.message\n : null) ??\n payload.rawText ??\n fallbackHttpMessage;\n\n // A named server refusal keeps its name. Everything else stays a\n // NetworkError, exactly as before.\n const named = readErrorCodeFields(payload.data);\n if (named.code) {\n throw new ApiError(message, named.code, response.status, named.errorParams);\n }\n\n throw new NetworkError(message, response.status);\n }\n\n if (response.status === 204 && payload.data === null) {\n return {\n success: true,\n };\n }\n\n if (!payload.data || typeof payload.data !== 'object' || !('status' in payload.data)) {\n throw new NetworkError('Invalid API response', response.status);\n }\n\n const data = payload.data as ApiResponse<T>;\n const mapped = mapApiResponse(data);\n return mapped.success\n ? mapped\n : {\n ...mapped,\n responseReceived: true,\n responseDefinitive: data.status >= 400 && data.status < 500 && data.status !== 408,\n status: response.status,\n };\n } catch (error) {\n let normalizedError = error instanceof Error ? error : new Error(String(error));\n\n if (error instanceof DOMException && error.name === 'AbortError') {\n normalizedError = new NetworkError('Request timeout', 408);\n }\n\n // Read from the base class, not NetworkError: a named ApiError also\n // carries the HTTP status, and losing it would misclassify a 400\n // refusal as a transport failure — retried and reported as an outage.\n const statusCode =\n normalizedError instanceof ShoppexError\n ? normalizedError.statusCode\n : undefined;\n\n lastFailure = {\n message: normalizedError.message,\n statusCode,\n isTransport: statusCode === undefined || statusCode === 408,\n responseReceived,\n responseDefinitive,\n ...(normalizedError instanceof ApiError\n ? {\n code: normalizedError.code,\n ...(normalizedError.errorParams ? { errorParams: normalizedError.errorParams } : {}),\n }\n : {}),\n };\n\n // A named 4xx is the server's decision, not a transport hiccup:\n // `ApiError` only exists when the response carried an error code, and\n // a client-error status means the request itself was refused. Repeating\n // it verbatim cannot change the answer — it just multiplies the load\n // and delays the refusal the caller is waiting on by the full backoff\n // schedule. 408 stays retryable (it is a timeout wearing a 4xx) and\n // every 5xx, network failure and unnamed error retries exactly as\n // before.\n const isNamedClientRefusal =\n normalizedError instanceof ApiError\n && statusCode !== undefined\n && statusCode >= 400\n && statusCode < 500\n && statusCode !== 408;\n\n if (isNamedClientRefusal) {\n break;\n }\n\n if (attempt < retryCount) {\n await sleep(Math.pow(2, attempt) * 500);\n continue;\n }\n }\n }\n\n return {\n success: false,\n message: lastFailure?.message ?? 'Unknown error',\n ...(lastFailure ? { responseReceived: lastFailure.responseReceived } : {}),\n ...(lastFailure?.responseDefinitive ? { responseDefinitive: true } : {}),\n ...(lastFailure?.responseReceived && lastFailure.statusCode !== undefined\n ? { status: lastFailure.statusCode }\n : {}),\n ...(lastFailure?.code ? { code: lastFailure.code } : {}),\n ...(lastFailure?.errorParams ? { errorParams: lastFailure.errorParams } : {}),\n };\n };\n\n // Every cached payload is specific to the audience it was fetched for, so\n // the key carries the locale and (for priced reads) the buyer currency. A\n // locale or currency switch reads its own entry rather than the previous\n // audience's payload for up to the TTL.\n const result =\n method === 'GET' && cache && cache.ttl > 0\n ? await getOrFetch(\n `${locale ?? ''}|${buyerCurrency ?? ''}|${cache.key ?? `GET:${url}`}`,\n executeRequest,\n { ttl: cache.ttl, staleWhileRevalidate: cache.staleWhileRevalidate },\n (value) => value.success\n )\n : await executeRequest();\n\n const failureForTelemetry = lastFailure as FailureInfo | null;\n\n if (!result.success && failureForTelemetry?.isTransport) {\n\n await reportStorefrontClientError({\n endpoint,\n method,\n message: result.message ?? failureForTelemetry.message,\n statusCode: failureForTelemetry.statusCode,\n attemptCount: retryCount + 1,\n requestUrl: url,\n responseReceived: failureForTelemetry.responseReceived,\n });\n }\n\n return result;\n}\n\nasync function parseResponsePayload(response: Response): Promise<ParsedResponsePayload> {\n try {\n const rawText = await response.text();\n if (!rawText) {\n return { data: null, rawText: null };\n }\n\n try {\n return {\n data: JSON.parse(rawText) as unknown,\n rawText: null,\n };\n } catch {\n const normalizedText = rawText.trim();\n return {\n data: null,\n rawText: normalizedText.length > 0 ? normalizedText : null,\n };\n }\n } catch {\n return { data: null, rawText: null };\n }\n}\n\nfunction isDefinitiveHttpRefusal(payload: unknown): boolean {\n if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n return false;\n }\n\n const record = payload as Record<string, unknown>;\n return typeof record.status === 'number' && record.status >= 400 && record.status < 500;\n}\n\nfunction mapApiResponse<T>(apiResponse: ApiResponse<T>): SDKResponse<T> {\n if (apiResponse.status >= 200 && apiResponse.status < 300) {\n return {\n success: true,\n data: apiResponse.data,\n ...(apiResponse.message ? { message: apiResponse.message } : {}),\n };\n }\n\n return {\n success: false,\n message: apiResponse.error ?? apiResponse.message ?? `Request failed with status ${apiResponse.status}`,\n // The refusal the server actually made, kept machine-readable. Without it\n // a caller can only string-match a localized sentence, which breaks in\n // every locale but one.\n ...readErrorCodeFields(apiResponse),\n };\n}\n\n/**\n * Pull the localized-error envelope (`error_code` / `error_params`) off any\n * server payload shape. Returns an empty object when the payload carries none,\n * so the fields stay absent rather than becoming `undefined` keys.\n */\nfunction readErrorCodeFields(payload: unknown): { code?: string; errorParams?: Record<string, unknown> } {\n if (!payload || typeof payload !== 'object') {\n return {};\n }\n\n const record = payload as Record<string, unknown>;\n const code = typeof record.error_code === 'string' && record.error_code.length > 0\n ? record.error_code\n : null;\n if (!code) {\n return {};\n }\n\n const params = record.error_params;\n return {\n code,\n ...(params && typeof params === 'object' && !Array.isArray(params)\n ? { errorParams: params as Record<string, unknown> }\n : {}),\n };\n}\n\nexport async function get<T>(\n endpoint: string,\n options?: Omit<RequestOptions, 'method' | 'body'>\n): Promise<SDKResponse<T>> {\n return request<T>(endpoint, { ...options, method: 'GET' });\n}\n\nexport async function post<T>(\n endpoint: string,\n body?: unknown,\n options?: Omit<RequestOptions, 'method' | 'body'>\n): Promise<SDKResponse<T>> {\n return request<T>(endpoint, { ...options, method: 'POST', body });\n}\n","import { storefrontStorageKey } from '@shoppex/contracts/storefront-storage-key';\nimport { getConfig, isInitialized } from '../core/config';\nimport { post } from '../core/client';\nimport type { AffiliateValidation, SDKResponse } from '../types';\n\nconst STORAGE_KEY = 'shoppex:affiliate_code:v1';\nconst SESSION_STORAGE_KEY = 'shoppex:affiliate_session:v1';\nconst DEFAULT_TTL_DAYS = 30;\n// 24 base-36 characters provide about 124 bits of entropy and stay within the API's 8-64 character limit.\nconst FALLBACK_SESSION_KEY_LENGTH = 24;\nconst SESSION_KEY_ALPHABET = 'abcdefghijklmnopqrstuvwxyz0123456789';\n\nexport type AffiliateAttributionMode = 'LAST_CLICK' | 'FIRST_CLICK';\n\ntype StoredAffiliate = {\n code: string;\n expiresAt: number;\n /**\n * The attribution mode that applied when this entry was written (ADR-0067).\n *\n * Optional on purpose. The storage key stays `v1` because bumping it would\n * discard every in-flight attribution in every buyer's browser — real,\n * already-earned commission. An entry written before this field existed\n * reads as LAST_CLICK, which is exactly the behaviour it was written under.\n */\n mode?: AffiliateAttributionMode;\n /**\n * The window this entry was written under, in days. Same optionality rule as\n * `mode`: absent on pre-ADR-0067 entries, which then fall back to 30.\n *\n * Kept so a re-landing that cannot reach the server can renew the entry with\n * the shop's window instead of collapsing it to the 30-day default.\n */\n windowDays?: number;\n};\n\nfunction normalizeMode(value: unknown): AffiliateAttributionMode {\n return value === 'FIRST_CLICK' ? 'FIRST_CLICK' : 'LAST_CLICK';\n}\n\nfunction nowMs() {\n return Date.now();\n}\n\nfunction ttlMs(days: number) {\n return Math.max(1, days) * 24 * 60 * 60 * 1000;\n}\n\nfunction normalizeAffiliateCode(code: string | null | undefined): string | null {\n const normalized = code?.trim().toLowerCase();\n return normalized ? normalized : null;\n}\n\nfunction safeRead(): StoredAffiliate | null {\n if (typeof window === 'undefined') return null;\n try {\n const raw = window.localStorage.getItem(storefrontStorageKey(STORAGE_KEY));\n if (!raw) return null;\n const parsed = JSON.parse(raw) as StoredAffiliate;\n if (!parsed || typeof parsed.code !== 'string' || typeof parsed.expiresAt !== 'number') return null;\n return parsed.mode === undefined ? parsed : { ...parsed, mode: normalizeMode(parsed.mode) };\n } catch {\n return null;\n }\n}\n\nfunction safeWrite(value: StoredAffiliate) {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(storefrontStorageKey(STORAGE_KEY), JSON.stringify(value));\n } catch {\n // ignore\n }\n}\n\n/**\n * Write a previously read entry back verbatim (ADR-0067).\n *\n * Distinct from `setAffiliateCode`, which recomputes `expiresAt` from now:\n * restoring a first-click hold must not extend its window, because the window\n * runs from the click that earned it.\n */\nfunction restoreStoredAffiliate(value: StoredAffiliate): void {\n safeWrite(value);\n}\n\nexport function setAffiliateCode(\n code: string | null | undefined,\n ttlDays = DEFAULT_TTL_DAYS,\n mode?: AffiliateAttributionMode,\n): string | null {\n const normalized = normalizeAffiliateCode(code);\n if (!normalized) {\n clearAffiliateCode();\n return null;\n }\n\n safeWrite({\n code: normalized,\n expiresAt: nowMs() + ttlMs(ttlDays),\n windowDays: ttlDays,\n ...(mode ? { mode } : {}),\n });\n return normalized;\n}\n\n/**\n * The stored attribution, or null when nothing valid is held.\n *\n * Unlike `getAffiliateCode()` this also reports the mode the entry was written\n * under, which is what `captureAffiliateFromUrl` needs BEFORE it decides\n * whether it may overwrite.\n */\nexport function getStoredAffiliate(): {\n code: string;\n mode: AffiliateAttributionMode;\n windowDays: number;\n /**\n * When this entry expires, as written. Reported so a hold that has to be put\n * back after an early overwrite keeps its original expiry — the window runs\n * from the click that earned it, not from the landing that failed to take it.\n */\n expiresAt: number;\n} | null {\n const stored = safeRead();\n if (!stored) return null;\n if (stored.expiresAt <= nowMs()) {\n clearAffiliateCode();\n return null;\n }\n\n const code = normalizeAffiliateCode(stored.code);\n if (!code) return null;\n\n const windowDays = typeof stored.windowDays === 'number' && stored.windowDays > 0\n ? stored.windowDays\n : DEFAULT_TTL_DAYS;\n\n return { code, mode: normalizeMode(stored.mode), windowDays, expiresAt: stored.expiresAt };\n}\n\nexport function clearAffiliateCode(): void {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.removeItem(storefrontStorageKey(STORAGE_KEY));\n } catch {\n // ignore\n }\n}\n\nexport function getAffiliateCode(): string | null {\n const stored = safeRead();\n if (!stored) return null;\n if (stored.expiresAt <= nowMs()) {\n clearAffiliateCode();\n return null;\n }\n return normalizeAffiliateCode(stored.code);\n}\n\nfunction createAffiliateSessionKey(): string {\n try {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n } catch {\n // Fall through to the browser-safe random key.\n }\n\n let key = '';\n for (let index = 0; index < FALLBACK_SESSION_KEY_LENGTH; index += 1) {\n key += SESSION_KEY_ALPHABET[Math.floor(Math.random() * SESSION_KEY_ALPHABET.length)];\n }\n return key;\n}\n\n// Retained for the page's lifetime when sessionStorage is unavailable, so\n// repeated events in a storage-restricted browser still share one key and the\n// server-side session dedupe keeps working.\nlet inMemorySessionKey: string | null = null;\n\nfunction getAffiliateSessionKey(): string {\n try {\n const stored = window.sessionStorage.getItem(storefrontStorageKey(SESSION_STORAGE_KEY));\n if (stored && stored.length >= 8 && stored.length <= 64) {\n return stored;\n }\n } catch {\n // Read blocked entirely: the retained key is all we have.\n if (inMemorySessionKey) return inMemorySessionKey;\n }\n\n const key = createAffiliateSessionKey();\n try {\n window.sessionStorage.setItem(storefrontStorageKey(SESSION_STORAGE_KEY), key);\n // A write that silently no-ops (quota) must not hand out a fresh key per\n // event — verify it landed before trusting storage over the retained key.\n if (window.sessionStorage.getItem(storefrontStorageKey(SESSION_STORAGE_KEY)) === key) {\n inMemorySessionKey = key;\n return key;\n }\n } catch {\n // Fall through to the retained key.\n }\n\n if (!inMemorySessionKey) inMemorySessionKey = key;\n return inMemorySessionKey;\n}\n\nexport async function trackAffiliateEvent(\n eventType: 'add_to_cart' | 'checkout_started',\n options?: {\n /**\n * The code the surrounding call actually resolved and submitted (e.g.\n * checkout()'s tri-state result). `null` means the caller explicitly\n * submitted WITHOUT a referral — no event is recorded, so an ambient\n * stored code is never credited for a sale it did not get. Omit the\n * options object entirely to attribute to the stored ambient code.\n */\n code: string | null;\n /**\n * Overrides the per-browser-session dedupe key. checkout entry points\n * pass `inv:<invoiceId>` so every created invoice counts as exactly one\n * checkout — a session-wide key would drop the second checkout of a\n * buyer who orders twice in one session while both sales still count.\n */\n dedupeKey?: string;\n }\n): Promise<void> {\n try {\n // A preview page (an unpublished draft) credits no affiliate funnel.\n if (typeof window === 'undefined' || !isInitialized() || getConfig().preview) return;\n\n const code = options === undefined\n ? getAffiliateCode()\n : normalizeAffiliateCode(options.code);\n if (!code) return;\n\n const config = getConfig();\n // Raw fetch instead of the shared post helper: `keepalive` lets the\n // request survive the checkout redirect that immediately follows, which\n // would otherwise cancel it and undercount checkouts.\n await fetch(`${config.apiBaseUrl}/v1/storefront/affiliates/events`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n keepalive: true,\n body: JSON.stringify({\n shop_slug: config.storeSlug,\n code,\n event_type: eventType,\n // Dedupe key: per browser session by default (one add-to-cart per\n // session per link), or the caller's key — checkout passes one per\n // created invoice.\n session_key: options?.dedupeKey?.slice(0, 64) ?? getAffiliateSessionKey(),\n }),\n });\n } catch {\n // Funnel tracking must never break cart or checkout behavior.\n }\n}\n\nexport async function validateAffiliateCode(code: string): Promise<SDKResponse<AffiliateValidation>> {\n const normalizedCode = normalizeAffiliateCode(code);\n if (!normalizedCode) {\n return {\n success: false,\n data: {\n valid: false,\n affiliate_code: null,\n discount_active: false,\n discount_percent: 0,\n },\n message: 'Affiliate code is required',\n };\n }\n\n const config = getConfig();\n // The attribution the browser already holds, so the response can report ITS\n // policy too (ADR-0067). `applyAffiliateCode` below needs that to know\n // whether storing this code would take a sale away from a protected\n // first-click hold.\n const held = getStoredAffiliate();\n const response = await post<AffiliateValidation>(\n '/v1/storefront/affiliates/resolve',\n {\n shop_slug: config.storeSlug,\n code: normalizedCode,\n ...(held && held.code !== normalizedCode ? { held_code: held.code } : {}),\n },\n { retries: 0 }\n );\n\n if (!response.success) {\n return response;\n }\n\n if (!response.data?.valid || !response.data.affiliate_code) {\n const programDisabled = response.data?.program_enabled === false;\n return {\n success: false,\n data: {\n valid: false,\n ...(response.data?.program_enabled !== undefined ? { program_enabled: response.data.program_enabled } : {}),\n affiliate_code: null,\n discount_active: false,\n discount_percent: 0,\n },\n message: response.message\n ?? (programDisabled ? 'Affiliate program is disabled for this shop.' : 'Invalid affiliate code.'),\n };\n }\n\n return {\n success: true,\n data: {\n valid: true,\n ...(response.data.program_enabled !== undefined ? { program_enabled: response.data.program_enabled } : {}),\n affiliate_code: normalizeAffiliateCode(response.data.affiliate_code),\n discount_active: Boolean(response.data.discount_active),\n discount_percent: Number(response.data.discount_percent ?? 0),\n // Passed through rather than dropped: a caller that stores the code has\n // no other way to learn the policy, and defaulting to 30-day last-click\n // would quietly discard a first-click tier and any custom window.\n attribution_mode: normalizeMode(response.data.attribution_mode),\n attribution_window_days: typeof response.data.attribution_window_days === 'number'\n && response.data.attribution_window_days >= 1\n ? Math.trunc(response.data.attribution_window_days)\n : DEFAULT_TTL_DAYS,\n held_attribution_mode: response.data.held_attribution_mode === 'FIRST_CLICK'\n || response.data.held_attribution_mode === 'LAST_CLICK'\n ? response.data.held_attribution_mode\n : null,\n },\n ...(response.message ? { message: response.message } : {}),\n };\n}\n\n/**\n * Validate a manually entered code and store it (ADR-0067).\n *\n * Attribution is governed by the same rules as a `?ref=` landing, deliberately:\n * a themed \"apply code\" box must not be a way around first-click, or the rule\n * is bypassed by any storefront that offers one. So a still-protected hold\n * keeps the sale, and the stored entry always carries the mode and window the\n * server just reported — the old unconditional `setAffiliateCode(code)` wrote\n * a 30-day last-click entry whatever the shop or tier had configured.\n *\n * The result reports what is now ATTRIBUTED, not merely what was validated:\n * `affiliate_code` carries the winning code and `applied` says whether that is\n * the one you passed. The documented integration hands `affiliate_code`\n * straight to `checkout({ affiliateCode })`, and an explicit checkout code\n * overrides storage — so returning the losing code here would credit it and\n * walk right around the hold this function just honoured.\n */\nexport async function applyAffiliateCode(code: string): Promise<SDKResponse<AffiliateValidation>> {\n const held = getStoredAffiliate();\n const result = await validateAffiliateCode(code);\n\n if (result.success && result.data?.affiliate_code) {\n const applied = result.data.affiliate_code;\n const holdsOtherCode = held !== null && held.code !== applied;\n // The server's answer about the HELD code decides, never the arriving\n // one's; null means it no longer resolves, and the stored mode is then all\n // that is left.\n const heldMode = holdsOtherCode\n ? (result.data.held_attribution_mode ?? held.mode)\n : null;\n\n if (heldMode === 'FIRST_CLICK' && held) {\n return {\n ...result,\n data: { ...result.data, affiliate_code: held.code, applied: false },\n };\n }\n\n setAffiliateCode(\n applied,\n result.data.attribution_window_days ?? DEFAULT_TTL_DAYS,\n result.data.attribution_mode,\n );\n return { ...result, data: { ...result.data, applied: true } };\n }\n\n return result;\n}\n\n/**\n * Capture an affiliate code from the current URL and store it (ADR-0067).\n *\n * Example:\n * - URL: https://mystore.com/product/abc?ref=deadbeef\n * - captureAffiliateFromUrl() stores \"deadbeef\" and returns it.\n *\n * Under LAST_CLICK (the default, and the only behaviour before ADR-0067) a new\n * `?ref=` replaces whatever was stored. Under FIRST_CLICK an existing,\n * unexpired attribution wins and the new code is NOT stored — the landing is\n * still reported to the server so the affiliate's click statistics stay\n * honest, but the credit stays with whoever was there first.\n *\n * The mode comes from the server, which means the FIRST landing in a browser\n * can never be blocked by it — correct, because there is nothing to protect\n * yet. From then on the mode travels with the stored entry.\n *\n * Enforcement is client-side. A buyer who edits localStorage can re-attribute\n * their own visit; this is the same trust level as the window itself and must\n * not be presented to merchants as fraud protection.\n */\nexport async function captureAffiliateFromUrl(param = 'ref'): Promise<string | null> {\n if (typeof window === 'undefined') return null;\n\n let code: string | null = null;\n try {\n const url = new URL(window.location.href);\n const raw = url.searchParams.get(param);\n code = raw ? raw.trim() : null;\n } catch {\n code = null;\n }\n\n code = normalizeAffiliateCode(code);\n if (!code) return null;\n\n // Read BEFORE writing: under first-click the held entry is the one that\n // counts, and the old \"store immediately\" would have destroyed it.\n const held = getStoredAffiliate();\n // A DIFFERENT attribution is held, so this landing can take a sale away from\n // someone. Whether it may is the server's answer below.\n const holdsOtherCode = held !== null && held.code !== code;\n // The stored mode can be stale. Preserve every different held code until\n // the server resolves its policy, including while checkout reads storage.\n if (!holdsOtherCode) {\n // Store immediately so we don't lose it if the attribution call fails.\n // The window is the previous one we were told about, not a fixed 30 days —\n // a shop with a 90-day window must not silently drop to 30 when the\n // attribution call fails and this early write is all that survives.\n setAffiliateCode(code, held?.windowDays ?? DEFAULT_TTL_DAYS, held?.mode);\n }\n\n // Optional: validate + normalize with backend. If invalid, clear it.\n if (isInitialized()) {\n try {\n const config = getConfig();\n const res = await post<{\n accepted?: boolean;\n affiliate_code?: string | null;\n attribution_mode?: string | null;\n attribution_window_days?: number | null;\n held_attribution_mode?: string | null;\n }>(\n '/v1/storefront/affiliates/attribution',\n {\n shop_slug: config.storeSlug,\n code,\n // Sent so the server can report the policy of the attribution we\n // already hold. Its mode — not the arriving code's — decides whether\n // that hold may be released.\n ...(held ? { held_code: held.code } : {}),\n },\n { retries: 0 }\n );\n\n const serverMode = res.success && res.data?.attribution_mode\n ? normalizeMode(res.data.attribution_mode)\n : null;\n const serverWindow = res.success && typeof res.data?.attribution_window_days === 'number'\n ? res.data.attribution_window_days\n : DEFAULT_TTL_DAYS;\n\n // The shop may have switched to last-click since the entry was written, and the\n // server is the authority — without this check a stale FIRST_CLICK entry\n // would keep winning for up to a full window (365 days) and pay the\n // wrong affiliate on every sale in between.\n // Whether the hold survives is decided by the HELD code's current\n // policy, never by the arriving one. Affiliate A stored under a\n // first-click tier must keep the sale even when affiliate B arrives from\n // a last-click tier — using B's mode here would hand B the commission.\n // `held_attribution_mode` is null when the server no longer resolves the\n // held code; the stored mode is then the only information left.\n const heldMode = res.success && res.data?.held_attribution_mode\n ? normalizeMode(res.data.held_attribution_mode)\n : null;\n const holdsFirstClick = holdsOtherCode && (heldMode ?? held?.mode) === 'FIRST_CLICK';\n\n if (holdsFirstClick && held) {\n // First-click still applies: keep the first attribution. Its expiry is\n // deliberately NOT extended — the window runs from the click that\n // earned it.\n restoreStoredAffiliate({\n code: held.code,\n expiresAt: held.expiresAt,\n windowDays: held.windowDays,\n mode: heldMode ?? held.mode,\n });\n return held.code;\n }\n\n if (res.success && res.data?.accepted && res.data.affiliate_code) {\n setAffiliateCode(res.data.affiliate_code, serverWindow, serverMode ?? undefined);\n return res.data.affiliate_code;\n }\n // Clear only on a definitive refusal (the server answered and said the\n // code is not attributable). A rate limit or transport failure must not\n // destroy a valid referral before checkout — from-cart validates later.\n if (res.success && res.data && res.data.accepted === false) {\n if (holdsOtherCode) return held.code;\n clearAffiliateCode();\n return null;\n }\n // Reached on a non-success response (`post()` resolves rather than\n // throws on an HTTP failure, e.g. the route's 429). Nothing was\n // overwritten in that case, so returning the arriving code would hand a\n // custom storefront that submits this value manually to the newcomer\n // while storage still holds the first click. Same answer as the catch\n // below, for the same reason.\n return holdsOtherCode ? held.code : code;\n } catch {\n // Without a policy response, preserve the existing attribution.\n return holdsOtherCode ? held.code : code;\n }\n }\n\n // Not initialized: preserve any different held attribution.\n return holdsOtherCode ? held.code : code;\n}\n","/**\n * The buyer's cookie banner choice as it travels: the storefront cookie, the\n * checkout URL hash, and which category each integration needs. No zod here:\n * the storefront SDK bundles this module, the settings schemas stay in\n * `storefront-cookie-consent.ts`.\n */\nimport type { CookieConsentCategory } from './storefront-cookie-consent.js';\n\n/**\n * The buyer's choice, a first-party cookie on the storefront host, matched\n * whole (`v1.f0.a1.m0`) and never decoded. A value of another version counts\n * as no choice, so bumping the version asks every buyer again.\n */\nexport const COOKIE_CONSENT_VERSION = 1;\nexport const COOKIE_CONSENT_COOKIE = 'shoppex_consent';\n\n/**\n * The hosted checkout (another site) cannot read the storefront's cookie, so\n * the SDK carries the value in the checkout URL's hash under this key.\n */\nexport const COOKIE_CONSENT_CHECKOUT_HASH_KEY = 'shoppex_consent';\n\nexport type CookieConsentChoice = Record<CookieConsentCategory, boolean>;\n\nconst COOKIE_CONSENT_VALUE = new RegExp(`^v${COOKIE_CONSENT_VERSION}\\\\.f([01])\\\\.a([01])\\\\.m([01])$`);\n\n/** The choice a cookie value records, or null for anything that is not one. */\nexport function parseCookieConsentValue(value: string | null | undefined): CookieConsentChoice | null {\n const match = value ? COOKIE_CONSENT_VALUE.exec(value) : null;\n return match ? { functional: match[1] === '1', analytics: match[2] === '1', marketing: match[3] === '1' } : null;\n}\n\n/**\n * Which category each integration needs. Chat widgets are `functional`: each\n * sets its own third-party cookies on page load, before the buyer asked for\n * help, so none is strictly necessary (Intercom also records visits; it stays\n * functional because merchants enable it as their support chat). Google Tag\n * Manager is `marketing`: a container can fire any ad tag, so it needs the\n * stricter category; Consent Mode tells the tags inside what else was allowed.\n */\nexport const INTEGRATION_CONSENT_CATEGORIES: Record<string, CookieConsentCategory> = {\n google_analytics: 'analytics',\n microsoft_clarity: 'analytics',\n hotjar: 'analytics',\n plausible: 'analytics',\n google_tag_manager: 'marketing',\n meta_pixel: 'marketing',\n tiktok_pixel: 'marketing',\n google_ads: 'marketing',\n reddit_pixel: 'marketing',\n snapchat_pixel: 'marketing',\n pinterest_tag: 'marketing',\n crisp: 'functional',\n tawk_to: 'functional',\n livechat: 'functional',\n intercom: 'functional',\n chatwoot: 'functional',\n};\n","/**\n * Analytics session of this tab (web analytics, Design Batch 3 feature 1).\n *\n * Storing an id in the browser needs consent (TTDSG/TDDDG §25), so every\n * stored analytics value here exists only after a yes to \"analytics\" on the\n * shop's cookie banner (the `shoppex_consent` cookie). Without that yes the\n * storefront is still counted, cookieless: the server derives the visit from\n * a daily-salted hash and nothing is kept in the browser. Global Privacy\n * Control and Do Not Track count as a no. A no (or a withdrawn yes) removes\n * what was stored.\n *\n * - session id: sessionStorage, ends after 30 minutes without a page view,\n * or on a new landing: a page reached from another site or another\n * campaign than the one the session started with, also when it started\n * direct (the server then starts a new visit, and one session never spans\n * two visits). A new landing from another site drops the stored campaign.\n * - visits: localStorage, the session ids of the last 30 days (newest first,\n * at most 20). Checkout sends them so the server can find where the buyer\n * came from; the server reads every source fact itself.\n * - time on screen: counted in memory while the tab is visible and sent with\n * the next page view, or as `page_leave` when the tab is hidden, to the\n * session the page was viewed in.\n * - a yes given without a reload (`shoppex:consent`) starts the session on a\n * page already counted (`session_start`).\n *\n * `packages/storefront-host/src/pageTracker.installScript.ts` repeats these\n * rules for code storefronts; `pageTracker.test.ts` locks the parity.\n */\n\nimport { COOKIE_CONSENT_COOKIE, parseCookieConsentValue } from '@shoppex/contracts/storefront-consent-choice';\nimport { storefrontStorageKey } from '@shoppex/contracts/storefront-storage-key';\nimport { getItem, removeItem, setItem } from '../utils/storage';\n\nexport const ANALYTICS_SESSION_IDLE_MS = 30 * 60 * 1000;\nexport const ANALYTICS_VISITS_WINDOW_MS = 30 * 24 * 60 * 60 * 1000;\nexport const ANALYTICS_VISITS_MAX = 20;\n/** Same cap as the ping route: a visit stops counting after 30 minutes on one page. */\nexport const MAX_ENGAGED_MS_PER_PAGE = 30 * 60 * 1000;\n/** Key prefix of the stored landing campaign (`attribution.ts`). */\nexport const UTM_STORAGE_PREFIX = 'shoppex:utm:';\n\n/** Storage keys (the storage wrapper adds the `shoppex_` prefix). */\nexport const analyticsSessionKey = (storeSlug: string) => `analytics_session_${storeSlug}`;\nexport const analyticsVisitsKey = (storeSlug: string) => `analytics_visits_${storeSlug}`;\n\ninterface StoredSession {\n id: string;\n /** Epoch ms of the last page view. */\n at: number;\n /** Referrer host the session started with ('' for none). */\n r?: string;\n /** utm source|medium|campaign the session started with ('' for none). */\n u?: string;\n}\n\n/** Where this page came from: another site's host and the URL's campaign ('' for none). */\nfunction pageLanding(): { r: string; u: string } {\n let r = '';\n try {\n r = document.referrer ? new URL(document.referrer).hostname : '';\n } catch {\n // An unreadable referrer names no other site.\n }\n const params = new URLSearchParams(window.location?.search ?? '');\n const u = ['source', 'medium', 'campaign'].map((key) => params.get(`utm_${key}`)?.trim().toLowerCase() ?? '').join('|');\n return { r: r === window.location?.hostname ? '' : r, u: u === '||' ? '' : u };\n}\n\nexport type AnalyticsConsent = 'granted' | 'declined' | 'unknown';\n\nexport function readAnalyticsConsent(): AnalyticsConsent {\n if (typeof document === 'undefined' || typeof navigator === 'undefined') return 'unknown';\n const privacy = navigator as Navigator & { globalPrivacyControl?: boolean };\n if (privacy.globalPrivacyControl === true || privacy.doNotTrack === '1') return 'declined';\n const prefix = `${COOKIE_CONSENT_COOKIE}=`;\n let raw: string | undefined;\n try {\n raw = document.cookie.split(/;\\s*/).find((part) => part.startsWith(prefix))?.slice(prefix.length);\n } catch {\n // A sandboxed frame without its own origin cannot read cookies: no yes was given here.\n return 'unknown';\n }\n const choice = parseCookieConsentValue(raw ?? null);\n if (!choice) return 'unknown';\n return choice.analytics ? 'granted' : 'declined';\n}\n\nfunction readVisits(storeSlug: string, now: number): StoredSession[] {\n const stored = getItem<StoredSession[]>(analyticsVisitsKey(storeSlug));\n if (!Array.isArray(stored)) return [];\n return stored.filter((visit) => typeof visit?.id === 'string' && typeof visit.at === 'number' && now - visit.at < ANALYTICS_VISITS_WINDOW_MS);\n}\n\n/** Removes every stored analytics value of this shop (no consent, or withdrawn). */\nexport function forgetAnalyticsData(storeSlug: string): void {\n removeItem(analyticsSessionKey(storeSlug), 'sessionStorage');\n removeItem(analyticsVisitsKey(storeSlug));\n}\n\n/**\n * The tab's session id after an analytics yes, else null (and nothing stored).\n * `touch` (a page view) starts a session after 30 idle minutes and restarts\n * the idle time; without it the current session is only read.\n */\nexport function analyticsSessionId(storeSlug: string, options: { touch: boolean }, now = Date.now()): string | null {\n // SDK 1.0.102 and older kept a presence id here, without consent.\n removeItem(`presence_connection_${storeSlug}`);\n if (readAnalyticsConsent() !== 'granted') {\n forgetAnalyticsData(storeSlug);\n return null;\n }\n const stored = getItem<StoredSession>(analyticsSessionKey(storeSlug), 'sessionStorage');\n const live = stored && typeof stored.id === 'string' && typeof stored.at === 'number' && now - stored.at < ANALYTICS_SESSION_IDLE_MS\n ? stored.id\n : null;\n if (!options.touch) return live;\n const landing = pageLanding();\n // A page without a referrer or campaign of its own (inside the store)\n // continues the session; any other one than the session began with, also\n // after a direct start, is a new landing.\n const newLanding = (landing.r && landing.r !== stored?.r) || (landing.u && landing.u !== stored?.u);\n if (live && !newLanding) {\n setItem<StoredSession>(analyticsSessionKey(storeSlug), { ...stored, id: live, at: now }, 'sessionStorage');\n return live;\n }\n if (typeof crypto === 'undefined' || typeof crypto.randomUUID !== 'function') return null;\n // The campaign of the visit before must not tag this one; a campaign of\n // this page is stored again with its page view.\n if (landing.r) {\n try {\n globalThis.localStorage.removeItem(storefrontStorageKey(`${UTM_STORAGE_PREFIX}${storeSlug}`));\n } catch {\n // Storage blocked: nothing is stored either.\n }\n }\n const id = crypto.randomUUID();\n setItem<StoredSession>(analyticsSessionKey(storeSlug), { id, at: now, ...landing }, 'sessionStorage');\n setItem<StoredSession[]>(\n analyticsVisitsKey(storeSlug),\n [{ id, at: now }, ...readVisits(storeSlug, now)].slice(0, ANALYTICS_VISITS_MAX),\n );\n return id;\n}\n\n/** What a checkout sends about where the buyer came from (`attribution`). */\nexport function checkoutAttribution(storeSlug: string, now = Date.now()): { session_ids: string[] } | { declined: true } | undefined {\n const consent = readAnalyticsConsent();\n if (consent === 'declined') {\n forgetAnalyticsData(storeSlug);\n return { declined: true };\n }\n if (consent === 'unknown') return undefined;\n const sessionIds = readVisits(storeSlug, now).map((visit) => visit.id);\n return sessionIds.length > 0 ? { session_ids: sessionIds } : undefined;\n}\n\nlet engagedMs = 0;\nlet visibleSince: number | null = null;\nlet clockInstalled = false;\nlet pageViewed = false;\n// The session this page was viewed in. Its time on screen belongs there even\n// when 30 idle minutes end that session before the next view or page_leave.\nlet pageSession: string | null = null;\n\n/** Records that this page's view went out, in `sessionId` (null: counted cookieless). */\nexport function markPageViewed(sessionId: string | null): void {\n pageViewed = true;\n pageSession = sessionId;\n}\n\n/** The session this page's time on screen belongs to; null before a view or without one. */\nexport function currentPageSession(): string | null {\n return pageSession;\n}\n\n/** Whether this page's view already went out (a later yes then starts a session for it). */\nexport function isPageViewed(): boolean {\n return pageViewed;\n}\n\nfunction settleClock(now: number): void {\n if (visibleSince !== null) {\n engagedMs += now - visibleSince;\n visibleSince = document.visibilityState === 'visible' ? now : null;\n }\n}\n\nlet consentListenerInstalled = false;\n\n/** Calls `onYes` (once per page install) when the buyer says yes to analytics without a reload. */\nexport function onAnalyticsConsent(onYes: () => void): void {\n if (consentListenerInstalled || typeof window === 'undefined') return;\n consentListenerInstalled = true;\n // The banner dispatches `shoppex:consent` on every choice (and once on load for a stored one).\n window.addEventListener('shoppex:consent', () => {\n if (readAnalyticsConsent() === 'granted') onYes();\n });\n}\n\n/** Starts counting time on screen (once per page). */\nexport function installEngagedClock(onHidden: () => void): void {\n if (clockInstalled || typeof document === 'undefined') return;\n clockInstalled = true;\n visibleSince = document.visibilityState === 'visible' ? Date.now() : null;\n document.addEventListener('visibilitychange', () => {\n const now = Date.now();\n if (document.visibilityState === 'visible') {\n visibleSince ??= now;\n return;\n }\n settleClock(now);\n visibleSince = null;\n onHidden();\n });\n // A page restored from the back/forward cache fires no visibilitychange.\n window.addEventListener('pagehide', () => {\n settleClock(Date.now());\n visibleSince = null;\n onHidden();\n });\n window.addEventListener('pageshow', (event) => {\n if (event.persisted && document.visibilityState === 'visible') visibleSince = Date.now();\n });\n}\n\n/** Time on screen since the last take, capped per page; the clock restarts. */\nexport function takeEngagedMs(now = Date.now()): number {\n settleClock(now);\n const taken = Math.min(Math.max(0, Math.round(engagedMs)), MAX_ENGAGED_MS_PER_PAGE);\n engagedMs = 0;\n return taken;\n}\n\n/** Test hook: the clock is page state. */\nexport function resetEngagedClockForTests(): void {\n engagedMs = 0;\n visibleSince = null;\n clockInstalled = false;\n pageViewed = false;\n pageSession = null;\n consentListenerInstalled = false;\n}\n","/**\n * UTM attribution for storefront page views.\n *\n * Campaign parameters only appear on the landing URL, but a visitor usually\n * browses several pages before doing anything interesting. Without persistence\n * every page after the first would be attributed to \"direct\" and the numbers\n * would understate every campaign.\n *\n * Last-touch: a fresh set of parameters replaces the stored one, matching what\n * merchants expect from analytics tools — the most recent campaign gets credit.\n * Navigating without parameters keeps whatever was stored, until a new\n * landing from another site starts a new analytics session.\n *\n * Storing needs an analytics yes on the shop's cookie banner (TTDSG §25):\n * without it only the parameters of the current URL are reported and any\n * stored set is removed.\n */\n\nimport { storefrontStorageKey } from '@shoppex/contracts/storefront-storage-key';\nimport { UTM_STORAGE_PREFIX, readAnalyticsConsent } from './analytics-session';\n\nconst TTL_MS = 30 * 24 * 60 * 60 * 1000;\n\nconst UTM_KEYS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'] as const;\n\ntype UtmKey = (typeof UTM_KEYS)[number];\n\nexport type UtmParameters = Partial<Record<UtmKey, string>>;\n\ninterface StoredAttribution {\n utm: UtmParameters;\n /** Epoch ms of the last touch, used for TTL expiry. */\n at: number;\n}\n\n/** Values are merchant-supplied and land in a text column; keep them bounded. */\nconst MAX_VALUE_LENGTH = 255;\n\nfunction readFromUrl(search: string): UtmParameters {\n let params: URLSearchParams;\n try {\n params = new URLSearchParams(search);\n } catch {\n return {};\n }\n\n const utm: UtmParameters = {};\n for (const key of UTM_KEYS) {\n const value = params.get(key)?.trim();\n if (value) {\n utm[key] = value.slice(0, MAX_VALUE_LENGTH);\n }\n }\n return utm;\n}\n\nfunction storageKey(storeSlug: string): string {\n return `${UTM_STORAGE_PREFIX}${storeSlug}`;\n}\n\nfunction readStored(storeSlug: string): UtmParameters {\n try {\n const raw = window.localStorage.getItem(storefrontStorageKey(storageKey(storeSlug)));\n if (!raw) return {};\n\n const parsed = JSON.parse(raw) as StoredAttribution;\n if (!parsed || typeof parsed.at !== 'number' || typeof parsed.utm !== 'object') return {};\n if (Date.now() - parsed.at > TTL_MS) {\n window.localStorage.removeItem(storefrontStorageKey(storageKey(storeSlug)));\n return {};\n }\n\n const utm: UtmParameters = {};\n for (const key of UTM_KEYS) {\n const value = parsed.utm?.[key];\n if (typeof value === 'string' && value.length > 0) {\n utm[key] = value.slice(0, MAX_VALUE_LENGTH);\n }\n }\n return utm;\n } catch {\n // Private mode, quota errors, corrupt JSON — attribution is best-effort and\n // must never break a page view.\n return {};\n }\n}\n\nfunction writeStored(storeSlug: string, utm: UtmParameters): void {\n try {\n const payload: StoredAttribution = { utm, at: Date.now() };\n window.localStorage.setItem(storefrontStorageKey(storageKey(storeSlug)), JSON.stringify(payload));\n } catch {\n // Ignore: the current page view still reports the parameters it just read.\n }\n}\n\n/**\n * Resolves the UTM parameters to report for the current page view.\n *\n * Reads the current URL first; when it carries any campaign parameter that set\n * wins and is persisted. Otherwise the stored set is returned unchanged.\n *\n * @returns the parameters, or undefined when there is nothing to report\n */\nexport function resolveUtmParameters(storeSlug: string): UtmParameters | undefined {\n if (typeof window === 'undefined' || typeof window.location === 'undefined') {\n return undefined;\n }\n\n const fromUrl = readFromUrl(window.location.search);\n if (readAnalyticsConsent() !== 'granted') {\n try {\n window.localStorage.removeItem(storefrontStorageKey(storageKey(storeSlug)));\n } catch {\n // Storage blocked: nothing is stored either.\n }\n return Object.keys(fromUrl).length > 0 ? fromUrl : undefined;\n }\n if (Object.keys(fromUrl).length > 0) {\n writeStored(storeSlug, fromUrl);\n return fromUrl;\n }\n\n const stored = readStored(storeSlug);\n return Object.keys(stored).length > 0 ? stored : undefined;\n}\n","/**\n * The storefront page a view or presence ping reports, for the merchant's live\n * \"Top page\".\n *\n * Only `location.pathname` is read. The query string and fragment are never\n * sent: they can carry emails, sign-in tokens or checkout ids. The API\n * normalises the path again (trailing slash, repeated slashes, length) before\n * it stores it; the cap here only keeps the ping body inside the API's input\n * bound so an unusually long path cannot invalidate the rest of the ping.\n */\nconst MAX_PATH_LENGTH = 256;\n\nexport function resolveStorefrontPagePath(): string | undefined {\n if (typeof window === 'undefined') return undefined;\n\n let pathname: string | undefined;\n try {\n const location = window.location;\n pathname = typeof location?.pathname === 'string' && location.pathname\n ? location.pathname\n : new URL(String(location?.href ?? '')).pathname;\n } catch {\n return undefined;\n }\n\n if (!pathname || !pathname.startsWith('/')) return undefined;\n return pathname.slice(0, MAX_PATH_LENGTH);\n}\n","/**\n * Whether the storefront platform already reports page views and presence.\n *\n * `workers/storefront` injects a small tracker into every code storefront page\n * (`@shoppex/storefront-host/page-tracker`). It sends the same ping this SDK\n * sends, on load, on every client-side navigation and as a 60s presence\n * heartbeat, and it sets this flag before any theme code runs. While the flag\n * is set, `trackPageView()` without cart data and `touchStorefrontPresence()`\n * do nothing, so a theme that also reports views is not counted twice. A\n * `trackPageView(cartValue, itemCount)` still reports the cart the tracker\n * cannot see, as cart activity (`event_type: 'presence'`) that counts no view.\n *\n * The document lane never sets the flag; there the SDK stays the only\n * reporter. The literal is duplicated in the tracker (the worker does not\n * bundle the SDK); the tracker's test locks the two together.\n */\nexport const PLATFORM_PAGE_TRACKER_FLAG = '__shoppexPageTracker';\n\nexport function isPlatformPageTrackerActive(): boolean {\n if (typeof window === 'undefined') return false;\n try {\n return Boolean((window as unknown as Record<string, unknown>)[PLATFORM_PAGE_TRACKER_FLAG]);\n } catch {\n return false;\n }\n}\n","import { isInitialized, getConfig } from '../core/config';\nimport { buildEndpoint } from '../core/endpoint';\nimport {\n analyticsSessionId,\n currentPageSession,\n installEngagedClock,\n isPageViewed,\n markPageViewed,\n onAnalyticsConsent,\n readAnalyticsConsent,\n takeEngagedMs,\n} from '../core/analytics-session';\nimport { resolveUtmParameters } from '../core/attribution';\nimport { resolveStorefrontPagePath } from '../core/page-path';\nimport { isPlatformPageTrackerActive } from '../core/page-tracker';\nimport { getItem, removeItem, setItem } from '../utils/storage';\n\n// Cart reporting state, shared by every tab of the shop through localStorage.\n// A cart change in one tab reaches the others as a `storage` event, and only\n// one tab should send it.\n//\n// Order: every cart state gets a sequence number (`cart_seq`, with its\n// `cart_seq_scope`) when it is reported to the SDK, from a counter shared by\n// all tabs. The server keeps the cart with the highest sequence of the scope\n// and ignores an older one that arrives later, so the order in which pings\n// reach the server no longer decides the live cart, also across tabs.\n//\n// Deduplication keeps two values, so a failed send can never leave an unsent\n// cart looking reported:\n// - confirmed: the acknowledged cart state with the highest sequence (written\n// only after a 2xx response, and only over a lower sequence, the same rule\n// the server applies);\n// - in flight: the cart state a tab is sending right now, with its sequence,\n// its own token and a short lifetime, so a concurrent echo in another tab\n// skips it.\nconst CONFIRMED_CART_STORAGE_PREFIX = 'reported_cart_';\nconst IN_FLIGHT_CART_STORAGE_PREFIX = 'reporting_cart_';\n// Not under `cart_`: storefront-commerce treats every `shoppex_cart_*` storage\n// event as a cart change, so a sequence write there would echo between tabs.\nconst CART_SEQUENCE_STORAGE_PREFIX = 'presence_cart_seq_';\n/**\n * A ping that has not answered after this long is abandoned as failed, so a\n * hung request cannot hold up this tab's later cart sends. A claim older than\n * this belongs to a send that is over (or a tab that closed) and is ignored.\n */\nexport const CART_CLAIM_TTL_MS = 10_000;\n\ntype ReportedCart = { snapshot: string; seq: number };\ntype InFlightCart = ReportedCart & { token: string; at: number };\n\nfunction confirmedCartKey(storeSlug: string): string {\n return `${CONFIRMED_CART_STORAGE_PREFIX}${storeSlug}`;\n}\n\nfunction inFlightCartKey(storeSlug: string): string {\n return `${IN_FLIGHT_CART_STORAGE_PREFIX}${storeSlug}`;\n}\n\nfunction cartSequenceKey(storeSlug: string): string {\n return `${CART_SEQUENCE_STORAGE_PREFIX}${storeSlug}`;\n}\n\nfunction cartSnapshot(cartValue: number | undefined, itemCount: number | undefined): string {\n return `${cartValue ?? ''}|${itemCount ?? ''}`;\n}\n\nfunction isCartSequence(value: unknown): value is number {\n return typeof value === 'number' && Number.isSafeInteger(value) && value > 0;\n}\n\n/**\n * The order of one cart state: a sequence and the scope it belongs to. The\n * server only compares sequences of one scope, so the scope is created with\n * the shared counter and lives in the same localStorage record: every tab that\n * takes a sequence from the counter also takes its scope. The presence\n * connection id is not used for this, because code outside the cart path\n * (heartbeats, the code-storefront page tracker) creates it without the lock.\n */\ntype CartOrder = { scope: string; seq: number };\n\nconst CART_SEQUENCE_SCOPE_MAX_LENGTH = 64;\n\nfunction readCartCounter(storeSlug: string): CartOrder | null {\n const counter = getItem<CartOrder>(cartSequenceKey(storeSlug));\n if (\n !counter\n || typeof counter.scope !== 'string'\n || counter.scope.length === 0\n || counter.scope.length > CART_SEQUENCE_SCOPE_MAX_LENGTH\n || !isCartSequence(counter.seq)\n ) {\n return null;\n }\n return counter;\n}\n\n// The last order this tab handed out: keeps the sequence rising in this tab\n// when localStorage is unavailable.\nlet lastCartOrder: CartOrder | null = null;\n\n/**\n * The next cart order: the counter's scope (created on first use) and the\n * current time in ms, or one above the highest sequence any tab of the shop\n * handed out when that is higher (two changes in the same millisecond, or a\n * clock set back).\n */\nfunction nextCartOrder(storeSlug: string): CartOrder {\n const stored = readCartCounter(storeSlug);\n const scope = stored?.scope ?? lastCartOrder?.scope ?? createClaimToken();\n const floor = Math.max(stored?.seq ?? 0, lastCartOrder?.scope === scope ? lastCartOrder.seq : 0);\n const order: CartOrder = { scope, seq: Math.max(Date.now(), floor + 1) };\n lastCartOrder = order;\n setItem(cartSequenceKey(storeSlug), order);\n return order;\n}\n\ntype CartSequenceLocks = {\n request(name: string, callback: () => CartOrder): Promise<CartOrder>;\n};\n\nfunction cartSequenceLocks(): CartSequenceLocks | null {\n if (typeof navigator === 'undefined') return null;\n const locks = (navigator as { locks?: CartSequenceLocks }).locks;\n return locks && typeof locks.request === 'function' ? locks : null;\n}\n\n/**\n * Reserves the order of a cart state when it is reported to the SDK, not when\n * it is sent, so a state that waited in a queue cannot overtake a newer one\n * reported meanwhile in another tab.\n *\n * The read-increment-write of the shared counter runs under a Web Lock, so two\n * tabs never hand out the same sequence or create two scopes: the server\n * ignores an equal sequence, and does not compare different scopes. Distinct\n * sequences are enough, whichever tab gets the higher one: the tab that\n * reported the older cart receives the newer one as a `storage` echo, reports\n * it with a later sequence, and that is not skipped while the server holds the\n * older cart. Grants follow request order, so this tab's own sequences keep\n * call order.\n *\n * Without Web Locks (browsers before 2022, opaque origins) the counter is\n * updated without the lock: two tabs reporting within the same millisecond can\n * then share a sequence (the server keeps the one that arrives first), and two\n * first-use tabs can create two scopes (the last write wins).\n */\nfunction reserveCartOrder(storeSlug: string): Promise<CartOrder> {\n const take = (): CartOrder => nextCartOrder(storeSlug);\n const locks = cartSequenceLocks();\n if (!locks) return Promise.resolve(take());\n return locks.request(cartSequenceKey(storeSlug), take).catch(take);\n}\n\nfunction readConfirmedCart(storeSlug: string): ReportedCart | null {\n const confirmed = getItem<ReportedCart>(confirmedCartKey(storeSlug));\n if (!confirmed || typeof confirmed.snapshot !== 'string' || !isCartSequence(confirmed.seq)) return null;\n return confirmed;\n}\n\nfunction readInFlightCart(storeSlug: string): InFlightCart | null {\n const claim = getItem<InFlightCart>(inFlightCartKey(storeSlug));\n if (\n !claim\n || typeof claim.snapshot !== 'string'\n || !isCartSequence(claim.seq)\n || typeof claim.token !== 'string'\n || typeof claim.at !== 'number'\n ) {\n return null;\n }\n return claim;\n}\n\n/**\n * Whether the server holds this cart state, or will once the send in flight\n * lands: the in-flight state when some tab is sending one with a higher\n * sequence than the confirmed state (the server keeps the higher one), else\n * the confirmed state. So a cross-tab echo of a state being sent is skipped,\n * and a revert to the confirmed state while another tab sends a newer state\n * still goes out.\n */\nfunction isCartReportedOrInFlight(storeSlug: string, snapshot: string): boolean {\n const confirmed = readConfirmedCart(storeSlug);\n const claim = readInFlightCart(storeSlug);\n const liveClaim = claim && Date.now() - claim.at < CART_CLAIM_TTL_MS ? claim : null;\n const expected = liveClaim && (!confirmed || liveClaim.seq > confirmed.seq) ? liveClaim : confirmed;\n return expected?.snapshot === snapshot;\n}\n\nfunction createClaimToken(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') return crypto.randomUUID();\n return `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`;\n}\n\n/**\n * Claims a cart state for the duration of one send. When the send ends,\n * `settle(delivered)` confirms the state if it was delivered and its sequence\n * is above the confirmed one (a delivered older state was ignored by the\n * server), and clears the claim while it is still this send's.\n */\nfunction claimCartReport(\n storeSlug: string,\n seq: number,\n cartValue?: number,\n itemCount?: number,\n): (delivered: boolean) => void {\n const snapshot = cartSnapshot(cartValue, itemCount);\n const token = createClaimToken();\n setItem<InFlightCart>(inFlightCartKey(storeSlug), { snapshot, seq, token, at: Date.now() });\n return (delivered) => {\n if (delivered) {\n const confirmed = readConfirmedCart(storeSlug);\n if (!confirmed || seq > confirmed.seq) setItem<ReportedCart>(confirmedCartKey(storeSlug), { snapshot, seq });\n }\n if (readInFlightCart(storeSlug)?.token === token) removeItem(inFlightCartKey(storeSlug));\n };\n}\n\n// Cart-carrying pings of this tab go out one at a time. The server orders cart\n// states by sequence, so this queue is not what keeps the order: it coalesces.\n// A cart change that waited while a newer one was asked for is dropped (only\n// the newest cart state is worth sending), and a change is checked against the\n// shared state when its turn comes, after this tab's earlier send settled.\n// Page views are never dropped.\nlet cartSendTail: Promise<void> = Promise.resolve();\nlet latestCartRequest = 0;\n\nfunction enqueueCartSend(send: (isLatest: () => boolean) => Promise<void>): Promise<void> {\n const request = ++latestCartRequest;\n const run = () => send(() => request === latestCartRequest);\n cartSendTail = cartSendTail.then(run, run);\n return cartSendTail;\n}\n\nasync function postPing(body: Record<string, unknown>): Promise<boolean> {\n const config = getConfig();\n const controller = typeof AbortController === 'undefined' ? undefined : new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timedOut = new Promise<false>((resolve) => {\n timer = setTimeout(() => {\n controller?.abort();\n resolve(false);\n }, CART_CLAIM_TTL_MS);\n });\n try {\n const endpoint = buildEndpoint('/v1/storefront/shops/:storeSlug/ping', {\n storeSlug: config.storeSlug,\n });\n const delivered = fetch(`${config.apiBaseUrl}${endpoint}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: controller?.signal,\n }).then((response) => response.ok);\n return await Promise.race([delivered, timedOut]);\n } catch {\n // Intentionally silent - analytics should never block the user experience\n return false;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Counts a page view. Call it once per page load or client-side navigation.\n * Passing the cart also records it for the live visitor map.\n */\nexport async function trackPageView(cartValue?: number, itemCount?: number): Promise<void> {\n if (!isInitialized()) return;\n if (typeof document === 'undefined') return;\n const config = getConfig();\n const carriesCart = cartValue !== undefined || itemCount !== undefined;\n const reservedOrder = carriesCart ? reserveCartOrder(config.storeSlug) : undefined;\n // Code storefronts: the edge-injected tracker already counted this view. It\n // never knows the cart, so the cart still goes out, as cart activity that\n // does not count a second view. Sent on every page load, like a view.\n if (isPlatformPageTrackerActive()) {\n if (reservedOrder) await enqueueCartSend(async () => sendCartActivity(await reservedOrder, cartValue, itemCount));\n return;\n }\n\n const sendView = async (): Promise<void> => {\n const order = reservedOrder ? await reservedOrder : undefined;\n const settle = order ? claimCartReport(config.storeSlug, order.seq, cartValue, itemCount) : undefined;\n const sessionId = analyticsSessionId(config.storeSlug, { touch: true });\n // The page before belongs to the session it was viewed in, which 30 idle\n // minutes may have ended: its time goes there, not into the new session.\n const previousSession = currentPageSession();\n if (previousSession && previousSession !== sessionId) reportPageLeave();\n markPageViewed(sessionId);\n if (sessionId) installEngagedClock(reportPageLeave);\n onAnalyticsConsent(startSessionOnConsent);\n const delivered = await postPing({\n referer: document.referrer || undefined,\n cart_value: cartValue,\n item_count: itemCount,\n cart_seq: order?.seq,\n cart_seq_scope: order?.scope,\n session_id: sessionId ?? undefined,\n // Time on screen of the page before this one (client-side navigation).\n engaged_ms: sessionId ? takeEngagedMs() || undefined : undefined,\n path: resolveStorefrontPagePath(),\n utm: resolveUtmParameters(config.storeSlug),\n });\n settle?.(delivered);\n };\n // A view with a cart takes its place in the cart queue; one without a cart\n // has nothing to coalesce with and goes out at once.\n await (reservedOrder ? enqueueCartSend(sendView) : sendView());\n}\n\n/**\n * Reports a cart change for the live visitor map without counting a page view\n * (`event_type: 'presence'`). Use it when the cart changes on a page that was\n * already counted. A cart state the server holds, or will hold once a send in\n * flight lands, is not sent again, so a cross-tab `storage` echo of a change is\n * not a second ping. A failed send leaves nothing behind: the same state goes\n * out again on the next change or page load.\n *\n * The sequence is taken at call time; the check runs when the change's turn\n * comes, after this tab's earlier sends settled: a revert to the confirmed\n * cart while another state is on the wire must still go out.\n */\nexport async function trackCartActivity(cartValue: number, itemCount: number): Promise<void> {\n if (!isInitialized()) return;\n if (typeof document === 'undefined') return;\n const snapshot = cartSnapshot(cartValue, itemCount);\n const reservedOrder = reserveCartOrder(getConfig().storeSlug);\n await enqueueCartSend(async (isLatest) => {\n const order = await reservedOrder;\n // A newer change may have been asked for meanwhile, or this state may have\n // been confirmed or claimed by then (by this tab or another).\n if (!isLatest() || isCartReportedOrInFlight(getConfig().storeSlug, snapshot)) return;\n await sendCartActivity(order, cartValue, itemCount);\n });\n}\n\nasync function sendCartActivity(order: CartOrder, cartValue?: number, itemCount?: number): Promise<void> {\n const config = getConfig();\n const settle = claimCartReport(config.storeSlug, order.seq, cartValue, itemCount);\n const delivered = await postPing({\n event_type: 'presence',\n cart_value: cartValue,\n item_count: itemCount,\n cart_seq: order.seq,\n cart_seq_scope: order.scope,\n // A cart marks the analytics session as one that did not bounce.\n session_id: analyticsSessionId(config.storeSlug, { touch: false }) ?? undefined,\n path: resolveStorefrontPagePath(),\n });\n settle(delivered);\n}\n\n/**\n * Counts that this visit opened a product. A `/product/{slug}` page needs no\n * call: the server finds its product from the path. Call it on a product page\n * with another path (a code storefront route of your own); the server keeps\n * the product only when the shop owns it. Not a page view.\n */\nexport async function trackProductView(productId: string): Promise<void> {\n if (!isInitialized() || typeof document === 'undefined' || !productId) return;\n await sendVisitEvent({ event_type: 'product_view', product_id: productId });\n}\n\n/**\n * Counts an item put in the cart (add to cart and Buy Now) for the funnel's\n * \"Added to cart\" step. Sent on code storefronts too: the platform page\n * tracker counts pages, never carts. Called by the cart module.\n */\nexport async function trackCartAdd(productId: string, variantId: string, quantity: number): Promise<void> {\n if (!isInitialized() || typeof document === 'undefined' || quantity < 1) return;\n await sendVisitEvent({ event_type: 'cart_add', product_id: productId, variant_id: variantId, quantity });\n}\n\nasync function sendVisitEvent(body: Record<string, unknown>): Promise<void> {\n const config = getConfig();\n // A preview page (an unpublished draft) is no visit: its views and carts stay out of the funnel.\n if (config.preview) return;\n // A visit can end while the buyer sits on a page: the referrer and campaign\n // let the server start the next one with its source. The event keeps the\n // server visit alive or starts it, so it does the same to the session: a\n // checkout after 30 idle minutes then credits the visit of this cart add,\n // not the one before it.\n await postPing({\n ...body,\n referer: document.referrer || undefined,\n session_id: analyticsSessionId(config.storeSlug, { touch: true }) ?? undefined,\n path: resolveStorefrontPagePath(),\n utm: resolveUtmParameters(config.storeSlug),\n });\n}\n\n/**\n * A yes on the cookie banner comes without a reload. On a page already\n * counted cookieless, it starts the analytics session at once\n * (`session_start`: no second page view), so a checkout from this page is\n * linked to the visit.\n */\nfunction startSessionOnConsent(): void {\n const config = getConfig();\n if (!isPageViewed() || analyticsSessionId(config.storeSlug, { touch: false })) return;\n const sessionId = analyticsSessionId(config.storeSlug, { touch: true });\n if (!sessionId) return;\n markPageViewed(sessionId);\n installEngagedClock(reportPageLeave);\n void postPing({\n event_type: 'session_start',\n referer: document.referrer || undefined,\n session_id: sessionId,\n path: resolveStorefrontPagePath(),\n utm: resolveUtmParameters(config.storeSlug),\n });\n}\n\n/**\n * Sends the time on screen of this page when the tab is hidden or left\n * (`page_leave`), to the session the page was viewed in. keepalive lets the\n * request outlive the page. Only with an analytics yes; nothing goes out when\n * there is no time to report.\n */\nfunction reportPageLeave(): void {\n const config = getConfig();\n const sessionId = currentPageSession();\n const engagedMs = takeEngagedMs();\n if (!sessionId || engagedMs === 0 || readAnalyticsConsent() !== 'granted') return;\n try {\n const endpoint = buildEndpoint('/v1/storefront/shops/:storeSlug/ping', { storeSlug: config.storeSlug });\n void fetch(`${config.apiBaseUrl}${endpoint}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ event_type: 'page_leave', session_id: sessionId, engaged_ms: engagedMs }),\n keepalive: true,\n }).catch(() => {});\n } catch {\n // Analytics never breaks the page.\n }\n}\n","import type { CartAddon, CartItem } from '../types/cart';\n\nfunction hashString(value: string): string {\n let hash = 2166136261;\n for (let i = 0; i < value.length; i += 1) {\n hash ^= value.charCodeAt(i);\n hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);\n }\n return (hash >>> 0).toString(16);\n}\n\nfunction normalizeAddons(addons: CartAddon[] | undefined): CartAddon[] {\n if (!addons?.length) return [];\n return [...addons]\n .map((addon) => ({ id: addon.id, quantity: addon.quantity ?? 1 }))\n .sort((a, b) => a.id.localeCompare(b.id));\n}\n\nfunction normalizeCustomFields(fields: Record<string, string> | undefined): Record<string, string> {\n if (!fields) return {};\n const entries = Object.entries(fields)\n .filter(([, value]) => typeof value === 'string')\n .sort(([a], [b]) => a.localeCompare(b));\n return Object.fromEntries(entries);\n}\n\nexport type CartLineIdentityInput = Pick<\n CartItem,\n 'product_id' | 'variant_id' | 'price_variant_id' | 'addons' | 'custom_fields' | 'price_data' | 'pay_what_you_want_price'\n>;\n\nexport function computeCartLineId(input: CartLineIdentityInput): string {\n const payload = {\n product_id: input.product_id,\n variant_id: input.variant_id,\n price_variant_id: input.price_variant_id ?? null,\n addons: normalizeAddons(input.addons),\n custom_fields: normalizeCustomFields(input.custom_fields),\n unit_price:\n typeof input.price_data?.unit_price === 'number' && Number.isFinite(input.price_data.unit_price)\n ? input.price_data.unit_price\n : null,\n pay_what_you_want_price:\n typeof input.pay_what_you_want_price === 'number' && Number.isFinite(input.pay_what_you_want_price)\n ? input.pay_what_you_want_price\n : null,\n };\n return hashString(JSON.stringify(payload));\n}\n\nexport function ensureCartLineId(item: CartItem): CartItem {\n if (typeof item.line_id === 'string' && item.line_id.trim()) {\n return item;\n }\n return { ...item, line_id: computeCartLineId(item) };\n}\n","/**\n * Catalog unit prices support mills (one thousandth of a currency unit).\n *\n * This is intentionally separate from invoice and payment totals. A unit can\n * cost $0.012, while the payable line total is still rounded to the currency's\n * minor unit after `unit price × quantity`.\n */\nexport const CATALOG_UNIT_PRICE_DECIMAL_PLACES = 3;\n\n/**\n * Payable line amounts and invoice totals remain cent amounts. This is a\n * separate boundary from catalog unit prices: multiply the mill-priced unit by\n * quantity first, then round the resulting line amount to this precision.\n */\nexport const PAYABLE_AMOUNT_DECIMAL_PLACES = 2;\n\nexport const CATALOG_UNIT_PRICE_FORMAT_OPTIONS = {\n maximumFractionDigits: CATALOG_UNIT_PRICE_DECIMAL_PLACES,\n} as const;\n\n/**\n * Browser-safe half-up rounding for non-negative payable amounts.\n *\n * The exponent shift avoids the common `1.005 * 100` binary-float trap and\n * mirrors the backend's decimal.js ROUND_HALF_UP policy. Negative values are\n * handled symmetrically so the helper remains safe for display calculations.\n */\nexport function roundPayableAmount(value: number): number {\n if (!Number.isFinite(value)) return value;\n\n const sign = value < 0 ? -1 : 1;\n const shifted = shiftDecimal(Math.abs(value), PAYABLE_AMOUNT_DECIMAL_PLACES);\n const rounded = Math.round(shifted);\n if (rounded === 0) return 0;\n return sign * shiftDecimal(rounded, -PAYABLE_AMOUNT_DECIMAL_PLACES);\n}\n\nfunction shiftDecimal(value: number, places: number): number {\n const [coefficient, currentExponent = '0'] = String(value).split('e');\n return Number(`${coefficient}e${Number(currentExponent) + places}`);\n}\n\nfunction countSignificantDecimalPlaces(value: string | number): number | null {\n const source = String(value).trim();\n const match = source.match(/^[-+]?(\\d+)(?:\\.(\\d*))?(?:e([-+]?\\d+))?$/i)\n ?? source.match(/^[-+]?\\.(\\d+)(?:e([-+]?\\d+))?$/i);\n if (!match) return null;\n\n const startsWithDecimalPoint = /^[-+]?\\./.test(source);\n const integerPart = startsWithDecimalPoint ? '0' : match[1];\n const fractionPart = startsWithDecimalPoint ? match[1] : (match[2] ?? '');\n const exponentText = startsWithDecimalPoint ? match[2] : match[3];\n const exponent = Number(exponentText ?? 0);\n if (!Number.isInteger(exponent)) return null;\n\n const digitsWithoutInsignificantZeros = `${integerPart}${fractionPart}`.replace(/0+$/, '');\n if (digitsWithoutInsignificantZeros.length === 0) return 0;\n\n const decimalPoint = integerPart.length + exponent;\n return Math.max(0, digitsWithoutInsignificantZeros.length - decimalPoint);\n}\n\nexport function hasCatalogUnitPricePrecision(value: string | number): boolean {\n const decimalPlaces = countSignificantDecimalPlaces(value);\n return decimalPlaces !== null && decimalPlaces <= CATALOG_UNIT_PRICE_DECIMAL_PLACES;\n}\n\nexport function getCatalogUnitPricePrecisionMessage(value: string | number): string {\n return `Price supports at most ${CATALOG_UNIT_PRICE_DECIMAL_PLACES} decimal places; received ${String(value)}.`;\n}\n","/**\n * Cart Module\n *\n * localStorage-based cart with support for Shoppex features:\n * - Addons (express shipping, gift wrap, etc.)\n * - Custom Fields (engraving, gift message, etc.)\n * - Price Variants (different pricing tiers)\n */\n\nimport { getItem, setItem, removeItem, type StorageArea } from '../utils/storage';\nimport { getConfig } from '../core/config';\nimport { post } from '../core/client';\nimport { CartError } from '../core/errors';\nimport type {\n CartItem,\n CartAddOptions,\n CartItemUpdate,\n CartPayload,\n CartMetadata,\n CartStats,\n CartQuote,\n CartBasketMergeLine,\n CartCodeSource,\n} from '../types';\nimport { getAffiliateCode, trackAffiliateEvent } from './affiliates';\nimport { trackCartAdd } from './analytics';\nimport { computeCartLineId, ensureCartLineId } from '../utils/cart-line-id';\nimport {\n normalizeRequestedCurrency,\n resolveBuyerCurrency,\n} from '../utils/requested-currency';\nimport { roundPayableAmount } from '@shoppex/contracts/catalog-unit-price';\n\nconst STORAGE_KEYS = {\n cart: 'cart',\n cartBackup: 'cart_backup',\n meta: 'cart_meta',\n metaBackup: 'cart_backup_meta',\n coupon: 'cart_coupon',\n couponBackup: 'cart_coupon_backup',\n} as const;\n\ntype StorageKeyType = keyof typeof STORAGE_KEYS;\n\nfunction getStorageKey(type: StorageKeyType): string {\n return `${STORAGE_KEYS[type]}_${getConfig().storeSlug}`;\n}\n\n// A preview-link page (an unpublished draft) keeps its own cart in this tab\n// only: trying the draft never reads or writes the buyer's live cart, in this\n// tab or another. Its keys carry the preview namespace of every storefront\n// storage key (utils/storage).\nfunction cartStorageArea(): StorageArea {\n return getConfig().preview ? 'sessionStorage' : 'localStorage';\n}\n\nfunction readCartStorage<T>(type: StorageKeyType): T | null {\n return getItem<T>(getStorageKey(type), cartStorageArea());\n}\n\nfunction writeCartStorage<T>(type: StorageKeyType, value: T): void {\n setItem(getStorageKey(type), value, cartStorageArea());\n}\n\nfunction removeCartStorage(type: StorageKeyType): void {\n removeItem(getStorageKey(type), cartStorageArea());\n}\n\nfunction hashString(value: string): string {\n let hash = 2166136261;\n for (let i = 0; i < value.length; i += 1) {\n hash ^= value.charCodeAt(i);\n hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);\n }\n return (hash >>> 0).toString(16);\n}\n\nfunction computeChecksum(cart: CartItem[]): string {\n return hashString(JSON.stringify(cart));\n}\n\nfunction normalizeQuantity(value: number): number {\n if (!Number.isFinite(value)) {\n throw new CartError('quantity must be a finite number');\n }\n return Math.floor(value);\n}\n\nfunction normalizeCouponCode(value: string | null | undefined): string | null {\n const normalized = value?.trim().toUpperCase();\n return normalized ? normalized : null;\n}\n\ntype StoredCartCode = {\n code: string;\n source: CartCodeSource;\n};\n\nfunction getStoredCartCode(): StoredCartCode | null {\n const raw = readCartStorage<unknown>('coupon');\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n return null;\n }\n const record = raw as Record<string, unknown>;\n const code = typeof record.code === 'string' ? normalizeCouponCode(record.code) : null;\n const source = record.source === 'COUPON' || record.source === 'AFFILIATE'\n ? record.source\n : null;\n return code && source ? { code, source } : null;\n}\n\nfunction normalizeCartItems(value: unknown): CartItem[] {\n if (!Array.isArray(value)) return [];\n const normalized: CartItem[] = [];\n for (const entry of value) {\n if (!entry || typeof entry !== 'object') continue;\n const record = entry as Record<string, unknown>;\n const productId = typeof record.product_id === 'string' ? record.product_id.trim() : '';\n const variantId = typeof record.variant_id === 'string' ? record.variant_id.trim() : '';\n const quantity = Number(record.quantity);\n\n if (!productId || !variantId || !Number.isFinite(quantity) || quantity < 1) {\n continue;\n }\n\n const item: CartItem = {\n line_id: '',\n product_id: productId,\n variant_id: variantId,\n quantity: Math.floor(quantity),\n };\n\n if (typeof record.price_variant_id === 'string') {\n item.price_variant_id = record.price_variant_id;\n }\n if (record.price_data && typeof record.price_data === 'object') {\n const priceData = record.price_data as Record<string, unknown>;\n if (typeof priceData.unit_price === 'number' && Number.isFinite(priceData.unit_price)) {\n item.price_data = { unit_price: priceData.unit_price };\n }\n }\n if (typeof record.pay_what_you_want_price === 'number' && Number.isFinite(record.pay_what_you_want_price)) {\n item.pay_what_you_want_price = record.pay_what_you_want_price;\n }\n if (Array.isArray(record.addons)) {\n item.addons = record.addons as CartItem['addons'];\n }\n if (record.custom_fields && typeof record.custom_fields === 'object' && !Array.isArray(record.custom_fields)) {\n item.custom_fields = record.custom_fields as Record<string, string>;\n }\n\n // Preserve the optional display snapshot (title/variant_title/image_url/addon_labels) across the\n // localStorage round-trip so the njk cart drawer/page can render without a product fetch.\n if (typeof record.title === 'string') {\n item.title = record.title;\n }\n if (typeof record.variant_title === 'string') {\n item.variant_title = record.variant_title;\n }\n if (typeof record.image_url === 'string') {\n item.image_url = record.image_url;\n }\n if (Array.isArray(record.addon_labels)) {\n item.addon_labels = record.addon_labels.filter((label): label is string => typeof label === 'string');\n }\n if (typeof record.max_quantity === 'number' && Number.isFinite(record.max_quantity)) {\n item.max_quantity = record.max_quantity;\n }\n if (typeof record.min_quantity === 'number' && Number.isFinite(record.min_quantity)) {\n item.min_quantity = record.min_quantity;\n }\n\n // Self-heal on READ: clamp quantity to the stored [min,max] here, after the bounds are read. This is\n // the single chokepoint every access flows through (getCart -> getCartPayload -> serializeCart/\n // quoteCart -> checkout), so a stale/tampered/restored localStorage line can never reach checkout\n // out of bounds — closing restoreCartFromBackup and direct-localStorage-edit at the root, not just\n // the write paths.\n clampQuantityToBounds(item);\n\n const storedLineId = typeof record.line_id === 'string' ? record.line_id.trim() : '';\n item.line_id = storedLineId || computeCartLineId(item);\n\n normalized.push(ensureCartLineId(item));\n }\n return normalized;\n}\n\nfunction getCartMetadata(): CartMetadata | null {\n return readCartStorage<CartMetadata>('meta');\n}\n\nexport function getCartCoupon(): string | null {\n return getStoredCartCode()?.code ?? null;\n}\n\nexport function getCartCouponSource(): CartCodeSource | null {\n return getStoredCartCode()?.source ?? null;\n}\n\nexport function setCartCoupon(\n coupon: string | null | undefined,\n source: CartCodeSource = 'COUPON',\n): string | null {\n const normalizedCoupon = normalizeCouponCode(coupon);\n if (!normalizedCoupon) {\n removeCartStorage('coupon');\n return null;\n }\n\n writeCartStorage('coupon', { code: normalizedCoupon, source });\n return normalizedCoupon;\n}\n\nexport function clearCartCoupon(): void {\n removeCartStorage('coupon');\n}\n\nfunction writeCart(cart: CartItem[]): void {\n const normalizedCart = normalizeCartItems(cart);\n writeCartStorage('cart', normalizedCart);\n const now = Date.now();\n const previous = getCartMetadata();\n const nextMeta: CartMetadata = {\n created_at: previous?.created_at ?? now,\n last_modified: now,\n version: (previous?.version ?? 0) + 1,\n checksum: computeChecksum(normalizedCart),\n };\n writeCartStorage('meta', nextMeta);\n\n if (normalizedCart.length === 0) {\n clearCartCoupon();\n }\n}\n\nfunction setCartWithMetadata(cart: CartItem[], metadata?: CartMetadata | null): void {\n const normalizedCart = normalizeCartItems(cart);\n writeCartStorage('cart', normalizedCart);\n const now = Date.now();\n const base = metadata ?? getCartMetadata();\n const nextMeta: CartMetadata = {\n created_at: base?.created_at ?? now,\n last_modified: now,\n version: base?.version ?? 1,\n checksum: computeChecksum(normalizedCart),\n };\n writeCartStorage('meta', nextMeta);\n}\n\nexport function getCart(): CartItem[] {\n const raw = readCartStorage<unknown>('cart');\n return normalizeCartItems(raw);\n}\n\n/** Resolve a cart line_id for product+variant. When multiple configs exist, returns the first line. */\nexport function resolveCartLineId(\n productId: string,\n variantId: string,\n cart: CartItem[] = getCart(),\n): string {\n const matches = cart.filter(\n (item) => item.product_id === productId && item.variant_id === variantId,\n );\n if (matches.length === 0) {\n throw new CartError(`No cart line found for ${productId}/${variantId}`);\n }\n return matches[0].line_id;\n}\n\nexport function getCartItemCount(): number {\n const cart = getCart();\n return cart.reduce((sum, item) => sum + item.quantity, 0);\n}\n\nexport function addToCart(\n productId: string,\n variantId: string,\n quantity: number = 1,\n options?: CartAddOptions\n): void {\n if (!productId || !variantId) {\n throw new CartError('product_id and variant_id are required');\n }\n\n const normalizedQuantity = normalizeQuantity(quantity);\n if (normalizedQuantity < 1) {\n throw new CartError('quantity must be at least 1');\n }\n\n const cart = getCart();\n\n const lineId = computeCartLineId({\n product_id: productId,\n variant_id: variantId,\n addons: options?.addons,\n custom_fields: options?.custom_fields,\n price_variant_id: options?.price_variant_id,\n price_data: options?.price_data,\n pay_what_you_want_price: options?.pay_what_you_want_price,\n });\n\n const existingIndex = cart.findIndex((item) => item.line_id === lineId);\n const quantityBeforeAdd = existingIndex >= 0 ? cart[existingIndex].quantity : 0;\n\n if (existingIndex >= 0) {\n cart[existingIndex].quantity += normalizedQuantity;\n\n if (options?.addons) {\n cart[existingIndex].addons = options.addons;\n }\n if (options?.custom_fields) {\n cart[existingIndex].custom_fields = options.custom_fields;\n }\n if (options?.price_variant_id) {\n cart[existingIndex].price_variant_id = options.price_variant_id;\n }\n if (options?.price_data) {\n cart[existingIndex].price_data = options.price_data;\n }\n if (options?.pay_what_you_want_price !== undefined) {\n cart[existingIndex].pay_what_you_want_price = options.pay_what_you_want_price;\n }\n applyDisplaySnapshot(cart[existingIndex], options);\n clampQuantityToBounds(cart[existingIndex]);\n } else {\n const pushed: CartItem = {\n line_id: lineId,\n product_id: productId,\n variant_id: variantId,\n quantity: normalizedQuantity,\n addons: options?.addons,\n custom_fields: options?.custom_fields,\n price_variant_id: options?.price_variant_id,\n price_data: options?.price_data,\n pay_what_you_want_price: options?.pay_what_you_want_price,\n title: options?.title,\n variant_title: options?.variant_title,\n image_url: options?.image_url,\n addon_labels: options?.addon_labels,\n max_quantity: options?.max_quantity,\n min_quantity: options?.min_quantity,\n };\n clampQuantityToBounds(pushed);\n cart.push(pushed);\n }\n\n const intendedQuantity = (existingIndex >= 0 ? cart[existingIndex] : cart[cart.length - 1]).quantity;\n writeCart(cart);\n // The storage wrapper swallows quota/availability failures, and the cart\n // and metadata writes can fail independently, so the funnel event is gated\n // on the LINE itself: the post-clamp quantity actually grew (a clamped\n // max-quantity no-op did not add anything) AND that exact quantity is\n // readable back from storage (the write of the cart payload landed).\n const persistedLine = getCart().find((item) => item.line_id === lineId);\n if (intendedQuantity > quantityBeforeAdd && persistedLine?.quantity === intendedQuantity) {\n // Attribute like checkout() does: a code applied to the cart (AFFILIATE\n // coupon source) outranks the ambient stored referral.\n const cartAffiliateCode = getCartCouponSource() === 'AFFILIATE' ? getCartCoupon() : null;\n void trackAffiliateEvent('add_to_cart', cartAffiliateCode ? { code: cartAffiliateCode } : undefined);\n void trackCartAdd(productId, variantId, intendedQuantity - quantityBeforeAdd);\n }\n}\n\n// Cart-wide invariant: a line's quantity must stay within its stored [min_quantity, max_quantity]\n// bounds. Every write path routes through this — addToCart (merge+push), setCartItem (merge+push),\n// updateCartItem, mergeBaskets (merge+push), moveBasketItem (merge+push) — AND, crucially, the READ\n// path normalizeCartItems (getCart) clamps too, so a stale/tampered/restored localStorage line is\n// self-healed before it can reach checkout. No entrypoint can persist or serve a quantity outside the\n// purchasable range the backend would reject.\n// Order matters: apply min FIRST, then max — so on the degenerate min>max case (e.g. quantity_min 2 but\n// only 1 in stock) MAX wins and the line is never pushed above the stock cap (over-stock is the harder\n// backend reject than under-min). Never below 1. No-op for the bound(s) that are absent.\nfunction clampQuantityToBounds(item: CartItem): void {\n const min = item.min_quantity;\n if (typeof min === 'number' && Number.isFinite(min) && item.quantity < min) {\n item.quantity = Math.floor(min);\n }\n const max = item.max_quantity;\n if (typeof max === 'number' && Number.isFinite(max) && item.quantity > max) {\n item.quantity = Math.floor(max);\n }\n if (item.quantity < 1) {\n item.quantity = 1;\n }\n}\n\n// Copy the optional display snapshot fields from add-options onto an existing line. Display-only —\n// kept separate from the pricing/identity fields so the snapshot logic is identical for add and set.\nfunction applyDisplaySnapshot(item: CartItem, options?: CartAddOptions): void {\n // Authoritative full re-snapshot (buy-box producer): replace ALL display fields verbatim, including\n // CLEARING ones the new snapshot omits — a removed add-on or a lifted cap must not leave stale data.\n if (options?.replace_display_snapshot) {\n item.title = options.title;\n item.variant_title = options.variant_title;\n item.image_url = options.image_url;\n item.addon_labels = options.addon_labels;\n item.max_quantity = options.max_quantity;\n item.min_quantity = options.min_quantity;\n return;\n }\n // Partial direct SDK call: only overwrite the fields actually provided.\n if (options?.title !== undefined) {\n item.title = options.title;\n }\n if (options?.variant_title !== undefined) {\n item.variant_title = options.variant_title;\n }\n if (options?.image_url !== undefined) {\n item.image_url = options.image_url;\n }\n if (options?.addon_labels !== undefined) {\n item.addon_labels = options.addon_labels;\n }\n if (options?.max_quantity !== undefined) {\n item.max_quantity = options.max_quantity;\n }\n if (options?.min_quantity !== undefined) {\n item.min_quantity = options.min_quantity;\n }\n}\n\nexport function setCartItem(\n productId: string,\n variantId: string,\n quantity: number = 1,\n options?: CartAddOptions\n): void {\n if (!productId || !variantId) {\n throw new CartError('product_id and variant_id are required');\n }\n\n const normalizedQuantity = normalizeQuantity(quantity);\n if (normalizedQuantity < 1) {\n throw new CartError('quantity must be at least 1');\n }\n\n const cart = getCart();\n const lineId = computeCartLineId({\n product_id: productId,\n variant_id: variantId,\n addons: options?.addons,\n custom_fields: options?.custom_fields,\n price_variant_id: options?.price_variant_id,\n price_data: options?.price_data,\n pay_what_you_want_price: options?.pay_what_you_want_price,\n });\n\n // Buy-now / replace semantics: one visible line per (product_id, variant_id). Drop any prior\n // line_ids for that pair so a config change (addons, price_data) does not leave a stale sibling.\n for (let index = cart.length - 1; index >= 0; index -= 1) {\n if (cart[index].product_id === productId && cart[index].variant_id === variantId) {\n cart.splice(index, 1);\n }\n }\n\n const pushed: CartItem = {\n line_id: lineId,\n product_id: productId,\n variant_id: variantId,\n quantity: normalizedQuantity,\n addons: options?.addons,\n custom_fields: options?.custom_fields,\n price_variant_id: options?.price_variant_id,\n price_data: options?.price_data,\n pay_what_you_want_price: options?.pay_what_you_want_price,\n title: options?.title,\n variant_title: options?.variant_title,\n image_url: options?.image_url,\n addon_labels: options?.addon_labels,\n max_quantity: options?.max_quantity,\n min_quantity: options?.min_quantity,\n };\n clampQuantityToBounds(pushed);\n cart.push(pushed);\n\n writeCart(cart);\n // Buy Now: the funnel counts the item as added, gated on the write landing like addToCart.\n const persistedLine = getCart().find((item) => item.line_id === lineId);\n if (persistedLine) void trackCartAdd(productId, variantId, persistedLine.quantity);\n}\n\n/**\n * Patch one cart line.\n *\n * TRI-STATE BOUNDS: `min_quantity`/`max_quantity` accept `null` to DELETE the\n * stored bound — see {@link CartItemUpdate}. `undefined` (or an absent key)\n * leaves it alone, which is why a removed ceiling needs its own spelling.\n *\n * NO-OP UPDATES DO NOT WRITE. An update that leaves the cart byte-identical\n * returns without touching storage: no metadata bump, no `version` increment,\n * and — because the storage write is what other tabs observe — no `storage`\n * event. Writing anyway made an ineffective heal indistinguishable from a real\n * cart change, and two tabs healing the same line could hand the event back and\n * forth indefinitely. Line-shape healing of a legacy stored row is NOT this\n * function's job: `normalizeCartItems` clamps and repairs on every READ, which\n * is the chokepoint every access already flows through.\n */\nexport function updateCartItem(\n lineId: string,\n updates: CartItemUpdate\n): void {\n const cart = getCart();\n const normalizedLineId = lineId.trim();\n if (!normalizedLineId) {\n throw new CartError('line_id is required');\n }\n\n const index = cart.findIndex((item) => item.line_id === normalizedLineId);\n\n if (index < 0) {\n throw new CartError('Item not found in cart');\n }\n\n // The exact bytes the result is compared against, taken BEFORE any mutation.\n const before = JSON.stringify(cart);\n\n if (updates.quantity !== undefined) {\n const normalizedQuantity = normalizeQuantity(updates.quantity);\n if (normalizedQuantity < 1) {\n cart.splice(index, 1);\n writeCart(cart);\n return;\n }\n cart[index].quantity = normalizedQuantity;\n }\n\n if (updates.addons !== undefined) {\n cart[index].addons = updates.addons;\n }\n\n if (updates.custom_fields !== undefined) {\n cart[index].custom_fields = updates.custom_fields;\n }\n\n if (updates.price_variant_id !== undefined) {\n cart[index].price_variant_id = updates.price_variant_id;\n }\n if (updates.price_data !== undefined) {\n cart[index].price_data = updates.price_data;\n }\n if (updates.pay_what_you_want_price !== undefined) {\n cart[index].pay_what_you_want_price = updates.pay_what_you_want_price;\n }\n // The option name, restated by a settled quote from the catalog (`CartQuoteLine`).\n if (updates.variant_title !== undefined) {\n if (updates.variant_title === null) delete cart[index].variant_title;\n else cart[index].variant_title = updates.variant_title;\n }\n // Tri-state: `null` is the merchant's bound being REMOVED, and it has to\n // delete the stored key — a bound that can only be raised and lowered but\n // never cleared outlives the limit it describes.\n if (updates.max_quantity !== undefined) {\n if (updates.max_quantity === null) delete cart[index].max_quantity;\n else cart[index].max_quantity = updates.max_quantity;\n }\n if (updates.min_quantity !== undefined) {\n if (updates.min_quantity === null) delete cart[index].min_quantity;\n else cart[index].min_quantity = updates.min_quantity;\n }\n clampQuantityToBounds(cart[index]);\n\n // Pricing and configuration fields are part of a cart line's identity.\n // Recompute after every update and merge if the new identity already exists.\n const nextLineId = computeCartLineId(cart[index]);\n const duplicateIndex = cart.findIndex((item, itemIndex) => itemIndex !== index && item.line_id === nextLineId);\n if (duplicateIndex >= 0) {\n cart[duplicateIndex].quantity += cart[index].quantity;\n clampQuantityToBounds(cart[duplicateIndex]);\n cart.splice(index, 1);\n } else {\n cart[index].line_id = nextLineId;\n }\n\n // Nothing moved: writing would bump `version`/`last_modified` and emit a\n // storage event that says the cart changed when it did not.\n if (JSON.stringify(cart) === before) return;\n\n writeCart(cart);\n}\n\nexport function removeFromCart(lineId: string): void {\n const normalizedLineId = lineId.trim();\n if (!normalizedLineId) {\n throw new CartError('line_id is required');\n }\n\n const cart = getCart();\n const filtered = cart.filter((item) => item.line_id !== normalizedLineId);\n writeCart(filtered);\n}\n\n/**\n * Discards the cart entirely — and with it the proof that describes it.\n *\n * PAYMENT PATH. `latestQuoteToken` is evidence about a specific cart, and this\n * is the one mutation after which that cart does not exist in any form. Held\n * across the clear, the proof outlives its subject: a caller that clears and\n * re-adds (Buy Now REPLACES the cart) hands `/from-cart` a token bound to the\n * previous cart's hash, which is refused as `quote_token_stale` — a hand-off\n * dead-ended by a proof nobody asked for. And with no re-quote in between there\n * is nothing to replace it with, so the retry is refused identically.\n *\n * Only this path clears it. Every OTHER mutation turns one cart into another\n * cart, where a proof that no longer matches is the server's to refuse: it\n * answers `quote_token_stale`, the surfaces re-quote, and the buyer approves the\n * new total. Dropping the proof there instead would silently remove the approved\n * -total ceiling from a checkout that raced the re-quote, which is the failure\n * the token exists to prevent.\n */\nexport function clearCart(): void {\n removeCartStorage('cart');\n removeCartStorage('meta');\n clearCartCoupon();\n clearLatestQuoteToken();\n}\n\nexport function createCartBackup(): void {\n const cart = getCart();\n writeCartStorage('cartBackup', cart);\n const cartCode = getStoredCartCode();\n if (cartCode) {\n writeCartStorage('couponBackup', cartCode);\n } else {\n removeCartStorage('couponBackup');\n }\n const metadata = getCartMetadata();\n if (metadata) {\n writeCartStorage('metaBackup', metadata);\n } else {\n const now = Date.now();\n writeCartStorage('metaBackup', {\n created_at: now,\n last_modified: now,\n version: 1,\n checksum: computeChecksum(cart),\n });\n }\n}\n\nexport function restoreCartFromBackup(): boolean {\n const backupRaw = readCartStorage<unknown>('cartBackup');\n const backup = normalizeCartItems(backupRaw);\n const backupMeta = readCartStorage<CartMetadata>('metaBackup');\n const backupCoupon = readCartStorage<unknown>('couponBackup');\n\n if (backup && backup.length > 0) {\n setCartWithMetadata(backup, backupMeta);\n if (backupCoupon && typeof backupCoupon === 'object' && !Array.isArray(backupCoupon)) {\n const record = backupCoupon as Record<string, unknown>;\n const source = record.source === 'COUPON' || record.source === 'AFFILIATE'\n ? record.source\n : null;\n if (typeof record.code === 'string' && source) {\n setCartCoupon(record.code, source);\n } else {\n clearCartCoupon();\n }\n } else {\n clearCartCoupon();\n }\n return true;\n }\n\n return false;\n}\n\nexport function mergeBaskets(items: CartBasketMergeLine[]): CartItem[] {\n const cart = getCart();\n\n for (const incoming of items) {\n const productId = typeof incoming.product_id === 'string' ? incoming.product_id.trim() : '';\n const variantId = typeof incoming.variant_id === 'string' ? incoming.variant_id.trim() : '';\n if (!productId || !variantId) {\n continue;\n }\n\n let normalizedQuantity: number;\n try {\n normalizedQuantity = normalizeQuantity(incoming.quantity);\n } catch {\n continue;\n }\n\n if (normalizedQuantity < 1) {\n continue;\n }\n\n const mergedLine = ensureCartLineId({\n ...incoming,\n line_id: incoming.line_id ?? computeCartLineId(incoming),\n product_id: productId,\n variant_id: variantId,\n quantity: normalizedQuantity,\n });\n const index = cart.findIndex((item) => item.line_id === mergedLine.line_id);\n\n if (index >= 0) {\n cart[index].quantity = Math.max(cart[index].quantity, normalizedQuantity);\n clampQuantityToBounds(cart[index]);\n } else {\n clampQuantityToBounds(mergedLine);\n cart.push(mergedLine);\n }\n }\n\n writeCart(cart);\n return cart;\n}\n\nexport function moveBasketItem(\n fromProductId: string,\n fromVariantId: string,\n toProductId: string,\n toVariantId: string\n): void {\n const cart = getCart();\n const fromIndex = cart.findIndex(\n (item) => item.product_id === fromProductId && item.variant_id === fromVariantId\n );\n\n if (fromIndex < 0) {\n throw new CartError('Item not found in cart');\n }\n\n const [fromItem] = cart.splice(fromIndex, 1);\n const toLineId = computeCartLineId({\n ...fromItem,\n product_id: toProductId,\n variant_id: toVariantId,\n });\n const toIndex = cart.findIndex((item) => item.line_id === toLineId);\n\n if (toIndex >= 0) {\n cart[toIndex].quantity += fromItem.quantity;\n clampQuantityToBounds(cart[toIndex]);\n } else {\n const moved = ensureCartLineId({\n ...fromItem,\n product_id: toProductId,\n variant_id: toVariantId,\n line_id: toLineId,\n });\n clampQuantityToBounds(moved);\n cart.push(moved);\n }\n\n writeCart(cart);\n}\n\nexport function validateCartIntegrity(): boolean {\n const cart = getCart();\n const metadata = getCartMetadata();\n const checksum = computeChecksum(cart);\n\n if (!metadata) {\n setCartWithMetadata(cart, null);\n return true;\n }\n\n return metadata.checksum === checksum;\n}\n\nexport function getCartStats(): CartStats {\n const cart = getCart();\n const integrityValid = validateCartIntegrity();\n const metadata = getCartMetadata();\n const backup = readCartStorage<CartItem[]>('cartBackup') ?? [];\n const hasCompletePriceSnapshots =\n cart.length > 0 &&\n cart.every((item) => typeof item.price_data?.unit_price === 'number');\n const totalPrice = cart.reduce((sum, item) => {\n const unitPrice = item.price_data?.unit_price ?? 0;\n return sum + roundPayableAmount(unitPrice * item.quantity);\n }, 0);\n\n return {\n item_count: cart.length,\n total_quantity: cart.reduce((sum, item) => sum + item.quantity, 0),\n last_modified: metadata?.last_modified ?? 0,\n version: metadata?.version ?? 0,\n has_backup: backup.length > 0,\n integrity_valid: integrityValid,\n total_price: roundPayableAmount(totalPrice),\n total_price_is_estimate: cart.length > 0 && !hasCompletePriceSnapshots,\n };\n}\n\nexport function getCartPayload(coupon?: string): CartPayload {\n const config = getConfig();\n const normalizedCoupon = normalizeCouponCode(coupon) ?? getCartCoupon() ?? undefined;\n return {\n store_slug: config.storeSlug,\n items: getCart(),\n coupon: normalizedCoupon,\n };\n}\n\n/**\n * The ambient referral code checkout() will submit as `affiliate_code`.\n *\n * Read exactly like checkout()'s normalizeAffiliateCode ambient branch: the\n * referral code the cart itself carries (source `AFFILIATE`) takes precedence\n * over the stored `?ref=` attribution. Sending it with the quote is what makes\n * the displayed total equal the amount the invoice will charge — without it a\n * cart holding both a coupon and a `?ref=` attribution quotes high.\n */\nfunction getAmbientAffiliateCodeForQuote(): string | null {\n const storedCode = getCartCoupon();\n const storedSource = getCartCouponSource();\n if (storedSource === 'AFFILIATE' && storedCode) {\n return storedCode.trim().toLowerCase();\n }\n return getAffiliateCode();\n}\n\n/**\n * The proof from the most recent successful quote, held in memory only.\n *\n * Module-scoped rather than persisted: the token is evidence about a cart as\n * it was priced moments ago, and a stale one from a previous page load is\n * simply ignored by the server. Not exported as public API — `checkout()`\n * reads it, callers do not have to know it exists.\n */\nlet latestQuoteToken: string | null = null;\n\n/**\n * Which quote call the held token belongs to.\n *\n * Quote responses settle in ARRIVAL order, not request order: two overlapping\n * `quoteCart` calls (cart A, then cart A+B) can answer with the OLDER one last,\n * and the token stored is then evidence about a cart the buyer no longer has.\n *\n * That is not a mispricing — `/from-cart` binds the token to a hash of the cart\n * content, currency, shop and submitted codes (`isCartQuoteTokenApplicable`),\n * so a superseded token simply fails to apply and is treated as ABSENT, and the\n * proof is a one-directional CEILING that can never lower a price. What it\n * costs is the ceiling itself: the buyer silently loses the protection for the\n * rest of that checkout. Keeping the newest call's answer is what keeps the\n * proof present for the cart actually on screen.\n */\nlet quoteSequence = 0;\n\n/** @internal — read by checkout(); exported only across module boundaries. */\nexport function getLatestQuoteToken(): string | null {\n return latestQuoteToken;\n}\n\n/** @internal — test seam and cart-reset hook. */\nexport function clearLatestQuoteToken(): void {\n latestQuoteToken = null;\n // A quote already in flight must not resurrect the proof this cleared.\n quoteSequence += 1;\n}\n\nexport async function quoteCart(coupon?: string, currency?: string) {\n const sequence = (quoteSequence += 1);\n const payload = getCartPayload(coupon);\n const normalizedCurrency = normalizeRequestedCurrency(currency)\n ?? resolveBuyerCurrency(getConfig().currency);\n const response = await post<CartQuote>('/v1/storefront/cart/quote', {\n shop_slug: payload.store_slug,\n cart: payload.items,\n coupon: payload.coupon,\n affiliate_code: getAmbientAffiliateCodeForQuote() ?? undefined,\n currency: normalizedCurrency ?? undefined,\n });\n\n // Only a successful quote replaces the held proof — a failed quote must not\n // clear a still-valid one.\n //\n // A SUCCESSFUL quote that carries no token clears it, rather than leaving the\n // previous one in place. The proof is evidence about one specific priced\n // cart, and `/from-cart` refuses a submitted proof it cannot apply\n // (`quote_token_stale` / `_invalid`) instead of ignoring it. So a held token\n // that this quote did not reissue is not a harmless leftover: every later\n // `checkout()` submits it, is refused, and re-quoting never helps because a\n // tokenless answer used to leave it untouched — a dead end the buyer cannot\n // escape from inside the cart.\n //\n // And only the NEWEST call may replace it: a slower earlier quote answering\n // last would otherwise overwrite the current cart's proof with one bound to a\n // cart hash that no longer exists.\n if (sequence !== quoteSequence) return response;\n if (response.success) {\n latestQuoteToken = typeof response.data?.quote_token === 'string'\n ? response.data.quote_token\n : null;\n }\n\n return response;\n}\n\nexport function serializeCart(coupon?: string): string {\n const payload = getCartPayload(coupon);\n const json = JSON.stringify(payload);\n // UTF-8 safe Base64: encodeURIComponent converts to UTF-8, unescape converts percent-encoding to bytes\n if (typeof btoa !== 'undefined') {\n return btoa(unescape(encodeURIComponent(json)));\n }\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(json, 'utf8').toString('base64');\n }\n throw new CartError('Base64 encoding is not available in this environment');\n}\n","/**\n * The storage half of the storefront SDK: init and config, the cart, the\n * quote, coupon and referral storage, referral capture, and page-view and\n * cart-activity tracking.\n *\n * The ThemeDocument commerce runtime (packages/storefront-commerce) carries\n * this object in the script every page loads and fetches the rest of\n * `storefrontSdk` (storefront-sdk.ts, which builds on this object) as its\n * `sdk` chunk on first use. `quoteCart` stays here because it shares its\n * module with the cart and the quote token the checkout hand-off submits;\n * referral capture and page views stay because moving them later would lose\n * a `?ref=` or a bounced view.\n */\n\nimport { initConfig, isInitialized, getConfig } from './core/config';\nimport type { ShoppexInitOptions } from './types';\nimport {\n getCart,\n getCartItemCount,\n getCartCoupon,\n getCartCouponSource,\n setCartCoupon,\n clearCartCoupon,\n addToCart,\n setCartItem,\n updateCartItem,\n removeFromCart,\n clearCart,\n createCartBackup,\n restoreCartFromBackup,\n mergeBaskets,\n moveBasketItem,\n getCartStats,\n validateCartIntegrity,\n quoteCart,\n getLatestQuoteToken,\n resolveCartLineId,\n} from './modules/cart';\nimport {\n captureAffiliateFromUrl,\n getAffiliateCode,\n getStoredAffiliate,\n setAffiliateCode,\n clearAffiliateCode,\n trackAffiliateEvent,\n} from './modules/affiliates';\nimport { trackCartActivity, trackPageView, trackProductView } from './modules/analytics';\n\n/**\n * Initialize the SDK with a store slug\n */\nfunction init(storeSlug: string, options?: ShoppexInitOptions): void;\nfunction init(options: ShoppexInitOptions & { storeId: string }): void;\nfunction init(\n storeSlugOrOptions: string | (ShoppexInitOptions & { storeId: string }),\n options?: ShoppexInitOptions\n): void {\n if (typeof storeSlugOrOptions === 'string') {\n initConfig(storeSlugOrOptions, options);\n } else {\n initConfig(storeSlugOrOptions.storeId, storeSlugOrOptions);\n }\n}\n\nexport const storefrontStorageSdk = {\n // Initialization\n init,\n isInitialized,\n getConfig,\n\n // Cart\n getCart,\n getCartItemCount,\n getCartCoupon,\n getCartCouponSource,\n setCartCoupon,\n clearCartCoupon,\n addToCart,\n setCartItem,\n updateCartItem,\n removeFromCart,\n clearCart,\n createCartBackup,\n restoreCartFromBackup,\n mergeBaskets,\n moveBasketItem,\n getCartStats,\n validateCartIntegrity,\n quoteCart,\n getLatestQuoteToken,\n resolveCartLineId,\n\n // Affiliates (referral storage and capture)\n captureAffiliateFromUrl,\n getAffiliateCode,\n getStoredAffiliate,\n setAffiliateCode,\n clearAffiliateCode,\n trackAffiliateEvent,\n\n // Analytics\n trackPageView,\n trackCartActivity,\n trackProductView,\n};\n\nexport default storefrontStorageSdk;\n","// settings & const\nconst PATH_PARAM_RE = /\\{[^{}]+\\}/g;\n\nconst supportsRequestInitExt = () => {\n return (\n typeof process === \"object\" &&\n Number.parseInt(process?.versions?.node?.substring(0, 2)) >= 18 &&\n process.versions.undici\n );\n};\n\n/**\n * Returns a cheap, non-cryptographically-secure random ID\n * Courtesy of @imranbarbhuiya (https://github.com/imranbarbhuiya)\n */\nexport function randomID() {\n return Math.random().toString(36).slice(2, 11);\n}\n\n/**\n * Create an openapi-fetch client.\n * @type {import(\"./index.js\").default}\n */\nexport default function createClient(clientOptions) {\n let {\n baseUrl = \"\",\n Request: CustomRequest = globalThis.Request,\n fetch: baseFetch = globalThis.fetch,\n querySerializer: globalQuerySerializer,\n bodySerializer: globalBodySerializer,\n pathSerializer: globalPathSerializer,\n headers: baseHeaders,\n requestInitExt = undefined,\n ...baseOptions\n } = { ...clientOptions };\n requestInitExt = supportsRequestInitExt() ? requestInitExt : undefined;\n baseUrl = removeTrailingSlash(baseUrl);\n const globalMiddlewares = [];\n\n /**\n * Per-request fetch (keeps settings created in createClient()\n * @param {T} url\n * @param {import('./index.js').FetchOptions<T>} fetchOptions\n */\n async function coreFetch(schemaPath, fetchOptions) {\n const {\n baseUrl: localBaseUrl,\n fetch = baseFetch,\n Request = CustomRequest,\n headers,\n params = {},\n parseAs = \"json\",\n querySerializer: requestQuerySerializer,\n bodySerializer = globalBodySerializer ?? defaultBodySerializer,\n pathSerializer: requestPathSerializer,\n body,\n middleware: requestMiddlewares = [],\n ...init\n } = fetchOptions || {};\n let finalBaseUrl = baseUrl;\n if (localBaseUrl) {\n finalBaseUrl = removeTrailingSlash(localBaseUrl) ?? baseUrl;\n }\n\n let querySerializer =\n typeof globalQuerySerializer === \"function\"\n ? globalQuerySerializer\n : createQuerySerializer(globalQuerySerializer);\n if (requestQuerySerializer) {\n querySerializer =\n typeof requestQuerySerializer === \"function\"\n ? requestQuerySerializer\n : createQuerySerializer({\n ...(typeof globalQuerySerializer === \"object\" ? globalQuerySerializer : {}),\n ...requestQuerySerializer,\n });\n }\n\n const pathSerializer = requestPathSerializer || globalPathSerializer || defaultPathSerializer;\n\n const serializedBody =\n body === undefined\n ? undefined\n : bodySerializer(\n body,\n // Note: we declare mergeHeaders() both here and below because it’s a bit of a chicken-or-egg situation:\n // bodySerializer() needs all headers so we aren’t dropping ones set by the user, however,\n // the result of this ALSO sets the lowest-priority content-type header. So we re-merge below,\n // setting the content-type at the very beginning to be overwritten.\n // Lastly, based on the way headers work, it’s not a simple “present-or-not” check becauase null intentionally un-sets headers.\n mergeHeaders(baseHeaders, headers, params.header),\n );\n const finalHeaders = mergeHeaders(\n // with no body, we should not to set Content-Type\n serializedBody === undefined ||\n // if serialized body is FormData; browser will correctly set Content-Type & boundary expression\n serializedBody instanceof FormData\n ? {}\n : {\n \"Content-Type\": \"application/json\",\n },\n baseHeaders,\n headers,\n params.header,\n );\n\n // Client level middleware take priority over request-level middleware\n const finalMiddlewares = [...globalMiddlewares, ...requestMiddlewares];\n\n const requestInit = {\n redirect: \"follow\",\n ...baseOptions,\n ...init,\n body: serializedBody,\n headers: finalHeaders,\n };\n\n let id;\n let options;\n let request = new Request(\n createFinalURL(schemaPath, { baseUrl: finalBaseUrl, params, querySerializer, pathSerializer }),\n requestInit,\n );\n let response;\n\n /** Add custom parameters to Request object */\n for (const key in init) {\n if (!(key in request)) {\n request[key] = init[key];\n }\n }\n\n if (finalMiddlewares.length) {\n id = randomID();\n\n // middleware (request)\n options = Object.freeze({\n baseUrl: finalBaseUrl,\n fetch,\n parseAs,\n querySerializer,\n bodySerializer,\n pathSerializer,\n });\n for (const m of finalMiddlewares) {\n if (m && typeof m === \"object\" && typeof m.onRequest === \"function\") {\n const result = await m.onRequest({\n request,\n schemaPath,\n params,\n options,\n id,\n });\n if (result) {\n if (result instanceof Request) {\n request = result;\n } else if (result instanceof Response) {\n response = result;\n break;\n } else {\n throw new Error(\"onRequest: must return new Request() or Response() when modifying the request\");\n }\n }\n }\n }\n }\n\n if (!response) {\n // fetch!\n try {\n response = await fetch(request, requestInitExt);\n } catch (error) {\n let errorAfterMiddleware = error;\n // middleware (error)\n // execute in reverse-array order (first priority gets last transform)\n if (finalMiddlewares.length) {\n for (let i = finalMiddlewares.length - 1; i >= 0; i--) {\n const m = finalMiddlewares[i];\n if (m && typeof m === \"object\" && typeof m.onError === \"function\") {\n const result = await m.onError({\n request,\n error: errorAfterMiddleware,\n schemaPath,\n params,\n options,\n id,\n });\n if (result) {\n // if error is handled by returning a response, skip remaining middleware\n if (result instanceof Response) {\n errorAfterMiddleware = undefined;\n response = result;\n break;\n }\n\n if (result instanceof Error) {\n errorAfterMiddleware = result;\n continue;\n }\n\n throw new Error(\"onError: must return new Response() or instance of Error\");\n }\n }\n }\n }\n\n // rethrow error if not handled by middleware\n if (errorAfterMiddleware) {\n throw errorAfterMiddleware;\n }\n }\n\n // middleware (response)\n // execute in reverse-array order (first priority gets last transform)\n if (finalMiddlewares.length) {\n for (let i = finalMiddlewares.length - 1; i >= 0; i--) {\n const m = finalMiddlewares[i];\n if (m && typeof m === \"object\" && typeof m.onResponse === \"function\") {\n const result = await m.onResponse({\n request,\n response,\n schemaPath,\n params,\n options,\n id,\n });\n if (result) {\n if (!(result instanceof Response)) {\n throw new Error(\"onResponse: must return new Response() when modifying the response\");\n }\n response = result;\n }\n }\n }\n }\n }\n\n const contentLength = response.headers.get(\"Content-Length\");\n // handle empty content\n if (\n response.status === 204 ||\n request.method === \"HEAD\" ||\n (contentLength === \"0\" && !response.headers.get(\"Transfer-Encoding\")?.includes(\"chunked\"))\n ) {\n return response.ok ? { data: undefined, response } : { error: undefined, response };\n }\n\n // parse response (falling back to .text() when necessary)\n if (response.ok) {\n const getResponseData = async () => {\n // if \"stream\", skip parsing entirely\n if (parseAs === \"stream\") {\n return response.body;\n }\n\n if (parseAs === \"json\" && !contentLength) {\n // use text() when no content-length is provided to avoid errors parsing empty bodies (200 with no content)\n const raw = await response.text();\n return raw ? JSON.parse(raw) : undefined;\n }\n\n return await response[parseAs]();\n };\n return { data: await getResponseData(), response };\n }\n\n // handle errors\n let error = await response.text();\n try {\n error = JSON.parse(error); // attempt to parse as JSON\n } catch {\n // noop\n }\n return { error, response };\n }\n\n return {\n request(method, url, init) {\n return coreFetch(url, { ...init, method: method.toUpperCase() });\n },\n /** Call a GET endpoint */\n GET(url, init) {\n return coreFetch(url, { ...init, method: \"GET\" });\n },\n /** Call a PUT endpoint */\n PUT(url, init) {\n return coreFetch(url, { ...init, method: \"PUT\" });\n },\n /** Call a POST endpoint */\n POST(url, init) {\n return coreFetch(url, { ...init, method: \"POST\" });\n },\n /** Call a DELETE endpoint */\n DELETE(url, init) {\n return coreFetch(url, { ...init, method: \"DELETE\" });\n },\n /** Call a OPTIONS endpoint */\n OPTIONS(url, init) {\n return coreFetch(url, { ...init, method: \"OPTIONS\" });\n },\n /** Call a HEAD endpoint */\n HEAD(url, init) {\n return coreFetch(url, { ...init, method: \"HEAD\" });\n },\n /** Call a PATCH endpoint */\n PATCH(url, init) {\n return coreFetch(url, { ...init, method: \"PATCH\" });\n },\n /** Call a TRACE endpoint */\n TRACE(url, init) {\n return coreFetch(url, { ...init, method: \"TRACE\" });\n },\n /** Register middleware */\n use(...middleware) {\n for (const m of middleware) {\n if (!m) {\n continue;\n }\n if (typeof m !== \"object\" || !(\"onRequest\" in m || \"onResponse\" in m || \"onError\" in m)) {\n throw new Error(\"Middleware must be an object with one of `onRequest()`, `onResponse() or `onError()`\");\n }\n globalMiddlewares.push(m);\n }\n },\n /** Unregister middleware */\n eject(...middleware) {\n for (const m of middleware) {\n const i = globalMiddlewares.indexOf(m);\n if (i !== -1) {\n globalMiddlewares.splice(i, 1);\n }\n }\n },\n };\n}\n\nclass PathCallForwarder {\n constructor(client, url) {\n this.client = client;\n this.url = url;\n }\n\n GET = (init) => {\n return this.client.GET(this.url, init);\n };\n PUT = (init) => {\n return this.client.PUT(this.url, init);\n };\n POST = (init) => {\n return this.client.POST(this.url, init);\n };\n DELETE = (init) => {\n return this.client.DELETE(this.url, init);\n };\n OPTIONS = (init) => {\n return this.client.OPTIONS(this.url, init);\n };\n HEAD = (init) => {\n return this.client.HEAD(this.url, init);\n };\n PATCH = (init) => {\n return this.client.PATCH(this.url, init);\n };\n TRACE = (init) => {\n return this.client.TRACE(this.url, init);\n };\n}\n\nclass PathClientProxyHandler {\n constructor() {\n this.client = null;\n }\n\n // Assume the property is an URL.\n get(coreClient, url) {\n const forwarder = new PathCallForwarder(coreClient, url);\n this.client[url] = forwarder;\n return forwarder;\n }\n}\n\n/**\n * Wrap openapi-fetch client to support a path based API.\n * @type {import(\"./index.js\").wrapAsPathBasedClient}\n */\nexport function wrapAsPathBasedClient(coreClient) {\n const handler = new PathClientProxyHandler();\n const proxy = new Proxy(coreClient, handler);\n\n // Put the proxy on the prototype chain of the actual client.\n // This means if we do not have a memoized PathCallForwarder,\n // we fall back to the proxy to synthesize it.\n // However, the proxy itself is not on the hot-path (if we fetch the same\n // endpoint multiple times, only the first call will hit the proxy).\n function Client() {}\n Client.prototype = proxy;\n\n const client = new Client();\n\n // Feed the client back to the proxy handler so it can store the generated\n // PathCallForwarder.\n handler.client = client;\n\n return client;\n}\n\n/**\n * Convenience method to an openapi-fetch path based client.\n * Strictly equivalent to `wrapAsPathBasedClient(createClient(...))`.\n * @type {import(\"./index.js\").createPathBasedClient}\n */\nexport function createPathBasedClient(clientOptions) {\n return wrapAsPathBasedClient(createClient(clientOptions));\n}\n\n// utils\n\n/**\n * Serialize primitive param values\n * @type {import(\"./index.js\").serializePrimitiveParam}\n */\nexport function serializePrimitiveParam(name, value, options) {\n if (value === undefined || value === null) {\n return \"\";\n }\n if (typeof value === \"object\") {\n throw new Error(\n \"Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.\",\n );\n }\n return `${name}=${options?.allowReserved === true ? value : encodeURIComponent(value)}`;\n}\n\n/**\n * Serialize object param (shallow only)\n * @type {import(\"./index.js\").serializeObjectParam}\n */\nexport function serializeObjectParam(name, value, options) {\n if (!value || typeof value !== \"object\") {\n return \"\";\n }\n const values = [];\n const joiner =\n {\n simple: \",\",\n label: \".\",\n matrix: \";\",\n }[options.style] || \"&\";\n\n // explode: false\n if (options.style !== \"deepObject\" && options.explode === false) {\n for (const k in value) {\n values.push(k, options.allowReserved === true ? value[k] : encodeURIComponent(value[k]));\n }\n const final = values.join(\",\"); // note: values are always joined by comma in explode: false (but joiner can prefix)\n switch (options.style) {\n case \"form\": {\n return `${name}=${final}`;\n }\n case \"label\": {\n return `.${final}`;\n }\n case \"matrix\": {\n return `;${name}=${final}`;\n }\n default: {\n return final;\n }\n }\n }\n\n // explode: true\n for (const k in value) {\n const finalName = options.style === \"deepObject\" ? `${name}[${k}]` : k;\n values.push(serializePrimitiveParam(finalName, value[k], options));\n }\n const final = values.join(joiner);\n return options.style === \"label\" || options.style === \"matrix\" ? `${joiner}${final}` : final;\n}\n\n/**\n * Serialize array param (shallow only)\n * @type {import(\"./index.js\").serializeArrayParam}\n */\nexport function serializeArrayParam(name, value, options) {\n if (!Array.isArray(value)) {\n return \"\";\n }\n\n // explode: false\n if (options.explode === false) {\n const joiner = { form: \",\", spaceDelimited: \"%20\", pipeDelimited: \"|\" }[options.style] || \",\"; // note: for arrays, joiners vary wildly based on style + explode behavior\n const final = (options.allowReserved === true ? value : value.map((v) => encodeURIComponent(v))).join(joiner);\n switch (options.style) {\n case \"simple\": {\n return final;\n }\n case \"label\": {\n return `.${final}`;\n }\n case \"matrix\": {\n return `;${name}=${final}`;\n }\n // case \"spaceDelimited\":\n // case \"pipeDelimited\":\n default: {\n return `${name}=${final}`;\n }\n }\n }\n\n // explode: true\n const joiner = { simple: \",\", label: \".\", matrix: \";\" }[options.style] || \"&\";\n const values = [];\n for (const v of value) {\n if (options.style === \"simple\" || options.style === \"label\") {\n values.push(options.allowReserved === true ? v : encodeURIComponent(v));\n } else {\n values.push(serializePrimitiveParam(name, v, options));\n }\n }\n return options.style === \"label\" || options.style === \"matrix\"\n ? `${joiner}${values.join(joiner)}`\n : values.join(joiner);\n}\n\n/**\n * Serialize query params to string\n * @type {import(\"./index.js\").createQuerySerializer}\n */\nexport function createQuerySerializer(options) {\n return function querySerializer(queryParams) {\n const search = [];\n if (queryParams && typeof queryParams === \"object\") {\n for (const name in queryParams) {\n const value = queryParams[name];\n if (value === undefined || value === null) {\n continue;\n }\n if (Array.isArray(value)) {\n if (value.length === 0) {\n continue;\n }\n search.push(\n serializeArrayParam(name, value, {\n style: \"form\",\n explode: true,\n ...options?.array,\n allowReserved: options?.allowReserved || false,\n }),\n );\n continue;\n }\n if (typeof value === \"object\") {\n search.push(\n serializeObjectParam(name, value, {\n style: \"deepObject\",\n explode: true,\n ...options?.object,\n allowReserved: options?.allowReserved || false,\n }),\n );\n continue;\n }\n search.push(serializePrimitiveParam(name, value, options));\n }\n }\n return search.join(\"&\");\n };\n}\n\n/**\n * Handle different OpenAPI 3.x serialization styles\n * @type {import(\"./index.js\").defaultPathSerializer}\n * @see https://swagger.io/docs/specification/serialization/#path\n */\nexport function defaultPathSerializer(pathname, pathParams) {\n let nextURL = pathname;\n for (const match of pathname.match(PATH_PARAM_RE) ?? []) {\n let name = match.substring(1, match.length - 1);\n let explode = false;\n let style = \"simple\";\n if (name.endsWith(\"*\")) {\n explode = true;\n name = name.substring(0, name.length - 1);\n }\n if (name.startsWith(\".\")) {\n style = \"label\";\n name = name.substring(1);\n } else if (name.startsWith(\";\")) {\n style = \"matrix\";\n name = name.substring(1);\n }\n if (!pathParams || pathParams[name] === undefined || pathParams[name] === null) {\n continue;\n }\n const value = pathParams[name];\n if (Array.isArray(value)) {\n nextURL = nextURL.replace(match, serializeArrayParam(name, value, { style, explode }));\n continue;\n }\n if (typeof value === \"object\") {\n nextURL = nextURL.replace(match, serializeObjectParam(name, value, { style, explode }));\n continue;\n }\n if (style === \"matrix\") {\n nextURL = nextURL.replace(match, `;${serializePrimitiveParam(name, value)}`);\n continue;\n }\n nextURL = nextURL.replace(match, style === \"label\" ? `.${encodeURIComponent(value)}` : encodeURIComponent(value));\n }\n return nextURL;\n}\n\n/**\n * Serialize body object to string\n * @type {import(\"./index.js\").defaultBodySerializer}\n */\nexport function defaultBodySerializer(body, headers) {\n if (body instanceof FormData) {\n return body;\n }\n if (headers) {\n const contentType =\n headers.get instanceof Function\n ? (headers.get(\"Content-Type\") ?? headers.get(\"content-type\"))\n : (headers[\"Content-Type\"] ?? headers[\"content-type\"]);\n if (contentType === \"application/x-www-form-urlencoded\") {\n return new URLSearchParams(body).toString();\n }\n }\n return JSON.stringify(body);\n}\n\n/**\n * Construct URL string from baseUrl and handle path and query params\n * @type {import(\"./index.js\").createFinalURL}\n */\nexport function createFinalURL(pathname, options) {\n let finalURL = `${options.baseUrl}${pathname}`;\n if (options.params?.path) {\n finalURL = options.pathSerializer(finalURL, options.params.path);\n }\n let search = options.querySerializer(options.params.query ?? {});\n if (search.startsWith(\"?\")) {\n search = search.substring(1);\n }\n if (search) {\n finalURL += `?${search}`;\n }\n return finalURL;\n}\n\n/**\n * Merge headers a and b, with b taking priority\n * @type {import(\"./index.js\").mergeHeaders}\n */\nexport function mergeHeaders(...allHeaders) {\n const finalHeaders = new Headers();\n for (const h of allHeaders) {\n if (!h || typeof h !== \"object\") {\n continue;\n }\n const iterator = h instanceof Headers ? h.entries() : Object.entries(h);\n for (const [k, v] of iterator) {\n if (v === null) {\n finalHeaders.delete(k);\n } else if (Array.isArray(v)) {\n for (const v2 of v) {\n finalHeaders.append(k, v2);\n }\n } else if (v !== undefined) {\n finalHeaders.set(k, v);\n }\n }\n }\n return finalHeaders;\n}\n\n/**\n * Remove trailing slash from url\n * @type {import(\"./index.js\").removeTrailingSlash}\n */\nexport function removeTrailingSlash(url) {\n if (url.endsWith(\"/\")) {\n return url.substring(0, url.length - 1);\n }\n return url;\n}\n","import createClient from 'openapi-fetch';\nimport type { paths } from './api-types.js';\n\n/**\n * Create a type-safe API client.\n *\n * Lives in its own module (subpath `@shoppex/contracts/api-client`) so buyer-facing\n * bundles can take the client without the root barrel and the zod schemas it\n * re-exports.\n *\n * @example\n * const client = createApiClient('https://api.shoppex.io/v1');\n *\n * // Fully typed request and response\n * const { data, error } = await client.GET('/products', {\n * params: { query: { page: 1, limit: 25 } }\n * });\n */\nexport function createApiClient(baseUrl: string, token?: string) {\n return createClient<paths>({\n baseUrl,\n headers: token ? { Authorization: `Bearer ${token}` } : undefined,\n });\n}\n","/**\n * Typed OpenAPI client factory.\n *\n * Surfaces the generated `createApiClient` from `@shoppex/contracts` with the\n * SDK's configured `apiBaseUrl`. This lets consumers of `@shoppexio/storefront`\n * call any public Dev API endpoint with full end-to-end types without\n * rebuilding a client from scratch.\n *\n * Prefer the high-level modules (`shoppex.getProducts()` etc.) for common\n * read flows — they handle caching, pagination defaults, and storefront\n * scoping. Drop down to `shoppex.client()` only when you need an endpoint\n * the high-level API does not cover yet.\n */\n\nimport { createApiClient } from '@shoppex/contracts/api-client';\nimport type { ShoppexConfig } from '../types';\nimport { DEFAULT_API_BASE_URL, getConfig } from './config';\n\ntype ApiClient = ReturnType<typeof createApiClient>;\n\nlet cachedClient: ApiClient | null = null;\nlet cachedConfig: ShoppexConfig | null = null;\n\n/**\n * Return a typed OpenAPI client bound to the SDK's configured API base URL.\n * The client is cached for the config object it was built from: every init\n * creates a new config object, so a re-init rebuilds it. Keyed here instead of\n * reset from `initConfig`, so `core/config.ts` (which every SDK user loads)\n * does not import this module and its `openapi-fetch` dependency.\n */\nexport function getTypedClient(token?: string): ApiClient {\n const config = getConfig();\n\n if (cachedClient && cachedConfig === config && !token) {\n return cachedClient;\n }\n\n const client = createApiClient(config.apiBaseUrl ?? DEFAULT_API_BASE_URL, token);\n\n if (!token) {\n cachedClient = client;\n cachedConfig = config;\n }\n\n return client;\n}\n","/**\n * Store Module\n *\n * API methods for store data.\n */\n\nimport { forwardFailure, get } from '../core/client';\nimport { DEFAULT_API_BASE_URL, getConfig, isInitialized, setShopId } from '../core/config';\nimport { buildEndpoint } from '../core/endpoint';\nimport type {\n SDKResponse,\n Shop,\n Product,\n StorefrontData,\n ProductGroup,\n Category,\n StorefrontAddonBootstrap,\n CursorPagination,\n} from '../types';\n\ninterface StoreResponse {\n shop: Shop;\n products?: Product[];\n products_pagination?: CursorPagination | null;\n groups?: ProductGroup[];\n items?: StorefrontData['items'];\n categories?: Category[];\n addons?: StorefrontAddonBootstrap;\n}\n\ninterface StorefrontResponse {\n shop: Shop;\n}\n\nexport interface GetStorefrontOptions {\n productsLimit?: number;\n productsCursor?: string | null;\n}\n\nconst STORE_CACHE_TTL = 5 * 60 * 1000;\n\nexport async function getStore(): Promise<SDKResponse<Shop>> {\n const config = getConfig();\n const response = await get<StoreResponse>(\n buildEndpoint('/v1/storefront/shops/name/:storeSlug', {\n storeSlug: config.storeSlug,\n }),\n {\n buyerCurrency: true,\n cache: {\n key: `store:${config.storeSlug}`,\n ttl: STORE_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n // Cache the shopId for slug lookups\n if (response.data.shop?.id) {\n setShopId(response.data.shop.id);\n }\n return {\n success: true,\n data: response.data.shop,\n };\n }\n\n return forwardFailure(response);\n}\n\nexport async function resolveStoreByDomain(\n domain?: string,\n apiBaseUrl?: string\n): Promise<SDKResponse<Shop>> {\n const resolvedDomain =\n domain ??\n (typeof window !== 'undefined' ? window.location.hostname : '');\n\n if (!resolvedDomain) {\n return {\n success: false,\n message: 'Domain is required to resolve store',\n };\n }\n\n const cleanDomain = resolvedDomain\n .replace(/^https?:\\/\\//, '')\n .split('/')[0]\n .trim();\n\n const baseUrl =\n apiBaseUrl ??\n (isInitialized() ? getConfig().apiBaseUrl : DEFAULT_API_BASE_URL);\n\n const response = await get<StorefrontResponse>(\n buildEndpoint('/v1/storefront/shops/domain/:domain', {\n domain: cleanDomain,\n }),\n {\n baseUrl,\n buyerCurrency: true,\n cache: {\n key: `store:domain:${cleanDomain}`,\n ttl: STORE_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data?.shop) {\n if (response.data.shop.id) {\n setShopId(response.data.shop.id);\n }\n return {\n success: true,\n data: response.data.shop,\n };\n }\n\n return forwardFailure(response, { message: response.message ?? 'Failed to resolve store' });\n}\n\nexport async function getStorefront(options?: GetStorefrontOptions): Promise<SDKResponse<StorefrontData>> {\n const config = getConfig();\n const query = new URLSearchParams();\n if (Number.isFinite(options?.productsLimit)) {\n query.set('products_limit', String(Math.max(1, Math.floor(options?.productsLimit ?? 0))));\n }\n if (typeof options?.productsCursor === 'string' && options.productsCursor.trim().length > 0) {\n query.set('products_cursor', options.productsCursor);\n }\n const querySuffix = query.size > 0 ? `?${query.toString()}` : '';\n const response = await get<StoreResponse>(\n `${buildEndpoint('/v1/storefront/shops/name/:storeSlug', {\n storeSlug: config.storeSlug,\n })}${querySuffix}`,\n {\n buyerCurrency: true,\n cache: {\n key: `storefront:${config.storeSlug}:${options?.productsLimit ?? 'full'}:${options?.productsCursor ?? 'start'}`,\n ttl: STORE_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n // Cache the shopId for slug lookups\n if (response.data.shop?.id) {\n setShopId(response.data.shop.id);\n }\n return {\n success: true,\n data: {\n shop: response.data.shop,\n products: response.data.products ?? [],\n products_pagination: response.data.products_pagination ?? null,\n groups: response.data.groups ?? [],\n items: response.data.items ?? [],\n categories: response.data.categories ?? [],\n addons: response.data.addons ?? { items: [] },\n },\n };\n }\n\n return forwardFailure(response);\n}\n\nexport async function getStoreLogoUrl(): Promise<string | null> {\n const response = await getStore();\n\n if (response.success && response.data?.logo) {\n return response.data.logo;\n }\n\n return null;\n}\n\nexport async function getStoreBannerUrl(): Promise<string | null> {\n const response = await getStore();\n\n if (response.success && response.data?.banner) {\n return response.data.banner;\n }\n\n return null;\n}\n","import type { Product, ProductGroup } from '../types/index.js';\n\nexport function buildStorefrontProductLookup(products: Product[] = []): Map<string, Product> {\n const lookup = new Map<string, Product>();\n for (const product of products) {\n if (!product?.uniqid || lookup.has(product.uniqid)) continue;\n lookup.set(product.uniqid, product);\n }\n return lookup;\n}\n\n// Groups reference their products by uniqid; the objects live once in `products`.\nexport function getStorefrontGroupProducts(\n group: ProductGroup,\n productsOrLookup: Product[] | Map<string, Product> = [],\n): Product[] {\n const lookup = productsOrLookup instanceof Map\n ? productsOrLookup\n : buildStorefrontProductLookup(productsOrLookup);\n return (group.product_uniqids ?? []).flatMap((uniqid) => {\n const product = lookup.get(uniqid);\n return product ? [product] : [];\n });\n}\n\nexport function getMergedStorefrontProducts(products: Product[] = []): Product[] {\n return Array.from(buildStorefrontProductLookup(products).values());\n}\n","/**\n * Products Module\n *\n * API methods for product data.\n */\n\nimport { forwardFailure, get } from '../core/client';\nimport { getConfig, getShopId } from '../core/config';\nimport { buildEndpoint } from '../core/endpoint';\nimport type {\n SDKResponse,\n Product,\n ProductCategory,\n ProductGroup,\n ProductVariant,\n PriceVariant,\n CursorPagination,\n} from '../types';\nimport { getStore } from './store';\nimport { getMergedStorefrontProducts } from '../utils/storefront-catalog';\n\ninterface ProductsResponse {\n products: Product[];\n groups?: ProductGroup[];\n pagination?: CursorPagination | null;\n}\n\ninterface ProductResponse {\n product: Product;\n}\n\nconst PRODUCTS_CACHE_TTL = 2 * 60 * 1000;\n\nexport interface GetStorefrontProductsPageOptions {\n cursor?: string | null;\n limit?: number;\n sort?: 'featured' | 'newest' | 'price-asc' | 'price-desc' | string | null;\n category?: string | null;\n hideOutOfStock?: boolean;\n}\n\nfunction getStorefrontProductsPageCategoryCacheKey(category: string | null | undefined): string {\n if (category === undefined) return 'category:unset';\n if (category === null) return 'category:null';\n return `category:${category}`;\n}\n\nfunction priceVariantToProductVariant(variant: PriceVariant & { stock?: number }): ProductVariant {\n return {\n id: variant.id,\n title: variant.title ?? variant.label ?? '',\n price: typeof variant.price === 'number' ? variant.price : Number(variant.price) || 0,\n sku: variant.sku,\n stock: typeof variant.stock === 'number' ? variant.stock : undefined,\n orderable: typeof variant.orderable === 'boolean' ? variant.orderable : undefined,\n quantity_min: variant.quantity_min,\n quantity_max: variant.quantity_max,\n quantityMin: variant.quantityMin,\n quantityMax: variant.quantityMax,\n image_id: variant.image_id,\n imageId: variant.imageId,\n cloudflare_image_id: variant.cloudflare_image_id,\n cloudflareImageId: variant.cloudflareImageId,\n image_url: variant.image_url,\n imageUrl: variant.imageUrl,\n visibility: variant.visibility,\n is_private: variant.is_private,\n };\n}\n\nfunction normalizeProduct(product: Product): Product {\n if (product.variants && product.variants.length > 0) {\n return product;\n }\n\n const priceVariants = product.price_variants;\n if (!Array.isArray(priceVariants) || priceVariants.length === 0) {\n return product;\n }\n\n return {\n ...product,\n variants: priceVariants.map((variant) =>\n priceVariantToProductVariant(variant as PriceVariant & { stock?: number })\n ),\n };\n}\n\nexport async function getProducts(): Promise<SDKResponse<Product[]>> {\n const config = getConfig();\n const response = await get<ProductsResponse>(\n buildEndpoint('/v1/storefront/products/public/:storeSlug', {\n storeSlug: config.storeSlug,\n }),\n {\n buyerCurrency: true,\n cache: {\n key: `products:${config.storeSlug}`,\n ttl: PRODUCTS_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n // The public route returns every public product exactly once in the flat `products` array —\n // group-bound products (e.g. variant-style DYNAMIC products) are included there too, so no\n // group merge is needed anymore. Groups only carry `product_uniqids` references into this\n // list. getMergedStorefrontProducts just dedupes by uniqid (first entry wins).\n return {\n success: true,\n data: getMergedStorefrontProducts(response.data.products.map(normalizeProduct)),\n };\n }\n\n return forwardFailure(response, { data: [] });\n}\n\nexport async function getStorefrontProductsPage(\n options?: GetStorefrontProductsPageOptions,\n): Promise<SDKResponse<{ products: Product[]; pagination: CursorPagination | null }>> {\n const config = getConfig();\n const query = new URLSearchParams();\n if (typeof options?.cursor === 'string' && options.cursor.trim().length > 0) {\n query.set('cursor', options.cursor);\n }\n if (Number.isFinite(options?.limit)) {\n query.set('limit', String(Math.max(1, Math.floor(options?.limit ?? 0))));\n }\n if (typeof options?.sort === 'string' && options.sort.trim().length > 0) {\n query.set('sort', options.sort.trim());\n }\n if (typeof options?.category === 'string' && options.category.trim().length > 0) {\n query.set('category', options.category.trim());\n }\n if (options?.hideOutOfStock === true) {\n query.set('hide_out_of_stock', 'true');\n }\n const querySuffix = query.size > 0 ? `?${query.toString()}` : '';\n\n const response = await get<ProductsResponse>(\n `${buildEndpoint('/v1/storefront/products/shop/:storeSlug', {\n storeSlug: config.storeSlug,\n })}${querySuffix}`,\n {\n buyerCurrency: true,\n cache: {\n key: `products:page:${config.storeSlug}:${options?.limit ?? 'default'}:${options?.cursor ?? 'start'}:${options?.sort ?? 'featured'}:${getStorefrontProductsPageCategoryCacheKey(options?.category)}:${options?.hideOutOfStock === true ? 'in-stock' : 'all-stock'}`,\n ttl: PRODUCTS_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n return {\n success: true,\n data: {\n products: response.data.products.map(normalizeProduct),\n pagination: response.data.pagination ?? null,\n },\n };\n }\n\n return forwardFailure(response);\n}\n\nexport async function getProduct(\n idOrSlug: string,\n options: {\n /**\n * A variant id from the page URL (`?variant=<id>`). A private variant is\n * listed only when it is named here; it then comes first in the variants,\n * so a buy box that opens on the first sellable option preselects it.\n */\n variant?: string;\n } = {},\n): Promise<SDKResponse<Product>> {\n // Slug lookups need the current shop id. Resolve it lazily so callers do not\n // have to remember to call getStore()/getStorefront() first.\n let shopId = getShopId();\n if (!shopId) {\n const store = await getStore();\n if (!store.success) {\n // The store lookup failed for a reason the caller must see (a refused\n // currency, a suspended shop); a product read without the shop id would\n // only turn that into a misleading not-found.\n return forwardFailure(store);\n }\n shopId = store.data?.id ?? null;\n }\n\n const query = new URLSearchParams();\n if (shopId) query.set('slug_shop_id', shopId);\n if (options.variant) query.set('variant', options.variant);\n const queryParams = query.size > 0 ? `?${query.toString()}` : '';\n\n const response = await get<ProductResponse>(\n `${buildEndpoint('/v1/storefront/products/unique/:idOrSlug', { idOrSlug })}${queryParams}`,\n {\n buyerCurrency: true,\n cache: {\n key: `product:${idOrSlug}:${shopId ?? 'no-shop'}:${options.variant ?? 'no-variant'}`,\n ttl: PRODUCTS_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data?.product) {\n return {\n success: true,\n data: normalizeProduct(response.data.product),\n };\n }\n\n return forwardFailure(response);\n}\n\nexport async function getCategories(): Promise<SDKResponse<string[]>> {\n const products = await getProducts();\n\n if (!products.success || !products.data) {\n return forwardFailure(products);\n }\n\n const categories = new Set<string>();\n for (const product of products.data) {\n if (product.categories) {\n for (const category of product.categories) {\n if (typeof category === 'string') {\n categories.add(category);\n } else if (category && typeof category === 'object' && 'uniqid' in category) {\n categories.add((category as ProductCategory).uniqid);\n }\n }\n }\n }\n\n return {\n success: true,\n data: Array.from(categories),\n };\n}\n","// Standalone product-redirect placeholder engine. Intentionally does NOT import from\n// manual-gateway-template.ts: that file is consumed via its own package subpath export\n// (@shoppex/contracts/manual-gateway-template), and a cross-subpath relative import here\n// breaks Next.js/Turbopack module resolution for client components that only depend on\n// this subpath. The scan/render logic is small enough to duplicate safely.\n\nexport const PRODUCT_REDIRECT_TEMPLATE_VARIABLES = ['product_id', 'order_id'] as const;\n\nexport type ProductRedirectTemplateVariable = typeof PRODUCT_REDIRECT_TEMPLATE_VARIABLES[number];\nexport type ProductRedirectTemplateVars = Record<ProductRedirectTemplateVariable, string>;\n\nexport const PRODUCT_REDIRECT_TEMPLATE_VARIABLE_EXAMPLES = [\n '{{product_id}}',\n '{{order_id}}',\n] as const;\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction buildVariablePattern(key: string, style: 'double' | 'single'): RegExp {\n const escapedKey = escapeRegExp(key);\n if (style === 'double') {\n return new RegExp(`\\\\{\\\\{\\\\s*${escapedKey}\\\\s*\\\\}\\\\}`, 'gi');\n }\n\n return new RegExp(`\\\\{?\\\\{\\\\s*${escapedKey}\\\\s*\\\\}(?!\\\\})`, 'gi');\n}\n\n// A single-brace pattern also takes the `{` before its token (`\\{?`), and a match that starts with\n// `{{` is dropped: that token sits inside a `{{` run. This stands in for a negative lookbehind on\n// `{`, which WebKit before Safari 16.4 cannot parse; the dashboard and checkout bundles ship this file.\nfunction isInsideDoubleBrace(raw: string): boolean {\n return raw.startsWith('{{');\n}\n\n/** The double-brace matches, then the single-brace matches outside a `{{` run. */\nfunction placeholderMatches(template: string, patterns: { double: RegExp; single: RegExp }) {\n return [\n ...template.matchAll(patterns.double),\n ...[...template.matchAll(patterns.single)].filter((match) => !isInsideDoubleBrace(match[0])),\n ];\n}\n\n// Accepts a partial var map: only the keys present (and non-empty) are\n// substituted. A variable the caller cannot supply is left as a raw placeholder\n// so downstream fail-closed checks (findRemainingProductRedirectPlaceholders)\n// reject the URL instead of emitting an encoded \"\" / \"null\".\nexport function renderProductRedirectTemplate(\n template: string,\n vars: Partial<ProductRedirectTemplateVars>,\n): string {\n let rendered = template;\n for (const [key, value] of Object.entries(vars)) {\n if (typeof value !== 'string' || value.length === 0) continue;\n const replacement = encodeURIComponent(value);\n rendered = rendered.replace(buildVariablePattern(key, 'double'), replacement);\n rendered = rendered.replace(buildVariablePattern(key, 'single'), (raw) => (isInsideDoubleBrace(raw) ? raw : replacement));\n }\n return rendered;\n}\n\nconst PLACEHOLDER_SCAN_PATTERNS = {\n double: /\\{\\{\\s*([a-zA-Z][a-zA-Z0-9_]*)\\s*\\}\\}/g,\n single: /\\{?\\{\\s*([a-zA-Z][a-zA-Z0-9_]*)\\s*\\}(?!\\})/g,\n};\n\nconst REMAINING_PLACEHOLDER_PATTERNS = {\n double: /\\{\\{[\\s\\S]*?\\}\\}/g,\n single: /\\{?\\{[^{}]+\\}(?!\\})/g,\n};\n\n// A fully rendered redirect URL never contains a literal curly brace — any `{`\n// or `}` left after substitution is a malformed/unrendered placeholder fragment\n// (e.g. the unbalanced `{{product_id` or trailing `}` in `{{product_id}}}`).\n// The balanced-span patterns above miss these, so scan for any brace that\n// survives once the balanced spans are stripped out.\nfunction findDanglingBraceFragments(template: string): string[] {\n const stripped = template\n .replace(REMAINING_PLACEHOLDER_PATTERNS.double, '')\n .replace(REMAINING_PLACEHOLDER_PATTERNS.single, (raw) => (isInsideDoubleBrace(raw) ? raw : ''));\n return /[{}]/.test(stripped) ? [...new Set(stripped.match(/[{}]+/g) ?? [])] : [];\n}\n\nexport function findUnsupportedProductRedirectPlaceholders(template: string): string[] {\n if (!template.trim()) {\n return [];\n }\n\n const allowedVariables = new Set<string>(PRODUCT_REDIRECT_TEMPLATE_VARIABLES);\n const unsupported = new Set<string>();\n const allowedRawSpans = new Set<string>();\n\n for (const match of placeholderMatches(template, PLACEHOLDER_SCAN_PATTERNS)) {\n const raw = match[0];\n const name = match[1]?.toLowerCase();\n if (name && !allowedVariables.has(name)) {\n unsupported.add(raw);\n } else if (name) {\n allowedRawSpans.add(raw);\n }\n }\n\n // Also reject malformed placeholder syntax (e.g. {{order-id}}, {{ product_id | x }}) that the\n // strict name patterns above don't match — same rationale as the manual-gateway scanner: catch\n // it at save time instead of letting a raw token survive to checkout.\n for (const match of placeholderMatches(template, REMAINING_PLACEHOLDER_PATTERNS)) {\n const raw = match[0];\n if (!allowedRawSpans.has(raw)) {\n unsupported.add(raw);\n }\n }\n\n // Reject unbalanced braces (e.g. `{{product_id` or `{{product_id}}}`) that the\n // balanced-span patterns never see — fail closed at save time rather than\n // letting a malformed token reach checkout.\n for (const fragment of findDanglingBraceFragments(template)) {\n unsupported.add(fragment);\n }\n\n return [...unsupported];\n}\n\nexport function findRemainingProductRedirectPlaceholders(template: string): string[] {\n if (!template.trim()) {\n return [];\n }\n\n const remaining = new Set<string>();\n for (const match of placeholderMatches(template, REMAINING_PLACEHOLDER_PATTERNS)) {\n remaining.add(match[0]);\n }\n\n // A rendered URL must not carry any leftover brace — including unbalanced ones\n // the balanced-span patterns miss — or checkout would redirect to a literal\n // malformed token instead of failing closed.\n for (const fragment of findDanglingBraceFragments(template)) {\n remaining.add(fragment);\n }\n\n return [...remaining];\n}\n\nexport function isSafeHttpsRedirectTemplateUrl(url: string): boolean {\n const trimmed = url.trim();\n if (!trimmed) {\n return false;\n }\n\n try {\n const parsed = new URL(trimmed);\n return parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n","/**\n * Checkout Module\n *\n * Creates invoice via backend API and redirects to hosted checkout page.\n * All checkout flows go through: checkout.shoppex.io/invoice/{invoiceId}\n */\n\nimport { checkoutAttribution } from '../core/analytics-session';\nimport { getConfig } from '../core/config';\nimport { post } from '../core/client';\nimport { getCart, getCartCoupon, getCartCouponSource, createCartBackup, clearCart, getLatestQuoteToken } from './cart';\nimport { getAffiliateCode, trackAffiliateEvent } from './affiliates';\nimport type { CartItem, CartAddon } from '../types/cart';\nimport type { BuyerRewards } from '../types/api';\nimport {\n findRemainingProductRedirectPlaceholders,\n isSafeHttpsRedirectTemplateUrl,\n} from '@shoppex/contracts/redirect-link-template';\nimport {\n COOKIE_CONSENT_CHECKOUT_HASH_KEY,\n COOKIE_CONSENT_COOKIE,\n parseCookieConsentValue,\n} from '@shoppex/contracts/storefront-consent-choice';\nimport {\n normalizeRequestedCurrency,\n resolveBuyerCurrency,\n} from '../utils/requested-currency';\n\nexport interface CheckoutOptions {\n autoRedirect?: boolean;\n locale?: string;\n email?: string;\n coupon?: string;\n currency?: string;\n /**\n * Absolute HTTPS URL used after a completed purchase when the product does\n * not define its own redirect. This is persisted on the invoice, so each\n * sales channel can provide its own return destination.\n */\n redirectUrl?: string;\n /**\n * Pin the quote proof this hand-off submits, as a tri-state: `undefined`\n * lets the SDK read the latest settled quote from storage, `null` submits\n * explicitly none, and a string submits exactly that token.\n */\n quoteToken?: string | null;\n /**\n * Referral (affiliate) code to submit, as a tri-state:\n *\n * - `undefined` — the SDK resolves it from storage (cart-applied referral\n * code first, then the ambient `?ref=` attribution).\n * - `''` — explicitly none: submit no referral code and do NOT re-read\n * storage. This is how a caller pins \"quoted WITHOUT a referral\"; without\n * it a code captured between the quote and the submit would be applied to\n * a total the buyer never saw.\n * - non-empty — pinned: submit exactly this code.\n *\n * `referralCode` is an alias and follows the same rules; `affiliateCode`\n * wins when both are present.\n */\n affiliateCode?: string;\n /** Alias of {@link CheckoutOptions.affiliateCode}, same tri-state. */\n referralCode?: string;\n customerCheckoutPath?: '/dashboard/api/checkout';\n /**\n * The cart this hand-off was approved FOR, as `JSON.stringify(getCart())`.\n *\n * PAYMENT PATH. A caller that writes the cart and reads it back before\n * checking out (Buy Now, which replaces the cart, is the sharp case) verifies\n * a cart it read at one moment, while these functions read storage again on\n * their way into the request — and localStorage is shared with every other\n * tab on the domain. A write landing in that gap is billed without ever\n * having passed the caller's verification.\n *\n * The caller cannot close that itself: any check it makes is one more read\n * BEFORE this one. Pinning the expected bytes moves the comparison to the\n * only place it can be conclusive — against the exact cart the call is about\n * to POST. A mismatch refuses before anything is created or sent.\n *\n * Honoured identically by BOTH invoice-creating entry points, `checkout()`\n * and `buildCheckoutUrl()` — they hit the same endpoint and create the same\n * invoice, so a pin that held on one and not the other would be a promise\n * the caller could not rely on. Only the refusal shape differs, following\n * each function's own success shape: `checkout()` returns\n * `{ success: false }`, `buildCheckoutUrl()` throws.\n *\n * Optional and additive: omitted, nothing changes, and the server is not\n * involved either way.\n */\n expectedCart?: string;\n}\n\nexport interface CheckoutResult {\n success: boolean;\n redirectUrl?: string;\n invoiceId?: string;\n rewards?: BuyerRewards | null;\n message?: string;\n /**\n * The server's machine-readable refusal identifier when the checkout was\n * refused, e.g. `errors.checkout.price_increased_since_quote` or\n * `errors.checkout.affiliate_code_not_applicable`. Branch on this rather\n * than on `message`, which is localized display copy.\n *\n * The quote-proof family — `errors.checkout.quote_token_invalid`,\n * `errors.checkout.quote_token_expired`, `errors.checkout.quote_token_stale`\n * — says the proof this call submitted could not be honoured: not ours, past\n * its window, or priced for a cart/currency/codes that have since moved. The\n * server refuses rather than pricing without the ceiling, so the caller's\n * response is always the same: `quoteCart()` again, show the buyer the new\n * total, and only then retry. A retry with the same stale token is refused\n * identically.\n *\n * Absent for failures the server never named (transport, timeout, an empty\n * cart caught client-side).\n */\n code?: string;\n}\n\n/**\n * Typed refusal from {@link buildCheckoutUrl}. The function keeps its existing\n * throw-based contract while preserving the server error code and status.\n */\nexport class CheckoutCreateError extends Error {\n readonly code?: string;\n readonly status?: number;\n\n constructor(message: string, options: {\n code?: string;\n status?: number;\n } = {}) {\n super(message);\n this.name = 'CheckoutCreateError';\n this.code = options.code;\n this.status = options.status;\n Object.setPrototypeOf(this, CheckoutCreateError.prototype);\n }\n}\n\ninterface CheckoutApiResponse {\n invoiceId?: string;\n checkoutUrl?: string;\n invoice_id?: string;\n checkout_url?: string;\n uniqid?: string;\n url?: string;\n url_branded?: string;\n rewards?: BuyerRewards | null;\n invoice?: {\n invoiceId?: string;\n checkoutUrl?: string;\n invoice_id?: string;\n checkout_url?: string;\n uniqid?: string;\n url?: string;\n url_branded?: string;\n rewards?: BuyerRewards | null;\n };\n}\n\ninterface NormalizedCheckoutData {\n invoiceId: string;\n checkoutUrl: string;\n rewards: BuyerRewards | null;\n}\n\nconst CHECKOUT_PREFILL_EMAIL_HASH_KEY = 'shoppex_prefill_email';\n\n/**\n * PAYMENT PATH. The single refusal copy for a broken `expectedCart` pin, shared\n * by every entry point that honours the pin so the buyer reads the same\n * sentence whichever one the theme calls. One literal, because two copies drift\n * and the difference would be visible to buyers on the same storefront.\n */\nconst CART_CHANGED_MESSAGE = 'Your cart changed while checkout was starting. Please review it and try again.';\n\n/**\n * PAYMENT PATH. True when the caller pinned a cart and storage no longer holds\n * it — see `CheckoutOptions.expectedCart`. Compared against the exact array the\n * caller is about to bill, which is the only comparison that is conclusive:\n * anything the caller checks itself is one more read BEFORE the read that\n * feeds the request.\n *\n * An omitted pin is not a mismatch. The pin is additive, and a caller that\n * never made the promise is left exactly as it was.\n */\nfunction isExpectedCartMismatch(cart: CartItem[], expectedCart: string | undefined): boolean {\n return expectedCart !== undefined && JSON.stringify(cart) !== expectedCart;\n}\n\nfunction normalizeCoupon(coupon: string | null | undefined): string | null {\n const normalized = coupon?.trim();\n return normalized ? normalized : null;\n}\n\nfunction normalizeEmail(email: string | null | undefined): string | null {\n const normalized = email?.trim();\n return normalized ? normalized : null;\n}\n\nfunction resolvePostPurchaseRedirectUrl(\n redirectUrl: string | null | undefined,\n): { value: string | null; error: null } | { value: null; error: string } {\n const normalized = redirectUrl?.trim();\n if (!normalized) {\n return { value: null, error: null };\n }\n if (!isSafeHttpsRedirectTemplateUrl(normalized)) {\n return { value: null, error: 'redirectUrl must be an absolute HTTPS URL.' };\n }\n if (findRemainingProductRedirectPlaceholders(normalized).length > 0) {\n return { value: null, error: 'redirectUrl must not contain template placeholders.' };\n }\n return { value: normalized, error: null };\n}\n\ninterface PendingCheckoutCreate {\n fingerprint: string;\n key: string;\n}\n\nconst pendingCheckoutCreates = new Map<string, PendingCheckoutCreate>();\n\nfunction acquireCheckoutCreateIdempotency(\n requestTarget: { endpoint: string; baseUrl?: string },\n createIntent: object,\n): PendingCheckoutCreate {\n const fingerprint = JSON.stringify({\n endpoint: requestTarget.endpoint,\n baseUrl: requestTarget.baseUrl ?? null,\n createIntent,\n });\n const existingAttempt = pendingCheckoutCreates.get(fingerprint);\n if (existingAttempt) {\n return existingAttempt;\n }\n\n const attempt = {\n fingerprint,\n key: globalThis.crypto.randomUUID(),\n };\n pendingCheckoutCreates.set(fingerprint, attempt);\n return attempt;\n}\n\nfunction releaseCheckoutCreateIdempotency(\n attempt: PendingCheckoutCreate,\n outcomeDefinitive: boolean,\n): void {\n // Only a parsed server refusal or a validated success makes the outcome\n // definitive. A rejected fetch, timeout, truncated body, or malformed body\n // may follow a committed create, so the next identical intent replays it.\n // An attempt is identified by its key, not object identity, so a late\n // definitive outcome cannot release a newer attempt for the same intent.\n if (outcomeDefinitive && pendingCheckoutCreates.get(attempt.fingerprint)?.key === attempt.key) {\n pendingCheckoutCreates.delete(attempt.fingerprint);\n }\n}\n\nfunction resolveCustomerCheckoutRequestTarget(options: CheckoutOptions): {\n endpoint: string;\n baseUrl?: string;\n} {\n if (\n options.customerCheckoutPath === '/dashboard/api/checkout'\n && typeof window !== 'undefined'\n && typeof window.location?.origin === 'string'\n ) {\n return {\n endpoint: options.customerCheckoutPath,\n baseUrl: window.location.origin,\n };\n }\n\n return { endpoint: '/v1/storefront/invoices/from-cart' };\n}\n\nfunction resolveRequestedCheckoutCurrency(options: CheckoutOptions): string | null {\n // An EXPLICIT currency option pins the request outright — '' means \"the\n // server default\", and neither falls through to the location/config reads.\n if (options.currency !== undefined) {\n return normalizeRequestedCurrency(options.currency);\n }\n return resolveBuyerCurrency(getConfig().currency);\n}\n\n/**\n * The currency an option-less checkout would request right now (location,\n * then config).\n */\nexport function getRequestedCheckoutCurrency(): string | null {\n return resolveBuyerCurrency(getConfig().currency);\n}\n\nfunction normalizeCheckoutFailureMessage(rawMessage: string | null | undefined): string {\n const message = rawMessage?.trim() ?? '';\n if (!message) {\n return 'Checkout failed. Please try again.';\n }\n\n if (isStaleCartProductError(message)) {\n return 'Your cart is outdated. Please add the products again.';\n }\n\n const httpMatch = message.match(/^HTTP\\s+(\\d{3})(?::\\s*(.*))?$/i);\n if (httpMatch) {\n const status = Number(httpMatch[1]);\n const detail = httpMatch[2]?.trim();\n\n if (detail && detail.length > 0) {\n return `Checkout failed: ${detail}`;\n }\n\n if (status >= 500) {\n return 'Checkout is temporarily unavailable. Please try again.';\n }\n\n if (status === 400) {\n return 'Checkout failed. Please check your details and try again.';\n }\n\n if (status === 401 || status === 403) {\n return 'Checkout is currently unavailable for this request.';\n }\n\n return 'Checkout failed. Please try again.';\n }\n\n if (/^internal server error$/i.test(message)) {\n return 'Checkout is temporarily unavailable. Please try again.';\n }\n\n return message;\n}\n\nfunction isStaleCartProductError(rawMessage: string | null | undefined): boolean {\n const message = rawMessage?.trim().toLowerCase() ?? '';\n if (!message) {\n return false;\n }\n\n return message.includes('product not found')\n || message.includes('product not available')\n || message.includes('products are no longer available')\n || message.includes('outdated product');\n}\n\nfunction validateCheckoutUrl(\n checkoutUrl: string,\n checkoutBaseUrl: string | undefined,\n expectedInvoiceId?: string\n): string | null {\n const expectedBaseUrl = checkoutBaseUrl?.trim();\n if (!expectedBaseUrl) {\n return null;\n }\n\n try {\n const parsedCheckoutUrl = new URL(checkoutUrl);\n const parsedExpectedBaseUrl = new URL(expectedBaseUrl);\n\n if (parsedCheckoutUrl.origin !== parsedExpectedBaseUrl.origin) {\n return null;\n }\n\n const normalizedPath = parsedCheckoutUrl.pathname.replace(/\\/+$/, '');\n const normalizedBasePath = parsedExpectedBaseUrl.pathname.replace(/\\/+$/, '');\n const expectedInvoicePath = `${normalizedBasePath}/invoice/`.replace(/\\/{2,}/g, '/');\n if (!normalizedPath.startsWith(expectedInvoicePath)) {\n return null;\n }\n\n const invoiceIdSegment = normalizedPath.slice(expectedInvoicePath.length);\n if (!invoiceIdSegment || invoiceIdSegment.includes('/')) {\n return null;\n }\n\n if (expectedInvoiceId) {\n const normalizedExpectedInvoiceId = expectedInvoiceId.trim();\n const invoiceIdFromUrl = decodeURIComponent(invoiceIdSegment);\n if (!normalizedExpectedInvoiceId || invoiceIdFromUrl !== normalizedExpectedInvoiceId) {\n return null;\n }\n }\n\n return parsedCheckoutUrl.toString();\n } catch {\n return null;\n }\n}\n\nfunction buildCheckoutUrlFromInvoiceId(\n checkoutBaseUrl: string | undefined,\n invoiceId: string\n): string | null {\n const normalizedBaseUrl = checkoutBaseUrl?.trim();\n if (!normalizedBaseUrl) {\n return null;\n }\n\n try {\n const baseUrl = new URL(normalizedBaseUrl);\n const basePath = baseUrl.pathname.replace(/\\/+$/, '');\n baseUrl.pathname = `${basePath}/invoice/${encodeURIComponent(invoiceId)}`.replace(/\\/{2,}/g, '/');\n baseUrl.search = '';\n baseUrl.hash = '';\n return baseUrl.toString();\n } catch {\n return null;\n }\n}\n\n/**\n * The buyer's cookie banner choice on this storefront, when it recorded one.\n * The hosted checkout is another site and cannot read the cookie, yet sends the\n * shop's Purchase pixels only under the same choice, so the value travels in\n * the checkout URL's hash (never sent to a server).\n */\nfunction readStorefrontConsentValue(): string | null {\n if (typeof document === 'undefined' || typeof document.cookie !== 'string') return null;\n const value = document.cookie\n .split(';')\n .map((part) => part.trim())\n .find((part) => part.startsWith(`${COOKIE_CONSENT_COOKIE}=`))\n ?.slice(COOKIE_CONSENT_COOKIE.length + 1);\n return parseCookieConsentValue(value) ? value! : null;\n}\n\nfunction appendCheckoutUrlOptions(\n checkoutUrl: string,\n options: { email?: string | null; locale?: string },\n): string {\n const normalizedEmail = normalizeEmail(options.email);\n const normalizedLocale = typeof options.locale === 'string' ? options.locale.trim() : '';\n const consent = readStorefrontConsentValue();\n\n if (!normalizedEmail && !normalizedLocale && !consent) {\n return checkoutUrl;\n }\n\n try {\n const parsedCheckoutUrl = new URL(checkoutUrl);\n if (normalizedLocale) {\n parsedCheckoutUrl.searchParams.set('locale', normalizedLocale);\n }\n if (normalizedEmail || consent) {\n const hashParams = new URLSearchParams(parsedCheckoutUrl.hash.startsWith('#')\n ? parsedCheckoutUrl.hash.slice(1)\n : parsedCheckoutUrl.hash);\n if (normalizedEmail) hashParams.set(CHECKOUT_PREFILL_EMAIL_HASH_KEY, normalizedEmail);\n if (consent) hashParams.set(COOKIE_CONSENT_CHECKOUT_HASH_KEY, consent);\n parsedCheckoutUrl.hash = hashParams.toString();\n }\n return parsedCheckoutUrl.toString();\n } catch {\n return checkoutUrl;\n }\n}\n\nfunction normalizeCheckoutResponse(\n response: CheckoutApiResponse | undefined,\n checkoutBaseUrl: string | undefined\n): NormalizedCheckoutData | null {\n const nestedInvoice = response?.invoice;\n const invoiceId = response?.invoiceId?.trim()\n || response?.invoice_id?.trim()\n || response?.uniqid?.trim()\n || nestedInvoice?.invoiceId?.trim()\n || nestedInvoice?.invoice_id?.trim()\n || nestedInvoice?.uniqid?.trim();\n let checkoutUrl = response?.checkoutUrl?.trim()\n || response?.checkout_url?.trim()\n || response?.url_branded?.trim()\n || response?.url?.trim()\n || nestedInvoice?.checkoutUrl?.trim()\n || nestedInvoice?.checkout_url?.trim()\n || nestedInvoice?.url_branded?.trim()\n || nestedInvoice?.url?.trim();\n\n if (!checkoutUrl && invoiceId && nestedInvoice) {\n checkoutUrl = buildCheckoutUrlFromInvoiceId(checkoutBaseUrl, invoiceId) ?? undefined;\n }\n\n if (!invoiceId || !checkoutUrl) {\n return null;\n }\n\n return {\n invoiceId,\n checkoutUrl,\n rewards: response?.rewards ?? nestedInvoice?.rewards ?? null,\n };\n}\n\nfunction resolveCheckoutOptions(\n couponOrOptions?: string | CheckoutOptions,\n options?: CheckoutOptions\n): CheckoutOptions {\n if (typeof couponOrOptions === 'string') {\n return {\n ...options,\n coupon: couponOrOptions,\n };\n }\n\n return couponOrOptions ?? options ?? {};\n}\n\nfunction normalizeAffiliateCode(options: CheckoutOptions, storedAffiliateCode: string | null): string | null {\n const explicitCode = options.affiliateCode ?? options.referralCode;\n // Tri-state, mirroring `coupon`: an explicit empty string means \"none\" and\n // must suppress the storage re-read. Only `undefined` lets the SDK resolve\n // the code itself — otherwise a referral captured after the quote was\n // rendered would be applied to a total the buyer never saw.\n if (typeof explicitCode === 'string') {\n const normalized = explicitCode.trim().toLowerCase();\n return normalized.length > 0 ? normalized : null;\n }\n\n return storedAffiliateCode?.trim().toLowerCase() ?? getAffiliateCode();\n}\n\nfunction resolveCheckoutCodes(options: CheckoutOptions): {\n coupon: string | null;\n affiliateCode: string | null;\n} {\n const storedCode = getCartCoupon();\n const storedSource = getCartCouponSource();\n const coupon = options.coupon === undefined\n ? (storedSource === 'COUPON' ? storedCode : null)\n : normalizeCoupon(options.coupon);\n const storedAffiliateCode = options.coupon === undefined && storedSource === 'AFFILIATE'\n ? storedCode\n : null;\n\n return {\n coupon,\n affiliateCode: normalizeAffiliateCode(options, storedAffiliateCode),\n };\n}\n\nfunction mapCartItemsForApi(items: CartItem[]) {\n const normalizeVariantIdForApi = (value: string | null | undefined): string | null => {\n const normalized = value?.trim();\n if (!normalized) return null;\n // Themes use \"default\" as a sentinel for \"no variant selected\".\n // Backend expects `null` in that case.\n if (normalized.toLowerCase() === 'default') return null;\n return normalized;\n };\n\n return items.map((item) => ({\n product_id: item.product_id,\n variant_id: normalizeVariantIdForApi(item.variant_id),\n quantity: item.quantity,\n addons: item.addons?.map((a: CartAddon) => ({ id: a.id, quantity: a.quantity ?? 1 })),\n custom_fields: item.custom_fields,\n price_variant_id: item.price_variant_id || null,\n pay_what_you_want_price: item.pay_what_you_want_price,\n }));\n}\n\nexport async function checkout(\n couponOrOptions?: string | CheckoutOptions,\n options?: CheckoutOptions\n): Promise<CheckoutResult> {\n const resolvedOptions = resolveCheckoutOptions(couponOrOptions, options);\n return performCheckout(resolvedOptions);\n}\n\nasync function performCheckout(\n resolvedOptions: CheckoutOptions,\n): Promise<CheckoutResult> {\n const { autoRedirect = true, email } = resolvedOptions;\n const checkoutCodes = resolveCheckoutCodes(resolvedOptions);\n const normalizedCoupon = checkoutCodes.coupon;\n const normalizedEmail = normalizeEmail(email);\n const normalizedAffiliateCode = checkoutCodes.affiliateCode;\n const requestedCurrency = resolveRequestedCheckoutCurrency(resolvedOptions);\n const postPurchaseRedirect = resolvePostPurchaseRedirectUrl(resolvedOptions.redirectUrl);\n\n const cart = getCart();\n if (cart.length === 0) {\n return {\n success: false,\n message: 'Cart is empty',\n };\n }\n\n // PAYMENT PATH. The cart the caller approved, compared against the cart this\n // call will actually POST — see `CheckoutOptions.expectedCart`. Refused\n // before the backup and before the request, so a cart that changed under the\n // caller is never billed and nothing is left half-done.\n if (isExpectedCartMismatch(cart, resolvedOptions.expectedCart)) {\n return {\n success: false,\n message: CART_CHANGED_MESSAGE,\n };\n }\n if (postPurchaseRedirect.error) {\n return {\n success: false,\n message: postPurchaseRedirect.error,\n };\n }\n\n createCartBackup();\n\n const config = getConfig();\n const checkoutRequestTarget = resolveCustomerCheckoutRequestTarget(resolvedOptions);\n\n const createIntent = {\n shop_slug: config.storeSlug,\n cart: mapCartItemsForApi(cart),\n email: normalizedEmail,\n coupon: normalizedCoupon,\n currency: requestedCurrency,\n return_url: postPurchaseRedirect.value ?? undefined,\n affiliate_code: normalizedAffiliateCode,\n // Proof of the total the buyer approved, from the last quoteCart(). Sent\n // automatically so the server can refuse an invoice priced above it.\n // Undefined when nothing has been quoted this session — the endpoint\n // treats that exactly as an older SDK.\n quote_token: resolvedOptions.quoteToken !== undefined\n ? (resolvedOptions.quoteToken ?? undefined)\n : (getLatestQuoteToken() ?? undefined),\n // Where the buyer came from: their analytics sessions after a yes on the\n // cookie banner, `declined` after a no. The server looks up the sources.\n attribution: checkoutAttribution(config.storeSlug),\n };\n const createAttempt = acquireCheckoutCreateIdempotency(checkoutRequestTarget, createIntent);\n const response = await post<CheckoutApiResponse>(\n checkoutRequestTarget.endpoint,\n createIntent,\n {\n retries: 0,\n baseUrl: checkoutRequestTarget.baseUrl,\n headers: {\n 'X-Idempotency-Key': createAttempt.key,\n },\n }\n );\n if (!response.success || !response.data) {\n releaseCheckoutCreateIdempotency(createAttempt, response.responseDefinitive === true);\n if (isStaleCartProductError(response.message)) {\n clearCart();\n }\n return {\n success: false,\n message: normalizeCheckoutFailureMessage(response.message),\n // The server's machine-readable refusal, preserved so callers can react\n // to e.g. `errors.checkout.price_increased_since_quote` without matching\n // localized copy.\n ...(response.code ? { code: response.code } : {}),\n };\n }\n\n const checkoutData = normalizeCheckoutResponse(response.data, config.checkoutBaseUrl);\n if (!checkoutData) {\n return {\n success: false,\n message: 'Failed to create invoice',\n };\n }\n\n const { invoiceId } = checkoutData;\n const safeCheckoutUrl = validateCheckoutUrl(\n checkoutData.checkoutUrl,\n config.checkoutBaseUrl,\n invoiceId\n );\n if (!safeCheckoutUrl) {\n return {\n success: false,\n message: 'Failed to create invoice',\n };\n }\n\n releaseCheckoutCreateIdempotency(createAttempt, true);\n\n // One checkout_started per created invoice: dedupes accidental duplicate\n // sends without dropping a buyer's genuine second order in the same session.\n void trackAffiliateEvent('checkout_started', {\n code: normalizedAffiliateCode,\n dedupeKey: `inv:${invoiceId}`,\n });\n\n const checkoutUrlWithPrefill = appendCheckoutUrlOptions(safeCheckoutUrl, {\n email: normalizedEmail,\n locale: resolvedOptions.locale ?? config.locale,\n });\n\n if (autoRedirect) {\n if (typeof window !== 'undefined' && window?.location) {\n window.location.href = checkoutUrlWithPrefill;\n clearCart();\n }\n }\n\n return {\n success: true,\n redirectUrl: checkoutUrlWithPrefill,\n invoiceId,\n rewards: checkoutData.rewards,\n };\n}\n\n/**\n * Build checkout URL by creating invoice first.\n * Returns the checkout URL for the created invoice.\n *\n * PAYMENT PATH. \"Build a URL\" names what this returns, not a lighter way to\n * price a cart: it POSTs the same invoice-creating endpoint as `checkout()` and\n * bills whatever storage holds when it reads. It therefore honours\n * `CheckoutOptions.expectedCart` on exactly the same terms — a pinned cart that\n * moved is refused, not invoiced.\n *\n * A refusal throws, like every other refusal on this function: the success\n * shape is a URL string, so there is no in-band value that a caller could\n * mistake for one. The thrown message is the buyer-facing copy, identical to\n * the sentence `checkout()` returns, and callers that already handle the\n * `Cart is empty` throw handle this one unchanged.\n */\nexport async function buildCheckoutUrl(\n couponOrOptions?: string | CheckoutOptions,\n options?: CheckoutOptions\n): Promise<string> {\n const resolvedOptions = resolveCheckoutOptions(couponOrOptions, options);\n return performBuildCheckoutUrl(resolvedOptions);\n}\n\nasync function performBuildCheckoutUrl(\n resolvedOptions: CheckoutOptions,\n): Promise<string> {\n const { email } = resolvedOptions;\n const checkoutCodes = resolveCheckoutCodes(resolvedOptions);\n const normalizedCoupon = checkoutCodes.coupon;\n const normalizedEmail = normalizeEmail(email);\n const normalizedAffiliateCode = checkoutCodes.affiliateCode;\n const requestedCurrency = resolveRequestedCheckoutCurrency(resolvedOptions);\n const postPurchaseRedirect = resolvePostPurchaseRedirectUrl(resolvedOptions.redirectUrl);\n\n const cart = getCart();\n if (cart.length === 0) {\n throw new Error('Cart is empty');\n }\n\n // PAYMENT PATH. Same position `checkout()` puts it in: after the empty-cart\n // check and before anything is created or sent. This path has no cart backup\n // to write, so the request is the first side effect there is — refusing here\n // means a cart that changed under the caller never reaches the endpoint, and\n // the buyer's cart is left exactly as the interfering write left it. It\n // matters most with no quote token in play, because then nothing downstream\n // carries an approved-total ceiling either.\n if (isExpectedCartMismatch(cart, resolvedOptions.expectedCart)) {\n throw new Error(CART_CHANGED_MESSAGE);\n }\n if (postPurchaseRedirect.error) {\n throw new Error(postPurchaseRedirect.error);\n }\n\n const config = getConfig();\n const checkoutRequestTarget = resolveCustomerCheckoutRequestTarget(resolvedOptions);\n\n const createIntent = {\n shop_slug: config.storeSlug,\n cart: mapCartItemsForApi(cart),\n email: normalizedEmail,\n coupon: normalizedCoupon,\n currency: requestedCurrency,\n return_url: postPurchaseRedirect.value ?? undefined,\n affiliate_code: normalizedAffiliateCode,\n // Same invoice-creating endpoint as `checkout()`, so it carries the same\n // proof of the approved total. \"Build a URL\" describes what this returns\n // to the caller, not a different way to price a cart — omitting the\n // token here left a public path on which the server had nothing to check\n // the invoice against. Same optional semantics: undefined when nothing\n // was quoted this session.\n quote_token: resolvedOptions.quoteToken !== undefined\n ? (resolvedOptions.quoteToken ?? undefined)\n : (getLatestQuoteToken() ?? undefined),\n };\n const createAttempt = acquireCheckoutCreateIdempotency(checkoutRequestTarget, createIntent);\n const response = await post<CheckoutApiResponse>(\n checkoutRequestTarget.endpoint,\n createIntent,\n {\n retries: 0,\n baseUrl: checkoutRequestTarget.baseUrl,\n headers: {\n 'X-Idempotency-Key': createAttempt.key,\n },\n }\n );\n if (!response.success || !response.data) {\n releaseCheckoutCreateIdempotency(createAttempt, response.responseDefinitive === true);\n if (isStaleCartProductError(response.message)) {\n clearCart();\n }\n throw new CheckoutCreateError(normalizeCheckoutFailureMessage(response.message), {\n ...(response.code ? { code: response.code } : {}),\n ...(response.status !== undefined ? { status: response.status } : {}),\n });\n }\n const checkoutData = normalizeCheckoutResponse(response.data, config.checkoutBaseUrl);\n if (!checkoutData) {\n throw new Error('Failed to create invoice');\n }\n\n const safeCheckoutUrl = validateCheckoutUrl(\n checkoutData.checkoutUrl,\n config.checkoutBaseUrl,\n checkoutData.invoiceId\n );\n if (!safeCheckoutUrl) {\n throw new Error('Failed to create invoice');\n }\n\n releaseCheckoutCreateIdempotency(createAttempt, true);\n\n // Same funnel point as checkout(): both entry points create the invoice.\n void trackAffiliateEvent('checkout_started', {\n code: normalizedAffiliateCode,\n dedupeKey: `inv:${checkoutData.invoiceId}`,\n });\n\n return appendCheckoutUrlOptions(safeCheckoutUrl, {\n email: normalizedEmail,\n locale: resolvedOptions.locale ?? config.locale,\n });\n}\n\n/**\n * @deprecated Use buildCheckoutUrl instead.\n * Sync version is no longer supported as invoice creation requires API call.\n */\nexport function buildCheckoutUrlSync(): never {\n throw new Error('buildCheckoutUrlSync is deprecated. Use buildCheckoutUrl (async) instead.');\n}\n","/**\n * Coupons Module\n *\n * Coupon validation before checkout.\n */\n\nimport { post } from '../core/client';\nimport { getShopId } from '../core/config';\nimport { getStore } from './store';\nimport { getCart } from './cart';\nimport type { SDKResponse, CouponValidation, CouponValidationOptions } from '../types';\n\nasync function resolveShopId(): Promise<string | null> {\n const cachedShopId = getShopId();\n if (cachedShopId) {\n return cachedShopId;\n }\n\n const storeResult = await getStore();\n if (!storeResult.success || !storeResult.data?.id) {\n return null;\n }\n\n return storeResult.data.id;\n}\n\nexport async function validateCoupon(\n code: string,\n productOrOptions?: string | CouponValidationOptions\n): Promise<SDKResponse<CouponValidation>> {\n const trimmedCode = code.trim();\n if (!trimmedCode) {\n return {\n success: false,\n message: 'Coupon code is required',\n };\n }\n\n const payload: Record<string, unknown> = {\n code: trimmedCode,\n };\n const productId = typeof productOrOptions === 'string'\n ? productOrOptions\n : productOrOptions?.productId;\n const variantId = typeof productOrOptions === 'string'\n ? undefined\n : productOrOptions?.variantId;\n\n if (variantId && !productId) {\n return {\n success: false,\n message: 'productId is required when variantId is provided',\n };\n }\n\n if (productId) {\n payload.product_id = productId;\n if (variantId) {\n payload.variant_id = variantId;\n }\n } else {\n const cart = getCart();\n if (cart.length === 0) {\n return {\n success: false,\n message: 'Cart is empty',\n };\n }\n\n const shopId = await resolveShopId();\n if (!shopId) {\n return {\n success: false,\n message: 'Failed to resolve store',\n };\n }\n\n payload.cart = JSON.stringify({\n shop_id: shopId,\n products: cart.map((item) => ({\n uniqid: item.product_id,\n quantity: item.quantity,\n variant_id: item.variant_id,\n price_variant_id: item.price_variant_id,\n addons: item.addons?.map((addon) => ({\n id: addon.id,\n quantity: addon.quantity ?? 1,\n })),\n })),\n });\n }\n\n const response = await post<CouponValidation>(\n '/v1/storefront/coupons/check',\n payload\n );\n\n return response;\n}\n","/**\n * Reviews Module\n *\n * Shop-level feedback/reviews.\n * Note: Shoppex has shop-level feedback, not product-level reviews.\n */\n\nimport { forwardFailure, get } from '../core/client';\nimport { getConfig } from '../core/config';\nimport { buildEndpoint } from '../core/endpoint';\nimport type { SDKResponse, Feedback, ShopReviewsPage } from '../types';\n\nconst REVIEWS_PAGE_LIMIT = 100;\nconst REVIEWS_CACHE_TTL = 2 * 60 * 1000;\n\nfunction toFiniteNumber(value: unknown): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value;\n }\n\n if (typeof value === 'string' && value.trim() !== '') {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : null;\n }\n\n return null;\n}\n\nfunction firstString(...values: unknown[]): string | undefined {\n for (const value of values) {\n if (typeof value === 'string' && value.length > 0) {\n return value;\n }\n }\n\n return undefined;\n}\n\nfunction normalizeFeedback(raw: Feedback, index: number): Feedback {\n const record = raw as Feedback & Record<string, unknown>;\n const rating = toFiniteNumber(record.rating) ?? toFiniteNumber(record.score) ?? 0;\n const comment = firstString(record.comment, record.message);\n const author = firstString(record.author, record.customer_name);\n const createdAt = record.created_at ?? record.createdAt;\n const created_at =\n typeof createdAt === 'number' || typeof createdAt === 'string'\n ? String(createdAt)\n : '';\n const id = firstString(record.id, record.uniqid) ?? `review:${created_at || index}`;\n\n return {\n ...record,\n id,\n rating,\n ...(comment ? { comment } : {}),\n ...(author ? { author } : {}),\n created_at,\n };\n}\n\n/** `code` of a filtered request the API answered without applying the filter. */\nexport const PRODUCT_FILTER_UNSUPPORTED = 'reviews_product_filter_unsupported';\n\nexport interface ShopReviewsPageOptions {\n /**\n * One product's reviews, by the product's public id (the `id` the catalog\n * carries). The page's `summary` then counts that product's reviews only.\n */\n product?: string | null;\n}\n\nexport async function getShopReviewsPage(\n cursor?: string | null,\n options: ShopReviewsPageOptions = {},\n): Promise<SDKResponse<ShopReviewsPage>> {\n const config = getConfig();\n const query = new URLSearchParams();\n query.set('limit', String(REVIEWS_PAGE_LIMIT));\n if (typeof cursor === 'string' && cursor.trim().length > 0) {\n query.set('cursor', cursor);\n }\n const product = typeof options.product === 'string' ? options.product.trim() : '';\n if (product) {\n query.set('product', product);\n }\n const querySuffix = `?${query.toString()}`;\n\n const response = await get<ShopReviewsPage>(\n `${buildEndpoint('/v1/storefront/feedback/shop/:storeSlug', {\n storeSlug: config.storeSlug,\n })}${querySuffix}`,\n {\n cache: {\n key: `reviews:${config.storeSlug}:${product || 'all'}:${cursor ?? 'start'}:${REVIEWS_PAGE_LIMIT}`,\n ttl: REVIEWS_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n // A filtered request is only answered when the API says it applied that\n // filter. An API that predates `product` ignores it and returns the whole\n // shop's reviews, which a caller would otherwise show as this product's.\n if (product && response.data.product !== product) {\n // The server did answer (2xx), so `status` and `responseReceived` say\n // so: this is a refusal of an unsupported filter, not a transport failure\n // a caller should retry or report as offline.\n return {\n success: false,\n message: 'Reviews for a single product are not available from this store yet.',\n code: PRODUCT_FILTER_UNSUPPORTED,\n status: 200,\n responseReceived: true,\n };\n }\n return {\n success: true,\n data: {\n ...response.data,\n feedback: response.data.feedback.map(normalizeFeedback),\n },\n };\n }\n\n return forwardFailure(response);\n}\n\nexport async function getShopReviews(): Promise<SDKResponse<Feedback[]>> {\n const allFeedback: Feedback[] = [];\n const seenCursors = new Set<string>();\n let cursor: string | null = null;\n\n while (true) {\n const response = await getShopReviewsPage(cursor);\n if (!response.success || !response.data) {\n return {\n success: false,\n message: response.message,\n data: [],\n };\n }\n\n allFeedback.push(...response.data.feedback);\n\n const pagination = response.data.pagination;\n if (!pagination?.has_more || !pagination.next_cursor) {\n break;\n }\n\n if (seenCursors.has(pagination.next_cursor)) {\n break;\n }\n\n seenCursors.add(pagination.next_cursor);\n cursor = pagination.next_cursor;\n }\n\n return {\n success: true,\n data: allFeedback,\n };\n}\n","import type { Product, PriceVariant, ProductVariant } from '../types/index.js';\n\ntype VariantLike =\n | Pick<ProductVariant, 'stock' | 'orderable' >\n | Pick<PriceVariant, 'stock' | 'orderable' >;\n\ntype ProductLike = Pick<Product, 'type' | 'stock' | 'orderable' | 'on_hold' | 'price_variants' | 'variants'> & {\n onHold?: boolean | number | string | null;\n is_on_hold?: boolean | number | string | null;\n isOnHold?: boolean | number | string | null;\n};\n\n/** The sentinel every predicate in this module already treats as \"unbounded\". */\nconst UNLIMITED_STOCK = -1;\n\n\nfunction normalizeStockValue(value: unknown): number | null {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n return null;\n }\n\n return Math.trunc(value);\n}\n\nfunction isTruthyFlag(value: unknown): boolean {\n if (value === true) return true;\n if (typeof value === 'number' && Number.isFinite(value)) return value !== 0;\n if (typeof value === 'string') {\n const normalized = value.trim().toLowerCase();\n return normalized === 'true' || normalized === '1';\n }\n return false;\n}\n\nfunction isProductOnHold(product: ProductLike | null | undefined): boolean {\n if (!product) return false;\n return isTruthyFlag(product.on_hold)\n || isTruthyFlag(product.onHold)\n || isTruthyFlag(product.is_on_hold)\n || isTruthyFlag(product.isOnHold);\n}\n\nfunction collectVariantStocks(product: ProductLike): number[] {\n const priceVariants = Array.isArray(product.price_variants) ? product.price_variants : [];\n if (priceVariants.length > 0) {\n return priceVariants.map((variant) => resolveVariantStockValue(variant));\n }\n\n const legacyVariants = Array.isArray(product.variants) ? product.variants : [];\n\n return legacyVariants.map((variant) => resolveVariantStockValue(variant));\n}\n\nexport function resolveVariantStockValue(variant: VariantLike | null | undefined): number {\n const normalized = normalizeStockValue(variant?.stock);\n return normalized ?? UNLIMITED_STOCK;\n}\n\nexport function resolveDisplayStock(product: ProductLike | null | undefined): number {\n if (!product) {\n return UNLIMITED_STOCK;\n }\n\n if (typeof product.type === 'string' && product.type.toUpperCase() === 'SERIALS') {\n return normalizeStockValue(product.stock) ?? UNLIMITED_STOCK;\n }\n\n const variantStocks = collectVariantStocks(product);\n if (variantStocks.length > 0) {\n // A single unbounded option makes the product unbounded.\n if (variantStocks.some((stock) => stock < 0)) {\n return UNLIMITED_STOCK;\n }\n\n const total = variantStocks.reduce((sum, stock) => sum + Math.max(stock, 0), 0);\n return total;\n }\n\n return normalizeStockValue(product.stock) ?? UNLIMITED_STOCK;\n}\n\nexport function isProductOutOfStock(product: ProductLike | null | undefined): boolean {\n // `on_hold` is a merchant pause, not a supply signal — it forces unavailable\n // BEFORE any `orderable` widening can apply.\n if (isProductOnHold(product)) return true;\n return resolveDisplayStock(product) === 0;\n}\n\nexport function isProductInStock(product: ProductLike | null | undefined): boolean {\n return !isProductOutOfStock(product);\n}\n\nexport function isVariantOutOfStock(variant: VariantLike | null | undefined): boolean {\n return resolveVariantStockValue(variant) === 0;\n}\n","import type { Product, ProductGroup } from '../types/index.js';\nimport {\n buildStorefrontProductLookup,\n getMergedStorefrontProducts,\n getStorefrontGroupProducts,\n} from './storefront-catalog.js';\nimport { isProductInStock } from './storefront-stock.js';\n\nexport interface StorefrontSearchFilterOptions {\n hideOutOfStock?: boolean;\n maxResults?: number;\n}\n\nexport type StorefrontCatalogSearchItem =\n | { type: 'product'; product: Product }\n // Groups only carry `product_uniqids`; `products` holds the resolved product\n // objects (in group order) so consumers never re-resolve references themselves.\n | { type: 'group'; group: ProductGroup; products: Product[] };\n\nexport function stripHtmlFromText(value: string | null | undefined): string {\n if (!value) return '';\n return value.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').trim();\n}\n\nexport function normalizeSearchQuery(query: string): string {\n return query.trim().toLowerCase();\n}\n\nfunction pushSearchPart(parts: string[], value: string | null | undefined): void {\n const normalized = stripHtmlFromText(value).toLowerCase();\n if (normalized) {\n parts.push(normalized);\n }\n}\n\nexport function collectProductSearchHaystack(product: Product): string[] {\n const parts: string[] = [];\n\n pushSearchPart(parts, product.title);\n pushSearchPart(parts, product.slug ?? undefined);\n pushSearchPart(parts, product.description);\n\n for (const highlight of product.product_highlights ?? []) {\n pushSearchPart(parts, highlight);\n }\n\n for (const variant of product.variants ?? []) {\n pushSearchPart(parts, variant.title);\n }\n\n for (const variant of product.price_variants ?? []) {\n pushSearchPart(parts, variant.title ?? variant.label);\n }\n\n return parts;\n}\n\nexport function productMatchesSearchQuery(product: Product, query: string): boolean {\n const normalized = normalizeSearchQuery(query);\n if (!normalized) return false;\n\n return collectProductSearchHaystack(product).some((haystack) => haystack.includes(normalized));\n}\n\nexport function groupMatchesSearchQuery(group: ProductGroup, query: string): boolean {\n const normalized = normalizeSearchQuery(query);\n if (!normalized) return false;\n\n const title = stripHtmlFromText(group.title).toLowerCase();\n const slug = stripHtmlFromText(group.slug ?? group.name ?? undefined).toLowerCase();\n const description = stripHtmlFromText(group.description).toLowerCase();\n\n return title.includes(normalized)\n || slug.includes(normalized)\n || description.includes(normalized);\n}\n\nexport function filterProductsBySearchQuery(\n products: Product[],\n query: string,\n options?: StorefrontSearchFilterOptions,\n): Product[] {\n const normalized = normalizeSearchQuery(query);\n if (!normalized) return [];\n\n let results = products.filter((product) => productMatchesSearchQuery(product, normalized));\n\n if (options?.hideOutOfStock) {\n results = results.filter((product) => isProductInStock(product));\n }\n\n if (options?.maxResults != null) {\n return results.slice(0, options.maxResults);\n }\n\n return results;\n}\n\nfunction groupHasVisibleProducts(\n groupProducts: Product[],\n hideOutOfStock: boolean,\n): boolean {\n if (groupProducts.length === 0) return false;\n if (!hideOutOfStock) return true;\n return groupProducts.some((product) => isProductInStock(product));\n}\n\nexport function searchMergedStorefrontCatalogItems(\n products: Product[],\n groups: ProductGroup[],\n query: string,\n options?: StorefrontSearchFilterOptions,\n): StorefrontCatalogSearchItem[] {\n const normalized = normalizeSearchQuery(query);\n if (!normalized) return [];\n\n const hideOutOfStock = options?.hideOutOfStock === true;\n const coveredProductIds = new Set<string>();\n const coveredGroupIds = new Set<string>();\n const results: StorefrontCatalogSearchItem[] = [];\n // Build the uniqid lookup once per search run; groups resolve against it.\n const lookup = buildStorefrontProductLookup(products);\n\n for (const group of groups) {\n const groupKey = group.uniqid ?? group.id;\n if (!groupKey || coveredGroupIds.has(groupKey)) continue;\n if (!groupMatchesSearchQuery(group, normalized)) continue;\n\n const groupProducts = getStorefrontGroupProducts(group, lookup);\n if (!groupHasVisibleProducts(groupProducts, hideOutOfStock)) continue;\n\n coveredGroupIds.add(groupKey);\n for (const product of groupProducts) {\n if (product?.uniqid) coveredProductIds.add(product.uniqid);\n }\n results.push({ type: 'group', group, products: groupProducts });\n }\n\n const merged = getMergedStorefrontProducts(products);\n for (const product of merged) {\n if (!product?.uniqid || coveredProductIds.has(product.uniqid)) continue;\n if (!productMatchesSearchQuery(product, normalized)) continue;\n if (hideOutOfStock && !isProductInStock(product)) continue;\n coveredProductIds.add(product.uniqid);\n results.push({ type: 'product', product });\n }\n\n if (options?.maxResults != null) {\n return results.slice(0, options.maxResults);\n }\n\n return results;\n}\n\nexport function searchMergedStorefrontCatalog(\n products: Product[],\n groups: ProductGroup[],\n query: string,\n options?: StorefrontSearchFilterOptions,\n): Product[] {\n const items = searchMergedStorefrontCatalogItems(products, groups, query, options);\n const matchedIds = new Set<string>();\n const results: Product[] = [];\n\n const addProduct = (product: Product) => {\n if (!product?.uniqid || matchedIds.has(product.uniqid)) return;\n if (options?.hideOutOfStock && !isProductInStock(product)) return;\n matchedIds.add(product.uniqid);\n results.push(product);\n };\n\n for (const item of items) {\n if (item.type === 'product') {\n addProduct(item.product);\n continue;\n }\n\n for (const product of item.products) {\n addProduct(product);\n }\n }\n\n if (options?.maxResults != null) {\n return results.slice(0, options.maxResults);\n }\n\n return results;\n}\n","import { getStorefront } from './store.js';\nimport { isInitialized } from '../core/config.js';\nimport {\n searchMergedStorefrontCatalog,\n searchMergedStorefrontCatalogItems,\n type StorefrontCatalogSearchItem,\n} from '../utils/storefront-search.js';\nimport type { SDKResponse, Product } from '../types/index.js';\n\nexport interface SearchOptions {\n hideOutOfStock?: boolean;\n maxResults?: number;\n}\n\nexport type { StorefrontCatalogSearchItem };\n\nexport async function searchCatalogItems(\n query: string,\n options?: SearchOptions,\n): Promise<SDKResponse<StorefrontCatalogSearchItem[]>> {\n if (!isInitialized()) {\n return { success: false, message: 'SDK not initialized' };\n }\n\n const trimmed = query.trim();\n if (!trimmed) {\n return { success: true, data: [] };\n }\n\n const storefront = await getStorefront();\n if (!storefront.success || !storefront.data) {\n return {\n success: false,\n message: storefront.message ?? 'Failed to fetch storefront catalog',\n };\n }\n\n const results = searchMergedStorefrontCatalogItems(\n storefront.data.products ?? [],\n storefront.data.groups ?? [],\n trimmed,\n {\n hideOutOfStock: options?.hideOutOfStock,\n maxResults: options?.maxResults,\n },\n );\n\n return { success: true, data: results };\n}\n\nexport async function searchProducts(\n query: string,\n options?: SearchOptions,\n): Promise<SDKResponse<Product[]>> {\n if (!isInitialized()) {\n return { success: false, message: 'SDK not initialized' };\n }\n\n const trimmed = query.trim();\n if (!trimmed) {\n return { success: true, data: [] };\n }\n\n const storefront = await getStorefront();\n if (!storefront.success || !storefront.data) {\n return {\n success: false,\n message: storefront.message ?? 'Failed to fetch storefront catalog',\n };\n }\n\n const results = searchMergedStorefrontCatalog(\n storefront.data.products ?? [],\n storefront.data.groups ?? [],\n trimmed,\n {\n hideOutOfStock: options?.hideOutOfStock,\n maxResults: options?.maxResults,\n },\n );\n\n return { success: true, data: results };\n}\n","/**\n * Invoices Module\n *\n * Invoice status checking after payment.\n */\n\nimport { get } from '../core/client';\nimport { buildEndpoint } from '../core/endpoint';\nimport type { SDKResponse, Invoice } from '../types';\n\nfunction normalizeInvoiceId(invoiceId: string): string | null {\n const normalized = invoiceId.trim();\n if (!normalized) {\n return null;\n }\n return normalized;\n}\n\nexport async function getInvoice(\n invoiceId: string\n): Promise<SDKResponse<Invoice>> {\n const normalizedInvoiceId = normalizeInvoiceId(invoiceId);\n if (!normalizedInvoiceId) {\n return {\n success: false,\n message: 'Invoice ID is required',\n };\n }\n\n const response = await get<{ invoice: Invoice }>(\n buildEndpoint('/v1/storefront/invoices/unique/:invoiceId', {\n invoiceId: normalizedInvoiceId,\n })\n );\n if (!response.success) {\n return {\n success: false,\n message: response.message,\n };\n }\n\n if (!response.data?.invoice) {\n return {\n success: false,\n message: 'Invalid invoice response',\n };\n }\n\n return {\n success: true,\n data: response.data.invoice,\n };\n}\n\nexport async function getInvoiceStatus(\n invoiceId: string\n): Promise<SDKResponse<{ status: string }>> {\n const normalizedInvoiceId = normalizeInvoiceId(invoiceId);\n if (!normalizedInvoiceId) {\n return {\n success: false,\n message: 'Invoice ID is required',\n };\n }\n\n const response = await get<{ invoice: { status: string } }>(\n buildEndpoint('/v1/storefront/invoices/status/:invoiceId', {\n invoiceId: normalizedInvoiceId,\n })\n );\n if (!response.success) {\n return {\n success: false,\n message: response.message,\n };\n }\n\n if (!response.data?.invoice?.status) {\n return {\n success: false,\n message: 'Invalid invoice status response',\n };\n }\n\n return {\n success: true,\n data: { status: response.data.invoice.status },\n };\n}\n","/**\n * Pages Module\n *\n * API methods for public pages.\n */\n\nimport { forwardFailure, get } from '../core/client';\nimport { getConfig } from '../core/config';\nimport { buildEndpoint } from '../core/endpoint';\nimport type { SDKResponse, Page } from '../types';\n\ninterface PagesResponse {\n pages: Page[];\n}\n\ninterface PageResponse {\n page: Page;\n}\n\nconst PAGES_CACHE_TTL = 5 * 60 * 1000;\n\n/**\n * Get all public pages for the store\n */\nexport async function getPages(): Promise<SDKResponse<Page[]>> {\n const config = getConfig();\n const response = await get<PagesResponse>(\n buildEndpoint('/v1/storefront/shops/name/:storeSlug/pages', {\n storeSlug: config.storeSlug,\n }),\n {\n cache: {\n key: `pages:${config.storeSlug}`,\n ttl: PAGES_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n return {\n success: true,\n data: response.data.pages,\n };\n }\n\n // The failure as the client saw it, `status` included: a storefront has to\n // tell a page that does not exist (404) from an API it could not reach.\n return forwardFailure(response);\n}\n\n/**\n * Get a public page by slug\n */\nexport async function getPage(slug: string): Promise<SDKResponse<Page>> {\n const config = getConfig();\n const response = await get<PageResponse>(\n buildEndpoint('/v1/storefront/shops/name/:storeSlug/pages/:slug', {\n storeSlug: config.storeSlug,\n slug,\n }),\n {\n cache: {\n key: `page:${config.storeSlug}:${slug}`,\n ttl: PAGES_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n return {\n success: true,\n data: response.data.page,\n };\n }\n\n // The failure as the client saw it, `status` included: a storefront has to\n // tell a page that does not exist (404) from an API it could not reach.\n return forwardFailure(response);\n}\n","const NAVIGATION_MENU_SLOT_CONFIG = {\n header: {\n title: 'Header',\n aliases: ['Header Menu'],\n },\n footer: {\n title: 'Footer',\n aliases: ['Footer Links', 'Legal Links'],\n },\n} as const;\n\nexport type NavigationMenuSlot = keyof typeof NAVIGATION_MENU_SLOT_CONFIG;\n\nfunction normalizeNavigationToken(value: string): string {\n return value.trim().toLowerCase().replace(/\\s+/g, ' ');\n}\n\nexport function getNavigationMenuCanonicalTitle(slot: NavigationMenuSlot): string {\n return NAVIGATION_MENU_SLOT_CONFIG[slot].title;\n}\n\nexport function getNavigationMenuTitles(slot: NavigationMenuSlot): string[] {\n const config = NAVIGATION_MENU_SLOT_CONFIG[slot];\n return [config.title, ...config.aliases];\n}\n\nexport function isNavigationMenuSlot(value: string): value is NavigationMenuSlot {\n return value in NAVIGATION_MENU_SLOT_CONFIG;\n}\n\nexport function resolveNavigationMenuSlot(value: string | null | undefined): NavigationMenuSlot | null {\n if (!value) return null;\n\n const normalizedValue = normalizeNavigationToken(value);\n for (const slot of Object.keys(NAVIGATION_MENU_SLOT_CONFIG) as NavigationMenuSlot[]) {\n const candidates = [slot, ...getNavigationMenuTitles(slot)];\n if (candidates.some((candidate) => normalizeNavigationToken(candidate) === normalizedValue)) {\n return slot;\n }\n }\n\n return null;\n}\n\nexport function isSystemNavigationMenuTitle(value: string | null | undefined): boolean {\n return resolveNavigationMenuSlot(value) !== null;\n}\n\nexport const NAVIGATION_MENU_SLOTS = Object.keys(NAVIGATION_MENU_SLOT_CONFIG) as NavigationMenuSlot[];\n","/**\n * Navigation Module\n *\n * API methods for menus and navigation.\n */\n\nimport { get } from '../core/client';\nimport { getConfig } from '../core/config';\nimport { buildEndpoint } from '../core/endpoint';\nimport type { SDKResponse, Menu } from '../types';\nimport type { NavigationMenuSlot } from '@shoppex/contracts/navigation';\nimport { getNavigationMenuTitles } from '@shoppex/contracts/navigation';\n\ninterface MenusResponse {\n menus: Menu[];\n}\n\ninterface MenuResponse {\n menu: Menu;\n}\n\nconst NAVIGATION_CACHE_TTL = 5 * 60 * 1000;\n\n/**\n * Get all menus for the store\n */\nexport async function getMenus(): Promise<SDKResponse<Menu[]>> {\n const config = getConfig();\n const response = await get<MenusResponse>(\n buildEndpoint('/v1/storefront/shops/name/:storeSlug/menus', {\n storeSlug: config.storeSlug,\n }),\n {\n cache: {\n key: `menus:${config.storeSlug}`,\n ttl: NAVIGATION_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n return {\n success: true,\n data: response.data.menus,\n };\n }\n\n return {\n success: false,\n message: response.message,\n };\n}\n\n/**\n * Get a menu by its exact title.\n */\nexport async function getMenuByTitle(title: string): Promise<SDKResponse<Menu>> {\n const config = getConfig();\n const response = await get<MenuResponse>(\n buildEndpoint('/v1/storefront/shops/name/:storeSlug/menus/:title', {\n storeSlug: config.storeSlug,\n title,\n }),\n {\n cache: {\n key: `menu:${config.storeSlug}:${title}`,\n ttl: NAVIGATION_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n return {\n success: true,\n data: response.data.menu,\n };\n }\n\n return {\n success: false,\n message: response.message,\n };\n}\n\n/**\n * Get a menu by its exact title.\n */\nexport async function getMenu(title: string): Promise<SDKResponse<Menu>> {\n return getMenuByTitle(title);\n}\n\n/**\n * Get a menu by canonical slot. The backend resolves legacy menu titles too.\n */\nexport async function getMenuBySlot(slot: NavigationMenuSlot): Promise<SDKResponse<Menu>> {\n const config = getConfig();\n const response = await get<MenuResponse>(\n buildEndpoint('/v1/storefront/shops/name/:storeSlug/menus/:title', {\n storeSlug: config.storeSlug,\n title: slot,\n }),\n {\n cache: {\n key: `menu-slot:${config.storeSlug}:${slot}`,\n ttl: NAVIGATION_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n return {\n success: true,\n data: response.data.menu,\n };\n }\n\n return {\n success: false,\n message: response.message,\n };\n}\n\nexport function getMenuSlotTitles(slot: NavigationMenuSlot): string[] {\n return getNavigationMenuTitles(slot);\n}\n","import { get, post } from '../core/client';\nimport { getConfig, getShopId, isInitialized } from '../core/config';\nimport { buildEndpoint } from '../core/endpoint';\nimport { resolveUtmParameters } from '../core/attribution';\nimport { resolveStorefrontPagePath } from '../core/page-path';\nimport { isPlatformPageTrackerActive } from '../core/page-tracker';\nimport type { SDKResponse, StorefrontOnlineUsers, StorefrontRecentSales } from '../types';\n\n/**\n * Anonymized recent-sales feed for storefront social proof (product title +\n * relative age only — never buyer identity). Empty items when the shop has no\n * recent completed orders.\n */\nexport async function getStorefrontRecentSales(): Promise<SDKResponse<StorefrontRecentSales>> {\n if (!isInitialized()) {\n return { success: false, message: 'SDK not initialized' };\n }\n\n const config = getConfig();\n const shopId = getShopId();\n const endpoint = shopId\n ? buildEndpoint('/v1/storefront/shops/id/:id/recent-sales', { id: shopId })\n : buildEndpoint('/v1/storefront/shops/:storeSlug/recent-sales', {\n storeSlug: config.storeSlug,\n });\n\n return get<StorefrontRecentSales>(endpoint, {\n cache: false,\n retries: 0,\n timeout: 5000,\n });\n}\n\nexport async function getStorefrontOnlineUsers(): Promise<SDKResponse<StorefrontOnlineUsers>> {\n if (!isInitialized()) {\n return { success: false, message: 'SDK not initialized' };\n }\n\n const config = getConfig();\n const shopId = getShopId();\n const endpoint = shopId\n ? buildEndpoint('/v1/storefront/shops/id/:id/online-users', { id: shopId })\n : buildEndpoint('/v1/storefront/shops/:storeSlug/online-users', {\n storeSlug: config.storeSlug,\n });\n\n return get<StorefrontOnlineUsers>(endpoint, {\n cache: false,\n retries: 0,\n timeout: 5000,\n });\n}\n\n/**\n * Keeps this visitor's live presence fresh. The ping carries\n * `event_type: 'presence'`, so the server refreshes the live session without\n * counting a shop view: an idle tab that touches presence every minute must\n * not add a view every few minutes. Page views go through `trackPageView()`.\n */\nexport async function touchStorefrontPresence(): Promise<SDKResponse<{ pong: string }>> {\n if (!isInitialized()) {\n return { success: false, message: 'SDK not initialized' };\n }\n if (typeof document === 'undefined') {\n return { success: false, message: 'Document is not available' };\n }\n // Code storefronts: the edge-injected tracker keeps this visitor's presence\n // fresh itself; a second touch from here would be a duplicate ping.\n if (isPlatformPageTrackerActive()) {\n return { success: true, message: 'Presence is reported by the storefront page tracker' };\n }\n // A preview page (an unpublished draft) is not a live visitor.\n if (getConfig().preview) {\n return { success: true, message: 'A preview page reports no presence' };\n }\n\n const config = getConfig();\n const shopId = getShopId();\n const endpoint = shopId\n ? buildEndpoint('/v1/storefront/shops/id/:id/ping', { id: shopId })\n : buildEndpoint('/v1/storefront/shops/:storeSlug/ping', {\n storeSlug: config.storeSlug,\n });\n\n return post<{ pong: string }>(\n endpoint,\n {\n event_type: 'presence',\n referer: document.referrer || undefined,\n path: resolveStorefrontPagePath(),\n utm: resolveUtmParameters(config.storeSlug),\n },\n {\n retries: 0,\n timeout: 5000,\n },\n );\n}\n","/**\n * Formatting Utilities\n */\n\nimport { getConfig } from '../core/config';\nimport { CATALOG_UNIT_PRICE_FORMAT_OPTIONS } from '@shoppex/contracts/catalog-unit-price';\n\nexport function createFormatter(\n currency?: string,\n locale?: string\n): Intl.NumberFormat {\n const config = getConfig();\n\n return new Intl.NumberFormat(locale ?? config.locale ?? 'en-US', {\n style: 'currency',\n currency: currency ?? config.currency ?? 'USD',\n ...CATALOG_UNIT_PRICE_FORMAT_OPTIONS,\n });\n}\n\nexport function formatPrice(\n amount: number | string,\n currency?: string,\n locale?: string\n): string {\n const numericAmount = typeof amount === 'string' ? parseFloat(amount) : amount;\n if (Number.isNaN(numericAmount)) {\n return createFormatter(currency, locale).format(0);\n }\n return createFormatter(currency, locale).format(numericAmount);\n}\n","import type { ThemeConfig, ResolvedThemeSettings } from '../types/theme-config';\nimport { get } from '../core/client';\nimport { buildEndpoint } from '../core/endpoint';\n\ntype JsonRecord = Record<string, unknown>;\n\nexport interface PublishedBuilderSettings {\n version: number;\n revision: number;\n theme: {\n content: JsonRecord;\n layout: JsonRecord;\n style_slots: JsonRecord;\n pages?: unknown[];\n terms?: JsonRecord;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\nexport interface PublishedThemeSettingsPayload {\n settings: ResolvedThemeSettings;\n builder_settings: PublishedBuilderSettings | null;\n content: JsonRecord;\n style_slots: JsonRecord;\n}\n\nfunction isRecord(value: unknown): value is JsonRecord {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction normalizePublishedBuilderSettings(value: unknown): PublishedBuilderSettings | null {\n if (!isRecord(value) || !isRecord(value.theme)) {\n return null;\n }\n\n return {\n ...value,\n version: typeof value.version === 'number' ? value.version : 0,\n revision: typeof value.revision === 'number' ? value.revision : 0,\n theme: {\n ...value.theme,\n content: isRecord(value.theme.content) ? value.theme.content : {},\n layout: isRecord(value.theme.layout) ? value.theme.layout : {},\n style_slots: isRecord(value.theme.style_slots) ? value.theme.style_slots : {},\n ...(Array.isArray(value.theme.pages) ? { pages: value.theme.pages } : {}),\n ...(isRecord(value.theme.terms) ? { terms: value.theme.terms } : {}),\n },\n };\n}\n\nfunction normalizePublishedThemeSettingsPayload(value: unknown): PublishedThemeSettingsPayload | null {\n if (!isRecord(value)) {\n return null;\n }\n\n return {\n settings: isRecord(value.settings) ? value.settings as ResolvedThemeSettings : {},\n builder_settings: normalizePublishedBuilderSettings(value.builder_settings),\n content: isRecord(value.content) ? value.content : {},\n style_slots: isRecord(value.style_slots) ? value.style_slots : {},\n };\n}\n\nexport async function fetchPublishedBuilderSettings(\n shopSlug: string\n): Promise<PublishedThemeSettingsPayload | null> {\n const result = await get<PublishedThemeSettingsPayload>(\n buildEndpoint('/v1/storefront/themes/builder/published/:shopSlug', { shopSlug })\n );\n\n return result.success && result.data ? normalizePublishedThemeSettingsPayload(result.data) : null;\n}\n\nexport async function fetchPublishedThemeSettings(\n shopSlug: string\n): Promise<ResolvedThemeSettings | null> {\n const payload = await fetchPublishedBuilderSettings(shopSlug);\n return payload ? payload.settings : null;\n}\n\nexport function resolveDefaults(config: ThemeConfig): ResolvedThemeSettings {\n const resolved: ResolvedThemeSettings = {};\n for (const [category, fields] of Object.entries(config.settings)) {\n resolved[category] = {};\n for (const [key, field] of Object.entries(fields)) {\n resolved[category][key] = field.default;\n }\n }\n return resolved;\n}\n\nexport function mergeSettings(\n defaults: ResolvedThemeSettings,\n overrides: Partial<ResolvedThemeSettings>\n): ResolvedThemeSettings {\n const merged = { ...defaults };\n for (const [category, fields] of Object.entries(overrides)) {\n if (fields) {\n merged[category] = { ...merged[category], ...fields };\n }\n }\n return merged;\n}\n","/**\n * The storefront SDK without the signed-in customer account calls.\n *\n * The ThemeDocument commerce runtime (packages/storefront-commerce) loads on\n * every page of every Easy-lane storefront and uses this object, not the full\n * `shoppex` one: the account calls validate their responses with the zod\n * schemas of `@shoppex/contracts/customer-account-wire` (~100 KB minified),\n * and the Easy lane's account page runs its own script. `shoppex` (index.ts)\n * is this object plus the account calls. The storage half\n * (storefront-storage-sdk.ts) is its own object, so the commerce runtime's\n * core can carry it without the network modules below.\n */\n\nimport { storefrontStorageSdk } from './storefront-storage-sdk';\nimport { getTypedClient } from './core/typed-client';\n// Store module\nimport {\n getStore,\n getStorefront,\n getStoreLogoUrl,\n getStoreBannerUrl,\n resolveStoreByDomain,\n} from './modules/store';\n// Products module\nimport { getProducts, getProduct, getCategories, getStorefrontProductsPage } from './modules/products';\n// Checkout module\nimport { checkout, buildCheckoutUrl, buildCheckoutUrlSync, getRequestedCheckoutCurrency } from './modules/checkout';\n// Affiliate module (network calls; storage and capture are in storefrontStorageSdk)\nimport { applyAffiliateCode, validateAffiliateCode } from './modules/affiliates';\n// Coupons module\nimport { validateCoupon } from './modules/coupons';\n// Reviews module\nimport { getShopReviews, getShopReviewsPage } from './modules/reviews';\n// Search module\nimport { searchProducts, searchCatalogItems } from './modules/search';\n// Invoices module\nimport { getInvoice, getInvoiceStatus } from './modules/invoices';\n// Pages module\nimport { getPages, getPage } from './modules/pages';\n// Navigation module\nimport { getMenus, getMenu, getMenuBySlot, getMenuByTitle, getMenuSlotTitles } from './modules/navigation';\n// Presence module\nimport { getStorefrontOnlineUsers, getStorefrontRecentSales, touchStorefrontPresence } from './modules/presence';\n// Format utilities\nimport { createFormatter, formatPrice } from './utils/format';\nimport { clearCache, invalidateCache, getCacheStats } from './core/cache';\nimport { fetchPublishedBuilderSettings, fetchPublishedThemeSettings, resolveDefaults, mergeSettings } from './modules/theme';\n\nexport const storefrontSdk = {\n // Initialization, cart, quote, coupon and referral storage, analytics\n ...storefrontStorageSdk,\n\n // Typed OpenAPI client — drop to this when you need an endpoint the\n // high-level modules below do not cover yet.\n client: getTypedClient,\n\n // Store\n getStore,\n getStorefront,\n getStoreLogoUrl,\n getStoreBannerUrl,\n resolveStoreByDomain,\n\n // Products\n getProducts,\n getStorefrontProductsPage,\n getProduct,\n getCategories,\n\n // Checkout\n checkout,\n buildCheckoutUrl,\n buildCheckoutUrlSync,\n getRequestedCheckoutCurrency,\n\n // Affiliates\n validateAffiliateCode,\n applyAffiliateCode,\n\n // Coupons\n validateCoupon,\n\n // Reviews\n getShopReviews,\n getShopReviewsPage,\n\n // Search\n searchProducts,\n searchCatalogItems,\n\n // Invoices\n getInvoice,\n getInvoiceStatus,\n\n // Pages\n getPages,\n getPage,\n\n // Navigation\n getMenus,\n getMenu,\n getMenuBySlot,\n getMenuByTitle,\n getMenuSlotTitles,\n\n // Presence\n getStorefrontOnlineUsers,\n getStorefrontRecentSales,\n touchStorefrontPresence,\n\n // Formatting\n createFormatter,\n formatPrice,\n\n // Cache\n clearCache,\n invalidateCache,\n getCacheStats,\n\n // Theme settings helpers\n fetchPublishedBuilderSettings,\n fetchPublishedThemeSettings,\n resolveDefaults,\n mergeSettings,\n};\n\nexport type StorefrontSdk = typeof storefrontSdk;\n\nexport default storefrontSdk;\n","/**\n * Select (dropdown) product custom fields: the buyer picks exactly one of the\n * merchant's option labels.\n *\n * A definition carries `options` only when its `type` is `select`; every other\n * type keeps its wire unchanged. The product write boundaries refuse a select\n * without 2–20 unique, trimmed labels of 1–100 characters, refuse `options` on\n * any other type, and refuse a default on a select (the buyer always makes the\n * choice). An order stores the picked label as text, so renaming or removing\n * an option later changes only new orders.\n */\nexport const SELECT_CUSTOM_FIELD_MIN_OPTIONS = 2;\nexport const SELECT_CUSTOM_FIELD_MAX_OPTIONS = 20;\nexport const SELECT_CUSTOM_FIELD_OPTION_MAX_LENGTH = 100;\n\n/**\n * The option labels of a stored select definition. The write boundary\n * guarantees an array of trimmed strings; readers keep only strings so a\n * malformed row cannot put a non-string into a buyer control.\n */\nexport function readSelectCustomFieldOptions(raw: unknown): string[] {\n return Array.isArray(raw) ? raw.filter((option): option is string => typeof option === 'string') : [];\n}\n","import { readSelectCustomFieldOptions } from '@shoppex/contracts/product-custom-fields';\n\nexport interface StorefrontCustomField {\n name: string;\n type: string;\n required: boolean;\n defaultValue: string;\n placeholder: string;\n regex?: string;\n /** Only on a `select`: the labels the buyer picks one of. */\n options?: string[];\n}\n\nfunction parseCustomFieldsSource(raw: unknown): unknown[] {\n if (Array.isArray(raw)) return raw;\n\n if (typeof raw === 'string') {\n try {\n const parsed = JSON.parse(raw) as unknown;\n if (Array.isArray(parsed)) return parsed;\n if (parsed && typeof parsed === 'object') {\n const fields = (parsed as { custom_fields?: unknown[]; customFields?: unknown[] }).custom_fields\n ?? (parsed as { custom_fields?: unknown[]; customFields?: unknown[] }).customFields;\n return Array.isArray(fields) ? fields : [];\n }\n } catch {\n return [];\n }\n\n return [];\n }\n\n if (raw && typeof raw === 'object') {\n const fields = (raw as { custom_fields?: unknown[]; customFields?: unknown[] }).custom_fields\n ?? (raw as { custom_fields?: unknown[]; customFields?: unknown[] }).customFields;\n return Array.isArray(fields) ? fields : [];\n }\n\n return [];\n}\n\n// The dashboard has stored boolean flags as a boolean, a number and a string over time.\nfunction isFlagSet(value: unknown): boolean {\n return value === true || value === 'true' || value === 1 || value === '1';\n}\n\nexport function normalizeStorefrontCustomFields(raw: unknown): StorefrontCustomField[] {\n return parseCustomFieldsSource(raw)\n .filter((field): field is Record<string, unknown> => !!field && typeof field === 'object' && !Array.isArray(field))\n // A post-payment field is asked on the invoice after payment; the server drops\n // a value the cart sends for it, so checkout must not ask for it first.\n .filter((field) => ![field.collect_after_payment, field.collectAfterPayment].some(isFlagSet))\n .map((field) => {\n const rawType = typeof field.type === 'string' ? field.type.trim().toLowerCase() : 'text';\n const type = rawType.length > 0 ? rawType : 'text';\n const defaultValue = [\n field.default_value,\n field.default,\n field.value,\n ].find((candidate) => typeof candidate === 'string' && candidate.trim().length > 0);\n\n return {\n name: typeof field.name === 'string' ? field.name.trim() : '',\n type,\n required: isFlagSet(field.required),\n defaultValue: typeof defaultValue === 'string' ? defaultValue : '',\n placeholder: typeof field.placeholder === 'string' ? field.placeholder : '',\n regex: typeof field.regex === 'string' ? field.regex : undefined,\n ...(type === 'select' ? { options: readSelectCustomFieldOptions(field.options) } : {}),\n };\n })\n .filter((field) => field.name.length > 0 && field.type !== 'hidden');\n}\n\nexport function isStorefrontCheckboxCustomFieldValueChecked(value: string | undefined): boolean {\n const normalized = value?.trim().toLowerCase() ?? '';\n return normalized === 'true' || normalized === '1' || normalized === 'yes' || normalized === 'on';\n}\n\nexport function validateStorefrontCustomFieldValue(field: StorefrontCustomField, value: string): string | null {\n if (field.type === 'checkbox') {\n if (field.required && !isStorefrontCheckboxCustomFieldValueChecked(value)) {\n return `${field.name} is required.`;\n }\n return null;\n }\n\n const normalized = value.trim();\n if (field.required && !normalized) {\n return `${field.name} is required.`;\n }\n\n // The server refuses any other answer with `custom_field_option_invalid`.\n if (field.type === 'select') {\n return normalized && !(field.options ?? []).includes(normalized)\n ? `${field.name} must be one of the listed options.`\n : null;\n }\n\n if (field.regex && normalized) {\n try {\n const pattern = new RegExp(field.regex);\n if (!pattern.test(normalized)) {\n return `${field.name} has an invalid format.`;\n }\n } catch {\n return null;\n }\n }\n\n return null;\n}\n\nexport function buildStorefrontCustomFieldPayload(\n fields: StorefrontCustomField[],\n values: Record<string, string>,\n): Record<string, string> {\n const nextValues: Record<string, string> = {};\n\n fields.forEach((field) => {\n const rawValue = values[field.name] ?? field.defaultValue ?? '';\n\n if (field.type === 'checkbox') {\n if (isStorefrontCheckboxCustomFieldValueChecked(rawValue)) {\n nextValues[field.name] = 'true';\n }\n return;\n }\n\n const normalized = rawValue.trim();\n if (normalized.length > 0) {\n nextValues[field.name] = normalized;\n }\n });\n\n return nextValues;\n}\n","import { DEFAULT_API_BASE_URL } from '../core/config';\n\nexport type StorefrontContactTicketInput = {\n shopSlug: string;\n email: string;\n message: string;\n title?: string;\n name?: string;\n invoiceId?: string;\n apiBaseUrl?: string;\n};\n\nexport type StorefrontContactTicketResult = {\n uniqid: string;\n};\n\nfunction isLocalDevHost(host: string): boolean {\n if (host === 'localhost' || host === '127.0.0.1' || host === '::1' || host.endsWith('.localhost')) {\n return true;\n }\n if (/^10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/.test(host)) {\n return true;\n }\n if (/^192\\.168\\.\\d{1,3}\\.\\d{1,3}$/.test(host)) {\n return true;\n }\n const private172 = host.match(/^172\\.(\\d{1,2})\\.\\d{1,3}\\.\\d{1,3}$/);\n if (private172) {\n const octet = Number(private172[1]);\n return octet >= 16 && octet <= 31;\n }\n return false;\n}\n\nexport function resolveStorefrontApiBaseUrl(options?: {\n apiBaseUrl?: string;\n hostname?: string;\n}): string {\n if (options?.apiBaseUrl?.trim()) {\n return options.apiBaseUrl.replace(/\\/+$/, '');\n }\n\n const hostname = options?.hostname\n ?? (typeof window !== 'undefined' ? window.location.hostname : '');\n\n if (hostname && !isLocalDevHost(hostname)) {\n return DEFAULT_API_BASE_URL;\n }\n\n // Edge/njk commerce is a classic IIFE (not an ES module) — import.meta is a syntax error there.\n // Storefront bootstrap sets window.apiBaseUrl; Vite/React callers may pass options.apiBaseUrl.\n if (typeof window !== 'undefined') {\n const bootstrapBase = (window as { apiBaseUrl?: unknown }).apiBaseUrl;\n if (typeof bootstrapBase === 'string' && bootstrapBase.trim()) {\n return bootstrapBase.replace(/\\/+$/, '');\n }\n }\n\n return 'http://localhost:3001'.replace(/\\/+$/, '');\n}\n\nexport function buildStorefrontContactMessage(input: {\n name?: string;\n message: string;\n maxLength?: number;\n}): string {\n const customerName = input.name?.trim() ?? '';\n const baseMessage = input.message.trim();\n const fullMessage = `${customerName ? `Name: ${customerName}\\n\\n` : ''}${baseMessage}`;\n const maxLength = input.maxLength ?? 2000;\n return fullMessage.slice(0, maxLength);\n}\n\nexport async function submitStorefrontContactTicket(\n input: StorefrontContactTicketInput,\n): Promise<StorefrontContactTicketResult> {\n const shopSlug = input.shopSlug.trim();\n if (!shopSlug) {\n throw new Error('Store data is not ready yet. Please try again in a moment.');\n }\n\n const normalizedEmail = input.email.trim().toLowerCase();\n const subject = input.title?.trim() ?? '';\n const title = subject.length >= 2 ? subject.slice(0, 30) : 'Contact Request';\n const message = buildStorefrontContactMessage({\n name: input.name,\n message: input.message,\n });\n const invoiceId = input.invoiceId?.trim() || undefined;\n const apiBaseUrl = resolveStorefrontApiBaseUrl({ apiBaseUrl: input.apiBaseUrl });\n\n const response = await fetch(\n `${apiBaseUrl}/v1/storefront/shops/name/${encodeURIComponent(shopSlug)}/tickets`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify({\n email: normalizedEmail,\n title,\n message,\n ...(invoiceId ? { invoice_id: invoiceId } : {}),\n }),\n },\n );\n\n const payload = await response.json().catch(() => null) as {\n message?: string;\n error?: string;\n data?: { uniqid?: string };\n } | null;\n\n if (!response.ok) {\n throw new Error(payload?.message || payload?.error || 'Failed to send your message.');\n }\n\n const uniqid = payload?.data?.uniqid;\n if (!uniqid) {\n throw new Error('Ticket created, but the response was incomplete.');\n }\n\n return { uniqid };\n}\n\nexport type StorefrontSocialLinks = {\n discord?: string | null;\n telegram?: string | null;\n};\n\nexport function resolveStorefrontSocialLinks(store: {\n discord_link?: string | null;\n telegram_link?: string | null;\n social?: Record<string, string | null | undefined> | null;\n} | null | undefined): StorefrontSocialLinks {\n return {\n discord: store?.discord_link ?? store?.social?.discord ?? null,\n telegram: store?.telegram_link ?? store?.social?.telegram ?? null,\n };\n}\n","/**\n * Customer Module\n *\n * Authenticated customer account calls for code-lane storefronts. The edge\n * worker owns the HttpOnly session cookie and derives the shop from the host.\n * This module therefore sends neither a session token nor shop identity.\n */\n\nimport {\n customerLoyaltyRedeemSchema,\n customerLoyaltySchema,\n customerPortalAffiliateCreateLinkSchema,\n customerPortalDashboardSchema,\n customerPortalInvoiceDetailSchema,\n customerPortalNotificationPreferencesSchema,\n customerPortalOrderReviewSchema,\n customerPortalPaginatedInvoicesSchema,\n customerWarrantyClaimSchema,\n customerWarrantyListSchema,\n type CustomerLoyaltyRedeemWire,\n type CustomerLoyaltyWire,\n type CustomerPortalAffiliateCreateLinkWire,\n type CustomerPortalDashboardWire,\n type CustomerPortalInvoiceDetailWire,\n type CustomerPortalNotificationPreferencesWire,\n type CustomerPortalOrderReviewWire,\n type CustomerPortalPaginatedInvoicesWire,\n type CustomerWarrantyClaimWire,\n type CustomerWarrantyListWire,\n} from '@shoppex/contracts/customer-account-wire';\nimport type { SDKResponse } from '../types';\n\nconst CUSTOMER_API_PREFIX = '/api/customer';\n\ntype CustomerMethod = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';\n\n/**\n * A producer-owned schema for the response payload.\n *\n * Only the endpoints whose shape is defined in `@shoppex/contracts` get one.\n * The rest stay `unknown` on purpose: inventing a type here would assert a wire\n * shape the producer never promised, which is the pattern the retired portal's\n * 544-line hand-written type file demonstrates the cost of.\n */\ninterface CustomerPayloadSchema<T> {\n safeParse(value: unknown): { success: true; data: T } | { success: false };\n}\n\ninterface CustomerRequestOptions<T> {\n method?: CustomerMethod;\n body?: unknown;\n /** Multipart payload. Mutually exclusive with `body`; the browser sets the boundary. */\n formData?: FormData;\n schema?: CustomerPayloadSchema<T>;\n}\n\nexport interface CustomerOrdersQuery {\n page?: number;\n limit?: number;\n /**\n * Invoice status filter, verbatim from the producer's enum. Anything else is\n * answered with a 400 rather than quietly ignored, so pass what the buyer\n * actually chose.\n */\n status?: string;\n /** Partial invoice-id search. The producer trims it to 64 characters. */\n search?: string;\n}\n\ninterface CustomerApiEnvelope {\n status: number;\n data: unknown;\n error?: unknown;\n message?: unknown;\n error_code?: unknown;\n error_params?: unknown;\n}\n\nexport interface CustomerTicketPayload {\n title?: string;\n message: string;\n invoice_id?: string;\n /** Images staged with `uploadTicketImage`, sent with this message. */\n attachment_ids?: string[];\n}\n\nexport interface CustomerProfilePatch {\n name: string;\n}\n\nexport interface CustomerSubscriptionCancelOptions {\n cancel_at_period_end?: boolean;\n reason?: string | null;\n}\n\nexport interface CustomerEmailPreferencesPatch {\n global_unsubscribed?: boolean;\n list_subscriptions?: Array<{ list_id: string; subscribed: boolean }>;\n}\n\n/** Which order mails the buyer receives. A key left out is left as it is. */\nexport interface CustomerNotificationPreferencesPatch {\n order_created_emails?: boolean;\n order_completed_emails?: boolean;\n payment_issue_emails?: boolean;\n}\n\nexport interface CustomerAffiliateLinkInput {\n code: string;\n label: string;\n /** Asking for a rate of one's own sends the link to the shop for approval. */\n requested_affiliate_revenue_percent?: number;\n requested_affiliate_customer_discount_percent?: number;\n}\n\nexport interface CustomerInvoicePdf {\n blob: Blob;\n /** From the producer's `Content-Disposition`; null when it named none. */\n filename: string | null;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction narrowEnvelope(value: unknown): CustomerApiEnvelope | null {\n if (!isRecord(value) || typeof value.status !== 'number' || !('data' in value)) {\n return null;\n }\n\n return value as unknown as CustomerApiEnvelope;\n}\n\nfunction readMessage(envelope: CustomerApiEnvelope, response: Response): string {\n if (typeof envelope.error === 'string' && envelope.error.length > 0) {\n return envelope.error;\n }\n\n if (typeof envelope.message === 'string' && envelope.message.length > 0) {\n return envelope.message;\n }\n\n return response.statusText\n ? `HTTP ${response.status}: ${response.statusText}`\n : `HTTP ${response.status}`;\n}\n\nfunction readErrorFields(envelope: CustomerApiEnvelope): Pick<SDKResponse<unknown>, 'code' | 'errorParams'> {\n const code = typeof envelope.error_code === 'string' && envelope.error_code.length > 0\n ? envelope.error_code\n : null;\n\n if (!code) {\n return {};\n }\n\n return {\n code,\n ...(isRecord(envelope.error_params) ? { errorParams: envelope.error_params } : {}),\n };\n}\n\nasync function requestCustomer<T = unknown>(\n path: string,\n options: CustomerRequestOptions<T> = {},\n): Promise<SDKResponse<T>> {\n const method = options.method ?? 'GET';\n const headers: Record<string, string> = {\n Accept: 'application/json',\n };\n\n if (options.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n }\n\n // FormData carries its own multipart boundary in the Content-Type the browser\n // generates; setting the header here would produce a body the server cannot parse.\n const payload = options.formData ?? (options.body !== undefined ? JSON.stringify(options.body) : undefined);\n\n try {\n const response = await fetch(`${CUSTOMER_API_PREFIX}${path}`, {\n method,\n headers,\n body: payload,\n credentials: 'same-origin',\n cache: 'no-store',\n });\n\n if (response.status === 204) {\n return response.ok\n ? { success: true, status: response.status }\n : {\n success: false,\n status: response.status,\n message: readMessage({ status: response.status, data: null }, response),\n };\n }\n\n let rawEnvelope: unknown;\n try {\n rawEnvelope = await response.json();\n } catch {\n return { success: false, status: response.status, message: 'Invalid customer API response' };\n }\n\n const envelope = narrowEnvelope(rawEnvelope);\n if (!envelope) {\n return { success: false, status: response.status, message: 'Invalid customer API response' };\n }\n\n // A money mutation the producer completed but whose answer it withheld\n // keeps the handler's 2xx. Left to the checks below it reads as an empty\n // success, or as a contract mismatch the buyer is told to try again; with\n // the code, the caller re-reads the account instead of sending it twice.\n if (\n !response.ok || envelope.status < 200 || envelope.status >= 300\n || envelope.error_code === 'RESPONSE_CONTRACT_VIOLATION'\n ) {\n return {\n success: false,\n // The transport status, not the envelope's: a caller deciding whether\n // the buyer is signed out must not be steered by a body the edge may\n // never have produced.\n status: response.status,\n message: readMessage(envelope, response),\n ...readErrorFields(envelope),\n };\n }\n\n const message = typeof envelope.message === 'string' && envelope.message.length > 0\n ? { message: envelope.message }\n : {};\n\n if (!options.schema) {\n return { success: true, data: envelope.data as T, ...message };\n }\n\n const parsed = options.schema.safeParse(envelope.data);\n if (!parsed.success) {\n // Fail loudly instead of handing back a payload that does not match what\n // the producer promised. A silently reshaped or partially-read response\n // is how a contract drift reaches the buyer's screen as wrong data.\n return { success: false, message: 'Customer API response did not match the expected contract' };\n }\n\n return { success: true, data: parsed.data, ...message };\n } catch (error) {\n return {\n success: false,\n message: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n/** One basket line for a QUOTE. `variant_id` is omitted, never null, when a product has no variants. */\nexport interface ResellerOrderItem {\n product_id: string;\n variant_id?: string;\n quantity: number;\n}\n\nexport interface ResellerCatalogQuery {\n search?: string;\n page?: number;\n per_page?: number;\n}\n\nexport interface ResellerOrdersQuery {\n page?: number;\n per_page?: number;\n}\n\nexport function requestOtp(email: string): Promise<SDKResponse<unknown>> {\n return requestCustomer('/auth/otp/request', {\n method: 'POST',\n body: { email },\n });\n}\n\n/**\n * The wire field is `otp`, not `code` — `CustomerOtpVerifyBodySchema` in\n * `apps/backend-elysia/src/routes/v1/customer/schemas.ts` requires it under that\n * name, and a `code` body is rejected with 400.\n */\nexport function verifyOtp(email: string, otp: string): Promise<SDKResponse<unknown>> {\n return requestCustomer('/auth/otp/verify', {\n method: 'POST',\n body: { email, otp },\n });\n}\n\nexport function logout(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/auth/logout', { method: 'POST' });\n}\n\nexport function me(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/me');\n}\n\nexport function dashboard(): Promise<SDKResponse<CustomerPortalDashboardWire>> {\n return requestCustomer('/dashboard', { schema: customerPortalDashboardSchema });\n}\n\n/**\n * Paginated order history.\n *\n * Page-based, matching the producer: `invoices.routes.ts` reads `page` and\n * `limit` and answers with a `has_more` envelope. A cursor parameter would be\n * ignored upstream and silently return page one forever.\n *\n * `status` and `search` are filtered SERVER-side, which is why they belong\n * here rather than in the caller: `/invoices` is paged, and a filter applied\n * to the page in hand would filter only the rows that page happens to hold.\n * The producer spells the search `q`.\n */\nexport function orders(options: CustomerOrdersQuery = {}): Promise<SDKResponse<CustomerPortalPaginatedInvoicesWire>> {\n const query = new URLSearchParams();\n if (options.page !== undefined) query.set('page', String(options.page));\n if (options.limit !== undefined) query.set('limit', String(options.limit));\n if (options.status) query.set('status', options.status);\n if (options.search) query.set('q', options.search);\n\n const suffix = query.size > 0 ? `?${query.toString()}` : '';\n return requestCustomer(`/invoices${suffix}`, { schema: customerPortalPaginatedInvoicesSchema });\n}\n\nexport function order(id: string): Promise<SDKResponse<CustomerPortalInvoiceDetailWire>> {\n return requestCustomer(`/invoice/${encodeURIComponent(id)}`, {\n schema: customerPortalInvoiceDetailSchema,\n });\n}\n\n/**\n * Whether the buyer may review this paid order, and the review they left.\n *\n * `can_review` is the producer's decision (paid, reviews on, not yet reviewed).\n * The review itself is written on the hosted page `review_url` names: this\n * script runs beside merchant theme code, which must not post as the buyer.\n */\nexport function orderReview(uniqid: string): Promise<SDKResponse<CustomerPortalOrderReviewWire>> {\n return requestCustomer(`/invoices/${encodeURIComponent(uniqid)}/review`, { schema: customerPortalOrderReviewSchema });\n}\n\n/**\n * The invoice as a PDF, for the buyer to save.\n *\n * A file, not the JSON envelope, so it does not go through `requestCustomer`.\n * Anything but a PDF on a 2xx is a contract failure rather than a download: a\n * proxy's HTML error page saved as `invoice.pdf` is a file that will not open.\n */\nexport async function invoicePdf(id: string): Promise<SDKResponse<CustomerInvoicePdf>> {\n try {\n const response = await fetch(`${CUSTOMER_API_PREFIX}/invoices/${encodeURIComponent(id)}/pdf`, {\n method: 'GET',\n headers: { Accept: 'application/pdf' },\n credentials: 'same-origin',\n cache: 'no-store',\n });\n\n if (!response.ok) {\n let envelope: CustomerApiEnvelope | null = null;\n try {\n envelope = narrowEnvelope(await response.json());\n } catch {\n envelope = null;\n }\n return {\n success: false,\n status: response.status,\n message: readMessage(envelope ?? { status: response.status, data: null }, response),\n };\n }\n\n if (!(response.headers.get('content-type') ?? '').toLowerCase().startsWith('application/pdf')) {\n return { success: false, message: 'Customer API response did not match the expected contract' };\n }\n\n return {\n success: true,\n data: {\n blob: await response.blob(),\n filename: response.headers.get('content-disposition')?.match(/filename=\"([^\"]+)\"/i)?.[1] ?? null,\n },\n };\n } catch (error) {\n return {\n success: false,\n message: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\nexport function loyalty(): Promise<SDKResponse<CustomerLoyaltyWire>> {\n return requestCustomer('/loyalty', { schema: customerLoyaltySchema });\n}\n\nexport function redeemLoyaltyPoints(input: {\n points: number;\n idempotencyKey: string;\n}): Promise<SDKResponse<CustomerLoyaltyRedeemWire>> {\n return requestCustomer('/loyalty/redeem', {\n method: 'POST',\n body: {\n points: input.points,\n idempotency_key: input.idempotencyKey,\n },\n schema: customerLoyaltyRedeemSchema,\n });\n}\n\n/**\n * The warranties this buyer holds — all of them, or the ones on one order.\n *\n * `invoiceUniqid` becomes the producer's own `invoice=` filter, which matches\n * `invoices.uniqid`: the id an order carries everywhere a storefront shows one.\n * So an order detail asks for its own cover rather than reading every warranty\n * the buyer owns and discarding most of them.\n */\nexport function warranties(invoiceUniqid?: string): Promise<SDKResponse<CustomerWarrantyListWire>> {\n const suffix = invoiceUniqid ? `?invoice=${encodeURIComponent(invoiceUniqid)}` : '';\n return requestCustomer(`/warranties${suffix}`, { schema: customerWarrantyListSchema });\n}\n\nexport function claimWarranty(\n uniqid: string,\n message?: string,\n): Promise<SDKResponse<CustomerWarrantyClaimWire>> {\n return requestCustomer(`/warranties/${encodeURIComponent(uniqid)}/claim`, {\n method: 'POST',\n body: message ? { message } : {},\n schema: customerWarrantyClaimSchema,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Licenses, subscriptions and tickets have NO collection route.\n//\n// Those three lists arrive inside `/dashboard` — `licenses.routes.ts`,\n// `subscriptions.routes.ts` and `tickets.routes.ts` expose per-item routes only.\n// A `GET /licenses` here would 404 on every call, which is what the earlier\n// spelling of this module did.\n// ---------------------------------------------------------------------------\n\nexport function resetLicenseHwid(uniqid: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/licenses/${encodeURIComponent(uniqid)}/reset-hwid`, {\n method: 'POST',\n body: {},\n });\n}\n\nexport function subscriptionBillingHistory(uniqid: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/subscriptions/${encodeURIComponent(uniqid)}/billing-history`);\n}\n\nexport function cancelSubscription(\n uniqid: string,\n options: CustomerSubscriptionCancelOptions = {},\n): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/subscriptions/${encodeURIComponent(uniqid)}/cancel`, {\n method: 'POST',\n body: {\n ...(options.cancel_at_period_end !== undefined\n ? { cancel_at_period_end: options.cancel_at_period_end }\n : {}),\n ...(options.reason !== undefined ? { reason: options.reason } : {}),\n },\n });\n}\n\nexport function pauseSubscription(uniqid: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/subscriptions/${encodeURIComponent(uniqid)}/pause`, {\n method: 'POST',\n body: {},\n });\n}\n\nexport function resumeSubscription(uniqid: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/subscriptions/${encodeURIComponent(uniqid)}/resume`, {\n method: 'POST',\n body: {},\n });\n}\n\nexport function undoSubscriptionCancel(uniqid: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/subscriptions/${encodeURIComponent(uniqid)}/undo-cancel`, {\n method: 'POST',\n body: {},\n });\n}\n\nexport function favorites(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/favorites');\n}\n\n/** Idempotent upstream, and a PUT — `customer-favorites.ts` has no POST route. */\nexport function addFavorite(productUniqid: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/favorites/${encodeURIComponent(productUniqid)}`, { method: 'PUT' });\n}\n\nexport function removeFavorite(productUniqid: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/favorites/${encodeURIComponent(productUniqid)}`, { method: 'DELETE' });\n}\n\nexport function affiliate(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/affiliate');\n}\n\nexport function affiliateStats(days?: number): Promise<SDKResponse<unknown>> {\n const suffix = days === undefined ? '' : `?days=${encodeURIComponent(String(days))}`;\n return requestCustomer(`/affiliate/stats${suffix}`);\n}\n\n/**\n * A referral link with a code of the buyer's choosing.\n *\n * `status` in the answer is `pending` when the shop approves links first, or\n * when the link asks for rates of its own. Nothing here pays out, converts or\n * shares a commission: those decide where earned money goes and are not\n * reachable from a storefront.\n */\nexport function createAffiliateLink(\n input: CustomerAffiliateLinkInput,\n): Promise<SDKResponse<CustomerPortalAffiliateCreateLinkWire>> {\n return requestCustomer('/affiliate/links', {\n method: 'POST',\n body: {\n code: input.code,\n label: input.label,\n ...(input.requested_affiliate_revenue_percent !== undefined\n ? { requested_affiliate_revenue_percent: input.requested_affiliate_revenue_percent }\n : {}),\n ...(input.requested_affiliate_customer_discount_percent !== undefined\n ? { requested_affiliate_customer_discount_percent: input.requested_affiliate_customer_discount_percent }\n : {}),\n },\n schema: customerPortalAffiliateCreateLinkSchema,\n });\n}\n\nexport function createTicket(payload: CustomerTicketPayload): Promise<SDKResponse<unknown>> {\n return requestCustomer('/tickets', {\n method: 'POST',\n body: {\n ...(payload.title !== undefined ? { title: payload.title } : {}),\n message: payload.message,\n ...(payload.invoice_id !== undefined ? { invoice_id: payload.invoice_id } : {}),\n ...(payload.attachment_ids?.length ? { attachment_ids: payload.attachment_ids } : {}),\n },\n });\n}\n\nexport function ticket(uniqid: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/tickets/${encodeURIComponent(uniqid)}`);\n}\n\nexport function replyToTicket(uniqid: string, message: string, attachmentIds: string[] = []): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/tickets/${encodeURIComponent(uniqid)}/reply`, {\n method: 'POST',\n body: attachmentIds.length > 0 ? { message, attachment_ids: attachmentIds } : { message },\n });\n}\n\n/**\n * Stage one image for a reply on ticket `ticket`, or for the ticket the buyer is\n * about to create when `ticket` is left out (`POST /v1/customer/ticket-attachments`).\n * JPG, PNG, WebP or GIF up to 5 MB, five per message; the producer answers its\n * own refusal (409/413/415). Send the returned `attachment.id` with the message.\n * The public contact form has no upload.\n */\nexport function uploadTicketImage(file: File, ticket?: string): Promise<SDKResponse<unknown>> {\n const form = new FormData();\n form.append('file', file);\n if (ticket) form.append('ticket', ticket);\n return requestCustomer('/ticket-attachments', { method: 'POST', formData: form });\n}\n\n/** Drop an image staged with `uploadTicketImage` that the buyer removed before sending. */\nexport function discardTicketImage(id: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/ticket-attachments/${encodeURIComponent(id)}`, { method: 'DELETE' });\n}\n\n/**\n * The producer is `POST /v1/customer/profile`, not PATCH.\n *\n * There is no `GET /profile` to pair with it — the buyer's own record comes from\n * `/me` and `/dashboard`.\n */\nexport function updateProfile(patch: CustomerProfilePatch): Promise<SDKResponse<unknown>> {\n return requestCustomer('/profile', {\n method: 'POST',\n body: { name: patch.name },\n });\n}\n\nexport function updateAvatar(file: File): Promise<SDKResponse<unknown>> {\n const form = new FormData();\n form.append('file', file);\n return requestCustomer('/profile/avatar', { method: 'POST', formData: form });\n}\n\nexport function removeAvatar(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/profile/avatar', { method: 'DELETE' });\n}\n\nexport function emailPreferences(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/email-marketing/preferences');\n}\n\nexport function updateEmailPreferences(\n patch: CustomerEmailPreferencesPatch,\n): Promise<SDKResponse<unknown>> {\n return requestCustomer('/email-marketing/preferences', {\n method: 'PATCH',\n body: {\n ...(patch.global_unsubscribed !== undefined\n ? { global_unsubscribed: patch.global_unsubscribed }\n : {}),\n ...(patch.list_subscriptions !== undefined\n ? { list_subscriptions: patch.list_subscriptions }\n : {}),\n },\n });\n}\n\n/**\n * Order mail, as opposed to the marketing lists above: order placed, order\n * completed, payment needs attention. Its own producer\n * (`routes/v1/customer-notifications.ts`), and it answers the saved set.\n */\nexport function notificationPreferences(): Promise<SDKResponse<CustomerPortalNotificationPreferencesWire>> {\n return requestCustomer('/notification-preferences', {\n schema: customerPortalNotificationPreferencesSchema,\n });\n}\n\nexport function updateNotificationPreferences(\n patch: CustomerNotificationPreferencesPatch,\n): Promise<SDKResponse<CustomerPortalNotificationPreferencesWire>> {\n return requestCustomer('/notification-preferences', {\n method: 'PATCH',\n body: {\n ...(patch.order_created_emails !== undefined\n ? { order_created_emails: patch.order_created_emails }\n : {}),\n ...(patch.order_completed_emails !== undefined\n ? { order_completed_emails: patch.order_completed_emails }\n : {}),\n ...(patch.payment_issue_emails !== undefined\n ? { payment_issue_emails: patch.payment_issue_emails }\n : {}),\n },\n schema: customerPortalNotificationPreferencesSchema,\n });\n}\n\nexport function sessions(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/sessions');\n}\n\nexport function revokeSession(id: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/sessions/${encodeURIComponent(id)}`, { method: 'DELETE' });\n}\n\n/**\n * Ends every session except this one.\n *\n * `others=true` is required, not decorative: `RevokeOtherSessionsQuerySchema`\n * declares it as a literal, so the route answers 400 without it. The selector\n * is explicit on purpose — \"revoke sessions\" with no qualifier is one typo away\n * from signing the buyer out of the device they are holding.\n */\nexport function revokeAllSessions(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/sessions?others=true', { method: 'DELETE' });\n}\n\n// ---------------------------------------------------------------------------\n// Wholesale (reseller program)\n//\n// A second program on the same account: its own way in, its own prepaid\n// balance, its own prices. Every route re-checks \"program enabled AND this\n// reseller is ACTIVE\" server-side, so nothing a storefront caches can widen\n// what a buyer may do here.\n//\n// Two writes are deliberately absent, and adding them back would be adding\n// methods that answer 404: the storefront worker refuses them. On a code\n// storefront the JavaScript on this origin is the MERCHANT's and it holds the\n// buyer's cookie, so the edge's same-origin check proves that script sent the\n// request, never that the buyer wanted it.\n// - placing a wholesale order debits the buyer's prepaid balance; a purchase\n// needs a boundary the merchant does not control\n// - minting an API key hands back a plaintext credential that keeps\n// authorizing orders after the session ends\n// Pricing a basket stays, because it writes nothing.\n// ---------------------------------------------------------------------------\n\n/** The program's state and this buyer's place in it. Null reseller means not enrolled. */\nexport function reseller(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/reseller');\n}\n\n/** `APPLICATION` mode. The note is optional unless the shop requires one. */\nexport function applyForReseller(note?: string): Promise<SDKResponse<unknown>> {\n return requestCustomer('/reseller/apply', {\n method: 'POST',\n body: note === undefined ? {} : { note },\n });\n}\n\n/** `OPEN` mode: no application, the buyer is a reseller when they say so. */\nexport function enrollAsReseller(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/reseller/enroll', { method: 'POST', body: {} });\n}\n\n/** `MANUAL` mode: the merchant invited this buyer and gave them a token. */\nexport function acceptResellerInvite(token: string): Promise<SDKResponse<unknown>> {\n return requestCustomer('/reseller/accept-invite', { method: 'POST', body: { token } });\n}\n\n/** The buyer's own tier prices. Page-based, like the order history. */\nexport function resellerCatalog(options: ResellerCatalogQuery = {}): Promise<SDKResponse<unknown>> {\n const query = new URLSearchParams();\n if (options.search !== undefined) query.set('search', options.search);\n if (options.page !== undefined) query.set('page', String(options.page));\n if (options.per_page !== undefined) query.set('per_page', String(options.per_page));\n\n const suffix = query.size > 0 ? `?${query.toString()}` : '';\n return requestCustomer(`/reseller/catalog${suffix}`);\n}\n\n/**\n * Prices a basket and writes nothing.\n *\n * The volume discount cannot be derived from the catalog — it only reports that\n * one exists — so a storefront that adds up unit prices itself shows a total\n * the shop will not charge. This is the number to display.\n */\nexport function quoteResellerOrder(items: ResellerOrderItem[]): Promise<SDKResponse<unknown>> {\n return requestCustomer('/reseller/orders/quote', { method: 'POST', body: { items } });\n}\n\nexport function resellerOrders(options: ResellerOrdersQuery = {}): Promise<SDKResponse<unknown>> {\n const query = new URLSearchParams();\n if (options.page !== undefined) query.set('page', String(options.page));\n if (options.per_page !== undefined) query.set('per_page', String(options.per_page));\n\n const suffix = query.size > 0 ? `?${query.toString()}` : '';\n return requestCustomer(`/reseller/orders${suffix}`);\n}\n\n/** One order with its lines, delivery state and delivered serials. */\nexport function resellerOrder(uniqid: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/reseller/orders/${encodeURIComponent(uniqid)}`);\n}\n\n/** The prepaid balance the wholesale orders are paid from. */\nexport function resellerWallet(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/reseller/wallet');\n}\n\nexport function resellerApiKeys(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/reseller/api-keys');\n}\n\n/*\n * There is no `revokeResellerApiKey`. Revoking is irreversible and stops\n * whatever the key was driving, and this SDK is the transport for code\n * storefronts — merchant-authored JavaScript running with the buyer's session,\n * where a confirmation proves nothing because the merchant renders it. The\n * edge omits the DELETE from `CUSTOMER_API_ALLOWLIST`\n * (`workers/storefront/src/customer-api.ts`), so exporting a method for it\n * would advertise a call that always answers 404.\n */\n","/**\n * Shoppex Storefront SDK\n *\n * Usage:\n * ```html\n * <script src=\"https://cdn.shoppex.io/sdk/v1.0/shoppex.umd.js\"></script>\n * <script>\n * shoppex.init('my-store');\n *\n * shoppex.getStore().then(store => console.log(store));\n * shoppex.addToCart('product-id', 'variant-id', 2);\n * shoppex.checkout();\n * </script>\n * ```\n */\n\nimport { storefrontSdk } from './storefront-sdk';\n\n// Re-export types\nexport * from './types';\nexport * from './core/errors';\nexport {\n buildStorefrontCustomFieldPayload,\n isStorefrontCheckboxCustomFieldValueChecked,\n normalizeStorefrontCustomFields,\n validateStorefrontCustomFieldValue,\n} from './utils/storefront-custom-fields';\nexport type { StorefrontCustomField } from './utils/storefront-custom-fields';\nexport {\n isProductInStock,\n isProductOutOfStock,\n isVariantOutOfStock,\n resolveDisplayStock,\n resolveVariantStockValue,\n} from './utils/storefront-stock';\nexport {\n buildStorefrontProductLookup,\n getMergedStorefrontProducts,\n getStorefrontGroupProducts,\n} from './utils/storefront-catalog';\nexport {\n stripHtmlFromText,\n normalizeSearchQuery,\n collectProductSearchHaystack,\n productMatchesSearchQuery,\n groupMatchesSearchQuery,\n filterProductsBySearchQuery,\n searchMergedStorefrontCatalog,\n searchMergedStorefrontCatalogItems,\n} from './utils/storefront-search';\nexport type { StorefrontSearchFilterOptions, StorefrontCatalogSearchItem } from './utils/storefront-search';\nexport {\n buildStorefrontContactMessage,\n resolveStorefrontApiBaseUrl,\n resolveStorefrontSocialLinks,\n submitStorefrontContactTicket,\n} from './utils/storefront-contact';\nexport type {\n StorefrontContactTicketInput,\n StorefrontContactTicketResult,\n StorefrontSocialLinks,\n} from './utils/storefront-contact';\nexport type {\n BlockDefinition,\n BlockInstance,\n PageLayout,\n ThemeConfig,\n ThemeBlockManifest,\n SettingField,\n SectionDefinition,\n ResolvedThemeSettings,\n} from './types/theme-config';\nexport type { PublishedBuilderSettings, PublishedThemeSettingsPayload } from './modules/theme';\nexport type { NavigationMenuSlot } from '@shoppex/contracts/navigation';\nexport {\n CATALOG_UNIT_PRICE_DECIMAL_PLACES,\n CATALOG_UNIT_PRICE_FORMAT_OPTIONS,\n PAYABLE_AMOUNT_DECIMAL_PLACES,\n roundPayableAmount,\n} from '@shoppex/contracts/catalog-unit-price';\n\n// resolveCartLineId is re-exported on the default shoppex object below (not only type-only).\nexport { computeCartLineId, ensureCartLineId } from './utils/cart-line-id';\nexport type { CartLineIdentityInput } from './utils/cart-line-id';\n\nexport type { CheckoutOptions, CheckoutResult } from './modules/checkout';\nexport { CheckoutCreateError } from './modules/checkout';\nexport type { SearchOptions } from './modules/search';\n\nexport { getShopReviewsPage, PRODUCT_FILTER_UNSUPPORTED } from './modules/reviews';\n\n// Customer module\nimport {\n requestOtp,\n verifyOtp,\n logout,\n me,\n dashboard,\n orders,\n order,\n invoicePdf,\n loyalty,\n redeemLoyaltyPoints,\n warranties,\n claimWarranty,\n orderReview,\n resetLicenseHwid,\n subscriptionBillingHistory,\n cancelSubscription,\n pauseSubscription,\n resumeSubscription,\n undoSubscriptionCancel,\n favorites,\n addFavorite,\n removeFavorite,\n affiliate,\n affiliateStats,\n createAffiliateLink,\n createTicket,\n ticket,\n replyToTicket,\n uploadTicketImage,\n discardTicketImage,\n updateProfile,\n updateAvatar,\n removeAvatar,\n emailPreferences,\n updateEmailPreferences,\n notificationPreferences,\n updateNotificationPreferences,\n sessions,\n revokeSession,\n revokeAllSessions,\n reseller,\n applyForReseller,\n enrollAsReseller,\n acceptResellerInvite,\n resellerCatalog,\n quoteResellerOrder,\n resellerOrders,\n resellerOrder,\n resellerWallet,\n resellerApiKeys,\n} from './modules/customer';\nexport {\n requestOtp,\n verifyOtp,\n logout,\n me,\n dashboard,\n orders,\n order,\n invoicePdf,\n loyalty,\n redeemLoyaltyPoints,\n warranties,\n claimWarranty,\n orderReview,\n resetLicenseHwid,\n subscriptionBillingHistory,\n cancelSubscription,\n pauseSubscription,\n resumeSubscription,\n undoSubscriptionCancel,\n favorites,\n addFavorite,\n removeFavorite,\n affiliate,\n affiliateStats,\n createAffiliateLink,\n createTicket,\n ticket,\n replyToTicket,\n uploadTicketImage,\n discardTicketImage,\n updateProfile,\n updateAvatar,\n removeAvatar,\n emailPreferences,\n updateEmailPreferences,\n notificationPreferences,\n updateNotificationPreferences,\n sessions,\n revokeSession,\n revokeAllSessions,\n reseller,\n applyForReseller,\n enrollAsReseller,\n acceptResellerInvite,\n resellerCatalog,\n quoteResellerOrder,\n resellerOrders,\n resellerOrder,\n resellerWallet,\n resellerApiKeys,\n} from './modules/customer';\nexport type {\n CustomerTicketPayload,\n CustomerProfilePatch,\n CustomerSubscriptionCancelOptions,\n CustomerEmailPreferencesPatch,\n CustomerNotificationPreferencesPatch,\n CustomerAffiliateLinkInput,\n CustomerInvoicePdf,\n ResellerOrderItem,\n ResellerCatalogQuery,\n ResellerOrdersQuery,\n} from './modules/customer';\n\nexport { fetchPublishedBuilderSettings, fetchPublishedThemeSettings, resolveDefaults, mergeSettings } from './modules/theme';\nexport { trackCartActivity, trackPageView, trackProductView } from './modules/analytics';\nexport { getStorefrontOnlineUsers, getStorefrontRecentSales, touchStorefrontPresence } from './modules/presence';\nexport { getMenus, getMenu, getMenuBySlot, getMenuByTitle, getMenuSlotTitles } from './modules/navigation';\n\n/**\n * Shoppex SDK instance\n */\nexport const shoppex = {\n ...storefrontSdk,\n\n // Customer account\n requestOtp,\n verifyOtp,\n logout,\n me,\n dashboard,\n orders,\n order,\n invoicePdf,\n loyalty,\n redeemLoyaltyPoints,\n warranties,\n claimWarranty,\n orderReview,\n resetLicenseHwid,\n subscriptionBillingHistory,\n cancelSubscription,\n pauseSubscription,\n resumeSubscription,\n undoSubscriptionCancel,\n favorites,\n addFavorite,\n removeFavorite,\n affiliate,\n affiliateStats,\n createAffiliateLink,\n createTicket,\n ticket,\n replyToTicket,\n uploadTicketImage,\n discardTicketImage,\n updateProfile,\n updateAvatar,\n removeAvatar,\n emailPreferences,\n updateEmailPreferences,\n notificationPreferences,\n updateNotificationPreferences,\n sessions,\n revokeSession,\n revokeAllSessions,\n reseller,\n applyForReseller,\n enrollAsReseller,\n acceptResellerInvite,\n resellerCatalog,\n quoteResellerOrder,\n resellerOrders,\n resellerOrder,\n resellerWallet,\n resellerApiKeys,\n};\n\n// Default export for ES modules\nexport default shoppex;\n\n// UMD global exposure — never clobber an already-initialized client. Theme\n// artifacts can load multiple SDK chunks; a late bundle must not reset init.\nif (typeof window !== 'undefined') {\n const w = window as unknown as { shoppex?: typeof shoppex };\n if (!w.shoppex?.isInitialized?.()) {\n w.shoppex = shoppex;\n }\n}\n"],"mappings":"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","names":["cache","order","request","engagedMs","hashString","fetch","init","request","error","final","joiner","normalizeAffiliateCode","cachedShopId","isRecord","ticket"]}
|
|
1
|
+
{"version":3,"sources":["../../sdk/src/core/errors.ts","../../sdk/src/utils/requested-currency.ts","../../sdk/src/core/config.ts","../../sdk/src/utils/storage.ts","../../sdk/src/core/cache.ts","../../sdk/src/core/endpoint.ts","../../sdk/src/core/telemetry.ts","../../sdk/src/core/client.ts","../../sdk/src/modules/affiliates.ts","../../contracts/src/storefront-consent-choice.ts","../../sdk/src/core/analytics-session.ts","../../sdk/src/core/attribution.ts","../../sdk/src/core/page-path.ts","../../sdk/src/core/page-tracker.ts","../../sdk/src/modules/analytics.ts","../../sdk/src/utils/cart-line-id.ts","../../contracts/src/catalog-unit-price.ts","../../sdk/src/modules/cart.ts","../../sdk/src/storefront-storage-sdk.ts","../../../node_modules/.bun/openapi-fetch@0.17.0/node_modules/openapi-fetch/src/index.js","../../contracts/src/api-client.ts","../../sdk/src/core/typed-client.ts","../../sdk/src/modules/store.ts","../../sdk/src/utils/storefront-catalog.ts","../../sdk/src/modules/products.ts","../../contracts/src/redirect-link-template.ts","../../sdk/src/modules/checkout.ts","../../sdk/src/modules/coupons.ts","../../sdk/src/modules/reviews.ts","../../sdk/src/utils/storefront-stock.ts","../../sdk/src/utils/storefront-search.ts","../../sdk/src/modules/search.ts","../../sdk/src/modules/invoices.ts","../../sdk/src/modules/pages.ts","../../contracts/src/navigation.ts","../../sdk/src/modules/navigation.ts","../../sdk/src/modules/presence.ts","../../sdk/src/utils/format.ts","../../sdk/src/modules/theme.ts","../../sdk/src/storefront-sdk.ts","../../contracts/src/product-custom-fields.ts","../../sdk/src/utils/storefront-custom-fields.ts","../../sdk/src/utils/storefront-contact.ts","../../sdk/src/modules/customer.ts","../../sdk/src/index.ts"],"sourcesContent":["/**\n * SDK Error Classes\n */\n\n/**\n * `SDKResponse.code` of a priced read that asked for a currency the shop does\n * not sell in (ADR-0066). `errorParams.requested` names the currency,\n * `errorParams.available` lists the enabled ones.\n */\nexport const CURRENCY_UNAVAILABLE_ERROR_CODE = 'errors.storefront.currency_unavailable';\n\nexport class ShoppexError extends Error {\n public readonly code: string;\n public readonly statusCode?: number;\n\n constructor(message: string, code: string, statusCode?: number) {\n super(message);\n this.name = 'ShoppexError';\n this.code = code;\n this.statusCode = statusCode;\n Object.setPrototypeOf(this, ShoppexError.prototype);\n }\n}\n\nexport class NotInitializedError extends ShoppexError {\n constructor() {\n super(\n 'SDK not initialized. Call shoppex.init() first.',\n 'NOT_INITIALIZED'\n );\n this.name = 'NotInitializedError';\n Object.setPrototypeOf(this, NotInitializedError.prototype);\n }\n}\n\nexport class NetworkError extends ShoppexError {\n constructor(message: string, statusCode?: number) {\n super(message, 'NETWORK_ERROR', statusCode);\n this.name = 'NetworkError';\n Object.setPrototypeOf(this, NetworkError.prototype);\n }\n}\n\n/**\n * A refusal the SERVER made and named. `code` is the backend's `error_code`\n * (e.g. `errors.checkout.coupon_no_longer_valid`) — the branchable identity of\n * the refusal, stable across locales, unlike the localized `message`.\n *\n * Distinct from {@link NetworkError}, whose `code` is always `NETWORK_ERROR`:\n * that one means \"the request did not produce a named answer\".\n */\nexport class ApiError extends ShoppexError {\n public readonly errorParams?: Record<string, unknown>;\n\n constructor(\n message: string,\n code: string,\n statusCode?: number,\n errorParams?: Record<string, unknown>,\n ) {\n super(message, code, statusCode);\n this.name = 'ApiError';\n this.errorParams = errorParams;\n Object.setPrototypeOf(this, ApiError.prototype);\n }\n}\n\nexport class ValidationError extends ShoppexError {\n public readonly invalidFields?: string[];\n\n constructor(message: string, invalidFields?: string[]) {\n super(message, 'VALIDATION_ERROR');\n this.name = 'ValidationError';\n this.invalidFields = invalidFields;\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\nexport class CartError extends ShoppexError {\n constructor(message: string) {\n super(message, 'BASKET_ERROR');\n this.name = 'CartError';\n Object.setPrototypeOf(this, CartError.prototype);\n }\n}\n","export function normalizeRequestedCurrency(value: string | null | undefined): string | null {\n const normalized = value?.trim().toUpperCase();\n return normalized && /^[A-Z]{3}$/.test(normalized) ? normalized : null;\n}\n\n/**\n * The buyer currency every priced SDK call uses (ADR-0066): an explicit\n * `?currency=` on the page wins, then the currency from `init()`. One rule for\n * catalog reads, cart quotes and checkout, so they can never disagree.\n */\nexport function resolveBuyerCurrency(configCurrency: string | null | undefined): string | null {\n return getRequestedCurrencyFromLocation() ?? normalizeRequestedCurrency(configCurrency);\n}\n\nexport function getRequestedCurrencyFromLocation(): string | null {\n if (typeof window === 'undefined' || !window.location) {\n return null;\n }\n\n const search = typeof window.location.search === 'string' ? window.location.search : '';\n if (search) {\n return normalizeRequestedCurrency(new URLSearchParams(search).get('currency'));\n }\n\n const href = typeof window.location.href === 'string' ? window.location.href : '';\n if (!href) {\n return null;\n }\n\n try {\n return normalizeRequestedCurrency(\n new URL(href, 'https://storefront.shoppex.local').searchParams.get('currency'),\n );\n } catch {\n return null;\n }\n}\n","/**\n * SDK Configuration Management\n */\n\nimport type { ShoppexConfig, ShoppexInitOptions } from '../types';\nimport { NotInitializedError, ValidationError } from './errors';\nimport { normalizeRequestedCurrency } from '../utils/requested-currency';\n\nexport const DEFAULT_API_BASE_URL = 'https://api.shoppex.io';\n\nlet currentConfig: ShoppexConfig | null = null;\nlet cachedShopId: string | null = null;\n\nexport const DEFAULT_CHECKOUT_BASE_URL = 'https://checkout.shoppex.io';\n\nexport function initConfig(\n storeSlug: string,\n options?: ShoppexInitOptions\n): ShoppexConfig {\n // Validate before touching any module state: a rejected init must leave\n // the previous configuration fully intact, not half of it.\n const currency = normalizeInitCurrency(options?.currency);\n const normalizedShopId = options?.shopId?.trim();\n\n // Reset cached shop id on every init to avoid cross-store leakage\n // when the SDK is re-initialized with a different slug.\n cachedShopId = normalizedShopId ? normalizedShopId : null;\n\n currentConfig = {\n storeSlug,\n locale: options?.locale,\n currency,\n apiBaseUrl: options?.apiBaseUrl ?? DEFAULT_API_BASE_URL,\n checkoutBaseUrl: options?.checkoutBaseUrl ?? DEFAULT_CHECKOUT_BASE_URL,\n preview: options?.preview === true,\n };\n // Response cache keys carry the locale and buyer currency (client.ts), so a\n // re-init with another audience reads its own entries instead of the\n // previous audience's payloads. The typed client is keyed on this object\n // (typed-client.ts), so it is rebuilt too.\n return currentConfig;\n}\n\n/**\n * The init currency is a contract input (ADR-0066): it is sent on every priced\n * read and refused by the API when the shop does not sell in it. A value that\n * cannot be a currency code is a programming error worth failing at init, not\n * a request the backend should have to reject on every call.\n */\nfunction normalizeInitCurrency(value: string | undefined): string | undefined {\n if (value === undefined || value.trim() === '') {\n return undefined;\n }\n const normalized = normalizeRequestedCurrency(value);\n if (!normalized) {\n throw new ValidationError(\n `Invalid currency \"${value}\": pass an ISO 4217 code such as \"EUR\".`,\n ['currency'],\n );\n }\n return normalized;\n}\n\nexport function getConfig(): ShoppexConfig {\n if (!currentConfig) {\n throw new NotInitializedError();\n }\n return currentConfig;\n}\n\nexport function isInitialized(): boolean {\n return currentConfig !== null;\n}\n\nexport function resetConfig(): void {\n currentConfig = null;\n cachedShopId = null;\n}\n\nexport function setShopId(shopId: string): void {\n cachedShopId = shopId;\n}\n\nexport function getShopId(): string | null {\n return cachedShopId;\n}\n","/**\n * Web Storage Wrapper\n *\n * Handles localStorage (default) and sessionStorage access with error handling\n * for environments where storage is not available.\n */\n\nimport { storefrontStorageKey } from '@shoppex/contracts/storefront-storage-key';\n\nconst STORAGE_PREFIX = 'shoppex_';\n\nexport type StorageArea = 'localStorage' | 'sessionStorage';\n\nfunction getKey(key: string): string {\n return `${STORAGE_PREFIX}${key}`;\n}\n\nexport function getItem<T>(key: string, area: StorageArea = 'localStorage'): T | null {\n try {\n const item = globalThis[area].getItem(storefrontStorageKey(getKey(key)));\n if (!item) return null;\n return JSON.parse(item) as T;\n } catch {\n return null;\n }\n}\n\nexport function setItem<T>(key: string, value: T, area: StorageArea = 'localStorage'): void {\n try {\n globalThis[area].setItem(storefrontStorageKey(getKey(key)), JSON.stringify(value));\n } catch {\n console.warn(`[shoppex] Failed to save to ${area}`);\n }\n}\n\nexport function removeItem(key: string, area: StorageArea = 'localStorage'): void {\n try {\n globalThis[area].removeItem(storefrontStorageKey(getKey(key)));\n } catch {\n // Ignore errors\n }\n}\n","/**\n * In-memory cache with pending request deduplication.\n */\n\nexport interface CacheEntry<T> {\n data: T;\n expiresAt: number;\n updatedAt: number;\n ttl: number;\n}\n\nexport interface CacheOptions {\n ttl: number;\n staleWhileRevalidate?: boolean;\n}\n\nexport interface CacheStats {\n hits: number;\n misses: number;\n pendingRequests: number;\n entries: number;\n}\n\nconst cache = new Map<string, CacheEntry<unknown>>();\nconst pending = new Map<string, Promise<unknown>>();\n\nconst stats = {\n hits: 0,\n misses: 0,\n};\n\nfunction isExpired(entry: CacheEntry<unknown>): boolean {\n return Date.now() > entry.expiresAt;\n}\n\nexport function getCacheStats(): CacheStats {\n return {\n hits: stats.hits,\n misses: stats.misses,\n pendingRequests: pending.size,\n entries: cache.size,\n };\n}\n\nexport function clearCache(): void {\n cache.clear();\n pending.clear();\n}\n\n// Keys written through the client carry the audience they were fetched for\n// as `<locale>|<currency>|<key>`. Callers invalidate by the bare key or\n// prefix (`products:my-store`) and mean every audience's copy of it.\nconst AUDIENCE_PREFIX = /^[^|]*\\|[^|]*\\|/;\n\nexport function invalidateCache(prefixOrKey: string): void {\n for (const key of cache.keys()) {\n const bareKey = key.replace(AUDIENCE_PREFIX, '');\n if (\n key === prefixOrKey\n || key.startsWith(prefixOrKey)\n || bareKey === prefixOrKey\n || bareKey.startsWith(prefixOrKey)\n ) {\n cache.delete(key);\n }\n }\n}\n\nexport function setCacheEntry<T>(key: string, data: T, ttl: number): void {\n const now = Date.now();\n cache.set(key, {\n data,\n ttl,\n updatedAt: now,\n expiresAt: now + ttl,\n });\n}\n\nexport function getCacheEntry<T>(key: string): CacheEntry<T> | null {\n const entry = cache.get(key) as CacheEntry<T> | undefined;\n if (!entry) return null;\n return entry;\n}\n\nexport async function getOrFetch<T>(\n key: string,\n fetcher: () => Promise<T>,\n options: CacheOptions,\n shouldCache: (value: T) => boolean = () => true\n): Promise<T> {\n const entry = getCacheEntry<T>(key);\n\n if (entry && !isExpired(entry)) {\n stats.hits += 1;\n return entry.data;\n }\n\n if (entry && options.staleWhileRevalidate) {\n stats.hits += 1;\n if (!pending.has(key)) {\n const refreshPromise = (async () => {\n try {\n const data = await fetcher();\n if (shouldCache(data)) {\n setCacheEntry(key, data, options.ttl);\n }\n return data;\n } finally {\n pending.delete(key);\n }\n })();\n pending.set(key, refreshPromise as Promise<unknown>);\n }\n return entry.data;\n }\n\n if (pending.has(key)) {\n return pending.get(key) as Promise<T>;\n }\n\n stats.misses += 1;\n const promise = (async () => {\n try {\n const data = await fetcher();\n if (shouldCache(data)) {\n setCacheEntry(key, data, options.ttl);\n }\n return data;\n } finally {\n pending.delete(key);\n }\n })();\n\n pending.set(key, promise as Promise<unknown>);\n return promise;\n}\n","const PARAM_PATTERN = /:([A-Za-z0-9_]+)/g;\n\nexport function buildEndpoint(\n template: string,\n params: Record<string, string | number | null | undefined>\n): string {\n return template.replace(PARAM_PATTERN, (_, key: string) => {\n const rawValue = params[key];\n if (rawValue === null || rawValue === undefined) {\n throw new Error(`Missing endpoint param: ${key}`);\n }\n\n const value = String(rawValue).trim();\n if (!value) {\n throw new Error(`Endpoint param \"${key}\" must not be empty`);\n }\n\n return encodeURIComponent(value);\n });\n}\n","import { getConfig, getShopId, isInitialized } from './config';\nimport { buildEndpoint } from './endpoint';\nimport { getItem, setItem } from '../utils/storage';\n\nconst CLIENT_ERROR_DEDUPE_WINDOW_MS = 15_000;\n// The ping endpoint rejects longer values (422); the report is cut to fit\n// instead of being lost.\nconst CLIENT_ERROR_TEXT_MAX_LENGTH = 500;\nconst CLIENT_ERROR_URL_MAX_LENGTH = 2000;\n\ntype VisibilityStateValue = 'hidden' | 'visible' | 'prerender' | 'unloaded';\ntype RequestMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';\n\nexport interface StorefrontClientErrorPayload {\n endpoint: string;\n method: RequestMethod;\n message: string;\n statusCode?: number;\n source?: 'sdk';\n phase?: 'request';\n attemptCount?: number;\n responseReceived?: boolean;\n pageUrl?: string;\n requestUrl?: string;\n online?: boolean;\n visibilityState?: VisibilityStateValue;\n}\n\nfunction getRecentClientErrorKey(payload: StorefrontClientErrorPayload): string {\n return [\n payload.method,\n payload.endpoint,\n payload.statusCode ?? 'none',\n payload.message.trim().toLowerCase(),\n payload.responseReceived ? 'response' : 'no-response',\n ].join('|');\n}\n\nfunction shouldSkipDuplicateClientError(payload: StorefrontClientErrorPayload): boolean {\n const dedupeKey = `client_error_${getRecentClientErrorKey(payload)}`;\n const now = Date.now();\n const lastSeenAt = getItem<number>(dedupeKey);\n if (typeof lastSeenAt === 'number' && now - lastSeenAt < CLIENT_ERROR_DEDUPE_WINDOW_MS) {\n return true;\n }\n\n setItem(dedupeKey, now);\n return false;\n}\n\nexport async function reportStorefrontClientError(payload: StorefrontClientErrorPayload): Promise<void> {\n if (!isInitialized()) return;\n if (typeof window === 'undefined') return;\n if (shouldSkipDuplicateClientError(payload)) return;\n\n const config = getConfig();\n const shopId = getShopId();\n const endpoint = shopId\n ? buildEndpoint('/v1/storefront/shops/id/:id/ping', { id: shopId })\n : buildEndpoint('/v1/storefront/shops/:storeSlug/ping', { storeSlug: config.storeSlug });\n const body = JSON.stringify({\n event_type: 'client_error',\n referer: document.referrer || undefined,\n client_error: {\n source: payload.source ?? 'sdk',\n phase: payload.phase ?? 'request',\n endpoint: payload.endpoint.slice(0, CLIENT_ERROR_TEXT_MAX_LENGTH),\n method: payload.method,\n message: payload.message.slice(0, CLIENT_ERROR_TEXT_MAX_LENGTH),\n status_code: payload.statusCode,\n attempt_count: payload.attemptCount,\n response_received: payload.responseReceived ?? false,\n page_url: (payload.pageUrl ?? window.location.href).slice(0, CLIENT_ERROR_URL_MAX_LENGTH),\n request_url: payload.requestUrl?.slice(0, CLIENT_ERROR_URL_MAX_LENGTH),\n online: payload.online ?? (typeof navigator !== 'undefined' ? navigator.onLine : undefined),\n visibility_state:\n payload.visibilityState ??\n (typeof document !== 'undefined'\n ? (document.visibilityState as VisibilityStateValue)\n : undefined),\n },\n });\n\n const targetUrl = `${config.apiBaseUrl}${endpoint}`;\n\n try {\n if (typeof navigator !== 'undefined' && typeof navigator.sendBeacon === 'function') {\n const beaconBody = new Blob([body], { type: 'application/json' });\n if (navigator.sendBeacon(targetUrl, beaconBody)) {\n return;\n }\n }\n\n await fetch(targetUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body,\n keepalive: true,\n });\n } catch {\n // Telemetry must never break storefront usage.\n }\n}\n","/**\n * HTTP Client for SDK\n *\n * IMPORTANT: No credentials! SDK runs on external domains,\n * and CORS with wildcard origin doesn't allow credentials.\n * All endpoints are public storefront endpoints.\n */\n\nimport type { ApiResponse, SDKResponse } from '../types';\nimport { getConfig, isInitialized } from './config';\nimport { ApiError, NetworkError, ShoppexError } from './errors';\nimport { getOrFetch, type CacheOptions } from './cache';\nimport { reportStorefrontClientError } from './telemetry';\nimport { resolveBuyerCurrency } from '../utils/requested-currency';\n\nconst DEFAULT_TIMEOUT = 10000;\nconst MAX_RETRIES = 2;\n\ninterface RequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\n body?: unknown;\n timeout?: number;\n retries?: number;\n baseUrl?: string;\n headers?: Record<string, string>;\n cache?: (CacheOptions & { key?: string }) | false;\n /**\n * This read prices its payload, so it travels with the buyer currency from\n * `init({ currency })` as `?currency=` (ADR-0066). The API prices the\n * response in that currency or refuses with\n * `errors.storefront.currency_unavailable`; it never silently serves the\n * shop default. Leave unset for reads that carry no prices.\n */\n buyerCurrency?: boolean;\n}\n\ninterface ParsedResponsePayload {\n data: unknown | null;\n rawText: string | null;\n}\n\ninterface FailureInfo {\n message: string;\n statusCode?: number;\n isTransport: boolean;\n responseReceived: boolean;\n responseDefinitive: boolean;\n /** The server's `error_code`, when the failure was a named refusal. */\n code?: string;\n errorParams?: Record<string, unknown>;\n}\n\nasync function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction appendQueryParam(url: string, key: string, value: string): string {\n const separator = url.includes('?') ? '&' : '?';\n return `${url}${separator}${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n}\n\n/**\n * Re-shape a failed response for a module's own return type without losing\n * the failure contract: `code` / `errorParams` are what callers branch on\n * (`errors.storefront.currency_unavailable`), `status` / `responseReceived` /\n * `responseDefinitive` are what mutation helpers and retries read. A wrapper\n * that rebuilds `{ success: false, message }` by hand silently drops them.\n */\nexport function forwardFailure<T>(\n response: SDKResponse<unknown>,\n overrides: { message?: string; data?: T } = {},\n): SDKResponse<T> {\n const { success: _success, data: _data, ...failure } = response;\n return {\n ...failure,\n success: false,\n message: overrides.message ?? response.message,\n ...(overrides.data !== undefined ? { data: overrides.data } : {}),\n };\n}\n\nexport async function request<T>(\n endpoint: string,\n options: RequestOptions = {}\n): Promise<SDKResponse<T>> {\n const config = options.baseUrl ? null : getConfig();\n // The audience (locale, buyer currency) travels with EVERY request of an\n // initialized SDK — a baseUrl override (e.g. resolveStoreByDomain) must not\n // silently drop it back to server-side negotiation (Codex P2).\n const audience = config ?? (isInitialized() ? getConfig() : null);\n const {\n method = 'GET',\n body,\n timeout = DEFAULT_TIMEOUT,\n retries,\n baseUrl,\n headers: requestHeaders,\n cache,\n buyerCurrency: pricesInBuyerCurrency = false,\n } = options;\n const retryCount =\n retries ?? (method === 'GET' ? MAX_RETRIES : 0);\n\n const apiBaseUrl = baseUrl ?? config?.apiBaseUrl ?? '';\n // One place knows the transport: currency is a query parameter, not a\n // header, because the storefront API keys its HTTP cache on the URL. The\n // value follows the same rule as cart quotes and checkout (page URL, then\n // init config), so the catalog is never priced differently from the cart.\n const buyerCurrency = pricesInBuyerCurrency ? resolveBuyerCurrency(audience?.currency) : null;\n const url = buyerCurrency\n ? appendQueryParam(`${apiBaseUrl}${endpoint}`, 'currency', buyerCurrency)\n : `${apiBaseUrl}${endpoint}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n ...requestHeaders,\n };\n // Explicit request locale (ADR-0055): without it the backend would fall\n // back to Accept-Language, detaching catalog content from the page locale.\n const locale = typeof audience?.locale === 'string' && audience.locale.trim() ? audience.locale.trim() : null;\n if (locale) {\n headers['x-shoppex-locale'] = locale;\n }\n\n let lastFailure: FailureInfo | null = null;\n\n const executeRequest = async (): Promise<SDKResponse<T>> => {\n for (let attempt = 0; attempt <= retryCount; attempt++) {\n let responseReceived = false;\n let responseDefinitive = false;\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n responseReceived = true;\n\n clearTimeout(timeoutId);\n\n const payload = await parseResponsePayload(response);\n if (!response.ok) {\n responseDefinitive = isDefinitiveHttpRefusal(payload.data)\n && response.status >= 400\n && response.status < 500\n && response.status !== 408;\n const fallbackHttpMessage = response.statusText\n ? `HTTP ${response.status}: ${response.statusText}`\n : `HTTP ${response.status}`;\n const message =\n (payload.data && typeof payload.data === 'object' && 'error' in payload.data && typeof payload.data.error === 'string'\n ? payload.data.error\n : null) ??\n (payload.data && typeof payload.data === 'object' && 'message' in payload.data && typeof payload.data.message === 'string'\n ? payload.data.message\n : null) ??\n payload.rawText ??\n fallbackHttpMessage;\n\n // A named server refusal keeps its name. Everything else stays a\n // NetworkError, exactly as before.\n const named = readErrorCodeFields(payload.data);\n if (named.code) {\n throw new ApiError(message, named.code, response.status, named.errorParams);\n }\n\n throw new NetworkError(message, response.status);\n }\n\n if (response.status === 204 && payload.data === null) {\n return {\n success: true,\n };\n }\n\n if (!payload.data || typeof payload.data !== 'object' || !('status' in payload.data)) {\n throw new NetworkError('Invalid API response', response.status);\n }\n\n const data = payload.data as ApiResponse<T>;\n const mapped = mapApiResponse(data);\n return mapped.success\n ? mapped\n : {\n ...mapped,\n responseReceived: true,\n responseDefinitive: data.status >= 400 && data.status < 500 && data.status !== 408,\n status: response.status,\n };\n } catch (error) {\n let normalizedError = error instanceof Error ? error : new Error(String(error));\n\n if (error instanceof DOMException && error.name === 'AbortError') {\n normalizedError = new NetworkError('Request timeout', 408);\n }\n\n // Read from the base class, not NetworkError: a named ApiError also\n // carries the HTTP status, and losing it would misclassify a 400\n // refusal as a transport failure — retried and reported as an outage.\n const statusCode =\n normalizedError instanceof ShoppexError\n ? normalizedError.statusCode\n : undefined;\n\n lastFailure = {\n message: normalizedError.message,\n statusCode,\n isTransport: statusCode === undefined || statusCode === 408,\n responseReceived,\n responseDefinitive,\n ...(normalizedError instanceof ApiError\n ? {\n code: normalizedError.code,\n ...(normalizedError.errorParams ? { errorParams: normalizedError.errorParams } : {}),\n }\n : {}),\n };\n\n // A named 4xx is the server's decision, not a transport hiccup:\n // `ApiError` only exists when the response carried an error code, and\n // a client-error status means the request itself was refused. Repeating\n // it verbatim cannot change the answer — it just multiplies the load\n // and delays the refusal the caller is waiting on by the full backoff\n // schedule. 408 stays retryable (it is a timeout wearing a 4xx) and\n // every 5xx, network failure and unnamed error retries exactly as\n // before.\n const isNamedClientRefusal =\n normalizedError instanceof ApiError\n && statusCode !== undefined\n && statusCode >= 400\n && statusCode < 500\n && statusCode !== 408;\n\n if (isNamedClientRefusal) {\n break;\n }\n\n if (attempt < retryCount) {\n await sleep(Math.pow(2, attempt) * 500);\n continue;\n }\n }\n }\n\n return {\n success: false,\n message: lastFailure?.message ?? 'Unknown error',\n ...(lastFailure ? { responseReceived: lastFailure.responseReceived } : {}),\n ...(lastFailure?.responseDefinitive ? { responseDefinitive: true } : {}),\n ...(lastFailure?.responseReceived && lastFailure.statusCode !== undefined\n ? { status: lastFailure.statusCode }\n : {}),\n ...(lastFailure?.code ? { code: lastFailure.code } : {}),\n ...(lastFailure?.errorParams ? { errorParams: lastFailure.errorParams } : {}),\n };\n };\n\n // Every cached payload is specific to the audience it was fetched for, so\n // the key carries the locale and (for priced reads) the buyer currency. A\n // locale or currency switch reads its own entry rather than the previous\n // audience's payload for up to the TTL.\n const result =\n method === 'GET' && cache && cache.ttl > 0\n ? await getOrFetch(\n `${locale ?? ''}|${buyerCurrency ?? ''}|${cache.key ?? `GET:${url}`}`,\n executeRequest,\n { ttl: cache.ttl, staleWhileRevalidate: cache.staleWhileRevalidate },\n (value) => value.success\n )\n : await executeRequest();\n\n const failureForTelemetry = lastFailure as FailureInfo | null;\n\n if (!result.success && failureForTelemetry?.isTransport) {\n\n await reportStorefrontClientError({\n endpoint,\n method,\n message: result.message ?? failureForTelemetry.message,\n statusCode: failureForTelemetry.statusCode,\n attemptCount: retryCount + 1,\n requestUrl: url,\n responseReceived: failureForTelemetry.responseReceived,\n });\n }\n\n return result;\n}\n\nasync function parseResponsePayload(response: Response): Promise<ParsedResponsePayload> {\n try {\n const rawText = await response.text();\n if (!rawText) {\n return { data: null, rawText: null };\n }\n\n try {\n return {\n data: JSON.parse(rawText) as unknown,\n rawText: null,\n };\n } catch {\n const normalizedText = rawText.trim();\n return {\n data: null,\n rawText: normalizedText.length > 0 ? normalizedText : null,\n };\n }\n } catch {\n return { data: null, rawText: null };\n }\n}\n\nfunction isDefinitiveHttpRefusal(payload: unknown): boolean {\n if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n return false;\n }\n\n const record = payload as Record<string, unknown>;\n return typeof record.status === 'number' && record.status >= 400 && record.status < 500;\n}\n\nfunction mapApiResponse<T>(apiResponse: ApiResponse<T>): SDKResponse<T> {\n if (apiResponse.status >= 200 && apiResponse.status < 300) {\n return {\n success: true,\n data: apiResponse.data,\n ...(apiResponse.message ? { message: apiResponse.message } : {}),\n };\n }\n\n return {\n success: false,\n message: apiResponse.error ?? apiResponse.message ?? `Request failed with status ${apiResponse.status}`,\n // The refusal the server actually made, kept machine-readable. Without it\n // a caller can only string-match a localized sentence, which breaks in\n // every locale but one.\n ...readErrorCodeFields(apiResponse),\n };\n}\n\n/**\n * Pull the localized-error envelope (`error_code` / `error_params`) off any\n * server payload shape. Returns an empty object when the payload carries none,\n * so the fields stay absent rather than becoming `undefined` keys.\n */\nfunction readErrorCodeFields(payload: unknown): { code?: string; errorParams?: Record<string, unknown> } {\n if (!payload || typeof payload !== 'object') {\n return {};\n }\n\n const record = payload as Record<string, unknown>;\n const code = typeof record.error_code === 'string' && record.error_code.length > 0\n ? record.error_code\n : null;\n if (!code) {\n return {};\n }\n\n const params = record.error_params;\n return {\n code,\n ...(params && typeof params === 'object' && !Array.isArray(params)\n ? { errorParams: params as Record<string, unknown> }\n : {}),\n };\n}\n\nexport async function get<T>(\n endpoint: string,\n options?: Omit<RequestOptions, 'method' | 'body'>\n): Promise<SDKResponse<T>> {\n return request<T>(endpoint, { ...options, method: 'GET' });\n}\n\nexport async function post<T>(\n endpoint: string,\n body?: unknown,\n options?: Omit<RequestOptions, 'method' | 'body'>\n): Promise<SDKResponse<T>> {\n return request<T>(endpoint, { ...options, method: 'POST', body });\n}\n","import { storefrontStorageKey } from '@shoppex/contracts/storefront-storage-key';\nimport { getConfig, isInitialized } from '../core/config';\nimport { post } from '../core/client';\nimport type { AffiliateValidation, SDKResponse } from '../types';\n\nconst STORAGE_KEY = 'shoppex:affiliate_code:v1';\nconst SESSION_STORAGE_KEY = 'shoppex:affiliate_session:v1';\nconst DEFAULT_TTL_DAYS = 30;\n// 24 base-36 characters provide about 124 bits of entropy and stay within the API's 8-64 character limit.\nconst FALLBACK_SESSION_KEY_LENGTH = 24;\nconst SESSION_KEY_ALPHABET = 'abcdefghijklmnopqrstuvwxyz0123456789';\n\nexport type AffiliateAttributionMode = 'LAST_CLICK' | 'FIRST_CLICK';\n\ntype StoredAffiliate = {\n code: string;\n expiresAt: number;\n /**\n * The attribution mode that applied when this entry was written (ADR-0067).\n *\n * Optional on purpose. The storage key stays `v1` because bumping it would\n * discard every in-flight attribution in every buyer's browser — real,\n * already-earned commission. An entry written before this field existed\n * reads as LAST_CLICK, which is exactly the behaviour it was written under.\n */\n mode?: AffiliateAttributionMode;\n /**\n * The window this entry was written under, in days. Same optionality rule as\n * `mode`: absent on pre-ADR-0067 entries, which then fall back to 30.\n *\n * Kept so a re-landing that cannot reach the server can renew the entry with\n * the shop's window instead of collapsing it to the 30-day default.\n */\n windowDays?: number;\n};\n\nfunction normalizeMode(value: unknown): AffiliateAttributionMode {\n return value === 'FIRST_CLICK' ? 'FIRST_CLICK' : 'LAST_CLICK';\n}\n\nfunction nowMs() {\n return Date.now();\n}\n\nfunction ttlMs(days: number) {\n return Math.max(1, days) * 24 * 60 * 60 * 1000;\n}\n\nfunction normalizeAffiliateCode(code: string | null | undefined): string | null {\n const normalized = code?.trim().toLowerCase();\n return normalized ? normalized : null;\n}\n\nfunction safeRead(): StoredAffiliate | null {\n if (typeof window === 'undefined') return null;\n try {\n const raw = window.localStorage.getItem(storefrontStorageKey(STORAGE_KEY));\n if (!raw) return null;\n const parsed = JSON.parse(raw) as StoredAffiliate;\n if (!parsed || typeof parsed.code !== 'string' || typeof parsed.expiresAt !== 'number') return null;\n return parsed.mode === undefined ? parsed : { ...parsed, mode: normalizeMode(parsed.mode) };\n } catch {\n return null;\n }\n}\n\nfunction safeWrite(value: StoredAffiliate) {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(storefrontStorageKey(STORAGE_KEY), JSON.stringify(value));\n } catch {\n // ignore\n }\n}\n\n/**\n * Write a previously read entry back verbatim (ADR-0067).\n *\n * Distinct from `setAffiliateCode`, which recomputes `expiresAt` from now:\n * restoring a first-click hold must not extend its window, because the window\n * runs from the click that earned it.\n */\nfunction restoreStoredAffiliate(value: StoredAffiliate): void {\n safeWrite(value);\n}\n\nexport function setAffiliateCode(\n code: string | null | undefined,\n ttlDays = DEFAULT_TTL_DAYS,\n mode?: AffiliateAttributionMode,\n): string | null {\n const normalized = normalizeAffiliateCode(code);\n if (!normalized) {\n clearAffiliateCode();\n return null;\n }\n\n safeWrite({\n code: normalized,\n expiresAt: nowMs() + ttlMs(ttlDays),\n windowDays: ttlDays,\n ...(mode ? { mode } : {}),\n });\n return normalized;\n}\n\n/**\n * The stored attribution, or null when nothing valid is held.\n *\n * Unlike `getAffiliateCode()` this also reports the mode the entry was written\n * under, which is what `captureAffiliateFromUrl` needs BEFORE it decides\n * whether it may overwrite.\n */\nexport function getStoredAffiliate(): {\n code: string;\n mode: AffiliateAttributionMode;\n windowDays: number;\n /**\n * When this entry expires, as written. Reported so a hold that has to be put\n * back after an early overwrite keeps its original expiry — the window runs\n * from the click that earned it, not from the landing that failed to take it.\n */\n expiresAt: number;\n} | null {\n const stored = safeRead();\n if (!stored) return null;\n if (stored.expiresAt <= nowMs()) {\n clearAffiliateCode();\n return null;\n }\n\n const code = normalizeAffiliateCode(stored.code);\n if (!code) return null;\n\n const windowDays = typeof stored.windowDays === 'number' && stored.windowDays > 0\n ? stored.windowDays\n : DEFAULT_TTL_DAYS;\n\n return { code, mode: normalizeMode(stored.mode), windowDays, expiresAt: stored.expiresAt };\n}\n\nexport function clearAffiliateCode(): void {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.removeItem(storefrontStorageKey(STORAGE_KEY));\n } catch {\n // ignore\n }\n}\n\nexport function getAffiliateCode(): string | null {\n const stored = safeRead();\n if (!stored) return null;\n if (stored.expiresAt <= nowMs()) {\n clearAffiliateCode();\n return null;\n }\n return normalizeAffiliateCode(stored.code);\n}\n\nfunction createAffiliateSessionKey(): string {\n try {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n } catch {\n // Fall through to the browser-safe random key.\n }\n\n let key = '';\n for (let index = 0; index < FALLBACK_SESSION_KEY_LENGTH; index += 1) {\n key += SESSION_KEY_ALPHABET[Math.floor(Math.random() * SESSION_KEY_ALPHABET.length)];\n }\n return key;\n}\n\n// Retained for the page's lifetime when sessionStorage is unavailable, so\n// repeated events in a storage-restricted browser still share one key and the\n// server-side session dedupe keeps working.\nlet inMemorySessionKey: string | null = null;\n\nfunction getAffiliateSessionKey(): string {\n try {\n const stored = window.sessionStorage.getItem(storefrontStorageKey(SESSION_STORAGE_KEY));\n if (stored && stored.length >= 8 && stored.length <= 64) {\n return stored;\n }\n } catch {\n // Read blocked entirely: the retained key is all we have.\n if (inMemorySessionKey) return inMemorySessionKey;\n }\n\n const key = createAffiliateSessionKey();\n try {\n window.sessionStorage.setItem(storefrontStorageKey(SESSION_STORAGE_KEY), key);\n // A write that silently no-ops (quota) must not hand out a fresh key per\n // event — verify it landed before trusting storage over the retained key.\n if (window.sessionStorage.getItem(storefrontStorageKey(SESSION_STORAGE_KEY)) === key) {\n inMemorySessionKey = key;\n return key;\n }\n } catch {\n // Fall through to the retained key.\n }\n\n if (!inMemorySessionKey) inMemorySessionKey = key;\n return inMemorySessionKey;\n}\n\nexport async function trackAffiliateEvent(\n eventType: 'add_to_cart' | 'checkout_started',\n options?: {\n /**\n * The code the surrounding call actually resolved and submitted (e.g.\n * checkout()'s tri-state result). `null` means the caller explicitly\n * submitted WITHOUT a referral — no event is recorded, so an ambient\n * stored code is never credited for a sale it did not get. Omit the\n * options object entirely to attribute to the stored ambient code.\n */\n code: string | null;\n /**\n * Overrides the per-browser-session dedupe key. checkout entry points\n * pass `inv:<invoiceId>` so every created invoice counts as exactly one\n * checkout — a session-wide key would drop the second checkout of a\n * buyer who orders twice in one session while both sales still count.\n */\n dedupeKey?: string;\n }\n): Promise<void> {\n try {\n // A preview page (an unpublished draft) credits no affiliate funnel.\n if (typeof window === 'undefined' || !isInitialized() || getConfig().preview) return;\n\n const code = options === undefined\n ? getAffiliateCode()\n : normalizeAffiliateCode(options.code);\n if (!code) return;\n\n const config = getConfig();\n // Raw fetch instead of the shared post helper: `keepalive` lets the\n // request survive the checkout redirect that immediately follows, which\n // would otherwise cancel it and undercount checkouts.\n await fetch(`${config.apiBaseUrl}/v1/storefront/affiliates/events`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n keepalive: true,\n body: JSON.stringify({\n shop_slug: config.storeSlug,\n code,\n event_type: eventType,\n // Dedupe key: per browser session by default (one add-to-cart per\n // session per link), or the caller's key — checkout passes one per\n // created invoice.\n session_key: options?.dedupeKey?.slice(0, 64) ?? getAffiliateSessionKey(),\n }),\n });\n } catch {\n // Funnel tracking must never break cart or checkout behavior.\n }\n}\n\nexport async function validateAffiliateCode(code: string): Promise<SDKResponse<AffiliateValidation>> {\n const normalizedCode = normalizeAffiliateCode(code);\n if (!normalizedCode) {\n return {\n success: false,\n data: {\n valid: false,\n affiliate_code: null,\n discount_active: false,\n discount_percent: 0,\n },\n message: 'Affiliate code is required',\n };\n }\n\n const config = getConfig();\n // The attribution the browser already holds, so the response can report ITS\n // policy too (ADR-0067). `applyAffiliateCode` below needs that to know\n // whether storing this code would take a sale away from a protected\n // first-click hold.\n const held = getStoredAffiliate();\n const response = await post<AffiliateValidation>(\n '/v1/storefront/affiliates/resolve',\n {\n shop_slug: config.storeSlug,\n code: normalizedCode,\n ...(held && held.code !== normalizedCode ? { held_code: held.code } : {}),\n },\n { retries: 0 }\n );\n\n if (!response.success) {\n return response;\n }\n\n if (!response.data?.valid || !response.data.affiliate_code) {\n const programDisabled = response.data?.program_enabled === false;\n return {\n success: false,\n data: {\n valid: false,\n ...(response.data?.program_enabled !== undefined ? { program_enabled: response.data.program_enabled } : {}),\n affiliate_code: null,\n discount_active: false,\n discount_percent: 0,\n },\n message: response.message\n ?? (programDisabled ? 'Affiliate program is disabled for this shop.' : 'Invalid affiliate code.'),\n };\n }\n\n return {\n success: true,\n data: {\n valid: true,\n ...(response.data.program_enabled !== undefined ? { program_enabled: response.data.program_enabled } : {}),\n affiliate_code: normalizeAffiliateCode(response.data.affiliate_code),\n discount_active: Boolean(response.data.discount_active),\n discount_percent: Number(response.data.discount_percent ?? 0),\n // Passed through rather than dropped: a caller that stores the code has\n // no other way to learn the policy, and defaulting to 30-day last-click\n // would quietly discard a first-click tier and any custom window.\n attribution_mode: normalizeMode(response.data.attribution_mode),\n attribution_window_days: typeof response.data.attribution_window_days === 'number'\n && response.data.attribution_window_days >= 1\n ? Math.trunc(response.data.attribution_window_days)\n : DEFAULT_TTL_DAYS,\n held_attribution_mode: response.data.held_attribution_mode === 'FIRST_CLICK'\n || response.data.held_attribution_mode === 'LAST_CLICK'\n ? response.data.held_attribution_mode\n : null,\n },\n ...(response.message ? { message: response.message } : {}),\n };\n}\n\n/**\n * Validate a manually entered code and store it (ADR-0067).\n *\n * Attribution is governed by the same rules as a `?ref=` landing, deliberately:\n * a themed \"apply code\" box must not be a way around first-click, or the rule\n * is bypassed by any storefront that offers one. So a still-protected hold\n * keeps the sale, and the stored entry always carries the mode and window the\n * server just reported — the old unconditional `setAffiliateCode(code)` wrote\n * a 30-day last-click entry whatever the shop or tier had configured.\n *\n * The result reports what is now ATTRIBUTED, not merely what was validated:\n * `affiliate_code` carries the winning code and `applied` says whether that is\n * the one you passed. The documented integration hands `affiliate_code`\n * straight to `checkout({ affiliateCode })`, and an explicit checkout code\n * overrides storage — so returning the losing code here would credit it and\n * walk right around the hold this function just honoured.\n */\nexport async function applyAffiliateCode(code: string): Promise<SDKResponse<AffiliateValidation>> {\n const held = getStoredAffiliate();\n const result = await validateAffiliateCode(code);\n\n if (result.success && result.data?.affiliate_code) {\n const applied = result.data.affiliate_code;\n const holdsOtherCode = held !== null && held.code !== applied;\n // The server's answer about the HELD code decides, never the arriving\n // one's; null means it no longer resolves, and the stored mode is then all\n // that is left.\n const heldMode = holdsOtherCode\n ? (result.data.held_attribution_mode ?? held.mode)\n : null;\n\n if (heldMode === 'FIRST_CLICK' && held) {\n return {\n ...result,\n data: { ...result.data, affiliate_code: held.code, applied: false },\n };\n }\n\n setAffiliateCode(\n applied,\n result.data.attribution_window_days ?? DEFAULT_TTL_DAYS,\n result.data.attribution_mode,\n );\n return { ...result, data: { ...result.data, applied: true } };\n }\n\n return result;\n}\n\n/**\n * Capture an affiliate code from the current URL and store it (ADR-0067).\n *\n * Example:\n * - URL: https://mystore.com/product/abc?ref=deadbeef\n * - captureAffiliateFromUrl() stores \"deadbeef\" and returns it.\n *\n * Under LAST_CLICK (the default, and the only behaviour before ADR-0067) a new\n * `?ref=` replaces whatever was stored. Under FIRST_CLICK an existing,\n * unexpired attribution wins and the new code is NOT stored — the landing is\n * still reported to the server so the affiliate's click statistics stay\n * honest, but the credit stays with whoever was there first.\n *\n * The mode comes from the server, which means the FIRST landing in a browser\n * can never be blocked by it — correct, because there is nothing to protect\n * yet. From then on the mode travels with the stored entry.\n *\n * Enforcement is client-side. A buyer who edits localStorage can re-attribute\n * their own visit; this is the same trust level as the window itself and must\n * not be presented to merchants as fraud protection.\n */\nexport async function captureAffiliateFromUrl(param = 'ref'): Promise<string | null> {\n if (typeof window === 'undefined') return null;\n\n let code: string | null = null;\n try {\n const url = new URL(window.location.href);\n const raw = url.searchParams.get(param);\n code = raw ? raw.trim() : null;\n } catch {\n code = null;\n }\n\n code = normalizeAffiliateCode(code);\n if (!code) return null;\n\n // Read BEFORE writing: under first-click the held entry is the one that\n // counts, and the old \"store immediately\" would have destroyed it.\n const held = getStoredAffiliate();\n // A DIFFERENT attribution is held, so this landing can take a sale away from\n // someone. Whether it may is the server's answer below.\n const holdsOtherCode = held !== null && held.code !== code;\n // The stored mode can be stale. Preserve every different held code until\n // the server resolves its policy, including while checkout reads storage.\n if (!holdsOtherCode) {\n // Store immediately so we don't lose it if the attribution call fails.\n // The window is the previous one we were told about, not a fixed 30 days —\n // a shop with a 90-day window must not silently drop to 30 when the\n // attribution call fails and this early write is all that survives.\n setAffiliateCode(code, held?.windowDays ?? DEFAULT_TTL_DAYS, held?.mode);\n }\n\n // Optional: validate + normalize with backend. If invalid, clear it.\n if (isInitialized()) {\n try {\n const config = getConfig();\n const res = await post<{\n accepted?: boolean;\n affiliate_code?: string | null;\n attribution_mode?: string | null;\n attribution_window_days?: number | null;\n held_attribution_mode?: string | null;\n }>(\n '/v1/storefront/affiliates/attribution',\n {\n shop_slug: config.storeSlug,\n code,\n // Sent so the server can report the policy of the attribution we\n // already hold. Its mode — not the arriving code's — decides whether\n // that hold may be released.\n ...(held ? { held_code: held.code } : {}),\n },\n { retries: 0 }\n );\n\n const serverMode = res.success && res.data?.attribution_mode\n ? normalizeMode(res.data.attribution_mode)\n : null;\n const serverWindow = res.success && typeof res.data?.attribution_window_days === 'number'\n ? res.data.attribution_window_days\n : DEFAULT_TTL_DAYS;\n\n // The shop may have switched to last-click since the entry was written, and the\n // server is the authority — without this check a stale FIRST_CLICK entry\n // would keep winning for up to a full window (365 days) and pay the\n // wrong affiliate on every sale in between.\n // Whether the hold survives is decided by the HELD code's current\n // policy, never by the arriving one. Affiliate A stored under a\n // first-click tier must keep the sale even when affiliate B arrives from\n // a last-click tier — using B's mode here would hand B the commission.\n // `held_attribution_mode` is null when the server no longer resolves the\n // held code; the stored mode is then the only information left.\n const heldMode = res.success && res.data?.held_attribution_mode\n ? normalizeMode(res.data.held_attribution_mode)\n : null;\n const holdsFirstClick = holdsOtherCode && (heldMode ?? held?.mode) === 'FIRST_CLICK';\n\n if (holdsFirstClick && held) {\n // First-click still applies: keep the first attribution. Its expiry is\n // deliberately NOT extended — the window runs from the click that\n // earned it.\n restoreStoredAffiliate({\n code: held.code,\n expiresAt: held.expiresAt,\n windowDays: held.windowDays,\n mode: heldMode ?? held.mode,\n });\n return held.code;\n }\n\n if (res.success && res.data?.accepted && res.data.affiliate_code) {\n setAffiliateCode(res.data.affiliate_code, serverWindow, serverMode ?? undefined);\n return res.data.affiliate_code;\n }\n // Clear only on a definitive refusal (the server answered and said the\n // code is not attributable). A rate limit or transport failure must not\n // destroy a valid referral before checkout — from-cart validates later.\n if (res.success && res.data && res.data.accepted === false) {\n if (holdsOtherCode) return held.code;\n clearAffiliateCode();\n return null;\n }\n // Reached on a non-success response (`post()` resolves rather than\n // throws on an HTTP failure, e.g. the route's 429). Nothing was\n // overwritten in that case, so returning the arriving code would hand a\n // custom storefront that submits this value manually to the newcomer\n // while storage still holds the first click. Same answer as the catch\n // below, for the same reason.\n return holdsOtherCode ? held.code : code;\n } catch {\n // Without a policy response, preserve the existing attribution.\n return holdsOtherCode ? held.code : code;\n }\n }\n\n // Not initialized: preserve any different held attribution.\n return holdsOtherCode ? held.code : code;\n}\n","/**\n * The buyer's cookie banner choice as it travels: the storefront cookie, the\n * checkout URL hash, and which category each integration needs. No zod here:\n * the storefront SDK bundles this module, the settings schemas stay in\n * `storefront-cookie-consent.ts`.\n */\nimport type { CookieConsentCategory } from './storefront-cookie-consent.js';\n\n/**\n * The buyer's choice, a first-party cookie on the storefront host, matched\n * whole (`v1.f0.a1.m0`) and never decoded. A value of another version counts\n * as no choice, so bumping the version asks every buyer again.\n */\nexport const COOKIE_CONSENT_VERSION = 1;\nexport const COOKIE_CONSENT_COOKIE = 'shoppex_consent';\n\n/**\n * The hosted checkout (another site) cannot read the storefront's cookie, so\n * the SDK carries the value in the checkout URL's hash under this key.\n */\nexport const COOKIE_CONSENT_CHECKOUT_HASH_KEY = 'shoppex_consent';\n\nexport type CookieConsentChoice = Record<CookieConsentCategory, boolean>;\n\nconst COOKIE_CONSENT_VALUE = new RegExp(`^v${COOKIE_CONSENT_VERSION}\\\\.f([01])\\\\.a([01])\\\\.m([01])$`);\n\n/** The choice a cookie value records, or null for anything that is not one. */\nexport function parseCookieConsentValue(value: string | null | undefined): CookieConsentChoice | null {\n const match = value ? COOKIE_CONSENT_VALUE.exec(value) : null;\n return match ? { functional: match[1] === '1', analytics: match[2] === '1', marketing: match[3] === '1' } : null;\n}\n\n/**\n * Which category each integration needs. Chat widgets are `functional`: each\n * sets its own third-party cookies on page load, before the buyer asked for\n * help, so none is strictly necessary (Intercom also records visits; it stays\n * functional because merchants enable it as their support chat). Google Tag\n * Manager is `marketing`: a container can fire any ad tag, so it needs the\n * stricter category; Consent Mode tells the tags inside what else was allowed.\n */\nexport const INTEGRATION_CONSENT_CATEGORIES: Record<string, CookieConsentCategory> = {\n google_analytics: 'analytics',\n microsoft_clarity: 'analytics',\n hotjar: 'analytics',\n plausible: 'analytics',\n google_tag_manager: 'marketing',\n meta_pixel: 'marketing',\n tiktok_pixel: 'marketing',\n google_ads: 'marketing',\n reddit_pixel: 'marketing',\n snapchat_pixel: 'marketing',\n pinterest_tag: 'marketing',\n crisp: 'functional',\n tawk_to: 'functional',\n livechat: 'functional',\n intercom: 'functional',\n chatwoot: 'functional',\n};\n","/**\n * Analytics session of this tab (web analytics, Design Batch 3 feature 1).\n *\n * Storing an id in the browser needs consent (TTDSG/TDDDG §25), so every\n * stored analytics value here exists only after a yes to \"analytics\" on the\n * shop's cookie banner (the `shoppex_consent` cookie). Without that yes the\n * storefront is still counted, cookieless: the server derives the visit from\n * a daily-salted hash and nothing is kept in the browser. Global Privacy\n * Control and Do Not Track count as a no. A no (or a withdrawn yes) removes\n * what was stored.\n *\n * - session id: sessionStorage, ends after 30 minutes without a page view,\n * or on a new landing: a page reached from another site or another\n * campaign than the one the session started with, also when it started\n * direct (the server then starts a new visit, and one session never spans\n * two visits). A new landing from another site drops the stored campaign.\n * - visits: localStorage, the session ids of the last 30 days (newest first,\n * at most 20). Checkout sends them so the server can find where the buyer\n * came from; the server reads every source fact itself.\n * - time on screen: counted in memory while the tab is visible and sent with\n * the next page view, or as `page_leave` when the tab is hidden, to the\n * session the page was viewed in.\n * - a yes given without a reload (`shoppex:consent`) starts the session on a\n * page already counted (`session_start`).\n *\n * `packages/storefront-host/src/pageTracker.installScript.ts` repeats these\n * rules for code storefronts; `pageTracker.test.ts` locks the parity.\n */\n\nimport { COOKIE_CONSENT_COOKIE, parseCookieConsentValue } from '@shoppex/contracts/storefront-consent-choice';\nimport { storefrontStorageKey } from '@shoppex/contracts/storefront-storage-key';\nimport { getItem, removeItem, setItem } from '../utils/storage';\n\nexport const ANALYTICS_SESSION_IDLE_MS = 30 * 60 * 1000;\nexport const ANALYTICS_VISITS_WINDOW_MS = 30 * 24 * 60 * 60 * 1000;\nexport const ANALYTICS_VISITS_MAX = 20;\n/** Same cap as the ping route: a visit stops counting after 30 minutes on one page. */\nexport const MAX_ENGAGED_MS_PER_PAGE = 30 * 60 * 1000;\n/** Key prefix of the stored landing campaign (`attribution.ts`). */\nexport const UTM_STORAGE_PREFIX = 'shoppex:utm:';\n\n/** Storage keys (the storage wrapper adds the `shoppex_` prefix). */\nexport const analyticsSessionKey = (storeSlug: string) => `analytics_session_${storeSlug}`;\nexport const analyticsVisitsKey = (storeSlug: string) => `analytics_visits_${storeSlug}`;\n\ninterface StoredSession {\n id: string;\n /** Epoch ms of the last page view. */\n at: number;\n /** Referrer host the session started with ('' for none). */\n r?: string;\n /** utm source|medium|campaign the session started with ('' for none). */\n u?: string;\n}\n\n/** Where this page came from: another site's host and the URL's campaign ('' for none). */\nfunction pageLanding(): { r: string; u: string } {\n let r = '';\n try {\n r = document.referrer ? new URL(document.referrer).hostname : '';\n } catch {\n // An unreadable referrer names no other site.\n }\n const params = new URLSearchParams(window.location?.search ?? '');\n const u = ['source', 'medium', 'campaign'].map((key) => params.get(`utm_${key}`)?.trim().toLowerCase() ?? '').join('|');\n return { r: r === window.location?.hostname ? '' : r, u: u === '||' ? '' : u };\n}\n\nexport type AnalyticsConsent = 'granted' | 'declined' | 'unknown';\n\nexport function readAnalyticsConsent(): AnalyticsConsent {\n if (typeof document === 'undefined' || typeof navigator === 'undefined') return 'unknown';\n const privacy = navigator as Navigator & { globalPrivacyControl?: boolean };\n if (privacy.globalPrivacyControl === true || privacy.doNotTrack === '1') return 'declined';\n const prefix = `${COOKIE_CONSENT_COOKIE}=`;\n let raw: string | undefined;\n try {\n raw = document.cookie.split(/;\\s*/).find((part) => part.startsWith(prefix))?.slice(prefix.length);\n } catch {\n // A sandboxed frame without its own origin cannot read cookies: no yes was given here.\n return 'unknown';\n }\n const choice = parseCookieConsentValue(raw ?? null);\n if (!choice) return 'unknown';\n return choice.analytics ? 'granted' : 'declined';\n}\n\nfunction readVisits(storeSlug: string, now: number): StoredSession[] {\n const stored = getItem<StoredSession[]>(analyticsVisitsKey(storeSlug));\n if (!Array.isArray(stored)) return [];\n return stored.filter((visit) => typeof visit?.id === 'string' && typeof visit.at === 'number' && now - visit.at < ANALYTICS_VISITS_WINDOW_MS);\n}\n\n/** Removes every stored analytics value of this shop (no consent, or withdrawn). */\nexport function forgetAnalyticsData(storeSlug: string): void {\n removeItem(analyticsSessionKey(storeSlug), 'sessionStorage');\n removeItem(analyticsVisitsKey(storeSlug));\n}\n\n/**\n * The tab's session id after an analytics yes, else null (and nothing stored).\n * `touch` (a page view) starts a session after 30 idle minutes and restarts\n * the idle time; without it the current session is only read.\n */\nexport function analyticsSessionId(storeSlug: string, options: { touch: boolean }, now = Date.now()): string | null {\n // SDK 1.0.102 and older kept a presence id here, without consent.\n removeItem(`presence_connection_${storeSlug}`);\n if (readAnalyticsConsent() !== 'granted') {\n forgetAnalyticsData(storeSlug);\n return null;\n }\n const stored = getItem<StoredSession>(analyticsSessionKey(storeSlug), 'sessionStorage');\n const live = stored && typeof stored.id === 'string' && typeof stored.at === 'number' && now - stored.at < ANALYTICS_SESSION_IDLE_MS\n ? stored.id\n : null;\n if (!options.touch) return live;\n const landing = pageLanding();\n // A page without a referrer or campaign of its own (inside the store)\n // continues the session; any other one than the session began with, also\n // after a direct start, is a new landing.\n const newLanding = (landing.r && landing.r !== stored?.r) || (landing.u && landing.u !== stored?.u);\n if (live && !newLanding) {\n setItem<StoredSession>(analyticsSessionKey(storeSlug), { ...stored, id: live, at: now }, 'sessionStorage');\n return live;\n }\n if (typeof crypto === 'undefined' || typeof crypto.randomUUID !== 'function') return null;\n // The campaign of the visit before must not tag this one; a campaign of\n // this page is stored again with its page view.\n if (landing.r) {\n try {\n globalThis.localStorage.removeItem(storefrontStorageKey(`${UTM_STORAGE_PREFIX}${storeSlug}`));\n } catch {\n // Storage blocked: nothing is stored either.\n }\n }\n const id = crypto.randomUUID();\n setItem<StoredSession>(analyticsSessionKey(storeSlug), { id, at: now, ...landing }, 'sessionStorage');\n setItem<StoredSession[]>(\n analyticsVisitsKey(storeSlug),\n [{ id, at: now }, ...readVisits(storeSlug, now)].slice(0, ANALYTICS_VISITS_MAX),\n );\n return id;\n}\n\n/** What a checkout sends about where the buyer came from (`attribution`). */\nexport function checkoutAttribution(storeSlug: string, now = Date.now()): { session_ids: string[] } | { declined: true } | undefined {\n const consent = readAnalyticsConsent();\n if (consent === 'declined') {\n forgetAnalyticsData(storeSlug);\n return { declined: true };\n }\n if (consent === 'unknown') return undefined;\n const sessionIds = readVisits(storeSlug, now).map((visit) => visit.id);\n return sessionIds.length > 0 ? { session_ids: sessionIds } : undefined;\n}\n\nlet engagedMs = 0;\nlet visibleSince: number | null = null;\nlet clockInstalled = false;\nlet pageViewed = false;\n// The session this page was viewed in. Its time on screen belongs there even\n// when 30 idle minutes end that session before the next view or page_leave.\nlet pageSession: string | null = null;\n\n/** Records that this page's view went out, in `sessionId` (null: counted cookieless). */\nexport function markPageViewed(sessionId: string | null): void {\n pageViewed = true;\n pageSession = sessionId;\n}\n\n/** The session this page's time on screen belongs to; null before a view or without one. */\nexport function currentPageSession(): string | null {\n return pageSession;\n}\n\n/** Whether this page's view already went out (a later yes then starts a session for it). */\nexport function isPageViewed(): boolean {\n return pageViewed;\n}\n\nfunction settleClock(now: number): void {\n if (visibleSince !== null) {\n engagedMs += now - visibleSince;\n visibleSince = document.visibilityState === 'visible' ? now : null;\n }\n}\n\nlet consentListenerInstalled = false;\n\n/** Calls `onYes` (once per page install) when the buyer says yes to analytics without a reload. */\nexport function onAnalyticsConsent(onYes: () => void): void {\n if (consentListenerInstalled || typeof window === 'undefined') return;\n consentListenerInstalled = true;\n // The banner dispatches `shoppex:consent` on every choice (and once on load for a stored one).\n window.addEventListener('shoppex:consent', () => {\n if (readAnalyticsConsent() === 'granted') onYes();\n });\n}\n\n/** Starts counting time on screen (once per page). */\nexport function installEngagedClock(onHidden: () => void): void {\n if (clockInstalled || typeof document === 'undefined') return;\n clockInstalled = true;\n visibleSince = document.visibilityState === 'visible' ? Date.now() : null;\n document.addEventListener('visibilitychange', () => {\n const now = Date.now();\n if (document.visibilityState === 'visible') {\n visibleSince ??= now;\n return;\n }\n settleClock(now);\n visibleSince = null;\n onHidden();\n });\n // A page restored from the back/forward cache fires no visibilitychange.\n window.addEventListener('pagehide', () => {\n settleClock(Date.now());\n visibleSince = null;\n onHidden();\n });\n window.addEventListener('pageshow', (event) => {\n if (event.persisted && document.visibilityState === 'visible') visibleSince = Date.now();\n });\n}\n\n/** Time on screen since the last take, capped per page; the clock restarts. */\nexport function takeEngagedMs(now = Date.now()): number {\n settleClock(now);\n const taken = Math.min(Math.max(0, Math.round(engagedMs)), MAX_ENGAGED_MS_PER_PAGE);\n engagedMs = 0;\n return taken;\n}\n\n/** Test hook: the clock is page state. */\nexport function resetEngagedClockForTests(): void {\n engagedMs = 0;\n visibleSince = null;\n clockInstalled = false;\n pageViewed = false;\n pageSession = null;\n consentListenerInstalled = false;\n}\n","/**\n * UTM attribution for storefront page views.\n *\n * Campaign parameters only appear on the landing URL, but a visitor usually\n * browses several pages before doing anything interesting. Without persistence\n * every page after the first would be attributed to \"direct\" and the numbers\n * would understate every campaign.\n *\n * Last-touch: a fresh set of parameters replaces the stored one, matching what\n * merchants expect from analytics tools — the most recent campaign gets credit.\n * Navigating without parameters keeps whatever was stored, until a new\n * landing from another site starts a new analytics session.\n *\n * Storing needs an analytics yes on the shop's cookie banner (TTDSG §25):\n * without it only the parameters of the current URL are reported and any\n * stored set is removed.\n */\n\nimport { storefrontStorageKey } from '@shoppex/contracts/storefront-storage-key';\nimport { UTM_STORAGE_PREFIX, readAnalyticsConsent } from './analytics-session';\n\nconst TTL_MS = 30 * 24 * 60 * 60 * 1000;\n\nconst UTM_KEYS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'] as const;\n\ntype UtmKey = (typeof UTM_KEYS)[number];\n\nexport type UtmParameters = Partial<Record<UtmKey, string>>;\n\ninterface StoredAttribution {\n utm: UtmParameters;\n /** Epoch ms of the last touch, used for TTL expiry. */\n at: number;\n}\n\n/** Values are merchant-supplied and land in a text column; keep them bounded. */\nconst MAX_VALUE_LENGTH = 255;\n\nfunction readFromUrl(search: string): UtmParameters {\n let params: URLSearchParams;\n try {\n params = new URLSearchParams(search);\n } catch {\n return {};\n }\n\n const utm: UtmParameters = {};\n for (const key of UTM_KEYS) {\n const value = params.get(key)?.trim();\n if (value) {\n utm[key] = value.slice(0, MAX_VALUE_LENGTH);\n }\n }\n return utm;\n}\n\nfunction storageKey(storeSlug: string): string {\n return `${UTM_STORAGE_PREFIX}${storeSlug}`;\n}\n\nfunction readStored(storeSlug: string): UtmParameters {\n try {\n const raw = window.localStorage.getItem(storefrontStorageKey(storageKey(storeSlug)));\n if (!raw) return {};\n\n const parsed = JSON.parse(raw) as StoredAttribution;\n if (!parsed || typeof parsed.at !== 'number' || typeof parsed.utm !== 'object') return {};\n if (Date.now() - parsed.at > TTL_MS) {\n window.localStorage.removeItem(storefrontStorageKey(storageKey(storeSlug)));\n return {};\n }\n\n const utm: UtmParameters = {};\n for (const key of UTM_KEYS) {\n const value = parsed.utm?.[key];\n if (typeof value === 'string' && value.length > 0) {\n utm[key] = value.slice(0, MAX_VALUE_LENGTH);\n }\n }\n return utm;\n } catch {\n // Private mode, quota errors, corrupt JSON — attribution is best-effort and\n // must never break a page view.\n return {};\n }\n}\n\nfunction writeStored(storeSlug: string, utm: UtmParameters): void {\n try {\n const payload: StoredAttribution = { utm, at: Date.now() };\n window.localStorage.setItem(storefrontStorageKey(storageKey(storeSlug)), JSON.stringify(payload));\n } catch {\n // Ignore: the current page view still reports the parameters it just read.\n }\n}\n\n/**\n * Resolves the UTM parameters to report for the current page view.\n *\n * Reads the current URL first; when it carries any campaign parameter that set\n * wins and is persisted. Otherwise the stored set is returned unchanged.\n *\n * @returns the parameters, or undefined when there is nothing to report\n */\nexport function resolveUtmParameters(storeSlug: string): UtmParameters | undefined {\n if (typeof window === 'undefined' || typeof window.location === 'undefined') {\n return undefined;\n }\n\n const fromUrl = readFromUrl(window.location.search);\n if (readAnalyticsConsent() !== 'granted') {\n try {\n window.localStorage.removeItem(storefrontStorageKey(storageKey(storeSlug)));\n } catch {\n // Storage blocked: nothing is stored either.\n }\n return Object.keys(fromUrl).length > 0 ? fromUrl : undefined;\n }\n if (Object.keys(fromUrl).length > 0) {\n writeStored(storeSlug, fromUrl);\n return fromUrl;\n }\n\n const stored = readStored(storeSlug);\n return Object.keys(stored).length > 0 ? stored : undefined;\n}\n","/**\n * The storefront page a view or presence ping reports, for the merchant's live\n * \"Top page\".\n *\n * Only `location.pathname` is read. The query string and fragment are never\n * sent: they can carry emails, sign-in tokens or checkout ids. The API\n * normalises the path again (trailing slash, repeated slashes, length) before\n * it stores it; the cap here only keeps the ping body inside the API's input\n * bound so an unusually long path cannot invalidate the rest of the ping.\n */\nconst MAX_PATH_LENGTH = 256;\n\nexport function resolveStorefrontPagePath(): string | undefined {\n if (typeof window === 'undefined') return undefined;\n\n let pathname: string | undefined;\n try {\n const location = window.location;\n pathname = typeof location?.pathname === 'string' && location.pathname\n ? location.pathname\n : new URL(String(location?.href ?? '')).pathname;\n } catch {\n return undefined;\n }\n\n if (!pathname || !pathname.startsWith('/')) return undefined;\n return pathname.slice(0, MAX_PATH_LENGTH);\n}\n","/**\n * Whether the storefront platform already reports page views and presence.\n *\n * `workers/storefront` injects a small tracker into every code storefront page\n * (`@shoppex/storefront-host/page-tracker`). It sends the same ping this SDK\n * sends, on load, on every client-side navigation and as a 60s presence\n * heartbeat, and it sets this flag before any theme code runs. While the flag\n * is set, `trackPageView()` without cart data and `touchStorefrontPresence()`\n * do nothing, so a theme that also reports views is not counted twice. A\n * `trackPageView(cartValue, itemCount)` still reports the cart the tracker\n * cannot see, as cart activity (`event_type: 'presence'`) that counts no view.\n *\n * The document lane never sets the flag; there the SDK stays the only\n * reporter. The literal is duplicated in the tracker (the worker does not\n * bundle the SDK); the tracker's test locks the two together.\n */\nexport const PLATFORM_PAGE_TRACKER_FLAG = '__shoppexPageTracker';\n\nexport function isPlatformPageTrackerActive(): boolean {\n if (typeof window === 'undefined') return false;\n try {\n return Boolean((window as unknown as Record<string, unknown>)[PLATFORM_PAGE_TRACKER_FLAG]);\n } catch {\n return false;\n }\n}\n","import { isInitialized, getConfig } from '../core/config';\nimport { buildEndpoint } from '../core/endpoint';\nimport {\n analyticsSessionId,\n currentPageSession,\n installEngagedClock,\n isPageViewed,\n markPageViewed,\n onAnalyticsConsent,\n readAnalyticsConsent,\n takeEngagedMs,\n} from '../core/analytics-session';\nimport { resolveUtmParameters } from '../core/attribution';\nimport { resolveStorefrontPagePath } from '../core/page-path';\nimport { isPlatformPageTrackerActive } from '../core/page-tracker';\nimport { getItem, removeItem, setItem } from '../utils/storage';\n\n// Cart reporting state, shared by every tab of the shop through localStorage.\n// A cart change in one tab reaches the others as a `storage` event, and only\n// one tab should send it.\n//\n// Order: every cart state gets a sequence number (`cart_seq`, with its\n// `cart_seq_scope`) when it is reported to the SDK, from a counter shared by\n// all tabs. The server keeps the cart with the highest sequence of the scope\n// and ignores an older one that arrives later, so the order in which pings\n// reach the server no longer decides the live cart, also across tabs.\n//\n// Deduplication keeps two values, so a failed send can never leave an unsent\n// cart looking reported:\n// - confirmed: the acknowledged cart state with the highest sequence (written\n// only after a 2xx response, and only over a lower sequence, the same rule\n// the server applies);\n// - in flight: the cart state a tab is sending right now, with its sequence,\n// its own token and a short lifetime, so a concurrent echo in another tab\n// skips it.\nconst CONFIRMED_CART_STORAGE_PREFIX = 'reported_cart_';\nconst IN_FLIGHT_CART_STORAGE_PREFIX = 'reporting_cart_';\n// Not under `cart_`: storefront-commerce treats every `shoppex_cart_*` storage\n// event as a cart change, so a sequence write there would echo between tabs.\nconst CART_SEQUENCE_STORAGE_PREFIX = 'presence_cart_seq_';\n/**\n * A ping that has not answered after this long is abandoned as failed, so a\n * hung request cannot hold up this tab's later cart sends. A claim older than\n * this belongs to a send that is over (or a tab that closed) and is ignored.\n */\nexport const CART_CLAIM_TTL_MS = 10_000;\n\ntype ReportedCart = { snapshot: string; seq: number };\ntype InFlightCart = ReportedCart & { token: string; at: number };\n\nfunction confirmedCartKey(storeSlug: string): string {\n return `${CONFIRMED_CART_STORAGE_PREFIX}${storeSlug}`;\n}\n\nfunction inFlightCartKey(storeSlug: string): string {\n return `${IN_FLIGHT_CART_STORAGE_PREFIX}${storeSlug}`;\n}\n\nfunction cartSequenceKey(storeSlug: string): string {\n return `${CART_SEQUENCE_STORAGE_PREFIX}${storeSlug}`;\n}\n\nfunction cartSnapshot(cartValue: number | undefined, itemCount: number | undefined): string {\n return `${cartValue ?? ''}|${itemCount ?? ''}`;\n}\n\nfunction isCartSequence(value: unknown): value is number {\n return typeof value === 'number' && Number.isSafeInteger(value) && value > 0;\n}\n\n/**\n * The order of one cart state: a sequence and the scope it belongs to. The\n * server only compares sequences of one scope, so the scope is created with\n * the shared counter and lives in the same localStorage record: every tab that\n * takes a sequence from the counter also takes its scope. The presence\n * connection id is not used for this, because code outside the cart path\n * (heartbeats, the code-storefront page tracker) creates it without the lock.\n */\ntype CartOrder = { scope: string; seq: number };\n\nconst CART_SEQUENCE_SCOPE_MAX_LENGTH = 64;\n\nfunction readCartCounter(storeSlug: string): CartOrder | null {\n const counter = getItem<CartOrder>(cartSequenceKey(storeSlug));\n if (\n !counter\n || typeof counter.scope !== 'string'\n || counter.scope.length === 0\n || counter.scope.length > CART_SEQUENCE_SCOPE_MAX_LENGTH\n || !isCartSequence(counter.seq)\n ) {\n return null;\n }\n return counter;\n}\n\n// The last order this tab handed out: keeps the sequence rising in this tab\n// when localStorage is unavailable.\nlet lastCartOrder: CartOrder | null = null;\n\n/**\n * The next cart order: the counter's scope (created on first use) and the\n * current time in ms, or one above the highest sequence any tab of the shop\n * handed out when that is higher (two changes in the same millisecond, or a\n * clock set back).\n */\nfunction nextCartOrder(storeSlug: string): CartOrder {\n const stored = readCartCounter(storeSlug);\n const scope = stored?.scope ?? lastCartOrder?.scope ?? createClaimToken();\n const floor = Math.max(stored?.seq ?? 0, lastCartOrder?.scope === scope ? lastCartOrder.seq : 0);\n const order: CartOrder = { scope, seq: Math.max(Date.now(), floor + 1) };\n lastCartOrder = order;\n setItem(cartSequenceKey(storeSlug), order);\n return order;\n}\n\ntype CartSequenceLocks = {\n request(name: string, callback: () => CartOrder): Promise<CartOrder>;\n};\n\nfunction cartSequenceLocks(): CartSequenceLocks | null {\n if (typeof navigator === 'undefined') return null;\n const locks = (navigator as { locks?: CartSequenceLocks }).locks;\n return locks && typeof locks.request === 'function' ? locks : null;\n}\n\n/**\n * Reserves the order of a cart state when it is reported to the SDK, not when\n * it is sent, so a state that waited in a queue cannot overtake a newer one\n * reported meanwhile in another tab.\n *\n * The read-increment-write of the shared counter runs under a Web Lock, so two\n * tabs never hand out the same sequence or create two scopes: the server\n * ignores an equal sequence, and does not compare different scopes. Distinct\n * sequences are enough, whichever tab gets the higher one: the tab that\n * reported the older cart receives the newer one as a `storage` echo, reports\n * it with a later sequence, and that is not skipped while the server holds the\n * older cart. Grants follow request order, so this tab's own sequences keep\n * call order.\n *\n * Without Web Locks (browsers before 2022, opaque origins) the counter is\n * updated without the lock: two tabs reporting within the same millisecond can\n * then share a sequence (the server keeps the one that arrives first), and two\n * first-use tabs can create two scopes (the last write wins).\n */\nfunction reserveCartOrder(storeSlug: string): Promise<CartOrder> {\n const take = (): CartOrder => nextCartOrder(storeSlug);\n const locks = cartSequenceLocks();\n if (!locks) return Promise.resolve(take());\n return locks.request(cartSequenceKey(storeSlug), take).catch(take);\n}\n\nfunction readConfirmedCart(storeSlug: string): ReportedCart | null {\n const confirmed = getItem<ReportedCart>(confirmedCartKey(storeSlug));\n if (!confirmed || typeof confirmed.snapshot !== 'string' || !isCartSequence(confirmed.seq)) return null;\n return confirmed;\n}\n\nfunction readInFlightCart(storeSlug: string): InFlightCart | null {\n const claim = getItem<InFlightCart>(inFlightCartKey(storeSlug));\n if (\n !claim\n || typeof claim.snapshot !== 'string'\n || !isCartSequence(claim.seq)\n || typeof claim.token !== 'string'\n || typeof claim.at !== 'number'\n ) {\n return null;\n }\n return claim;\n}\n\n/**\n * Whether the server holds this cart state, or will once the send in flight\n * lands: the in-flight state when some tab is sending one with a higher\n * sequence than the confirmed state (the server keeps the higher one), else\n * the confirmed state. So a cross-tab echo of a state being sent is skipped,\n * and a revert to the confirmed state while another tab sends a newer state\n * still goes out.\n */\nfunction isCartReportedOrInFlight(storeSlug: string, snapshot: string): boolean {\n const confirmed = readConfirmedCart(storeSlug);\n const claim = readInFlightCart(storeSlug);\n const liveClaim = claim && Date.now() - claim.at < CART_CLAIM_TTL_MS ? claim : null;\n const expected = liveClaim && (!confirmed || liveClaim.seq > confirmed.seq) ? liveClaim : confirmed;\n return expected?.snapshot === snapshot;\n}\n\nfunction createClaimToken(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') return crypto.randomUUID();\n return `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`;\n}\n\n/**\n * Claims a cart state for the duration of one send. When the send ends,\n * `settle(delivered)` confirms the state if it was delivered and its sequence\n * is above the confirmed one (a delivered older state was ignored by the\n * server), and clears the claim while it is still this send's.\n */\nfunction claimCartReport(\n storeSlug: string,\n seq: number,\n cartValue?: number,\n itemCount?: number,\n): (delivered: boolean) => void {\n const snapshot = cartSnapshot(cartValue, itemCount);\n const token = createClaimToken();\n setItem<InFlightCart>(inFlightCartKey(storeSlug), { snapshot, seq, token, at: Date.now() });\n return (delivered) => {\n if (delivered) {\n const confirmed = readConfirmedCart(storeSlug);\n if (!confirmed || seq > confirmed.seq) setItem<ReportedCart>(confirmedCartKey(storeSlug), { snapshot, seq });\n }\n if (readInFlightCart(storeSlug)?.token === token) removeItem(inFlightCartKey(storeSlug));\n };\n}\n\n// Cart-carrying pings of this tab go out one at a time. The server orders cart\n// states by sequence, so this queue is not what keeps the order: it coalesces.\n// A cart change that waited while a newer one was asked for is dropped (only\n// the newest cart state is worth sending), and a change is checked against the\n// shared state when its turn comes, after this tab's earlier send settled.\n// Page views are never dropped.\nlet cartSendTail: Promise<void> = Promise.resolve();\nlet latestCartRequest = 0;\n\nfunction enqueueCartSend(send: (isLatest: () => boolean) => Promise<void>): Promise<void> {\n const request = ++latestCartRequest;\n const run = () => send(() => request === latestCartRequest);\n cartSendTail = cartSendTail.then(run, run);\n return cartSendTail;\n}\n\nasync function postPing(body: Record<string, unknown>): Promise<boolean> {\n const config = getConfig();\n const controller = typeof AbortController === 'undefined' ? undefined : new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timedOut = new Promise<false>((resolve) => {\n timer = setTimeout(() => {\n controller?.abort();\n resolve(false);\n }, CART_CLAIM_TTL_MS);\n });\n try {\n const endpoint = buildEndpoint('/v1/storefront/shops/:storeSlug/ping', {\n storeSlug: config.storeSlug,\n });\n const delivered = fetch(`${config.apiBaseUrl}${endpoint}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: controller?.signal,\n }).then((response) => response.ok);\n return await Promise.race([delivered, timedOut]);\n } catch {\n // Intentionally silent - analytics should never block the user experience\n return false;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Counts a page view. Call it once per page load or client-side navigation.\n * Passing the cart also records it for the live visitor map.\n */\nexport async function trackPageView(cartValue?: number, itemCount?: number): Promise<void> {\n if (!isInitialized()) return;\n if (typeof document === 'undefined') return;\n const config = getConfig();\n const carriesCart = cartValue !== undefined || itemCount !== undefined;\n const reservedOrder = carriesCart ? reserveCartOrder(config.storeSlug) : undefined;\n // Code storefronts: the edge-injected tracker already counted this view. It\n // never knows the cart, so the cart still goes out, as cart activity that\n // does not count a second view. Sent on every page load, like a view.\n if (isPlatformPageTrackerActive()) {\n if (reservedOrder) await enqueueCartSend(async () => sendCartActivity(await reservedOrder, cartValue, itemCount));\n return;\n }\n\n const sendView = async (): Promise<void> => {\n const order = reservedOrder ? await reservedOrder : undefined;\n const settle = order ? claimCartReport(config.storeSlug, order.seq, cartValue, itemCount) : undefined;\n const sessionId = analyticsSessionId(config.storeSlug, { touch: true });\n // The page before belongs to the session it was viewed in, which 30 idle\n // minutes may have ended: its time goes there, not into the new session.\n const previousSession = currentPageSession();\n if (previousSession && previousSession !== sessionId) reportPageLeave();\n markPageViewed(sessionId);\n if (sessionId) installEngagedClock(reportPageLeave);\n onAnalyticsConsent(startSessionOnConsent);\n const delivered = await postPing({\n referer: document.referrer || undefined,\n cart_value: cartValue,\n item_count: itemCount,\n cart_seq: order?.seq,\n cart_seq_scope: order?.scope,\n session_id: sessionId ?? undefined,\n // Time on screen of the page before this one (client-side navigation).\n engaged_ms: sessionId ? takeEngagedMs() || undefined : undefined,\n path: resolveStorefrontPagePath(),\n utm: resolveUtmParameters(config.storeSlug),\n });\n settle?.(delivered);\n };\n // A view with a cart takes its place in the cart queue; one without a cart\n // has nothing to coalesce with and goes out at once.\n await (reservedOrder ? enqueueCartSend(sendView) : sendView());\n}\n\n/**\n * Reports a cart change for the live visitor map without counting a page view\n * (`event_type: 'presence'`). Use it when the cart changes on a page that was\n * already counted. A cart state the server holds, or will hold once a send in\n * flight lands, is not sent again, so a cross-tab `storage` echo of a change is\n * not a second ping. A failed send leaves nothing behind: the same state goes\n * out again on the next change or page load.\n *\n * The sequence is taken at call time; the check runs when the change's turn\n * comes, after this tab's earlier sends settled: a revert to the confirmed\n * cart while another state is on the wire must still go out.\n */\nexport async function trackCartActivity(cartValue: number, itemCount: number): Promise<void> {\n if (!isInitialized()) return;\n if (typeof document === 'undefined') return;\n const snapshot = cartSnapshot(cartValue, itemCount);\n const reservedOrder = reserveCartOrder(getConfig().storeSlug);\n await enqueueCartSend(async (isLatest) => {\n const order = await reservedOrder;\n // A newer change may have been asked for meanwhile, or this state may have\n // been confirmed or claimed by then (by this tab or another).\n if (!isLatest() || isCartReportedOrInFlight(getConfig().storeSlug, snapshot)) return;\n await sendCartActivity(order, cartValue, itemCount);\n });\n}\n\nasync function sendCartActivity(order: CartOrder, cartValue?: number, itemCount?: number): Promise<void> {\n const config = getConfig();\n const settle = claimCartReport(config.storeSlug, order.seq, cartValue, itemCount);\n const delivered = await postPing({\n event_type: 'presence',\n cart_value: cartValue,\n item_count: itemCount,\n cart_seq: order.seq,\n cart_seq_scope: order.scope,\n // A cart marks the analytics session as one that did not bounce.\n session_id: analyticsSessionId(config.storeSlug, { touch: false }) ?? undefined,\n path: resolveStorefrontPagePath(),\n });\n settle(delivered);\n}\n\n/**\n * Counts that this visit opened a product. A `/product/{slug}` page needs no\n * call: the server finds its product from the path. Call it on a product page\n * with another path (a code storefront route of your own); the server keeps\n * the product only when the shop owns it. Not a page view.\n */\nexport async function trackProductView(productId: string): Promise<void> {\n if (!isInitialized() || typeof document === 'undefined' || !productId) return;\n await sendVisitEvent({ event_type: 'product_view', product_id: productId });\n}\n\n/**\n * Counts an item put in the cart (add to cart and Buy Now) for the funnel's\n * \"Added to cart\" step. Sent on code storefronts too: the platform page\n * tracker counts pages, never carts. Called by the cart module.\n */\nexport async function trackCartAdd(productId: string, variantId: string, quantity: number): Promise<void> {\n if (!isInitialized() || typeof document === 'undefined' || quantity < 1) return;\n await sendVisitEvent({ event_type: 'cart_add', product_id: productId, variant_id: variantId, quantity });\n}\n\nasync function sendVisitEvent(body: Record<string, unknown>): Promise<void> {\n const config = getConfig();\n // A preview page (an unpublished draft) is no visit: its views and carts stay out of the funnel.\n if (config.preview) return;\n // A visit can end while the buyer sits on a page: the referrer and campaign\n // let the server start the next one with its source. The event keeps the\n // server visit alive or starts it, so it does the same to the session: a\n // checkout after 30 idle minutes then credits the visit of this cart add,\n // not the one before it.\n await postPing({\n ...body,\n referer: document.referrer || undefined,\n session_id: analyticsSessionId(config.storeSlug, { touch: true }) ?? undefined,\n path: resolveStorefrontPagePath(),\n utm: resolveUtmParameters(config.storeSlug),\n });\n}\n\n/**\n * A yes on the cookie banner comes without a reload. On a page already\n * counted cookieless, it starts the analytics session at once\n * (`session_start`: no second page view), so a checkout from this page is\n * linked to the visit.\n */\nfunction startSessionOnConsent(): void {\n const config = getConfig();\n if (!isPageViewed() || analyticsSessionId(config.storeSlug, { touch: false })) return;\n const sessionId = analyticsSessionId(config.storeSlug, { touch: true });\n if (!sessionId) return;\n markPageViewed(sessionId);\n installEngagedClock(reportPageLeave);\n void postPing({\n event_type: 'session_start',\n referer: document.referrer || undefined,\n session_id: sessionId,\n path: resolveStorefrontPagePath(),\n utm: resolveUtmParameters(config.storeSlug),\n });\n}\n\n/**\n * Sends the time on screen of this page when the tab is hidden or left\n * (`page_leave`), to the session the page was viewed in. keepalive lets the\n * request outlive the page. Only with an analytics yes; nothing goes out when\n * there is no time to report.\n */\nfunction reportPageLeave(): void {\n const config = getConfig();\n const sessionId = currentPageSession();\n const engagedMs = takeEngagedMs();\n if (!sessionId || engagedMs === 0 || readAnalyticsConsent() !== 'granted') return;\n try {\n const endpoint = buildEndpoint('/v1/storefront/shops/:storeSlug/ping', { storeSlug: config.storeSlug });\n void fetch(`${config.apiBaseUrl}${endpoint}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ event_type: 'page_leave', session_id: sessionId, engaged_ms: engagedMs }),\n keepalive: true,\n }).catch(() => {});\n } catch {\n // Analytics never breaks the page.\n }\n}\n","import type { CartAddon, CartItem } from '../types/cart';\n\nfunction hashString(value: string): string {\n let hash = 2166136261;\n for (let i = 0; i < value.length; i += 1) {\n hash ^= value.charCodeAt(i);\n hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);\n }\n return (hash >>> 0).toString(16);\n}\n\nfunction normalizeAddons(addons: CartAddon[] | undefined): CartAddon[] {\n if (!addons?.length) return [];\n return [...addons]\n .map((addon) => ({ id: addon.id, quantity: addon.quantity ?? 1 }))\n .sort((a, b) => a.id.localeCompare(b.id));\n}\n\nfunction normalizeCustomFields(fields: Record<string, string> | undefined): Record<string, string> {\n if (!fields) return {};\n const entries = Object.entries(fields)\n .filter(([, value]) => typeof value === 'string')\n .sort(([a], [b]) => a.localeCompare(b));\n return Object.fromEntries(entries);\n}\n\nexport type CartLineIdentityInput = Pick<\n CartItem,\n 'product_id' | 'variant_id' | 'price_variant_id' | 'addons' | 'custom_fields' | 'price_data' | 'pay_what_you_want_price'\n>;\n\nexport function computeCartLineId(input: CartLineIdentityInput): string {\n const payload = {\n product_id: input.product_id,\n variant_id: input.variant_id,\n price_variant_id: input.price_variant_id ?? null,\n addons: normalizeAddons(input.addons),\n custom_fields: normalizeCustomFields(input.custom_fields),\n unit_price:\n typeof input.price_data?.unit_price === 'number' && Number.isFinite(input.price_data.unit_price)\n ? input.price_data.unit_price\n : null,\n pay_what_you_want_price:\n typeof input.pay_what_you_want_price === 'number' && Number.isFinite(input.pay_what_you_want_price)\n ? input.pay_what_you_want_price\n : null,\n };\n return hashString(JSON.stringify(payload));\n}\n\nexport function ensureCartLineId(item: CartItem): CartItem {\n if (typeof item.line_id === 'string' && item.line_id.trim()) {\n return item;\n }\n return { ...item, line_id: computeCartLineId(item) };\n}\n","/**\n * Catalog unit prices support mills (one thousandth of a currency unit).\n *\n * This is intentionally separate from invoice and payment totals. A unit can\n * cost $0.012, while the payable line total is still rounded to the currency's\n * minor unit after `unit price × quantity`.\n */\nexport const CATALOG_UNIT_PRICE_DECIMAL_PLACES = 3;\n\n/**\n * Payable line amounts and invoice totals remain cent amounts. This is a\n * separate boundary from catalog unit prices: multiply the mill-priced unit by\n * quantity first, then round the resulting line amount to this precision.\n */\nexport const PAYABLE_AMOUNT_DECIMAL_PLACES = 2;\n\nexport const CATALOG_UNIT_PRICE_FORMAT_OPTIONS = {\n maximumFractionDigits: CATALOG_UNIT_PRICE_DECIMAL_PLACES,\n} as const;\n\n/**\n * Browser-safe half-up rounding for non-negative payable amounts.\n *\n * The exponent shift avoids the common `1.005 * 100` binary-float trap and\n * mirrors the backend's decimal.js ROUND_HALF_UP policy. Negative values are\n * handled symmetrically so the helper remains safe for display calculations.\n */\nexport function roundPayableAmount(value: number): number {\n if (!Number.isFinite(value)) return value;\n\n const sign = value < 0 ? -1 : 1;\n const shifted = shiftDecimal(Math.abs(value), PAYABLE_AMOUNT_DECIMAL_PLACES);\n const rounded = Math.round(shifted);\n if (rounded === 0) return 0;\n return sign * shiftDecimal(rounded, -PAYABLE_AMOUNT_DECIMAL_PLACES);\n}\n\nfunction shiftDecimal(value: number, places: number): number {\n const [coefficient, currentExponent = '0'] = String(value).split('e');\n return Number(`${coefficient}e${Number(currentExponent) + places}`);\n}\n\nfunction countSignificantDecimalPlaces(value: string | number): number | null {\n const source = String(value).trim();\n const match = source.match(/^[-+]?(\\d+)(?:\\.(\\d*))?(?:e([-+]?\\d+))?$/i)\n ?? source.match(/^[-+]?\\.(\\d+)(?:e([-+]?\\d+))?$/i);\n if (!match) return null;\n\n const startsWithDecimalPoint = /^[-+]?\\./.test(source);\n const integerPart = startsWithDecimalPoint ? '0' : match[1];\n const fractionPart = startsWithDecimalPoint ? match[1] : (match[2] ?? '');\n const exponentText = startsWithDecimalPoint ? match[2] : match[3];\n const exponent = Number(exponentText ?? 0);\n if (!Number.isInteger(exponent)) return null;\n\n const digitsWithoutInsignificantZeros = `${integerPart}${fractionPart}`.replace(/0+$/, '');\n if (digitsWithoutInsignificantZeros.length === 0) return 0;\n\n const decimalPoint = integerPart.length + exponent;\n return Math.max(0, digitsWithoutInsignificantZeros.length - decimalPoint);\n}\n\nexport function hasCatalogUnitPricePrecision(value: string | number): boolean {\n const decimalPlaces = countSignificantDecimalPlaces(value);\n return decimalPlaces !== null && decimalPlaces <= CATALOG_UNIT_PRICE_DECIMAL_PLACES;\n}\n\nexport function getCatalogUnitPricePrecisionMessage(value: string | number): string {\n return `Price supports at most ${CATALOG_UNIT_PRICE_DECIMAL_PLACES} decimal places; received ${String(value)}.`;\n}\n","/**\n * Cart Module\n *\n * localStorage-based cart with support for Shoppex features:\n * - Addons (express shipping, gift wrap, etc.)\n * - Custom Fields (engraving, gift message, etc.)\n * - Price Variants (different pricing tiers)\n */\n\nimport { getItem, setItem, removeItem, type StorageArea } from '../utils/storage';\nimport { getConfig } from '../core/config';\nimport { post } from '../core/client';\nimport { CartError } from '../core/errors';\nimport type {\n CartItem,\n CartAddOptions,\n CartItemUpdate,\n CartPayload,\n CartMetadata,\n CartStats,\n CartQuote,\n CartBasketMergeLine,\n CartCodeSource,\n} from '../types';\nimport { getAffiliateCode, trackAffiliateEvent } from './affiliates';\nimport { trackCartAdd } from './analytics';\nimport { computeCartLineId, ensureCartLineId } from '../utils/cart-line-id';\nimport {\n normalizeRequestedCurrency,\n resolveBuyerCurrency,\n} from '../utils/requested-currency';\nimport { roundPayableAmount } from '@shoppex/contracts/catalog-unit-price';\n\nconst STORAGE_KEYS = {\n cart: 'cart',\n cartBackup: 'cart_backup',\n meta: 'cart_meta',\n metaBackup: 'cart_backup_meta',\n coupon: 'cart_coupon',\n couponBackup: 'cart_coupon_backup',\n} as const;\n\ntype StorageKeyType = keyof typeof STORAGE_KEYS;\n\nfunction getStorageKey(type: StorageKeyType): string {\n return `${STORAGE_KEYS[type]}_${getConfig().storeSlug}`;\n}\n\n// A preview-link page (an unpublished draft) keeps its own cart in this tab\n// only: trying the draft never reads or writes the buyer's live cart, in this\n// tab or another. Its keys carry the preview namespace of every storefront\n// storage key (utils/storage).\nfunction cartStorageArea(): StorageArea {\n return getConfig().preview ? 'sessionStorage' : 'localStorage';\n}\n\nfunction readCartStorage<T>(type: StorageKeyType): T | null {\n return getItem<T>(getStorageKey(type), cartStorageArea());\n}\n\nfunction writeCartStorage<T>(type: StorageKeyType, value: T): void {\n setItem(getStorageKey(type), value, cartStorageArea());\n}\n\nfunction removeCartStorage(type: StorageKeyType): void {\n removeItem(getStorageKey(type), cartStorageArea());\n}\n\nfunction hashString(value: string): string {\n let hash = 2166136261;\n for (let i = 0; i < value.length; i += 1) {\n hash ^= value.charCodeAt(i);\n hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);\n }\n return (hash >>> 0).toString(16);\n}\n\nfunction computeChecksum(cart: CartItem[]): string {\n return hashString(JSON.stringify(cart));\n}\n\nfunction normalizeQuantity(value: number): number {\n if (!Number.isFinite(value)) {\n throw new CartError('quantity must be a finite number');\n }\n return Math.floor(value);\n}\n\nfunction normalizeCouponCode(value: string | null | undefined): string | null {\n const normalized = value?.trim().toUpperCase();\n return normalized ? normalized : null;\n}\n\ntype StoredCartCode = {\n code: string;\n source: CartCodeSource;\n};\n\nfunction getStoredCartCode(): StoredCartCode | null {\n const raw = readCartStorage<unknown>('coupon');\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n return null;\n }\n const record = raw as Record<string, unknown>;\n const code = typeof record.code === 'string' ? normalizeCouponCode(record.code) : null;\n const source = record.source === 'COUPON' || record.source === 'AFFILIATE'\n ? record.source\n : null;\n return code && source ? { code, source } : null;\n}\n\nfunction normalizeCartItems(value: unknown): CartItem[] {\n if (!Array.isArray(value)) return [];\n const normalized: CartItem[] = [];\n for (const entry of value) {\n if (!entry || typeof entry !== 'object') continue;\n const record = entry as Record<string, unknown>;\n const productId = typeof record.product_id === 'string' ? record.product_id.trim() : '';\n const variantId = typeof record.variant_id === 'string' ? record.variant_id.trim() : '';\n const quantity = Number(record.quantity);\n\n if (!productId || !variantId || !Number.isFinite(quantity) || quantity < 1) {\n continue;\n }\n\n const item: CartItem = {\n line_id: '',\n product_id: productId,\n variant_id: variantId,\n quantity: Math.floor(quantity),\n };\n\n if (typeof record.price_variant_id === 'string') {\n item.price_variant_id = record.price_variant_id;\n }\n if (record.price_data && typeof record.price_data === 'object') {\n const priceData = record.price_data as Record<string, unknown>;\n if (typeof priceData.unit_price === 'number' && Number.isFinite(priceData.unit_price)) {\n item.price_data = { unit_price: priceData.unit_price };\n }\n }\n if (typeof record.pay_what_you_want_price === 'number' && Number.isFinite(record.pay_what_you_want_price)) {\n item.pay_what_you_want_price = record.pay_what_you_want_price;\n }\n if (Array.isArray(record.addons)) {\n item.addons = record.addons as CartItem['addons'];\n }\n if (record.custom_fields && typeof record.custom_fields === 'object' && !Array.isArray(record.custom_fields)) {\n item.custom_fields = record.custom_fields as Record<string, string>;\n }\n\n // Preserve the optional display snapshot (title/variant_title/image_url/addon_labels) across the\n // localStorage round-trip so the njk cart drawer/page can render without a product fetch.\n if (typeof record.title === 'string') {\n item.title = record.title;\n }\n if (typeof record.variant_title === 'string') {\n item.variant_title = record.variant_title;\n }\n if (typeof record.image_url === 'string') {\n item.image_url = record.image_url;\n }\n if (Array.isArray(record.addon_labels)) {\n item.addon_labels = record.addon_labels.filter((label): label is string => typeof label === 'string');\n }\n if (typeof record.max_quantity === 'number' && Number.isFinite(record.max_quantity)) {\n item.max_quantity = record.max_quantity;\n }\n if (typeof record.min_quantity === 'number' && Number.isFinite(record.min_quantity)) {\n item.min_quantity = record.min_quantity;\n }\n\n // Self-heal on READ: clamp quantity to the stored [min,max] here, after the bounds are read. This is\n // the single chokepoint every access flows through (getCart -> getCartPayload -> serializeCart/\n // quoteCart -> checkout), so a stale/tampered/restored localStorage line can never reach checkout\n // out of bounds — closing restoreCartFromBackup and direct-localStorage-edit at the root, not just\n // the write paths.\n clampQuantityToBounds(item);\n\n const storedLineId = typeof record.line_id === 'string' ? record.line_id.trim() : '';\n item.line_id = storedLineId || computeCartLineId(item);\n\n normalized.push(ensureCartLineId(item));\n }\n return normalized;\n}\n\nfunction getCartMetadata(): CartMetadata | null {\n return readCartStorage<CartMetadata>('meta');\n}\n\nexport function getCartCoupon(): string | null {\n return getStoredCartCode()?.code ?? null;\n}\n\nexport function getCartCouponSource(): CartCodeSource | null {\n return getStoredCartCode()?.source ?? null;\n}\n\nexport function setCartCoupon(\n coupon: string | null | undefined,\n source: CartCodeSource = 'COUPON',\n): string | null {\n const normalizedCoupon = normalizeCouponCode(coupon);\n if (!normalizedCoupon) {\n removeCartStorage('coupon');\n return null;\n }\n\n writeCartStorage('coupon', { code: normalizedCoupon, source });\n return normalizedCoupon;\n}\n\nexport function clearCartCoupon(): void {\n removeCartStorage('coupon');\n}\n\nfunction writeCart(cart: CartItem[]): void {\n const normalizedCart = normalizeCartItems(cart);\n writeCartStorage('cart', normalizedCart);\n const now = Date.now();\n const previous = getCartMetadata();\n const nextMeta: CartMetadata = {\n created_at: previous?.created_at ?? now,\n last_modified: now,\n version: (previous?.version ?? 0) + 1,\n checksum: computeChecksum(normalizedCart),\n };\n writeCartStorage('meta', nextMeta);\n\n if (normalizedCart.length === 0) {\n clearCartCoupon();\n }\n}\n\nfunction setCartWithMetadata(cart: CartItem[], metadata?: CartMetadata | null): void {\n const normalizedCart = normalizeCartItems(cart);\n writeCartStorage('cart', normalizedCart);\n const now = Date.now();\n const base = metadata ?? getCartMetadata();\n const nextMeta: CartMetadata = {\n created_at: base?.created_at ?? now,\n last_modified: now,\n version: base?.version ?? 1,\n checksum: computeChecksum(normalizedCart),\n };\n writeCartStorage('meta', nextMeta);\n}\n\nexport function getCart(): CartItem[] {\n const raw = readCartStorage<unknown>('cart');\n return normalizeCartItems(raw);\n}\n\n/** Resolve a cart line_id for product+variant. When multiple configs exist, returns the first line. */\nexport function resolveCartLineId(\n productId: string,\n variantId: string,\n cart: CartItem[] = getCart(),\n): string {\n const matches = cart.filter(\n (item) => item.product_id === productId && item.variant_id === variantId,\n );\n if (matches.length === 0) {\n throw new CartError(`No cart line found for ${productId}/${variantId}`);\n }\n return matches[0].line_id;\n}\n\nexport function getCartItemCount(): number {\n const cart = getCart();\n return cart.reduce((sum, item) => sum + item.quantity, 0);\n}\n\nexport function addToCart(\n productId: string,\n variantId: string,\n quantity: number = 1,\n options?: CartAddOptions\n): void {\n if (!productId || !variantId) {\n throw new CartError('product_id and variant_id are required');\n }\n\n const normalizedQuantity = normalizeQuantity(quantity);\n if (normalizedQuantity < 1) {\n throw new CartError('quantity must be at least 1');\n }\n\n const cart = getCart();\n\n const lineId = computeCartLineId({\n product_id: productId,\n variant_id: variantId,\n addons: options?.addons,\n custom_fields: options?.custom_fields,\n price_variant_id: options?.price_variant_id,\n price_data: options?.price_data,\n pay_what_you_want_price: options?.pay_what_you_want_price,\n });\n\n const existingIndex = cart.findIndex((item) => item.line_id === lineId);\n const quantityBeforeAdd = existingIndex >= 0 ? cart[existingIndex].quantity : 0;\n\n if (existingIndex >= 0) {\n cart[existingIndex].quantity += normalizedQuantity;\n\n if (options?.addons) {\n cart[existingIndex].addons = options.addons;\n }\n if (options?.custom_fields) {\n cart[existingIndex].custom_fields = options.custom_fields;\n }\n if (options?.price_variant_id) {\n cart[existingIndex].price_variant_id = options.price_variant_id;\n }\n if (options?.price_data) {\n cart[existingIndex].price_data = options.price_data;\n }\n if (options?.pay_what_you_want_price !== undefined) {\n cart[existingIndex].pay_what_you_want_price = options.pay_what_you_want_price;\n }\n applyDisplaySnapshot(cart[existingIndex], options);\n clampQuantityToBounds(cart[existingIndex]);\n } else {\n const pushed: CartItem = {\n line_id: lineId,\n product_id: productId,\n variant_id: variantId,\n quantity: normalizedQuantity,\n addons: options?.addons,\n custom_fields: options?.custom_fields,\n price_variant_id: options?.price_variant_id,\n price_data: options?.price_data,\n pay_what_you_want_price: options?.pay_what_you_want_price,\n title: options?.title,\n variant_title: options?.variant_title,\n image_url: options?.image_url,\n addon_labels: options?.addon_labels,\n max_quantity: options?.max_quantity,\n min_quantity: options?.min_quantity,\n };\n clampQuantityToBounds(pushed);\n cart.push(pushed);\n }\n\n const intendedQuantity = (existingIndex >= 0 ? cart[existingIndex] : cart[cart.length - 1]).quantity;\n writeCart(cart);\n // The storage wrapper swallows quota/availability failures, and the cart\n // and metadata writes can fail independently, so the funnel event is gated\n // on the LINE itself: the post-clamp quantity actually grew (a clamped\n // max-quantity no-op did not add anything) AND that exact quantity is\n // readable back from storage (the write of the cart payload landed).\n const persistedLine = getCart().find((item) => item.line_id === lineId);\n if (intendedQuantity > quantityBeforeAdd && persistedLine?.quantity === intendedQuantity) {\n // Attribute like checkout() does: a code applied to the cart (AFFILIATE\n // coupon source) outranks the ambient stored referral.\n const cartAffiliateCode = getCartCouponSource() === 'AFFILIATE' ? getCartCoupon() : null;\n void trackAffiliateEvent('add_to_cart', cartAffiliateCode ? { code: cartAffiliateCode } : undefined);\n void trackCartAdd(productId, variantId, intendedQuantity - quantityBeforeAdd);\n }\n}\n\n// Cart-wide invariant: a line's quantity must stay within its stored [min_quantity, max_quantity]\n// bounds. Every write path routes through this — addToCart (merge+push), setCartItem (merge+push),\n// updateCartItem, mergeBaskets (merge+push), moveBasketItem (merge+push) — AND, crucially, the READ\n// path normalizeCartItems (getCart) clamps too, so a stale/tampered/restored localStorage line is\n// self-healed before it can reach checkout. No entrypoint can persist or serve a quantity outside the\n// purchasable range the backend would reject.\n// Order matters: apply min FIRST, then max — so on the degenerate min>max case (e.g. quantity_min 2 but\n// only 1 in stock) MAX wins and the line is never pushed above the stock cap (over-stock is the harder\n// backend reject than under-min). Never below 1. No-op for the bound(s) that are absent.\nfunction clampQuantityToBounds(item: CartItem): void {\n const min = item.min_quantity;\n if (typeof min === 'number' && Number.isFinite(min) && item.quantity < min) {\n item.quantity = Math.floor(min);\n }\n const max = item.max_quantity;\n if (typeof max === 'number' && Number.isFinite(max) && item.quantity > max) {\n item.quantity = Math.floor(max);\n }\n if (item.quantity < 1) {\n item.quantity = 1;\n }\n}\n\n// Copy the optional display snapshot fields from add-options onto an existing line. Display-only —\n// kept separate from the pricing/identity fields so the snapshot logic is identical for add and set.\nfunction applyDisplaySnapshot(item: CartItem, options?: CartAddOptions): void {\n // Authoritative full re-snapshot (buy-box producer): replace ALL display fields verbatim, including\n // CLEARING ones the new snapshot omits — a removed add-on or a lifted cap must not leave stale data.\n if (options?.replace_display_snapshot) {\n item.title = options.title;\n item.variant_title = options.variant_title;\n item.image_url = options.image_url;\n item.addon_labels = options.addon_labels;\n item.max_quantity = options.max_quantity;\n item.min_quantity = options.min_quantity;\n return;\n }\n // Partial direct SDK call: only overwrite the fields actually provided.\n if (options?.title !== undefined) {\n item.title = options.title;\n }\n if (options?.variant_title !== undefined) {\n item.variant_title = options.variant_title;\n }\n if (options?.image_url !== undefined) {\n item.image_url = options.image_url;\n }\n if (options?.addon_labels !== undefined) {\n item.addon_labels = options.addon_labels;\n }\n if (options?.max_quantity !== undefined) {\n item.max_quantity = options.max_quantity;\n }\n if (options?.min_quantity !== undefined) {\n item.min_quantity = options.min_quantity;\n }\n}\n\nexport function setCartItem(\n productId: string,\n variantId: string,\n quantity: number = 1,\n options?: CartAddOptions\n): void {\n if (!productId || !variantId) {\n throw new CartError('product_id and variant_id are required');\n }\n\n const normalizedQuantity = normalizeQuantity(quantity);\n if (normalizedQuantity < 1) {\n throw new CartError('quantity must be at least 1');\n }\n\n const cart = getCart();\n const lineId = computeCartLineId({\n product_id: productId,\n variant_id: variantId,\n addons: options?.addons,\n custom_fields: options?.custom_fields,\n price_variant_id: options?.price_variant_id,\n price_data: options?.price_data,\n pay_what_you_want_price: options?.pay_what_you_want_price,\n });\n\n // Buy-now / replace semantics: one visible line per (product_id, variant_id). Drop any prior\n // line_ids for that pair so a config change (addons, price_data) does not leave a stale sibling.\n for (let index = cart.length - 1; index >= 0; index -= 1) {\n if (cart[index].product_id === productId && cart[index].variant_id === variantId) {\n cart.splice(index, 1);\n }\n }\n\n const pushed: CartItem = {\n line_id: lineId,\n product_id: productId,\n variant_id: variantId,\n quantity: normalizedQuantity,\n addons: options?.addons,\n custom_fields: options?.custom_fields,\n price_variant_id: options?.price_variant_id,\n price_data: options?.price_data,\n pay_what_you_want_price: options?.pay_what_you_want_price,\n title: options?.title,\n variant_title: options?.variant_title,\n image_url: options?.image_url,\n addon_labels: options?.addon_labels,\n max_quantity: options?.max_quantity,\n min_quantity: options?.min_quantity,\n };\n clampQuantityToBounds(pushed);\n cart.push(pushed);\n\n writeCart(cart);\n // Buy Now: the funnel counts the item as added, gated on the write landing like addToCart.\n const persistedLine = getCart().find((item) => item.line_id === lineId);\n if (persistedLine) void trackCartAdd(productId, variantId, persistedLine.quantity);\n}\n\n/**\n * Patch one cart line.\n *\n * TRI-STATE BOUNDS: `min_quantity`/`max_quantity` accept `null` to DELETE the\n * stored bound — see {@link CartItemUpdate}. `undefined` (or an absent key)\n * leaves it alone, which is why a removed ceiling needs its own spelling.\n *\n * NO-OP UPDATES DO NOT WRITE. An update that leaves the cart byte-identical\n * returns without touching storage: no metadata bump, no `version` increment,\n * and — because the storage write is what other tabs observe — no `storage`\n * event. Writing anyway made an ineffective heal indistinguishable from a real\n * cart change, and two tabs healing the same line could hand the event back and\n * forth indefinitely. Line-shape healing of a legacy stored row is NOT this\n * function's job: `normalizeCartItems` clamps and repairs on every READ, which\n * is the chokepoint every access already flows through.\n */\nexport function updateCartItem(\n lineId: string,\n updates: CartItemUpdate\n): void {\n const cart = getCart();\n const normalizedLineId = lineId.trim();\n if (!normalizedLineId) {\n throw new CartError('line_id is required');\n }\n\n const index = cart.findIndex((item) => item.line_id === normalizedLineId);\n\n if (index < 0) {\n throw new CartError('Item not found in cart');\n }\n\n // The exact bytes the result is compared against, taken BEFORE any mutation.\n const before = JSON.stringify(cart);\n\n if (updates.quantity !== undefined) {\n const normalizedQuantity = normalizeQuantity(updates.quantity);\n if (normalizedQuantity < 1) {\n cart.splice(index, 1);\n writeCart(cart);\n return;\n }\n cart[index].quantity = normalizedQuantity;\n }\n\n if (updates.addons !== undefined) {\n cart[index].addons = updates.addons;\n }\n\n if (updates.custom_fields !== undefined) {\n cart[index].custom_fields = updates.custom_fields;\n }\n\n if (updates.price_variant_id !== undefined) {\n cart[index].price_variant_id = updates.price_variant_id;\n }\n if (updates.price_data !== undefined) {\n cart[index].price_data = updates.price_data;\n }\n if (updates.pay_what_you_want_price !== undefined) {\n cart[index].pay_what_you_want_price = updates.pay_what_you_want_price;\n }\n // The option name, restated by a settled quote from the catalog (`CartQuoteLine`).\n if (updates.variant_title !== undefined) {\n if (updates.variant_title === null) delete cart[index].variant_title;\n else cart[index].variant_title = updates.variant_title;\n }\n // Tri-state: `null` is the merchant's bound being REMOVED, and it has to\n // delete the stored key — a bound that can only be raised and lowered but\n // never cleared outlives the limit it describes.\n if (updates.max_quantity !== undefined) {\n if (updates.max_quantity === null) delete cart[index].max_quantity;\n else cart[index].max_quantity = updates.max_quantity;\n }\n if (updates.min_quantity !== undefined) {\n if (updates.min_quantity === null) delete cart[index].min_quantity;\n else cart[index].min_quantity = updates.min_quantity;\n }\n clampQuantityToBounds(cart[index]);\n\n // Pricing and configuration fields are part of a cart line's identity.\n // Recompute after every update and merge if the new identity already exists.\n const nextLineId = computeCartLineId(cart[index]);\n const duplicateIndex = cart.findIndex((item, itemIndex) => itemIndex !== index && item.line_id === nextLineId);\n if (duplicateIndex >= 0) {\n cart[duplicateIndex].quantity += cart[index].quantity;\n clampQuantityToBounds(cart[duplicateIndex]);\n cart.splice(index, 1);\n } else {\n cart[index].line_id = nextLineId;\n }\n\n // Nothing moved: writing would bump `version`/`last_modified` and emit a\n // storage event that says the cart changed when it did not.\n if (JSON.stringify(cart) === before) return;\n\n writeCart(cart);\n}\n\nexport function removeFromCart(lineId: string): void {\n const normalizedLineId = lineId.trim();\n if (!normalizedLineId) {\n throw new CartError('line_id is required');\n }\n\n const cart = getCart();\n const filtered = cart.filter((item) => item.line_id !== normalizedLineId);\n writeCart(filtered);\n}\n\n/**\n * Discards the cart entirely — and with it the proof that describes it.\n *\n * PAYMENT PATH. `latestQuoteToken` is evidence about a specific cart, and this\n * is the one mutation after which that cart does not exist in any form. Held\n * across the clear, the proof outlives its subject: a caller that clears and\n * re-adds (Buy Now REPLACES the cart) hands `/from-cart` a token bound to the\n * previous cart's hash, which is refused as `quote_token_stale` — a hand-off\n * dead-ended by a proof nobody asked for. And with no re-quote in between there\n * is nothing to replace it with, so the retry is refused identically.\n *\n * Only this path clears it. Every OTHER mutation turns one cart into another\n * cart, where a proof that no longer matches is the server's to refuse: it\n * answers `quote_token_stale`, the surfaces re-quote, and the buyer approves the\n * new total. Dropping the proof there instead would silently remove the approved\n * -total ceiling from a checkout that raced the re-quote, which is the failure\n * the token exists to prevent.\n */\nexport function clearCart(): void {\n removeCartStorage('cart');\n removeCartStorage('meta');\n clearCartCoupon();\n clearLatestQuoteToken();\n}\n\nexport function createCartBackup(): void {\n const cart = getCart();\n writeCartStorage('cartBackup', cart);\n const cartCode = getStoredCartCode();\n if (cartCode) {\n writeCartStorage('couponBackup', cartCode);\n } else {\n removeCartStorage('couponBackup');\n }\n const metadata = getCartMetadata();\n if (metadata) {\n writeCartStorage('metaBackup', metadata);\n } else {\n const now = Date.now();\n writeCartStorage('metaBackup', {\n created_at: now,\n last_modified: now,\n version: 1,\n checksum: computeChecksum(cart),\n });\n }\n}\n\nexport function restoreCartFromBackup(): boolean {\n const backupRaw = readCartStorage<unknown>('cartBackup');\n const backup = normalizeCartItems(backupRaw);\n const backupMeta = readCartStorage<CartMetadata>('metaBackup');\n const backupCoupon = readCartStorage<unknown>('couponBackup');\n\n if (backup && backup.length > 0) {\n setCartWithMetadata(backup, backupMeta);\n if (backupCoupon && typeof backupCoupon === 'object' && !Array.isArray(backupCoupon)) {\n const record = backupCoupon as Record<string, unknown>;\n const source = record.source === 'COUPON' || record.source === 'AFFILIATE'\n ? record.source\n : null;\n if (typeof record.code === 'string' && source) {\n setCartCoupon(record.code, source);\n } else {\n clearCartCoupon();\n }\n } else {\n clearCartCoupon();\n }\n return true;\n }\n\n return false;\n}\n\nexport function mergeBaskets(items: CartBasketMergeLine[]): CartItem[] {\n const cart = getCart();\n\n for (const incoming of items) {\n const productId = typeof incoming.product_id === 'string' ? incoming.product_id.trim() : '';\n const variantId = typeof incoming.variant_id === 'string' ? incoming.variant_id.trim() : '';\n if (!productId || !variantId) {\n continue;\n }\n\n let normalizedQuantity: number;\n try {\n normalizedQuantity = normalizeQuantity(incoming.quantity);\n } catch {\n continue;\n }\n\n if (normalizedQuantity < 1) {\n continue;\n }\n\n const mergedLine = ensureCartLineId({\n ...incoming,\n line_id: incoming.line_id ?? computeCartLineId(incoming),\n product_id: productId,\n variant_id: variantId,\n quantity: normalizedQuantity,\n });\n const index = cart.findIndex((item) => item.line_id === mergedLine.line_id);\n\n if (index >= 0) {\n cart[index].quantity = Math.max(cart[index].quantity, normalizedQuantity);\n clampQuantityToBounds(cart[index]);\n } else {\n clampQuantityToBounds(mergedLine);\n cart.push(mergedLine);\n }\n }\n\n writeCart(cart);\n return cart;\n}\n\nexport function moveBasketItem(\n fromProductId: string,\n fromVariantId: string,\n toProductId: string,\n toVariantId: string\n): void {\n const cart = getCart();\n const fromIndex = cart.findIndex(\n (item) => item.product_id === fromProductId && item.variant_id === fromVariantId\n );\n\n if (fromIndex < 0) {\n throw new CartError('Item not found in cart');\n }\n\n const [fromItem] = cart.splice(fromIndex, 1);\n const toLineId = computeCartLineId({\n ...fromItem,\n product_id: toProductId,\n variant_id: toVariantId,\n });\n const toIndex = cart.findIndex((item) => item.line_id === toLineId);\n\n if (toIndex >= 0) {\n cart[toIndex].quantity += fromItem.quantity;\n clampQuantityToBounds(cart[toIndex]);\n } else {\n const moved = ensureCartLineId({\n ...fromItem,\n product_id: toProductId,\n variant_id: toVariantId,\n line_id: toLineId,\n });\n clampQuantityToBounds(moved);\n cart.push(moved);\n }\n\n writeCart(cart);\n}\n\nexport function validateCartIntegrity(): boolean {\n const cart = getCart();\n const metadata = getCartMetadata();\n const checksum = computeChecksum(cart);\n\n if (!metadata) {\n setCartWithMetadata(cart, null);\n return true;\n }\n\n return metadata.checksum === checksum;\n}\n\nexport function getCartStats(): CartStats {\n const cart = getCart();\n const integrityValid = validateCartIntegrity();\n const metadata = getCartMetadata();\n const backup = readCartStorage<CartItem[]>('cartBackup') ?? [];\n const hasCompletePriceSnapshots =\n cart.length > 0 &&\n cart.every((item) => typeof item.price_data?.unit_price === 'number');\n const totalPrice = cart.reduce((sum, item) => {\n const unitPrice = item.price_data?.unit_price ?? 0;\n return sum + roundPayableAmount(unitPrice * item.quantity);\n }, 0);\n\n return {\n item_count: cart.length,\n total_quantity: cart.reduce((sum, item) => sum + item.quantity, 0),\n last_modified: metadata?.last_modified ?? 0,\n version: metadata?.version ?? 0,\n has_backup: backup.length > 0,\n integrity_valid: integrityValid,\n total_price: roundPayableAmount(totalPrice),\n total_price_is_estimate: cart.length > 0 && !hasCompletePriceSnapshots,\n };\n}\n\nexport function getCartPayload(coupon?: string): CartPayload {\n const config = getConfig();\n const normalizedCoupon = normalizeCouponCode(coupon) ?? getCartCoupon() ?? undefined;\n return {\n store_slug: config.storeSlug,\n items: getCart(),\n coupon: normalizedCoupon,\n };\n}\n\n/**\n * The ambient referral code checkout() will submit as `affiliate_code`.\n *\n * Read exactly like checkout()'s normalizeAffiliateCode ambient branch: the\n * referral code the cart itself carries (source `AFFILIATE`) takes precedence\n * over the stored `?ref=` attribution. Sending it with the quote is what makes\n * the displayed total equal the amount the invoice will charge — without it a\n * cart holding both a coupon and a `?ref=` attribution quotes high.\n */\nfunction getAmbientAffiliateCodeForQuote(): string | null {\n const storedCode = getCartCoupon();\n const storedSource = getCartCouponSource();\n if (storedSource === 'AFFILIATE' && storedCode) {\n return storedCode.trim().toLowerCase();\n }\n return getAffiliateCode();\n}\n\n/**\n * The proof from the most recent successful quote, held in memory only.\n *\n * Module-scoped rather than persisted: the token is evidence about a cart as\n * it was priced moments ago, and a stale one from a previous page load is\n * simply ignored by the server. Not exported as public API — `checkout()`\n * reads it, callers do not have to know it exists.\n */\nlet latestQuoteToken: string | null = null;\n\n/**\n * Which quote call the held token belongs to.\n *\n * Quote responses settle in ARRIVAL order, not request order: two overlapping\n * `quoteCart` calls (cart A, then cart A+B) can answer with the OLDER one last,\n * and the token stored is then evidence about a cart the buyer no longer has.\n *\n * That is not a mispricing — `/from-cart` binds the token to a hash of the cart\n * content, currency, shop and submitted codes (`isCartQuoteTokenApplicable`),\n * so a superseded token simply fails to apply and is treated as ABSENT, and the\n * proof is a one-directional CEILING that can never lower a price. What it\n * costs is the ceiling itself: the buyer silently loses the protection for the\n * rest of that checkout. Keeping the newest call's answer is what keeps the\n * proof present for the cart actually on screen.\n */\nlet quoteSequence = 0;\n\n/** @internal — read by checkout(); exported only across module boundaries. */\nexport function getLatestQuoteToken(): string | null {\n return latestQuoteToken;\n}\n\n/** @internal — test seam and cart-reset hook. */\nexport function clearLatestQuoteToken(): void {\n latestQuoteToken = null;\n // A quote already in flight must not resurrect the proof this cleared.\n quoteSequence += 1;\n}\n\nexport async function quoteCart(coupon?: string, currency?: string) {\n const sequence = (quoteSequence += 1);\n const payload = getCartPayload(coupon);\n const normalizedCurrency = normalizeRequestedCurrency(currency)\n ?? resolveBuyerCurrency(getConfig().currency);\n const response = await post<CartQuote>('/v1/storefront/cart/quote', {\n shop_slug: payload.store_slug,\n cart: payload.items,\n coupon: payload.coupon,\n affiliate_code: getAmbientAffiliateCodeForQuote() ?? undefined,\n currency: normalizedCurrency ?? undefined,\n });\n\n // Only a successful quote replaces the held proof — a failed quote must not\n // clear a still-valid one.\n //\n // A SUCCESSFUL quote that carries no token clears it, rather than leaving the\n // previous one in place. The proof is evidence about one specific priced\n // cart, and `/from-cart` refuses a submitted proof it cannot apply\n // (`quote_token_stale` / `_invalid`) instead of ignoring it. So a held token\n // that this quote did not reissue is not a harmless leftover: every later\n // `checkout()` submits it, is refused, and re-quoting never helps because a\n // tokenless answer used to leave it untouched — a dead end the buyer cannot\n // escape from inside the cart.\n //\n // And only the NEWEST call may replace it: a slower earlier quote answering\n // last would otherwise overwrite the current cart's proof with one bound to a\n // cart hash that no longer exists.\n if (sequence !== quoteSequence) return response;\n if (response.success) {\n latestQuoteToken = typeof response.data?.quote_token === 'string'\n ? response.data.quote_token\n : null;\n }\n\n return response;\n}\n\nexport function serializeCart(coupon?: string): string {\n const payload = getCartPayload(coupon);\n const json = JSON.stringify(payload);\n // UTF-8 safe Base64: encodeURIComponent converts to UTF-8, unescape converts percent-encoding to bytes\n if (typeof btoa !== 'undefined') {\n return btoa(unescape(encodeURIComponent(json)));\n }\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(json, 'utf8').toString('base64');\n }\n throw new CartError('Base64 encoding is not available in this environment');\n}\n","/**\n * The storage half of the storefront SDK: init and config, the cart, the\n * quote, coupon and referral storage, referral capture, and page-view and\n * cart-activity tracking.\n *\n * The ThemeDocument commerce runtime (packages/storefront-commerce) carries\n * this object in the script every page loads and fetches the rest of\n * `storefrontSdk` (storefront-sdk.ts, which builds on this object) as its\n * `sdk` chunk on first use. `quoteCart` stays here because it shares its\n * module with the cart and the quote token the checkout hand-off submits;\n * referral capture and page views stay because moving them later would lose\n * a `?ref=` or a bounced view.\n */\n\nimport { initConfig, isInitialized, getConfig } from './core/config';\nimport type { ShoppexInitOptions } from './types';\nimport {\n getCart,\n getCartItemCount,\n getCartCoupon,\n getCartCouponSource,\n setCartCoupon,\n clearCartCoupon,\n addToCart,\n setCartItem,\n updateCartItem,\n removeFromCart,\n clearCart,\n createCartBackup,\n restoreCartFromBackup,\n mergeBaskets,\n moveBasketItem,\n getCartStats,\n validateCartIntegrity,\n quoteCart,\n getLatestQuoteToken,\n resolveCartLineId,\n} from './modules/cart';\nimport {\n captureAffiliateFromUrl,\n getAffiliateCode,\n getStoredAffiliate,\n setAffiliateCode,\n clearAffiliateCode,\n trackAffiliateEvent,\n} from './modules/affiliates';\nimport { trackCartActivity, trackPageView, trackProductView } from './modules/analytics';\n\n/**\n * Initialize the SDK with a store slug\n */\nfunction init(storeSlug: string, options?: ShoppexInitOptions): void;\nfunction init(options: ShoppexInitOptions & { storeId: string }): void;\nfunction init(\n storeSlugOrOptions: string | (ShoppexInitOptions & { storeId: string }),\n options?: ShoppexInitOptions\n): void {\n if (typeof storeSlugOrOptions === 'string') {\n initConfig(storeSlugOrOptions, options);\n } else {\n initConfig(storeSlugOrOptions.storeId, storeSlugOrOptions);\n }\n}\n\nexport const storefrontStorageSdk = {\n // Initialization\n init,\n isInitialized,\n getConfig,\n\n // Cart\n getCart,\n getCartItemCount,\n getCartCoupon,\n getCartCouponSource,\n setCartCoupon,\n clearCartCoupon,\n addToCart,\n setCartItem,\n updateCartItem,\n removeFromCart,\n clearCart,\n createCartBackup,\n restoreCartFromBackup,\n mergeBaskets,\n moveBasketItem,\n getCartStats,\n validateCartIntegrity,\n quoteCart,\n getLatestQuoteToken,\n resolveCartLineId,\n\n // Affiliates (referral storage and capture)\n captureAffiliateFromUrl,\n getAffiliateCode,\n getStoredAffiliate,\n setAffiliateCode,\n clearAffiliateCode,\n trackAffiliateEvent,\n\n // Analytics\n trackPageView,\n trackCartActivity,\n trackProductView,\n};\n\nexport default storefrontStorageSdk;\n","// settings & const\nconst PATH_PARAM_RE = /\\{[^{}]+\\}/g;\n\nconst supportsRequestInitExt = () => {\n return (\n typeof process === \"object\" &&\n Number.parseInt(process?.versions?.node?.substring(0, 2)) >= 18 &&\n process.versions.undici\n );\n};\n\n/**\n * Returns a cheap, non-cryptographically-secure random ID\n * Courtesy of @imranbarbhuiya (https://github.com/imranbarbhuiya)\n */\nexport function randomID() {\n return Math.random().toString(36).slice(2, 11);\n}\n\n/**\n * Create an openapi-fetch client.\n * @type {import(\"./index.js\").default}\n */\nexport default function createClient(clientOptions) {\n let {\n baseUrl = \"\",\n Request: CustomRequest = globalThis.Request,\n fetch: baseFetch = globalThis.fetch,\n querySerializer: globalQuerySerializer,\n bodySerializer: globalBodySerializer,\n pathSerializer: globalPathSerializer,\n headers: baseHeaders,\n requestInitExt = undefined,\n ...baseOptions\n } = { ...clientOptions };\n requestInitExt = supportsRequestInitExt() ? requestInitExt : undefined;\n baseUrl = removeTrailingSlash(baseUrl);\n const globalMiddlewares = [];\n\n /**\n * Per-request fetch (keeps settings created in createClient()\n * @param {T} url\n * @param {import('./index.js').FetchOptions<T>} fetchOptions\n */\n async function coreFetch(schemaPath, fetchOptions) {\n const {\n baseUrl: localBaseUrl,\n fetch = baseFetch,\n Request = CustomRequest,\n headers,\n params = {},\n parseAs = \"json\",\n querySerializer: requestQuerySerializer,\n bodySerializer = globalBodySerializer ?? defaultBodySerializer,\n pathSerializer: requestPathSerializer,\n body,\n middleware: requestMiddlewares = [],\n ...init\n } = fetchOptions || {};\n let finalBaseUrl = baseUrl;\n if (localBaseUrl) {\n finalBaseUrl = removeTrailingSlash(localBaseUrl) ?? baseUrl;\n }\n\n let querySerializer =\n typeof globalQuerySerializer === \"function\"\n ? globalQuerySerializer\n : createQuerySerializer(globalQuerySerializer);\n if (requestQuerySerializer) {\n querySerializer =\n typeof requestQuerySerializer === \"function\"\n ? requestQuerySerializer\n : createQuerySerializer({\n ...(typeof globalQuerySerializer === \"object\" ? globalQuerySerializer : {}),\n ...requestQuerySerializer,\n });\n }\n\n const pathSerializer = requestPathSerializer || globalPathSerializer || defaultPathSerializer;\n\n const serializedBody =\n body === undefined\n ? undefined\n : bodySerializer(\n body,\n // Note: we declare mergeHeaders() both here and below because it’s a bit of a chicken-or-egg situation:\n // bodySerializer() needs all headers so we aren’t dropping ones set by the user, however,\n // the result of this ALSO sets the lowest-priority content-type header. So we re-merge below,\n // setting the content-type at the very beginning to be overwritten.\n // Lastly, based on the way headers work, it’s not a simple “present-or-not” check becauase null intentionally un-sets headers.\n mergeHeaders(baseHeaders, headers, params.header),\n );\n const finalHeaders = mergeHeaders(\n // with no body, we should not to set Content-Type\n serializedBody === undefined ||\n // if serialized body is FormData; browser will correctly set Content-Type & boundary expression\n serializedBody instanceof FormData\n ? {}\n : {\n \"Content-Type\": \"application/json\",\n },\n baseHeaders,\n headers,\n params.header,\n );\n\n // Client level middleware take priority over request-level middleware\n const finalMiddlewares = [...globalMiddlewares, ...requestMiddlewares];\n\n const requestInit = {\n redirect: \"follow\",\n ...baseOptions,\n ...init,\n body: serializedBody,\n headers: finalHeaders,\n };\n\n let id;\n let options;\n let request = new Request(\n createFinalURL(schemaPath, { baseUrl: finalBaseUrl, params, querySerializer, pathSerializer }),\n requestInit,\n );\n let response;\n\n /** Add custom parameters to Request object */\n for (const key in init) {\n if (!(key in request)) {\n request[key] = init[key];\n }\n }\n\n if (finalMiddlewares.length) {\n id = randomID();\n\n // middleware (request)\n options = Object.freeze({\n baseUrl: finalBaseUrl,\n fetch,\n parseAs,\n querySerializer,\n bodySerializer,\n pathSerializer,\n });\n for (const m of finalMiddlewares) {\n if (m && typeof m === \"object\" && typeof m.onRequest === \"function\") {\n const result = await m.onRequest({\n request,\n schemaPath,\n params,\n options,\n id,\n });\n if (result) {\n if (result instanceof Request) {\n request = result;\n } else if (result instanceof Response) {\n response = result;\n break;\n } else {\n throw new Error(\"onRequest: must return new Request() or Response() when modifying the request\");\n }\n }\n }\n }\n }\n\n if (!response) {\n // fetch!\n try {\n response = await fetch(request, requestInitExt);\n } catch (error) {\n let errorAfterMiddleware = error;\n // middleware (error)\n // execute in reverse-array order (first priority gets last transform)\n if (finalMiddlewares.length) {\n for (let i = finalMiddlewares.length - 1; i >= 0; i--) {\n const m = finalMiddlewares[i];\n if (m && typeof m === \"object\" && typeof m.onError === \"function\") {\n const result = await m.onError({\n request,\n error: errorAfterMiddleware,\n schemaPath,\n params,\n options,\n id,\n });\n if (result) {\n // if error is handled by returning a response, skip remaining middleware\n if (result instanceof Response) {\n errorAfterMiddleware = undefined;\n response = result;\n break;\n }\n\n if (result instanceof Error) {\n errorAfterMiddleware = result;\n continue;\n }\n\n throw new Error(\"onError: must return new Response() or instance of Error\");\n }\n }\n }\n }\n\n // rethrow error if not handled by middleware\n if (errorAfterMiddleware) {\n throw errorAfterMiddleware;\n }\n }\n\n // middleware (response)\n // execute in reverse-array order (first priority gets last transform)\n if (finalMiddlewares.length) {\n for (let i = finalMiddlewares.length - 1; i >= 0; i--) {\n const m = finalMiddlewares[i];\n if (m && typeof m === \"object\" && typeof m.onResponse === \"function\") {\n const result = await m.onResponse({\n request,\n response,\n schemaPath,\n params,\n options,\n id,\n });\n if (result) {\n if (!(result instanceof Response)) {\n throw new Error(\"onResponse: must return new Response() when modifying the response\");\n }\n response = result;\n }\n }\n }\n }\n }\n\n const contentLength = response.headers.get(\"Content-Length\");\n // handle empty content\n if (\n response.status === 204 ||\n request.method === \"HEAD\" ||\n (contentLength === \"0\" && !response.headers.get(\"Transfer-Encoding\")?.includes(\"chunked\"))\n ) {\n return response.ok ? { data: undefined, response } : { error: undefined, response };\n }\n\n // parse response (falling back to .text() when necessary)\n if (response.ok) {\n const getResponseData = async () => {\n // if \"stream\", skip parsing entirely\n if (parseAs === \"stream\") {\n return response.body;\n }\n\n if (parseAs === \"json\" && !contentLength) {\n // use text() when no content-length is provided to avoid errors parsing empty bodies (200 with no content)\n const raw = await response.text();\n return raw ? JSON.parse(raw) : undefined;\n }\n\n return await response[parseAs]();\n };\n return { data: await getResponseData(), response };\n }\n\n // handle errors\n let error = await response.text();\n try {\n error = JSON.parse(error); // attempt to parse as JSON\n } catch {\n // noop\n }\n return { error, response };\n }\n\n return {\n request(method, url, init) {\n return coreFetch(url, { ...init, method: method.toUpperCase() });\n },\n /** Call a GET endpoint */\n GET(url, init) {\n return coreFetch(url, { ...init, method: \"GET\" });\n },\n /** Call a PUT endpoint */\n PUT(url, init) {\n return coreFetch(url, { ...init, method: \"PUT\" });\n },\n /** Call a POST endpoint */\n POST(url, init) {\n return coreFetch(url, { ...init, method: \"POST\" });\n },\n /** Call a DELETE endpoint */\n DELETE(url, init) {\n return coreFetch(url, { ...init, method: \"DELETE\" });\n },\n /** Call a OPTIONS endpoint */\n OPTIONS(url, init) {\n return coreFetch(url, { ...init, method: \"OPTIONS\" });\n },\n /** Call a HEAD endpoint */\n HEAD(url, init) {\n return coreFetch(url, { ...init, method: \"HEAD\" });\n },\n /** Call a PATCH endpoint */\n PATCH(url, init) {\n return coreFetch(url, { ...init, method: \"PATCH\" });\n },\n /** Call a TRACE endpoint */\n TRACE(url, init) {\n return coreFetch(url, { ...init, method: \"TRACE\" });\n },\n /** Register middleware */\n use(...middleware) {\n for (const m of middleware) {\n if (!m) {\n continue;\n }\n if (typeof m !== \"object\" || !(\"onRequest\" in m || \"onResponse\" in m || \"onError\" in m)) {\n throw new Error(\"Middleware must be an object with one of `onRequest()`, `onResponse() or `onError()`\");\n }\n globalMiddlewares.push(m);\n }\n },\n /** Unregister middleware */\n eject(...middleware) {\n for (const m of middleware) {\n const i = globalMiddlewares.indexOf(m);\n if (i !== -1) {\n globalMiddlewares.splice(i, 1);\n }\n }\n },\n };\n}\n\nclass PathCallForwarder {\n constructor(client, url) {\n this.client = client;\n this.url = url;\n }\n\n GET = (init) => {\n return this.client.GET(this.url, init);\n };\n PUT = (init) => {\n return this.client.PUT(this.url, init);\n };\n POST = (init) => {\n return this.client.POST(this.url, init);\n };\n DELETE = (init) => {\n return this.client.DELETE(this.url, init);\n };\n OPTIONS = (init) => {\n return this.client.OPTIONS(this.url, init);\n };\n HEAD = (init) => {\n return this.client.HEAD(this.url, init);\n };\n PATCH = (init) => {\n return this.client.PATCH(this.url, init);\n };\n TRACE = (init) => {\n return this.client.TRACE(this.url, init);\n };\n}\n\nclass PathClientProxyHandler {\n constructor() {\n this.client = null;\n }\n\n // Assume the property is an URL.\n get(coreClient, url) {\n const forwarder = new PathCallForwarder(coreClient, url);\n this.client[url] = forwarder;\n return forwarder;\n }\n}\n\n/**\n * Wrap openapi-fetch client to support a path based API.\n * @type {import(\"./index.js\").wrapAsPathBasedClient}\n */\nexport function wrapAsPathBasedClient(coreClient) {\n const handler = new PathClientProxyHandler();\n const proxy = new Proxy(coreClient, handler);\n\n // Put the proxy on the prototype chain of the actual client.\n // This means if we do not have a memoized PathCallForwarder,\n // we fall back to the proxy to synthesize it.\n // However, the proxy itself is not on the hot-path (if we fetch the same\n // endpoint multiple times, only the first call will hit the proxy).\n function Client() {}\n Client.prototype = proxy;\n\n const client = new Client();\n\n // Feed the client back to the proxy handler so it can store the generated\n // PathCallForwarder.\n handler.client = client;\n\n return client;\n}\n\n/**\n * Convenience method to an openapi-fetch path based client.\n * Strictly equivalent to `wrapAsPathBasedClient(createClient(...))`.\n * @type {import(\"./index.js\").createPathBasedClient}\n */\nexport function createPathBasedClient(clientOptions) {\n return wrapAsPathBasedClient(createClient(clientOptions));\n}\n\n// utils\n\n/**\n * Serialize primitive param values\n * @type {import(\"./index.js\").serializePrimitiveParam}\n */\nexport function serializePrimitiveParam(name, value, options) {\n if (value === undefined || value === null) {\n return \"\";\n }\n if (typeof value === \"object\") {\n throw new Error(\n \"Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.\",\n );\n }\n return `${name}=${options?.allowReserved === true ? value : encodeURIComponent(value)}`;\n}\n\n/**\n * Serialize object param (shallow only)\n * @type {import(\"./index.js\").serializeObjectParam}\n */\nexport function serializeObjectParam(name, value, options) {\n if (!value || typeof value !== \"object\") {\n return \"\";\n }\n const values = [];\n const joiner =\n {\n simple: \",\",\n label: \".\",\n matrix: \";\",\n }[options.style] || \"&\";\n\n // explode: false\n if (options.style !== \"deepObject\" && options.explode === false) {\n for (const k in value) {\n values.push(k, options.allowReserved === true ? value[k] : encodeURIComponent(value[k]));\n }\n const final = values.join(\",\"); // note: values are always joined by comma in explode: false (but joiner can prefix)\n switch (options.style) {\n case \"form\": {\n return `${name}=${final}`;\n }\n case \"label\": {\n return `.${final}`;\n }\n case \"matrix\": {\n return `;${name}=${final}`;\n }\n default: {\n return final;\n }\n }\n }\n\n // explode: true\n for (const k in value) {\n const finalName = options.style === \"deepObject\" ? `${name}[${k}]` : k;\n values.push(serializePrimitiveParam(finalName, value[k], options));\n }\n const final = values.join(joiner);\n return options.style === \"label\" || options.style === \"matrix\" ? `${joiner}${final}` : final;\n}\n\n/**\n * Serialize array param (shallow only)\n * @type {import(\"./index.js\").serializeArrayParam}\n */\nexport function serializeArrayParam(name, value, options) {\n if (!Array.isArray(value)) {\n return \"\";\n }\n\n // explode: false\n if (options.explode === false) {\n const joiner = { form: \",\", spaceDelimited: \"%20\", pipeDelimited: \"|\" }[options.style] || \",\"; // note: for arrays, joiners vary wildly based on style + explode behavior\n const final = (options.allowReserved === true ? value : value.map((v) => encodeURIComponent(v))).join(joiner);\n switch (options.style) {\n case \"simple\": {\n return final;\n }\n case \"label\": {\n return `.${final}`;\n }\n case \"matrix\": {\n return `;${name}=${final}`;\n }\n // case \"spaceDelimited\":\n // case \"pipeDelimited\":\n default: {\n return `${name}=${final}`;\n }\n }\n }\n\n // explode: true\n const joiner = { simple: \",\", label: \".\", matrix: \";\" }[options.style] || \"&\";\n const values = [];\n for (const v of value) {\n if (options.style === \"simple\" || options.style === \"label\") {\n values.push(options.allowReserved === true ? v : encodeURIComponent(v));\n } else {\n values.push(serializePrimitiveParam(name, v, options));\n }\n }\n return options.style === \"label\" || options.style === \"matrix\"\n ? `${joiner}${values.join(joiner)}`\n : values.join(joiner);\n}\n\n/**\n * Serialize query params to string\n * @type {import(\"./index.js\").createQuerySerializer}\n */\nexport function createQuerySerializer(options) {\n return function querySerializer(queryParams) {\n const search = [];\n if (queryParams && typeof queryParams === \"object\") {\n for (const name in queryParams) {\n const value = queryParams[name];\n if (value === undefined || value === null) {\n continue;\n }\n if (Array.isArray(value)) {\n if (value.length === 0) {\n continue;\n }\n search.push(\n serializeArrayParam(name, value, {\n style: \"form\",\n explode: true,\n ...options?.array,\n allowReserved: options?.allowReserved || false,\n }),\n );\n continue;\n }\n if (typeof value === \"object\") {\n search.push(\n serializeObjectParam(name, value, {\n style: \"deepObject\",\n explode: true,\n ...options?.object,\n allowReserved: options?.allowReserved || false,\n }),\n );\n continue;\n }\n search.push(serializePrimitiveParam(name, value, options));\n }\n }\n return search.join(\"&\");\n };\n}\n\n/**\n * Handle different OpenAPI 3.x serialization styles\n * @type {import(\"./index.js\").defaultPathSerializer}\n * @see https://swagger.io/docs/specification/serialization/#path\n */\nexport function defaultPathSerializer(pathname, pathParams) {\n let nextURL = pathname;\n for (const match of pathname.match(PATH_PARAM_RE) ?? []) {\n let name = match.substring(1, match.length - 1);\n let explode = false;\n let style = \"simple\";\n if (name.endsWith(\"*\")) {\n explode = true;\n name = name.substring(0, name.length - 1);\n }\n if (name.startsWith(\".\")) {\n style = \"label\";\n name = name.substring(1);\n } else if (name.startsWith(\";\")) {\n style = \"matrix\";\n name = name.substring(1);\n }\n if (!pathParams || pathParams[name] === undefined || pathParams[name] === null) {\n continue;\n }\n const value = pathParams[name];\n if (Array.isArray(value)) {\n nextURL = nextURL.replace(match, serializeArrayParam(name, value, { style, explode }));\n continue;\n }\n if (typeof value === \"object\") {\n nextURL = nextURL.replace(match, serializeObjectParam(name, value, { style, explode }));\n continue;\n }\n if (style === \"matrix\") {\n nextURL = nextURL.replace(match, `;${serializePrimitiveParam(name, value)}`);\n continue;\n }\n nextURL = nextURL.replace(match, style === \"label\" ? `.${encodeURIComponent(value)}` : encodeURIComponent(value));\n }\n return nextURL;\n}\n\n/**\n * Serialize body object to string\n * @type {import(\"./index.js\").defaultBodySerializer}\n */\nexport function defaultBodySerializer(body, headers) {\n if (body instanceof FormData) {\n return body;\n }\n if (headers) {\n const contentType =\n headers.get instanceof Function\n ? (headers.get(\"Content-Type\") ?? headers.get(\"content-type\"))\n : (headers[\"Content-Type\"] ?? headers[\"content-type\"]);\n if (contentType === \"application/x-www-form-urlencoded\") {\n return new URLSearchParams(body).toString();\n }\n }\n return JSON.stringify(body);\n}\n\n/**\n * Construct URL string from baseUrl and handle path and query params\n * @type {import(\"./index.js\").createFinalURL}\n */\nexport function createFinalURL(pathname, options) {\n let finalURL = `${options.baseUrl}${pathname}`;\n if (options.params?.path) {\n finalURL = options.pathSerializer(finalURL, options.params.path);\n }\n let search = options.querySerializer(options.params.query ?? {});\n if (search.startsWith(\"?\")) {\n search = search.substring(1);\n }\n if (search) {\n finalURL += `?${search}`;\n }\n return finalURL;\n}\n\n/**\n * Merge headers a and b, with b taking priority\n * @type {import(\"./index.js\").mergeHeaders}\n */\nexport function mergeHeaders(...allHeaders) {\n const finalHeaders = new Headers();\n for (const h of allHeaders) {\n if (!h || typeof h !== \"object\") {\n continue;\n }\n const iterator = h instanceof Headers ? h.entries() : Object.entries(h);\n for (const [k, v] of iterator) {\n if (v === null) {\n finalHeaders.delete(k);\n } else if (Array.isArray(v)) {\n for (const v2 of v) {\n finalHeaders.append(k, v2);\n }\n } else if (v !== undefined) {\n finalHeaders.set(k, v);\n }\n }\n }\n return finalHeaders;\n}\n\n/**\n * Remove trailing slash from url\n * @type {import(\"./index.js\").removeTrailingSlash}\n */\nexport function removeTrailingSlash(url) {\n if (url.endsWith(\"/\")) {\n return url.substring(0, url.length - 1);\n }\n return url;\n}\n","import createClient from 'openapi-fetch';\nimport type { paths } from './api-types.js';\n\n/**\n * Create a type-safe API client.\n *\n * Lives in its own module (subpath `@shoppex/contracts/api-client`) so buyer-facing\n * bundles can take the client without the root barrel and the zod schemas it\n * re-exports.\n *\n * @example\n * const client = createApiClient('https://api.shoppex.io/v1');\n *\n * // Fully typed request and response\n * const { data, error } = await client.GET('/products', {\n * params: { query: { page: 1, limit: 25 } }\n * });\n */\nexport function createApiClient(baseUrl: string, token?: string) {\n return createClient<paths>({\n baseUrl,\n headers: token ? { Authorization: `Bearer ${token}` } : undefined,\n });\n}\n","/**\n * Typed OpenAPI client factory.\n *\n * Surfaces the generated `createApiClient` from `@shoppex/contracts` with the\n * SDK's configured `apiBaseUrl`. This lets consumers of `@shoppexio/storefront`\n * call any public Dev API endpoint with full end-to-end types without\n * rebuilding a client from scratch.\n *\n * Prefer the high-level modules (`shoppex.getProducts()` etc.) for common\n * read flows — they handle caching, pagination defaults, and storefront\n * scoping. Drop down to `shoppex.client()` only when you need an endpoint\n * the high-level API does not cover yet.\n */\n\nimport { createApiClient } from '@shoppex/contracts/api-client';\nimport type { ShoppexConfig } from '../types';\nimport { DEFAULT_API_BASE_URL, getConfig } from './config';\n\ntype ApiClient = ReturnType<typeof createApiClient>;\n\nlet cachedClient: ApiClient | null = null;\nlet cachedConfig: ShoppexConfig | null = null;\n\n/**\n * Return a typed OpenAPI client bound to the SDK's configured API base URL.\n * The client is cached for the config object it was built from: every init\n * creates a new config object, so a re-init rebuilds it. Keyed here instead of\n * reset from `initConfig`, so `core/config.ts` (which every SDK user loads)\n * does not import this module and its `openapi-fetch` dependency.\n */\nexport function getTypedClient(token?: string): ApiClient {\n const config = getConfig();\n\n if (cachedClient && cachedConfig === config && !token) {\n return cachedClient;\n }\n\n const client = createApiClient(config.apiBaseUrl ?? DEFAULT_API_BASE_URL, token);\n\n if (!token) {\n cachedClient = client;\n cachedConfig = config;\n }\n\n return client;\n}\n","/**\n * Store Module\n *\n * API methods for store data.\n */\n\nimport { forwardFailure, get } from '../core/client';\nimport { DEFAULT_API_BASE_URL, getConfig, isInitialized, setShopId } from '../core/config';\nimport { buildEndpoint } from '../core/endpoint';\nimport type {\n SDKResponse,\n Shop,\n Product,\n StorefrontData,\n ProductGroup,\n Category,\n StorefrontAddonBootstrap,\n CursorPagination,\n} from '../types';\n\ninterface StoreResponse {\n shop: Shop;\n products?: Product[];\n products_pagination?: CursorPagination | null;\n groups?: ProductGroup[];\n items?: StorefrontData['items'];\n categories?: Category[];\n addons?: StorefrontAddonBootstrap;\n}\n\ninterface StorefrontResponse {\n shop: Shop;\n}\n\nexport interface GetStorefrontOptions {\n productsLimit?: number;\n productsCursor?: string | null;\n}\n\nconst STORE_CACHE_TTL = 5 * 60 * 1000;\n\nexport async function getStore(): Promise<SDKResponse<Shop>> {\n const config = getConfig();\n const response = await get<StoreResponse>(\n buildEndpoint('/v1/storefront/shops/name/:storeSlug', {\n storeSlug: config.storeSlug,\n }),\n {\n buyerCurrency: true,\n cache: {\n key: `store:${config.storeSlug}`,\n ttl: STORE_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n // Cache the shopId for slug lookups\n if (response.data.shop?.id) {\n setShopId(response.data.shop.id);\n }\n return {\n success: true,\n data: response.data.shop,\n };\n }\n\n return forwardFailure(response);\n}\n\nexport async function resolveStoreByDomain(\n domain?: string,\n apiBaseUrl?: string\n): Promise<SDKResponse<Shop>> {\n const resolvedDomain =\n domain ??\n (typeof window !== 'undefined' ? window.location.hostname : '');\n\n if (!resolvedDomain) {\n return {\n success: false,\n message: 'Domain is required to resolve store',\n };\n }\n\n const cleanDomain = resolvedDomain\n .replace(/^https?:\\/\\//, '')\n .split('/')[0]\n .trim();\n\n const baseUrl =\n apiBaseUrl ??\n (isInitialized() ? getConfig().apiBaseUrl : DEFAULT_API_BASE_URL);\n\n const response = await get<StorefrontResponse>(\n buildEndpoint('/v1/storefront/shops/domain/:domain', {\n domain: cleanDomain,\n }),\n {\n baseUrl,\n buyerCurrency: true,\n cache: {\n key: `store:domain:${cleanDomain}`,\n ttl: STORE_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data?.shop) {\n if (response.data.shop.id) {\n setShopId(response.data.shop.id);\n }\n return {\n success: true,\n data: response.data.shop,\n };\n }\n\n return forwardFailure(response, { message: response.message ?? 'Failed to resolve store' });\n}\n\nexport async function getStorefront(options?: GetStorefrontOptions): Promise<SDKResponse<StorefrontData>> {\n const config = getConfig();\n const query = new URLSearchParams();\n if (Number.isFinite(options?.productsLimit)) {\n query.set('products_limit', String(Math.max(1, Math.floor(options?.productsLimit ?? 0))));\n }\n if (typeof options?.productsCursor === 'string' && options.productsCursor.trim().length > 0) {\n query.set('products_cursor', options.productsCursor);\n }\n const querySuffix = query.size > 0 ? `?${query.toString()}` : '';\n const response = await get<StoreResponse>(\n `${buildEndpoint('/v1/storefront/shops/name/:storeSlug', {\n storeSlug: config.storeSlug,\n })}${querySuffix}`,\n {\n buyerCurrency: true,\n cache: {\n key: `storefront:${config.storeSlug}:${options?.productsLimit ?? 'full'}:${options?.productsCursor ?? 'start'}`,\n ttl: STORE_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n // Cache the shopId for slug lookups\n if (response.data.shop?.id) {\n setShopId(response.data.shop.id);\n }\n return {\n success: true,\n data: {\n shop: response.data.shop,\n products: response.data.products ?? [],\n products_pagination: response.data.products_pagination ?? null,\n groups: response.data.groups ?? [],\n items: response.data.items ?? [],\n categories: response.data.categories ?? [],\n addons: response.data.addons ?? { items: [] },\n },\n };\n }\n\n return forwardFailure(response);\n}\n\nexport async function getStoreLogoUrl(): Promise<string | null> {\n const response = await getStore();\n\n if (response.success && response.data?.logo) {\n return response.data.logo;\n }\n\n return null;\n}\n\nexport async function getStoreBannerUrl(): Promise<string | null> {\n const response = await getStore();\n\n if (response.success && response.data?.banner) {\n return response.data.banner;\n }\n\n return null;\n}\n","import type { Product, ProductGroup } from '../types/index.js';\n\nexport function buildStorefrontProductLookup(products: Product[] = []): Map<string, Product> {\n const lookup = new Map<string, Product>();\n for (const product of products) {\n if (!product?.uniqid || lookup.has(product.uniqid)) continue;\n lookup.set(product.uniqid, product);\n }\n return lookup;\n}\n\n// Groups reference their products by uniqid; the objects live once in `products`.\nexport function getStorefrontGroupProducts(\n group: ProductGroup,\n productsOrLookup: Product[] | Map<string, Product> = [],\n): Product[] {\n const lookup = productsOrLookup instanceof Map\n ? productsOrLookup\n : buildStorefrontProductLookup(productsOrLookup);\n return (group.product_uniqids ?? []).flatMap((uniqid) => {\n const product = lookup.get(uniqid);\n return product ? [product] : [];\n });\n}\n\nexport function getMergedStorefrontProducts(products: Product[] = []): Product[] {\n return Array.from(buildStorefrontProductLookup(products).values());\n}\n","/**\n * Products Module\n *\n * API methods for product data.\n */\n\nimport { forwardFailure, get } from '../core/client';\nimport { getConfig, getShopId } from '../core/config';\nimport { buildEndpoint } from '../core/endpoint';\nimport type {\n SDKResponse,\n Product,\n ProductCategory,\n ProductGroup,\n ProductVariant,\n PriceVariant,\n CursorPagination,\n} from '../types';\nimport { getStore } from './store';\nimport { getMergedStorefrontProducts } from '../utils/storefront-catalog';\n\ninterface ProductsResponse {\n products: Product[];\n groups?: ProductGroup[];\n pagination?: CursorPagination | null;\n}\n\ninterface ProductResponse {\n product: Product;\n}\n\nconst PRODUCTS_CACHE_TTL = 2 * 60 * 1000;\n\nexport interface GetStorefrontProductsPageOptions {\n cursor?: string | null;\n limit?: number;\n sort?: 'featured' | 'newest' | 'price-asc' | 'price-desc' | string | null;\n category?: string | null;\n hideOutOfStock?: boolean;\n}\n\nfunction getStorefrontProductsPageCategoryCacheKey(category: string | null | undefined): string {\n if (category === undefined) return 'category:unset';\n if (category === null) return 'category:null';\n return `category:${category}`;\n}\n\nfunction priceVariantToProductVariant(variant: PriceVariant & { stock?: number }): ProductVariant {\n return {\n id: variant.id,\n title: variant.title ?? variant.label ?? '',\n price: typeof variant.price === 'number' ? variant.price : Number(variant.price) || 0,\n sku: variant.sku,\n stock: typeof variant.stock === 'number' ? variant.stock : undefined,\n orderable: typeof variant.orderable === 'boolean' ? variant.orderable : undefined,\n quantity_min: variant.quantity_min,\n quantity_max: variant.quantity_max,\n quantityMin: variant.quantityMin,\n quantityMax: variant.quantityMax,\n image_id: variant.image_id,\n imageId: variant.imageId,\n cloudflare_image_id: variant.cloudflare_image_id,\n cloudflareImageId: variant.cloudflareImageId,\n image_url: variant.image_url,\n imageUrl: variant.imageUrl,\n visibility: variant.visibility,\n is_private: variant.is_private,\n };\n}\n\nfunction normalizeProduct(product: Product): Product {\n if (product.variants && product.variants.length > 0) {\n return product;\n }\n\n const priceVariants = product.price_variants;\n if (!Array.isArray(priceVariants) || priceVariants.length === 0) {\n return product;\n }\n\n return {\n ...product,\n variants: priceVariants.map((variant) =>\n priceVariantToProductVariant(variant as PriceVariant & { stock?: number })\n ),\n };\n}\n\nexport async function getProducts(): Promise<SDKResponse<Product[]>> {\n const config = getConfig();\n const response = await get<ProductsResponse>(\n buildEndpoint('/v1/storefront/products/public/:storeSlug', {\n storeSlug: config.storeSlug,\n }),\n {\n buyerCurrency: true,\n cache: {\n key: `products:${config.storeSlug}`,\n ttl: PRODUCTS_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n // The public route returns every public product exactly once in the flat `products` array —\n // group-bound products (e.g. variant-style DYNAMIC products) are included there too, so no\n // group merge is needed anymore. Groups only carry `product_uniqids` references into this\n // list. getMergedStorefrontProducts just dedupes by uniqid (first entry wins).\n return {\n success: true,\n data: getMergedStorefrontProducts(response.data.products.map(normalizeProduct)),\n };\n }\n\n return forwardFailure(response, { data: [] });\n}\n\nexport async function getStorefrontProductsPage(\n options?: GetStorefrontProductsPageOptions,\n): Promise<SDKResponse<{ products: Product[]; pagination: CursorPagination | null }>> {\n const config = getConfig();\n const query = new URLSearchParams();\n if (typeof options?.cursor === 'string' && options.cursor.trim().length > 0) {\n query.set('cursor', options.cursor);\n }\n if (Number.isFinite(options?.limit)) {\n query.set('limit', String(Math.max(1, Math.floor(options?.limit ?? 0))));\n }\n if (typeof options?.sort === 'string' && options.sort.trim().length > 0) {\n query.set('sort', options.sort.trim());\n }\n if (typeof options?.category === 'string' && options.category.trim().length > 0) {\n query.set('category', options.category.trim());\n }\n if (options?.hideOutOfStock === true) {\n query.set('hide_out_of_stock', 'true');\n }\n const querySuffix = query.size > 0 ? `?${query.toString()}` : '';\n\n const response = await get<ProductsResponse>(\n `${buildEndpoint('/v1/storefront/products/shop/:storeSlug', {\n storeSlug: config.storeSlug,\n })}${querySuffix}`,\n {\n buyerCurrency: true,\n cache: {\n key: `products:page:${config.storeSlug}:${options?.limit ?? 'default'}:${options?.cursor ?? 'start'}:${options?.sort ?? 'featured'}:${getStorefrontProductsPageCategoryCacheKey(options?.category)}:${options?.hideOutOfStock === true ? 'in-stock' : 'all-stock'}`,\n ttl: PRODUCTS_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n return {\n success: true,\n data: {\n products: response.data.products.map(normalizeProduct),\n pagination: response.data.pagination ?? null,\n },\n };\n }\n\n return forwardFailure(response);\n}\n\nexport async function getProduct(\n idOrSlug: string,\n options: {\n /**\n * A variant id from the page URL (`?variant=<id>`). A private variant is\n * listed only when it is named here; it then comes first in the variants,\n * so a buy box that opens on the first sellable option preselects it.\n */\n variant?: string;\n } = {},\n): Promise<SDKResponse<Product>> {\n // Slug lookups need the current shop id. Resolve it lazily so callers do not\n // have to remember to call getStore()/getStorefront() first.\n let shopId = getShopId();\n if (!shopId) {\n const store = await getStore();\n if (!store.success) {\n // The store lookup failed for a reason the caller must see (a refused\n // currency, a suspended shop); a product read without the shop id would\n // only turn that into a misleading not-found.\n return forwardFailure(store);\n }\n shopId = store.data?.id ?? null;\n }\n\n const query = new URLSearchParams();\n if (shopId) query.set('slug_shop_id', shopId);\n if (options.variant) query.set('variant', options.variant);\n const queryParams = query.size > 0 ? `?${query.toString()}` : '';\n\n const response = await get<ProductResponse>(\n `${buildEndpoint('/v1/storefront/products/unique/:idOrSlug', { idOrSlug })}${queryParams}`,\n {\n buyerCurrency: true,\n cache: {\n key: `product:${idOrSlug}:${shopId ?? 'no-shop'}:${options.variant ?? 'no-variant'}`,\n ttl: PRODUCTS_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data?.product) {\n return {\n success: true,\n data: normalizeProduct(response.data.product),\n };\n }\n\n return forwardFailure(response);\n}\n\nexport async function getCategories(): Promise<SDKResponse<string[]>> {\n const products = await getProducts();\n\n if (!products.success || !products.data) {\n return forwardFailure(products);\n }\n\n const categories = new Set<string>();\n for (const product of products.data) {\n if (product.categories) {\n for (const category of product.categories) {\n if (typeof category === 'string') {\n categories.add(category);\n } else if (category && typeof category === 'object' && 'uniqid' in category) {\n categories.add((category as ProductCategory).uniqid);\n }\n }\n }\n }\n\n return {\n success: true,\n data: Array.from(categories),\n };\n}\n","// Standalone product-redirect placeholder engine. Intentionally does NOT import from\n// manual-gateway-template.ts: that file is consumed via its own package subpath export\n// (@shoppex/contracts/manual-gateway-template), and a cross-subpath relative import here\n// breaks Next.js/Turbopack module resolution for client components that only depend on\n// this subpath. The scan/render logic is small enough to duplicate safely.\n\nexport const PRODUCT_REDIRECT_TEMPLATE_VARIABLES = ['product_id', 'order_id'] as const;\n\nexport type ProductRedirectTemplateVariable = typeof PRODUCT_REDIRECT_TEMPLATE_VARIABLES[number];\nexport type ProductRedirectTemplateVars = Record<ProductRedirectTemplateVariable, string>;\n\nexport const PRODUCT_REDIRECT_TEMPLATE_VARIABLE_EXAMPLES = [\n '{{product_id}}',\n '{{order_id}}',\n] as const;\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction buildVariablePattern(key: string, style: 'double' | 'single'): RegExp {\n const escapedKey = escapeRegExp(key);\n if (style === 'double') {\n return new RegExp(`\\\\{\\\\{\\\\s*${escapedKey}\\\\s*\\\\}\\\\}`, 'gi');\n }\n\n return new RegExp(`\\\\{?\\\\{\\\\s*${escapedKey}\\\\s*\\\\}(?!\\\\})`, 'gi');\n}\n\n// A single-brace pattern also takes the `{` before its token (`\\{?`), and a match that starts with\n// `{{` is dropped: that token sits inside a `{{` run. This stands in for a negative lookbehind on\n// `{`, which WebKit before Safari 16.4 cannot parse; the dashboard and checkout bundles ship this file.\nfunction isInsideDoubleBrace(raw: string): boolean {\n return raw.startsWith('{{');\n}\n\n/** The double-brace matches, then the single-brace matches outside a `{{` run. */\nfunction placeholderMatches(template: string, patterns: { double: RegExp; single: RegExp }) {\n return [\n ...template.matchAll(patterns.double),\n ...[...template.matchAll(patterns.single)].filter((match) => !isInsideDoubleBrace(match[0])),\n ];\n}\n\n// Accepts a partial var map: only the keys present (and non-empty) are\n// substituted. A variable the caller cannot supply is left as a raw placeholder\n// so downstream fail-closed checks (findRemainingProductRedirectPlaceholders)\n// reject the URL instead of emitting an encoded \"\" / \"null\".\nexport function renderProductRedirectTemplate(\n template: string,\n vars: Partial<ProductRedirectTemplateVars>,\n): string {\n let rendered = template;\n for (const [key, value] of Object.entries(vars)) {\n if (typeof value !== 'string' || value.length === 0) continue;\n const replacement = encodeURIComponent(value);\n rendered = rendered.replace(buildVariablePattern(key, 'double'), replacement);\n rendered = rendered.replace(buildVariablePattern(key, 'single'), (raw) => (isInsideDoubleBrace(raw) ? raw : replacement));\n }\n return rendered;\n}\n\nconst PLACEHOLDER_SCAN_PATTERNS = {\n double: /\\{\\{\\s*([a-zA-Z][a-zA-Z0-9_]*)\\s*\\}\\}/g,\n single: /\\{?\\{\\s*([a-zA-Z][a-zA-Z0-9_]*)\\s*\\}(?!\\})/g,\n};\n\nconst REMAINING_PLACEHOLDER_PATTERNS = {\n double: /\\{\\{[\\s\\S]*?\\}\\}/g,\n single: /\\{?\\{[^{}]+\\}(?!\\})/g,\n};\n\n// A fully rendered redirect URL never contains a literal curly brace — any `{`\n// or `}` left after substitution is a malformed/unrendered placeholder fragment\n// (e.g. the unbalanced `{{product_id` or trailing `}` in `{{product_id}}}`).\n// The balanced-span patterns above miss these, so scan for any brace that\n// survives once the balanced spans are stripped out.\nfunction findDanglingBraceFragments(template: string): string[] {\n const stripped = template\n .replace(REMAINING_PLACEHOLDER_PATTERNS.double, '')\n .replace(REMAINING_PLACEHOLDER_PATTERNS.single, (raw) => (isInsideDoubleBrace(raw) ? raw : ''));\n return /[{}]/.test(stripped) ? [...new Set(stripped.match(/[{}]+/g) ?? [])] : [];\n}\n\nexport function findUnsupportedProductRedirectPlaceholders(template: string): string[] {\n if (!template.trim()) {\n return [];\n }\n\n const allowedVariables = new Set<string>(PRODUCT_REDIRECT_TEMPLATE_VARIABLES);\n const unsupported = new Set<string>();\n const allowedRawSpans = new Set<string>();\n\n for (const match of placeholderMatches(template, PLACEHOLDER_SCAN_PATTERNS)) {\n const raw = match[0];\n const name = match[1]?.toLowerCase();\n if (name && !allowedVariables.has(name)) {\n unsupported.add(raw);\n } else if (name) {\n allowedRawSpans.add(raw);\n }\n }\n\n // Also reject malformed placeholder syntax (e.g. {{order-id}}, {{ product_id | x }}) that the\n // strict name patterns above don't match — same rationale as the manual-gateway scanner: catch\n // it at save time instead of letting a raw token survive to checkout.\n for (const match of placeholderMatches(template, REMAINING_PLACEHOLDER_PATTERNS)) {\n const raw = match[0];\n if (!allowedRawSpans.has(raw)) {\n unsupported.add(raw);\n }\n }\n\n // Reject unbalanced braces (e.g. `{{product_id` or `{{product_id}}}`) that the\n // balanced-span patterns never see — fail closed at save time rather than\n // letting a malformed token reach checkout.\n for (const fragment of findDanglingBraceFragments(template)) {\n unsupported.add(fragment);\n }\n\n return [...unsupported];\n}\n\nexport function findRemainingProductRedirectPlaceholders(template: string): string[] {\n if (!template.trim()) {\n return [];\n }\n\n const remaining = new Set<string>();\n for (const match of placeholderMatches(template, REMAINING_PLACEHOLDER_PATTERNS)) {\n remaining.add(match[0]);\n }\n\n // A rendered URL must not carry any leftover brace — including unbalanced ones\n // the balanced-span patterns miss — or checkout would redirect to a literal\n // malformed token instead of failing closed.\n for (const fragment of findDanglingBraceFragments(template)) {\n remaining.add(fragment);\n }\n\n return [...remaining];\n}\n\nexport function isSafeHttpsRedirectTemplateUrl(url: string): boolean {\n const trimmed = url.trim();\n if (!trimmed) {\n return false;\n }\n\n try {\n const parsed = new URL(trimmed);\n return parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n","/**\n * Checkout Module\n *\n * Creates invoice via backend API and redirects to hosted checkout page.\n * All checkout flows go through: checkout.shoppex.io/invoice/{invoiceId}\n */\n\nimport { checkoutAttribution } from '../core/analytics-session';\nimport { getConfig } from '../core/config';\nimport { post } from '../core/client';\nimport { getCart, getCartCoupon, getCartCouponSource, createCartBackup, clearCart, getLatestQuoteToken } from './cart';\nimport { getAffiliateCode, trackAffiliateEvent } from './affiliates';\nimport type { CartItem, CartAddon } from '../types/cart';\nimport type { BuyerRewards } from '../types/api';\nimport {\n findRemainingProductRedirectPlaceholders,\n isSafeHttpsRedirectTemplateUrl,\n} from '@shoppex/contracts/redirect-link-template';\nimport {\n COOKIE_CONSENT_CHECKOUT_HASH_KEY,\n COOKIE_CONSENT_COOKIE,\n parseCookieConsentValue,\n} from '@shoppex/contracts/storefront-consent-choice';\nimport {\n normalizeRequestedCurrency,\n resolveBuyerCurrency,\n} from '../utils/requested-currency';\n\nexport interface CheckoutOptions {\n autoRedirect?: boolean;\n locale?: string;\n email?: string;\n coupon?: string;\n currency?: string;\n /**\n * Absolute HTTPS URL used after a completed purchase when the product does\n * not define its own redirect. This is persisted on the invoice, so each\n * sales channel can provide its own return destination.\n */\n redirectUrl?: string;\n /**\n * Pin the quote proof this hand-off submits, as a tri-state: `undefined`\n * lets the SDK read the latest settled quote from storage, `null` submits\n * explicitly none, and a string submits exactly that token.\n */\n quoteToken?: string | null;\n /**\n * Referral (affiliate) code to submit, as a tri-state:\n *\n * - `undefined` — the SDK resolves it from storage (cart-applied referral\n * code first, then the ambient `?ref=` attribution).\n * - `''` — explicitly none: submit no referral code and do NOT re-read\n * storage. This is how a caller pins \"quoted WITHOUT a referral\"; without\n * it a code captured between the quote and the submit would be applied to\n * a total the buyer never saw.\n * - non-empty — pinned: submit exactly this code.\n *\n * `referralCode` is an alias and follows the same rules; `affiliateCode`\n * wins when both are present.\n */\n affiliateCode?: string;\n /** Alias of {@link CheckoutOptions.affiliateCode}, same tri-state. */\n referralCode?: string;\n customerCheckoutPath?: '/dashboard/api/checkout';\n /**\n * The cart this hand-off was approved FOR, as `JSON.stringify(getCart())`.\n *\n * PAYMENT PATH. A caller that writes the cart and reads it back before\n * checking out (Buy Now, which replaces the cart, is the sharp case) verifies\n * a cart it read at one moment, while these functions read storage again on\n * their way into the request — and localStorage is shared with every other\n * tab on the domain. A write landing in that gap is billed without ever\n * having passed the caller's verification.\n *\n * The caller cannot close that itself: any check it makes is one more read\n * BEFORE this one. Pinning the expected bytes moves the comparison to the\n * only place it can be conclusive — against the exact cart the call is about\n * to POST. A mismatch refuses before anything is created or sent.\n *\n * Honoured identically by BOTH invoice-creating entry points, `checkout()`\n * and `buildCheckoutUrl()` — they hit the same endpoint and create the same\n * invoice, so a pin that held on one and not the other would be a promise\n * the caller could not rely on. Only the refusal shape differs, following\n * each function's own success shape: `checkout()` returns\n * `{ success: false }`, `buildCheckoutUrl()` throws.\n *\n * Optional and additive: omitted, nothing changes, and the server is not\n * involved either way.\n */\n expectedCart?: string;\n}\n\nexport interface CheckoutResult {\n success: boolean;\n redirectUrl?: string;\n invoiceId?: string;\n rewards?: BuyerRewards | null;\n message?: string;\n /**\n * The server's machine-readable refusal identifier when the checkout was\n * refused, e.g. `errors.checkout.price_increased_since_quote` or\n * `errors.checkout.affiliate_code_not_applicable`. Branch on this rather\n * than on `message`, which is localized display copy.\n *\n * The quote-proof family — `errors.checkout.quote_token_invalid`,\n * `errors.checkout.quote_token_expired`, `errors.checkout.quote_token_stale`\n * — says the proof this call submitted could not be honoured: not ours, past\n * its window, or priced for a cart/currency/codes that have since moved. The\n * server refuses rather than pricing without the ceiling, so the caller's\n * response is always the same: `quoteCart()` again, show the buyer the new\n * total, and only then retry. A retry with the same stale token is refused\n * identically.\n *\n * Absent for failures the server never named (transport, timeout, an empty\n * cart caught client-side).\n */\n code?: string;\n}\n\n/**\n * Typed refusal from {@link buildCheckoutUrl}. The function keeps its existing\n * throw-based contract while preserving the server error code and status.\n */\nexport class CheckoutCreateError extends Error {\n readonly code?: string;\n readonly status?: number;\n\n constructor(message: string, options: {\n code?: string;\n status?: number;\n } = {}) {\n super(message);\n this.name = 'CheckoutCreateError';\n this.code = options.code;\n this.status = options.status;\n Object.setPrototypeOf(this, CheckoutCreateError.prototype);\n }\n}\n\ninterface CheckoutApiResponse {\n invoiceId?: string;\n checkoutUrl?: string;\n invoice_id?: string;\n checkout_url?: string;\n uniqid?: string;\n url?: string;\n url_branded?: string;\n rewards?: BuyerRewards | null;\n invoice?: {\n invoiceId?: string;\n checkoutUrl?: string;\n invoice_id?: string;\n checkout_url?: string;\n uniqid?: string;\n url?: string;\n url_branded?: string;\n rewards?: BuyerRewards | null;\n };\n}\n\ninterface NormalizedCheckoutData {\n invoiceId: string;\n checkoutUrl: string;\n rewards: BuyerRewards | null;\n}\n\nconst CHECKOUT_PREFILL_EMAIL_HASH_KEY = 'shoppex_prefill_email';\n\n/**\n * PAYMENT PATH. The single refusal copy for a broken `expectedCart` pin, shared\n * by every entry point that honours the pin so the buyer reads the same\n * sentence whichever one the theme calls. One literal, because two copies drift\n * and the difference would be visible to buyers on the same storefront.\n */\nconst CART_CHANGED_MESSAGE = 'Your cart changed while checkout was starting. Please review it and try again.';\n\n/**\n * PAYMENT PATH. True when the caller pinned a cart and storage no longer holds\n * it — see `CheckoutOptions.expectedCart`. Compared against the exact array the\n * caller is about to bill, which is the only comparison that is conclusive:\n * anything the caller checks itself is one more read BEFORE the read that\n * feeds the request.\n *\n * An omitted pin is not a mismatch. The pin is additive, and a caller that\n * never made the promise is left exactly as it was.\n */\nfunction isExpectedCartMismatch(cart: CartItem[], expectedCart: string | undefined): boolean {\n return expectedCart !== undefined && JSON.stringify(cart) !== expectedCart;\n}\n\nfunction normalizeCoupon(coupon: string | null | undefined): string | null {\n const normalized = coupon?.trim();\n return normalized ? normalized : null;\n}\n\nfunction normalizeEmail(email: string | null | undefined): string | null {\n const normalized = email?.trim();\n return normalized ? normalized : null;\n}\n\nfunction resolvePostPurchaseRedirectUrl(\n redirectUrl: string | null | undefined,\n): { value: string | null; error: null } | { value: null; error: string } {\n const normalized = redirectUrl?.trim();\n if (!normalized) {\n return { value: null, error: null };\n }\n if (!isSafeHttpsRedirectTemplateUrl(normalized)) {\n return { value: null, error: 'redirectUrl must be an absolute HTTPS URL.' };\n }\n if (findRemainingProductRedirectPlaceholders(normalized).length > 0) {\n return { value: null, error: 'redirectUrl must not contain template placeholders.' };\n }\n return { value: normalized, error: null };\n}\n\ninterface PendingCheckoutCreate {\n fingerprint: string;\n key: string;\n}\n\nconst pendingCheckoutCreates = new Map<string, PendingCheckoutCreate>();\n\nfunction acquireCheckoutCreateIdempotency(\n requestTarget: { endpoint: string; baseUrl?: string },\n createIntent: object,\n): PendingCheckoutCreate {\n const fingerprint = JSON.stringify({\n endpoint: requestTarget.endpoint,\n baseUrl: requestTarget.baseUrl ?? null,\n createIntent,\n });\n const existingAttempt = pendingCheckoutCreates.get(fingerprint);\n if (existingAttempt) {\n return existingAttempt;\n }\n\n const attempt = {\n fingerprint,\n key: globalThis.crypto.randomUUID(),\n };\n pendingCheckoutCreates.set(fingerprint, attempt);\n return attempt;\n}\n\nfunction releaseCheckoutCreateIdempotency(\n attempt: PendingCheckoutCreate,\n outcomeDefinitive: boolean,\n): void {\n // Only a parsed server refusal or a validated success makes the outcome\n // definitive. A rejected fetch, timeout, truncated body, or malformed body\n // may follow a committed create, so the next identical intent replays it.\n // An attempt is identified by its key, not object identity, so a late\n // definitive outcome cannot release a newer attempt for the same intent.\n if (outcomeDefinitive && pendingCheckoutCreates.get(attempt.fingerprint)?.key === attempt.key) {\n pendingCheckoutCreates.delete(attempt.fingerprint);\n }\n}\n\nfunction resolveCustomerCheckoutRequestTarget(options: CheckoutOptions): {\n endpoint: string;\n baseUrl?: string;\n} {\n if (\n options.customerCheckoutPath === '/dashboard/api/checkout'\n && typeof window !== 'undefined'\n && typeof window.location?.origin === 'string'\n ) {\n return {\n endpoint: options.customerCheckoutPath,\n baseUrl: window.location.origin,\n };\n }\n\n return { endpoint: '/v1/storefront/invoices/from-cart' };\n}\n\nfunction resolveRequestedCheckoutCurrency(options: CheckoutOptions): string | null {\n // An EXPLICIT currency option pins the request outright — '' means \"the\n // server default\", and neither falls through to the location/config reads.\n if (options.currency !== undefined) {\n return normalizeRequestedCurrency(options.currency);\n }\n return resolveBuyerCurrency(getConfig().currency);\n}\n\n/**\n * The currency an option-less checkout would request right now (location,\n * then config).\n */\nexport function getRequestedCheckoutCurrency(): string | null {\n return resolveBuyerCurrency(getConfig().currency);\n}\n\nfunction normalizeCheckoutFailureMessage(rawMessage: string | null | undefined): string {\n const message = rawMessage?.trim() ?? '';\n if (!message) {\n return 'Checkout failed. Please try again.';\n }\n\n if (isStaleCartProductError(message)) {\n return 'Your cart is outdated. Please add the products again.';\n }\n\n const httpMatch = message.match(/^HTTP\\s+(\\d{3})(?::\\s*(.*))?$/i);\n if (httpMatch) {\n const status = Number(httpMatch[1]);\n const detail = httpMatch[2]?.trim();\n\n if (detail && detail.length > 0) {\n return `Checkout failed: ${detail}`;\n }\n\n if (status >= 500) {\n return 'Checkout is temporarily unavailable. Please try again.';\n }\n\n if (status === 400) {\n return 'Checkout failed. Please check your details and try again.';\n }\n\n if (status === 401 || status === 403) {\n return 'Checkout is currently unavailable for this request.';\n }\n\n return 'Checkout failed. Please try again.';\n }\n\n if (/^internal server error$/i.test(message)) {\n return 'Checkout is temporarily unavailable. Please try again.';\n }\n\n return message;\n}\n\nfunction isStaleCartProductError(rawMessage: string | null | undefined): boolean {\n const message = rawMessage?.trim().toLowerCase() ?? '';\n if (!message) {\n return false;\n }\n\n return message.includes('product not found')\n || message.includes('product not available')\n || message.includes('products are no longer available')\n || message.includes('outdated product');\n}\n\nfunction validateCheckoutUrl(\n checkoutUrl: string,\n checkoutBaseUrl: string | undefined,\n expectedInvoiceId?: string\n): string | null {\n const expectedBaseUrl = checkoutBaseUrl?.trim();\n if (!expectedBaseUrl) {\n return null;\n }\n\n try {\n const parsedCheckoutUrl = new URL(checkoutUrl);\n const parsedExpectedBaseUrl = new URL(expectedBaseUrl);\n\n if (parsedCheckoutUrl.origin !== parsedExpectedBaseUrl.origin) {\n return null;\n }\n\n const normalizedPath = parsedCheckoutUrl.pathname.replace(/\\/+$/, '');\n const normalizedBasePath = parsedExpectedBaseUrl.pathname.replace(/\\/+$/, '');\n const expectedInvoicePath = `${normalizedBasePath}/invoice/`.replace(/\\/{2,}/g, '/');\n if (!normalizedPath.startsWith(expectedInvoicePath)) {\n return null;\n }\n\n const invoiceIdSegment = normalizedPath.slice(expectedInvoicePath.length);\n if (!invoiceIdSegment || invoiceIdSegment.includes('/')) {\n return null;\n }\n\n if (expectedInvoiceId) {\n const normalizedExpectedInvoiceId = expectedInvoiceId.trim();\n const invoiceIdFromUrl = decodeURIComponent(invoiceIdSegment);\n if (!normalizedExpectedInvoiceId || invoiceIdFromUrl !== normalizedExpectedInvoiceId) {\n return null;\n }\n }\n\n return parsedCheckoutUrl.toString();\n } catch {\n return null;\n }\n}\n\nfunction buildCheckoutUrlFromInvoiceId(\n checkoutBaseUrl: string | undefined,\n invoiceId: string\n): string | null {\n const normalizedBaseUrl = checkoutBaseUrl?.trim();\n if (!normalizedBaseUrl) {\n return null;\n }\n\n try {\n const baseUrl = new URL(normalizedBaseUrl);\n const basePath = baseUrl.pathname.replace(/\\/+$/, '');\n baseUrl.pathname = `${basePath}/invoice/${encodeURIComponent(invoiceId)}`.replace(/\\/{2,}/g, '/');\n baseUrl.search = '';\n baseUrl.hash = '';\n return baseUrl.toString();\n } catch {\n return null;\n }\n}\n\n/**\n * The buyer's cookie banner choice on this storefront, when it recorded one.\n * The hosted checkout is another site and cannot read the cookie, yet sends the\n * shop's Purchase pixels only under the same choice, so the value travels in\n * the checkout URL's hash (never sent to a server).\n */\nfunction readStorefrontConsentValue(): string | null {\n if (typeof document === 'undefined' || typeof document.cookie !== 'string') return null;\n const value = document.cookie\n .split(';')\n .map((part) => part.trim())\n .find((part) => part.startsWith(`${COOKIE_CONSENT_COOKIE}=`))\n ?.slice(COOKIE_CONSENT_COOKIE.length + 1);\n return parseCookieConsentValue(value) ? value! : null;\n}\n\nfunction appendCheckoutUrlOptions(\n checkoutUrl: string,\n options: { email?: string | null; locale?: string },\n): string {\n const normalizedEmail = normalizeEmail(options.email);\n const normalizedLocale = typeof options.locale === 'string' ? options.locale.trim() : '';\n const consent = readStorefrontConsentValue();\n\n if (!normalizedEmail && !normalizedLocale && !consent) {\n return checkoutUrl;\n }\n\n try {\n const parsedCheckoutUrl = new URL(checkoutUrl);\n if (normalizedLocale) {\n parsedCheckoutUrl.searchParams.set('locale', normalizedLocale);\n }\n if (normalizedEmail || consent) {\n const hashParams = new URLSearchParams(parsedCheckoutUrl.hash.startsWith('#')\n ? parsedCheckoutUrl.hash.slice(1)\n : parsedCheckoutUrl.hash);\n if (normalizedEmail) hashParams.set(CHECKOUT_PREFILL_EMAIL_HASH_KEY, normalizedEmail);\n if (consent) hashParams.set(COOKIE_CONSENT_CHECKOUT_HASH_KEY, consent);\n parsedCheckoutUrl.hash = hashParams.toString();\n }\n return parsedCheckoutUrl.toString();\n } catch {\n return checkoutUrl;\n }\n}\n\nfunction normalizeCheckoutResponse(\n response: CheckoutApiResponse | undefined,\n checkoutBaseUrl: string | undefined\n): NormalizedCheckoutData | null {\n const nestedInvoice = response?.invoice;\n const invoiceId = response?.invoiceId?.trim()\n || response?.invoice_id?.trim()\n || response?.uniqid?.trim()\n || nestedInvoice?.invoiceId?.trim()\n || nestedInvoice?.invoice_id?.trim()\n || nestedInvoice?.uniqid?.trim();\n let checkoutUrl = response?.checkoutUrl?.trim()\n || response?.checkout_url?.trim()\n || response?.url_branded?.trim()\n || response?.url?.trim()\n || nestedInvoice?.checkoutUrl?.trim()\n || nestedInvoice?.checkout_url?.trim()\n || nestedInvoice?.url_branded?.trim()\n || nestedInvoice?.url?.trim();\n\n if (!checkoutUrl && invoiceId && nestedInvoice) {\n checkoutUrl = buildCheckoutUrlFromInvoiceId(checkoutBaseUrl, invoiceId) ?? undefined;\n }\n\n if (!invoiceId || !checkoutUrl) {\n return null;\n }\n\n return {\n invoiceId,\n checkoutUrl,\n rewards: response?.rewards ?? nestedInvoice?.rewards ?? null,\n };\n}\n\nfunction resolveCheckoutOptions(\n couponOrOptions?: string | CheckoutOptions,\n options?: CheckoutOptions\n): CheckoutOptions {\n if (typeof couponOrOptions === 'string') {\n return {\n ...options,\n coupon: couponOrOptions,\n };\n }\n\n return couponOrOptions ?? options ?? {};\n}\n\nfunction normalizeAffiliateCode(options: CheckoutOptions, storedAffiliateCode: string | null): string | null {\n const explicitCode = options.affiliateCode ?? options.referralCode;\n // Tri-state, mirroring `coupon`: an explicit empty string means \"none\" and\n // must suppress the storage re-read. Only `undefined` lets the SDK resolve\n // the code itself — otherwise a referral captured after the quote was\n // rendered would be applied to a total the buyer never saw.\n if (typeof explicitCode === 'string') {\n const normalized = explicitCode.trim().toLowerCase();\n return normalized.length > 0 ? normalized : null;\n }\n\n return storedAffiliateCode?.trim().toLowerCase() ?? getAffiliateCode();\n}\n\nfunction resolveCheckoutCodes(options: CheckoutOptions): {\n coupon: string | null;\n affiliateCode: string | null;\n} {\n const storedCode = getCartCoupon();\n const storedSource = getCartCouponSource();\n const coupon = options.coupon === undefined\n ? (storedSource === 'COUPON' ? storedCode : null)\n : normalizeCoupon(options.coupon);\n const storedAffiliateCode = options.coupon === undefined && storedSource === 'AFFILIATE'\n ? storedCode\n : null;\n\n return {\n coupon,\n affiliateCode: normalizeAffiliateCode(options, storedAffiliateCode),\n };\n}\n\nfunction mapCartItemsForApi(items: CartItem[]) {\n const normalizeVariantIdForApi = (value: string | null | undefined): string | null => {\n const normalized = value?.trim();\n if (!normalized) return null;\n // Themes use \"default\" as a sentinel for \"no variant selected\".\n // Backend expects `null` in that case.\n if (normalized.toLowerCase() === 'default') return null;\n return normalized;\n };\n\n return items.map((item) => ({\n product_id: item.product_id,\n variant_id: normalizeVariantIdForApi(item.variant_id),\n quantity: item.quantity,\n addons: item.addons?.map((a: CartAddon) => ({ id: a.id, quantity: a.quantity ?? 1 })),\n custom_fields: item.custom_fields,\n price_variant_id: item.price_variant_id || null,\n pay_what_you_want_price: item.pay_what_you_want_price,\n }));\n}\n\nexport async function checkout(\n couponOrOptions?: string | CheckoutOptions,\n options?: CheckoutOptions\n): Promise<CheckoutResult> {\n const resolvedOptions = resolveCheckoutOptions(couponOrOptions, options);\n return performCheckout(resolvedOptions);\n}\n\nasync function performCheckout(\n resolvedOptions: CheckoutOptions,\n): Promise<CheckoutResult> {\n const { autoRedirect = true, email } = resolvedOptions;\n const checkoutCodes = resolveCheckoutCodes(resolvedOptions);\n const normalizedCoupon = checkoutCodes.coupon;\n const normalizedEmail = normalizeEmail(email);\n const normalizedAffiliateCode = checkoutCodes.affiliateCode;\n const requestedCurrency = resolveRequestedCheckoutCurrency(resolvedOptions);\n const postPurchaseRedirect = resolvePostPurchaseRedirectUrl(resolvedOptions.redirectUrl);\n\n const cart = getCart();\n if (cart.length === 0) {\n return {\n success: false,\n message: 'Cart is empty',\n };\n }\n\n // PAYMENT PATH. The cart the caller approved, compared against the cart this\n // call will actually POST — see `CheckoutOptions.expectedCart`. Refused\n // before the backup and before the request, so a cart that changed under the\n // caller is never billed and nothing is left half-done.\n if (isExpectedCartMismatch(cart, resolvedOptions.expectedCart)) {\n return {\n success: false,\n message: CART_CHANGED_MESSAGE,\n };\n }\n if (postPurchaseRedirect.error) {\n return {\n success: false,\n message: postPurchaseRedirect.error,\n };\n }\n\n createCartBackup();\n\n const config = getConfig();\n const checkoutRequestTarget = resolveCustomerCheckoutRequestTarget(resolvedOptions);\n\n const createIntent = {\n shop_slug: config.storeSlug,\n cart: mapCartItemsForApi(cart),\n email: normalizedEmail,\n coupon: normalizedCoupon,\n currency: requestedCurrency,\n return_url: postPurchaseRedirect.value ?? undefined,\n affiliate_code: normalizedAffiliateCode,\n // Proof of the total the buyer approved, from the last quoteCart(). Sent\n // automatically so the server can refuse an invoice priced above it.\n // Undefined when nothing has been quoted this session — the endpoint\n // treats that exactly as an older SDK.\n quote_token: resolvedOptions.quoteToken !== undefined\n ? (resolvedOptions.quoteToken ?? undefined)\n : (getLatestQuoteToken() ?? undefined),\n // Where the buyer came from: their analytics sessions after a yes on the\n // cookie banner, `declined` after a no. The server looks up the sources.\n attribution: checkoutAttribution(config.storeSlug),\n };\n const createAttempt = acquireCheckoutCreateIdempotency(checkoutRequestTarget, createIntent);\n const response = await post<CheckoutApiResponse>(\n checkoutRequestTarget.endpoint,\n createIntent,\n {\n retries: 0,\n baseUrl: checkoutRequestTarget.baseUrl,\n headers: {\n 'X-Idempotency-Key': createAttempt.key,\n },\n }\n );\n if (!response.success || !response.data) {\n releaseCheckoutCreateIdempotency(createAttempt, response.responseDefinitive === true);\n if (isStaleCartProductError(response.message)) {\n clearCart();\n }\n return {\n success: false,\n message: normalizeCheckoutFailureMessage(response.message),\n // The server's machine-readable refusal, preserved so callers can react\n // to e.g. `errors.checkout.price_increased_since_quote` without matching\n // localized copy.\n ...(response.code ? { code: response.code } : {}),\n };\n }\n\n const checkoutData = normalizeCheckoutResponse(response.data, config.checkoutBaseUrl);\n if (!checkoutData) {\n return {\n success: false,\n message: 'Failed to create invoice',\n };\n }\n\n const { invoiceId } = checkoutData;\n const safeCheckoutUrl = validateCheckoutUrl(\n checkoutData.checkoutUrl,\n config.checkoutBaseUrl,\n invoiceId\n );\n if (!safeCheckoutUrl) {\n return {\n success: false,\n message: 'Failed to create invoice',\n };\n }\n\n releaseCheckoutCreateIdempotency(createAttempt, true);\n\n // One checkout_started per created invoice: dedupes accidental duplicate\n // sends without dropping a buyer's genuine second order in the same session.\n void trackAffiliateEvent('checkout_started', {\n code: normalizedAffiliateCode,\n dedupeKey: `inv:${invoiceId}`,\n });\n\n const checkoutUrlWithPrefill = appendCheckoutUrlOptions(safeCheckoutUrl, {\n email: normalizedEmail,\n locale: resolvedOptions.locale ?? config.locale,\n });\n\n if (autoRedirect) {\n if (typeof window !== 'undefined' && window?.location) {\n window.location.href = checkoutUrlWithPrefill;\n clearCart();\n }\n }\n\n return {\n success: true,\n redirectUrl: checkoutUrlWithPrefill,\n invoiceId,\n rewards: checkoutData.rewards,\n };\n}\n\n/**\n * Build checkout URL by creating invoice first.\n * Returns the checkout URL for the created invoice.\n *\n * PAYMENT PATH. \"Build a URL\" names what this returns, not a lighter way to\n * price a cart: it POSTs the same invoice-creating endpoint as `checkout()` and\n * bills whatever storage holds when it reads. It therefore honours\n * `CheckoutOptions.expectedCart` on exactly the same terms — a pinned cart that\n * moved is refused, not invoiced.\n *\n * A refusal throws, like every other refusal on this function: the success\n * shape is a URL string, so there is no in-band value that a caller could\n * mistake for one. The thrown message is the buyer-facing copy, identical to\n * the sentence `checkout()` returns, and callers that already handle the\n * `Cart is empty` throw handle this one unchanged.\n */\nexport async function buildCheckoutUrl(\n couponOrOptions?: string | CheckoutOptions,\n options?: CheckoutOptions\n): Promise<string> {\n const resolvedOptions = resolveCheckoutOptions(couponOrOptions, options);\n return performBuildCheckoutUrl(resolvedOptions);\n}\n\nasync function performBuildCheckoutUrl(\n resolvedOptions: CheckoutOptions,\n): Promise<string> {\n const { email } = resolvedOptions;\n const checkoutCodes = resolveCheckoutCodes(resolvedOptions);\n const normalizedCoupon = checkoutCodes.coupon;\n const normalizedEmail = normalizeEmail(email);\n const normalizedAffiliateCode = checkoutCodes.affiliateCode;\n const requestedCurrency = resolveRequestedCheckoutCurrency(resolvedOptions);\n const postPurchaseRedirect = resolvePostPurchaseRedirectUrl(resolvedOptions.redirectUrl);\n\n const cart = getCart();\n if (cart.length === 0) {\n throw new Error('Cart is empty');\n }\n\n // PAYMENT PATH. Same position `checkout()` puts it in: after the empty-cart\n // check and before anything is created or sent. This path has no cart backup\n // to write, so the request is the first side effect there is — refusing here\n // means a cart that changed under the caller never reaches the endpoint, and\n // the buyer's cart is left exactly as the interfering write left it. It\n // matters most with no quote token in play, because then nothing downstream\n // carries an approved-total ceiling either.\n if (isExpectedCartMismatch(cart, resolvedOptions.expectedCart)) {\n throw new Error(CART_CHANGED_MESSAGE);\n }\n if (postPurchaseRedirect.error) {\n throw new Error(postPurchaseRedirect.error);\n }\n\n const config = getConfig();\n const checkoutRequestTarget = resolveCustomerCheckoutRequestTarget(resolvedOptions);\n\n const createIntent = {\n shop_slug: config.storeSlug,\n cart: mapCartItemsForApi(cart),\n email: normalizedEmail,\n coupon: normalizedCoupon,\n currency: requestedCurrency,\n return_url: postPurchaseRedirect.value ?? undefined,\n affiliate_code: normalizedAffiliateCode,\n // Same invoice-creating endpoint as `checkout()`, so it carries the same\n // proof of the approved total. \"Build a URL\" describes what this returns\n // to the caller, not a different way to price a cart — omitting the\n // token here left a public path on which the server had nothing to check\n // the invoice against. Same optional semantics: undefined when nothing\n // was quoted this session.\n quote_token: resolvedOptions.quoteToken !== undefined\n ? (resolvedOptions.quoteToken ?? undefined)\n : (getLatestQuoteToken() ?? undefined),\n };\n const createAttempt = acquireCheckoutCreateIdempotency(checkoutRequestTarget, createIntent);\n const response = await post<CheckoutApiResponse>(\n checkoutRequestTarget.endpoint,\n createIntent,\n {\n retries: 0,\n baseUrl: checkoutRequestTarget.baseUrl,\n headers: {\n 'X-Idempotency-Key': createAttempt.key,\n },\n }\n );\n if (!response.success || !response.data) {\n releaseCheckoutCreateIdempotency(createAttempt, response.responseDefinitive === true);\n if (isStaleCartProductError(response.message)) {\n clearCart();\n }\n throw new CheckoutCreateError(normalizeCheckoutFailureMessage(response.message), {\n ...(response.code ? { code: response.code } : {}),\n ...(response.status !== undefined ? { status: response.status } : {}),\n });\n }\n const checkoutData = normalizeCheckoutResponse(response.data, config.checkoutBaseUrl);\n if (!checkoutData) {\n throw new Error('Failed to create invoice');\n }\n\n const safeCheckoutUrl = validateCheckoutUrl(\n checkoutData.checkoutUrl,\n config.checkoutBaseUrl,\n checkoutData.invoiceId\n );\n if (!safeCheckoutUrl) {\n throw new Error('Failed to create invoice');\n }\n\n releaseCheckoutCreateIdempotency(createAttempt, true);\n\n // Same funnel point as checkout(): both entry points create the invoice.\n void trackAffiliateEvent('checkout_started', {\n code: normalizedAffiliateCode,\n dedupeKey: `inv:${checkoutData.invoiceId}`,\n });\n\n return appendCheckoutUrlOptions(safeCheckoutUrl, {\n email: normalizedEmail,\n locale: resolvedOptions.locale ?? config.locale,\n });\n}\n\n/**\n * @deprecated Use buildCheckoutUrl instead.\n * Sync version is no longer supported as invoice creation requires API call.\n */\nexport function buildCheckoutUrlSync(): never {\n throw new Error('buildCheckoutUrlSync is deprecated. Use buildCheckoutUrl (async) instead.');\n}\n","/**\n * Coupons Module\n *\n * Coupon validation before checkout.\n */\n\nimport { post } from '../core/client';\nimport { getShopId } from '../core/config';\nimport { getStore } from './store';\nimport { getCart } from './cart';\nimport type { SDKResponse, CouponValidation, CouponValidationOptions } from '../types';\n\nasync function resolveShopId(): Promise<string | null> {\n const cachedShopId = getShopId();\n if (cachedShopId) {\n return cachedShopId;\n }\n\n const storeResult = await getStore();\n if (!storeResult.success || !storeResult.data?.id) {\n return null;\n }\n\n return storeResult.data.id;\n}\n\nexport async function validateCoupon(\n code: string,\n productOrOptions?: string | CouponValidationOptions\n): Promise<SDKResponse<CouponValidation>> {\n const trimmedCode = code.trim();\n if (!trimmedCode) {\n return {\n success: false,\n message: 'Coupon code is required',\n };\n }\n\n const payload: Record<string, unknown> = {\n code: trimmedCode,\n };\n const productId = typeof productOrOptions === 'string'\n ? productOrOptions\n : productOrOptions?.productId;\n const variantId = typeof productOrOptions === 'string'\n ? undefined\n : productOrOptions?.variantId;\n\n if (variantId && !productId) {\n return {\n success: false,\n message: 'productId is required when variantId is provided',\n };\n }\n\n if (productId) {\n payload.product_id = productId;\n if (variantId) {\n payload.variant_id = variantId;\n }\n } else {\n const cart = getCart();\n if (cart.length === 0) {\n return {\n success: false,\n message: 'Cart is empty',\n };\n }\n\n const shopId = await resolveShopId();\n if (!shopId) {\n return {\n success: false,\n message: 'Failed to resolve store',\n };\n }\n\n payload.cart = JSON.stringify({\n shop_id: shopId,\n products: cart.map((item) => ({\n uniqid: item.product_id,\n quantity: item.quantity,\n variant_id: item.variant_id,\n price_variant_id: item.price_variant_id,\n addons: item.addons?.map((addon) => ({\n id: addon.id,\n quantity: addon.quantity ?? 1,\n })),\n })),\n });\n }\n\n const response = await post<CouponValidation>(\n '/v1/storefront/coupons/check',\n payload\n );\n\n return response;\n}\n","/**\n * Reviews Module\n *\n * Shop-level feedback/reviews.\n * Note: Shoppex has shop-level feedback, not product-level reviews.\n */\n\nimport { forwardFailure, get } from '../core/client';\nimport { getConfig } from '../core/config';\nimport { buildEndpoint } from '../core/endpoint';\nimport type { SDKResponse, Feedback, ShopReviewsPage } from '../types';\n\nconst REVIEWS_PAGE_LIMIT = 100;\nconst REVIEWS_CACHE_TTL = 2 * 60 * 1000;\n\nfunction toFiniteNumber(value: unknown): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value;\n }\n\n if (typeof value === 'string' && value.trim() !== '') {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : null;\n }\n\n return null;\n}\n\nfunction firstString(...values: unknown[]): string | undefined {\n for (const value of values) {\n if (typeof value === 'string' && value.length > 0) {\n return value;\n }\n }\n\n return undefined;\n}\n\nfunction normalizeFeedback(raw: Feedback, index: number): Feedback {\n const record = raw as Feedback & Record<string, unknown>;\n const rating = toFiniteNumber(record.rating) ?? toFiniteNumber(record.score) ?? 0;\n const comment = firstString(record.comment, record.message);\n const author = firstString(record.author, record.customer_name);\n const createdAt = record.created_at ?? record.createdAt;\n const created_at =\n typeof createdAt === 'number' || typeof createdAt === 'string'\n ? String(createdAt)\n : '';\n const id = firstString(record.id, record.uniqid) ?? `review:${created_at || index}`;\n\n return {\n ...record,\n id,\n rating,\n ...(comment ? { comment } : {}),\n ...(author ? { author } : {}),\n created_at,\n };\n}\n\n/** `code` of a filtered request the API answered without applying the filter. */\nexport const PRODUCT_FILTER_UNSUPPORTED = 'reviews_product_filter_unsupported';\n\nexport interface ShopReviewsPageOptions {\n /**\n * One product's reviews, by the product's public id (the `id` the catalog\n * carries). The page's `summary` then counts that product's reviews only.\n */\n product?: string | null;\n}\n\nexport async function getShopReviewsPage(\n cursor?: string | null,\n options: ShopReviewsPageOptions = {},\n): Promise<SDKResponse<ShopReviewsPage>> {\n const config = getConfig();\n const query = new URLSearchParams();\n query.set('limit', String(REVIEWS_PAGE_LIMIT));\n if (typeof cursor === 'string' && cursor.trim().length > 0) {\n query.set('cursor', cursor);\n }\n const product = typeof options.product === 'string' ? options.product.trim() : '';\n if (product) {\n query.set('product', product);\n }\n const querySuffix = `?${query.toString()}`;\n\n const response = await get<ShopReviewsPage>(\n `${buildEndpoint('/v1/storefront/feedback/shop/:storeSlug', {\n storeSlug: config.storeSlug,\n })}${querySuffix}`,\n {\n cache: {\n key: `reviews:${config.storeSlug}:${product || 'all'}:${cursor ?? 'start'}:${REVIEWS_PAGE_LIMIT}`,\n ttl: REVIEWS_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n // A filtered request is only answered when the API says it applied that\n // filter. An API that predates `product` ignores it and returns the whole\n // shop's reviews, which a caller would otherwise show as this product's.\n if (product && response.data.product !== product) {\n // The server did answer (2xx), so `status` and `responseReceived` say\n // so: this is a refusal of an unsupported filter, not a transport failure\n // a caller should retry or report as offline.\n return {\n success: false,\n message: 'Reviews for a single product are not available from this store yet.',\n code: PRODUCT_FILTER_UNSUPPORTED,\n status: 200,\n responseReceived: true,\n };\n }\n return {\n success: true,\n data: {\n ...response.data,\n feedback: response.data.feedback.map(normalizeFeedback),\n },\n };\n }\n\n return forwardFailure(response);\n}\n\nexport async function getShopReviews(): Promise<SDKResponse<Feedback[]>> {\n const allFeedback: Feedback[] = [];\n const seenCursors = new Set<string>();\n let cursor: string | null = null;\n\n while (true) {\n const response = await getShopReviewsPage(cursor);\n if (!response.success || !response.data) {\n return {\n success: false,\n message: response.message,\n data: [],\n };\n }\n\n allFeedback.push(...response.data.feedback);\n\n const pagination = response.data.pagination;\n if (!pagination?.has_more || !pagination.next_cursor) {\n break;\n }\n\n if (seenCursors.has(pagination.next_cursor)) {\n break;\n }\n\n seenCursors.add(pagination.next_cursor);\n cursor = pagination.next_cursor;\n }\n\n return {\n success: true,\n data: allFeedback,\n };\n}\n","import type { Product, PriceVariant, ProductVariant } from '../types/index.js';\n\ntype VariantLike =\n | Pick<ProductVariant, 'stock' | 'orderable' >\n | Pick<PriceVariant, 'stock' | 'orderable' >;\n\ntype ProductLike = Pick<Product, 'type' | 'stock' | 'orderable' | 'on_hold' | 'price_variants' | 'variants'> & {\n onHold?: boolean | number | string | null;\n is_on_hold?: boolean | number | string | null;\n isOnHold?: boolean | number | string | null;\n};\n\n/** The sentinel every predicate in this module already treats as \"unbounded\". */\nconst UNLIMITED_STOCK = -1;\n\n\nfunction normalizeStockValue(value: unknown): number | null {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n return null;\n }\n\n return Math.trunc(value);\n}\n\nfunction isTruthyFlag(value: unknown): boolean {\n if (value === true) return true;\n if (typeof value === 'number' && Number.isFinite(value)) return value !== 0;\n if (typeof value === 'string') {\n const normalized = value.trim().toLowerCase();\n return normalized === 'true' || normalized === '1';\n }\n return false;\n}\n\nfunction isProductOnHold(product: ProductLike | null | undefined): boolean {\n if (!product) return false;\n return isTruthyFlag(product.on_hold)\n || isTruthyFlag(product.onHold)\n || isTruthyFlag(product.is_on_hold)\n || isTruthyFlag(product.isOnHold);\n}\n\nfunction collectVariantStocks(product: ProductLike): number[] {\n const priceVariants = Array.isArray(product.price_variants) ? product.price_variants : [];\n if (priceVariants.length > 0) {\n return priceVariants.map((variant) => resolveVariantStockValue(variant));\n }\n\n const legacyVariants = Array.isArray(product.variants) ? product.variants : [];\n\n return legacyVariants.map((variant) => resolveVariantStockValue(variant));\n}\n\nexport function resolveVariantStockValue(variant: VariantLike | null | undefined): number {\n const normalized = normalizeStockValue(variant?.stock);\n return normalized ?? UNLIMITED_STOCK;\n}\n\nexport function resolveDisplayStock(product: ProductLike | null | undefined): number {\n if (!product) {\n return UNLIMITED_STOCK;\n }\n\n if (typeof product.type === 'string' && product.type.toUpperCase() === 'SERIALS') {\n return normalizeStockValue(product.stock) ?? UNLIMITED_STOCK;\n }\n\n const variantStocks = collectVariantStocks(product);\n if (variantStocks.length > 0) {\n // A single unbounded option makes the product unbounded.\n if (variantStocks.some((stock) => stock < 0)) {\n return UNLIMITED_STOCK;\n }\n\n const total = variantStocks.reduce((sum, stock) => sum + Math.max(stock, 0), 0);\n return total;\n }\n\n return normalizeStockValue(product.stock) ?? UNLIMITED_STOCK;\n}\n\nexport function isProductOutOfStock(product: ProductLike | null | undefined): boolean {\n // `on_hold` is a merchant pause, not a supply signal — it forces unavailable\n // BEFORE any `orderable` widening can apply.\n if (isProductOnHold(product)) return true;\n return resolveDisplayStock(product) === 0;\n}\n\nexport function isProductInStock(product: ProductLike | null | undefined): boolean {\n return !isProductOutOfStock(product);\n}\n\nexport function isVariantOutOfStock(variant: VariantLike | null | undefined): boolean {\n return resolveVariantStockValue(variant) === 0;\n}\n","import type { Product, ProductGroup } from '../types/index.js';\nimport {\n buildStorefrontProductLookup,\n getMergedStorefrontProducts,\n getStorefrontGroupProducts,\n} from './storefront-catalog.js';\nimport { isProductInStock } from './storefront-stock.js';\n\nexport interface StorefrontSearchFilterOptions {\n hideOutOfStock?: boolean;\n maxResults?: number;\n}\n\nexport type StorefrontCatalogSearchItem =\n | { type: 'product'; product: Product }\n // Groups only carry `product_uniqids`; `products` holds the resolved product\n // objects (in group order) so consumers never re-resolve references themselves.\n | { type: 'group'; group: ProductGroup; products: Product[] };\n\nexport function stripHtmlFromText(value: string | null | undefined): string {\n if (!value) return '';\n return value.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').trim();\n}\n\nexport function normalizeSearchQuery(query: string): string {\n return query.trim().toLowerCase();\n}\n\nfunction pushSearchPart(parts: string[], value: string | null | undefined): void {\n const normalized = stripHtmlFromText(value).toLowerCase();\n if (normalized) {\n parts.push(normalized);\n }\n}\n\nexport function collectProductSearchHaystack(product: Product): string[] {\n const parts: string[] = [];\n\n pushSearchPart(parts, product.title);\n pushSearchPart(parts, product.slug ?? undefined);\n pushSearchPart(parts, product.description);\n\n for (const highlight of product.product_highlights ?? []) {\n pushSearchPart(parts, highlight);\n }\n\n for (const variant of product.variants ?? []) {\n pushSearchPart(parts, variant.title);\n }\n\n for (const variant of product.price_variants ?? []) {\n pushSearchPart(parts, variant.title ?? variant.label);\n }\n\n return parts;\n}\n\nexport function productMatchesSearchQuery(product: Product, query: string): boolean {\n const normalized = normalizeSearchQuery(query);\n if (!normalized) return false;\n\n return collectProductSearchHaystack(product).some((haystack) => haystack.includes(normalized));\n}\n\nexport function groupMatchesSearchQuery(group: ProductGroup, query: string): boolean {\n const normalized = normalizeSearchQuery(query);\n if (!normalized) return false;\n\n const title = stripHtmlFromText(group.title).toLowerCase();\n const slug = stripHtmlFromText(group.slug ?? group.name ?? undefined).toLowerCase();\n const description = stripHtmlFromText(group.description).toLowerCase();\n\n return title.includes(normalized)\n || slug.includes(normalized)\n || description.includes(normalized);\n}\n\nexport function filterProductsBySearchQuery(\n products: Product[],\n query: string,\n options?: StorefrontSearchFilterOptions,\n): Product[] {\n const normalized = normalizeSearchQuery(query);\n if (!normalized) return [];\n\n let results = products.filter((product) => productMatchesSearchQuery(product, normalized));\n\n if (options?.hideOutOfStock) {\n results = results.filter((product) => isProductInStock(product));\n }\n\n if (options?.maxResults != null) {\n return results.slice(0, options.maxResults);\n }\n\n return results;\n}\n\nfunction groupHasVisibleProducts(\n groupProducts: Product[],\n hideOutOfStock: boolean,\n): boolean {\n if (groupProducts.length === 0) return false;\n if (!hideOutOfStock) return true;\n return groupProducts.some((product) => isProductInStock(product));\n}\n\nexport function searchMergedStorefrontCatalogItems(\n products: Product[],\n groups: ProductGroup[],\n query: string,\n options?: StorefrontSearchFilterOptions,\n): StorefrontCatalogSearchItem[] {\n const normalized = normalizeSearchQuery(query);\n if (!normalized) return [];\n\n const hideOutOfStock = options?.hideOutOfStock === true;\n const coveredProductIds = new Set<string>();\n const coveredGroupIds = new Set<string>();\n const results: StorefrontCatalogSearchItem[] = [];\n // Build the uniqid lookup once per search run; groups resolve against it.\n const lookup = buildStorefrontProductLookup(products);\n\n for (const group of groups) {\n const groupKey = group.uniqid ?? group.id;\n if (!groupKey || coveredGroupIds.has(groupKey)) continue;\n if (!groupMatchesSearchQuery(group, normalized)) continue;\n\n const groupProducts = getStorefrontGroupProducts(group, lookup);\n if (!groupHasVisibleProducts(groupProducts, hideOutOfStock)) continue;\n\n coveredGroupIds.add(groupKey);\n for (const product of groupProducts) {\n if (product?.uniqid) coveredProductIds.add(product.uniqid);\n }\n results.push({ type: 'group', group, products: groupProducts });\n }\n\n const merged = getMergedStorefrontProducts(products);\n for (const product of merged) {\n if (!product?.uniqid || coveredProductIds.has(product.uniqid)) continue;\n if (!productMatchesSearchQuery(product, normalized)) continue;\n if (hideOutOfStock && !isProductInStock(product)) continue;\n coveredProductIds.add(product.uniqid);\n results.push({ type: 'product', product });\n }\n\n if (options?.maxResults != null) {\n return results.slice(0, options.maxResults);\n }\n\n return results;\n}\n\nexport function searchMergedStorefrontCatalog(\n products: Product[],\n groups: ProductGroup[],\n query: string,\n options?: StorefrontSearchFilterOptions,\n): Product[] {\n const items = searchMergedStorefrontCatalogItems(products, groups, query, options);\n const matchedIds = new Set<string>();\n const results: Product[] = [];\n\n const addProduct = (product: Product) => {\n if (!product?.uniqid || matchedIds.has(product.uniqid)) return;\n if (options?.hideOutOfStock && !isProductInStock(product)) return;\n matchedIds.add(product.uniqid);\n results.push(product);\n };\n\n for (const item of items) {\n if (item.type === 'product') {\n addProduct(item.product);\n continue;\n }\n\n for (const product of item.products) {\n addProduct(product);\n }\n }\n\n if (options?.maxResults != null) {\n return results.slice(0, options.maxResults);\n }\n\n return results;\n}\n","import { getStorefront } from './store.js';\nimport { isInitialized } from '../core/config.js';\nimport {\n searchMergedStorefrontCatalog,\n searchMergedStorefrontCatalogItems,\n type StorefrontCatalogSearchItem,\n} from '../utils/storefront-search.js';\nimport type { SDKResponse, Product } from '../types/index.js';\n\nexport interface SearchOptions {\n hideOutOfStock?: boolean;\n maxResults?: number;\n}\n\nexport type { StorefrontCatalogSearchItem };\n\nexport async function searchCatalogItems(\n query: string,\n options?: SearchOptions,\n): Promise<SDKResponse<StorefrontCatalogSearchItem[]>> {\n if (!isInitialized()) {\n return { success: false, message: 'SDK not initialized' };\n }\n\n const trimmed = query.trim();\n if (!trimmed) {\n return { success: true, data: [] };\n }\n\n const storefront = await getStorefront();\n if (!storefront.success || !storefront.data) {\n return {\n success: false,\n message: storefront.message ?? 'Failed to fetch storefront catalog',\n };\n }\n\n const results = searchMergedStorefrontCatalogItems(\n storefront.data.products ?? [],\n storefront.data.groups ?? [],\n trimmed,\n {\n hideOutOfStock: options?.hideOutOfStock,\n maxResults: options?.maxResults,\n },\n );\n\n return { success: true, data: results };\n}\n\nexport async function searchProducts(\n query: string,\n options?: SearchOptions,\n): Promise<SDKResponse<Product[]>> {\n if (!isInitialized()) {\n return { success: false, message: 'SDK not initialized' };\n }\n\n const trimmed = query.trim();\n if (!trimmed) {\n return { success: true, data: [] };\n }\n\n const storefront = await getStorefront();\n if (!storefront.success || !storefront.data) {\n return {\n success: false,\n message: storefront.message ?? 'Failed to fetch storefront catalog',\n };\n }\n\n const results = searchMergedStorefrontCatalog(\n storefront.data.products ?? [],\n storefront.data.groups ?? [],\n trimmed,\n {\n hideOutOfStock: options?.hideOutOfStock,\n maxResults: options?.maxResults,\n },\n );\n\n return { success: true, data: results };\n}\n","/**\n * Invoices Module\n *\n * Invoice status checking after payment.\n */\n\nimport { get } from '../core/client';\nimport { buildEndpoint } from '../core/endpoint';\nimport type { SDKResponse, Invoice } from '../types';\n\nfunction normalizeInvoiceId(invoiceId: string): string | null {\n const normalized = invoiceId.trim();\n if (!normalized) {\n return null;\n }\n return normalized;\n}\n\nexport async function getInvoice(\n invoiceId: string\n): Promise<SDKResponse<Invoice>> {\n const normalizedInvoiceId = normalizeInvoiceId(invoiceId);\n if (!normalizedInvoiceId) {\n return {\n success: false,\n message: 'Invoice ID is required',\n };\n }\n\n const response = await get<{ invoice: Invoice }>(\n buildEndpoint('/v1/storefront/invoices/unique/:invoiceId', {\n invoiceId: normalizedInvoiceId,\n })\n );\n if (!response.success) {\n return {\n success: false,\n message: response.message,\n };\n }\n\n if (!response.data?.invoice) {\n return {\n success: false,\n message: 'Invalid invoice response',\n };\n }\n\n return {\n success: true,\n data: response.data.invoice,\n };\n}\n\nexport async function getInvoiceStatus(\n invoiceId: string\n): Promise<SDKResponse<{ status: string }>> {\n const normalizedInvoiceId = normalizeInvoiceId(invoiceId);\n if (!normalizedInvoiceId) {\n return {\n success: false,\n message: 'Invoice ID is required',\n };\n }\n\n const response = await get<{ invoice: { status: string } }>(\n buildEndpoint('/v1/storefront/invoices/status/:invoiceId', {\n invoiceId: normalizedInvoiceId,\n })\n );\n if (!response.success) {\n return {\n success: false,\n message: response.message,\n };\n }\n\n if (!response.data?.invoice?.status) {\n return {\n success: false,\n message: 'Invalid invoice status response',\n };\n }\n\n return {\n success: true,\n data: { status: response.data.invoice.status },\n };\n}\n","/**\n * Pages Module\n *\n * API methods for public pages.\n */\n\nimport { forwardFailure, get } from '../core/client';\nimport { getConfig } from '../core/config';\nimport { buildEndpoint } from '../core/endpoint';\nimport type { SDKResponse, Page } from '../types';\n\ninterface PagesResponse {\n pages: Page[];\n}\n\ninterface PageResponse {\n page: Page;\n}\n\nconst PAGES_CACHE_TTL = 5 * 60 * 1000;\n\n/**\n * Get all public pages for the store\n */\nexport async function getPages(): Promise<SDKResponse<Page[]>> {\n const config = getConfig();\n const response = await get<PagesResponse>(\n buildEndpoint('/v1/storefront/shops/name/:storeSlug/pages', {\n storeSlug: config.storeSlug,\n }),\n {\n cache: {\n key: `pages:${config.storeSlug}`,\n ttl: PAGES_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n return {\n success: true,\n data: response.data.pages,\n };\n }\n\n // The failure as the client saw it, `status` included: a storefront has to\n // tell a page that does not exist (404) from an API it could not reach.\n return forwardFailure(response);\n}\n\n/**\n * Get a public page by slug\n */\nexport async function getPage(slug: string): Promise<SDKResponse<Page>> {\n const config = getConfig();\n const response = await get<PageResponse>(\n buildEndpoint('/v1/storefront/shops/name/:storeSlug/pages/:slug', {\n storeSlug: config.storeSlug,\n slug,\n }),\n {\n cache: {\n key: `page:${config.storeSlug}:${slug}`,\n ttl: PAGES_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n return {\n success: true,\n data: response.data.page,\n };\n }\n\n // The failure as the client saw it, `status` included: a storefront has to\n // tell a page that does not exist (404) from an API it could not reach.\n return forwardFailure(response);\n}\n","const NAVIGATION_MENU_SLOT_CONFIG = {\n header: {\n title: 'Header',\n aliases: ['Header Menu'],\n },\n footer: {\n title: 'Footer',\n aliases: ['Footer Links', 'Legal Links'],\n },\n} as const;\n\nexport type NavigationMenuSlot = keyof typeof NAVIGATION_MENU_SLOT_CONFIG;\n\nfunction normalizeNavigationToken(value: string): string {\n return value.trim().toLowerCase().replace(/\\s+/g, ' ');\n}\n\nexport function getNavigationMenuCanonicalTitle(slot: NavigationMenuSlot): string {\n return NAVIGATION_MENU_SLOT_CONFIG[slot].title;\n}\n\nexport function getNavigationMenuTitles(slot: NavigationMenuSlot): string[] {\n const config = NAVIGATION_MENU_SLOT_CONFIG[slot];\n return [config.title, ...config.aliases];\n}\n\nexport function isNavigationMenuSlot(value: string): value is NavigationMenuSlot {\n return value in NAVIGATION_MENU_SLOT_CONFIG;\n}\n\nexport function resolveNavigationMenuSlot(value: string | null | undefined): NavigationMenuSlot | null {\n if (!value) return null;\n\n const normalizedValue = normalizeNavigationToken(value);\n for (const slot of Object.keys(NAVIGATION_MENU_SLOT_CONFIG) as NavigationMenuSlot[]) {\n const candidates = [slot, ...getNavigationMenuTitles(slot)];\n if (candidates.some((candidate) => normalizeNavigationToken(candidate) === normalizedValue)) {\n return slot;\n }\n }\n\n return null;\n}\n\nexport function isSystemNavigationMenuTitle(value: string | null | undefined): boolean {\n return resolveNavigationMenuSlot(value) !== null;\n}\n\nexport const NAVIGATION_MENU_SLOTS = Object.keys(NAVIGATION_MENU_SLOT_CONFIG) as NavigationMenuSlot[];\n","/**\n * Navigation Module\n *\n * API methods for menus and navigation.\n */\n\nimport { get } from '../core/client';\nimport { getConfig } from '../core/config';\nimport { buildEndpoint } from '../core/endpoint';\nimport type { SDKResponse, Menu } from '../types';\nimport type { NavigationMenuSlot } from '@shoppex/contracts/navigation';\nimport { getNavigationMenuTitles } from '@shoppex/contracts/navigation';\n\ninterface MenusResponse {\n menus: Menu[];\n}\n\ninterface MenuResponse {\n menu: Menu;\n}\n\nconst NAVIGATION_CACHE_TTL = 5 * 60 * 1000;\n\n/**\n * Get all menus for the store\n */\nexport async function getMenus(): Promise<SDKResponse<Menu[]>> {\n const config = getConfig();\n const response = await get<MenusResponse>(\n buildEndpoint('/v1/storefront/shops/name/:storeSlug/menus', {\n storeSlug: config.storeSlug,\n }),\n {\n cache: {\n key: `menus:${config.storeSlug}`,\n ttl: NAVIGATION_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n return {\n success: true,\n data: response.data.menus,\n };\n }\n\n return {\n success: false,\n message: response.message,\n };\n}\n\n/**\n * Get a menu by its exact title.\n */\nexport async function getMenuByTitle(title: string): Promise<SDKResponse<Menu>> {\n const config = getConfig();\n const response = await get<MenuResponse>(\n buildEndpoint('/v1/storefront/shops/name/:storeSlug/menus/:title', {\n storeSlug: config.storeSlug,\n title,\n }),\n {\n cache: {\n key: `menu:${config.storeSlug}:${title}`,\n ttl: NAVIGATION_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n return {\n success: true,\n data: response.data.menu,\n };\n }\n\n return {\n success: false,\n message: response.message,\n };\n}\n\n/**\n * Get a menu by its exact title.\n */\nexport async function getMenu(title: string): Promise<SDKResponse<Menu>> {\n return getMenuByTitle(title);\n}\n\n/**\n * Get a menu by canonical slot. The backend resolves legacy menu titles too.\n */\nexport async function getMenuBySlot(slot: NavigationMenuSlot): Promise<SDKResponse<Menu>> {\n const config = getConfig();\n const response = await get<MenuResponse>(\n buildEndpoint('/v1/storefront/shops/name/:storeSlug/menus/:title', {\n storeSlug: config.storeSlug,\n title: slot,\n }),\n {\n cache: {\n key: `menu-slot:${config.storeSlug}:${slot}`,\n ttl: NAVIGATION_CACHE_TTL,\n staleWhileRevalidate: true,\n },\n }\n );\n\n if (response.success && response.data) {\n return {\n success: true,\n data: response.data.menu,\n };\n }\n\n return {\n success: false,\n message: response.message,\n };\n}\n\nexport function getMenuSlotTitles(slot: NavigationMenuSlot): string[] {\n return getNavigationMenuTitles(slot);\n}\n","import { get, post } from '../core/client';\nimport { getConfig, getShopId, isInitialized } from '../core/config';\nimport { buildEndpoint } from '../core/endpoint';\nimport { resolveUtmParameters } from '../core/attribution';\nimport { resolveStorefrontPagePath } from '../core/page-path';\nimport { isPlatformPageTrackerActive } from '../core/page-tracker';\nimport type { SDKResponse, StorefrontOnlineUsers, StorefrontRecentSales } from '../types';\n\n/**\n * Anonymized recent-sales feed for storefront social proof (product title +\n * relative age only — never buyer identity). Empty items when the shop has no\n * recent completed orders.\n */\nexport async function getStorefrontRecentSales(): Promise<SDKResponse<StorefrontRecentSales>> {\n if (!isInitialized()) {\n return { success: false, message: 'SDK not initialized' };\n }\n\n const config = getConfig();\n const shopId = getShopId();\n const endpoint = shopId\n ? buildEndpoint('/v1/storefront/shops/id/:id/recent-sales', { id: shopId })\n : buildEndpoint('/v1/storefront/shops/:storeSlug/recent-sales', {\n storeSlug: config.storeSlug,\n });\n\n return get<StorefrontRecentSales>(endpoint, {\n cache: false,\n retries: 0,\n timeout: 5000,\n });\n}\n\nexport async function getStorefrontOnlineUsers(): Promise<SDKResponse<StorefrontOnlineUsers>> {\n if (!isInitialized()) {\n return { success: false, message: 'SDK not initialized' };\n }\n\n const config = getConfig();\n const shopId = getShopId();\n const endpoint = shopId\n ? buildEndpoint('/v1/storefront/shops/id/:id/online-users', { id: shopId })\n : buildEndpoint('/v1/storefront/shops/:storeSlug/online-users', {\n storeSlug: config.storeSlug,\n });\n\n return get<StorefrontOnlineUsers>(endpoint, {\n cache: false,\n retries: 0,\n timeout: 5000,\n });\n}\n\n/**\n * Keeps this visitor's live presence fresh. The ping carries\n * `event_type: 'presence'`, so the server refreshes the live session without\n * counting a shop view: an idle tab that touches presence every minute must\n * not add a view every few minutes. Page views go through `trackPageView()`.\n */\nexport async function touchStorefrontPresence(): Promise<SDKResponse<{ pong: string }>> {\n if (!isInitialized()) {\n return { success: false, message: 'SDK not initialized' };\n }\n if (typeof document === 'undefined') {\n return { success: false, message: 'Document is not available' };\n }\n // Code storefronts: the edge-injected tracker keeps this visitor's presence\n // fresh itself; a second touch from here would be a duplicate ping.\n if (isPlatformPageTrackerActive()) {\n return { success: true, message: 'Presence is reported by the storefront page tracker' };\n }\n // A preview page (an unpublished draft) is not a live visitor.\n if (getConfig().preview) {\n return { success: true, message: 'A preview page reports no presence' };\n }\n\n const config = getConfig();\n const shopId = getShopId();\n const endpoint = shopId\n ? buildEndpoint('/v1/storefront/shops/id/:id/ping', { id: shopId })\n : buildEndpoint('/v1/storefront/shops/:storeSlug/ping', {\n storeSlug: config.storeSlug,\n });\n\n return post<{ pong: string }>(\n endpoint,\n {\n event_type: 'presence',\n referer: document.referrer || undefined,\n path: resolveStorefrontPagePath(),\n utm: resolveUtmParameters(config.storeSlug),\n },\n {\n retries: 0,\n timeout: 5000,\n },\n );\n}\n","/**\n * Formatting Utilities\n */\n\nimport { getConfig } from '../core/config';\nimport { CATALOG_UNIT_PRICE_FORMAT_OPTIONS } from '@shoppex/contracts/catalog-unit-price';\n\nexport function createFormatter(\n currency?: string,\n locale?: string\n): Intl.NumberFormat {\n const config = getConfig();\n\n return new Intl.NumberFormat(locale ?? config.locale ?? 'en-US', {\n style: 'currency',\n currency: currency ?? config.currency ?? 'USD',\n ...CATALOG_UNIT_PRICE_FORMAT_OPTIONS,\n });\n}\n\nexport function formatPrice(\n amount: number | string,\n currency?: string,\n locale?: string\n): string {\n const numericAmount = typeof amount === 'string' ? parseFloat(amount) : amount;\n if (Number.isNaN(numericAmount)) {\n return createFormatter(currency, locale).format(0);\n }\n return createFormatter(currency, locale).format(numericAmount);\n}\n","import type { ThemeConfig, ResolvedThemeSettings } from '../types/theme-config';\nimport { get } from '../core/client';\nimport { buildEndpoint } from '../core/endpoint';\n\ntype JsonRecord = Record<string, unknown>;\n\nexport interface PublishedBuilderSettings {\n version: number;\n revision: number;\n theme: {\n content: JsonRecord;\n layout: JsonRecord;\n style_slots: JsonRecord;\n pages?: unknown[];\n terms?: JsonRecord;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\nexport interface PublishedThemeSettingsPayload {\n settings: ResolvedThemeSettings;\n builder_settings: PublishedBuilderSettings | null;\n content: JsonRecord;\n style_slots: JsonRecord;\n}\n\nfunction isRecord(value: unknown): value is JsonRecord {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction normalizePublishedBuilderSettings(value: unknown): PublishedBuilderSettings | null {\n if (!isRecord(value) || !isRecord(value.theme)) {\n return null;\n }\n\n return {\n ...value,\n version: typeof value.version === 'number' ? value.version : 0,\n revision: typeof value.revision === 'number' ? value.revision : 0,\n theme: {\n ...value.theme,\n content: isRecord(value.theme.content) ? value.theme.content : {},\n layout: isRecord(value.theme.layout) ? value.theme.layout : {},\n style_slots: isRecord(value.theme.style_slots) ? value.theme.style_slots : {},\n ...(Array.isArray(value.theme.pages) ? { pages: value.theme.pages } : {}),\n ...(isRecord(value.theme.terms) ? { terms: value.theme.terms } : {}),\n },\n };\n}\n\nfunction normalizePublishedThemeSettingsPayload(value: unknown): PublishedThemeSettingsPayload | null {\n if (!isRecord(value)) {\n return null;\n }\n\n return {\n settings: isRecord(value.settings) ? value.settings as ResolvedThemeSettings : {},\n builder_settings: normalizePublishedBuilderSettings(value.builder_settings),\n content: isRecord(value.content) ? value.content : {},\n style_slots: isRecord(value.style_slots) ? value.style_slots : {},\n };\n}\n\nexport async function fetchPublishedBuilderSettings(\n shopSlug: string\n): Promise<PublishedThemeSettingsPayload | null> {\n const result = await get<PublishedThemeSettingsPayload>(\n buildEndpoint('/v1/storefront/themes/builder/published/:shopSlug', { shopSlug })\n );\n\n return result.success && result.data ? normalizePublishedThemeSettingsPayload(result.data) : null;\n}\n\nexport async function fetchPublishedThemeSettings(\n shopSlug: string\n): Promise<ResolvedThemeSettings | null> {\n const payload = await fetchPublishedBuilderSettings(shopSlug);\n return payload ? payload.settings : null;\n}\n\nexport function resolveDefaults(config: ThemeConfig): ResolvedThemeSettings {\n const resolved: ResolvedThemeSettings = {};\n for (const [category, fields] of Object.entries(config.settings)) {\n resolved[category] = {};\n for (const [key, field] of Object.entries(fields)) {\n resolved[category][key] = field.default;\n }\n }\n return resolved;\n}\n\nexport function mergeSettings(\n defaults: ResolvedThemeSettings,\n overrides: Partial<ResolvedThemeSettings>\n): ResolvedThemeSettings {\n const merged = { ...defaults };\n for (const [category, fields] of Object.entries(overrides)) {\n if (fields) {\n merged[category] = { ...merged[category], ...fields };\n }\n }\n return merged;\n}\n","/**\n * The storefront SDK without the signed-in customer account calls.\n *\n * The ThemeDocument commerce runtime (packages/storefront-commerce) loads on\n * every page of every Easy-lane storefront and uses this object, not the full\n * `shoppex` one: the account calls validate their responses with the zod\n * schemas of `@shoppex/contracts/customer-account-wire` (~100 KB minified),\n * and the Easy lane's account page runs its own script. `shoppex` (index.ts)\n * is this object plus the account calls. The storage half\n * (storefront-storage-sdk.ts) is its own object, so the commerce runtime's\n * core can carry it without the network modules below.\n */\n\nimport { storefrontStorageSdk } from './storefront-storage-sdk';\nimport { getTypedClient } from './core/typed-client';\n// Store module\nimport {\n getStore,\n getStorefront,\n getStoreLogoUrl,\n getStoreBannerUrl,\n resolveStoreByDomain,\n} from './modules/store';\n// Products module\nimport { getProducts, getProduct, getCategories, getStorefrontProductsPage } from './modules/products';\n// Checkout module\nimport { checkout, buildCheckoutUrl, buildCheckoutUrlSync, getRequestedCheckoutCurrency } from './modules/checkout';\n// Affiliate module (network calls; storage and capture are in storefrontStorageSdk)\nimport { applyAffiliateCode, validateAffiliateCode } from './modules/affiliates';\n// Coupons module\nimport { validateCoupon } from './modules/coupons';\n// Reviews module\nimport { getShopReviews, getShopReviewsPage } from './modules/reviews';\n// Search module\nimport { searchProducts, searchCatalogItems } from './modules/search';\n// Invoices module\nimport { getInvoice, getInvoiceStatus } from './modules/invoices';\n// Pages module\nimport { getPages, getPage } from './modules/pages';\n// Navigation module\nimport { getMenus, getMenu, getMenuBySlot, getMenuByTitle, getMenuSlotTitles } from './modules/navigation';\n// Presence module\nimport { getStorefrontOnlineUsers, getStorefrontRecentSales, touchStorefrontPresence } from './modules/presence';\n// Format utilities\nimport { createFormatter, formatPrice } from './utils/format';\nimport { clearCache, invalidateCache, getCacheStats } from './core/cache';\nimport { fetchPublishedBuilderSettings, fetchPublishedThemeSettings, resolveDefaults, mergeSettings } from './modules/theme';\n\nexport const storefrontSdk = {\n // Initialization, cart, quote, coupon and referral storage, analytics\n ...storefrontStorageSdk,\n\n // Typed OpenAPI client — drop to this when you need an endpoint the\n // high-level modules below do not cover yet.\n client: getTypedClient,\n\n // Store\n getStore,\n getStorefront,\n getStoreLogoUrl,\n getStoreBannerUrl,\n resolveStoreByDomain,\n\n // Products\n getProducts,\n getStorefrontProductsPage,\n getProduct,\n getCategories,\n\n // Checkout\n checkout,\n buildCheckoutUrl,\n buildCheckoutUrlSync,\n getRequestedCheckoutCurrency,\n\n // Affiliates\n validateAffiliateCode,\n applyAffiliateCode,\n\n // Coupons\n validateCoupon,\n\n // Reviews\n getShopReviews,\n getShopReviewsPage,\n\n // Search\n searchProducts,\n searchCatalogItems,\n\n // Invoices\n getInvoice,\n getInvoiceStatus,\n\n // Pages\n getPages,\n getPage,\n\n // Navigation\n getMenus,\n getMenu,\n getMenuBySlot,\n getMenuByTitle,\n getMenuSlotTitles,\n\n // Presence\n getStorefrontOnlineUsers,\n getStorefrontRecentSales,\n touchStorefrontPresence,\n\n // Formatting\n createFormatter,\n formatPrice,\n\n // Cache\n clearCache,\n invalidateCache,\n getCacheStats,\n\n // Theme settings helpers\n fetchPublishedBuilderSettings,\n fetchPublishedThemeSettings,\n resolveDefaults,\n mergeSettings,\n};\n\nexport type StorefrontSdk = typeof storefrontSdk;\n\nexport default storefrontSdk;\n","/**\n * Select (dropdown) product custom fields: the buyer picks exactly one of the\n * merchant's option labels.\n *\n * A definition carries `options` only when its `type` is `select`; every other\n * type keeps its wire unchanged. The product write boundaries refuse a select\n * without 2–20 unique, trimmed labels of 1–100 characters, refuse `options` on\n * any other type, and refuse a default on a select (the buyer always makes the\n * choice). An order stores the picked label as text, so renaming or removing\n * an option later changes only new orders.\n */\nexport const SELECT_CUSTOM_FIELD_MIN_OPTIONS = 2;\nexport const SELECT_CUSTOM_FIELD_MAX_OPTIONS = 20;\nexport const SELECT_CUSTOM_FIELD_OPTION_MAX_LENGTH = 100;\n\n/**\n * The option labels of a stored select definition. The write boundary\n * guarantees an array of trimmed strings; readers keep only strings so a\n * malformed row cannot put a non-string into a buyer control.\n */\nexport function readSelectCustomFieldOptions(raw: unknown): string[] {\n return Array.isArray(raw) ? raw.filter((option): option is string => typeof option === 'string') : [];\n}\n","import { readSelectCustomFieldOptions } from '@shoppex/contracts/product-custom-fields';\n\nexport interface StorefrontCustomField {\n name: string;\n type: string;\n required: boolean;\n defaultValue: string;\n placeholder: string;\n regex?: string;\n /** Only on a `select`: the labels the buyer picks one of. */\n options?: string[];\n}\n\nfunction parseCustomFieldsSource(raw: unknown): unknown[] {\n if (Array.isArray(raw)) return raw;\n\n if (typeof raw === 'string') {\n try {\n const parsed = JSON.parse(raw) as unknown;\n if (Array.isArray(parsed)) return parsed;\n if (parsed && typeof parsed === 'object') {\n const fields = (parsed as { custom_fields?: unknown[]; customFields?: unknown[] }).custom_fields\n ?? (parsed as { custom_fields?: unknown[]; customFields?: unknown[] }).customFields;\n return Array.isArray(fields) ? fields : [];\n }\n } catch {\n return [];\n }\n\n return [];\n }\n\n if (raw && typeof raw === 'object') {\n const fields = (raw as { custom_fields?: unknown[]; customFields?: unknown[] }).custom_fields\n ?? (raw as { custom_fields?: unknown[]; customFields?: unknown[] }).customFields;\n return Array.isArray(fields) ? fields : [];\n }\n\n return [];\n}\n\n// The dashboard has stored boolean flags as a boolean, a number and a string over time.\nfunction isFlagSet(value: unknown): boolean {\n return value === true || value === 'true' || value === 1 || value === '1';\n}\n\nexport function normalizeStorefrontCustomFields(raw: unknown): StorefrontCustomField[] {\n return parseCustomFieldsSource(raw)\n .filter((field): field is Record<string, unknown> => !!field && typeof field === 'object' && !Array.isArray(field))\n // A post-payment field is asked on the invoice after payment; the server drops\n // a value the cart sends for it, so checkout must not ask for it first.\n .filter((field) => ![field.collect_after_payment, field.collectAfterPayment].some(isFlagSet))\n .map((field) => {\n const rawType = typeof field.type === 'string' ? field.type.trim().toLowerCase() : 'text';\n const type = rawType.length > 0 ? rawType : 'text';\n const defaultValue = [\n field.default_value,\n field.default,\n field.value,\n ].find((candidate) => typeof candidate === 'string' && candidate.trim().length > 0);\n\n return {\n name: typeof field.name === 'string' ? field.name.trim() : '',\n type,\n required: isFlagSet(field.required),\n defaultValue: typeof defaultValue === 'string' ? defaultValue : '',\n placeholder: typeof field.placeholder === 'string' ? field.placeholder : '',\n regex: typeof field.regex === 'string' ? field.regex : undefined,\n ...(type === 'select' ? { options: readSelectCustomFieldOptions(field.options) } : {}),\n };\n })\n .filter((field) => field.name.length > 0 && field.type !== 'hidden');\n}\n\nexport function isStorefrontCheckboxCustomFieldValueChecked(value: string | undefined): boolean {\n const normalized = value?.trim().toLowerCase() ?? '';\n return normalized === 'true' || normalized === '1' || normalized === 'yes' || normalized === 'on';\n}\n\nexport function validateStorefrontCustomFieldValue(field: StorefrontCustomField, value: string): string | null {\n if (field.type === 'checkbox') {\n if (field.required && !isStorefrontCheckboxCustomFieldValueChecked(value)) {\n return `${field.name} is required.`;\n }\n return null;\n }\n\n const normalized = value.trim();\n if (field.required && !normalized) {\n return `${field.name} is required.`;\n }\n\n // The server refuses any other answer with `custom_field_option_invalid`.\n if (field.type === 'select') {\n return normalized && !(field.options ?? []).includes(normalized)\n ? `${field.name} must be one of the listed options.`\n : null;\n }\n\n if (field.regex && normalized) {\n try {\n const pattern = new RegExp(field.regex);\n if (!pattern.test(normalized)) {\n return `${field.name} has an invalid format.`;\n }\n } catch {\n return null;\n }\n }\n\n return null;\n}\n\nexport function buildStorefrontCustomFieldPayload(\n fields: StorefrontCustomField[],\n values: Record<string, string>,\n): Record<string, string> {\n const nextValues: Record<string, string> = {};\n\n fields.forEach((field) => {\n const rawValue = values[field.name] ?? field.defaultValue ?? '';\n\n if (field.type === 'checkbox') {\n if (isStorefrontCheckboxCustomFieldValueChecked(rawValue)) {\n nextValues[field.name] = 'true';\n }\n return;\n }\n\n const normalized = rawValue.trim();\n if (normalized.length > 0) {\n nextValues[field.name] = normalized;\n }\n });\n\n return nextValues;\n}\n","import { DEFAULT_API_BASE_URL } from '../core/config';\n\nexport type StorefrontContactTicketInput = {\n shopSlug: string;\n email: string;\n message: string;\n title?: string;\n name?: string;\n invoiceId?: string;\n apiBaseUrl?: string;\n};\n\nexport type StorefrontContactTicketResult = {\n uniqid: string;\n};\n\nfunction isLocalDevHost(host: string): boolean {\n if (host === 'localhost' || host === '127.0.0.1' || host === '::1' || host.endsWith('.localhost')) {\n return true;\n }\n if (/^10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/.test(host)) {\n return true;\n }\n if (/^192\\.168\\.\\d{1,3}\\.\\d{1,3}$/.test(host)) {\n return true;\n }\n const private172 = host.match(/^172\\.(\\d{1,2})\\.\\d{1,3}\\.\\d{1,3}$/);\n if (private172) {\n const octet = Number(private172[1]);\n return octet >= 16 && octet <= 31;\n }\n return false;\n}\n\nexport function resolveStorefrontApiBaseUrl(options?: {\n apiBaseUrl?: string;\n hostname?: string;\n}): string {\n if (options?.apiBaseUrl?.trim()) {\n return options.apiBaseUrl.replace(/\\/+$/, '');\n }\n\n const hostname = options?.hostname\n ?? (typeof window !== 'undefined' ? window.location.hostname : '');\n\n if (hostname && !isLocalDevHost(hostname)) {\n return DEFAULT_API_BASE_URL;\n }\n\n // Edge/njk commerce is a classic IIFE (not an ES module) — import.meta is a syntax error there.\n // Storefront bootstrap sets window.apiBaseUrl; Vite/React callers may pass options.apiBaseUrl.\n if (typeof window !== 'undefined') {\n const bootstrapBase = (window as { apiBaseUrl?: unknown }).apiBaseUrl;\n if (typeof bootstrapBase === 'string' && bootstrapBase.trim()) {\n return bootstrapBase.replace(/\\/+$/, '');\n }\n }\n\n return 'http://localhost:3001'.replace(/\\/+$/, '');\n}\n\nexport function buildStorefrontContactMessage(input: {\n name?: string;\n message: string;\n maxLength?: number;\n}): string {\n const customerName = input.name?.trim() ?? '';\n const baseMessage = input.message.trim();\n const fullMessage = `${customerName ? `Name: ${customerName}\\n\\n` : ''}${baseMessage}`;\n const maxLength = input.maxLength ?? 2000;\n return fullMessage.slice(0, maxLength);\n}\n\nexport async function submitStorefrontContactTicket(\n input: StorefrontContactTicketInput,\n): Promise<StorefrontContactTicketResult> {\n const shopSlug = input.shopSlug.trim();\n if (!shopSlug) {\n throw new Error('Store data is not ready yet. Please try again in a moment.');\n }\n\n const normalizedEmail = input.email.trim().toLowerCase();\n const subject = input.title?.trim() ?? '';\n const title = subject.length >= 2 ? subject.slice(0, 30) : 'Contact Request';\n const message = buildStorefrontContactMessage({\n name: input.name,\n message: input.message,\n });\n const invoiceId = input.invoiceId?.trim() || undefined;\n const apiBaseUrl = resolveStorefrontApiBaseUrl({ apiBaseUrl: input.apiBaseUrl });\n\n const response = await fetch(\n `${apiBaseUrl}/v1/storefront/shops/name/${encodeURIComponent(shopSlug)}/tickets`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify({\n email: normalizedEmail,\n title,\n message,\n ...(invoiceId ? { invoice_id: invoiceId } : {}),\n }),\n },\n );\n\n const payload = await response.json().catch(() => null) as {\n message?: string;\n error?: string;\n data?: { uniqid?: string };\n } | null;\n\n if (!response.ok) {\n throw new Error(payload?.message || payload?.error || 'Failed to send your message.');\n }\n\n const uniqid = payload?.data?.uniqid;\n if (!uniqid) {\n throw new Error('Ticket created, but the response was incomplete.');\n }\n\n return { uniqid };\n}\n\nexport type StorefrontSocialLinks = {\n discord?: string | null;\n telegram?: string | null;\n};\n\nexport function resolveStorefrontSocialLinks(store: {\n discord_link?: string | null;\n telegram_link?: string | null;\n social?: Record<string, string | null | undefined> | null;\n} | null | undefined): StorefrontSocialLinks {\n return {\n discord: store?.discord_link ?? store?.social?.discord ?? null,\n telegram: store?.telegram_link ?? store?.social?.telegram ?? null,\n };\n}\n","/**\n * Customer Module\n *\n * Authenticated customer account calls for code-lane storefronts. The edge\n * worker owns the HttpOnly session cookie and derives the shop from the host.\n * This module therefore sends neither a session token nor shop identity.\n */\n\nimport {\n customerLoyaltyRedeemSchema,\n customerLoyaltySchema,\n customerPortalAffiliateCreateLinkSchema,\n customerPortalDashboardSchema,\n customerPortalInvoiceDetailSchema,\n customerPortalNotificationPreferencesSchema,\n customerPortalOrderReviewSchema,\n customerPortalPaginatedInvoicesSchema,\n customerWarrantyClaimSchema,\n customerWarrantyListSchema,\n type CustomerLoyaltyRedeemWire,\n type CustomerLoyaltyWire,\n type CustomerPortalAffiliateCreateLinkWire,\n type CustomerPortalDashboardWire,\n type CustomerPortalInvoiceDetailWire,\n type CustomerPortalNotificationPreferencesWire,\n type CustomerPortalOrderReviewWire,\n type CustomerPortalPaginatedInvoicesWire,\n type CustomerWarrantyClaimWire,\n type CustomerWarrantyListWire,\n} from '@shoppex/contracts/customer-account-wire';\nimport type { SDKResponse } from '../types';\n\nconst CUSTOMER_API_PREFIX = '/api/customer';\n\ntype CustomerMethod = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';\n\n/**\n * A producer-owned schema for the response payload.\n *\n * Only the endpoints whose shape is defined in `@shoppex/contracts` get one.\n * The rest stay `unknown` on purpose: inventing a type here would assert a wire\n * shape the producer never promised, which is the pattern the retired portal's\n * 544-line hand-written type file demonstrates the cost of.\n */\ninterface CustomerPayloadSchema<T> {\n safeParse(value: unknown): { success: true; data: T } | { success: false };\n}\n\ninterface CustomerRequestOptions<T> {\n method?: CustomerMethod;\n body?: unknown;\n /** Multipart payload. Mutually exclusive with `body`; the browser sets the boundary. */\n formData?: FormData;\n schema?: CustomerPayloadSchema<T>;\n}\n\nexport interface CustomerOrdersQuery {\n page?: number;\n limit?: number;\n /**\n * Invoice status filter, verbatim from the producer's enum. Anything else is\n * answered with a 400 rather than quietly ignored, so pass what the buyer\n * actually chose.\n */\n status?: string;\n /** Partial invoice-id search. The producer trims it to 64 characters. */\n search?: string;\n}\n\ninterface CustomerApiEnvelope {\n status: number;\n data: unknown;\n error?: unknown;\n message?: unknown;\n error_code?: unknown;\n error_params?: unknown;\n}\n\nexport interface CustomerTicketPayload {\n title?: string;\n message: string;\n invoice_id?: string;\n /** Images staged with `uploadTicketImage`, sent with this message. */\n attachment_ids?: string[];\n}\n\nexport interface CustomerProfilePatch {\n name: string;\n}\n\nexport interface CustomerSubscriptionCancelOptions {\n cancel_at_period_end?: boolean;\n reason?: string | null;\n}\n\n/** Why a buyer pauses (`SUBSCRIPTION_PAUSE_REASONS`); the dashboard's `pause_options.reason_enabled` says whether to ask. */\nexport type CustomerSubscriptionPauseReason = 'taking_a_break' | 'too_expensive' | 'not_using' | 'not_working' | 'other';\n\n/**\n * A buyer pause: one of the dashboard's `pause_options.lengths[].days`, and a reason when the\n * shop asks for one. Without `length_days` the backend pauses for the shop's longest pause.\n */\nexport interface CustomerSubscriptionPauseOptions {\n length_days?: 7 | 14 | 30 | 60 | 90;\n reason?: CustomerSubscriptionPauseReason | null;\n}\n\nexport interface CustomerEmailPreferencesPatch {\n global_unsubscribed?: boolean;\n list_subscriptions?: Array<{ list_id: string; subscribed: boolean }>;\n}\n\n/** Which order mails the buyer receives. A key left out is left as it is. */\nexport interface CustomerNotificationPreferencesPatch {\n order_created_emails?: boolean;\n order_completed_emails?: boolean;\n payment_issue_emails?: boolean;\n}\n\nexport interface CustomerAffiliateLinkInput {\n code: string;\n label: string;\n /** Asking for a rate of one's own sends the link to the shop for approval. */\n requested_affiliate_revenue_percent?: number;\n requested_affiliate_customer_discount_percent?: number;\n}\n\nexport interface CustomerInvoicePdf {\n blob: Blob;\n /** From the producer's `Content-Disposition`; null when it named none. */\n filename: string | null;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction narrowEnvelope(value: unknown): CustomerApiEnvelope | null {\n if (!isRecord(value) || typeof value.status !== 'number' || !('data' in value)) {\n return null;\n }\n\n return value as unknown as CustomerApiEnvelope;\n}\n\nfunction readMessage(envelope: CustomerApiEnvelope, response: Response): string {\n if (typeof envelope.error === 'string' && envelope.error.length > 0) {\n return envelope.error;\n }\n\n if (typeof envelope.message === 'string' && envelope.message.length > 0) {\n return envelope.message;\n }\n\n return response.statusText\n ? `HTTP ${response.status}: ${response.statusText}`\n : `HTTP ${response.status}`;\n}\n\nfunction readErrorFields(envelope: CustomerApiEnvelope): Pick<SDKResponse<unknown>, 'code' | 'errorParams'> {\n const code = typeof envelope.error_code === 'string' && envelope.error_code.length > 0\n ? envelope.error_code\n : null;\n\n if (!code) {\n return {};\n }\n\n return {\n code,\n ...(isRecord(envelope.error_params) ? { errorParams: envelope.error_params } : {}),\n };\n}\n\nasync function requestCustomer<T = unknown>(\n path: string,\n options: CustomerRequestOptions<T> = {},\n): Promise<SDKResponse<T>> {\n const method = options.method ?? 'GET';\n const headers: Record<string, string> = {\n Accept: 'application/json',\n };\n\n if (options.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n }\n\n // FormData carries its own multipart boundary in the Content-Type the browser\n // generates; setting the header here would produce a body the server cannot parse.\n const payload = options.formData ?? (options.body !== undefined ? JSON.stringify(options.body) : undefined);\n\n try {\n const response = await fetch(`${CUSTOMER_API_PREFIX}${path}`, {\n method,\n headers,\n body: payload,\n credentials: 'same-origin',\n cache: 'no-store',\n });\n\n if (response.status === 204) {\n return response.ok\n ? { success: true, status: response.status }\n : {\n success: false,\n status: response.status,\n message: readMessage({ status: response.status, data: null }, response),\n };\n }\n\n let rawEnvelope: unknown;\n try {\n rawEnvelope = await response.json();\n } catch {\n return { success: false, status: response.status, message: 'Invalid customer API response' };\n }\n\n const envelope = narrowEnvelope(rawEnvelope);\n if (!envelope) {\n return { success: false, status: response.status, message: 'Invalid customer API response' };\n }\n\n // A money mutation the producer completed but whose answer it withheld\n // keeps the handler's 2xx. Left to the checks below it reads as an empty\n // success, or as a contract mismatch the buyer is told to try again; with\n // the code, the caller re-reads the account instead of sending it twice.\n if (\n !response.ok || envelope.status < 200 || envelope.status >= 300\n || envelope.error_code === 'RESPONSE_CONTRACT_VIOLATION'\n ) {\n return {\n success: false,\n // The transport status, not the envelope's: a caller deciding whether\n // the buyer is signed out must not be steered by a body the edge may\n // never have produced.\n status: response.status,\n message: readMessage(envelope, response),\n ...readErrorFields(envelope),\n };\n }\n\n const message = typeof envelope.message === 'string' && envelope.message.length > 0\n ? { message: envelope.message }\n : {};\n\n if (!options.schema) {\n return { success: true, data: envelope.data as T, ...message };\n }\n\n const parsed = options.schema.safeParse(envelope.data);\n if (!parsed.success) {\n // Fail loudly instead of handing back a payload that does not match what\n // the producer promised. A silently reshaped or partially-read response\n // is how a contract drift reaches the buyer's screen as wrong data.\n return { success: false, message: 'Customer API response did not match the expected contract' };\n }\n\n return { success: true, data: parsed.data, ...message };\n } catch (error) {\n return {\n success: false,\n message: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n/** One basket line for a QUOTE. `variant_id` is omitted, never null, when a product has no variants. */\nexport interface ResellerOrderItem {\n product_id: string;\n variant_id?: string;\n quantity: number;\n}\n\nexport interface ResellerCatalogQuery {\n search?: string;\n page?: number;\n per_page?: number;\n}\n\nexport interface ResellerOrdersQuery {\n page?: number;\n per_page?: number;\n}\n\nexport function requestOtp(email: string): Promise<SDKResponse<unknown>> {\n return requestCustomer('/auth/otp/request', {\n method: 'POST',\n body: { email },\n });\n}\n\n/**\n * The wire field is `otp`, not `code` — `CustomerOtpVerifyBodySchema` in\n * `apps/backend-elysia/src/routes/v1/customer/schemas.ts` requires it under that\n * name, and a `code` body is rejected with 400.\n */\nexport function verifyOtp(email: string, otp: string): Promise<SDKResponse<unknown>> {\n return requestCustomer('/auth/otp/verify', {\n method: 'POST',\n body: { email, otp },\n });\n}\n\nexport function logout(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/auth/logout', { method: 'POST' });\n}\n\nexport function me(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/me');\n}\n\nexport function dashboard(): Promise<SDKResponse<CustomerPortalDashboardWire>> {\n return requestCustomer('/dashboard', { schema: customerPortalDashboardSchema });\n}\n\n/**\n * Paginated order history.\n *\n * Page-based, matching the producer: `invoices.routes.ts` reads `page` and\n * `limit` and answers with a `has_more` envelope. A cursor parameter would be\n * ignored upstream and silently return page one forever.\n *\n * `status` and `search` are filtered SERVER-side, which is why they belong\n * here rather than in the caller: `/invoices` is paged, and a filter applied\n * to the page in hand would filter only the rows that page happens to hold.\n * The producer spells the search `q`.\n */\nexport function orders(options: CustomerOrdersQuery = {}): Promise<SDKResponse<CustomerPortalPaginatedInvoicesWire>> {\n const query = new URLSearchParams();\n if (options.page !== undefined) query.set('page', String(options.page));\n if (options.limit !== undefined) query.set('limit', String(options.limit));\n if (options.status) query.set('status', options.status);\n if (options.search) query.set('q', options.search);\n\n const suffix = query.size > 0 ? `?${query.toString()}` : '';\n return requestCustomer(`/invoices${suffix}`, { schema: customerPortalPaginatedInvoicesSchema });\n}\n\nexport function order(id: string): Promise<SDKResponse<CustomerPortalInvoiceDetailWire>> {\n return requestCustomer(`/invoice/${encodeURIComponent(id)}`, {\n schema: customerPortalInvoiceDetailSchema,\n });\n}\n\n/**\n * Whether the buyer may review this paid order, and the review they left.\n *\n * `can_review` is the producer's decision (paid, reviews on, not yet reviewed).\n * The review itself is written on the hosted page `review_url` names: this\n * script runs beside merchant theme code, which must not post as the buyer.\n */\nexport function orderReview(uniqid: string): Promise<SDKResponse<CustomerPortalOrderReviewWire>> {\n return requestCustomer(`/invoices/${encodeURIComponent(uniqid)}/review`, { schema: customerPortalOrderReviewSchema });\n}\n\n/**\n * The invoice as a PDF, for the buyer to save.\n *\n * A file, not the JSON envelope, so it does not go through `requestCustomer`.\n * Anything but a PDF on a 2xx is a contract failure rather than a download: a\n * proxy's HTML error page saved as `invoice.pdf` is a file that will not open.\n */\nexport async function invoicePdf(id: string): Promise<SDKResponse<CustomerInvoicePdf>> {\n try {\n const response = await fetch(`${CUSTOMER_API_PREFIX}/invoices/${encodeURIComponent(id)}/pdf`, {\n method: 'GET',\n headers: { Accept: 'application/pdf' },\n credentials: 'same-origin',\n cache: 'no-store',\n });\n\n if (!response.ok) {\n let envelope: CustomerApiEnvelope | null = null;\n try {\n envelope = narrowEnvelope(await response.json());\n } catch {\n envelope = null;\n }\n return {\n success: false,\n status: response.status,\n message: readMessage(envelope ?? { status: response.status, data: null }, response),\n };\n }\n\n if (!(response.headers.get('content-type') ?? '').toLowerCase().startsWith('application/pdf')) {\n return { success: false, message: 'Customer API response did not match the expected contract' };\n }\n\n return {\n success: true,\n data: {\n blob: await response.blob(),\n filename: response.headers.get('content-disposition')?.match(/filename=\"([^\"]+)\"/i)?.[1] ?? null,\n },\n };\n } catch (error) {\n return {\n success: false,\n message: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\nexport function loyalty(): Promise<SDKResponse<CustomerLoyaltyWire>> {\n return requestCustomer('/loyalty', { schema: customerLoyaltySchema });\n}\n\nexport function redeemLoyaltyPoints(input: {\n points: number;\n idempotencyKey: string;\n}): Promise<SDKResponse<CustomerLoyaltyRedeemWire>> {\n return requestCustomer('/loyalty/redeem', {\n method: 'POST',\n body: {\n points: input.points,\n idempotency_key: input.idempotencyKey,\n },\n schema: customerLoyaltyRedeemSchema,\n });\n}\n\n/**\n * The warranties this buyer holds — all of them, or the ones on one order.\n *\n * `invoiceUniqid` becomes the producer's own `invoice=` filter, which matches\n * `invoices.uniqid`: the id an order carries everywhere a storefront shows one.\n * So an order detail asks for its own cover rather than reading every warranty\n * the buyer owns and discarding most of them.\n */\nexport function warranties(invoiceUniqid?: string): Promise<SDKResponse<CustomerWarrantyListWire>> {\n const suffix = invoiceUniqid ? `?invoice=${encodeURIComponent(invoiceUniqid)}` : '';\n return requestCustomer(`/warranties${suffix}`, { schema: customerWarrantyListSchema });\n}\n\nexport function claimWarranty(\n uniqid: string,\n message?: string,\n): Promise<SDKResponse<CustomerWarrantyClaimWire>> {\n return requestCustomer(`/warranties/${encodeURIComponent(uniqid)}/claim`, {\n method: 'POST',\n body: message ? { message } : {},\n schema: customerWarrantyClaimSchema,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Licenses, subscriptions and tickets have NO collection route.\n//\n// Those three lists arrive inside `/dashboard` — `licenses.routes.ts`,\n// `subscriptions.routes.ts` and `tickets.routes.ts` expose per-item routes only.\n// A `GET /licenses` here would 404 on every call, which is what the earlier\n// spelling of this module did.\n// ---------------------------------------------------------------------------\n\nexport function resetLicenseHwid(uniqid: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/licenses/${encodeURIComponent(uniqid)}/reset-hwid`, {\n method: 'POST',\n body: {},\n });\n}\n\nexport function subscriptionBillingHistory(uniqid: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/subscriptions/${encodeURIComponent(uniqid)}/billing-history`);\n}\n\nexport function cancelSubscription(\n uniqid: string,\n options: CustomerSubscriptionCancelOptions = {},\n): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/subscriptions/${encodeURIComponent(uniqid)}/cancel`, {\n method: 'POST',\n body: {\n ...(options.cancel_at_period_end !== undefined\n ? { cancel_at_period_end: options.cancel_at_period_end }\n : {}),\n ...(options.reason !== undefined ? { reason: options.reason } : {}),\n },\n });\n}\n\nexport function pauseSubscription(\n uniqid: string,\n options: CustomerSubscriptionPauseOptions = {},\n): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/subscriptions/${encodeURIComponent(uniqid)}/pause`, {\n method: 'POST',\n body: {\n ...(options.length_days !== undefined ? { length_days: options.length_days } : {}),\n ...(options.reason !== undefined ? { reason: options.reason } : {}),\n },\n });\n}\n\nexport function resumeSubscription(uniqid: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/subscriptions/${encodeURIComponent(uniqid)}/resume`, {\n method: 'POST',\n body: {},\n });\n}\n\nexport function undoSubscriptionCancel(uniqid: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/subscriptions/${encodeURIComponent(uniqid)}/undo-cancel`, {\n method: 'POST',\n body: {},\n });\n}\n\nexport function favorites(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/favorites');\n}\n\n/** Idempotent upstream, and a PUT — `customer-favorites.ts` has no POST route. */\nexport function addFavorite(productUniqid: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/favorites/${encodeURIComponent(productUniqid)}`, { method: 'PUT' });\n}\n\nexport function removeFavorite(productUniqid: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/favorites/${encodeURIComponent(productUniqid)}`, { method: 'DELETE' });\n}\n\nexport function affiliate(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/affiliate');\n}\n\nexport function affiliateStats(days?: number): Promise<SDKResponse<unknown>> {\n const suffix = days === undefined ? '' : `?days=${encodeURIComponent(String(days))}`;\n return requestCustomer(`/affiliate/stats${suffix}`);\n}\n\n/**\n * A referral link with a code of the buyer's choosing.\n *\n * `status` in the answer is `pending` when the shop approves links first, or\n * when the link asks for rates of its own. Nothing here pays out, converts or\n * shares a commission: those decide where earned money goes and are not\n * reachable from a storefront.\n */\nexport function createAffiliateLink(\n input: CustomerAffiliateLinkInput,\n): Promise<SDKResponse<CustomerPortalAffiliateCreateLinkWire>> {\n return requestCustomer('/affiliate/links', {\n method: 'POST',\n body: {\n code: input.code,\n label: input.label,\n ...(input.requested_affiliate_revenue_percent !== undefined\n ? { requested_affiliate_revenue_percent: input.requested_affiliate_revenue_percent }\n : {}),\n ...(input.requested_affiliate_customer_discount_percent !== undefined\n ? { requested_affiliate_customer_discount_percent: input.requested_affiliate_customer_discount_percent }\n : {}),\n },\n schema: customerPortalAffiliateCreateLinkSchema,\n });\n}\n\nexport function createTicket(payload: CustomerTicketPayload): Promise<SDKResponse<unknown>> {\n return requestCustomer('/tickets', {\n method: 'POST',\n body: {\n ...(payload.title !== undefined ? { title: payload.title } : {}),\n message: payload.message,\n ...(payload.invoice_id !== undefined ? { invoice_id: payload.invoice_id } : {}),\n ...(payload.attachment_ids?.length ? { attachment_ids: payload.attachment_ids } : {}),\n },\n });\n}\n\nexport function ticket(uniqid: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/tickets/${encodeURIComponent(uniqid)}`);\n}\n\nexport function replyToTicket(uniqid: string, message: string, attachmentIds: string[] = []): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/tickets/${encodeURIComponent(uniqid)}/reply`, {\n method: 'POST',\n body: attachmentIds.length > 0 ? { message, attachment_ids: attachmentIds } : { message },\n });\n}\n\n/**\n * Stage one image for a reply on ticket `ticket`, or for the ticket the buyer is\n * about to create when `ticket` is left out (`POST /v1/customer/ticket-attachments`).\n * JPG, PNG, WebP or GIF up to 5 MB, five per message; the producer answers its\n * own refusal (409/413/415). Send the returned `attachment.id` with the message.\n * The public contact form has no upload.\n */\nexport function uploadTicketImage(file: File, ticket?: string): Promise<SDKResponse<unknown>> {\n const form = new FormData();\n form.append('file', file);\n if (ticket) form.append('ticket', ticket);\n return requestCustomer('/ticket-attachments', { method: 'POST', formData: form });\n}\n\n/** Drop an image staged with `uploadTicketImage` that the buyer removed before sending. */\nexport function discardTicketImage(id: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/ticket-attachments/${encodeURIComponent(id)}`, { method: 'DELETE' });\n}\n\n/**\n * The producer is `POST /v1/customer/profile`, not PATCH.\n *\n * There is no `GET /profile` to pair with it — the buyer's own record comes from\n * `/me` and `/dashboard`.\n */\nexport function updateProfile(patch: CustomerProfilePatch): Promise<SDKResponse<unknown>> {\n return requestCustomer('/profile', {\n method: 'POST',\n body: { name: patch.name },\n });\n}\n\nexport function updateAvatar(file: File): Promise<SDKResponse<unknown>> {\n const form = new FormData();\n form.append('file', file);\n return requestCustomer('/profile/avatar', { method: 'POST', formData: form });\n}\n\nexport function removeAvatar(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/profile/avatar', { method: 'DELETE' });\n}\n\nexport function emailPreferences(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/email-marketing/preferences');\n}\n\nexport function updateEmailPreferences(\n patch: CustomerEmailPreferencesPatch,\n): Promise<SDKResponse<unknown>> {\n return requestCustomer('/email-marketing/preferences', {\n method: 'PATCH',\n body: {\n ...(patch.global_unsubscribed !== undefined\n ? { global_unsubscribed: patch.global_unsubscribed }\n : {}),\n ...(patch.list_subscriptions !== undefined\n ? { list_subscriptions: patch.list_subscriptions }\n : {}),\n },\n });\n}\n\n/**\n * Order mail, as opposed to the marketing lists above: order placed, order\n * completed, payment needs attention. Its own producer\n * (`routes/v1/customer-notifications.ts`), and it answers the saved set.\n */\nexport function notificationPreferences(): Promise<SDKResponse<CustomerPortalNotificationPreferencesWire>> {\n return requestCustomer('/notification-preferences', {\n schema: customerPortalNotificationPreferencesSchema,\n });\n}\n\nexport function updateNotificationPreferences(\n patch: CustomerNotificationPreferencesPatch,\n): Promise<SDKResponse<CustomerPortalNotificationPreferencesWire>> {\n return requestCustomer('/notification-preferences', {\n method: 'PATCH',\n body: {\n ...(patch.order_created_emails !== undefined\n ? { order_created_emails: patch.order_created_emails }\n : {}),\n ...(patch.order_completed_emails !== undefined\n ? { order_completed_emails: patch.order_completed_emails }\n : {}),\n ...(patch.payment_issue_emails !== undefined\n ? { payment_issue_emails: patch.payment_issue_emails }\n : {}),\n },\n schema: customerPortalNotificationPreferencesSchema,\n });\n}\n\nexport function sessions(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/sessions');\n}\n\nexport function revokeSession(id: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/sessions/${encodeURIComponent(id)}`, { method: 'DELETE' });\n}\n\n/**\n * Ends every session except this one.\n *\n * `others=true` is required, not decorative: `RevokeOtherSessionsQuerySchema`\n * declares it as a literal, so the route answers 400 without it. The selector\n * is explicit on purpose — \"revoke sessions\" with no qualifier is one typo away\n * from signing the buyer out of the device they are holding.\n */\nexport function revokeAllSessions(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/sessions?others=true', { method: 'DELETE' });\n}\n\n// ---------------------------------------------------------------------------\n// Wholesale (reseller program)\n//\n// A second program on the same account: its own way in, its own prepaid\n// balance, its own prices. Every route re-checks \"program enabled AND this\n// reseller is ACTIVE\" server-side, so nothing a storefront caches can widen\n// what a buyer may do here.\n//\n// Two writes are deliberately absent, and adding them back would be adding\n// methods that answer 404: the storefront worker refuses them. On a code\n// storefront the JavaScript on this origin is the MERCHANT's and it holds the\n// buyer's cookie, so the edge's same-origin check proves that script sent the\n// request, never that the buyer wanted it.\n// - placing a wholesale order debits the buyer's prepaid balance; a purchase\n// needs a boundary the merchant does not control\n// - minting an API key hands back a plaintext credential that keeps\n// authorizing orders after the session ends\n// Pricing a basket stays, because it writes nothing.\n// ---------------------------------------------------------------------------\n\n/** The program's state and this buyer's place in it. Null reseller means not enrolled. */\nexport function reseller(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/reseller');\n}\n\n/** `APPLICATION` mode. The note is optional unless the shop requires one. */\nexport function applyForReseller(note?: string): Promise<SDKResponse<unknown>> {\n return requestCustomer('/reseller/apply', {\n method: 'POST',\n body: note === undefined ? {} : { note },\n });\n}\n\n/** `OPEN` mode: no application, the buyer is a reseller when they say so. */\nexport function enrollAsReseller(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/reseller/enroll', { method: 'POST', body: {} });\n}\n\n/** `MANUAL` mode: the merchant invited this buyer and gave them a token. */\nexport function acceptResellerInvite(token: string): Promise<SDKResponse<unknown>> {\n return requestCustomer('/reseller/accept-invite', { method: 'POST', body: { token } });\n}\n\n/** The buyer's own tier prices. Page-based, like the order history. */\nexport function resellerCatalog(options: ResellerCatalogQuery = {}): Promise<SDKResponse<unknown>> {\n const query = new URLSearchParams();\n if (options.search !== undefined) query.set('search', options.search);\n if (options.page !== undefined) query.set('page', String(options.page));\n if (options.per_page !== undefined) query.set('per_page', String(options.per_page));\n\n const suffix = query.size > 0 ? `?${query.toString()}` : '';\n return requestCustomer(`/reseller/catalog${suffix}`);\n}\n\n/**\n * Prices a basket and writes nothing.\n *\n * The volume discount cannot be derived from the catalog — it only reports that\n * one exists — so a storefront that adds up unit prices itself shows a total\n * the shop will not charge. This is the number to display.\n */\nexport function quoteResellerOrder(items: ResellerOrderItem[]): Promise<SDKResponse<unknown>> {\n return requestCustomer('/reseller/orders/quote', { method: 'POST', body: { items } });\n}\n\nexport function resellerOrders(options: ResellerOrdersQuery = {}): Promise<SDKResponse<unknown>> {\n const query = new URLSearchParams();\n if (options.page !== undefined) query.set('page', String(options.page));\n if (options.per_page !== undefined) query.set('per_page', String(options.per_page));\n\n const suffix = query.size > 0 ? `?${query.toString()}` : '';\n return requestCustomer(`/reseller/orders${suffix}`);\n}\n\n/** One order with its lines, delivery state and delivered serials. */\nexport function resellerOrder(uniqid: string): Promise<SDKResponse<unknown>> {\n return requestCustomer(`/reseller/orders/${encodeURIComponent(uniqid)}`);\n}\n\n/** The prepaid balance the wholesale orders are paid from. */\nexport function resellerWallet(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/reseller/wallet');\n}\n\nexport function resellerApiKeys(): Promise<SDKResponse<unknown>> {\n return requestCustomer('/reseller/api-keys');\n}\n\n/*\n * There is no `revokeResellerApiKey`. Revoking is irreversible and stops\n * whatever the key was driving, and this SDK is the transport for code\n * storefronts — merchant-authored JavaScript running with the buyer's session,\n * where a confirmation proves nothing because the merchant renders it. The\n * edge omits the DELETE from `CUSTOMER_API_ALLOWLIST`\n * (`workers/storefront/src/customer-api.ts`), so exporting a method for it\n * would advertise a call that always answers 404.\n */\n","/**\n * Shoppex Storefront SDK\n *\n * Usage:\n * ```html\n * <script src=\"https://cdn.shoppex.io/sdk/v1.0/shoppex.umd.js\"></script>\n * <script>\n * shoppex.init('my-store');\n *\n * shoppex.getStore().then(store => console.log(store));\n * shoppex.addToCart('product-id', 'variant-id', 2);\n * shoppex.checkout();\n * </script>\n * ```\n */\n\nimport { storefrontSdk } from './storefront-sdk';\n\n// Re-export types\nexport * from './types';\nexport * from './core/errors';\nexport {\n buildStorefrontCustomFieldPayload,\n isStorefrontCheckboxCustomFieldValueChecked,\n normalizeStorefrontCustomFields,\n validateStorefrontCustomFieldValue,\n} from './utils/storefront-custom-fields';\nexport type { StorefrontCustomField } from './utils/storefront-custom-fields';\nexport {\n isProductInStock,\n isProductOutOfStock,\n isVariantOutOfStock,\n resolveDisplayStock,\n resolveVariantStockValue,\n} from './utils/storefront-stock';\nexport {\n buildStorefrontProductLookup,\n getMergedStorefrontProducts,\n getStorefrontGroupProducts,\n} from './utils/storefront-catalog';\nexport {\n stripHtmlFromText,\n normalizeSearchQuery,\n collectProductSearchHaystack,\n productMatchesSearchQuery,\n groupMatchesSearchQuery,\n filterProductsBySearchQuery,\n searchMergedStorefrontCatalog,\n searchMergedStorefrontCatalogItems,\n} from './utils/storefront-search';\nexport type { StorefrontSearchFilterOptions, StorefrontCatalogSearchItem } from './utils/storefront-search';\nexport {\n buildStorefrontContactMessage,\n resolveStorefrontApiBaseUrl,\n resolveStorefrontSocialLinks,\n submitStorefrontContactTicket,\n} from './utils/storefront-contact';\nexport type {\n StorefrontContactTicketInput,\n StorefrontContactTicketResult,\n StorefrontSocialLinks,\n} from './utils/storefront-contact';\nexport type {\n BlockDefinition,\n BlockInstance,\n PageLayout,\n ThemeConfig,\n ThemeBlockManifest,\n SettingField,\n SectionDefinition,\n ResolvedThemeSettings,\n} from './types/theme-config';\nexport type { PublishedBuilderSettings, PublishedThemeSettingsPayload } from './modules/theme';\nexport type { NavigationMenuSlot } from '@shoppex/contracts/navigation';\nexport {\n CATALOG_UNIT_PRICE_DECIMAL_PLACES,\n CATALOG_UNIT_PRICE_FORMAT_OPTIONS,\n PAYABLE_AMOUNT_DECIMAL_PLACES,\n roundPayableAmount,\n} from '@shoppex/contracts/catalog-unit-price';\n\n// resolveCartLineId is re-exported on the default shoppex object below (not only type-only).\nexport { computeCartLineId, ensureCartLineId } from './utils/cart-line-id';\nexport type { CartLineIdentityInput } from './utils/cart-line-id';\n\nexport type { CheckoutOptions, CheckoutResult } from './modules/checkout';\nexport { CheckoutCreateError } from './modules/checkout';\nexport type { SearchOptions } from './modules/search';\n\nexport { getShopReviewsPage, PRODUCT_FILTER_UNSUPPORTED } from './modules/reviews';\n\n// Customer module\nimport {\n requestOtp,\n verifyOtp,\n logout,\n me,\n dashboard,\n orders,\n order,\n invoicePdf,\n loyalty,\n redeemLoyaltyPoints,\n warranties,\n claimWarranty,\n orderReview,\n resetLicenseHwid,\n subscriptionBillingHistory,\n cancelSubscription,\n pauseSubscription,\n resumeSubscription,\n undoSubscriptionCancel,\n favorites,\n addFavorite,\n removeFavorite,\n affiliate,\n affiliateStats,\n createAffiliateLink,\n createTicket,\n ticket,\n replyToTicket,\n uploadTicketImage,\n discardTicketImage,\n updateProfile,\n updateAvatar,\n removeAvatar,\n emailPreferences,\n updateEmailPreferences,\n notificationPreferences,\n updateNotificationPreferences,\n sessions,\n revokeSession,\n revokeAllSessions,\n reseller,\n applyForReseller,\n enrollAsReseller,\n acceptResellerInvite,\n resellerCatalog,\n quoteResellerOrder,\n resellerOrders,\n resellerOrder,\n resellerWallet,\n resellerApiKeys,\n} from './modules/customer';\nexport {\n requestOtp,\n verifyOtp,\n logout,\n me,\n dashboard,\n orders,\n order,\n invoicePdf,\n loyalty,\n redeemLoyaltyPoints,\n warranties,\n claimWarranty,\n orderReview,\n resetLicenseHwid,\n subscriptionBillingHistory,\n cancelSubscription,\n pauseSubscription,\n resumeSubscription,\n undoSubscriptionCancel,\n favorites,\n addFavorite,\n removeFavorite,\n affiliate,\n affiliateStats,\n createAffiliateLink,\n createTicket,\n ticket,\n replyToTicket,\n uploadTicketImage,\n discardTicketImage,\n updateProfile,\n updateAvatar,\n removeAvatar,\n emailPreferences,\n updateEmailPreferences,\n notificationPreferences,\n updateNotificationPreferences,\n sessions,\n revokeSession,\n revokeAllSessions,\n reseller,\n applyForReseller,\n enrollAsReseller,\n acceptResellerInvite,\n resellerCatalog,\n quoteResellerOrder,\n resellerOrders,\n resellerOrder,\n resellerWallet,\n resellerApiKeys,\n} from './modules/customer';\nexport type {\n CustomerTicketPayload,\n CustomerProfilePatch,\n CustomerSubscriptionCancelOptions,\n CustomerSubscriptionPauseOptions,\n CustomerSubscriptionPauseReason,\n CustomerEmailPreferencesPatch,\n CustomerNotificationPreferencesPatch,\n CustomerAffiliateLinkInput,\n CustomerInvoicePdf,\n ResellerOrderItem,\n ResellerCatalogQuery,\n ResellerOrdersQuery,\n} from './modules/customer';\n\nexport { fetchPublishedBuilderSettings, fetchPublishedThemeSettings, resolveDefaults, mergeSettings } from './modules/theme';\nexport { trackCartActivity, trackPageView, trackProductView } from './modules/analytics';\nexport { getStorefrontOnlineUsers, getStorefrontRecentSales, touchStorefrontPresence } from './modules/presence';\nexport { getMenus, getMenu, getMenuBySlot, getMenuByTitle, getMenuSlotTitles } from './modules/navigation';\n\n/**\n * Shoppex SDK instance\n */\nexport const shoppex = {\n ...storefrontSdk,\n\n // Customer account\n requestOtp,\n verifyOtp,\n logout,\n me,\n dashboard,\n orders,\n order,\n invoicePdf,\n loyalty,\n redeemLoyaltyPoints,\n warranties,\n claimWarranty,\n orderReview,\n resetLicenseHwid,\n subscriptionBillingHistory,\n cancelSubscription,\n pauseSubscription,\n resumeSubscription,\n undoSubscriptionCancel,\n favorites,\n addFavorite,\n removeFavorite,\n affiliate,\n affiliateStats,\n createAffiliateLink,\n createTicket,\n ticket,\n replyToTicket,\n uploadTicketImage,\n discardTicketImage,\n updateProfile,\n updateAvatar,\n removeAvatar,\n emailPreferences,\n updateEmailPreferences,\n notificationPreferences,\n updateNotificationPreferences,\n sessions,\n revokeSession,\n revokeAllSessions,\n reseller,\n applyForReseller,\n enrollAsReseller,\n acceptResellerInvite,\n resellerCatalog,\n quoteResellerOrder,\n resellerOrders,\n resellerOrder,\n resellerWallet,\n resellerApiKeys,\n};\n\n// Default export for ES modules\nexport default shoppex;\n\n// UMD global exposure — never clobber an already-initialized client. Theme\n// artifacts can load multiple SDK chunks; a late bundle must not reset init.\nif (typeof window !== 'undefined') {\n const w = window as unknown as { shoppex?: typeof shoppex };\n if (!w.shoppex?.isInitialized?.()) {\n w.shoppex = shoppex;\n }\n}\n"],"mappings":"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","names":["cache","order","request","engagedMs","hashString","fetch","init","request","error","final","joiner","normalizeAffiliateCode","cachedShopId","isRecord","ticket"]}
|