@numueg/theme-sdk 0.13.1 → 0.13.2

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types/theme.ts","../src/hooks/useProduct.ts","../src/hooks/useCollection.ts","../src/hooks/useListingHeading.ts","../src/hooks/useCart.ts","../src/hooks/useCurrentTemplate.ts","../src/hooks/useMetafield.ts","../src/hooks/useArticles.ts","../src/hooks/useSection.ts","../src/hooks/useSectionGroup.ts","../src/hooks/useCurrency.ts","../src/hooks/useMoney.ts","../src/hooks/useImage.ts","../src/contexts/customer-actions.ts","../src/hooks/useCustomerActions.ts","../src/hooks/useOrders.ts","../src/hooks/useCustomerAddresses.ts","../src/hooks/useNavigation.ts","../src/hooks/useSearch.ts","../src/hooks/useAnalytics.ts","../src/lib/dataCache.ts","../src/hooks/useApp.ts","../src/hooks/useWishlist.ts","../src/hooks/useRelatedProducts.ts","../src/hooks/useActivePromotions.ts","../src/utils/money.ts","../src/lib/promotions.ts","../src/hooks/useProductSizeChart.ts","../src/utils/variants.ts","../src/utils/selectionRegistry.ts","../src/hooks/useVariantSelection.ts","../src/hooks/useGiftCardBalance.ts","../src/hooks/useReorder.ts","../src/hooks/useCheckout.ts","../src/hooks/useShippingRates.ts","../src/components/NuMuProvider.tsx","../src/components/ProductProvider.tsx","../src/components/CollectionProvider.tsx","../src/utils/logoStyle.ts","../src/utils/styleTokens.ts","../src/mount.tsx","../src/entry.tsx","../src/components/Money.tsx","../src/utils/imageTransform.ts","../src/components/Image.tsx","../src/components/HeroMedia.tsx","../src/components/Logo.tsx","../src/components/Link.tsx","../src/components/AddToCartButton.tsx","../src/components/Section.tsx","../src/components/Form.tsx","../src/utils/routes.ts","../src/components/ProductCard.tsx","../src/components/CollectionCard.tsx","../src/components/RichText.tsx","../src/components/CurrencySwitcher.tsx","../src/components/LocaleSwitcher.tsx","../src/components/Editable.tsx","../src/components/Icon.tsx","../src/utils/federation.ts","../src/utils/dynamicSources.ts","../src/hooks/useResolvedSettings.ts","../src/utils/defineSection.ts","../src/utils/assetUrl.ts","../src/utils/templates.ts","../src/utils/locales.ts"],"names":["useContext","ProductContext","CollectionContext","CartContext","CurrentTemplateContext","PageContext","createContext","ThemeSettingsContext","useMemo","CurrencyContext","useShop","formatMoney","useLocalization","useCustomer","useState","useEffect","unwrap","useCallback","NavigationContext","LocalizationContext","EMPTY","useRef","cache","useSyncExternalStore","opts","jsx","ShopContext","CustomerContext","pageData","forwardRef","ThemeMountBridge","useImperativeHandle","StrictMode","hydrateRoot","createRoot","createElement","DEFAULT_WIDTHS","useThemeSettings","Fragment","Component","jsxs","ABSOLUTE_URL","readCsrfCookie","joinClass","EditableText","EditableImage"],"mappings":"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","file":"index.cjs","sourcesContent":["/** V3 Theme Settings — the canonical data shape */\nexport interface ThemeSettingsV3 {\n schema_version: 3;\n theme_id: string;\n global_settings: Record<string, any>;\n templates: Record<string, PageTemplate>;\n section_groups: Record<string, SectionGroup>;\n external_theme?: ExternalThemeMetadata | null;\n}\n\nexport interface PageTemplate {\n name: string;\n sections: Record<string, SectionInstance>;\n order: string[];\n}\n\nexport interface SectionGroup {\n name: string;\n sections: Record<string, SectionInstance>;\n order: string[];\n}\n\nexport interface SectionInstance {\n type: string;\n settings: Record<string, any>;\n disabled?: boolean;\n blocks?: Record<string, BlockInstance>;\n block_order?: string[];\n}\n\nexport interface BlockInstance {\n type: string;\n settings: Record<string, any>;\n disabled?: boolean;\n /** Nested child blocks (blocks-in-blocks): a block can hold its own\n * block container — e.g. a footer \"column\" holding \"link\" blocks, or\n * a mega-menu. Same shape as a section's block container, so the\n * render/editor walk is uniform at any depth. Optional + absent on\n * leaf blocks, so pre-nesting payloads load unchanged. */\n blocks?: Record<string, BlockInstance>;\n block_order?: string[];\n}\n\nexport interface ExternalThemeMetadata {\n bundle_url: string;\n css_url?: string | null;\n mode?: string;\n settings_schema?: Record<string, any> | null;\n section_schemas?: Record<string, any> | null;\n}\n\n/**\n * Live mount handle returned by a V3 theme bundle's `mount(el, ctx)`.\n *\n * Two shapes accepted by the host:\n *\n * 1. **Legacy** — `mount(el, ctx): () => void`\n * The bundle returns only a cleanup function. Every host-side\n * themeSettings change forces a full unmount + remount, which is\n * expensive but always correct. Hosts must keep supporting this\n * for older bundles built against pre-0.2 SDK versions.\n *\n * 2. **Wave 3+** — `mount(el, ctx): MountResult`\n * The bundle returns an object with `cleanup` + an `applyDraft`\n * method that takes a fresh `ThemeSettingsV3` and re-renders the\n * bundle's React tree in-place (no createRoot churn). This is the\n * fast path used by the customizer's live preview — a keystroke\n * in the dashboard becomes a single React reconciliation in the\n * iframe, typically < 16 ms.\n *\n * Hosts feature-detect by checking `typeof handle === \"function\"`\n * (legacy) vs `typeof handle === \"object\" && handle.cleanup`\n * (Wave 3+). Theme authors should prefer the MountResult shape — the\n * `numuTheme` plugin's typings will flag the missing applyDraft once\n * the editor's live-preview path requires it.\n */\nexport interface MountResult {\n /** Unmount the bundle's React tree and release any resources. */\n cleanup: () => void;\n /**\n * Apply a fresh draft (e.g. from the customizer iframe's\n * `numu:theme:update` postMessage) without tearing down the tree.\n * Implementations typically forward the value to a useState setter\n * inside a wrapper that renders `<NuMuProvider themeSettings={...}>`.\n *\n * Safe to call repeatedly; the bundle is expected to dedup\n * reference-equal calls on its own. Returns nothing — selection /\n * navigation echo back via postMessage.\n */\n applyDraft: (next: ThemeSettingsV3) => void;\n}\n\n/** Section schema for customizer form generation */\nexport interface SectionSchema {\n type: string;\n name: string;\n name_ar?: string;\n tag?: string;\n class?: string;\n limit?: number;\n settings: SettingDefinition[];\n blocks?: BlockSchema[];\n max_blocks?: number;\n presets?: SectionPreset[];\n}\n\nexport interface BlockSchema {\n type: string;\n name: string;\n name_ar?: string;\n limit?: number;\n settings: SettingDefinition[];\n /** Child block types this block accepts (recursive). When present,\n * the customizer lets merchants add/remove/reorder these inside the\n * block, up to `max_blocks`. Enables footer columns, mega-menus,\n * multi-column layouts. The host caps practical nesting depth\n * (MAX_BLOCK_DEPTH). */\n blocks?: BlockSchema[];\n max_blocks?: number;\n}\n\n/** Max nesting depth the customizer allows for blocks-in-blocks. Depth\n * 1 = a top-level block in a section; a block at this depth can't take\n * children. Generous (below Shopify's 8) and cheap to raise. Kept in\n * sync with the merchant hub's MAX_BLOCK_DEPTH. */\nexport const MAX_BLOCK_DEPTH = 5;\n\n/**\n * Setting types the V3 customizer renders. Themes can declare any\n * string here; unknown types fall through to a plain text input. The\n * union below documents the canonical set so theme authors get\n * autocomplete and TypeScript errors on typos.\n */\nexport type SettingType =\n | \"text\"\n | \"textarea\"\n | \"richtext\"\n | \"number\"\n | \"range\"\n | \"color\"\n | \"checkbox\"\n | \"select\"\n | \"radio\"\n | \"font\"\n | \"image_picker\"\n | \"url\"\n | \"product\"\n | \"product_list\"\n | \"collection\"\n | \"collection_list\"\n | \"header\"\n | \"paragraph\"\n | \"html\"\n | \"date\"\n | \"time\"\n | \"video_picker\"\n | \"color_scheme\"\n | \"page_picker\"\n | \"blog_picker\"\n | \"link_list_picker\"\n | \"variant_picker\"\n | \"file_upload\"\n | \"icon_picker\"\n | \"icon\";\n\n/**\n * `visible_if` — conditional visibility expression evaluated against\n * sibling settings in the same schema. Two flavors:\n *\n * - String DSL: `\"settings.show_button == true && settings.layout != 'minimal'\"`\n * - Object form: `{ show_button: true, layout: [\"full\", \"split\"] }`\n *\n * Evaluator lives in the merchant hub: any setting whose expression is\n * falsy is skipped from the rendered form.\n */\nexport type VisibleIf = string | Record<string, unknown>;\n\nexport interface SettingDefinition {\n type: SettingType | (string & {}); // unions stay open for forward-compat\n id: string;\n label: string;\n label_ar?: string;\n default?: any;\n info?: string;\n info_ar?: string;\n placeholder?: string;\n options?: { value: string; label: string; label_ar?: string }[];\n min?: number;\n max?: number;\n step?: number;\n unit?: string;\n /** Hide this setting unless the expression evaluates truthy. */\n visible_if?: VisibleIf;\n /** Aspect hint for image_picker previews + server crops, e.g. \"16/9\". */\n aspect_ratio?: string;\n}\n\nexport interface PresetBlock {\n type: string;\n settings?: Record<string, any>;\n /** Nested starter blocks materialized when the preset is applied\n * (recursive). Lets a preset ship, e.g., a footer column already\n * populated with link blocks. */\n blocks?: PresetBlock[];\n}\n\nexport interface SectionPreset {\n name: string;\n /** Localized names so the Add Section dialog reads in the editor's\n * current locale. Falls back to `name` when the locale is missing. */\n locales?: {\n en?: { name?: string };\n ar?: { name?: string };\n };\n settings?: Record<string, any>;\n blocks?: PresetBlock[];\n}\n\n/**\n * Section component props.\n *\n * Generic over the settings shape so a theme can type its own settings\n * without hand-rolling a parallel props interface (the `EmpSectionProps`\n * pattern every theme was duplicating). `id`/`type` mirror the section\n * instance's key + `SectionInstance.type` so a component can key React\n * lists, dispatch on type, or emit editor anchors without threading them\n * separately; `groupId` names the owning `SectionGroup` for header/footer\n * group sections (absent for template sections).\n *\n * // Loosely typed (default) — settings is Record<string, unknown>:\n * function Hero(props: SectionProps) { … }\n *\n * // Strongly typed:\n * interface HeroSettings { headline: string; show_cta: boolean }\n * function Hero({ settings }: SectionProps<HeroSettings>) {\n * return <h1>{settings.headline}</h1>;\n * }\n */\nexport interface SectionProps<S = Record<string, unknown>> {\n /** The section instance's key within its template/group. */\n id: string;\n /** The section's `type` (its schema type / component name). */\n type: string;\n /** Owning section-group id for header/footer group sections; absent for\n * template-level sections. */\n groupId?: string;\n settings: S;\n blocks?: Record<string, BlockInstance>;\n blockOrder?: string[];\n storeData?: any;\n}\n\n/** Block component props */\nexport interface BlockProps {\n settings: Record<string, any>;\n /** Child block instances when this block nests others (footer column,\n * mega-menu, …). Mirror the section→block render: map `blockOrder`\n * and look each id up in `blocks`, wrapping each child in `<Block>`. */\n blocks?: Record<string, BlockInstance>;\n blockOrder?: string[];\n}\n","import { useContext } from \"react\";\nimport { ProductContext } from \"../contexts\";\nimport type { Product } from \"../types/entities\";\n\nexport function useProduct(): Product {\n const ctx = useContext(ProductContext);\n if (!ctx) throw new Error(\"useProduct must be used within ProductProvider\");\n return ctx;\n}\n\nexport function useProductOptional(): Product | null {\n return useContext(ProductContext);\n}\n","import { useContext } from \"react\";\nimport { CollectionContext } from \"../contexts\";\nimport type { Collection } from \"../types/entities\";\n\nexport function useCollection(): Collection {\n const ctx = useContext(CollectionContext);\n if (!ctx) throw new Error(\"useCollection must be used within CollectionProvider\");\n return ctx;\n}\n\nexport function useCollectionOptional(): Collection | null {\n return useContext(CollectionContext);\n}\n","import { useContext } from \"react\";\nimport { CollectionContext } from \"../contexts\";\nimport type { Collection } from \"../types/entities\";\n\nexport interface ListingHeading {\n /** The collection the shopper is inside, or `null` on the all-products listing. */\n collection: Collection | null;\n /** `true` when this listing is scoped to one collection. */\n isCollection: boolean;\n /** What to render as the page heading. */\n title: string;\n /** What to render under it. Empty string when there is nothing to say. */\n description: string;\n}\n\nexport interface ListingHeadingOptions {\n /** The merchant's own heading from this section's settings, if they set one. */\n title?: string | null;\n /** The merchant's own sub-heading from this section's settings. */\n description?: string | null;\n /**\n * The theme's wording for the UNSCOPED listing — already localized by the\n * theme, e.g. `localized(locale, \"All products\", \"كل المنتجات\")`.\n */\n defaultTitle?: string | null;\n}\n\n/**\n * What a product-listing section should call itself.\n *\n * Every theme hardcoded \"All products\" as its listing heading, so a shopper who\n * clicked into a category landed on a page titled **All products** showing a\n * subset of the catalog. The products were correctly scoped — the page just\n * never said which collection it was. That reads as a bug (\"where did the rest\n * go?\") and it costs the collection name in the one place it matters most.\n *\n * Precedence, highest first:\n * 1. the collection's own name — when the shopper is inside one, that IS the\n * page, and it always beats a static setting;\n * 2. the merchant's section setting — their wording for the all-products page;\n * 3. the theme's default.\n *\n * Categories carry no separate Arabic column, so `collection.name` is rendered\n * as the merchant typed it; only the fallback is localized, by the caller.\n *\n * @example\n * const { title, description, isCollection } = useListingHeading({\n * title: asString(s.title),\n * description: asString(s.subtitle),\n * defaultTitle: localized(locale, \"All products\", \"كل المنتجات\"),\n * });\n */\nexport function useListingHeading(\n options: ListingHeadingOptions = {},\n): ListingHeading {\n const collection = useContext(CollectionContext);\n const clean = (v: unknown): string =>\n typeof v === \"string\" && v.trim() !== \"\" ? v.trim() : \"\";\n\n const collectionName = clean(collection?.name);\n const collectionDescription = clean(\n (collection as { description?: unknown } | null)?.description,\n );\n\n return {\n collection: collection ?? null,\n isCollection: collectionName !== \"\",\n title:\n collectionName ||\n clean(options.title) ||\n clean(options.defaultTitle) ||\n \"\",\n description:\n collectionDescription || clean(options.description) || \"\",\n };\n}\n","import { useContext } from \"react\";\nimport { CartContext } from \"../contexts\";\n\nexport function useCart() {\n const ctx = useContext(CartContext);\n if (!ctx) throw new Error(\"useCart must be used within NuMuProvider\");\n return ctx;\n}\n","\"use client\";\n\nimport { useContext } from \"react\";\nimport { CurrentTemplateContext } from \"../contexts\";\n\n/**\n * useCurrentTemplate — read the active page template's id.\n *\n * Values are the same strings used as keys in\n * `themeSettings.templates.<id>`:\n *\n * \"home\" | \"product\" | \"collection\" | \"cart\" | \"checkout\"\n * \"order-confirmation\" | \"profile\" | \"page\" | \"404\" | \"password\"\n *\n * Themes use this to render the matching section list:\n *\n * const template = useCurrentTemplate();\n * const settings = useThemeSettings();\n * const sections = settings.templates?.[template]?.sections ?? {};\n *\n * Default: \"home\" — when the host hasn't supplied a CurrentTemplate\n * provider, themes still render their home template instead of\n * crashing or showing a blank screen.\n *\n * The hook is read-only; the active template changes via the host\n * navigating between Next.js routes (each route's `page.tsx` wraps\n * its content with the correct currentTemplate at the\n * `<NuMuProvider currentTemplate=\"…\">` prop).\n */\nexport function useCurrentTemplate(): string {\n return useContext(CurrentTemplateContext);\n}\n","import { useContext } from \"react\";\nimport { CollectionContext, PageContext, ProductContext } from \"../contexts\";\nimport type { Metafield } from \"../types/entities\";\n\n/**\n * Owners a theme can read metafields from. Matches the platform's\n * metafield owner types (product / collection / page). Only PUBLIC\n * metafields ever reach the storefront — the privacy filter runs\n * server-side at the payload layer, so a private field is simply absent\n * here, never present-but-hidden.\n */\nexport type MetafieldOwner = \"product\" | \"collection\" | \"page\";\n\nfunction isMetafield(value: unknown): value is Metafield {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as Metafield).namespace === \"string\" &&\n typeof (value as Metafield).key === \"string\"\n );\n}\n\n/**\n * CMS page routes project the page record at `page.data.page` (see the\n * host's `/pages/[handle]` route); other page types may surface a flat\n * `data.metafields`. Accept both, prefer the nested record.\n */\nfunction pageMetafields(data: Record<string, unknown> | undefined): Metafield[] {\n if (!data) return [];\n const record = data.page as Record<string, unknown> | undefined;\n for (const candidate of [record?.metafields, data.metafields]) {\n if (Array.isArray(candidate)) return candidate.filter(isMetafield);\n }\n return [];\n}\n\n/**\n * All public metafields of the given owner currently in context.\n * Empty array when the owner isn't in context (e.g. `\"product\"` on a\n * collection page) or has no fields — never throws.\n */\nexport function useMetafields(owner: MetafieldOwner): Metafield[] {\n const product = useContext(ProductContext);\n const collection = useContext(CollectionContext);\n const page = useContext(PageContext);\n switch (owner) {\n case \"product\":\n return product?.metafields ?? [];\n case \"collection\":\n return collection?.metafields ?? [];\n case \"page\":\n return pageMetafields(page?.data);\n default:\n return [];\n }\n}\n\n/**\n * Read one merchant-defined field directly:\n *\n * ```tsx\n * const material = useMetafield(\"product\", \"specs\", \"material\");\n * if (material) <dd>{String(material.value)}</dd>;\n * ```\n *\n * Returns the full {@link Metafield} (value pre-coerced to its declared\n * type by the platform) or `null` when missing — same convention as the\n * dynamic-source resolver (`{owner}.metafield:{namespace}.{key}`), so a\n * theme's own fallback renders for stores that haven't set the field.\n */\nexport function useMetafield(\n owner: MetafieldOwner,\n namespace: string,\n key: string,\n): Metafield | null {\n const fields = useMetafields(owner);\n return (\n fields.find((m) => m.namespace === namespace && m.key === key) ?? null\n );\n}\n","import { useContext } from \"react\";\nimport { PageContext } from \"../contexts\";\nimport type {\n ArticleDetail,\n ArticleSummary,\n BlogSummary,\n} from \"../types/entities\";\n\n/**\n * Blog/article hooks — read the content the host resolves server-side\n * into the page descriptor:\n *\n * `blogs` template → `page.data.blogs` → useBlogs()\n * `blog` template → `page.data.blog` + `.articles` → useBlog() / useArticles()\n * `article` template → `page.data.article` → useArticle()\n *\n * All of them degrade to `[]` / `null` outside their template (or on a\n * store with no blog content) — never throw, so a section can render its\n * empty state. Text fields are bilingual maps; the body is UN-sanitized\n * merchant HTML — render via `<RichText>`.\n */\n\nfunction pageData(): Record<string, unknown> | undefined {\n // A hook in all but name; isolated so each public hook stays a plain\n // one-liner over the same context read.\n return useContext(PageContext)?.data;\n}\n\n/** Published blogs of the store (blogs-index template). */\nexport function useBlogs(): BlogSummary[] {\n const data = pageData();\n const blogs = data?.blogs;\n return Array.isArray(blogs) ? (blogs as BlogSummary[]) : [];\n}\n\n/** The current blog (blog template), or the article's blog on an article page. */\nexport function useBlog(): BlogSummary | null {\n const data = pageData();\n const blog = data?.blog ?? (data?.article as ArticleDetail | undefined)?.blog;\n return blog && typeof blog === \"object\" ? (blog as BlogSummary) : null;\n}\n\n/** Published articles of the current blog (blog template), newest first. */\nexport function useArticles(): ArticleSummary[] {\n const data = pageData();\n const articles = data?.articles;\n return Array.isArray(articles) ? (articles as ArticleSummary[]) : [];\n}\n\n/** The current article (article template). */\nexport function useArticle(): ArticleDetail | null {\n const data = pageData();\n const article = data?.article;\n return article && typeof article === \"object\"\n ? (article as ArticleDetail)\n : null;\n}\n","import { createContext, useContext } from \"react\";\nimport type { SectionInstance } from \"../types/theme\";\n\nexport const SectionContext = createContext<SectionInstance | null>(null);\n\nexport function useSection(): SectionInstance {\n const ctx = useContext(SectionContext);\n if (!ctx) throw new Error(\"useSection must be used within a section component\");\n return ctx;\n}\n\nexport function useSectionOptional(): SectionInstance | null {\n return useContext(SectionContext);\n}\n","\"use client\";\n\nimport { useContext, useMemo } from \"react\";\nimport { ThemeSettingsContext } from \"../contexts\";\nimport type { SectionInstance } from \"../types/theme\";\n\n/**\n * A section instance from a section group, carrying its own `id` (the key it\n * had inside the group's `sections` map). The raw `SectionInstance` drops the\n * id — but a theme needs it to key its React list, wire `<Section id={…}>`\n * click-to-select, and look the type up in its own registry — so\n * `useSectionGroup` re-attaches it here.\n */\nexport interface SectionGroupInstance extends SectionInstance {\n /** The instance's key within the group's `sections` map. */\n id: string;\n}\n\nconst EMPTY: readonly SectionGroupInstance[] = Object.freeze([]);\n\n/**\n * useSectionGroup — read the ordered section instances for a named section\n * group (\"header\", \"footer\", or any custom global group) out of\n * `themeSettings.section_groups[group]`.\n *\n * This is the SDK side of \"global sections shared across pages\": the host\n * ships one `section_groups` map on every page, and a theme renders a given\n * group in its layout (header/footer) or wherever it wants a page-independent\n * section list. The returned array is in the group's `order`, and each entry\n * carries its `id` so the theme can key + select + dispatch on it:\n *\n * ```tsx\n * const headerSections = useSectionGroup(\"header\");\n * return headerSections.map(({ id, type, settings }) => {\n * const Comp = registry[type]?.render; // theme owns the registry\n * return Comp ? (\n * <Section key={id} id={id} type={type} groupId=\"header\">\n * <Comp settings={settings} />\n * </Section>\n * ) : null;\n * });\n * ```\n *\n * Pure data hook — it does NOT map types to components. The SDK has no section\n * registry (a theme builds its own via `collectSections`), so there is no\n * generic `<GlobalSections>` renderer to ship: the theme walks the returned\n * instances through its own registry, exactly as it already does for template\n * sections. Returns `[]` (a stable reference) when there is no provider, no\n * `section_groups`, the named group is absent, or its `order` is empty.\n *\n * Disabled instances are INCLUDED (a `disabled` flag is preserved on each\n * entry); filter with `.filter((s) => !s.disabled)` if the theme hides them.\n * Ids listed in `order` but missing from `sections` are skipped defensively.\n */\nexport function useSectionGroup(group: string): SectionGroupInstance[] {\n const settings = useContext(ThemeSettingsContext);\n return useMemo(() => {\n const grp = settings?.section_groups?.[group];\n if (!grp || !Array.isArray(grp.order) || grp.order.length === 0) {\n return EMPTY as SectionGroupInstance[];\n }\n const sections = grp.sections ?? {};\n const out: SectionGroupInstance[] = [];\n for (const id of grp.order) {\n const instance = sections[id];\n if (!instance) continue; // order references a removed section — skip.\n out.push({ id, ...instance });\n }\n return out;\n }, [settings, group]);\n}\n","\"use client\";\nimport { useContext, useMemo } from \"react\";\nimport { CurrencyContext } from \"../contexts\";\nimport { useShop } from \"./useShop\";\nimport type { CurrencyState } from \"../contexts\";\n\n/**\n * Multi-currency presentment — Phase 6, lifted into a provider context in\n * Phase 2 (correctness).\n *\n * The store's *capture* currency (what Paymob/Stripe/etc. charges) never\n * changes mid-session. This hook is purely about **display**: letting\n * visitors browse prices in a currency they recognize.\n *\n * As of Phase 2 the currency config + selection live in `CurrencyContext`,\n * fetched ONCE by `NuMuProvider` (see `/api/storefront/currencies`) and shared\n * by every consumer. Before this, each `useCurrency()` caller fetched its own\n * copy and held the selection in per-instance state, so a `<CurrencySwitcher>`\n * change never reached the `<Money>` tags. Now it does — changing the selected\n * currency re-renders every `<Money>`/`useMoney()` on the page, no reload.\n *\n * Usage:\n *\n * const { base, selected, presentment, convert, setSelected } = useCurrency();\n * <p>{convert(product.price.amount_cents)} {selected}</p>\n * {presentment.length > 1 && (\n * <select value={selected} onChange={(e) => setSelected(e.target.value)}>\n * {presentment.map(c => <option key={c}>{c}</option>)}\n * </select>\n * )}\n *\n * Behavior (owned by `NuMuProvider`):\n * - `selected` defaults to the persisted `numu_currency` cookie if valid,\n * else `default_presentment`, else `base`.\n * - `setSelected` writes the cookie (path=/, 30d) so navigation preserves\n * the choice across pages.\n * - `convert(cents)` returns the converted cents in `selected`, using the\n * rates from the API. When no rate exists, returns the input unchanged\n * (theme renders in base — better than a wrong number).\n *\n * Use `<CurrencySwitcher>` from the SDK for an opinionated UI, or read this\n * hook directly for full control.\n */\n\n// Re-export the currency types from their canonical home (contexts) so\n// existing `import type { CurrencyConfig, CurrencyState } from\n// \"@numueg/theme-sdk\"` (which flows through this module's re-export in\n// index.ts) keeps resolving unchanged.\nexport type { CurrencyConfig, CurrencyState } from \"../contexts\";\n\nexport function useCurrency(): CurrencyState {\n const ctx = useContext(CurrencyContext);\n const shop = useShop();\n\n // Fallback for trees without a NuMuProvider currency value — SSR before the\n // provider's fetch resolves, or a theme mounted outside NuMuProvider. A\n // base-only, no-conversion state so `<Money>`/`<CurrencySwitcher>` render the\n // store currency instead of crashing. The provider owns the real fetch.\n const fallback = useMemo<CurrencyState>(() => {\n const ccy = shop?.currency || \"EGP\";\n return {\n base: ccy,\n selected: ccy,\n presentment: [ccy],\n rates: {},\n autoConvert: false,\n loading: false,\n setSelected: () => {},\n convert: (cents: number) => cents,\n };\n }, [shop?.currency]);\n\n return ctx ?? fallback;\n}\n","\"use client\";\n\nimport { useLocalization } from \"./useLocalization\";\nimport { useShop } from \"./useShop\";\nimport { useCurrency } from \"./useCurrency\";\n\n/**\n * useMoney — convenience hook that returns a formatter bound to the active\n * store's currency.\n *\n * Useful when a section needs to format multiple amounts in a render:\n *\n * const money = useMoney();\n * return <td>{money(item.price * item.quantity)}</td>\n *\n * Multi-currency: like <Money>, when the store has `auto_convert` on and no\n * `currencyOverride` is passed, amounts are converted to and formatted in the\n * visitor's SELECTED presentment currency (shared via `useCurrency()`), so a\n * `<CurrencySwitcher>` change reflows these too. Pass a `currencyOverride` to\n * pin a specific currency and skip conversion.\n *\n * For one-off price displays prefer the <Money> component which handles\n * compare-at and inline rendering.\n */\nexport function useMoney(currencyOverride?: string) {\n const { formatMoney } = useLocalization();\n const shop = useShop();\n const { selected, base, autoConvert, convert } = useCurrency();\n return (amount: number) => {\n const shouldConvert =\n autoConvert && !currencyOverride && !!selected && selected !== base;\n if (shouldConvert) {\n // convert() works in cents; amount is major units — round-trip.\n const converted = convert(Math.round(amount * 100), selected) / 100;\n return formatMoney(converted, selected);\n }\n return formatMoney(amount, currencyOverride || shop?.currency);\n };\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\n\ninterface UseImageOptions {\n /** Sizes attribute (CSS sizes form). */\n sizes?: string;\n /** Widths to generate in srcSet. Falsy → use defaults. */\n widths?: number[];\n /** Pass-through alt text — useImage doesn't render anything; the\n * caller does. */\n alt?: string;\n}\n\ninterface ImageDescriptor {\n src: string | null;\n srcSet: string | null;\n sizes: string;\n alt: string;\n}\n\nconst DEFAULT_WIDTHS = [320, 480, 640, 768, 1024, 1280, 1600, 1920];\nconst DEFAULT_SIZES =\n \"(min-width: 1024px) 25vw, (min-width: 640px) 50vw, 100vw\";\n\n/**\n * useImage — returns srcSet/sizes for a CDN-served image so themes\n * don't have to hand-roll responsive image markup. Pairs with the\n * <Image> component, but is also useful when the theme wants to render\n * something other than a plain `<img>` (e.g., `<picture>` with art\n * direction or a CSS `background-image` via inline style).\n *\n * Returns `null` srcSet if the source URL already encodes a width\n * directive (theme author opted out of auto-sizing).\n */\nexport function useImage(\n src: string | null | undefined,\n opts: UseImageOptions = {},\n): ImageDescriptor {\n const { sizes = DEFAULT_SIZES, widths = DEFAULT_WIDTHS, alt = \"\" } = opts;\n return useMemo(() => {\n if (!src) return { src: null, srcSet: null, sizes, alt };\n if (/[?&]w=\\d+/.test(src)) return { src, srcSet: null, sizes, alt };\n const sep = src.includes(\"?\") ? \"&\" : \"?\";\n const srcSet = widths.map((w) => `${src}${sep}w=${w} ${w}w`).join(\", \");\n return { src, srcSet, sizes, alt };\n }, [src, sizes, widths, alt]);\n}\n","\"use client\";\n\nimport { createContext } from \"react\";\n\n/**\n * The action surface a theme can call to drive customer auth +\n * profile mutations. Each action returns the parsed response body\n * (or throws on network failure); the *result* of the operation is\n * conveyed by the response shape, not the throw boundary.\n *\n * The provider implements these by calling /api/customer/* proxy\n * routes on the storefront, which in turn forward to FastAPI's\n * /storefront/store/{store_id}/auth/* and /storefront/me/* endpoints.\n *\n * Why a separate context (vs bundling onto CustomerContext): the\n * value `Customer | null` was already in CustomerContext for\n * back-compat with themes that read `useCustomer()`. Adding a\n * sibling context for actions keeps the existing read hook stable\n * while letting themes opt into actions via `useCustomerActions()`.\n */\nexport interface CustomerActions {\n /** Email + password → returns { success, data?, error? }. On\n * success the SDK refreshes the customer context automatically. */\n login: (input: {\n email: string;\n password: string;\n }) => Promise<unknown>;\n\n /** Create a new customer + log them in. Some stores require\n * email verification before login is fully usable; this flow\n * still issues the auth cookie so the customer can verify from\n * the welcome email and land logged-in. */\n register: (input: {\n email: string;\n password: string;\n first_name?: string;\n last_name?: string;\n phone?: string;\n accepts_marketing?: boolean;\n }) => Promise<unknown>;\n\n /** Clear the customer_access_token cookie + refresh the context\n * to null. Idempotent: safe to call when not logged in. */\n logout: () => Promise<unknown>;\n\n /** Issue a password-reset email. Anti-enumeration: response\n * never reveals whether the email exists. */\n requestRecover: (input: { email: string }) => Promise<unknown>;\n\n /** Submit the new password with the token from the recovery email. */\n confirmReset: (input: {\n token: string;\n password: string;\n }) => Promise<unknown>;\n\n /** Verify the email with the token from the welcome email. */\n verifyEmail: (input: { token: string }) => Promise<unknown>;\n\n /** Resend the verification email. Server-side rate-limited to\n * prevent email-bombing. */\n resendVerification: (input: { email: string }) => Promise<unknown>;\n\n /** Update the customer's profile (name / phone / marketing). */\n updateProfile: (input: {\n first_name?: string;\n last_name?: string;\n phone?: string;\n accepts_marketing?: boolean;\n }) => Promise<unknown>;\n\n /** Change the customer's password from inside the dashboard.\n * Backend requires the current password as confirmation. */\n changePassword: (input: {\n current_password: string;\n new_password: string;\n }) => Promise<unknown>;\n\n /** Re-fetch the customer profile from the backend and replace\n * the context value. Themes call this after performing any\n * out-of-band mutation that changed the customer's record. */\n refresh: () => Promise<void>;\n}\n\nconst NOOP_ACTIONS: CustomerActions = {\n login: async () => ({}),\n register: async () => ({}),\n logout: async () => ({}),\n requestRecover: async () => ({}),\n confirmReset: async () => ({}),\n verifyEmail: async () => ({}),\n resendVerification: async () => ({}),\n updateProfile: async () => ({}),\n changePassword: async () => ({}),\n refresh: async () => undefined,\n};\n\nexport const CustomerActionsContext =\n createContext<CustomerActions>(NOOP_ACTIONS);\n","\"use client\";\n\nimport { useContext } from \"react\";\nimport { CustomerActionsContext, type CustomerActions } from \"../contexts/customer-actions\";\n\n/**\n * Returns the customer-mutation actions provided by NuMuProvider.\n *\n * Pair with `useCustomer()` for read access:\n *\n * const customer = useCustomer();\n * const { login, logout, register } = useCustomerActions();\n *\n * The actions hit the storefront's `/api/customer/*` proxies, which\n * own the cookie/CSRF/idempotency story. Themes don't talk to the\n * backend directly — they get a stable client-side surface here.\n */\nexport function useCustomerActions(): CustomerActions {\n return useContext(CustomerActionsContext);\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { useCustomer } from \"./useCustomer\";\n\n/**\n * Customer order history.\n *\n * `useOrders()` returns the logged-in customer's orders, paginated.\n * The hook is gated on `useCustomer()` — when null (anonymous\n * visitor), it returns an empty list without hitting the network.\n *\n * `useOrder(id)` fetches a single order. Backend rejects with 404\n * when the id doesn't belong to the customer regardless of whether\n * it exists for someone else (avoids enumeration).\n */\n\nexport interface OrderListEntry {\n id: string;\n order_number: string;\n status: string;\n payment_status: string;\n fulfillment_status: string;\n total: number;\n currency: string;\n created_at: string | null;\n item_count?: number;\n}\n\nexport interface OrderListState {\n orders: OrderListEntry[];\n loading: boolean;\n error: Error | null;\n refresh: () => void;\n}\n\nexport interface OrderDetail extends OrderListEntry {\n line_items: unknown[];\n shipping_address?: Record<string, unknown> | null;\n billing_address?: Record<string, unknown> | null;\n subtotal: number;\n shipping_cost: number;\n tax_amount: number;\n discount_amount: number;\n}\n\nexport interface OrderState {\n order: OrderDetail | null;\n loading: boolean;\n error: Error | null;\n refresh: () => void;\n}\n\nfunction unwrap(json: unknown): unknown {\n if (json && typeof json === \"object\" && \"data\" in json) {\n return (json as { data: unknown }).data;\n }\n return json;\n}\n\nexport function useOrders(): OrderListState {\n const customer = useCustomer();\n const [orders, setOrders] = useState<OrderListEntry[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [tick, setTick] = useState(0);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n if (!customer) {\n // Anonymous: nothing to fetch. Reset state so a logged-out\n // visitor doesn't see stale data carried over from a prior session.\n setOrders([]);\n setError(null);\n setLoading(false);\n return;\n }\n let cancelled = false;\n setLoading(true);\n setError(null);\n void (async () => {\n try {\n const res = await fetch(\"/api/customer/me/orders\", {\n method: \"GET\",\n credentials: \"include\",\n cache: \"no-store\",\n });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const body = unwrap(await res.json());\n if (cancelled) return;\n // Backend returns either a list directly or a paginated wrapper\n // `{ items, total, page, ... }`. Normalize to a list.\n const list = Array.isArray(body)\n ? body\n : Array.isArray((body as Record<string, unknown>)?.items)\n ? ((body as { items: OrderListEntry[] }).items)\n : [];\n setOrders(list as OrderListEntry[]);\n } catch (err) {\n if (cancelled) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [customer, tick]);\n\n return {\n orders,\n loading,\n error,\n refresh: () => setTick((t) => t + 1),\n };\n}\n\nexport function useOrder(id: string | null | undefined): OrderState {\n const customer = useCustomer();\n const [order, setOrder] = useState<OrderDetail | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [tick, setTick] = useState(0);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n if (!id) {\n setOrder(null);\n setError(null);\n setLoading(false);\n return;\n }\n let cancelled = false;\n setLoading(true);\n setError(null);\n void (async () => {\n try {\n // Logged-in customer → full owned-order detail. Guest (the common\n // post-purchase order-confirmation case) → the PUBLIC order-tracking\n // endpoint, protected by the unguessable order UUID. Without this a\n // guest's confirmation page showed \"order not found\".\n const trackUrl = `/api/storefront/track/${encodeURIComponent(id)}`;\n let res = customer\n ? await fetch(`/api/customer/me/orders/${encodeURIComponent(id)}`, {\n method: \"GET\",\n credentials: \"include\",\n cache: \"no-store\",\n })\n : await fetch(trackUrl, { cache: \"no-store\" });\n // A logged-in user opening someone else's confirmation link (or an\n // order not yet linked to their account) 404s on /me/orders — fall\n // back to the public track view so the page still renders.\n if (!res.ok && customer) {\n res = await fetch(trackUrl, { cache: \"no-store\" });\n }\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const body = unwrap(await res.json());\n if (cancelled) return;\n setOrder(body as OrderDetail);\n } catch (err) {\n if (cancelled) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [customer, id, tick]);\n\n return {\n order,\n loading,\n error,\n refresh: () => setTick((t) => t + 1),\n };\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { useCustomer } from \"./useCustomer\";\n\n/**\n * Customer address book. Used by:\n * - The /account/addresses dashboard (list + CRUD).\n * - Checkout autofill (default address selected by default).\n *\n * Mutations return the updated row (or void on delete) and bump the\n * internal tick so the list reflects state changes immediately.\n * Anonymous visitors get an empty list with no network calls.\n */\n\nexport interface CustomerAddress {\n id: string;\n first_name?: string | null;\n last_name?: string | null;\n address_line1?: string | null;\n address_line2?: string | null;\n city?: string | null;\n state?: string | null;\n postal_code?: string | null;\n country?: string | null;\n phone?: string | null;\n label?: string | null;\n is_default?: boolean;\n // Optional geocoding fields — present when the merchant collects them.\n latitude?: number | null;\n longitude?: number | null;\n}\n\nexport type AddressInput = Omit<CustomerAddress, \"id\" | \"is_default\"> & {\n is_default?: boolean;\n};\n\nexport interface CustomerAddressesState {\n addresses: CustomerAddress[];\n loading: boolean;\n error: Error | null;\n refresh: () => void;\n addAddress: (input: AddressInput) => Promise<CustomerAddress | null>;\n updateAddress: (\n id: string,\n input: Partial<AddressInput>,\n ) => Promise<CustomerAddress | null>;\n deleteAddress: (id: string) => Promise<boolean>;\n setDefaultAddress: (id: string) => Promise<boolean>;\n}\n\nfunction unwrap(json: unknown): unknown {\n if (json && typeof json === \"object\" && \"data\" in json) {\n return (json as { data: unknown }).data;\n }\n return json;\n}\n\nasync function readBody(res: Response): Promise<unknown> {\n try {\n return unwrap(await res.json());\n } catch {\n return null;\n }\n}\n\nexport function useCustomerAddresses(): CustomerAddressesState {\n const customer = useCustomer();\n const [addresses, setAddresses] = useState<CustomerAddress[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [tick, setTick] = useState(0);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n if (!customer) {\n setAddresses([]);\n setLoading(false);\n setError(null);\n return;\n }\n let cancelled = false;\n setLoading(true);\n setError(null);\n void (async () => {\n try {\n const res = await fetch(\"/api/customer/me/addresses\", {\n method: \"GET\",\n credentials: \"include\",\n cache: \"no-store\",\n });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const body = await readBody(res);\n if (cancelled) return;\n const list = Array.isArray(body)\n ? body\n : Array.isArray((body as Record<string, unknown>)?.items)\n ? ((body as { items: CustomerAddress[] }).items)\n : [];\n setAddresses(list as CustomerAddress[]);\n } catch (err) {\n if (cancelled) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [customer, tick]);\n\n const refresh = useCallback(() => setTick((t) => t + 1), []);\n\n // CSRF: cart and customer mutations both echo the `numu_csrf` cookie\n // value as `x-numu-csrf` header. Read it from document.cookie just-\n // in-time so we always send the freshest value (the cookie may be\n // refreshed by /api/cart on first mount).\n function readCsrf(): string | null {\n if (typeof document === \"undefined\") return null;\n const m = document.cookie.match(/(?:^|; )numu_csrf=([^;]+)/);\n return m ? decodeURIComponent(m[1]) : null;\n }\n\n function mutationHeaders(): Record<string, string> {\n const h: Record<string, string> = { \"Content-Type\": \"application/json\" };\n const csrf = readCsrf();\n if (csrf) h[\"x-numu-csrf\"] = csrf;\n return h;\n }\n\n const addAddress = useCallback(\n async (input: AddressInput) => {\n const res = await fetch(\"/api/customer/me/addresses\", {\n method: \"POST\",\n credentials: \"include\",\n headers: mutationHeaders(),\n body: JSON.stringify(input),\n });\n if (!res.ok) return null;\n const created = (await readBody(res)) as CustomerAddress | null;\n refresh();\n return created;\n },\n [refresh],\n );\n\n const updateAddress = useCallback(\n async (id: string, input: Partial<AddressInput>) => {\n const res = await fetch(\n `/api/customer/me/addresses/${encodeURIComponent(id)}`,\n {\n method: \"PUT\",\n credentials: \"include\",\n headers: mutationHeaders(),\n body: JSON.stringify(input),\n },\n );\n if (!res.ok) return null;\n const updated = (await readBody(res)) as CustomerAddress | null;\n refresh();\n return updated;\n },\n [refresh],\n );\n\n const deleteAddress = useCallback(\n async (id: string) => {\n const res = await fetch(\n `/api/customer/me/addresses/${encodeURIComponent(id)}`,\n {\n method: \"DELETE\",\n credentials: \"include\",\n headers: mutationHeaders(),\n },\n );\n if (!res.ok) return false;\n refresh();\n return true;\n },\n [refresh],\n );\n\n const setDefaultAddress = useCallback(\n async (id: string) => {\n const res = await fetch(\n `/api/customer/me/addresses/${encodeURIComponent(id)}/default`,\n {\n method: \"PUT\",\n credentials: \"include\",\n headers: mutationHeaders(),\n },\n );\n if (!res.ok) return false;\n refresh();\n return true;\n },\n [refresh],\n );\n\n return {\n addresses,\n loading,\n error,\n refresh,\n addAddress,\n updateAddress,\n deleteAddress,\n setDefaultAddress,\n };\n}\n","\"use client\";\nimport { useContext, useEffect, useMemo, useState } from \"react\";\nimport {\n LocalizationContext,\n NavigationContext,\n type MenuItemData,\n} from \"../contexts\";\n\n/**\n * Menu item, modeled on Shopify's `linklists` entries.\n *\n * Themes typically render header/footer nav as a tree — we expose\n * `children` so a single fetch hydrates an arbitrary depth. Backends\n * that don't support nesting return a flat list (children=[]).\n */\nexport interface NavigationItem {\n id: string;\n title: string;\n /** The URL the menu item points to — relative path or absolute URL. */\n url: string;\n /** Optional foreign keys when the item references a typed resource. */\n resource_type?: \"product\" | \"collection\" | \"page\" | \"blog\" | \"article\" | \"url\" | null;\n resource_handle?: string | null;\n /**\n * §5 hide-page → hide-nav-link. `false` when the target CMS page is\n * unpublished/deleted (backend-annotated). Defaults to `true` (visible)\n * when the backend doesn't annotate, so themes can safely filter on\n * `item.target_visible !== false`.\n */\n target_visible: boolean;\n children: NavigationItem[];\n}\n\nexport interface NavigationState {\n /** Items in display order. Empty array when the menu is missing or still loading. */\n items: NavigationItem[];\n loading: boolean;\n /** Non-null when the fetch failed — the menu still resolves to []. */\n error: Error | null;\n}\n\nconst cache = new Map<string, NavigationItem[]>();\n\n/**\n * Resolve a bilingual label to a single display string for `locale`,\n * degrading gracefully: active locale → English → Arabic → first value.\n */\nfunction localizeLabel(\n label: Record<string, string> | undefined,\n locale: string,\n): string {\n if (!label) return \"\";\n return (\n label[locale] ||\n label.en ||\n label.ar ||\n Object.values(label).find((v) => !!v) ||\n \"\"\n );\n}\n\n/** Map the backend item `type` onto the SDK's `resource_type` union. */\nfunction mapResourceType(type?: string | null): NavigationItem[\"resource_type\"] {\n switch (type) {\n case \"product\":\n return \"product\";\n case \"collection\":\n return \"collection\";\n case \"page\":\n return \"page\";\n case \"blog\":\n return \"blog\";\n case \"article\":\n return \"article\";\n case \"http\":\n case \"url\":\n return \"url\";\n default:\n return null;\n }\n}\n\n/** Localize a raw (bilingual) menu item tree into display NavigationItems. */\nfunction toNavigationItem(raw: MenuItemData, locale: string): NavigationItem {\n return {\n id: raw.id,\n title: localizeLabel(raw.label, locale),\n url: raw.url || \"/\",\n resource_type: mapResourceType(raw.type),\n resource_handle: raw.resource_id ?? null,\n target_visible: raw.target_visible !== false,\n children: (raw.children ?? [])\n .map((child) => toNavigationItem(child, locale))\n .filter((child) => child.target_visible),\n };\n}\n\n/**\n * Fetch a merchant-managed nav menu by handle.\n *\n * Resolution order (Phase 2.4):\n * 1. Host-injected menus — the storefront resolves menus server-side\n * (`GET /storefront/store/{id}/menus`) and injects them via\n * `NuMuProvider`'s `navigation` prop → `NavigationContext`. When the\n * handle is present we localize + return it synchronously, no fetch.\n * A non-empty map that lacks the handle means \"no such menu\" → [].\n * 2. `options.initialItems` — a theme that pre-fetched its own list.\n * 3. Client fetch of `GET /api/storefront/navigation/{handle}` — the\n * legacy fallback for hosts that inject nothing. On 404 / network\n * error the hook resolves to [] (a missing menu is a soft failure;\n * the theme falls back to its own DEFAULT_NAV).\n */\nexport function useNavigation(\n handle: string,\n options?: { initialItems?: NavigationItem[] },\n): NavigationState {\n // NavigationContext defaults to {} outside a provider; LocalizationContext\n // is read defensively (no throw) so useNavigation works even if a theme\n // calls it above NuMuProvider in a test harness.\n const navMap = useContext(NavigationContext);\n const localization = useContext(LocalizationContext);\n const locale = localization?.locale ?? \"en\";\n\n const hostProvidedAny = !!navMap && Object.keys(navMap).length > 0;\n const rawItems = handle ? navMap?.[handle] : undefined;\n\n // Localized view of host-injected items. `null` means \"host wired no\n // navigation at all\" → fall through to initialItems / fetch. `[]` means\n // the host IS authoritative but this handle is absent/empty → render\n // nothing (no doomed fetch).\n const hostItems = useMemo<NavigationItem[] | null>(() => {\n if (rawItems)\n return rawItems\n .map((it) => toNavigationItem(it, locale))\n // §5 hide-page → hide-nav-link: drop items whose target CMS page is\n // unpublished/deleted (backend-annotated). Children already filtered\n // in toNavigationItem; this drops hidden top-level entries so every\n // theme using useNavigation gets the behaviour for free.\n .filter((it) => it.target_visible);\n if (hostProvidedAny) return [];\n return null;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [rawItems, hostProvidedAny, locale]);\n\n const [items, setItems] = useState<NavigationItem[]>(\n hostItems ?? options?.initialItems ?? cache.get(handle) ?? [],\n );\n const [loading, setLoading] = useState(\n hostItems === null && !options?.initialItems && !cache.has(handle),\n );\n const [error, setError] = useState<Error | null>(null);\n\n // Keep items in sync with host-injected menus (locale switch, or the\n // map arriving after first paint). When the host is authoritative we\n // never fetch.\n useEffect(() => {\n if (hostItems === null) return;\n setItems(hostItems);\n setLoading(false);\n setError(null);\n }, [hostItems]);\n\n useEffect(() => {\n // Host-injected menus win — skip the network entirely.\n if (hostItems !== null) return;\n if (typeof window === \"undefined\") return;\n if (!handle) {\n setItems([]);\n setLoading(false);\n return;\n }\n if (cache.has(handle) && !options?.initialItems) {\n setItems(cache.get(handle) || []);\n setLoading(false);\n return;\n }\n let cancelled = false;\n setLoading(true);\n setError(null);\n void (async () => {\n try {\n const res = await fetch(\n `/api/storefront/navigation/${encodeURIComponent(handle)}`,\n { cache: \"no-store\" },\n );\n if (!res.ok) {\n // 404 = no such menu; render nothing instead of an error UI.\n if (cancelled) return;\n cache.set(handle, []);\n setItems([]);\n return;\n }\n const json = (await res.json()) as\n | { items?: NavigationItem[] }\n | NavigationItem[];\n const list: NavigationItem[] = Array.isArray(json)\n ? json\n : json.items || [];\n if (cancelled) return;\n cache.set(handle, list);\n setItems(list);\n } catch (err) {\n if (cancelled) return;\n // Non-OK / network failure → empty list + surface error so\n // themes can decide whether to log or show a fallback.\n setError(err instanceof Error ? err : new Error(String(err)));\n setItems([]);\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n return () => {\n cancelled = true;\n };\n // Deliberate: re-run when `handle` or host-injection state changes;\n // `initialItems` change shouldn't refetch (theme passes it once).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [handle, hostItems === null]);\n\n return { items, loading, error };\n}\n","\"use client\";\nimport { useEffect, useRef, useState } from \"react\";\nimport type { Product, Collection, Page } from \"../types/entities\";\n\n/**\n * Mixed-result search shape. The backend tsvector implementation lands in\n * Phase 4; until then this hook talks to /api/storefront/search and\n * gracefully degrades (empty results) when the endpoint isn't available.\n *\n * Two modes:\n * - \"predictive\" (default): debounced, capped at 5 per type, returns\n * fast for autocomplete dropdowns.\n * - \"full\": full result set with paging, used by /search pages.\n */\n\nexport interface SearchResults {\n products: Product[];\n collections: Collection[];\n pages: Page[];\n /** Articles will populate once the blog backend lands; field shape is\n * reserved here so themes can write code that doesn't break on\n * upgrade. */\n articles: Array<{ id: string; title: string; handle: string; excerpt?: string }>;\n total: number;\n}\n\nexport interface UseSearchOptions {\n /** \"predictive\" debounces and caps; \"full\" returns paged results. */\n mode?: \"predictive\" | \"full\";\n /** Restrict to specific result types. Default: all. */\n types?: Array<\"products\" | \"collections\" | \"pages\" | \"articles\">;\n /** Per-type cap. Predictive mode defaults to 5; full mode defaults to 24. */\n limit?: number;\n /** Debounce window in ms for predictive mode. Default 200. */\n debounceMs?: number;\n /** Skip the debounce (e.g. when the user submits the form). */\n immediate?: boolean;\n}\n\nexport interface SearchState {\n query: string;\n results: SearchResults;\n loading: boolean;\n error: Error | null;\n}\n\nconst EMPTY: SearchResults = {\n products: [],\n collections: [],\n pages: [],\n articles: [],\n total: 0,\n};\n\nexport function useSearch(\n query: string,\n options: UseSearchOptions = {},\n): SearchState {\n const {\n mode = \"predictive\",\n types,\n limit,\n debounceMs = 200,\n immediate = false,\n } = options;\n\n const [results, setResults] = useState<SearchResults>(EMPTY);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const lastRequestId = useRef(0);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const trimmed = query.trim();\n if (!trimmed) {\n setResults(EMPTY);\n setLoading(false);\n setError(null);\n return;\n }\n\n const requestId = ++lastRequestId.current;\n setLoading(true);\n setError(null);\n\n const run = async () => {\n try {\n const params = new URLSearchParams({ q: trimmed, mode });\n if (types?.length) params.set(\"types\", types.join(\",\"));\n if (limit) params.set(\"limit\", String(limit));\n const res = await fetch(`/api/storefront/search?${params}`, {\n cache: \"no-store\",\n });\n if (requestId !== lastRequestId.current) return; // superseded\n if (!res.ok) {\n // Backend search not yet wired (Phase 4). Empty result is\n // an acceptable degraded mode — themes show \"no results\"\n // instead of an error banner.\n setResults(EMPTY);\n return;\n }\n const json = (await res.json()) as Partial<SearchResults> & {\n data?: Partial<SearchResults>;\n };\n const body = json.data || json;\n if (requestId !== lastRequestId.current) return;\n setResults({\n products: body.products || [],\n collections: body.collections || [],\n pages: body.pages || [],\n articles: body.articles || [],\n total: body.total || 0,\n });\n } catch (err) {\n if (requestId !== lastRequestId.current) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n setResults(EMPTY);\n } finally {\n if (requestId === lastRequestId.current) setLoading(false);\n }\n };\n\n if (immediate || mode === \"full\") {\n void run();\n return;\n }\n const t = setTimeout(run, debounceMs);\n return () => clearTimeout(t);\n }, [query, mode, debounceMs, immediate, limit, types?.join(\",\")]); // eslint-disable-line react-hooks/exhaustive-deps\n\n return { query, results, loading, error };\n}\n","\"use client\";\nimport { useCallback, useMemo } from \"react\";\n\n/**\n * Theme-facing analytics dispatcher.\n *\n * Two delivery channels, fired in parallel:\n * 1. Server-side track: POST /api/storefront/track with the event\n * payload. The host storefront proxies to FastAPI's funnel-event\n * endpoint (/storefront/store/{id}/track) and fans out to\n * merchant-configured pixels (GA4 Measurement Protocol, Meta CAPI,\n * TikTok Events API). Failed pixels never block the UI — we\n * don't await the response.\n * 2. Window CustomEvent (`numu:analytics:event`): so theme devs can\n * wire their own GTM container, third-party SDK, or in-house\n * pixel without going through the server. Detail shape mirrors\n * what gets POSTed.\n *\n * Standard event names (recommended for compatibility with GA4 / Meta):\n * page_view, view_item, view_collection, search, add_to_cart,\n * remove_from_cart, view_cart, begin_checkout, add_payment_info,\n * add_shipping_info, purchase, refund, sign_up, login,\n * add_to_wishlist, share. Custom names are also fine — the dispatcher\n * does not validate, so themes can ship store-specific events.\n *\n * Funnel-event mapping\n * --------------------\n * Standard event names that map to the backend's funnel steps are\n * dispatched with the full funnel-event payload shape (path,\n * session_fingerprint, attribution envelope from\n * window.__numu_attribution). This is what powers the merchant\n * funnel / journey / multi-touch attribution dashboards. Events with\n * no funnel mapping still POST with the loose `{event, payload}`\n * shape — the proxy forwards them so the pixel-fanout layer still\n * fires.\n */\n\nexport interface AnalyticsPayload {\n /** Standard or custom event name. Lowercase + underscores recommended. */\n [key: string]: unknown;\n}\n\nexport interface AnalyticsApi {\n /**\n * Fire an event. Non-blocking — both the fetch and the CustomEvent\n * dispatch happen in the next microtask; theme code shouldn't await.\n */\n track: (eventName: string, payload?: AnalyticsPayload) => void;\n}\n\n/**\n * Standard event name → backend funnel step mapping.\n *\n * Only events listed here drive the funnel / attribution dashboards.\n * Everything else still POSTs (for pixel fanout) but doesn't land in\n * the funnel_events table. The mapping mirrors what the bazaar\n * storefront's trackingService uses on the SaaS side.\n */\nconst EVENT_TO_FUNNEL_STEP: Record<string, string> = {\n page_view: \"page_view\",\n view_item: \"product_view\",\n view_collection: \"page_view\",\n add_to_cart: \"add_to_cart\",\n begin_checkout: \"checkout_started\",\n purchase: \"order_completed\",\n // Wave 2+ standard Meta events — backend's FUNNEL_STEP_TO_META_EVENT\n // table accepts these as funnel steps directly.\n search: \"search\",\n lead: \"lead\",\n sign_up: \"complete_registration\",\n add_to_wishlist: \"add_to_wishlist\",\n add_payment_info: \"add_payment_info\",\n};\n\ninterface AttributionEnvelope {\n v?: number;\n first_touch?: unknown;\n last_touch?: unknown;\n session_id?: string | null;\n}\n\ninterface NumuAttributionBridge {\n get(): AttributionEnvelope | null;\n}\n\ninterface NumuCustomerBridge {\n /** Authenticated customer's UUID, or null when the visitor is a guest. */\n getId(): string | null;\n}\n\ndeclare global {\n interface Window {\n __numu_attribution?: NumuAttributionBridge;\n /**\n * Optional bridge installed by the host storefront's customer\n * provider. When set, the SDK includes ``customer_id`` on\n * funnel-step events so the backend can record touches against\n * the authenticated customer immediately instead of waiting for\n * the next checkout to backfill.\n */\n __numu_customer?: NumuCustomerBridge;\n }\n}\n\nfunction readAttribution(): AttributionEnvelope | null {\n if (typeof window === \"undefined\") return null;\n try {\n return window.__numu_attribution?.get?.() ?? null;\n } catch {\n return null;\n }\n}\n\nfunction readCustomerId(): string | null {\n if (typeof window === \"undefined\") return null;\n try {\n return window.__numu_customer?.getId?.() ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * Session fingerprint for funnel-event dedup.\n *\n * The attribution envelope's session_id (ULID, stable for cookie\n * lifetime) is the natural fingerprint — same cookie lifetime as the\n * attribution window, so funnel + journey + multi-touch all agree on\n * what \"one session\" means.\n *\n * Fallback: a per-tab random string when no envelope exists yet (first\n * visit before AttributionProvider's effect has run). Persisted on the\n * window so subsequent calls in the same tab reuse it — otherwise\n * each event would generate its own fingerprint and the funnel\n * dashboard would over-count distinct sessions.\n */\nfunction getFingerprint(): string {\n if (typeof window === \"undefined\") return \"ssr\";\n const env = readAttribution();\n if (env?.session_id) return env.session_id;\n\n const w = window as unknown as { __numu_session_fp?: string };\n if (w.__numu_session_fp) return w.__numu_session_fp;\n // crypto.randomUUID is universally available in our supported\n // browsers (no IE / pre-2022 mobile Safari). Skip the fallback.\n const fp = crypto.randomUUID();\n w.__numu_session_fp = fp;\n return fp;\n}\n\n/**\n * Free function body of the hook's `track`.\n *\n * Extracted so unit tests can call it directly without spinning up a\n * React renderer for what is essentially a side-effect dispatcher.\n * The exported `useAnalytics` hook is a thin memoization wrapper.\n */\nexport function dispatchAnalyticsEvent(\n eventName: string,\n payload: AnalyticsPayload = {},\n): void {\n if (typeof window === \"undefined\") return;\n\n // ONE event id for BOTH channels. The host's <MetaPixel>/<TikTokPixel>\n // bridges fire the browser pixel with `detail.event_id`, and the /track\n // POST below carries the same id — that's what lets Meta/TikTok dedupe\n // the browser event against the server-side CAPI/Events-API fire.\n // (Previously the CustomEvent had NO id while the POST minted its own,\n // so any theme calling track() double-counted on both platforms.)\n const eventId = crypto.randomUUID();\n\n // 1. Window CustomEvent — synchronous, cheap. Themes that wire\n // their own pixels listen here; the host pixel bridges too.\n try {\n window.dispatchEvent(\n new CustomEvent(\"numu:analytics:event\", {\n detail: { event: eventName, payload, event_id: eventId, ts: Date.now() },\n }),\n );\n } catch {\n /* CustomEvent unsupported — no DOM event polyfill needed today. */\n }\n\n // 2. Server-side fanout. Funnel-step events get the strict payload\n // shape the backend's funnel_events table expects (path,\n // fingerprint, step, step_data, attribution). Non-funnel events\n // keep the loose shape for the pixel-fanout layer.\n const step = EVENT_TO_FUNNEL_STEP[eventName] ?? null;\n // Lifting customer_id once so we don't read the bridge twice per\n // dispatch. Absent (null) for guests / unauthenticated visitors;\n // present for logged-in customers whose journey rows should land\n // with customer_id set immediately instead of waiting for the\n // next checkout to backfill.\n const customerId = readCustomerId();\n const body: Record<string, unknown> = step\n ? {\n event_id: eventId,\n path: window.location.pathname,\n fingerprint: getFingerprint(),\n step,\n step_data: payload,\n referrer:\n typeof document !== \"undefined\" && document.referrer\n ? document.referrer\n : undefined,\n attribution: readAttribution() ?? undefined,\n customer_id: customerId ?? undefined,\n }\n : {\n event: eventName,\n payload,\n event_id: eventId,\n ts: Date.now(),\n attribution: readAttribution() ?? undefined,\n customer_id: customerId ?? undefined,\n };\n\n void (async () => {\n try {\n await fetch(\"/api/storefront/track\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n keepalive: true, // survive page-unload (e.g. begin_checkout → redirect)\n });\n } catch {\n /* swallowed by design */\n }\n })();\n}\n\nexport function useAnalytics(): AnalyticsApi {\n const track = useCallback(\n (eventName: string, payload: AnalyticsPayload = {}) => {\n dispatchAnalyticsEvent(eventName, payload);\n },\n [],\n );\n\n return useMemo(() => ({ track }), [track]);\n}\n","\"use client\";\nimport { useCallback, useEffect, useRef, useSyncExternalStore } from \"react\";\n\n/**\n * Shared client-data layer (Phase 3) — a tiny SWR-style cache with ZERO\n * runtime dependencies.\n *\n * Why this exists (from the audit): several hooks fetched + held per-instance\n * state, so N components rendering the same resource fired N identical requests\n * AND drifted out of sync (e.g. two wishlist hearts for one product; `useApp`\n * applying an out-of-order response over a newer one). `useCachedResource`\n * centralizes fetching behind one module-level store keyed by a string:\n *\n * (a) DEDUP — the first consumer of a key starts the fetch and stashes the\n * in-flight promise on the entry; every other consumer that revalidates\n * the same key while it's pending joins that promise instead of firing a\n * second request. N consumers → ONE network call.\n * (b) CACHE — results live on the entry keyed by string, so a later mount\n * reads the cached value immediately (and skips refetch within\n * `dedupeIntervalMs`).\n * (c) SUBSCRIBE / NOTIFY — every hook instance subscribes to its key via\n * `useSyncExternalStore`. Any update (fetch resolve, `mutate`) rebuilds\n * the entry's immutable snapshot and notifies ALL subscribers, so every\n * instance re-renders with the same value — cross-instance state sync.\n * (d) REVALIDATE + CANCELLATION — each fetch reserves a monotonic sequence\n * number and an `AbortController`. Starting a new (forced) fetch aborts\n * the previous one; when any fetch settles, its result is applied ONLY if\n * its sequence is still the latest (`mySeq === entry.seq`). So a slow,\n * superseded response can never overwrite a newer result regardless of\n * the order the network resolves them in.\n *\n * SSR-safe: the fetch is triggered from `useEffect` (never runs under\n * `renderToString`), and `useSyncExternalStore`'s server snapshot returns the\n * `initialData` fallback without ever touching the module cache — so nothing is\n * written to the shared map on the server and there is no cross-request bleed.\n *\n * This is intentionally NOT a full SWR clone (no focus/reconnect revalidation,\n * no suspense, no infinite pagination). It's the smallest primitive that fixes\n * the audited dedup + sync + ordering bugs and that themes can reuse.\n */\n\n/** The reactive slice a consumer reads. */\nexport interface CachedResourceState<T> {\n /** Latest cached value, or `initialData` before the first fetch settles. */\n data: T | undefined;\n /** Error from the most recent settled fetch (cleared on success / mutate). */\n error: Error | undefined;\n /** True until the first fetch (or `mutate`) settles a value for this key. */\n isLoading: boolean;\n /** True whenever a fetch is currently in flight (initial OR background). */\n isValidating: boolean;\n}\n\n/** Fetcher receives an AbortSignal so a superseding fetch can cancel it. */\nexport type CacheFetcher<T> = (signal: AbortSignal) => Promise<T>;\n\n/** `mutate` accepts a value or an updater `(current) => next`. */\nexport type CacheMutator<T> =\n | T\n | undefined\n | ((current: T | undefined) => T | undefined);\n\nexport interface MutateOptions {\n /** After applying the local value, kick a fresh (forced) revalidation. */\n revalidate?: boolean;\n}\n\nexport interface CachedResource<T> extends CachedResourceState<T> {\n /**\n * Optimistically write the cached value for this key (all subscribers\n * re-render). Pass `{ revalidate: true }` to also refetch afterwards.\n */\n mutate: (next: CacheMutator<T>, opts?: MutateOptions) => void;\n /** Force a fresh fetch, superseding + aborting any in-flight request. */\n revalidate: () => Promise<void>;\n}\n\nexport interface UseCachedResourceOptions<T> {\n /**\n * Value shown on the server and on the first client paint before the fetch\n * resolves. Used as the SSR snapshot (SSR-safe: no fetch on the server).\n */\n initialData?: T;\n /** When `false`, the hook holds no subscription and never fetches. */\n enabled?: boolean;\n /** Auto-fetch on mount / key change (default `true`). */\n revalidateOnMount?: boolean;\n /**\n * Skip the mount fetch if a value settled within this window (ms). Prevents\n * a staggered second mount from refetching a still-fresh key. Default 2000.\n */\n dedupeIntervalMs?: number;\n /** Called on a non-abort fetch error, with the key. */\n onError?: (error: Error, key: string) => void;\n}\n\ninterface Entry<T> {\n data: T | undefined;\n error: Error | undefined;\n /** Has a fetch or mutate produced a value yet? Drives `isLoading`. */\n settled: boolean;\n /** Is a fetch currently running? Drives `isValidating`. */\n inFlight: boolean;\n /** Monotonic request counter; only `mySeq === seq` may apply a result. */\n seq: number;\n lastFetchAt: number;\n /** In-flight fetch promise, for cross-instance dedup. */\n promise: Promise<void> | undefined;\n controller: AbortController | undefined;\n /** Latest fetcher seen for this key, so `mutate({revalidate})` can refetch. */\n fetcher: CacheFetcher<T> | undefined;\n subscribers: Set<() => void>;\n /** Cached immutable snapshot — stable ref until state actually changes. */\n snapshot: CachedResourceState<T>;\n}\n\n// Module-level store. Only ever written on the client (see SSR note above).\nconst cache = new Map<string, Entry<unknown>>();\n\nfunction buildSnapshot<T>(entry: Entry<T>): CachedResourceState<T> {\n return {\n data: entry.data,\n error: entry.error,\n isLoading: !entry.settled,\n isValidating: entry.inFlight,\n };\n}\n\n/** Rebuild the entry's snapshot and notify every subscriber. */\nfunction commit<T>(entry: Entry<T>): void {\n entry.snapshot = buildSnapshot(entry);\n entry.subscribers.forEach((cb) => cb());\n}\n\nfunction getEntry<T>(key: string, initialData?: T): Entry<T> {\n let entry = cache.get(key) as Entry<T> | undefined;\n if (!entry) {\n entry = {\n data: initialData,\n error: undefined,\n settled: false,\n inFlight: false,\n seq: 0,\n lastFetchAt: 0,\n promise: undefined,\n controller: undefined,\n fetcher: undefined,\n subscribers: new Set(),\n snapshot: {\n data: initialData,\n error: undefined,\n isLoading: true,\n isValidating: false,\n },\n };\n cache.set(key, entry as unknown as Entry<unknown>);\n }\n return entry;\n}\n\n/**\n * Fetch (or join an in-flight fetch for) `key`.\n *\n * Dedup: a non-forced call with a pending promise returns that promise instead\n * of starting a second request. Ordering: each fetch takes `mySeq = ++seq` and\n * a fresh AbortController; a forced call aborts the previous controller. A\n * result is applied only when `mySeq === entry.seq` at settle time, so a\n * superseded (out-of-order) response is dropped.\n */\nexport function revalidateResource<T>(\n key: string,\n fetcher: CacheFetcher<T>,\n opts?: { force?: boolean; onError?: (error: Error, key: string) => void },\n): Promise<void> {\n const entry = getEntry<T>(key);\n entry.fetcher = fetcher;\n\n // Dedup: join the request already in flight for this key.\n if (!opts?.force && entry.promise) return entry.promise;\n\n const mySeq = ++entry.seq;\n if (entry.controller) entry.controller.abort();\n const controller = new AbortController();\n entry.controller = controller;\n entry.inFlight = true;\n commit(entry);\n\n const run = (async () => {\n try {\n const data = await fetcher(controller.signal);\n if (mySeq !== entry.seq) return; // superseded by a newer request\n entry.data = data;\n entry.error = undefined;\n entry.settled = true;\n entry.lastFetchAt = Date.now();\n } catch (err) {\n if (controller.signal.aborted) return; // cancelled by a newer request\n if (mySeq !== entry.seq) return; // superseded by a newer request\n const error = err instanceof Error ? err : new Error(String(err));\n entry.error = error;\n entry.settled = true;\n entry.lastFetchAt = Date.now();\n opts?.onError?.(error, key);\n } finally {\n // Only the winning (latest) request flips inFlight off + commits, so a\n // superseded fetch resolving late can't clobber the newer one's state.\n if (mySeq === entry.seq) {\n entry.inFlight = false;\n entry.controller = undefined;\n commit(entry);\n }\n }\n })();\n\n entry.promise = run;\n void run.finally(() => {\n // Clear only if still ours — a forced fetch may have replaced the promise.\n if (entry.promise === run) entry.promise = undefined;\n });\n return run;\n}\n\n/** Imperatively write a key's cached value and notify all subscribers. */\nexport function mutateResource<T>(\n key: string,\n next: CacheMutator<T>,\n opts?: MutateOptions,\n): void {\n const entry = getEntry<T>(key);\n const value =\n typeof next === \"function\"\n ? (next as (current: T | undefined) => T | undefined)(entry.data)\n : next;\n entry.data = value;\n entry.error = undefined;\n entry.settled = true;\n commit(entry);\n if (opts?.revalidate && entry.fetcher) {\n void revalidateResource(key, entry.fetcher, { force: true });\n }\n}\n\n/** Peek the current cached value for a key without subscribing. */\nexport function readResource<T>(key: string): T | undefined {\n return (cache.get(key) as Entry<T> | undefined)?.data;\n}\n\n/** Drop one key (or the whole cache when called with no argument). */\nexport function clearResource(key?: string): void {\n if (key === undefined) {\n cache.clear();\n return;\n }\n cache.delete(key);\n}\n\nconst NOOP = () => {};\n\n/**\n * Subscribe to a cached resource keyed by `key`, deduping the fetch across all\n * instances and keeping them in sync. See the module docblock for the full\n * contract.\n *\n * @param key Cache key. `null`/`undefined`/`\"\"` (or `enabled: false`)\n * disables the hook — no subscription, no fetch, `initialData`\n * is returned.\n * @param fetcher `(signal) => Promise<T>`. Recreated-per-render is fine; the\n * latest is captured in a ref so it doesn't retrigger fetches.\n * @param options See {@link UseCachedResourceOptions}.\n */\nexport function useCachedResource<T>(\n key: string | null | undefined,\n fetcher: CacheFetcher<T>,\n options?: UseCachedResourceOptions<T>,\n): CachedResource<T> {\n const enabled = options?.enabled !== false && key != null && key !== \"\";\n const revalidateOnMount = options?.revalidateOnMount !== false;\n const dedupeIntervalMs = options?.dedupeIntervalMs ?? 2000;\n const cacheKey = enabled ? (key as string) : \"\";\n\n // Keep latest fetcher / callbacks / initialData in refs so the fetch effect\n // can depend on `key` alone — an inline fetcher recreated every render must\n // not retrigger the request.\n const fetcherRef = useRef(fetcher);\n fetcherRef.current = fetcher;\n const onErrorRef = useRef(options?.onError);\n onErrorRef.current = options?.onError;\n const initialDataRef = useRef(options?.initialData);\n\n // Stable fallback snapshot for the disabled + SSR paths.\n // `useSyncExternalStore` requires getSnapshot to return a cached reference,\n // so we freeze one object (initialData is first-render-wins, like SWR's\n // fallbackData). isLoading mirrors \"will this hook fetch on mount?\" so the\n // server markup matches the client's first (pre-effect) snapshot.\n const fallbackRef = useRef<CachedResourceState<T> | null>(null);\n if (fallbackRef.current === null) {\n fallbackRef.current = {\n data: initialDataRef.current,\n error: undefined,\n isLoading: enabled && revalidateOnMount,\n isValidating: false,\n };\n }\n\n const subscribe = useCallback(\n (cb: () => void) => {\n if (!enabled) return NOOP;\n const entry = getEntry<T>(cacheKey, initialDataRef.current);\n entry.subscribers.add(cb);\n return () => {\n entry.subscribers.delete(cb);\n };\n },\n [cacheKey, enabled],\n );\n\n const getSnapshot = useCallback((): CachedResourceState<T> => {\n if (!enabled) return fallbackRef.current as CachedResourceState<T>;\n return getEntry<T>(cacheKey, initialDataRef.current).snapshot;\n }, [cacheKey, enabled]);\n\n const getServerSnapshot = useCallback(\n (): CachedResourceState<T> => fallbackRef.current as CachedResourceState<T>,\n [],\n );\n\n const state = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n\n // Fetch trigger. Runs on mount + key change (client only — effects never run\n // under renderToString, keeping SSR fetch-free). No abort-on-unmount: the\n // in-flight request is shared across instances via dedup, so one unmounting\n // consumer must not cancel a fetch the others still await. Cancellation of a\n // SUPERSEDED request is handled inside revalidateResource (seq + abort).\n useEffect(() => {\n if (!enabled) return;\n const entry = getEntry<T>(cacheKey, initialDataRef.current);\n const fresh =\n entry.settled && Date.now() - entry.lastFetchAt < dedupeIntervalMs;\n if (revalidateOnMount && !fresh) {\n void revalidateResource<T>(\n cacheKey,\n (signal) => fetcherRef.current(signal),\n { onError: (e, k) => onErrorRef.current?.(e, k) },\n );\n }\n }, [cacheKey, enabled, revalidateOnMount, dedupeIntervalMs]);\n\n const mutate = useCallback(\n (next: CacheMutator<T>, opts?: MutateOptions) => {\n if (!enabled) return;\n mutateResource<T>(cacheKey, next, opts);\n },\n [cacheKey, enabled],\n );\n\n const revalidate = useCallback((): Promise<void> => {\n if (!enabled) return Promise.resolve();\n return revalidateResource<T>(\n cacheKey,\n (signal) => fetcherRef.current(signal),\n { force: true, onError: (e, k) => onErrorRef.current?.(e, k) },\n );\n }, [cacheKey, enabled]);\n\n return {\n data: state.data,\n error: state.error,\n isLoading: state.isLoading,\n isValidating: state.isValidating,\n mutate,\n revalidate,\n };\n}\n","\"use client\";\nimport { useCallback } from \"react\";\nimport { useShop } from \"./useShop\";\nimport { useCachedResource } from \"../lib/dataCache\";\n\n/**\n * Read app-provided data + manifest for a slug installed on the\n * current store.\n *\n * Phase 6 wired this to the real backend at\n * `/api/storefront/store/{store_id}/apps/{slug}`. Theme usage:\n *\n * const recommend = useApp<RecommendationData>(\"recommendation-engine\");\n * if (!recommend.available) return <Fallback />;\n * if (recommend.loading) return <Skeleton />;\n * return <RecommendList items={recommend.data?.products ?? []} />;\n *\n * `available` flips to true only when an enabled installation exists\n * for the store. Apps the merchant hasn't installed surface as\n * `{ available: false }` rather than as a network error — themes\n * branch on availability without try/catch.\n *\n * Phase 3 (client-data layer): the fetch now runs through the shared\n * `useCachedResource` store keyed by `numu:app:<store_id>:<slug>`. Two upgrades\n * over the old per-instance `useState` + fetch:\n * - DEDUP + SYNC: N consumers of the same app slug share ONE request and one\n * result, instead of each firing its own `/apps/{slug}` fetch.\n * - CANCELLATION / ORDERING: the fetcher receives an AbortSignal and the\n * cache seq-guards results, so a slow response for a superseded slug (or a\n * superseded `refresh()`) can no longer apply stale state over a newer one\n * — the audited \"out-of-order responses apply stale state\" bug.\n *\n * `loading` reflects the FIRST load only; a `refresh()` revalidates in the\n * background (`isValidating`) while keeping the last-good data visible, rather\n * than blanking to a skeleton on every manual refresh.\n */\n\nexport interface AppManifestBlock {\n type: string;\n name: string;\n block_schema: Record<string, unknown>;\n}\n\nexport interface AppPayload<T = unknown> {\n slug: string;\n name: string;\n description: string | null;\n icon_url: string | null;\n version: string;\n manifest: Record<string, unknown>;\n settings: Record<string, unknown>;\n blocks: AppManifestBlock[];\n /** App-provided data (shape defined by the app developer). Today\n * the response always returns null for `data` — apps emit data via\n * their `endpoints.data` URL, which the theme fetches separately.\n * Surfaced here so the field is stable when v2 lands the proxy. */\n data: T | null;\n}\n\nexport interface AppState<T = unknown> {\n data: AppPayload<T> | null;\n loading: boolean;\n available: boolean;\n error: Error | null;\n /** Re-fetch the install. Returns a promise that resolves when the\n * request settles (regardless of success). */\n refresh: () => Promise<void>;\n}\n\n/** Normalized fetch result cached per key. `available:false` covers both the\n * \"not installed\" (404) and \"no payload\" cases so themes branch on one flag. */\ninterface AppFetchResult<T> {\n payload: AppPayload<T> | null;\n available: boolean;\n}\n\nexport function useApp<T = unknown>(slug: string): AppState<T> {\n const shop = useShop();\n // Key on store + slug so a different slug is a different cache entry — a\n // rapid slug switch reads its own entry rather than racing one shared slot.\n const key = slug ? `numu:app:${shop.id}:${slug}` : \"\";\n\n const fetcher = useCallback(\n async (signal: AbortSignal): Promise<AppFetchResult<T>> => {\n const url = `/api/storefront/apps/${encodeURIComponent(slug)}`;\n const res = await fetch(url, {\n credentials: \"include\",\n headers: { Accept: \"application/json\" },\n signal,\n });\n if (res.status === 404) {\n // Not installed (or app disabled). Standard not-available shape —\n // keeps theme branching simple (no thrown error).\n return { payload: null, available: false };\n }\n if (!res.ok) {\n throw new Error(`useApp(${slug}) failed: HTTP ${res.status}`);\n }\n const body = (await res.json()) as {\n data?: (AppPayload<T> & { available?: boolean }) | null;\n };\n const payload = body.data ?? null;\n if (!payload) return { payload: null, available: false };\n return {\n payload: payload as AppPayload<T>,\n available: payload.available !== false,\n };\n },\n [slug],\n );\n\n const { data, isLoading, error, revalidate } = useCachedResource<\n AppFetchResult<T>\n >(key, fetcher, {\n enabled: Boolean(slug),\n initialData: { payload: null, available: false },\n });\n\n const refresh = useCallback(async (): Promise<void> => {\n await revalidate();\n }, [revalidate]);\n\n // Preserve the original contract: on error, present as not-available with a\n // null payload (the error is still surfaced separately).\n return {\n data: error ? null : data?.payload ?? null,\n loading: isLoading,\n available: error ? false : data?.available ?? false,\n error: error ?? null,\n refresh,\n };\n}\n","\"use client\";\nimport { useCallback } from \"react\";\nimport { useCachedResource, readResource } from \"../lib/dataCache\";\n\n/**\n * Wishlist hook with localStorage fallback.\n *\n * Architecture (Phase 4 lands the server side):\n * - Authenticated customer: persists to /api/customer/me/wishlist\n * (server-backed, syncs across devices).\n * - Anonymous visitor: persists to localStorage under\n * `numu_wishlist_<store_id>`. On login, the wishlist merges into\n * the server-side list (mirrors the cart's session→customer flow).\n *\n * v1 implementation: localStorage only. The /api/customer/me/wishlist\n * endpoint isn't wired yet; an authed visitor still gets the local\n * fallback so themes work end-to-end. When the endpoint lands, the\n * fetcher below swaps its localStorage read for the server fetch and the\n * mutation methods gain a `{ revalidate: true }` write-through.\n *\n * Phase 3 (client-data layer): the items list now lives in the shared\n * `useCachedResource` store keyed by `numu_wishlist_<store_id>`, NOT in\n * per-instance `useState`. Previously two `<Heart>`s for the same product\n * each held their own copy, so adding via one never re-rendered the other —\n * the two hearts DESYNCED. Now every `useWishlist(storeId)` consumer reads\n * and writes ONE shared entry, so an add/remove anywhere reflows every heart.\n * Writes are optimistic (the shared store updates instantly) and roll back if\n * persistence throws.\n */\n\nexport interface WishlistItem {\n product_id: string;\n /** Optional variant scoping — themes that show variant pickers can\n * wishlist a specific size/color combo separately. */\n variant_id?: string | null;\n /** Server timestamp once persistence lands; ms-since-epoch in v1. */\n added_at: number;\n}\n\nexport interface WishlistState {\n items: WishlistItem[];\n loading: boolean;\n has: (productId: string, variantId?: string | null) => boolean;\n addToWishlist: (productId: string, variantId?: string | null) => void;\n removeFromWishlist: (productId: string, variantId?: string | null) => void;\n clear: () => void;\n}\n\nfunction storageKey(storeId: string): string {\n return `numu_wishlist_${storeId}`;\n}\n\nfunction readLocal(storeId: string): WishlistItem[] {\n if (typeof window === \"undefined\") return [];\n try {\n const raw = window.localStorage.getItem(storageKey(storeId));\n if (!raw) return [];\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed) ? (parsed as WishlistItem[]) : [];\n } catch {\n return [];\n }\n}\n\n/**\n * Persist the list. Unlike the previous swallow-all writer, this THROWS on a\n * write failure (quota / private mode) so the optimistic mutation can roll\n * back — the shared store must not diverge from what actually persisted.\n */\nfunction persistWishlist(storeId: string, items: WishlistItem[]): void {\n if (typeof window === \"undefined\") return;\n window.localStorage.setItem(storageKey(storeId), JSON.stringify(items));\n}\n\nfunction sameItem(\n a: WishlistItem,\n productId: string,\n variantId?: string | null,\n): boolean {\n return (\n a.product_id === productId && (a.variant_id ?? null) === (variantId ?? null)\n );\n}\n\n// Stable empty reference so `items` identity doesn't churn every render.\nconst EMPTY: WishlistItem[] = [];\n\n/**\n * @param storeId The store the wishlist is scoped to. Pass `useShop().id`.\n * Without it, the hook can't keep one merchant's wishlist\n * from leaking into another's localStorage on a shared\n * domain (e.g. apex preview).\n */\nexport function useWishlist(storeId: string): WishlistState {\n const key = storageKey(storeId);\n\n // Hydrate from localStorage. Wrapped in a resolved promise so the shared\n // cache has one code path for both the v1 localStorage read and the future\n // server-backed fetch. SSR-safe: readLocal returns [] on the server and the\n // fetch only runs client-side inside useCachedResource's effect.\n const fetcher = useCallback(\n () => Promise.resolve(readLocal(storeId)),\n [storeId],\n );\n\n const { data, isLoading, mutate } = useCachedResource<WishlistItem[]>(\n key,\n fetcher,\n { initialData: EMPTY },\n );\n\n const items = data ?? EMPTY;\n\n const has = useCallback(\n (productId: string, variantId?: string | null) =>\n items.some((it) => sameItem(it, productId, variantId)),\n [items],\n );\n\n // Shared optimistic write: compute next from the CURRENT shared value (not a\n // stale closure), publish it to every subscriber immediately, then persist;\n // roll back to the previous value if the write throws. Returning `null` from\n // `compute` means \"no change\" (e.g. adding a duplicate) — skip entirely.\n const applyOptimistic = useCallback(\n (compute: (prev: WishlistItem[]) => WishlistItem[] | null) => {\n const prev = readResource<WishlistItem[]>(key) ?? EMPTY;\n const next = compute(prev);\n if (next === null) return;\n mutate(next, { revalidate: false });\n try {\n persistWishlist(storeId, next);\n } catch {\n mutate(prev, { revalidate: false });\n }\n },\n [key, storeId, mutate],\n );\n\n const addToWishlist = useCallback(\n (productId: string, variantId?: string | null) =>\n applyOptimistic((prev) =>\n prev.some((it) => sameItem(it, productId, variantId))\n ? null\n : [\n ...prev,\n {\n product_id: productId,\n variant_id: variantId ?? null,\n added_at: Date.now(),\n },\n ],\n ),\n [applyOptimistic],\n );\n\n const removeFromWishlist = useCallback(\n (productId: string, variantId?: string | null) =>\n applyOptimistic((prev) => {\n const next = prev.filter((it) => !sameItem(it, productId, variantId));\n return next.length === prev.length ? null : next;\n }),\n [applyOptimistic],\n );\n\n const clear = useCallback(\n () => applyOptimistic((prev) => (prev.length === 0 ? null : [])),\n [applyOptimistic],\n );\n\n return { items, loading: isLoading, has, addToWishlist, removeFromWishlist, clear };\n}\n","\"use client\";\nimport { useCallback } from \"react\";\nimport type { Product } from \"../types/entities\";\nimport { useCachedResource } from \"../lib/dataCache\";\n\n/**\n * Fetch products related to the given product (same category, excluding\n * self). Phase 3 lands collaborative-filtering / \"frequently bought\n * together\"; v1 ships the simpler same-category-minus-self heuristic.\n *\n * Backend contract: GET /api/storefront/products/{id}/related?limit=N\n * → { items: Product[] } | { data: Product[] } | Product[]\n *\n * Returns an empty list (no error) when the endpoint is missing or the\n * product has no siblings — themes should branch on `items.length` and\n * either render the section or skip it entirely.\n *\n * Phase 3 (client-data layer): routed through the shared `useCachedResource`\n * store keyed by `numu:related:<productId>:<limit>`. Two \"related products\"\n * sections on the same PDP now share ONE request + one result instead of each\n * refetching, and the AbortSignal + cache seq-guard drop a superseded response\n * (e.g. after a rapid product switch) so it can't overwrite the newer list.\n */\n\nexport interface RelatedProductsState {\n items: Product[];\n loading: boolean;\n error: Error | null;\n}\n\n// Stable empty reference so `items` identity doesn't churn every render.\nconst EMPTY: Product[] = [];\n\nexport function useRelatedProducts(\n productId: string | null | undefined,\n options: { limit?: number } = {},\n): RelatedProductsState {\n const limit = options.limit ?? 4;\n const key = productId ? `numu:related:${productId}:${limit}` : \"\";\n\n const fetcher = useCallback(\n async (signal: AbortSignal): Promise<Product[]> => {\n const res = await fetch(\n `/api/storefront/products/${encodeURIComponent(\n productId as string,\n )}/related?limit=${limit}`,\n { cache: \"no-store\", signal },\n );\n if (!res.ok) {\n // Endpoint not yet wired — treat as \"no related items available\"\n // (empty, not an error) so themes just skip the section.\n return EMPTY;\n }\n const json = (await res.json()) as\n | { items?: Product[]; data?: Product[] }\n | Product[];\n return Array.isArray(json)\n ? json\n : Array.isArray(json.data)\n ? json.data\n : Array.isArray(json.items)\n ? json.items\n : EMPTY;\n },\n [productId, limit],\n );\n\n const { data, isLoading, error } = useCachedResource<Product[]>(key, fetcher, {\n enabled: Boolean(productId),\n initialData: EMPTY,\n });\n\n return { items: data ?? EMPTY, loading: isLoading, error: error ?? null };\n}\n","\"use client\";\nimport { useCallback } from \"react\";\nimport { useCachedResource } from \"../lib/dataCache\";\nimport type { ActivePromotionsPayload } from \"../types/promotions\";\n\n/**\n * The store's active promotions for the current visitor.\n *\n * Reads the host proxy `GET /api/storefront/promotions` (never NUMU-api\n * directly — the host owns credentials, caching and the store resolution).\n * The backend groups by surface; the host already renders announcement bars,\n * popups, the cookie banner and floating widgets in the shell, so what a\n * theme normally wants is `auto_discounts` — the offers that price the cart\n * with no code to type.\n *\n * SSR-safe: `useCachedResource` doesn't fetch during server render, so this\n * resolves on hydrate. Sections must therefore tolerate a null first pass —\n * render nothing (or a skeleton) rather than assuming data on first paint.\n *\n * Returns `null` on any miss (offline, 404, flag off). That is deliberate:\n * a promotions outage should make an offer banner disappear, never break the\n * page it sits on.\n *\n * @param page page path used for page-targeted promotions (default \"/\")\n * @param locale \"ar\" | \"en\" — selects the translated content\n */\nexport function useActivePromotions(\n page: string = \"/\",\n locale: string = \"ar\",\n): ActivePromotionsPayload | null {\n const key = `numu:promotions:${page}:${locale}`;\n\n const fetcher = useCallback(\n async (signal: AbortSignal): Promise<ActivePromotionsPayload | null> => {\n const qs = new URLSearchParams({ page, locale });\n const res = await fetch(`/api/storefront/promotions?${qs.toString()}`, {\n credentials: \"include\",\n cache: \"no-store\",\n signal,\n });\n if (!res.ok) return null;\n const json = (await res.json()) as\n | { data?: ActivePromotionsPayload }\n | ActivePromotionsPayload\n | null;\n if (!json) return null;\n return (\n ((json as { data?: ActivePromotionsPayload }).data ??\n (json as ActivePromotionsPayload)) ||\n null\n );\n },\n [page, locale],\n );\n\n const { data } = useCachedResource<ActivePromotionsPayload | null>(\n key,\n fetcher,\n { initialData: null },\n );\n\n return data ?? null;\n}\n","/**\n * Money formatting for NUMU storefronts.\n *\n * Three implementations of this existed and disagreed:\n *\n * - the themes' own `fmt` (4 byte-identical copies): EGP fallback,\n * `maximumFractionDigits: 0`, locale `\"ar\"` mapped to `\"ar-EG\"`\n * - `@numueg/theme-kit`'s `formatMoney`: **USD** fallback, 2 fraction\n * digits, raw locale passed through\n * - `NuMuProvider`'s own `formatMoney`: a third variant again\n *\n * This adopts the themes' behaviour, because that is what production renders\n * today: adopting the kit's would silently turn every promo nudge from\n * `LE 500` into `£E 500.00` on live stores. NUMU is Egypt-first — EGP is the\n * right fallback, whole piastres are noise at Egyptian price points, and\n * `ar-EG` is what produces Egyptian Arabic numerals and currency placement.\n *\n * The unit is CENTS, matching the API end to end. `formatMoneyMajor` exists\n * for the one place that already divided (the SDK exposes cart money in major\n * units), so nobody has to remember which side of the boundary they're on.\n */\n\nexport interface FormatMoneyOptions {\n /** Currency code. Falls back to EGP — Egypt-first, not USD. */\n currency?: string | null;\n /** `\"ar\"` maps to `ar-EG`; anything else formats as `en-EG`. */\n locale?: string | null;\n /**\n * Fraction digits. Defaults to 0: Egyptian retail prices are whole pounds,\n * and `500.00 EGP` reads as noise next to `500 EGP`. Pass 2 where sub-unit\n * precision genuinely matters (a unit price, an FX-converted amount).\n */\n fractionDigits?: number;\n}\n\nfunction resolveLocale(locale: string | null | undefined): string {\n return locale === \"ar\" ? \"ar-EG\" : \"en-EG\";\n}\n\n/**\n * Format an integer amount of cents.\n *\n * @example formatMoney(50000) // \"EGP 500\"\n * @example formatMoney(50000, { locale: \"ar\" }) // \"٥٠٠ ج.م.‏\"\n */\nexport function formatMoney(\n cents: number,\n options: FormatMoneyOptions = {},\n): string {\n const { currency, locale, fractionDigits = 0 } = options;\n // A non-finite amount formats as the zero of its currency rather than\n // \"NaN EGP\" on a product card.\n const safe = Number.isFinite(cents) ? cents : 0;\n return new Intl.NumberFormat(resolveLocale(locale), {\n style: \"currency\",\n currency: currency || \"EGP\",\n maximumFractionDigits: fractionDigits,\n }).format(safe / 100);\n}\n\n/**\n * Format an amount already expressed in major units.\n *\n * The SDK hands cart money to themes in major units while the API speaks\n * cents, so a shared helper that only accepted one of the two guaranteed a\n * factor-of-100 bug at the seam.\n */\nexport function formatMoneyMajor(\n amount: number,\n options: FormatMoneyOptions = {},\n): string {\n return formatMoney(\n (Number.isFinite(amount) ? amount : 0) * 100,\n options,\n );\n}\n\n/** Cents to major units. Non-finite input yields 0, never NaN. */\nexport function centsToMajor(cents: number): number {\n return (Number.isFinite(cents) ? cents : 0) / 100;\n}\n\n/** Major units to integer cents, rounded — the inverse of `centsToMajor`. */\nexport function majorToCents(amount: number): number {\n return Math.round((Number.isFinite(amount) ? amount : 0) * 100);\n}\n","/**\n * Pure helpers for rendering platform promotions in a theme.\n *\n * These are headless by design — data and logic only, zero markup and zero\n * styling — so every theme keeps its own look while sharing one correct\n * implementation of the fiddly parts (unit counting, group math, the\n * cents→major boundary).\n *\n * The hard rule these encode: **a theme never computes a discount.** The\n * engine prices the cart and reports what it saved; helpers here only\n * describe progress toward an offer and format what the engine already\n * decided. Anything else eventually renders a number the server won't honour.\n */\n\nimport type { Cart } from \"../types/entities\";\nimport { centsToMajor } from \"../utils/money\";\nimport type {\n ActivePromotion,\n ActivePromotionsPayload,\n MultibuyOffer,\n OfferProgress,\n} from \"../types/promotions\";\n\n/**\n * Extract the usable multibuy offers (\"any N for a fixed total P\").\n *\n * Accepts either the whole `/api/storefront/promotions` payload or just an\n * array of promotions, so callers don't have to reach into `auto_discounts`\n * themselves. Anything that isn't a well-formed multibuy — a kind this SDK\n * version doesn't know, a missing N or P — is skipped rather than thrown on:\n * a theme built before a rule kind existed must keep rendering when a\n * merchant starts using it.\n */\nexport function multibuyOffers(\n promotions: ActivePromotionsPayload | ActivePromotion[] | null | undefined,\n): MultibuyOffer[] {\n if (!promotions) return [];\n const list: ActivePromotion[] = Array.isArray(promotions)\n ? promotions\n : (promotions.auto_discounts ?? []);\n\n const offers: MultibuyOffer[] = [];\n for (const promo of list) {\n const rule = promo?.discount_rule;\n if (!rule || rule.kind !== \"multibuy\") continue;\n const quantity = rule.multibuy_quantity;\n const groupPriceCents = rule.multibuy_price_cents;\n // Both are required by the engine; a rule missing either is malformed\n // data, not an offer we should advertise.\n if (typeof quantity !== \"number\" || quantity < 2) continue;\n if (typeof groupPriceCents !== \"number\" || groupPriceCents <= 0) continue;\n const eligibleProductIds = promo.eligible_product_ids ?? [];\n const eligibleCategoryIds = promo.eligible_category_ids ?? [];\n offers.push({\n promotionId: promo.promotion_id,\n quantity,\n groupPriceCents,\n groupPriceMajor: centsToMajor(groupPriceCents),\n headline: promo.translated_content?.headline,\n eligibleProductIds,\n eligibleCategoryIds,\n // No scoping rows at all ⇒ every product qualifies. Note an older\n // backend that doesn't send these fields also lands here, which is the\n // right default: counting everything is what themes did before.\n isStoreWide:\n eligibleProductIds.length === 0 && eligibleCategoryIds.length === 0,\n raw: promo,\n });\n }\n return offers;\n}\n\n/**\n * Does this product take part in the offer?\n *\n * A store-wide offer includes everything. Otherwise the product must be named\n * directly or sit in a named category. A scoped offer over a product whose\n * `category_id` we don't know returns false — better to under-promise than to\n * advertise a discount the server won't apply.\n */\nexport function offerIncludesProduct(\n offer: MultibuyOffer | null | undefined,\n product: { id?: string; product_id?: string; category_id?: string | null },\n): boolean {\n if (!offer) return false;\n if (offer.isStoreWide) return true;\n const id = product?.product_id ?? product?.id;\n if (id && offer.eligibleProductIds.includes(id)) return true;\n const category = product?.category_id;\n return Boolean(category && offer.eligibleCategoryIds.includes(category));\n}\n\n/**\n * How many cart UNITS actually qualify for the offer.\n *\n * Units, not lines — three of one product is a valid trio, the way the engine\n * scores it. For a scoped offer this is what the nudge must count; counting\n * the whole cart is how a shopper gets told \"add 2 more\" and then doesn't get\n * the discount.\n */\nexport function eligibleUnitsInCart(\n offer: MultibuyOffer | null | undefined,\n cart: Cart | null | undefined,\n): number {\n if (!offer) return 0;\n return (cart?.items ?? []).reduce((sum, item) => {\n if (!item) return sum;\n if (!offerIncludesProduct(offer, item)) return sum;\n return sum + (item.quantity || 0);\n }, 0);\n}\n\n/**\n * Where the cart stands against one multibuy offer.\n *\n * Counts UNITS, not lines — three of the same product is a valid trio, the\n * same way the engine scores it. `savingMajor` is read from the cart's\n * engine-supplied `applied_promotions`, so an unlocked offer shows the real\n * saving and a theme can never drift from the charged amount.\n *\n * Scoping is handled automatically: when the offer names products or\n * categories, only qualifying units are counted (via `eligibleUnitsInCart`).\n * Pass `eligibleUnits` explicitly to override that — e.g. when the theme has\n * a better source of truth than the cart lines.\n */\nexport function offerProgress(\n offer: MultibuyOffer | null | undefined,\n cart: Cart | null | undefined,\n eligibleUnits?: number,\n): OfferProgress {\n const empty: OfferProgress = {\n unitsInCart: 0,\n unitsNeeded: 0,\n groupsUnlocked: 0,\n savingMajor: 0,\n };\n if (!offer) return empty;\n\n const unitsInCart =\n typeof eligibleUnits === \"number\"\n ? Math.max(0, eligibleUnits)\n : eligibleUnitsInCart(offer, cart);\n\n const groupsUnlocked = Math.floor(unitsInCart / offer.quantity);\n const remainder = unitsInCart % offer.quantity;\n // 0 when the cart just completed a group — \"add N more\" would be noise\n // right after an unlock. The theme decides whether to nudge for the next\n // group; the number here stays honest about the current one.\n const unitsNeeded = remainder === 0 ? 0 : offer.quantity - remainder;\n\n // The engine's own number, already in major units (normalizeCartFromServer\n // converted it). Matching on promotion id keeps a stacked cart honest.\n const applied = (cart?.applied_promotions ?? []).find(\n (p) => p && p.id === offer.promotionId,\n );\n\n return {\n unitsInCart,\n unitsNeeded,\n groupsUnlocked,\n savingMajor: applied ? applied.amount || 0 : 0,\n };\n}\n\n/**\n * Should a product page advertise this offer?\n *\n * Only when N of this product actually costs more than the group price —\n * otherwise the \"deal\" is worse than just buying them, and §5 of the offer\n * spec forbids advertising it (the engine likewise refuses to apply it).\n *\n * @param unitPriceMajor the product's price in MAJOR units, as a theme has it\n */\nexport function offerBeatsRegularPrice(\n offer: MultibuyOffer | null | undefined,\n unitPriceMajor: number | null | undefined,\n): boolean {\n if (!offer || typeof unitPriceMajor !== \"number\" || unitPriceMajor <= 0) {\n return false;\n }\n // Compare in cents to dodge float drift on prices like 249.99.\n const unitCents = Math.round(unitPriceMajor * 100);\n return unitCents * offer.quantity > offer.groupPriceCents;\n}\n","\"use client\";\nimport { useMemo } from \"react\";\nimport type { Product, Store, SizeChart } from \"../types/entities\";\nimport { useProductOptional } from \"./useProduct\";\nimport { useShop } from \"./useShop\";\n\n/**\n * useProductSizeChart — resolve the size chart to show for a product.\n *\n * The merchant hub writes the per-product chart to\n * `product.attributes.size_chart` and the store-wide default to\n * `store.settings.size_chart`, with an explicit `mode`:\n *\n * \"off\" → never show, even if a store default exists\n * \"custom\" → use the product's own chart\n * \"default\" → fall back to the store-wide chart\n * (legacy) → no `mode`: a populated product chart wins, else the default\n *\n * This hook centralises that precedence so every theme resolves it identically\n * (the backend `SizeChartSchema` validator and the hub editor share the same\n * shape). Returns `null` when there is nothing to show — render the size-guide\n * trigger only when this is non-null.\n *\n * @param productOverride - resolve against this product instead of the one in\n * context (e.g. when rendering a chart for a related/quick-view product).\n */\nexport function useProductSizeChart(\n productOverride?: Product | null,\n): SizeChart | null {\n const ctxProduct = useProductOptional();\n const product = productOverride ?? ctxProduct;\n const shop = useShop() as Store | undefined;\n const storeSettings = shop?.settings;\n\n return useMemo(\n () => resolveSizeChart(product?.attributes, storeSettings),\n [product?.attributes, storeSettings],\n );\n}\n\nfunction hasRows(c: unknown): c is SizeChart {\n return (\n !!c &&\n typeof c === \"object\" &&\n Array.isArray((c as SizeChart).rows) &&\n (c as SizeChart).rows.length > 0\n );\n}\n\n/**\n * Pure resolver (no React) — exported so non-hook code (SSR helpers, tests)\n * can apply the same precedence.\n */\nexport function resolveSizeChart(\n productAttributes: Record<string, unknown> | undefined,\n storeSettings: Record<string, unknown> | undefined,\n): SizeChart | null {\n const product = productAttributes?.size_chart as SizeChart | undefined;\n const storeDefault = storeSettings?.size_chart as SizeChart | undefined;\n\n if (product?.mode === \"off\") return null;\n if (product?.mode === \"custom\") return hasRows(product) ? product : null;\n if (product?.mode === \"default\") return hasRows(storeDefault) ? storeDefault : null;\n\n // No explicit mode (legacy): a populated product chart wins, else the default.\n if (hasRows(product)) return product;\n if (hasRows(storeDefault)) return storeDefault;\n return null;\n}\n","/**\n * Variant resolution helpers — Phase 8.1.\n *\n * Themes render a variant picker (Size + Color radios), then ask the\n * SDK \"given my current selection, which variant is it?\" The matching\n * variant's id is what add-to-cart sends.\n */\n\nimport type { Product, ProductVariant } from \"../types/entities\";\n\n/**\n * Pick the variant that exactly matches the given option_values map.\n * Returns null when no variant matches — themes render that as\n * \"Combination unavailable\" or a disabled buy button.\n */\nexport function findVariantByOptions(\n product: Pick<Product, \"variants\">,\n selection: Record<string, string>,\n): ProductVariant | null {\n const variants = product.variants || [];\n if (variants.length === 0) return null;\n // Single-variant products (no axes): the only variant matches the\n // empty selection trivially.\n if (variants.length === 1 && Object.keys(selection).length === 0) {\n return variants[0];\n }\n for (const v of variants) {\n const opts = v.option_values || v.options || {};\n const matches = Object.entries(selection).every(\n ([axis, value]) => opts[axis] === value,\n );\n if (matches && Object.keys(selection).length === Object.keys(opts).length) {\n return v;\n }\n }\n return null;\n}\n\n/**\n * Find the \"default\" variant — the one the PDP should auto-select on\n * first render. Prefers the first in-stock variant; falls back to the\n * first variant if all are out of stock (so the picker still shows\n * something coherent).\n */\nexport function defaultVariant(product: Pick<Product, \"variants\">): ProductVariant | null {\n const variants = product.variants || [];\n if (variants.length === 0) return null;\n const inStock = variants.find((v) => v.is_in_stock || v.in_stock);\n return inStock || variants[0];\n}\n\n/**\n * Given a partial selection (e.g. just Size=M, no Color yet), return\n * the set of values still available on each unselected axis. Themes\n * use this to disable swatches whose paired variants are all out of\n * stock for the current selection.\n */\nexport function availableValues(\n product: Pick<Product, \"options\" | \"variants\">,\n selection: Record<string, string>,\n): Record<string, Set<string>> {\n const axes = product.options || [];\n const variants = product.variants || [];\n const out: Record<string, Set<string>> = {};\n for (const axis of axes) {\n const set = new Set<string>();\n for (const v of variants) {\n const opts = v.option_values || v.options || {};\n // Only consider variants compatible with the locked-in part of\n // the selection (every locked axis must match this variant).\n const compatible = Object.entries(selection).every(\n ([k, val]) => k === axis.name || opts[k] === val,\n );\n if (compatible && opts[axis.name]) {\n set.add(opts[axis.name]);\n }\n }\n // When NO variant carries option-value data for this axis, availability\n // is UNKNOWN — not \"all sold out\". This happens for legacy products whose\n // axes live in `attributes.variants` (derived into `options`) but have no\n // SKU-tracked variant rows, so every `variant.option_values` is empty.\n // Falling back to the axis's declared values keeps the picker usable\n // instead of rendering every swatch struck-through. A genuinely\n // constrained axis (≥1 variant with data) keeps its computed set.\n out[axis.name] = set.size > 0 ? set : new Set(axis.values || []);\n }\n return out;\n}\n","/**\n * Live variant-picker selection registry.\n *\n * `useVariantSelection` publishes its current axis→value map here keyed by\n * product id; `AddToCartButton` reads it back at click time. This is what\n * lets the selection reach the cart even when no real variant row matches —\n * legacy products keep their axes in attributes JSON with a single\n * placeholder variant whose option_values is {}, so `findVariantByOptions`\n * returns null and there'd otherwise be nothing to send.\n *\n * Module-scoped (not React context) on purpose: the hook instance lives in\n * the theme's PDP section while the button may be a sibling — they share no\n * provider of ours. Bounded: one entry per product id, last write wins.\n */\n\nconst selections = new Map<string, Record<string, string>>();\n\nexport function publishVariantSelection(\n productId: string | undefined | null,\n selection: Record<string, string>,\n): void {\n if (!productId) return;\n selections.set(productId, selection);\n}\n\n/** Latest non-empty selection for a product, or null. */\nexport function readVariantSelection(\n productId: string | undefined | null,\n): Record<string, string> | null {\n if (!productId) return null;\n const sel = selections.get(productId);\n if (!sel) return null;\n const filtered: Record<string, string> = {};\n for (const [k, v] of Object.entries(sel)) {\n if (v) filtered[k] = v;\n }\n return Object.keys(filtered).length > 0 ? filtered : null;\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport {\n availableValues,\n defaultVariant,\n findVariantByOptions,\n} from \"../utils/variants\";\nimport { publishVariantSelection } from \"../utils/selectionRegistry\";\nimport type { Product, ProductVariant } from \"../types/entities\";\n\nexport interface UseVariantSelection {\n /** Currently-selected axis → value map. */\n selection: Record<string, string>;\n /** The variant matching the current selection, if any. */\n variant: ProductVariant | null;\n /** Pick a value on one axis. Other axes stay locked. */\n select: (axis: string, value: string) => void;\n /** Reset the selection (e.g. on \"Choose another\" button). */\n reset: () => void;\n /**\n * For each unselected axis, the set of values that lead to at\n * least one in-stock variant given the current locked axes.\n * Themes use this to grey out swatches.\n */\n availability: Record<string, Set<string>>;\n /**\n * True when every option axis on the product has a chosen value\n * and `variant` is resolved. Buy buttons should disable until\n * this flips to true on products with options.\n */\n isComplete: boolean;\n}\n\n/**\n * Hook that owns variant-axis selection state for a PDP.\n *\n * Initial state auto-selects the default variant's axis values so\n * the PDP loads with a coherent price + image + buy state, matching\n * Shopify's behavior. Themes that prefer \"Choose your size\" empty\n * state can pass `autoSelect: false`.\n */\nexport function useVariantSelection(\n product: Pick<Product, \"options\" | \"variants\"> & { id?: string },\n opts: { autoSelect?: boolean } = {},\n): UseVariantSelection {\n const autoSelect = opts.autoSelect ?? true;\n\n const initial = useMemo<Record<string, string>>(() => {\n if (!autoSelect) return {};\n const dv = defaultVariant(product);\n if (!dv) return {};\n const opts = dv.option_values || dv.options || {};\n return { ...opts };\n }, [product, autoSelect]);\n\n const [selection, setSelection] = useState<Record<string, string>>(initial);\n\n const select = useCallback((axis: string, value: string) => {\n setSelection((prev) => ({ ...prev, [axis]: value }));\n }, []);\n\n const reset = useCallback(() => setSelection({}), []);\n\n const variant = useMemo(\n () => findVariantByOptions(product, selection),\n [product, selection],\n );\n\n // Mirror the live selection into the module registry so AddToCartButton\n // can attach it to the cart write even when no variant row matches\n // (legacy products: axes in attributes JSON, placeholder variant with\n // empty option_values). Themes pass full product objects, so `id` is\n // present in practice; the widened param type keeps this non-breaking.\n useEffect(() => {\n publishVariantSelection(product.id, selection);\n }, [product.id, selection]);\n\n const availability = useMemo(\n () => availableValues(product, selection),\n [product, selection],\n );\n\n const isComplete = useMemo(() => {\n const axes = product.options || [];\n if (axes.length === 0) return true;\n return axes.every((a) => Boolean(selection[a.name]));\n }, [product, selection]);\n\n return { selection, variant, select, reset, availability, isComplete };\n}\n","\"use client\";\n\nimport { useCallback, useState } from \"react\";\n\n/**\n * Gift card balance check — Phase 8.3.\n *\n * Themes call this from the checkout payment step to validate a\n * customer-typed code before sending it as part of the checkout\n * payload. The backend returns 404 for any non-redeemable card\n * (expired, depleted, voided, or wrong store) — the response shape\n * stays uniform so the hook can't be used to probe for valid codes.\n *\n * Backend contract (via storefront proxy):\n * GET /api/gift-cards/{code}\n * → 200 { data: { last_four, current_balance_cents, currency,\n * expires_at? } }\n * → 404 { error: { code, message } }\n */\n\nexport interface GiftCardBalance {\n last_four: string;\n current_balance_cents: number;\n currency: string;\n expires_at: string | null;\n}\n\nexport interface UseGiftCardBalance {\n /** Last lookup result, or null when nothing checked yet / failed. */\n balance: GiftCardBalance | null;\n /** True while a lookup is in flight. */\n loading: boolean;\n /** Latest error from the lookup, if any. Cleared on next check. */\n error: Error | null;\n /** Trigger a balance check. Returns the result or null on failure. */\n check: (code: string) => Promise<GiftCardBalance | null>;\n /** Clear the last result + error (e.g. when the user clears the input). */\n reset: () => void;\n}\n\nexport function useGiftCardBalance(): UseGiftCardBalance {\n const [balance, setBalance] = useState<GiftCardBalance | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const check = useCallback(async (code: string): Promise<GiftCardBalance | null> => {\n if (typeof window === \"undefined\") return null;\n const trimmed = (code || \"\").trim();\n if (!trimmed) {\n setError(new Error(\"Enter a gift card code.\"));\n setBalance(null);\n return null;\n }\n setLoading(true);\n setError(null);\n try {\n const res = await fetch(\n `/api/gift-cards/${encodeURIComponent(trimmed)}`,\n { cache: \"no-store\" },\n );\n if (!res.ok) {\n setBalance(null);\n // 404 = invalid/redeemed/expired — surface a friendly message\n // rather than the raw API code so themes don't need to map it.\n if (res.status === 404) {\n setError(new Error(\"That gift card isn't valid or has been used up.\"));\n return null;\n }\n setError(new Error(`Couldn't check gift card (HTTP ${res.status}).`));\n return null;\n }\n const json = (await res.json()) as { data?: GiftCardBalance };\n const data = json?.data;\n if (!data) {\n setBalance(null);\n setError(new Error(\"Unexpected response from server.\"));\n return null;\n }\n setBalance(data);\n return data;\n } catch (err) {\n setBalance(null);\n setError(err instanceof Error ? err : new Error(String(err)));\n return null;\n } finally {\n setLoading(false);\n }\n }, []);\n\n const reset = useCallback(() => {\n setBalance(null);\n setError(null);\n }, []);\n\n return { balance, loading, error, check, reset };\n}\n","\"use client\";\n\nimport { useCallback, useState } from \"react\";\n\n/**\n * Reorder / \"buy again\" — Phase 8.5.\n *\n * Clones every line item from an existing order into the current cart.\n * The backend skips lines whose product is deleted/archived, whose\n * variant is gone, or that are out of stock — returning per-line\n * reasons so themes can show a \"couldn't add X items\" banner.\n *\n * Backend contract:\n * POST /storefront/me/orders/{order_id}/reorder\n * → 200 { data: { added_count, skipped[], cart_total_items } }\n * → 404 if order doesn't belong to the current customer\n */\n\nexport type ReorderSkipReason =\n | \"product_deleted\"\n | \"product_archived\"\n | \"out_of_stock\"\n | \"variant_unavailable\";\n\nexport interface ReorderSkippedItem {\n product_id: string;\n variant_id: string | null;\n quantity: number;\n reason: ReorderSkipReason | string;\n}\n\nexport interface ReorderResult {\n added_count: number;\n skipped: ReorderSkippedItem[];\n cart_total_items: number;\n}\n\nexport interface UseReorder {\n /** Last reorder result. */\n result: ReorderResult | null;\n /** True while a reorder is in flight. */\n loading: boolean;\n /** Latest error, cleared on next reorder call. */\n error: Error | null;\n /** Trigger the reorder. Returns the result or null on failure. */\n reorder: (orderId: string) => Promise<ReorderResult | null>;\n /** Clear the last result + error (e.g. after dismissing the banner). */\n reset: () => void;\n}\n\nexport function useReorder(): UseReorder {\n const [result, setResult] = useState<ReorderResult | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const reorder = useCallback(\n async (orderId: string): Promise<ReorderResult | null> => {\n if (typeof window === \"undefined\") return null;\n if (!orderId) {\n setError(new Error(\"Order id is required.\"));\n return null;\n }\n setLoading(true);\n setError(null);\n try {\n // Read the CSRF cookie value and echo it as a header — the\n // storefront's mutating proxies verify the double-submit.\n const csrf =\n typeof document !== \"undefined\"\n ? (document.cookie.match(/(?:^|; )numu_csrf=([^;]+)/)?.[1] ?? \"\")\n : \"\";\n const res = await fetch(\n `/api/customer/orders/${encodeURIComponent(orderId)}/reorder`,\n {\n method: \"POST\",\n headers: csrf ? { \"x-numu-csrf\": csrf } : {},\n credentials: \"include\",\n },\n );\n if (!res.ok) {\n if (res.status === 401) {\n setError(new Error(\"Please sign in to reorder.\"));\n } else if (res.status === 404) {\n setError(new Error(\"That order can't be found on your account.\"));\n } else {\n setError(new Error(`Couldn't reorder (HTTP ${res.status}).`));\n }\n return null;\n }\n const json = (await res.json()) as { data?: ReorderResult };\n const data = json?.data;\n if (!data) {\n setError(new Error(\"Unexpected response from server.\"));\n return null;\n }\n setResult(data);\n return data;\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n return null;\n } finally {\n setLoading(false);\n }\n },\n [],\n );\n\n const reset = useCallback(() => {\n setResult(null);\n setError(null);\n }, []);\n\n return { result, loading, error, reorder, reset };\n}\n","\"use client\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\n\n/**\n * Programmatic checkout driver — Phase 7.6.\n *\n * The storefront's multi-step checkout pages (Phase 1.2) own the\n * default flow: contact → shipping → payment → review → processing →\n * thank-you. This hook gives themes a programmatic alternative so a\n * BYOT theme can render the checkout exactly how it wants — single-\n * page, accordion, full-bleed hero, whatever — without being forced\n * through the platform's step pages.\n *\n * State lives in `numu_checkout_state` sessionStorage (same blob the\n * platform's step pages use) so themes that drive checkout\n * programmatically can hand off to the platform mid-flow (e.g. theme\n * collects contact + shipping, then redirects to /checkout/payment\n * for the gateway capture). The platform-side state machine guards\n * deep-links via `hasContactStep / hasShippingStep / hasPaymentStep`\n * regardless of how the state got populated.\n *\n * Usage:\n *\n * const checkout = useCheckout();\n * checkout.contact.set({ email, phone, shipping_address });\n * await checkout.shipping.refresh();\n * checkout.shipping.select(rate.id);\n * checkout.payment.select(\"paymob\");\n * const result = await checkout.placeOrder();\n * if (result.payment_url) window.location.assign(result.payment_url);\n */\n\nexport type CheckoutStep =\n | \"contact\"\n | \"shipping\"\n | \"payment\"\n | \"review\"\n | \"processing\";\n\nexport interface CheckoutAddress {\n first_name?: string;\n last_name?: string;\n line1?: string;\n line2?: string | null;\n city?: string;\n state?: string | null;\n postal_code?: string | null;\n country?: string;\n phone?: string | null;\n}\n\nexport interface ShippingRateOption {\n id: string;\n name: string;\n amount_cents: number;\n currency: string;\n estimated_days_min?: number | null;\n estimated_days_max?: number | null;\n carrier?: string | null;\n}\n\nexport interface CheckoutSessionState {\n email: string;\n phone: string;\n shipping_address: CheckoutAddress;\n selected_shipping_rate_id: string | null;\n shipping_method: string | null;\n payment_method: string | null;\n cod_requested: boolean;\n deposit_gateway: string | null;\n saved_payment_method_id: string | null;\n customer_notes: string;\n coupon_code: string;\n}\n\nexport interface PlaceOrderResult {\n order_id: string;\n order_number: string;\n total: number;\n currency: string;\n payment_status: string;\n payment_url?: string | null;\n payment_data?: Record<string, unknown> | null;\n}\n\nexport interface CheckoutApi {\n state: CheckoutSessionState;\n step: CheckoutStep;\n contact: {\n set: (input: {\n email?: string;\n phone?: string;\n shipping_address?: CheckoutAddress;\n }) => void;\n isComplete: () => boolean;\n };\n shipping: {\n rates: ShippingRateOption[] | null;\n loading: boolean;\n refresh: () => Promise<ShippingRateOption[]>;\n select: (rateId: string) => void;\n isComplete: () => boolean;\n };\n payment: {\n select: (\n method: string,\n opts?: { saved_payment_method_id?: string; deposit_gateway?: string },\n ) => void;\n isComplete: () => boolean;\n };\n setNotes: (notes: string) => void;\n setCoupon: (code: string) => void;\n placeOrder: () => Promise<PlaceOrderResult>;\n reset: () => void;\n}\n\nconst STORAGE_KEY = \"numu_checkout_state\";\n\nconst EMPTY_STATE: CheckoutSessionState = {\n email: \"\",\n phone: \"\",\n shipping_address: {},\n selected_shipping_rate_id: null,\n shipping_method: null,\n payment_method: null,\n cod_requested: false,\n deposit_gateway: null,\n saved_payment_method_id: null,\n customer_notes: \"\",\n coupon_code: \"\",\n};\n\nfunction readState(): CheckoutSessionState {\n if (typeof window === \"undefined\") return { ...EMPTY_STATE };\n try {\n const raw = window.sessionStorage.getItem(STORAGE_KEY);\n if (!raw) return { ...EMPTY_STATE };\n return { ...EMPTY_STATE, ...JSON.parse(raw) };\n } catch {\n return { ...EMPTY_STATE };\n }\n}\n\nfunction writeState(state: CheckoutSessionState): void {\n if (typeof window === \"undefined\") return;\n try {\n window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify(state));\n // Notify any other useCheckout() consumers in the same tab.\n window.dispatchEvent(new CustomEvent(\"numu:checkout:updated\"));\n } catch {\n /* Safari private mode → swallow */\n }\n}\n\nfunction hasContact(s: CheckoutSessionState): boolean {\n return Boolean(\n s.email &&\n s.shipping_address?.line1 &&\n s.shipping_address?.city &&\n s.shipping_address?.country,\n );\n}\n\nfunction hasShipping(s: CheckoutSessionState): boolean {\n return hasContact(s) && Boolean(s.selected_shipping_rate_id);\n}\n\nfunction hasPayment(s: CheckoutSessionState): boolean {\n return hasShipping(s) && Boolean(s.payment_method);\n}\n\nfunction resolveStep(s: CheckoutSessionState): CheckoutStep {\n if (!hasContact(s)) return \"contact\";\n if (!hasShipping(s)) return \"shipping\";\n if (!hasPayment(s)) return \"payment\";\n return \"review\";\n}\n\nexport function useCheckout(): CheckoutApi {\n const [state, setState] = useState<CheckoutSessionState>(() => readState());\n const [rates, setRates] = useState<ShippingRateOption[] | null>(null);\n const [ratesLoading, setRatesLoading] = useState(false);\n\n // Sync from sessionStorage when other consumers update (other tab\n // would not trigger the same-tab event but storage event handles it).\n useEffect(() => {\n function onChange() {\n setState(readState());\n }\n window.addEventListener(\"numu:checkout:updated\", onChange);\n window.addEventListener(\"storage\", (e) => {\n if (e.key === STORAGE_KEY) onChange();\n });\n return () => {\n window.removeEventListener(\"numu:checkout:updated\", onChange);\n };\n }, []);\n\n const patch = useCallback((partial: Partial<CheckoutSessionState>) => {\n setState((prev) => {\n const next = { ...prev, ...partial };\n writeState(next);\n return next;\n });\n }, []);\n\n const refreshShipping = useCallback(async (): Promise<ShippingRateOption[]> => {\n setRatesLoading(true);\n try {\n const res = await fetch(\"/api/shipping/options\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ shipping_address: state.shipping_address }),\n });\n if (!res.ok) {\n setRates([]);\n return [];\n }\n const body = await res.json();\n const list: ShippingRateOption[] =\n (body?.data?.options || body?.data || body?.options || []) as ShippingRateOption[];\n setRates(list);\n return list;\n } catch {\n setRates([]);\n return [];\n } finally {\n setRatesLoading(false);\n }\n }, [state.shipping_address]);\n\n const placeOrder = useCallback(async (): Promise<PlaceOrderResult> => {\n // Cart line items are read server-side from the session cookie;\n // we still pass an empty list because the schema requires the field.\n const payload = {\n line_items: [],\n shipping_address: state.shipping_address,\n payment_method: state.payment_method,\n selected_shipping_rate_id: state.selected_shipping_rate_id,\n shipping_method: state.shipping_method,\n guest_email: state.email,\n cod_requested: state.cod_requested,\n deposit_gateway: state.deposit_gateway,\n saved_payment_method_id: state.saved_payment_method_id,\n customer_notes: state.customer_notes || null,\n coupon_code: state.coupon_code || null,\n };\n const res = await fetch(\"/api/checkout\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n // Idempotency-Key prevents a double-click double-charge.\n \"Idempotency-Key\":\n typeof crypto !== \"undefined\" && \"randomUUID\" in crypto\n ? crypto.randomUUID()\n : `${Date.now()}-${Math.random()}`,\n },\n body: JSON.stringify(payload),\n });\n const body = await res.json();\n if (!res.ok) {\n const detail =\n body?.detail || body?.error || `Checkout failed (${res.status})`;\n throw new Error(typeof detail === \"string\" ? detail : JSON.stringify(detail));\n }\n const data = (body?.data || body) as PlaceOrderResult;\n return data;\n }, [state]);\n\n const step = useMemo(() => resolveStep(state), [state]);\n\n const api = useMemo<CheckoutApi>(\n () => ({\n state,\n step,\n contact: {\n set: (input) =>\n patch({\n ...(input.email !== undefined && { email: input.email }),\n ...(input.phone !== undefined && { phone: input.phone }),\n ...(input.shipping_address && {\n shipping_address: {\n ...state.shipping_address,\n ...input.shipping_address,\n },\n // Invalidate downstream picks when address changes.\n selected_shipping_rate_id: null,\n shipping_method: null,\n }),\n }),\n isComplete: () => hasContact(state),\n },\n shipping: {\n rates,\n loading: ratesLoading,\n refresh: refreshShipping,\n select: (rateId) => {\n const rate = rates?.find((r) => r.id === rateId);\n patch({\n selected_shipping_rate_id: rateId,\n shipping_method: rate?.name || null,\n });\n },\n isComplete: () => hasShipping(state),\n },\n payment: {\n select: (method, opts) =>\n patch({\n payment_method: method,\n cod_requested: method === \"cod\",\n deposit_gateway: opts?.deposit_gateway || null,\n saved_payment_method_id: opts?.saved_payment_method_id || null,\n }),\n isComplete: () => hasPayment(state),\n },\n setNotes: (notes) => patch({ customer_notes: notes }),\n setCoupon: (code) => patch({ coupon_code: code }),\n placeOrder,\n reset: () => {\n if (typeof window !== \"undefined\") {\n try {\n window.sessionStorage.removeItem(STORAGE_KEY);\n } catch {\n /* swallow */\n }\n }\n setState({ ...EMPTY_STATE });\n setRates(null);\n },\n }),\n [state, step, rates, ratesLoading, refreshShipping, placeOrder, patch],\n );\n\n return api;\n}\n","\"use client\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport type { CheckoutAddress, ShippingRateOption } from \"./useCheckout\";\n\n/**\n * Fetch shipping rate options for an address — Phase 7.4.\n *\n * Themes that want to display rates on the cart page (Shopify\n * pattern: \"Shipping calculated at checkout — preview from cart\")\n * use this. It posts to /api/shipping/options the same way the\n * platform's shipping step does, but as a self-contained hook so\n * themes don't need to drive the full useCheckout() machinery for a\n * simple display.\n *\n * Returns null when no address is provided (the typical pre-input\n * state) — themes branch on `rates !== null` to decide whether to\n * show the rates panel or a \"Enter address\" prompt.\n *\n * Optionally accepts a `location_id` for multi-location stores\n * (Phase 8.2) — the resolver uses the named fulfilling location's\n * origin address when calculating rates. Ignored if multi-location\n * is off.\n *\n * Usage:\n *\n * const { rates, loading, refresh } = useShippingRates({\n * address: { country: \"EG\", city: \"Cairo\" },\n * });\n */\n\nexport interface UseShippingRatesOptions {\n address?: CheckoutAddress | null;\n location_id?: string | null;\n /** Auto-fetch on mount + when the address changes. Default true. */\n enabled?: boolean;\n}\n\nexport interface UseShippingRatesState {\n rates: ShippingRateOption[] | null;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n}\n\nfunction isAddressSufficient(a?: CheckoutAddress | null): boolean {\n if (!a) return false;\n // Country alone gets a zone-level estimate; city + country gets\n // the rate properly. We require at least country since zones are\n // country-keyed.\n return Boolean(a.country);\n}\n\nexport function useShippingRates({\n address,\n location_id,\n enabled = true,\n}: UseShippingRatesOptions = {}): UseShippingRatesState {\n const [rates, setRates] = useState<ShippingRateOption[] | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const refresh = useCallback(async (): Promise<void> => {\n if (!isAddressSufficient(address)) {\n setRates(null);\n return;\n }\n setLoading(true);\n setError(null);\n try {\n const res = await fetch(\"/api/shipping/options\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n shipping_address: address,\n ...(location_id ? { location_id } : {}),\n }),\n });\n if (!res.ok) {\n // 404 = country not covered by any zone. Surface as \"no\n // rates\" rather than an error so themes can render a\n // \"We don't ship to {country}\" message gracefully.\n if (res.status === 404) {\n setRates([]);\n return;\n }\n throw new Error(`shipping rates: HTTP ${res.status}`);\n }\n const body = await res.json();\n const list: ShippingRateOption[] =\n (body?.data?.options || body?.data || body?.options || []) as ShippingRateOption[];\n setRates(list);\n } catch (e) {\n setError(e instanceof Error ? e : new Error(String(e)));\n setRates([]);\n } finally {\n setLoading(false);\n }\n }, [address, location_id]);\n\n useEffect(() => {\n if (!enabled) return;\n void refresh();\n }, [enabled, refresh]);\n\n return { rates, loading, error, refresh };\n}\n","\"use client\";\nimport {\n useEffect,\n useState,\n useCallback,\n useMemo,\n useRef,\n type ReactNode,\n} from \"react\";\nimport {\n ShopContext,\n CartContext,\n CustomerContext,\n ThemeSettingsContext,\n LocalizationContext,\n CurrentTemplateContext,\n PageContext,\n NavigationContext,\n CurrencyContext,\n} from \"../contexts\";\nimport {\n CustomerActionsContext,\n type CustomerActions,\n} from \"../contexts/customer-actions\";\nimport { readVariantSelection } from \"../utils/selectionRegistry\";\nimport type { Store, Cart, CartItem, Customer } from \"../types/entities\";\nimport type { ThemeSettingsV3 } from \"../types/theme\";\nimport type {\n LocalizationState,\n MenuItemData,\n CartMutationResult,\n CurrencyConfig,\n CurrencyState,\n} from \"../contexts\";\n\nconst RTL_LOCALES = [\"ar\", \"he\", \"fa\", \"ur\"];\n\ninterface NuMuProviderProps {\n store: Store;\n themeSettings: ThemeSettingsV3;\n initialCart?: Cart;\n customer?: Customer | null;\n locale?: string;\n translations?: Record<string, string>;\n /**\n * Wave 5 — id of the active page template. Hosts pass this from the\n * route (e.g. \"product\" inside app/(store)/[subdomain]/product/[id]).\n * Themes read it via `useCurrentTemplate()` to render the matching\n * section list. Defaults to \"home\" when omitted, so existing themes\n * built before the prop existed keep rendering their home template.\n */\n currentTemplate?: string;\n /**\n * I3 — resolved alternate template key for the current page (e.g.\n * `\"product.wholesale\"`) when the storefront routed it to a template\n * suffix. Published on the synthesized `PageContext` value so themes read\n * it via `usePage()?.template`. Distinct from `currentTemplate`, which is\n * the base route type (`\"product\"`). Omit for pages on their default\n * template; additive, so themes/hosts predating it are unaffected.\n */\n pageTemplate?: string;\n /**\n * Pre-fetched product list for the current page. Themes that call\n * `useProducts()` will read these from PageContext without needing\n * `fetchIfMissing: true`. Hosts typically populate this from their\n * route loader / SSR pass; omitting it leaves `useProducts()`\n * returning an empty array unless the theme opts into client fetch.\n */\n initialProducts?: import(\"../types/entities\").Product[];\n /**\n * Pre-fetched collection list — same pattern as initialProducts for\n * `useCollections()`. Categories/collections shown on the home page\n * read this slot.\n */\n initialCollections?: import(\"../types/entities\").Collection[];\n /**\n * Phase 2.4 — store navigation menus keyed by handle (`main-menu`,\n * `footer`, …), resolved server-side by the host and injected so a\n * theme's `useNavigation(handle)` resolves synchronously without a\n * client round-trip. Omit for hosts/themes that don't wire menus —\n * `useNavigation` then falls back to its own fetch or the theme's\n * `DEFAULT_NAV`.\n */\n navigation?: Record<string, MenuItemData[]>;\n children: ReactNode;\n}\n\nconst EMPTY_CART: Cart = {\n id: \"\",\n items: [],\n subtotal: 0,\n total: 0,\n currency: \"EGP\",\n};\n\n/**\n * The storefront's /api/cart returns money in CENTS (matching the checkout\n * and built-in cart, which divide by 100 themselves). Themes consume the cart\n * via useCart() and render with <Money>/formatMoney, which expect MAJOR units\n * — the same convention as Product.price after the host normalizes it. Convert\n * cart money to major here so the BYOT boundary is consistent end-to-end.\n *\n * Display-only: checkout submits quantities (the server recomputes amounts),\n * so this never changes what the customer is charged.\n */\nfunction normalizeCartFromServer(cart: Cart): Cart {\n const toMajor = (n: number | null | undefined): number =>\n typeof n === \"number\" ? n / 100 : 0;\n // The wire shape carries `automatic_discount_cents`; the theme-facing `Cart`\n // exposes the converted `automatic_discount`. Destructure the raw name OUT\n // of the spread rather than just adding the converted one beside it —\n // otherwise both survive, 100x apart, and the one carrying the name a theme\n // dev reaches for first (it's the name used by the backend response, by\n // `adaptCart`, and throughout the offers docs) is the unconverted one.\n // TypeScript wouldn't catch that read, since the field isn't on `Cart`.\n const { automatic_discount_cents: wireAutomaticCents, ...rest } = cart as Cart & {\n automatic_discount_cents?: number;\n };\n return {\n ...rest,\n subtotal: toMajor(cart.subtotal),\n total: toMajor(cart.total),\n ...(cart.discount_amount != null\n ? { discount_amount: toMajor(cart.discount_amount) }\n : {}),\n // Offers-v2 automatic promotions. These MUST be converted here too —\n // they arrive in cents next to already-major totals, so forwarding them\n // raw makes every theme render a saving 100x too large. This function is\n // the one and only cents→major boundary for the cart.\n //\n // The backend field is `automatic_discount_cents`; themes get\n // `automatic_discount` (major), because a `_cents` name holding pounds\n // invites exactly the double-divide this conversion exists to prevent.\n ...(wireAutomaticCents != null\n ? { automatic_discount: toMajor(wireAutomaticCents) }\n : {}),\n ...(Array.isArray(cart.applied_promotions)\n ? {\n applied_promotions: cart.applied_promotions.map((p) => ({\n ...p,\n amount: toMajor(p.amount),\n })),\n }\n : {}),\n items: Array.isArray(cart.items)\n ? cart.items.map((it) => {\n // The storefront/backend cart line item ships `product_name` +\n // `unit_price`/`total_price` (cents), not the `name`/`price` the\n // SDK's CartItem interface (and themes) expect. Map them here so\n // every theme's cart renders the real name + price instead of a\n // blank name and 0.00. Honour `name`/`price` first for any backend\n // that already uses them.\n const raw = it as CartItem & {\n product_name?: string;\n unit_price?: number;\n };\n return {\n ...it,\n name: raw.name || raw.product_name || \"\",\n price: toMajor(raw.price ?? raw.unit_price),\n variant_name: raw.variant_name ?? undefined,\n };\n })\n : [],\n };\n}\n\n/**\n * The storefront's /api/cart* routes return the cart inside a `{data}`\n * envelope (`{ success, data: Cart, message }`) — the platform-wide response\n * shape the hub / admin / customer-fetch all unwrap. The cart logic here\n * historically read the response AS the cart, so `data.items` was `undefined`\n * and the cart silently stayed EMPTY: add-to-cart returned 200/201 but the\n * header count and cart page never updated. Unwrap `.data` when present.\n */\nfunction unwrapCart(json: unknown): Cart {\n if (\n json &&\n typeof json === \"object\" &&\n \"data\" in json &&\n (json as { data?: unknown }).data &&\n typeof (json as { data?: unknown }).data === \"object\"\n ) {\n return (json as { data: Cart }).data;\n }\n return json as Cart;\n}\n\n/**\n * Read the `numu_csrf` cookie value from document.cookie.\n *\n * The storefront's GET /api/cart sets this on first fetch; we echo it\n * back in `x-numu-csrf` on every mutation so the proxy can verify the\n * double-submit. Without this gate any XSS in a theme can drain the\n * customer's cart by hitting /api/cart/add directly.\n */\nfunction readCsrfCookie(): string | null {\n if (typeof document === \"undefined\") return null;\n const match = document.cookie.match(/(?:^|;\\s*)numu_csrf=([^;]+)/);\n return match ? decodeURIComponent(match[1]) : null;\n}\n\n// ── Currency cookie (numu_currency) ────────────────────────────────────────\n// Persists the visitor's presentment-currency choice so it survives cross-page\n// navigation. Owned by NuMuProvider (was previously in useCurrency).\nconst CURRENCY_COOKIE_NAME = \"numu_currency\";\nconst CURRENCY_COOKIE_MAX_AGE = 60 * 60 * 24 * 30; // 30 days\n\nfunction readCurrencyCookie(): string | null {\n if (typeof document === \"undefined\") return null;\n const match = document.cookie.match(\n new RegExp(`(?:^|;\\\\s*)${CURRENCY_COOKIE_NAME}=([^;]+)`),\n );\n return match ? decodeURIComponent(match[1]) : null;\n}\n\nfunction writeCurrencyCookie(value: string): void {\n if (typeof document === \"undefined\") return;\n document.cookie = `${CURRENCY_COOKIE_NAME}=${encodeURIComponent(value)}; path=/; max-age=${CURRENCY_COOKIE_MAX_AGE}; SameSite=Lax`;\n}\n\n/**\n * postCartMutation — shared helper for cart writes.\n *\n * Three concerns layered together:\n *\n * 1. Request versioning so a burst of \"+ + +\" clicks doesn't apply\n * stale responses. Each call reserves a token; only the response\n * for the highest-numbered token is allowed to update local state.\n *\n * 2. CSRF: every cart mutation includes `x-numu-csrf` from the cookie.\n * The /api/cart/* proxy compares cookie + header (double-submit)\n * and rejects mismatches with 403.\n *\n * 3. Idempotency: each call mints a UUID idempotency key. The\n * backend (when supported) caches the response for that key in\n * Redis so a double-clicked Add-to-Cart only mutates state once.\n * Wire format is stable; backend honoring it is opt-in.\n *\n * Resolves a `CartMutationResult` so the caller can tell success from\n * failure. Previously this swallowed `!res.ok` with a bare `return`, so an\n * out-of-stock / validation / 403 rejection was indistinguishable from a\n * successful write — and `addItem` fired its `add_to_cart` analytics event\n * regardless. Now a non-2xx resolves `{ ok: false, status, message }` (and\n * does NOT apply a cart), so themes can surface the error and analytics can\n * be gated on `ok`. On success it applies the cart and resolves\n * `{ ok: true, status }`. Network throws still reject (callers that relied on\n * try/catch keep that behavior); `mutate` wraps this and always sets loading.\n */\nasync function postCartMutation(\n endpoint: string,\n body: unknown,\n applyCart: (cart: Cart) => void,\n reserveToken: () => number,\n): Promise<CartMutationResult> {\n const token = reserveToken();\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n const csrf = readCsrfCookie();\n if (csrf) headers[\"x-numu-csrf\"] = csrf;\n // Idempotency key — randomUUID is widely supported; fall back if not\n // (older Safari, embedded webviews).\n const idempotencyKey =\n typeof crypto !== \"undefined\" && \"randomUUID\" in crypto\n ? crypto.randomUUID()\n : `${Date.now()}-${Math.random().toString(36).slice(2)}`;\n headers[\"x-numu-idempotency-key\"] = idempotencyKey;\n\n const res = await fetch(endpoint, {\n method: body === undefined ? \"DELETE\" : \"POST\",\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n });\n if (!res.ok) {\n // Non-2xx (OOS, validation, 403 CSRF, …). Pull the backend's error text\n // when the body parses so a theme can show a real message; never apply a\n // cart from a failed write.\n let message: string | undefined;\n try {\n const err = (await res.json()) as Record<string, unknown> | null;\n if (err && typeof err === \"object\") {\n const m = err.message ?? err.error ?? err.detail;\n if (typeof m === \"string\") message = m;\n }\n } catch {\n // Non-JSON / empty error body — status alone carries the signal.\n }\n void token;\n return { ok: false, status: res.status, message };\n }\n const json = await res.json();\n const applied = unwrapCart(json);\n applyCart(applied);\n // Token was actually consumed on entry; applyCart enforces ordering\n // via the closure below.\n void token;\n // Hand the written cart back in the SDK's public convention (MAJOR units —\n // applyCart normalizes for state separately) so callers like addItem can\n // read the added line's price without racing React state.\n return { ok: true, status: res.status, cart: normalizeCartFromServer(applied) };\n}\n\nexport function NuMuProvider({\n store,\n themeSettings,\n initialCart,\n customer,\n locale: initialLocale,\n translations: initialTranslations,\n currentTemplate = \"home\",\n pageTemplate,\n initialProducts,\n initialCollections,\n navigation,\n children,\n}: NuMuProviderProps) {\n // Synthesise a Page record so `useProducts()` and `useCollections()`\n // can read pre-fetched lists via PageContext. Stable identity ensures\n // we don't bust the context on every render (initialProducts and\n // initialCollections come in as fresh arrays from the host's\n // useMemo'd ctx, so referential equality already holds across renders\n // without changes; useMemo here is belt-and-suspenders).\n const pageValue = useMemo(\n () =>\n ({\n type: currentTemplate,\n title: store?.name ?? \"\",\n // I3 — resolved alternate template key (e.g. \"product.wholesale\"),\n // surfaced via usePage()?.template. Omitted when undefined so a\n // page on its default template exposes no `template` field.\n ...(pageTemplate ? { template: pageTemplate } : {}),\n data: {\n products: initialProducts ?? [],\n collections: initialCollections ?? [],\n },\n }) as import(\"../types/entities\").Page,\n [currentTemplate, pageTemplate, store?.name, initialProducts, initialCollections],\n );\n const [cart, setCart] = useState<Cart>(\n initialCart || { ...EMPTY_CART, currency: store.currency },\n );\n // `loading` starts TRUE when the cart is NOT hydrated (no initialCart): the\n // cart is EMPTY_CART only because the on-mount GET /api/cart hasn't landed\n // yet, NOT because the cart is genuinely empty. Without this, a returning\n // shopper's cart page flashed \"YOUR CART IS EMPTY\" for the fetch window\n // (themes gate their empty state on `loading` — see cart sections). Cleared\n // in the initial-fetch effect's finally. When the host hydrates `initialCart`\n // (SSR), the cart is already known → not loading.\n const [loading, setLoading] = useState(!initialCart);\n // Phase 3.6 — locale precedence:\n // 1. `initialLocale` prop (storefront pages that resolved it server-side)\n // 2. `numu_locale` cookie (client-side fallback for pages that don't\n // thread the prop through)\n // 3. `store.default_language`\n // 4. \"en\"\n const [locale, setLocale] = useState(() => {\n if (initialLocale) return initialLocale;\n if (typeof document !== \"undefined\") {\n const m = document.cookie.match(/(?:^|; )numu_locale=([^;]+)/);\n if (m) return decodeURIComponent(m[1]);\n }\n return store.default_language || \"en\";\n });\n const [translations] = useState(initialTranslations || {});\n\n // ── Customer state + auth actions ──────────────────────────────────────\n // Customer comes from one of three sources, in order of precedence:\n // 1. SSR-supplied `customer` prop (when /account/* routes pre-fetch\n // the customer server-side via the cookie).\n // 2. The mount effect below which calls GET /api/customer/me, used\n // on routes that don't pre-fetch (home/product/etc.) to keep the\n // cart drawer / header user menu accurate.\n // 3. Mutations triggered by `useCustomerActions()` (login/logout/\n // register/updateProfile) — these refresh state immediately.\n const [customerState, setCustomerState] = useState<Customer | null>(\n customer ?? null,\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n // Skip the GET if the SSR pass already supplied a customer; the\n // round-trip would only confirm what we already know and waste a\n // request budget on every navigation.\n if (customer) return;\n let cancelled = false;\n void (async () => {\n try {\n const res = await fetch(\"/api/customer/me\", {\n method: \"GET\",\n credentials: \"include\",\n cache: \"no-store\",\n });\n if (cancelled) return;\n // 401 means logged-out: leave customerState=null. Any other\n // non-OK is treated the same — the customer can still browse.\n if (!res.ok) return;\n const json = await res.json();\n const next =\n json && typeof json === \"object\" && \"data\" in json\n ? (json as { data: Customer }).data\n : (json as Customer);\n if (next && typeof next === \"object\") {\n setCustomerState(next);\n }\n } catch {\n // Network blip — keep current customerState.\n }\n })();\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Refresh re-fetches /api/customer/me; used after any mutation that\n // changed the customer record (login/register/profile update).\n const refreshCustomer = useCallback(async () => {\n if (typeof window === \"undefined\") return;\n try {\n const res = await fetch(\"/api/customer/me\", {\n method: \"GET\",\n credentials: \"include\",\n cache: \"no-store\",\n });\n if (res.status === 401) {\n setCustomerState(null);\n return;\n }\n if (!res.ok) return;\n const json = await res.json();\n const next =\n json && typeof json === \"object\" && \"data\" in json\n ? (json as { data: Customer }).data\n : (json as Customer);\n setCustomerState(next ?? null);\n } catch {\n // ignore\n }\n }, []);\n\n // CSRF: customer mutations echo `numu_csrf` cookie value as header\n // for double-submit. Read just-in-time so we always send the freshest\n // (the cookie may rotate on /api/cart roundtrip).\n function readCsrf(): string | null {\n if (typeof document === \"undefined\") return null;\n const m = document.cookie.match(/(?:^|; )numu_csrf=([^;]+)/);\n return m ? decodeURIComponent(m[1]) : null;\n }\n\n async function postCustomer(path: string, body: unknown): Promise<unknown> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n const csrf = readCsrf();\n if (csrf) headers[\"x-numu-csrf\"] = csrf;\n const res = await fetch(path, {\n method: \"POST\",\n credentials: \"include\",\n cache: \"no-store\",\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n let json: unknown = null;\n try {\n json = await res.json();\n } catch {\n // empty body — fine\n }\n return json;\n }\n\n async function putCustomer(path: string, body: unknown): Promise<unknown> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n const csrf = readCsrf();\n if (csrf) headers[\"x-numu-csrf\"] = csrf;\n const res = await fetch(path, {\n method: \"PUT\",\n credentials: \"include\",\n cache: \"no-store\",\n headers,\n body: JSON.stringify(body ?? {}),\n });\n try {\n return await res.json();\n } catch {\n return null;\n }\n }\n\n const customerActions: CustomerActions = useMemo(\n () => ({\n login: async (input) => {\n const r = await postCustomer(\"/api/customer/login\", input);\n await refreshCustomer();\n return r;\n },\n register: async (input) => {\n const r = await postCustomer(\"/api/customer/register\", input);\n await refreshCustomer();\n return r;\n },\n logout: async () => {\n const r = await postCustomer(\"/api/customer/logout\", {});\n // Don't wait on refresh — backend cleared the cookie, so\n // setCustomerState(null) directly avoids a redundant 401.\n setCustomerState(null);\n return r;\n },\n requestRecover: (input) =>\n postCustomer(\"/api/customer/recover\", input),\n confirmReset: async (input) => {\n const r = await postCustomer(\"/api/customer/reset\", input);\n // Reset clears all sessions on the backend; user must log in\n // again. Force null so any stale state from before the reset\n // doesn't linger.\n setCustomerState(null);\n return r;\n },\n verifyEmail: async (input) => {\n const r = await postCustomer(\"/api/customer/verify-email\", input);\n await refreshCustomer();\n return r;\n },\n resendVerification: (input) =>\n postCustomer(\"/api/customer/resend-verification\", input),\n updateProfile: async (input) => {\n const r = await putCustomer(\"/api/customer/me\", input);\n await refreshCustomer();\n return r;\n },\n changePassword: (input) =>\n putCustomer(\"/api/customer/me/password\", input),\n refresh: refreshCustomer,\n }),\n [refreshCustomer],\n );\n\n // ── Initial cart fetch ─────────────────────────────────────────────────\n // GET /api/cart on mount serves two purposes:\n // 1. Hydrates the live cart state for returning visitors so the\n // header cart count is accurate before any user interaction.\n // 2. Mints the `numu_csrf` cookie (the storefront's GET /api/cart\n // handler emits Set-Cookie if missing). Subsequent cart-write\n // calls read this cookie via document.cookie and echo it as\n // the `x-numu-csrf` header for double-submit verification.\n // Without this priming round-trip, a first-Add-to-Cart 403s\n // because the cookie hasn't been issued yet.\n //\n // SSR-safe: `fetch` is a browser-only call here; we gate on `window`.\n // Errors are swallowed — the cart context starts empty either way,\n // and downstream actions surface their own errors.\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n let cancelled = false;\n void (async () => {\n try {\n const res = await fetch(\"/api/cart\", {\n method: \"GET\",\n credentials: \"include\",\n cache: \"no-store\",\n });\n if (!res.ok || cancelled) return;\n const json = await res.json();\n const data = unwrapCart(json);\n if (data && typeof data === \"object\") {\n setCart(normalizeCartFromServer(data));\n }\n } catch {\n // Network blip / not-yet-deployed cart endpoint. Leave the\n // empty initial cart in place; the user can still browse.\n } finally {\n // Initial cart load resolved (success OR failure): the cart state is\n // now authoritative, so drop the loading flag. Themes stop showing\n // their loading placeholder and reveal the real cart / empty state.\n if (!cancelled) setLoading(false);\n }\n })();\n return () => {\n cancelled = true;\n };\n // Run once per mount; the cart endpoint is idempotent and the\n // CSRF cookie persists across navigations within the SPA.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // ── Request-versioning machinery ───────────────────────────────────────\n // `nextRequestId` increases on each cart mutation; `latestApplied` tracks\n // the highest id whose response has been applied. A response is applied\n // only if its id is >= latestApplied (i.e., not superseded).\n const nextRequestId = useRef(0);\n const latestApplied = useRef(0);\n\n const reserveToken = useCallback(() => {\n nextRequestId.current += 1;\n return nextRequestId.current;\n }, []);\n\n const buildApplyCart = useCallback(\n (token: number) => (newCart: Cart) => {\n if (token < latestApplied.current) {\n // A later request has already updated state — ignore stale response.\n return;\n }\n latestApplied.current = token;\n setCart(normalizeCartFromServer(newCart));\n },\n [],\n );\n\n const mutate = useCallback(\n async (endpoint: string, body: unknown): Promise<CartMutationResult> => {\n const token = reserveToken();\n setLoading(true);\n try {\n return await postCartMutation(\n endpoint,\n body,\n buildApplyCart(token),\n () => token, // already reserved; just return the same token\n );\n } finally {\n setLoading(false);\n }\n },\n [reserveToken, buildApplyCart],\n );\n\n // ── Cart actions ───────────────────────────────────────────────────────\n\n const addItem = useCallback(\n async (\n productId: string,\n variantId?: string,\n quantity?: number,\n selectedOptions?: Record<string, string>,\n ): Promise<CartMutationResult> => {\n // Shared event id for Meta AddToCart dedup: the host /api/cart/add route\n // fires the CAPI event with this id, and the host <MetaPixel> bridge\n // fires the matching browser fbq from the CustomEvent below.\n const eventId =\n typeof crypto !== \"undefined\" && crypto.randomUUID\n ? crypto.randomUUID()\n : `${Date.now()}`;\n const qty = quantity || 1;\n // Picker axes — the backend uses them ONLY as a variant_name fallback\n // when the variant row can't name itself (legacy products keep axes in\n // attributes JSON with a placeholder variant whose option_values is {}).\n // Falls back to the live useVariantSelection state for this product so\n // themes calling addItem directly get the rule with no changes.\n const axes =\n selectedOptions && Object.keys(selectedOptions).length > 0\n ? selectedOptions\n : (readVariantSelection(productId) ?? undefined);\n const result = await mutate(\"/api/cart/add\", {\n product_id: productId,\n variant_id: variantId,\n quantity: qty,\n selected_options: axes,\n _event_id: eventId,\n });\n // Gate the AddToCart analytics on a SUCCESSFUL write. This previously\n // fired unconditionally, so an out-of-stock / validation / 403 rejection\n // still reported a phantom add_to_cart to Meta/GA and inflated the\n // funnel. On failure, return the result so the theme can react (toast,\n // \"out of stock\", …) without a spurious conversion event.\n if (!result.ok) return result;\n // Browser-side AddToCart signal — CAPI is fired server-side by the cart\n // route with the same id. Dispatched directly (not via useAnalytics) so\n // we control the event_id and avoid a duplicate /track POST.\n // value/currency (MAJOR units, from the written line's snapshot price)\n // make the event usable for value-based optimization + dynamic ads.\n try {\n if (typeof window !== \"undefined\") {\n const line = result.cart?.items.find((it) =>\n variantId ? it.variant_id === variantId : it.product_id === productId,\n );\n const value =\n line && typeof line.price === \"number\" && line.price > 0\n ? Math.round(line.price * qty * 100) / 100\n : undefined;\n window.dispatchEvent(\n new CustomEvent(\"numu:analytics:event\", {\n detail: {\n event: \"add_to_cart\",\n payload: {\n content_ids: [productId],\n content_type: \"product\",\n num_items: qty,\n ...(value !== undefined\n ? { value, currency: result.cart?.currency }\n : {}),\n },\n event_id: eventId,\n },\n }),\n );\n }\n } catch {\n /* CustomEvent unsupported — server CAPI still covers the event */\n }\n return result;\n },\n [mutate],\n );\n\n const removeItem = useCallback(\n (itemId: string) => mutate(\"/api/cart/remove\", { item_id: itemId }),\n [mutate],\n );\n\n const updateQuantity = useCallback(\n (itemId: string, quantity: number) =>\n mutate(\"/api/cart/update\", { item_id: itemId, quantity }),\n [mutate],\n );\n\n const applyDiscount = useCallback(\n (code: string) => mutate(\"/api/cart/discount\", { code }),\n [mutate],\n );\n\n const removeDiscount = useCallback(\n // DELETE — postCartMutation interprets undefined body as DELETE.\n () => mutate(\"/api/cart/discount\", undefined),\n [mutate],\n );\n\n /**\n * Persist a customer note on the cart. Round-trips to the backend so the\n * note survives reload (the previous local-only behavior was a footgun).\n */\n const updateNote = useCallback(\n (note: string) => mutate(\"/api/cart/update\", { note }),\n [mutate],\n );\n\n const clearCart = useCallback(async () => {\n setCart({ ...EMPTY_CART, currency: store.currency });\n }, [store.currency]);\n\n // Broadcast a `numu:cart:updated` CustomEvent on every cart change.\n // Why: non-React themes (vanilla JS / Alpine / Vue islands) can't\n // consume `useCart()`. They listen on `window` instead, which gives\n // them the same write-then-react contract React themes get for free.\n // The event detail mirrors the React `cart` shape so consumers don't\n // need to re-fetch.\n //\n // We skip the first dispatch — the initial state is the empty\n // placeholder before the GET /api/cart response lands, and themes\n // that ran their own `numu:cart:fetched`-style logic on page load\n // would otherwise see a spurious empty event right after rendering.\n const cartFirstRender = useRef(true);\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n if (cartFirstRender.current) {\n cartFirstRender.current = false;\n return;\n }\n window.dispatchEvent(\n new CustomEvent(\"numu:cart:updated\", { detail: cart }),\n );\n }, [cart]);\n\n const cartValue = useMemo(\n () => ({\n cart,\n addItem,\n removeItem,\n updateQuantity,\n applyDiscount,\n removeDiscount,\n updateNote,\n clearCart,\n loading,\n }),\n [\n cart,\n addItem,\n removeItem,\n updateQuantity,\n applyDiscount,\n removeDiscount,\n updateNote,\n clearCart,\n loading,\n ],\n );\n\n // ── Localization with memoized Intl formatters ─────────────────────────\n // Building Intl.NumberFormat / Intl.DateTimeFormat per call is costly;\n // memoize on (locale, currency).\n //\n // Resilience: stores can come back from older API rows with `currency`\n // null/empty. `Intl.NumberFormat({ currency: \"\" })` throws \"Currency\n // code is required with currency style\", which crashes the entire\n // render tree. Fall back to USD for the formatter so themes keep\n // working — merchants will see prices in USD until they configure a\n // real currency, which is a clearer signal than a blank screen.\n const safeCurrency = (store.currency || \"USD\").toUpperCase();\n\n // Phase 3.7 — numeral system. Merchants opt into Arab-Indic\n // digits (٠١٢٣٤) for Arabic stores via store.settings.numerals.\n // Western (default) keeps the ASCII digits everyone's used to.\n // We construct intl locales with the appropriate `-u-nu-<system>`\n // extension so money + date + count formatters all stay consistent.\n const numeralSystem =\n ((store as unknown as { settings?: { numerals?: string } }).settings\n ?.numerals === \"arabic\")\n ? \"arab\"\n : \"latn\";\n const intlLocale = `${locale}-u-nu-${numeralSystem}`;\n\n // We deliberately compute intlLocale BEFORE these memos so the\n // numbering-system extension is part of the formatter cache key —\n // a merchant flipping store.settings.numerals from \"western\" to\n // \"arabic\" rebuilds the formatters on the next render rather than\n // continuing to render Western digits from the stale cache.\n const moneyFmt = useMemo(() => {\n try {\n return new Intl.NumberFormat(intlLocale, {\n style: \"currency\",\n currency: safeCurrency,\n });\n } catch {\n // Pathologic intlLocale (engine doesn't support `-u-nu-arab`\n // for the active language) — fall back to the bare locale.\n return new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency: safeCurrency,\n });\n }\n }, [intlLocale, locale, safeCurrency]);\n const dateFmt = useMemo(() => {\n try {\n return new Intl.DateTimeFormat(intlLocale, {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n });\n } catch {\n return new Intl.DateTimeFormat(locale, {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n });\n }\n }, [intlLocale, locale]);\n\n // Phase 3.6 — locales the store advertises. Falls back to a single-\n // entry list (the active locale) so themes can render the\n // LocaleSwitcher unconditionally without an extra check.\n const availableLocales = useMemo(() => {\n const list =\n (store as unknown as { available_locales?: string[] }).available_locales;\n if (Array.isArray(list) && list.length > 0) return list;\n return [locale];\n }, [store, locale]);\n\n // Phase 3.6 — locale switcher. Writes the cookie + reloads so the\n // server-rendered layout picks up the change. We prefer cookie over\n // querystring because cookie persists across cross-page navigation\n // without each page having to thread `?locale=ar` through every link.\n const switchLocale = useCallback((next: string) => {\n if (typeof document === \"undefined\") return;\n if (!next) return;\n // 1-year cookie; SameSite=Lax so it travels with same-origin nav\n // but doesn't leak on cross-site requests. Path=/ so every page\n // sees it.\n document.cookie =\n `numu_locale=${encodeURIComponent(next)}; ` +\n `Path=/; Max-Age=${60 * 60 * 24 * 365}; SameSite=Lax`;\n setLocale(next);\n // Reload so SSR re-runs with the new cookie. Themes that want\n // client-only locale swaps (no SSR re-render) can wrap their text\n // in `useTranslation()` and skip the reload — but locale-aware\n // SSR data (translated product names, RTL <html dir>) needs the\n // reload to take effect.\n if (typeof window !== \"undefined\") {\n window.location.reload();\n }\n }, []);\n\n // Default (no-options) number formatter — memoized so the formatNumber\n // hot path doesn't construct one per call. Declared BEFORE the\n // localization useMemo so the closure captures the resolved value.\n const defaultNumberFmt = useMemo(() => {\n try {\n return new Intl.NumberFormat(intlLocale);\n } catch {\n return new Intl.NumberFormat(locale);\n }\n }, [intlLocale, locale]);\n\n const localization: LocalizationState = useMemo(\n () => ({\n locale,\n direction: RTL_LOCALES.includes(locale) ? \"rtl\" : \"ltr\",\n translations,\n availableLocales,\n setLocale: switchLocale,\n formatMoney: (amount: number, currency?: string) => {\n const ccy = (currency || safeCurrency).toUpperCase();\n if (ccy !== safeCurrency) {\n // Override-currency path is rare; pay the formatter cost only here.\n // Empty/invalid override falls back to the store's safeCurrency\n // before this branch via the `||` above, so we never construct\n // an Intl.NumberFormat with `currency: \"\"`.\n try {\n return new Intl.NumberFormat(intlLocale, {\n style: \"currency\",\n currency: ccy,\n }).format(amount);\n } catch {\n return moneyFmt.format(amount);\n }\n }\n return moneyFmt.format(amount);\n },\n formatDate: (date: string | Date) =>\n dateFmt.format(typeof date === \"string\" ? new Date(date) : date),\n formatNumber: (n: number, options?: Intl.NumberFormatOptions) => {\n if (!options) return defaultNumberFmt.format(n);\n try {\n return new Intl.NumberFormat(intlLocale, options).format(n);\n } catch {\n return String(n);\n }\n },\n }),\n [\n locale,\n translations,\n safeCurrency,\n moneyFmt,\n dateFmt,\n availableLocales,\n switchLocale,\n intlLocale,\n defaultNumberFmt,\n ],\n );\n\n // ── Multi-currency presentment (fetched ONCE here) ─────────────────────\n // Lifted out of useCurrency() so a single fetch + a single selection back\n // EVERY <Money>/useMoney()/<CurrencySwitcher> on the page. Before this, each\n // useCurrency() caller fetched its own copy and held selection in local\n // state, so a <CurrencySwitcher> change never reached the price tags.\n const [currencyConfig, setCurrencyConfig] = useState<CurrencyConfig | null>(\n null,\n );\n const [currencyLoading, setCurrencyLoading] = useState(true);\n // Empty until the fetch resolves cookie→default→base. Starts empty on BOTH\n // server and client so the first client render matches the server markup\n // (hydration-safe); the effect sets the real value AFTER mount, and any\n // resulting price re-format is a post-hydration update.\n const [currencySelected, setCurrencySelected] = useState<string>(\"\");\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n let cancelled = false;\n void (async () => {\n try {\n const res = await fetch(\"/api/storefront/currencies\", {\n credentials: \"include\",\n headers: { Accept: \"application/json\" },\n });\n if (!res.ok) throw new Error(`currencies: HTTP ${res.status}`);\n const body = (await res.json()) as { data: CurrencyConfig };\n if (cancelled) return;\n setCurrencyConfig(body.data);\n // cookie → default_presentment → base, validated against presentment\n // so a stale cookie can't lock the visitor onto a removed currency.\n const cookie = readCurrencyCookie();\n const valid =\n cookie && body.data.presentment?.includes(cookie) ? cookie : null;\n setCurrencySelected(\n valid || body.data.default_presentment || body.data.base,\n );\n } catch {\n if (cancelled) return;\n setCurrencyConfig(null);\n setCurrencySelected(store.currency || \"EGP\");\n } finally {\n if (!cancelled) setCurrencyLoading(false);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [store.id, store.currency]);\n\n const currencyRates = useMemo<Record<string, number>>(() => {\n const out: Record<string, number> = {};\n if (!currencyConfig) return out;\n for (const [k, v] of Object.entries(currencyConfig.rates)) {\n const n = Number.parseFloat(v);\n if (Number.isFinite(n)) out[k] = n;\n }\n return out;\n }, [currencyConfig]);\n\n const convertCurrency = useCallback(\n (cents: number, target?: string): number => {\n if (!currencyConfig) return cents;\n const to = target || currencySelected;\n if (!to || to === currencyConfig.base) return cents;\n const rate = currencyRates[to];\n if (!rate || !Number.isFinite(rate)) return cents;\n return Math.round(cents * rate);\n },\n [currencyConfig, currencyRates, currencySelected],\n );\n\n const setCurrency = useCallback((currency: string) => {\n setCurrencySelected(currency);\n writeCurrencyCookie(currency);\n }, []);\n\n const currencyValue = useMemo<CurrencyState>(\n () => ({\n base: currencyConfig?.base || store.currency || \"EGP\",\n selected:\n currencySelected || currencyConfig?.base || store.currency || \"EGP\",\n presentment: currencyConfig?.presentment || [store.currency || \"EGP\"],\n rates: currencyRates,\n autoConvert: Boolean(currencyConfig?.auto_convert),\n loading: currencyLoading,\n setSelected: setCurrency,\n convert: convertCurrency,\n }),\n [\n currencyConfig,\n currencySelected,\n currencyRates,\n currencyLoading,\n store.currency,\n setCurrency,\n convertCurrency,\n ],\n );\n\n return (\n <ShopContext.Provider value={store}>\n <ThemeSettingsContext.Provider value={themeSettings}>\n <CurrentTemplateContext.Provider value={currentTemplate}>\n <PageContext.Provider value={pageValue}>\n <LocalizationContext.Provider value={localization}>\n <CurrencyContext.Provider value={currencyValue}>\n <CartContext.Provider value={cartValue}>\n <CustomerContext.Provider value={customerState}>\n <CustomerActionsContext.Provider value={customerActions}>\n <NavigationContext.Provider value={navigation ?? {}}>\n {children}\n </NavigationContext.Provider>\n </CustomerActionsContext.Provider>\n </CustomerContext.Provider>\n </CartContext.Provider>\n </CurrencyContext.Provider>\n </LocalizationContext.Provider>\n </PageContext.Provider>\n </CurrentTemplateContext.Provider>\n </ThemeSettingsContext.Provider>\n </ShopContext.Provider>\n );\n}\n","\"use client\";\nimport type { ReactNode } from \"react\";\nimport { ProductContext } from \"../contexts\";\nimport type { Product } from \"../types/entities\";\n\ninterface ProductProviderProps {\n product: Product;\n children: ReactNode;\n}\n\nexport function ProductProvider({ product, children }: ProductProviderProps) {\n return <ProductContext.Provider value={product}>{children}</ProductContext.Provider>;\n}\n","\"use client\";\nimport type { ReactNode } from \"react\";\nimport { CollectionContext } from \"../contexts\";\nimport type { Collection } from \"../types/entities\";\n\ninterface CollectionProviderProps {\n collection: Collection;\n children: ReactNode;\n}\n\nexport function CollectionProvider({ collection, children }: CollectionProviderProps) {\n return <CollectionContext.Provider value={collection}>{children}</CollectionContext.Provider>;\n}\n","/**\n * Engine-level logo appearance (shape + size).\n *\n * A merchant can crop the store logo into a shape and pick its size from the\n * theme editor's global settings (`logo_shape` / `logo_size`). The logic lives\n * here — once, in the SDK — so EVERY V3 theme renders the chosen shape the same\n * way instead of each theme re-implementing it.\n *\n * Why inline styles (not Tailwind classes): the SDK is consumed from\n * `node_modules`, which a theme's Tailwind build does not scan — so utility\n * classes like `rounded-full` / `h-16` would never be generated. Inline\n * `CSSProperties` are self-contained and work in any theme regardless of its\n * CSS setup. The shapes are pure CSS (border-radius / clip-path) applied to a\n * plain `<img>`, so animated **GIF logos keep playing** under every shape.\n */\n\nimport type { CSSProperties } from \"react\";\n\nexport type LogoShape = \"none\" | \"square\" | \"rounded\" | \"circle\" | \"triangle\";\nexport type LogoSize = \"small\" | \"medium\" | \"large\";\n\n/** Bilingual options for the `logo_shape` global setting (schema authoring). */\nexport const LOGO_SHAPE_OPTIONS = [\n { value: \"none\", label: \"Original\", label_ar: \"الأصلي\" },\n { value: \"square\", label: \"Square\", label_ar: \"مربع\" },\n { value: \"rounded\", label: \"Rounded square\", label_ar: \"مربع بزوايا دائرية\" },\n { value: \"circle\", label: \"Circle\", label_ar: \"دائرة\" },\n { value: \"triangle\", label: \"Triangle\", label_ar: \"مثلث\" },\n] as const;\n\n/** Bilingual options for the `logo_size` global setting (schema authoring). */\nexport const LOGO_SIZE_OPTIONS = [\n { value: \"small\", label: \"Small\", label_ar: \"صغير\" },\n { value: \"medium\", label: \"Medium\", label_ar: \"متوسط\" },\n { value: \"large\", label: \"Large\", label_ar: \"كبير\" },\n] as const;\n\n// Box edge length (px) for a shaped logo. Circle/rounded only reveal the\n// inscribed area, so they read smaller than a square/triangle at the same box —\n// they get a larger frame to stay legible.\nconst SHAPED_PX: Record<LogoSize, { plain: number; rounded: number }> = {\n small: { plain: 32, rounded: 48 },\n medium: { plain: 40, rounded: 64 },\n large: { plain: 56, rounded: 80 },\n};\n\nfunction normalizeSize(size: string | undefined): LogoSize {\n return size === \"large\" || size === \"medium\" ? size : \"small\";\n}\n\n/**\n * Inline style for a logo `<img>` given the merchant's shape + size.\n *\n * Returns `undefined` for `none` (and unknown shapes) so the theme keeps its\n * own native logo sizing untouched — only an explicitly chosen shape overrides\n * it. A shaped logo gets a fixed square box with `object-fit: cover` plus the\n * shape (border-radius for square/rounded/circle, clip-path for triangle).\n */\nexport function logoImgStyle(\n shape: string | undefined,\n size: string | undefined,\n): CSSProperties | undefined {\n if (!shape || shape === \"none\") return undefined;\n\n const s = normalizeSize(size);\n const isRound = shape === \"circle\" || shape === \"rounded\";\n const px = isRound ? SHAPED_PX[s].rounded : SHAPED_PX[s].plain;\n const base: CSSProperties = {\n height: px,\n width: px,\n objectFit: \"cover\",\n flex: \"0 0 auto\",\n };\n\n switch (shape) {\n case \"circle\":\n return { ...base, borderRadius: \"9999px\" };\n case \"rounded\":\n return { ...base, borderRadius: \"0.5rem\" };\n case \"triangle\":\n return { ...base, clipPath: \"polygon(50% 0%, 100% 100%, 0% 100%)\" };\n case \"square\":\n default:\n return base;\n }\n}\n\n/**\n * Derived CSS-custom-property tokens for the chosen logo shape/size. Emitted by\n * `computeGlobalStyleTokens` so host-rendered surfaces (e.g. the checkout\n * header) can match the storefront logo. Returns `{}` for `none`.\n */\nexport function logoStyleTokens(\n shape: string | undefined,\n size: string | undefined,\n): Record<string, string> {\n const style = logoImgStyle(shape, size);\n if (!style) return {};\n const box = `${style.height as number}px`;\n return {\n \"--theme-logo-box\": box,\n \"--theme-logo-radius\":\n typeof style.borderRadius === \"string\" ? style.borderRadius : \"0\",\n \"--theme-logo-clip\":\n typeof style.clipPath === \"string\" ? style.clipPath : \"none\",\n };\n}\n","/**\n * `applyGlobalStyleTokens(globalSettings, el)` — Phase 3.5.\n *\n * Bridges a store's **global theme settings** (colors, fonts, layout) to\n * **CSS custom properties** on the bundle's mount root, so editing a color\n * or font in Theme Settings actually re-paints the storefront. Before this,\n * themes shipped static CSS tokens that nothing wrote to → the pickers were\n * a silent no-op.\n *\n * ## Token contract (canonical names every theme can rely on)\n *\n * For each global setting `<id>` we set `--theme-<id>` verbatim (colors as\n * their value, fonts resolved to a CSS font stack, other scalars as-is).\n * Themes consume these with the current static value as a fallback:\n *\n * --by-cream: var(--theme-background_color, #f7f1e8);\n * --by-espresso: var(--theme-primary_color, #3a2418);\n * --by-font-serif: var(--theme-heading_font, \"Cormorant Garamond\", serif);\n *\n * In addition, well-known ids are aliased to **role** tokens so themes that\n * prefer semantic names share one vocabulary:\n *\n * colors → --theme-color-{background,text,primary,secondary,accent,border,button}\n * fonts → --theme-font-{heading,body}\n *\n * `color_scheme` / `color_scheme_group` settings (object values keyed by role)\n * emit `--scheme-<id>-<role>`.\n *\n * The helper is **idempotent** and safe to call on every `applyDraft` so the\n * customizer's live preview re-paints as the merchant drags a color.\n */\n\nimport { logoStyleTokens } from \"./logoStyle\";\n\ntype GlobalSettings = Record<string, unknown> | null | undefined;\n\n/** id → canonical color role. Covers both `<role>_color` and `color_<role>`. */\nconst COLOR_ROLE_ALIASES: Record<string, string> = {\n background_color: \"background\",\n color_background: \"background\",\n bg_color: \"background\",\n text_color: \"text\",\n color_text: \"text\",\n primary_color: \"primary\",\n color_primary: \"primary\",\n secondary_color: \"secondary\",\n color_secondary: \"secondary\",\n accent_color: \"accent\",\n color_accent: \"accent\",\n border_color: \"border\",\n color_border: \"border\",\n button_color: \"button\",\n color_button: \"button\",\n button_text_color: \"button-text\",\n color_button_text: \"button-text\",\n};\n\n/** id → canonical font role. */\nconst FONT_ROLE_ALIASES: Record<string, string> = {\n heading_font: \"heading\",\n font_heading: \"heading\",\n headings_font: \"heading\",\n body_font: \"body\",\n font_body: \"body\",\n text_font: \"body\",\n};\n\n/**\n * Font token → CSS stack + optional Google Fonts href. A `font_picker`/select\n * stores a token (e.g. \"cormorant\"); we resolve it to a real stack and inject\n * the webfont so a picked font actually loads. Unknown tokens fall through and\n * are used verbatim as the family (so a theme can store a raw stack too).\n */\nconst FONT_REGISTRY: Record<string, { stack: string; href?: string }> = {\n cormorant: {\n stack: '\"Cormorant Garamond\", Georgia, \"Times New Roman\", serif',\n href: \"https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap\",\n },\n \"dm-sans\": {\n stack: '\"DM Sans\", system-ui, -apple-system, \"Segoe UI\", sans-serif',\n href: \"https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,700&display=swap\",\n },\n playfair: {\n stack: '\"Playfair Display\", Georgia, serif',\n href: \"https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700&display=swap\",\n },\n inter: {\n stack: '\"Inter\", system-ui, -apple-system, sans-serif',\n href: \"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap\",\n },\n poppins: {\n stack: '\"Poppins\", system-ui, sans-serif',\n href: \"https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap\",\n },\n montserrat: {\n stack: '\"Montserrat\", system-ui, sans-serif',\n href: \"https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700&display=swap\",\n },\n lora: {\n stack: '\"Lora\", Georgia, serif',\n href: \"https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,500;0,600;1,400&display=swap\",\n },\n cairo: {\n stack: '\"Cairo\", system-ui, sans-serif',\n href: \"https://fonts.googleapis.com/css2?family=Cairo:wght@400;500;600;700&display=swap\",\n },\n tajawal: {\n stack: '\"Tajawal\", system-ui, sans-serif',\n href: \"https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700&display=swap\",\n },\n};\n\nconst COLOR_RE = /^(#([0-9a-f]{3,8})|rgba?\\(|hsla?\\(|color\\(|var\\()/i;\n\nfunction isColorValue(v: unknown): v is string {\n return typeof v === \"string\" && COLOR_RE.test(v.trim());\n}\n\nfunction isFontToken(v: unknown): v is string {\n return typeof v === \"string\" && Object.prototype.hasOwnProperty.call(FONT_REGISTRY, v);\n}\n\n/** Idempotently inject a webfont <link> into <head>. */\nfunction injectFontLink(href: string): void {\n if (typeof document === \"undefined\" || !href) return;\n const existing = document.querySelector(\n `link[data-numu-font][href=\"${href}\"]`,\n );\n if (existing) return;\n const link = document.createElement(\"link\");\n link.rel = \"stylesheet\";\n link.href = href;\n link.setAttribute(\"data-numu-font\", \"\");\n document.head.appendChild(link);\n}\n\n/** Pure registry lookup — no webfont injection. */\nfunction lookupFontStack(value: string): string {\n return FONT_REGISTRY[value]?.stack ?? value;\n}\n\n/**\n * Resolve a font setting value to a CSS stack. Known tokens map through the\n * registry (and load the webfont); anything else is treated as a literal\n * family/stack the theme author supplied.\n */\nexport function resolveFontStack(value: string): string {\n const entry = FONT_REGISTRY[value];\n if (entry) {\n if (entry.href) injectFontLink(entry.href);\n return entry.stack;\n }\n return value;\n}\n\n/** Result of `computeGlobalStyleTokens` — everything a host needs to paint\n * global settings without a DOM. */\nexport interface ComputedStyleTokens {\n /** CSS custom properties to set on the theme's mount root. */\n cssVars: Record<string, string>;\n /** Google-Fonts stylesheet hrefs for any registry fonts in use. */\n fontHrefs: string[];\n}\n\n/**\n * Pure half of `applyGlobalStyleTokens`: compute the exact CSS custom\n * properties (and webfont hrefs) a settings object maps to, without touching\n * any DOM. This is what lets a host SERVER-render a theme with the same vars\n * the bundle applies on mount — both sides call this one function, so the\n * values cannot drift (drift = unstyled flash or hydration noise).\n *\n * Includes the explicit `heading_font` / `body_font` resolution that\n * `mountTheme` historically layered on top: any string value for those two\n * ids resolves through the registry (or passes verbatim) so a picked font\n * gets a real stack even when it isn't a known token.\n */\nexport function computeGlobalStyleTokens(\n globalSettings: GlobalSettings,\n): ComputedStyleTokens {\n const cssVars: Record<string, string> = {};\n const fontHrefs: string[] = [];\n if (!globalSettings || typeof globalSettings !== \"object\") {\n return { cssVars, fontHrefs };\n }\n\n const pushHref = (href?: string) => {\n if (href && !fontHrefs.includes(href)) fontHrefs.push(href);\n };\n\n for (const [key, value] of Object.entries(globalSettings)) {\n if (!key || key.startsWith(\"__\")) continue;\n\n // color_scheme / color_scheme_group → object of role:color\n if (value && typeof value === \"object\" && !Array.isArray(value)) {\n for (const [role, c] of Object.entries(value as Record<string, unknown>)) {\n if (isColorValue(c)) cssVars[`--scheme-${key}-${role}`] = c;\n }\n continue;\n }\n\n if (isColorValue(value)) {\n cssVars[`--theme-${key}`] = value.trim();\n const role = COLOR_ROLE_ALIASES[key];\n if (role) cssVars[`--theme-color-${role}`] = value.trim();\n continue;\n }\n\n if (isFontToken(value)) {\n const entry = FONT_REGISTRY[value];\n cssVars[`--theme-${key}`] = entry.stack;\n const role = FONT_ROLE_ALIASES[key];\n if (role) cssVars[`--theme-font-${role}`] = entry.stack;\n pushHref(entry.href);\n continue;\n }\n\n // Plain scalar (layout values like page_width \"1240px\", spacing, etc.).\n if (typeof value === \"string\" || typeof value === \"number\") {\n const v = String(value).trim();\n if (v) cssVars[`--theme-${key}`] = v;\n }\n }\n\n // Explicit heading/body resolution (formerly done by mountTheme's effect):\n // non-registry font names fall through the scalar branch verbatim above;\n // these two ids always get the resolved stack + webfont.\n for (const id of [\"heading_font\", \"body_font\"] as const) {\n const value = (globalSettings as Record<string, unknown>)[id];\n if (typeof value === \"string\" && value.trim()) {\n cssVars[`--theme-${id}`] = lookupFontStack(value);\n pushHref(FONT_REGISTRY[value]?.href);\n }\n }\n\n // Derived logo shape/size tokens (--theme-logo-box / -radius / -clip) so\n // host-rendered surfaces (e.g. the checkout header) can mirror the storefront\n // logo. No-op unless `logo_shape` is an actual shape.\n const gs = globalSettings as Record<string, unknown>;\n const logoTokens = logoStyleTokens(\n typeof gs.logo_shape === \"string\" ? gs.logo_shape : undefined,\n typeof gs.logo_size === \"string\" ? gs.logo_size : undefined,\n );\n for (const [k, v] of Object.entries(logoTokens)) cssVars[k] = v;\n\n return { cssVars, fontHrefs };\n}\n\n/**\n * Map a store's global settings onto CSS custom properties on `el`. Call on\n * mount and on every `applyDraft` (live preview). No-op when `el` or the\n * settings are missing. Reserved `__`-prefixed keys (e.g. `__translations`)\n * are skipped. Thin DOM shell over `computeGlobalStyleTokens`.\n */\nexport function applyGlobalStyleTokens(\n globalSettings: GlobalSettings,\n el: HTMLElement | null | undefined,\n): void {\n if (!el || !globalSettings || typeof globalSettings !== \"object\") return;\n const { cssVars, fontHrefs } = computeGlobalStyleTokens(globalSettings);\n const style = el.style;\n for (const [prop, value] of Object.entries(cssVars)) {\n style.setProperty(prop, value);\n }\n for (const href of fontHrefs) injectFontLink(href);\n}\n","\"use client\";\n\n/**\n * `mountTheme(el, ctx, renderApp)` — the canonical V3 bundle entry helper.\n *\n * ## Why this exists\n *\n * Every theme bundle exports `mount(el, ctx): MountResult`. Historically each\n * theme hand-wrote that function, and the wiring it needs is non-trivial and\n * easy to get wrong:\n *\n * 1. **Forward the real catalog.** The host ships the page's products /\n * collections in `ctx.page.data` (home + listing routes) and the product\n * in `ctx.page.data.product` (PDP). A theme that doesn't pass these into\n * `NuMuProvider` (+ wrap the PDP in `<ProductProvider>`) sees\n * `useProducts()` / `useProductOptional()` return empty on a REAL store —\n * so product sections render \"No products yet\" or fall back to demo data\n * on a stocked merchant. This was the single most common BYOT bug:\n * only bon-younes wired it; the other 13 themes dropped the catalog.\n *\n * 2. **Apply global style tokens.** Merchant-chosen colors/fonts live in\n * `themeSettings.global_settings`; they only paint if the bundle calls\n * `applyGlobalStyleTokens` on its mount root (and resolves font tokens\n * to real stacks + injects the webfont link). Themes that skipped this\n * ignored every color/font picker.\n *\n * 3. **Forward navigation.** `useNavigation(handle)` only resolves the\n * header/footer menus the host pre-resolved if the bundle passes\n * `ctx.navigation` into `NuMuProvider`.\n *\n * 4. **Live-preview + lifecycle.** The customizer streams draft settings via\n * the host's `applyDraft`; the bundle must hold them in state and re-paint\n * the style tokens on every draft. And it must return a `MountResult`\n * (`cleanup` + `applyDraft`) the host's `ByotThemeBoundary` understands.\n *\n * `mountTheme` does all of that once, so a theme's `main.tsx` collapses to:\n *\n * ```tsx\n * import { mountTheme } from \"@numueg/theme-sdk\";\n * export function mount(el, ctx) {\n * return mountTheme(el, ctx, ({ currentTemplate }) =>\n * <ThemeApp currentTemplate={currentTemplate} />,\n * );\n * }\n * ```\n *\n * The theme owns only its section list (`ThemeApp`). Everything in the list\n * above is handled here — fix it once, every theme benefits.\n *\n * ## Both ctx shapes\n *\n * The host (numu-storefront `ByotThemeBoundary`) passes\n * `{ themeSettings, storeData, page, locale, demo, navigation }`. Older / dev\n * contexts used `{ store, currentTemplate }`. We normalise both so a bundle\n * built against this helper works regardless of which host calls it.\n */\n\nimport {\n StrictMode,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useState,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { createRoot, hydrateRoot, type Root } from \"react-dom/client\";\n\nimport { NuMuProvider } from \"./components/NuMuProvider\";\nimport { ProductProvider } from \"./components/ProductProvider\";\nimport { CollectionProvider } from \"./components/CollectionProvider\";\nimport { applyGlobalStyleTokens } from \"./utils/styleTokens\";\nimport type {\n Store,\n Cart,\n Customer,\n Product,\n Collection,\n} from \"./types/entities\";\nimport type { ThemeSettingsV3, MountResult } from \"./types/theme\";\nimport type { MenuItemData } from \"./contexts\";\n\n/** Minimal page descriptor the host forwards in the mount context. */\nexport interface ThemeMountPage {\n type?: string;\n handle?: string;\n title?: string;\n data?: Record<string, unknown>;\n /**\n * Resolved alternate template key for this page (e.g. `\"product.wholesale\"`)\n * when the storefront routed it to a template suffix. `mountTheme` forwards\n * it to `NuMuProvider` so a theme reads it via `usePage()?.template`. Absent\n * for pages on their default template. Additive/optional.\n */\n template?: string;\n}\n\n/**\n * The mount context a host (or dev harness) passes to a bundle's `mount`.\n * Accepts both the current storefront shape (`storeData`/`page`) and the\n * legacy/dev shape (`store`/`currentTemplate`); `mountTheme` normalises them.\n */\nexport interface ThemeMountContext {\n // Current storefront contract\n storeData?: Store;\n page?: ThemeMountPage;\n // Legacy / dev contract\n store?: Store;\n currentTemplate?: string;\n // Common\n themeSettings: ThemeSettingsV3;\n initialCart?: Cart;\n customer?: Customer | null;\n locale?: string;\n translations?: Record<string, string>;\n /** AUTHORITATIVE marketplace-preview flag from the host (true only for the\n * catalog \"Try theme\" preview). Themes with demo-image fallbacks gate on\n * it so a real installed store never shows demo imagery. */\n demo?: boolean;\n /** Store navigation menus keyed by handle, resolved server-side. */\n navigation?: Record<string, MenuItemData[]>;\n /**\n * Host signal that the container already holds server-rendered HTML for\n * this exact ctx (produced via `createApp` from `defineThemeEntry`).\n * `mountTheme` then adopts it with `hydrateRoot` instead of re-rendering\n * from scratch. Ignored when the container is empty, so a host can pass\n * it optimistically and still get a plain client mount on SSR failure.\n */\n hydrate?: boolean;\n [extra: string]: unknown;\n}\n\n/** Arguments handed to a theme's render callback on every (re)render. */\nexport interface ThemeRenderArgs {\n /** Active template key — \"home\" | \"product\" | \"collection\" | \"cart\" | … */\n currentTemplate: string;\n /** Marketplace-preview flag (see ThemeMountContext.demo). */\n demo: boolean;\n /** The raw host page descriptor (type/handle/data), or null. */\n page: ThemeMountPage | null;\n /** Normalised store record (never undefined). */\n store: Store;\n /** Live theme settings (reflects customizer drafts via applyDraft). */\n themeSettings: ThemeSettingsV3;\n}\n\ninterface DraftHandle {\n applyDraft: (next: ThemeSettingsV3) => void;\n}\n\n/** Normalise the two ctx shapes' store slot; never return undefined — SDK\n * code reads `store.currency` without optional chaining and would throw.\n * Also maps the storefront's snake_case `default_currency` onto `currency`\n * when the latter is missing (pre-0.3 scaffolds did this per-theme; doing\n * it here keeps server render and client hydrate byte-identical). */\nfunction pickStore(ctx: ThemeMountContext): Store {\n const s = ctx.storeData ?? ctx.store;\n if (s) {\n const raw = s as Store & { default_currency?: string };\n if (!raw.currency && raw.default_currency) {\n return { ...raw, currency: raw.default_currency };\n }\n return s;\n }\n return {\n id: \"unknown\",\n name: \"Store\",\n slug: \"store\",\n currency: \"EGP\",\n default_language: \"en\",\n use_nextjs_storefront: true,\n } as Store;\n}\n\n/** Resolve the active template from either contract, defaulting to \"home\". */\nfunction pickTemplate(ctx: ThemeMountContext): string {\n if (typeof ctx.currentTemplate === \"string\" && ctx.currentTemplate) {\n return ctx.currentTemplate;\n }\n const pageType = ctx.page?.type;\n if (typeof pageType === \"string\" && pageType) return pageType;\n return \"home\";\n}\n\n/** Resolve the demo flag: explicit host flag wins; else infer from empty\n * templates (the marketplace preview ships none → render bundled preset). */\nfunction pickDemo(ctx: ThemeMountContext, themeSettings: ThemeSettingsV3): boolean {\n if (typeof ctx.demo === \"boolean\") return ctx.demo;\n const t = themeSettings.templates;\n return !t || Object.keys(t).length === 0;\n}\n\n/**\n * Wrap the theme app in the singular-entity providers the current route\n * supplies. A PDP ships `page.data.product` → ProductProvider (so\n * useProduct() resolves); a collection route ships `page.data.collection`\n * → CollectionProvider (so useCollection()/useCollectionOptional() resolve\n * the active collection's name + products). Listing/home routes ship\n * neither and the app renders unwrapped.\n */\nfunction wrapEntityProviders(\n app: ReactNode,\n pageData: { product?: Product; collection?: Collection },\n): ReactNode {\n let inner = app;\n if (pageData.collection) {\n inner = (\n <CollectionProvider collection={pageData.collection}>\n {inner}\n </CollectionProvider>\n );\n }\n if (pageData.product) {\n inner = <ProductProvider product={pageData.product}>{inner}</ProductProvider>;\n }\n return inner;\n}\n\n/**\n * Bridge that holds live draft settings, re-applies global style tokens on\n * every change, and wires the full provider stack (catalog + nav) around the\n * theme's app. Exposes `applyDraft` so the host can stream customizer edits.\n */\nconst ThemeMountBridge = forwardRef<\n DraftHandle,\n {\n ctx: ThemeMountContext;\n /** Null when rendered off-DOM (`createApp` for server rendering); the\n * style-token effect is a no-op there — the host SSRs the same vars\n * via `computeGlobalStyleTokens`. */\n mountEl: HTMLElement | null;\n renderApp: (args: ThemeRenderArgs) => ReactNode;\n }\n>(function ThemeMountBridge({ ctx, mountEl, renderApp }, ref) {\n const [themeSettings, setThemeSettings] = useState<ThemeSettingsV3>(\n ctx.themeSettings,\n );\n useImperativeHandle(\n ref,\n () => ({\n applyDraft: (next) =>\n setThemeSettings((prev) => (prev === next ? prev : next)),\n }),\n [],\n );\n\n // Global settings (colors/fonts/layout) → CSS custom properties on the\n // mount root. Re-runs on every draft so the customizer's live preview\n // re-paints as a merchant drags a color or picks a font.\n // (applyGlobalStyleTokens resolves heading/body fonts to real stacks and\n // injects webfont links — see computeGlobalStyleTokens, which is the\n // single source of truth shared with hosts that SSR these vars.)\n useEffect(() => {\n if (!mountEl) return;\n const gs = (themeSettings.global_settings ?? {}) as Record<string, unknown>;\n applyGlobalStyleTokens(gs, mountEl);\n }, [themeSettings, mountEl]);\n\n const store = pickStore(ctx);\n const template = pickTemplate(ctx);\n const demo = pickDemo(ctx, themeSettings);\n\n // Real catalog the host forwards: home/listing routes ship\n // page.data.{products,collections}; the PDP ships page.data.product.\n // Feeding these into NuMuProvider (+ ProductProvider) is what makes\n // useProducts()/useProduct() return the merchant's ACTUAL catalog.\n const pageData = (ctx.page?.data ?? {}) as {\n products?: Product[];\n collections?: Collection[];\n collection?: Collection;\n product?: Product;\n };\n\n const app = renderApp({\n currentTemplate: template,\n demo,\n page: ctx.page ?? null,\n store,\n themeSettings,\n });\n\n return (\n <NuMuProvider\n store={store}\n themeSettings={themeSettings}\n initialCart={ctx.initialCart}\n customer={ctx.customer}\n locale={ctx.locale}\n translations={ctx.translations}\n navigation={ctx.navigation}\n initialProducts={pageData.products}\n initialCollections={pageData.collections}\n currentTemplate={template}\n pageTemplate={ctx.page?.template}\n >\n {wrapEntityProviders(app, pageData)}\n </NuMuProvider>\n );\n});\n\n/**\n * Build the canonical theme element tree for a ctx. BOTH render paths go\n * through here — `mountTheme` (client mount/hydrate) and `createApp`\n * (host-side `renderToString`) — so the server markup and the hydration\n * tree are the same React tree by construction. `mountEl` is a prop, not\n * DOM output, so it differing between server (null) and client (the\n * container) cannot cause a hydration mismatch.\n */\nexport function buildThemeElement(\n ctx: ThemeMountContext,\n mountEl: HTMLElement | null,\n renderApp: (args: ThemeRenderArgs) => ReactNode,\n ref?: (h: DraftHandle | null) => void,\n): ReactElement {\n return (\n <StrictMode>\n <ThemeMountBridge ctx={ctx} mountEl={mountEl} renderApp={renderApp} ref={ref} />\n </StrictMode>\n );\n}\n\n/**\n * Mount a V3 theme. Owns the React root, the provider stack (catalog + nav +\n * style tokens), and the live-preview draft cycle. Returns the host-contract\n * `MountResult` (`cleanup` + `applyDraft`).\n *\n * When the host passes `ctx.hydrate === true` and the container already\n * holds server-rendered HTML (produced by this theme's `createApp` with the\n * identical ctx), the tree is adopted via `hydrateRoot` — no re-render, no\n * flash. An empty container downgrades to a plain client mount so hosts can\n * pass the flag optimistically.\n *\n * @param el the host-supplied container element\n * @param ctx the mount context (either host or legacy/dev shape)\n * @param renderApp returns the theme's section tree for the current args\n */\nexport function mountTheme(\n el: HTMLElement,\n ctx: ThemeMountContext,\n renderApp: (args: ThemeRenderArgs) => ReactNode,\n): MountResult {\n const handleRef = { current: null as DraftHandle | null };\n const element = buildThemeElement(ctx, el, renderApp, (h) => {\n handleRef.current = h;\n });\n\n const shouldHydrate = ctx.hydrate === true && el.firstElementChild !== null;\n let root: Root;\n if (shouldHydrate) {\n root = hydrateRoot(el, element);\n } else {\n root = createRoot(el);\n root.render(element);\n }\n\n return {\n applyDraft: (next) => handleRef.current?.applyDraft(next),\n cleanup: () => {\n root.unmount();\n handleRef.current = null;\n },\n };\n}\n","\"use client\";\n\n/**\n * `defineThemeEntry(renderApp)` — one-call theme entry that yields BOTH\n * halves of the V3 contract from a single component:\n *\n * - `mount(el, ctx)` — the client entry every host already calls\n * (now hydration-aware via `ctx.hydrate`).\n * - `createApp(ctx)` — the same React tree as a plain element, so the\n * host can `renderToString(createApp(ctx))` on the\n * server and ship real HTML before any JS runs.\n *\n * ```tsx\n * // src/main.tsx\n * import { defineThemeEntry } from \"@numueg/theme-sdk\";\n *\n * const entry = defineThemeEntry(({ currentTemplate }) => (\n * <ThemeApp currentTemplate={currentTemplate} />\n * ));\n *\n * export const mount = entry.mount;\n * export const createApp = entry.createApp;\n * ```\n *\n * Why both MUST come from one definition: hydration only succeeds when the\n * server markup and the client tree are identical. Routing both through\n * `buildThemeElement` makes that true by construction — a theme cannot\n * accidentally ship a `createApp` that disagrees with its `mount`.\n *\n * Themes that only export `mount` keep working exactly as before; they are\n * simply never server-rendered (the host detects the missing `createApp`\n * and falls back to today's client-only mount).\n */\n\nimport type { ReactElement, ReactNode } from \"react\";\n\nimport {\n buildThemeElement,\n mountTheme,\n type ThemeMountContext,\n type ThemeRenderArgs,\n} from \"./mount\";\nimport type { MountResult } from \"./types/theme\";\n\n/** The pair of entry points a V3 theme bundle exports. */\nexport interface ThemeEntry {\n /** Client entry — host contract `mount(el, ctx): MountResult`. */\n mount: (el: HTMLElement, ctx: ThemeMountContext) => MountResult;\n /**\n * Server entry — returns the exact element tree `mount` would render,\n * for host-side `renderToString`. Must stay side-effect free: no DOM\n * access happens until React effects run (which they don't on the\n * server).\n */\n createApp: (ctx: ThemeMountContext) => ReactElement;\n}\n\nexport function defineThemeEntry(\n renderApp: (args: ThemeRenderArgs) => ReactNode,\n): ThemeEntry {\n return {\n mount: (el, ctx) => mountTheme(el, ctx, renderApp),\n createApp: (ctx) => buildThemeElement(ctx, null, renderApp),\n };\n}\n","\"use client\";\n\nimport { createElement, type ElementType, type ReactNode } from \"react\";\nimport { useLocalization } from \"../hooks/useLocalization\";\nimport { useShop } from \"../hooks/useShop\";\nimport { useCurrency } from \"../hooks/useCurrency\";\n\ninterface MoneyProps {\n /** Amount in major units (e.g. dollars, not cents). */\n amount: number;\n /** ISO-4217 currency code. Defaults to the active store's currency. */\n currency?: string;\n /**\n * When the same product has both a sale price and a compare-at price,\n * pass the higher (compare-at) value here and we'll render it with a\n * strike-through next to the active price. Skipped when undefined or\n * <= the main amount.\n */\n compareAt?: number;\n className?: string;\n /** Custom HTML element tag — defaults to `span`. */\n as?: ElementType;\n}\n\n/**\n * <Money amount={49.99} /> — formatted price, locale-aware.\n *\n * Wraps useLocalization().formatMoney so theme code stops re-implementing\n * Intl.NumberFormat. Renders inline with `dir=\"auto\"` so the digits\n * flow naturally in RTL (Arabic) without flipping the currency symbol.\n *\n * Multi-currency: when the store has `auto_convert` on and the caller did NOT\n * pin an explicit `currency`, the amount is presented in the visitor's\n * SELECTED currency (converted via the shared rates from `useCurrency()`). A\n * `<CurrencySwitcher>` change therefore re-renders every `<Money>` on the page\n * without a reload. An explicit `currency` prop means \"this amount is already\n * in that currency\" — it is respected and never converted.\n *\n * Usage:\n * <Money amount={product.price} compareAt={product.compare_at_price} />\n */\nexport function Money({\n amount,\n currency,\n compareAt,\n className,\n as = \"span\",\n}: MoneyProps) {\n const { formatMoney } = useLocalization();\n const shop = useShop();\n const { selected, base, autoConvert, convert } = useCurrency();\n\n const shouldConvert =\n autoConvert && !currency && !!selected && selected !== base;\n const ccy = shouldConvert ? selected : currency || shop?.currency;\n // convert() works in cents; Money's amount is major units — round-trip\n // through cents so currencies with minor units convert correctly.\n const toDisplay = (major: number): number =>\n shouldConvert ? convert(Math.round(major * 100), selected) / 100 : major;\n\n const showCompare = compareAt != null && compareAt > amount;\n\n const children: ReactNode[] = [\n <span key=\"amt\">{formatMoney(toDisplay(amount), ccy)}</span>,\n ];\n if (showCompare) {\n children.push(\" \");\n children.push(\n <s key=\"cmp\" style={{ opacity: 0.6 }}>\n {formatMoney(toDisplay(compareAt), ccy)}\n </s>,\n );\n }\n\n return createElement(\n as,\n { className, dir: \"auto\" },\n children,\n );\n}\n","import type { CSSProperties } from \"react\";\n\n/**\n * Non-destructive image framing transform (focal / zoom / rotation).\n *\n * An image setting value may carry optional `transform` metadata\n * (`{ url, alt, transform }`). The original asset is never modified — the\n * storefront reproduces the framing purely from these numbers via CSS, so the\n * SAME uploaded image can be framed differently per placement (hero vs card).\n *\n * Hoisted into the SDK (was duplicated in every theme's `_shared.ts` and in\n * the merchant-hub editor's `imageTransform.ts`). The editor copy MUST stay\n * equivalent so its preview matches the storefront render exactly.\n */\nexport interface ImageTransform {\n v: 1;\n focal?: { x: number; y: number }; // 0..1, default center\n zoom?: number; // 1..4, default 1\n rotation?: number; // degrees, default 0\n fit?: \"cover\" | \"contain\";\n}\n\nconst _clampT = (n: number, lo: number, hi: number): number =>\n Math.min(hi, Math.max(lo, Number.isFinite(n) ? n : lo));\n\n/** Read the transform off an image setting value (string | {url,alt,transform}). */\nexport function asImageTransform(v: unknown): ImageTransform | undefined {\n if (v && typeof v === \"object\" && \"transform\" in v) {\n const t = (v as { transform?: unknown }).transform;\n if (t && typeof t === \"object\") return t as ImageTransform;\n }\n return undefined;\n}\n\n/**\n * CSS reproducing the transform on an `<img>` that fills a fixed-aspect,\n * overflow-hidden frame. Default fit is `cover` (Shopify-style: the image\n * fills its frame, cropping to the focal point) — pass `\"contain\"` only for\n * placements that must show the whole image (e.g. a logo).\n *\n * **No transform → empty object.** An inline style beats a className, so\n * returning `{ objectFit: fit }` here would silently override a placement's\n * own `object-contain` / `object-none` class on every untransformed image —\n * which is most merchant images. The section's className stays in charge; a\n * caller that needs a guaranteed fit supplies it itself, e.g.\n * `{ objectFit: fit, ...applyImageTransform(t, fit) }` (see `HeroMedia`).\n * This matches `Image.tsx`'s untransformed branch and the behaviour every\n * theme's local copy has shipped with.\n */\nexport function applyImageTransform(\n t: ImageTransform | undefined | null,\n fit: \"cover\" | \"contain\" = \"cover\",\n): CSSProperties {\n if (!t) return {};\n const fx = Math.round(_clampT(t.focal?.x ?? 0.5, 0, 1) * 1e4) / 100;\n const fy = Math.round(_clampT(t.focal?.y ?? 0.5, 0, 1) * 1e4) / 100;\n const zoom = _clampT(t.zoom ?? 1, 1, 4);\n const rot = (((t.rotation ?? 0) % 360) + 360) % 360;\n const effFit = t.fit ?? fit;\n const style: CSSProperties = {\n transform: `scale(${zoom}) rotate(${rot}deg)`,\n transformOrigin: `${fx}% ${fy}%`,\n objectFit: effFit,\n };\n if (effFit === \"cover\") style.objectPosition = `${fx}% ${fy}%`;\n return style;\n}\n\n/**\n * focalSrc — build a URL for a server-side, focal-point-aware image transform.\n *\n * OPT-IN helper. A theme that wants a bandwidth-efficient SMART CROP for a big\n * image (typically a hero) calls this to point the <img src> at the storefront's\n * `/api/image-transform` endpoint with focal/aspect params. The endpoint honors\n * them only when Cloudflare Image Resizing is enabled on the zone\n * (NUMU_CF_IMAGE_RESIZING=1); otherwise it gracefully ignores them and serves a\n * plain resized image — so the theme's CSS `applyImageTransform` framing remains\n * the correctness baseline either way. This is purely a perf optimization.\n *\n * Returns a RELATIVE path (`/api/image-transform?...`) — the SDK runs\n * same-origin inside the storefront, matching how <Form>/useShop build URLs.\n *\n * @example\n * <img\n * src={focalSrc(hero.url, { width: 1600, focal: t?.focal, aspect: \"16/9\" })}\n * style={applyImageTransform(t, \"cover\")} // CSS still frames as fallback\n * />\n */\nexport interface FocalSrcOptions {\n /** Target width in px (e.g. 1600 for a desktop hero). Required for a crop. */\n width?: number;\n /** Focal point, normalized 0..1 (0.5,0.5 = center). */\n focal?: { x?: number; y?: number };\n /** Target aspect ratio \"W/H\" (e.g. \"16/9\"); drives the crop box height. */\n aspect?: string;\n /** Crop mode. Default \"cover\". */\n fit?: \"cover\" | \"contain\";\n /** Quality 1..100. */\n quality?: number;\n /** Output format. */\n format?: \"webp\" | \"avif\" | \"jpeg\" | \"jpg\" | \"png\";\n}\n\nconst clamp01 = (n: number) => Math.min(1, Math.max(0, n));\n\n/**\n * Does the HOST honor server-side crop params (`fp-x`/`fp-y`/`ar`/`fit`)?\n *\n * The storefront's `/api/image-transform` only acts on them when Cloudflare\n * Image Resizing is enabled (`NUMU_CF_IMAGE_RESIZING=1`); with CF off it\n * DROPS them and forwards `url`+`w`+`q` to `/_next/image`. So on every store\n * running today, a URL carrying `&ar=4/5&fit=cover` fetches byte-for-byte the\n * same image as the width-only URL — the params are inert.\n *\n * Inert is not free. A URL that differs from the width-only form is a\n * different cache key, so it misses the host's `<link rel=preload as=image>`\n * for the hero (which is width-only by construction — the host can't know a\n * theme's `mobileAspect`). Measured on vionne: the mobile hero was preloaded\n * at high priority, discarded, and re-requested 6.9 s later once the theme\n * hydrated — the single largest contributor to an 18.7 s mobile LCP.\n *\n * So: emit crop params only when the host says it will honor them. The\n * storefront sets `__NUMU_CF_IMAGE_RESIZING__` (see the storefront's\n * RuntimeImportMap) from the same env var the route reads, which keeps the\n * URL we build and the transform the server performs in lockstep. Absent the\n * flag we assume off — the safe default, since that's the configuration every\n * store runs and CSS `applyImageTransform` frames the image regardless.\n *\n * Read through `globalThis` so the value is identical under the SSR worker\n * and in the browser (a `typeof window` check would diverge and produce a\n * hydration mismatch on `src` the moment CF is switched on).\n */\nfunction hostHonorsCropParams(): boolean {\n return (\n (globalThis as { __NUMU_CF_IMAGE_RESIZING__?: boolean })\n .__NUMU_CF_IMAGE_RESIZING__ === true\n );\n}\n\nexport function focalSrc(\n url: string | null | undefined,\n options: FocalSrcOptions = {},\n): string {\n if (!url) return \"\";\n // data: URIs and already-transformed URLs pass through untouched.\n if (url.startsWith(\"data:\") || /[?&](fp-x|fp-y)=/.test(url)) return url;\n\n const crop = hostHonorsCropParams();\n const p = new URLSearchParams();\n p.set(\"url\", url);\n if (options.width) p.set(\"w\", String(Math.round(options.width)));\n if (crop && options.focal?.x != null) p.set(\"fp-x\", String(clamp01(options.focal.x)));\n if (crop && options.focal?.y != null) p.set(\"fp-y\", String(clamp01(options.focal.y)));\n if (crop && options.aspect) p.set(\"ar\", options.aspect);\n if (crop && options.fit) p.set(\"fit\", options.fit);\n if (options.quality) p.set(\"q\", String(Math.min(100, Math.max(1, Math.round(options.quality)))));\n if (options.format) p.set(\"f\", options.format.toLowerCase());\n\n return `/api/image-transform?${p.toString()}`;\n}\n","\"use client\";\n\nimport type { CSSProperties, ImgHTMLAttributes } from \"react\";\nimport { applyImageTransform, type ImageTransform } from \"../utils/imageTransform\";\n\ninterface ImageProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, \"src\" | \"srcSet\"> {\n src: string | undefined | null;\n alt: string;\n /**\n * Comma-separated breakpoints for the `sizes` attribute. Default\n * matches a typical responsive grid:\n * \"(min-width: 1024px) 25vw, (min-width: 640px) 50vw, 100vw\"\n */\n sizes?: string;\n /**\n * When true (default), generate a `srcSet` with several widths.\n * Disable for above-the-fold hero images where you want a single\n * source under direct theme control.\n */\n responsive?: boolean;\n /**\n * Loading strategy. Default \"lazy\" matches Shopify themes; pass\n * \"eager\" for above-the-fold imagery.\n */\n loading?: \"eager\" | \"lazy\";\n /**\n * Above-the-fold? When true, forces loading=\"eager\" + fetchPriority=\"high\"\n * (overrides `loading`). Use on the hero / LCP image. Default false.\n */\n priority?: boolean;\n /**\n * Shopify-style frame. When set (e.g. \"3/4\", \"16/9\", \"1/1\") the image is\n * wrapped in a fixed-aspect, overflow-hidden box and the `<img>` fills it.\n * Combined with `objectFit=\"cover\"` (the default) this guarantees the image\n * ALWAYS fits its frame — no letterboxing, no overflow — cropping to the\n * focal point. Omit to render a bare `<img>` (legacy behavior).\n */\n aspectRatio?: string;\n /**\n * How the image fills its box. Default \"cover\" (fill + crop) — the merchant\n * never sees a letterboxed/squashed image. Use \"contain\" for logos/badges\n * that must show in full.\n */\n objectFit?: \"cover\" | \"contain\" | \"fill\" | \"scale-down\" | \"none\";\n /** CSS object-position (e.g. \"50% 50%\"). Ignored if `transform` is set. */\n objectPosition?: string;\n /**\n * Non-destructive focal/zoom/rotation metadata from the image setting value\n * (`asImageTransform(setting)`). When present it drives object-fit +\n * object-position + scale/rotate so the editor preview and the live render\n * match exactly. Overrides `objectFit`/`objectPosition`.\n */\n transform?: ImageTransform | null;\n}\n\nconst DEFAULT_WIDTHS = [320, 480, 640, 768, 1024, 1280, 1600, 1920];\n\n/**\n * Build a srcSet string from a base image URL by appending a width\n * query param. Works for any CDN that honors `?w=` (R2 image-resizing,\n * Cloudflare Images, Imgix-compatibles). Hosts that ignore the param\n * just serve the original; not a regression.\n *\n * If the URL already has query params we preserve them; if it already\n * has a width directive we pass through unchanged (assume the theme\n * author knows what they want).\n */\nfunction buildSrcSet(src: string, widths: number[] = DEFAULT_WIDTHS): string {\n if (/[?&]w=\\d+/.test(src)) return \"\";\n const sep = src.includes(\"?\") ? \"&\" : \"?\";\n return widths.map((w) => `${src}${sep}w=${w} ${w}w`).join(\", \");\n}\n\n/**\n * <Image> — drop-in replacement for `<img>` with srcSet + lazy loading\n * defaults. Themes should use this everywhere they'd otherwise write a\n * raw `<img>` so merchant-uploaded images get responsive variants and\n * lazy loading without per-section work.\n *\n * If `src` is empty/null, renders a placeholder div so the layout\n * doesn't shift while a merchant configures images in the customizer.\n */\nexport function Image({\n src,\n alt,\n sizes = \"(min-width: 1024px) 25vw, (min-width: 640px) 50vw, 100vw\",\n responsive = true,\n loading = \"lazy\",\n priority = false,\n aspectRatio,\n objectFit,\n objectPosition,\n transform,\n className,\n style,\n ...rest\n}: ImageProps) {\n // Frame mode: a fixed-aspect, overflow-hidden wrapper the <img> fills. This\n // is what guarantees \"the image always fits its frame\" regardless of the\n // uploaded image's own aspect ratio.\n const framed = Boolean(aspectRatio);\n\n if (!src) {\n const placeholder = (\n <div\n className={framed ? undefined : className}\n role=\"img\"\n aria-label={alt}\n style={{\n backgroundColor: \"rgba(0,0,0,0.05)\",\n display: \"block\",\n width: \"100%\",\n height: framed ? \"100%\" : undefined,\n ...(framed ? {} : style),\n }}\n />\n );\n if (!framed) return placeholder;\n return (\n <span\n className={className}\n style={{ display: \"block\", aspectRatio, overflow: \"hidden\", ...style }}\n >\n {placeholder}\n </span>\n );\n }\n\n const srcSet = responsive ? buildSrcSet(src) : undefined;\n // Above-the-fold hero: eager + high fetch priority, overriding `loading`.\n const effLoading = priority ? \"eager\" : loading;\n\n // Resolve the fit styling. An explicit transform wins (focal/zoom/rotate).\n // Inside a frame, default to cover so the image always fills it. Without a\n // frame, only apply a fit when the caller explicitly asked — preserving the\n // legacy bare-<img> behavior (and never overriding a className like\n // `object-contain` with an inline style).\n const effFit = objectFit ?? (framed ? \"cover\" : undefined);\n const fitStyle: CSSProperties = transform\n ? applyImageTransform(transform, effFit === \"contain\" ? \"contain\" : \"cover\")\n : {\n ...(effFit ? { objectFit: effFit } : {}),\n ...(objectPosition ? { objectPosition } : {}),\n };\n\n const img = (\n <img\n src={src}\n alt={alt}\n srcSet={srcSet || undefined}\n sizes={srcSet ? sizes : undefined}\n loading={effLoading}\n fetchPriority={priority ? \"high\" : undefined}\n decoding=\"async\"\n className={framed ? undefined : className}\n style={\n framed\n ? { width: \"100%\", height: \"100%\", display: \"block\", ...fitStyle }\n : { ...fitStyle, ...style }\n }\n {...rest}\n />\n );\n\n if (!framed) return img;\n return (\n <span\n className={className}\n style={{\n display: \"block\",\n position: \"relative\",\n width: \"100%\",\n aspectRatio,\n overflow: \"hidden\",\n ...style,\n }}\n >\n {img}\n </span>\n );\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type {\n CSSProperties,\n ImgHTMLAttributes,\n ReactEventHandler,\n} from \"react\";\nimport {\n applyImageTransform,\n focalSrc,\n type FocalSrcOptions,\n type ImageTransform,\n} from \"../utils/imageTransform\";\n\n/**\n * Width ladder for hero srcSet. MUST be a subset of the storefront's\n * `next.config.ts` images.deviceSizes = [640,768,1024,1280,1920]. On the\n * default (Cloudflare-off) path /api/image-transform 302s to /_next/image,\n * which returns HTTP 400 for ANY width not in deviceSizes. When CF Image\n * Resizing is on, CF accepts arbitrary widths — so this safe subset works on\n * both paths. (Do NOT add 2400/3200 here without also adding them to deviceSizes.)\n */\nconst HERO_WIDTHS = [640, 768, 1024, 1280, 1920];\n/** Default mobile breakpoint (px) — matches Tailwind `md`. */\nconst DEFAULT_BREAKPOINT = 768;\n/** Base width requested for the rendered desktop / mobile `<img src>` fallback. */\nconst DESKTOP_BASE_WIDTH = 1920;\nconst MOBILE_BASE_WIDTH = 1280;\n\nexport interface HeroMediaProps\n extends Omit<ImgHTMLAttributes<HTMLImageElement>, \"src\" | \"srcSet\" | \"alt\" | \"style\"> {\n /** Desktop (primary) image URL. */\n src: string | null | undefined;\n alt: string;\n /** Desktop focal/zoom/rotation (`asImageTransform(setting)`). */\n transform?: ImageTransform | null;\n /** Optional mobile art-direction image. When set → swaps below `breakpoint`. */\n mobileSrc?: string | null;\n /** Mobile focal/zoom/rotation. Falls back to the desktop transform's focal. */\n mobileTransform?: ImageTransform | null;\n /** Server-crop box aspect for desktop, e.g. \"16/9\". Match the theme container. */\n desktopAspect?: string;\n /** Server-crop box aspect for mobile, e.g. \"4/5\". */\n mobileAspect?: string;\n /** object-fit. Default \"cover\". Pass \"contain\" for letterboxed art. */\n fit?: \"cover\" | \"contain\";\n /** Above-the-fold? Default true → loading=eager + fetchPriority=high. */\n priority?: boolean;\n /** sizes attribute. Hero is full-width → default \"100vw\". */\n sizes?: string;\n /** Below this width (px) the mobile image is used. Default 768. */\n breakpoint?: number;\n /**\n * Pre-fetch the alternate (off-breakpoint) image so a Desktop↔Mobile swap is an\n * instant cache hit instead of a flash-and-fetch. Default true. Set false to save\n * the one extra background request when smooth resizing isn't worth the bandwidth.\n */\n preloadAlternate?: boolean;\n className?: string;\n style?: CSSProperties;\n}\n\nfunction heroSrcSet(url: string, opts: Omit<FocalSrcOptions, \"width\">): string {\n return HERO_WIDTHS\n .map((w) => `${focalSrc(url, { width: w, ...opts })} ${w}w`)\n .join(\", \");\n}\n\n/**\n * <HeroMedia> — above-the-fold hero image for V3 themes.\n *\n * - Real responsive srcSet routed through /api/image-transform (resize + AVIF/WebP,\n * + focal smart-crop when Cloudflare Image Resizing is enabled).\n * - LCP perf defaults: loading=eager + fetchPriority=high (disable via priority={false}).\n * - Non-destructive focal/zoom/rotation framing via applyImageTransform.\n * - Optional MOBILE art-direction image: a different bitmap below `breakpoint`.\n *\n * ## Why matchMedia, not <picture><source media>\n * Art direction is resolved in JS (a `matchMedia` listener) rather than a native\n * `<picture><source media>`. A native `<picture>` does NOT reliably re-pick its source\n * when an EMBEDDED preview resizes its iframe — exactly what the theme editor's\n * Desktop/Mobile toggle does — so the hero would stay stuck on the desktop bitmap at\n * mobile sizes. CSS media queries DO re-evaluate on that resize (Tailwind flips the\n * container to portrait), and `matchMedia` shares that engine, so the swap is\n * deterministic. The state initialises from `matchMedia` so the first client paint is\n * already correct (V3 themes mount client-side) — no desktop→mobile flash on phones.\n *\n * ## Smooth swap\n * The off-breakpoint image is pre-warmed (low priority, after paint) so toggling the\n * breakpoint — the editor switch, or a window resize — paints from cache instantly\n * instead of fetching on demand. See `preloadAlternate`.\n *\n * When `mobileSrc` is omitted this is a single responsive <img> filling its parent —\n * the theme keeps its own wrapper/sizing, identical to a raw <img> plus srcSet + perf.\n */\nexport function HeroMedia({\n src,\n alt,\n transform,\n mobileSrc,\n mobileTransform,\n desktopAspect,\n mobileAspect,\n fit = \"cover\",\n priority = true,\n sizes = \"100vw\",\n breakpoint = DEFAULT_BREAKPOINT,\n preloadAlternate = true,\n className,\n style,\n ...rest\n}: HeroMediaProps) {\n const hasMobile = !!mobileSrc;\n const mobileQuery = `(max-width: ${breakpoint - 1}px)`;\n\n // Which art-direction image is active. Initialised from matchMedia so the FIRST\n // client paint is already correct (no desktop→mobile flash on phones), then kept in\n // sync by a change listener (the reliable replacement for <picture> source re-pick).\n const [isMobile, setIsMobile] = useState(\n () =>\n hasMobile &&\n typeof window !== \"undefined\" &&\n typeof window.matchMedia === \"function\" &&\n window.matchMedia(mobileQuery).matches,\n );\n\n // If the storefront's /api/image-transform refuses the image host (it's not on the\n // allow-list → 403), the optimized request fails. Fall back to the RAW url so the\n // hero still renders — never a regression vs a plain <img>. The optimize path\n // (resize/AVIF) still applies for allow-listed hosts (the common case). The theme's\n // own onError (if any) only fires once the RAW url ALSO fails (genuinely broken).\n const [rawFallback, setRawFallback] = useState(false);\n const { onError: themeOnError, ...imgRest } = rest;\n const handleError: ReactEventHandler<HTMLImageElement> = (e) => {\n if (!rawFallback) setRawFallback(true);\n else themeOnError?.(e);\n };\n\n // Keep `isMobile` in sync with the viewport. matchMedia change events fire on every\n // resize that crosses the breakpoint, INCLUDING an iframe resize — so the editor's\n // Desktop/Mobile toggle deterministically swaps the bitmap.\n useEffect(() => {\n if (!hasMobile || typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") {\n return;\n }\n const mq = window.matchMedia(mobileQuery);\n const sync = () => setIsMobile(mq.matches);\n sync();\n mq.addEventListener?.(\"change\", sync);\n return () => mq.removeEventListener?.(\"change\", sync);\n }, [hasMobile, mobileQuery]);\n\n // Framing inputs (safe to compute every render; cheap + pure).\n const desktopFocal = transform?.focal;\n const mobileFocal = mobileTransform?.focal ?? desktopFocal;\n // Desktop server-crop params (focal/aspect/fit) are requested ONLY when an explicit\n // desktopAspect is set. A full-bleed desktop hero (no aspect) stays width-only\n // — byte-matching the host's width-only <link rel=preload> so the preload is credited.\n // CSS applyImageTransform still frames the desktop focal either way.\n //\n // The MOBILE branch below always asks for them, which used to mean the mobile hero\n // URL could never match that preload. It matches now regardless: focalSrc drops all\n // four params unless the host advertises `__NUMU_CF_IMAGE_RESIZING__` — and with CF\n // off (every store today) the endpoint was discarding them anyway. See focalSrc.\n const desktopCrop: Omit<FocalSrcOptions, \"width\"> = desktopAspect\n ? { focal: desktopFocal, aspect: desktopAspect, fit }\n : {};\n const mobileCrop: Omit<FocalSrcOptions, \"width\"> = {\n focal: mobileFocal,\n aspect: mobileAspect,\n fit,\n };\n\n // Pre-warm the ALTERNATE image (low priority, after paint) so the breakpoint swap is\n // an instant cache hit. The active image is already fetched by the rendered <img>;\n // re-warming it would be a no-op cache hit, so we only warm the off-breakpoint one.\n useEffect(() => {\n if (!preloadAlternate || !hasMobile || !src || !mobileSrc) return;\n if (typeof window === \"undefined\" || typeof window.Image !== \"function\") return;\n const altUrl = isMobile\n ? rawFallback\n ? src\n : focalSrc(src, { width: DESKTOP_BASE_WIDTH, ...desktopCrop })\n : rawFallback\n ? mobileSrc\n : focalSrc(mobileSrc, { width: MOBILE_BASE_WIDTH, ...mobileCrop });\n if (!altUrl) return;\n const im = new window.Image();\n im.onerror = () => {};\n try {\n (im as unknown as { fetchPriority?: string }).fetchPriority = \"low\";\n } catch {\n /* not supported — ignore */\n }\n im.decoding = \"async\";\n im.src = altUrl;\n if (typeof im.decode === \"function\") im.decode().catch(() => {});\n // desktopCrop/mobileCrop are derived from the deps below; intentionally omitted.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [preloadAlternate, hasMobile, src, mobileSrc, isMobile, rawFallback]);\n\n if (!src) {\n // Placeholder so layout doesn't shift while the merchant configures the image.\n return (\n <div\n className={className}\n role=\"img\"\n aria-label={alt}\n style={{ width: \"100%\", height: \"100%\", backgroundColor: \"rgba(0,0,0,0.05)\", ...style }}\n />\n );\n }\n\n const useMobile = hasMobile && isMobile;\n const activeUrl = useMobile ? (mobileSrc as string) : src;\n const activeCrop = useMobile ? mobileCrop : desktopCrop;\n const activeBase = useMobile ? MOBILE_BASE_WIDTH : DESKTOP_BASE_WIDTH;\n const activeSrc = rawFallback\n ? activeUrl\n : focalSrc(activeUrl, { width: activeBase, ...activeCrop });\n const activeSrcSet = rawFallback ? undefined : heroSrcSet(activeUrl, activeCrop);\n // A hero always fills its frame, so the fit is supplied here rather than by\n // `applyImageTransform` — that helper returns {} for an untransformed image\n // so it never overrides a section's own object-fit class (see its docs).\n const fitStyle: CSSProperties = {\n objectFit: fit,\n ...applyImageTransform(useMobile ? mobileTransform ?? transform : transform, fit),\n };\n\n return (\n <img\n src={activeSrc}\n srcSet={activeSrcSet}\n sizes={activeSrcSet ? sizes : undefined}\n alt={alt}\n loading={priority ? \"eager\" : \"lazy\"}\n fetchPriority={priority ? \"high\" : undefined}\n decoding=\"async\"\n onError={handleError}\n className={className}\n style={{ width: \"100%\", height: \"100%\", display: \"block\", ...fitStyle, ...style }}\n {...imgRest}\n />\n );\n}\n","\"use client\";\n\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { useThemeSettings } from \"../hooks/useThemeSettings\";\nimport { useShop } from \"../hooks/useShop\";\nimport { logoImgStyle } from \"../utils/logoStyle\";\n\nexport interface LogoProps {\n /** Explicit logo URL; falls back to global_settings.logo_url then shop.logo_url. */\n src?: string | null;\n /** Alt text; falls back to the brand name / shop name. */\n alt?: string;\n /** Overrides `global_settings.logo_shape` (none/square/rounded/circle/triangle). */\n shape?: string;\n /** Overrides `global_settings.logo_size` (small/medium/large). */\n size?: string;\n className?: string;\n style?: CSSProperties;\n /** Rendered when there is no logo URL (e.g. brand-name text). */\n fallback?: ReactNode;\n}\n\nconst str = (v: unknown): string => (typeof v === \"string\" ? v : \"\");\n\nconst NONE_HEIGHT: Record<string, number> = { small: 28, medium: 36, large: 48 };\n\n/**\n * Engine-level store logo. Reads `logo_url`, `logo_shape`, and `logo_size` from\n * the theme's global settings (overridable via props), and renders a plain\n * `<img>` with the chosen shape/size applied via inline styles — so it works in\n * any theme regardless of its CSS setup and keeps **animated GIF logos playing**\n * under every shape. Renders `fallback` (or nothing) when no logo is set.\n */\nexport function Logo({\n src,\n alt,\n shape,\n size,\n className,\n style,\n fallback,\n}: LogoProps) {\n const settings = useThemeSettings();\n const shop = useShop();\n const g = (settings?.global_settings ?? {}) as Record<string, unknown>;\n\n const url = str(src) || str(g.logo_url) || shop?.logo_url || \"\";\n const resolvedShape = shape || str(g.logo_shape) || \"none\";\n const resolvedSize = size || str(g.logo_size) || \"small\";\n const altText = alt || str(g.brand_name) || shop?.name || \"\";\n\n if (!url) return <>{fallback ?? null}</>;\n\n const shaped = resolvedShape !== \"none\";\n const imgStyle: CSSProperties = shaped\n ? { ...logoImgStyle(resolvedShape, resolvedSize), ...style }\n : {\n height: NONE_HEIGHT[resolvedSize] ?? NONE_HEIGHT.small,\n width: \"auto\",\n objectFit: \"contain\",\n ...style,\n };\n\n return (\n <img\n src={url}\n alt={altText}\n className={className}\n style={imgStyle}\n loading=\"eager\"\n />\n );\n}\n","\"use client\";\n\nimport type { AnchorHTMLAttributes, MouseEvent, ReactNode } from \"react\";\nimport { useShop } from \"../hooks/useShop\";\n\ninterface LinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, \"href\"> {\n /**\n * Path relative to the storefront root, e.g. \"/products/foo\",\n * \"/collections/all\", \"/cart\", \"/pages/about\". External URLs (with\n * a protocol) are passed through unchanged.\n */\n to: string;\n children: ReactNode;\n}\n\nconst ABSOLUTE_URL = /^[a-z]+:|^\\/\\//i;\n\n/**\n * Event dispatched on `window` when a Link is clicked and eligible for\n * client-side (soft) navigation. `detail.href` is the target path.\n *\n * Contract: the event is CANCELABLE. A host that can perform soft\n * navigation (e.g. the Next.js storefront routing through its client\n * router) listens for it and calls `event.preventDefault()` to claim\n * the navigation. If no listener claims it, the Link falls back to\n * default anchor behavior — a normal full-page navigation — so themes\n * running under hosts without the bridge (older storefronts, the CLI\n * dev server, static previews) keep working unchanged.\n */\nexport const NAVIGATE_EVENT = \"numu:navigate\";\n\nexport interface NavigateEventDetail {\n href: string;\n}\n\n/**\n * Ask the host to soft-navigate to `href`. Returns true when a host\n * listener claimed the navigation (the caller should suppress its own\n * default behavior), false when no handler is present (the caller\n * should fall back to a full navigation). Exposed for themes that\n * navigate programmatically (e.g. after a search submit).\n */\nexport function requestNavigate(href: string): boolean {\n if (typeof window === \"undefined\") return false;\n const event = new CustomEvent<NavigateEventDetail>(NAVIGATE_EVENT, {\n detail: { href },\n cancelable: true,\n });\n // dispatchEvent returns false when a listener called preventDefault()\n // — i.e. the host claimed the navigation.\n return !window.dispatchEvent(event);\n}\n\n/**\n * Route-aware <Link>. Themes write paths as `/products/<slug>` (matches\n * the production subdomain root). The storefront proxy rewrites those\n * under `/<subdomain>/...` in dev path-segment routing; in production\n * the subdomain hostname does the same job at the edge.\n *\n * Navigation is a two-tier contract:\n * 1. Soft (preferred): on an eligible plain left-click we dispatch a\n * cancelable NAVIGATE_EVENT. A router-aware host claims it with\n * preventDefault() and performs a client-side transition — React,\n * the SDK runtime, and the evaluated theme bundle all stay warm,\n * so page-to-page moves skip the full document reload + remount.\n * 2. Hard (fallback): no listener claims the event → default anchor\n * behavior, a normal full-page navigation. Identical to the\n * pre-0.10 behavior, so themes never break on hosts without the\n * bridge.\n *\n * Soft navigation is only attempted for storefront-internal paths and\n * unmodified left-clicks: external URLs (protocol or `//`), hash-only\n * anchors, modified clicks (ctrl/cmd/shift/alt — \"open in new tab\"),\n * non-left buttons, `target` other than `_self`, and `download` links\n * all keep default browser behavior.\n */\nexport function Link({ to, children, onClick, ...rest }: LinkProps) {\n const shop = useShop();\n const isAbsolute = ABSOLUTE_URL.test(to);\n let href = to;\n if (!isAbsolute && shop && !to.startsWith(\"/\")) {\n // Relative paths like \"products/foo\" treated as siblings of current.\n // Most themes use leading slashes; this is a defensive fallback.\n href = `/${to}`;\n }\n\n const handleClick = (e: MouseEvent<HTMLAnchorElement>) => {\n // The theme's own handler runs first and can preventDefault() to\n // opt out of navigation entirely (e.g. quick-view interception).\n onClick?.(e);\n if (e.defaultPrevented) return;\n // Only unmodified left-clicks on same-document targets are soft-nav\n // candidates; everything else keeps native browser semantics.\n if (e.button !== 0) return;\n if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;\n if (rest.target && rest.target !== \"_self\") return;\n if (rest.download !== undefined) return;\n if (isAbsolute) return;\n // Guard on `to` (the author-written path), not `href`: the shop\n // normalizer above prefixes bare paths with \"/\", turning \"#reviews\"\n // into \"/#reviews\" — which would slip past an href-only check and\n // wrongly soft-nav an in-page anchor.\n if (to.startsWith(\"#\") || href.startsWith(\"#\")) return;\n if (requestNavigate(href)) e.preventDefault();\n };\n\n return (\n <a href={href} onClick={handleClick} {...rest}>\n {children}\n </a>\n );\n}\n","\"use client\";\n\nimport { useState, type ButtonHTMLAttributes, type ReactNode } from \"react\";\nimport { useCart } from \"../hooks/useCart\";\nimport type { Product, ProductVariant } from \"../types/entities\";\n\ninterface AddToCartButtonProps\n extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, \"onClick\" | \"disabled\"> {\n product: Product;\n variant?: ProductVariant;\n quantity?: number;\n /**\n * Picker axes to persist on the cart line ({Color: \"Black\"}). Optional —\n * when omitted, the button reads the live useVariantSelection state for\n * this product from the SDK registry, so existing themes get the variant\n * label end-to-end (cart → checkout → order → email) with no changes.\n */\n selectedOptions?: Record<string, string>;\n /** Custom labels — fallbacks are English defaults. */\n label?: ReactNode;\n loadingLabel?: ReactNode;\n soldOutLabel?: ReactNode;\n errorLabel?: ReactNode;\n /** Called after successful addition. Useful for analytics events. */\n onAdded?: (product: Product, variant?: ProductVariant) => void;\n}\n\n/**\n * Themed Add-to-Cart button with built-in loading/disabled/error states.\n *\n * Wraps useCart().addItem and tracks its own UX state machine:\n * idle → adding → idle (or → error briefly, then idle)\n *\n * Renders a regular `<button>` so themes style it with whatever class\n * names they want — we only own the disabled/aria-busy logic and label\n * swaps. If the variant (or product) is out of stock, button is\n * disabled and shows soldOutLabel.\n *\n * Doesn't trap navigation — for \"buy now\" flows that should redirect\n * to checkout, themes wrap this in their own `<a>` after onAdded.\n */\nexport function AddToCartButton({\n product,\n variant,\n quantity = 1,\n selectedOptions,\n label = \"Add to cart\",\n loadingLabel = \"Adding…\",\n soldOutLabel = \"Sold out\",\n errorLabel = \"Couldn't add — try again\",\n onAdded,\n ...rest\n}: AddToCartButtonProps) {\n const { addItem } = useCart();\n const [state, setState] = useState<\"idle\" | \"adding\" | \"error\">(\"idle\");\n\n const inStock = variant?.in_stock ?? product.in_stock;\n if (!inStock) {\n return (\n <button\n type=\"button\"\n disabled\n aria-disabled=\"true\"\n {...rest}\n >\n {soldOutLabel}\n </button>\n );\n }\n\n async function handleClick() {\n if (state === \"adding\") return;\n setState(\"adding\");\n try {\n // addItem itself falls back to the live useVariantSelection state for\n // this product when no explicit axes are passed; the backend only uses\n // them when the variant row can't name itself (empty option_values).\n await addItem(product.id, variant?.id, quantity, selectedOptions);\n setState(\"idle\");\n onAdded?.(product, variant);\n } catch {\n setState(\"error\");\n // Auto-clear after 2s so the merchant can try again.\n setTimeout(() => setState(\"idle\"), 2000);\n }\n }\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={state === \"adding\"}\n aria-busy={state === \"adding\"}\n {...rest}\n >\n {state === \"adding\"\n ? loadingLabel\n : state === \"error\"\n ? errorLabel\n : label}\n </button>\n );\n}\n","\"use client\";\n\nimport {\n Component,\n type HTMLAttributes,\n type ReactNode,\n} from \"react\";\n\ninterface SectionProps extends HTMLAttributes<HTMLElement> {\n /** Section instance id (the order key in templates). Required for the\n * customizer's click-to-select to work. */\n id: string;\n /** Section type as registered in the theme registry / schemas. */\n type: string;\n /** Section group id (header / footer / announcement-bar) when this\n * section is mounted inside a group rather than a page template. */\n groupId?: string;\n /** Override the fallback shown when this section throws. Defaults to\n * a small inline error card (visible to the merchant in the customizer,\n * invisible to live shoppers — see CSS comment below). */\n errorFallback?: ReactNode;\n children: ReactNode;\n}\n\n// ── Section ErrorBoundary ───────────────────────────────────────────────────\n//\n// One thrown section used to take down the whole bundle's React tree —\n// every other section unmounted along with the bad one, leaving the\n// merchant with a blank storefront and no way to find the offender.\n//\n// We catch render/lifecycle errors at the per-section seam so a bug in\n// \"Hero v2\" doesn't break the perfectly fine \"Newsletter\" section\n// rendered on the same page. The boundary:\n//\n// 1. Logs the error + section context to console.error so the dev\n// console makes the offender obvious.\n// 2. Re-renders a fallback (defaults to a small error card; theme\n// can override via the `errorFallback` prop).\n// 3. Posts `numu:editor:section-error` to window.parent so the V3\n// customizer can highlight the offending section in its tree.\n//\n// The boundary is INSIDE the `<section data-section-id>` wrapper, so\n// the data attributes still let the customizer click-select the bad\n// section even when its body crashed — merchants can delete it.\n\ninterface BoundaryState {\n error: Error | null;\n}\n\ninterface SectionErrorBoundaryProps {\n sectionId: string;\n sectionType: string;\n fallback: ReactNode;\n children: ReactNode;\n}\n\nclass SectionErrorBoundary extends Component<\n SectionErrorBoundaryProps,\n BoundaryState\n> {\n state: BoundaryState = { error: null };\n\n static getDerivedStateFromError(error: Error): BoundaryState {\n return { error };\n }\n\n componentDidCatch(error: Error) {\n // Match the host's <ByotThemeBoundary> log shape so the prefix is\n // recognizable in the iframe console even when both boundaries fire.\n console.error(\n `[Section ${this.props.sectionType}#${this.props.sectionId}] threw:`,\n error,\n );\n if (typeof window !== \"undefined\" && window.parent !== window) {\n try {\n window.parent.postMessage(\n {\n type: \"numu:editor:section-error\",\n payload: {\n sectionId: this.props.sectionId,\n sectionType: this.props.sectionType,\n message: error.message,\n },\n },\n \"*\",\n );\n } catch {\n // Cross-origin postMessage with `*` is permissive enough that\n // this branch is for true edge cases (sandboxed iframe with\n // disallow-script). Nothing useful to do.\n }\n }\n }\n\n render() {\n if (this.state.error) return this.props.fallback;\n return this.props.children;\n }\n}\n\nfunction defaultSectionFallback(\n sectionType: string,\n sectionId: string,\n): ReactNode {\n return (\n <div\n role=\"alert\"\n data-numu-section-error=\"true\"\n style={{\n padding: \"1rem\",\n border: \"1px dashed #f87171\",\n background: \"#fef2f2\",\n color: \"#b91c1c\",\n fontFamily:\n \"system-ui, -apple-system, BlinkMacSystemFont, sans-serif\",\n fontSize: \"0.875rem\",\n lineHeight: 1.5,\n borderRadius: \"0.375rem\",\n margin: \"0.5rem 0\",\n }}\n >\n <div style={{ fontWeight: 600, marginBottom: \"0.25rem\" }}>\n Section failed to render\n </div>\n <div style={{ opacity: 0.9 }}>\n <code style={{ fontFamily: \"monospace\" }}>{sectionType}</code> threw\n an error. Check the browser console for details.\n </div>\n <div\n style={{\n opacity: 0.6,\n fontSize: \"0.75rem\",\n marginTop: \"0.25rem\",\n fontFamily: \"monospace\",\n }}\n >\n section #{sectionId}\n </div>\n </div>\n );\n}\n\n/**\n * <Section> — wrapper that emits the `data-section-id` / `data-section-type`\n * attributes the storefront's PreviewBridge needs to relay clicks back\n * to the V3 customizer for \"select section X\" navigation.\n *\n * Use this around the top-level element of every section component:\n *\n * export default function Hero({ settings, ...sectionMeta }) {\n * return (\n * <Section id={sectionMeta.id} type=\"hero\">\n * <h1>{settings.headline}</h1>\n * </Section>\n * );\n * }\n *\n * Without `data-section-id` on a real DOM ancestor, clicking anywhere\n * in the section in the customizer iframe falls through to the page\n * background and the merchant has to use the section list panel to\n * select sections — slow and confusing.\n *\n * Errors thrown by `children` are caught by an internal ErrorBoundary\n * so one bad section doesn't unmount its siblings. Customize the\n * fallback via `errorFallback`.\n */\nexport function Section({\n id,\n type,\n groupId,\n errorFallback,\n children,\n ...rest\n}: SectionProps) {\n return (\n <section\n data-section-id={id}\n data-section-type={type}\n data-group-id={groupId}\n {...rest}\n >\n <SectionErrorBoundary\n sectionId={id}\n sectionType={type}\n fallback={errorFallback ?? defaultSectionFallback(type, id)}\n >\n {children}\n </SectionErrorBoundary>\n </section>\n );\n}\n\ninterface BlockProps extends HTMLAttributes<HTMLDivElement> {\n /** Block instance id within its parent section. */\n id: string;\n type: string;\n /** Override the fallback shown when this block throws. */\n errorFallback?: ReactNode;\n children: ReactNode;\n}\n\n/**\n * <Block> — analog to <Section> for nested block selection. Same DOM\n * attribute contract; PreviewBridge reads `data-block-id` and reports\n * the block as selected when its child clicks bubble up.\n *\n * Wraps `children` in the same per-instance ErrorBoundary as <Section>\n * so a bad block within a section isolates its failure.\n */\nexport function Block({ id, type, errorFallback, children, ...rest }: BlockProps) {\n return (\n <div data-block-id={id} data-block-type={type} {...rest}>\n <SectionErrorBoundary\n sectionId={id}\n sectionType={type}\n fallback={errorFallback ?? defaultSectionFallback(type, id)}\n >\n {children}\n </SectionErrorBoundary>\n </div>\n );\n}\n","\"use client\";\n\nimport {\n useState,\n type FormEvent,\n type FormHTMLAttributes,\n type ReactNode,\n} from \"react\";\n\ninterface FormProps\n extends Omit<\n FormHTMLAttributes<HTMLFormElement>,\n \"onSubmit\" | \"method\" | \"action\" | \"children\" | \"onError\"\n > {\n /**\n * Endpoint to POST/etc. the form values to. Should be one of the\n * storefront's `/api/*` proxy routes — they handle CSRF + cookie\n * forwarding + idempotency on the way to FastAPI.\n */\n action: string;\n /**\n * HTTP method. POST is the typical theme use-case (newsletter,\n * contact, customer login, address create). GET is supported for\n * search-style forms.\n */\n method?: \"POST\" | \"GET\" | \"PUT\" | \"DELETE\";\n /**\n * Called with the JSON-decoded response body on success. Use to\n * trigger a toast, redirect, etc. Theme owns the UX.\n */\n onSuccess?: (response: unknown) => void;\n /**\n * Called with the Error on failure. Falls through to the default\n * error label otherwise.\n */\n onError?: (error: Error) => void;\n /**\n * Render-prop access to the in-flight state if the theme wants to\n * show its own loading / disabled / error UI. Default `children`\n * behavior just lets the form's inputs and submit button render —\n * we don't impose styling.\n */\n children?:\n | ReactNode\n | ((state: { submitting: boolean; error: Error | null }) => ReactNode);\n}\n\nconst ABSOLUTE_URL = /^[a-z]+:|^\\/\\//i;\n\nfunction readCsrfCookie(): string | null {\n if (typeof document === \"undefined\") return null;\n const m = document.cookie.match(/(?:^|;\\s*)numu_csrf=([^;]+)/);\n return m ? decodeURIComponent(m[1]) : null;\n}\n\nfunction newIdempotencyKey(): string {\n if (typeof crypto !== \"undefined\" && \"randomUUID\" in crypto) {\n return crypto.randomUUID();\n }\n return `${Date.now()}-${Math.random().toString(36).slice(2)}`;\n}\n\n/**\n * <Form action=\"/api/cart/add\" method=\"POST\" onSuccess={...}>\n *\n * Theme-friendly wrapper around `<form>` that handles:\n * - CSRF: reads `numu_csrf` cookie, sends as `x-numu-csrf` header on\n * every mutating request. Same wire format as <NuMuProvider>'s\n * cart machinery — interoperates seamlessly.\n * - Idempotency: mints a UUID per submit, sends as\n * `x-numu-idempotency-key`. Backend dedupes if it supports the\n * header (cart endpoints today; more later).\n * - Submit lifecycle: tracks `submitting` + `error` state and\n * either passes them to a render-prop child or wires them to a\n * submit-button's `disabled` automatically.\n * - Throws away page navigation: `onSubmit` calls preventDefault and\n * fetches via JSON. Themes that want classic POST-and-navigate\n * can drop down to a plain `<form>`.\n *\n * Refuses to submit to absolute URLs (must point at the storefront\n * itself or an `/api/*` proxy) so a misconfigured theme can't leak\n * customer data to a third party origin.\n */\nexport function Form({\n action,\n method = \"POST\",\n onSuccess,\n onError,\n children,\n ...rest\n}: FormProps) {\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n async function handleSubmit(e: FormEvent<HTMLFormElement>) {\n e.preventDefault();\n\n if (ABSOLUTE_URL.test(action)) {\n const err = new Error(\n `<Form action> must be a same-origin path (got \"${action}\"). ` +\n `Use a /api/* proxy route or your route handler.`,\n );\n setError(err);\n onError?.(err);\n return;\n }\n\n setSubmitting(true);\n setError(null);\n try {\n const formData = new FormData(e.currentTarget);\n const isMutation = method !== \"GET\";\n\n // Convert FormData → JSON. Themes can pass `data-numu-multipart=\"true\"`\n // on the form to opt into multipart instead (file uploads).\n const isMultipart =\n e.currentTarget.dataset?.numuMultipart === \"true\";\n\n const headers: Record<string, string> = {};\n if (!isMultipart) headers[\"Content-Type\"] = \"application/json\";\n if (isMutation) {\n const csrf = readCsrfCookie();\n if (csrf) headers[\"x-numu-csrf\"] = csrf;\n headers[\"x-numu-idempotency-key\"] = newIdempotencyKey();\n }\n\n let url = action;\n let body: BodyInit | undefined;\n if (method === \"GET\") {\n const params = new URLSearchParams();\n for (const [k, v] of formData.entries()) {\n if (typeof v === \"string\") params.append(k, v);\n }\n const sep = action.includes(\"?\") ? \"&\" : \"?\";\n url = `${action}${sep}${params.toString()}`;\n } else if (isMultipart) {\n body = formData;\n } else {\n const obj: Record<string, FormDataEntryValue> = {};\n for (const [k, v] of formData.entries()) obj[k] = v;\n body = JSON.stringify(obj);\n }\n\n const res = await fetch(url, { method, headers, body });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(\n `${method} ${action} failed: ${res.status} ${res.statusText}${\n text ? ` — ${text.slice(0, 200)}` : \"\"\n }`,\n );\n }\n const json = res.headers\n .get(\"content-type\")\n ?.includes(\"application/json\")\n ? await res.json()\n : await res.text();\n onSuccess?.(json);\n } catch (err) {\n const e2 = err instanceof Error ? err : new Error(String(err));\n setError(e2);\n onError?.(e2);\n } finally {\n setSubmitting(false);\n }\n }\n\n return (\n <form\n onSubmit={handleSubmit}\n method={method}\n action={action}\n aria-busy={submitting}\n {...rest}\n >\n {typeof children === \"function\"\n ? children({ submitting, error })\n : children}\n </form>\n );\n}\n","/**\n * Storefront route builders.\n *\n * The storefront's URL shape is platform knowledge, not theme knowledge: a\n * theme that hardcodes `/products/${slug}` has quietly taken a dependency on\n * the host's routing, and every copy of that template is a place the fleet can\n * disagree with the host. Centralising the templates here means a route change\n * is one edit rather than a fleet-wide grep.\n *\n * Hoisted out of the themes' `sections/_shared.ts`, where `productHref` was\n * hand-copied into 4 themes and their 4 scaffold templates.\n */\n\n/**\n * Link to a product detail page.\n *\n * Falls back to the product index when there's no identifier, so a card built\n * from incomplete data links somewhere useful instead of `/products/undefined`.\n */\nexport function productHref(slugOrId: string | undefined | null): string {\n if (!slugOrId) return \"/products\";\n return `/products/${slugOrId}`;\n}\n\n/**\n * Link to a collection page.\n *\n * Prefers the slug and falls back to the id, because a category with no slug\n * is common in practice and the bare template produces `/collections/undefined`\n * — a 404 the merchant sees as a broken menu item. Accepts either a category\n * object or a plain slug string so call sites don't have to unpack first.\n */\nexport function collectionHref(\n category: string | { slug?: string | null; id?: string | null } | null | undefined,\n): string {\n if (!category) return \"/collections\";\n if (typeof category === \"string\") {\n return category ? `/collections/${category}` : \"/collections\";\n }\n const key = category.slug || category.id;\n return key ? `/collections/${key}` : \"/collections\";\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport type { Product } from \"../types/entities\";\nimport { Image } from \"./Image\";\nimport { Money } from \"./Money\";\nimport { Link } from \"./Link\";\nimport { AddToCartButton } from \"./AddToCartButton\";\nimport { productHref } from \"../utils/routes\";\n\n/**\n * Opinionated product tile.\n *\n * Themes drop this anywhere a product list is needed — collection\n * pages, search results, recommendations, recently-viewed grids.\n * Renders image + title + price (with compare-at strike-through when\n * present) + an optional \"Sold out\" badge + AddToCartButton.\n *\n * The component is **unstyled by default** — it ships only structural\n * markup with stable class names. Themes provide the CSS. Class names\n * use a `numu-product-card__*` BEM convention so themes can target\n * pieces without grep-and-replace if NUMU later renames anything.\n *\n * Class hooks:\n * .numu-product-card — root <article>\n * .numu-product-card__link — wrapping <a>\n * .numu-product-card__media — image container\n * .numu-product-card__image — the <img> itself\n * .numu-product-card__badge — \"Sold out\" overlay\n * .numu-product-card__title — title <h3>\n * .numu-product-card__price — price wrapper\n * .numu-product-card__cta — CTA wrapper (AddToCartButton)\n *\n * Themes can override any piece by passing `slots`:\n * <ProductCard product={p} slots={{ price: <CustomPrice /> }} />\n *\n * For deeper customization, themes should compose the primitives\n * (Image / Money / Link / AddToCartButton) directly instead.\n */\nexport interface ProductCardSlots {\n /** Replaces the badge area (default: \"Sold out\" when out of stock, else nothing). */\n badge?: ReactNode;\n /** Replaces the title `<h3>` block. */\n title?: ReactNode;\n /** Replaces the price `<Money>` block. */\n price?: ReactNode;\n /** Replaces the AddToCartButton. Pass `null` to hide it. */\n cta?: ReactNode | null;\n}\n\nexport interface ProductCardProps {\n product: Product;\n /** Override the link target. Default: `/products/{slug}`. */\n href?: string;\n className?: string;\n slots?: ProductCardSlots;\n /**\n * Image sizing hint for the responsive srcSet. Default: a 4-up grid\n * sizing (~25vw at desktop, ~50vw at tablet, ~100vw at mobile).\n * Override when rendering in a different layout density.\n */\n imageSizes?: string;\n}\n\nfunction joinClass(...names: Array<string | undefined | null | false>): string {\n return names.filter(Boolean).join(\" \");\n}\n\nexport function ProductCard({\n product,\n href,\n className,\n slots,\n imageSizes,\n}: ProductCardProps) {\n // Same builder the themes use, so the card and a theme's own links can't\n // disagree about the product route.\n const target = href ?? productHref(product.slug);\n const firstImage = product.images?.[0];\n const inStock = product.in_stock;\n\n const badge =\n slots?.badge !== undefined\n ? slots.badge\n : inStock\n ? null\n : (\n <span className=\"numu-product-card__badge\">Sold out</span>\n );\n\n return (\n <article className={joinClass(\"numu-product-card\", className)}>\n <Link to={target} className=\"numu-product-card__link\">\n <div className=\"numu-product-card__media\">\n <Image\n src={firstImage?.url}\n alt={firstImage?.alt || product.name}\n sizes={imageSizes}\n className=\"numu-product-card__image\"\n />\n {badge}\n </div>\n {slots?.title ?? (\n <h3 className=\"numu-product-card__title\">{product.name}</h3>\n )}\n {slots?.price ?? (\n <div className=\"numu-product-card__price\">\n <Money\n amount={product.price}\n compareAt={product.compare_at_price}\n currency={product.currency}\n />\n </div>\n )}\n </Link>\n {slots?.cta === null\n ? null\n : (\n <div className=\"numu-product-card__cta\">\n {slots?.cta ?? <AddToCartButton product={product} />}\n </div>\n )}\n </article>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport type { Collection } from \"../types/entities\";\nimport { Image } from \"./Image\";\nimport { Link } from \"./Link\";\n\n/**\n * Opinionated collection tile.\n *\n * Renders a single collection's hero image + name + product count.\n * Used by collection-list sections, footer \"Featured collections\"\n * blocks, and search-result mixed views.\n *\n * Unstyled by default; themes ship the CSS. Class hooks:\n * .numu-collection-card — root <article>\n * .numu-collection-card__link — wrapping <a>\n * .numu-collection-card__media — image container\n * .numu-collection-card__image — the <img>\n * .numu-collection-card__title — title <h3>\n * .numu-collection-card__count — product count line\n */\nexport interface CollectionCardSlots {\n title?: ReactNode;\n /** Replaces the \"N products\" line. Pass null to hide it. */\n count?: ReactNode | null;\n}\n\nexport interface CollectionCardProps {\n collection: Collection;\n /** Override the link target. Default: `/collections/{slug}`. */\n href?: string;\n className?: string;\n slots?: CollectionCardSlots;\n imageSizes?: string;\n}\n\nfunction joinClass(...names: Array<string | undefined | null | false>): string {\n return names.filter(Boolean).join(\" \");\n}\n\nexport function CollectionCard({\n collection,\n href,\n className,\n slots,\n imageSizes,\n}: CollectionCardProps) {\n const target = href ?? `/collections/${collection.slug}`;\n const productCount =\n typeof collection.product_count === \"number\"\n ? collection.product_count\n : undefined;\n\n return (\n <article className={joinClass(\"numu-collection-card\", className)}>\n <Link to={target} className=\"numu-collection-card__link\">\n <div className=\"numu-collection-card__media\">\n <Image\n src={collection.image_url}\n alt={collection.name}\n sizes={imageSizes}\n className=\"numu-collection-card__image\"\n />\n </div>\n {slots?.title ?? (\n <h3 className=\"numu-collection-card__title\">{collection.name}</h3>\n )}\n {slots?.count === null\n ? null\n : (slots?.count ?? (\n productCount !== undefined && (\n <p className=\"numu-collection-card__count\">\n {productCount === 1 ? \"1 product\" : `${productCount} products`}\n </p>\n )\n ))}\n </Link>\n </article>\n );\n}\n","\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\n\n/**\n * <RichText html=... /> — sanitized HTML renderer.\n *\n * Wraps `dangerouslySetInnerHTML` so theme code stops calling it\n * directly with merchant-supplied content. Themes that need to render\n * rich-text fields (product descriptions, page bodies, blog articles,\n * policy bodies) go through this so an XSS in a single field can't\n * cross-contaminate the whole storefront.\n *\n * **Why a built-in allowlist sanitizer instead of DOMPurify?**\n * The audit plan called for DOMPurify, but adding it as a hard dep\n * inflates every theme bundle by ~12KB gzipped — and the merchant-\n * editable surface is small enough (a fixed set of formatting tags +\n * links + images) that a curated allowlist is both smaller AND easier\n * to reason about. If a theme needs richer sanitization (embeds,\n * iframes, MathML), it can import DOMPurify directly and pre-sanitize\n * before passing the result here.\n *\n * Allowed tags:\n * p, br, hr, h1-h6, blockquote, pre, code,\n * strong, b, em, i, u, s, sub, sup, mark,\n * ul, ol, li, dl, dt, dd,\n * a (href, target, rel only),\n * img (src, alt, width, height, loading only — http(s) URLs only),\n * table, thead, tbody, tr, th, td,\n * span, div (with class attribute only).\n *\n * Stripped:\n * <script>, <style>, <iframe>, <object>, <embed>, <link>, <meta>,\n * form/input, on*= handlers, javascript:/data: URLs, srcset on\n * <img> (we let the storefront's image-transform handle that\n * uniformly).\n */\nexport interface RichTextProps {\n html: string | null | undefined;\n className?: string;\n /** Element to render — defaults to `<div>`. Use `<article>` for body content. */\n as?: \"div\" | \"article\" | \"section\" | \"aside\";\n}\n\nconst ALLOWED_TAGS: ReadonlySet<string> = new Set([\n \"p\", \"br\", \"hr\",\n \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\",\n \"blockquote\", \"pre\", \"code\",\n \"strong\", \"b\", \"em\", \"i\", \"u\", \"s\", \"sub\", \"sup\", \"mark\",\n \"ul\", \"ol\", \"li\", \"dl\", \"dt\", \"dd\",\n \"a\", \"img\",\n \"table\", \"thead\", \"tbody\", \"tr\", \"th\", \"td\",\n \"span\", \"div\",\n]);\n\nconst ALLOWED_ATTRS_BY_TAG: Record<string, ReadonlySet<string>> = {\n a: new Set([\"href\", \"target\", \"rel\", \"class\", \"title\"]),\n img: new Set([\"src\", \"alt\", \"width\", \"height\", \"loading\", \"class\"]),\n span: new Set([\"class\"]),\n div: new Set([\"class\"]),\n p: new Set([\"class\"]),\n h1: new Set([\"class\"]), h2: new Set([\"class\"]), h3: new Set([\"class\"]),\n h4: new Set([\"class\"]), h5: new Set([\"class\"]), h6: new Set([\"class\"]),\n blockquote: new Set([\"class\"]),\n pre: new Set([\"class\"]),\n code: new Set([\"class\"]),\n ul: new Set([\"class\"]), ol: new Set([\"class\"]), li: new Set([\"class\"]),\n table: new Set([\"class\"]),\n thead: new Set([\"class\"]), tbody: new Set([\"class\"]),\n tr: new Set([\"class\"]), th: new Set([\"class\"]), td: new Set([\"class\"]),\n};\n\nconst URL_SAFE_PROTOCOLS = /^(https?|mailto|tel):/i;\n\nfunction isSafeUrl(url: string): boolean {\n const trimmed = url.trim();\n if (!trimmed) return false;\n // Relative paths are fine.\n if (trimmed.startsWith(\"/\") || trimmed.startsWith(\"#\") || trimmed.startsWith(\"?\")) {\n return true;\n }\n // Protocol-bearing — only http/https/mailto/tel.\n return URL_SAFE_PROTOCOLS.test(trimmed);\n}\n\n/**\n * Sanitize an HTML string against the allowlist above. Runs server-\n * AND client-side because rich-text fields are server-rendered for SEO.\n *\n * Implementation note: in the browser we use DOMParser (structural allowlist\n * — see `sanitizeHtmlClient`/`walk`). On the server (no DOM) we fall through\n * to `sanitizeHtmlServer`, a hardened regex denylist that strips dangerous\n * element blocks to a fixpoint, removes inline event handlers (incl.\n * slash-separated ones), and drops non-allowlisted `href`/`src` URLs. Themes\n * needing server-rendered rich content with edge-case structure should\n * sanitize on the API tier and pass already-safe HTML through.\n */\nexport function sanitizeHtml(input: string): string {\n if (!input) return \"\";\n if (typeof window === \"undefined\" || typeof DOMParser === \"undefined\") {\n return sanitizeHtmlServer(input);\n }\n return sanitizeHtmlClient(input);\n}\n\nfunction sanitizeHtmlClient(input: string): string {\n const doc = new DOMParser().parseFromString(\n `<div>${input}</div>`,\n \"text/html\",\n );\n const root = doc.body.firstElementChild;\n if (!root) return \"\";\n walk(root);\n return root.innerHTML;\n}\n\nfunction walk(node: Element): void {\n const children = Array.from(node.children);\n for (const child of children) {\n const tag = child.tagName.toLowerCase();\n if (!ALLOWED_TAGS.has(tag)) {\n // Replace forbidden tag with its sanitized text content. Drops\n // entire subtree if the tag is one we never want (script/style).\n if (tag === \"script\" || tag === \"style\" || tag === \"iframe\" || tag === \"object\" || tag === \"embed\") {\n child.remove();\n } else {\n const text = child.textContent || \"\";\n child.replaceWith(document.createTextNode(text));\n }\n continue;\n }\n // Strip disallowed attributes.\n const allowed = ALLOWED_ATTRS_BY_TAG[tag] || new Set<string>();\n for (const attr of Array.from(child.attributes)) {\n const name = attr.name.toLowerCase();\n // on*= handlers → always strip.\n if (name.startsWith(\"on\")) {\n child.removeAttribute(attr.name);\n continue;\n }\n if (!allowed.has(name)) {\n child.removeAttribute(attr.name);\n continue;\n }\n // URL-bearing attrs → protocol-check.\n if ((name === \"href\" || name === \"src\") && !isSafeUrl(attr.value)) {\n child.removeAttribute(attr.name);\n continue;\n }\n }\n // Anchor hardening: every external link gets rel=\"noopener noreferrer\"\n // when target=\"_blank\" is set. Stops reverse-tabnabbing without the\n // theme dev having to remember.\n if (tag === \"a\" && child.getAttribute(\"target\") === \"_blank\") {\n child.setAttribute(\"rel\", \"noopener noreferrer\");\n }\n walk(child);\n }\n}\n\n/**\n * Server-side fallback sanitizer — DOM-free, so it runs during SSR (this is\n * the string that ships in the FIRST paint before hydration upgrades to the\n * structural DOMParser walk). Being regex-based it can't be a full parser, so\n * it's hardened as a denylist that closes the known bypasses:\n *\n * (a) Inline event handlers: the separator before the `on…` name is a class\n * `[\\s/\"'<]`, not just `\\s`, so slash-separated handlers are caught —\n * `<img/onerror=alert(1)>` (no whitespace before `onerror`) previously\n * survived the `\\s+on\\w+=` pass entirely.\n * (b) Dangerous element blocks (`<script>`, `<style>`, `<iframe>`, …) are\n * stripped to a FIXPOINT (repeat until the string stops changing).\n * A single pass is defeatable by nesting —\n * `<scr<script></script>ipt>alert(1)</scr…ipt>` collapses into a fresh\n * `<script>` once the inner match is removed.\n * (c) `javascript:` / `data:` (and any non-allowlisted protocol) in\n * `href`/`src` are removed via `isSafeUrl` (allowlist: http(s), mailto,\n * tel, relative). The whole attribute is dropped when the value fails.\n *\n * The client path (`sanitizeHtmlClient`) remains the real allowlist — it walks\n * a parsed DOM and drops any tag/attribute not on the allowlist — and takes\n * over after mount. Themes needing richer SSR structure should sanitize on the\n * API tier and pass already-safe HTML through.\n */\nfunction sanitizeHtmlServer(input: string): string {\n if (!input) return \"\";\n let s = input;\n let prev: string;\n\n // (b) Strip dangerous element blocks + any standalone opener/closer/void of\n // document-scope tags, repeated to a fixpoint so nested/truncated markup\n // can't reconstitute an executable island after one pass.\n const DANGEROUS: RegExp[] = [\n /<script\\b[\\s\\S]*?<\\/script\\s*>/gi,\n /<style\\b[\\s\\S]*?<\\/style\\s*>/gi,\n /<iframe\\b[\\s\\S]*?<\\/iframe\\s*>/gi,\n /<object\\b[\\s\\S]*?<\\/object\\s*>/gi,\n /<embed\\b[\\s\\S]*?<\\/embed\\s*>/gi,\n /<\\/?(?:script|style|iframe|object|embed|link|meta|form|input)\\b[^>]*>/gi,\n ];\n do {\n prev = s;\n for (const re of DANGEROUS) s = s.replace(re, \"\");\n } while (s !== prev);\n\n // (a) Strip inline event handlers to a fixpoint, with a broadened separator\n // class so slash/quote-separated handlers are caught, not just space-led.\n const HANDLER = /[\\s/\"'<]on\\w+\\s*=\\s*(\"[^\"]*\"|'[^']*'|[^\\s>]+)/gi;\n do {\n prev = s;\n s = s.replace(HANDLER, \"\");\n } while (s !== prev);\n\n // (c) Strip non-allowlisted URLs (javascript:/data:/…) in href/src — the\n // whole attribute is dropped when isSafeUrl rejects the value.\n s = s.replace(\n /[\\s/\"'<](href|src)\\s*=\\s*(\"[^\"]*\"|'[^']*'|[^\\s>]+)/gi,\n (full: string, _attr: string, val: string) => {\n const cleaned = String(val).replace(/^['\"]|['\"]$/g, \"\");\n return isSafeUrl(cleaned) ? full : \"\";\n },\n );\n\n return s;\n}\n\nexport function RichText({ html, className, as = \"div\" }: RichTextProps) {\n // Hydration-stable two-pass sanitize: the FIRST client render must produce\n // the same string the server produced, so when the theme is server-rendered\n // (`createApp` + hydrateRoot) the dangerouslySetInnerHTML payloads match.\n // The regex pass and the DOMParser pass can legitimately differ on edge\n // cases (attribute ordering, entity normalisation), so we render the\n // server-algorithm output first everywhere and upgrade to the structural\n // DOMParser sanitize after mount.\n const [domReady, setDomReady] = useState(false);\n useEffect(() => {\n setDomReady(true);\n }, []);\n const safe = useMemo(\n () => (domReady ? sanitizeHtml(html || \"\") : sanitizeHtmlServer(html || \"\")),\n [html, domReady],\n );\n if (!safe) return null;\n const Tag = as;\n return (\n <Tag\n className={className}\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: safe }}\n />\n );\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useCurrency } from \"../hooks/useCurrency\";\n\n/**\n * <CurrencySwitcher /> — wired in Phase 6.\n *\n * Reads presentment currencies + the persisted selection from\n * `useCurrency()`, which talks to\n * `/api/storefront/store/{id}/currencies`. Changing the dropdown\n * writes the `numu_currency` cookie via the hook, which then\n * propagates to `<Money>`'s display.\n *\n * Renders nothing when the store offers only one currency — themes\n * can drop the component into a layout without conditional render.\n *\n * Pass `render` to take over the markup completely (e.g. a custom\n * dropdown component or a flag-icon grid).\n */\n\nexport interface CurrencySwitcherProps {\n className?: string;\n onSelect?: (currency: string) => void;\n render?: (state: {\n currencies: string[];\n current: string;\n onChange: (next: string) => void;\n }) => React.ReactNode;\n}\n\nexport function CurrencySwitcher({\n className,\n onSelect,\n render,\n}: CurrencySwitcherProps) {\n const { presentment, selected, setSelected, loading } = useCurrency();\n\n const handleChange = useCallback(\n (next: string) => {\n if (next === selected) return;\n setSelected(next);\n onSelect?.(next);\n },\n [selected, setSelected, onSelect],\n );\n\n // No alternatives, or still loading the list. We don't want to\n // briefly flash a 1-option dropdown while the API resolves.\n if (loading) return null;\n if (presentment.length <= 1) return null;\n\n if (render) {\n return (\n <>\n {render({\n currencies: presentment,\n current: selected,\n onChange: handleChange,\n })}\n </>\n );\n }\n\n return (\n <select\n className={className ?? \"numu-currency-switcher\"}\n value={selected}\n onChange={(e) => handleChange(e.target.value)}\n aria-label=\"Currency\"\n >\n {presentment.map((c) => (\n <option key={c} value={c}>\n {c}\n </option>\n ))}\n </select>\n );\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useShop } from \"../hooks/useShop\";\nimport { useLocalization } from \"../hooks/useLocalization\";\n\n/**\n * <LocaleSwitcher /> — language toggle for stores with multiple locales.\n *\n * v1 supports Arabic + English (the storefront's default_language gates\n * which one is the \"primary\"). This component:\n * - Reads `store.available_locales` (or falls back to\n * [default_language, \"en\"] for stores that haven't been migrated yet).\n * - Renders nothing when there's only one locale.\n * - On change, sets a `numu_locale` cookie + reloads the page so the\n * server-rendered layout picks up the new locale (the storefront\n * middleware reads the cookie and stamps `<html lang/dir>`\n * accordingly).\n *\n * Why a hard reload instead of client-side state swap:\n * Locale impacts SSR-rendered content (currency formatting, product\n * field translations, page metadata). Client-side toggling would\n * leave the SSR output inconsistent until the next navigation.\n * One reload trades a brief flicker for guaranteed correctness.\n */\n\nconst LANG_LABELS: Record<string, string> = {\n ar: \"العربية\",\n en: \"English\",\n fr: \"Français\",\n he: \"עברית\",\n fa: \"فارسی\",\n ur: \"اردو\",\n es: \"Español\",\n de: \"Deutsch\",\n};\n\nexport interface LocaleSwitcherProps {\n className?: string;\n onSelect?: (locale: string) => void;\n /** Custom renderer. Receives the resolved locale list + current selection. */\n render?: (state: {\n locales: string[];\n current: string;\n labelFor: (code: string) => string;\n onChange: (next: string) => void;\n }) => React.ReactNode;\n}\n\nexport function LocaleSwitcher({\n className,\n onSelect,\n render,\n}: LocaleSwitcherProps) {\n const shop = useShop();\n const { locale } = useLocalization();\n const available =\n (shop as unknown as { available_locales?: string[] }).available_locales || [];\n // Fallback for stores that don't yet expose available_locales: assume\n // the store's default_language plus English when they differ.\n const list =\n available.length > 0\n ? available\n : shop.default_language === \"en\"\n ? [\"en\"]\n : Array.from(new Set([shop.default_language, \"en\"]));\n\n const labelFor = useCallback((code: string): string => {\n return LANG_LABELS[code] || code.toUpperCase();\n }, []);\n\n const handleChange = useCallback(\n (next: string) => {\n if (next === locale) return;\n onSelect?.(next);\n if (typeof document !== \"undefined\") {\n const oneYear = 60 * 60 * 24 * 365;\n document.cookie = `numu_locale=${encodeURIComponent(next)}; path=/; max-age=${oneYear}; samesite=lax`;\n }\n // Hard reload so SSR re-runs with the new locale. Use replace()\n // so the locale toggle doesn't pollute browser back history.\n if (typeof window !== \"undefined\") {\n window.location.reload();\n }\n },\n [locale, onSelect],\n );\n\n if (list.length <= 1) return null;\n\n if (render) {\n return <>{render({ locales: list, current: locale, labelFor, onChange: handleChange })}</>;\n }\n\n return (\n <select\n className={className ?? \"numu-locale-switcher\"}\n value={locale}\n onChange={(e) => handleChange(e.target.value)}\n aria-label=\"Language\"\n >\n {list.map((l) => (\n <option key={l} value={l}>\n {labelFor(l)}\n </option>\n ))}\n </select>\n );\n}\n","\"use client\";\n\n/**\n * <EditableText> / <EditableImage> — V3 SDK editor-affordance markers.\n *\n * These are the \"I want to edit this\" hooks for V3 themes. They render\n * a normal element (span / img) on live storefronts, but inside the\n * customizer iframe they:\n *\n * 1. Stamp a `data-numu-editable` attribute so the storefront's\n * PreviewBridge can scope click-to-select to specific fields\n * (rather than the whole section).\n * 2. Show a subtle hover affordance (dotted underline / ring) so the\n * merchant discovers what's editable inline.\n * 3. Bubble up a `numu:editor:select-field` postMessage on click,\n * so the dashboard can scroll the matching setting input into\n * view + focus it.\n *\n * Editor mode is detected the same way PreviewBridge does — query\n * params `editor=v3` OR `preview=true`. Outside the editor, these are\n * pass-through `<span>` / `<img>` with no extra cost.\n *\n * Usage in a V3 section:\n *\n * import { EditableText, EditableImage } from \"@numueg/theme-sdk\";\n *\n * export default function Hero({ instance }: SectionProps) {\n * const { settings } = instance;\n * return (\n * <>\n * <EditableText\n * settingId=\"headline\"\n * sectionId={instance.id}\n * value={settings.headline}\n * as=\"h1\"\n * className=\"text-4xl\"\n * />\n * <EditableImage\n * settingId=\"hero_image\"\n * sectionId={instance.id}\n * src={settings.hero_image}\n * alt={settings.image_alt}\n * />\n * </>\n * );\n * }\n *\n * Why two components instead of one polymorphic `<Editable>`? Text and\n * image have different click semantics (text → focus the matching\n * setting; image → open the media picker) and different DOM shapes,\n * and we want the JSX to read naturally. Future field types (link,\n * color picker, video) get their own component pair.\n */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useMemo,\n useState,\n type ElementType,\n type HTMLAttributes,\n type ImgHTMLAttributes,\n type ReactNode,\n} from \"react\";\n\n// ─── Editor-mode detection ──────────────────────────────────────────────────\n\n/**\n * The detection runs lazily (after mount) to keep SSR HTML identical\n * to the first client paint. If we read window.location during render,\n * we'd return false on the server and true on the client → hydration\n * mismatch. By gating on a useEffect-set state, the initial paint\n * never adds editor-only attributes, and they appear on the second\n * paint (one tick later, after the bridge is awake anyway).\n */\nfunction useIsEditor(): boolean {\n const [isEditor, setIsEditor] = useState(false);\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n try {\n const params = new URLSearchParams(window.location.search);\n const flag =\n params.get(\"editor\") === \"v3\" || params.get(\"preview\") === \"true\";\n // The iframe-only check: the merchant's customizer renders this\n // bundle inside an iframe. On a \"plain\" preview tab (no parent\n // window), we keep the editor-mode markers off — they'd be\n // useless to a merchant browsing their own storefront in a\n // separate tab.\n const inFrame = window.parent !== window;\n setIsEditor(flag && inFrame);\n } catch {\n // No-op — SSR / sandboxed environments fall through to false.\n }\n }, []);\n return isEditor;\n}\n\n/**\n * Post a \"this field was clicked\" event to the dashboard so the editor\n * can scroll the matching setting input into view + focus it.\n *\n * Origin is `*` because the parent's origin varies (dev / staging /\n * prod / different merchant subdomains). The dashboard side enforces\n * origin matching for INBOUND messages from the iframe, so an\n * attacker can't spoof a select-field event by hijacking\n * postMessage — the dashboard's origin gate drops anything not from\n * the storefront's exact origin.\n */\nfunction postFieldSelected(\n sectionId: string,\n settingId: string,\n blockId?: string | null,\n): void {\n if (typeof window === \"undefined\") return;\n if (window.parent === window) return;\n try {\n window.parent.postMessage(\n {\n type: \"numu:editor:select-field\",\n payload: {\n sectionId,\n blockId: blockId ?? null,\n settingId,\n },\n },\n \"*\",\n );\n } catch {\n /* parent gone / sandboxed strictly — no-op */\n }\n}\n\n// ─── EditableText ───────────────────────────────────────────────────────────\n\nexport interface EditableTextProps\n extends Omit<HTMLAttributes<HTMLElement>, \"children\"> {\n /** The section instance id (key inside templates.<page>.sections). */\n sectionId: string;\n /** Optional block id when the field lives inside a section block. */\n blockId?: string | null;\n /** The setting key from the section's schema (e.g. \"headline\"). */\n settingId: string;\n /** The current text value (may be HTML for inline_richtext settings). */\n value: string | undefined | null;\n /**\n * Element to render. Defaults to `<span>` so the component is\n * inline-compatible. Pass \"h1\" / \"h2\" / \"p\" / \"div\" for block-level\n * usage.\n */\n as?: ElementType;\n /**\n * Set to true to render the value as HTML (for inline_richtext\n * settings whose stored form is `<b>Welcome</b>`). Defaults to false\n * — plain-text fields are rendered as a text node.\n */\n html?: boolean;\n /** Empty-state placeholder shown when value is \"\" / null. */\n placeholder?: ReactNode;\n}\n\nexport const EditableText = forwardRef<HTMLElement, EditableTextProps>(\n function EditableText(\n {\n sectionId,\n blockId,\n settingId,\n value,\n as: Component = \"span\",\n html = false,\n placeholder,\n className,\n onClick,\n style,\n ...rest\n },\n ref,\n ) {\n const isEditor = useIsEditor();\n\n const handleClick = useCallback(\n (e: React.MouseEvent<HTMLElement>) => {\n // Forward the click first so themes that wired their own\n // handler keep working.\n onClick?.(e);\n if (!isEditor) return;\n // The whole point: route the click to the matching setting\n // input. Stop propagation only when the editor is open so we\n // don't double-fire the section-level click-to-select handler\n // that PreviewBridge installs at the document level. Themes\n // can still receive the click via their own onClick prop\n // (already invoked above).\n e.stopPropagation();\n postFieldSelected(sectionId, settingId, blockId);\n },\n [isEditor, onClick, sectionId, settingId, blockId],\n );\n\n const editorAttrs = useMemo(\n () =>\n isEditor\n ? {\n \"data-numu-editable\": \"text\",\n \"data-numu-section-id\": sectionId,\n \"data-numu-setting-id\": settingId,\n \"data-numu-block-id\": blockId ?? undefined,\n role: \"button\" as const,\n tabIndex: 0,\n }\n : {},\n [isEditor, sectionId, settingId, blockId],\n );\n\n const effectiveStyle = isEditor\n ? {\n ...style,\n cursor: \"text\" as const,\n // Subtle dotted underline so the merchant discovers what's\n // editable. The dashed style + inherited color keeps the\n // affordance from clashing with the theme's typography.\n textDecoration: \"underline dotted rgba(99, 102, 241, 0.7)\",\n textUnderlineOffset: \"4px\",\n }\n : style;\n\n const isEmpty = value == null || value === \"\";\n const display = isEmpty && placeholder !== undefined ? placeholder : value ?? \"\";\n\n if (html && typeof display === \"string\") {\n return (\n <Component\n ref={ref}\n className={className}\n style={effectiveStyle}\n onClick={handleClick}\n dangerouslySetInnerHTML={{ __html: display }}\n {...editorAttrs}\n {...rest}\n />\n );\n }\n return (\n <Component\n ref={ref}\n className={className}\n style={effectiveStyle}\n onClick={handleClick}\n {...editorAttrs}\n {...rest}\n >\n {display}\n </Component>\n );\n },\n);\n\n// ─── EditableImage ──────────────────────────────────────────────────────────\n\nexport interface EditableImageProps\n extends Omit<ImgHTMLAttributes<HTMLImageElement>, \"src\"> {\n sectionId: string;\n blockId?: string | null;\n settingId: string;\n /** Image src — may be empty/undefined if the merchant hasn't picked one yet. */\n src: string | undefined | null;\n /** Placeholder src shown when `src` is empty. Defaults to a 1x1 transparent gif. */\n emptyPlaceholderSrc?: string;\n}\n\nconst EMPTY_GIF =\n \"data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==\";\n\nexport const EditableImage = forwardRef<HTMLImageElement, EditableImageProps>(\n function EditableImage(\n {\n sectionId,\n blockId,\n settingId,\n src,\n alt,\n emptyPlaceholderSrc,\n className,\n onClick,\n style,\n ...rest\n },\n ref,\n ) {\n const isEditor = useIsEditor();\n const isEmpty = !src;\n\n const handleClick = useCallback(\n (e: React.MouseEvent<HTMLImageElement>) => {\n onClick?.(e);\n if (!isEditor) return;\n e.stopPropagation();\n postFieldSelected(sectionId, settingId, blockId);\n },\n [isEditor, onClick, sectionId, settingId, blockId],\n );\n\n const editorAttrs = useMemo(\n () =>\n isEditor\n ? {\n \"data-numu-editable\": \"image\",\n \"data-numu-section-id\": sectionId,\n \"data-numu-setting-id\": settingId,\n \"data-numu-block-id\": blockId ?? undefined,\n role: \"button\" as const,\n tabIndex: 0,\n }\n : {},\n [isEditor, sectionId, settingId, blockId],\n );\n\n const effectiveStyle = isEditor\n ? {\n ...style,\n cursor: \"pointer\" as const,\n outline: isEmpty\n ? \"2px dashed rgba(99, 102, 241, 0.6)\"\n : \"2px dashed transparent\",\n outlineOffset: \"-2px\",\n }\n : style;\n\n const effectiveSrc = src || emptyPlaceholderSrc || EMPTY_GIF;\n const effectiveAlt = alt ?? \"\";\n\n return (\n <img\n ref={ref}\n src={effectiveSrc}\n alt={effectiveAlt}\n className={className}\n style={effectiveStyle}\n onClick={handleClick}\n {...editorAttrs}\n {...rest}\n />\n );\n },\n);\n","/**\n * Icon — the shared icon set for the `icon_picker` setting type.\n *\n * Names are the stored setting values. BOTH the merchant-hub editor's icon\n * grid AND themes render through this same map, so a picked icon looks\n * identical in the customizer and on the storefront.\n *\n * We ship inline SVG (no icon-library dependency) on purpose: the SDK is the\n * host-provided runtime singleton, and keeping it dependency-free avoids\n * bundling an icon library into every storefront. Each entry below is the\n * inner markup of a 24×24 stroke icon; <Icon> wraps it with the shared\n * stroke attributes and sizing.\n *\n * ⚠️ KEEP IN SYNC with the editor's copy in\n * numo-merchant-hub/src/features/theme-editor-v3/components/inputs/SettingInputV3.tsx\n * (the ICON_DEFS in IconPickerButton). The keys are the contract between\n * the picker and this renderer — a name the picker offers must exist here\n * or the theme falls back to a neutral glyph.\n */\n\nexport const ICON_DEFS: Record<string, string> = {\n star: '<polygon points=\"12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2\"/>',\n heart:\n '<path d=\"M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.29 1.51 4.04 3 5.5l7 7Z\"/>',\n check: '<path d=\"M20 6 9 17l-5-5\"/>',\n \"check-circle\": '<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"m9 12 2 2 4-4\"/>',\n shield: '<path d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10Z\"/>',\n \"shield-check\":\n '<path d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10Z\"/><path d=\"m9 12 2 2 4-4\"/>',\n truck:\n '<path d=\"M10 17h4V5H2v12h3\"/><path d=\"M20 17h2v-3.34a4 4 0 0 0-1.17-2.83L19 9h-5v8h1\"/><circle cx=\"7.5\" cy=\"17.5\" r=\"2.5\"/><circle cx=\"17.5\" cy=\"17.5\" r=\"2.5\"/>',\n \"shopping-bag\":\n '<path d=\"M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z\"/><path d=\"M3 6h18\"/><path d=\"M16 10a4 4 0 0 1-8 0\"/>',\n \"shopping-cart\":\n '<circle cx=\"8\" cy=\"21\" r=\"1\"/><circle cx=\"19\" cy=\"21\" r=\"1\"/><path d=\"M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12\"/>',\n gift:\n '<rect x=\"3\" y=\"8\" width=\"18\" height=\"4\" rx=\"1\"/><path d=\"M12 8v13\"/><path d=\"M19 12v7a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-7\"/><path d=\"M7.5 8a2.5 2.5 0 0 1 0-5C9 3 10.5 4.5 12 8c1.5-3.5 3-5 4.5-5a2.5 2.5 0 0 1 0 5\"/>',\n tag: '<path d=\"M20.59 13.41 13.42 20.6a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82Z\"/><circle cx=\"7\" cy=\"7\" r=\"1\"/>',\n zap: '<polygon points=\"13 2 3 14 12 14 11 22 21 10 12 10 13 2\"/>',\n sparkles:\n '<path d=\"M12 3 13.9 9.2 20 11l-6.1 1.8L12 19l-1.9-6.2L4 11l6.1-1.8L12 3Z\"/><path d=\"M5 3v4\"/><path d=\"M3 5h4\"/><path d=\"M19 17v4\"/><path d=\"M17 19h4\"/>',\n flame:\n '<path d=\"M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.07-2.14-.22-4.05 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.15.43-2.29 1-3a2.5 2.5 0 0 0 2.5 2.5Z\"/>',\n leaf:\n '<path d=\"M11 20A7 7 0 0 1 9.8 6.1C15.5 5 17 4.48 19 2c1 2 2 4.18 2 8 0 5.5-4.78 10-10 10Z\"/><path d=\"M2 21c0-3 1.85-5.36 5.08-6\"/>',\n globe:\n '<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M2 12h20\"/><path d=\"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10Z\"/>',\n \"map-pin\":\n '<path d=\"M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/>',\n phone:\n '<path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92Z\"/>',\n mail:\n '<rect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\"/><path d=\"m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7\"/>',\n clock: '<circle cx=\"12\" cy=\"12\" r=\"10\"/><polyline points=\"12 6 12 12 16 14\"/>',\n lock:\n '<rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\" ry=\"2\"/><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"/>',\n headphones:\n '<path d=\"M3 14h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-7a9 9 0 0 1 18 0v7a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3\"/>',\n percent:\n '<line x1=\"19\" x2=\"5\" y1=\"5\" y2=\"19\"/><circle cx=\"6.5\" cy=\"6.5\" r=\"2.5\"/><circle cx=\"17.5\" cy=\"17.5\" r=\"2.5\"/>',\n users:\n '<path d=\"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2\"/><circle cx=\"9\" cy=\"7\" r=\"4\"/><path d=\"M22 21v-2a4 4 0 0 0-3-3.87\"/><path d=\"M16 3.13a4 4 0 0 1 0 7.75\"/>',\n home:\n '<path d=\"m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z\"/><polyline points=\"9 22 9 12 15 12 15 22\"/>',\n store:\n '<path d=\"M2 7l2-4h16l2 4\"/><path d=\"M4 7v13a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1V7\"/><path d=\"M2 7h20\"/><path d=\"M9 21v-6h6v6\"/>',\n bell:\n '<path d=\"M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9\"/><path d=\"M10.3 21a1.94 1.94 0 0 0 3.4 0\"/>',\n camera:\n '<path d=\"M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z\"/><circle cx=\"12\" cy=\"13\" r=\"3\"/>',\n image:\n '<rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" ry=\"2\"/><circle cx=\"9\" cy=\"9\" r=\"2\"/><path d=\"m21 15-3.09-3.09a2 2 0 0 0-2.82 0L6 21\"/>',\n smile:\n '<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M8 14s1.5 2 4 2 4-2 4-2\"/><line x1=\"9\" x2=\"9.01\" y1=\"9\" y2=\"9\"/><line x1=\"15\" x2=\"15.01\" y1=\"9\" y2=\"9\"/>',\n send: '<path d=\"m22 2-7 20-4-9-9-4Z\"/><path d=\"M22 2 11 13\"/>',\n \"message-circle\":\n '<path d=\"M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5Z\"/>',\n search: '<circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"m21 21-4.3-4.3\"/>',\n package:\n '<path d=\"M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z\"/><path d=\"m3.3 7 8.7 5 8.7-5\"/><path d=\"M12 22V12\"/>',\n award:\n '<circle cx=\"12\" cy=\"8\" r=\"6\"/><path d=\"M15.477 12.89 17 22l-5-3-5 3 1.523-9.11\"/>',\n coffee:\n '<path d=\"M10 2v2\"/><path d=\"M14 2v2\"/><path d=\"M6 2v2\"/><path d=\"M16 8a1 1 0 0 1 1 1v8a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1h14a4 4 0 1 1 0 8h-1\"/>',\n};\n\nexport const ICON_NAMES: string[] = Object.keys(ICON_DEFS);\n\n/** Public alias for the icon name → inner-SVG map. */\nexport const IconMap = ICON_DEFS;\n\nexport interface IconProps {\n /** Icon name from {@link ICON_NAMES}. Unknown names render a neutral glyph. */\n name: string;\n /** Pixel size (width === height). Defaults to 24. */\n size?: number | string;\n strokeWidth?: number;\n className?: string;\n /** Accessible label. When omitted the icon is treated as decorative. */\n title?: string;\n}\n\nconst FALLBACK = ICON_DEFS[\"check-circle\"];\n\n/**\n * Render an icon by name from the shared {@link ICON_DEFS} set. Inherits color\n * from `currentColor`, so set the parent's text color to recolor it.\n */\nexport function Icon({\n name,\n size = 24,\n strokeWidth = 2,\n className,\n title,\n}: IconProps) {\n const inner = ICON_DEFS[name] ?? FALLBACK;\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n role={title ? \"img\" : undefined}\n aria-hidden={title ? undefined : true}\n aria-label={title}\n dangerouslySetInnerHTML={{ __html: inner }}\n />\n );\n}\n","\"use client\";\n\n/**\n * Module Federation singleton sharing for @numueg/theme-sdk.\n *\n * Why this exists:\n * BYOT bundles (loaded at runtime as cross-origin ESM modules) need to\n * share React + the SDK with the host storefront. Otherwise React's\n * internal \"two copies\" check trips and hooks crash. The host registers\n * its singletons here; the BYOT bundle reads them via the SDK shim.\n *\n * Threat model:\n * We do NOT want third-party scripts (analytics, chat widgets, BYOT\n * community themes) to read PII off the SDK. The earlier version stored\n * the SDK on `window.__NUMU_SDK__` — anything in the page could read it\n * and call `useCustomer()` etc.\n *\n * Mitigation:\n * The singleton is keyed by a Symbol that's only handed to consumers\n * we've verified (the storefront's BYOT entry function passes it to the\n * bundle's `setup()`). Symbols can't be enumerated through `window` or\n * `Object.getOwnPropertyNames`, so a leaked global reference doesn't\n * yield SDK access.\n *\n * For maximum safety we also expose `clearSdkSingleton()` so the host\n * can revoke after a BYOT theme is unmounted.\n */\n\ninterface SdkSingleton {\n useShop: unknown;\n useProduct: unknown;\n useCollection: unknown;\n useCart: unknown;\n useCustomer: unknown;\n useThemeSettings: unknown;\n useLocalization: unknown;\n usePage: unknown;\n useSection: unknown;\n NuMuProvider: unknown;\n ProductProvider: unknown;\n CollectionProvider: unknown;\n}\n\ninterface ReactSingleton {\n React: unknown;\n ReactDOM: unknown;\n}\n\n// We pin the slot keys via `Symbol.for(name)` so ALL copies of this\n// SDK module — even when bundled with a BYOT theme — resolve to the\n// SAME Symbol identity through the global Symbol registry. The\n// previous implementation also wrote the Symbol back to a string-keyed\n// `globalThis[\"__NUMU_SDK_SLOT__\"]` slot \"so multiple module copies\n// could find it\" — but `Symbol.for()` already supplies that identity\n// (that's its entire purpose), and writing to a string-keyed\n// globalThis property put the slot name into `Object.keys(globalThis)`,\n// breaking the Principle II \"not enumerable\" privacy contract.\n//\n// What's still public:\n// - The Symbol's *name* is in the global Symbol registry. A motivated\n// attacker who knows the name can call Symbol.for() to recover the\n// same Symbol. Privacy here is obscurity-through-naming, not crypto.\n// - The actual SDK object lives at `globalThis[symbol]` — invisible\n// to `Object.keys`, `Object.getOwnPropertyNames`, and accidental\n// enumeration by third-party scripts that don't know to call\n// `Object.getOwnPropertySymbols`.\nfunction sdkSlot(): symbol {\n return Symbol.for(\"@numueg/theme-sdk:singleton\");\n}\n\nfunction reactSlot(): symbol {\n return Symbol.for(\"@numueg/theme-sdk:react\");\n}\n\nexport function registerSdkSingleton(sdk: SdkSingleton): void {\n if (typeof globalThis === \"undefined\") return;\n (globalThis as Record<symbol, unknown>)[sdkSlot()] = sdk;\n}\n\nexport function getSdkSingleton(): SdkSingleton | null {\n if (typeof globalThis === \"undefined\") return null;\n return (\n ((globalThis as Record<symbol, unknown>)[sdkSlot()] as SdkSingleton) ??\n null\n );\n}\n\nexport function clearSdkSingleton(): void {\n if (typeof globalThis === \"undefined\") return;\n delete (globalThis as Record<symbol, unknown>)[sdkSlot()];\n}\n\nexport function registerReactSingleton(\n react: unknown,\n reactDom: unknown,\n): void {\n if (typeof globalThis === \"undefined\") return;\n (globalThis as Record<symbol, unknown>)[reactSlot()] = {\n React: react,\n ReactDOM: reactDom,\n } satisfies ReactSingleton;\n}\n\nexport function getReactSingleton(): ReactSingleton | null {\n if (typeof globalThis === \"undefined\") return null;\n return (\n ((globalThis as Record<symbol, unknown>)[\n reactSlot()\n ] as ReactSingleton) ?? null\n );\n}\n\nexport function isSdkAvailable(): boolean {\n return getSdkSingleton() !== null;\n}\n","/**\n * Dynamic sources — Shopify-parity feature that lets merchants bind a\n * section setting to a value that's pulled from store data at render\n * time instead of being a literal authored value.\n *\n * Stored shape:\n * { __numu_source: \"<path>\" }\n *\n * Paths use dot notation against the resolution context:\n * - `product.title` / `product.description` / `product.price` /\n * `product.image` / `product.first_image_url`\n * - `collection.title` / `collection.description` / `collection.image`\n * - `store.name` / `store.description`\n *\n * Why a reserved discriminant key (`__numu_source`)?\n *\n * Setting values today are plain literals (`\"Hero headline\"`,\n * `12345`, `true`). Themes that read settings as strings/numbers\n * would break if we suddenly stored an object. The reserved key\n * tags object-shape values so the resolver only intercepts the ones\n * it knows about. Anything else (e.g. the `{ url, alt }` shape from\n * the image picker, or a future structured setting) passes through.\n *\n * Bindable-by-type matrix (enforced in the customizer's source picker):\n *\n * text | product.title, product.description (snippet),\n * | collection.title, collection.description (snippet),\n * | store.name, store.description\n * textarea | same as text + full descriptions\n * richtext | full descriptions only\n * url | not bindable yet — product/collection URLs require\n * | the host's route resolver; deferred to a follow-up.\n * image_picker | product.image, collection.image, store.logo\n * number/range | product.price (raw cents) — risky because format\n * | varies. Deferred.\n * color/checkbox/select/radio/font | not bindable.\n *\n * Themes consume dynamic sources via `useResolvedSettings(instance)`\n * which returns the section's settings map with every dynamic ref\n * pre-resolved against the active product/collection/store context.\n * Literal values pass through unchanged.\n */\n\nimport type { Collection, Product, Store } from \"../types/entities\";\n\n/** Stored shape for a dynamic source reference. */\nexport interface DynamicSourceRef {\n __numu_source: string;\n}\n\n/**\n * Type guard. True when `value` is a dynamic source reference object.\n * Order matters: we check the discriminant key BEFORE assuming the\n * value is anything else, so an `{ __numu_source: \"...\" }` from the\n * draft doesn't get treated as a literal record.\n */\nexport function isDynamicSource(value: unknown): value is DynamicSourceRef {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { __numu_source?: unknown }).__numu_source === \"string\"\n );\n}\n\n/**\n * Build a fresh dynamic source ref. Pure helper used by the customizer\n * when the merchant clicks a source in the picker.\n */\nexport function dynamicSource(path: string): DynamicSourceRef {\n return { __numu_source: path };\n}\n\n/** Resolution context for `resolveDynamicValue`. Each field is\n * independently optional so callers can pass only what's relevant\n * (e.g. cart template skips product/collection). */\nexport interface DynamicResolveContext {\n product?: Product | null;\n collection?: Collection | null;\n store?: Pick<Store, \"name\" | \"description\" | \"logo_url\"> | null;\n}\n\n/**\n * Look up the path inside the resolution context. Returns `null` when\n * the source is unknown OR the context doesn't have the resource\n * needed to resolve it (e.g. `product.title` when no product is in\n * context). The customizer's source picker already hides incompatible\n * sources, so this fallback only fires during preview navigation\n * (merchant flips to a product template before the picker re-renders).\n */\nexport function resolveSourcePath(\n path: string,\n ctx: DynamicResolveContext,\n): unknown {\n const [root, ...rest] = path.split(\".\");\n switch (root) {\n case \"product\": {\n const p = ctx.product;\n if (!p) return null;\n return resolveProductField(p, rest.join(\".\"));\n }\n case \"collection\": {\n const c = ctx.collection;\n if (!c) return null;\n return resolveCollectionField(c, rest.join(\".\"));\n }\n case \"store\": {\n const s = ctx.store;\n if (!s) return null;\n return resolveStoreField(s, rest.join(\".\"));\n }\n default:\n return null;\n }\n}\n\n/** Merchant-defined field: `metafield:{namespace}.{key}`. Only public\n * metafields reach the storefront; missing → null (setting default renders). */\nfunction resolveMetafield(\n metafields: { namespace: string; key: string; value: unknown }[] | undefined,\n field: string,\n): unknown {\n const address = field.slice(\"metafield:\".length);\n const dot = address.indexOf(\".\");\n if (dot === -1) return null;\n const namespace = address.slice(0, dot);\n const key = address.slice(dot + 1);\n const hit = (metafields ?? []).find(\n (m) => m.namespace === namespace && m.key === key,\n );\n return hit ? (hit.value ?? null) : null;\n}\n\nfunction resolveProductField(p: Product, field: string): unknown {\n if (field.startsWith(\"metafield:\")) return resolveMetafield(p.metafields, field);\n switch (field) {\n case \"title\":\n case \"name\":\n return p.name;\n case \"description\":\n return p.description ?? \"\";\n case \"description_snippet\":\n // 200-char excerpt — useful for short-description settings that\n // would otherwise inherit a full HTML body.\n return (p.description ?? \"\").replace(/<[^>]+>/g, \" \").trim().slice(0, 200);\n case \"price\":\n return p.price;\n case \"sku\":\n // SKU lives on the default variant in most stores.\n return p.variants?.[0]?.sku ?? null;\n case \"image\":\n case \"first_image_url\":\n return p.images?.[0]?.url ?? null;\n case \"slug\":\n return p.slug;\n default:\n return null;\n }\n}\n\nfunction resolveCollectionField(c: Collection, field: string): unknown {\n if (field.startsWith(\"metafield:\")) return resolveMetafield(c.metafields, field);\n switch (field) {\n case \"title\":\n case \"name\":\n return c.name;\n case \"description\":\n return c.description ?? \"\";\n case \"description_snippet\":\n return (c.description ?? \"\").replace(/<[^>]+>/g, \" \").trim().slice(0, 200);\n case \"image\":\n return c.image_url ?? null;\n case \"slug\":\n return c.slug;\n case \"product_count\":\n return c.product_count ?? null;\n default:\n return null;\n }\n}\n\nfunction resolveStoreField(\n s: Pick<Store, \"name\" | \"description\" | \"logo_url\">,\n field: string,\n): unknown {\n switch (field) {\n case \"name\":\n return s.name ?? \"\";\n case \"description\":\n return s.description ?? \"\";\n case \"logo\":\n return s.logo_url ?? null;\n default:\n return null;\n }\n}\n\n/**\n * Resolve a single setting value. Literal values pass through\n * unchanged; dynamic references resolve against the context. Returns\n * `null` (not the original ref) when resolution fails, so themes can\n * branch on the null and either render a placeholder or hide the\n * element entirely.\n */\nexport function resolveDynamicValue<T = unknown>(\n value: unknown,\n ctx: DynamicResolveContext,\n): T | null {\n if (!isDynamicSource(value)) return value as T;\n return resolveSourcePath(value.__numu_source, ctx) as T | null;\n}\n\n/**\n * Walk every key of a settings map and resolve every dynamic\n * reference. Pure helper backing `useResolvedSettings`.\n *\n * The generic is unconstrained on purpose. Theme authors typically\n * type their settings as `interface HeroSettings { headline?: string }`,\n * and TypeScript interfaces don't implicitly satisfy\n * `Record<string, unknown>` — there's no index signature on an\n * interface. Leaving `T` open lets us pass through whatever shape the\n * caller declared and still return the resolved-but-same shape.\n */\nexport function resolveSettingsMap<T = Record<string, unknown>>(\n settings: T,\n ctx: DynamicResolveContext,\n): T {\n if (!settings || typeof settings !== \"object\") return settings;\n const input = settings as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(input)) {\n const v = input[key];\n if (isDynamicSource(v)) {\n const resolved = resolveSourcePath(v.__numu_source, ctx);\n // Preserve nullish from resolution failure so the consumer can\n // detect \"I asked for product.title but no product is active.\"\n out[key] = resolved;\n } else {\n out[key] = v;\n }\n }\n return out as T;\n}\n","\"use client\";\nimport { useContext, useMemo } from \"react\";\nimport { ProductContext, CollectionContext, ShopContext } from \"../contexts\";\nimport type { BlockInstance, SectionInstance } from \"../types/theme\";\nimport {\n type DynamicResolveContext,\n resolveSettingsMap,\n} from \"../utils/dynamicSources\";\n\n/**\n * Resolve every dynamic source in a section's settings against the\n * active product / collection / store contexts.\n *\n * Section components that want to support merchant-bound fields call\n * this in place of reading `instance.settings` directly:\n *\n * const settings = useResolvedSettings(instance);\n *\n * Literal values pass through; `{ __numu_source: \"product.title\" }`\n * becomes the current product's title when the section is rendered\n * inside a `<ProductProvider>`. The returned object is memoized on\n * the upstream contexts so themes can pass it straight into\n * `useMemo` deps without retriggering renders.\n *\n * When the bound resource isn't in context (e.g. `product.*` on a\n * non-product template), the resolved value is `null`. Themes can\n * detect this and render a placeholder or hide the affected element.\n *\n * Note: the SectionContext provider already supplies the `instance`\n * to children of `<Section>` — but we take it explicitly so section\n * components can call this hook before they've descended into\n * SectionContext (i.e. at the top of their render function, alongside\n * destructuring `settings` from props).\n */\nexport function useResolvedSettings<T = Record<string, unknown>>(\n instance: SectionInstance | BlockInstance | null | undefined,\n): T {\n const product = useContext(ProductContext);\n const collection = useContext(CollectionContext);\n const store = useContext(ShopContext);\n\n // Stabilize the resolution context object so the memo only invalidates\n // when one of the upstream values actually changes. Without this each\n // render would build a fresh `{ product, collection, store }` and the\n // useMemo dep array would never hit.\n const ctx = useMemo<DynamicResolveContext>(\n () => ({ product, collection, store }),\n [product, collection, store],\n );\n\n return useMemo(() => {\n const settings = (instance?.settings ?? {}) as T;\n return resolveSettingsMap<T>(settings, ctx);\n }, [instance, ctx]);\n}\n","/**\n * Section + block authoring helpers.\n *\n * `defineSection` and `defineBlock` bind a JSON schema to its render\n * component so theme authors don't keep two files in sync by hand.\n * The plugin ships the schema half (writes `schemas/sections/<type>.json`\n * for the customizer), the runtime imports the component half — both\n * sourced from the same factory call.\n *\n * Why factories instead of two separate files:\n * Pre-Phase-2 layout was:\n * theme/main.tsx → registers components\n * theme/schemas/sections/Hero.json → declares schema\n * Drift was the bug. Renaming a setting required edits in two places;\n * adding a new section meant remembering to update three lists.\n * Factories collapse that into a single export the plugin and runtime\n * both read.\n *\n * Usage:\n * // sections/Hero.tsx\n * import { defineSection } from \"@numueg/theme-sdk\";\n * export default defineSection({\n * schema: {\n * type: \"hero\",\n * name: \"Hero\",\n * settings: [{ type: \"text\", id: \"heading\", label: \"Heading\" }],\n * presets: [{ name: \"Hero — Centered\", settings: { heading: \"Welcome\" } }],\n * },\n * render: ({ settings }) => <h1>{settings.heading}</h1>,\n * });\n *\n * The plugin's section-discovery scan picks up files under\n * `src/sections/**\\/*.{tsx,ts}` whose default export is a section\n * definition. No registration list needed.\n */\n\nimport type { ComponentType } from \"react\";\nimport type {\n BlockProps,\n BlockSchema,\n SectionProps,\n SectionSchema,\n} from \"../types/theme\";\n\nconst SECTION_MARKER = Symbol.for(\"numu.theme.section\");\nconst BLOCK_MARKER = Symbol.for(\"numu.theme.block\");\n\n/**\n * A defined section: paired schema + render component.\n *\n * The marker symbol lets the plugin's discovery scan identify section\n * definitions without depending on a structural shape that themes might\n * accidentally collide with.\n */\nexport interface DefinedSection {\n schema: SectionSchema;\n render: ComponentType<SectionProps>;\n readonly [SECTION_MARKER]: true;\n}\n\nexport interface DefinedBlock {\n schema: BlockSchema;\n render: ComponentType<BlockProps>;\n readonly [BLOCK_MARKER]: true;\n}\n\nexport interface DefineSectionInput {\n schema: SectionSchema;\n render: ComponentType<SectionProps>;\n}\n\nexport interface DefineBlockInput {\n schema: BlockSchema;\n render: ComponentType<BlockProps>;\n}\n\n/**\n * Bind a section schema to its renderer.\n *\n * Validates at runtime that `schema.type` is a stable identifier\n * (lowercase + dashes/underscores) — drift here breaks the plugin's\n * codegen step (which writes `__generated__/sections.d.ts` keyed off\n * `schema.type`).\n */\nexport function defineSection(input: DefineSectionInput): DefinedSection {\n if (!input?.schema?.type) {\n throw new Error(\n \"defineSection: `schema.type` is required and must be a stable string id.\",\n );\n }\n if (!/^[a-z][a-z0-9_-]*$/.test(input.schema.type)) {\n throw new Error(\n `defineSection: section type '${input.schema.type}' must be lowercase alphanumeric ` +\n `with dashes/underscores. The codegen step uses this as a TS key.`,\n );\n }\n if (typeof input.render !== \"function\") {\n throw new Error(\n \"defineSection: `render` must be a React component function.\",\n );\n }\n return Object.freeze({\n schema: input.schema,\n render: input.render,\n [SECTION_MARKER]: true as const,\n });\n}\n\nexport function defineBlock(input: DefineBlockInput): DefinedBlock {\n if (!input?.schema?.type) {\n throw new Error(\"defineBlock: `schema.type` is required.\");\n }\n if (!/^[a-z@][a-z0-9_/-]*$/i.test(input.schema.type)) {\n throw new Error(\n `defineBlock: block type '${input.schema.type}' has illegal chars. ` +\n `Use a-z, 0-9, dashes/underscores; @app/<slug>/<block> form is also accepted.`,\n );\n }\n if (typeof input.render !== \"function\") {\n throw new Error(\n \"defineBlock: `render` must be a React component function.\",\n );\n }\n return Object.freeze({\n schema: input.schema,\n render: input.render,\n [BLOCK_MARKER]: true as const,\n });\n}\n\nexport function isDefinedSection(v: unknown): v is DefinedSection {\n return (\n typeof v === \"object\" &&\n v !== null &&\n (v as Record<symbol, unknown>)[SECTION_MARKER] === true\n );\n}\n\nexport function isDefinedBlock(v: unknown): v is DefinedBlock {\n return (\n typeof v === \"object\" &&\n v !== null &&\n (v as Record<symbol, unknown>)[BLOCK_MARKER] === true\n );\n}\n\n/**\n * Build a section registry from a Vite glob import.\n *\n * Themes call this at the top of their `main.tsx`:\n *\n * const sectionModules = import.meta.glob<{ default: DefinedSection }>(\n * \"./sections/*.tsx\", { eager: true });\n * const sections = collectSections(sectionModules);\n *\n * The returned object is keyed by `schema.type` for direct lookup at\n * render time. Modules whose default export isn't a DefinedSection are\n * skipped with a console warning (drops a half-migrated section without\n * breaking the rest of the bundle).\n */\nexport function collectSections<T extends Record<string, unknown>>(\n modules: T,\n): Record<string, DefinedSection> {\n const out: Record<string, DefinedSection> = {};\n for (const [path, mod] of Object.entries(modules)) {\n const def = (mod as { default?: unknown }).default;\n if (!isDefinedSection(def)) {\n if (typeof console !== \"undefined\") {\n console.warn(\n `[numu] ${path}: default export is not a defineSection() result; skipped.`,\n );\n }\n continue;\n }\n if (out[def.schema.type]) {\n throw new Error(\n `[numu] duplicate section type '${def.schema.type}': ` +\n `previously defined, now also defined in ${path}.`,\n );\n }\n out[def.schema.type] = def;\n }\n return out;\n}\n\nexport function collectBlocks<T extends Record<string, unknown>>(\n modules: T,\n): Record<string, DefinedBlock> {\n const out: Record<string, DefinedBlock> = {};\n for (const [path, mod] of Object.entries(modules)) {\n const def = (mod as { default?: unknown }).default;\n if (!isDefinedBlock(def)) {\n if (typeof console !== \"undefined\") {\n console.warn(\n `[numu] ${path}: default export is not a defineBlock() result; skipped.`,\n );\n }\n continue;\n }\n if (out[def.schema.type]) {\n throw new Error(\n `[numu] duplicate block type '${def.schema.type}': ` +\n `previously defined, now also defined in ${path}.`,\n );\n }\n out[def.schema.type] = def;\n }\n return out;\n}\n","/**\n * `assetUrl(name)` — resolve a theme-bundled asset's runtime URL.\n *\n * Themes ship static assets (images, fonts, JSON) under `assets/`.\n * The plugin copies each asset to `dist/assets/` with a content-hashed\n * filename and writes a manifest (`asset-manifest.json`) mapping each\n * source path to the hashed name.\n *\n * At runtime this function reads the manifest off the runtime window\n * object (`window.__NUMU_ASSET_MANIFEST`) — populated by the storefront's\n * `<RuntimeImportMap>` component when the theme bundle is loaded —\n * and returns the absolute URL to the hashed file.\n *\n * Why a runtime helper instead of bake-time string interpolation:\n * The same theme bundle is reused across hosted stores. The asset\n * base URL differs per environment (CDN vs local dev) and per store\n * (subdomain vs custom domain). Resolving at runtime keeps a single\n * bundle deployable across all of them.\n *\n * Usage:\n * <Image src={assetUrl(\"hero.jpg\")} alt=\"...\" />\n * <link rel=\"preload\" as=\"font\" href={assetUrl(\"fonts/Inter.woff2\")} />\n *\n * Behavior when the manifest is missing or the asset isn't listed:\n * Returns the original `name` (prefixed with the conventional\n * `/assets/` path) as a fallback. This keeps dev workable when the\n * plugin's asset-pipeline step hasn't run yet, and surfaces obviously-\n * wrong asset names as 404s rather than silent failures.\n */\n\ninterface AssetManifest {\n /** Map of source asset path → hashed filename in dist/assets/ */\n [sourcePath: string]: string;\n}\n\ninterface AssetRuntimeConfig {\n /** Manifest written by the plugin at build time and injected at runtime. */\n __NUMU_ASSET_MANIFEST?: AssetManifest;\n /**\n * Optional CDN/path prefix. Defaults to \"/assets/\" — themes hosted on\n * a CDN can override by setting this on `window` before mount.\n */\n __NUMU_ASSET_BASE_URL?: string;\n}\n\nfunction getRuntime(): AssetRuntimeConfig {\n if (typeof window !== \"undefined\") {\n return window as unknown as AssetRuntimeConfig;\n }\n // Server-side render (host SSR worker): the host injects the manifest and\n // base URL onto globalThis before calling createApp, so server markup\n // resolves the same hashed URLs the client would — no <img src> hydration\n // patch-up.\n if (typeof globalThis !== \"undefined\") {\n return globalThis as unknown as AssetRuntimeConfig;\n }\n return {};\n}\n\nexport function assetUrl(name: string): string {\n if (!name) return \"\";\n // Already-absolute or already-resolved (starts with /, http://, https://) →\n // pass through. Theme code that mixes hand-written paths with assetUrl()\n // is fine, this is just a no-op for those.\n if (/^https?:\\/\\//i.test(name) || name.startsWith(\"//\")) return name;\n\n const runtime = getRuntime();\n const manifest = runtime.__NUMU_ASSET_MANIFEST;\n const base = runtime.__NUMU_ASSET_BASE_URL || \"/assets/\";\n\n // Normalize: strip leading \"./\" or \"assets/\" so callers can write\n // `assetUrl(\"hero.jpg\")` or `assetUrl(\"./hero.jpg\")` interchangeably.\n let key = name.replace(/^\\.\\//, \"\");\n if (key.startsWith(\"/\")) key = key.slice(1);\n if (key.startsWith(\"assets/\")) key = key.slice(\"assets/\".length);\n\n const hashed = manifest?.[key];\n // No manifest hit → fall back to the bare path under base. Keeps dev\n // (where the plugin watch hasn't emitted a manifest yet) workable.\n const filename = hashed || key;\n // Ensure exactly one slash between base and filename.\n const cleanBase = base.endsWith(\"/\") ? base : `${base}/`;\n return `${cleanBase}${filename}`;\n}\n","/**\n * Template + section-group resolution — the \"no blank page\" engine.\n *\n * This is engine policy, not theme code, and it was copy-pasted into every\n * theme: `src/sections/_template-utils.ts` is BYTE-IDENTICAL across 11 of the\n * 14 themes that carry it (md5 59608dd4f4a702136854d7aaf33ba5e3); the\n * remaining copies differ only in comments and brace style. The file's own\n * header instructed theme authors to copy it and said it could be deleted\n * \"once the published SDK ships its own sanitizeTemplate\". This is that.\n *\n * Why centralising it is safe — and why it matters:\n * - It contains ZERO design. It decides WHICH sections render, never how\n * they look, so it cannot homogenise themes.\n * - Getting it subtly wrong renders an EMPTY STORE. Empire re-implemented a\n * weaker version inline with no unknown-type filtering, so a stale\n * customisation renders \"Unknown section\" placeholders there while every\n * other theme degrades gracefully. One implementation removes that class.\n *\n * The two rules it encodes, both learned from real blank-page incidents:\n * 1. A template may arrive as an ARRAY or as a MAP + `order[]`. The\n * customizer writes one shape, theme presets use the other.\n * 2. Host customisation wins over the theme's bundled preset — UNLESS it\n * resolves to nothing this theme can render, in which case fall back to\n * the preset rather than showing the shopper an empty page.\n */\n\nimport type { SectionInstance } from \"../types/theme\";\n\n/** A template or section group, in either of the two shapes hosts send. */\nexport interface MaybeOrderedTemplate {\n name?: string;\n sections?: Record<string, SectionInstance> | SectionInstance[];\n order?: string[];\n}\n\n/** A section instance paired with the stable id the customizer selects by. */\nexport interface ResolvedSection {\n id: string;\n instance: SectionInstance;\n}\n\n/**\n * Normalise a template/group into an ordered list.\n *\n * Array form gets synthetic `${type}-${index}` ids (presets have no ids of\n * their own). Map form is walked in `order`, skipping ids the map doesn't\n * contain — a dangling id in `order` is a customisation that referenced a\n * deleted section and must not throw.\n */\nexport function resolveSections(\n group: MaybeOrderedTemplate | undefined,\n): ResolvedSection[] {\n if (!group) return [];\n if (Array.isArray(group.sections)) {\n return group.sections.map((instance, idx) => ({\n id: `${instance.type}-${idx}`,\n instance,\n }));\n }\n const map = (group.sections ?? {}) as Record<string, SectionInstance>;\n const order = group.order ?? Object.keys(map);\n const out: ResolvedSection[] = [];\n for (const id of order) {\n const instance = map[id];\n if (instance) out.push({ id, instance });\n }\n return out;\n}\n\n/**\n * Choose between the host's customisation and the theme's bundled preset,\n * then drop section types this theme cannot render.\n *\n * `isKnown` is the theme's own registry lookup — the one thing that genuinely\n * belongs to the theme, so it stays a parameter.\n *\n * The order of the three checks is load-bearing:\n * - nothing from the host → preset (a fresh install renders its demo)\n * - host sections, none known → preset (a customisation built for a\n * DIFFERENT theme must not blank the page)\n * - otherwise → host sections, unknown types filtered out\n */\nexport function selectTemplateSections(\n hostTemplate: MaybeOrderedTemplate | undefined,\n builtinTemplate: MaybeOrderedTemplate | undefined,\n isKnown: (sectionType: string) => boolean,\n): ResolvedSection[] {\n const hostSections = resolveSections(hostTemplate);\n if (hostSections.length === 0) {\n return resolveSections(builtinTemplate);\n }\n const anyKnown = hostSections.some(({ instance }) => isKnown(instance.type));\n if (!anyKnown) return resolveSections(builtinTemplate);\n return hostSections.filter(({ instance }) => isKnown(instance.type));\n}\n\n/**\n * Find the theme's header/footer for a route it has no template for.\n *\n * Chrome reaches a theme from `section_groups` — except most themes never used\n * that channel: they put the header and footer INLINE in each template's own\n * section list. That works right up until the shopper hits a route the theme\n * ships no template for. Then there are no sections, so there is no chrome,\n * and the page renders with no navigation and no way back into the store.\n *\n * That is what `/blogs` looked like on every theme: correct, readable content\n * with nothing around it — no logo, no menu, no cart, no footer. A shopper\n * arriving from search had to press Back to escape.\n *\n * The template's OWN inline chrome still wins when it has some. This only\n * supplies chrome to routes that would otherwise have none, by borrowing the\n * chrome the theme already renders everywhere else — `home` first, since it is\n * the one template every theme ships and the one merchants customise.\n *\n * Returns `[]` when the theme genuinely has no chrome of this kind anywhere,\n * so a caller can still fall back to its own default.\n */\nexport function selectChromeSections(options: {\n /** `section_groups[kind]` from the host — the customizer's channel. */\n hostGroup?: MaybeOrderedTemplate;\n /** The theme's own preset `section_groups[kind]`. */\n presetGroup?: MaybeOrderedTemplate;\n /** Chrome found inline in the CURRENT template's section list. */\n inline?: ResolvedSection[];\n /** Every template the theme can draw on — host customisation and presets. */\n templates?: Array<MaybeOrderedTemplate | undefined>;\n /** True for the section types that count as this kind of chrome. */\n isChrome: (sectionType: string) => boolean;\n /** The theme's registry lookup. */\n isKnown: (sectionType: string) => boolean;\n}): ResolvedSection[] {\n const { hostGroup, presetGroup, inline, templates, isChrome, isKnown } =\n options;\n const known = (list: ResolvedSection[]) =>\n list.filter(({ instance }) => isKnown(instance.type));\n\n const fromHost = known(resolveSections(hostGroup));\n if (fromHost.length > 0) return fromHost;\n\n if (inline && inline.length > 0) return known(inline);\n\n const fromPreset = known(resolveSections(presetGroup));\n if (fromPreset.length > 0) return fromPreset;\n\n // Last resort: borrow from any template that carries this chrome inline.\n for (const template of templates ?? []) {\n const borrowed = known(resolveSections(template)).filter(({ instance }) =>\n isChrome(instance.type),\n );\n if (borrowed.length > 0) return borrowed;\n }\n return [];\n}\n","/**\n * Theme-bundled locale files: load + merge.\n *\n * The plugin discovers `locales/<code>.json` (and the fallback\n * `locales/en.default.json`) and bakes them into the bundle as a map\n * keyed by locale code. The runtime calls `pickTranslations(map, locale)`\n * to resolve the right one, with English fallback for missing keys.\n *\n * Conventions:\n * - locales/en.default.json is the canonical English source. It's\n * the fallback for any other locale's missing keys.\n * - locales/ar.json (and friends) override or extend the default.\n * - Nested keys are flattened with dot notation: `{\"hero\": {\"cta\": \"Buy\"}}`\n * becomes `\"hero.cta\"` for `t(\"hero.cta\")` to look up.\n *\n * Why flatten:\n * `useTranslation()` returns `t(key)` which expects a string lookup —\n * structured access would force every theme to write\n * `translations.hero?.cta ?? \"Buy\"`. Flattening keeps the call site\n * short and matches Shopify's `t` semantics.\n */\n\nexport interface LocaleMessages {\n [key: string]: string;\n}\n\nexport interface LocaleBundle {\n /** Locale code → flat key/value messages. */\n [locale: string]: LocaleMessages;\n}\n\n/**\n * Recursively flatten a nested locale object into dot-keyed strings.\n *\n * Non-string leaves are skipped with a console warning — translations\n * are user-facing strings; numbers and booleans don't belong in a\n * locale file (they should be in schema settings).\n */\nexport function flattenMessages(\n source: Record<string, unknown>,\n prefix = \"\",\n): LocaleMessages {\n const out: LocaleMessages = {};\n for (const [key, val] of Object.entries(source)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n if (val === null || val === undefined) continue;\n if (typeof val === \"string\") {\n out[fullKey] = val;\n } else if (typeof val === \"object\" && !Array.isArray(val)) {\n Object.assign(\n out,\n flattenMessages(val as Record<string, unknown>, fullKey),\n );\n } else if (typeof console !== \"undefined\") {\n console.warn(\n `[numu] locale key '${fullKey}' has non-string value (${typeof val}); skipped.`,\n );\n }\n }\n return out;\n}\n\n/**\n * Resolve the messages map for the requested locale, falling back to\n * \"en\" then \"en.default\" then an empty map. Missing keys in the\n * requested locale are filled from \"en\" (so an Arabic translation\n * file with 90% coverage doesn't show empty strings for the missing\n * 10%; English shows through).\n */\nexport function pickTranslations(\n bundle: LocaleBundle,\n locale: string,\n): LocaleMessages {\n const fallback = bundle[\"en\"] || bundle[\"en.default\"] || {};\n const requested = bundle[locale];\n if (!requested) return fallback;\n // Merge: fallback < requested. The requested locale wins per-key;\n // any key the requested locale doesn't define falls through to en.\n return { ...fallback, ...requested };\n}\n\n/**\n * Build a LocaleBundle from raw imports. Themes call this in their\n * `main.tsx` after a Vite glob import:\n *\n * const localeModules = import.meta.glob<Record<string, unknown>>(\n * \"./locales/*.json\", { eager: true, import: \"default\" });\n * const translations = buildLocaleBundle(localeModules);\n *\n * `localeModules` keys are paths like `./locales/ar.json`; we strip\n * the directory + extension to get the locale code, and flatten each\n * value.\n */\nexport function buildLocaleBundle<T extends Record<string, unknown>>(\n modules: T,\n): LocaleBundle {\n const bundle: LocaleBundle = {};\n for (const [path, raw] of Object.entries(modules)) {\n const m = /\\/([^/]+)\\.json$/.exec(path);\n if (!m) continue;\n let code = m[1];\n // `en.default` → keep as-is so pickTranslations can find it; theme\n // devs naming the file that way is a soft signal that this is the\n // canonical English source.\n if (code !== \"en.default\") {\n // Strip trailing \".default\" from any other code (someone might\n // write `ar.default.json` by mistake).\n code = code.replace(/\\.default$/, \"\");\n }\n const value = raw as unknown;\n if (typeof value === \"object\" && value !== null) {\n bundle[code] = flattenMessages(value as Record<string, unknown>);\n }\n }\n return bundle;\n}\n"]}
1
+ {"version":3,"sources":["../src/types/theme.ts","../src/hooks/useProduct.ts","../src/hooks/useCollection.ts","../src/hooks/useListingHeading.ts","../src/hooks/useCart.ts","../src/hooks/useCurrentTemplate.ts","../src/hooks/useMetafield.ts","../src/hooks/useArticles.ts","../src/hooks/useSection.ts","../src/hooks/useSectionGroup.ts","../src/hooks/useCurrency.ts","../src/hooks/useMoney.ts","../src/hooks/useImage.ts","../src/contexts/customer-actions.ts","../src/hooks/useCustomerActions.ts","../src/hooks/useOrders.ts","../src/hooks/useCustomerAddresses.ts","../src/hooks/useNavigation.ts","../src/hooks/useSearch.ts","../src/hooks/useAnalytics.ts","../src/lib/dataCache.ts","../src/hooks/useApp.ts","../src/hooks/useWishlist.ts","../src/hooks/useRelatedProducts.ts","../src/hooks/useActivePromotions.ts","../src/utils/money.ts","../src/lib/promotions.ts","../src/hooks/useProductSizeChart.ts","../src/utils/variants.ts","../src/utils/selectionRegistry.ts","../src/hooks/useVariantSelection.ts","../src/hooks/useGiftCardBalance.ts","../src/hooks/useReorder.ts","../src/hooks/useCheckout.ts","../src/hooks/useShippingRates.ts","../src/components/NuMuProvider.tsx","../src/components/ProductProvider.tsx","../src/components/CollectionProvider.tsx","../src/utils/logoStyle.ts","../src/utils/styleTokens.ts","../src/mount.tsx","../src/entry.tsx","../src/components/Money.tsx","../src/utils/imageTransform.ts","../src/components/Image.tsx","../src/components/HeroMedia.tsx","../src/components/Logo.tsx","../src/components/Link.tsx","../src/components/AddToCartButton.tsx","../src/components/Section.tsx","../src/components/Form.tsx","../src/utils/routes.ts","../src/components/ProductCard.tsx","../src/components/CollectionCard.tsx","../src/components/RichText.tsx","../src/components/CurrencySwitcher.tsx","../src/components/LocaleSwitcher.tsx","../src/components/Editable.tsx","../src/components/Icon.tsx","../src/utils/federation.ts","../src/utils/dynamicSources.ts","../src/hooks/useResolvedSettings.ts","../src/utils/defineSection.ts","../src/utils/assetUrl.ts","../src/utils/templates.ts","../src/utils/locales.ts"],"names":["useContext","ProductContext","CollectionContext","CartContext","CurrentTemplateContext","PageContext","createContext","ThemeSettingsContext","useMemo","CurrencyContext","useShop","formatMoney","useLocalization","useCustomer","useState","useEffect","unwrap","useCallback","NavigationContext","LocalizationContext","EMPTY","useRef","cache","useSyncExternalStore","opts","jsx","ShopContext","CustomerContext","pageData","forwardRef","ThemeMountBridge","useImperativeHandle","StrictMode","hydrateRoot","createRoot","createElement","DEFAULT_WIDTHS","useThemeSettings","Fragment","Component","jsxs","ABSOLUTE_URL","readCsrfCookie","joinClass","EditableText","EditableImage"],"mappings":"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","file":"index.cjs","sourcesContent":["/** V3 Theme Settings — the canonical data shape */\nexport interface ThemeSettingsV3 {\n schema_version: 3;\n theme_id: string;\n global_settings: Record<string, any>;\n templates: Record<string, PageTemplate>;\n section_groups: Record<string, SectionGroup>;\n external_theme?: ExternalThemeMetadata | null;\n}\n\nexport interface PageTemplate {\n name: string;\n sections: Record<string, SectionInstance>;\n order: string[];\n}\n\nexport interface SectionGroup {\n name: string;\n sections: Record<string, SectionInstance>;\n order: string[];\n}\n\nexport interface SectionInstance {\n type: string;\n settings: Record<string, any>;\n disabled?: boolean;\n blocks?: Record<string, BlockInstance>;\n block_order?: string[];\n}\n\nexport interface BlockInstance {\n type: string;\n settings: Record<string, any>;\n disabled?: boolean;\n /** Nested child blocks (blocks-in-blocks): a block can hold its own\n * block container — e.g. a footer \"column\" holding \"link\" blocks, or\n * a mega-menu. Same shape as a section's block container, so the\n * render/editor walk is uniform at any depth. Optional + absent on\n * leaf blocks, so pre-nesting payloads load unchanged. */\n blocks?: Record<string, BlockInstance>;\n block_order?: string[];\n}\n\nexport interface ExternalThemeMetadata {\n bundle_url: string;\n css_url?: string | null;\n mode?: string;\n settings_schema?: Record<string, any> | null;\n section_schemas?: Record<string, any> | null;\n}\n\n/**\n * Live mount handle returned by a V3 theme bundle's `mount(el, ctx)`.\n *\n * Two shapes accepted by the host:\n *\n * 1. **Legacy** — `mount(el, ctx): () => void`\n * The bundle returns only a cleanup function. Every host-side\n * themeSettings change forces a full unmount + remount, which is\n * expensive but always correct. Hosts must keep supporting this\n * for older bundles built against pre-0.2 SDK versions.\n *\n * 2. **Wave 3+** — `mount(el, ctx): MountResult`\n * The bundle returns an object with `cleanup` + an `applyDraft`\n * method that takes a fresh `ThemeSettingsV3` and re-renders the\n * bundle's React tree in-place (no createRoot churn). This is the\n * fast path used by the customizer's live preview — a keystroke\n * in the dashboard becomes a single React reconciliation in the\n * iframe, typically < 16 ms.\n *\n * Hosts feature-detect by checking `typeof handle === \"function\"`\n * (legacy) vs `typeof handle === \"object\" && handle.cleanup`\n * (Wave 3+). Theme authors should prefer the MountResult shape — the\n * `numuTheme` plugin's typings will flag the missing applyDraft once\n * the editor's live-preview path requires it.\n */\nexport interface MountResult {\n /** Unmount the bundle's React tree and release any resources. */\n cleanup: () => void;\n /**\n * Apply a fresh draft (e.g. from the customizer iframe's\n * `numu:theme:update` postMessage) without tearing down the tree.\n * Implementations typically forward the value to a useState setter\n * inside a wrapper that renders `<NuMuProvider themeSettings={...}>`.\n *\n * Safe to call repeatedly; the bundle is expected to dedup\n * reference-equal calls on its own. Returns nothing — selection /\n * navigation echo back via postMessage.\n */\n applyDraft: (next: ThemeSettingsV3) => void;\n}\n\n/** Section schema for customizer form generation */\nexport interface SectionSchema {\n type: string;\n name: string;\n name_ar?: string;\n tag?: string;\n class?: string;\n limit?: number;\n settings: SettingDefinition[];\n blocks?: BlockSchema[];\n max_blocks?: number;\n presets?: SectionPreset[];\n}\n\nexport interface BlockSchema {\n type: string;\n name: string;\n name_ar?: string;\n limit?: number;\n settings: SettingDefinition[];\n /** Child block types this block accepts (recursive). When present,\n * the customizer lets merchants add/remove/reorder these inside the\n * block, up to `max_blocks`. Enables footer columns, mega-menus,\n * multi-column layouts. The host caps practical nesting depth\n * (MAX_BLOCK_DEPTH). */\n blocks?: BlockSchema[];\n max_blocks?: number;\n}\n\n/** Max nesting depth the customizer allows for blocks-in-blocks. Depth\n * 1 = a top-level block in a section; a block at this depth can't take\n * children. Generous (below Shopify's 8) and cheap to raise. Kept in\n * sync with the merchant hub's MAX_BLOCK_DEPTH. */\nexport const MAX_BLOCK_DEPTH = 5;\n\n/**\n * Setting types the V3 customizer renders. Themes can declare any\n * string here; unknown types fall through to a plain text input. The\n * union below documents the canonical set so theme authors get\n * autocomplete and TypeScript errors on typos.\n */\nexport type SettingType =\n | \"text\"\n | \"textarea\"\n | \"richtext\"\n | \"number\"\n | \"range\"\n | \"color\"\n | \"checkbox\"\n | \"select\"\n | \"radio\"\n | \"font\"\n | \"image_picker\"\n | \"url\"\n | \"product\"\n | \"product_list\"\n | \"collection\"\n | \"collection_list\"\n | \"header\"\n | \"paragraph\"\n | \"html\"\n | \"date\"\n | \"time\"\n | \"video_picker\"\n | \"color_scheme\"\n | \"page_picker\"\n | \"blog_picker\"\n | \"link_list_picker\"\n | \"variant_picker\"\n | \"file_upload\"\n | \"icon_picker\"\n | \"icon\";\n\n/**\n * `visible_if` — conditional visibility expression evaluated against\n * sibling settings in the same schema. Two flavors:\n *\n * - String DSL: `\"settings.show_button == true && settings.layout != 'minimal'\"`\n * - Object form: `{ show_button: true, layout: [\"full\", \"split\"] }`\n *\n * Evaluator lives in the merchant hub: any setting whose expression is\n * falsy is skipped from the rendered form.\n */\nexport type VisibleIf = string | Record<string, unknown>;\n\nexport interface SettingDefinition {\n type: SettingType | (string & {}); // unions stay open for forward-compat\n id: string;\n label: string;\n label_ar?: string;\n default?: any;\n info?: string;\n info_ar?: string;\n placeholder?: string;\n options?: { value: string; label: string; label_ar?: string }[];\n min?: number;\n max?: number;\n step?: number;\n unit?: string;\n /** Hide this setting unless the expression evaluates truthy. */\n visible_if?: VisibleIf;\n /** Aspect hint for image_picker previews + server crops, e.g. \"16/9\". */\n aspect_ratio?: string;\n}\n\nexport interface PresetBlock {\n type: string;\n settings?: Record<string, any>;\n /** Nested starter blocks materialized when the preset is applied\n * (recursive). Lets a preset ship, e.g., a footer column already\n * populated with link blocks. */\n blocks?: PresetBlock[];\n}\n\nexport interface SectionPreset {\n name: string;\n /** Localized names so the Add Section dialog reads in the editor's\n * current locale. Falls back to `name` when the locale is missing. */\n locales?: {\n en?: { name?: string };\n ar?: { name?: string };\n };\n settings?: Record<string, any>;\n blocks?: PresetBlock[];\n}\n\n/**\n * Section component props.\n *\n * Generic over the settings shape so a theme can type its own settings\n * without hand-rolling a parallel props interface (the `EmpSectionProps`\n * pattern every theme was duplicating). `id`/`type` mirror the section\n * instance's key + `SectionInstance.type` so a component can key React\n * lists, dispatch on type, or emit editor anchors without threading them\n * separately; `groupId` names the owning `SectionGroup` for header/footer\n * group sections (absent for template sections).\n *\n * // Loosely typed (default) — settings is Record<string, unknown>:\n * function Hero(props: SectionProps) { … }\n *\n * // Strongly typed:\n * interface HeroSettings { headline: string; show_cta: boolean }\n * function Hero({ settings }: SectionProps<HeroSettings>) {\n * return <h1>{settings.headline}</h1>;\n * }\n */\nexport interface SectionProps<S = Record<string, unknown>> {\n /** The section instance's key within its template/group. */\n id: string;\n /** The section's `type` (its schema type / component name). */\n type: string;\n /** Owning section-group id for header/footer group sections; absent for\n * template-level sections. */\n groupId?: string;\n settings: S;\n blocks?: Record<string, BlockInstance>;\n blockOrder?: string[];\n storeData?: any;\n}\n\n/** Block component props */\nexport interface BlockProps {\n settings: Record<string, any>;\n /** Child block instances when this block nests others (footer column,\n * mega-menu, …). Mirror the section→block render: map `blockOrder`\n * and look each id up in `blocks`, wrapping each child in `<Block>`. */\n blocks?: Record<string, BlockInstance>;\n blockOrder?: string[];\n}\n","import { useContext } from \"react\";\nimport { ProductContext } from \"../contexts\";\nimport type { Product } from \"../types/entities\";\n\nexport function useProduct(): Product {\n const ctx = useContext(ProductContext);\n if (!ctx) throw new Error(\"useProduct must be used within ProductProvider\");\n return ctx;\n}\n\nexport function useProductOptional(): Product | null {\n return useContext(ProductContext);\n}\n","import { useContext } from \"react\";\nimport { CollectionContext } from \"../contexts\";\nimport type { Collection } from \"../types/entities\";\n\nexport function useCollection(): Collection {\n const ctx = useContext(CollectionContext);\n if (!ctx) throw new Error(\"useCollection must be used within CollectionProvider\");\n return ctx;\n}\n\nexport function useCollectionOptional(): Collection | null {\n return useContext(CollectionContext);\n}\n","import { useContext } from \"react\";\nimport { CollectionContext } from \"../contexts\";\nimport type { Collection } from \"../types/entities\";\n\nexport interface ListingHeading {\n /** The collection the shopper is inside, or `null` on the all-products listing. */\n collection: Collection | null;\n /** `true` when this listing is scoped to one collection. */\n isCollection: boolean;\n /** What to render as the page heading. */\n title: string;\n /** What to render under it. Empty string when there is nothing to say. */\n description: string;\n}\n\nexport interface ListingHeadingOptions {\n /** The merchant's own heading from this section's settings, if they set one. */\n title?: string | null;\n /** The merchant's own sub-heading from this section's settings. */\n description?: string | null;\n /**\n * The theme's wording for the UNSCOPED listing — already localized by the\n * theme, e.g. `localized(locale, \"All products\", \"كل المنتجات\")`.\n */\n defaultTitle?: string | null;\n}\n\n/**\n * What a product-listing section should call itself.\n *\n * Every theme hardcoded \"All products\" as its listing heading, so a shopper who\n * clicked into a category landed on a page titled **All products** showing a\n * subset of the catalog. The products were correctly scoped — the page just\n * never said which collection it was. That reads as a bug (\"where did the rest\n * go?\") and it costs the collection name in the one place it matters most.\n *\n * Precedence, highest first:\n * 1. the collection's own name — when the shopper is inside one, that IS the\n * page, and it always beats a static setting;\n * 2. the merchant's section setting — their wording for the all-products page;\n * 3. the theme's default.\n *\n * Categories carry no separate Arabic column, so `collection.name` is rendered\n * as the merchant typed it; only the fallback is localized, by the caller.\n *\n * @example\n * const { title, description, isCollection } = useListingHeading({\n * title: asString(s.title),\n * description: asString(s.subtitle),\n * defaultTitle: localized(locale, \"All products\", \"كل المنتجات\"),\n * });\n */\nexport function useListingHeading(\n options: ListingHeadingOptions = {},\n): ListingHeading {\n const collection = useContext(CollectionContext);\n const clean = (v: unknown): string =>\n typeof v === \"string\" && v.trim() !== \"\" ? v.trim() : \"\";\n\n const collectionName = clean(collection?.name);\n const collectionDescription = clean(\n (collection as { description?: unknown } | null)?.description,\n );\n\n return {\n collection: collection ?? null,\n isCollection: collectionName !== \"\",\n title:\n collectionName ||\n clean(options.title) ||\n clean(options.defaultTitle) ||\n \"\",\n description:\n collectionDescription || clean(options.description) || \"\",\n };\n}\n","import { useContext } from \"react\";\nimport { CartContext } from \"../contexts\";\n\nexport function useCart() {\n const ctx = useContext(CartContext);\n if (!ctx) throw new Error(\"useCart must be used within NuMuProvider\");\n return ctx;\n}\n","\"use client\";\n\nimport { useContext } from \"react\";\nimport { CurrentTemplateContext } from \"../contexts\";\n\n/**\n * useCurrentTemplate — read the active page template's id.\n *\n * Values are the same strings used as keys in\n * `themeSettings.templates.<id>`:\n *\n * \"home\" | \"product\" | \"collection\" | \"cart\" | \"checkout\"\n * \"order-confirmation\" | \"profile\" | \"page\" | \"404\" | \"password\"\n *\n * Themes use this to render the matching section list:\n *\n * const template = useCurrentTemplate();\n * const settings = useThemeSettings();\n * const sections = settings.templates?.[template]?.sections ?? {};\n *\n * Default: \"home\" — when the host hasn't supplied a CurrentTemplate\n * provider, themes still render their home template instead of\n * crashing or showing a blank screen.\n *\n * The hook is read-only; the active template changes via the host\n * navigating between Next.js routes (each route's `page.tsx` wraps\n * its content with the correct currentTemplate at the\n * `<NuMuProvider currentTemplate=\"…\">` prop).\n */\nexport function useCurrentTemplate(): string {\n return useContext(CurrentTemplateContext);\n}\n","import { useContext } from \"react\";\nimport { CollectionContext, PageContext, ProductContext } from \"../contexts\";\nimport type { Metafield } from \"../types/entities\";\n\n/**\n * Owners a theme can read metafields from. Matches the platform's\n * metafield owner types (product / collection / page). Only PUBLIC\n * metafields ever reach the storefront — the privacy filter runs\n * server-side at the payload layer, so a private field is simply absent\n * here, never present-but-hidden.\n */\nexport type MetafieldOwner = \"product\" | \"collection\" | \"page\";\n\nfunction isMetafield(value: unknown): value is Metafield {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as Metafield).namespace === \"string\" &&\n typeof (value as Metafield).key === \"string\"\n );\n}\n\n/**\n * CMS page routes project the page record at `page.data.page` (see the\n * host's `/pages/[handle]` route); other page types may surface a flat\n * `data.metafields`. Accept both, prefer the nested record.\n */\nfunction pageMetafields(data: Record<string, unknown> | undefined): Metafield[] {\n if (!data) return [];\n const record = data.page as Record<string, unknown> | undefined;\n for (const candidate of [record?.metafields, data.metafields]) {\n if (Array.isArray(candidate)) return candidate.filter(isMetafield);\n }\n return [];\n}\n\n/**\n * All public metafields of the given owner currently in context.\n * Empty array when the owner isn't in context (e.g. `\"product\"` on a\n * collection page) or has no fields — never throws.\n */\nexport function useMetafields(owner: MetafieldOwner): Metafield[] {\n const product = useContext(ProductContext);\n const collection = useContext(CollectionContext);\n const page = useContext(PageContext);\n switch (owner) {\n case \"product\":\n return product?.metafields ?? [];\n case \"collection\":\n return collection?.metafields ?? [];\n case \"page\":\n return pageMetafields(page?.data);\n default:\n return [];\n }\n}\n\n/**\n * Read one merchant-defined field directly:\n *\n * ```tsx\n * const material = useMetafield(\"product\", \"specs\", \"material\");\n * if (material) <dd>{String(material.value)}</dd>;\n * ```\n *\n * Returns the full {@link Metafield} (value pre-coerced to its declared\n * type by the platform) or `null` when missing — same convention as the\n * dynamic-source resolver (`{owner}.metafield:{namespace}.{key}`), so a\n * theme's own fallback renders for stores that haven't set the field.\n */\nexport function useMetafield(\n owner: MetafieldOwner,\n namespace: string,\n key: string,\n): Metafield | null {\n const fields = useMetafields(owner);\n return (\n fields.find((m) => m.namespace === namespace && m.key === key) ?? null\n );\n}\n","import { useContext } from \"react\";\nimport { PageContext } from \"../contexts\";\nimport type {\n ArticleDetail,\n ArticleSummary,\n BlogSummary,\n} from \"../types/entities\";\n\n/**\n * Blog/article hooks — read the content the host resolves server-side\n * into the page descriptor:\n *\n * `blogs` template → `page.data.blogs` → useBlogs()\n * `blog` template → `page.data.blog` + `.articles` → useBlog() / useArticles()\n * `article` template → `page.data.article` → useArticle()\n *\n * All of them degrade to `[]` / `null` outside their template (or on a\n * store with no blog content) — never throw, so a section can render its\n * empty state. Text fields are bilingual maps; the body is UN-sanitized\n * merchant HTML — render via `<RichText>`.\n */\n\nfunction pageData(): Record<string, unknown> | undefined {\n // A hook in all but name; isolated so each public hook stays a plain\n // one-liner over the same context read.\n return useContext(PageContext)?.data;\n}\n\n/** Published blogs of the store (blogs-index template). */\nexport function useBlogs(): BlogSummary[] {\n const data = pageData();\n const blogs = data?.blogs;\n return Array.isArray(blogs) ? (blogs as BlogSummary[]) : [];\n}\n\n/** The current blog (blog template), or the article's blog on an article page. */\nexport function useBlog(): BlogSummary | null {\n const data = pageData();\n const blog = data?.blog ?? (data?.article as ArticleDetail | undefined)?.blog;\n return blog && typeof blog === \"object\" ? (blog as BlogSummary) : null;\n}\n\n/** Published articles of the current blog (blog template), newest first. */\nexport function useArticles(): ArticleSummary[] {\n const data = pageData();\n const articles = data?.articles;\n return Array.isArray(articles) ? (articles as ArticleSummary[]) : [];\n}\n\n/** The current article (article template). */\nexport function useArticle(): ArticleDetail | null {\n const data = pageData();\n const article = data?.article;\n return article && typeof article === \"object\"\n ? (article as ArticleDetail)\n : null;\n}\n","import { createContext, useContext } from \"react\";\nimport type { SectionInstance } from \"../types/theme\";\n\nexport const SectionContext = createContext<SectionInstance | null>(null);\n\nexport function useSection(): SectionInstance {\n const ctx = useContext(SectionContext);\n if (!ctx) throw new Error(\"useSection must be used within a section component\");\n return ctx;\n}\n\nexport function useSectionOptional(): SectionInstance | null {\n return useContext(SectionContext);\n}\n","\"use client\";\n\nimport { useContext, useMemo } from \"react\";\nimport { ThemeSettingsContext } from \"../contexts\";\nimport type { SectionInstance } from \"../types/theme\";\n\n/**\n * A section instance from a section group, carrying its own `id` (the key it\n * had inside the group's `sections` map). The raw `SectionInstance` drops the\n * id — but a theme needs it to key its React list, wire `<Section id={…}>`\n * click-to-select, and look the type up in its own registry — so\n * `useSectionGroup` re-attaches it here.\n */\nexport interface SectionGroupInstance extends SectionInstance {\n /** The instance's key within the group's `sections` map. */\n id: string;\n}\n\nconst EMPTY: readonly SectionGroupInstance[] = Object.freeze([]);\n\n/**\n * useSectionGroup — read the ordered section instances for a named section\n * group (\"header\", \"footer\", or any custom global group) out of\n * `themeSettings.section_groups[group]`.\n *\n * This is the SDK side of \"global sections shared across pages\": the host\n * ships one `section_groups` map on every page, and a theme renders a given\n * group in its layout (header/footer) or wherever it wants a page-independent\n * section list. The returned array is in the group's `order`, and each entry\n * carries its `id` so the theme can key + select + dispatch on it:\n *\n * ```tsx\n * const headerSections = useSectionGroup(\"header\");\n * return headerSections.map(({ id, type, settings }) => {\n * const Comp = registry[type]?.render; // theme owns the registry\n * return Comp ? (\n * <Section key={id} id={id} type={type} groupId=\"header\">\n * <Comp settings={settings} />\n * </Section>\n * ) : null;\n * });\n * ```\n *\n * Pure data hook — it does NOT map types to components. The SDK has no section\n * registry (a theme builds its own via `collectSections`), so there is no\n * generic `<GlobalSections>` renderer to ship: the theme walks the returned\n * instances through its own registry, exactly as it already does for template\n * sections. Returns `[]` (a stable reference) when there is no provider, no\n * `section_groups`, the named group is absent, or its `order` is empty.\n *\n * Disabled instances are INCLUDED (a `disabled` flag is preserved on each\n * entry); filter with `.filter((s) => !s.disabled)` if the theme hides them.\n * Ids listed in `order` but missing from `sections` are skipped defensively.\n */\nexport function useSectionGroup(group: string): SectionGroupInstance[] {\n const settings = useContext(ThemeSettingsContext);\n return useMemo(() => {\n const grp = settings?.section_groups?.[group];\n if (!grp || !Array.isArray(grp.order) || grp.order.length === 0) {\n return EMPTY as SectionGroupInstance[];\n }\n const sections = grp.sections ?? {};\n const out: SectionGroupInstance[] = [];\n for (const id of grp.order) {\n const instance = sections[id];\n if (!instance) continue; // order references a removed section — skip.\n out.push({ id, ...instance });\n }\n return out;\n }, [settings, group]);\n}\n","\"use client\";\nimport { useContext, useMemo } from \"react\";\nimport { CurrencyContext } from \"../contexts\";\nimport { useShop } from \"./useShop\";\nimport type { CurrencyState } from \"../contexts\";\n\n/**\n * Multi-currency presentment — Phase 6, lifted into a provider context in\n * Phase 2 (correctness).\n *\n * The store's *capture* currency (what Paymob/Stripe/etc. charges) never\n * changes mid-session. This hook is purely about **display**: letting\n * visitors browse prices in a currency they recognize.\n *\n * As of Phase 2 the currency config + selection live in `CurrencyContext`,\n * fetched ONCE by `NuMuProvider` (see `/api/storefront/currencies`) and shared\n * by every consumer. Before this, each `useCurrency()` caller fetched its own\n * copy and held the selection in per-instance state, so a `<CurrencySwitcher>`\n * change never reached the `<Money>` tags. Now it does — changing the selected\n * currency re-renders every `<Money>`/`useMoney()` on the page, no reload.\n *\n * Usage:\n *\n * const { base, selected, presentment, convert, setSelected } = useCurrency();\n * <p>{convert(product.price.amount_cents)} {selected}</p>\n * {presentment.length > 1 && (\n * <select value={selected} onChange={(e) => setSelected(e.target.value)}>\n * {presentment.map(c => <option key={c}>{c}</option>)}\n * </select>\n * )}\n *\n * Behavior (owned by `NuMuProvider`):\n * - `selected` defaults to the persisted `numu_currency` cookie if valid,\n * else `default_presentment`, else `base`.\n * - `setSelected` writes the cookie (path=/, 30d) so navigation preserves\n * the choice across pages.\n * - `convert(cents)` returns the converted cents in `selected`, using the\n * rates from the API. When no rate exists, returns the input unchanged\n * (theme renders in base — better than a wrong number).\n *\n * Use `<CurrencySwitcher>` from the SDK for an opinionated UI, or read this\n * hook directly for full control.\n */\n\n// Re-export the currency types from their canonical home (contexts) so\n// existing `import type { CurrencyConfig, CurrencyState } from\n// \"@numueg/theme-sdk\"` (which flows through this module's re-export in\n// index.ts) keeps resolving unchanged.\nexport type { CurrencyConfig, CurrencyState } from \"../contexts\";\n\nexport function useCurrency(): CurrencyState {\n const ctx = useContext(CurrencyContext);\n const shop = useShop();\n\n // Fallback for trees without a NuMuProvider currency value — SSR before the\n // provider's fetch resolves, or a theme mounted outside NuMuProvider. A\n // base-only, no-conversion state so `<Money>`/`<CurrencySwitcher>` render the\n // store currency instead of crashing. The provider owns the real fetch.\n const fallback = useMemo<CurrencyState>(() => {\n const ccy = shop?.currency || \"EGP\";\n return {\n base: ccy,\n selected: ccy,\n presentment: [ccy],\n rates: {},\n autoConvert: false,\n loading: false,\n setSelected: () => {},\n convert: (cents: number) => cents,\n };\n }, [shop?.currency]);\n\n return ctx ?? fallback;\n}\n","\"use client\";\n\nimport { useLocalization } from \"./useLocalization\";\nimport { useShop } from \"./useShop\";\nimport { useCurrency } from \"./useCurrency\";\n\n/**\n * useMoney — convenience hook that returns a formatter bound to the active\n * store's currency.\n *\n * Useful when a section needs to format multiple amounts in a render:\n *\n * const money = useMoney();\n * return <td>{money(item.price * item.quantity)}</td>\n *\n * Multi-currency: like <Money>, when the store has `auto_convert` on and no\n * `currencyOverride` is passed, amounts are converted to and formatted in the\n * visitor's SELECTED presentment currency (shared via `useCurrency()`), so a\n * `<CurrencySwitcher>` change reflows these too. Pass a `currencyOverride` to\n * pin a specific currency and skip conversion.\n *\n * For one-off price displays prefer the <Money> component which handles\n * compare-at and inline rendering.\n */\nexport function useMoney(currencyOverride?: string) {\n const { formatMoney } = useLocalization();\n const shop = useShop();\n const { selected, base, autoConvert, convert } = useCurrency();\n return (amount: number) => {\n const shouldConvert =\n autoConvert && !currencyOverride && !!selected && selected !== base;\n if (shouldConvert) {\n // convert() works in cents; amount is major units — round-trip.\n const converted = convert(Math.round(amount * 100), selected) / 100;\n return formatMoney(converted, selected);\n }\n return formatMoney(amount, currencyOverride || shop?.currency);\n };\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\n\ninterface UseImageOptions {\n /** Sizes attribute (CSS sizes form). */\n sizes?: string;\n /** Widths to generate in srcSet. Falsy → use defaults. */\n widths?: number[];\n /** Pass-through alt text — useImage doesn't render anything; the\n * caller does. */\n alt?: string;\n}\n\ninterface ImageDescriptor {\n src: string | null;\n srcSet: string | null;\n sizes: string;\n alt: string;\n}\n\nconst DEFAULT_WIDTHS = [320, 480, 640, 768, 1024, 1280, 1600, 1920];\nconst DEFAULT_SIZES =\n \"(min-width: 1024px) 25vw, (min-width: 640px) 50vw, 100vw\";\n\n/**\n * useImage — returns srcSet/sizes for a CDN-served image so themes\n * don't have to hand-roll responsive image markup. Pairs with the\n * <Image> component, but is also useful when the theme wants to render\n * something other than a plain `<img>` (e.g., `<picture>` with art\n * direction or a CSS `background-image` via inline style).\n *\n * Returns `null` srcSet if the source URL already encodes a width\n * directive (theme author opted out of auto-sizing).\n */\nexport function useImage(\n src: string | null | undefined,\n opts: UseImageOptions = {},\n): ImageDescriptor {\n const { sizes = DEFAULT_SIZES, widths = DEFAULT_WIDTHS, alt = \"\" } = opts;\n return useMemo(() => {\n if (!src) return { src: null, srcSet: null, sizes, alt };\n if (/[?&]w=\\d+/.test(src)) return { src, srcSet: null, sizes, alt };\n const sep = src.includes(\"?\") ? \"&\" : \"?\";\n const srcSet = widths.map((w) => `${src}${sep}w=${w} ${w}w`).join(\", \");\n return { src, srcSet, sizes, alt };\n }, [src, sizes, widths, alt]);\n}\n","\"use client\";\n\nimport { createContext } from \"react\";\n\n/**\n * The action surface a theme can call to drive customer auth +\n * profile mutations. Each action returns the parsed response body\n * (or throws on network failure); the *result* of the operation is\n * conveyed by the response shape, not the throw boundary.\n *\n * The provider implements these by calling /api/customer/* proxy\n * routes on the storefront, which in turn forward to FastAPI's\n * /storefront/store/{store_id}/auth/* and /storefront/me/* endpoints.\n *\n * Why a separate context (vs bundling onto CustomerContext): the\n * value `Customer | null` was already in CustomerContext for\n * back-compat with themes that read `useCustomer()`. Adding a\n * sibling context for actions keeps the existing read hook stable\n * while letting themes opt into actions via `useCustomerActions()`.\n */\nexport interface CustomerActions {\n /** Email + password → returns { success, data?, error? }. On\n * success the SDK refreshes the customer context automatically. */\n login: (input: {\n email: string;\n password: string;\n }) => Promise<unknown>;\n\n /** Create a new customer + log them in. Some stores require\n * email verification before login is fully usable; this flow\n * still issues the auth cookie so the customer can verify from\n * the welcome email and land logged-in. */\n register: (input: {\n email: string;\n password: string;\n first_name?: string;\n last_name?: string;\n phone?: string;\n accepts_marketing?: boolean;\n }) => Promise<unknown>;\n\n /** Clear the customer_access_token cookie + refresh the context\n * to null. Idempotent: safe to call when not logged in. */\n logout: () => Promise<unknown>;\n\n /** Issue a password-reset email. Anti-enumeration: response\n * never reveals whether the email exists. */\n requestRecover: (input: { email: string }) => Promise<unknown>;\n\n /** Submit the new password with the token from the recovery email. */\n confirmReset: (input: {\n token: string;\n password: string;\n }) => Promise<unknown>;\n\n /** Verify the email with the token from the welcome email. */\n verifyEmail: (input: { token: string }) => Promise<unknown>;\n\n /** Resend the verification email. Server-side rate-limited to\n * prevent email-bombing. */\n resendVerification: (input: { email: string }) => Promise<unknown>;\n\n /** Update the customer's profile (name / phone / marketing). */\n updateProfile: (input: {\n first_name?: string;\n last_name?: string;\n phone?: string;\n accepts_marketing?: boolean;\n }) => Promise<unknown>;\n\n /** Change the customer's password from inside the dashboard.\n * Backend requires the current password as confirmation. */\n changePassword: (input: {\n current_password: string;\n new_password: string;\n }) => Promise<unknown>;\n\n /** Re-fetch the customer profile from the backend and replace\n * the context value. Themes call this after performing any\n * out-of-band mutation that changed the customer's record. */\n refresh: () => Promise<void>;\n}\n\nconst NOOP_ACTIONS: CustomerActions = {\n login: async () => ({}),\n register: async () => ({}),\n logout: async () => ({}),\n requestRecover: async () => ({}),\n confirmReset: async () => ({}),\n verifyEmail: async () => ({}),\n resendVerification: async () => ({}),\n updateProfile: async () => ({}),\n changePassword: async () => ({}),\n refresh: async () => undefined,\n};\n\nexport const CustomerActionsContext =\n createContext<CustomerActions>(NOOP_ACTIONS);\n","\"use client\";\n\nimport { useContext } from \"react\";\nimport { CustomerActionsContext, type CustomerActions } from \"../contexts/customer-actions\";\n\n/**\n * Returns the customer-mutation actions provided by NuMuProvider.\n *\n * Pair with `useCustomer()` for read access:\n *\n * const customer = useCustomer();\n * const { login, logout, register } = useCustomerActions();\n *\n * The actions hit the storefront's `/api/customer/*` proxies, which\n * own the cookie/CSRF/idempotency story. Themes don't talk to the\n * backend directly — they get a stable client-side surface here.\n */\nexport function useCustomerActions(): CustomerActions {\n return useContext(CustomerActionsContext);\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { useCustomer } from \"./useCustomer\";\n\n/**\n * Customer order history.\n *\n * `useOrders()` returns the logged-in customer's orders, paginated.\n * The hook is gated on `useCustomer()` — when null (anonymous\n * visitor), it returns an empty list without hitting the network.\n *\n * `useOrder(id)` fetches a single order. Backend rejects with 404\n * when the id doesn't belong to the customer regardless of whether\n * it exists for someone else (avoids enumeration).\n */\n\nexport interface OrderListEntry {\n id: string;\n order_number: string;\n status: string;\n payment_status: string;\n fulfillment_status: string;\n total: number;\n currency: string;\n created_at: string | null;\n item_count?: number;\n}\n\nexport interface OrderListState {\n orders: OrderListEntry[];\n loading: boolean;\n error: Error | null;\n refresh: () => void;\n}\n\nexport interface OrderDetail extends OrderListEntry {\n line_items: unknown[];\n shipping_address?: Record<string, unknown> | null;\n billing_address?: Record<string, unknown> | null;\n subtotal: number;\n shipping_cost: number;\n tax_amount: number;\n discount_amount: number;\n}\n\nexport interface OrderState {\n order: OrderDetail | null;\n loading: boolean;\n error: Error | null;\n refresh: () => void;\n}\n\nfunction unwrap(json: unknown): unknown {\n if (json && typeof json === \"object\" && \"data\" in json) {\n return (json as { data: unknown }).data;\n }\n return json;\n}\n\nexport function useOrders(): OrderListState {\n const customer = useCustomer();\n const [orders, setOrders] = useState<OrderListEntry[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [tick, setTick] = useState(0);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n if (!customer) {\n // Anonymous: nothing to fetch. Reset state so a logged-out\n // visitor doesn't see stale data carried over from a prior session.\n setOrders([]);\n setError(null);\n setLoading(false);\n return;\n }\n let cancelled = false;\n setLoading(true);\n setError(null);\n void (async () => {\n try {\n const res = await fetch(\"/api/customer/me/orders\", {\n method: \"GET\",\n credentials: \"include\",\n cache: \"no-store\",\n });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const body = unwrap(await res.json());\n if (cancelled) return;\n // Backend returns either a list directly or a paginated wrapper\n // `{ items, total, page, ... }`. Normalize to a list.\n const list = Array.isArray(body)\n ? body\n : Array.isArray((body as Record<string, unknown>)?.items)\n ? ((body as { items: OrderListEntry[] }).items)\n : [];\n setOrders(list as OrderListEntry[]);\n } catch (err) {\n if (cancelled) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [customer, tick]);\n\n return {\n orders,\n loading,\n error,\n refresh: () => setTick((t) => t + 1),\n };\n}\n\nexport function useOrder(id: string | null | undefined): OrderState {\n const customer = useCustomer();\n const [order, setOrder] = useState<OrderDetail | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [tick, setTick] = useState(0);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n if (!id) {\n setOrder(null);\n setError(null);\n setLoading(false);\n return;\n }\n let cancelled = false;\n setLoading(true);\n setError(null);\n void (async () => {\n try {\n // Logged-in customer → full owned-order detail. Guest (the common\n // post-purchase order-confirmation case) → the PUBLIC order-tracking\n // endpoint, protected by the unguessable order UUID. Without this a\n // guest's confirmation page showed \"order not found\".\n const trackUrl = `/api/storefront/track/${encodeURIComponent(id)}`;\n let res = customer\n ? await fetch(`/api/customer/me/orders/${encodeURIComponent(id)}`, {\n method: \"GET\",\n credentials: \"include\",\n cache: \"no-store\",\n })\n : await fetch(trackUrl, { cache: \"no-store\" });\n // A logged-in user opening someone else's confirmation link (or an\n // order not yet linked to their account) 404s on /me/orders — fall\n // back to the public track view so the page still renders.\n if (!res.ok && customer) {\n res = await fetch(trackUrl, { cache: \"no-store\" });\n }\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const body = unwrap(await res.json());\n if (cancelled) return;\n setOrder(body as OrderDetail);\n } catch (err) {\n if (cancelled) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [customer, id, tick]);\n\n return {\n order,\n loading,\n error,\n refresh: () => setTick((t) => t + 1),\n };\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { useCustomer } from \"./useCustomer\";\n\n/**\n * Customer address book. Used by:\n * - The /account/addresses dashboard (list + CRUD).\n * - Checkout autofill (default address selected by default).\n *\n * Mutations return the updated row (or void on delete) and bump the\n * internal tick so the list reflects state changes immediately.\n * Anonymous visitors get an empty list with no network calls.\n */\n\nexport interface CustomerAddress {\n id: string;\n first_name?: string | null;\n last_name?: string | null;\n address_line1?: string | null;\n address_line2?: string | null;\n city?: string | null;\n state?: string | null;\n postal_code?: string | null;\n country?: string | null;\n phone?: string | null;\n label?: string | null;\n is_default?: boolean;\n // Optional geocoding fields — present when the merchant collects them.\n latitude?: number | null;\n longitude?: number | null;\n}\n\nexport type AddressInput = Omit<CustomerAddress, \"id\" | \"is_default\"> & {\n is_default?: boolean;\n};\n\nexport interface CustomerAddressesState {\n addresses: CustomerAddress[];\n loading: boolean;\n error: Error | null;\n refresh: () => void;\n addAddress: (input: AddressInput) => Promise<CustomerAddress | null>;\n updateAddress: (\n id: string,\n input: Partial<AddressInput>,\n ) => Promise<CustomerAddress | null>;\n deleteAddress: (id: string) => Promise<boolean>;\n setDefaultAddress: (id: string) => Promise<boolean>;\n}\n\nfunction unwrap(json: unknown): unknown {\n if (json && typeof json === \"object\" && \"data\" in json) {\n return (json as { data: unknown }).data;\n }\n return json;\n}\n\nasync function readBody(res: Response): Promise<unknown> {\n try {\n return unwrap(await res.json());\n } catch {\n return null;\n }\n}\n\nexport function useCustomerAddresses(): CustomerAddressesState {\n const customer = useCustomer();\n const [addresses, setAddresses] = useState<CustomerAddress[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [tick, setTick] = useState(0);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n if (!customer) {\n setAddresses([]);\n setLoading(false);\n setError(null);\n return;\n }\n let cancelled = false;\n setLoading(true);\n setError(null);\n void (async () => {\n try {\n const res = await fetch(\"/api/customer/me/addresses\", {\n method: \"GET\",\n credentials: \"include\",\n cache: \"no-store\",\n });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const body = await readBody(res);\n if (cancelled) return;\n const list = Array.isArray(body)\n ? body\n : Array.isArray((body as Record<string, unknown>)?.items)\n ? ((body as { items: CustomerAddress[] }).items)\n : [];\n setAddresses(list as CustomerAddress[]);\n } catch (err) {\n if (cancelled) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [customer, tick]);\n\n const refresh = useCallback(() => setTick((t) => t + 1), []);\n\n // CSRF: cart and customer mutations both echo the `numu_csrf` cookie\n // value as `x-numu-csrf` header. Read it from document.cookie just-\n // in-time so we always send the freshest value (the cookie may be\n // refreshed by /api/cart on first mount).\n function readCsrf(): string | null {\n if (typeof document === \"undefined\") return null;\n const m = document.cookie.match(/(?:^|; )numu_csrf=([^;]+)/);\n return m ? decodeURIComponent(m[1]) : null;\n }\n\n function mutationHeaders(): Record<string, string> {\n const h: Record<string, string> = { \"Content-Type\": \"application/json\" };\n const csrf = readCsrf();\n if (csrf) h[\"x-numu-csrf\"] = csrf;\n return h;\n }\n\n const addAddress = useCallback(\n async (input: AddressInput) => {\n const res = await fetch(\"/api/customer/me/addresses\", {\n method: \"POST\",\n credentials: \"include\",\n headers: mutationHeaders(),\n body: JSON.stringify(input),\n });\n if (!res.ok) return null;\n const created = (await readBody(res)) as CustomerAddress | null;\n refresh();\n return created;\n },\n [refresh],\n );\n\n const updateAddress = useCallback(\n async (id: string, input: Partial<AddressInput>) => {\n const res = await fetch(\n `/api/customer/me/addresses/${encodeURIComponent(id)}`,\n {\n method: \"PUT\",\n credentials: \"include\",\n headers: mutationHeaders(),\n body: JSON.stringify(input),\n },\n );\n if (!res.ok) return null;\n const updated = (await readBody(res)) as CustomerAddress | null;\n refresh();\n return updated;\n },\n [refresh],\n );\n\n const deleteAddress = useCallback(\n async (id: string) => {\n const res = await fetch(\n `/api/customer/me/addresses/${encodeURIComponent(id)}`,\n {\n method: \"DELETE\",\n credentials: \"include\",\n headers: mutationHeaders(),\n },\n );\n if (!res.ok) return false;\n refresh();\n return true;\n },\n [refresh],\n );\n\n const setDefaultAddress = useCallback(\n async (id: string) => {\n const res = await fetch(\n `/api/customer/me/addresses/${encodeURIComponent(id)}/default`,\n {\n method: \"PUT\",\n credentials: \"include\",\n headers: mutationHeaders(),\n },\n );\n if (!res.ok) return false;\n refresh();\n return true;\n },\n [refresh],\n );\n\n return {\n addresses,\n loading,\n error,\n refresh,\n addAddress,\n updateAddress,\n deleteAddress,\n setDefaultAddress,\n };\n}\n","\"use client\";\nimport { useContext, useEffect, useMemo, useState } from \"react\";\nimport {\n LocalizationContext,\n NavigationContext,\n type MenuItemData,\n} from \"../contexts\";\n\n/**\n * Menu item, modeled on Shopify's `linklists` entries.\n *\n * Themes typically render header/footer nav as a tree — we expose\n * `children` so a single fetch hydrates an arbitrary depth. Backends\n * that don't support nesting return a flat list (children=[]).\n */\nexport interface NavigationItem {\n id: string;\n title: string;\n /** The URL the menu item points to — relative path or absolute URL. */\n url: string;\n /** Optional foreign keys when the item references a typed resource. */\n resource_type?: \"product\" | \"collection\" | \"page\" | \"blog\" | \"article\" | \"url\" | null;\n resource_handle?: string | null;\n /**\n * §5 hide-page → hide-nav-link. `false` when the target CMS page is\n * unpublished/deleted (backend-annotated). Defaults to `true` (visible)\n * when the backend doesn't annotate, so themes can safely filter on\n * `item.target_visible !== false`.\n */\n target_visible: boolean;\n children: NavigationItem[];\n}\n\nexport interface NavigationState {\n /** Items in display order. Empty array when the menu is missing or still loading. */\n items: NavigationItem[];\n loading: boolean;\n /** Non-null when the fetch failed — the menu still resolves to []. */\n error: Error | null;\n}\n\nconst cache = new Map<string, NavigationItem[]>();\n\n/**\n * Resolve a bilingual label to a single display string for `locale`,\n * degrading gracefully: active locale → English → Arabic → first value.\n */\nfunction localizeLabel(\n label: Record<string, string> | undefined,\n locale: string,\n): string {\n if (!label) return \"\";\n return (\n label[locale] ||\n label.en ||\n label.ar ||\n Object.values(label).find((v) => !!v) ||\n \"\"\n );\n}\n\n/** Map the backend item `type` onto the SDK's `resource_type` union. */\nfunction mapResourceType(type?: string | null): NavigationItem[\"resource_type\"] {\n switch (type) {\n case \"product\":\n return \"product\";\n case \"collection\":\n return \"collection\";\n case \"page\":\n return \"page\";\n case \"blog\":\n return \"blog\";\n case \"article\":\n return \"article\";\n case \"http\":\n case \"url\":\n return \"url\";\n default:\n return null;\n }\n}\n\n/** Localize a raw (bilingual) menu item tree into display NavigationItems. */\nfunction toNavigationItem(raw: MenuItemData, locale: string): NavigationItem {\n return {\n id: raw.id,\n title: localizeLabel(raw.label, locale),\n url: raw.url || \"/\",\n resource_type: mapResourceType(raw.type),\n resource_handle: raw.resource_id ?? null,\n target_visible: raw.target_visible !== false,\n children: (raw.children ?? [])\n .map((child) => toNavigationItem(child, locale))\n .filter((child) => child.target_visible),\n };\n}\n\n/**\n * Fetch a merchant-managed nav menu by handle.\n *\n * Resolution order (Phase 2.4):\n * 1. Host-injected menus — the storefront resolves menus server-side\n * (`GET /storefront/store/{id}/menus`) and injects them via\n * `NuMuProvider`'s `navigation` prop → `NavigationContext`. When the\n * handle is present we localize + return it synchronously, no fetch.\n * A non-empty map that lacks the handle means \"no such menu\" → [].\n * 2. `options.initialItems` — a theme that pre-fetched its own list.\n * 3. Client fetch of `GET /api/storefront/navigation/{handle}` — the\n * legacy fallback for hosts that inject nothing. On 404 / network\n * error the hook resolves to [] (a missing menu is a soft failure;\n * the theme falls back to its own DEFAULT_NAV).\n */\nexport function useNavigation(\n handle: string,\n options?: { initialItems?: NavigationItem[] },\n): NavigationState {\n // NavigationContext defaults to {} outside a provider; LocalizationContext\n // is read defensively (no throw) so useNavigation works even if a theme\n // calls it above NuMuProvider in a test harness.\n const navMap = useContext(NavigationContext);\n const localization = useContext(LocalizationContext);\n const locale = localization?.locale ?? \"en\";\n\n const hostProvidedAny = !!navMap && Object.keys(navMap).length > 0;\n const rawItems = handle ? navMap?.[handle] : undefined;\n\n // Localized view of host-injected items. `null` means \"host wired no\n // navigation at all\" → fall through to initialItems / fetch. `[]` means\n // the host IS authoritative but this handle is absent/empty → render\n // nothing (no doomed fetch).\n const hostItems = useMemo<NavigationItem[] | null>(() => {\n if (rawItems)\n return rawItems\n .map((it) => toNavigationItem(it, locale))\n // §5 hide-page → hide-nav-link: drop items whose target CMS page is\n // unpublished/deleted (backend-annotated). Children already filtered\n // in toNavigationItem; this drops hidden top-level entries so every\n // theme using useNavigation gets the behaviour for free.\n .filter((it) => it.target_visible);\n if (hostProvidedAny) return [];\n return null;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [rawItems, hostProvidedAny, locale]);\n\n const [items, setItems] = useState<NavigationItem[]>(\n hostItems ?? options?.initialItems ?? cache.get(handle) ?? [],\n );\n const [loading, setLoading] = useState(\n hostItems === null && !options?.initialItems && !cache.has(handle),\n );\n const [error, setError] = useState<Error | null>(null);\n\n // Keep items in sync with host-injected menus (locale switch, or the\n // map arriving after first paint). When the host is authoritative we\n // never fetch.\n useEffect(() => {\n if (hostItems === null) return;\n setItems(hostItems);\n setLoading(false);\n setError(null);\n }, [hostItems]);\n\n useEffect(() => {\n // Host-injected menus win — skip the network entirely.\n if (hostItems !== null) return;\n if (typeof window === \"undefined\") return;\n if (!handle) {\n setItems([]);\n setLoading(false);\n return;\n }\n if (cache.has(handle) && !options?.initialItems) {\n setItems(cache.get(handle) || []);\n setLoading(false);\n return;\n }\n let cancelled = false;\n setLoading(true);\n setError(null);\n void (async () => {\n try {\n const res = await fetch(\n `/api/storefront/navigation/${encodeURIComponent(handle)}`,\n { cache: \"no-store\" },\n );\n if (!res.ok) {\n // 404 = no such menu; render nothing instead of an error UI.\n if (cancelled) return;\n cache.set(handle, []);\n setItems([]);\n return;\n }\n const json = (await res.json()) as\n | { items?: NavigationItem[] }\n | NavigationItem[];\n const list: NavigationItem[] = Array.isArray(json)\n ? json\n : json.items || [];\n if (cancelled) return;\n cache.set(handle, list);\n setItems(list);\n } catch (err) {\n if (cancelled) return;\n // Non-OK / network failure → empty list + surface error so\n // themes can decide whether to log or show a fallback.\n setError(err instanceof Error ? err : new Error(String(err)));\n setItems([]);\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n return () => {\n cancelled = true;\n };\n // Deliberate: re-run when `handle` or host-injection state changes;\n // `initialItems` change shouldn't refetch (theme passes it once).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [handle, hostItems === null]);\n\n return { items, loading, error };\n}\n","\"use client\";\nimport { useEffect, useRef, useState } from \"react\";\nimport type { Product, Collection, Page } from \"../types/entities\";\n\n/**\n * Mixed-result search shape. The backend tsvector implementation lands in\n * Phase 4; until then this hook talks to /api/storefront/search and\n * gracefully degrades (empty results) when the endpoint isn't available.\n *\n * Two modes:\n * - \"predictive\" (default): debounced, capped at 5 per type, returns\n * fast for autocomplete dropdowns.\n * - \"full\": full result set with paging, used by /search pages.\n */\n\nexport interface SearchResults {\n products: Product[];\n collections: Collection[];\n pages: Page[];\n /** Articles will populate once the blog backend lands; field shape is\n * reserved here so themes can write code that doesn't break on\n * upgrade. */\n articles: Array<{ id: string; title: string; handle: string; excerpt?: string }>;\n total: number;\n}\n\nexport interface UseSearchOptions {\n /** \"predictive\" debounces and caps; \"full\" returns paged results. */\n mode?: \"predictive\" | \"full\";\n /** Restrict to specific result types. Default: all. */\n types?: Array<\"products\" | \"collections\" | \"pages\" | \"articles\">;\n /** Per-type cap. Predictive mode defaults to 5; full mode defaults to 24. */\n limit?: number;\n /** Debounce window in ms for predictive mode. Default 200. */\n debounceMs?: number;\n /** Skip the debounce (e.g. when the user submits the form). */\n immediate?: boolean;\n}\n\nexport interface SearchState {\n query: string;\n results: SearchResults;\n loading: boolean;\n error: Error | null;\n}\n\nconst EMPTY: SearchResults = {\n products: [],\n collections: [],\n pages: [],\n articles: [],\n total: 0,\n};\n\nexport function useSearch(\n query: string,\n options: UseSearchOptions = {},\n): SearchState {\n const {\n mode = \"predictive\",\n types,\n limit,\n debounceMs = 200,\n immediate = false,\n } = options;\n\n const [results, setResults] = useState<SearchResults>(EMPTY);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const lastRequestId = useRef(0);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const trimmed = query.trim();\n if (!trimmed) {\n setResults(EMPTY);\n setLoading(false);\n setError(null);\n return;\n }\n\n const requestId = ++lastRequestId.current;\n setLoading(true);\n setError(null);\n\n const run = async () => {\n try {\n const params = new URLSearchParams({ q: trimmed, mode });\n if (types?.length) params.set(\"types\", types.join(\",\"));\n if (limit) params.set(\"limit\", String(limit));\n const res = await fetch(`/api/storefront/search?${params}`, {\n cache: \"no-store\",\n });\n if (requestId !== lastRequestId.current) return; // superseded\n if (!res.ok) {\n // Backend search not yet wired (Phase 4). Empty result is\n // an acceptable degraded mode — themes show \"no results\"\n // instead of an error banner.\n setResults(EMPTY);\n return;\n }\n const json = (await res.json()) as Partial<SearchResults> & {\n data?: Partial<SearchResults>;\n };\n const body = json.data || json;\n if (requestId !== lastRequestId.current) return;\n setResults({\n products: body.products || [],\n collections: body.collections || [],\n pages: body.pages || [],\n articles: body.articles || [],\n total: body.total || 0,\n });\n } catch (err) {\n if (requestId !== lastRequestId.current) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n setResults(EMPTY);\n } finally {\n if (requestId === lastRequestId.current) setLoading(false);\n }\n };\n\n if (immediate || mode === \"full\") {\n void run();\n return;\n }\n const t = setTimeout(run, debounceMs);\n return () => clearTimeout(t);\n }, [query, mode, debounceMs, immediate, limit, types?.join(\",\")]); // eslint-disable-line react-hooks/exhaustive-deps\n\n return { query, results, loading, error };\n}\n","\"use client\";\nimport { useCallback, useMemo } from \"react\";\n\n/**\n * Theme-facing analytics dispatcher.\n *\n * Two delivery channels, fired in parallel:\n * 1. Server-side track: POST /api/storefront/track with the event\n * payload. The host storefront proxies to FastAPI's funnel-event\n * endpoint (/storefront/store/{id}/track) and fans out to\n * merchant-configured pixels (GA4 Measurement Protocol, Meta CAPI,\n * TikTok Events API). Failed pixels never block the UI — we\n * don't await the response.\n * 2. Window CustomEvent (`numu:analytics:event`): so theme devs can\n * wire their own GTM container, third-party SDK, or in-house\n * pixel without going through the server. Detail shape mirrors\n * what gets POSTed.\n *\n * Standard event names (recommended for compatibility with GA4 / Meta):\n * page_view, view_item, view_collection, search, add_to_cart,\n * remove_from_cart, view_cart, begin_checkout, add_payment_info,\n * add_shipping_info, purchase, refund, sign_up, login,\n * add_to_wishlist, share. Custom names are also fine — the dispatcher\n * does not validate, so themes can ship store-specific events.\n *\n * Funnel-event mapping\n * --------------------\n * Standard event names that map to the backend's funnel steps are\n * dispatched with the full funnel-event payload shape (path,\n * session_fingerprint, attribution envelope from\n * window.__numu_attribution). This is what powers the merchant\n * funnel / journey / multi-touch attribution dashboards. Events with\n * no funnel mapping still POST with the loose `{event, payload}`\n * shape — the proxy forwards them so the pixel-fanout layer still\n * fires.\n */\n\nexport interface AnalyticsPayload {\n /** Standard or custom event name. Lowercase + underscores recommended. */\n [key: string]: unknown;\n}\n\nexport interface AnalyticsApi {\n /**\n * Fire an event. Non-blocking — both the fetch and the CustomEvent\n * dispatch happen in the next microtask; theme code shouldn't await.\n */\n track: (eventName: string, payload?: AnalyticsPayload) => void;\n}\n\n/**\n * Standard event name → backend funnel step mapping.\n *\n * Only events listed here drive the funnel / attribution dashboards.\n * Everything else still POSTs (for pixel fanout) but doesn't land in\n * the funnel_events table. The mapping mirrors what the bazaar\n * storefront's trackingService uses on the SaaS side.\n */\nconst EVENT_TO_FUNNEL_STEP: Record<string, string> = {\n page_view: \"page_view\",\n view_item: \"product_view\",\n view_collection: \"page_view\",\n add_to_cart: \"add_to_cart\",\n begin_checkout: \"checkout_started\",\n purchase: \"order_completed\",\n // Wave 2+ standard Meta events — backend's FUNNEL_STEP_TO_META_EVENT\n // table accepts these as funnel steps directly.\n search: \"search\",\n lead: \"lead\",\n sign_up: \"complete_registration\",\n add_to_wishlist: \"add_to_wishlist\",\n add_payment_info: \"add_payment_info\",\n};\n\ninterface AttributionEnvelope {\n v?: number;\n first_touch?: unknown;\n last_touch?: unknown;\n session_id?: string | null;\n}\n\ninterface NumuAttributionBridge {\n get(): AttributionEnvelope | null;\n}\n\ninterface NumuCustomerBridge {\n /** Authenticated customer's UUID, or null when the visitor is a guest. */\n getId(): string | null;\n}\n\ndeclare global {\n interface Window {\n __numu_attribution?: NumuAttributionBridge;\n /**\n * Optional bridge installed by the host storefront's customer\n * provider. When set, the SDK includes ``customer_id`` on\n * funnel-step events so the backend can record touches against\n * the authenticated customer immediately instead of waiting for\n * the next checkout to backfill.\n */\n __numu_customer?: NumuCustomerBridge;\n }\n}\n\nfunction readAttribution(): AttributionEnvelope | null {\n if (typeof window === \"undefined\") return null;\n try {\n return window.__numu_attribution?.get?.() ?? null;\n } catch {\n return null;\n }\n}\n\nfunction readCustomerId(): string | null {\n if (typeof window === \"undefined\") return null;\n try {\n return window.__numu_customer?.getId?.() ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * Session fingerprint for funnel-event dedup.\n *\n * The attribution envelope's session_id (ULID, stable for cookie\n * lifetime) is the natural fingerprint — same cookie lifetime as the\n * attribution window, so funnel + journey + multi-touch all agree on\n * what \"one session\" means.\n *\n * Fallback: a per-tab random string when no envelope exists yet (first\n * visit before AttributionProvider's effect has run). Persisted on the\n * window so subsequent calls in the same tab reuse it — otherwise\n * each event would generate its own fingerprint and the funnel\n * dashboard would over-count distinct sessions.\n */\nfunction getFingerprint(): string {\n if (typeof window === \"undefined\") return \"ssr\";\n const env = readAttribution();\n if (env?.session_id) return env.session_id;\n\n const w = window as unknown as { __numu_session_fp?: string };\n if (w.__numu_session_fp) return w.__numu_session_fp;\n // crypto.randomUUID is universally available in our supported\n // browsers (no IE / pre-2022 mobile Safari). Skip the fallback.\n const fp = crypto.randomUUID();\n w.__numu_session_fp = fp;\n return fp;\n}\n\n/**\n * Free function body of the hook's `track`.\n *\n * Extracted so unit tests can call it directly without spinning up a\n * React renderer for what is essentially a side-effect dispatcher.\n * The exported `useAnalytics` hook is a thin memoization wrapper.\n */\nexport function dispatchAnalyticsEvent(\n eventName: string,\n payload: AnalyticsPayload = {},\n): void {\n if (typeof window === \"undefined\") return;\n\n // ONE event id for BOTH channels. The host's <MetaPixel>/<TikTokPixel>\n // bridges fire the browser pixel with `detail.event_id`, and the /track\n // POST below carries the same id — that's what lets Meta/TikTok dedupe\n // the browser event against the server-side CAPI/Events-API fire.\n // (Previously the CustomEvent had NO id while the POST minted its own,\n // so any theme calling track() double-counted on both platforms.)\n const eventId = crypto.randomUUID();\n\n // 1. Window CustomEvent — synchronous, cheap. Themes that wire\n // their own pixels listen here; the host pixel bridges too.\n try {\n window.dispatchEvent(\n new CustomEvent(\"numu:analytics:event\", {\n detail: { event: eventName, payload, event_id: eventId, ts: Date.now() },\n }),\n );\n } catch {\n /* CustomEvent unsupported — no DOM event polyfill needed today. */\n }\n\n // 2. Server-side fanout. Funnel-step events get the strict payload\n // shape the backend's funnel_events table expects (path,\n // fingerprint, step, step_data, attribution). Non-funnel events\n // keep the loose shape for the pixel-fanout layer.\n const step = EVENT_TO_FUNNEL_STEP[eventName] ?? null;\n // Lifting customer_id once so we don't read the bridge twice per\n // dispatch. Absent (null) for guests / unauthenticated visitors;\n // present for logged-in customers whose journey rows should land\n // with customer_id set immediately instead of waiting for the\n // next checkout to backfill.\n const customerId = readCustomerId();\n // Absolute URL as well as the path. The backend uses it for the CAPI\n // `event_source_url`; without it a theme-fired event fell back to the store\n // origin, so every one of them looked like it happened on the homepage —\n // which is the field Meta's URL-based audience rules read.\n const pageUrl =\n typeof window !== \"undefined\" ? window.location.href : undefined;\n\n // NOTE: no `user_data` here, deliberately. Identity is resolved SERVER-side\n // from `fingerprint` — the backend looks up the shopper's contact details\n // and hashes them before anything leaves for Meta. Passing PII through the\n // SDK would mean a theme bundle handling a shopper's email in its own\n // scope, and BYOT bundles are third-party code running on the storefront's\n // origin. The fingerprint is enough, and it is not PII.\n const body: Record<string, unknown> = step\n ? {\n event_id: eventId,\n path: window.location.pathname,\n page_url: pageUrl,\n fingerprint: getFingerprint(),\n step,\n step_data: payload,\n referrer:\n typeof document !== \"undefined\" && document.referrer\n ? document.referrer\n : undefined,\n attribution: readAttribution() ?? undefined,\n customer_id: customerId ?? undefined,\n }\n : {\n event: eventName,\n payload,\n event_id: eventId,\n page_url: pageUrl,\n ts: Date.now(),\n attribution: readAttribution() ?? undefined,\n customer_id: customerId ?? undefined,\n };\n\n void (async () => {\n try {\n await fetch(\"/api/storefront/track\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n keepalive: true, // survive page-unload (e.g. begin_checkout → redirect)\n });\n } catch {\n /* swallowed by design */\n }\n })();\n}\n\nexport function useAnalytics(): AnalyticsApi {\n const track = useCallback(\n (eventName: string, payload: AnalyticsPayload = {}) => {\n dispatchAnalyticsEvent(eventName, payload);\n },\n [],\n );\n\n return useMemo(() => ({ track }), [track]);\n}\n","\"use client\";\nimport { useCallback, useEffect, useRef, useSyncExternalStore } from \"react\";\n\n/**\n * Shared client-data layer (Phase 3) — a tiny SWR-style cache with ZERO\n * runtime dependencies.\n *\n * Why this exists (from the audit): several hooks fetched + held per-instance\n * state, so N components rendering the same resource fired N identical requests\n * AND drifted out of sync (e.g. two wishlist hearts for one product; `useApp`\n * applying an out-of-order response over a newer one). `useCachedResource`\n * centralizes fetching behind one module-level store keyed by a string:\n *\n * (a) DEDUP — the first consumer of a key starts the fetch and stashes the\n * in-flight promise on the entry; every other consumer that revalidates\n * the same key while it's pending joins that promise instead of firing a\n * second request. N consumers → ONE network call.\n * (b) CACHE — results live on the entry keyed by string, so a later mount\n * reads the cached value immediately (and skips refetch within\n * `dedupeIntervalMs`).\n * (c) SUBSCRIBE / NOTIFY — every hook instance subscribes to its key via\n * `useSyncExternalStore`. Any update (fetch resolve, `mutate`) rebuilds\n * the entry's immutable snapshot and notifies ALL subscribers, so every\n * instance re-renders with the same value — cross-instance state sync.\n * (d) REVALIDATE + CANCELLATION — each fetch reserves a monotonic sequence\n * number and an `AbortController`. Starting a new (forced) fetch aborts\n * the previous one; when any fetch settles, its result is applied ONLY if\n * its sequence is still the latest (`mySeq === entry.seq`). So a slow,\n * superseded response can never overwrite a newer result regardless of\n * the order the network resolves them in.\n *\n * SSR-safe: the fetch is triggered from `useEffect` (never runs under\n * `renderToString`), and `useSyncExternalStore`'s server snapshot returns the\n * `initialData` fallback without ever touching the module cache — so nothing is\n * written to the shared map on the server and there is no cross-request bleed.\n *\n * This is intentionally NOT a full SWR clone (no focus/reconnect revalidation,\n * no suspense, no infinite pagination). It's the smallest primitive that fixes\n * the audited dedup + sync + ordering bugs and that themes can reuse.\n */\n\n/** The reactive slice a consumer reads. */\nexport interface CachedResourceState<T> {\n /** Latest cached value, or `initialData` before the first fetch settles. */\n data: T | undefined;\n /** Error from the most recent settled fetch (cleared on success / mutate). */\n error: Error | undefined;\n /** True until the first fetch (or `mutate`) settles a value for this key. */\n isLoading: boolean;\n /** True whenever a fetch is currently in flight (initial OR background). */\n isValidating: boolean;\n}\n\n/** Fetcher receives an AbortSignal so a superseding fetch can cancel it. */\nexport type CacheFetcher<T> = (signal: AbortSignal) => Promise<T>;\n\n/** `mutate` accepts a value or an updater `(current) => next`. */\nexport type CacheMutator<T> =\n | T\n | undefined\n | ((current: T | undefined) => T | undefined);\n\nexport interface MutateOptions {\n /** After applying the local value, kick a fresh (forced) revalidation. */\n revalidate?: boolean;\n}\n\nexport interface CachedResource<T> extends CachedResourceState<T> {\n /**\n * Optimistically write the cached value for this key (all subscribers\n * re-render). Pass `{ revalidate: true }` to also refetch afterwards.\n */\n mutate: (next: CacheMutator<T>, opts?: MutateOptions) => void;\n /** Force a fresh fetch, superseding + aborting any in-flight request. */\n revalidate: () => Promise<void>;\n}\n\nexport interface UseCachedResourceOptions<T> {\n /**\n * Value shown on the server and on the first client paint before the fetch\n * resolves. Used as the SSR snapshot (SSR-safe: no fetch on the server).\n */\n initialData?: T;\n /** When `false`, the hook holds no subscription and never fetches. */\n enabled?: boolean;\n /** Auto-fetch on mount / key change (default `true`). */\n revalidateOnMount?: boolean;\n /**\n * Skip the mount fetch if a value settled within this window (ms). Prevents\n * a staggered second mount from refetching a still-fresh key. Default 2000.\n */\n dedupeIntervalMs?: number;\n /** Called on a non-abort fetch error, with the key. */\n onError?: (error: Error, key: string) => void;\n}\n\ninterface Entry<T> {\n data: T | undefined;\n error: Error | undefined;\n /** Has a fetch or mutate produced a value yet? Drives `isLoading`. */\n settled: boolean;\n /** Is a fetch currently running? Drives `isValidating`. */\n inFlight: boolean;\n /** Monotonic request counter; only `mySeq === seq` may apply a result. */\n seq: number;\n lastFetchAt: number;\n /** In-flight fetch promise, for cross-instance dedup. */\n promise: Promise<void> | undefined;\n controller: AbortController | undefined;\n /** Latest fetcher seen for this key, so `mutate({revalidate})` can refetch. */\n fetcher: CacheFetcher<T> | undefined;\n subscribers: Set<() => void>;\n /** Cached immutable snapshot — stable ref until state actually changes. */\n snapshot: CachedResourceState<T>;\n}\n\n// Module-level store. Only ever written on the client (see SSR note above).\nconst cache = new Map<string, Entry<unknown>>();\n\nfunction buildSnapshot<T>(entry: Entry<T>): CachedResourceState<T> {\n return {\n data: entry.data,\n error: entry.error,\n isLoading: !entry.settled,\n isValidating: entry.inFlight,\n };\n}\n\n/** Rebuild the entry's snapshot and notify every subscriber. */\nfunction commit<T>(entry: Entry<T>): void {\n entry.snapshot = buildSnapshot(entry);\n entry.subscribers.forEach((cb) => cb());\n}\n\nfunction getEntry<T>(key: string, initialData?: T): Entry<T> {\n let entry = cache.get(key) as Entry<T> | undefined;\n if (!entry) {\n entry = {\n data: initialData,\n error: undefined,\n settled: false,\n inFlight: false,\n seq: 0,\n lastFetchAt: 0,\n promise: undefined,\n controller: undefined,\n fetcher: undefined,\n subscribers: new Set(),\n snapshot: {\n data: initialData,\n error: undefined,\n isLoading: true,\n isValidating: false,\n },\n };\n cache.set(key, entry as unknown as Entry<unknown>);\n }\n return entry;\n}\n\n/**\n * Fetch (or join an in-flight fetch for) `key`.\n *\n * Dedup: a non-forced call with a pending promise returns that promise instead\n * of starting a second request. Ordering: each fetch takes `mySeq = ++seq` and\n * a fresh AbortController; a forced call aborts the previous controller. A\n * result is applied only when `mySeq === entry.seq` at settle time, so a\n * superseded (out-of-order) response is dropped.\n */\nexport function revalidateResource<T>(\n key: string,\n fetcher: CacheFetcher<T>,\n opts?: { force?: boolean; onError?: (error: Error, key: string) => void },\n): Promise<void> {\n const entry = getEntry<T>(key);\n entry.fetcher = fetcher;\n\n // Dedup: join the request already in flight for this key.\n if (!opts?.force && entry.promise) return entry.promise;\n\n const mySeq = ++entry.seq;\n if (entry.controller) entry.controller.abort();\n const controller = new AbortController();\n entry.controller = controller;\n entry.inFlight = true;\n commit(entry);\n\n const run = (async () => {\n try {\n const data = await fetcher(controller.signal);\n if (mySeq !== entry.seq) return; // superseded by a newer request\n entry.data = data;\n entry.error = undefined;\n entry.settled = true;\n entry.lastFetchAt = Date.now();\n } catch (err) {\n if (controller.signal.aborted) return; // cancelled by a newer request\n if (mySeq !== entry.seq) return; // superseded by a newer request\n const error = err instanceof Error ? err : new Error(String(err));\n entry.error = error;\n entry.settled = true;\n entry.lastFetchAt = Date.now();\n opts?.onError?.(error, key);\n } finally {\n // Only the winning (latest) request flips inFlight off + commits, so a\n // superseded fetch resolving late can't clobber the newer one's state.\n if (mySeq === entry.seq) {\n entry.inFlight = false;\n entry.controller = undefined;\n commit(entry);\n }\n }\n })();\n\n entry.promise = run;\n void run.finally(() => {\n // Clear only if still ours — a forced fetch may have replaced the promise.\n if (entry.promise === run) entry.promise = undefined;\n });\n return run;\n}\n\n/** Imperatively write a key's cached value and notify all subscribers. */\nexport function mutateResource<T>(\n key: string,\n next: CacheMutator<T>,\n opts?: MutateOptions,\n): void {\n const entry = getEntry<T>(key);\n const value =\n typeof next === \"function\"\n ? (next as (current: T | undefined) => T | undefined)(entry.data)\n : next;\n entry.data = value;\n entry.error = undefined;\n entry.settled = true;\n commit(entry);\n if (opts?.revalidate && entry.fetcher) {\n void revalidateResource(key, entry.fetcher, { force: true });\n }\n}\n\n/** Peek the current cached value for a key without subscribing. */\nexport function readResource<T>(key: string): T | undefined {\n return (cache.get(key) as Entry<T> | undefined)?.data;\n}\n\n/** Drop one key (or the whole cache when called with no argument). */\nexport function clearResource(key?: string): void {\n if (key === undefined) {\n cache.clear();\n return;\n }\n cache.delete(key);\n}\n\nconst NOOP = () => {};\n\n/**\n * Subscribe to a cached resource keyed by `key`, deduping the fetch across all\n * instances and keeping them in sync. See the module docblock for the full\n * contract.\n *\n * @param key Cache key. `null`/`undefined`/`\"\"` (or `enabled: false`)\n * disables the hook — no subscription, no fetch, `initialData`\n * is returned.\n * @param fetcher `(signal) => Promise<T>`. Recreated-per-render is fine; the\n * latest is captured in a ref so it doesn't retrigger fetches.\n * @param options See {@link UseCachedResourceOptions}.\n */\nexport function useCachedResource<T>(\n key: string | null | undefined,\n fetcher: CacheFetcher<T>,\n options?: UseCachedResourceOptions<T>,\n): CachedResource<T> {\n const enabled = options?.enabled !== false && key != null && key !== \"\";\n const revalidateOnMount = options?.revalidateOnMount !== false;\n const dedupeIntervalMs = options?.dedupeIntervalMs ?? 2000;\n const cacheKey = enabled ? (key as string) : \"\";\n\n // Keep latest fetcher / callbacks / initialData in refs so the fetch effect\n // can depend on `key` alone — an inline fetcher recreated every render must\n // not retrigger the request.\n const fetcherRef = useRef(fetcher);\n fetcherRef.current = fetcher;\n const onErrorRef = useRef(options?.onError);\n onErrorRef.current = options?.onError;\n const initialDataRef = useRef(options?.initialData);\n\n // Stable fallback snapshot for the disabled + SSR paths.\n // `useSyncExternalStore` requires getSnapshot to return a cached reference,\n // so we freeze one object (initialData is first-render-wins, like SWR's\n // fallbackData). isLoading mirrors \"will this hook fetch on mount?\" so the\n // server markup matches the client's first (pre-effect) snapshot.\n const fallbackRef = useRef<CachedResourceState<T> | null>(null);\n if (fallbackRef.current === null) {\n fallbackRef.current = {\n data: initialDataRef.current,\n error: undefined,\n isLoading: enabled && revalidateOnMount,\n isValidating: false,\n };\n }\n\n const subscribe = useCallback(\n (cb: () => void) => {\n if (!enabled) return NOOP;\n const entry = getEntry<T>(cacheKey, initialDataRef.current);\n entry.subscribers.add(cb);\n return () => {\n entry.subscribers.delete(cb);\n };\n },\n [cacheKey, enabled],\n );\n\n const getSnapshot = useCallback((): CachedResourceState<T> => {\n if (!enabled) return fallbackRef.current as CachedResourceState<T>;\n return getEntry<T>(cacheKey, initialDataRef.current).snapshot;\n }, [cacheKey, enabled]);\n\n const getServerSnapshot = useCallback(\n (): CachedResourceState<T> => fallbackRef.current as CachedResourceState<T>,\n [],\n );\n\n const state = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n\n // Fetch trigger. Runs on mount + key change (client only — effects never run\n // under renderToString, keeping SSR fetch-free). No abort-on-unmount: the\n // in-flight request is shared across instances via dedup, so one unmounting\n // consumer must not cancel a fetch the others still await. Cancellation of a\n // SUPERSEDED request is handled inside revalidateResource (seq + abort).\n useEffect(() => {\n if (!enabled) return;\n const entry = getEntry<T>(cacheKey, initialDataRef.current);\n const fresh =\n entry.settled && Date.now() - entry.lastFetchAt < dedupeIntervalMs;\n if (revalidateOnMount && !fresh) {\n void revalidateResource<T>(\n cacheKey,\n (signal) => fetcherRef.current(signal),\n { onError: (e, k) => onErrorRef.current?.(e, k) },\n );\n }\n }, [cacheKey, enabled, revalidateOnMount, dedupeIntervalMs]);\n\n const mutate = useCallback(\n (next: CacheMutator<T>, opts?: MutateOptions) => {\n if (!enabled) return;\n mutateResource<T>(cacheKey, next, opts);\n },\n [cacheKey, enabled],\n );\n\n const revalidate = useCallback((): Promise<void> => {\n if (!enabled) return Promise.resolve();\n return revalidateResource<T>(\n cacheKey,\n (signal) => fetcherRef.current(signal),\n { force: true, onError: (e, k) => onErrorRef.current?.(e, k) },\n );\n }, [cacheKey, enabled]);\n\n return {\n data: state.data,\n error: state.error,\n isLoading: state.isLoading,\n isValidating: state.isValidating,\n mutate,\n revalidate,\n };\n}\n","\"use client\";\nimport { useCallback } from \"react\";\nimport { useShop } from \"./useShop\";\nimport { useCachedResource } from \"../lib/dataCache\";\n\n/**\n * Read app-provided data + manifest for a slug installed on the\n * current store.\n *\n * Phase 6 wired this to the real backend at\n * `/api/storefront/store/{store_id}/apps/{slug}`. Theme usage:\n *\n * const recommend = useApp<RecommendationData>(\"recommendation-engine\");\n * if (!recommend.available) return <Fallback />;\n * if (recommend.loading) return <Skeleton />;\n * return <RecommendList items={recommend.data?.products ?? []} />;\n *\n * `available` flips to true only when an enabled installation exists\n * for the store. Apps the merchant hasn't installed surface as\n * `{ available: false }` rather than as a network error — themes\n * branch on availability without try/catch.\n *\n * Phase 3 (client-data layer): the fetch now runs through the shared\n * `useCachedResource` store keyed by `numu:app:<store_id>:<slug>`. Two upgrades\n * over the old per-instance `useState` + fetch:\n * - DEDUP + SYNC: N consumers of the same app slug share ONE request and one\n * result, instead of each firing its own `/apps/{slug}` fetch.\n * - CANCELLATION / ORDERING: the fetcher receives an AbortSignal and the\n * cache seq-guards results, so a slow response for a superseded slug (or a\n * superseded `refresh()`) can no longer apply stale state over a newer one\n * — the audited \"out-of-order responses apply stale state\" bug.\n *\n * `loading` reflects the FIRST load only; a `refresh()` revalidates in the\n * background (`isValidating`) while keeping the last-good data visible, rather\n * than blanking to a skeleton on every manual refresh.\n */\n\nexport interface AppManifestBlock {\n type: string;\n name: string;\n block_schema: Record<string, unknown>;\n}\n\nexport interface AppPayload<T = unknown> {\n slug: string;\n name: string;\n description: string | null;\n icon_url: string | null;\n version: string;\n manifest: Record<string, unknown>;\n settings: Record<string, unknown>;\n blocks: AppManifestBlock[];\n /** App-provided data (shape defined by the app developer). Today\n * the response always returns null for `data` — apps emit data via\n * their `endpoints.data` URL, which the theme fetches separately.\n * Surfaced here so the field is stable when v2 lands the proxy. */\n data: T | null;\n}\n\nexport interface AppState<T = unknown> {\n data: AppPayload<T> | null;\n loading: boolean;\n available: boolean;\n error: Error | null;\n /** Re-fetch the install. Returns a promise that resolves when the\n * request settles (regardless of success). */\n refresh: () => Promise<void>;\n}\n\n/** Normalized fetch result cached per key. `available:false` covers both the\n * \"not installed\" (404) and \"no payload\" cases so themes branch on one flag. */\ninterface AppFetchResult<T> {\n payload: AppPayload<T> | null;\n available: boolean;\n}\n\nexport function useApp<T = unknown>(slug: string): AppState<T> {\n const shop = useShop();\n // Key on store + slug so a different slug is a different cache entry — a\n // rapid slug switch reads its own entry rather than racing one shared slot.\n const key = slug ? `numu:app:${shop.id}:${slug}` : \"\";\n\n const fetcher = useCallback(\n async (signal: AbortSignal): Promise<AppFetchResult<T>> => {\n const url = `/api/storefront/apps/${encodeURIComponent(slug)}`;\n const res = await fetch(url, {\n credentials: \"include\",\n headers: { Accept: \"application/json\" },\n signal,\n });\n if (res.status === 404) {\n // Not installed (or app disabled). Standard not-available shape —\n // keeps theme branching simple (no thrown error).\n return { payload: null, available: false };\n }\n if (!res.ok) {\n throw new Error(`useApp(${slug}) failed: HTTP ${res.status}`);\n }\n const body = (await res.json()) as {\n data?: (AppPayload<T> & { available?: boolean }) | null;\n };\n const payload = body.data ?? null;\n if (!payload) return { payload: null, available: false };\n return {\n payload: payload as AppPayload<T>,\n available: payload.available !== false,\n };\n },\n [slug],\n );\n\n const { data, isLoading, error, revalidate } = useCachedResource<\n AppFetchResult<T>\n >(key, fetcher, {\n enabled: Boolean(slug),\n initialData: { payload: null, available: false },\n });\n\n const refresh = useCallback(async (): Promise<void> => {\n await revalidate();\n }, [revalidate]);\n\n // Preserve the original contract: on error, present as not-available with a\n // null payload (the error is still surfaced separately).\n return {\n data: error ? null : data?.payload ?? null,\n loading: isLoading,\n available: error ? false : data?.available ?? false,\n error: error ?? null,\n refresh,\n };\n}\n","\"use client\";\nimport { useCallback } from \"react\";\nimport { useCachedResource, readResource } from \"../lib/dataCache\";\n\n/**\n * Wishlist hook with localStorage fallback.\n *\n * Architecture (Phase 4 lands the server side):\n * - Authenticated customer: persists to /api/customer/me/wishlist\n * (server-backed, syncs across devices).\n * - Anonymous visitor: persists to localStorage under\n * `numu_wishlist_<store_id>`. On login, the wishlist merges into\n * the server-side list (mirrors the cart's session→customer flow).\n *\n * v1 implementation: localStorage only. The /api/customer/me/wishlist\n * endpoint isn't wired yet; an authed visitor still gets the local\n * fallback so themes work end-to-end. When the endpoint lands, the\n * fetcher below swaps its localStorage read for the server fetch and the\n * mutation methods gain a `{ revalidate: true }` write-through.\n *\n * Phase 3 (client-data layer): the items list now lives in the shared\n * `useCachedResource` store keyed by `numu_wishlist_<store_id>`, NOT in\n * per-instance `useState`. Previously two `<Heart>`s for the same product\n * each held their own copy, so adding via one never re-rendered the other —\n * the two hearts DESYNCED. Now every `useWishlist(storeId)` consumer reads\n * and writes ONE shared entry, so an add/remove anywhere reflows every heart.\n * Writes are optimistic (the shared store updates instantly) and roll back if\n * persistence throws.\n */\n\nexport interface WishlistItem {\n product_id: string;\n /** Optional variant scoping — themes that show variant pickers can\n * wishlist a specific size/color combo separately. */\n variant_id?: string | null;\n /** Server timestamp once persistence lands; ms-since-epoch in v1. */\n added_at: number;\n}\n\nexport interface WishlistState {\n items: WishlistItem[];\n loading: boolean;\n has: (productId: string, variantId?: string | null) => boolean;\n addToWishlist: (productId: string, variantId?: string | null) => void;\n removeFromWishlist: (productId: string, variantId?: string | null) => void;\n clear: () => void;\n}\n\nfunction storageKey(storeId: string): string {\n return `numu_wishlist_${storeId}`;\n}\n\nfunction readLocal(storeId: string): WishlistItem[] {\n if (typeof window === \"undefined\") return [];\n try {\n const raw = window.localStorage.getItem(storageKey(storeId));\n if (!raw) return [];\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed) ? (parsed as WishlistItem[]) : [];\n } catch {\n return [];\n }\n}\n\n/**\n * Persist the list. Unlike the previous swallow-all writer, this THROWS on a\n * write failure (quota / private mode) so the optimistic mutation can roll\n * back — the shared store must not diverge from what actually persisted.\n */\nfunction persistWishlist(storeId: string, items: WishlistItem[]): void {\n if (typeof window === \"undefined\") return;\n window.localStorage.setItem(storageKey(storeId), JSON.stringify(items));\n}\n\nfunction sameItem(\n a: WishlistItem,\n productId: string,\n variantId?: string | null,\n): boolean {\n return (\n a.product_id === productId && (a.variant_id ?? null) === (variantId ?? null)\n );\n}\n\n// Stable empty reference so `items` identity doesn't churn every render.\nconst EMPTY: WishlistItem[] = [];\n\n/**\n * @param storeId The store the wishlist is scoped to. Pass `useShop().id`.\n * Without it, the hook can't keep one merchant's wishlist\n * from leaking into another's localStorage on a shared\n * domain (e.g. apex preview).\n */\nexport function useWishlist(storeId: string): WishlistState {\n const key = storageKey(storeId);\n\n // Hydrate from localStorage. Wrapped in a resolved promise so the shared\n // cache has one code path for both the v1 localStorage read and the future\n // server-backed fetch. SSR-safe: readLocal returns [] on the server and the\n // fetch only runs client-side inside useCachedResource's effect.\n const fetcher = useCallback(\n () => Promise.resolve(readLocal(storeId)),\n [storeId],\n );\n\n const { data, isLoading, mutate } = useCachedResource<WishlistItem[]>(\n key,\n fetcher,\n { initialData: EMPTY },\n );\n\n const items = data ?? EMPTY;\n\n const has = useCallback(\n (productId: string, variantId?: string | null) =>\n items.some((it) => sameItem(it, productId, variantId)),\n [items],\n );\n\n // Shared optimistic write: compute next from the CURRENT shared value (not a\n // stale closure), publish it to every subscriber immediately, then persist;\n // roll back to the previous value if the write throws. Returning `null` from\n // `compute` means \"no change\" (e.g. adding a duplicate) — skip entirely.\n const applyOptimistic = useCallback(\n (compute: (prev: WishlistItem[]) => WishlistItem[] | null) => {\n const prev = readResource<WishlistItem[]>(key) ?? EMPTY;\n const next = compute(prev);\n if (next === null) return;\n mutate(next, { revalidate: false });\n try {\n persistWishlist(storeId, next);\n } catch {\n mutate(prev, { revalidate: false });\n }\n },\n [key, storeId, mutate],\n );\n\n const addToWishlist = useCallback(\n (productId: string, variantId?: string | null) =>\n applyOptimistic((prev) =>\n prev.some((it) => sameItem(it, productId, variantId))\n ? null\n : [\n ...prev,\n {\n product_id: productId,\n variant_id: variantId ?? null,\n added_at: Date.now(),\n },\n ],\n ),\n [applyOptimistic],\n );\n\n const removeFromWishlist = useCallback(\n (productId: string, variantId?: string | null) =>\n applyOptimistic((prev) => {\n const next = prev.filter((it) => !sameItem(it, productId, variantId));\n return next.length === prev.length ? null : next;\n }),\n [applyOptimistic],\n );\n\n const clear = useCallback(\n () => applyOptimistic((prev) => (prev.length === 0 ? null : [])),\n [applyOptimistic],\n );\n\n return { items, loading: isLoading, has, addToWishlist, removeFromWishlist, clear };\n}\n","\"use client\";\nimport { useCallback } from \"react\";\nimport type { Product } from \"../types/entities\";\nimport { useCachedResource } from \"../lib/dataCache\";\n\n/**\n * Fetch products related to the given product (same category, excluding\n * self). Phase 3 lands collaborative-filtering / \"frequently bought\n * together\"; v1 ships the simpler same-category-minus-self heuristic.\n *\n * Backend contract: GET /api/storefront/products/{id}/related?limit=N\n * → { items: Product[] } | { data: Product[] } | Product[]\n *\n * Returns an empty list (no error) when the endpoint is missing or the\n * product has no siblings — themes should branch on `items.length` and\n * either render the section or skip it entirely.\n *\n * Phase 3 (client-data layer): routed through the shared `useCachedResource`\n * store keyed by `numu:related:<productId>:<limit>`. Two \"related products\"\n * sections on the same PDP now share ONE request + one result instead of each\n * refetching, and the AbortSignal + cache seq-guard drop a superseded response\n * (e.g. after a rapid product switch) so it can't overwrite the newer list.\n */\n\nexport interface RelatedProductsState {\n items: Product[];\n loading: boolean;\n error: Error | null;\n}\n\n// Stable empty reference so `items` identity doesn't churn every render.\nconst EMPTY: Product[] = [];\n\nexport function useRelatedProducts(\n productId: string | null | undefined,\n options: { limit?: number } = {},\n): RelatedProductsState {\n const limit = options.limit ?? 4;\n const key = productId ? `numu:related:${productId}:${limit}` : \"\";\n\n const fetcher = useCallback(\n async (signal: AbortSignal): Promise<Product[]> => {\n const res = await fetch(\n `/api/storefront/products/${encodeURIComponent(\n productId as string,\n )}/related?limit=${limit}`,\n { cache: \"no-store\", signal },\n );\n if (!res.ok) {\n // Endpoint not yet wired — treat as \"no related items available\"\n // (empty, not an error) so themes just skip the section.\n return EMPTY;\n }\n const json = (await res.json()) as\n | { items?: Product[]; data?: Product[] }\n | Product[];\n return Array.isArray(json)\n ? json\n : Array.isArray(json.data)\n ? json.data\n : Array.isArray(json.items)\n ? json.items\n : EMPTY;\n },\n [productId, limit],\n );\n\n const { data, isLoading, error } = useCachedResource<Product[]>(key, fetcher, {\n enabled: Boolean(productId),\n initialData: EMPTY,\n });\n\n return { items: data ?? EMPTY, loading: isLoading, error: error ?? null };\n}\n","\"use client\";\nimport { useCallback } from \"react\";\nimport { useCachedResource } from \"../lib/dataCache\";\nimport type { ActivePromotionsPayload } from \"../types/promotions\";\n\n/**\n * The store's active promotions for the current visitor.\n *\n * Reads the host proxy `GET /api/storefront/promotions` (never NUMU-api\n * directly — the host owns credentials, caching and the store resolution).\n * The backend groups by surface; the host already renders announcement bars,\n * popups, the cookie banner and floating widgets in the shell, so what a\n * theme normally wants is `auto_discounts` — the offers that price the cart\n * with no code to type.\n *\n * SSR-safe: `useCachedResource` doesn't fetch during server render, so this\n * resolves on hydrate. Sections must therefore tolerate a null first pass —\n * render nothing (or a skeleton) rather than assuming data on first paint.\n *\n * Returns `null` on any miss (offline, 404, flag off). That is deliberate:\n * a promotions outage should make an offer banner disappear, never break the\n * page it sits on.\n *\n * @param page page path used for page-targeted promotions (default \"/\")\n * @param locale \"ar\" | \"en\" — selects the translated content\n */\nexport function useActivePromotions(\n page: string = \"/\",\n locale: string = \"ar\",\n): ActivePromotionsPayload | null {\n const key = `numu:promotions:${page}:${locale}`;\n\n const fetcher = useCallback(\n async (signal: AbortSignal): Promise<ActivePromotionsPayload | null> => {\n const qs = new URLSearchParams({ page, locale });\n const res = await fetch(`/api/storefront/promotions?${qs.toString()}`, {\n credentials: \"include\",\n cache: \"no-store\",\n signal,\n });\n if (!res.ok) return null;\n const json = (await res.json()) as\n | { data?: ActivePromotionsPayload }\n | ActivePromotionsPayload\n | null;\n if (!json) return null;\n return (\n ((json as { data?: ActivePromotionsPayload }).data ??\n (json as ActivePromotionsPayload)) ||\n null\n );\n },\n [page, locale],\n );\n\n const { data } = useCachedResource<ActivePromotionsPayload | null>(\n key,\n fetcher,\n { initialData: null },\n );\n\n return data ?? null;\n}\n","/**\n * Money formatting for NUMU storefronts.\n *\n * Three implementations of this existed and disagreed:\n *\n * - the themes' own `fmt` (4 byte-identical copies): EGP fallback,\n * `maximumFractionDigits: 0`, locale `\"ar\"` mapped to `\"ar-EG\"`\n * - `@numueg/theme-kit`'s `formatMoney`: **USD** fallback, 2 fraction\n * digits, raw locale passed through\n * - `NuMuProvider`'s own `formatMoney`: a third variant again\n *\n * This adopts the themes' behaviour, because that is what production renders\n * today: adopting the kit's would silently turn every promo nudge from\n * `LE 500` into `£E 500.00` on live stores. NUMU is Egypt-first — EGP is the\n * right fallback, whole piastres are noise at Egyptian price points, and\n * `ar-EG` is what produces Egyptian Arabic numerals and currency placement.\n *\n * The unit is CENTS, matching the API end to end. `formatMoneyMajor` exists\n * for the one place that already divided (the SDK exposes cart money in major\n * units), so nobody has to remember which side of the boundary they're on.\n */\n\nexport interface FormatMoneyOptions {\n /** Currency code. Falls back to EGP — Egypt-first, not USD. */\n currency?: string | null;\n /** `\"ar\"` maps to `ar-EG`; anything else formats as `en-EG`. */\n locale?: string | null;\n /**\n * Fraction digits. Defaults to 0: Egyptian retail prices are whole pounds,\n * and `500.00 EGP` reads as noise next to `500 EGP`. Pass 2 where sub-unit\n * precision genuinely matters (a unit price, an FX-converted amount).\n */\n fractionDigits?: number;\n}\n\nfunction resolveLocale(locale: string | null | undefined): string {\n return locale === \"ar\" ? \"ar-EG\" : \"en-EG\";\n}\n\n/**\n * Format an integer amount of cents.\n *\n * @example formatMoney(50000) // \"EGP 500\"\n * @example formatMoney(50000, { locale: \"ar\" }) // \"٥٠٠ ج.م.‏\"\n */\nexport function formatMoney(\n cents: number,\n options: FormatMoneyOptions = {},\n): string {\n const { currency, locale, fractionDigits = 0 } = options;\n // A non-finite amount formats as the zero of its currency rather than\n // \"NaN EGP\" on a product card.\n const safe = Number.isFinite(cents) ? cents : 0;\n return new Intl.NumberFormat(resolveLocale(locale), {\n style: \"currency\",\n currency: currency || \"EGP\",\n maximumFractionDigits: fractionDigits,\n }).format(safe / 100);\n}\n\n/**\n * Format an amount already expressed in major units.\n *\n * The SDK hands cart money to themes in major units while the API speaks\n * cents, so a shared helper that only accepted one of the two guaranteed a\n * factor-of-100 bug at the seam.\n */\nexport function formatMoneyMajor(\n amount: number,\n options: FormatMoneyOptions = {},\n): string {\n return formatMoney(\n (Number.isFinite(amount) ? amount : 0) * 100,\n options,\n );\n}\n\n/** Cents to major units. Non-finite input yields 0, never NaN. */\nexport function centsToMajor(cents: number): number {\n return (Number.isFinite(cents) ? cents : 0) / 100;\n}\n\n/** Major units to integer cents, rounded — the inverse of `centsToMajor`. */\nexport function majorToCents(amount: number): number {\n return Math.round((Number.isFinite(amount) ? amount : 0) * 100);\n}\n","/**\n * Pure helpers for rendering platform promotions in a theme.\n *\n * These are headless by design — data and logic only, zero markup and zero\n * styling — so every theme keeps its own look while sharing one correct\n * implementation of the fiddly parts (unit counting, group math, the\n * cents→major boundary).\n *\n * The hard rule these encode: **a theme never computes a discount.** The\n * engine prices the cart and reports what it saved; helpers here only\n * describe progress toward an offer and format what the engine already\n * decided. Anything else eventually renders a number the server won't honour.\n */\n\nimport type { Cart } from \"../types/entities\";\nimport { centsToMajor } from \"../utils/money\";\nimport type {\n ActivePromotion,\n ActivePromotionsPayload,\n MultibuyOffer,\n OfferProgress,\n} from \"../types/promotions\";\n\n/**\n * Extract the usable multibuy offers (\"any N for a fixed total P\").\n *\n * Accepts either the whole `/api/storefront/promotions` payload or just an\n * array of promotions, so callers don't have to reach into `auto_discounts`\n * themselves. Anything that isn't a well-formed multibuy — a kind this SDK\n * version doesn't know, a missing N or P — is skipped rather than thrown on:\n * a theme built before a rule kind existed must keep rendering when a\n * merchant starts using it.\n */\nexport function multibuyOffers(\n promotions: ActivePromotionsPayload | ActivePromotion[] | null | undefined,\n): MultibuyOffer[] {\n if (!promotions) return [];\n const list: ActivePromotion[] = Array.isArray(promotions)\n ? promotions\n : (promotions.auto_discounts ?? []);\n\n const offers: MultibuyOffer[] = [];\n for (const promo of list) {\n const rule = promo?.discount_rule;\n if (!rule || rule.kind !== \"multibuy\") continue;\n const quantity = rule.multibuy_quantity;\n const groupPriceCents = rule.multibuy_price_cents;\n // Both are required by the engine; a rule missing either is malformed\n // data, not an offer we should advertise.\n if (typeof quantity !== \"number\" || quantity < 2) continue;\n if (typeof groupPriceCents !== \"number\" || groupPriceCents <= 0) continue;\n const eligibleProductIds = promo.eligible_product_ids ?? [];\n const eligibleCategoryIds = promo.eligible_category_ids ?? [];\n offers.push({\n promotionId: promo.promotion_id,\n quantity,\n groupPriceCents,\n groupPriceMajor: centsToMajor(groupPriceCents),\n headline: promo.translated_content?.headline,\n eligibleProductIds,\n eligibleCategoryIds,\n // No scoping rows at all ⇒ every product qualifies. Note an older\n // backend that doesn't send these fields also lands here, which is the\n // right default: counting everything is what themes did before.\n isStoreWide:\n eligibleProductIds.length === 0 && eligibleCategoryIds.length === 0,\n raw: promo,\n });\n }\n return offers;\n}\n\n/**\n * Does this product take part in the offer?\n *\n * A store-wide offer includes everything. Otherwise the product must be named\n * directly or sit in a named category. A scoped offer over a product whose\n * `category_id` we don't know returns false — better to under-promise than to\n * advertise a discount the server won't apply.\n */\nexport function offerIncludesProduct(\n offer: MultibuyOffer | null | undefined,\n product: { id?: string; product_id?: string; category_id?: string | null },\n): boolean {\n if (!offer) return false;\n if (offer.isStoreWide) return true;\n const id = product?.product_id ?? product?.id;\n if (id && offer.eligibleProductIds.includes(id)) return true;\n const category = product?.category_id;\n return Boolean(category && offer.eligibleCategoryIds.includes(category));\n}\n\n/**\n * How many cart UNITS actually qualify for the offer.\n *\n * Units, not lines — three of one product is a valid trio, the way the engine\n * scores it. For a scoped offer this is what the nudge must count; counting\n * the whole cart is how a shopper gets told \"add 2 more\" and then doesn't get\n * the discount.\n */\nexport function eligibleUnitsInCart(\n offer: MultibuyOffer | null | undefined,\n cart: Cart | null | undefined,\n): number {\n if (!offer) return 0;\n return (cart?.items ?? []).reduce((sum, item) => {\n if (!item) return sum;\n if (!offerIncludesProduct(offer, item)) return sum;\n return sum + (item.quantity || 0);\n }, 0);\n}\n\n/**\n * Where the cart stands against one multibuy offer.\n *\n * Counts UNITS, not lines — three of the same product is a valid trio, the\n * same way the engine scores it. `savingMajor` is read from the cart's\n * engine-supplied `applied_promotions`, so an unlocked offer shows the real\n * saving and a theme can never drift from the charged amount.\n *\n * Scoping is handled automatically: when the offer names products or\n * categories, only qualifying units are counted (via `eligibleUnitsInCart`).\n * Pass `eligibleUnits` explicitly to override that — e.g. when the theme has\n * a better source of truth than the cart lines.\n */\nexport function offerProgress(\n offer: MultibuyOffer | null | undefined,\n cart: Cart | null | undefined,\n eligibleUnits?: number,\n): OfferProgress {\n const empty: OfferProgress = {\n unitsInCart: 0,\n unitsNeeded: 0,\n groupsUnlocked: 0,\n savingMajor: 0,\n };\n if (!offer) return empty;\n\n const unitsInCart =\n typeof eligibleUnits === \"number\"\n ? Math.max(0, eligibleUnits)\n : eligibleUnitsInCart(offer, cart);\n\n const groupsUnlocked = Math.floor(unitsInCart / offer.quantity);\n const remainder = unitsInCart % offer.quantity;\n // 0 when the cart just completed a group — \"add N more\" would be noise\n // right after an unlock. The theme decides whether to nudge for the next\n // group; the number here stays honest about the current one.\n const unitsNeeded = remainder === 0 ? 0 : offer.quantity - remainder;\n\n // The engine's own number, already in major units (normalizeCartFromServer\n // converted it). Matching on promotion id keeps a stacked cart honest.\n const applied = (cart?.applied_promotions ?? []).find(\n (p) => p && p.id === offer.promotionId,\n );\n\n return {\n unitsInCart,\n unitsNeeded,\n groupsUnlocked,\n savingMajor: applied ? applied.amount || 0 : 0,\n };\n}\n\n/**\n * Should a product page advertise this offer?\n *\n * Only when N of this product actually costs more than the group price —\n * otherwise the \"deal\" is worse than just buying them, and §5 of the offer\n * spec forbids advertising it (the engine likewise refuses to apply it).\n *\n * @param unitPriceMajor the product's price in MAJOR units, as a theme has it\n */\nexport function offerBeatsRegularPrice(\n offer: MultibuyOffer | null | undefined,\n unitPriceMajor: number | null | undefined,\n): boolean {\n if (!offer || typeof unitPriceMajor !== \"number\" || unitPriceMajor <= 0) {\n return false;\n }\n // Compare in cents to dodge float drift on prices like 249.99.\n const unitCents = Math.round(unitPriceMajor * 100);\n return unitCents * offer.quantity > offer.groupPriceCents;\n}\n","\"use client\";\nimport { useMemo } from \"react\";\nimport type { Product, Store, SizeChart } from \"../types/entities\";\nimport { useProductOptional } from \"./useProduct\";\nimport { useShop } from \"./useShop\";\n\n/**\n * useProductSizeChart — resolve the size chart to show for a product.\n *\n * The merchant hub writes the per-product chart to\n * `product.attributes.size_chart` and the store-wide default to\n * `store.settings.size_chart`, with an explicit `mode`:\n *\n * \"off\" → never show, even if a store default exists\n * \"custom\" → use the product's own chart\n * \"default\" → fall back to the store-wide chart\n * (legacy) → no `mode`: a populated product chart wins, else the default\n *\n * This hook centralises that precedence so every theme resolves it identically\n * (the backend `SizeChartSchema` validator and the hub editor share the same\n * shape). Returns `null` when there is nothing to show — render the size-guide\n * trigger only when this is non-null.\n *\n * @param productOverride - resolve against this product instead of the one in\n * context (e.g. when rendering a chart for a related/quick-view product).\n */\nexport function useProductSizeChart(\n productOverride?: Product | null,\n): SizeChart | null {\n const ctxProduct = useProductOptional();\n const product = productOverride ?? ctxProduct;\n const shop = useShop() as Store | undefined;\n const storeSettings = shop?.settings;\n\n return useMemo(\n () => resolveSizeChart(product?.attributes, storeSettings),\n [product?.attributes, storeSettings],\n );\n}\n\nfunction hasRows(c: unknown): c is SizeChart {\n return (\n !!c &&\n typeof c === \"object\" &&\n Array.isArray((c as SizeChart).rows) &&\n (c as SizeChart).rows.length > 0\n );\n}\n\n/**\n * Pure resolver (no React) — exported so non-hook code (SSR helpers, tests)\n * can apply the same precedence.\n */\nexport function resolveSizeChart(\n productAttributes: Record<string, unknown> | undefined,\n storeSettings: Record<string, unknown> | undefined,\n): SizeChart | null {\n const product = productAttributes?.size_chart as SizeChart | undefined;\n const storeDefault = storeSettings?.size_chart as SizeChart | undefined;\n\n if (product?.mode === \"off\") return null;\n if (product?.mode === \"custom\") return hasRows(product) ? product : null;\n if (product?.mode === \"default\") return hasRows(storeDefault) ? storeDefault : null;\n\n // No explicit mode (legacy): a populated product chart wins, else the default.\n if (hasRows(product)) return product;\n if (hasRows(storeDefault)) return storeDefault;\n return null;\n}\n","/**\n * Variant resolution helpers — Phase 8.1.\n *\n * Themes render a variant picker (Size + Color radios), then ask the\n * SDK \"given my current selection, which variant is it?\" The matching\n * variant's id is what add-to-cart sends.\n */\n\nimport type { Product, ProductVariant } from \"../types/entities\";\n\n/**\n * Pick the variant that exactly matches the given option_values map.\n * Returns null when no variant matches — themes render that as\n * \"Combination unavailable\" or a disabled buy button.\n */\nexport function findVariantByOptions(\n product: Pick<Product, \"variants\">,\n selection: Record<string, string>,\n): ProductVariant | null {\n const variants = product.variants || [];\n if (variants.length === 0) return null;\n // Single-variant products (no axes): the only variant matches the\n // empty selection trivially.\n if (variants.length === 1 && Object.keys(selection).length === 0) {\n return variants[0];\n }\n for (const v of variants) {\n const opts = v.option_values || v.options || {};\n const matches = Object.entries(selection).every(\n ([axis, value]) => opts[axis] === value,\n );\n if (matches && Object.keys(selection).length === Object.keys(opts).length) {\n return v;\n }\n }\n return null;\n}\n\n/**\n * Find the \"default\" variant — the one the PDP should auto-select on\n * first render. Prefers the first in-stock variant; falls back to the\n * first variant if all are out of stock (so the picker still shows\n * something coherent).\n */\nexport function defaultVariant(product: Pick<Product, \"variants\">): ProductVariant | null {\n const variants = product.variants || [];\n if (variants.length === 0) return null;\n const inStock = variants.find((v) => v.is_in_stock || v.in_stock);\n return inStock || variants[0];\n}\n\n/**\n * Given a partial selection (e.g. just Size=M, no Color yet), return\n * the set of values still available on each unselected axis. Themes\n * use this to disable swatches whose paired variants are all out of\n * stock for the current selection.\n */\nexport function availableValues(\n product: Pick<Product, \"options\" | \"variants\">,\n selection: Record<string, string>,\n): Record<string, Set<string>> {\n const axes = product.options || [];\n const variants = product.variants || [];\n const out: Record<string, Set<string>> = {};\n for (const axis of axes) {\n const set = new Set<string>();\n for (const v of variants) {\n const opts = v.option_values || v.options || {};\n // Only consider variants compatible with the locked-in part of\n // the selection (every locked axis must match this variant).\n const compatible = Object.entries(selection).every(\n ([k, val]) => k === axis.name || opts[k] === val,\n );\n if (compatible && opts[axis.name]) {\n set.add(opts[axis.name]);\n }\n }\n // When NO variant carries option-value data for this axis, availability\n // is UNKNOWN — not \"all sold out\". This happens for legacy products whose\n // axes live in `attributes.variants` (derived into `options`) but have no\n // SKU-tracked variant rows, so every `variant.option_values` is empty.\n // Falling back to the axis's declared values keeps the picker usable\n // instead of rendering every swatch struck-through. A genuinely\n // constrained axis (≥1 variant with data) keeps its computed set.\n out[axis.name] = set.size > 0 ? set : new Set(axis.values || []);\n }\n return out;\n}\n","/**\n * Live variant-picker selection registry.\n *\n * `useVariantSelection` publishes its current axis→value map here keyed by\n * product id; `AddToCartButton` reads it back at click time. This is what\n * lets the selection reach the cart even when no real variant row matches —\n * legacy products keep their axes in attributes JSON with a single\n * placeholder variant whose option_values is {}, so `findVariantByOptions`\n * returns null and there'd otherwise be nothing to send.\n *\n * Module-scoped (not React context) on purpose: the hook instance lives in\n * the theme's PDP section while the button may be a sibling — they share no\n * provider of ours. Bounded: one entry per product id, last write wins.\n */\n\nconst selections = new Map<string, Record<string, string>>();\n\nexport function publishVariantSelection(\n productId: string | undefined | null,\n selection: Record<string, string>,\n): void {\n if (!productId) return;\n selections.set(productId, selection);\n}\n\n/** Latest non-empty selection for a product, or null. */\nexport function readVariantSelection(\n productId: string | undefined | null,\n): Record<string, string> | null {\n if (!productId) return null;\n const sel = selections.get(productId);\n if (!sel) return null;\n const filtered: Record<string, string> = {};\n for (const [k, v] of Object.entries(sel)) {\n if (v) filtered[k] = v;\n }\n return Object.keys(filtered).length > 0 ? filtered : null;\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport {\n availableValues,\n defaultVariant,\n findVariantByOptions,\n} from \"../utils/variants\";\nimport { publishVariantSelection } from \"../utils/selectionRegistry\";\nimport type { Product, ProductVariant } from \"../types/entities\";\n\nexport interface UseVariantSelection {\n /** Currently-selected axis → value map. */\n selection: Record<string, string>;\n /** The variant matching the current selection, if any. */\n variant: ProductVariant | null;\n /** Pick a value on one axis. Other axes stay locked. */\n select: (axis: string, value: string) => void;\n /** Reset the selection (e.g. on \"Choose another\" button). */\n reset: () => void;\n /**\n * For each unselected axis, the set of values that lead to at\n * least one in-stock variant given the current locked axes.\n * Themes use this to grey out swatches.\n */\n availability: Record<string, Set<string>>;\n /**\n * True when every option axis on the product has a chosen value\n * and `variant` is resolved. Buy buttons should disable until\n * this flips to true on products with options.\n */\n isComplete: boolean;\n}\n\n/**\n * Hook that owns variant-axis selection state for a PDP.\n *\n * Initial state auto-selects the default variant's axis values so\n * the PDP loads with a coherent price + image + buy state, matching\n * Shopify's behavior. Themes that prefer \"Choose your size\" empty\n * state can pass `autoSelect: false`.\n */\nexport function useVariantSelection(\n product: Pick<Product, \"options\" | \"variants\"> & { id?: string },\n opts: { autoSelect?: boolean } = {},\n): UseVariantSelection {\n const autoSelect = opts.autoSelect ?? true;\n\n const initial = useMemo<Record<string, string>>(() => {\n if (!autoSelect) return {};\n const dv = defaultVariant(product);\n if (!dv) return {};\n const opts = dv.option_values || dv.options || {};\n return { ...opts };\n }, [product, autoSelect]);\n\n const [selection, setSelection] = useState<Record<string, string>>(initial);\n\n const select = useCallback((axis: string, value: string) => {\n setSelection((prev) => ({ ...prev, [axis]: value }));\n }, []);\n\n const reset = useCallback(() => setSelection({}), []);\n\n const variant = useMemo(\n () => findVariantByOptions(product, selection),\n [product, selection],\n );\n\n // Mirror the live selection into the module registry so AddToCartButton\n // can attach it to the cart write even when no variant row matches\n // (legacy products: axes in attributes JSON, placeholder variant with\n // empty option_values). Themes pass full product objects, so `id` is\n // present in practice; the widened param type keeps this non-breaking.\n useEffect(() => {\n publishVariantSelection(product.id, selection);\n }, [product.id, selection]);\n\n const availability = useMemo(\n () => availableValues(product, selection),\n [product, selection],\n );\n\n const isComplete = useMemo(() => {\n const axes = product.options || [];\n if (axes.length === 0) return true;\n return axes.every((a) => Boolean(selection[a.name]));\n }, [product, selection]);\n\n return { selection, variant, select, reset, availability, isComplete };\n}\n","\"use client\";\n\nimport { useCallback, useState } from \"react\";\n\n/**\n * Gift card balance check — Phase 8.3.\n *\n * Themes call this from the checkout payment step to validate a\n * customer-typed code before sending it as part of the checkout\n * payload. The backend returns 404 for any non-redeemable card\n * (expired, depleted, voided, or wrong store) — the response shape\n * stays uniform so the hook can't be used to probe for valid codes.\n *\n * Backend contract (via storefront proxy):\n * GET /api/gift-cards/{code}\n * → 200 { data: { last_four, current_balance_cents, currency,\n * expires_at? } }\n * → 404 { error: { code, message } }\n */\n\nexport interface GiftCardBalance {\n last_four: string;\n current_balance_cents: number;\n currency: string;\n expires_at: string | null;\n}\n\nexport interface UseGiftCardBalance {\n /** Last lookup result, or null when nothing checked yet / failed. */\n balance: GiftCardBalance | null;\n /** True while a lookup is in flight. */\n loading: boolean;\n /** Latest error from the lookup, if any. Cleared on next check. */\n error: Error | null;\n /** Trigger a balance check. Returns the result or null on failure. */\n check: (code: string) => Promise<GiftCardBalance | null>;\n /** Clear the last result + error (e.g. when the user clears the input). */\n reset: () => void;\n}\n\nexport function useGiftCardBalance(): UseGiftCardBalance {\n const [balance, setBalance] = useState<GiftCardBalance | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const check = useCallback(async (code: string): Promise<GiftCardBalance | null> => {\n if (typeof window === \"undefined\") return null;\n const trimmed = (code || \"\").trim();\n if (!trimmed) {\n setError(new Error(\"Enter a gift card code.\"));\n setBalance(null);\n return null;\n }\n setLoading(true);\n setError(null);\n try {\n const res = await fetch(\n `/api/gift-cards/${encodeURIComponent(trimmed)}`,\n { cache: \"no-store\" },\n );\n if (!res.ok) {\n setBalance(null);\n // 404 = invalid/redeemed/expired — surface a friendly message\n // rather than the raw API code so themes don't need to map it.\n if (res.status === 404) {\n setError(new Error(\"That gift card isn't valid or has been used up.\"));\n return null;\n }\n setError(new Error(`Couldn't check gift card (HTTP ${res.status}).`));\n return null;\n }\n const json = (await res.json()) as { data?: GiftCardBalance };\n const data = json?.data;\n if (!data) {\n setBalance(null);\n setError(new Error(\"Unexpected response from server.\"));\n return null;\n }\n setBalance(data);\n return data;\n } catch (err) {\n setBalance(null);\n setError(err instanceof Error ? err : new Error(String(err)));\n return null;\n } finally {\n setLoading(false);\n }\n }, []);\n\n const reset = useCallback(() => {\n setBalance(null);\n setError(null);\n }, []);\n\n return { balance, loading, error, check, reset };\n}\n","\"use client\";\n\nimport { useCallback, useState } from \"react\";\n\n/**\n * Reorder / \"buy again\" — Phase 8.5.\n *\n * Clones every line item from an existing order into the current cart.\n * The backend skips lines whose product is deleted/archived, whose\n * variant is gone, or that are out of stock — returning per-line\n * reasons so themes can show a \"couldn't add X items\" banner.\n *\n * Backend contract:\n * POST /storefront/me/orders/{order_id}/reorder\n * → 200 { data: { added_count, skipped[], cart_total_items } }\n * → 404 if order doesn't belong to the current customer\n */\n\nexport type ReorderSkipReason =\n | \"product_deleted\"\n | \"product_archived\"\n | \"out_of_stock\"\n | \"variant_unavailable\";\n\nexport interface ReorderSkippedItem {\n product_id: string;\n variant_id: string | null;\n quantity: number;\n reason: ReorderSkipReason | string;\n}\n\nexport interface ReorderResult {\n added_count: number;\n skipped: ReorderSkippedItem[];\n cart_total_items: number;\n}\n\nexport interface UseReorder {\n /** Last reorder result. */\n result: ReorderResult | null;\n /** True while a reorder is in flight. */\n loading: boolean;\n /** Latest error, cleared on next reorder call. */\n error: Error | null;\n /** Trigger the reorder. Returns the result or null on failure. */\n reorder: (orderId: string) => Promise<ReorderResult | null>;\n /** Clear the last result + error (e.g. after dismissing the banner). */\n reset: () => void;\n}\n\nexport function useReorder(): UseReorder {\n const [result, setResult] = useState<ReorderResult | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const reorder = useCallback(\n async (orderId: string): Promise<ReorderResult | null> => {\n if (typeof window === \"undefined\") return null;\n if (!orderId) {\n setError(new Error(\"Order id is required.\"));\n return null;\n }\n setLoading(true);\n setError(null);\n try {\n // Read the CSRF cookie value and echo it as a header — the\n // storefront's mutating proxies verify the double-submit.\n const csrf =\n typeof document !== \"undefined\"\n ? (document.cookie.match(/(?:^|; )numu_csrf=([^;]+)/)?.[1] ?? \"\")\n : \"\";\n const res = await fetch(\n `/api/customer/orders/${encodeURIComponent(orderId)}/reorder`,\n {\n method: \"POST\",\n headers: csrf ? { \"x-numu-csrf\": csrf } : {},\n credentials: \"include\",\n },\n );\n if (!res.ok) {\n if (res.status === 401) {\n setError(new Error(\"Please sign in to reorder.\"));\n } else if (res.status === 404) {\n setError(new Error(\"That order can't be found on your account.\"));\n } else {\n setError(new Error(`Couldn't reorder (HTTP ${res.status}).`));\n }\n return null;\n }\n const json = (await res.json()) as { data?: ReorderResult };\n const data = json?.data;\n if (!data) {\n setError(new Error(\"Unexpected response from server.\"));\n return null;\n }\n setResult(data);\n return data;\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n return null;\n } finally {\n setLoading(false);\n }\n },\n [],\n );\n\n const reset = useCallback(() => {\n setResult(null);\n setError(null);\n }, []);\n\n return { result, loading, error, reorder, reset };\n}\n","\"use client\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\n\n/**\n * Programmatic checkout driver — Phase 7.6.\n *\n * The storefront's multi-step checkout pages (Phase 1.2) own the\n * default flow: contact → shipping → payment → review → processing →\n * thank-you. This hook gives themes a programmatic alternative so a\n * BYOT theme can render the checkout exactly how it wants — single-\n * page, accordion, full-bleed hero, whatever — without being forced\n * through the platform's step pages.\n *\n * State lives in `numu_checkout_state` sessionStorage (same blob the\n * platform's step pages use) so themes that drive checkout\n * programmatically can hand off to the platform mid-flow (e.g. theme\n * collects contact + shipping, then redirects to /checkout/payment\n * for the gateway capture). The platform-side state machine guards\n * deep-links via `hasContactStep / hasShippingStep / hasPaymentStep`\n * regardless of how the state got populated.\n *\n * Usage:\n *\n * const checkout = useCheckout();\n * checkout.contact.set({ email, phone, shipping_address });\n * await checkout.shipping.refresh();\n * checkout.shipping.select(rate.id);\n * checkout.payment.select(\"paymob\");\n * const result = await checkout.placeOrder();\n * if (result.payment_url) window.location.assign(result.payment_url);\n */\n\nexport type CheckoutStep =\n | \"contact\"\n | \"shipping\"\n | \"payment\"\n | \"review\"\n | \"processing\";\n\nexport interface CheckoutAddress {\n first_name?: string;\n last_name?: string;\n line1?: string;\n line2?: string | null;\n city?: string;\n state?: string | null;\n postal_code?: string | null;\n country?: string;\n phone?: string | null;\n}\n\nexport interface ShippingRateOption {\n id: string;\n name: string;\n amount_cents: number;\n currency: string;\n estimated_days_min?: number | null;\n estimated_days_max?: number | null;\n carrier?: string | null;\n}\n\nexport interface CheckoutSessionState {\n email: string;\n phone: string;\n shipping_address: CheckoutAddress;\n selected_shipping_rate_id: string | null;\n shipping_method: string | null;\n payment_method: string | null;\n cod_requested: boolean;\n deposit_gateway: string | null;\n saved_payment_method_id: string | null;\n customer_notes: string;\n coupon_code: string;\n}\n\nexport interface PlaceOrderResult {\n order_id: string;\n order_number: string;\n total: number;\n currency: string;\n payment_status: string;\n payment_url?: string | null;\n payment_data?: Record<string, unknown> | null;\n}\n\nexport interface CheckoutApi {\n state: CheckoutSessionState;\n step: CheckoutStep;\n contact: {\n set: (input: {\n email?: string;\n phone?: string;\n shipping_address?: CheckoutAddress;\n }) => void;\n isComplete: () => boolean;\n };\n shipping: {\n rates: ShippingRateOption[] | null;\n loading: boolean;\n refresh: () => Promise<ShippingRateOption[]>;\n select: (rateId: string) => void;\n isComplete: () => boolean;\n };\n payment: {\n select: (\n method: string,\n opts?: { saved_payment_method_id?: string; deposit_gateway?: string },\n ) => void;\n isComplete: () => boolean;\n };\n setNotes: (notes: string) => void;\n setCoupon: (code: string) => void;\n placeOrder: () => Promise<PlaceOrderResult>;\n reset: () => void;\n}\n\nconst STORAGE_KEY = \"numu_checkout_state\";\n\nconst EMPTY_STATE: CheckoutSessionState = {\n email: \"\",\n phone: \"\",\n shipping_address: {},\n selected_shipping_rate_id: null,\n shipping_method: null,\n payment_method: null,\n cod_requested: false,\n deposit_gateway: null,\n saved_payment_method_id: null,\n customer_notes: \"\",\n coupon_code: \"\",\n};\n\nfunction readState(): CheckoutSessionState {\n if (typeof window === \"undefined\") return { ...EMPTY_STATE };\n try {\n const raw = window.sessionStorage.getItem(STORAGE_KEY);\n if (!raw) return { ...EMPTY_STATE };\n return { ...EMPTY_STATE, ...JSON.parse(raw) };\n } catch {\n return { ...EMPTY_STATE };\n }\n}\n\nfunction writeState(state: CheckoutSessionState): void {\n if (typeof window === \"undefined\") return;\n try {\n window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify(state));\n // Notify any other useCheckout() consumers in the same tab.\n window.dispatchEvent(new CustomEvent(\"numu:checkout:updated\"));\n } catch {\n /* Safari private mode → swallow */\n }\n}\n\nfunction hasContact(s: CheckoutSessionState): boolean {\n return Boolean(\n s.email &&\n s.shipping_address?.line1 &&\n s.shipping_address?.city &&\n s.shipping_address?.country,\n );\n}\n\nfunction hasShipping(s: CheckoutSessionState): boolean {\n return hasContact(s) && Boolean(s.selected_shipping_rate_id);\n}\n\nfunction hasPayment(s: CheckoutSessionState): boolean {\n return hasShipping(s) && Boolean(s.payment_method);\n}\n\nfunction resolveStep(s: CheckoutSessionState): CheckoutStep {\n if (!hasContact(s)) return \"contact\";\n if (!hasShipping(s)) return \"shipping\";\n if (!hasPayment(s)) return \"payment\";\n return \"review\";\n}\n\nexport function useCheckout(): CheckoutApi {\n const [state, setState] = useState<CheckoutSessionState>(() => readState());\n const [rates, setRates] = useState<ShippingRateOption[] | null>(null);\n const [ratesLoading, setRatesLoading] = useState(false);\n\n // Sync from sessionStorage when other consumers update (other tab\n // would not trigger the same-tab event but storage event handles it).\n useEffect(() => {\n function onChange() {\n setState(readState());\n }\n window.addEventListener(\"numu:checkout:updated\", onChange);\n window.addEventListener(\"storage\", (e) => {\n if (e.key === STORAGE_KEY) onChange();\n });\n return () => {\n window.removeEventListener(\"numu:checkout:updated\", onChange);\n };\n }, []);\n\n const patch = useCallback((partial: Partial<CheckoutSessionState>) => {\n setState((prev) => {\n const next = { ...prev, ...partial };\n writeState(next);\n return next;\n });\n }, []);\n\n const refreshShipping = useCallback(async (): Promise<ShippingRateOption[]> => {\n setRatesLoading(true);\n try {\n const res = await fetch(\"/api/shipping/options\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ shipping_address: state.shipping_address }),\n });\n if (!res.ok) {\n setRates([]);\n return [];\n }\n const body = await res.json();\n const list: ShippingRateOption[] =\n (body?.data?.options || body?.data || body?.options || []) as ShippingRateOption[];\n setRates(list);\n return list;\n } catch {\n setRates([]);\n return [];\n } finally {\n setRatesLoading(false);\n }\n }, [state.shipping_address]);\n\n const placeOrder = useCallback(async (): Promise<PlaceOrderResult> => {\n // Cart line items are read server-side from the session cookie;\n // we still pass an empty list because the schema requires the field.\n const payload = {\n line_items: [],\n shipping_address: state.shipping_address,\n payment_method: state.payment_method,\n selected_shipping_rate_id: state.selected_shipping_rate_id,\n shipping_method: state.shipping_method,\n guest_email: state.email,\n cod_requested: state.cod_requested,\n deposit_gateway: state.deposit_gateway,\n saved_payment_method_id: state.saved_payment_method_id,\n customer_notes: state.customer_notes || null,\n coupon_code: state.coupon_code || null,\n };\n const res = await fetch(\"/api/checkout\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n // Idempotency-Key prevents a double-click double-charge.\n \"Idempotency-Key\":\n typeof crypto !== \"undefined\" && \"randomUUID\" in crypto\n ? crypto.randomUUID()\n : `${Date.now()}-${Math.random()}`,\n },\n body: JSON.stringify(payload),\n });\n const body = await res.json();\n if (!res.ok) {\n const detail =\n body?.detail || body?.error || `Checkout failed (${res.status})`;\n throw new Error(typeof detail === \"string\" ? detail : JSON.stringify(detail));\n }\n const data = (body?.data || body) as PlaceOrderResult;\n return data;\n }, [state]);\n\n const step = useMemo(() => resolveStep(state), [state]);\n\n const api = useMemo<CheckoutApi>(\n () => ({\n state,\n step,\n contact: {\n set: (input) =>\n patch({\n ...(input.email !== undefined && { email: input.email }),\n ...(input.phone !== undefined && { phone: input.phone }),\n ...(input.shipping_address && {\n shipping_address: {\n ...state.shipping_address,\n ...input.shipping_address,\n },\n // Invalidate downstream picks when address changes.\n selected_shipping_rate_id: null,\n shipping_method: null,\n }),\n }),\n isComplete: () => hasContact(state),\n },\n shipping: {\n rates,\n loading: ratesLoading,\n refresh: refreshShipping,\n select: (rateId) => {\n const rate = rates?.find((r) => r.id === rateId);\n patch({\n selected_shipping_rate_id: rateId,\n shipping_method: rate?.name || null,\n });\n },\n isComplete: () => hasShipping(state),\n },\n payment: {\n select: (method, opts) =>\n patch({\n payment_method: method,\n cod_requested: method === \"cod\",\n deposit_gateway: opts?.deposit_gateway || null,\n saved_payment_method_id: opts?.saved_payment_method_id || null,\n }),\n isComplete: () => hasPayment(state),\n },\n setNotes: (notes) => patch({ customer_notes: notes }),\n setCoupon: (code) => patch({ coupon_code: code }),\n placeOrder,\n reset: () => {\n if (typeof window !== \"undefined\") {\n try {\n window.sessionStorage.removeItem(STORAGE_KEY);\n } catch {\n /* swallow */\n }\n }\n setState({ ...EMPTY_STATE });\n setRates(null);\n },\n }),\n [state, step, rates, ratesLoading, refreshShipping, placeOrder, patch],\n );\n\n return api;\n}\n","\"use client\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport type { CheckoutAddress, ShippingRateOption } from \"./useCheckout\";\n\n/**\n * Fetch shipping rate options for an address — Phase 7.4.\n *\n * Themes that want to display rates on the cart page (Shopify\n * pattern: \"Shipping calculated at checkout — preview from cart\")\n * use this. It posts to /api/shipping/options the same way the\n * platform's shipping step does, but as a self-contained hook so\n * themes don't need to drive the full useCheckout() machinery for a\n * simple display.\n *\n * Returns null when no address is provided (the typical pre-input\n * state) — themes branch on `rates !== null` to decide whether to\n * show the rates panel or a \"Enter address\" prompt.\n *\n * Optionally accepts a `location_id` for multi-location stores\n * (Phase 8.2) — the resolver uses the named fulfilling location's\n * origin address when calculating rates. Ignored if multi-location\n * is off.\n *\n * Usage:\n *\n * const { rates, loading, refresh } = useShippingRates({\n * address: { country: \"EG\", city: \"Cairo\" },\n * });\n */\n\nexport interface UseShippingRatesOptions {\n address?: CheckoutAddress | null;\n location_id?: string | null;\n /** Auto-fetch on mount + when the address changes. Default true. */\n enabled?: boolean;\n}\n\nexport interface UseShippingRatesState {\n rates: ShippingRateOption[] | null;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n}\n\nfunction isAddressSufficient(a?: CheckoutAddress | null): boolean {\n if (!a) return false;\n // Country alone gets a zone-level estimate; city + country gets\n // the rate properly. We require at least country since zones are\n // country-keyed.\n return Boolean(a.country);\n}\n\nexport function useShippingRates({\n address,\n location_id,\n enabled = true,\n}: UseShippingRatesOptions = {}): UseShippingRatesState {\n const [rates, setRates] = useState<ShippingRateOption[] | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const refresh = useCallback(async (): Promise<void> => {\n if (!isAddressSufficient(address)) {\n setRates(null);\n return;\n }\n setLoading(true);\n setError(null);\n try {\n const res = await fetch(\"/api/shipping/options\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n shipping_address: address,\n ...(location_id ? { location_id } : {}),\n }),\n });\n if (!res.ok) {\n // 404 = country not covered by any zone. Surface as \"no\n // rates\" rather than an error so themes can render a\n // \"We don't ship to {country}\" message gracefully.\n if (res.status === 404) {\n setRates([]);\n return;\n }\n throw new Error(`shipping rates: HTTP ${res.status}`);\n }\n const body = await res.json();\n const list: ShippingRateOption[] =\n (body?.data?.options || body?.data || body?.options || []) as ShippingRateOption[];\n setRates(list);\n } catch (e) {\n setError(e instanceof Error ? e : new Error(String(e)));\n setRates([]);\n } finally {\n setLoading(false);\n }\n }, [address, location_id]);\n\n useEffect(() => {\n if (!enabled) return;\n void refresh();\n }, [enabled, refresh]);\n\n return { rates, loading, error, refresh };\n}\n","\"use client\";\nimport {\n useEffect,\n useState,\n useCallback,\n useMemo,\n useRef,\n type ReactNode,\n} from \"react\";\nimport {\n ShopContext,\n CartContext,\n CustomerContext,\n ThemeSettingsContext,\n LocalizationContext,\n CurrentTemplateContext,\n PageContext,\n NavigationContext,\n CurrencyContext,\n} from \"../contexts\";\nimport {\n CustomerActionsContext,\n type CustomerActions,\n} from \"../contexts/customer-actions\";\nimport { readVariantSelection } from \"../utils/selectionRegistry\";\nimport type { Store, Cart, CartItem, Customer } from \"../types/entities\";\nimport type { ThemeSettingsV3 } from \"../types/theme\";\nimport type {\n LocalizationState,\n MenuItemData,\n CartMutationResult,\n CurrencyConfig,\n CurrencyState,\n} from \"../contexts\";\n\nconst RTL_LOCALES = [\"ar\", \"he\", \"fa\", \"ur\"];\n\ninterface NuMuProviderProps {\n store: Store;\n themeSettings: ThemeSettingsV3;\n initialCart?: Cart;\n customer?: Customer | null;\n locale?: string;\n translations?: Record<string, string>;\n /**\n * Wave 5 — id of the active page template. Hosts pass this from the\n * route (e.g. \"product\" inside app/(store)/[subdomain]/product/[id]).\n * Themes read it via `useCurrentTemplate()` to render the matching\n * section list. Defaults to \"home\" when omitted, so existing themes\n * built before the prop existed keep rendering their home template.\n */\n currentTemplate?: string;\n /**\n * I3 — resolved alternate template key for the current page (e.g.\n * `\"product.wholesale\"`) when the storefront routed it to a template\n * suffix. Published on the synthesized `PageContext` value so themes read\n * it via `usePage()?.template`. Distinct from `currentTemplate`, which is\n * the base route type (`\"product\"`). Omit for pages on their default\n * template; additive, so themes/hosts predating it are unaffected.\n */\n pageTemplate?: string;\n /**\n * Pre-fetched product list for the current page. Themes that call\n * `useProducts()` will read these from PageContext without needing\n * `fetchIfMissing: true`. Hosts typically populate this from their\n * route loader / SSR pass; omitting it leaves `useProducts()`\n * returning an empty array unless the theme opts into client fetch.\n */\n initialProducts?: import(\"../types/entities\").Product[];\n /**\n * Pre-fetched collection list — same pattern as initialProducts for\n * `useCollections()`. Categories/collections shown on the home page\n * read this slot.\n */\n initialCollections?: import(\"../types/entities\").Collection[];\n /**\n * Phase 2.4 — store navigation menus keyed by handle (`main-menu`,\n * `footer`, …), resolved server-side by the host and injected so a\n * theme's `useNavigation(handle)` resolves synchronously without a\n * client round-trip. Omit for hosts/themes that don't wire menus —\n * `useNavigation` then falls back to its own fetch or the theme's\n * `DEFAULT_NAV`.\n */\n navigation?: Record<string, MenuItemData[]>;\n children: ReactNode;\n}\n\nconst EMPTY_CART: Cart = {\n id: \"\",\n items: [],\n subtotal: 0,\n total: 0,\n currency: \"EGP\",\n};\n\n/**\n * The storefront's /api/cart returns money in CENTS (matching the checkout\n * and built-in cart, which divide by 100 themselves). Themes consume the cart\n * via useCart() and render with <Money>/formatMoney, which expect MAJOR units\n * — the same convention as Product.price after the host normalizes it. Convert\n * cart money to major here so the BYOT boundary is consistent end-to-end.\n *\n * Display-only: checkout submits quantities (the server recomputes amounts),\n * so this never changes what the customer is charged.\n */\nfunction normalizeCartFromServer(cart: Cart): Cart {\n const toMajor = (n: number | null | undefined): number =>\n typeof n === \"number\" ? n / 100 : 0;\n // The wire shape carries `automatic_discount_cents`; the theme-facing `Cart`\n // exposes the converted `automatic_discount`. Destructure the raw name OUT\n // of the spread rather than just adding the converted one beside it —\n // otherwise both survive, 100x apart, and the one carrying the name a theme\n // dev reaches for first (it's the name used by the backend response, by\n // `adaptCart`, and throughout the offers docs) is the unconverted one.\n // TypeScript wouldn't catch that read, since the field isn't on `Cart`.\n const { automatic_discount_cents: wireAutomaticCents, ...rest } = cart as Cart & {\n automatic_discount_cents?: number;\n };\n return {\n ...rest,\n subtotal: toMajor(cart.subtotal),\n total: toMajor(cart.total),\n ...(cart.discount_amount != null\n ? { discount_amount: toMajor(cart.discount_amount) }\n : {}),\n // Offers-v2 automatic promotions. These MUST be converted here too —\n // they arrive in cents next to already-major totals, so forwarding them\n // raw makes every theme render a saving 100x too large. This function is\n // the one and only cents→major boundary for the cart.\n //\n // The backend field is `automatic_discount_cents`; themes get\n // `automatic_discount` (major), because a `_cents` name holding pounds\n // invites exactly the double-divide this conversion exists to prevent.\n ...(wireAutomaticCents != null\n ? { automatic_discount: toMajor(wireAutomaticCents) }\n : {}),\n ...(Array.isArray(cart.applied_promotions)\n ? {\n applied_promotions: cart.applied_promotions.map((p) => ({\n ...p,\n amount: toMajor(p.amount),\n })),\n }\n : {}),\n items: Array.isArray(cart.items)\n ? cart.items.map((it) => {\n // The storefront/backend cart line item ships `product_name` +\n // `unit_price`/`total_price` (cents), not the `name`/`price` the\n // SDK's CartItem interface (and themes) expect. Map them here so\n // every theme's cart renders the real name + price instead of a\n // blank name and 0.00. Honour `name`/`price` first for any backend\n // that already uses them.\n const raw = it as CartItem & {\n product_name?: string;\n unit_price?: number;\n };\n return {\n ...it,\n name: raw.name || raw.product_name || \"\",\n price: toMajor(raw.price ?? raw.unit_price),\n variant_name: raw.variant_name ?? undefined,\n };\n })\n : [],\n };\n}\n\n/**\n * The storefront's /api/cart* routes return the cart inside a `{data}`\n * envelope (`{ success, data: Cart, message }`) — the platform-wide response\n * shape the hub / admin / customer-fetch all unwrap. The cart logic here\n * historically read the response AS the cart, so `data.items` was `undefined`\n * and the cart silently stayed EMPTY: add-to-cart returned 200/201 but the\n * header count and cart page never updated. Unwrap `.data` when present.\n */\nfunction unwrapCart(json: unknown): Cart {\n if (\n json &&\n typeof json === \"object\" &&\n \"data\" in json &&\n (json as { data?: unknown }).data &&\n typeof (json as { data?: unknown }).data === \"object\"\n ) {\n return (json as { data: Cart }).data;\n }\n return json as Cart;\n}\n\n/**\n * Read the `numu_csrf` cookie value from document.cookie.\n *\n * The storefront's GET /api/cart sets this on first fetch; we echo it\n * back in `x-numu-csrf` on every mutation so the proxy can verify the\n * double-submit. Without this gate any XSS in a theme can drain the\n * customer's cart by hitting /api/cart/add directly.\n */\nfunction readCsrfCookie(): string | null {\n if (typeof document === \"undefined\") return null;\n const match = document.cookie.match(/(?:^|;\\s*)numu_csrf=([^;]+)/);\n return match ? decodeURIComponent(match[1]) : null;\n}\n\n// ── Currency cookie (numu_currency) ────────────────────────────────────────\n// Persists the visitor's presentment-currency choice so it survives cross-page\n// navigation. Owned by NuMuProvider (was previously in useCurrency).\nconst CURRENCY_COOKIE_NAME = \"numu_currency\";\nconst CURRENCY_COOKIE_MAX_AGE = 60 * 60 * 24 * 30; // 30 days\n\nfunction readCurrencyCookie(): string | null {\n if (typeof document === \"undefined\") return null;\n const match = document.cookie.match(\n new RegExp(`(?:^|;\\\\s*)${CURRENCY_COOKIE_NAME}=([^;]+)`),\n );\n return match ? decodeURIComponent(match[1]) : null;\n}\n\nfunction writeCurrencyCookie(value: string): void {\n if (typeof document === \"undefined\") return;\n document.cookie = `${CURRENCY_COOKIE_NAME}=${encodeURIComponent(value)}; path=/; max-age=${CURRENCY_COOKIE_MAX_AGE}; SameSite=Lax`;\n}\n\n/**\n * postCartMutation — shared helper for cart writes.\n *\n * Three concerns layered together:\n *\n * 1. Request versioning so a burst of \"+ + +\" clicks doesn't apply\n * stale responses. Each call reserves a token; only the response\n * for the highest-numbered token is allowed to update local state.\n *\n * 2. CSRF: every cart mutation includes `x-numu-csrf` from the cookie.\n * The /api/cart/* proxy compares cookie + header (double-submit)\n * and rejects mismatches with 403.\n *\n * 3. Idempotency: each call mints a UUID idempotency key. The\n * backend (when supported) caches the response for that key in\n * Redis so a double-clicked Add-to-Cart only mutates state once.\n * Wire format is stable; backend honoring it is opt-in.\n *\n * Resolves a `CartMutationResult` so the caller can tell success from\n * failure. Previously this swallowed `!res.ok` with a bare `return`, so an\n * out-of-stock / validation / 403 rejection was indistinguishable from a\n * successful write — and `addItem` fired its `add_to_cart` analytics event\n * regardless. Now a non-2xx resolves `{ ok: false, status, message }` (and\n * does NOT apply a cart), so themes can surface the error and analytics can\n * be gated on `ok`. On success it applies the cart and resolves\n * `{ ok: true, status }`. Network throws still reject (callers that relied on\n * try/catch keep that behavior); `mutate` wraps this and always sets loading.\n */\nasync function postCartMutation(\n endpoint: string,\n body: unknown,\n applyCart: (cart: Cart) => void,\n reserveToken: () => number,\n): Promise<CartMutationResult> {\n const token = reserveToken();\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n const csrf = readCsrfCookie();\n if (csrf) headers[\"x-numu-csrf\"] = csrf;\n // Idempotency key — randomUUID is widely supported; fall back if not\n // (older Safari, embedded webviews).\n const idempotencyKey =\n typeof crypto !== \"undefined\" && \"randomUUID\" in crypto\n ? crypto.randomUUID()\n : `${Date.now()}-${Math.random().toString(36).slice(2)}`;\n headers[\"x-numu-idempotency-key\"] = idempotencyKey;\n\n const res = await fetch(endpoint, {\n method: body === undefined ? \"DELETE\" : \"POST\",\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n });\n if (!res.ok) {\n // Non-2xx (OOS, validation, 403 CSRF, …). Pull the backend's error text\n // when the body parses so a theme can show a real message; never apply a\n // cart from a failed write.\n let message: string | undefined;\n try {\n const err = (await res.json()) as Record<string, unknown> | null;\n if (err && typeof err === \"object\") {\n const m = err.message ?? err.error ?? err.detail;\n if (typeof m === \"string\") message = m;\n }\n } catch {\n // Non-JSON / empty error body — status alone carries the signal.\n }\n void token;\n return { ok: false, status: res.status, message };\n }\n const json = await res.json();\n const applied = unwrapCart(json);\n applyCart(applied);\n // Token was actually consumed on entry; applyCart enforces ordering\n // via the closure below.\n void token;\n // Hand the written cart back in the SDK's public convention (MAJOR units —\n // applyCart normalizes for state separately) so callers like addItem can\n // read the added line's price without racing React state.\n return { ok: true, status: res.status, cart: normalizeCartFromServer(applied) };\n}\n\nexport function NuMuProvider({\n store,\n themeSettings,\n initialCart,\n customer,\n locale: initialLocale,\n translations: initialTranslations,\n currentTemplate = \"home\",\n pageTemplate,\n initialProducts,\n initialCollections,\n navigation,\n children,\n}: NuMuProviderProps) {\n // Synthesise a Page record so `useProducts()` and `useCollections()`\n // can read pre-fetched lists via PageContext. Stable identity ensures\n // we don't bust the context on every render (initialProducts and\n // initialCollections come in as fresh arrays from the host's\n // useMemo'd ctx, so referential equality already holds across renders\n // without changes; useMemo here is belt-and-suspenders).\n const pageValue = useMemo(\n () =>\n ({\n type: currentTemplate,\n title: store?.name ?? \"\",\n // I3 — resolved alternate template key (e.g. \"product.wholesale\"),\n // surfaced via usePage()?.template. Omitted when undefined so a\n // page on its default template exposes no `template` field.\n ...(pageTemplate ? { template: pageTemplate } : {}),\n data: {\n products: initialProducts ?? [],\n collections: initialCollections ?? [],\n },\n }) as import(\"../types/entities\").Page,\n [currentTemplate, pageTemplate, store?.name, initialProducts, initialCollections],\n );\n const [cart, setCart] = useState<Cart>(\n initialCart || { ...EMPTY_CART, currency: store.currency },\n );\n // `loading` starts TRUE when the cart is NOT hydrated (no initialCart): the\n // cart is EMPTY_CART only because the on-mount GET /api/cart hasn't landed\n // yet, NOT because the cart is genuinely empty. Without this, a returning\n // shopper's cart page flashed \"YOUR CART IS EMPTY\" for the fetch window\n // (themes gate their empty state on `loading` — see cart sections). Cleared\n // in the initial-fetch effect's finally. When the host hydrates `initialCart`\n // (SSR), the cart is already known → not loading.\n const [loading, setLoading] = useState(!initialCart);\n // Phase 3.6 — locale precedence:\n // 1. `initialLocale` prop (storefront pages that resolved it server-side)\n // 2. `numu_locale` cookie (client-side fallback for pages that don't\n // thread the prop through)\n // 3. `store.default_language`\n // 4. \"en\"\n const [locale, setLocale] = useState(() => {\n if (initialLocale) return initialLocale;\n if (typeof document !== \"undefined\") {\n const m = document.cookie.match(/(?:^|; )numu_locale=([^;]+)/);\n if (m) return decodeURIComponent(m[1]);\n }\n return store.default_language || \"en\";\n });\n const [translations] = useState(initialTranslations || {});\n\n // ── Customer state + auth actions ──────────────────────────────────────\n // Customer comes from one of three sources, in order of precedence:\n // 1. SSR-supplied `customer` prop (when /account/* routes pre-fetch\n // the customer server-side via the cookie).\n // 2. The mount effect below which calls GET /api/customer/me, used\n // on routes that don't pre-fetch (home/product/etc.) to keep the\n // cart drawer / header user menu accurate.\n // 3. Mutations triggered by `useCustomerActions()` (login/logout/\n // register/updateProfile) — these refresh state immediately.\n const [customerState, setCustomerState] = useState<Customer | null>(\n customer ?? null,\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n // Skip the GET if the SSR pass already supplied a customer; the\n // round-trip would only confirm what we already know and waste a\n // request budget on every navigation.\n if (customer) return;\n let cancelled = false;\n void (async () => {\n try {\n const res = await fetch(\"/api/customer/me\", {\n method: \"GET\",\n credentials: \"include\",\n cache: \"no-store\",\n });\n if (cancelled) return;\n // 401 means logged-out: leave customerState=null. Any other\n // non-OK is treated the same — the customer can still browse.\n if (!res.ok) return;\n const json = await res.json();\n const next =\n json && typeof json === \"object\" && \"data\" in json\n ? (json as { data: Customer }).data\n : (json as Customer);\n if (next && typeof next === \"object\") {\n setCustomerState(next);\n }\n } catch {\n // Network blip — keep current customerState.\n }\n })();\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Refresh re-fetches /api/customer/me; used after any mutation that\n // changed the customer record (login/register/profile update).\n const refreshCustomer = useCallback(async () => {\n if (typeof window === \"undefined\") return;\n try {\n const res = await fetch(\"/api/customer/me\", {\n method: \"GET\",\n credentials: \"include\",\n cache: \"no-store\",\n });\n if (res.status === 401) {\n setCustomerState(null);\n return;\n }\n if (!res.ok) return;\n const json = await res.json();\n const next =\n json && typeof json === \"object\" && \"data\" in json\n ? (json as { data: Customer }).data\n : (json as Customer);\n setCustomerState(next ?? null);\n } catch {\n // ignore\n }\n }, []);\n\n // CSRF: customer mutations echo `numu_csrf` cookie value as header\n // for double-submit. Read just-in-time so we always send the freshest\n // (the cookie may rotate on /api/cart roundtrip).\n function readCsrf(): string | null {\n if (typeof document === \"undefined\") return null;\n const m = document.cookie.match(/(?:^|; )numu_csrf=([^;]+)/);\n return m ? decodeURIComponent(m[1]) : null;\n }\n\n async function postCustomer(path: string, body: unknown): Promise<unknown> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n const csrf = readCsrf();\n if (csrf) headers[\"x-numu-csrf\"] = csrf;\n const res = await fetch(path, {\n method: \"POST\",\n credentials: \"include\",\n cache: \"no-store\",\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n let json: unknown = null;\n try {\n json = await res.json();\n } catch {\n // empty body — fine\n }\n return json;\n }\n\n async function putCustomer(path: string, body: unknown): Promise<unknown> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n const csrf = readCsrf();\n if (csrf) headers[\"x-numu-csrf\"] = csrf;\n const res = await fetch(path, {\n method: \"PUT\",\n credentials: \"include\",\n cache: \"no-store\",\n headers,\n body: JSON.stringify(body ?? {}),\n });\n try {\n return await res.json();\n } catch {\n return null;\n }\n }\n\n const customerActions: CustomerActions = useMemo(\n () => ({\n login: async (input) => {\n const r = await postCustomer(\"/api/customer/login\", input);\n await refreshCustomer();\n return r;\n },\n register: async (input) => {\n const r = await postCustomer(\"/api/customer/register\", input);\n await refreshCustomer();\n return r;\n },\n logout: async () => {\n const r = await postCustomer(\"/api/customer/logout\", {});\n // Don't wait on refresh — backend cleared the cookie, so\n // setCustomerState(null) directly avoids a redundant 401.\n setCustomerState(null);\n return r;\n },\n requestRecover: (input) =>\n postCustomer(\"/api/customer/recover\", input),\n confirmReset: async (input) => {\n const r = await postCustomer(\"/api/customer/reset\", input);\n // Reset clears all sessions on the backend; user must log in\n // again. Force null so any stale state from before the reset\n // doesn't linger.\n setCustomerState(null);\n return r;\n },\n verifyEmail: async (input) => {\n const r = await postCustomer(\"/api/customer/verify-email\", input);\n await refreshCustomer();\n return r;\n },\n resendVerification: (input) =>\n postCustomer(\"/api/customer/resend-verification\", input),\n updateProfile: async (input) => {\n const r = await putCustomer(\"/api/customer/me\", input);\n await refreshCustomer();\n return r;\n },\n changePassword: (input) =>\n putCustomer(\"/api/customer/me/password\", input),\n refresh: refreshCustomer,\n }),\n [refreshCustomer],\n );\n\n // ── Initial cart fetch ─────────────────────────────────────────────────\n // GET /api/cart on mount serves two purposes:\n // 1. Hydrates the live cart state for returning visitors so the\n // header cart count is accurate before any user interaction.\n // 2. Mints the `numu_csrf` cookie (the storefront's GET /api/cart\n // handler emits Set-Cookie if missing). Subsequent cart-write\n // calls read this cookie via document.cookie and echo it as\n // the `x-numu-csrf` header for double-submit verification.\n // Without this priming round-trip, a first-Add-to-Cart 403s\n // because the cookie hasn't been issued yet.\n //\n // SSR-safe: `fetch` is a browser-only call here; we gate on `window`.\n // Errors are swallowed — the cart context starts empty either way,\n // and downstream actions surface their own errors.\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n let cancelled = false;\n void (async () => {\n try {\n const res = await fetch(\"/api/cart\", {\n method: \"GET\",\n credentials: \"include\",\n cache: \"no-store\",\n });\n if (!res.ok || cancelled) return;\n const json = await res.json();\n const data = unwrapCart(json);\n if (data && typeof data === \"object\") {\n setCart(normalizeCartFromServer(data));\n }\n } catch {\n // Network blip / not-yet-deployed cart endpoint. Leave the\n // empty initial cart in place; the user can still browse.\n } finally {\n // Initial cart load resolved (success OR failure): the cart state is\n // now authoritative, so drop the loading flag. Themes stop showing\n // their loading placeholder and reveal the real cart / empty state.\n if (!cancelled) setLoading(false);\n }\n })();\n return () => {\n cancelled = true;\n };\n // Run once per mount; the cart endpoint is idempotent and the\n // CSRF cookie persists across navigations within the SPA.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // ── Request-versioning machinery ───────────────────────────────────────\n // `nextRequestId` increases on each cart mutation; `latestApplied` tracks\n // the highest id whose response has been applied. A response is applied\n // only if its id is >= latestApplied (i.e., not superseded).\n const nextRequestId = useRef(0);\n const latestApplied = useRef(0);\n\n const reserveToken = useCallback(() => {\n nextRequestId.current += 1;\n return nextRequestId.current;\n }, []);\n\n const buildApplyCart = useCallback(\n (token: number) => (newCart: Cart) => {\n if (token < latestApplied.current) {\n // A later request has already updated state — ignore stale response.\n return;\n }\n latestApplied.current = token;\n setCart(normalizeCartFromServer(newCart));\n },\n [],\n );\n\n const mutate = useCallback(\n async (endpoint: string, body: unknown): Promise<CartMutationResult> => {\n const token = reserveToken();\n setLoading(true);\n try {\n return await postCartMutation(\n endpoint,\n body,\n buildApplyCart(token),\n () => token, // already reserved; just return the same token\n );\n } finally {\n setLoading(false);\n }\n },\n [reserveToken, buildApplyCart],\n );\n\n // ── Cart actions ───────────────────────────────────────────────────────\n\n const addItem = useCallback(\n async (\n productId: string,\n variantId?: string,\n quantity?: number,\n selectedOptions?: Record<string, string>,\n ): Promise<CartMutationResult> => {\n // Shared event id for Meta AddToCart dedup: the host /api/cart/add route\n // fires the CAPI event with this id, and the host <MetaPixel> bridge\n // fires the matching browser fbq from the CustomEvent below.\n const eventId =\n typeof crypto !== \"undefined\" && crypto.randomUUID\n ? crypto.randomUUID()\n : `${Date.now()}`;\n const qty = quantity || 1;\n // Picker axes — the backend uses them ONLY as a variant_name fallback\n // when the variant row can't name itself (legacy products keep axes in\n // attributes JSON with a placeholder variant whose option_values is {}).\n // Falls back to the live useVariantSelection state for this product so\n // themes calling addItem directly get the rule with no changes.\n const axes =\n selectedOptions && Object.keys(selectedOptions).length > 0\n ? selectedOptions\n : (readVariantSelection(productId) ?? undefined);\n const result = await mutate(\"/api/cart/add\", {\n product_id: productId,\n variant_id: variantId,\n quantity: qty,\n selected_options: axes,\n _event_id: eventId,\n });\n // Gate the AddToCart analytics on a SUCCESSFUL write. This previously\n // fired unconditionally, so an out-of-stock / validation / 403 rejection\n // still reported a phantom add_to_cart to Meta/GA and inflated the\n // funnel. On failure, return the result so the theme can react (toast,\n // \"out of stock\", …) without a spurious conversion event.\n if (!result.ok) return result;\n // Browser-side AddToCart signal — CAPI is fired server-side by the cart\n // route with the same id. Dispatched directly (not via useAnalytics) so\n // we control the event_id and avoid a duplicate /track POST.\n // value/currency (MAJOR units, from the written line's snapshot price)\n // make the event usable for value-based optimization + dynamic ads.\n try {\n if (typeof window !== \"undefined\") {\n const line = result.cart?.items.find((it) =>\n variantId ? it.variant_id === variantId : it.product_id === productId,\n );\n const value =\n line && typeof line.price === \"number\" && line.price > 0\n ? Math.round(line.price * qty * 100) / 100\n : undefined;\n window.dispatchEvent(\n new CustomEvent(\"numu:analytics:event\", {\n detail: {\n event: \"add_to_cart\",\n payload: {\n content_ids: [productId],\n content_type: \"product\",\n num_items: qty,\n ...(value !== undefined\n ? { value, currency: result.cart?.currency }\n : {}),\n },\n event_id: eventId,\n },\n }),\n );\n }\n } catch {\n /* CustomEvent unsupported — server CAPI still covers the event */\n }\n return result;\n },\n [mutate],\n );\n\n const removeItem = useCallback(\n (itemId: string) => mutate(\"/api/cart/remove\", { item_id: itemId }),\n [mutate],\n );\n\n const updateQuantity = useCallback(\n (itemId: string, quantity: number) =>\n mutate(\"/api/cart/update\", { item_id: itemId, quantity }),\n [mutate],\n );\n\n const applyDiscount = useCallback(\n (code: string) => mutate(\"/api/cart/discount\", { code }),\n [mutate],\n );\n\n const removeDiscount = useCallback(\n // DELETE — postCartMutation interprets undefined body as DELETE.\n () => mutate(\"/api/cart/discount\", undefined),\n [mutate],\n );\n\n /**\n * Persist a customer note on the cart. Round-trips to the backend so the\n * note survives reload (the previous local-only behavior was a footgun).\n */\n const updateNote = useCallback(\n (note: string) => mutate(\"/api/cart/update\", { note }),\n [mutate],\n );\n\n const clearCart = useCallback(async () => {\n setCart({ ...EMPTY_CART, currency: store.currency });\n }, [store.currency]);\n\n // Broadcast a `numu:cart:updated` CustomEvent on every cart change.\n // Why: non-React themes (vanilla JS / Alpine / Vue islands) can't\n // consume `useCart()`. They listen on `window` instead, which gives\n // them the same write-then-react contract React themes get for free.\n // The event detail mirrors the React `cart` shape so consumers don't\n // need to re-fetch.\n //\n // We skip the first dispatch — the initial state is the empty\n // placeholder before the GET /api/cart response lands, and themes\n // that ran their own `numu:cart:fetched`-style logic on page load\n // would otherwise see a spurious empty event right after rendering.\n const cartFirstRender = useRef(true);\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n if (cartFirstRender.current) {\n cartFirstRender.current = false;\n return;\n }\n window.dispatchEvent(\n new CustomEvent(\"numu:cart:updated\", { detail: cart }),\n );\n }, [cart]);\n\n const cartValue = useMemo(\n () => ({\n cart,\n addItem,\n removeItem,\n updateQuantity,\n applyDiscount,\n removeDiscount,\n updateNote,\n clearCart,\n loading,\n }),\n [\n cart,\n addItem,\n removeItem,\n updateQuantity,\n applyDiscount,\n removeDiscount,\n updateNote,\n clearCart,\n loading,\n ],\n );\n\n // ── Localization with memoized Intl formatters ─────────────────────────\n // Building Intl.NumberFormat / Intl.DateTimeFormat per call is costly;\n // memoize on (locale, currency).\n //\n // Resilience: stores can come back from older API rows with `currency`\n // null/empty. `Intl.NumberFormat({ currency: \"\" })` throws \"Currency\n // code is required with currency style\", which crashes the entire\n // render tree. Fall back to USD for the formatter so themes keep\n // working — merchants will see prices in USD until they configure a\n // real currency, which is a clearer signal than a blank screen.\n const safeCurrency = (store.currency || \"USD\").toUpperCase();\n\n // Phase 3.7 — numeral system. Merchants opt into Arab-Indic\n // digits (٠١٢٣٤) for Arabic stores via store.settings.numerals.\n // Western (default) keeps the ASCII digits everyone's used to.\n // We construct intl locales with the appropriate `-u-nu-<system>`\n // extension so money + date + count formatters all stay consistent.\n const numeralSystem =\n ((store as unknown as { settings?: { numerals?: string } }).settings\n ?.numerals === \"arabic\")\n ? \"arab\"\n : \"latn\";\n const intlLocale = `${locale}-u-nu-${numeralSystem}`;\n\n // We deliberately compute intlLocale BEFORE these memos so the\n // numbering-system extension is part of the formatter cache key —\n // a merchant flipping store.settings.numerals from \"western\" to\n // \"arabic\" rebuilds the formatters on the next render rather than\n // continuing to render Western digits from the stale cache.\n const moneyFmt = useMemo(() => {\n try {\n return new Intl.NumberFormat(intlLocale, {\n style: \"currency\",\n currency: safeCurrency,\n });\n } catch {\n // Pathologic intlLocale (engine doesn't support `-u-nu-arab`\n // for the active language) — fall back to the bare locale.\n return new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency: safeCurrency,\n });\n }\n }, [intlLocale, locale, safeCurrency]);\n const dateFmt = useMemo(() => {\n try {\n return new Intl.DateTimeFormat(intlLocale, {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n });\n } catch {\n return new Intl.DateTimeFormat(locale, {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n });\n }\n }, [intlLocale, locale]);\n\n // Phase 3.6 — locales the store advertises. Falls back to a single-\n // entry list (the active locale) so themes can render the\n // LocaleSwitcher unconditionally without an extra check.\n const availableLocales = useMemo(() => {\n const list =\n (store as unknown as { available_locales?: string[] }).available_locales;\n if (Array.isArray(list) && list.length > 0) return list;\n return [locale];\n }, [store, locale]);\n\n // Phase 3.6 — locale switcher. Writes the cookie + reloads so the\n // server-rendered layout picks up the change. We prefer cookie over\n // querystring because cookie persists across cross-page navigation\n // without each page having to thread `?locale=ar` through every link.\n const switchLocale = useCallback((next: string) => {\n if (typeof document === \"undefined\") return;\n if (!next) return;\n // 1-year cookie; SameSite=Lax so it travels with same-origin nav\n // but doesn't leak on cross-site requests. Path=/ so every page\n // sees it.\n document.cookie =\n `numu_locale=${encodeURIComponent(next)}; ` +\n `Path=/; Max-Age=${60 * 60 * 24 * 365}; SameSite=Lax`;\n setLocale(next);\n // Reload so SSR re-runs with the new cookie. Themes that want\n // client-only locale swaps (no SSR re-render) can wrap their text\n // in `useTranslation()` and skip the reload — but locale-aware\n // SSR data (translated product names, RTL <html dir>) needs the\n // reload to take effect.\n if (typeof window !== \"undefined\") {\n window.location.reload();\n }\n }, []);\n\n // Default (no-options) number formatter — memoized so the formatNumber\n // hot path doesn't construct one per call. Declared BEFORE the\n // localization useMemo so the closure captures the resolved value.\n const defaultNumberFmt = useMemo(() => {\n try {\n return new Intl.NumberFormat(intlLocale);\n } catch {\n return new Intl.NumberFormat(locale);\n }\n }, [intlLocale, locale]);\n\n const localization: LocalizationState = useMemo(\n () => ({\n locale,\n direction: RTL_LOCALES.includes(locale) ? \"rtl\" : \"ltr\",\n translations,\n availableLocales,\n setLocale: switchLocale,\n formatMoney: (amount: number, currency?: string) => {\n const ccy = (currency || safeCurrency).toUpperCase();\n if (ccy !== safeCurrency) {\n // Override-currency path is rare; pay the formatter cost only here.\n // Empty/invalid override falls back to the store's safeCurrency\n // before this branch via the `||` above, so we never construct\n // an Intl.NumberFormat with `currency: \"\"`.\n try {\n return new Intl.NumberFormat(intlLocale, {\n style: \"currency\",\n currency: ccy,\n }).format(amount);\n } catch {\n return moneyFmt.format(amount);\n }\n }\n return moneyFmt.format(amount);\n },\n formatDate: (date: string | Date) =>\n dateFmt.format(typeof date === \"string\" ? new Date(date) : date),\n formatNumber: (n: number, options?: Intl.NumberFormatOptions) => {\n if (!options) return defaultNumberFmt.format(n);\n try {\n return new Intl.NumberFormat(intlLocale, options).format(n);\n } catch {\n return String(n);\n }\n },\n }),\n [\n locale,\n translations,\n safeCurrency,\n moneyFmt,\n dateFmt,\n availableLocales,\n switchLocale,\n intlLocale,\n defaultNumberFmt,\n ],\n );\n\n // ── Multi-currency presentment (fetched ONCE here) ─────────────────────\n // Lifted out of useCurrency() so a single fetch + a single selection back\n // EVERY <Money>/useMoney()/<CurrencySwitcher> on the page. Before this, each\n // useCurrency() caller fetched its own copy and held selection in local\n // state, so a <CurrencySwitcher> change never reached the price tags.\n const [currencyConfig, setCurrencyConfig] = useState<CurrencyConfig | null>(\n null,\n );\n const [currencyLoading, setCurrencyLoading] = useState(true);\n // Empty until the fetch resolves cookie→default→base. Starts empty on BOTH\n // server and client so the first client render matches the server markup\n // (hydration-safe); the effect sets the real value AFTER mount, and any\n // resulting price re-format is a post-hydration update.\n const [currencySelected, setCurrencySelected] = useState<string>(\"\");\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n let cancelled = false;\n void (async () => {\n try {\n const res = await fetch(\"/api/storefront/currencies\", {\n credentials: \"include\",\n headers: { Accept: \"application/json\" },\n });\n if (!res.ok) throw new Error(`currencies: HTTP ${res.status}`);\n const body = (await res.json()) as { data: CurrencyConfig };\n if (cancelled) return;\n setCurrencyConfig(body.data);\n // cookie → default_presentment → base, validated against presentment\n // so a stale cookie can't lock the visitor onto a removed currency.\n const cookie = readCurrencyCookie();\n const valid =\n cookie && body.data.presentment?.includes(cookie) ? cookie : null;\n setCurrencySelected(\n valid || body.data.default_presentment || body.data.base,\n );\n } catch {\n if (cancelled) return;\n setCurrencyConfig(null);\n setCurrencySelected(store.currency || \"EGP\");\n } finally {\n if (!cancelled) setCurrencyLoading(false);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [store.id, store.currency]);\n\n const currencyRates = useMemo<Record<string, number>>(() => {\n const out: Record<string, number> = {};\n if (!currencyConfig) return out;\n for (const [k, v] of Object.entries(currencyConfig.rates)) {\n const n = Number.parseFloat(v);\n if (Number.isFinite(n)) out[k] = n;\n }\n return out;\n }, [currencyConfig]);\n\n const convertCurrency = useCallback(\n (cents: number, target?: string): number => {\n if (!currencyConfig) return cents;\n const to = target || currencySelected;\n if (!to || to === currencyConfig.base) return cents;\n const rate = currencyRates[to];\n if (!rate || !Number.isFinite(rate)) return cents;\n return Math.round(cents * rate);\n },\n [currencyConfig, currencyRates, currencySelected],\n );\n\n const setCurrency = useCallback((currency: string) => {\n setCurrencySelected(currency);\n writeCurrencyCookie(currency);\n }, []);\n\n const currencyValue = useMemo<CurrencyState>(\n () => ({\n base: currencyConfig?.base || store.currency || \"EGP\",\n selected:\n currencySelected || currencyConfig?.base || store.currency || \"EGP\",\n presentment: currencyConfig?.presentment || [store.currency || \"EGP\"],\n rates: currencyRates,\n autoConvert: Boolean(currencyConfig?.auto_convert),\n loading: currencyLoading,\n setSelected: setCurrency,\n convert: convertCurrency,\n }),\n [\n currencyConfig,\n currencySelected,\n currencyRates,\n currencyLoading,\n store.currency,\n setCurrency,\n convertCurrency,\n ],\n );\n\n return (\n <ShopContext.Provider value={store}>\n <ThemeSettingsContext.Provider value={themeSettings}>\n <CurrentTemplateContext.Provider value={currentTemplate}>\n <PageContext.Provider value={pageValue}>\n <LocalizationContext.Provider value={localization}>\n <CurrencyContext.Provider value={currencyValue}>\n <CartContext.Provider value={cartValue}>\n <CustomerContext.Provider value={customerState}>\n <CustomerActionsContext.Provider value={customerActions}>\n <NavigationContext.Provider value={navigation ?? {}}>\n {children}\n </NavigationContext.Provider>\n </CustomerActionsContext.Provider>\n </CustomerContext.Provider>\n </CartContext.Provider>\n </CurrencyContext.Provider>\n </LocalizationContext.Provider>\n </PageContext.Provider>\n </CurrentTemplateContext.Provider>\n </ThemeSettingsContext.Provider>\n </ShopContext.Provider>\n );\n}\n","\"use client\";\nimport type { ReactNode } from \"react\";\nimport { ProductContext } from \"../contexts\";\nimport type { Product } from \"../types/entities\";\n\ninterface ProductProviderProps {\n product: Product;\n children: ReactNode;\n}\n\nexport function ProductProvider({ product, children }: ProductProviderProps) {\n return <ProductContext.Provider value={product}>{children}</ProductContext.Provider>;\n}\n","\"use client\";\nimport type { ReactNode } from \"react\";\nimport { CollectionContext } from \"../contexts\";\nimport type { Collection } from \"../types/entities\";\n\ninterface CollectionProviderProps {\n collection: Collection;\n children: ReactNode;\n}\n\nexport function CollectionProvider({ collection, children }: CollectionProviderProps) {\n return <CollectionContext.Provider value={collection}>{children}</CollectionContext.Provider>;\n}\n","/**\n * Engine-level logo appearance (shape + size).\n *\n * A merchant can crop the store logo into a shape and pick its size from the\n * theme editor's global settings (`logo_shape` / `logo_size`). The logic lives\n * here — once, in the SDK — so EVERY V3 theme renders the chosen shape the same\n * way instead of each theme re-implementing it.\n *\n * Why inline styles (not Tailwind classes): the SDK is consumed from\n * `node_modules`, which a theme's Tailwind build does not scan — so utility\n * classes like `rounded-full` / `h-16` would never be generated. Inline\n * `CSSProperties` are self-contained and work in any theme regardless of its\n * CSS setup. The shapes are pure CSS (border-radius / clip-path) applied to a\n * plain `<img>`, so animated **GIF logos keep playing** under every shape.\n */\n\nimport type { CSSProperties } from \"react\";\n\nexport type LogoShape = \"none\" | \"square\" | \"rounded\" | \"circle\" | \"triangle\";\nexport type LogoSize = \"small\" | \"medium\" | \"large\";\n\n/** Bilingual options for the `logo_shape` global setting (schema authoring). */\nexport const LOGO_SHAPE_OPTIONS = [\n { value: \"none\", label: \"Original\", label_ar: \"الأصلي\" },\n { value: \"square\", label: \"Square\", label_ar: \"مربع\" },\n { value: \"rounded\", label: \"Rounded square\", label_ar: \"مربع بزوايا دائرية\" },\n { value: \"circle\", label: \"Circle\", label_ar: \"دائرة\" },\n { value: \"triangle\", label: \"Triangle\", label_ar: \"مثلث\" },\n] as const;\n\n/** Bilingual options for the `logo_size` global setting (schema authoring). */\nexport const LOGO_SIZE_OPTIONS = [\n { value: \"small\", label: \"Small\", label_ar: \"صغير\" },\n { value: \"medium\", label: \"Medium\", label_ar: \"متوسط\" },\n { value: \"large\", label: \"Large\", label_ar: \"كبير\" },\n] as const;\n\n// Box edge length (px) for a shaped logo. Circle/rounded only reveal the\n// inscribed area, so they read smaller than a square/triangle at the same box —\n// they get a larger frame to stay legible.\nconst SHAPED_PX: Record<LogoSize, { plain: number; rounded: number }> = {\n small: { plain: 32, rounded: 48 },\n medium: { plain: 40, rounded: 64 },\n large: { plain: 56, rounded: 80 },\n};\n\nfunction normalizeSize(size: string | undefined): LogoSize {\n return size === \"large\" || size === \"medium\" ? size : \"small\";\n}\n\n/**\n * Inline style for a logo `<img>` given the merchant's shape + size.\n *\n * Returns `undefined` for `none` (and unknown shapes) so the theme keeps its\n * own native logo sizing untouched — only an explicitly chosen shape overrides\n * it. A shaped logo gets a fixed square box with `object-fit: cover` plus the\n * shape (border-radius for square/rounded/circle, clip-path for triangle).\n */\nexport function logoImgStyle(\n shape: string | undefined,\n size: string | undefined,\n): CSSProperties | undefined {\n if (!shape || shape === \"none\") return undefined;\n\n const s = normalizeSize(size);\n const isRound = shape === \"circle\" || shape === \"rounded\";\n const px = isRound ? SHAPED_PX[s].rounded : SHAPED_PX[s].plain;\n const base: CSSProperties = {\n height: px,\n width: px,\n objectFit: \"cover\",\n flex: \"0 0 auto\",\n };\n\n switch (shape) {\n case \"circle\":\n return { ...base, borderRadius: \"9999px\" };\n case \"rounded\":\n return { ...base, borderRadius: \"0.5rem\" };\n case \"triangle\":\n return { ...base, clipPath: \"polygon(50% 0%, 100% 100%, 0% 100%)\" };\n case \"square\":\n default:\n return base;\n }\n}\n\n/**\n * Derived CSS-custom-property tokens for the chosen logo shape/size. Emitted by\n * `computeGlobalStyleTokens` so host-rendered surfaces (e.g. the checkout\n * header) can match the storefront logo. Returns `{}` for `none`.\n */\nexport function logoStyleTokens(\n shape: string | undefined,\n size: string | undefined,\n): Record<string, string> {\n const style = logoImgStyle(shape, size);\n if (!style) return {};\n const box = `${style.height as number}px`;\n return {\n \"--theme-logo-box\": box,\n \"--theme-logo-radius\":\n typeof style.borderRadius === \"string\" ? style.borderRadius : \"0\",\n \"--theme-logo-clip\":\n typeof style.clipPath === \"string\" ? style.clipPath : \"none\",\n };\n}\n","/**\n * `applyGlobalStyleTokens(globalSettings, el)` — Phase 3.5.\n *\n * Bridges a store's **global theme settings** (colors, fonts, layout) to\n * **CSS custom properties** on the bundle's mount root, so editing a color\n * or font in Theme Settings actually re-paints the storefront. Before this,\n * themes shipped static CSS tokens that nothing wrote to → the pickers were\n * a silent no-op.\n *\n * ## Token contract (canonical names every theme can rely on)\n *\n * For each global setting `<id>` we set `--theme-<id>` verbatim (colors as\n * their value, fonts resolved to a CSS font stack, other scalars as-is).\n * Themes consume these with the current static value as a fallback:\n *\n * --by-cream: var(--theme-background_color, #f7f1e8);\n * --by-espresso: var(--theme-primary_color, #3a2418);\n * --by-font-serif: var(--theme-heading_font, \"Cormorant Garamond\", serif);\n *\n * In addition, well-known ids are aliased to **role** tokens so themes that\n * prefer semantic names share one vocabulary:\n *\n * colors → --theme-color-{background,text,primary,secondary,accent,border,button}\n * fonts → --theme-font-{heading,body}\n *\n * `color_scheme` / `color_scheme_group` settings (object values keyed by role)\n * emit `--scheme-<id>-<role>`.\n *\n * The helper is **idempotent** and safe to call on every `applyDraft` so the\n * customizer's live preview re-paints as the merchant drags a color.\n */\n\nimport { logoStyleTokens } from \"./logoStyle\";\n\ntype GlobalSettings = Record<string, unknown> | null | undefined;\n\n/** id → canonical color role. Covers both `<role>_color` and `color_<role>`. */\nconst COLOR_ROLE_ALIASES: Record<string, string> = {\n background_color: \"background\",\n color_background: \"background\",\n bg_color: \"background\",\n text_color: \"text\",\n color_text: \"text\",\n primary_color: \"primary\",\n color_primary: \"primary\",\n secondary_color: \"secondary\",\n color_secondary: \"secondary\",\n accent_color: \"accent\",\n color_accent: \"accent\",\n border_color: \"border\",\n color_border: \"border\",\n button_color: \"button\",\n color_button: \"button\",\n button_text_color: \"button-text\",\n color_button_text: \"button-text\",\n};\n\n/** id → canonical font role. */\nconst FONT_ROLE_ALIASES: Record<string, string> = {\n heading_font: \"heading\",\n font_heading: \"heading\",\n headings_font: \"heading\",\n body_font: \"body\",\n font_body: \"body\",\n text_font: \"body\",\n};\n\n/**\n * Font token → CSS stack + optional Google Fonts href. A `font_picker`/select\n * stores a token (e.g. \"cormorant\"); we resolve it to a real stack and inject\n * the webfont so a picked font actually loads. Unknown tokens fall through and\n * are used verbatim as the family (so a theme can store a raw stack too).\n */\nconst FONT_REGISTRY: Record<string, { stack: string; href?: string }> = {\n cormorant: {\n stack: '\"Cormorant Garamond\", Georgia, \"Times New Roman\", serif',\n href: \"https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap\",\n },\n \"dm-sans\": {\n stack: '\"DM Sans\", system-ui, -apple-system, \"Segoe UI\", sans-serif',\n href: \"https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,700&display=swap\",\n },\n playfair: {\n stack: '\"Playfair Display\", Georgia, serif',\n href: \"https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700&display=swap\",\n },\n inter: {\n stack: '\"Inter\", system-ui, -apple-system, sans-serif',\n href: \"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap\",\n },\n poppins: {\n stack: '\"Poppins\", system-ui, sans-serif',\n href: \"https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap\",\n },\n montserrat: {\n stack: '\"Montserrat\", system-ui, sans-serif',\n href: \"https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700&display=swap\",\n },\n lora: {\n stack: '\"Lora\", Georgia, serif',\n href: \"https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,500;0,600;1,400&display=swap\",\n },\n cairo: {\n stack: '\"Cairo\", system-ui, sans-serif',\n href: \"https://fonts.googleapis.com/css2?family=Cairo:wght@400;500;600;700&display=swap\",\n },\n tajawal: {\n stack: '\"Tajawal\", system-ui, sans-serif',\n href: \"https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700&display=swap\",\n },\n};\n\nconst COLOR_RE = /^(#([0-9a-f]{3,8})|rgba?\\(|hsla?\\(|color\\(|var\\()/i;\n\nfunction isColorValue(v: unknown): v is string {\n return typeof v === \"string\" && COLOR_RE.test(v.trim());\n}\n\nfunction isFontToken(v: unknown): v is string {\n return typeof v === \"string\" && Object.prototype.hasOwnProperty.call(FONT_REGISTRY, v);\n}\n\n/** Idempotently inject a webfont <link> into <head>. */\nfunction injectFontLink(href: string): void {\n if (typeof document === \"undefined\" || !href) return;\n const existing = document.querySelector(\n `link[data-numu-font][href=\"${href}\"]`,\n );\n if (existing) return;\n const link = document.createElement(\"link\");\n link.rel = \"stylesheet\";\n link.href = href;\n link.setAttribute(\"data-numu-font\", \"\");\n document.head.appendChild(link);\n}\n\n/** Pure registry lookup — no webfont injection. */\nfunction lookupFontStack(value: string): string {\n return FONT_REGISTRY[value]?.stack ?? value;\n}\n\n/**\n * Resolve a font setting value to a CSS stack. Known tokens map through the\n * registry (and load the webfont); anything else is treated as a literal\n * family/stack the theme author supplied.\n */\nexport function resolveFontStack(value: string): string {\n const entry = FONT_REGISTRY[value];\n if (entry) {\n if (entry.href) injectFontLink(entry.href);\n return entry.stack;\n }\n return value;\n}\n\n/** Result of `computeGlobalStyleTokens` — everything a host needs to paint\n * global settings without a DOM. */\nexport interface ComputedStyleTokens {\n /** CSS custom properties to set on the theme's mount root. */\n cssVars: Record<string, string>;\n /** Google-Fonts stylesheet hrefs for any registry fonts in use. */\n fontHrefs: string[];\n}\n\n/**\n * Pure half of `applyGlobalStyleTokens`: compute the exact CSS custom\n * properties (and webfont hrefs) a settings object maps to, without touching\n * any DOM. This is what lets a host SERVER-render a theme with the same vars\n * the bundle applies on mount — both sides call this one function, so the\n * values cannot drift (drift = unstyled flash or hydration noise).\n *\n * Includes the explicit `heading_font` / `body_font` resolution that\n * `mountTheme` historically layered on top: any string value for those two\n * ids resolves through the registry (or passes verbatim) so a picked font\n * gets a real stack even when it isn't a known token.\n */\nexport function computeGlobalStyleTokens(\n globalSettings: GlobalSettings,\n): ComputedStyleTokens {\n const cssVars: Record<string, string> = {};\n const fontHrefs: string[] = [];\n if (!globalSettings || typeof globalSettings !== \"object\") {\n return { cssVars, fontHrefs };\n }\n\n const pushHref = (href?: string) => {\n if (href && !fontHrefs.includes(href)) fontHrefs.push(href);\n };\n\n for (const [key, value] of Object.entries(globalSettings)) {\n if (!key || key.startsWith(\"__\")) continue;\n\n // color_scheme / color_scheme_group → object of role:color\n if (value && typeof value === \"object\" && !Array.isArray(value)) {\n for (const [role, c] of Object.entries(value as Record<string, unknown>)) {\n if (isColorValue(c)) cssVars[`--scheme-${key}-${role}`] = c;\n }\n continue;\n }\n\n if (isColorValue(value)) {\n cssVars[`--theme-${key}`] = value.trim();\n const role = COLOR_ROLE_ALIASES[key];\n if (role) cssVars[`--theme-color-${role}`] = value.trim();\n continue;\n }\n\n if (isFontToken(value)) {\n const entry = FONT_REGISTRY[value];\n cssVars[`--theme-${key}`] = entry.stack;\n const role = FONT_ROLE_ALIASES[key];\n if (role) cssVars[`--theme-font-${role}`] = entry.stack;\n pushHref(entry.href);\n continue;\n }\n\n // Plain scalar (layout values like page_width \"1240px\", spacing, etc.).\n if (typeof value === \"string\" || typeof value === \"number\") {\n const v = String(value).trim();\n if (v) cssVars[`--theme-${key}`] = v;\n }\n }\n\n // Explicit heading/body resolution (formerly done by mountTheme's effect):\n // non-registry font names fall through the scalar branch verbatim above;\n // these two ids always get the resolved stack + webfont.\n for (const id of [\"heading_font\", \"body_font\"] as const) {\n const value = (globalSettings as Record<string, unknown>)[id];\n if (typeof value === \"string\" && value.trim()) {\n cssVars[`--theme-${id}`] = lookupFontStack(value);\n pushHref(FONT_REGISTRY[value]?.href);\n }\n }\n\n // Derived logo shape/size tokens (--theme-logo-box / -radius / -clip) so\n // host-rendered surfaces (e.g. the checkout header) can mirror the storefront\n // logo. No-op unless `logo_shape` is an actual shape.\n const gs = globalSettings as Record<string, unknown>;\n const logoTokens = logoStyleTokens(\n typeof gs.logo_shape === \"string\" ? gs.logo_shape : undefined,\n typeof gs.logo_size === \"string\" ? gs.logo_size : undefined,\n );\n for (const [k, v] of Object.entries(logoTokens)) cssVars[k] = v;\n\n return { cssVars, fontHrefs };\n}\n\n/**\n * Map a store's global settings onto CSS custom properties on `el`. Call on\n * mount and on every `applyDraft` (live preview). No-op when `el` or the\n * settings are missing. Reserved `__`-prefixed keys (e.g. `__translations`)\n * are skipped. Thin DOM shell over `computeGlobalStyleTokens`.\n */\nexport function applyGlobalStyleTokens(\n globalSettings: GlobalSettings,\n el: HTMLElement | null | undefined,\n): void {\n if (!el || !globalSettings || typeof globalSettings !== \"object\") return;\n const { cssVars, fontHrefs } = computeGlobalStyleTokens(globalSettings);\n const style = el.style;\n for (const [prop, value] of Object.entries(cssVars)) {\n style.setProperty(prop, value);\n }\n for (const href of fontHrefs) injectFontLink(href);\n}\n","\"use client\";\n\n/**\n * `mountTheme(el, ctx, renderApp)` — the canonical V3 bundle entry helper.\n *\n * ## Why this exists\n *\n * Every theme bundle exports `mount(el, ctx): MountResult`. Historically each\n * theme hand-wrote that function, and the wiring it needs is non-trivial and\n * easy to get wrong:\n *\n * 1. **Forward the real catalog.** The host ships the page's products /\n * collections in `ctx.page.data` (home + listing routes) and the product\n * in `ctx.page.data.product` (PDP). A theme that doesn't pass these into\n * `NuMuProvider` (+ wrap the PDP in `<ProductProvider>`) sees\n * `useProducts()` / `useProductOptional()` return empty on a REAL store —\n * so product sections render \"No products yet\" or fall back to demo data\n * on a stocked merchant. This was the single most common BYOT bug:\n * only bon-younes wired it; the other 13 themes dropped the catalog.\n *\n * 2. **Apply global style tokens.** Merchant-chosen colors/fonts live in\n * `themeSettings.global_settings`; they only paint if the bundle calls\n * `applyGlobalStyleTokens` on its mount root (and resolves font tokens\n * to real stacks + injects the webfont link). Themes that skipped this\n * ignored every color/font picker.\n *\n * 3. **Forward navigation.** `useNavigation(handle)` only resolves the\n * header/footer menus the host pre-resolved if the bundle passes\n * `ctx.navigation` into `NuMuProvider`.\n *\n * 4. **Live-preview + lifecycle.** The customizer streams draft settings via\n * the host's `applyDraft`; the bundle must hold them in state and re-paint\n * the style tokens on every draft. And it must return a `MountResult`\n * (`cleanup` + `applyDraft`) the host's `ByotThemeBoundary` understands.\n *\n * `mountTheme` does all of that once, so a theme's `main.tsx` collapses to:\n *\n * ```tsx\n * import { mountTheme } from \"@numueg/theme-sdk\";\n * export function mount(el, ctx) {\n * return mountTheme(el, ctx, ({ currentTemplate }) =>\n * <ThemeApp currentTemplate={currentTemplate} />,\n * );\n * }\n * ```\n *\n * The theme owns only its section list (`ThemeApp`). Everything in the list\n * above is handled here — fix it once, every theme benefits.\n *\n * ## Both ctx shapes\n *\n * The host (numu-storefront `ByotThemeBoundary`) passes\n * `{ themeSettings, storeData, page, locale, demo, navigation }`. Older / dev\n * contexts used `{ store, currentTemplate }`. We normalise both so a bundle\n * built against this helper works regardless of which host calls it.\n */\n\nimport {\n StrictMode,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useState,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { createRoot, hydrateRoot, type Root } from \"react-dom/client\";\n\nimport { NuMuProvider } from \"./components/NuMuProvider\";\nimport { ProductProvider } from \"./components/ProductProvider\";\nimport { CollectionProvider } from \"./components/CollectionProvider\";\nimport { applyGlobalStyleTokens } from \"./utils/styleTokens\";\nimport type {\n Store,\n Cart,\n Customer,\n Product,\n Collection,\n} from \"./types/entities\";\nimport type { ThemeSettingsV3, MountResult } from \"./types/theme\";\nimport type { MenuItemData } from \"./contexts\";\n\n/** Minimal page descriptor the host forwards in the mount context. */\nexport interface ThemeMountPage {\n type?: string;\n handle?: string;\n title?: string;\n data?: Record<string, unknown>;\n /**\n * Resolved alternate template key for this page (e.g. `\"product.wholesale\"`)\n * when the storefront routed it to a template suffix. `mountTheme` forwards\n * it to `NuMuProvider` so a theme reads it via `usePage()?.template`. Absent\n * for pages on their default template. Additive/optional.\n */\n template?: string;\n}\n\n/**\n * The mount context a host (or dev harness) passes to a bundle's `mount`.\n * Accepts both the current storefront shape (`storeData`/`page`) and the\n * legacy/dev shape (`store`/`currentTemplate`); `mountTheme` normalises them.\n */\nexport interface ThemeMountContext {\n // Current storefront contract\n storeData?: Store;\n page?: ThemeMountPage;\n // Legacy / dev contract\n store?: Store;\n currentTemplate?: string;\n // Common\n themeSettings: ThemeSettingsV3;\n initialCart?: Cart;\n customer?: Customer | null;\n locale?: string;\n translations?: Record<string, string>;\n /** AUTHORITATIVE marketplace-preview flag from the host (true only for the\n * catalog \"Try theme\" preview). Themes with demo-image fallbacks gate on\n * it so a real installed store never shows demo imagery. */\n demo?: boolean;\n /** Store navigation menus keyed by handle, resolved server-side. */\n navigation?: Record<string, MenuItemData[]>;\n /**\n * Host signal that the container already holds server-rendered HTML for\n * this exact ctx (produced via `createApp` from `defineThemeEntry`).\n * `mountTheme` then adopts it with `hydrateRoot` instead of re-rendering\n * from scratch. Ignored when the container is empty, so a host can pass\n * it optimistically and still get a plain client mount on SSR failure.\n */\n hydrate?: boolean;\n [extra: string]: unknown;\n}\n\n/** Arguments handed to a theme's render callback on every (re)render. */\nexport interface ThemeRenderArgs {\n /** Active template key — \"home\" | \"product\" | \"collection\" | \"cart\" | … */\n currentTemplate: string;\n /** Marketplace-preview flag (see ThemeMountContext.demo). */\n demo: boolean;\n /** The raw host page descriptor (type/handle/data), or null. */\n page: ThemeMountPage | null;\n /** Normalised store record (never undefined). */\n store: Store;\n /** Live theme settings (reflects customizer drafts via applyDraft). */\n themeSettings: ThemeSettingsV3;\n}\n\ninterface DraftHandle {\n applyDraft: (next: ThemeSettingsV3) => void;\n}\n\n/** Normalise the two ctx shapes' store slot; never return undefined — SDK\n * code reads `store.currency` without optional chaining and would throw.\n * Also maps the storefront's snake_case `default_currency` onto `currency`\n * when the latter is missing (pre-0.3 scaffolds did this per-theme; doing\n * it here keeps server render and client hydrate byte-identical). */\nfunction pickStore(ctx: ThemeMountContext): Store {\n const s = ctx.storeData ?? ctx.store;\n if (s) {\n const raw = s as Store & { default_currency?: string };\n if (!raw.currency && raw.default_currency) {\n return { ...raw, currency: raw.default_currency };\n }\n return s;\n }\n return {\n id: \"unknown\",\n name: \"Store\",\n slug: \"store\",\n currency: \"EGP\",\n default_language: \"en\",\n use_nextjs_storefront: true,\n } as Store;\n}\n\n/** Resolve the active template from either contract, defaulting to \"home\". */\nfunction pickTemplate(ctx: ThemeMountContext): string {\n if (typeof ctx.currentTemplate === \"string\" && ctx.currentTemplate) {\n return ctx.currentTemplate;\n }\n const pageType = ctx.page?.type;\n if (typeof pageType === \"string\" && pageType) return pageType;\n return \"home\";\n}\n\n/** Resolve the demo flag: explicit host flag wins; else infer from empty\n * templates (the marketplace preview ships none → render bundled preset). */\nfunction pickDemo(ctx: ThemeMountContext, themeSettings: ThemeSettingsV3): boolean {\n if (typeof ctx.demo === \"boolean\") return ctx.demo;\n const t = themeSettings.templates;\n return !t || Object.keys(t).length === 0;\n}\n\n/**\n * Wrap the theme app in the singular-entity providers the current route\n * supplies. A PDP ships `page.data.product` → ProductProvider (so\n * useProduct() resolves); a collection route ships `page.data.collection`\n * → CollectionProvider (so useCollection()/useCollectionOptional() resolve\n * the active collection's name + products). Listing/home routes ship\n * neither and the app renders unwrapped.\n */\nfunction wrapEntityProviders(\n app: ReactNode,\n pageData: { product?: Product; collection?: Collection },\n): ReactNode {\n let inner = app;\n if (pageData.collection) {\n inner = (\n <CollectionProvider collection={pageData.collection}>\n {inner}\n </CollectionProvider>\n );\n }\n if (pageData.product) {\n inner = <ProductProvider product={pageData.product}>{inner}</ProductProvider>;\n }\n return inner;\n}\n\n/**\n * Bridge that holds live draft settings, re-applies global style tokens on\n * every change, and wires the full provider stack (catalog + nav) around the\n * theme's app. Exposes `applyDraft` so the host can stream customizer edits.\n */\nconst ThemeMountBridge = forwardRef<\n DraftHandle,\n {\n ctx: ThemeMountContext;\n /** Null when rendered off-DOM (`createApp` for server rendering); the\n * style-token effect is a no-op there — the host SSRs the same vars\n * via `computeGlobalStyleTokens`. */\n mountEl: HTMLElement | null;\n renderApp: (args: ThemeRenderArgs) => ReactNode;\n }\n>(function ThemeMountBridge({ ctx, mountEl, renderApp }, ref) {\n const [themeSettings, setThemeSettings] = useState<ThemeSettingsV3>(\n ctx.themeSettings,\n );\n useImperativeHandle(\n ref,\n () => ({\n applyDraft: (next) =>\n setThemeSettings((prev) => (prev === next ? prev : next)),\n }),\n [],\n );\n\n // Global settings (colors/fonts/layout) → CSS custom properties on the\n // mount root. Re-runs on every draft so the customizer's live preview\n // re-paints as a merchant drags a color or picks a font.\n // (applyGlobalStyleTokens resolves heading/body fonts to real stacks and\n // injects webfont links — see computeGlobalStyleTokens, which is the\n // single source of truth shared with hosts that SSR these vars.)\n useEffect(() => {\n if (!mountEl) return;\n const gs = (themeSettings.global_settings ?? {}) as Record<string, unknown>;\n applyGlobalStyleTokens(gs, mountEl);\n }, [themeSettings, mountEl]);\n\n const store = pickStore(ctx);\n const template = pickTemplate(ctx);\n const demo = pickDemo(ctx, themeSettings);\n\n // Real catalog the host forwards: home/listing routes ship\n // page.data.{products,collections}; the PDP ships page.data.product.\n // Feeding these into NuMuProvider (+ ProductProvider) is what makes\n // useProducts()/useProduct() return the merchant's ACTUAL catalog.\n const pageData = (ctx.page?.data ?? {}) as {\n products?: Product[];\n collections?: Collection[];\n collection?: Collection;\n product?: Product;\n };\n\n const app = renderApp({\n currentTemplate: template,\n demo,\n page: ctx.page ?? null,\n store,\n themeSettings,\n });\n\n return (\n <NuMuProvider\n store={store}\n themeSettings={themeSettings}\n initialCart={ctx.initialCart}\n customer={ctx.customer}\n locale={ctx.locale}\n translations={ctx.translations}\n navigation={ctx.navigation}\n initialProducts={pageData.products}\n initialCollections={pageData.collections}\n currentTemplate={template}\n pageTemplate={ctx.page?.template}\n >\n {wrapEntityProviders(app, pageData)}\n </NuMuProvider>\n );\n});\n\n/**\n * Build the canonical theme element tree for a ctx. BOTH render paths go\n * through here — `mountTheme` (client mount/hydrate) and `createApp`\n * (host-side `renderToString`) — so the server markup and the hydration\n * tree are the same React tree by construction. `mountEl` is a prop, not\n * DOM output, so it differing between server (null) and client (the\n * container) cannot cause a hydration mismatch.\n */\nexport function buildThemeElement(\n ctx: ThemeMountContext,\n mountEl: HTMLElement | null,\n renderApp: (args: ThemeRenderArgs) => ReactNode,\n ref?: (h: DraftHandle | null) => void,\n): ReactElement {\n return (\n <StrictMode>\n <ThemeMountBridge ctx={ctx} mountEl={mountEl} renderApp={renderApp} ref={ref} />\n </StrictMode>\n );\n}\n\n/**\n * Mount a V3 theme. Owns the React root, the provider stack (catalog + nav +\n * style tokens), and the live-preview draft cycle. Returns the host-contract\n * `MountResult` (`cleanup` + `applyDraft`).\n *\n * When the host passes `ctx.hydrate === true` and the container already\n * holds server-rendered HTML (produced by this theme's `createApp` with the\n * identical ctx), the tree is adopted via `hydrateRoot` — no re-render, no\n * flash. An empty container downgrades to a plain client mount so hosts can\n * pass the flag optimistically.\n *\n * @param el the host-supplied container element\n * @param ctx the mount context (either host or legacy/dev shape)\n * @param renderApp returns the theme's section tree for the current args\n */\nexport function mountTheme(\n el: HTMLElement,\n ctx: ThemeMountContext,\n renderApp: (args: ThemeRenderArgs) => ReactNode,\n): MountResult {\n const handleRef = { current: null as DraftHandle | null };\n const element = buildThemeElement(ctx, el, renderApp, (h) => {\n handleRef.current = h;\n });\n\n const shouldHydrate = ctx.hydrate === true && el.firstElementChild !== null;\n let root: Root;\n if (shouldHydrate) {\n root = hydrateRoot(el, element);\n } else {\n root = createRoot(el);\n root.render(element);\n }\n\n return {\n applyDraft: (next) => handleRef.current?.applyDraft(next),\n cleanup: () => {\n root.unmount();\n handleRef.current = null;\n },\n };\n}\n","\"use client\";\n\n/**\n * `defineThemeEntry(renderApp)` — one-call theme entry that yields BOTH\n * halves of the V3 contract from a single component:\n *\n * - `mount(el, ctx)` — the client entry every host already calls\n * (now hydration-aware via `ctx.hydrate`).\n * - `createApp(ctx)` — the same React tree as a plain element, so the\n * host can `renderToString(createApp(ctx))` on the\n * server and ship real HTML before any JS runs.\n *\n * ```tsx\n * // src/main.tsx\n * import { defineThemeEntry } from \"@numueg/theme-sdk\";\n *\n * const entry = defineThemeEntry(({ currentTemplate }) => (\n * <ThemeApp currentTemplate={currentTemplate} />\n * ));\n *\n * export const mount = entry.mount;\n * export const createApp = entry.createApp;\n * ```\n *\n * Why both MUST come from one definition: hydration only succeeds when the\n * server markup and the client tree are identical. Routing both through\n * `buildThemeElement` makes that true by construction — a theme cannot\n * accidentally ship a `createApp` that disagrees with its `mount`.\n *\n * Themes that only export `mount` keep working exactly as before; they are\n * simply never server-rendered (the host detects the missing `createApp`\n * and falls back to today's client-only mount).\n */\n\nimport type { ReactElement, ReactNode } from \"react\";\n\nimport {\n buildThemeElement,\n mountTheme,\n type ThemeMountContext,\n type ThemeRenderArgs,\n} from \"./mount\";\nimport type { MountResult } from \"./types/theme\";\n\n/** The pair of entry points a V3 theme bundle exports. */\nexport interface ThemeEntry {\n /** Client entry — host contract `mount(el, ctx): MountResult`. */\n mount: (el: HTMLElement, ctx: ThemeMountContext) => MountResult;\n /**\n * Server entry — returns the exact element tree `mount` would render,\n * for host-side `renderToString`. Must stay side-effect free: no DOM\n * access happens until React effects run (which they don't on the\n * server).\n */\n createApp: (ctx: ThemeMountContext) => ReactElement;\n}\n\nexport function defineThemeEntry(\n renderApp: (args: ThemeRenderArgs) => ReactNode,\n): ThemeEntry {\n return {\n mount: (el, ctx) => mountTheme(el, ctx, renderApp),\n createApp: (ctx) => buildThemeElement(ctx, null, renderApp),\n };\n}\n","\"use client\";\n\nimport { createElement, type ElementType, type ReactNode } from \"react\";\nimport { useLocalization } from \"../hooks/useLocalization\";\nimport { useShop } from \"../hooks/useShop\";\nimport { useCurrency } from \"../hooks/useCurrency\";\n\ninterface MoneyProps {\n /** Amount in major units (e.g. dollars, not cents). */\n amount: number;\n /** ISO-4217 currency code. Defaults to the active store's currency. */\n currency?: string;\n /**\n * When the same product has both a sale price and a compare-at price,\n * pass the higher (compare-at) value here and we'll render it with a\n * strike-through next to the active price. Skipped when undefined or\n * <= the main amount.\n */\n compareAt?: number;\n className?: string;\n /** Custom HTML element tag — defaults to `span`. */\n as?: ElementType;\n}\n\n/**\n * <Money amount={49.99} /> — formatted price, locale-aware.\n *\n * Wraps useLocalization().formatMoney so theme code stops re-implementing\n * Intl.NumberFormat. Renders inline with `dir=\"auto\"` so the digits\n * flow naturally in RTL (Arabic) without flipping the currency symbol.\n *\n * Multi-currency: when the store has `auto_convert` on and the caller did NOT\n * pin an explicit `currency`, the amount is presented in the visitor's\n * SELECTED currency (converted via the shared rates from `useCurrency()`). A\n * `<CurrencySwitcher>` change therefore re-renders every `<Money>` on the page\n * without a reload. An explicit `currency` prop means \"this amount is already\n * in that currency\" — it is respected and never converted.\n *\n * Usage:\n * <Money amount={product.price} compareAt={product.compare_at_price} />\n */\nexport function Money({\n amount,\n currency,\n compareAt,\n className,\n as = \"span\",\n}: MoneyProps) {\n const { formatMoney } = useLocalization();\n const shop = useShop();\n const { selected, base, autoConvert, convert } = useCurrency();\n\n const shouldConvert =\n autoConvert && !currency && !!selected && selected !== base;\n const ccy = shouldConvert ? selected : currency || shop?.currency;\n // convert() works in cents; Money's amount is major units — round-trip\n // through cents so currencies with minor units convert correctly.\n const toDisplay = (major: number): number =>\n shouldConvert ? convert(Math.round(major * 100), selected) / 100 : major;\n\n const showCompare = compareAt != null && compareAt > amount;\n\n const children: ReactNode[] = [\n <span key=\"amt\">{formatMoney(toDisplay(amount), ccy)}</span>,\n ];\n if (showCompare) {\n children.push(\" \");\n children.push(\n <s key=\"cmp\" style={{ opacity: 0.6 }}>\n {formatMoney(toDisplay(compareAt), ccy)}\n </s>,\n );\n }\n\n return createElement(\n as,\n { className, dir: \"auto\" },\n children,\n );\n}\n","import type { CSSProperties } from \"react\";\n\n/**\n * Non-destructive image framing transform (focal / zoom / rotation).\n *\n * An image setting value may carry optional `transform` metadata\n * (`{ url, alt, transform }`). The original asset is never modified — the\n * storefront reproduces the framing purely from these numbers via CSS, so the\n * SAME uploaded image can be framed differently per placement (hero vs card).\n *\n * Hoisted into the SDK (was duplicated in every theme's `_shared.ts` and in\n * the merchant-hub editor's `imageTransform.ts`). The editor copy MUST stay\n * equivalent so its preview matches the storefront render exactly.\n */\nexport interface ImageTransform {\n v: 1;\n focal?: { x: number; y: number }; // 0..1, default center\n zoom?: number; // 1..4, default 1\n rotation?: number; // degrees, default 0\n fit?: \"cover\" | \"contain\";\n}\n\nconst _clampT = (n: number, lo: number, hi: number): number =>\n Math.min(hi, Math.max(lo, Number.isFinite(n) ? n : lo));\n\n/** Read the transform off an image setting value (string | {url,alt,transform}). */\nexport function asImageTransform(v: unknown): ImageTransform | undefined {\n if (v && typeof v === \"object\" && \"transform\" in v) {\n const t = (v as { transform?: unknown }).transform;\n if (t && typeof t === \"object\") return t as ImageTransform;\n }\n return undefined;\n}\n\n/**\n * CSS reproducing the transform on an `<img>` that fills a fixed-aspect,\n * overflow-hidden frame. Default fit is `cover` (Shopify-style: the image\n * fills its frame, cropping to the focal point) — pass `\"contain\"` only for\n * placements that must show the whole image (e.g. a logo).\n *\n * **No transform → empty object.** An inline style beats a className, so\n * returning `{ objectFit: fit }` here would silently override a placement's\n * own `object-contain` / `object-none` class on every untransformed image —\n * which is most merchant images. The section's className stays in charge; a\n * caller that needs a guaranteed fit supplies it itself, e.g.\n * `{ objectFit: fit, ...applyImageTransform(t, fit) }` (see `HeroMedia`).\n * This matches `Image.tsx`'s untransformed branch and the behaviour every\n * theme's local copy has shipped with.\n */\nexport function applyImageTransform(\n t: ImageTransform | undefined | null,\n fit: \"cover\" | \"contain\" = \"cover\",\n): CSSProperties {\n if (!t) return {};\n const fx = Math.round(_clampT(t.focal?.x ?? 0.5, 0, 1) * 1e4) / 100;\n const fy = Math.round(_clampT(t.focal?.y ?? 0.5, 0, 1) * 1e4) / 100;\n const zoom = _clampT(t.zoom ?? 1, 1, 4);\n const rot = (((t.rotation ?? 0) % 360) + 360) % 360;\n const effFit = t.fit ?? fit;\n const style: CSSProperties = {\n transform: `scale(${zoom}) rotate(${rot}deg)`,\n transformOrigin: `${fx}% ${fy}%`,\n objectFit: effFit,\n };\n if (effFit === \"cover\") style.objectPosition = `${fx}% ${fy}%`;\n return style;\n}\n\n/**\n * focalSrc — build a URL for a server-side, focal-point-aware image transform.\n *\n * OPT-IN helper. A theme that wants a bandwidth-efficient SMART CROP for a big\n * image (typically a hero) calls this to point the <img src> at the storefront's\n * `/api/image-transform` endpoint with focal/aspect params. The endpoint honors\n * them only when Cloudflare Image Resizing is enabled on the zone\n * (NUMU_CF_IMAGE_RESIZING=1); otherwise it gracefully ignores them and serves a\n * plain resized image — so the theme's CSS `applyImageTransform` framing remains\n * the correctness baseline either way. This is purely a perf optimization.\n *\n * Returns a RELATIVE path (`/api/image-transform?...`) — the SDK runs\n * same-origin inside the storefront, matching how <Form>/useShop build URLs.\n *\n * @example\n * <img\n * src={focalSrc(hero.url, { width: 1600, focal: t?.focal, aspect: \"16/9\" })}\n * style={applyImageTransform(t, \"cover\")} // CSS still frames as fallback\n * />\n */\nexport interface FocalSrcOptions {\n /** Target width in px (e.g. 1600 for a desktop hero). Required for a crop. */\n width?: number;\n /** Focal point, normalized 0..1 (0.5,0.5 = center). */\n focal?: { x?: number; y?: number };\n /** Target aspect ratio \"W/H\" (e.g. \"16/9\"); drives the crop box height. */\n aspect?: string;\n /** Crop mode. Default \"cover\". */\n fit?: \"cover\" | \"contain\";\n /** Quality 1..100. */\n quality?: number;\n /** Output format. */\n format?: \"webp\" | \"avif\" | \"jpeg\" | \"jpg\" | \"png\";\n}\n\nconst clamp01 = (n: number) => Math.min(1, Math.max(0, n));\n\n/**\n * Does the HOST honor server-side crop params (`fp-x`/`fp-y`/`ar`/`fit`)?\n *\n * The storefront's `/api/image-transform` only acts on them when Cloudflare\n * Image Resizing is enabled (`NUMU_CF_IMAGE_RESIZING=1`); with CF off it\n * DROPS them and forwards `url`+`w`+`q` to `/_next/image`. So on every store\n * running today, a URL carrying `&ar=4/5&fit=cover` fetches byte-for-byte the\n * same image as the width-only URL — the params are inert.\n *\n * Inert is not free. A URL that differs from the width-only form is a\n * different cache key, so it misses the host's `<link rel=preload as=image>`\n * for the hero (which is width-only by construction — the host can't know a\n * theme's `mobileAspect`). Measured on vionne: the mobile hero was preloaded\n * at high priority, discarded, and re-requested 6.9 s later once the theme\n * hydrated — the single largest contributor to an 18.7 s mobile LCP.\n *\n * So: emit crop params only when the host says it will honor them. The\n * storefront sets `__NUMU_CF_IMAGE_RESIZING__` (see the storefront's\n * RuntimeImportMap) from the same env var the route reads, which keeps the\n * URL we build and the transform the server performs in lockstep. Absent the\n * flag we assume off — the safe default, since that's the configuration every\n * store runs and CSS `applyImageTransform` frames the image regardless.\n *\n * Read through `globalThis` so the value is identical under the SSR worker\n * and in the browser (a `typeof window` check would diverge and produce a\n * hydration mismatch on `src` the moment CF is switched on).\n */\nfunction hostHonorsCropParams(): boolean {\n return (\n (globalThis as { __NUMU_CF_IMAGE_RESIZING__?: boolean })\n .__NUMU_CF_IMAGE_RESIZING__ === true\n );\n}\n\nexport function focalSrc(\n url: string | null | undefined,\n options: FocalSrcOptions = {},\n): string {\n if (!url) return \"\";\n // data: URIs and already-transformed URLs pass through untouched.\n if (url.startsWith(\"data:\") || /[?&](fp-x|fp-y)=/.test(url)) return url;\n\n const crop = hostHonorsCropParams();\n const p = new URLSearchParams();\n p.set(\"url\", url);\n if (options.width) p.set(\"w\", String(Math.round(options.width)));\n if (crop && options.focal?.x != null) p.set(\"fp-x\", String(clamp01(options.focal.x)));\n if (crop && options.focal?.y != null) p.set(\"fp-y\", String(clamp01(options.focal.y)));\n if (crop && options.aspect) p.set(\"ar\", options.aspect);\n if (crop && options.fit) p.set(\"fit\", options.fit);\n if (options.quality) p.set(\"q\", String(Math.min(100, Math.max(1, Math.round(options.quality)))));\n if (options.format) p.set(\"f\", options.format.toLowerCase());\n\n return `/api/image-transform?${p.toString()}`;\n}\n","\"use client\";\n\nimport type { CSSProperties, ImgHTMLAttributes } from \"react\";\nimport { applyImageTransform, type ImageTransform } from \"../utils/imageTransform\";\n\ninterface ImageProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, \"src\" | \"srcSet\"> {\n src: string | undefined | null;\n alt: string;\n /**\n * Comma-separated breakpoints for the `sizes` attribute. Default\n * matches a typical responsive grid:\n * \"(min-width: 1024px) 25vw, (min-width: 640px) 50vw, 100vw\"\n */\n sizes?: string;\n /**\n * When true (default), generate a `srcSet` with several widths.\n * Disable for above-the-fold hero images where you want a single\n * source under direct theme control.\n */\n responsive?: boolean;\n /**\n * Loading strategy. Default \"lazy\" matches Shopify themes; pass\n * \"eager\" for above-the-fold imagery.\n */\n loading?: \"eager\" | \"lazy\";\n /**\n * Above-the-fold? When true, forces loading=\"eager\" + fetchPriority=\"high\"\n * (overrides `loading`). Use on the hero / LCP image. Default false.\n */\n priority?: boolean;\n /**\n * Shopify-style frame. When set (e.g. \"3/4\", \"16/9\", \"1/1\") the image is\n * wrapped in a fixed-aspect, overflow-hidden box and the `<img>` fills it.\n * Combined with `objectFit=\"cover\"` (the default) this guarantees the image\n * ALWAYS fits its frame — no letterboxing, no overflow — cropping to the\n * focal point. Omit to render a bare `<img>` (legacy behavior).\n */\n aspectRatio?: string;\n /**\n * How the image fills its box. Default \"cover\" (fill + crop) — the merchant\n * never sees a letterboxed/squashed image. Use \"contain\" for logos/badges\n * that must show in full.\n */\n objectFit?: \"cover\" | \"contain\" | \"fill\" | \"scale-down\" | \"none\";\n /** CSS object-position (e.g. \"50% 50%\"). Ignored if `transform` is set. */\n objectPosition?: string;\n /**\n * Non-destructive focal/zoom/rotation metadata from the image setting value\n * (`asImageTransform(setting)`). When present it drives object-fit +\n * object-position + scale/rotate so the editor preview and the live render\n * match exactly. Overrides `objectFit`/`objectPosition`.\n */\n transform?: ImageTransform | null;\n}\n\nconst DEFAULT_WIDTHS = [320, 480, 640, 768, 1024, 1280, 1600, 1920];\n\n/**\n * Build a srcSet string from a base image URL by appending a width\n * query param. Works for any CDN that honors `?w=` (R2 image-resizing,\n * Cloudflare Images, Imgix-compatibles). Hosts that ignore the param\n * just serve the original; not a regression.\n *\n * If the URL already has query params we preserve them; if it already\n * has a width directive we pass through unchanged (assume the theme\n * author knows what they want).\n */\nfunction buildSrcSet(src: string, widths: number[] = DEFAULT_WIDTHS): string {\n if (/[?&]w=\\d+/.test(src)) return \"\";\n const sep = src.includes(\"?\") ? \"&\" : \"?\";\n return widths.map((w) => `${src}${sep}w=${w} ${w}w`).join(\", \");\n}\n\n/**\n * <Image> — drop-in replacement for `<img>` with srcSet + lazy loading\n * defaults. Themes should use this everywhere they'd otherwise write a\n * raw `<img>` so merchant-uploaded images get responsive variants and\n * lazy loading without per-section work.\n *\n * If `src` is empty/null, renders a placeholder div so the layout\n * doesn't shift while a merchant configures images in the customizer.\n */\nexport function Image({\n src,\n alt,\n sizes = \"(min-width: 1024px) 25vw, (min-width: 640px) 50vw, 100vw\",\n responsive = true,\n loading = \"lazy\",\n priority = false,\n aspectRatio,\n objectFit,\n objectPosition,\n transform,\n className,\n style,\n ...rest\n}: ImageProps) {\n // Frame mode: a fixed-aspect, overflow-hidden wrapper the <img> fills. This\n // is what guarantees \"the image always fits its frame\" regardless of the\n // uploaded image's own aspect ratio.\n const framed = Boolean(aspectRatio);\n\n if (!src) {\n const placeholder = (\n <div\n className={framed ? undefined : className}\n role=\"img\"\n aria-label={alt}\n style={{\n backgroundColor: \"rgba(0,0,0,0.05)\",\n display: \"block\",\n width: \"100%\",\n height: framed ? \"100%\" : undefined,\n ...(framed ? {} : style),\n }}\n />\n );\n if (!framed) return placeholder;\n return (\n <span\n className={className}\n style={{ display: \"block\", aspectRatio, overflow: \"hidden\", ...style }}\n >\n {placeholder}\n </span>\n );\n }\n\n const srcSet = responsive ? buildSrcSet(src) : undefined;\n // Above-the-fold hero: eager + high fetch priority, overriding `loading`.\n const effLoading = priority ? \"eager\" : loading;\n\n // Resolve the fit styling. An explicit transform wins (focal/zoom/rotate).\n // Inside a frame, default to cover so the image always fills it. Without a\n // frame, only apply a fit when the caller explicitly asked — preserving the\n // legacy bare-<img> behavior (and never overriding a className like\n // `object-contain` with an inline style).\n const effFit = objectFit ?? (framed ? \"cover\" : undefined);\n const fitStyle: CSSProperties = transform\n ? applyImageTransform(transform, effFit === \"contain\" ? \"contain\" : \"cover\")\n : {\n ...(effFit ? { objectFit: effFit } : {}),\n ...(objectPosition ? { objectPosition } : {}),\n };\n\n const img = (\n <img\n src={src}\n alt={alt}\n srcSet={srcSet || undefined}\n sizes={srcSet ? sizes : undefined}\n loading={effLoading}\n fetchPriority={priority ? \"high\" : undefined}\n decoding=\"async\"\n className={framed ? undefined : className}\n style={\n framed\n ? { width: \"100%\", height: \"100%\", display: \"block\", ...fitStyle }\n : { ...fitStyle, ...style }\n }\n {...rest}\n />\n );\n\n if (!framed) return img;\n return (\n <span\n className={className}\n style={{\n display: \"block\",\n position: \"relative\",\n width: \"100%\",\n aspectRatio,\n overflow: \"hidden\",\n ...style,\n }}\n >\n {img}\n </span>\n );\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type {\n CSSProperties,\n ImgHTMLAttributes,\n ReactEventHandler,\n} from \"react\";\nimport {\n applyImageTransform,\n focalSrc,\n type FocalSrcOptions,\n type ImageTransform,\n} from \"../utils/imageTransform\";\n\n/**\n * Width ladder for hero srcSet. MUST be a subset of the storefront's\n * `next.config.ts` images.deviceSizes = [640,768,1024,1280,1920]. On the\n * default (Cloudflare-off) path /api/image-transform 302s to /_next/image,\n * which returns HTTP 400 for ANY width not in deviceSizes. When CF Image\n * Resizing is on, CF accepts arbitrary widths — so this safe subset works on\n * both paths. (Do NOT add 2400/3200 here without also adding them to deviceSizes.)\n */\nconst HERO_WIDTHS = [640, 768, 1024, 1280, 1920];\n/** Default mobile breakpoint (px) — matches Tailwind `md`. */\nconst DEFAULT_BREAKPOINT = 768;\n/** Base width requested for the rendered desktop / mobile `<img src>` fallback. */\nconst DESKTOP_BASE_WIDTH = 1920;\nconst MOBILE_BASE_WIDTH = 1280;\n\nexport interface HeroMediaProps\n extends Omit<ImgHTMLAttributes<HTMLImageElement>, \"src\" | \"srcSet\" | \"alt\" | \"style\"> {\n /** Desktop (primary) image URL. */\n src: string | null | undefined;\n alt: string;\n /** Desktop focal/zoom/rotation (`asImageTransform(setting)`). */\n transform?: ImageTransform | null;\n /** Optional mobile art-direction image. When set → swaps below `breakpoint`. */\n mobileSrc?: string | null;\n /** Mobile focal/zoom/rotation. Falls back to the desktop transform's focal. */\n mobileTransform?: ImageTransform | null;\n /** Server-crop box aspect for desktop, e.g. \"16/9\". Match the theme container. */\n desktopAspect?: string;\n /** Server-crop box aspect for mobile, e.g. \"4/5\". */\n mobileAspect?: string;\n /** object-fit. Default \"cover\". Pass \"contain\" for letterboxed art. */\n fit?: \"cover\" | \"contain\";\n /** Above-the-fold? Default true → loading=eager + fetchPriority=high. */\n priority?: boolean;\n /** sizes attribute. Hero is full-width → default \"100vw\". */\n sizes?: string;\n /** Below this width (px) the mobile image is used. Default 768. */\n breakpoint?: number;\n /**\n * Pre-fetch the alternate (off-breakpoint) image so a Desktop↔Mobile swap is an\n * instant cache hit instead of a flash-and-fetch. Default true. Set false to save\n * the one extra background request when smooth resizing isn't worth the bandwidth.\n */\n preloadAlternate?: boolean;\n className?: string;\n style?: CSSProperties;\n}\n\nfunction heroSrcSet(url: string, opts: Omit<FocalSrcOptions, \"width\">): string {\n return HERO_WIDTHS\n .map((w) => `${focalSrc(url, { width: w, ...opts })} ${w}w`)\n .join(\", \");\n}\n\n/**\n * <HeroMedia> — above-the-fold hero image for V3 themes.\n *\n * - Real responsive srcSet routed through /api/image-transform (resize + AVIF/WebP,\n * + focal smart-crop when Cloudflare Image Resizing is enabled).\n * - LCP perf defaults: loading=eager + fetchPriority=high (disable via priority={false}).\n * - Non-destructive focal/zoom/rotation framing via applyImageTransform.\n * - Optional MOBILE art-direction image: a different bitmap below `breakpoint`.\n *\n * ## Why matchMedia, not <picture><source media>\n * Art direction is resolved in JS (a `matchMedia` listener) rather than a native\n * `<picture><source media>`. A native `<picture>` does NOT reliably re-pick its source\n * when an EMBEDDED preview resizes its iframe — exactly what the theme editor's\n * Desktop/Mobile toggle does — so the hero would stay stuck on the desktop bitmap at\n * mobile sizes. CSS media queries DO re-evaluate on that resize (Tailwind flips the\n * container to portrait), and `matchMedia` shares that engine, so the swap is\n * deterministic. The state initialises from `matchMedia` so the first client paint is\n * already correct (V3 themes mount client-side) — no desktop→mobile flash on phones.\n *\n * ## Smooth swap\n * The off-breakpoint image is pre-warmed (low priority, after paint) so toggling the\n * breakpoint — the editor switch, or a window resize — paints from cache instantly\n * instead of fetching on demand. See `preloadAlternate`.\n *\n * When `mobileSrc` is omitted this is a single responsive <img> filling its parent —\n * the theme keeps its own wrapper/sizing, identical to a raw <img> plus srcSet + perf.\n */\nexport function HeroMedia({\n src,\n alt,\n transform,\n mobileSrc,\n mobileTransform,\n desktopAspect,\n mobileAspect,\n fit = \"cover\",\n priority = true,\n sizes = \"100vw\",\n breakpoint = DEFAULT_BREAKPOINT,\n preloadAlternate = true,\n className,\n style,\n ...rest\n}: HeroMediaProps) {\n const hasMobile = !!mobileSrc;\n const mobileQuery = `(max-width: ${breakpoint - 1}px)`;\n\n // Which art-direction image is active. Initialised from matchMedia so the FIRST\n // client paint is already correct (no desktop→mobile flash on phones), then kept in\n // sync by a change listener (the reliable replacement for <picture> source re-pick).\n const [isMobile, setIsMobile] = useState(\n () =>\n hasMobile &&\n typeof window !== \"undefined\" &&\n typeof window.matchMedia === \"function\" &&\n window.matchMedia(mobileQuery).matches,\n );\n\n // If the storefront's /api/image-transform refuses the image host (it's not on the\n // allow-list → 403), the optimized request fails. Fall back to the RAW url so the\n // hero still renders — never a regression vs a plain <img>. The optimize path\n // (resize/AVIF) still applies for allow-listed hosts (the common case). The theme's\n // own onError (if any) only fires once the RAW url ALSO fails (genuinely broken).\n const [rawFallback, setRawFallback] = useState(false);\n const { onError: themeOnError, ...imgRest } = rest;\n const handleError: ReactEventHandler<HTMLImageElement> = (e) => {\n if (!rawFallback) setRawFallback(true);\n else themeOnError?.(e);\n };\n\n // Keep `isMobile` in sync with the viewport. matchMedia change events fire on every\n // resize that crosses the breakpoint, INCLUDING an iframe resize — so the editor's\n // Desktop/Mobile toggle deterministically swaps the bitmap.\n useEffect(() => {\n if (!hasMobile || typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") {\n return;\n }\n const mq = window.matchMedia(mobileQuery);\n const sync = () => setIsMobile(mq.matches);\n sync();\n mq.addEventListener?.(\"change\", sync);\n return () => mq.removeEventListener?.(\"change\", sync);\n }, [hasMobile, mobileQuery]);\n\n // Framing inputs (safe to compute every render; cheap + pure).\n const desktopFocal = transform?.focal;\n const mobileFocal = mobileTransform?.focal ?? desktopFocal;\n // Desktop server-crop params (focal/aspect/fit) are requested ONLY when an explicit\n // desktopAspect is set. A full-bleed desktop hero (no aspect) stays width-only\n // — byte-matching the host's width-only <link rel=preload> so the preload is credited.\n // CSS applyImageTransform still frames the desktop focal either way.\n //\n // The MOBILE branch below always asks for them, which used to mean the mobile hero\n // URL could never match that preload. It matches now regardless: focalSrc drops all\n // four params unless the host advertises `__NUMU_CF_IMAGE_RESIZING__` — and with CF\n // off (every store today) the endpoint was discarding them anyway. See focalSrc.\n const desktopCrop: Omit<FocalSrcOptions, \"width\"> = desktopAspect\n ? { focal: desktopFocal, aspect: desktopAspect, fit }\n : {};\n const mobileCrop: Omit<FocalSrcOptions, \"width\"> = {\n focal: mobileFocal,\n aspect: mobileAspect,\n fit,\n };\n\n // Pre-warm the ALTERNATE image (low priority, after paint) so the breakpoint swap is\n // an instant cache hit. The active image is already fetched by the rendered <img>;\n // re-warming it would be a no-op cache hit, so we only warm the off-breakpoint one.\n useEffect(() => {\n if (!preloadAlternate || !hasMobile || !src || !mobileSrc) return;\n if (typeof window === \"undefined\" || typeof window.Image !== \"function\") return;\n const altUrl = isMobile\n ? rawFallback\n ? src\n : focalSrc(src, { width: DESKTOP_BASE_WIDTH, ...desktopCrop })\n : rawFallback\n ? mobileSrc\n : focalSrc(mobileSrc, { width: MOBILE_BASE_WIDTH, ...mobileCrop });\n if (!altUrl) return;\n const im = new window.Image();\n im.onerror = () => {};\n try {\n (im as unknown as { fetchPriority?: string }).fetchPriority = \"low\";\n } catch {\n /* not supported — ignore */\n }\n im.decoding = \"async\";\n im.src = altUrl;\n if (typeof im.decode === \"function\") im.decode().catch(() => {});\n // desktopCrop/mobileCrop are derived from the deps below; intentionally omitted.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [preloadAlternate, hasMobile, src, mobileSrc, isMobile, rawFallback]);\n\n if (!src) {\n // Placeholder so layout doesn't shift while the merchant configures the image.\n return (\n <div\n className={className}\n role=\"img\"\n aria-label={alt}\n style={{ width: \"100%\", height: \"100%\", backgroundColor: \"rgba(0,0,0,0.05)\", ...style }}\n />\n );\n }\n\n const useMobile = hasMobile && isMobile;\n const activeUrl = useMobile ? (mobileSrc as string) : src;\n const activeCrop = useMobile ? mobileCrop : desktopCrop;\n const activeBase = useMobile ? MOBILE_BASE_WIDTH : DESKTOP_BASE_WIDTH;\n const activeSrc = rawFallback\n ? activeUrl\n : focalSrc(activeUrl, { width: activeBase, ...activeCrop });\n const activeSrcSet = rawFallback ? undefined : heroSrcSet(activeUrl, activeCrop);\n // A hero always fills its frame, so the fit is supplied here rather than by\n // `applyImageTransform` — that helper returns {} for an untransformed image\n // so it never overrides a section's own object-fit class (see its docs).\n const fitStyle: CSSProperties = {\n objectFit: fit,\n ...applyImageTransform(useMobile ? mobileTransform ?? transform : transform, fit),\n };\n\n return (\n <img\n src={activeSrc}\n srcSet={activeSrcSet}\n sizes={activeSrcSet ? sizes : undefined}\n alt={alt}\n loading={priority ? \"eager\" : \"lazy\"}\n fetchPriority={priority ? \"high\" : undefined}\n decoding=\"async\"\n onError={handleError}\n className={className}\n style={{ width: \"100%\", height: \"100%\", display: \"block\", ...fitStyle, ...style }}\n {...imgRest}\n />\n );\n}\n","\"use client\";\n\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { useThemeSettings } from \"../hooks/useThemeSettings\";\nimport { useShop } from \"../hooks/useShop\";\nimport { logoImgStyle } from \"../utils/logoStyle\";\n\nexport interface LogoProps {\n /** Explicit logo URL; falls back to global_settings.logo_url then shop.logo_url. */\n src?: string | null;\n /** Alt text; falls back to the brand name / shop name. */\n alt?: string;\n /** Overrides `global_settings.logo_shape` (none/square/rounded/circle/triangle). */\n shape?: string;\n /** Overrides `global_settings.logo_size` (small/medium/large). */\n size?: string;\n className?: string;\n style?: CSSProperties;\n /** Rendered when there is no logo URL (e.g. brand-name text). */\n fallback?: ReactNode;\n}\n\nconst str = (v: unknown): string => (typeof v === \"string\" ? v : \"\");\n\nconst NONE_HEIGHT: Record<string, number> = { small: 28, medium: 36, large: 48 };\n\n/**\n * Engine-level store logo. Reads `logo_url`, `logo_shape`, and `logo_size` from\n * the theme's global settings (overridable via props), and renders a plain\n * `<img>` with the chosen shape/size applied via inline styles — so it works in\n * any theme regardless of its CSS setup and keeps **animated GIF logos playing**\n * under every shape. Renders `fallback` (or nothing) when no logo is set.\n */\nexport function Logo({\n src,\n alt,\n shape,\n size,\n className,\n style,\n fallback,\n}: LogoProps) {\n const settings = useThemeSettings();\n const shop = useShop();\n const g = (settings?.global_settings ?? {}) as Record<string, unknown>;\n\n const url = str(src) || str(g.logo_url) || shop?.logo_url || \"\";\n const resolvedShape = shape || str(g.logo_shape) || \"none\";\n const resolvedSize = size || str(g.logo_size) || \"small\";\n const altText = alt || str(g.brand_name) || shop?.name || \"\";\n\n if (!url) return <>{fallback ?? null}</>;\n\n const shaped = resolvedShape !== \"none\";\n const imgStyle: CSSProperties = shaped\n ? { ...logoImgStyle(resolvedShape, resolvedSize), ...style }\n : {\n height: NONE_HEIGHT[resolvedSize] ?? NONE_HEIGHT.small,\n width: \"auto\",\n objectFit: \"contain\",\n ...style,\n };\n\n return (\n <img\n src={url}\n alt={altText}\n className={className}\n style={imgStyle}\n loading=\"eager\"\n />\n );\n}\n","\"use client\";\n\nimport type { AnchorHTMLAttributes, MouseEvent, ReactNode } from \"react\";\nimport { useShop } from \"../hooks/useShop\";\n\ninterface LinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, \"href\"> {\n /**\n * Path relative to the storefront root, e.g. \"/products/foo\",\n * \"/collections/all\", \"/cart\", \"/pages/about\". External URLs (with\n * a protocol) are passed through unchanged.\n */\n to: string;\n children: ReactNode;\n}\n\nconst ABSOLUTE_URL = /^[a-z]+:|^\\/\\//i;\n\n/**\n * Event dispatched on `window` when a Link is clicked and eligible for\n * client-side (soft) navigation. `detail.href` is the target path.\n *\n * Contract: the event is CANCELABLE. A host that can perform soft\n * navigation (e.g. the Next.js storefront routing through its client\n * router) listens for it and calls `event.preventDefault()` to claim\n * the navigation. If no listener claims it, the Link falls back to\n * default anchor behavior — a normal full-page navigation — so themes\n * running under hosts without the bridge (older storefronts, the CLI\n * dev server, static previews) keep working unchanged.\n */\nexport const NAVIGATE_EVENT = \"numu:navigate\";\n\nexport interface NavigateEventDetail {\n href: string;\n}\n\n/**\n * Ask the host to soft-navigate to `href`. Returns true when a host\n * listener claimed the navigation (the caller should suppress its own\n * default behavior), false when no handler is present (the caller\n * should fall back to a full navigation). Exposed for themes that\n * navigate programmatically (e.g. after a search submit).\n */\nexport function requestNavigate(href: string): boolean {\n if (typeof window === \"undefined\") return false;\n const event = new CustomEvent<NavigateEventDetail>(NAVIGATE_EVENT, {\n detail: { href },\n cancelable: true,\n });\n // dispatchEvent returns false when a listener called preventDefault()\n // — i.e. the host claimed the navigation.\n return !window.dispatchEvent(event);\n}\n\n/**\n * Route-aware <Link>. Themes write paths as `/products/<slug>` (matches\n * the production subdomain root). The storefront proxy rewrites those\n * under `/<subdomain>/...` in dev path-segment routing; in production\n * the subdomain hostname does the same job at the edge.\n *\n * Navigation is a two-tier contract:\n * 1. Soft (preferred): on an eligible plain left-click we dispatch a\n * cancelable NAVIGATE_EVENT. A router-aware host claims it with\n * preventDefault() and performs a client-side transition — React,\n * the SDK runtime, and the evaluated theme bundle all stay warm,\n * so page-to-page moves skip the full document reload + remount.\n * 2. Hard (fallback): no listener claims the event → default anchor\n * behavior, a normal full-page navigation. Identical to the\n * pre-0.10 behavior, so themes never break on hosts without the\n * bridge.\n *\n * Soft navigation is only attempted for storefront-internal paths and\n * unmodified left-clicks: external URLs (protocol or `//`), hash-only\n * anchors, modified clicks (ctrl/cmd/shift/alt — \"open in new tab\"),\n * non-left buttons, `target` other than `_self`, and `download` links\n * all keep default browser behavior.\n */\nexport function Link({ to, children, onClick, ...rest }: LinkProps) {\n const shop = useShop();\n const isAbsolute = ABSOLUTE_URL.test(to);\n let href = to;\n if (!isAbsolute && shop && !to.startsWith(\"/\")) {\n // Relative paths like \"products/foo\" treated as siblings of current.\n // Most themes use leading slashes; this is a defensive fallback.\n href = `/${to}`;\n }\n\n const handleClick = (e: MouseEvent<HTMLAnchorElement>) => {\n // The theme's own handler runs first and can preventDefault() to\n // opt out of navigation entirely (e.g. quick-view interception).\n onClick?.(e);\n if (e.defaultPrevented) return;\n // Only unmodified left-clicks on same-document targets are soft-nav\n // candidates; everything else keeps native browser semantics.\n if (e.button !== 0) return;\n if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;\n if (rest.target && rest.target !== \"_self\") return;\n if (rest.download !== undefined) return;\n if (isAbsolute) return;\n // Guard on `to` (the author-written path), not `href`: the shop\n // normalizer above prefixes bare paths with \"/\", turning \"#reviews\"\n // into \"/#reviews\" — which would slip past an href-only check and\n // wrongly soft-nav an in-page anchor.\n if (to.startsWith(\"#\") || href.startsWith(\"#\")) return;\n if (requestNavigate(href)) e.preventDefault();\n };\n\n return (\n <a href={href} onClick={handleClick} {...rest}>\n {children}\n </a>\n );\n}\n","\"use client\";\n\nimport { useState, type ButtonHTMLAttributes, type ReactNode } from \"react\";\nimport { useCart } from \"../hooks/useCart\";\nimport type { Product, ProductVariant } from \"../types/entities\";\n\ninterface AddToCartButtonProps\n extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, \"onClick\" | \"disabled\"> {\n product: Product;\n variant?: ProductVariant;\n quantity?: number;\n /**\n * Picker axes to persist on the cart line ({Color: \"Black\"}). Optional —\n * when omitted, the button reads the live useVariantSelection state for\n * this product from the SDK registry, so existing themes get the variant\n * label end-to-end (cart → checkout → order → email) with no changes.\n */\n selectedOptions?: Record<string, string>;\n /** Custom labels — fallbacks are English defaults. */\n label?: ReactNode;\n loadingLabel?: ReactNode;\n soldOutLabel?: ReactNode;\n errorLabel?: ReactNode;\n /** Called after successful addition. Useful for analytics events. */\n onAdded?: (product: Product, variant?: ProductVariant) => void;\n}\n\n/**\n * Themed Add-to-Cart button with built-in loading/disabled/error states.\n *\n * Wraps useCart().addItem and tracks its own UX state machine:\n * idle → adding → idle (or → error briefly, then idle)\n *\n * Renders a regular `<button>` so themes style it with whatever class\n * names they want — we only own the disabled/aria-busy logic and label\n * swaps. If the variant (or product) is out of stock, button is\n * disabled and shows soldOutLabel.\n *\n * Doesn't trap navigation — for \"buy now\" flows that should redirect\n * to checkout, themes wrap this in their own `<a>` after onAdded.\n */\nexport function AddToCartButton({\n product,\n variant,\n quantity = 1,\n selectedOptions,\n label = \"Add to cart\",\n loadingLabel = \"Adding…\",\n soldOutLabel = \"Sold out\",\n errorLabel = \"Couldn't add — try again\",\n onAdded,\n ...rest\n}: AddToCartButtonProps) {\n const { addItem } = useCart();\n const [state, setState] = useState<\"idle\" | \"adding\" | \"error\">(\"idle\");\n\n const inStock = variant?.in_stock ?? product.in_stock;\n if (!inStock) {\n return (\n <button\n type=\"button\"\n disabled\n aria-disabled=\"true\"\n {...rest}\n >\n {soldOutLabel}\n </button>\n );\n }\n\n async function handleClick() {\n if (state === \"adding\") return;\n setState(\"adding\");\n try {\n // addItem itself falls back to the live useVariantSelection state for\n // this product when no explicit axes are passed; the backend only uses\n // them when the variant row can't name itself (empty option_values).\n await addItem(product.id, variant?.id, quantity, selectedOptions);\n setState(\"idle\");\n onAdded?.(product, variant);\n } catch {\n setState(\"error\");\n // Auto-clear after 2s so the merchant can try again.\n setTimeout(() => setState(\"idle\"), 2000);\n }\n }\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={state === \"adding\"}\n aria-busy={state === \"adding\"}\n {...rest}\n >\n {state === \"adding\"\n ? loadingLabel\n : state === \"error\"\n ? errorLabel\n : label}\n </button>\n );\n}\n","\"use client\";\n\nimport {\n Component,\n type HTMLAttributes,\n type ReactNode,\n} from \"react\";\n\ninterface SectionProps extends HTMLAttributes<HTMLElement> {\n /** Section instance id (the order key in templates). Required for the\n * customizer's click-to-select to work. */\n id: string;\n /** Section type as registered in the theme registry / schemas. */\n type: string;\n /** Section group id (header / footer / announcement-bar) when this\n * section is mounted inside a group rather than a page template. */\n groupId?: string;\n /** Override the fallback shown when this section throws. Defaults to\n * a small inline error card (visible to the merchant in the customizer,\n * invisible to live shoppers — see CSS comment below). */\n errorFallback?: ReactNode;\n children: ReactNode;\n}\n\n// ── Section ErrorBoundary ───────────────────────────────────────────────────\n//\n// One thrown section used to take down the whole bundle's React tree —\n// every other section unmounted along with the bad one, leaving the\n// merchant with a blank storefront and no way to find the offender.\n//\n// We catch render/lifecycle errors at the per-section seam so a bug in\n// \"Hero v2\" doesn't break the perfectly fine \"Newsletter\" section\n// rendered on the same page. The boundary:\n//\n// 1. Logs the error + section context to console.error so the dev\n// console makes the offender obvious.\n// 2. Re-renders a fallback (defaults to a small error card; theme\n// can override via the `errorFallback` prop).\n// 3. Posts `numu:editor:section-error` to window.parent so the V3\n// customizer can highlight the offending section in its tree.\n//\n// The boundary is INSIDE the `<section data-section-id>` wrapper, so\n// the data attributes still let the customizer click-select the bad\n// section even when its body crashed — merchants can delete it.\n\ninterface BoundaryState {\n error: Error | null;\n}\n\ninterface SectionErrorBoundaryProps {\n sectionId: string;\n sectionType: string;\n fallback: ReactNode;\n children: ReactNode;\n}\n\nclass SectionErrorBoundary extends Component<\n SectionErrorBoundaryProps,\n BoundaryState\n> {\n state: BoundaryState = { error: null };\n\n static getDerivedStateFromError(error: Error): BoundaryState {\n return { error };\n }\n\n componentDidCatch(error: Error) {\n // Match the host's <ByotThemeBoundary> log shape so the prefix is\n // recognizable in the iframe console even when both boundaries fire.\n console.error(\n `[Section ${this.props.sectionType}#${this.props.sectionId}] threw:`,\n error,\n );\n if (typeof window !== \"undefined\" && window.parent !== window) {\n try {\n window.parent.postMessage(\n {\n type: \"numu:editor:section-error\",\n payload: {\n sectionId: this.props.sectionId,\n sectionType: this.props.sectionType,\n message: error.message,\n },\n },\n \"*\",\n );\n } catch {\n // Cross-origin postMessage with `*` is permissive enough that\n // this branch is for true edge cases (sandboxed iframe with\n // disallow-script). Nothing useful to do.\n }\n }\n }\n\n render() {\n if (this.state.error) return this.props.fallback;\n return this.props.children;\n }\n}\n\nfunction defaultSectionFallback(\n sectionType: string,\n sectionId: string,\n): ReactNode {\n return (\n <div\n role=\"alert\"\n data-numu-section-error=\"true\"\n style={{\n padding: \"1rem\",\n border: \"1px dashed #f87171\",\n background: \"#fef2f2\",\n color: \"#b91c1c\",\n fontFamily:\n \"system-ui, -apple-system, BlinkMacSystemFont, sans-serif\",\n fontSize: \"0.875rem\",\n lineHeight: 1.5,\n borderRadius: \"0.375rem\",\n margin: \"0.5rem 0\",\n }}\n >\n <div style={{ fontWeight: 600, marginBottom: \"0.25rem\" }}>\n Section failed to render\n </div>\n <div style={{ opacity: 0.9 }}>\n <code style={{ fontFamily: \"monospace\" }}>{sectionType}</code> threw\n an error. Check the browser console for details.\n </div>\n <div\n style={{\n opacity: 0.6,\n fontSize: \"0.75rem\",\n marginTop: \"0.25rem\",\n fontFamily: \"monospace\",\n }}\n >\n section #{sectionId}\n </div>\n </div>\n );\n}\n\n/**\n * <Section> — wrapper that emits the `data-section-id` / `data-section-type`\n * attributes the storefront's PreviewBridge needs to relay clicks back\n * to the V3 customizer for \"select section X\" navigation.\n *\n * Use this around the top-level element of every section component:\n *\n * export default function Hero({ settings, ...sectionMeta }) {\n * return (\n * <Section id={sectionMeta.id} type=\"hero\">\n * <h1>{settings.headline}</h1>\n * </Section>\n * );\n * }\n *\n * Without `data-section-id` on a real DOM ancestor, clicking anywhere\n * in the section in the customizer iframe falls through to the page\n * background and the merchant has to use the section list panel to\n * select sections — slow and confusing.\n *\n * Errors thrown by `children` are caught by an internal ErrorBoundary\n * so one bad section doesn't unmount its siblings. Customize the\n * fallback via `errorFallback`.\n */\nexport function Section({\n id,\n type,\n groupId,\n errorFallback,\n children,\n ...rest\n}: SectionProps) {\n return (\n <section\n data-section-id={id}\n data-section-type={type}\n data-group-id={groupId}\n {...rest}\n >\n <SectionErrorBoundary\n sectionId={id}\n sectionType={type}\n fallback={errorFallback ?? defaultSectionFallback(type, id)}\n >\n {children}\n </SectionErrorBoundary>\n </section>\n );\n}\n\ninterface BlockProps extends HTMLAttributes<HTMLDivElement> {\n /** Block instance id within its parent section. */\n id: string;\n type: string;\n /** Override the fallback shown when this block throws. */\n errorFallback?: ReactNode;\n children: ReactNode;\n}\n\n/**\n * <Block> — analog to <Section> for nested block selection. Same DOM\n * attribute contract; PreviewBridge reads `data-block-id` and reports\n * the block as selected when its child clicks bubble up.\n *\n * Wraps `children` in the same per-instance ErrorBoundary as <Section>\n * so a bad block within a section isolates its failure.\n */\nexport function Block({ id, type, errorFallback, children, ...rest }: BlockProps) {\n return (\n <div data-block-id={id} data-block-type={type} {...rest}>\n <SectionErrorBoundary\n sectionId={id}\n sectionType={type}\n fallback={errorFallback ?? defaultSectionFallback(type, id)}\n >\n {children}\n </SectionErrorBoundary>\n </div>\n );\n}\n","\"use client\";\n\nimport {\n useState,\n type FormEvent,\n type FormHTMLAttributes,\n type ReactNode,\n} from \"react\";\n\ninterface FormProps\n extends Omit<\n FormHTMLAttributes<HTMLFormElement>,\n \"onSubmit\" | \"method\" | \"action\" | \"children\" | \"onError\"\n > {\n /**\n * Endpoint to POST/etc. the form values to. Should be one of the\n * storefront's `/api/*` proxy routes — they handle CSRF + cookie\n * forwarding + idempotency on the way to FastAPI.\n */\n action: string;\n /**\n * HTTP method. POST is the typical theme use-case (newsletter,\n * contact, customer login, address create). GET is supported for\n * search-style forms.\n */\n method?: \"POST\" | \"GET\" | \"PUT\" | \"DELETE\";\n /**\n * Called with the JSON-decoded response body on success. Use to\n * trigger a toast, redirect, etc. Theme owns the UX.\n */\n onSuccess?: (response: unknown) => void;\n /**\n * Called with the Error on failure. Falls through to the default\n * error label otherwise.\n */\n onError?: (error: Error) => void;\n /**\n * Render-prop access to the in-flight state if the theme wants to\n * show its own loading / disabled / error UI. Default `children`\n * behavior just lets the form's inputs and submit button render —\n * we don't impose styling.\n */\n children?:\n | ReactNode\n | ((state: { submitting: boolean; error: Error | null }) => ReactNode);\n}\n\nconst ABSOLUTE_URL = /^[a-z]+:|^\\/\\//i;\n\nfunction readCsrfCookie(): string | null {\n if (typeof document === \"undefined\") return null;\n const m = document.cookie.match(/(?:^|;\\s*)numu_csrf=([^;]+)/);\n return m ? decodeURIComponent(m[1]) : null;\n}\n\nfunction newIdempotencyKey(): string {\n if (typeof crypto !== \"undefined\" && \"randomUUID\" in crypto) {\n return crypto.randomUUID();\n }\n return `${Date.now()}-${Math.random().toString(36).slice(2)}`;\n}\n\n/**\n * <Form action=\"/api/cart/add\" method=\"POST\" onSuccess={...}>\n *\n * Theme-friendly wrapper around `<form>` that handles:\n * - CSRF: reads `numu_csrf` cookie, sends as `x-numu-csrf` header on\n * every mutating request. Same wire format as <NuMuProvider>'s\n * cart machinery — interoperates seamlessly.\n * - Idempotency: mints a UUID per submit, sends as\n * `x-numu-idempotency-key`. Backend dedupes if it supports the\n * header (cart endpoints today; more later).\n * - Submit lifecycle: tracks `submitting` + `error` state and\n * either passes them to a render-prop child or wires them to a\n * submit-button's `disabled` automatically.\n * - Throws away page navigation: `onSubmit` calls preventDefault and\n * fetches via JSON. Themes that want classic POST-and-navigate\n * can drop down to a plain `<form>`.\n *\n * Refuses to submit to absolute URLs (must point at the storefront\n * itself or an `/api/*` proxy) so a misconfigured theme can't leak\n * customer data to a third party origin.\n */\nexport function Form({\n action,\n method = \"POST\",\n onSuccess,\n onError,\n children,\n ...rest\n}: FormProps) {\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n async function handleSubmit(e: FormEvent<HTMLFormElement>) {\n e.preventDefault();\n\n if (ABSOLUTE_URL.test(action)) {\n const err = new Error(\n `<Form action> must be a same-origin path (got \"${action}\"). ` +\n `Use a /api/* proxy route or your route handler.`,\n );\n setError(err);\n onError?.(err);\n return;\n }\n\n setSubmitting(true);\n setError(null);\n try {\n const formData = new FormData(e.currentTarget);\n const isMutation = method !== \"GET\";\n\n // Convert FormData → JSON. Themes can pass `data-numu-multipart=\"true\"`\n // on the form to opt into multipart instead (file uploads).\n const isMultipart =\n e.currentTarget.dataset?.numuMultipart === \"true\";\n\n const headers: Record<string, string> = {};\n if (!isMultipart) headers[\"Content-Type\"] = \"application/json\";\n if (isMutation) {\n const csrf = readCsrfCookie();\n if (csrf) headers[\"x-numu-csrf\"] = csrf;\n headers[\"x-numu-idempotency-key\"] = newIdempotencyKey();\n }\n\n let url = action;\n let body: BodyInit | undefined;\n if (method === \"GET\") {\n const params = new URLSearchParams();\n for (const [k, v] of formData.entries()) {\n if (typeof v === \"string\") params.append(k, v);\n }\n const sep = action.includes(\"?\") ? \"&\" : \"?\";\n url = `${action}${sep}${params.toString()}`;\n } else if (isMultipart) {\n body = formData;\n } else {\n const obj: Record<string, FormDataEntryValue> = {};\n for (const [k, v] of formData.entries()) obj[k] = v;\n body = JSON.stringify(obj);\n }\n\n const res = await fetch(url, { method, headers, body });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(\n `${method} ${action} failed: ${res.status} ${res.statusText}${\n text ? ` — ${text.slice(0, 200)}` : \"\"\n }`,\n );\n }\n const json = res.headers\n .get(\"content-type\")\n ?.includes(\"application/json\")\n ? await res.json()\n : await res.text();\n onSuccess?.(json);\n } catch (err) {\n const e2 = err instanceof Error ? err : new Error(String(err));\n setError(e2);\n onError?.(e2);\n } finally {\n setSubmitting(false);\n }\n }\n\n return (\n <form\n onSubmit={handleSubmit}\n method={method}\n action={action}\n aria-busy={submitting}\n {...rest}\n >\n {typeof children === \"function\"\n ? children({ submitting, error })\n : children}\n </form>\n );\n}\n","/**\n * Storefront route builders.\n *\n * The storefront's URL shape is platform knowledge, not theme knowledge: a\n * theme that hardcodes `/products/${slug}` has quietly taken a dependency on\n * the host's routing, and every copy of that template is a place the fleet can\n * disagree with the host. Centralising the templates here means a route change\n * is one edit rather than a fleet-wide grep.\n *\n * Hoisted out of the themes' `sections/_shared.ts`, where `productHref` was\n * hand-copied into 4 themes and their 4 scaffold templates.\n */\n\n/**\n * Link to a product detail page.\n *\n * Falls back to the product index when there's no identifier, so a card built\n * from incomplete data links somewhere useful instead of `/products/undefined`.\n */\nexport function productHref(slugOrId: string | undefined | null): string {\n if (!slugOrId) return \"/products\";\n return `/products/${slugOrId}`;\n}\n\n/**\n * Link to a collection page.\n *\n * Prefers the slug and falls back to the id, because a category with no slug\n * is common in practice and the bare template produces `/collections/undefined`\n * — a 404 the merchant sees as a broken menu item. Accepts either a category\n * object or a plain slug string so call sites don't have to unpack first.\n */\nexport function collectionHref(\n category: string | { slug?: string | null; id?: string | null } | null | undefined,\n): string {\n if (!category) return \"/collections\";\n if (typeof category === \"string\") {\n return category ? `/collections/${category}` : \"/collections\";\n }\n const key = category.slug || category.id;\n return key ? `/collections/${key}` : \"/collections\";\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport type { Product } from \"../types/entities\";\nimport { Image } from \"./Image\";\nimport { Money } from \"./Money\";\nimport { Link } from \"./Link\";\nimport { AddToCartButton } from \"./AddToCartButton\";\nimport { productHref } from \"../utils/routes\";\n\n/**\n * Opinionated product tile.\n *\n * Themes drop this anywhere a product list is needed — collection\n * pages, search results, recommendations, recently-viewed grids.\n * Renders image + title + price (with compare-at strike-through when\n * present) + an optional \"Sold out\" badge + AddToCartButton.\n *\n * The component is **unstyled by default** — it ships only structural\n * markup with stable class names. Themes provide the CSS. Class names\n * use a `numu-product-card__*` BEM convention so themes can target\n * pieces without grep-and-replace if NUMU later renames anything.\n *\n * Class hooks:\n * .numu-product-card — root <article>\n * .numu-product-card__link — wrapping <a>\n * .numu-product-card__media — image container\n * .numu-product-card__image — the <img> itself\n * .numu-product-card__badge — \"Sold out\" overlay\n * .numu-product-card__title — title <h3>\n * .numu-product-card__price — price wrapper\n * .numu-product-card__cta — CTA wrapper (AddToCartButton)\n *\n * Themes can override any piece by passing `slots`:\n * <ProductCard product={p} slots={{ price: <CustomPrice /> }} />\n *\n * For deeper customization, themes should compose the primitives\n * (Image / Money / Link / AddToCartButton) directly instead.\n */\nexport interface ProductCardSlots {\n /** Replaces the badge area (default: \"Sold out\" when out of stock, else nothing). */\n badge?: ReactNode;\n /** Replaces the title `<h3>` block. */\n title?: ReactNode;\n /** Replaces the price `<Money>` block. */\n price?: ReactNode;\n /** Replaces the AddToCartButton. Pass `null` to hide it. */\n cta?: ReactNode | null;\n}\n\nexport interface ProductCardProps {\n product: Product;\n /** Override the link target. Default: `/products/{slug}`. */\n href?: string;\n className?: string;\n slots?: ProductCardSlots;\n /**\n * Image sizing hint for the responsive srcSet. Default: a 4-up grid\n * sizing (~25vw at desktop, ~50vw at tablet, ~100vw at mobile).\n * Override when rendering in a different layout density.\n */\n imageSizes?: string;\n}\n\nfunction joinClass(...names: Array<string | undefined | null | false>): string {\n return names.filter(Boolean).join(\" \");\n}\n\nexport function ProductCard({\n product,\n href,\n className,\n slots,\n imageSizes,\n}: ProductCardProps) {\n // Same builder the themes use, so the card and a theme's own links can't\n // disagree about the product route.\n const target = href ?? productHref(product.slug);\n const firstImage = product.images?.[0];\n const inStock = product.in_stock;\n\n const badge =\n slots?.badge !== undefined\n ? slots.badge\n : inStock\n ? null\n : (\n <span className=\"numu-product-card__badge\">Sold out</span>\n );\n\n return (\n <article className={joinClass(\"numu-product-card\", className)}>\n <Link to={target} className=\"numu-product-card__link\">\n <div className=\"numu-product-card__media\">\n <Image\n src={firstImage?.url}\n alt={firstImage?.alt || product.name}\n sizes={imageSizes}\n className=\"numu-product-card__image\"\n />\n {badge}\n </div>\n {slots?.title ?? (\n <h3 className=\"numu-product-card__title\">{product.name}</h3>\n )}\n {slots?.price ?? (\n <div className=\"numu-product-card__price\">\n <Money\n amount={product.price}\n compareAt={product.compare_at_price}\n currency={product.currency}\n />\n </div>\n )}\n </Link>\n {slots?.cta === null\n ? null\n : (\n <div className=\"numu-product-card__cta\">\n {slots?.cta ?? <AddToCartButton product={product} />}\n </div>\n )}\n </article>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport type { Collection } from \"../types/entities\";\nimport { Image } from \"./Image\";\nimport { Link } from \"./Link\";\n\n/**\n * Opinionated collection tile.\n *\n * Renders a single collection's hero image + name + product count.\n * Used by collection-list sections, footer \"Featured collections\"\n * blocks, and search-result mixed views.\n *\n * Unstyled by default; themes ship the CSS. Class hooks:\n * .numu-collection-card — root <article>\n * .numu-collection-card__link — wrapping <a>\n * .numu-collection-card__media — image container\n * .numu-collection-card__image — the <img>\n * .numu-collection-card__title — title <h3>\n * .numu-collection-card__count — product count line\n */\nexport interface CollectionCardSlots {\n title?: ReactNode;\n /** Replaces the \"N products\" line. Pass null to hide it. */\n count?: ReactNode | null;\n}\n\nexport interface CollectionCardProps {\n collection: Collection;\n /** Override the link target. Default: `/collections/{slug}`. */\n href?: string;\n className?: string;\n slots?: CollectionCardSlots;\n imageSizes?: string;\n}\n\nfunction joinClass(...names: Array<string | undefined | null | false>): string {\n return names.filter(Boolean).join(\" \");\n}\n\nexport function CollectionCard({\n collection,\n href,\n className,\n slots,\n imageSizes,\n}: CollectionCardProps) {\n const target = href ?? `/collections/${collection.slug}`;\n const productCount =\n typeof collection.product_count === \"number\"\n ? collection.product_count\n : undefined;\n\n return (\n <article className={joinClass(\"numu-collection-card\", className)}>\n <Link to={target} className=\"numu-collection-card__link\">\n <div className=\"numu-collection-card__media\">\n <Image\n src={collection.image_url}\n alt={collection.name}\n sizes={imageSizes}\n className=\"numu-collection-card__image\"\n />\n </div>\n {slots?.title ?? (\n <h3 className=\"numu-collection-card__title\">{collection.name}</h3>\n )}\n {slots?.count === null\n ? null\n : (slots?.count ?? (\n productCount !== undefined && (\n <p className=\"numu-collection-card__count\">\n {productCount === 1 ? \"1 product\" : `${productCount} products`}\n </p>\n )\n ))}\n </Link>\n </article>\n );\n}\n","\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\n\n/**\n * <RichText html=... /> — sanitized HTML renderer.\n *\n * Wraps `dangerouslySetInnerHTML` so theme code stops calling it\n * directly with merchant-supplied content. Themes that need to render\n * rich-text fields (product descriptions, page bodies, blog articles,\n * policy bodies) go through this so an XSS in a single field can't\n * cross-contaminate the whole storefront.\n *\n * **Why a built-in allowlist sanitizer instead of DOMPurify?**\n * The audit plan called for DOMPurify, but adding it as a hard dep\n * inflates every theme bundle by ~12KB gzipped — and the merchant-\n * editable surface is small enough (a fixed set of formatting tags +\n * links + images) that a curated allowlist is both smaller AND easier\n * to reason about. If a theme needs richer sanitization (embeds,\n * iframes, MathML), it can import DOMPurify directly and pre-sanitize\n * before passing the result here.\n *\n * Allowed tags:\n * p, br, hr, h1-h6, blockquote, pre, code,\n * strong, b, em, i, u, s, sub, sup, mark,\n * ul, ol, li, dl, dt, dd,\n * a (href, target, rel only),\n * img (src, alt, width, height, loading only — http(s) URLs only),\n * table, thead, tbody, tr, th, td,\n * span, div (with class attribute only).\n *\n * Stripped:\n * <script>, <style>, <iframe>, <object>, <embed>, <link>, <meta>,\n * form/input, on*= handlers, javascript:/data: URLs, srcset on\n * <img> (we let the storefront's image-transform handle that\n * uniformly).\n */\nexport interface RichTextProps {\n html: string | null | undefined;\n className?: string;\n /** Element to render — defaults to `<div>`. Use `<article>` for body content. */\n as?: \"div\" | \"article\" | \"section\" | \"aside\";\n}\n\nconst ALLOWED_TAGS: ReadonlySet<string> = new Set([\n \"p\", \"br\", \"hr\",\n \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\",\n \"blockquote\", \"pre\", \"code\",\n \"strong\", \"b\", \"em\", \"i\", \"u\", \"s\", \"sub\", \"sup\", \"mark\",\n \"ul\", \"ol\", \"li\", \"dl\", \"dt\", \"dd\",\n \"a\", \"img\",\n \"table\", \"thead\", \"tbody\", \"tr\", \"th\", \"td\",\n \"span\", \"div\",\n]);\n\nconst ALLOWED_ATTRS_BY_TAG: Record<string, ReadonlySet<string>> = {\n a: new Set([\"href\", \"target\", \"rel\", \"class\", \"title\"]),\n img: new Set([\"src\", \"alt\", \"width\", \"height\", \"loading\", \"class\"]),\n span: new Set([\"class\"]),\n div: new Set([\"class\"]),\n p: new Set([\"class\"]),\n h1: new Set([\"class\"]), h2: new Set([\"class\"]), h3: new Set([\"class\"]),\n h4: new Set([\"class\"]), h5: new Set([\"class\"]), h6: new Set([\"class\"]),\n blockquote: new Set([\"class\"]),\n pre: new Set([\"class\"]),\n code: new Set([\"class\"]),\n ul: new Set([\"class\"]), ol: new Set([\"class\"]), li: new Set([\"class\"]),\n table: new Set([\"class\"]),\n thead: new Set([\"class\"]), tbody: new Set([\"class\"]),\n tr: new Set([\"class\"]), th: new Set([\"class\"]), td: new Set([\"class\"]),\n};\n\nconst URL_SAFE_PROTOCOLS = /^(https?|mailto|tel):/i;\n\nfunction isSafeUrl(url: string): boolean {\n const trimmed = url.trim();\n if (!trimmed) return false;\n // Relative paths are fine.\n if (trimmed.startsWith(\"/\") || trimmed.startsWith(\"#\") || trimmed.startsWith(\"?\")) {\n return true;\n }\n // Protocol-bearing — only http/https/mailto/tel.\n return URL_SAFE_PROTOCOLS.test(trimmed);\n}\n\n/**\n * Sanitize an HTML string against the allowlist above. Runs server-\n * AND client-side because rich-text fields are server-rendered for SEO.\n *\n * Implementation note: in the browser we use DOMParser (structural allowlist\n * — see `sanitizeHtmlClient`/`walk`). On the server (no DOM) we fall through\n * to `sanitizeHtmlServer`, a hardened regex denylist that strips dangerous\n * element blocks to a fixpoint, removes inline event handlers (incl.\n * slash-separated ones), and drops non-allowlisted `href`/`src` URLs. Themes\n * needing server-rendered rich content with edge-case structure should\n * sanitize on the API tier and pass already-safe HTML through.\n */\nexport function sanitizeHtml(input: string): string {\n if (!input) return \"\";\n if (typeof window === \"undefined\" || typeof DOMParser === \"undefined\") {\n return sanitizeHtmlServer(input);\n }\n return sanitizeHtmlClient(input);\n}\n\nfunction sanitizeHtmlClient(input: string): string {\n const doc = new DOMParser().parseFromString(\n `<div>${input}</div>`,\n \"text/html\",\n );\n const root = doc.body.firstElementChild;\n if (!root) return \"\";\n walk(root);\n return root.innerHTML;\n}\n\nfunction walk(node: Element): void {\n const children = Array.from(node.children);\n for (const child of children) {\n const tag = child.tagName.toLowerCase();\n if (!ALLOWED_TAGS.has(tag)) {\n // Replace forbidden tag with its sanitized text content. Drops\n // entire subtree if the tag is one we never want (script/style).\n if (tag === \"script\" || tag === \"style\" || tag === \"iframe\" || tag === \"object\" || tag === \"embed\") {\n child.remove();\n } else {\n const text = child.textContent || \"\";\n child.replaceWith(document.createTextNode(text));\n }\n continue;\n }\n // Strip disallowed attributes.\n const allowed = ALLOWED_ATTRS_BY_TAG[tag] || new Set<string>();\n for (const attr of Array.from(child.attributes)) {\n const name = attr.name.toLowerCase();\n // on*= handlers → always strip.\n if (name.startsWith(\"on\")) {\n child.removeAttribute(attr.name);\n continue;\n }\n if (!allowed.has(name)) {\n child.removeAttribute(attr.name);\n continue;\n }\n // URL-bearing attrs → protocol-check.\n if ((name === \"href\" || name === \"src\") && !isSafeUrl(attr.value)) {\n child.removeAttribute(attr.name);\n continue;\n }\n }\n // Anchor hardening: every external link gets rel=\"noopener noreferrer\"\n // when target=\"_blank\" is set. Stops reverse-tabnabbing without the\n // theme dev having to remember.\n if (tag === \"a\" && child.getAttribute(\"target\") === \"_blank\") {\n child.setAttribute(\"rel\", \"noopener noreferrer\");\n }\n walk(child);\n }\n}\n\n/**\n * Server-side fallback sanitizer — DOM-free, so it runs during SSR (this is\n * the string that ships in the FIRST paint before hydration upgrades to the\n * structural DOMParser walk). Being regex-based it can't be a full parser, so\n * it's hardened as a denylist that closes the known bypasses:\n *\n * (a) Inline event handlers: the separator before the `on…` name is a class\n * `[\\s/\"'<]`, not just `\\s`, so slash-separated handlers are caught —\n * `<img/onerror=alert(1)>` (no whitespace before `onerror`) previously\n * survived the `\\s+on\\w+=` pass entirely.\n * (b) Dangerous element blocks (`<script>`, `<style>`, `<iframe>`, …) are\n * stripped to a FIXPOINT (repeat until the string stops changing).\n * A single pass is defeatable by nesting —\n * `<scr<script></script>ipt>alert(1)</scr…ipt>` collapses into a fresh\n * `<script>` once the inner match is removed.\n * (c) `javascript:` / `data:` (and any non-allowlisted protocol) in\n * `href`/`src` are removed via `isSafeUrl` (allowlist: http(s), mailto,\n * tel, relative). The whole attribute is dropped when the value fails.\n *\n * The client path (`sanitizeHtmlClient`) remains the real allowlist — it walks\n * a parsed DOM and drops any tag/attribute not on the allowlist — and takes\n * over after mount. Themes needing richer SSR structure should sanitize on the\n * API tier and pass already-safe HTML through.\n */\nfunction sanitizeHtmlServer(input: string): string {\n if (!input) return \"\";\n let s = input;\n let prev: string;\n\n // (b) Strip dangerous element blocks + any standalone opener/closer/void of\n // document-scope tags, repeated to a fixpoint so nested/truncated markup\n // can't reconstitute an executable island after one pass.\n const DANGEROUS: RegExp[] = [\n /<script\\b[\\s\\S]*?<\\/script\\s*>/gi,\n /<style\\b[\\s\\S]*?<\\/style\\s*>/gi,\n /<iframe\\b[\\s\\S]*?<\\/iframe\\s*>/gi,\n /<object\\b[\\s\\S]*?<\\/object\\s*>/gi,\n /<embed\\b[\\s\\S]*?<\\/embed\\s*>/gi,\n /<\\/?(?:script|style|iframe|object|embed|link|meta|form|input)\\b[^>]*>/gi,\n ];\n do {\n prev = s;\n for (const re of DANGEROUS) s = s.replace(re, \"\");\n } while (s !== prev);\n\n // (a) Strip inline event handlers to a fixpoint, with a broadened separator\n // class so slash/quote-separated handlers are caught, not just space-led.\n const HANDLER = /[\\s/\"'<]on\\w+\\s*=\\s*(\"[^\"]*\"|'[^']*'|[^\\s>]+)/gi;\n do {\n prev = s;\n s = s.replace(HANDLER, \"\");\n } while (s !== prev);\n\n // (c) Strip non-allowlisted URLs (javascript:/data:/…) in href/src — the\n // whole attribute is dropped when isSafeUrl rejects the value.\n s = s.replace(\n /[\\s/\"'<](href|src)\\s*=\\s*(\"[^\"]*\"|'[^']*'|[^\\s>]+)/gi,\n (full: string, _attr: string, val: string) => {\n const cleaned = String(val).replace(/^['\"]|['\"]$/g, \"\");\n return isSafeUrl(cleaned) ? full : \"\";\n },\n );\n\n return s;\n}\n\nexport function RichText({ html, className, as = \"div\" }: RichTextProps) {\n // Hydration-stable two-pass sanitize: the FIRST client render must produce\n // the same string the server produced, so when the theme is server-rendered\n // (`createApp` + hydrateRoot) the dangerouslySetInnerHTML payloads match.\n // The regex pass and the DOMParser pass can legitimately differ on edge\n // cases (attribute ordering, entity normalisation), so we render the\n // server-algorithm output first everywhere and upgrade to the structural\n // DOMParser sanitize after mount.\n const [domReady, setDomReady] = useState(false);\n useEffect(() => {\n setDomReady(true);\n }, []);\n const safe = useMemo(\n () => (domReady ? sanitizeHtml(html || \"\") : sanitizeHtmlServer(html || \"\")),\n [html, domReady],\n );\n if (!safe) return null;\n const Tag = as;\n return (\n <Tag\n className={className}\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: safe }}\n />\n );\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useCurrency } from \"../hooks/useCurrency\";\n\n/**\n * <CurrencySwitcher /> — wired in Phase 6.\n *\n * Reads presentment currencies + the persisted selection from\n * `useCurrency()`, which talks to\n * `/api/storefront/store/{id}/currencies`. Changing the dropdown\n * writes the `numu_currency` cookie via the hook, which then\n * propagates to `<Money>`'s display.\n *\n * Renders nothing when the store offers only one currency — themes\n * can drop the component into a layout without conditional render.\n *\n * Pass `render` to take over the markup completely (e.g. a custom\n * dropdown component or a flag-icon grid).\n */\n\nexport interface CurrencySwitcherProps {\n className?: string;\n onSelect?: (currency: string) => void;\n render?: (state: {\n currencies: string[];\n current: string;\n onChange: (next: string) => void;\n }) => React.ReactNode;\n}\n\nexport function CurrencySwitcher({\n className,\n onSelect,\n render,\n}: CurrencySwitcherProps) {\n const { presentment, selected, setSelected, loading } = useCurrency();\n\n const handleChange = useCallback(\n (next: string) => {\n if (next === selected) return;\n setSelected(next);\n onSelect?.(next);\n },\n [selected, setSelected, onSelect],\n );\n\n // No alternatives, or still loading the list. We don't want to\n // briefly flash a 1-option dropdown while the API resolves.\n if (loading) return null;\n if (presentment.length <= 1) return null;\n\n if (render) {\n return (\n <>\n {render({\n currencies: presentment,\n current: selected,\n onChange: handleChange,\n })}\n </>\n );\n }\n\n return (\n <select\n className={className ?? \"numu-currency-switcher\"}\n value={selected}\n onChange={(e) => handleChange(e.target.value)}\n aria-label=\"Currency\"\n >\n {presentment.map((c) => (\n <option key={c} value={c}>\n {c}\n </option>\n ))}\n </select>\n );\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useShop } from \"../hooks/useShop\";\nimport { useLocalization } from \"../hooks/useLocalization\";\n\n/**\n * <LocaleSwitcher /> — language toggle for stores with multiple locales.\n *\n * v1 supports Arabic + English (the storefront's default_language gates\n * which one is the \"primary\"). This component:\n * - Reads `store.available_locales` (or falls back to\n * [default_language, \"en\"] for stores that haven't been migrated yet).\n * - Renders nothing when there's only one locale.\n * - On change, sets a `numu_locale` cookie + reloads the page so the\n * server-rendered layout picks up the new locale (the storefront\n * middleware reads the cookie and stamps `<html lang/dir>`\n * accordingly).\n *\n * Why a hard reload instead of client-side state swap:\n * Locale impacts SSR-rendered content (currency formatting, product\n * field translations, page metadata). Client-side toggling would\n * leave the SSR output inconsistent until the next navigation.\n * One reload trades a brief flicker for guaranteed correctness.\n */\n\nconst LANG_LABELS: Record<string, string> = {\n ar: \"العربية\",\n en: \"English\",\n fr: \"Français\",\n he: \"עברית\",\n fa: \"فارسی\",\n ur: \"اردو\",\n es: \"Español\",\n de: \"Deutsch\",\n};\n\nexport interface LocaleSwitcherProps {\n className?: string;\n onSelect?: (locale: string) => void;\n /** Custom renderer. Receives the resolved locale list + current selection. */\n render?: (state: {\n locales: string[];\n current: string;\n labelFor: (code: string) => string;\n onChange: (next: string) => void;\n }) => React.ReactNode;\n}\n\nexport function LocaleSwitcher({\n className,\n onSelect,\n render,\n}: LocaleSwitcherProps) {\n const shop = useShop();\n const { locale } = useLocalization();\n const available =\n (shop as unknown as { available_locales?: string[] }).available_locales || [];\n // Fallback for stores that don't yet expose available_locales: assume\n // the store's default_language plus English when they differ.\n const list =\n available.length > 0\n ? available\n : shop.default_language === \"en\"\n ? [\"en\"]\n : Array.from(new Set([shop.default_language, \"en\"]));\n\n const labelFor = useCallback((code: string): string => {\n return LANG_LABELS[code] || code.toUpperCase();\n }, []);\n\n const handleChange = useCallback(\n (next: string) => {\n if (next === locale) return;\n onSelect?.(next);\n if (typeof document !== \"undefined\") {\n const oneYear = 60 * 60 * 24 * 365;\n document.cookie = `numu_locale=${encodeURIComponent(next)}; path=/; max-age=${oneYear}; samesite=lax`;\n }\n // Hard reload so SSR re-runs with the new locale. Use replace()\n // so the locale toggle doesn't pollute browser back history.\n if (typeof window !== \"undefined\") {\n window.location.reload();\n }\n },\n [locale, onSelect],\n );\n\n if (list.length <= 1) return null;\n\n if (render) {\n return <>{render({ locales: list, current: locale, labelFor, onChange: handleChange })}</>;\n }\n\n return (\n <select\n className={className ?? \"numu-locale-switcher\"}\n value={locale}\n onChange={(e) => handleChange(e.target.value)}\n aria-label=\"Language\"\n >\n {list.map((l) => (\n <option key={l} value={l}>\n {labelFor(l)}\n </option>\n ))}\n </select>\n );\n}\n","\"use client\";\n\n/**\n * <EditableText> / <EditableImage> — V3 SDK editor-affordance markers.\n *\n * These are the \"I want to edit this\" hooks for V3 themes. They render\n * a normal element (span / img) on live storefronts, but inside the\n * customizer iframe they:\n *\n * 1. Stamp a `data-numu-editable` attribute so the storefront's\n * PreviewBridge can scope click-to-select to specific fields\n * (rather than the whole section).\n * 2. Show a subtle hover affordance (dotted underline / ring) so the\n * merchant discovers what's editable inline.\n * 3. Bubble up a `numu:editor:select-field` postMessage on click,\n * so the dashboard can scroll the matching setting input into\n * view + focus it.\n *\n * Editor mode is detected the same way PreviewBridge does — query\n * params `editor=v3` OR `preview=true`. Outside the editor, these are\n * pass-through `<span>` / `<img>` with no extra cost.\n *\n * Usage in a V3 section:\n *\n * import { EditableText, EditableImage } from \"@numueg/theme-sdk\";\n *\n * export default function Hero({ instance }: SectionProps) {\n * const { settings } = instance;\n * return (\n * <>\n * <EditableText\n * settingId=\"headline\"\n * sectionId={instance.id}\n * value={settings.headline}\n * as=\"h1\"\n * className=\"text-4xl\"\n * />\n * <EditableImage\n * settingId=\"hero_image\"\n * sectionId={instance.id}\n * src={settings.hero_image}\n * alt={settings.image_alt}\n * />\n * </>\n * );\n * }\n *\n * Why two components instead of one polymorphic `<Editable>`? Text and\n * image have different click semantics (text → focus the matching\n * setting; image → open the media picker) and different DOM shapes,\n * and we want the JSX to read naturally. Future field types (link,\n * color picker, video) get their own component pair.\n */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useMemo,\n useState,\n type ElementType,\n type HTMLAttributes,\n type ImgHTMLAttributes,\n type ReactNode,\n} from \"react\";\n\n// ─── Editor-mode detection ──────────────────────────────────────────────────\n\n/**\n * The detection runs lazily (after mount) to keep SSR HTML identical\n * to the first client paint. If we read window.location during render,\n * we'd return false on the server and true on the client → hydration\n * mismatch. By gating on a useEffect-set state, the initial paint\n * never adds editor-only attributes, and they appear on the second\n * paint (one tick later, after the bridge is awake anyway).\n */\nfunction useIsEditor(): boolean {\n const [isEditor, setIsEditor] = useState(false);\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n try {\n const params = new URLSearchParams(window.location.search);\n const flag =\n params.get(\"editor\") === \"v3\" || params.get(\"preview\") === \"true\";\n // The iframe-only check: the merchant's customizer renders this\n // bundle inside an iframe. On a \"plain\" preview tab (no parent\n // window), we keep the editor-mode markers off — they'd be\n // useless to a merchant browsing their own storefront in a\n // separate tab.\n const inFrame = window.parent !== window;\n setIsEditor(flag && inFrame);\n } catch {\n // No-op — SSR / sandboxed environments fall through to false.\n }\n }, []);\n return isEditor;\n}\n\n/**\n * Post a \"this field was clicked\" event to the dashboard so the editor\n * can scroll the matching setting input into view + focus it.\n *\n * Origin is `*` because the parent's origin varies (dev / staging /\n * prod / different merchant subdomains). The dashboard side enforces\n * origin matching for INBOUND messages from the iframe, so an\n * attacker can't spoof a select-field event by hijacking\n * postMessage — the dashboard's origin gate drops anything not from\n * the storefront's exact origin.\n */\nfunction postFieldSelected(\n sectionId: string,\n settingId: string,\n blockId?: string | null,\n): void {\n if (typeof window === \"undefined\") return;\n if (window.parent === window) return;\n try {\n window.parent.postMessage(\n {\n type: \"numu:editor:select-field\",\n payload: {\n sectionId,\n blockId: blockId ?? null,\n settingId,\n },\n },\n \"*\",\n );\n } catch {\n /* parent gone / sandboxed strictly — no-op */\n }\n}\n\n// ─── EditableText ───────────────────────────────────────────────────────────\n\nexport interface EditableTextProps\n extends Omit<HTMLAttributes<HTMLElement>, \"children\"> {\n /** The section instance id (key inside templates.<page>.sections). */\n sectionId: string;\n /** Optional block id when the field lives inside a section block. */\n blockId?: string | null;\n /** The setting key from the section's schema (e.g. \"headline\"). */\n settingId: string;\n /** The current text value (may be HTML for inline_richtext settings). */\n value: string | undefined | null;\n /**\n * Element to render. Defaults to `<span>` so the component is\n * inline-compatible. Pass \"h1\" / \"h2\" / \"p\" / \"div\" for block-level\n * usage.\n */\n as?: ElementType;\n /**\n * Set to true to render the value as HTML (for inline_richtext\n * settings whose stored form is `<b>Welcome</b>`). Defaults to false\n * — plain-text fields are rendered as a text node.\n */\n html?: boolean;\n /** Empty-state placeholder shown when value is \"\" / null. */\n placeholder?: ReactNode;\n}\n\nexport const EditableText = forwardRef<HTMLElement, EditableTextProps>(\n function EditableText(\n {\n sectionId,\n blockId,\n settingId,\n value,\n as: Component = \"span\",\n html = false,\n placeholder,\n className,\n onClick,\n style,\n ...rest\n },\n ref,\n ) {\n const isEditor = useIsEditor();\n\n const handleClick = useCallback(\n (e: React.MouseEvent<HTMLElement>) => {\n // Forward the click first so themes that wired their own\n // handler keep working.\n onClick?.(e);\n if (!isEditor) return;\n // The whole point: route the click to the matching setting\n // input. Stop propagation only when the editor is open so we\n // don't double-fire the section-level click-to-select handler\n // that PreviewBridge installs at the document level. Themes\n // can still receive the click via their own onClick prop\n // (already invoked above).\n e.stopPropagation();\n postFieldSelected(sectionId, settingId, blockId);\n },\n [isEditor, onClick, sectionId, settingId, blockId],\n );\n\n const editorAttrs = useMemo(\n () =>\n isEditor\n ? {\n \"data-numu-editable\": \"text\",\n \"data-numu-section-id\": sectionId,\n \"data-numu-setting-id\": settingId,\n \"data-numu-block-id\": blockId ?? undefined,\n role: \"button\" as const,\n tabIndex: 0,\n }\n : {},\n [isEditor, sectionId, settingId, blockId],\n );\n\n const effectiveStyle = isEditor\n ? {\n ...style,\n cursor: \"text\" as const,\n // Subtle dotted underline so the merchant discovers what's\n // editable. The dashed style + inherited color keeps the\n // affordance from clashing with the theme's typography.\n textDecoration: \"underline dotted rgba(99, 102, 241, 0.7)\",\n textUnderlineOffset: \"4px\",\n }\n : style;\n\n const isEmpty = value == null || value === \"\";\n const display = isEmpty && placeholder !== undefined ? placeholder : value ?? \"\";\n\n if (html && typeof display === \"string\") {\n return (\n <Component\n ref={ref}\n className={className}\n style={effectiveStyle}\n onClick={handleClick}\n dangerouslySetInnerHTML={{ __html: display }}\n {...editorAttrs}\n {...rest}\n />\n );\n }\n return (\n <Component\n ref={ref}\n className={className}\n style={effectiveStyle}\n onClick={handleClick}\n {...editorAttrs}\n {...rest}\n >\n {display}\n </Component>\n );\n },\n);\n\n// ─── EditableImage ──────────────────────────────────────────────────────────\n\nexport interface EditableImageProps\n extends Omit<ImgHTMLAttributes<HTMLImageElement>, \"src\"> {\n sectionId: string;\n blockId?: string | null;\n settingId: string;\n /** Image src — may be empty/undefined if the merchant hasn't picked one yet. */\n src: string | undefined | null;\n /** Placeholder src shown when `src` is empty. Defaults to a 1x1 transparent gif. */\n emptyPlaceholderSrc?: string;\n}\n\nconst EMPTY_GIF =\n \"data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==\";\n\nexport const EditableImage = forwardRef<HTMLImageElement, EditableImageProps>(\n function EditableImage(\n {\n sectionId,\n blockId,\n settingId,\n src,\n alt,\n emptyPlaceholderSrc,\n className,\n onClick,\n style,\n ...rest\n },\n ref,\n ) {\n const isEditor = useIsEditor();\n const isEmpty = !src;\n\n const handleClick = useCallback(\n (e: React.MouseEvent<HTMLImageElement>) => {\n onClick?.(e);\n if (!isEditor) return;\n e.stopPropagation();\n postFieldSelected(sectionId, settingId, blockId);\n },\n [isEditor, onClick, sectionId, settingId, blockId],\n );\n\n const editorAttrs = useMemo(\n () =>\n isEditor\n ? {\n \"data-numu-editable\": \"image\",\n \"data-numu-section-id\": sectionId,\n \"data-numu-setting-id\": settingId,\n \"data-numu-block-id\": blockId ?? undefined,\n role: \"button\" as const,\n tabIndex: 0,\n }\n : {},\n [isEditor, sectionId, settingId, blockId],\n );\n\n const effectiveStyle = isEditor\n ? {\n ...style,\n cursor: \"pointer\" as const,\n outline: isEmpty\n ? \"2px dashed rgba(99, 102, 241, 0.6)\"\n : \"2px dashed transparent\",\n outlineOffset: \"-2px\",\n }\n : style;\n\n const effectiveSrc = src || emptyPlaceholderSrc || EMPTY_GIF;\n const effectiveAlt = alt ?? \"\";\n\n return (\n <img\n ref={ref}\n src={effectiveSrc}\n alt={effectiveAlt}\n className={className}\n style={effectiveStyle}\n onClick={handleClick}\n {...editorAttrs}\n {...rest}\n />\n );\n },\n);\n","/**\n * Icon — the shared icon set for the `icon_picker` setting type.\n *\n * Names are the stored setting values. BOTH the merchant-hub editor's icon\n * grid AND themes render through this same map, so a picked icon looks\n * identical in the customizer and on the storefront.\n *\n * We ship inline SVG (no icon-library dependency) on purpose: the SDK is the\n * host-provided runtime singleton, and keeping it dependency-free avoids\n * bundling an icon library into every storefront. Each entry below is the\n * inner markup of a 24×24 stroke icon; <Icon> wraps it with the shared\n * stroke attributes and sizing.\n *\n * ⚠️ KEEP IN SYNC with the editor's copy in\n * numo-merchant-hub/src/features/theme-editor-v3/components/inputs/SettingInputV3.tsx\n * (the ICON_DEFS in IconPickerButton). The keys are the contract between\n * the picker and this renderer — a name the picker offers must exist here\n * or the theme falls back to a neutral glyph.\n */\n\nexport const ICON_DEFS: Record<string, string> = {\n star: '<polygon points=\"12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2\"/>',\n heart:\n '<path d=\"M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.29 1.51 4.04 3 5.5l7 7Z\"/>',\n check: '<path d=\"M20 6 9 17l-5-5\"/>',\n \"check-circle\": '<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"m9 12 2 2 4-4\"/>',\n shield: '<path d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10Z\"/>',\n \"shield-check\":\n '<path d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10Z\"/><path d=\"m9 12 2 2 4-4\"/>',\n truck:\n '<path d=\"M10 17h4V5H2v12h3\"/><path d=\"M20 17h2v-3.34a4 4 0 0 0-1.17-2.83L19 9h-5v8h1\"/><circle cx=\"7.5\" cy=\"17.5\" r=\"2.5\"/><circle cx=\"17.5\" cy=\"17.5\" r=\"2.5\"/>',\n \"shopping-bag\":\n '<path d=\"M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z\"/><path d=\"M3 6h18\"/><path d=\"M16 10a4 4 0 0 1-8 0\"/>',\n \"shopping-cart\":\n '<circle cx=\"8\" cy=\"21\" r=\"1\"/><circle cx=\"19\" cy=\"21\" r=\"1\"/><path d=\"M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12\"/>',\n gift:\n '<rect x=\"3\" y=\"8\" width=\"18\" height=\"4\" rx=\"1\"/><path d=\"M12 8v13\"/><path d=\"M19 12v7a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-7\"/><path d=\"M7.5 8a2.5 2.5 0 0 1 0-5C9 3 10.5 4.5 12 8c1.5-3.5 3-5 4.5-5a2.5 2.5 0 0 1 0 5\"/>',\n tag: '<path d=\"M20.59 13.41 13.42 20.6a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82Z\"/><circle cx=\"7\" cy=\"7\" r=\"1\"/>',\n zap: '<polygon points=\"13 2 3 14 12 14 11 22 21 10 12 10 13 2\"/>',\n sparkles:\n '<path d=\"M12 3 13.9 9.2 20 11l-6.1 1.8L12 19l-1.9-6.2L4 11l6.1-1.8L12 3Z\"/><path d=\"M5 3v4\"/><path d=\"M3 5h4\"/><path d=\"M19 17v4\"/><path d=\"M17 19h4\"/>',\n flame:\n '<path d=\"M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.07-2.14-.22-4.05 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.15.43-2.29 1-3a2.5 2.5 0 0 0 2.5 2.5Z\"/>',\n leaf:\n '<path d=\"M11 20A7 7 0 0 1 9.8 6.1C15.5 5 17 4.48 19 2c1 2 2 4.18 2 8 0 5.5-4.78 10-10 10Z\"/><path d=\"M2 21c0-3 1.85-5.36 5.08-6\"/>',\n globe:\n '<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M2 12h20\"/><path d=\"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10Z\"/>',\n \"map-pin\":\n '<path d=\"M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/>',\n phone:\n '<path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92Z\"/>',\n mail:\n '<rect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\"/><path d=\"m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7\"/>',\n clock: '<circle cx=\"12\" cy=\"12\" r=\"10\"/><polyline points=\"12 6 12 12 16 14\"/>',\n lock:\n '<rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\" ry=\"2\"/><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"/>',\n headphones:\n '<path d=\"M3 14h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-7a9 9 0 0 1 18 0v7a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3\"/>',\n percent:\n '<line x1=\"19\" x2=\"5\" y1=\"5\" y2=\"19\"/><circle cx=\"6.5\" cy=\"6.5\" r=\"2.5\"/><circle cx=\"17.5\" cy=\"17.5\" r=\"2.5\"/>',\n users:\n '<path d=\"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2\"/><circle cx=\"9\" cy=\"7\" r=\"4\"/><path d=\"M22 21v-2a4 4 0 0 0-3-3.87\"/><path d=\"M16 3.13a4 4 0 0 1 0 7.75\"/>',\n home:\n '<path d=\"m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z\"/><polyline points=\"9 22 9 12 15 12 15 22\"/>',\n store:\n '<path d=\"M2 7l2-4h16l2 4\"/><path d=\"M4 7v13a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1V7\"/><path d=\"M2 7h20\"/><path d=\"M9 21v-6h6v6\"/>',\n bell:\n '<path d=\"M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9\"/><path d=\"M10.3 21a1.94 1.94 0 0 0 3.4 0\"/>',\n camera:\n '<path d=\"M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z\"/><circle cx=\"12\" cy=\"13\" r=\"3\"/>',\n image:\n '<rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" ry=\"2\"/><circle cx=\"9\" cy=\"9\" r=\"2\"/><path d=\"m21 15-3.09-3.09a2 2 0 0 0-2.82 0L6 21\"/>',\n smile:\n '<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M8 14s1.5 2 4 2 4-2 4-2\"/><line x1=\"9\" x2=\"9.01\" y1=\"9\" y2=\"9\"/><line x1=\"15\" x2=\"15.01\" y1=\"9\" y2=\"9\"/>',\n send: '<path d=\"m22 2-7 20-4-9-9-4Z\"/><path d=\"M22 2 11 13\"/>',\n \"message-circle\":\n '<path d=\"M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5Z\"/>',\n search: '<circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"m21 21-4.3-4.3\"/>',\n package:\n '<path d=\"M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z\"/><path d=\"m3.3 7 8.7 5 8.7-5\"/><path d=\"M12 22V12\"/>',\n award:\n '<circle cx=\"12\" cy=\"8\" r=\"6\"/><path d=\"M15.477 12.89 17 22l-5-3-5 3 1.523-9.11\"/>',\n coffee:\n '<path d=\"M10 2v2\"/><path d=\"M14 2v2\"/><path d=\"M6 2v2\"/><path d=\"M16 8a1 1 0 0 1 1 1v8a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1h14a4 4 0 1 1 0 8h-1\"/>',\n};\n\nexport const ICON_NAMES: string[] = Object.keys(ICON_DEFS);\n\n/** Public alias for the icon name → inner-SVG map. */\nexport const IconMap = ICON_DEFS;\n\nexport interface IconProps {\n /** Icon name from {@link ICON_NAMES}. Unknown names render a neutral glyph. */\n name: string;\n /** Pixel size (width === height). Defaults to 24. */\n size?: number | string;\n strokeWidth?: number;\n className?: string;\n /** Accessible label. When omitted the icon is treated as decorative. */\n title?: string;\n}\n\nconst FALLBACK = ICON_DEFS[\"check-circle\"];\n\n/**\n * Render an icon by name from the shared {@link ICON_DEFS} set. Inherits color\n * from `currentColor`, so set the parent's text color to recolor it.\n */\nexport function Icon({\n name,\n size = 24,\n strokeWidth = 2,\n className,\n title,\n}: IconProps) {\n const inner = ICON_DEFS[name] ?? FALLBACK;\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n role={title ? \"img\" : undefined}\n aria-hidden={title ? undefined : true}\n aria-label={title}\n dangerouslySetInnerHTML={{ __html: inner }}\n />\n );\n}\n","\"use client\";\n\n/**\n * Module Federation singleton sharing for @numueg/theme-sdk.\n *\n * Why this exists:\n * BYOT bundles (loaded at runtime as cross-origin ESM modules) need to\n * share React + the SDK with the host storefront. Otherwise React's\n * internal \"two copies\" check trips and hooks crash. The host registers\n * its singletons here; the BYOT bundle reads them via the SDK shim.\n *\n * Threat model:\n * We do NOT want third-party scripts (analytics, chat widgets, BYOT\n * community themes) to read PII off the SDK. The earlier version stored\n * the SDK on `window.__NUMU_SDK__` — anything in the page could read it\n * and call `useCustomer()` etc.\n *\n * Mitigation:\n * The singleton is keyed by a Symbol that's only handed to consumers\n * we've verified (the storefront's BYOT entry function passes it to the\n * bundle's `setup()`). Symbols can't be enumerated through `window` or\n * `Object.getOwnPropertyNames`, so a leaked global reference doesn't\n * yield SDK access.\n *\n * For maximum safety we also expose `clearSdkSingleton()` so the host\n * can revoke after a BYOT theme is unmounted.\n */\n\ninterface SdkSingleton {\n useShop: unknown;\n useProduct: unknown;\n useCollection: unknown;\n useCart: unknown;\n useCustomer: unknown;\n useThemeSettings: unknown;\n useLocalization: unknown;\n usePage: unknown;\n useSection: unknown;\n NuMuProvider: unknown;\n ProductProvider: unknown;\n CollectionProvider: unknown;\n}\n\ninterface ReactSingleton {\n React: unknown;\n ReactDOM: unknown;\n}\n\n// We pin the slot keys via `Symbol.for(name)` so ALL copies of this\n// SDK module — even when bundled with a BYOT theme — resolve to the\n// SAME Symbol identity through the global Symbol registry. The\n// previous implementation also wrote the Symbol back to a string-keyed\n// `globalThis[\"__NUMU_SDK_SLOT__\"]` slot \"so multiple module copies\n// could find it\" — but `Symbol.for()` already supplies that identity\n// (that's its entire purpose), and writing to a string-keyed\n// globalThis property put the slot name into `Object.keys(globalThis)`,\n// breaking the Principle II \"not enumerable\" privacy contract.\n//\n// What's still public:\n// - The Symbol's *name* is in the global Symbol registry. A motivated\n// attacker who knows the name can call Symbol.for() to recover the\n// same Symbol. Privacy here is obscurity-through-naming, not crypto.\n// - The actual SDK object lives at `globalThis[symbol]` — invisible\n// to `Object.keys`, `Object.getOwnPropertyNames`, and accidental\n// enumeration by third-party scripts that don't know to call\n// `Object.getOwnPropertySymbols`.\nfunction sdkSlot(): symbol {\n return Symbol.for(\"@numueg/theme-sdk:singleton\");\n}\n\nfunction reactSlot(): symbol {\n return Symbol.for(\"@numueg/theme-sdk:react\");\n}\n\nexport function registerSdkSingleton(sdk: SdkSingleton): void {\n if (typeof globalThis === \"undefined\") return;\n (globalThis as Record<symbol, unknown>)[sdkSlot()] = sdk;\n}\n\nexport function getSdkSingleton(): SdkSingleton | null {\n if (typeof globalThis === \"undefined\") return null;\n return (\n ((globalThis as Record<symbol, unknown>)[sdkSlot()] as SdkSingleton) ??\n null\n );\n}\n\nexport function clearSdkSingleton(): void {\n if (typeof globalThis === \"undefined\") return;\n delete (globalThis as Record<symbol, unknown>)[sdkSlot()];\n}\n\nexport function registerReactSingleton(\n react: unknown,\n reactDom: unknown,\n): void {\n if (typeof globalThis === \"undefined\") return;\n (globalThis as Record<symbol, unknown>)[reactSlot()] = {\n React: react,\n ReactDOM: reactDom,\n } satisfies ReactSingleton;\n}\n\nexport function getReactSingleton(): ReactSingleton | null {\n if (typeof globalThis === \"undefined\") return null;\n return (\n ((globalThis as Record<symbol, unknown>)[\n reactSlot()\n ] as ReactSingleton) ?? null\n );\n}\n\nexport function isSdkAvailable(): boolean {\n return getSdkSingleton() !== null;\n}\n","/**\n * Dynamic sources — Shopify-parity feature that lets merchants bind a\n * section setting to a value that's pulled from store data at render\n * time instead of being a literal authored value.\n *\n * Stored shape:\n * { __numu_source: \"<path>\" }\n *\n * Paths use dot notation against the resolution context:\n * - `product.title` / `product.description` / `product.price` /\n * `product.image` / `product.first_image_url`\n * - `collection.title` / `collection.description` / `collection.image`\n * - `store.name` / `store.description`\n *\n * Why a reserved discriminant key (`__numu_source`)?\n *\n * Setting values today are plain literals (`\"Hero headline\"`,\n * `12345`, `true`). Themes that read settings as strings/numbers\n * would break if we suddenly stored an object. The reserved key\n * tags object-shape values so the resolver only intercepts the ones\n * it knows about. Anything else (e.g. the `{ url, alt }` shape from\n * the image picker, or a future structured setting) passes through.\n *\n * Bindable-by-type matrix (enforced in the customizer's source picker):\n *\n * text | product.title, product.description (snippet),\n * | collection.title, collection.description (snippet),\n * | store.name, store.description\n * textarea | same as text + full descriptions\n * richtext | full descriptions only\n * url | not bindable yet — product/collection URLs require\n * | the host's route resolver; deferred to a follow-up.\n * image_picker | product.image, collection.image, store.logo\n * number/range | product.price (raw cents) — risky because format\n * | varies. Deferred.\n * color/checkbox/select/radio/font | not bindable.\n *\n * Themes consume dynamic sources via `useResolvedSettings(instance)`\n * which returns the section's settings map with every dynamic ref\n * pre-resolved against the active product/collection/store context.\n * Literal values pass through unchanged.\n */\n\nimport type { Collection, Product, Store } from \"../types/entities\";\n\n/** Stored shape for a dynamic source reference. */\nexport interface DynamicSourceRef {\n __numu_source: string;\n}\n\n/**\n * Type guard. True when `value` is a dynamic source reference object.\n * Order matters: we check the discriminant key BEFORE assuming the\n * value is anything else, so an `{ __numu_source: \"...\" }` from the\n * draft doesn't get treated as a literal record.\n */\nexport function isDynamicSource(value: unknown): value is DynamicSourceRef {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { __numu_source?: unknown }).__numu_source === \"string\"\n );\n}\n\n/**\n * Build a fresh dynamic source ref. Pure helper used by the customizer\n * when the merchant clicks a source in the picker.\n */\nexport function dynamicSource(path: string): DynamicSourceRef {\n return { __numu_source: path };\n}\n\n/** Resolution context for `resolveDynamicValue`. Each field is\n * independently optional so callers can pass only what's relevant\n * (e.g. cart template skips product/collection). */\nexport interface DynamicResolveContext {\n product?: Product | null;\n collection?: Collection | null;\n store?: Pick<Store, \"name\" | \"description\" | \"logo_url\"> | null;\n}\n\n/**\n * Look up the path inside the resolution context. Returns `null` when\n * the source is unknown OR the context doesn't have the resource\n * needed to resolve it (e.g. `product.title` when no product is in\n * context). The customizer's source picker already hides incompatible\n * sources, so this fallback only fires during preview navigation\n * (merchant flips to a product template before the picker re-renders).\n */\nexport function resolveSourcePath(\n path: string,\n ctx: DynamicResolveContext,\n): unknown {\n const [root, ...rest] = path.split(\".\");\n switch (root) {\n case \"product\": {\n const p = ctx.product;\n if (!p) return null;\n return resolveProductField(p, rest.join(\".\"));\n }\n case \"collection\": {\n const c = ctx.collection;\n if (!c) return null;\n return resolveCollectionField(c, rest.join(\".\"));\n }\n case \"store\": {\n const s = ctx.store;\n if (!s) return null;\n return resolveStoreField(s, rest.join(\".\"));\n }\n default:\n return null;\n }\n}\n\n/** Merchant-defined field: `metafield:{namespace}.{key}`. Only public\n * metafields reach the storefront; missing → null (setting default renders). */\nfunction resolveMetafield(\n metafields: { namespace: string; key: string; value: unknown }[] | undefined,\n field: string,\n): unknown {\n const address = field.slice(\"metafield:\".length);\n const dot = address.indexOf(\".\");\n if (dot === -1) return null;\n const namespace = address.slice(0, dot);\n const key = address.slice(dot + 1);\n const hit = (metafields ?? []).find(\n (m) => m.namespace === namespace && m.key === key,\n );\n return hit ? (hit.value ?? null) : null;\n}\n\nfunction resolveProductField(p: Product, field: string): unknown {\n if (field.startsWith(\"metafield:\")) return resolveMetafield(p.metafields, field);\n switch (field) {\n case \"title\":\n case \"name\":\n return p.name;\n case \"description\":\n return p.description ?? \"\";\n case \"description_snippet\":\n // 200-char excerpt — useful for short-description settings that\n // would otherwise inherit a full HTML body.\n return (p.description ?? \"\").replace(/<[^>]+>/g, \" \").trim().slice(0, 200);\n case \"price\":\n return p.price;\n case \"sku\":\n // SKU lives on the default variant in most stores.\n return p.variants?.[0]?.sku ?? null;\n case \"image\":\n case \"first_image_url\":\n return p.images?.[0]?.url ?? null;\n case \"slug\":\n return p.slug;\n default:\n return null;\n }\n}\n\nfunction resolveCollectionField(c: Collection, field: string): unknown {\n if (field.startsWith(\"metafield:\")) return resolveMetafield(c.metafields, field);\n switch (field) {\n case \"title\":\n case \"name\":\n return c.name;\n case \"description\":\n return c.description ?? \"\";\n case \"description_snippet\":\n return (c.description ?? \"\").replace(/<[^>]+>/g, \" \").trim().slice(0, 200);\n case \"image\":\n return c.image_url ?? null;\n case \"slug\":\n return c.slug;\n case \"product_count\":\n return c.product_count ?? null;\n default:\n return null;\n }\n}\n\nfunction resolveStoreField(\n s: Pick<Store, \"name\" | \"description\" | \"logo_url\">,\n field: string,\n): unknown {\n switch (field) {\n case \"name\":\n return s.name ?? \"\";\n case \"description\":\n return s.description ?? \"\";\n case \"logo\":\n return s.logo_url ?? null;\n default:\n return null;\n }\n}\n\n/**\n * Resolve a single setting value. Literal values pass through\n * unchanged; dynamic references resolve against the context. Returns\n * `null` (not the original ref) when resolution fails, so themes can\n * branch on the null and either render a placeholder or hide the\n * element entirely.\n */\nexport function resolveDynamicValue<T = unknown>(\n value: unknown,\n ctx: DynamicResolveContext,\n): T | null {\n if (!isDynamicSource(value)) return value as T;\n return resolveSourcePath(value.__numu_source, ctx) as T | null;\n}\n\n/**\n * Walk every key of a settings map and resolve every dynamic\n * reference. Pure helper backing `useResolvedSettings`.\n *\n * The generic is unconstrained on purpose. Theme authors typically\n * type their settings as `interface HeroSettings { headline?: string }`,\n * and TypeScript interfaces don't implicitly satisfy\n * `Record<string, unknown>` — there's no index signature on an\n * interface. Leaving `T` open lets us pass through whatever shape the\n * caller declared and still return the resolved-but-same shape.\n */\nexport function resolveSettingsMap<T = Record<string, unknown>>(\n settings: T,\n ctx: DynamicResolveContext,\n): T {\n if (!settings || typeof settings !== \"object\") return settings;\n const input = settings as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(input)) {\n const v = input[key];\n if (isDynamicSource(v)) {\n const resolved = resolveSourcePath(v.__numu_source, ctx);\n // Preserve nullish from resolution failure so the consumer can\n // detect \"I asked for product.title but no product is active.\"\n out[key] = resolved;\n } else {\n out[key] = v;\n }\n }\n return out as T;\n}\n","\"use client\";\nimport { useContext, useMemo } from \"react\";\nimport { ProductContext, CollectionContext, ShopContext } from \"../contexts\";\nimport type { BlockInstance, SectionInstance } from \"../types/theme\";\nimport {\n type DynamicResolveContext,\n resolveSettingsMap,\n} from \"../utils/dynamicSources\";\n\n/**\n * Resolve every dynamic source in a section's settings against the\n * active product / collection / store contexts.\n *\n * Section components that want to support merchant-bound fields call\n * this in place of reading `instance.settings` directly:\n *\n * const settings = useResolvedSettings(instance);\n *\n * Literal values pass through; `{ __numu_source: \"product.title\" }`\n * becomes the current product's title when the section is rendered\n * inside a `<ProductProvider>`. The returned object is memoized on\n * the upstream contexts so themes can pass it straight into\n * `useMemo` deps without retriggering renders.\n *\n * When the bound resource isn't in context (e.g. `product.*` on a\n * non-product template), the resolved value is `null`. Themes can\n * detect this and render a placeholder or hide the affected element.\n *\n * Note: the SectionContext provider already supplies the `instance`\n * to children of `<Section>` — but we take it explicitly so section\n * components can call this hook before they've descended into\n * SectionContext (i.e. at the top of their render function, alongside\n * destructuring `settings` from props).\n */\nexport function useResolvedSettings<T = Record<string, unknown>>(\n instance: SectionInstance | BlockInstance | null | undefined,\n): T {\n const product = useContext(ProductContext);\n const collection = useContext(CollectionContext);\n const store = useContext(ShopContext);\n\n // Stabilize the resolution context object so the memo only invalidates\n // when one of the upstream values actually changes. Without this each\n // render would build a fresh `{ product, collection, store }` and the\n // useMemo dep array would never hit.\n const ctx = useMemo<DynamicResolveContext>(\n () => ({ product, collection, store }),\n [product, collection, store],\n );\n\n return useMemo(() => {\n const settings = (instance?.settings ?? {}) as T;\n return resolveSettingsMap<T>(settings, ctx);\n }, [instance, ctx]);\n}\n","/**\n * Section + block authoring helpers.\n *\n * `defineSection` and `defineBlock` bind a JSON schema to its render\n * component so theme authors don't keep two files in sync by hand.\n * The plugin ships the schema half (writes `schemas/sections/<type>.json`\n * for the customizer), the runtime imports the component half — both\n * sourced from the same factory call.\n *\n * Why factories instead of two separate files:\n * Pre-Phase-2 layout was:\n * theme/main.tsx → registers components\n * theme/schemas/sections/Hero.json → declares schema\n * Drift was the bug. Renaming a setting required edits in two places;\n * adding a new section meant remembering to update three lists.\n * Factories collapse that into a single export the plugin and runtime\n * both read.\n *\n * Usage:\n * // sections/Hero.tsx\n * import { defineSection } from \"@numueg/theme-sdk\";\n * export default defineSection({\n * schema: {\n * type: \"hero\",\n * name: \"Hero\",\n * settings: [{ type: \"text\", id: \"heading\", label: \"Heading\" }],\n * presets: [{ name: \"Hero — Centered\", settings: { heading: \"Welcome\" } }],\n * },\n * render: ({ settings }) => <h1>{settings.heading}</h1>,\n * });\n *\n * The plugin's section-discovery scan picks up files under\n * `src/sections/**\\/*.{tsx,ts}` whose default export is a section\n * definition. No registration list needed.\n */\n\nimport type { ComponentType } from \"react\";\nimport type {\n BlockProps,\n BlockSchema,\n SectionProps,\n SectionSchema,\n} from \"../types/theme\";\n\nconst SECTION_MARKER = Symbol.for(\"numu.theme.section\");\nconst BLOCK_MARKER = Symbol.for(\"numu.theme.block\");\n\n/**\n * A defined section: paired schema + render component.\n *\n * The marker symbol lets the plugin's discovery scan identify section\n * definitions without depending on a structural shape that themes might\n * accidentally collide with.\n */\nexport interface DefinedSection {\n schema: SectionSchema;\n render: ComponentType<SectionProps>;\n readonly [SECTION_MARKER]: true;\n}\n\nexport interface DefinedBlock {\n schema: BlockSchema;\n render: ComponentType<BlockProps>;\n readonly [BLOCK_MARKER]: true;\n}\n\nexport interface DefineSectionInput {\n schema: SectionSchema;\n render: ComponentType<SectionProps>;\n}\n\nexport interface DefineBlockInput {\n schema: BlockSchema;\n render: ComponentType<BlockProps>;\n}\n\n/**\n * Bind a section schema to its renderer.\n *\n * Validates at runtime that `schema.type` is a stable identifier\n * (lowercase + dashes/underscores) — drift here breaks the plugin's\n * codegen step (which writes `__generated__/sections.d.ts` keyed off\n * `schema.type`).\n */\nexport function defineSection(input: DefineSectionInput): DefinedSection {\n if (!input?.schema?.type) {\n throw new Error(\n \"defineSection: `schema.type` is required and must be a stable string id.\",\n );\n }\n if (!/^[a-z][a-z0-9_-]*$/.test(input.schema.type)) {\n throw new Error(\n `defineSection: section type '${input.schema.type}' must be lowercase alphanumeric ` +\n `with dashes/underscores. The codegen step uses this as a TS key.`,\n );\n }\n if (typeof input.render !== \"function\") {\n throw new Error(\n \"defineSection: `render` must be a React component function.\",\n );\n }\n return Object.freeze({\n schema: input.schema,\n render: input.render,\n [SECTION_MARKER]: true as const,\n });\n}\n\nexport function defineBlock(input: DefineBlockInput): DefinedBlock {\n if (!input?.schema?.type) {\n throw new Error(\"defineBlock: `schema.type` is required.\");\n }\n if (!/^[a-z@][a-z0-9_/-]*$/i.test(input.schema.type)) {\n throw new Error(\n `defineBlock: block type '${input.schema.type}' has illegal chars. ` +\n `Use a-z, 0-9, dashes/underscores; @app/<slug>/<block> form is also accepted.`,\n );\n }\n if (typeof input.render !== \"function\") {\n throw new Error(\n \"defineBlock: `render` must be a React component function.\",\n );\n }\n return Object.freeze({\n schema: input.schema,\n render: input.render,\n [BLOCK_MARKER]: true as const,\n });\n}\n\nexport function isDefinedSection(v: unknown): v is DefinedSection {\n return (\n typeof v === \"object\" &&\n v !== null &&\n (v as Record<symbol, unknown>)[SECTION_MARKER] === true\n );\n}\n\nexport function isDefinedBlock(v: unknown): v is DefinedBlock {\n return (\n typeof v === \"object\" &&\n v !== null &&\n (v as Record<symbol, unknown>)[BLOCK_MARKER] === true\n );\n}\n\n/**\n * Build a section registry from a Vite glob import.\n *\n * Themes call this at the top of their `main.tsx`:\n *\n * const sectionModules = import.meta.glob<{ default: DefinedSection }>(\n * \"./sections/*.tsx\", { eager: true });\n * const sections = collectSections(sectionModules);\n *\n * The returned object is keyed by `schema.type` for direct lookup at\n * render time. Modules whose default export isn't a DefinedSection are\n * skipped with a console warning (drops a half-migrated section without\n * breaking the rest of the bundle).\n */\nexport function collectSections<T extends Record<string, unknown>>(\n modules: T,\n): Record<string, DefinedSection> {\n const out: Record<string, DefinedSection> = {};\n for (const [path, mod] of Object.entries(modules)) {\n const def = (mod as { default?: unknown }).default;\n if (!isDefinedSection(def)) {\n if (typeof console !== \"undefined\") {\n console.warn(\n `[numu] ${path}: default export is not a defineSection() result; skipped.`,\n );\n }\n continue;\n }\n if (out[def.schema.type]) {\n throw new Error(\n `[numu] duplicate section type '${def.schema.type}': ` +\n `previously defined, now also defined in ${path}.`,\n );\n }\n out[def.schema.type] = def;\n }\n return out;\n}\n\nexport function collectBlocks<T extends Record<string, unknown>>(\n modules: T,\n): Record<string, DefinedBlock> {\n const out: Record<string, DefinedBlock> = {};\n for (const [path, mod] of Object.entries(modules)) {\n const def = (mod as { default?: unknown }).default;\n if (!isDefinedBlock(def)) {\n if (typeof console !== \"undefined\") {\n console.warn(\n `[numu] ${path}: default export is not a defineBlock() result; skipped.`,\n );\n }\n continue;\n }\n if (out[def.schema.type]) {\n throw new Error(\n `[numu] duplicate block type '${def.schema.type}': ` +\n `previously defined, now also defined in ${path}.`,\n );\n }\n out[def.schema.type] = def;\n }\n return out;\n}\n","/**\n * `assetUrl(name)` — resolve a theme-bundled asset's runtime URL.\n *\n * Themes ship static assets (images, fonts, JSON) under `assets/`.\n * The plugin copies each asset to `dist/assets/` with a content-hashed\n * filename and writes a manifest (`asset-manifest.json`) mapping each\n * source path to the hashed name.\n *\n * At runtime this function reads the manifest off the runtime window\n * object (`window.__NUMU_ASSET_MANIFEST`) — populated by the storefront's\n * `<RuntimeImportMap>` component when the theme bundle is loaded —\n * and returns the absolute URL to the hashed file.\n *\n * Why a runtime helper instead of bake-time string interpolation:\n * The same theme bundle is reused across hosted stores. The asset\n * base URL differs per environment (CDN vs local dev) and per store\n * (subdomain vs custom domain). Resolving at runtime keeps a single\n * bundle deployable across all of them.\n *\n * Usage:\n * <Image src={assetUrl(\"hero.jpg\")} alt=\"...\" />\n * <link rel=\"preload\" as=\"font\" href={assetUrl(\"fonts/Inter.woff2\")} />\n *\n * Behavior when the manifest is missing or the asset isn't listed:\n * Returns the original `name` (prefixed with the conventional\n * `/assets/` path) as a fallback. This keeps dev workable when the\n * plugin's asset-pipeline step hasn't run yet, and surfaces obviously-\n * wrong asset names as 404s rather than silent failures.\n */\n\ninterface AssetManifest {\n /** Map of source asset path → hashed filename in dist/assets/ */\n [sourcePath: string]: string;\n}\n\ninterface AssetRuntimeConfig {\n /** Manifest written by the plugin at build time and injected at runtime. */\n __NUMU_ASSET_MANIFEST?: AssetManifest;\n /**\n * Optional CDN/path prefix. Defaults to \"/assets/\" — themes hosted on\n * a CDN can override by setting this on `window` before mount.\n */\n __NUMU_ASSET_BASE_URL?: string;\n}\n\nfunction getRuntime(): AssetRuntimeConfig {\n if (typeof window !== \"undefined\") {\n return window as unknown as AssetRuntimeConfig;\n }\n // Server-side render (host SSR worker): the host injects the manifest and\n // base URL onto globalThis before calling createApp, so server markup\n // resolves the same hashed URLs the client would — no <img src> hydration\n // patch-up.\n if (typeof globalThis !== \"undefined\") {\n return globalThis as unknown as AssetRuntimeConfig;\n }\n return {};\n}\n\nexport function assetUrl(name: string): string {\n if (!name) return \"\";\n // Already-absolute or already-resolved (starts with /, http://, https://) →\n // pass through. Theme code that mixes hand-written paths with assetUrl()\n // is fine, this is just a no-op for those.\n if (/^https?:\\/\\//i.test(name) || name.startsWith(\"//\")) return name;\n\n const runtime = getRuntime();\n const manifest = runtime.__NUMU_ASSET_MANIFEST;\n const base = runtime.__NUMU_ASSET_BASE_URL || \"/assets/\";\n\n // Normalize: strip leading \"./\" or \"assets/\" so callers can write\n // `assetUrl(\"hero.jpg\")` or `assetUrl(\"./hero.jpg\")` interchangeably.\n let key = name.replace(/^\\.\\//, \"\");\n if (key.startsWith(\"/\")) key = key.slice(1);\n if (key.startsWith(\"assets/\")) key = key.slice(\"assets/\".length);\n\n const hashed = manifest?.[key];\n // No manifest hit → fall back to the bare path under base. Keeps dev\n // (where the plugin watch hasn't emitted a manifest yet) workable.\n const filename = hashed || key;\n // Ensure exactly one slash between base and filename.\n const cleanBase = base.endsWith(\"/\") ? base : `${base}/`;\n return `${cleanBase}${filename}`;\n}\n","/**\n * Template + section-group resolution — the \"no blank page\" engine.\n *\n * This is engine policy, not theme code, and it was copy-pasted into every\n * theme: `src/sections/_template-utils.ts` is BYTE-IDENTICAL across 11 of the\n * 14 themes that carry it (md5 59608dd4f4a702136854d7aaf33ba5e3); the\n * remaining copies differ only in comments and brace style. The file's own\n * header instructed theme authors to copy it and said it could be deleted\n * \"once the published SDK ships its own sanitizeTemplate\". This is that.\n *\n * Why centralising it is safe — and why it matters:\n * - It contains ZERO design. It decides WHICH sections render, never how\n * they look, so it cannot homogenise themes.\n * - Getting it subtly wrong renders an EMPTY STORE. Empire re-implemented a\n * weaker version inline with no unknown-type filtering, so a stale\n * customisation renders \"Unknown section\" placeholders there while every\n * other theme degrades gracefully. One implementation removes that class.\n *\n * The two rules it encodes, both learned from real blank-page incidents:\n * 1. A template may arrive as an ARRAY or as a MAP + `order[]`. The\n * customizer writes one shape, theme presets use the other.\n * 2. Host customisation wins over the theme's bundled preset — UNLESS it\n * resolves to nothing this theme can render, in which case fall back to\n * the preset rather than showing the shopper an empty page.\n */\n\nimport type { SectionInstance } from \"../types/theme\";\n\n/** A template or section group, in either of the two shapes hosts send. */\nexport interface MaybeOrderedTemplate {\n name?: string;\n sections?: Record<string, SectionInstance> | SectionInstance[];\n order?: string[];\n}\n\n/** A section instance paired with the stable id the customizer selects by. */\nexport interface ResolvedSection {\n id: string;\n instance: SectionInstance;\n}\n\n/**\n * Normalise a template/group into an ordered list.\n *\n * Array form gets synthetic `${type}-${index}` ids (presets have no ids of\n * their own). Map form is walked in `order`, skipping ids the map doesn't\n * contain — a dangling id in `order` is a customisation that referenced a\n * deleted section and must not throw.\n */\nexport function resolveSections(\n group: MaybeOrderedTemplate | undefined,\n): ResolvedSection[] {\n if (!group) return [];\n if (Array.isArray(group.sections)) {\n return group.sections.map((instance, idx) => ({\n id: `${instance.type}-${idx}`,\n instance,\n }));\n }\n const map = (group.sections ?? {}) as Record<string, SectionInstance>;\n const order = group.order ?? Object.keys(map);\n const out: ResolvedSection[] = [];\n for (const id of order) {\n const instance = map[id];\n if (instance) out.push({ id, instance });\n }\n return out;\n}\n\n/**\n * Choose between the host's customisation and the theme's bundled preset,\n * then drop section types this theme cannot render.\n *\n * `isKnown` is the theme's own registry lookup — the one thing that genuinely\n * belongs to the theme, so it stays a parameter.\n *\n * The order of the three checks is load-bearing:\n * - nothing from the host → preset (a fresh install renders its demo)\n * - host sections, none known → preset (a customisation built for a\n * DIFFERENT theme must not blank the page)\n * - otherwise → host sections, unknown types filtered out\n */\nexport function selectTemplateSections(\n hostTemplate: MaybeOrderedTemplate | undefined,\n builtinTemplate: MaybeOrderedTemplate | undefined,\n isKnown: (sectionType: string) => boolean,\n): ResolvedSection[] {\n const hostSections = resolveSections(hostTemplate);\n if (hostSections.length === 0) {\n return resolveSections(builtinTemplate);\n }\n const anyKnown = hostSections.some(({ instance }) => isKnown(instance.type));\n if (!anyKnown) return resolveSections(builtinTemplate);\n return hostSections.filter(({ instance }) => isKnown(instance.type));\n}\n\n/**\n * Find the theme's header/footer for a route it has no template for.\n *\n * Chrome reaches a theme from `section_groups` — except most themes never used\n * that channel: they put the header and footer INLINE in each template's own\n * section list. That works right up until the shopper hits a route the theme\n * ships no template for. Then there are no sections, so there is no chrome,\n * and the page renders with no navigation and no way back into the store.\n *\n * That is what `/blogs` looked like on every theme: correct, readable content\n * with nothing around it — no logo, no menu, no cart, no footer. A shopper\n * arriving from search had to press Back to escape.\n *\n * The template's OWN inline chrome still wins when it has some. This only\n * supplies chrome to routes that would otherwise have none, by borrowing the\n * chrome the theme already renders everywhere else — `home` first, since it is\n * the one template every theme ships and the one merchants customise.\n *\n * Returns `[]` when the theme genuinely has no chrome of this kind anywhere,\n * so a caller can still fall back to its own default.\n */\nexport function selectChromeSections(options: {\n /** `section_groups[kind]` from the host — the customizer's channel. */\n hostGroup?: MaybeOrderedTemplate;\n /** The theme's own preset `section_groups[kind]`. */\n presetGroup?: MaybeOrderedTemplate;\n /** Chrome found inline in the CURRENT template's section list. */\n inline?: ResolvedSection[];\n /** Every template the theme can draw on — host customisation and presets. */\n templates?: Array<MaybeOrderedTemplate | undefined>;\n /** True for the section types that count as this kind of chrome. */\n isChrome: (sectionType: string) => boolean;\n /** The theme's registry lookup. */\n isKnown: (sectionType: string) => boolean;\n}): ResolvedSection[] {\n const { hostGroup, presetGroup, inline, templates, isChrome, isKnown } =\n options;\n const known = (list: ResolvedSection[]) =>\n list.filter(({ instance }) => isKnown(instance.type));\n\n const fromHost = known(resolveSections(hostGroup));\n if (fromHost.length > 0) return fromHost;\n\n if (inline && inline.length > 0) return known(inline);\n\n const fromPreset = known(resolveSections(presetGroup));\n if (fromPreset.length > 0) return fromPreset;\n\n // Last resort: borrow from any template that carries this chrome inline.\n for (const template of templates ?? []) {\n const borrowed = known(resolveSections(template)).filter(({ instance }) =>\n isChrome(instance.type),\n );\n if (borrowed.length > 0) return borrowed;\n }\n return [];\n}\n","/**\n * Theme-bundled locale files: load + merge.\n *\n * The plugin discovers `locales/<code>.json` (and the fallback\n * `locales/en.default.json`) and bakes them into the bundle as a map\n * keyed by locale code. The runtime calls `pickTranslations(map, locale)`\n * to resolve the right one, with English fallback for missing keys.\n *\n * Conventions:\n * - locales/en.default.json is the canonical English source. It's\n * the fallback for any other locale's missing keys.\n * - locales/ar.json (and friends) override or extend the default.\n * - Nested keys are flattened with dot notation: `{\"hero\": {\"cta\": \"Buy\"}}`\n * becomes `\"hero.cta\"` for `t(\"hero.cta\")` to look up.\n *\n * Why flatten:\n * `useTranslation()` returns `t(key)` which expects a string lookup —\n * structured access would force every theme to write\n * `translations.hero?.cta ?? \"Buy\"`. Flattening keeps the call site\n * short and matches Shopify's `t` semantics.\n */\n\nexport interface LocaleMessages {\n [key: string]: string;\n}\n\nexport interface LocaleBundle {\n /** Locale code → flat key/value messages. */\n [locale: string]: LocaleMessages;\n}\n\n/**\n * Recursively flatten a nested locale object into dot-keyed strings.\n *\n * Non-string leaves are skipped with a console warning — translations\n * are user-facing strings; numbers and booleans don't belong in a\n * locale file (they should be in schema settings).\n */\nexport function flattenMessages(\n source: Record<string, unknown>,\n prefix = \"\",\n): LocaleMessages {\n const out: LocaleMessages = {};\n for (const [key, val] of Object.entries(source)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n if (val === null || val === undefined) continue;\n if (typeof val === \"string\") {\n out[fullKey] = val;\n } else if (typeof val === \"object\" && !Array.isArray(val)) {\n Object.assign(\n out,\n flattenMessages(val as Record<string, unknown>, fullKey),\n );\n } else if (typeof console !== \"undefined\") {\n console.warn(\n `[numu] locale key '${fullKey}' has non-string value (${typeof val}); skipped.`,\n );\n }\n }\n return out;\n}\n\n/**\n * Resolve the messages map for the requested locale, falling back to\n * \"en\" then \"en.default\" then an empty map. Missing keys in the\n * requested locale are filled from \"en\" (so an Arabic translation\n * file with 90% coverage doesn't show empty strings for the missing\n * 10%; English shows through).\n */\nexport function pickTranslations(\n bundle: LocaleBundle,\n locale: string,\n): LocaleMessages {\n const fallback = bundle[\"en\"] || bundle[\"en.default\"] || {};\n const requested = bundle[locale];\n if (!requested) return fallback;\n // Merge: fallback < requested. The requested locale wins per-key;\n // any key the requested locale doesn't define falls through to en.\n return { ...fallback, ...requested };\n}\n\n/**\n * Build a LocaleBundle from raw imports. Themes call this in their\n * `main.tsx` after a Vite glob import:\n *\n * const localeModules = import.meta.glob<Record<string, unknown>>(\n * \"./locales/*.json\", { eager: true, import: \"default\" });\n * const translations = buildLocaleBundle(localeModules);\n *\n * `localeModules` keys are paths like `./locales/ar.json`; we strip\n * the directory + extension to get the locale code, and flatten each\n * value.\n */\nexport function buildLocaleBundle<T extends Record<string, unknown>>(\n modules: T,\n): LocaleBundle {\n const bundle: LocaleBundle = {};\n for (const [path, raw] of Object.entries(modules)) {\n const m = /\\/([^/]+)\\.json$/.exec(path);\n if (!m) continue;\n let code = m[1];\n // `en.default` → keep as-is so pickTranslations can find it; theme\n // devs naming the file that way is a soft signal that this is the\n // canonical English source.\n if (code !== \"en.default\") {\n // Strip trailing \".default\" from any other code (someone might\n // write `ar.default.json` by mistake).\n code = code.replace(/\\.default$/, \"\");\n }\n const value = raw as unknown;\n if (typeof value === \"object\" && value !== null) {\n bundle[code] = flattenMessages(value as Record<string, unknown>);\n }\n }\n return bundle;\n}\n"]}