@fayz-ai/storefront 0.84.3 → 0.84.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CheckoutPage-4MFKLBEI.js +12 -0
- package/dist/{CheckoutPage-G5NYJF3Z.js.map → CheckoutPage-4MFKLBEI.js.map} +1 -1
- package/dist/MyPurchasesPage-F25MIFXT.js +11 -0
- package/dist/{MyPurchasesPage-GOK2RO7K.js.map → MyPurchasesPage-F25MIFXT.js.map} +1 -1
- package/dist/OrderConfirmationPage-SOQDD767.js +10 -0
- package/dist/{OrderConfirmationPage-DGLW5W75.js.map → OrderConfirmationPage-SOQDD767.js.map} +1 -1
- package/dist/{chunk-P4RRFQQX.js → chunk-BR3XHNVM.js} +5 -5
- package/dist/{chunk-P4RRFQQX.js.map → chunk-BR3XHNVM.js.map} +1 -1
- package/dist/{chunk-RZWTEC6H.js → chunk-C4XATNI2.js} +3 -3
- package/dist/{chunk-RZWTEC6H.js.map → chunk-C4XATNI2.js.map} +1 -1
- package/dist/{chunk-45R7CIEA.js → chunk-CE4U65TZ.js} +4 -4
- package/dist/{chunk-45R7CIEA.js.map → chunk-CE4U65TZ.js.map} +1 -1
- package/dist/{chunk-2D5BEM43.js → chunk-EFHQ5MAJ.js} +3 -3
- package/dist/{chunk-2D5BEM43.js.map → chunk-EFHQ5MAJ.js.map} +1 -1
- package/dist/{chunk-UJ2TIM4V.js → chunk-ELW7QWDJ.js} +13 -12
- package/dist/chunk-ELW7QWDJ.js.map +1 -0
- package/dist/{chunk-F3U4KZC7.js → chunk-IUP5SDTX.js} +5 -5
- package/dist/{chunk-F3U4KZC7.js.map → chunk-IUP5SDTX.js.map} +1 -1
- package/dist/{chunk-ZSNKJGE5.js → chunk-NS6UPIJ3.js} +3 -3
- package/dist/{chunk-ZSNKJGE5.js.map → chunk-NS6UPIJ3.js.map} +1 -1
- package/dist/{chunk-FPFGRUCS.js → chunk-OOQRYH3N.js} +6 -6
- package/dist/{chunk-FPFGRUCS.js.map → chunk-OOQRYH3N.js.map} +1 -1
- package/dist/{chunk-GVZ2SAOI.js → chunk-PSDR5TZD.js} +3 -2
- package/dist/chunk-PSDR5TZD.js.map +1 -0
- package/dist/{chunk-PURHMU2W.js → chunk-RJUEUMR6.js} +4 -4
- package/dist/{chunk-PURHMU2W.js.map → chunk-RJUEUMR6.js.map} +1 -1
- package/dist/{chunk-BKO2AQ3Q.js → chunk-SLJ4BRXD.js} +3 -3
- package/dist/{chunk-BKO2AQ3Q.js.map → chunk-SLJ4BRXD.js.map} +1 -1
- package/dist/{chunk-YSQBZ3RM.js → chunk-YCAWAON6.js} +7 -7
- package/dist/{chunk-YSQBZ3RM.js.map → chunk-YCAWAON6.js.map} +1 -1
- package/dist/{chunk-554XAQWK.js → chunk-YDZU2SZL.js} +4 -4
- package/dist/{chunk-554XAQWK.js.map → chunk-YDZU2SZL.js.map} +1 -1
- package/dist/{chunk-WSHCQ3Y6.js → chunk-Z5JT7T4I.js} +8 -8
- package/dist/{chunk-WSHCQ3Y6.js.map → chunk-Z5JT7T4I.js.map} +1 -1
- package/dist/components/delivery/StoreCover.d.ts.map +1 -1
- package/dist/document/config.d.ts +8 -0
- package/dist/document/config.d.ts.map +1 -1
- package/dist/host.js +4 -4
- package/dist/index.js +22 -22
- package/dist/render.js +9 -9
- package/dist/tanstack.js +8 -8
- package/package.json +2 -2
- package/dist/CheckoutPage-G5NYJF3Z.js +0 -12
- package/dist/MyPurchasesPage-GOK2RO7K.js +0 -11
- package/dist/OrderConfirmationPage-DGLW5W75.js +0 -10
- package/dist/chunk-GVZ2SAOI.js.map +0 -1
- package/dist/chunk-UJ2TIM4V.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/analytics/bus.ts","../src/app/hydration.ts","../src/views/StorefrontPage.tsx","../src/extend/slots.tsx","../src/extend/extension-points.ts","../src/stores/buyer.store.ts","../src/hooks/use-buyer-country.ts","../src/locales/index.ts","../src/hooks/use-discount-validator.ts","../src/stores/toast.store.ts","../src/components/account/SignInModal.tsx","../src/app/return-path.ts"],"names":["createContext","useContext","useMemo","repairBlockTree","jsx","renderBlocks","s","useCallback","create","toast","useState","useEffect"],"mappings":"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","file":"chunk-FPFGRUCS.js","sourcesContent":["/**\n * The storefront's own record of what a shopper does, kept apart from any\n * analytics vendor: components report here, and whatever is listening (the\n * PostHog client, a test, nothing) decides what to do with it.\n *\n * The page's recent events are kept and handed to every listener when it\n * starts, so the first product view of a page load reaches a client that is\n * still loading — each listener hears each event once.\n */\n\nexport type StorefrontEventName =\n | 'product_viewed'\n | 'product_added_to_cart'\n | 'product_removed_from_cart'\n | 'cart_viewed'\n | 'coupon_applied'\n | 'checkout_started'\n | 'checkout_step_viewed'\n | 'checkout_payment_selected'\n | 'checkout_error'\n | 'checkout_completed'\n | 'delivery_exit'\n /** A visitor saw an experiment's variant (see `useExperiment`). Once per page view and experiment. */\n | 'experiment_exposed'\n\nexport type StorefrontEventProperties = Record<string, string | number | boolean | null | undefined>\n\nexport interface StorefrontEvent {\n name: StorefrontEventName\n properties: StorefrontEventProperties\n at: number\n}\n\ntype Listener = (event: StorefrontEvent) => void\ntype Identifier = (email: string) => void\n\nconst MAX_PENDING = 50\nconst listeners = new Set<Listener>()\nlet pending: StorefrontEvent[] = []\nlet identifier: Identifier | null = null\nlet pendingEmail: string | null = null\n// Other sinks that want the buyer (the Meta Pixel's advanced matching). The\n// last e-mail is kept so a sink that starts late still gets it.\nconst buyerListeners = new Set<Identifier>()\nlet lastEmail: string | null = null\nconst lastAt = new Map<StorefrontEventName, number>()\n\nexport function trackStorefront(name: StorefrontEventName, properties: StorefrontEventProperties = {}): void {\n if (typeof window === 'undefined') return\n const event: StorefrontEvent = { name, properties, at: Date.now() }\n lastAt.set(name, event.at)\n // Every event is kept (the last MAX_PENDING), not only the ones reported\n // before the FIRST listener: a sink that starts later — the Meta Pixel, whose\n // id arrives with the store's settings — still hears the page's first\n // product view instead of losing it to PostHog having started first.\n pending.push(event)\n if (pending.length > MAX_PENDING) pending = pending.slice(-MAX_PENDING)\n for (const listener of listeners) {\n try { listener(event) } catch { /* a listener never breaks the store */ }\n }\n}\n\nexport function onStorefrontEvent(listener: Listener): () => void {\n listeners.add(listener)\n for (const event of pending) {\n try { listener(event) } catch { /* ignore */ }\n }\n return () => { listeners.delete(listener) }\n}\n\n/**\n * The buyer said who they are (the checkout's e-mail). Handed to the analytics\n * client to tie this visit to the orders the server reports; never sent on as\n * an event property.\n */\nexport function identifyStorefrontBuyer(email: string): void {\n const clean = email.trim().toLowerCase()\n if (!clean.includes('@')) return\n if (identifier) identifier(clean)\n else pendingEmail = clean\n lastEmail = clean\n for (const listener of buyerListeners) {\n try { listener(clean) } catch { /* a listener never breaks the store */ }\n }\n}\n\n/** Hear the buyer's e-mail (now, if already known, and on every change). */\nexport function onStorefrontBuyer(listener: Identifier): () => void {\n buyerListeners.add(listener)\n if (lastEmail) {\n try { listener(lastEmail) } catch { /* ignore */ }\n }\n return () => { buyerListeners.delete(listener) }\n}\n\nexport function setStorefrontIdentifier(fn: Identifier | null): void {\n identifier = fn\n if (fn && pendingEmail) {\n fn(pendingEmail)\n pendingEmail = null\n }\n}\n\n/** When this event was last reported on this page (0 = never). */\nexport function lastStorefrontEventAt(name: StorefrontEventName): number {\n return lastAt.get(name) ?? 0\n}\n\n/** Test seam: forget listeners and held events. */\nexport function resetStorefrontEvents(): void {\n listeners.clear()\n pending = []\n identifier = null\n pendingEmail = null\n buyerListeners.clear()\n lastEmail = null\n lastAt.clear()\n}\n","import type { PageDataEntry } from '../blocks/page-data'\n\n// ---------------------------------------------------------------------------\n// Carrying the server's answers into the browser.\n//\n// Server-rendered HTML is only half of SSR. Without the data that produced it,\n// the browser mounts, finds every need unresolved, and refetches the whole page\n// — so the shopper sees correct content flash to skeletons and back, the\n// provider is hit twice per visit, and the render cost was spent for nothing.\n//\n// `PageDataScope` already accepts `initial`. This is the wire: the renderer\n// serialises what it resolved, the browser reads it once, and the first client\n// render matches the server's markup instead of replacing it.\n// ---------------------------------------------------------------------------\n\n/** Where the payload lives in the document. */\nexport const PAGE_DATA_SCRIPT_ID = '__fayz_page_data__'\n\nexport interface HydrationPayload {\n /** Resolved page data, keyed by `dataNeedKey`. */\n entries: Record<string, PageDataEntry>\n /** The path the server rendered, so a mismatch is detectable rather than silent. */\n path: string\n}\n\n/**\n * Escape a JSON payload for embedding in a `<script>`.\n *\n * `</script>` inside a product description would otherwise close the tag early\n * and drop the rest of the document into the page as markup — the same class of\n * bug as unescaped JSON-LD, with a worse blast radius. `<` is escaped rather\n * than the closing sequence alone so no casing or whitespace variant slips past.\n */\nfunction escapeScriptJson(value: unknown): string {\n return JSON.stringify(value)\n .replace(/</g, '\\\\u003c')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029')\n}\n\n/**\n * The `<script>` tag carrying `payload`, for a renderer to place in the body.\n *\n * Only `ready` entries are carried. An entry that errored server-side is\n * deliberately dropped so the browser retries it: a transient provider failure\n * during a prerender would otherwise be baked into the page for as long as the\n * HTML is cached.\n */\nexport function serializePageData(payload: HydrationPayload): string {\n const ready: Record<string, PageDataEntry> = {}\n for (const [key, entry] of Object.entries(payload.entries)) {\n if (entry.status === 'ready') ready[key] = entry\n }\n const json = escapeScriptJson({ entries: ready, path: payload.path })\n return `<script id=\"${PAGE_DATA_SCRIPT_ID}\" type=\"application/json\">${json}</script>`\n}\n\nlet _read = false\nlet _cache: HydrationPayload | null = null\n\n/**\n * The payload this document was rendered with, or null.\n *\n * Read once and memoised: the tag describes the FIRST render only. After a\n * client-side navigation the document still contains it, and re-reading would\n * seed a new page with the previous one's data.\n */\nexport function readHydratedPageData(): HydrationPayload | null {\n if (_read) return _cache\n _read = true\n if (typeof document === 'undefined') return (_cache = null)\n const el = document.getElementById(PAGE_DATA_SCRIPT_ID)\n if (!el?.textContent) return (_cache = null)\n try {\n _cache = JSON.parse(el.textContent) as HydrationPayload\n } catch {\n // Malformed payload is a bug, but refetching is a correct fallback — never\n // let it take down a page that already rendered.\n _cache = null\n }\n return _cache\n}\n\n/**\n * Entries to seed a page at `path`, or undefined.\n *\n * Path-guarded: the payload belongs to the document the server rendered, so\n * handing it to a different route would seed that route with another page's\n * answers. Query strings are ignored — they address state within a page.\n */\nexport function hydratedEntriesFor(path: string): Record<string, PageDataEntry> | undefined {\n const payload = readHydratedPageData()\n if (!payload) return undefined\n const same = (a: string, b: string) => (a.split('?')[0] || '/') === (b.split('?')[0] || '/')\n return same(payload.path, path) ? payload.entries : undefined\n}\n\n/** Test seam: forget the memoised read. */\nexport function resetHydratedPageData(): void {\n _read = false\n _cache = null\n}\n","import React, { createContext, useContext, useMemo } from 'react'\nimport { renderBlocks, repairBlockTree } from '@fayz-ai/core'\nimport type { BlockNode, BlockTreeRepair } from '@fayz-ai/core'\nimport { checkPageBlocks, defaultPageBlocks, toBlockNodes } from '../blocks/page-blocks'\nimport type { StorefrontPageKind, StorefrontPageConfig } from '../blocks/page-blocks'\nimport type { ResolvedStorefrontConfig } from '../document/config'\nimport { PageDataScope } from '../blocks/page-data'\nimport { hydratedEntriesFor } from '../app/hydration'\nimport { useRoutePath } from '../app/router'\n\n// ---------------------------------------------------------------------------\n// One renderer for every composed page.\n//\n// The page kind and its route params travel by context rather than by props,\n// because the consumers are blocks — arbitrarily deep in a tree the page did not\n// author. `productBody` needs the slug; a store's own block placed on the PDP\n// wants the same product without the store having to thread it. Fase 3's slots\n// read this same context, which is why it is a page-level concern and not a\n// parameter of the body block.\n// ---------------------------------------------------------------------------\n\nexport interface StorefrontPageContextValue {\n kind: StorefrontPageKind\n /** Route params for the current page (`slug` on product and collection). */\n params: Record<string, string>\n}\n\nconst PageContext = createContext<StorefrontPageContextValue | null>(null)\n\nexport const StorefrontPageProvider = PageContext.Provider\n\n/** The page a block is rendering inside. Throws outside a composed page, because\n * a block reading page context off a page is a bug worth surfacing loudly. */\nexport function useStorefrontPage(): StorefrontPageContextValue {\n const ctx = useContext(PageContext)\n if (!ctx) throw new Error('useStorefrontPage must be used inside a storefront page')\n return ctx\n}\n\n/** The page a block is rendering inside, or null — for blocks that work on any surface. */\nexport function useStorefrontPageOptional(): StorefrontPageContextValue | null {\n return useContext(PageContext)\n}\n\n// Diagnostics are printed once per distinct tree, not once per render: a config\n// mistake is worth saying loudly, and worth saying only once.\n//\n// Not gated to development. Every finding here describes a page that is already\n// visibly wrong to a shopper — an unregistered block renders a marker, a missing\n// body block renders no products — so a store hitting one in production is\n// better off with the reason in the console than without it.\nconst reported = new Set<string>()\n\nfunction reportDiagnostics(\n kind: StorefrontPageKind,\n nodes: readonly BlockNode[],\n repairs: readonly BlockTreeRepair[],\n): void {\n const signature = `${kind}:${nodes.map((n) => `${n.type}#${n.id ?? ''}`).join(',')}`\n if (reported.has(signature)) return\n reported.add(signature)\n\n for (const repair of repairs) {\n // A repair means the page RENDERS correctly but the composition is missing\n // a block it cannot function without — say so, so the config gets fixed\n // instead of silently diverging from what the shopper sees.\n console.warn(\n `[storefront] forced-layout: re-inserted required block \"${repair.inserted}\" at ${repair.path}[${repair.index}] on the ${kind} page — add it to the composition`,\n )\n }\n\n for (const finding of checkPageBlocks(kind, nodes)) {\n const message = `[storefront] ${finding.rule}: ${finding.detail}`\n if (finding.level === 'error') console.error(message)\n else console.warn(message)\n }\n}\n\n/** Reset the once-per-tree diagnostic memo. Test seam. */\nexport function resetPageDiagnostics(): void {\n reported.clear()\n}\n\nexport interface StorefrontPageProps {\n kind: StorefrontPageKind\n /** The store's composition for this page. Omitted falls back to the SDK default. */\n page?: StorefrontPageConfig\n params?: Record<string, string>\n}\n\n/**\n * Render a page as a block tree.\n *\n * A store that has not composed the page gets `defaultPageBlocks(kind)` — the\n * native body alone — so adopting `pages` changes nothing until something is\n * actually added around it.\n */\nexport function StorefrontPage({ kind, page, params = {} }: StorefrontPageProps) {\n // The path this page is rendering, so hydrated data is matched to the route\n // it was resolved for rather than handed to whatever renders next.\n const routePath = useRoutePath()\n const { nodes, repairs } = useMemo(() => {\n const authored = page?.blocks ? toBlockNodes(page.blocks) : defaultPageBlocks(kind)\n // Forced-layout repair (I7): a tree that lost a block it cannot function\n // without gets it re-inserted at the template index before rendering —\n // repair what is recoverable, reject (validateStore) what is checkable.\n const repaired = repairBlockTree(authored)\n return { nodes: repaired.nodes as BlockNode[], repairs: repaired.repairs }\n }, [page, kind])\n\n reportDiagnostics(kind, nodes, repairs)\n\n const ctx = useMemo<StorefrontPageContextValue>(() => ({ kind, params }), [kind, params])\n\n return (\n <StorefrontPageProvider value={ctx}>\n {/* Data needs are collected from the REPAIRED tree — a re-inserted\n required block gets its data like any authored one — and resolved\n once for the whole page (M3). */}\n {/* Seeded with whatever the server already resolved for THIS path, so the\n first client render matches the served HTML instead of replacing it\n with skeletons and refetching. Undefined in a pure SPA. */}\n <PageDataScope nodes={nodes} params={params} initial={hydratedEntriesFor(routePath)}>\n {/* The document path of this page's block array, so a rendered block\n carries its own address back (editor mode only — see core/blocks\n setBlockEditorMode). `content` is a map keyed by slug rather than a\n singular page, so it gets no path until the editor needs one; the\n four singular kinds are where editing happens. */}\n <main>{renderBlocks(nodes, kind === 'content' ? undefined : `presentation.pages.${kind}.blocks`)}</main>\n </PageDataScope>\n </StorefrontPageProvider>\n )\n}\n\n/** The composition for a SINGULAR page kind, if the store declared one.\n * `content` pages are a map keyed by slug — resolve those with\n * `matchContentPage` instead. */\nexport function pageConfigFor(\n config: ResolvedStorefrontConfig,\n kind: Exclude<StorefrontPageKind, 'content'>,\n): StorefrontPageConfig | undefined {\n return config.pages?.[kind]\n}\n","import React, { createContext, useContext, useMemo } from 'react'\nimport { renderBlocks, repairBlockTree } from '@fayz-ai/core'\nimport type { Product } from '@fayz-ai/shop/types'\nimport { toBlockNodes } from '../blocks/page-blocks'\nimport type { StorefrontBlockLike } from '../blocks/page-blocks'\nimport { useStorefrontConfigOptional } from '../document/config'\nimport { PageDataScope } from '../blocks/page-data'\nimport { useStorefrontPageOptional } from '../views/StorefrontPage'\nimport type { CartLine } from '../stores/cart.store'\n\n// ---------------------------------------------------------------------------\n// Named slots — the missing rung.\n//\n// Between \"configure a section\" and \"rewrite the page\" there was nothing. So\n// every store that needed one store-specific thing inside an SDK page took the\n// only rung available and rewrote the page, inheriting its maintenance forever.\n// The cost is measurable: one store reimplemented the product page and, in doing\n// so, silently dropped option selection, quantity and add-to-cart, because\n// reimplementing a page means reimplementing everything the page did.\n//\n// Prior art: Shopify's theme app extensions — an app block drops into a named\n// location in a template it does not own. Same shape, same reason.\n//\n// Two decisions worth stating:\n//\n// Slots take BLOCK TREES, not components. A slot holding a component is code,\n// which means it cannot be edited by the visual editor, generated by the agent,\n// or serialized into a manifest. A slot holding blocks is the same currency as\n// the rest of the system.\n//\n// Slot content receives typed context. The point of `afterPrice` is to say\n// something about THIS product; a slot that cannot see the product is a slot\n// that can only hold static copy.\n// ---------------------------------------------------------------------------\n\n/** What each slot area hands to the blocks inside it. */\nexport interface StorefrontSlotContextMap {\n productDetail: {\n product: Product\n soldOut: boolean\n lowStock: boolean\n /** Percent off, or 0 when the product is not discounted. */\n discountPct: number\n }\n /**\n * The card, which renders once per product in a grid — so its context is the\n * one product that card is for, not the list.\n */\n productCard: {\n product: Product\n soldOut: boolean\n onSale: boolean\n /** True when the product has variants, so quick-add routes to the PDP. */\n hasOptions: boolean\n }\n catalog: {\n /** The products currently visible, after filters and search. */\n products: readonly Product[]\n /** True while the list is being fetched. */\n loading: boolean\n }\n /**\n * The delivery menu. One context for its three positions: what the shopper\n * is shown and the actions the menu itself would take, so a store's block\n * opens and adds exactly like the SDK's own rows (closed-store guard, toast,\n * options sheet) instead of clicking hidden buttons.\n */\n menu: {\n /** The cover as drawn for this visitor (it can be an A/B variant). */\n coverSize: 'full' | 'compact'\n /** The products the menu highlights, in order. */\n highlights: readonly Product[]\n /** The section a `sectionIntro` sits in; null in the other positions. */\n section: MenuSlotSection | null\n /** Opens the product's sheet, as tapping a row does. */\n openProduct: (product: Product) => void\n /** The one-tap add for `product`, or undefined when it needs its sheet\n * (options) or is sold out — then show it as such, not as addable. */\n quickAdd: (product: Product) => (() => void) | undefined\n }\n cart: { lines: readonly CartLine[]; subtotal: number }\n checkout: { subtotal: number; total: number }\n header: Record<string, never>\n footer: Record<string, never>\n}\n\n/** A menu section, as `menu.sectionIntro` sees it. */\nexport interface MenuSlotSection {\n slug: string\n name: string\n description: string | null\n products: readonly Product[]\n}\n\nexport type StorefrontSlotArea = keyof StorefrontSlotContextMap\n\ntype SlotBlocks = readonly StorefrontBlockLike[]\n\n/**\n * Where a store may graft blocks into an SDK page.\n *\n * Position names read as \"where\", not \"what\": `afterPrice` keeps meaning the\n * same thing if the price stops being a `<Price>` and starts being something\n * else, which a name like `priceBelowSlot` would not.\n */\nexport interface StorefrontSlots {\n productDetail?: {\n /** Between the breadcrumb and the product name. */\n beforeTitle?: SlotBlocks\n /** Immediately under the product name, above the price. */\n afterTitle?: SlotBlocks\n /** Under the price and discount badge. */\n afterPrice?: SlotBlocks\n /** Under the description paragraph. */\n afterDescription?: SlotBlocks\n /** Above the quantity + add-to-cart row. Where trust seals go. */\n beforeAddToCart?: SlotBlocks\n /** Under the add-to-cart row, above the delivery estimate. */\n afterAddToCart?: SlotBlocks\n /** Under the gallery column, in the left half of the page. */\n afterGallery?: SlotBlocks\n /** Above the specification table, below the two-column fold. */\n beforeSpecs?: SlotBlocks\n /** The bottom of the page, after related products. */\n afterDetail?: SlotBlocks\n }\n /**\n * The product card, wherever it appears — grid, rail, slider, related.\n *\n * This is where the fleet actually hurt: four of five customizing stores\n * forked a ~120-line card to add one thing to it, and each fork then lost\n * something else (the sale badge, the variant guard, `commerceMode` gating,\n * `theme.productCard` honouring).\n */\n productCard?: {\n /** Above the image, full card width. */\n top?: SlotBlocks\n /** Over the image. The container is `relative`; content positions itself. */\n imageOverlay?: SlotBlocks\n /** Between the product name and the price row. */\n afterName?: SlotBlocks\n /** Under the price row. */\n underPrice?: SlotBlocks\n }\n catalog?: {\n /** Above the page heading. */\n beforeHeading?: SlotBlocks\n /** Between the heading and the filters/grid row. */\n beforeGrid?: SlotBlocks\n /** Inside the filter column, under the filters. */\n afterFilters?: SlotBlocks\n /** Under the product grid. */\n afterGrid?: SlotBlocks\n }\n /**\n * The delivery menu. Server-rendered with the page — the reason these exist:\n * a store that grafted its own cover copy, highlight carousel and section\n * banners in with DOM portals after hydration got them on the client only,\n * so the layout shifted when they arrived and their images were found late.\n */\n menu?: {\n /** Inside the cover, after its own content. The cover is `relative`\n * (and `isolate`); content positions itself. */\n coverOverlay?: SlotBlocks\n /**\n * Inside the highlights section, under its heading. When filled it\n * REPLACES the default highlight rows — a store showing its highlights as\n * a carousel must not render the rows too and hide them with CSS.\n */\n highlights?: SlotBlocks\n /** The top of each category section, above its heading. */\n sectionIntro?: SlotBlocks\n }\n cart?: {\n /** Above the line items. */\n beforeLines?: SlotBlocks\n /** Between the lines and the totals. */\n beforeSummary?: SlotBlocks\n /** Under the totals, around the checkout button. */\n afterSummary?: SlotBlocks\n }\n checkout?: {\n /** Above the checkout form. */\n beforeForm?: SlotBlocks\n /** Under the payment method selector. */\n afterPaymentMethods?: SlotBlocks\n /** Under the whole form, around the place-order button. */\n afterForm?: SlotBlocks\n }\n header?: {\n /**\n * Left of the account/cart icons.\n *\n * Named for the actions row rather than for the header, because the header\n * has three layout variants (default, centered, search) that place the logo\n * differently. A slot \"left of the logo\" would land somewhere different in\n * each one; the actions row is shared, so this position is the same in all\n * three.\n */\n beforeActions?: SlotBlocks\n /** Right of the cart icon. */\n afterActions?: SlotBlocks\n /** A full-width strip under the whole header, in every variant. */\n belowNav?: SlotBlocks\n }\n footer?: {\n /** Above the footer columns. */\n before?: SlotBlocks\n /** Under the footer columns, above the credit line. */\n after?: SlotBlocks\n }\n}\n\n// --- The inventory, as data ---------------------------------------------------\n\nexport interface SlotDescriptor {\n area: StorefrontSlotArea\n name: string\n /** Dotted id used in diagnostics and docs. */\n id: string\n /** Where this slot sits in the page. */\n position: string\n /** Keys the blocks inside receive through `useSlotContext`. */\n provides: readonly string[]\n /**\n * `stable` means a store in our fleet actually needed this position and paid\n * for it by forking something; `experimental` means the position is plausible\n * but unproven and may move or be removed in a minor.\n *\n * The distinction is not decoration. Every slot is a compatibility promise,\n * and a surface that promises two dozen positions nobody asked for is a\n * surface that cannot be changed later. FastStore marks unproven API with an\n * `__experimental` prefix for the same reason; this is the same idea as a\n * field, so `fayz upgrade` can tell a store which unproven slots it depends on.\n */\n stability: 'stable' | 'experimental'\n /** For stable slots: the fork that proves the position was needed. */\n evidence?: string\n}\n\nconst PRODUCT_DETAIL_CONTEXT = ['product', 'soldOut', 'lowStock', 'discountPct'] as const\nconst PRODUCT_CARD_CONTEXT = ['product', 'soldOut', 'onSale', 'hasOptions'] as const\nconst CATALOG_CONTEXT = ['products', 'loading'] as const\nconst MENU_CONTEXT = ['coverSize', 'highlights', 'section', 'openProduct', 'quickAdd'] as const\nconst CART_CONTEXT = ['lines', 'subtotal'] as const\nconst CHECKOUT_CONTEXT = ['subtotal', 'total'] as const\n\n/**\n * Every slot, with its position, the context it provides, and whether a real\n * store ever asked for it.\n *\n * Shipped as data rather than written in prose because a prose inventory drifts\n * the first time a slot is added. The docs page and the agent's prompt both read\n * this, so there is one list and it is the code's.\n *\n * Six slots are `stable`: a store in the fleet needed that exact position and\n * paid for it by forking a page or a component. The rest are `experimental` —\n * plausible positions with no proven demand yet. Marking them honestly is what\n * keeps the surface changeable; a store that builds on one is told, by\n * `fayz upgrade`, that it did.\n */\nexport const STOREFRONT_SLOTS: readonly SlotDescriptor[] = [\n x('productDetail', 'beforeTitle', 'between the breadcrumb and the product name', PRODUCT_DETAIL_CONTEXT),\n x('productDetail', 'afterTitle', 'under the product name, above the price', PRODUCT_DETAIL_CONTEXT),\n x('productDetail', 'afterPrice', 'under the price and discount badge', PRODUCT_DETAIL_CONTEXT),\n // The one PDP position with proof: this store put a Materials/Symbolism/\n // Availability <dl> exactly here, and reimplementing the page to do it cost it\n // the gallery, option selection, quantity, specs, related products and every\n // head tag on every product page.\n s(\n 'productDetail',\n 'afterDescription',\n 'under the description paragraph, above the actions',\n PRODUCT_DETAIL_CONTEXT,\n 'cristinarotondaro-shop/src/storefront/components/product.tsx:71-86',\n ),\n x('productDetail', 'beforeAddToCart', 'above the quantity and add-to-cart row', PRODUCT_DETAIL_CONTEXT),\n x('productDetail', 'afterAddToCart', 'under the add-to-cart row', PRODUCT_DETAIL_CONTEXT),\n x('productDetail', 'afterGallery', 'under the gallery, in the left column', PRODUCT_DETAIL_CONTEXT),\n x('productDetail', 'beforeSpecs', 'above the specification table', PRODUCT_DETAIL_CONTEXT),\n s(\n 'productDetail',\n 'afterDetail',\n 'the bottom of the page, after related products',\n PRODUCT_DETAIL_CONTEXT,\n 'cristinarotondaro-shop/src/storefront/components/product.tsx:95-102 (enquiry panel)',\n ),\n // The four card positions. Three are stable on the strength of the fleet: this\n // is the component our stores forked most, and every fork lost something.\n s(\n 'productCard',\n 'afterName',\n 'between the product name and the price row',\n PRODUCT_CARD_CONTEXT,\n 'pulse-store PulseProductCard.tsx:70-76; artorious ArtoriusProductCard.tsx:107-118; compactor CompactorProductCard.tsx:99; cristinarotondaro product.tsx:34 — 4 of 5',\n ),\n s(\n 'productCard',\n 'imageOverlay',\n 'over the image; the container is relative, content positions itself',\n PRODUCT_CARD_CONTEXT,\n 'pulse PulseProductCard.tsx:40-44; artorious ArtoriusProductCard.tsx:67-92 — 3 of 5',\n ),\n s(\n 'productCard',\n 'underPrice',\n 'under the price row',\n PRODUCT_CARD_CONTEXT,\n 'compactor CompactorProductCard.tsx:104 (Pix + installment lines); config.payments.terms already exists for it',\n ),\n x('productCard', 'top', 'above the image, full card width', PRODUCT_CARD_CONTEXT),\n s(\n 'catalog',\n 'beforeHeading',\n 'above the catalog heading',\n CATALOG_CONTEXT,\n 'cristinarotondaro-shop/src/storefront/customization.tsx:414-426 (category hero)',\n ),\n s(\n 'catalog',\n 'beforeGrid',\n 'between the heading and the grid',\n CATALOG_CONTEXT,\n 'cristinarotondaro-shop/src/storefront/customization.tsx:427-429 (statement band)',\n ),\n x('catalog', 'afterFilters', 'inside the filter column, under the filters', CATALOG_CONTEXT),\n s(\n 'catalog',\n 'afterGrid',\n 'under the product grid',\n CATALOG_CONTEXT,\n 'cristinarotondaro-shop/src/storefront/customization.tsx:442-450 (bespoke empty state)',\n ),\n // The three menu positions are stable on one store's proof: Artorius put\n // its cover copy, a highlights carousel and per-category banners into the\n // SDK menu with portals after mount, and paid for it with a 0.24 layout\n // shift and a highlight image (its LCP) discovered only after hydration.\n s('menu', 'coverOverlay', 'inside the menu cover, after its own content', MENU_CONTEXT, 'artorious-shop src/custom/components/DeliveryBanners.tsx (hero copy portal)'),\n s('menu', 'highlights', 'inside the highlights section, replacing the default rows', MENU_CONTEXT, 'artorious-shop src/custom/components/DeliveryHighlightsCarousel.tsx (carousel portal + CSS hiding the rows)'),\n s('menu', 'sectionIntro', 'the top of each menu section, above its heading', MENU_CONTEXT, 'artorious-shop src/custom/components/DeliveryBanners.tsx (category banner portals)'),\n x('cart', 'beforeLines', 'above the cart line items', CART_CONTEXT),\n x('cart', 'beforeSummary', 'between the lines and the totals', CART_CONTEXT),\n s(\n 'cart',\n 'afterSummary',\n 'under the totals, around the checkout button',\n CART_CONTEXT,\n 'artorious-shop/docs/TODO.md:167-179; the CartDrawerFooterExtra contract exists for it',\n ),\n x('checkout', 'beforeForm', 'above the checkout form', CHECKOUT_CONTEXT),\n x('checkout', 'afterPaymentMethods', 'under the payment method selector', CHECKOUT_CONTEXT),\n x('checkout', 'afterForm', 'under the form, around the place-order button', CHECKOUT_CONTEXT),\n x('header', 'beforeActions', 'left of the account and cart icons', []),\n x('header', 'afterActions', 'right of the cart icon', []),\n x('header', 'belowNav', 'a full-width strip under the whole header', []),\n x('footer', 'before', 'above the footer columns', []),\n x('footer', 'after', 'under the footer columns, above the credit line', []),\n]\n\n/** A slot with proven demand. */\nfunction s(\n area: StorefrontSlotArea,\n name: string,\n position: string,\n provides: readonly string[],\n evidence: string,\n): SlotDescriptor {\n return { area, name, id: `${area}.${name}`, position, provides, stability: 'stable', evidence }\n}\n\n/** A plausible position with no proven demand yet. */\nfunction x(\n area: StorefrontSlotArea,\n name: string,\n position: string,\n provides: readonly string[],\n): SlotDescriptor {\n return { area, name, id: `${area}.${name}`, position, provides, stability: 'experimental' }\n}\n\nexport interface ListSlotsOptions {\n area?: StorefrontSlotArea\n /** Keep only slots a store has actually proven it needs. */\n stableOnly?: boolean\n}\n\n/** The slot inventory, optionally narrowed. */\nexport function listSlots(\n areaOrOptions?: StorefrontSlotArea | ListSlotsOptions,\n): readonly SlotDescriptor[] {\n const options: ListSlotsOptions =\n typeof areaOrOptions === 'string' ? { area: areaOrOptions } : areaOrOptions ?? {}\n return STOREFRONT_SLOTS.filter(\n (slot) =>\n (!options.area || slot.area === options.area) &&\n (!options.stableOnly || slot.stability === 'stable'),\n )\n}\n\n/** The slots a store's config actually fills, with their stability. */\nexport function usedSlots(slots: StorefrontSlots | undefined): readonly SlotDescriptor[] {\n if (!slots) return []\n return STOREFRONT_SLOTS.filter((slot) => {\n const area = slots[slot.area] as Record<string, SlotBlocks> | undefined\n return Boolean(area?.[slot.name]?.length)\n })\n}\n\n// --- Runtime ------------------------------------------------------------------\n\nconst SlotContext = createContext<Record<string, unknown> | null>(null)\n\n/**\n * The context the surrounding slot provides.\n *\n * The type parameter is the caller's assertion about which area it is rendering\n * in, which is as much as a registry-resolved block can be given: the block is\n * looked up by string, so nothing at the call site knows its area statically.\n * Returns null outside a slot, so a block can work both in a slot and in a page.\n */\nexport function useSlotContext<A extends StorefrontSlotArea>(): StorefrontSlotContextMap[A] | null {\n return useContext(SlotContext) as StorefrontSlotContextMap[A] | null\n}\n\nexport interface SlotProps<A extends StorefrontSlotArea> {\n area: A\n name: string\n context?: StorefrontSlotContextMap[A]\n}\n\n/** Whether a store put anything in a slot — for positions whose content\n * REPLACES the page's own (`menu.highlights`). */\nexport function useSlotFilled(area: StorefrontSlotArea, name: string): boolean {\n const config = useStorefrontConfigOptional()\n return Boolean((config?.slots?.[area] as Record<string, SlotBlocks> | undefined)?.[name]?.length)\n}\n\n/**\n * Render the blocks a store put in one slot.\n *\n * The slot reads its own content out of the config rather than being handed it,\n * so a page places `<Slot area=\"productDetail\" name=\"afterPrice\" />` without\n * threading `config.slots` down to every position. That matters because there\n * are two dozen of these call sites and every threaded prop is a chance to wire\n * one to the wrong slot.\n *\n * Renders nothing — not even a wrapper — when the slot is empty, which is the\n * overwhelmingly common case. An always-present wrapper would change the layout\n * of every page for every store that uses no slots at all.\n */\nexport function Slot<A extends StorefrontSlotArea>({ area, name, context }: SlotProps<A>) {\n const config = useStorefrontConfigOptional()\n const page = useStorefrontPageOptional()\n const blocks = (config?.slots?.[area] as Record<string, SlotBlocks> | undefined)?.[name]\n // Same forced-layout repair as StorefrontPage: a slot tree that lost a\n // required child gets it back before rendering (I7).\n const nodes = useMemo(\n () => (blocks?.length ? repairBlockTree(toBlockNodes(blocks)).nodes : null),\n [blocks],\n )\n const value = useMemo(() => (context ?? {}) as Record<string, unknown>, [context])\n if (!nodes) return null\n // A slot tree resolves its data needs like a page tree (M3): its own scope,\n // nested under the page's, so needs the page already resolved are reused and\n // `$param` bindings see the surrounding page's route params.\n return (\n <SlotContext.Provider value={value}>\n <PageDataScope nodes={nodes} params={page?.params}>\n {renderBlocks(nodes, `presentation.slots.${area}.${name}`)}\n </PageDataScope>\n </SlotContext.Provider>\n )\n}\n","import { clearExtensionPoints, defineExtensionPoint, runEscapeValve, runExtensionPoint } from '@fayz-ai/core'\nimport type { Product } from '@fayz-ai/shop/types'\nimport type { CartLine } from '../stores/cart.store'\n\n// ---------------------------------------------------------------------------\n// The storefront's extension points — spine M7, deliberately FEW.\n//\n// WooCommerce's ExtendSchema discipline is the model: of hundreds of possible\n// seams, only the ones where extension is legitimate are extensible, each with\n// a validated schema, and extension data lands under a namespaced key. Our\n// four many-handler points cover the four asks the fleet has actually made\n// (annotate a cart line, stamp data on an order, badge a product card, add a\n// checkout field), plus exactly ONE escape valve on the one irreversible\n// operation (order creation — I4). Everything else stays closed until a real\n// second consumer exists; adding a point here is an API decision, not a\n// convenience.\n// ---------------------------------------------------------------------------\n\nexport const CART_LINE_ANNOTATION_POINT = 'cart.lineAnnotation'\nexport const ORDER_METADATA_POINT = 'order.metadata'\nexport const PRODUCT_CARD_BADGE_POINT = 'product.cardBadge'\nexport const CHECKOUT_FIELD_POINT = 'checkout.field'\nexport const BEFORE_PLACE_ORDER_VALVE = 'checkout.beforePlaceOrder'\n\n// --- Wire shapes (each mirrors its point's JSON Schema 1:1) -------------------\n\n/** Input of cart.lineAnnotation — one cart line, serializable. */\nexport interface CartLineAnnotationInput {\n productId: string\n name: string\n quantity: number\n unitPrice: number\n slug?: string\n optionsLabel?: string\n}\n\n/** Output of cart.lineAnnotation — one annotation chip under the line. */\nexport interface CartLineAnnotation {\n /** Stable machine key (namespacing is the handler id; this keys within it). */\n key: string\n /** Shopper-facing text. */\n label: string\n /** Optional machine value carried alongside the label. */\n value?: string\n}\n\nexport interface OrderMetadataInput {\n items: Array<{ productId: string; quantity: number; unitPrice: number }>\n subtotal: number\n customerEmail?: string\n}\n\nexport interface ProductCardBadgeInput {\n id: string\n slug: string\n name: string\n price: number\n inventoryCount: number\n compareAtPrice?: number | null\n}\n\nexport interface ProductCardBadge {\n text: string\n tone?: 'default' | 'accent' | 'warning'\n}\n\nexport interface CheckoutFieldInput {\n customerEmail?: string\n}\n\n/** Output of checkout.field — one extra field the checkout form renders. The\n * captured value lands in the order metadata under the handler's namespace. */\nexport interface CheckoutFieldContribution {\n id: string\n label: string\n type: 'text' | 'checkbox'\n required?: boolean\n placeholder?: string\n}\n\n/** Input of the beforePlaceOrder escape valve — the serializable placement\n * intent, BEFORE the default provider path runs. */\nexport interface BeforePlaceOrderContext {\n items: Array<{ productId: string; variantId?: string; quantity: number; optionsLabel?: string }>\n customer: { name: string; email: string }\n currency?: string\n discountCode?: string\n shippingTotal?: number\n notes?: string\n customerId?: string\n}\n\nlet registered = false\n\n/** Test seam — clears the whole extension registry (declarations AND\n * handlers) and re-arms registration, so one suite cannot leak handlers into\n * the next. Pairs with core's clearExtensionPoints. */\nexport function resetStorefrontExtensionPoints(): void {\n clearExtensionPoints()\n registered = false\n}\n\n/** Declare the storefront extension points. Idempotent; called wherever blocks\n * are registered, so describeStore and the runtime always agree on the set. */\nexport function registerStorefrontExtensionPoints(): void {\n if (registered) return\n registered = true\n\n defineExtensionPoint({\n id: CART_LINE_ANNOTATION_POINT,\n description:\n 'Annotate one cart line (gift wrap, engraving, availability note). Handlers see the line, return one annotation; annotations render under the line in the cart drawer.',\n source: 'sdk',\n since: '0.10',\n input: {\n type: 'object',\n properties: {\n productId: { type: 'string', minLength: 1 },\n name: { type: 'string' },\n quantity: { type: 'integer', minimum: 1 },\n unitPrice: { type: 'number', minimum: 0 },\n slug: { type: 'string' },\n optionsLabel: { type: 'string' },\n },\n required: ['productId', 'name', 'quantity', 'unitPrice'],\n additionalProperties: false,\n },\n output: {\n type: 'object',\n properties: {\n key: { type: 'string', minLength: 1 },\n label: { type: 'string', minLength: 1 },\n value: { type: 'string' },\n },\n required: ['key', 'label'],\n additionalProperties: false,\n },\n })\n\n defineExtensionPoint({\n id: ORDER_METADATA_POINT,\n description:\n 'Contribute machine-readable metadata to an order at placement. Each handler returns an object; contributions land on the order namespaced by handler id, so two extensions can never collide.',\n source: 'sdk',\n since: '0.10',\n input: {\n type: 'object',\n properties: {\n items: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n productId: { type: 'string' },\n quantity: { type: 'integer', minimum: 1 },\n unitPrice: { type: 'number', minimum: 0 },\n },\n required: ['productId', 'quantity', 'unitPrice'],\n },\n },\n subtotal: { type: 'number', minimum: 0 },\n customerEmail: { type: 'string' },\n },\n required: ['items', 'subtotal'],\n additionalProperties: false,\n },\n output: { type: 'object' },\n })\n\n defineExtensionPoint({\n id: PRODUCT_CARD_BADGE_POINT,\n description:\n 'Badge a product card (\"Novo\", \"Últimas unidades\", \"Frete grátis\"). Handlers see a product summary and return a badge; badges render next to the built-in sale/sold-out chips.',\n source: 'sdk',\n since: '0.10',\n input: {\n type: 'object',\n properties: {\n id: { type: 'string', minLength: 1 },\n slug: { type: 'string' },\n name: { type: 'string' },\n price: { type: 'number' },\n inventoryCount: { type: 'integer' },\n compareAtPrice: { type: ['number', 'null'] },\n },\n required: ['id', 'name', 'price'],\n additionalProperties: false,\n },\n output: {\n type: 'object',\n properties: {\n text: { type: 'string', minLength: 1, maxLength: 24 },\n tone: { type: 'string', enum: ['default', 'accent', 'warning'] },\n },\n required: ['text'],\n additionalProperties: false,\n },\n })\n\n defineExtensionPoint({\n id: CHECKOUT_FIELD_POINT,\n description:\n 'Contribute one extra field to the checkout form (CPF/CNPJ, gift message, marketing opt-in). The captured value is stored on the order metadata under the handler id.',\n source: 'sdk',\n since: '0.10',\n input: {\n type: 'object',\n properties: { customerEmail: { type: 'string' } },\n additionalProperties: false,\n },\n output: {\n type: 'object',\n properties: {\n id: { type: 'string', minLength: 1 },\n label: { type: 'string', minLength: 1 },\n type: { type: 'string', enum: ['text', 'checkbox'] },\n required: { type: 'boolean' },\n placeholder: { type: 'string' },\n },\n required: ['id', 'label', 'type'],\n additionalProperties: false,\n },\n })\n\n // The ONE escape valve on the storefront's one irreversible operation (I4).\n // WooCommerce's policy, adopted verbatim: always nullable, non-null return\n // short-circuits the default order creation. The registry enforces the\n // single-registrant rule, so this can never rot into a hook graph.\n defineExtensionPoint({\n id: BEFORE_PLACE_ORDER_VALVE,\n description:\n 'THE escape valve for order creation. One registrant maximum. Return null to take the default placeOrder path; return an Order to replace order creation entirely (external OMS, quote-first flows).',\n source: 'sdk',\n since: '0.10',\n mode: 'escape',\n input: {\n type: 'object',\n properties: {\n items: {\n type: 'array',\n minItems: 1,\n items: {\n type: 'object',\n properties: {\n productId: { type: 'string', minLength: 1 },\n variantId: { type: 'string' },\n quantity: { type: 'integer', minimum: 1 },\n optionsLabel: { type: 'string' },\n },\n required: ['productId', 'quantity'],\n },\n },\n customer: {\n type: 'object',\n properties: { name: { type: 'string' }, email: { type: 'string', minLength: 3 } },\n required: ['name', 'email'],\n },\n currency: { type: 'string' },\n discountCode: { type: 'string' },\n shippingTotal: { type: 'number' },\n notes: { type: 'string' },\n customerId: { type: 'string' },\n },\n required: ['items', 'customer'],\n additionalProperties: false,\n },\n // An Order is a rich provider shape; the valve's contract pins what the\n // storefront actually needs to continue (an id and totals) and lets the\n // rest of the Order shape ride along.\n output: {\n type: 'object',\n properties: {\n id: { type: 'string', minLength: 1 },\n total: { type: 'number' },\n },\n required: ['id'],\n },\n })\n}\n\n// --- Consumption helpers (the storefront's own use of its points) -------------\n\n/** Run cart.lineAnnotation for one line → its annotations, handler-ordered. */\nexport async function getCartLineAnnotations(line: CartLine): Promise<CartLineAnnotation[]> {\n registerStorefrontExtensionPoints()\n const input: CartLineAnnotationInput = {\n productId: line.productId,\n name: line.name,\n quantity: line.quantity,\n unitPrice: line.unitPrice,\n ...(line.slug ? { slug: line.slug } : {}),\n ...(line.optionsLabel ? { optionsLabel: line.optionsLabel } : {}),\n }\n const contributions = await runExtensionPoint<CartLineAnnotationInput, CartLineAnnotation>(\n CART_LINE_ANNOTATION_POINT,\n input,\n )\n return contributions.map((c) => c.value)\n}\n\n/** Run product.cardBadge for one product → its badges, handler-ordered. */\nexport async function getProductCardBadges(product: Product): Promise<ProductCardBadge[]> {\n registerStorefrontExtensionPoints()\n const input: ProductCardBadgeInput = {\n id: product.id,\n slug: product.slug,\n name: product.name,\n price: product.price,\n inventoryCount: product.inventoryCount,\n compareAtPrice: product.compareAtPrice,\n }\n const contributions = await runExtensionPoint<ProductCardBadgeInput, ProductCardBadge>(\n PRODUCT_CARD_BADGE_POINT,\n input,\n )\n return contributions.map((c) => c.value)\n}\n\n/** Run checkout.field → the extra fields a checkout form should render. */\nexport async function getCheckoutFieldContributions(input: CheckoutFieldInput = {}): Promise<\n Array<CheckoutFieldContribution & { handlerId: string }>\n> {\n registerStorefrontExtensionPoints()\n const contributions = await runExtensionPoint<CheckoutFieldInput, CheckoutFieldContribution>(\n CHECKOUT_FIELD_POINT,\n input,\n )\n return contributions.map((c) => ({ ...c.value, handlerId: c.handlerId }))\n}\n\n/**\n * Run order.metadata → the namespaced metadata object for a new order, or\n * undefined when nothing contributed. Namespacing by handler id is the\n * WooCommerce ExtendSchema rule: two extensions cannot clobber each other.\n */\nexport async function collectOrderMetadata(input: OrderMetadataInput): Promise<Record<string, unknown> | undefined> {\n registerStorefrontExtensionPoints()\n const contributions = await runExtensionPoint<OrderMetadataInput, Record<string, unknown>>(\n ORDER_METADATA_POINT,\n input,\n )\n if (contributions.length === 0) return undefined\n return Object.fromEntries(contributions.map((c) => [c.handlerId, c.value]))\n}\n\n/** Run the beforePlaceOrder valve. Null → take the default path. */\nexport async function runBeforePlaceOrderValve<TOrder extends { id: string }>(\n ctx: BeforePlaceOrderContext,\n): Promise<TOrder | null> {\n registerStorefrontExtensionPoints()\n return runEscapeValve<BeforePlaceOrderContext, TOrder>(BEFORE_PLACE_ORDER_VALVE, ctx)\n}\n","import { create } from 'zustand'\nimport { persist } from 'zustand/middleware'\n\n// The country the buyer chose to ship to, remembered in this browser. Only an\n// explicit choice is stored; detection (host hint, browser language) is\n// re-derived every visit, so a wrong guess never sticks.\n\nexport const BUYER_COUNTRY_COOKIE = 'fayz_country'\n\nexport interface BuyerState {\n /** ISO2, set only when the buyer picked it. */\n picked: string | null\n pick(country: string): void\n}\n\nexport const useBuyerStore = create<BuyerState>()(\n persist(\n (set) => ({\n picked: null,\n pick(country) {\n const iso2 = country.trim().toUpperCase()\n set({ picked: iso2 })\n // Readable by the host too, so a server render of a private page\n // (checkout) can start in the right country.\n try {\n document.cookie = `${BUYER_COUNTRY_COOKIE}=${iso2}; path=/; max-age=31536000; samesite=lax`\n } catch {\n /* no document (SSR, tests) */\n }\n },\n }),\n { name: 'fayz.storefront.buyer.v1' },\n ),\n)\n","import { useEffect, useState } from 'react'\nimport { getCountrySchema, type CountryAddressSchema } from '@fayz-ai/core'\nimport { useStorefrontConfig } from '../document/config'\nimport { useBuyerStore } from '../stores/buyer.store'\nimport { useDeliveryStore } from '../stores/delivery.store'\n\nexport interface BuyerCountry {\n /** ISO2 the store is shipping to right now. */\n country: string\n /** Every country the store ships to, in config order. */\n allowed: readonly string[]\n /** That country's address shape. */\n schema: CountryAddressSchema\n setCountry(country: string): void\n}\n\n/** The region part of the browser's language ('es-ES' → 'ES'), if any. */\nfunction navigatorRegion(): string | undefined {\n try {\n for (const tag of navigator.languages ?? [navigator.language]) {\n const region = tag?.split(/[-_]/)[1]\n if (region && /^[A-Za-z]{2}$/.test(region)) return region.toUpperCase()\n }\n } catch {\n /* no navigator */\n }\n return undefined\n}\n\n/**\n * Where the order ships, like Amazon's \"Deliver to\".\n *\n * Order of evidence: the buyer's own pick, the host's per-request hint (its\n * CDN's geo), the browser's language region, the store default; always one of\n * `config.countries`. The first render uses only what the server also knows\n * (hint, default), so a cached page never hydrates into a different country;\n * the browser-only evidence applies after mount.\n */\nexport function useBuyerCountry(): BuyerCountry {\n const config = useStorefrontConfig()\n const allowed = config.countries\n const picked = useBuyerStore((s) => s.picked)\n const pick = useBuyerStore((s) => s.pick)\n const [mounted, setMounted] = useState(false)\n useEffect(() => setMounted(true), [])\n\n const ok = (c?: string | null): c is string => !!c && allowed.includes(c)\n let country = ok(config.countryHint) ? config.countryHint : config.defaultCountry\n if (allowed.length > 1 && mounted) {\n const region = navigatorRegion()\n if (ok(picked)) country = picked\n else if (!ok(config.countryHint) && ok(region)) country = region\n }\n\n return {\n country,\n allowed,\n schema: getCountrySchema(country),\n setCountry(next) {\n const iso2 = next.toUpperCase()\n if (!allowed.includes(iso2) || iso2 === country) return\n pick(iso2)\n // A quote and a looked-up address belong to the old country's postal code.\n useDeliveryStore.getState().clear()\n },\n }\n}\n","import { useCallback } from 'react'\nimport { useStorefrontConfig } from '../document/config'\nimport { translate, type MessageKey } from './messages'\n\nexport { MESSAGES, normalizeLanguage, translate, ptBR } from './messages'\nexport type { MessageKey, Messages, StorefrontLanguage } from './messages'\n\n/**\n * `t(key, vars)` in the store's language. The language is resolved config\n * (`language`, or the host's per-request `buyer.language`), so the server\n * render and the browser read the same words.\n */\nexport function useT(): (key: MessageKey, vars?: Record<string, string | number>) => string {\n const config = useStorefrontConfig()\n const language = config.language\n const overrides = config.messages\n return useCallback((key, vars) => translate(language, key, vars, overrides), [language, overrides])\n}\n","import { useCallback } from 'react'\nimport { validateDiscount } from '@fayz-ai/shop'\nimport {\n discountToPromotion,\n previewCouponPercent,\n storefrontDiscountToPromotion,\n} from '@fayz-ai/shop/rules'\nimport type { Promotion, RuleCartSnapshot } from '@fayz-ai/shop/rules'\nimport { useStorefrontConfig } from '../document/config'\nimport { useCartStore, selectSubtotal } from '../stores/cart.store'\nimport { formatMoney } from '../lib/format'\n\nexport interface DiscountValidation {\n valid: boolean\n percent: number\n /** The coupon zeroes freight instead of discounting the subtotal. */\n freeShipping?: boolean\n message?: string\n}\n\nconst REASON_MESSAGE: Record<string, string> = {\n expired: 'Cupom expirado.',\n not_started: 'Cupom ainda não está ativo.',\n usage_limit: 'Cupom esgotado.',\n not_found: 'Cupom inválido ou expirado.',\n inactive: 'Cupom inválido ou expirado.',\n rules_not_matched: 'Este cupom não se aplica ao seu carrinho.',\n unsupported: 'Este cupom não é suportado na loja.',\n}\n\n/** What the cart is worth right now — the number the server judges\n * `min_subtotal` against, and the one the storefront used to never send. */\nfunction cartSubtotal(): number {\n return selectSubtotal({ lines: useCartStore.getState().lines })\n}\n\n/** The live cart as the rule engine's snapshot — what eligibility rules\n * (minimum subtotal, product scoping) evaluate against in the preview. */\nfunction cartSnapshot(): RuleCartSnapshot {\n const lines = useCartStore.getState().lines\n return {\n items: lines.map((line) => ({\n id: line.lineId ?? line.productId,\n productId: line.productId,\n quantity: line.quantity,\n unitPrice: line.unitPrice,\n })),\n }\n}\n\n/**\n * Storefront coupon validator, backed by the RULE ENGINE (spine M6): a store's\n * `{code, percent}` config entries and its document `promotions` section are\n * both Promotions — one eligibility rule on `code` plus an application method\n * — gated by the same evaluator path the server mirrors. The hardcoded\n * \"trust config.discounts directly\" branch this hook used to carry is retired.\n *\n * Codes the local document does not know still go through the provider-backed\n * validateDiscount primitive (status/date-window/usage-limit on the discount\n * table), translated through the same adapter. The storefront cart models a\n * discount as a percentage, so non-percentage codes are rejected for\n * client-side preview — the server still honors them at checkout.\n */\nexport function useDiscountValidator(): (code: string) => Promise<DiscountValidation> {\n const config = useStorefrontConfig()\n return useCallback(async (code: string) => {\n const normalized = code.trim().toUpperCase()\n if (!normalized) return { valid: false, percent: 0, message: 'Informe um cupom.' }\n\n // Everything the store itself declares, as promotions (pure data).\n const local: Promotion[] = [\n ...(config.promotions ?? []),\n ...(config.discounts ?? []).map(storefrontDiscountToPromotion),\n ]\n const localPreview = previewCouponPercent(local, normalized, cartSnapshot())\n if (localPreview.valid) {\n return { valid: true, percent: localPreview.percent, freeShipping: localPreview.freeShipping }\n }\n if (localPreview.reason !== 'not_found') {\n return { valid: false, percent: 0, message: REASON_MESSAGE[localPreview.reason ?? 'not_found'] ?? 'Cupom inválido.' }\n }\n\n // Unknown locally → the provider's discount table, through the same engine.\n //\n // The SUBTOTAL travels: `min_subtotal` can only be judged with it, and\n // without it the server judged every cart as worth zero — a coupon with a\n // minimum was refused on a full cart, and the shopper read \"inválido ou\n // expirado\" about a coupon that was neither.\n const validation = await validateDiscount({ code: normalized, subtotal: cartSubtotal() })\n if (!validation.valid) {\n if (validation.reason === 'min_subtotal' && validation.minSubtotal != null) {\n const missing = formatMoney(validation.minSubtotal, config.currency, config.locale)\n return { valid: false, percent: 0, message: `Este cupom vale em pedidos a partir de ${missing}.` }\n }\n return { valid: false, percent: 0, message: REASON_MESSAGE[validation.reason ?? 'not_found'] ?? 'Cupom inválido ou expirado.' }\n }\n // fixed_amount is still previewed as unsupported: the cart models a\n // discount as a percentage, so there is no honest number to show. Freight,\n // on the other hand, is a flag — the cart can show it exactly.\n if (validation.type !== 'percentage' && validation.type !== 'free_shipping') {\n return { valid: false, percent: 0, message: REASON_MESSAGE.unsupported }\n }\n const promotion = discountToPromotion({\n id: `provider:${normalized}`,\n tenantId: 'storefront',\n title: normalized,\n code: validation.code ?? normalized,\n type: validation.type,\n method: 'code',\n value: validation.value,\n usageLimit: null,\n oncePerCustomer: false,\n minSubtotal: null,\n appliesTo: 'all',\n productIds: [],\n categoryIds: [],\n startsAt: '1970-01-01T00:00:00Z',\n endsAt: null,\n status: 'active',\n timesUsed: 0,\n createdAt: '1970-01-01T00:00:00Z',\n updatedAt: '1970-01-01T00:00:00Z',\n })\n const preview = promotion ? previewCouponPercent([promotion], normalized, cartSnapshot()) : null\n if (!preview?.valid) {\n return { valid: false, percent: 0, message: REASON_MESSAGE[preview?.reason ?? 'not_found'] ?? 'Cupom inválido.' }\n }\n return { valid: true, percent: preview.percent, freeShipping: preview.freeShipping }\n }, [config.discounts, config.promotions])\n}\n","import { create } from 'zustand'\n\nexport type ToastVariant = 'success' | 'error' | 'info'\n\n/**\n * Uma ação no aviso.\n *\n * Existe porque \"adicionado ao carrinho\" sem saída é uma notificação que\n * informa e some: quem quer fechar o pedido agora tem de ir procurar o\n * carrinho. Com ação, o aviso É o caminho — e continuar comprando é não fazer\n * nada, que é o que a maioria vai fazer.\n */\nexport interface ToastAction {\n label: string\n onClick: () => void\n}\n\nexport interface Toast {\n id: string\n title: string\n description?: string\n variant: ToastVariant\n durationMs: number\n action?: ToastAction\n}\n\ninterface ToastState {\n toasts: Toast[]\n push(input: {\n title: string\n description?: string\n variant?: ToastVariant\n durationMs?: number\n action?: ToastAction\n }): string\n dismiss(id: string): void\n}\n\nlet seq = 0\n\nexport const useToastStore = create<ToastState>((set) => ({\n toasts: [],\n push: (input) => {\n const id = `toast-${++seq}-${Date.now()}`\n const toast: Toast = {\n id,\n title: input.title,\n description: input.description,\n variant: input.variant ?? 'info',\n durationMs: input.durationMs ?? 3400,\n action: input.action,\n }\n set((s) => ({ toasts: [...s.toasts, toast] }))\n return id\n },\n dismiss: (id) => set((s) => ({ toasts: s.toasts.filter((t) => t.id !== id) })),\n}))\n\n/** Imperative toast API — callable from components, store actions, or workflows. */\nexport const toast = {\n success: (title: string, description?: string) => useToastStore.getState().push({ title, description, variant: 'success' }),\n error: (title: string, description?: string) => useToastStore.getState().push({ title, description, variant: 'error' }),\n info: (title: string, description?: string) => useToastStore.getState().push({ title, description, variant: 'info' }),\n}\n","import React, { useEffect, useState } from 'react'\nimport { Lock, X } from 'lucide-react'\nimport { establishCustomerSession } from '../../data/auth'\nimport { useSessionStore } from '../../stores/session.store'\nimport { Link } from '../../app/router'\n\ninterface SignInModalProps {\n /** Prefill the email field (e.g. from a checkout contact field). */\n defaultEmail?: string\n onClose: () => void\n /** Called after a successful sign-in, with the resolved session. */\n onSignedIn?: (session: { email: string | null; name: string | null }) => void\n}\n\n/**\n * Customer sign-in as a focused modal dialog. Used from checkout (\"Já tem\n * conta? Entrar\") so a returning buyer can authenticate without leaving the\n * page. Auth goes through the shared establishCustomerSession path.\n */\nexport function SignInModal({ defaultEmail = '', onClose, onSignedIn }: SignInModalProps) {\n const [email, setEmail] = useState(defaultEmail)\n const [password, setPassword] = useState('')\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => { if (event.key === 'Escape') onClose() }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n }, [onClose])\n\n async function submit(event: React.FormEvent) {\n event.preventDefault()\n if (!email.trim() || !password) return\n setBusy(true)\n setError(null)\n try {\n await establishCustomerSession(email, { password })\n const session = useSessionStore.getState()\n onSignedIn?.({ email: session.email, name: session.name })\n onClose()\n } catch {\n setError('Não foi possível entrar. Verifique seu e-mail e senha.')\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-[60] flex items-center justify-center p-4\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Entrar na sua conta\"\n >\n <div className=\"absolute inset-0 animate-fade-in bg-foreground/40 backdrop-blur-sm\" onClick={onClose} />\n <div\n className=\"relative z-10 w-full max-w-sm animate-fade-up border bg-card p-6 shadow-2xl\"\n style={{ borderRadius: 'var(--sf-radius-card)' }}\n >\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Fechar\"\n className=\"absolute right-4 top-4 rounded-full p-1 text-muted-foreground transition hover:bg-muted hover:text-foreground\"\n >\n <X className=\"h-5 w-5\" />\n </button>\n\n <div className=\"flex items-center gap-2\">\n <span className=\"flex h-9 w-9 items-center justify-center rounded-full bg-primary/10 text-primary\">\n <Lock className=\"h-4 w-4\" />\n </span>\n <div>\n <h2 className=\"sf-heading text-lg font-semibold leading-tight\">Entrar na sua conta</h2>\n <p className=\"text-xs text-muted-foreground\">Use seus dados salvos e acompanhe pedidos.</p>\n </div>\n </div>\n\n <form onSubmit={submit} className=\"mt-5 space-y-3\">\n <input\n type=\"email\"\n required\n autoFocus\n placeholder=\"voce@exemplo.com\"\n value={email}\n onChange={(event) => setEmail(event.target.value)}\n className=\"w-full border bg-background px-3 py-2.5 text-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/10\"\n style={{ borderRadius: 'var(--sf-radius-input)' }}\n />\n <input\n type=\"password\"\n required\n placeholder=\"Senha\"\n value={password}\n onChange={(event) => setPassword(event.target.value)}\n className=\"w-full border bg-background px-3 py-2.5 text-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/10\"\n style={{ borderRadius: 'var(--sf-radius-input)' }}\n />\n {error && <p className=\"text-sm text-destructive\">{error}</p>}\n <button\n type=\"submit\"\n disabled={busy}\n className=\"sf-cta w-full bg-primary py-3 font-semibold text-primary-foreground shadow-md transition-all hover:-translate-y-0.5 hover:shadow-lg disabled:opacity-60\"\n style={{ borderRadius: 'var(--sf-radius-button)' }}\n >\n {busy ? 'Entrando…' : 'Entrar'}\n </button>\n </form>\n\n <p className=\"mt-4 text-center text-sm text-muted-foreground\">\n Não tem conta?{' '}\n <Link to=\"/account\" onClick={onClose} className=\"font-semibold text-primary hover:underline\">\n Criar conta\n </Link>\n </p>\n </div>\n </div>\n )\n}\n","import type { useStorefrontConfig } from '../document/config'\n\ntype Config = ReturnType<typeof useStorefrontConfig>\n\nconst KEY = 'fayz:sf:return-path'\n\n/**\n * Onde \"voltar\" volta.\n *\n * O checkout mandava sempre para `catalogPath`, e no modo delivery isso é uma\n * página que a pessoa nunca viu: ela veio do cardápio, clicou em voltar, e\n * caiu numa grade de produtos com facetas. Não é um erro de rótulo — é perder\n * o lugar de alguém no meio de uma compra.\n *\n * Guardado por sessão e não derivado do modo: no delivery as DUAS telas\n * existem (`/delivery` e `/catalog`), então o modo sozinho não sabe de qual\n * delas a pessoa saiu. A sessão sabe.\n */\nexport function rememberReturnPath(path: string): void {\n try {\n if (typeof sessionStorage === 'undefined') return\n sessionStorage.setItem(KEY, path)\n } catch {\n // Aba anônima, storage bloqueado. O fallback abaixo continua correto.\n }\n}\n\n/**\n * A superfície de compra para onde voltar.\n *\n * Sem nada guardado — primeira carga direto no /checkout, SSR, storage\n * bloqueado — cai para o cardápio quando a loja está em modo delivery e para o\n * catálogo quando não está: o padrão certo para cada loja, em vez de um só para\n * as duas.\n */\nexport function returnPath(config: Config): string {\n try {\n if (typeof sessionStorage !== 'undefined') {\n const remembered = sessionStorage.getItem(KEY)\n if (remembered) return remembered\n }\n } catch {\n // segue para o padrão\n }\n return config.delivery?.menuPath ?? config.catalogPath\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/analytics/bus.ts","../src/app/hydration.ts","../src/views/StorefrontPage.tsx","../src/extend/slots.tsx","../src/extend/extension-points.ts","../src/stores/buyer.store.ts","../src/hooks/use-buyer-country.ts","../src/locales/index.ts","../src/hooks/use-discount-validator.ts","../src/stores/toast.store.ts","../src/components/account/SignInModal.tsx","../src/app/return-path.ts"],"names":["createContext","useContext","useMemo","repairBlockTree","jsx","renderBlocks","s","useCallback","create","toast","useState","useEffect"],"mappings":"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","file":"chunk-OOQRYH3N.js","sourcesContent":["/**\n * The storefront's own record of what a shopper does, kept apart from any\n * analytics vendor: components report here, and whatever is listening (the\n * PostHog client, a test, nothing) decides what to do with it.\n *\n * The page's recent events are kept and handed to every listener when it\n * starts, so the first product view of a page load reaches a client that is\n * still loading — each listener hears each event once.\n */\n\nexport type StorefrontEventName =\n | 'product_viewed'\n | 'product_added_to_cart'\n | 'product_removed_from_cart'\n | 'cart_viewed'\n | 'coupon_applied'\n | 'checkout_started'\n | 'checkout_step_viewed'\n | 'checkout_payment_selected'\n | 'checkout_error'\n | 'checkout_completed'\n | 'delivery_exit'\n /** A visitor saw an experiment's variant (see `useExperiment`). Once per page view and experiment. */\n | 'experiment_exposed'\n\nexport type StorefrontEventProperties = Record<string, string | number | boolean | null | undefined>\n\nexport interface StorefrontEvent {\n name: StorefrontEventName\n properties: StorefrontEventProperties\n at: number\n}\n\ntype Listener = (event: StorefrontEvent) => void\ntype Identifier = (email: string) => void\n\nconst MAX_PENDING = 50\nconst listeners = new Set<Listener>()\nlet pending: StorefrontEvent[] = []\nlet identifier: Identifier | null = null\nlet pendingEmail: string | null = null\n// Other sinks that want the buyer (the Meta Pixel's advanced matching). The\n// last e-mail is kept so a sink that starts late still gets it.\nconst buyerListeners = new Set<Identifier>()\nlet lastEmail: string | null = null\nconst lastAt = new Map<StorefrontEventName, number>()\n\nexport function trackStorefront(name: StorefrontEventName, properties: StorefrontEventProperties = {}): void {\n if (typeof window === 'undefined') return\n const event: StorefrontEvent = { name, properties, at: Date.now() }\n lastAt.set(name, event.at)\n // Every event is kept (the last MAX_PENDING), not only the ones reported\n // before the FIRST listener: a sink that starts later — the Meta Pixel, whose\n // id arrives with the store's settings — still hears the page's first\n // product view instead of losing it to PostHog having started first.\n pending.push(event)\n if (pending.length > MAX_PENDING) pending = pending.slice(-MAX_PENDING)\n for (const listener of listeners) {\n try { listener(event) } catch { /* a listener never breaks the store */ }\n }\n}\n\nexport function onStorefrontEvent(listener: Listener): () => void {\n listeners.add(listener)\n for (const event of pending) {\n try { listener(event) } catch { /* ignore */ }\n }\n return () => { listeners.delete(listener) }\n}\n\n/**\n * The buyer said who they are (the checkout's e-mail). Handed to the analytics\n * client to tie this visit to the orders the server reports; never sent on as\n * an event property.\n */\nexport function identifyStorefrontBuyer(email: string): void {\n const clean = email.trim().toLowerCase()\n if (!clean.includes('@')) return\n if (identifier) identifier(clean)\n else pendingEmail = clean\n lastEmail = clean\n for (const listener of buyerListeners) {\n try { listener(clean) } catch { /* a listener never breaks the store */ }\n }\n}\n\n/** Hear the buyer's e-mail (now, if already known, and on every change). */\nexport function onStorefrontBuyer(listener: Identifier): () => void {\n buyerListeners.add(listener)\n if (lastEmail) {\n try { listener(lastEmail) } catch { /* ignore */ }\n }\n return () => { buyerListeners.delete(listener) }\n}\n\nexport function setStorefrontIdentifier(fn: Identifier | null): void {\n identifier = fn\n if (fn && pendingEmail) {\n fn(pendingEmail)\n pendingEmail = null\n }\n}\n\n/** When this event was last reported on this page (0 = never). */\nexport function lastStorefrontEventAt(name: StorefrontEventName): number {\n return lastAt.get(name) ?? 0\n}\n\n/** Test seam: forget listeners and held events. */\nexport function resetStorefrontEvents(): void {\n listeners.clear()\n pending = []\n identifier = null\n pendingEmail = null\n buyerListeners.clear()\n lastEmail = null\n lastAt.clear()\n}\n","import type { PageDataEntry } from '../blocks/page-data'\n\n// ---------------------------------------------------------------------------\n// Carrying the server's answers into the browser.\n//\n// Server-rendered HTML is only half of SSR. Without the data that produced it,\n// the browser mounts, finds every need unresolved, and refetches the whole page\n// — so the shopper sees correct content flash to skeletons and back, the\n// provider is hit twice per visit, and the render cost was spent for nothing.\n//\n// `PageDataScope` already accepts `initial`. This is the wire: the renderer\n// serialises what it resolved, the browser reads it once, and the first client\n// render matches the server's markup instead of replacing it.\n// ---------------------------------------------------------------------------\n\n/** Where the payload lives in the document. */\nexport const PAGE_DATA_SCRIPT_ID = '__fayz_page_data__'\n\nexport interface HydrationPayload {\n /** Resolved page data, keyed by `dataNeedKey`. */\n entries: Record<string, PageDataEntry>\n /** The path the server rendered, so a mismatch is detectable rather than silent. */\n path: string\n}\n\n/**\n * Escape a JSON payload for embedding in a `<script>`.\n *\n * `</script>` inside a product description would otherwise close the tag early\n * and drop the rest of the document into the page as markup — the same class of\n * bug as unescaped JSON-LD, with a worse blast radius. `<` is escaped rather\n * than the closing sequence alone so no casing or whitespace variant slips past.\n */\nfunction escapeScriptJson(value: unknown): string {\n return JSON.stringify(value)\n .replace(/</g, '\\\\u003c')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029')\n}\n\n/**\n * The `<script>` tag carrying `payload`, for a renderer to place in the body.\n *\n * Only `ready` entries are carried. An entry that errored server-side is\n * deliberately dropped so the browser retries it: a transient provider failure\n * during a prerender would otherwise be baked into the page for as long as the\n * HTML is cached.\n */\nexport function serializePageData(payload: HydrationPayload): string {\n const ready: Record<string, PageDataEntry> = {}\n for (const [key, entry] of Object.entries(payload.entries)) {\n if (entry.status === 'ready') ready[key] = entry\n }\n const json = escapeScriptJson({ entries: ready, path: payload.path })\n return `<script id=\"${PAGE_DATA_SCRIPT_ID}\" type=\"application/json\">${json}</script>`\n}\n\nlet _read = false\nlet _cache: HydrationPayload | null = null\n\n/**\n * The payload this document was rendered with, or null.\n *\n * Read once and memoised: the tag describes the FIRST render only. After a\n * client-side navigation the document still contains it, and re-reading would\n * seed a new page with the previous one's data.\n */\nexport function readHydratedPageData(): HydrationPayload | null {\n if (_read) return _cache\n _read = true\n if (typeof document === 'undefined') return (_cache = null)\n const el = document.getElementById(PAGE_DATA_SCRIPT_ID)\n if (!el?.textContent) return (_cache = null)\n try {\n _cache = JSON.parse(el.textContent) as HydrationPayload\n } catch {\n // Malformed payload is a bug, but refetching is a correct fallback — never\n // let it take down a page that already rendered.\n _cache = null\n }\n return _cache\n}\n\n/**\n * Entries to seed a page at `path`, or undefined.\n *\n * Path-guarded: the payload belongs to the document the server rendered, so\n * handing it to a different route would seed that route with another page's\n * answers. Query strings are ignored — they address state within a page.\n */\nexport function hydratedEntriesFor(path: string): Record<string, PageDataEntry> | undefined {\n const payload = readHydratedPageData()\n if (!payload) return undefined\n const same = (a: string, b: string) => (a.split('?')[0] || '/') === (b.split('?')[0] || '/')\n return same(payload.path, path) ? payload.entries : undefined\n}\n\n/** Test seam: forget the memoised read. */\nexport function resetHydratedPageData(): void {\n _read = false\n _cache = null\n}\n","import React, { createContext, useContext, useMemo } from 'react'\nimport { renderBlocks, repairBlockTree } from '@fayz-ai/core'\nimport type { BlockNode, BlockTreeRepair } from '@fayz-ai/core'\nimport { checkPageBlocks, defaultPageBlocks, toBlockNodes } from '../blocks/page-blocks'\nimport type { StorefrontPageKind, StorefrontPageConfig } from '../blocks/page-blocks'\nimport type { ResolvedStorefrontConfig } from '../document/config'\nimport { PageDataScope } from '../blocks/page-data'\nimport { hydratedEntriesFor } from '../app/hydration'\nimport { useRoutePath } from '../app/router'\n\n// ---------------------------------------------------------------------------\n// One renderer for every composed page.\n//\n// The page kind and its route params travel by context rather than by props,\n// because the consumers are blocks — arbitrarily deep in a tree the page did not\n// author. `productBody` needs the slug; a store's own block placed on the PDP\n// wants the same product without the store having to thread it. Fase 3's slots\n// read this same context, which is why it is a page-level concern and not a\n// parameter of the body block.\n// ---------------------------------------------------------------------------\n\nexport interface StorefrontPageContextValue {\n kind: StorefrontPageKind\n /** Route params for the current page (`slug` on product and collection). */\n params: Record<string, string>\n}\n\nconst PageContext = createContext<StorefrontPageContextValue | null>(null)\n\nexport const StorefrontPageProvider = PageContext.Provider\n\n/** The page a block is rendering inside. Throws outside a composed page, because\n * a block reading page context off a page is a bug worth surfacing loudly. */\nexport function useStorefrontPage(): StorefrontPageContextValue {\n const ctx = useContext(PageContext)\n if (!ctx) throw new Error('useStorefrontPage must be used inside a storefront page')\n return ctx\n}\n\n/** The page a block is rendering inside, or null — for blocks that work on any surface. */\nexport function useStorefrontPageOptional(): StorefrontPageContextValue | null {\n return useContext(PageContext)\n}\n\n// Diagnostics are printed once per distinct tree, not once per render: a config\n// mistake is worth saying loudly, and worth saying only once.\n//\n// Not gated to development. Every finding here describes a page that is already\n// visibly wrong to a shopper — an unregistered block renders a marker, a missing\n// body block renders no products — so a store hitting one in production is\n// better off with the reason in the console than without it.\nconst reported = new Set<string>()\n\nfunction reportDiagnostics(\n kind: StorefrontPageKind,\n nodes: readonly BlockNode[],\n repairs: readonly BlockTreeRepair[],\n): void {\n const signature = `${kind}:${nodes.map((n) => `${n.type}#${n.id ?? ''}`).join(',')}`\n if (reported.has(signature)) return\n reported.add(signature)\n\n for (const repair of repairs) {\n // A repair means the page RENDERS correctly but the composition is missing\n // a block it cannot function without — say so, so the config gets fixed\n // instead of silently diverging from what the shopper sees.\n console.warn(\n `[storefront] forced-layout: re-inserted required block \"${repair.inserted}\" at ${repair.path}[${repair.index}] on the ${kind} page — add it to the composition`,\n )\n }\n\n for (const finding of checkPageBlocks(kind, nodes)) {\n const message = `[storefront] ${finding.rule}: ${finding.detail}`\n if (finding.level === 'error') console.error(message)\n else console.warn(message)\n }\n}\n\n/** Reset the once-per-tree diagnostic memo. Test seam. */\nexport function resetPageDiagnostics(): void {\n reported.clear()\n}\n\nexport interface StorefrontPageProps {\n kind: StorefrontPageKind\n /** The store's composition for this page. Omitted falls back to the SDK default. */\n page?: StorefrontPageConfig\n params?: Record<string, string>\n}\n\n/**\n * Render a page as a block tree.\n *\n * A store that has not composed the page gets `defaultPageBlocks(kind)` — the\n * native body alone — so adopting `pages` changes nothing until something is\n * actually added around it.\n */\nexport function StorefrontPage({ kind, page, params = {} }: StorefrontPageProps) {\n // The path this page is rendering, so hydrated data is matched to the route\n // it was resolved for rather than handed to whatever renders next.\n const routePath = useRoutePath()\n const { nodes, repairs } = useMemo(() => {\n const authored = page?.blocks ? toBlockNodes(page.blocks) : defaultPageBlocks(kind)\n // Forced-layout repair (I7): a tree that lost a block it cannot function\n // without gets it re-inserted at the template index before rendering —\n // repair what is recoverable, reject (validateStore) what is checkable.\n const repaired = repairBlockTree(authored)\n return { nodes: repaired.nodes as BlockNode[], repairs: repaired.repairs }\n }, [page, kind])\n\n reportDiagnostics(kind, nodes, repairs)\n\n const ctx = useMemo<StorefrontPageContextValue>(() => ({ kind, params }), [kind, params])\n\n return (\n <StorefrontPageProvider value={ctx}>\n {/* Data needs are collected from the REPAIRED tree — a re-inserted\n required block gets its data like any authored one — and resolved\n once for the whole page (M3). */}\n {/* Seeded with whatever the server already resolved for THIS path, so the\n first client render matches the served HTML instead of replacing it\n with skeletons and refetching. Undefined in a pure SPA. */}\n <PageDataScope nodes={nodes} params={params} initial={hydratedEntriesFor(routePath)}>\n {/* The document path of this page's block array, so a rendered block\n carries its own address back (editor mode only — see core/blocks\n setBlockEditorMode). `content` is a map keyed by slug rather than a\n singular page, so it gets no path until the editor needs one; the\n four singular kinds are where editing happens. */}\n <main>{renderBlocks(nodes, kind === 'content' ? undefined : `presentation.pages.${kind}.blocks`)}</main>\n </PageDataScope>\n </StorefrontPageProvider>\n )\n}\n\n/** The composition for a SINGULAR page kind, if the store declared one.\n * `content` pages are a map keyed by slug — resolve those with\n * `matchContentPage` instead. */\nexport function pageConfigFor(\n config: ResolvedStorefrontConfig,\n kind: Exclude<StorefrontPageKind, 'content'>,\n): StorefrontPageConfig | undefined {\n return config.pages?.[kind]\n}\n","import React, { createContext, useContext, useMemo } from 'react'\nimport { renderBlocks, repairBlockTree } from '@fayz-ai/core'\nimport type { Product } from '@fayz-ai/shop/types'\nimport { toBlockNodes } from '../blocks/page-blocks'\nimport type { StorefrontBlockLike } from '../blocks/page-blocks'\nimport { useStorefrontConfigOptional } from '../document/config'\nimport { PageDataScope } from '../blocks/page-data'\nimport { useStorefrontPageOptional } from '../views/StorefrontPage'\nimport type { CartLine } from '../stores/cart.store'\n\n// ---------------------------------------------------------------------------\n// Named slots — the missing rung.\n//\n// Between \"configure a section\" and \"rewrite the page\" there was nothing. So\n// every store that needed one store-specific thing inside an SDK page took the\n// only rung available and rewrote the page, inheriting its maintenance forever.\n// The cost is measurable: one store reimplemented the product page and, in doing\n// so, silently dropped option selection, quantity and add-to-cart, because\n// reimplementing a page means reimplementing everything the page did.\n//\n// Prior art: Shopify's theme app extensions — an app block drops into a named\n// location in a template it does not own. Same shape, same reason.\n//\n// Two decisions worth stating:\n//\n// Slots take BLOCK TREES, not components. A slot holding a component is code,\n// which means it cannot be edited by the visual editor, generated by the agent,\n// or serialized into a manifest. A slot holding blocks is the same currency as\n// the rest of the system.\n//\n// Slot content receives typed context. The point of `afterPrice` is to say\n// something about THIS product; a slot that cannot see the product is a slot\n// that can only hold static copy.\n// ---------------------------------------------------------------------------\n\n/** What each slot area hands to the blocks inside it. */\nexport interface StorefrontSlotContextMap {\n productDetail: {\n product: Product\n soldOut: boolean\n lowStock: boolean\n /** Percent off, or 0 when the product is not discounted. */\n discountPct: number\n }\n /**\n * The card, which renders once per product in a grid — so its context is the\n * one product that card is for, not the list.\n */\n productCard: {\n product: Product\n soldOut: boolean\n onSale: boolean\n /** True when the product has variants, so quick-add routes to the PDP. */\n hasOptions: boolean\n }\n catalog: {\n /** The products currently visible, after filters and search. */\n products: readonly Product[]\n /** True while the list is being fetched. */\n loading: boolean\n }\n /**\n * The delivery menu. One context for its three positions: what the shopper\n * is shown and the actions the menu itself would take, so a store's block\n * opens and adds exactly like the SDK's own rows (closed-store guard, toast,\n * options sheet) instead of clicking hidden buttons.\n */\n menu: {\n /** The cover as drawn for this visitor (it can be an A/B variant). */\n coverSize: 'full' | 'compact'\n /** The products the menu highlights, in order. */\n highlights: readonly Product[]\n /** The section a `sectionIntro` sits in; null in the other positions. */\n section: MenuSlotSection | null\n /** Opens the product's sheet, as tapping a row does. */\n openProduct: (product: Product) => void\n /** The one-tap add for `product`, or undefined when it needs its sheet\n * (options) or is sold out — then show it as such, not as addable. */\n quickAdd: (product: Product) => (() => void) | undefined\n }\n cart: { lines: readonly CartLine[]; subtotal: number }\n checkout: { subtotal: number; total: number }\n header: Record<string, never>\n footer: Record<string, never>\n}\n\n/** A menu section, as `menu.sectionIntro` sees it. */\nexport interface MenuSlotSection {\n slug: string\n name: string\n description: string | null\n products: readonly Product[]\n}\n\nexport type StorefrontSlotArea = keyof StorefrontSlotContextMap\n\ntype SlotBlocks = readonly StorefrontBlockLike[]\n\n/**\n * Where a store may graft blocks into an SDK page.\n *\n * Position names read as \"where\", not \"what\": `afterPrice` keeps meaning the\n * same thing if the price stops being a `<Price>` and starts being something\n * else, which a name like `priceBelowSlot` would not.\n */\nexport interface StorefrontSlots {\n productDetail?: {\n /** Between the breadcrumb and the product name. */\n beforeTitle?: SlotBlocks\n /** Immediately under the product name, above the price. */\n afterTitle?: SlotBlocks\n /** Under the price and discount badge. */\n afterPrice?: SlotBlocks\n /** Under the description paragraph. */\n afterDescription?: SlotBlocks\n /** Above the quantity + add-to-cart row. Where trust seals go. */\n beforeAddToCart?: SlotBlocks\n /** Under the add-to-cart row, above the delivery estimate. */\n afterAddToCart?: SlotBlocks\n /** Under the gallery column, in the left half of the page. */\n afterGallery?: SlotBlocks\n /** Above the specification table, below the two-column fold. */\n beforeSpecs?: SlotBlocks\n /** The bottom of the page, after related products. */\n afterDetail?: SlotBlocks\n }\n /**\n * The product card, wherever it appears — grid, rail, slider, related.\n *\n * This is where the fleet actually hurt: four of five customizing stores\n * forked a ~120-line card to add one thing to it, and each fork then lost\n * something else (the sale badge, the variant guard, `commerceMode` gating,\n * `theme.productCard` honouring).\n */\n productCard?: {\n /** Above the image, full card width. */\n top?: SlotBlocks\n /** Over the image. The container is `relative`; content positions itself. */\n imageOverlay?: SlotBlocks\n /** Between the product name and the price row. */\n afterName?: SlotBlocks\n /** Under the price row. */\n underPrice?: SlotBlocks\n }\n catalog?: {\n /** Above the page heading. */\n beforeHeading?: SlotBlocks\n /** Between the heading and the filters/grid row. */\n beforeGrid?: SlotBlocks\n /** Inside the filter column, under the filters. */\n afterFilters?: SlotBlocks\n /** Under the product grid. */\n afterGrid?: SlotBlocks\n }\n /**\n * The delivery menu. Server-rendered with the page — the reason these exist:\n * a store that grafted its own cover copy, highlight carousel and section\n * banners in with DOM portals after hydration got them on the client only,\n * so the layout shifted when they arrived and their images were found late.\n */\n menu?: {\n /** Inside the cover, after its own content. The cover is `relative`\n * (and `isolate`); content positions itself. */\n coverOverlay?: SlotBlocks\n /**\n * Inside the highlights section, under its heading. When filled it\n * REPLACES the default highlight rows — a store showing its highlights as\n * a carousel must not render the rows too and hide them with CSS.\n */\n highlights?: SlotBlocks\n /** The top of each category section, above its heading. */\n sectionIntro?: SlotBlocks\n }\n cart?: {\n /** Above the line items. */\n beforeLines?: SlotBlocks\n /** Between the lines and the totals. */\n beforeSummary?: SlotBlocks\n /** Under the totals, around the checkout button. */\n afterSummary?: SlotBlocks\n }\n checkout?: {\n /** Above the checkout form. */\n beforeForm?: SlotBlocks\n /** Under the payment method selector. */\n afterPaymentMethods?: SlotBlocks\n /** Under the whole form, around the place-order button. */\n afterForm?: SlotBlocks\n }\n header?: {\n /**\n * Left of the account/cart icons.\n *\n * Named for the actions row rather than for the header, because the header\n * has three layout variants (default, centered, search) that place the logo\n * differently. A slot \"left of the logo\" would land somewhere different in\n * each one; the actions row is shared, so this position is the same in all\n * three.\n */\n beforeActions?: SlotBlocks\n /** Right of the cart icon. */\n afterActions?: SlotBlocks\n /** A full-width strip under the whole header, in every variant. */\n belowNav?: SlotBlocks\n }\n footer?: {\n /** Above the footer columns. */\n before?: SlotBlocks\n /** Under the footer columns, above the credit line. */\n after?: SlotBlocks\n }\n}\n\n// --- The inventory, as data ---------------------------------------------------\n\nexport interface SlotDescriptor {\n area: StorefrontSlotArea\n name: string\n /** Dotted id used in diagnostics and docs. */\n id: string\n /** Where this slot sits in the page. */\n position: string\n /** Keys the blocks inside receive through `useSlotContext`. */\n provides: readonly string[]\n /**\n * `stable` means a store in our fleet actually needed this position and paid\n * for it by forking something; `experimental` means the position is plausible\n * but unproven and may move or be removed in a minor.\n *\n * The distinction is not decoration. Every slot is a compatibility promise,\n * and a surface that promises two dozen positions nobody asked for is a\n * surface that cannot be changed later. FastStore marks unproven API with an\n * `__experimental` prefix for the same reason; this is the same idea as a\n * field, so `fayz upgrade` can tell a store which unproven slots it depends on.\n */\n stability: 'stable' | 'experimental'\n /** For stable slots: the fork that proves the position was needed. */\n evidence?: string\n}\n\nconst PRODUCT_DETAIL_CONTEXT = ['product', 'soldOut', 'lowStock', 'discountPct'] as const\nconst PRODUCT_CARD_CONTEXT = ['product', 'soldOut', 'onSale', 'hasOptions'] as const\nconst CATALOG_CONTEXT = ['products', 'loading'] as const\nconst MENU_CONTEXT = ['coverSize', 'highlights', 'section', 'openProduct', 'quickAdd'] as const\nconst CART_CONTEXT = ['lines', 'subtotal'] as const\nconst CHECKOUT_CONTEXT = ['subtotal', 'total'] as const\n\n/**\n * Every slot, with its position, the context it provides, and whether a real\n * store ever asked for it.\n *\n * Shipped as data rather than written in prose because a prose inventory drifts\n * the first time a slot is added. The docs page and the agent's prompt both read\n * this, so there is one list and it is the code's.\n *\n * Six slots are `stable`: a store in the fleet needed that exact position and\n * paid for it by forking a page or a component. The rest are `experimental` —\n * plausible positions with no proven demand yet. Marking them honestly is what\n * keeps the surface changeable; a store that builds on one is told, by\n * `fayz upgrade`, that it did.\n */\nexport const STOREFRONT_SLOTS: readonly SlotDescriptor[] = [\n x('productDetail', 'beforeTitle', 'between the breadcrumb and the product name', PRODUCT_DETAIL_CONTEXT),\n x('productDetail', 'afterTitle', 'under the product name, above the price', PRODUCT_DETAIL_CONTEXT),\n x('productDetail', 'afterPrice', 'under the price and discount badge', PRODUCT_DETAIL_CONTEXT),\n // The one PDP position with proof: this store put a Materials/Symbolism/\n // Availability <dl> exactly here, and reimplementing the page to do it cost it\n // the gallery, option selection, quantity, specs, related products and every\n // head tag on every product page.\n s(\n 'productDetail',\n 'afterDescription',\n 'under the description paragraph, above the actions',\n PRODUCT_DETAIL_CONTEXT,\n 'cristinarotondaro-shop/src/storefront/components/product.tsx:71-86',\n ),\n x('productDetail', 'beforeAddToCart', 'above the quantity and add-to-cart row', PRODUCT_DETAIL_CONTEXT),\n x('productDetail', 'afterAddToCart', 'under the add-to-cart row', PRODUCT_DETAIL_CONTEXT),\n x('productDetail', 'afterGallery', 'under the gallery, in the left column', PRODUCT_DETAIL_CONTEXT),\n x('productDetail', 'beforeSpecs', 'above the specification table', PRODUCT_DETAIL_CONTEXT),\n s(\n 'productDetail',\n 'afterDetail',\n 'the bottom of the page, after related products',\n PRODUCT_DETAIL_CONTEXT,\n 'cristinarotondaro-shop/src/storefront/components/product.tsx:95-102 (enquiry panel)',\n ),\n // The four card positions. Three are stable on the strength of the fleet: this\n // is the component our stores forked most, and every fork lost something.\n s(\n 'productCard',\n 'afterName',\n 'between the product name and the price row',\n PRODUCT_CARD_CONTEXT,\n 'pulse-store PulseProductCard.tsx:70-76; artorious ArtoriusProductCard.tsx:107-118; compactor CompactorProductCard.tsx:99; cristinarotondaro product.tsx:34 — 4 of 5',\n ),\n s(\n 'productCard',\n 'imageOverlay',\n 'over the image; the container is relative, content positions itself',\n PRODUCT_CARD_CONTEXT,\n 'pulse PulseProductCard.tsx:40-44; artorious ArtoriusProductCard.tsx:67-92 — 3 of 5',\n ),\n s(\n 'productCard',\n 'underPrice',\n 'under the price row',\n PRODUCT_CARD_CONTEXT,\n 'compactor CompactorProductCard.tsx:104 (Pix + installment lines); config.payments.terms already exists for it',\n ),\n x('productCard', 'top', 'above the image, full card width', PRODUCT_CARD_CONTEXT),\n s(\n 'catalog',\n 'beforeHeading',\n 'above the catalog heading',\n CATALOG_CONTEXT,\n 'cristinarotondaro-shop/src/storefront/customization.tsx:414-426 (category hero)',\n ),\n s(\n 'catalog',\n 'beforeGrid',\n 'between the heading and the grid',\n CATALOG_CONTEXT,\n 'cristinarotondaro-shop/src/storefront/customization.tsx:427-429 (statement band)',\n ),\n x('catalog', 'afterFilters', 'inside the filter column, under the filters', CATALOG_CONTEXT),\n s(\n 'catalog',\n 'afterGrid',\n 'under the product grid',\n CATALOG_CONTEXT,\n 'cristinarotondaro-shop/src/storefront/customization.tsx:442-450 (bespoke empty state)',\n ),\n // The three menu positions are stable on one store's proof: Artorius put\n // its cover copy, a highlights carousel and per-category banners into the\n // SDK menu with portals after mount, and paid for it with a 0.24 layout\n // shift and a highlight image (its LCP) discovered only after hydration.\n s('menu', 'coverOverlay', 'inside the menu cover, after its own content', MENU_CONTEXT, 'artorious-shop src/custom/components/DeliveryBanners.tsx (hero copy portal)'),\n s('menu', 'highlights', 'inside the highlights section, replacing the default rows', MENU_CONTEXT, 'artorious-shop src/custom/components/DeliveryHighlightsCarousel.tsx (carousel portal + CSS hiding the rows)'),\n s('menu', 'sectionIntro', 'the top of each menu section, above its heading', MENU_CONTEXT, 'artorious-shop src/custom/components/DeliveryBanners.tsx (category banner portals)'),\n x('cart', 'beforeLines', 'above the cart line items', CART_CONTEXT),\n x('cart', 'beforeSummary', 'between the lines and the totals', CART_CONTEXT),\n s(\n 'cart',\n 'afterSummary',\n 'under the totals, around the checkout button',\n CART_CONTEXT,\n 'artorious-shop/docs/TODO.md:167-179; the CartDrawerFooterExtra contract exists for it',\n ),\n x('checkout', 'beforeForm', 'above the checkout form', CHECKOUT_CONTEXT),\n x('checkout', 'afterPaymentMethods', 'under the payment method selector', CHECKOUT_CONTEXT),\n x('checkout', 'afterForm', 'under the form, around the place-order button', CHECKOUT_CONTEXT),\n x('header', 'beforeActions', 'left of the account and cart icons', []),\n x('header', 'afterActions', 'right of the cart icon', []),\n x('header', 'belowNav', 'a full-width strip under the whole header', []),\n x('footer', 'before', 'above the footer columns', []),\n x('footer', 'after', 'under the footer columns, above the credit line', []),\n]\n\n/** A slot with proven demand. */\nfunction s(\n area: StorefrontSlotArea,\n name: string,\n position: string,\n provides: readonly string[],\n evidence: string,\n): SlotDescriptor {\n return { area, name, id: `${area}.${name}`, position, provides, stability: 'stable', evidence }\n}\n\n/** A plausible position with no proven demand yet. */\nfunction x(\n area: StorefrontSlotArea,\n name: string,\n position: string,\n provides: readonly string[],\n): SlotDescriptor {\n return { area, name, id: `${area}.${name}`, position, provides, stability: 'experimental' }\n}\n\nexport interface ListSlotsOptions {\n area?: StorefrontSlotArea\n /** Keep only slots a store has actually proven it needs. */\n stableOnly?: boolean\n}\n\n/** The slot inventory, optionally narrowed. */\nexport function listSlots(\n areaOrOptions?: StorefrontSlotArea | ListSlotsOptions,\n): readonly SlotDescriptor[] {\n const options: ListSlotsOptions =\n typeof areaOrOptions === 'string' ? { area: areaOrOptions } : areaOrOptions ?? {}\n return STOREFRONT_SLOTS.filter(\n (slot) =>\n (!options.area || slot.area === options.area) &&\n (!options.stableOnly || slot.stability === 'stable'),\n )\n}\n\n/** The slots a store's config actually fills, with their stability. */\nexport function usedSlots(slots: StorefrontSlots | undefined): readonly SlotDescriptor[] {\n if (!slots) return []\n return STOREFRONT_SLOTS.filter((slot) => {\n const area = slots[slot.area] as Record<string, SlotBlocks> | undefined\n return Boolean(area?.[slot.name]?.length)\n })\n}\n\n// --- Runtime ------------------------------------------------------------------\n\nconst SlotContext = createContext<Record<string, unknown> | null>(null)\n\n/**\n * The context the surrounding slot provides.\n *\n * The type parameter is the caller's assertion about which area it is rendering\n * in, which is as much as a registry-resolved block can be given: the block is\n * looked up by string, so nothing at the call site knows its area statically.\n * Returns null outside a slot, so a block can work both in a slot and in a page.\n */\nexport function useSlotContext<A extends StorefrontSlotArea>(): StorefrontSlotContextMap[A] | null {\n return useContext(SlotContext) as StorefrontSlotContextMap[A] | null\n}\n\nexport interface SlotProps<A extends StorefrontSlotArea> {\n area: A\n name: string\n context?: StorefrontSlotContextMap[A]\n}\n\n/** Whether a store put anything in a slot — for positions whose content\n * REPLACES the page's own (`menu.highlights`). */\nexport function useSlotFilled(area: StorefrontSlotArea, name: string): boolean {\n const config = useStorefrontConfigOptional()\n return Boolean((config?.slots?.[area] as Record<string, SlotBlocks> | undefined)?.[name]?.length)\n}\n\n/**\n * Render the blocks a store put in one slot.\n *\n * The slot reads its own content out of the config rather than being handed it,\n * so a page places `<Slot area=\"productDetail\" name=\"afterPrice\" />` without\n * threading `config.slots` down to every position. That matters because there\n * are two dozen of these call sites and every threaded prop is a chance to wire\n * one to the wrong slot.\n *\n * Renders nothing — not even a wrapper — when the slot is empty, which is the\n * overwhelmingly common case. An always-present wrapper would change the layout\n * of every page for every store that uses no slots at all.\n */\nexport function Slot<A extends StorefrontSlotArea>({ area, name, context }: SlotProps<A>) {\n const config = useStorefrontConfigOptional()\n const page = useStorefrontPageOptional()\n const blocks = (config?.slots?.[area] as Record<string, SlotBlocks> | undefined)?.[name]\n // Same forced-layout repair as StorefrontPage: a slot tree that lost a\n // required child gets it back before rendering (I7).\n const nodes = useMemo(\n () => (blocks?.length ? repairBlockTree(toBlockNodes(blocks)).nodes : null),\n [blocks],\n )\n const value = useMemo(() => (context ?? {}) as Record<string, unknown>, [context])\n if (!nodes) return null\n // A slot tree resolves its data needs like a page tree (M3): its own scope,\n // nested under the page's, so needs the page already resolved are reused and\n // `$param` bindings see the surrounding page's route params.\n return (\n <SlotContext.Provider value={value}>\n <PageDataScope nodes={nodes} params={page?.params}>\n {renderBlocks(nodes, `presentation.slots.${area}.${name}`)}\n </PageDataScope>\n </SlotContext.Provider>\n )\n}\n","import { clearExtensionPoints, defineExtensionPoint, runEscapeValve, runExtensionPoint } from '@fayz-ai/core'\nimport type { Product } from '@fayz-ai/shop/types'\nimport type { CartLine } from '../stores/cart.store'\n\n// ---------------------------------------------------------------------------\n// The storefront's extension points — spine M7, deliberately FEW.\n//\n// WooCommerce's ExtendSchema discipline is the model: of hundreds of possible\n// seams, only the ones where extension is legitimate are extensible, each with\n// a validated schema, and extension data lands under a namespaced key. Our\n// four many-handler points cover the four asks the fleet has actually made\n// (annotate a cart line, stamp data on an order, badge a product card, add a\n// checkout field), plus exactly ONE escape valve on the one irreversible\n// operation (order creation — I4). Everything else stays closed until a real\n// second consumer exists; adding a point here is an API decision, not a\n// convenience.\n// ---------------------------------------------------------------------------\n\nexport const CART_LINE_ANNOTATION_POINT = 'cart.lineAnnotation'\nexport const ORDER_METADATA_POINT = 'order.metadata'\nexport const PRODUCT_CARD_BADGE_POINT = 'product.cardBadge'\nexport const CHECKOUT_FIELD_POINT = 'checkout.field'\nexport const BEFORE_PLACE_ORDER_VALVE = 'checkout.beforePlaceOrder'\n\n// --- Wire shapes (each mirrors its point's JSON Schema 1:1) -------------------\n\n/** Input of cart.lineAnnotation — one cart line, serializable. */\nexport interface CartLineAnnotationInput {\n productId: string\n name: string\n quantity: number\n unitPrice: number\n slug?: string\n optionsLabel?: string\n}\n\n/** Output of cart.lineAnnotation — one annotation chip under the line. */\nexport interface CartLineAnnotation {\n /** Stable machine key (namespacing is the handler id; this keys within it). */\n key: string\n /** Shopper-facing text. */\n label: string\n /** Optional machine value carried alongside the label. */\n value?: string\n}\n\nexport interface OrderMetadataInput {\n items: Array<{ productId: string; quantity: number; unitPrice: number }>\n subtotal: number\n customerEmail?: string\n}\n\nexport interface ProductCardBadgeInput {\n id: string\n slug: string\n name: string\n price: number\n inventoryCount: number\n compareAtPrice?: number | null\n}\n\nexport interface ProductCardBadge {\n text: string\n tone?: 'default' | 'accent' | 'warning'\n}\n\nexport interface CheckoutFieldInput {\n customerEmail?: string\n}\n\n/** Output of checkout.field — one extra field the checkout form renders. The\n * captured value lands in the order metadata under the handler's namespace. */\nexport interface CheckoutFieldContribution {\n id: string\n label: string\n type: 'text' | 'checkbox'\n required?: boolean\n placeholder?: string\n}\n\n/** Input of the beforePlaceOrder escape valve — the serializable placement\n * intent, BEFORE the default provider path runs. */\nexport interface BeforePlaceOrderContext {\n items: Array<{ productId: string; variantId?: string; quantity: number; optionsLabel?: string }>\n customer: { name: string; email: string }\n currency?: string\n discountCode?: string\n shippingTotal?: number\n notes?: string\n customerId?: string\n}\n\nlet registered = false\n\n/** Test seam — clears the whole extension registry (declarations AND\n * handlers) and re-arms registration, so one suite cannot leak handlers into\n * the next. Pairs with core's clearExtensionPoints. */\nexport function resetStorefrontExtensionPoints(): void {\n clearExtensionPoints()\n registered = false\n}\n\n/** Declare the storefront extension points. Idempotent; called wherever blocks\n * are registered, so describeStore and the runtime always agree on the set. */\nexport function registerStorefrontExtensionPoints(): void {\n if (registered) return\n registered = true\n\n defineExtensionPoint({\n id: CART_LINE_ANNOTATION_POINT,\n description:\n 'Annotate one cart line (gift wrap, engraving, availability note). Handlers see the line, return one annotation; annotations render under the line in the cart drawer.',\n source: 'sdk',\n since: '0.10',\n input: {\n type: 'object',\n properties: {\n productId: { type: 'string', minLength: 1 },\n name: { type: 'string' },\n quantity: { type: 'integer', minimum: 1 },\n unitPrice: { type: 'number', minimum: 0 },\n slug: { type: 'string' },\n optionsLabel: { type: 'string' },\n },\n required: ['productId', 'name', 'quantity', 'unitPrice'],\n additionalProperties: false,\n },\n output: {\n type: 'object',\n properties: {\n key: { type: 'string', minLength: 1 },\n label: { type: 'string', minLength: 1 },\n value: { type: 'string' },\n },\n required: ['key', 'label'],\n additionalProperties: false,\n },\n })\n\n defineExtensionPoint({\n id: ORDER_METADATA_POINT,\n description:\n 'Contribute machine-readable metadata to an order at placement. Each handler returns an object; contributions land on the order namespaced by handler id, so two extensions can never collide.',\n source: 'sdk',\n since: '0.10',\n input: {\n type: 'object',\n properties: {\n items: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n productId: { type: 'string' },\n quantity: { type: 'integer', minimum: 1 },\n unitPrice: { type: 'number', minimum: 0 },\n },\n required: ['productId', 'quantity', 'unitPrice'],\n },\n },\n subtotal: { type: 'number', minimum: 0 },\n customerEmail: { type: 'string' },\n },\n required: ['items', 'subtotal'],\n additionalProperties: false,\n },\n output: { type: 'object' },\n })\n\n defineExtensionPoint({\n id: PRODUCT_CARD_BADGE_POINT,\n description:\n 'Badge a product card (\"Novo\", \"Últimas unidades\", \"Frete grátis\"). Handlers see a product summary and return a badge; badges render next to the built-in sale/sold-out chips.',\n source: 'sdk',\n since: '0.10',\n input: {\n type: 'object',\n properties: {\n id: { type: 'string', minLength: 1 },\n slug: { type: 'string' },\n name: { type: 'string' },\n price: { type: 'number' },\n inventoryCount: { type: 'integer' },\n compareAtPrice: { type: ['number', 'null'] },\n },\n required: ['id', 'name', 'price'],\n additionalProperties: false,\n },\n output: {\n type: 'object',\n properties: {\n text: { type: 'string', minLength: 1, maxLength: 24 },\n tone: { type: 'string', enum: ['default', 'accent', 'warning'] },\n },\n required: ['text'],\n additionalProperties: false,\n },\n })\n\n defineExtensionPoint({\n id: CHECKOUT_FIELD_POINT,\n description:\n 'Contribute one extra field to the checkout form (CPF/CNPJ, gift message, marketing opt-in). The captured value is stored on the order metadata under the handler id.',\n source: 'sdk',\n since: '0.10',\n input: {\n type: 'object',\n properties: { customerEmail: { type: 'string' } },\n additionalProperties: false,\n },\n output: {\n type: 'object',\n properties: {\n id: { type: 'string', minLength: 1 },\n label: { type: 'string', minLength: 1 },\n type: { type: 'string', enum: ['text', 'checkbox'] },\n required: { type: 'boolean' },\n placeholder: { type: 'string' },\n },\n required: ['id', 'label', 'type'],\n additionalProperties: false,\n },\n })\n\n // The ONE escape valve on the storefront's one irreversible operation (I4).\n // WooCommerce's policy, adopted verbatim: always nullable, non-null return\n // short-circuits the default order creation. The registry enforces the\n // single-registrant rule, so this can never rot into a hook graph.\n defineExtensionPoint({\n id: BEFORE_PLACE_ORDER_VALVE,\n description:\n 'THE escape valve for order creation. One registrant maximum. Return null to take the default placeOrder path; return an Order to replace order creation entirely (external OMS, quote-first flows).',\n source: 'sdk',\n since: '0.10',\n mode: 'escape',\n input: {\n type: 'object',\n properties: {\n items: {\n type: 'array',\n minItems: 1,\n items: {\n type: 'object',\n properties: {\n productId: { type: 'string', minLength: 1 },\n variantId: { type: 'string' },\n quantity: { type: 'integer', minimum: 1 },\n optionsLabel: { type: 'string' },\n },\n required: ['productId', 'quantity'],\n },\n },\n customer: {\n type: 'object',\n properties: { name: { type: 'string' }, email: { type: 'string', minLength: 3 } },\n required: ['name', 'email'],\n },\n currency: { type: 'string' },\n discountCode: { type: 'string' },\n shippingTotal: { type: 'number' },\n notes: { type: 'string' },\n customerId: { type: 'string' },\n },\n required: ['items', 'customer'],\n additionalProperties: false,\n },\n // An Order is a rich provider shape; the valve's contract pins what the\n // storefront actually needs to continue (an id and totals) and lets the\n // rest of the Order shape ride along.\n output: {\n type: 'object',\n properties: {\n id: { type: 'string', minLength: 1 },\n total: { type: 'number' },\n },\n required: ['id'],\n },\n })\n}\n\n// --- Consumption helpers (the storefront's own use of its points) -------------\n\n/** Run cart.lineAnnotation for one line → its annotations, handler-ordered. */\nexport async function getCartLineAnnotations(line: CartLine): Promise<CartLineAnnotation[]> {\n registerStorefrontExtensionPoints()\n const input: CartLineAnnotationInput = {\n productId: line.productId,\n name: line.name,\n quantity: line.quantity,\n unitPrice: line.unitPrice,\n ...(line.slug ? { slug: line.slug } : {}),\n ...(line.optionsLabel ? { optionsLabel: line.optionsLabel } : {}),\n }\n const contributions = await runExtensionPoint<CartLineAnnotationInput, CartLineAnnotation>(\n CART_LINE_ANNOTATION_POINT,\n input,\n )\n return contributions.map((c) => c.value)\n}\n\n/** Run product.cardBadge for one product → its badges, handler-ordered. */\nexport async function getProductCardBadges(product: Product): Promise<ProductCardBadge[]> {\n registerStorefrontExtensionPoints()\n const input: ProductCardBadgeInput = {\n id: product.id,\n slug: product.slug,\n name: product.name,\n price: product.price,\n inventoryCount: product.inventoryCount,\n compareAtPrice: product.compareAtPrice,\n }\n const contributions = await runExtensionPoint<ProductCardBadgeInput, ProductCardBadge>(\n PRODUCT_CARD_BADGE_POINT,\n input,\n )\n return contributions.map((c) => c.value)\n}\n\n/** Run checkout.field → the extra fields a checkout form should render. */\nexport async function getCheckoutFieldContributions(input: CheckoutFieldInput = {}): Promise<\n Array<CheckoutFieldContribution & { handlerId: string }>\n> {\n registerStorefrontExtensionPoints()\n const contributions = await runExtensionPoint<CheckoutFieldInput, CheckoutFieldContribution>(\n CHECKOUT_FIELD_POINT,\n input,\n )\n return contributions.map((c) => ({ ...c.value, handlerId: c.handlerId }))\n}\n\n/**\n * Run order.metadata → the namespaced metadata object for a new order, or\n * undefined when nothing contributed. Namespacing by handler id is the\n * WooCommerce ExtendSchema rule: two extensions cannot clobber each other.\n */\nexport async function collectOrderMetadata(input: OrderMetadataInput): Promise<Record<string, unknown> | undefined> {\n registerStorefrontExtensionPoints()\n const contributions = await runExtensionPoint<OrderMetadataInput, Record<string, unknown>>(\n ORDER_METADATA_POINT,\n input,\n )\n if (contributions.length === 0) return undefined\n return Object.fromEntries(contributions.map((c) => [c.handlerId, c.value]))\n}\n\n/** Run the beforePlaceOrder valve. Null → take the default path. */\nexport async function runBeforePlaceOrderValve<TOrder extends { id: string }>(\n ctx: BeforePlaceOrderContext,\n): Promise<TOrder | null> {\n registerStorefrontExtensionPoints()\n return runEscapeValve<BeforePlaceOrderContext, TOrder>(BEFORE_PLACE_ORDER_VALVE, ctx)\n}\n","import { create } from 'zustand'\nimport { persist } from 'zustand/middleware'\n\n// The country the buyer chose to ship to, remembered in this browser. Only an\n// explicit choice is stored; detection (host hint, browser language) is\n// re-derived every visit, so a wrong guess never sticks.\n\nexport const BUYER_COUNTRY_COOKIE = 'fayz_country'\n\nexport interface BuyerState {\n /** ISO2, set only when the buyer picked it. */\n picked: string | null\n pick(country: string): void\n}\n\nexport const useBuyerStore = create<BuyerState>()(\n persist(\n (set) => ({\n picked: null,\n pick(country) {\n const iso2 = country.trim().toUpperCase()\n set({ picked: iso2 })\n // Readable by the host too, so a server render of a private page\n // (checkout) can start in the right country.\n try {\n document.cookie = `${BUYER_COUNTRY_COOKIE}=${iso2}; path=/; max-age=31536000; samesite=lax`\n } catch {\n /* no document (SSR, tests) */\n }\n },\n }),\n { name: 'fayz.storefront.buyer.v1' },\n ),\n)\n","import { useEffect, useState } from 'react'\nimport { getCountrySchema, type CountryAddressSchema } from '@fayz-ai/core'\nimport { useStorefrontConfig } from '../document/config'\nimport { useBuyerStore } from '../stores/buyer.store'\nimport { useDeliveryStore } from '../stores/delivery.store'\n\nexport interface BuyerCountry {\n /** ISO2 the store is shipping to right now. */\n country: string\n /** Every country the store ships to, in config order. */\n allowed: readonly string[]\n /** That country's address shape. */\n schema: CountryAddressSchema\n setCountry(country: string): void\n}\n\n/** The region part of the browser's language ('es-ES' → 'ES'), if any. */\nfunction navigatorRegion(): string | undefined {\n try {\n for (const tag of navigator.languages ?? [navigator.language]) {\n const region = tag?.split(/[-_]/)[1]\n if (region && /^[A-Za-z]{2}$/.test(region)) return region.toUpperCase()\n }\n } catch {\n /* no navigator */\n }\n return undefined\n}\n\n/**\n * Where the order ships, like Amazon's \"Deliver to\".\n *\n * Order of evidence: the buyer's own pick, the host's per-request hint (its\n * CDN's geo), the browser's language region, the store default; always one of\n * `config.countries`. The first render uses only what the server also knows\n * (hint, default), so a cached page never hydrates into a different country;\n * the browser-only evidence applies after mount.\n */\nexport function useBuyerCountry(): BuyerCountry {\n const config = useStorefrontConfig()\n const allowed = config.countries\n const picked = useBuyerStore((s) => s.picked)\n const pick = useBuyerStore((s) => s.pick)\n const [mounted, setMounted] = useState(false)\n useEffect(() => setMounted(true), [])\n\n const ok = (c?: string | null): c is string => !!c && allowed.includes(c)\n let country = ok(config.countryHint) ? config.countryHint : config.defaultCountry\n if (allowed.length > 1 && mounted) {\n const region = navigatorRegion()\n if (ok(picked)) country = picked\n else if (!ok(config.countryHint) && ok(region)) country = region\n }\n\n return {\n country,\n allowed,\n schema: getCountrySchema(country),\n setCountry(next) {\n const iso2 = next.toUpperCase()\n if (!allowed.includes(iso2) || iso2 === country) return\n pick(iso2)\n // A quote and a looked-up address belong to the old country's postal code.\n useDeliveryStore.getState().clear()\n },\n }\n}\n","import { useCallback } from 'react'\nimport { useStorefrontConfig } from '../document/config'\nimport { translate, type MessageKey } from './messages'\n\nexport { MESSAGES, normalizeLanguage, translate, ptBR } from './messages'\nexport type { MessageKey, Messages, StorefrontLanguage } from './messages'\n\n/**\n * `t(key, vars)` in the store's language. The language is resolved config\n * (`language`, or the host's per-request `buyer.language`), so the server\n * render and the browser read the same words.\n */\nexport function useT(): (key: MessageKey, vars?: Record<string, string | number>) => string {\n const config = useStorefrontConfig()\n const language = config.language\n const overrides = config.messages\n return useCallback((key, vars) => translate(language, key, vars, overrides), [language, overrides])\n}\n","import { useCallback } from 'react'\nimport { validateDiscount } from '@fayz-ai/shop'\nimport {\n discountToPromotion,\n previewCouponPercent,\n storefrontDiscountToPromotion,\n} from '@fayz-ai/shop/rules'\nimport type { Promotion, RuleCartSnapshot } from '@fayz-ai/shop/rules'\nimport { useStorefrontConfig } from '../document/config'\nimport { useCartStore, selectSubtotal } from '../stores/cart.store'\nimport { formatMoney } from '../lib/format'\n\nexport interface DiscountValidation {\n valid: boolean\n percent: number\n /** The coupon zeroes freight instead of discounting the subtotal. */\n freeShipping?: boolean\n message?: string\n}\n\nconst REASON_MESSAGE: Record<string, string> = {\n expired: 'Cupom expirado.',\n not_started: 'Cupom ainda não está ativo.',\n usage_limit: 'Cupom esgotado.',\n not_found: 'Cupom inválido ou expirado.',\n inactive: 'Cupom inválido ou expirado.',\n rules_not_matched: 'Este cupom não se aplica ao seu carrinho.',\n unsupported: 'Este cupom não é suportado na loja.',\n}\n\n/** What the cart is worth right now — the number the server judges\n * `min_subtotal` against, and the one the storefront used to never send. */\nfunction cartSubtotal(): number {\n return selectSubtotal({ lines: useCartStore.getState().lines })\n}\n\n/** The live cart as the rule engine's snapshot — what eligibility rules\n * (minimum subtotal, product scoping) evaluate against in the preview. */\nfunction cartSnapshot(): RuleCartSnapshot {\n const lines = useCartStore.getState().lines\n return {\n items: lines.map((line) => ({\n id: line.lineId ?? line.productId,\n productId: line.productId,\n quantity: line.quantity,\n unitPrice: line.unitPrice,\n })),\n }\n}\n\n/**\n * Storefront coupon validator, backed by the RULE ENGINE (spine M6): a store's\n * `{code, percent}` config entries and its document `promotions` section are\n * both Promotions — one eligibility rule on `code` plus an application method\n * — gated by the same evaluator path the server mirrors. The hardcoded\n * \"trust config.discounts directly\" branch this hook used to carry is retired.\n *\n * Codes the local document does not know still go through the provider-backed\n * validateDiscount primitive (status/date-window/usage-limit on the discount\n * table), translated through the same adapter. The storefront cart models a\n * discount as a percentage, so non-percentage codes are rejected for\n * client-side preview — the server still honors them at checkout.\n */\nexport function useDiscountValidator(): (code: string) => Promise<DiscountValidation> {\n const config = useStorefrontConfig()\n return useCallback(async (code: string) => {\n const normalized = code.trim().toUpperCase()\n if (!normalized) return { valid: false, percent: 0, message: 'Informe um cupom.' }\n\n // Everything the store itself declares, as promotions (pure data).\n const local: Promotion[] = [\n ...(config.promotions ?? []),\n ...(config.discounts ?? []).map(storefrontDiscountToPromotion),\n ]\n const localPreview = previewCouponPercent(local, normalized, cartSnapshot())\n if (localPreview.valid) {\n return { valid: true, percent: localPreview.percent, freeShipping: localPreview.freeShipping }\n }\n if (localPreview.reason !== 'not_found') {\n return { valid: false, percent: 0, message: REASON_MESSAGE[localPreview.reason ?? 'not_found'] ?? 'Cupom inválido.' }\n }\n\n // Unknown locally → the provider's discount table, through the same engine.\n //\n // The SUBTOTAL travels: `min_subtotal` can only be judged with it, and\n // without it the server judged every cart as worth zero — a coupon with a\n // minimum was refused on a full cart, and the shopper read \"inválido ou\n // expirado\" about a coupon that was neither.\n const validation = await validateDiscount({ code: normalized, subtotal: cartSubtotal() })\n if (!validation.valid) {\n if (validation.reason === 'min_subtotal' && validation.minSubtotal != null) {\n const missing = formatMoney(validation.minSubtotal, config.currency, config.locale)\n return { valid: false, percent: 0, message: `Este cupom vale em pedidos a partir de ${missing}.` }\n }\n return { valid: false, percent: 0, message: REASON_MESSAGE[validation.reason ?? 'not_found'] ?? 'Cupom inválido ou expirado.' }\n }\n // fixed_amount is still previewed as unsupported: the cart models a\n // discount as a percentage, so there is no honest number to show. Freight,\n // on the other hand, is a flag — the cart can show it exactly.\n if (validation.type !== 'percentage' && validation.type !== 'free_shipping') {\n return { valid: false, percent: 0, message: REASON_MESSAGE.unsupported }\n }\n const promotion = discountToPromotion({\n id: `provider:${normalized}`,\n tenantId: 'storefront',\n title: normalized,\n code: validation.code ?? normalized,\n type: validation.type,\n method: 'code',\n value: validation.value,\n usageLimit: null,\n oncePerCustomer: false,\n minSubtotal: null,\n appliesTo: 'all',\n productIds: [],\n categoryIds: [],\n startsAt: '1970-01-01T00:00:00Z',\n endsAt: null,\n status: 'active',\n timesUsed: 0,\n createdAt: '1970-01-01T00:00:00Z',\n updatedAt: '1970-01-01T00:00:00Z',\n })\n const preview = promotion ? previewCouponPercent([promotion], normalized, cartSnapshot()) : null\n if (!preview?.valid) {\n return { valid: false, percent: 0, message: REASON_MESSAGE[preview?.reason ?? 'not_found'] ?? 'Cupom inválido.' }\n }\n return { valid: true, percent: preview.percent, freeShipping: preview.freeShipping }\n }, [config.discounts, config.promotions])\n}\n","import { create } from 'zustand'\n\nexport type ToastVariant = 'success' | 'error' | 'info'\n\n/**\n * Uma ação no aviso.\n *\n * Existe porque \"adicionado ao carrinho\" sem saída é uma notificação que\n * informa e some: quem quer fechar o pedido agora tem de ir procurar o\n * carrinho. Com ação, o aviso É o caminho — e continuar comprando é não fazer\n * nada, que é o que a maioria vai fazer.\n */\nexport interface ToastAction {\n label: string\n onClick: () => void\n}\n\nexport interface Toast {\n id: string\n title: string\n description?: string\n variant: ToastVariant\n durationMs: number\n action?: ToastAction\n}\n\ninterface ToastState {\n toasts: Toast[]\n push(input: {\n title: string\n description?: string\n variant?: ToastVariant\n durationMs?: number\n action?: ToastAction\n }): string\n dismiss(id: string): void\n}\n\nlet seq = 0\n\nexport const useToastStore = create<ToastState>((set) => ({\n toasts: [],\n push: (input) => {\n const id = `toast-${++seq}-${Date.now()}`\n const toast: Toast = {\n id,\n title: input.title,\n description: input.description,\n variant: input.variant ?? 'info',\n durationMs: input.durationMs ?? 3400,\n action: input.action,\n }\n set((s) => ({ toasts: [...s.toasts, toast] }))\n return id\n },\n dismiss: (id) => set((s) => ({ toasts: s.toasts.filter((t) => t.id !== id) })),\n}))\n\n/** Imperative toast API — callable from components, store actions, or workflows. */\nexport const toast = {\n success: (title: string, description?: string) => useToastStore.getState().push({ title, description, variant: 'success' }),\n error: (title: string, description?: string) => useToastStore.getState().push({ title, description, variant: 'error' }),\n info: (title: string, description?: string) => useToastStore.getState().push({ title, description, variant: 'info' }),\n}\n","import React, { useEffect, useState } from 'react'\nimport { Lock, X } from 'lucide-react'\nimport { establishCustomerSession } from '../../data/auth'\nimport { useSessionStore } from '../../stores/session.store'\nimport { Link } from '../../app/router'\n\ninterface SignInModalProps {\n /** Prefill the email field (e.g. from a checkout contact field). */\n defaultEmail?: string\n onClose: () => void\n /** Called after a successful sign-in, with the resolved session. */\n onSignedIn?: (session: { email: string | null; name: string | null }) => void\n}\n\n/**\n * Customer sign-in as a focused modal dialog. Used from checkout (\"Já tem\n * conta? Entrar\") so a returning buyer can authenticate without leaving the\n * page. Auth goes through the shared establishCustomerSession path.\n */\nexport function SignInModal({ defaultEmail = '', onClose, onSignedIn }: SignInModalProps) {\n const [email, setEmail] = useState(defaultEmail)\n const [password, setPassword] = useState('')\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => { if (event.key === 'Escape') onClose() }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n }, [onClose])\n\n async function submit(event: React.FormEvent) {\n event.preventDefault()\n if (!email.trim() || !password) return\n setBusy(true)\n setError(null)\n try {\n await establishCustomerSession(email, { password })\n const session = useSessionStore.getState()\n onSignedIn?.({ email: session.email, name: session.name })\n onClose()\n } catch {\n setError('Não foi possível entrar. Verifique seu e-mail e senha.')\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-[60] flex items-center justify-center p-4\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Entrar na sua conta\"\n >\n <div className=\"absolute inset-0 animate-fade-in bg-foreground/40 backdrop-blur-sm\" onClick={onClose} />\n <div\n className=\"relative z-10 w-full max-w-sm animate-fade-up border bg-card p-6 shadow-2xl\"\n style={{ borderRadius: 'var(--sf-radius-card)' }}\n >\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Fechar\"\n className=\"absolute right-4 top-4 rounded-full p-1 text-muted-foreground transition hover:bg-muted hover:text-foreground\"\n >\n <X className=\"h-5 w-5\" />\n </button>\n\n <div className=\"flex items-center gap-2\">\n <span className=\"flex h-9 w-9 items-center justify-center rounded-full bg-primary/10 text-primary\">\n <Lock className=\"h-4 w-4\" />\n </span>\n <div>\n <h2 className=\"sf-heading text-lg font-semibold leading-tight\">Entrar na sua conta</h2>\n <p className=\"text-xs text-muted-foreground\">Use seus dados salvos e acompanhe pedidos.</p>\n </div>\n </div>\n\n <form onSubmit={submit} className=\"mt-5 space-y-3\">\n <input\n type=\"email\"\n required\n autoFocus\n placeholder=\"voce@exemplo.com\"\n value={email}\n onChange={(event) => setEmail(event.target.value)}\n className=\"w-full border bg-background px-3 py-2.5 text-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/10\"\n style={{ borderRadius: 'var(--sf-radius-input)' }}\n />\n <input\n type=\"password\"\n required\n placeholder=\"Senha\"\n value={password}\n onChange={(event) => setPassword(event.target.value)}\n className=\"w-full border bg-background px-3 py-2.5 text-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/10\"\n style={{ borderRadius: 'var(--sf-radius-input)' }}\n />\n {error && <p className=\"text-sm text-destructive\">{error}</p>}\n <button\n type=\"submit\"\n disabled={busy}\n className=\"sf-cta w-full bg-primary py-3 font-semibold text-primary-foreground shadow-md transition-all hover:-translate-y-0.5 hover:shadow-lg disabled:opacity-60\"\n style={{ borderRadius: 'var(--sf-radius-button)' }}\n >\n {busy ? 'Entrando…' : 'Entrar'}\n </button>\n </form>\n\n <p className=\"mt-4 text-center text-sm text-muted-foreground\">\n Não tem conta?{' '}\n <Link to=\"/account\" onClick={onClose} className=\"font-semibold text-primary hover:underline\">\n Criar conta\n </Link>\n </p>\n </div>\n </div>\n )\n}\n","import type { useStorefrontConfig } from '../document/config'\n\ntype Config = ReturnType<typeof useStorefrontConfig>\n\nconst KEY = 'fayz:sf:return-path'\n\n/**\n * Onde \"voltar\" volta.\n *\n * O checkout mandava sempre para `catalogPath`, e no modo delivery isso é uma\n * página que a pessoa nunca viu: ela veio do cardápio, clicou em voltar, e\n * caiu numa grade de produtos com facetas. Não é um erro de rótulo — é perder\n * o lugar de alguém no meio de uma compra.\n *\n * Guardado por sessão e não derivado do modo: no delivery as DUAS telas\n * existem (`/delivery` e `/catalog`), então o modo sozinho não sabe de qual\n * delas a pessoa saiu. A sessão sabe.\n */\nexport function rememberReturnPath(path: string): void {\n try {\n if (typeof sessionStorage === 'undefined') return\n sessionStorage.setItem(KEY, path)\n } catch {\n // Aba anônima, storage bloqueado. O fallback abaixo continua correto.\n }\n}\n\n/**\n * A superfície de compra para onde voltar.\n *\n * Sem nada guardado — primeira carga direto no /checkout, SSR, storage\n * bloqueado — cai para o cardápio quando a loja está em modo delivery e para o\n * catálogo quando não está: o padrão certo para cada loja, em vez de um só para\n * as duas.\n */\nexport function returnPath(config: Config): string {\n try {\n if (typeof sessionStorage !== 'undefined') {\n const remembered = sessionStorage.getItem(KEY)\n if (remembered) return remembered\n }\n } catch {\n // segue para o padrão\n }\n return config.delivery?.menuPath ?? config.catalogPath\n}\n"]}
|
|
@@ -468,6 +468,7 @@ function resolveConfig(config) {
|
|
|
468
468
|
delivery: commerceMode === "delivery" ? {
|
|
469
469
|
menuPath: config.delivery?.menuPath ?? "/menu",
|
|
470
470
|
coverImage: config.delivery?.coverImage,
|
|
471
|
+
coverImageSrcSet: config.delivery?.coverImageSrcSet,
|
|
471
472
|
logoImage: config.delivery?.logoImage,
|
|
472
473
|
coverSize: config.delivery?.coverSize,
|
|
473
474
|
locality: config.delivery?.locality,
|
|
@@ -633,5 +634,5 @@ function withStaticRenderPass(pass, render) {
|
|
|
633
634
|
}
|
|
634
635
|
|
|
635
636
|
export { Link, MESSAGES, StorefrontConfigProvider, StorefrontRouterProvider, currentStaticRenderPass, getStorefrontComponents, matchPath, navigateTo, normalizeLanguage, resolveConfig, shellRouterAdapter, translate, useHashPath, useNavigate, useRoutePath, useRouterAdapter, useScrollToTopOnNavigate, useStorefrontConfig, useStorefrontConfigOptional, withStaticRenderPass };
|
|
636
|
-
//# sourceMappingURL=chunk-
|
|
637
|
-
//# sourceMappingURL=chunk-
|
|
637
|
+
//# sourceMappingURL=chunk-PSDR5TZD.js.map
|
|
638
|
+
//# sourceMappingURL=chunk-PSDR5TZD.js.map
|