@fayz-ai/storefront 0.84.3 → 0.85.0

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.
Files changed (53) hide show
  1. package/dist/CheckoutPage-4MFKLBEI.js +12 -0
  2. package/dist/{CheckoutPage-G5NYJF3Z.js.map → CheckoutPage-4MFKLBEI.js.map} +1 -1
  3. package/dist/MyPurchasesPage-F25MIFXT.js +11 -0
  4. package/dist/{MyPurchasesPage-GOK2RO7K.js.map → MyPurchasesPage-F25MIFXT.js.map} +1 -1
  5. package/dist/OrderConfirmationPage-SOQDD767.js +10 -0
  6. package/dist/{OrderConfirmationPage-DGLW5W75.js.map → OrderConfirmationPage-SOQDD767.js.map} +1 -1
  7. package/dist/{chunk-P4RRFQQX.js → chunk-BR3XHNVM.js} +5 -5
  8. package/dist/{chunk-P4RRFQQX.js.map → chunk-BR3XHNVM.js.map} +1 -1
  9. package/dist/{chunk-RZWTEC6H.js → chunk-C4XATNI2.js} +3 -3
  10. package/dist/{chunk-RZWTEC6H.js.map → chunk-C4XATNI2.js.map} +1 -1
  11. package/dist/{chunk-45R7CIEA.js → chunk-CE4U65TZ.js} +4 -4
  12. package/dist/{chunk-45R7CIEA.js.map → chunk-CE4U65TZ.js.map} +1 -1
  13. package/dist/{chunk-2D5BEM43.js → chunk-EFHQ5MAJ.js} +3 -3
  14. package/dist/{chunk-2D5BEM43.js.map → chunk-EFHQ5MAJ.js.map} +1 -1
  15. package/dist/{chunk-UJ2TIM4V.js → chunk-ELW7QWDJ.js} +13 -12
  16. package/dist/chunk-ELW7QWDJ.js.map +1 -0
  17. package/dist/{chunk-F3U4KZC7.js → chunk-IUP5SDTX.js} +5 -5
  18. package/dist/{chunk-F3U4KZC7.js.map → chunk-IUP5SDTX.js.map} +1 -1
  19. package/dist/{chunk-ZSNKJGE5.js → chunk-NS6UPIJ3.js} +3 -3
  20. package/dist/{chunk-ZSNKJGE5.js.map → chunk-NS6UPIJ3.js.map} +1 -1
  21. package/dist/{chunk-FPFGRUCS.js → chunk-OOQRYH3N.js} +6 -6
  22. package/dist/{chunk-FPFGRUCS.js.map → chunk-OOQRYH3N.js.map} +1 -1
  23. package/dist/{chunk-GVZ2SAOI.js → chunk-PSDR5TZD.js} +3 -2
  24. package/dist/chunk-PSDR5TZD.js.map +1 -0
  25. package/dist/{chunk-PURHMU2W.js → chunk-RJUEUMR6.js} +4 -4
  26. package/dist/{chunk-PURHMU2W.js.map → chunk-RJUEUMR6.js.map} +1 -1
  27. package/dist/{chunk-BKO2AQ3Q.js → chunk-SLJ4BRXD.js} +3 -3
  28. package/dist/{chunk-BKO2AQ3Q.js.map → chunk-SLJ4BRXD.js.map} +1 -1
  29. package/dist/{chunk-YSQBZ3RM.js → chunk-YCAWAON6.js} +7 -7
  30. package/dist/{chunk-YSQBZ3RM.js.map → chunk-YCAWAON6.js.map} +1 -1
  31. package/dist/{chunk-554XAQWK.js → chunk-YDZU2SZL.js} +4 -4
  32. package/dist/{chunk-554XAQWK.js.map → chunk-YDZU2SZL.js.map} +1 -1
  33. package/dist/{chunk-WSHCQ3Y6.js → chunk-Z5JT7T4I.js} +8 -8
  34. package/dist/{chunk-WSHCQ3Y6.js.map → chunk-Z5JT7T4I.js.map} +1 -1
  35. package/dist/components/delivery/StoreCover.d.ts.map +1 -1
  36. package/dist/document/config.d.ts +8 -0
  37. package/dist/document/config.d.ts.map +1 -1
  38. package/dist/edge.d.ts +1 -1
  39. package/dist/edge.d.ts.map +1 -1
  40. package/dist/edge.js +19 -2
  41. package/dist/edge.js.map +1 -1
  42. package/dist/host/edge-handler.d.ts +26 -0
  43. package/dist/host/edge-handler.d.ts.map +1 -1
  44. package/dist/host.js +4 -4
  45. package/dist/index.js +22 -22
  46. package/dist/render.js +9 -9
  47. package/dist/tanstack.js +8 -8
  48. package/package.json +1 -1
  49. package/dist/CheckoutPage-G5NYJF3Z.js +0 -12
  50. package/dist/MyPurchasesPage-GOK2RO7K.js +0 -11
  51. package/dist/OrderConfirmationPage-DGLW5W75.js +0 -10
  52. package/dist/chunk-GVZ2SAOI.js.map +0 -1
  53. package/dist/chunk-UJ2TIM4V.js.map +0 -1
package/dist/edge.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/analytics/edge.ts","../src/host/edge-handler.ts"],"names":["response"],"mappings":"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","file":"edge.js","sourcesContent":["/**\n * The store's own door to PostHog, for a Worker (or any fetch-style) host.\n *\n * Events sent to the store's domain under `/ingest` are not dropped by ad\n * blockers the way requests to a known analytics host are, and the store needs\n * no PostHog setting of its own: every store forwards to the same project.\n *\n * if (url.pathname.startsWith('/ingest')) return posthogProxy(request)\n */\nexport interface PostHogProxyOptions {\n /** The path the storefront's analytics client sends to. Default `/ingest`. */\n prefix?: string\n /** PostHog's region. Default `us`. */\n region?: 'us' | 'eu'\n}\n\nexport function isPostHogProxyPath(pathname: string, prefix = '/ingest'): boolean {\n return pathname === prefix || pathname.startsWith(`${prefix}/`)\n}\n\nexport async function posthogProxy(request: Request, options: PostHogProxyOptions = {}): Promise<Response> {\n const prefix = options.prefix ?? '/ingest'\n const region = options.region ?? 'us'\n const url = new URL(request.url)\n const path = url.pathname.slice(prefix.length) || '/'\n // The SDK's script and its remote config live on the assets host.\n const host = path.startsWith('/static/') || path.startsWith('/array/')\n ? `${region}-assets.i.posthog.com`\n : `${region}.i.posthog.com`\n const target = new URL(`https://${host}${path}${url.search}`)\n\n const headers = new Headers(request.headers)\n headers.delete('cookie')\n headers.set('host', host)\n // PostHog geolocates from the visitor, not from the Worker.\n const ip = request.headers.get('cf-connecting-ip') ?? request.headers.get('x-forwarded-for')\n if (ip) headers.set('x-forwarded-for', ip)\n\n const init: RequestInit = { method: request.method, headers, redirect: 'manual' }\n if (request.method !== 'GET' && request.method !== 'HEAD') init.body = await request.arrayBuffer()\n const response = await fetch(target, init)\n const out = new Response(response.body, response)\n out.headers.delete('set-cookie')\n return out\n}\n","import { isPostHogProxyPath, posthogProxy } from '../analytics/edge'\nimport {\n EXPERIMENT_HEADER,\n NO_ASSIGNMENTS,\n assignExperiments,\n encodeExperimentHeader,\n experimentCacheSuffix,\n runningExperiments,\n isBotUserAgent,\n readVisitorId,\n readPinnedVisitorId,\n isPinnableVisitorId,\n visitorCookie,\n type ExperimentAssignments,\n type StorefrontExperiment,\n} from '../experiments/assign'\n\n// ---------------------------------------------------------------------------\n// The Worker in front of a server-rendered store.\n//\n// Five jobs a store's request handler has before the framework renders\n// anything, first written for artorious-shop and the same for every store:\n//\n// 1. Analytics through the store's own domain (`/ingest` → PostHog), so ad\n// blockers that drop requests to a known analytics host do not drop it.\n// 2. The store's photos from the store's own origin. The bytes live in\n// Supabase Storage; a photo addressed at the storage project is a second\n// origin the browser pays DNS + TLS for (measured 156–241 ms TTFB against\n// 112–141 ms same-origin). Only public objects of the `shop-images`\n// bucket are forwarded — this is not a general proxy.\n// 3. A real edge cache. Public pages already leave with `Cache-Control:\n// public, s-maxage=…`, but on workers.dev nothing in front honours it, so\n// every view paid the full render. The Workers Cache API makes the header\n// mean what it says. Marketing parameters (utm_*, fbclid…) are dropped\n// from the key: ad traffic hits the same entry as everyone else.\n// 4. `X-Robots-Tag: noindex` on any host that is not the store's address, so\n// the deployment URL never competes with the domain.\n// 5. A/B assignment. With a running experiment, every page request is\n// assigned its variants HERE, before render, locally with PostHog's\n// bucketing (experiments/assign.ts — no network), and the edge cache is\n// keyed by them: one entry per combination of variants, so a cached page\n// is never one visitor's variant served to another.\n// ---------------------------------------------------------------------------\n\n/** `/storage/v1/object/public/shop-images/…` or the `render/image` variant of it. */\nconst STORAGE_PATH = /^\\/storage\\/v1\\/(object|render\\/image)\\/public\\/(shop-images\\/[^?#]+)$/\n\n/** Query parameters the renderer understands. Anything else is dropped rather\n * than forwarded, so a crawler cannot mint unlimited distinct variants. */\nconst RENDER_PARAMS = new Set(['width', 'height', 'quality', 'format', 'resize'])\n\n/** A year: the object path carries a timestamp and is never overwritten. */\nconst IMMUTABLE = 'public, max-age=31536000, s-maxage=31536000, immutable'\n\nconst TRACKING_PARAM = /^(utm_[a-z0-9_]+|fbclid|gclid|gbraid|wbraid|msclkid|ttclid|igshid|mc_cid|mc_eid|_ga|ref)$/i\n\nexport function isStorageRequest(url: URL): boolean {\n return STORAGE_PATH.test(url.pathname)\n}\n\n/**\n * Which format this visitor gets — the only part of the request, besides the\n * URL, that changes the bytes. The renderer answers WebP or the original\n * depending on `accept` and declares no `Vary`, so every cache in front of it\n * has to put the answer in the key itself.\n */\nexport function imageFormatKey(request: Request): 'webp' | 'orig' {\n return /image\\/webp/.test(request.headers.get('accept') ?? '') ? 'webp' : 'orig'\n}\n\n/** Answer a storage request from Supabase, on the store's own origin. */\nexport async function serveStorageImage(request: Request, url: URL, supabaseUrl: string | undefined): Promise<Response> {\n const match = STORAGE_PATH.exec(url.pathname)\n if (!match) return new Response('Not found', { status: 404 })\n const base = supabaseUrl?.replace(/\\/$/, '')\n if (!base) return new Response('Storage is not configured', { status: 502 })\n\n const [, kind, objectPath] = match\n const upstream = new URL(`${base}/storage/v1/${kind}/public/${objectPath}`)\n for (const [key, value] of url.searchParams) {\n if (RENDER_PARAMS.has(key)) upstream.searchParams.set(key, value)\n }\n // A canonical `accept`, not the visitor's verbatim: two browsers that both\n // take WebP must produce the same upstream request.\n const webp = imageFormatKey(request) === 'webp'\n const response = await fetch(upstream.toString(), { headers: { accept: webp ? 'image/webp,image/*;q=0.8' : 'image/*' } })\n if (!response.ok) {\n // Upstream's status is passed through (a deleted photo must not look like\n // a 200), never its cache directives.\n return new Response(response.status === 404 ? 'Not found' : 'Upstream error', {\n status: response.status === 404 ? 404 : 502,\n headers: { 'cache-control': 'public, max-age=60' },\n })\n }\n const headers = new Headers()\n headers.set('content-type', response.headers.get('content-type') ?? 'image/jpeg')\n headers.set('cache-control', IMMUTABLE)\n headers.set('x-image-origin', 'supabase')\n headers.set('vary', 'Accept')\n return new Response(response.body, { status: 200, headers })\n}\n\n/** The cache key for a request, or null when it is not cacheable. `variant`\n * is the experiment part (`experimentCacheSuffix`); empty means control. */\nexport function edgeCacheKey(request: Request, buildId: string, variant = ''): Request | null {\n if (request.method !== 'GET') return null\n const url = new URL(request.url)\n for (const key of [...url.searchParams.keys()]) {\n if (TRACKING_PARAM.test(key)) url.searchParams.delete(key)\n }\n url.hash = ''\n if (isStorageRequest(url)) url.searchParams.set('_fmt', imageFormatKey(request))\n // Cached HTML names this build's hashed chunks, and a deploy deletes them.\n // Keyed by build, old pages stop matching the moment the new Worker serves.\n url.searchParams.set('_build', buildId)\n if (variant) url.searchParams.set('_exp', variant)\n return new Request(url.toString(), { method: 'GET' })\n}\n\n/** Only what the response itself declares shareable and fresh for a while. */\nexport function edgeCacheable(response: Response): boolean {\n if (response.status !== 200) return false\n const cc = response.headers.get('cache-control') ?? ''\n return /\\bpublic\\b/.test(cc) && /\\bs-maxage=[1-9]\\d*/.test(cc) && !/\\b(no-store|private)\\b/.test(cc)\n}\n\nfunction withHeader(response: Response, name: string, value: string): Response {\n const headers = new Headers(response.headers)\n headers.set(name, value)\n return new Response(response.body, { status: response.status, statusText: response.statusText, headers })\n}\n\n/** Adds cookies without touching the ones the page already sets. */\nfunction withCookies(response: Response, cookies: readonly string[]): Response {\n if (!cookies.length) return response\n const headers = new Headers(response.headers)\n for (const cookie of cookies) headers.append('set-cookie', cookie)\n return new Response(response.body, { status: response.status, statusText: response.statusText, headers })\n}\n\nexport interface StorefrontEdgeOptions {\n /** The framework's own handler (TanStack Start's `handler.fetch`). */\n render(request: Request): Response | Promise<Response>\n /** From the store host: `host.isCanonicalHost`. */\n isCanonicalHost(url: URL): boolean\n /** One id per build, for the cache key. */\n buildId: string\n /** The Supabase project the photos live in (`PUBLIC_SUPABASE_URL`). */\n supabaseUrl?: string\n /** Keeps the Worker alive past the response (`waitUntil` from 'cloudflare:workers'). */\n waitUntil(promise: Promise<unknown>): void\n /** The Workers cache (`caches.default`). Omitted: no edge cache. */\n cache?: Cache\n /**\n * Development: NEVER cache. The Cloudflare vite plugin runs the Worker in\n * workerd locally too, and an entry cannot be purged, only outlived — a\n * price edited and reloaded shows the old one with nothing in the browser\n * able to help.\n */\n dev?: boolean\n /**\n * A/B tests: the store's declared experiments (`config.experiments`).\n * Nothing running: no assignment, no cookie, the cache key is the page's\n * alone — exactly the handler without tests.\n */\n experiments?: StorefrontEdgeExperiments\n}\n\nexport interface StorefrontEdgeExperiments {\n declared: Record<string, StorefrontExperiment> | undefined\n /**\n * The PostHog project token (`phc_…`), the same the storefront sends with —\n * used only to read PostHog's own cookie, so a returning visitor is bucketed\n * by the id PostHog already knows them by. Optional: without it, `fz_vid`.\n */\n posthogKey?: string\n}\n\n/** A page a visitor navigates to — not an asset, a photo, a feed or a POST. */\nfunction isPageRequest(request: Request, url: URL): boolean {\n if (request.method !== 'GET') return false\n if (isStorageRequest(url) || isPostHogProxyPath(url.pathname)) return false\n // Hashed bundles, fonts, images, the sitemap: anything with an extension.\n if (/\\.[a-z0-9]{1,8}$/i.test(url.pathname)) return false\n // TanStack's server functions and the router's data requests.\n if (url.pathname.startsWith('/_serverFn') || url.pathname.startsWith('/_server')) return false\n return true\n}\n\ninterface PageAssignment {\n assignments: ExperimentAssignments\n /** The cache-key part; empty for control. */\n variant: string\n /** Cookies for THIS visitor's response: a new id. */\n cookies: string[]\n}\n\n/**\n * Decide this request's variants — locally, with PostHog's bucketing, no\n * network. Never throws.\n */\nexport async function assignForRequest(request: Request, options: StorefrontEdgeExperiments): Promise<PageAssignment> {\n const running = runningExperiments(options.declared)\n const keys = Object.keys(running)\n const none: PageAssignment = { assignments: NO_ASSIGNMENTS, variant: '', cookies: [] }\n // Nothing running: no id, no cookie, the page's plain cache entry.\n if (!keys.length) return none\n // Crawlers and unfurlers see control and get no id: what is indexed and\n // shared must not depend on a coin flip, and a bot is not an exposure.\n if (isBotUserAgent(request.headers.get('user-agent'))) return none\n const cookieHeader = request.headers.get('cookie')\n // The bucket id is pinned in `fz_vid` the first time and read from there\n // ever after. A returning visitor without one is pinned to the anonymous id\n // PostHog already knows them by; an identified id (an e-mail) is never\n // stored — they get a fresh anonymous one.\n const pinned = readPinnedVisitorId(cookieHeader)\n const known = pinned ?? readVisitorId(cookieHeader, options.posthogKey ?? '')\n const distinctId = known && isPinnableVisitorId(known) ? known : crypto.randomUUID()\n const cookies = pinned ? [] : [visitorCookie(distinctId, new URL(request.url).protocol === 'https:')]\n try {\n const assignments = await assignExperiments({ experiments: running, distinctId })\n return { assignments, variant: experimentCacheSuffix(assignments, keys), cookies }\n } catch {\n // No SubtleCrypto (not a Worker, not a modern runtime): everyone control.\n return { ...none, cookies }\n }\n}\n\n/**\n * The request the renderer sees: the same, plus the variants — and ONLY the\n * variants. The visitor id stays out of the header on purpose: the rendered\n * HTML is cached and shared by every visitor in the same variant bucket, and\n * an id in it would hand one visitor's identity to the next. The browser\n * reads its own id from the cookie (`readVisitorId(document.cookie, …)`).\n */\nfunction withAssignment(request: Request, assignments: ExperimentAssignments): Request {\n const headers = new Headers(request.headers)\n headers.delete(EXPERIMENT_HEADER) // never trust one the visitor sent\n if (Object.keys(assignments.flags).length) {\n headers.set(EXPERIMENT_HEADER, encodeExperimentHeader({ flags: assignments.flags }))\n }\n return new Request(request, { headers })\n}\n\n/** The Worker's `fetch`, from the store's pieces. */\nexport function createStorefrontEdge(options: StorefrontEdgeOptions): (request: Request) => Promise<Response> {\n async function respond(request: Request): Promise<Response> {\n const url = new URL(request.url)\n if (isStorageRequest(url)) return serveStorageImage(request, url, options.supabaseUrl)\n const response = await options.render(request)\n if (options.isCanonicalHost(url)) return response\n return withHeader(response, 'x-robots-tag', 'noindex, nofollow')\n }\n\n return async (incoming) => {\n const url = new URL(incoming.url)\n // Analytics leaves through the store's own domain, never cached.\n if (isPostHogProxyPath(url.pathname)) return posthogProxy(incoming)\n\n // Variants first: they change the HTML, so they are part of the cache key.\n const page = options.experiments && isPageRequest(incoming, url)\n ? await assignForRequest(incoming, options.experiments)\n : null\n const request = page ? withAssignment(incoming, page.assignments) : incoming\n // Cookies are added to what THIS visitor receives, never to the cached\n // copy (a shared entry carrying one visitor's id would hand it to the\n // next), and appended, so a cookie the page itself sets survives.\n const finish = (response: Response) => withCookies(response, page?.cookies ?? [])\n\n if (options.dev || !options.cache) return finish(await respond(request))\n\n const key = edgeCacheKey(request, options.buildId, page?.variant ?? '')\n if (!key) return finish(await respond(request))\n const hit = await options.cache.match(key)\n if (hit) return finish(withHeader(hit, 'x-edge-cache', 'HIT'))\n\n const response = await respond(request)\n if (!edgeCacheable(response)) return finish(withHeader(response, 'x-edge-cache', 'BYPASS'))\n options.waitUntil(options.cache.put(key, response.clone()))\n return finish(withHeader(response, 'x-edge-cache', 'MISS'))\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/analytics/edge.ts","../src/host/edge-handler.ts"],"names":["response"],"mappings":"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","file":"edge.js","sourcesContent":["/**\n * The store's own door to PostHog, for a Worker (or any fetch-style) host.\n *\n * Events sent to the store's domain under `/ingest` are not dropped by ad\n * blockers the way requests to a known analytics host are, and the store needs\n * no PostHog setting of its own: every store forwards to the same project.\n *\n * if (url.pathname.startsWith('/ingest')) return posthogProxy(request)\n */\nexport interface PostHogProxyOptions {\n /** The path the storefront's analytics client sends to. Default `/ingest`. */\n prefix?: string\n /** PostHog's region. Default `us`. */\n region?: 'us' | 'eu'\n}\n\nexport function isPostHogProxyPath(pathname: string, prefix = '/ingest'): boolean {\n return pathname === prefix || pathname.startsWith(`${prefix}/`)\n}\n\nexport async function posthogProxy(request: Request, options: PostHogProxyOptions = {}): Promise<Response> {\n const prefix = options.prefix ?? '/ingest'\n const region = options.region ?? 'us'\n const url = new URL(request.url)\n const path = url.pathname.slice(prefix.length) || '/'\n // The SDK's script and its remote config live on the assets host.\n const host = path.startsWith('/static/') || path.startsWith('/array/')\n ? `${region}-assets.i.posthog.com`\n : `${region}.i.posthog.com`\n const target = new URL(`https://${host}${path}${url.search}`)\n\n const headers = new Headers(request.headers)\n headers.delete('cookie')\n headers.set('host', host)\n // PostHog geolocates from the visitor, not from the Worker.\n const ip = request.headers.get('cf-connecting-ip') ?? request.headers.get('x-forwarded-for')\n if (ip) headers.set('x-forwarded-for', ip)\n\n const init: RequestInit = { method: request.method, headers, redirect: 'manual' }\n if (request.method !== 'GET' && request.method !== 'HEAD') init.body = await request.arrayBuffer()\n const response = await fetch(target, init)\n const out = new Response(response.body, response)\n out.headers.delete('set-cookie')\n return out\n}\n","import { isPostHogProxyPath, posthogProxy } from '../analytics/edge'\nimport {\n EXPERIMENT_HEADER,\n NO_ASSIGNMENTS,\n assignExperiments,\n encodeExperimentHeader,\n experimentCacheSuffix,\n runningExperiments,\n isBotUserAgent,\n readVisitorId,\n readPinnedVisitorId,\n isPinnableVisitorId,\n visitorCookie,\n type ExperimentAssignments,\n type StorefrontExperiment,\n} from '../experiments/assign'\n\n// ---------------------------------------------------------------------------\n// The Worker in front of a server-rendered store.\n//\n// Five jobs a store's request handler has before the framework renders\n// anything, first written for artorious-shop and the same for every store:\n//\n// 1. Analytics through the store's own domain (`/ingest` → PostHog), so ad\n// blockers that drop requests to a known analytics host do not drop it.\n// 2. The store's photos from the store's own origin. The bytes live in\n// Supabase Storage; a photo addressed at the storage project is a second\n// origin the browser pays DNS + TLS for (measured 156–241 ms TTFB against\n// 112–141 ms same-origin). Only public objects of the `shop-images`\n// bucket are forwarded — this is not a general proxy.\n// 3. A real edge cache. Public pages already leave with `Cache-Control:\n// public, s-maxage=…`, but on workers.dev nothing in front honours it, so\n// every view paid the full render. The Workers Cache API makes the header\n// mean what it says. Marketing parameters (utm_*, fbclid…) are dropped\n// from the key: ad traffic hits the same entry as everyone else.\n// 4. `X-Robots-Tag: noindex` on any host that is not the store's address, so\n// the deployment URL never competes with the domain.\n// 5. A/B assignment. With a running experiment, every page request is\n// assigned its variants HERE, before render, locally with PostHog's\n// bucketing (experiments/assign.ts — no network), and the edge cache is\n// keyed by them: one entry per combination of variants, so a cached page\n// is never one visitor's variant served to another.\n// ---------------------------------------------------------------------------\n\n/** `/storage/v1/object/public/shop-images/…` or the `render/image` variant of it. */\nconst STORAGE_PATH = /^\\/storage\\/v1\\/(object|render\\/image)\\/public\\/(shop-images\\/[^?#]+)$/\n\n/** Query parameters the renderer understands. Anything else is dropped rather\n * than forwarded, so a crawler cannot mint unlimited distinct variants. */\nconst RENDER_PARAMS = new Set(['width', 'height', 'quality', 'format', 'resize'])\n\n/** A year: the object path carries a timestamp and is never overwritten. */\nconst IMMUTABLE = 'public, max-age=31536000, s-maxage=31536000, immutable'\n\nconst TRACKING_PARAM = /^(utm_[a-z0-9_]+|fbclid|gclid|gbraid|wbraid|msclkid|ttclid|igshid|mc_cid|mc_eid|_ga|ref)$/i\n\nexport function isStorageRequest(url: URL): boolean {\n return STORAGE_PATH.test(url.pathname)\n}\n\n/**\n * Which format this visitor gets — the only part of the request, besides the\n * URL, that changes the bytes. The renderer answers WebP or the original\n * depending on `accept` and declares no `Vary`, so every cache in front of it\n * has to put the answer in the key itself.\n */\nexport function imageFormatKey(request: Request): 'webp' | 'orig' {\n return /image\\/webp/.test(request.headers.get('accept') ?? '') ? 'webp' : 'orig'\n}\n\n/** Answer a storage request from Supabase, on the store's own origin. */\nexport async function serveStorageImage(request: Request, url: URL, supabaseUrl: string | undefined): Promise<Response> {\n const match = STORAGE_PATH.exec(url.pathname)\n if (!match) return new Response('Not found', { status: 404 })\n const base = supabaseUrl?.replace(/\\/$/, '')\n if (!base) return new Response('Storage is not configured', { status: 502 })\n\n const [, kind, objectPath] = match\n const upstream = new URL(`${base}/storage/v1/${kind}/public/${objectPath}`)\n for (const [key, value] of url.searchParams) {\n if (RENDER_PARAMS.has(key)) upstream.searchParams.set(key, value)\n }\n // A canonical `accept`, not the visitor's verbatim: two browsers that both\n // take WebP must produce the same upstream request.\n const webp = imageFormatKey(request) === 'webp'\n const response = await fetch(upstream.toString(), { headers: { accept: webp ? 'image/webp,image/*;q=0.8' : 'image/*' } })\n if (!response.ok) {\n // Upstream's status is passed through (a deleted photo must not look like\n // a 200), never its cache directives.\n return new Response(response.status === 404 ? 'Not found' : 'Upstream error', {\n status: response.status === 404 ? 404 : 502,\n headers: { 'cache-control': 'public, max-age=60' },\n })\n }\n const headers = new Headers()\n headers.set('content-type', response.headers.get('content-type') ?? 'image/jpeg')\n headers.set('cache-control', IMMUTABLE)\n headers.set('x-image-origin', 'supabase')\n headers.set('vary', 'Accept')\n return new Response(response.body, { status: 200, headers })\n}\n\n/** The cache key for a request, or null when it is not cacheable. `variant`\n * is the experiment part (`experimentCacheSuffix`); empty means control. */\nexport function edgeCacheKey(request: Request, buildId: string, variant = ''): Request | null {\n if (request.method !== 'GET') return null\n const url = new URL(request.url)\n for (const key of [...url.searchParams.keys()]) {\n if (TRACKING_PARAM.test(key)) url.searchParams.delete(key)\n }\n url.hash = ''\n if (isStorageRequest(url)) url.searchParams.set('_fmt', imageFormatKey(request))\n // Cached HTML names this build's hashed chunks, and a deploy deletes them.\n // Keyed by build, old pages stop matching the moment the new Worker serves.\n url.searchParams.set('_build', buildId)\n if (variant) url.searchParams.set('_exp', variant)\n return new Request(url.toString(), { method: 'GET' })\n}\n\n/** Only what the response itself declares shareable and fresh for a while. */\nexport function edgeCacheable(response: Response): boolean {\n if (response.status !== 200) return false\n const cc = response.headers.get('cache-control') ?? ''\n return /\\bpublic\\b/.test(cc) && /\\bs-maxage=[1-9]\\d*/.test(cc) && !/\\b(no-store|private)\\b/.test(cc)\n}\n\nfunction withHeader(response: Response, name: string, value: string): Response {\n const headers = new Headers(response.headers)\n headers.set(name, value)\n return new Response(response.body, { status: response.status, statusText: response.statusText, headers })\n}\n\n/** Adds cookies without touching the ones the page already sets. */\nfunction withCookies(response: Response, cookies: readonly string[]): Response {\n if (!cookies.length) return response\n const headers = new Headers(response.headers)\n for (const cookie of cookies) headers.append('set-cookie', cookie)\n return new Response(response.body, { status: response.status, statusText: response.statusText, headers })\n}\n\nexport interface StorefrontEdgeOptions {\n /** The framework's own handler (TanStack Start's `handler.fetch`). */\n render(request: Request): Response | Promise<Response>\n /** From the store host: `host.isCanonicalHost`. */\n isCanonicalHost(url: URL): boolean\n /** One id per build, for the cache key. */\n buildId: string\n /** The Supabase project the photos live in (`PUBLIC_SUPABASE_URL`). */\n supabaseUrl?: string\n /** Keeps the Worker alive past the response (`waitUntil` from 'cloudflare:workers'). */\n waitUntil(promise: Promise<unknown>): void\n /** The Workers cache (`caches.default`). Omitted: no edge cache. */\n cache?: Cache\n /**\n * Development: NEVER cache. The Cloudflare vite plugin runs the Worker in\n * workerd locally too, and an entry cannot be purged, only outlived — a\n * price edited and reloaded shows the old one with nothing in the browser\n * able to help.\n */\n dev?: boolean\n /**\n * A/B tests: the store's declared experiments (`config.experiments`).\n * Nothing running: no assignment, no cookie, the cache key is the page's\n * alone — exactly the handler without tests.\n */\n experiments?: StorefrontEdgeExperiments\n /**\n * Start the client bundle after the first frame is painted (see\n * `hydrateAfterFirstPaint`). Off by default; a server-rendered store whose\n * HTML is complete without JavaScript turns it on.\n */\n hydrateAfterFirstPaint?: boolean\n}\n\nexport interface StorefrontEdgeExperiments {\n declared: Record<string, StorefrontExperiment> | undefined\n /**\n * The PostHog project token (`phc_…`), the same the storefront sends with —\n * used only to read PostHog's own cookie, so a returning visitor is bucketed\n * by the id PostHog already knows them by. Optional: without it, `fz_vid`.\n */\n posthogKey?: string\n}\n\n/** A page a visitor navigates to — not an asset, a photo, a feed or a POST. */\nfunction isPageRequest(request: Request, url: URL): boolean {\n if (request.method !== 'GET') return false\n if (isStorageRequest(url) || isPostHogProxyPath(url.pathname)) return false\n // Hashed bundles, fonts, images, the sitemap: anything with an extension.\n if (/\\.[a-z0-9]{1,8}$/i.test(url.pathname)) return false\n // TanStack's server functions and the router's data requests.\n if (url.pathname.startsWith('/_serverFn') || url.pathname.startsWith('/_server')) return false\n return true\n}\n\ninterface PageAssignment {\n assignments: ExperimentAssignments\n /** The cache-key part; empty for control. */\n variant: string\n /** Cookies for THIS visitor's response: a new id. */\n cookies: string[]\n}\n\n/**\n * Decide this request's variants — locally, with PostHog's bucketing, no\n * network. Never throws.\n */\nexport async function assignForRequest(request: Request, options: StorefrontEdgeExperiments): Promise<PageAssignment> {\n const running = runningExperiments(options.declared)\n const keys = Object.keys(running)\n const none: PageAssignment = { assignments: NO_ASSIGNMENTS, variant: '', cookies: [] }\n // Nothing running: no id, no cookie, the page's plain cache entry.\n if (!keys.length) return none\n // Crawlers and unfurlers see control and get no id: what is indexed and\n // shared must not depend on a coin flip, and a bot is not an exposure.\n if (isBotUserAgent(request.headers.get('user-agent'))) return none\n const cookieHeader = request.headers.get('cookie')\n // The bucket id is pinned in `fz_vid` the first time and read from there\n // ever after. A returning visitor without one is pinned to the anonymous id\n // PostHog already knows them by; an identified id (an e-mail) is never\n // stored — they get a fresh anonymous one.\n const pinned = readPinnedVisitorId(cookieHeader)\n const known = pinned ?? readVisitorId(cookieHeader, options.posthogKey ?? '')\n const distinctId = known && isPinnableVisitorId(known) ? known : crypto.randomUUID()\n const cookies = pinned ? [] : [visitorCookie(distinctId, new URL(request.url).protocol === 'https:')]\n try {\n const assignments = await assignExperiments({ experiments: running, distinctId })\n return { assignments, variant: experimentCacheSuffix(assignments, keys), cookies }\n } catch {\n // No SubtleCrypto (not a Worker, not a modern runtime): everyone control.\n return { ...none, cookies }\n }\n}\n\n/**\n * The request the renderer sees: the same, plus the variants — and ONLY the\n * variants. The visitor id stays out of the header on purpose: the rendered\n * HTML is cached and shared by every visitor in the same variant bucket, and\n * an id in it would hand one visitor's identity to the next. The browser\n * reads its own id from the cookie (`readVisitorId(document.cookie, …)`).\n */\nfunction withAssignment(request: Request, assignments: ExperimentAssignments): Request {\n const headers = new Headers(request.headers)\n headers.delete(EXPERIMENT_HEADER) // never trust one the visitor sent\n if (Object.keys(assignments.flags).length) {\n headers.set(EXPERIMENT_HEADER, encodeExperimentHeader({ flags: assignments.flags }))\n }\n return new Request(request, { headers })\n}\n\n/** The Worker's `fetch`, from the store's pieces. */\nexport function createStorefrontEdge(options: StorefrontEdgeOptions): (request: Request) => Promise<Response> {\n async function respond(request: Request): Promise<Response> {\n const url = new URL(request.url)\n if (isStorageRequest(url)) return serveStorageImage(request, url, options.supabaseUrl)\n const rendered = await options.render(request)\n const response = options.hydrateAfterFirstPaint ? hydrateAfterFirstPaint(rendered) : rendered\n if (options.isCanonicalHost(url)) return response\n return withHeader(response, 'x-robots-tag', 'noindex, nofollow')\n }\n\n return async (incoming) => {\n const url = new URL(incoming.url)\n // Analytics leaves through the store's own domain, never cached.\n if (isPostHogProxyPath(url.pathname)) return posthogProxy(incoming)\n\n // Variants first: they change the HTML, so they are part of the cache key.\n const page = options.experiments && isPageRequest(incoming, url)\n ? await assignForRequest(incoming, options.experiments)\n : null\n const request = page ? withAssignment(incoming, page.assignments) : incoming\n // Cookies are added to what THIS visitor receives, never to the cached\n // copy (a shared entry carrying one visitor's id would hand it to the\n // next), and appended, so a cookie the page itself sets survives.\n const finish = (response: Response) => withCookies(response, page?.cookies ?? [])\n\n if (options.dev || !options.cache) return finish(await respond(request))\n\n const key = edgeCacheKey(request, options.buildId, page?.variant ?? '')\n if (!key) return finish(await respond(request))\n const hit = await options.cache.match(key)\n if (hit) return finish(withHeader(hit, 'x-edge-cache', 'HIT'))\n\n const response = await respond(request)\n if (!edgeCacheable(response)) return finish(withHeader(response, 'x-edge-cache', 'BYPASS'))\n options.waitUntil(options.cache.put(key, response.clone()))\n return finish(withHeader(response, 'x-edge-cache', 'MISS'))\n }\n}\n\n/** Minimal shape of the Workers runtime's streaming HTML rewriter. */\ninterface HtmlRewriterLike {\n on(selector: string, handlers: { element(el: HtmlElementLike): void }): HtmlRewriterLike\n transform(response: Response): Response\n}\ninterface HtmlElementLike {\n getAttribute(name: string): string | null\n hasAttribute(name: string): boolean\n removeAttribute(name: string): void\n setInnerContent(content: string, options?: { html?: boolean }): void\n}\n\n/** The inline loader that replaces the entry tag: import once a frame is painted. */\nexport function deferredEntryScript(src: string): string {\n // rAF runs before the next paint; the timeout queued from it runs after.\n return `requestAnimationFrame(function(){setTimeout(function(){import(${JSON.stringify(src)})},0)})`\n}\n\n/**\n * Let the server-rendered page paint before the client bundle runs.\n *\n * TanStack Start emits its entry as `<script type=\"module\" async src>`, which\n * executes the moment it arrives. On a fast connection that is BEFORE the\n * browser's first paint, so a page that was complete as HTML sat blank while\n * ~1 MB of JavaScript was evaluated and hydrated — and Lighthouse, seeing the\n * script run before the paint, counted the whole bundle as render-blocking\n * (FCP 1.0 s one run, 3.3 s the next). The entry is rewritten into an inline\n * module that imports the same URL after the first frame; its\n * `<link rel=\"modulepreload\">` still downloads it in parallel, so nothing\n * arrives later — it only runs later, after the shopper sees the page.\n *\n * Only HTML responses, only an `async` module entry with a `src`; everything\n * else passes through. Without the Workers `HTMLRewriter` (tests, Node) it is a\n * no-op.\n */\nexport function hydrateAfterFirstPaint(response: Response): Response {\n const Rewriter = (globalThis as { HTMLRewriter?: new () => HtmlRewriterLike }).HTMLRewriter\n if (!Rewriter || !(response.headers.get('content-type') ?? '').includes('text/html')) return response\n return new Rewriter()\n .on('script[type=\"module\"][src]', {\n element(el) {\n const src = el.getAttribute('src')\n if (!src || !el.hasAttribute('async') || src.includes('<')) return\n el.removeAttribute('src')\n el.removeAttribute('async')\n el.setInnerContent(deferredEntryScript(src), { html: true })\n },\n })\n .transform(response)\n}\n"]}
@@ -40,6 +40,12 @@ export interface StorefrontEdgeOptions {
40
40
  * alone — exactly the handler without tests.
41
41
  */
42
42
  experiments?: StorefrontEdgeExperiments;
43
+ /**
44
+ * Start the client bundle after the first frame is painted (see
45
+ * `hydrateAfterFirstPaint`). Off by default; a server-rendered store whose
46
+ * HTML is complete without JavaScript turns it on.
47
+ */
48
+ hydrateAfterFirstPaint?: boolean;
43
49
  }
44
50
  export interface StorefrontEdgeExperiments {
45
51
  declared: Record<string, StorefrontExperiment> | undefined;
@@ -64,5 +70,25 @@ interface PageAssignment {
64
70
  export declare function assignForRequest(request: Request, options: StorefrontEdgeExperiments): Promise<PageAssignment>;
65
71
  /** The Worker's `fetch`, from the store's pieces. */
66
72
  export declare function createStorefrontEdge(options: StorefrontEdgeOptions): (request: Request) => Promise<Response>;
73
+ /** The inline loader that replaces the entry tag: import once a frame is painted. */
74
+ export declare function deferredEntryScript(src: string): string;
75
+ /**
76
+ * Let the server-rendered page paint before the client bundle runs.
77
+ *
78
+ * TanStack Start emits its entry as `<script type="module" async src>`, which
79
+ * executes the moment it arrives. On a fast connection that is BEFORE the
80
+ * browser's first paint, so a page that was complete as HTML sat blank while
81
+ * ~1 MB of JavaScript was evaluated and hydrated — and Lighthouse, seeing the
82
+ * script run before the paint, counted the whole bundle as render-blocking
83
+ * (FCP 1.0 s one run, 3.3 s the next). The entry is rewritten into an inline
84
+ * module that imports the same URL after the first frame; its
85
+ * `<link rel="modulepreload">` still downloads it in parallel, so nothing
86
+ * arrives later — it only runs later, after the shopper sees the page.
87
+ *
88
+ * Only HTML responses, only an `async` module entry with a `src`; everything
89
+ * else passes through. Without the Workers `HTMLRewriter` (tests, Node) it is a
90
+ * no-op.
91
+ */
92
+ export declare function hydrateAfterFirstPaint(response: Response): Response;
67
93
  export {};
68
94
  //# sourceMappingURL=edge-handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"edge-handler.d.ts","sourceRoot":"","sources":["../../src/host/edge-handler.ts"],"names":[],"mappings":"AACA,OAAO,EAYL,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EAC1B,MAAM,uBAAuB,CAAA;AAyC9B,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAElD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAEhE;AAED,yEAAyE;AACzE,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,CA6BtH;AAED;6EAC6E;AAC7E,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,SAAK,GAAG,OAAO,GAAG,IAAI,CAa5F;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAIzD;AAgBD,MAAM,WAAW,qBAAqB;IACpC,sEAAsE;IACtE,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IACtD,mDAAmD;IACnD,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAA;IAClC,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAA;IACf,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wFAAwF;IACxF,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAA;IAC1C,oEAAoE;IACpE,KAAK,CAAC,EAAE,KAAK,CAAA;IACb;;;;;OAKG;IACH,GAAG,CAAC,EAAE,OAAO,CAAA;IACb;;;;OAIG;IACH,WAAW,CAAC,EAAE,yBAAyB,CAAA;CACxC;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,GAAG,SAAS,CAAA;IAC1D;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAaD,UAAU,cAAc;IACtB,WAAW,EAAE,qBAAqB,CAAA;IAClC,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAA;IACf,qDAAqD;IACrD,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,cAAc,CAAC,CAyBpH;AAkBD,qDAAqD;AACrD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAoC5G"}
1
+ {"version":3,"file":"edge-handler.d.ts","sourceRoot":"","sources":["../../src/host/edge-handler.ts"],"names":[],"mappings":"AACA,OAAO,EAYL,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EAC1B,MAAM,uBAAuB,CAAA;AAyC9B,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAElD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAEhE;AAED,yEAAyE;AACzE,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,CA6BtH;AAED;6EAC6E;AAC7E,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,SAAK,GAAG,OAAO,GAAG,IAAI,CAa5F;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAIzD;AAgBD,MAAM,WAAW,qBAAqB;IACpC,sEAAsE;IACtE,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IACtD,mDAAmD;IACnD,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAA;IAClC,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAA;IACf,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wFAAwF;IACxF,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAA;IAC1C,oEAAoE;IACpE,KAAK,CAAC,EAAE,KAAK,CAAA;IACb;;;;;OAKG;IACH,GAAG,CAAC,EAAE,OAAO,CAAA;IACb;;;;OAIG;IACH,WAAW,CAAC,EAAE,yBAAyB,CAAA;IACvC;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAA;CACjC;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,GAAG,SAAS,CAAA;IAC1D;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAaD,UAAU,cAAc;IACtB,WAAW,EAAE,qBAAqB,CAAA;IAClC,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAA;IACf,qDAAqD;IACrD,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,cAAc,CAAC,CAyBpH;AAkBD,qDAAqD;AACrD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAqC5G;AAcD,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAcnE"}
package/dist/host.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { buildRobotsTxt, buildSitemapXml } from './chunk-WCAQRATH.js';
2
2
  export { buildRobotsTxt, buildSitemapXml } from './chunk-WCAQRATH.js';
3
- import { storefrontPaths, isPublicPath, menuDataNeeds, isKnownPath, productSeo, menuSeo, pageSeo } from './chunk-45R7CIEA.js';
4
- export { menuDataNeeds } from './chunk-45R7CIEA.js';
5
- import { collectDataNeeds, resolvePageDataNeed, toBlockNodes, defaultPageBlocks } from './chunk-BKO2AQ3Q.js';
6
- import { resolveConfig, matchPath } from './chunk-GVZ2SAOI.js';
3
+ import { storefrontPaths, isPublicPath, menuDataNeeds, isKnownPath, productSeo, menuSeo, pageSeo } from './chunk-CE4U65TZ.js';
4
+ export { menuDataNeeds } from './chunk-CE4U65TZ.js';
5
+ import { collectDataNeeds, resolvePageDataNeed, toBlockNodes, defaultPageBlocks } from './chunk-SLJ4BRXD.js';
6
+ import { resolveConfig, matchPath } from './chunk-PSDR5TZD.js';
7
7
  import { validateExperiments } from './chunk-4REZOGGW.js';
8
8
  export { EXPERIMENT_HEADER, decodeExperimentHeader } from './chunk-4REZOGGW.js';
9
9
  import { buildSeoTags } from '@fayz-ai/core';
package/dist/index.js CHANGED
@@ -1,30 +1,30 @@
1
1
  export { auditStorefrontSeo, collectSeoAuditInput } from './chunk-6IXTENLB.js';
2
- import { placeStorefrontOrder } from './chunk-YSQBZ3RM.js';
3
- export { AddressForm, CheckoutPage, CountrySelect, DeliverToPicker, placeStorefrontOrder } from './chunk-YSQBZ3RM.js';
4
- export { OrderConfirmationPage } from './chunk-F3U4KZC7.js';
2
+ import { placeStorefrontOrder } from './chunk-YCAWAON6.js';
3
+ export { AddressForm, CheckoutPage, CountrySelect, DeliverToPicker, placeStorefrontOrder } from './chunk-YCAWAON6.js';
4
+ export { OrderConfirmationPage } from './chunk-IUP5SDTX.js';
5
5
  import './chunk-WDQFNHYO.js';
6
- export { MyPurchasesPage } from './chunk-WSHCQ3Y6.js';
7
- export { useMyOrders } from './chunk-ZSNKJGE5.js';
8
- export { OrderTrackingTimeline } from './chunk-PURHMU2W.js';
6
+ export { MyPurchasesPage } from './chunk-Z5JT7T4I.js';
7
+ export { useMyOrders } from './chunk-NS6UPIJ3.js';
8
+ export { OrderTrackingTimeline } from './chunk-RJUEUMR6.js';
9
9
  import './chunk-FCPOPWG3.js';
10
- import { STORE_SECTION_NAMES, isRecord, STORE_SECTIONS, slugifyStoreName, exportStore, validateStore, isJsonValue, sectionToJsonSchema, STOREFRONT_PAGE_KINDS, STOREFRONT_COMPONENT_KEYS, hydrateStoreDocument } from './chunk-P4RRFQQX.js';
11
- export { STOREFRONT_COMPONENT_KEYS, STOREFRONT_PAGE_KINDS, STORE_BACKEND_PROVIDERS, STORE_COMMERCE_MODES, STORE_DOCUMENT_KIND, STORE_PAYMENT_METHOD_KINDS, STORE_PAYMENT_MODES, STORE_ROUTE_CHROMES, STORE_ROUTE_KINDS, STORE_SECTIONS, STORE_SECTION_NAMES, exportStore, hydrateStoreDocument, sectionToJsonSchema, slugifyStoreName, validateStore } from './chunk-P4RRFQQX.js';
12
- import { initStorefrontRuntime, StorefrontConfigHost, StorefrontShell, registerStorefrontBlocks, useCatalogStore } from './chunk-UJ2TIM4V.js';
13
- export { AddressStrip, BenefitsRow, CartDrawer, CatalogPage, CategoryShowcase, ClosedStoreDialog, CollectionCta, CollectionHero, ContentPage, CountdownBand, EntityListBlock, ExperimentBlock, ExperimentProvider, ExperimentVariantBlock, FaqSection, FiltersPanel, FormBlock, HeroSection, ImageTiles, ItemSheet, ManifestoBlock, MediaCarousel, MenuItemRow, MenuPage, MenuToolbar, MotifStrip, NewsletterBand, PLACEHOLDER_ASPECTS, PaymentTerms, Price, ProductCard, ProductDetailPage, ProductEnquiryForm, ProductGallery, ProductGrid, ProductOptionSelector, ProductRail, ProductReviews, ProductSlider, ProductSpecs, ProductSpotlight, PromoBanner, QuantityInput, ScheduleSheet, SealsBand, SearchOverlay, ServiceHoursModal, StepsSection, StoreCover, StorefrontAnalytics, StorefrontConfigHost, StorefrontFooter, StorefrontHeader, StorefrontShell, StorefrontThemeStyle, StoryQuote, THEME_SCALE_FIELDS, THEME_SCALE_VAR_PREFIX, Testimonials, TierCards, applyDeliveryPolicy, applyStoreSettings, bannerPlaceholder, buildEnquiryFromForm, createStorefront, createStorefrontApp, entityListBlockMeta, initStorefrontRuntime, isExperimentBinding, matchesFacets, mergeCollectionFacet, nextMilestone, orderGalleryImages, overrideComponent, overrideProps, pickProductCardImage, productCardComponentContract, productPlaceholder, registerStorefrontBlocks, registerStorefrontEntities, registerStorefrontLoaders, resolveExperimental, resolveOverride, resolvePaymentTerms, resolveStorefrontProvider, sectionsToBlocks, selectIsOpen, selectShowsHours, startStorefrontPostHog, storeBuyerId, storefrontComponentContracts, themeToCss, toFacetMap, useCatalogStore, useCategories, useEnquiry, useExperiment, useExperimentValue, useMarketProduct, useProduct, useProducts, useServiceStore, useStorefrontActions, withFacet } from './chunk-UJ2TIM4V.js';
14
- import { registerStorefrontExtensionPoints, STOREFRONT_SLOTS, useBuyerCountry, StorefrontPage } from './chunk-FPFGRUCS.js';
15
- export { BEFORE_PLACE_ORDER_VALVE, BUYER_COUNTRY_COOKIE, CART_LINE_ANNOTATION_POINT, CHECKOUT_FIELD_POINT, ORDER_METADATA_POINT, PAGE_DATA_SCRIPT_ID, PRODUCT_CARD_BADGE_POINT, STOREFRONT_SLOTS, Slot, StorefrontPage, collectOrderMetadata, getCartLineAnnotations, getCheckoutFieldContributions, getProductCardBadges, hydratedEntriesFor, identifyStorefrontBuyer, listSlots, onStorefrontEvent, readHydratedPageData, registerStorefrontExtensionPoints, resetPageDiagnostics, resetStorefrontExtensionPoints, runBeforePlaceOrderValve, serializePageData, trackStorefront, useBuyerCountry, useBuyerStore, useDiscountValidator, useSlotContext, useSlotFilled, useStorefrontPage, useStorefrontPageOptional, useT, usedSlots } from './chunk-FPFGRUCS.js';
10
+ import { STORE_SECTION_NAMES, isRecord, STORE_SECTIONS, slugifyStoreName, exportStore, validateStore, isJsonValue, sectionToJsonSchema, STOREFRONT_PAGE_KINDS, STOREFRONT_COMPONENT_KEYS, hydrateStoreDocument } from './chunk-BR3XHNVM.js';
11
+ export { STOREFRONT_COMPONENT_KEYS, STOREFRONT_PAGE_KINDS, STORE_BACKEND_PROVIDERS, STORE_COMMERCE_MODES, STORE_DOCUMENT_KIND, STORE_PAYMENT_METHOD_KINDS, STORE_PAYMENT_MODES, STORE_ROUTE_CHROMES, STORE_ROUTE_KINDS, STORE_SECTIONS, STORE_SECTION_NAMES, exportStore, hydrateStoreDocument, sectionToJsonSchema, slugifyStoreName, validateStore } from './chunk-BR3XHNVM.js';
12
+ import { initStorefrontRuntime, StorefrontConfigHost, StorefrontShell, registerStorefrontBlocks, useCatalogStore } from './chunk-ELW7QWDJ.js';
13
+ export { AddressStrip, BenefitsRow, CartDrawer, CatalogPage, CategoryShowcase, ClosedStoreDialog, CollectionCta, CollectionHero, ContentPage, CountdownBand, EntityListBlock, ExperimentBlock, ExperimentProvider, ExperimentVariantBlock, FaqSection, FiltersPanel, FormBlock, HeroSection, ImageTiles, ItemSheet, ManifestoBlock, MediaCarousel, MenuItemRow, MenuPage, MenuToolbar, MotifStrip, NewsletterBand, PLACEHOLDER_ASPECTS, PaymentTerms, Price, ProductCard, ProductDetailPage, ProductEnquiryForm, ProductGallery, ProductGrid, ProductOptionSelector, ProductRail, ProductReviews, ProductSlider, ProductSpecs, ProductSpotlight, PromoBanner, QuantityInput, ScheduleSheet, SealsBand, SearchOverlay, ServiceHoursModal, StepsSection, StoreCover, StorefrontAnalytics, StorefrontConfigHost, StorefrontFooter, StorefrontHeader, StorefrontShell, StorefrontThemeStyle, StoryQuote, THEME_SCALE_FIELDS, THEME_SCALE_VAR_PREFIX, Testimonials, TierCards, applyDeliveryPolicy, applyStoreSettings, bannerPlaceholder, buildEnquiryFromForm, createStorefront, createStorefrontApp, entityListBlockMeta, initStorefrontRuntime, isExperimentBinding, matchesFacets, mergeCollectionFacet, nextMilestone, orderGalleryImages, overrideComponent, overrideProps, pickProductCardImage, productCardComponentContract, productPlaceholder, registerStorefrontBlocks, registerStorefrontEntities, registerStorefrontLoaders, resolveExperimental, resolveOverride, resolvePaymentTerms, resolveStorefrontProvider, sectionsToBlocks, selectIsOpen, selectShowsHours, startStorefrontPostHog, storeBuyerId, storefrontComponentContracts, themeToCss, toFacetMap, useCatalogStore, useCategories, useEnquiry, useExperiment, useExperimentValue, useMarketProduct, useProduct, useProducts, useServiceStore, useStorefrontActions, withFacet } from './chunk-ELW7QWDJ.js';
14
+ import { registerStorefrontExtensionPoints, STOREFRONT_SLOTS, useBuyerCountry, StorefrontPage } from './chunk-OOQRYH3N.js';
15
+ export { BEFORE_PLACE_ORDER_VALVE, BUYER_COUNTRY_COOKIE, CART_LINE_ANNOTATION_POINT, CHECKOUT_FIELD_POINT, ORDER_METADATA_POINT, PAGE_DATA_SCRIPT_ID, PRODUCT_CARD_BADGE_POINT, STOREFRONT_SLOTS, Slot, StorefrontPage, collectOrderMetadata, getCartLineAnnotations, getCheckoutFieldContributions, getProductCardBadges, hydratedEntriesFor, identifyStorefrontBuyer, listSlots, onStorefrontEvent, readHydratedPageData, registerStorefrontExtensionPoints, resetPageDiagnostics, resetStorefrontExtensionPoints, runBeforePlaceOrderValve, serializePageData, trackStorefront, useBuyerCountry, useBuyerStore, useDiscountValidator, useSlotContext, useSlotFilled, useStorefrontPage, useStorefrontPageOptional, useT, usedSlots } from './chunk-OOQRYH3N.js';
16
16
  export { Reveal, prefersReducedMotion, useInView, usePopOnChange, useScrolled } from './chunk-WXXYJZE6.js';
17
- export { AddressSheet } from './chunk-554XAQWK.js';
18
- import { useCartStore, selectTotal, selectShipping, selectDiscountTotal, selectSubtotal, selectCount, useDeliveryStore, selectRequiresShipping } from './chunk-RZWTEC6H.js';
19
- export { formatProductOptionSelection, getProductOptionGroups, marketForCountry, marketUnitPrice, normalizeProductOptionSelection, productOptionSelectionKey, resetProductOptionsDeprecationWarnings, resolveVariantForSelection, selectCount, selectDiscountTotal, selectShipping, selectSubtotal, selectTotal, selectionPrice, useCartStore, useMarketStore, withMarketPrice } from './chunk-RZWTEC6H.js';
17
+ export { AddressSheet } from './chunk-YDZU2SZL.js';
18
+ import { useCartStore, selectTotal, selectShipping, selectDiscountTotal, selectSubtotal, selectCount, useDeliveryStore, selectRequiresShipping } from './chunk-C4XATNI2.js';
19
+ export { formatProductOptionSelection, getProductOptionGroups, marketForCountry, marketUnitPrice, normalizeProductOptionSelection, productOptionSelectionKey, resetProductOptionsDeprecationWarnings, resolveVariantForSelection, selectCount, selectDiscountTotal, selectShipping, selectSubtotal, selectTotal, selectionPrice, useCartStore, useMarketStore, withMarketPrice } from './chunk-C4XATNI2.js';
20
20
  import './chunk-DVQHKNNX.js';
21
- import { formatMoney, useSessionStore } from './chunk-2D5BEM43.js';
22
- export { EmailConfirmationRequiredError, SmoothImage, TID, createLazyAuthAdapter, establishCustomerSession, formatMoney, getCustomerAuthAdapter, resolveAuthAdapter, roundCents, signInByEmail, signOutCustomer, signUpCustomer, useSessionStore, useStorefrontHead } from './chunk-2D5BEM43.js';
23
- export { isKnownPath, isPublicPath, menuDataNeeds, menuJsonLd, menuSeo, pageSeo, primaryImageUrl, productJsonLd, productSeo, resolveStorefrontRoute, storefrontPaths } from './chunk-45R7CIEA.js';
24
- import { isNestedBlockRef, BLOCK_STRUCTURAL_KEYS, blockInstanceId } from './chunk-BKO2AQ3Q.js';
25
- export { BlockDataError, CATALOG_BODY_BLOCK, PRODUCT_BODY_BLOCK, PageDataScope, checkPageBlocks, collectDataNeeds, contentPagePath, defaultPageBlocks, matchContentPage, mergePageTheme, pageThemeSelector, resolveDataParams, resolvePageData, resolvePageDataNeed, routePathParams, toBlockNodes, useBlockData, useLoader } from './chunk-BKO2AQ3Q.js';
26
- import { resolveConfig, useStorefrontConfig } from './chunk-GVZ2SAOI.js';
27
- export { Link, MESSAGES, StorefrontConfigProvider, StorefrontRouterProvider, currentStaticRenderPass, matchPath, navigateTo, normalizeLanguage, resolveConfig, shellRouterAdapter, translate, useHashPath, useNavigate, useRoutePath, useRouterAdapter, useScrollToTopOnNavigate, useStorefrontConfig, useStorefrontConfigOptional, withStaticRenderPass } from './chunk-GVZ2SAOI.js';
21
+ import { formatMoney, useSessionStore } from './chunk-EFHQ5MAJ.js';
22
+ export { EmailConfirmationRequiredError, SmoothImage, TID, createLazyAuthAdapter, establishCustomerSession, formatMoney, getCustomerAuthAdapter, resolveAuthAdapter, roundCents, signInByEmail, signOutCustomer, signUpCustomer, useSessionStore, useStorefrontHead } from './chunk-EFHQ5MAJ.js';
23
+ export { isKnownPath, isPublicPath, menuDataNeeds, menuJsonLd, menuSeo, pageSeo, primaryImageUrl, productJsonLd, productSeo, resolveStorefrontRoute, storefrontPaths } from './chunk-CE4U65TZ.js';
24
+ import { isNestedBlockRef, BLOCK_STRUCTURAL_KEYS, blockInstanceId } from './chunk-SLJ4BRXD.js';
25
+ export { BlockDataError, CATALOG_BODY_BLOCK, PRODUCT_BODY_BLOCK, PageDataScope, checkPageBlocks, collectDataNeeds, contentPagePath, defaultPageBlocks, matchContentPage, mergePageTheme, pageThemeSelector, resolveDataParams, resolvePageData, resolvePageDataNeed, routePathParams, toBlockNodes, useBlockData, useLoader } from './chunk-SLJ4BRXD.js';
26
+ import { resolveConfig, useStorefrontConfig } from './chunk-PSDR5TZD.js';
27
+ export { Link, MESSAGES, StorefrontConfigProvider, StorefrontRouterProvider, currentStaticRenderPass, matchPath, navigateTo, normalizeLanguage, resolveConfig, shellRouterAdapter, translate, useHashPath, useNavigate, useRoutePath, useRouterAdapter, useScrollToTopOnNavigate, useStorefrontConfig, useStorefrontConfigOptional, withStaticRenderPass } from './chunk-PSDR5TZD.js';
28
28
  export { CONTROL as EXPERIMENT_CONTROL, validateExperiments } from './chunk-4REZOGGW.js';
29
29
  import React3 from 'react';
30
30
  import { defineApp, registerScaffold, describeExtensionPoints, handleRegistry, describeEntities, describeLoaders, describeBlocks, ENTITY_FIELD_TYPES, BLOCK_SETTING_TYPES, errorMessage, normalizePostalCode, lookupPostalCode, formatPostalCode, BLOCK_PATH_ATTRIBUTE, BLOCK_TYPE_ATTRIBUTE, setBlockEditorMode, renderApp as renderApp$1 } from '@fayz-ai/core';
package/dist/render.js CHANGED
@@ -1,16 +1,16 @@
1
- import { validateStore, hydrateStoreDocument } from './chunk-P4RRFQQX.js';
1
+ import { validateStore, hydrateStoreDocument } from './chunk-BR3XHNVM.js';
2
2
  import { buildRobotsTxt, buildSitemapXml } from './chunk-WCAQRATH.js';
3
3
  export { buildRobotsTxt, buildSitemapXml } from './chunk-WCAQRATH.js';
4
- import { registerStorefrontBlocks, registerStorefrontEntities, StorefrontShell, themeToCss, resolveStorefrontProvider } from './chunk-UJ2TIM4V.js';
5
- import { resetPageDiagnostics, serializePageData } from './chunk-FPFGRUCS.js';
4
+ import { registerStorefrontBlocks, registerStorefrontEntities, StorefrontShell, themeToCss, resolveStorefrontProvider } from './chunk-ELW7QWDJ.js';
5
+ import { resetPageDiagnostics, serializePageData } from './chunk-OOQRYH3N.js';
6
6
  import './chunk-WXXYJZE6.js';
7
- import './chunk-554XAQWK.js';
8
- import './chunk-RZWTEC6H.js';
7
+ import './chunk-YDZU2SZL.js';
8
+ import './chunk-C4XATNI2.js';
9
9
  import './chunk-DVQHKNNX.js';
10
- import './chunk-2D5BEM43.js';
11
- import { storefrontPaths, isPublicPath } from './chunk-45R7CIEA.js';
12
- import { resolvePageData } from './chunk-BKO2AQ3Q.js';
13
- import { resolveConfig, withStaticRenderPass, StorefrontConfigProvider } from './chunk-GVZ2SAOI.js';
10
+ import './chunk-EFHQ5MAJ.js';
11
+ import { storefrontPaths, isPublicPath } from './chunk-CE4U65TZ.js';
12
+ import { resolvePageData } from './chunk-SLJ4BRXD.js';
13
+ import { resolveConfig, withStaticRenderPass, StorefrontConfigProvider } from './chunk-PSDR5TZD.js';
14
14
  import './chunk-4REZOGGW.js';
15
15
  import { renderToStaticMarkup } from 'react-dom/server';
16
16
  import { historyRouterAdapter, setBlockErrorVisibility, setBlockEditorMode, staticRouterAdapter, buildSeoTags, errorMessage } from '@fayz-ai/core';
package/dist/tanstack.js CHANGED
@@ -1,13 +1,13 @@
1
- import { StorefrontConfigHost, ExperimentProvider, StorefrontShell } from './chunk-UJ2TIM4V.js';
2
- import './chunk-FPFGRUCS.js';
1
+ import { StorefrontConfigHost, ExperimentProvider, StorefrontShell } from './chunk-ELW7QWDJ.js';
2
+ import './chunk-OOQRYH3N.js';
3
3
  import './chunk-WXXYJZE6.js';
4
- import './chunk-554XAQWK.js';
5
- import './chunk-RZWTEC6H.js';
4
+ import './chunk-YDZU2SZL.js';
5
+ import './chunk-C4XATNI2.js';
6
6
  import './chunk-DVQHKNNX.js';
7
- import './chunk-2D5BEM43.js';
8
- import './chunk-45R7CIEA.js';
9
- import { PageDataScope } from './chunk-BKO2AQ3Q.js';
10
- import { StorefrontRouterProvider } from './chunk-GVZ2SAOI.js';
7
+ import './chunk-EFHQ5MAJ.js';
8
+ import './chunk-CE4U65TZ.js';
9
+ import { PageDataScope } from './chunk-SLJ4BRXD.js';
10
+ import { StorefrontRouterProvider } from './chunk-PSDR5TZD.js';
11
11
  import './chunk-4REZOGGW.js';
12
12
  import { useEffect, useMemo, useState } from 'react';
13
13
  import { useMatches, useRouter, useRouterState } from '@tanstack/react-router';
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "fayz": {
4
4
  "status": "beta"
5
5
  },
6
- "version": "0.84.3",
6
+ "version": "0.85.0",
7
7
  "description": "Fayz SDK storefront kit — Shopify-style customer-facing ecommerce template components",
8
8
  "type": "module",
9
9
  "sideEffects": false,
@@ -1,12 +0,0 @@
1
- export { CheckoutPage } from './chunk-YSQBZ3RM.js';
2
- import './chunk-WDQFNHYO.js';
3
- import './chunk-ZSNKJGE5.js';
4
- import './chunk-FCPOPWG3.js';
5
- import './chunk-FPFGRUCS.js';
6
- import './chunk-WXXYJZE6.js';
7
- import './chunk-RZWTEC6H.js';
8
- import './chunk-2D5BEM43.js';
9
- import './chunk-BKO2AQ3Q.js';
10
- import './chunk-GVZ2SAOI.js';
11
- //# sourceMappingURL=CheckoutPage-G5NYJF3Z.js.map
12
- //# sourceMappingURL=CheckoutPage-G5NYJF3Z.js.map
@@ -1,11 +0,0 @@
1
- export { MyPurchasesPage } from './chunk-WSHCQ3Y6.js';
2
- import './chunk-ZSNKJGE5.js';
3
- import './chunk-PURHMU2W.js';
4
- import './chunk-FCPOPWG3.js';
5
- import './chunk-554XAQWK.js';
6
- import './chunk-RZWTEC6H.js';
7
- import './chunk-DVQHKNNX.js';
8
- import './chunk-2D5BEM43.js';
9
- import './chunk-GVZ2SAOI.js';
10
- //# sourceMappingURL=MyPurchasesPage-GOK2RO7K.js.map
11
- //# sourceMappingURL=MyPurchasesPage-GOK2RO7K.js.map
@@ -1,10 +0,0 @@
1
- export { OrderConfirmationPage } from './chunk-F3U4KZC7.js';
2
- import './chunk-WDQFNHYO.js';
3
- import './chunk-PURHMU2W.js';
4
- import './chunk-FCPOPWG3.js';
5
- import './chunk-WXXYJZE6.js';
6
- import './chunk-DVQHKNNX.js';
7
- import './chunk-2D5BEM43.js';
8
- import './chunk-GVZ2SAOI.js';
9
- //# sourceMappingURL=OrderConfirmationPage-DGLW5W75.js.map
10
- //# sourceMappingURL=OrderConfirmationPage-DGLW5W75.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/locales/messages.ts","../src/document/config.ts","../src/app/router.ts","../src/app/static-render.ts"],"names":["createContext","useContext","React"],"mappings":"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","file":"chunk-GVZ2SAOI.js","sourcesContent":["// ---------------------------------------------------------------------------\n// The storefront's own words (cart, checkout, delivery), per language.\n//\n// pt-BR is the source: copied verbatim from the screens as they were, so a\n// store that sets no language reads exactly what it always read. en and es\n// translate it; a key missing from either falls back to pt-BR, never to the\n// key itself. `{{name}}` marks a value filled in at the call site.\n// ---------------------------------------------------------------------------\n\nexport type StorefrontLanguage = 'pt-BR' | 'en' | 'es'\n\nexport const ptBR = {\n // Checkout shell\n 'checkout.title': 'Checkout — {{store}}',\n 'checkout.backToStore': 'Voltar à loja',\n 'checkout.secure': 'Checkout seguro',\n 'checkout.help': 'Ajuda',\n 'checkout.steps.label': 'Etapas do checkout',\n 'checkout.steps.1': 'Dados',\n 'checkout.steps.2': 'Entrega',\n 'checkout.steps.3': 'Pagamento',\n 'checkout.steps.4': 'Pronto',\n // Step 1 — contact\n 'checkout.contact.title': 'Informações de contato',\n 'checkout.contact.signedInAs': 'Conectado como {{email}}',\n 'checkout.contact.edit': 'Alterar',\n 'checkout.contact.notYou': 'Não é você?',\n 'checkout.contact.signOut': 'Sair',\n 'checkout.contact.emailLocked': 'O e-mail é o da sua conta.',\n 'checkout.contact.haveAccount': 'Já tem conta? Entrar',\n 'checkout.contact.email': 'E-mail',\n 'checkout.contact.name': 'Nome completo',\n 'checkout.contact.phone': 'Telefone',\n 'checkout.contact.phoneOptional': 'Telefone (opcional)',\n 'checkout.contact.document': 'CPF ou CNPJ',\n 'checkout.contact.documentOptional': 'CPF ou CNPJ (opcional)',\n 'checkout.contact.requiresAccount': 'Esta loja pede uma conta para finalizar a compra.',\n 'checkout.contact.signInOrCreate': 'Entrar ou criar conta',\n // Step 2 — address\n 'checkout.address.title': 'Endereço de entrega',\n 'checkout.address.loadingSaved': 'Buscando seus endereços salvos',\n 'checkout.address.selected': 'Selecionado',\n 'checkout.address.addNew': '+ Adicionar novo endereço',\n 'checkout.address.enter': 'Informe o endereço de entrega',\n 'checkout.address.enterHint': 'Preencher outro endereço para esta compra',\n 'checkout.address.lookingUp': 'Buscando o endereço deste CEP',\n 'checkout.address.notFound': 'CEP não encontrado — preencha o endereço à mão.',\n 'checkout.address.filled': 'Preenchemos o endereço para você.',\n 'checkout.address.regionFromPostal': 'Província preenchida pelo código postal.',\n 'checkout.address.optional': '{{label}} (opcional)',\n 'checkout.address.choose': 'Selecione',\n 'checkout.address.shipTo': 'Enviar para',\n // Step 3 — payment\n 'checkout.confirming.title': 'Confirmando seu pedido',\n 'checkout.confirming.label': 'Criando seu pedido',\n 'checkout.confirming.keepOpen': 'Não feche esta página — estamos registrando seu pedido na loja.',\n 'checkout.payment.title': 'Pagamento',\n 'checkout.payment.label': 'Forma de pagamento',\n 'checkout.payment.cardOnline': 'Você paga na página segura do provedor e volta para a loja',\n 'checkout.payment.placeOrder': 'Fazer pedido - {{total}}',\n 'checkout.payment.pendingNote': 'O pedido fica aguardando pagamento até a loja confirmar.',\n 'checkout.payment.unavailableCountry': 'Esta forma de pagamento não está disponível para {{country}}.',\n 'payment.pix.label': 'Pix',\n 'payment.pix.hint': 'Você recebe a chave para pagar após confirmar o pedido',\n 'payment.credit_card.label': 'Cartão de crédito',\n 'payment.credit_card.hint': 'Maquininha na entrega',\n 'payment.debit_card.label': 'Cartão de débito',\n 'payment.debit_card.hint': 'Maquininha na entrega',\n 'payment.boleto.label': 'Boleto',\n 'payment.boleto.hint': 'Enviado por e-mail após a confirmação',\n 'payment.cash.label': 'Dinheiro',\n 'payment.cash.hint': 'Pagamento na entrega',\n 'payment.other.label': 'Combinar com a loja',\n 'payment.other.hint': 'A loja entra em contato para acertar o pagamento',\n // Step 4\n 'checkout.done.title': 'Pagamento confirmado!',\n 'checkout.done.text': 'Seu pedido foi criado e a loja já foi avisada.',\n 'checkout.done.viewOrder': 'Ver meu pedido',\n // Navigation\n 'checkout.continueToDelivery': 'Continuar para a entrega',\n 'checkout.goToPayment': 'Ir para o pagamento - {{total}}',\n 'checkout.backToContact': 'Voltar aos dados',\n 'checkout.backToCart': 'Voltar ao carrinho',\n // Summary\n 'summary.title': 'Resumo do pedido',\n 'summary.subtotal': 'Subtotal',\n 'summary.discount': 'Desconto',\n 'summary.delivery': 'Entrega',\n 'summary.pickup': 'Retirada na loja',\n 'summary.noFee': 'Sem taxa',\n 'summary.free': 'Grátis',\n 'summary.total': 'Total',\n 'summary.protected': 'Compra protegida e dados criptografados.',\n 'summary.shipping': 'Frete',\n // Discount\n 'discount.placeholder': 'Cupom de desconto',\n 'discount.apply': 'Aplicar',\n 'discount.freeShipping': 'frete grátis',\n 'discount.percentOff': '{{percent}}% de desconto',\n 'discount.applied': '{{code}} aplicado: {{effect}}.',\n 'discount.appliedToast': 'Cupom aplicado!',\n 'discount.invalid': 'Cupom inválido.',\n 'discount.invalidToast': 'Cupom inválido',\n 'discount.checkCode': 'Verifique o código e tente novamente.',\n 'discount.cannotValidate': 'Não conseguimos validar esse cupom agora.',\n 'discount.cannotValidateToast': 'Não conseguimos validar o cupom',\n 'discount.tryLater': 'Tente de novo em alguns instantes.',\n // Legal\n 'legal.privacy': 'Privacidade',\n 'legal.terms': 'Termos',\n 'legal.refunds': 'Trocas e devoluções',\n // Validation\n 'error.requiresAccount': 'Esta loja pede uma conta para finalizar a compra. Entre ou crie a sua.',\n 'error.email': 'Informe um e-mail válido.',\n 'error.name': 'Informe seu nome completo.',\n 'error.phone': 'Informe um telefone de contato.',\n 'error.documentInvalid': 'CPF ou CNPJ inválido — confira os números.',\n 'error.documentMissing': 'Informe o CPF ou CNPJ do comprador.',\n 'error.taxIdInvalid': 'NIF/NIE inválido — confira o número.',\n 'error.address': 'Preencha ou selecione o endereço de entrega.',\n 'error.number': 'Falta o número do endereço.',\n 'error.complement': 'Informe o complemento (apto, bloco).',\n 'error.state': 'Informe a UF com duas letras (ex.: RJ).',\n 'error.postalInvalid': 'Confira o código postal (ex.: {{example}}).',\n 'error.region': 'Selecione a {{label}}.',\n 'error.refusedZone': 'Esta loja não entrega nesse endereço. Tente outro.',\n 'error.unserved': 'Ainda não entregamos nesse CEP. Tente outro endereço.',\n 'error.sessionMismatch': 'Sua sessão ficou presa a outro cadastro. Recarregue a página e tente de novo.',\n 'error.outOfStock': 'Um item do carrinho ficou sem estoque. Revise o carrinho e tente de novo.',\n 'error.placeOrder': 'Não foi possível concluir o pedido.',\n // Delivery estimator\n 'delivery.title': 'Calcular entrega',\n 'delivery.calculate': 'Calcular',\n 'delivery.postalLabel': 'CEP',\n 'delivery.change': 'Trocar CEP',\n 'delivery.unserved': 'Ainda não entregamos nesse CEP.',\n 'delivery.refused': 'Esta loja não entrega nesse endereço.',\n 'delivery.review': 'Entregamos nessa região, mas confirmamos com você antes de sair.',\n 'delivery.etaSoon': 'hoje ou amanhã',\n 'delivery.etaRange': '{{min}} a {{max}} dias úteis',\n 'delivery.etaDays': '{{days}} dia(s) útil(eis)',\n 'delivery.flatRate': 'O frete é calculado no checkout.',\n 'delivery.error.digits': 'Digite os 8 dígitos do CEP.',\n 'delivery.error.postal': 'Confira o código postal (ex.: {{example}}).',\n 'delivery.error.quote': 'Não foi possível calcular o frete agora. Tente de novo.',\n 'delivery.error.notFound': 'CEP não encontrado. Confira os números.',\n // Cart\n 'cart.title': 'Carrinho',\n 'cart.close': 'Fechar carrinho',\n 'cart.empty': 'Seu carrinho está vazio.',\n 'cart.remove': 'Remover {{name}}',\n 'cart.checkout': 'Finalizar compra',\n 'cart.missingForFree': 'Faltam {{amount}} para frete grátis',\n 'cart.wonFree': 'Você ganhou frete grátis!',\n 'cart.minimumOrder': 'Pedido mínimo para entrega: {{amount}}. Faltam {{missing}}.',\n 'delivery.eta': 'Entrega em ~{{duration}}',\n 'delivery.etaUpTo': 'Entrega em até {{duration}}',\n 'delivery.paused': 'Delivery fechado no momento',\n 'cart.deliveryPaused': 'O delivery está fechado no momento. Volte mais tarde para finalizar.',\n // Deliver to\n 'country.deliverTo': 'Enviar para',\n 'country.change': 'Trocar país',\n 'country.label': 'País de entrega',\n}\n\nexport type MessageKey = keyof typeof ptBR\nexport type Messages = Record<MessageKey, string>\n\nconst en: Partial<Messages> = {\n 'checkout.backToStore': 'Back to store',\n 'checkout.secure': 'Secure checkout',\n 'checkout.help': 'Help',\n 'checkout.steps.label': 'Checkout steps',\n 'checkout.steps.1': 'Details',\n 'checkout.steps.2': 'Delivery',\n 'checkout.steps.3': 'Payment',\n 'checkout.steps.4': 'Done',\n 'checkout.contact.title': 'Contact information',\n 'checkout.contact.signedInAs': 'Signed in as {{email}}',\n 'checkout.contact.edit': 'Change',\n 'checkout.contact.notYou': 'Not you?',\n 'checkout.contact.signOut': 'Sign out',\n 'checkout.contact.emailLocked': 'This is your account e-mail.',\n 'checkout.contact.haveAccount': 'Have an account? Sign in',\n 'checkout.contact.email': 'Email',\n 'checkout.contact.name': 'Full name',\n 'checkout.contact.phone': 'Phone',\n 'checkout.contact.phoneOptional': 'Phone (optional)',\n 'checkout.contact.document': 'Tax ID',\n 'checkout.contact.documentOptional': 'Tax ID (optional)',\n 'checkout.contact.requiresAccount': 'This store needs an account to complete the purchase.',\n 'checkout.contact.signInOrCreate': 'Sign in or create an account',\n 'checkout.address.title': 'Delivery address',\n 'checkout.address.loadingSaved': 'Loading your saved addresses',\n 'checkout.address.selected': 'Selected',\n 'checkout.address.addNew': '+ Add a new address',\n 'checkout.address.enter': 'Enter the delivery address',\n 'checkout.address.enterHint': 'Use a different address for this order',\n 'checkout.address.lookingUp': 'Looking up this postal code',\n 'checkout.address.notFound': 'Postal code not found — fill in the address by hand.',\n 'checkout.address.filled': 'We filled in the address for you.',\n 'checkout.address.regionFromPostal': 'Province filled in from the postcode.',\n 'checkout.address.optional': '{{label}} (optional)',\n 'checkout.address.choose': 'Select',\n 'checkout.address.shipTo': 'Ship to',\n 'checkout.confirming.title': 'Confirming your order',\n 'checkout.confirming.label': 'Creating your order',\n 'checkout.confirming.keepOpen': 'Don’t close this page — we’re registering your order with the store.',\n 'checkout.payment.title': 'Payment',\n 'checkout.payment.label': 'Payment method',\n 'checkout.payment.cardOnline': 'You pay on the provider’s secure page and come back to the store',\n 'checkout.payment.placeOrder': 'Place order - {{total}}',\n 'checkout.payment.pendingNote': 'The order awaits payment until the store confirms it.',\n 'checkout.payment.unavailableCountry': 'This payment method isn’t available for {{country}}.',\n 'payment.pix.hint': 'You get the key to pay after confirming the order',\n 'payment.credit_card.label': 'Credit card',\n 'payment.credit_card.hint': 'Card machine on delivery',\n 'payment.debit_card.label': 'Debit card',\n 'payment.debit_card.hint': 'Card machine on delivery',\n 'payment.boleto.hint': 'Sent by email after confirmation',\n 'payment.cash.label': 'Cash',\n 'payment.cash.hint': 'Pay on delivery',\n 'payment.other.label': 'Arrange with the store',\n 'payment.other.hint': 'The store will contact you to arrange payment',\n 'checkout.done.title': 'Payment confirmed!',\n 'checkout.done.text': 'Your order was created and the store has been notified.',\n 'checkout.done.viewOrder': 'View my order',\n 'checkout.continueToDelivery': 'Continue to delivery',\n 'checkout.goToPayment': 'Go to payment - {{total}}',\n 'checkout.backToContact': 'Back to details',\n 'checkout.backToCart': 'Back to cart',\n 'summary.title': 'Order summary',\n 'summary.discount': 'Discount',\n 'summary.delivery': 'Delivery',\n 'summary.pickup': 'Store pickup',\n 'summary.noFee': 'No fee',\n 'summary.free': 'Free',\n 'summary.protected': 'Protected purchase, encrypted data.',\n 'summary.shipping': 'Shipping',\n 'discount.placeholder': 'Discount code',\n 'discount.apply': 'Apply',\n 'discount.freeShipping': 'free shipping',\n 'discount.percentOff': '{{percent}}% off',\n 'discount.applied': '{{code}} applied: {{effect}}.',\n 'discount.appliedToast': 'Code applied!',\n 'discount.invalid': 'Invalid code.',\n 'discount.invalidToast': 'Invalid code',\n 'discount.checkCode': 'Check the code and try again.',\n 'discount.cannotValidate': 'We couldn’t check this code right now.',\n 'discount.cannotValidateToast': 'We couldn’t check the code',\n 'discount.tryLater': 'Try again in a moment.',\n 'legal.privacy': 'Privacy',\n 'legal.terms': 'Terms',\n 'legal.refunds': 'Returns',\n 'error.requiresAccount': 'This store needs an account to complete the purchase. Sign in or create one.',\n 'error.email': 'Enter a valid email.',\n 'error.name': 'Enter your full name.',\n 'error.phone': 'Enter a contact phone number.',\n 'error.documentInvalid': 'Invalid tax ID — check the numbers.',\n 'error.documentMissing': 'Enter the buyer’s tax ID.',\n 'error.taxIdInvalid': 'Invalid NIF/NIE — check the number.',\n 'error.address': 'Fill in or select the delivery address.',\n 'error.number': 'The street number is missing.',\n 'error.complement': 'Enter the apartment or unit.',\n 'error.state': 'Enter the two-letter state code (e.g. RJ).',\n 'error.postalInvalid': 'Check the postal code (e.g. {{example}}).',\n 'error.region': 'Select the {{label}}.',\n 'error.refusedZone': 'This store doesn’t deliver to this address. Try another.',\n 'error.unserved': 'We don’t deliver to this postal code yet. Try another address.',\n 'error.sessionMismatch': 'Your session got attached to another account. Reload the page and try again.',\n 'error.outOfStock': 'An item in your cart is out of stock. Review the cart and try again.',\n 'error.placeOrder': 'We couldn’t complete the order.',\n 'delivery.title': 'Estimate delivery',\n 'delivery.calculate': 'Estimate',\n 'delivery.postalLabel': 'Postal code',\n 'delivery.change': 'Change postal code',\n 'delivery.unserved': 'We don’t deliver to this postal code yet.',\n 'delivery.refused': 'This store doesn’t deliver to this address.',\n 'delivery.review': 'We deliver to this area, but we’ll confirm with you before shipping.',\n 'delivery.etaSoon': 'today or tomorrow',\n 'delivery.etaRange': '{{min}} to {{max}} business days',\n 'delivery.etaDays': '{{days}} business day(s)',\n 'delivery.flatRate': 'Shipping is calculated at checkout.',\n 'delivery.error.digits': 'Enter all 8 digits of the CEP.',\n 'delivery.error.postal': 'Check the postal code (e.g. {{example}}).',\n 'delivery.error.quote': 'We couldn’t calculate shipping right now. Try again.',\n 'delivery.error.notFound': 'Postal code not found. Check the numbers.',\n 'cart.title': 'Cart',\n 'cart.close': 'Close cart',\n 'cart.empty': 'Your cart is empty.',\n 'cart.remove': 'Remove {{name}}',\n 'cart.checkout': 'Checkout',\n 'cart.missingForFree': '{{amount}} away from free shipping',\n 'cart.wonFree': 'You got free shipping!',\n 'cart.minimumOrder': 'Minimum order for delivery: {{amount}}. {{missing}} to go.',\n 'delivery.eta': 'Delivery in ~{{duration}}',\n 'delivery.etaUpTo': 'Delivery within {{duration}}',\n 'delivery.paused': 'Delivery closed right now',\n 'cart.deliveryPaused': 'Delivery is closed right now. Come back later to check out.',\n 'country.deliverTo': 'Deliver to',\n 'country.change': 'Change country',\n 'country.label': 'Delivery country',\n}\n\nconst es: Partial<Messages> = {\n 'checkout.backToStore': 'Volver a la tienda',\n 'checkout.secure': 'Pago seguro',\n 'checkout.help': 'Ayuda',\n 'checkout.steps.label': 'Pasos del pago',\n 'checkout.steps.1': 'Datos',\n 'checkout.steps.2': 'Envío',\n 'checkout.steps.3': 'Pago',\n 'checkout.steps.4': 'Listo',\n 'checkout.contact.title': 'Datos de contacto',\n 'checkout.contact.signedInAs': 'Has iniciado sesión como {{email}}',\n 'checkout.contact.edit': 'Cambiar',\n 'checkout.contact.notYou': '¿No eres tú?',\n 'checkout.contact.signOut': 'Salir',\n 'checkout.contact.emailLocked': 'Es el correo de tu cuenta.',\n 'checkout.contact.haveAccount': '¿Ya tienes cuenta? Entrar',\n 'checkout.contact.email': 'Email',\n 'checkout.contact.name': 'Nombre completo',\n 'checkout.contact.phone': 'Teléfono',\n 'checkout.contact.phoneOptional': 'Teléfono (opcional)',\n 'checkout.contact.document': 'NIF/NIE',\n 'checkout.contact.documentOptional': 'NIF/NIE (opcional)',\n 'checkout.contact.requiresAccount': 'Esta tienda pide una cuenta para finalizar la compra.',\n 'checkout.contact.signInOrCreate': 'Entrar o crear cuenta',\n 'checkout.address.title': 'Dirección de envío',\n 'checkout.address.loadingSaved': 'Buscando tus direcciones guardadas',\n 'checkout.address.selected': 'Seleccionada',\n 'checkout.address.addNew': '+ Añadir una dirección nueva',\n 'checkout.address.enter': 'Indica la dirección de envío',\n 'checkout.address.enterHint': 'Usar otra dirección para este pedido',\n 'checkout.address.lookingUp': 'Buscando este código postal',\n 'checkout.address.notFound': 'Código postal no encontrado: rellena la dirección a mano.',\n 'checkout.address.filled': 'Hemos rellenado la dirección por ti.',\n 'checkout.address.regionFromPostal': 'Provincia rellenada a partir del código postal.',\n 'checkout.address.optional': '{{label}} (opcional)',\n 'checkout.address.choose': 'Selecciona',\n 'checkout.address.shipTo': 'Enviar a',\n 'checkout.confirming.title': 'Confirmando tu pedido',\n 'checkout.confirming.label': 'Creando tu pedido',\n 'checkout.confirming.keepOpen': 'No cierres esta página: estamos registrando tu pedido en la tienda.',\n 'checkout.payment.title': 'Pago',\n 'checkout.payment.label': 'Forma de pago',\n 'checkout.payment.cardOnline': 'Pagas en la página segura del proveedor y vuelves a la tienda',\n 'checkout.payment.placeOrder': 'Hacer pedido - {{total}}',\n 'checkout.payment.pendingNote': 'El pedido queda pendiente de pago hasta que la tienda lo confirme.',\n 'checkout.payment.unavailableCountry': 'Esta forma de pago no está disponible para {{country}}.',\n 'payment.pix.hint': 'Recibes la clave para pagar al confirmar el pedido',\n 'payment.credit_card.label': 'Tarjeta de crédito',\n 'payment.credit_card.hint': 'Datáfono en la entrega',\n 'payment.debit_card.label': 'Tarjeta de débito',\n 'payment.debit_card.hint': 'Datáfono en la entrega',\n 'payment.boleto.hint': 'Enviado por email tras la confirmación',\n 'payment.cash.label': 'Efectivo',\n 'payment.cash.hint': 'Pago en la entrega',\n 'payment.other.label': 'Acordar con la tienda',\n 'payment.other.hint': 'La tienda te contactará para acordar el pago',\n 'checkout.done.title': '¡Pago confirmado!',\n 'checkout.done.text': 'Tu pedido se ha creado y la tienda ya ha sido avisada.',\n 'checkout.done.viewOrder': 'Ver mi pedido',\n 'checkout.continueToDelivery': 'Continuar al envío',\n 'checkout.goToPayment': 'Ir al pago - {{total}}',\n 'checkout.backToContact': 'Volver a los datos',\n 'checkout.backToCart': 'Volver al carrito',\n 'summary.title': 'Resumen del pedido',\n 'summary.discount': 'Descuento',\n 'summary.delivery': 'Envío',\n 'summary.pickup': 'Recogida en tienda',\n 'summary.noFee': 'Sin coste',\n 'summary.free': 'Gratis',\n 'summary.protected': 'Compra protegida y datos cifrados.',\n 'summary.shipping': 'Envío',\n 'discount.placeholder': 'Código de descuento',\n 'discount.apply': 'Aplicar',\n 'discount.freeShipping': 'envío gratis',\n 'discount.percentOff': '{{percent}}% de descuento',\n 'discount.applied': '{{code}} aplicado: {{effect}}.',\n 'discount.appliedToast': '¡Código aplicado!',\n 'discount.invalid': 'Código no válido.',\n 'discount.invalidToast': 'Código no válido',\n 'discount.checkCode': 'Revisa el código e inténtalo de nuevo.',\n 'discount.cannotValidate': 'No hemos podido validar este código ahora.',\n 'discount.cannotValidateToast': 'No hemos podido validar el código',\n 'discount.tryLater': 'Inténtalo de nuevo en unos instantes.',\n 'legal.privacy': 'Privacidad',\n 'legal.terms': 'Términos',\n 'legal.refunds': 'Devoluciones',\n 'error.requiresAccount': 'Esta tienda pide una cuenta para finalizar la compra. Entra o crea la tuya.',\n 'error.email': 'Indica un email válido.',\n 'error.name': 'Indica tu nombre completo.',\n 'error.phone': 'Indica un teléfono de contacto.',\n 'error.documentInvalid': 'Documento no válido: revisa los números.',\n 'error.documentMissing': 'Indica el documento del comprador.',\n 'error.taxIdInvalid': 'NIF/NIE no válido: revisa el número.',\n 'error.address': 'Rellena o selecciona la dirección de envío.',\n 'error.number': 'Falta el número de la dirección.',\n 'error.complement': 'Indica el piso o la puerta.',\n 'error.state': 'Indica el estado con dos letras (ej.: RJ).',\n 'error.postalInvalid': 'Revisa el código postal (ej.: {{example}}).',\n 'error.region': 'Selecciona la {{label}}.',\n 'error.refusedZone': 'Esta tienda no envía a esta dirección. Prueba con otra.',\n 'error.unserved': 'Todavía no enviamos a este código postal. Prueba con otra dirección.',\n 'error.sessionMismatch': 'Tu sesión quedó vinculada a otra cuenta. Recarga la página e inténtalo de nuevo.',\n 'error.outOfStock': 'Un producto del carrito se ha agotado. Revisa el carrito e inténtalo de nuevo.',\n 'error.placeOrder': 'No se ha podido completar el pedido.',\n 'delivery.title': 'Calcular envío',\n 'delivery.calculate': 'Calcular',\n 'delivery.postalLabel': 'Código postal',\n 'delivery.change': 'Cambiar código postal',\n 'delivery.unserved': 'Todavía no enviamos a este código postal.',\n 'delivery.refused': 'Esta tienda no envía a esta dirección.',\n 'delivery.review': 'Enviamos a esta zona, pero lo confirmamos contigo antes de salir.',\n 'delivery.etaSoon': 'hoy o mañana',\n 'delivery.etaRange': 'de {{min}} a {{max}} días laborables',\n 'delivery.etaDays': '{{days}} día(s) laborable(s)',\n 'delivery.flatRate': 'El envío se calcula en el pago.',\n 'delivery.error.digits': 'Escribe los 8 dígitos del CEP.',\n 'delivery.error.postal': 'Revisa el código postal (ej.: {{example}}).',\n 'delivery.error.quote': 'No hemos podido calcular el envío ahora. Inténtalo de nuevo.',\n 'delivery.error.notFound': 'Código postal no encontrado. Revisa los números.',\n 'cart.title': 'Carrito',\n 'cart.close': 'Cerrar carrito',\n 'cart.empty': 'Tu carrito está vacío.',\n 'cart.remove': 'Quitar {{name}}',\n 'cart.checkout': 'Finalizar compra',\n 'cart.missingForFree': 'Te faltan {{amount}} para el envío gratis',\n 'cart.wonFree': '¡Tienes envío gratis!',\n 'cart.minimumOrder': 'Pedido mínimo para entrega: {{amount}}. Te faltan {{missing}}.',\n 'delivery.eta': 'Entrega en ~{{minutes}} min',\n 'country.deliverTo': 'Enviar a',\n 'country.change': 'Cambiar país',\n 'country.label': 'País de envío',\n}\n\nexport const MESSAGES: Record<StorefrontLanguage, Partial<Messages>> = { 'pt-BR': ptBR, en, es }\n\n/** 'pt', 'pt-PT', 'PT-br' → 'pt-BR'; 'en-GB' → 'en'; 'es-MX' → 'es'; anything else → null. */\nexport function normalizeLanguage(value?: string | null): StorefrontLanguage | null {\n const base = (value || '').toLowerCase().split(/[-_]/)[0]\n if (base === 'pt') return 'pt-BR'\n if (base === 'en') return 'en'\n if (base === 'es') return 'es'\n return null\n}\n\n/** Look a key up: the store's override, the language, then pt-BR. */\nexport function translate(\n language: StorefrontLanguage,\n key: MessageKey,\n vars?: Record<string, string | number>,\n overrides?: Partial<Record<StorefrontLanguage, Partial<Messages>>>,\n): string {\n let text = overrides?.[language]?.[key] ?? MESSAGES[language]?.[key] ?? overrides?.['pt-BR']?.[key] ?? ptBR[key]\n if (vars) for (const [name, value] of Object.entries(vars)) text = text.split(`{{${name}}}`).join(String(value))\n return text\n}\n","import React, { createContext, useContext, type ReactNode } from 'react'\nimport type { StorefrontAnalyticsConfig } from '../analytics/posthog'\nimport type { StorefrontExperiment } from '../experiments/assign'\nimport type { Experimental } from '../experiments/react'\nimport type { EntityDeclarationInput } from '@fayz-ai/core'\nimport type { ShopProvider } from '@fayz-ai/shop/provider'\nimport type { MockShopSeed } from '@fayz-ai/shop/mock'\nimport type { PaymentMethodKind, Product, ShopMarket, StoreSettings } from '@fayz-ai/shop/types'\nimport type { Promotion } from '@fayz-ai/shop/rules'\nimport type { StorefrontTheme } from '../lib/theme'\nimport type { HomeConfig, NavLink, FooterConfig } from '../blocks/sections'\nimport type { StorefrontPagesConfig } from '../blocks/page-blocks'\nimport { normalizeLanguage, type Messages, type StorefrontLanguage } from '../locales/messages'\n// Type-only: slots.tsx imports the config hook at runtime, so a value import\n// here would close the cycle.\nimport type { StorefrontSlots } from '../extend/slots'\nimport type { StorefrontAuthConfig } from '../data/auth'\nimport type { StorefrontComponents } from '../extend/component-contracts'\nimport type { StorefrontReviewsConfig } from '../components/product/ProductReviews'\nimport type { CatalogFacetConfig } from '../components/collection/FiltersPanel'\n\nexport type StorefrontRouteKind =\n | 'home'\n | 'catalog'\n | 'product'\n | 'checkout'\n | 'account'\n | 'order'\n | 'custom'\n\nexport type StorefrontRouteParams = Record<string, string>\n\nexport interface StorefrontRouteComponentProps {\n path: string\n params: StorefrontRouteParams\n config: ResolvedStorefrontConfig\n}\n\n/**\n * Quanta moldura o fluxo aguenta.\n *\n * default a vitrine inteira — nav de marketing, rodapé, tudo.\n * minimal marca + busca + carrinho, e o resto da navegação recolhida no\n * menu. É o cabeçalho de um app de pedido: o cardápio JÁ é a tarefa,\n * e cinco links concorrendo com ela no topo são cinco saídas.\n * focused sem moldura nenhuma. Para o checkout, onde qualquer link é fuga.\n *\n * `minimal` existe porque os dois extremos estavam errados para o cardápio:\n * `default` compete com o pedido e `focused` levaria junto o carrinho e a busca\n * — e esconder a navegação INTEIRA num fluxo é o oposto do que a regra de\n * navegação persistente pede. Recolher não é esconder.\n */\nexport type StorefrontRouteChrome = 'default' | 'minimal' | 'focused'\n/**\n * 'delivery' (0094) é 'checkout' com a ordem das perguntas invertida: a loja\n * responde \"estou aberta?\" e \"onde você está?\" ANTES do carrinho, e só pergunta\n * quem é o comprador no fim. Herda tudo que 'checkout' liga — carrinho, contas,\n * pagamento — e acrescenta a rota /menu, o seletor entrega × retirada e o\n * agendamento.\n *\n * Um modo e não uma flag solta porque as quatro coisas andam juntas: uma loja\n * com horário mas sem cardápio, ou com retirada mas sem horário, não é um\n * estado que alguém queira operar.\n */\nexport type StorefrontCommerceMode = 'checkout' | 'catalog' | 'enquiry' | 'delivery'\nexport type StorefrontImageLoadingMode = 'fade' | 'none'\n\nexport interface StorefrontImageLoadingConfig {\n mode?: StorefrontImageLoadingMode\n durationMs?: number\n easing?: string\n blur?: boolean\n /**\n * Where the browser gets a photo at the size it draws it.\n *\n * 'supabase' — images in the store's own storage are served as\n * delivery-time variants (`…/render/image/public/…?width=…`): resized once\n * per size, cached at the CDN, WebP for browsers that take it, and offered\n * as a `srcset` so a card never downloads the gallery's 4000 px original.\n * Requires the storage project to have image transformations enabled (a\n * plan feature); an image hotlinked from anywhere else is left untouched.\n * 'none' (default) — every image is loaded as it was stored.\n */\n transform?: 'supabase' | 'none'\n}\n\nexport interface StorefrontRouteDefinition {\n /**\n * Stable identifier for generated-code diffs, QA reports, and route ownership.\n */\n id: string\n /**\n * Hash route pattern. Supports the same params as matchPath, e.g. '/checkout'\n * or '/collections/:slug'. Custom routes are matched before SDK defaults.\n */\n path: string\n /**\n * Intent label for agents and manifests. It does not change matching behavior.\n */\n kind?: StorefrontRouteKind\n /**\n * Shell chrome for the route. `focused` hides storefront nav/footer/cart\n * around high-intent flows such as checkout.\n */\n chrome?: StorefrontRouteChrome\n /**\n * App-owned screen/workflow that can still use storefront/shop primitives.\n */\n component: React.ComponentType<StorefrontRouteComponentProps>\n}\n\nexport interface StorefrontDiscountConfig {\n code: string\n percent: number\n title?: string\n}\n\nexport interface StorefrontEnquiryConfig {\n label?: string\n successMessage?: string\n subjectPrefix?: string\n email?: string\n whatsappUrl?: string\n requirePhone?: boolean\n}\n\nexport interface StorefrontConfig {\n /** Store display name (header, page title) */\n name: string\n /** Optional logo node; defaults to the store name */\n logo?: React.ReactNode\n /** ISO 4217 — default 'BRL' */\n currency?: string\n /** Intl locale for money/date formatting — default 'pt-BR' */\n locale?: string\n /**\n * Language of the SDK's own screens (cart, checkout, delivery): 'pt-BR',\n * 'en' or 'es'. Default 'pt-BR'. Separate from `locale`, which formats money.\n * A host that knows the visitor's language per request passes it to\n * StorefrontConfigHost as `buyer.language` instead.\n */\n language?: string\n /** Per-store copy overrides, by language and message key. */\n messages?: Partial<Record<StorefrontLanguage, Partial<Messages>>>\n /**\n * ISO2 countries the store ships to. Default ['BR']. With more than one, the\n * buyer picks (or is detected into) one, and the address form, validation\n * and payment methods follow that country.\n */\n countries?: readonly string[]\n /** The country assumed before the buyer says otherwise. Default: countries[0]. */\n defaultCountry?: string\n /** Visual identity: colors, fonts, radius, header/card personality */\n theme?: StorefrontTheme\n /** Checkout-first default, catalog-only browsing, or product enquiry flow. */\n commerceMode?: StorefrontCommerceMode\n /** Promo message above the header (e.g. 'FRETE GRÁTIS ACIMA DE R$ 300') */\n announcement?: string\n /**\n * How pages are addressed when this store is served.\n *\n * `'hash'` (the default) needs no server configuration and is how every\n * shipped store works today. `'history'` gives each page a real URL, which is\n * what makes it indexable, shareable with its own link preview, and\n * prerenderable — and requires the host to serve the app shell for unknown\n * paths, or a deep link 404s before the app ever runs.\n */\n routing?: 'hash' | 'history'\n /**\n * Home page blueprint. When set, `/` renders it and the catalog moves to /catalog.\n *\n * Still fully supported — five of seven live stores write it. `pages.home` is\n * the same thing with room for the other routes; this stays as the short form.\n */\n home?: HomeConfig\n /**\n * Pages composed from blocks.\n *\n * `catalog` and `product` compose AROUND the native body block rather than\n * replacing it, so a store adds content to those pages without taking over\n * their maintenance. Omitting a page renders the SDK default — adopting this\n * field changes nothing until something is added.\n */\n pages?: StorefrontPagesConfig\n /**\n * Blocks grafted into named positions inside SDK pages.\n *\n * This is the rung between \"configure a section\" and \"rewrite the page\". If\n * you are about to reimplement an SDK page to add one thing to it, look for\n * the slot first — and if the position you need is missing, that is a gap in\n * this list rather than a reason to fork. `listSlots()` enumerates them.\n */\n slots?: StorefrontSlots\n /** Header nav links — defaults derived from home/catalog routing */\n nav?: NavLink[]\n /** Footer content (about text, contact, social) */\n footer?: FooterConfig\n /** Preferred backend descriptor for manifest/scaffold metadata. */\n backend?: { provider?: 'mock' | 'fayz-api' | 'fayz-shop' | 'custom'; url?: string }\n /** @deprecated Use backend/provider adapters. Storefront no longer creates Supabase clients. */\n supabaseUrl?: string\n /** @deprecated Use backend/provider adapters. Storefront no longer creates Supabase clients. */\n supabaseAnonKey?: string\n /** Explicit provider override (tests, custom backends) */\n provider?: ShopProvider\n /**\n * Product analytics. With `posthog` set, every page view, click, cart change\n * and checkout step is reported to that project, grouped under `storeId`.\n */\n analytics?: StorefrontAnalyticsConfig\n /** Per-store mock catalog (products/categories/discounts) for mock mode */\n catalog?: MockShopSeed\n /**\n * Custom entity declarations (spine M4), keyed by entity key. Registered\n * through defineEntity at runtime init, so one config field yields the\n * record schema, the storage descriptor, the generated RLS, the entity.*\n * loaders and the admin form.\n */\n entities?: Record<string, EntityDeclarationInput>\n /** Store-level discount codes available regardless of provider backend. */\n discounts?: StorefrontDiscountConfig[]\n /**\n * Rule-engine promotions (spine M6) — the serializable Promotion shape:\n * eligibility rules + application method, pure data. Rides in the Store\n * Document's `promotions` section; the mock provider evaluates them with\n * the reference evaluator, a live backend re-evaluates server-side. A\n * `{code, percent}` entry in `discounts` is the same thing in shorthand.\n */\n promotions?: Promotion[]\n /**\n * Institutional/legal page content (privacy, terms, returns). Plain text —\n * blank lines separate paragraphs. Unset pages render a placeholder so the\n * routes (and footer links) exist even before the store writes its policy.\n */\n legal?: { privacy?: string; terms?: string; returns?: string }\n /** Customer auth — same AuthAdapter contract as createSaasApp. Default: mock. */\n auth?: StorefrontAuthConfig\n /** Shipping pricing — default { flatRate: 0 } */\n shipping?: { flatRate?: number; freeAbove?: number }\n /**\n * Modo delivery (0094). Ignorado fora de `commerceMode: 'delivery'`.\n *\n * O que NÃO mora aqui, de propósito: horário de funcionamento, endereço de\n * retirada e prazo de preparo. Esses vêm do banco, porque uma lojista precisa\n * mudar o horário num feriado sem esperar um deploy — e um horário em arquivo\n * de configuração é exatamente isso.\n */\n delivery?: StorefrontDeliveryConfig\n /**\n * The A/B tests this store runs, by PostHog flag key. This is the source of\n * truth for who sees what: the edge buckets each visitor locally with\n * PostHog's hashing, before render, and any setting typed `Experimental<…>`,\n * any `experiment` block or any `useExperiment(key)` call reads it. The\n * PostHog Experiment on the same key reads the results. A key not declared,\n * or not `status: 'running'`, is always 'control'. See\n * docs/storefront/EXPERIMENTS.md.\n */\n experiments?: Record<string, StorefrontExperiment>\n /**\n * Payment behavior. v1 default 'mock' instantly marks orders paid with NO\n * real charge (demo). M4 sets 'pix-mercadopago' so orders stay pending until\n * a real payment webhook confirms settlement.\n */\n payments?: {\n /**\n * 'gateway' means a real PSP is connected: the checkout opens a charge and\n * the order waits for it. WHICH provider is deliberately not spelled here —\n * that lives in the store's connection row, server side. A storefront that\n * named the acquirer would need a redeploy to change acquirer.\n */\n mode?: 'mock' | 'pix-mercadopago' | 'gateway'\n /**\n * Which methods the checkout offers. Declaring them is what lets the order\n * record how the buyer intends to pay instead of assuming 'credit_card',\n * which is what it did while the card form was a simulation.\n */\n methods?: readonly PaymentMethodKind[]\n /**\n * Published payment terms, shown on the card and the PDP. These are the two\n * lines every Brazilian storefront carries and the SDK had no model for:\n * the Pix discount and the interest-free instalment.\n *\n * Display only — they describe what the merchant advertises, not a charge\n * the checkout computes. A product may override the Pix price per SKU via\n * `metadata.pixPrice`.\n */\n terms?: {\n /** e.g. 5 → \"5% de desconto no Pix\". */\n pixDiscountPercent?: number\n /** Longest interest-free plan offered. */\n maxInstallments?: number\n /** Don't split below this per-instalment value. Default 10. */\n minInstallmentValue?: number\n }\n }\n /**\n * The PDP specification table renders scalar `product.metadata` alongside\n * SKU/category/weight. Stores also keep bookkeeping in metadata; `exclude`\n * hides those keys and `labels` names the rest, so a store doesn't have to\n * fork ProductSpecs to stop showing an internal field.\n */\n productSpecs?: { exclude?: readonly string[]; labels?: Readonly<Record<string, string>> }\n /** Product reviews shown on the PDP. See ./components/product/ProductReviews. */\n reviews?: StorefrontReviewsConfig\n /**\n * Extra catalog refinements over `product.metadata`, rendered in the filters\n * panel and reflected in `?<key>=<value>`. This is how a store adds its own\n * discovery axis — colour, purpose, brand — without forking FiltersPanel.\n */\n catalogFacets?: readonly CatalogFacetConfig[]\n /** Product enquiry behavior for catalog/enquiry stores. */\n enquiry?: StorefrontEnquiryConfig\n /** Feature toggles — defaults depend on commerceMode. */\n features?: { discounts?: boolean; accounts?: boolean; cart?: boolean; checkout?: boolean }\n /** Global storefront image reveal behavior. Default is a soft fade. */\n imageLoading?: StorefrontImageLoadingConfig\n /** Header search behaviour. Omit for the inline live-filter. */\n search?: StorefrontSearchConfig\n /**\n * The merchant's own commercial policy, read from the store's settings row at\n * boot (see ./store-policy). NOT authored here: an app declares its defaults\n * through the fields above, and this arrives from the database to override the\n * ones the merchant actually decided.\n *\n * Present so components can read the decisions that have no equivalent\n * config field — whether an account is required, which optional checkout\n * fields to show. The ones that DO have a field (currency, payment methods)\n * are folded into those fields instead, so nothing has to read both.\n */\n policy?: StoreSettings\n /** Code-level component replacements. Kept out of serialized manifests. */\n components?: StorefrontComponents\n /** Code-level route overrides/custom routes. Kept out of serialized manifests. */\n routes?: readonly StorefrontRouteDefinition[]\n}\n\n/** See `StorefrontDeliveryConfig.coverSize`. */\nexport type StorefrontCoverSize = 'full' | 'compact'\n\n/** Entrega ou retirada, do ponto de vista da vitrine. */\nexport type FulfillmentMode = 'delivery' | 'pickup'\n\nexport interface StorefrontDeliveryConfig {\n /** Onde o cardápio mora. Default '/menu'. */\n menuPath?: string\n /**\n * A capa da loja — a foto que ocupa o topo do cardápio.\n *\n * É a única imagem do modo que NÃO vem do catálogo: capa é identidade da\n * loja, não de um produto. Sem ela o cabeçalho continua existindo, só que\n * sobre a cor da marca — o cardápio nunca depende de haver foto.\n */\n coverImage?: string\n /** O logo, no quadrado sobre a capa. Cai para a inicial do nome. */\n logoImage?: string\n /**\n * How much of the first screen the cover takes. 'full' (default) is the\n * cover as a store styles it; 'compact' shrinks it to a band so the first\n * dishes — photo, price, add button — are visible without scrolling on a\n * phone. The cover carries `data-cover-size`, so a store's own cover CSS can\n * follow it. Bindable to an experiment:\n * `{ experiment: 'menu-cover-compact', variants: { control: 'full', compact: 'compact' } }`.\n */\n coverSize?: Experimental<StorefrontCoverSize>\n /** \"Rio de Janeiro, RJ\" — a linha sob o nome. */\n locality?: string\n /**\n * Os slugs que sobem para \"Destaques\", NA ORDEM em que a lojista os quer.\n *\n * Curadoria é decisão de quem vende, e não há dado na vitrine que a\n * substitua: \"mais pedido\" precisaria de contagem de pedidos por produto,\n * que não existe aqui. Sem esta lista o cardápio cai para o que está em\n * promoção — um fato cadastrado, não um palpite — e, sem promoções, a seção\n * simplesmente não aparece.\n */\n highlightSlugs?: readonly string[]\n /** Modos oferecidos, NA ORDEM em que o seletor os mostra. Default ['delivery']. */\n fulfillmentModes?: readonly FulfillmentMode[]\n /** Oferecer \"Agendar\". Default false — e a loja ainda precisa concordar. */\n scheduling?: boolean\n /**\n * O balcão, para os pedidos de retirada.\n *\n * ESTÁ AQUI POR UMA LIMITAÇÃO CONHECIDA, e não porque este seja o lugar certo.\n * O lugar certo é `plg_shop_settings.pickup_address` (0094), para a lojista\n * mudar o endereço sem deploy — mas a vitrine lê configuração por\n * `shop_store_settings()`, uma RPC que devolve um SUBCONJUNTO fixo de colunas\n * e não inclui esta. Estender a RPC é uma migration, e a 0094 já está fechada.\n *\n * Então: a vitrine PREFERE o que vier do banco e cai para cá quando não vier.\n * No dia em que a RPC ganhar a coluna, esta chave para de ser lida sozinha,\n * sem tocar em app nenhum.\n */\n pickupAddress?: {\n postalCode: string\n street: string\n number?: string\n complement?: string\n district?: string\n city: string\n state: string\n }\n}\n\nexport interface ResolvedStorefrontConfig extends StorefrontConfig {\n currency: string\n locale: string\n language: StorefrontLanguage\n countries: readonly string[]\n defaultCountry: string\n /** The host's per-request country hint (e.g. the CDN's geo header), if any. */\n countryHint?: string\n /** The market the buyer is in (0116), when the store has markets. Its\n * currency, locale and shipping are already applied to this config. */\n market?: ShopMarket\n shipping: { flatRate: number; freeAbove?: number }\n payments: {\n mode: NonNullable<NonNullable<StorefrontConfig['payments']>['mode']>\n methods: readonly PaymentMethodKind[]\n terms?: NonNullable<StorefrontConfig['payments']>['terms']\n }\n commerceMode: StorefrontCommerceMode\n /** Presente somente no modo delivery — a rota /menu testa por este objeto. */\n delivery?: {\n menuPath: string\n coverImage?: string\n logoImage?: string\n coverSize?: StorefrontDeliveryConfig['coverSize']\n locality?: string\n highlightSlugs?: readonly string[]\n fulfillmentModes: readonly FulfillmentMode[]\n scheduling: boolean\n pickupAddress?: StorefrontDeliveryConfig['pickupAddress']\n /** From the store's Delivery settings (shop 0130), when it set them. */\n etaMinutes?: number\n /** The minimum order on the items' subtotal; the server refuses below it. */\n minOrderTotal?: number\n /** The house switched its delivery off (shop 0131): no order until it is back. */\n paused?: boolean\n }\n enquiry: Required<Pick<StorefrontEnquiryConfig, 'label' | 'successMessage' | 'subjectPrefix'>> &\n Omit<StorefrontEnquiryConfig, 'label' | 'successMessage' | 'subjectPrefix'>\n features: { discounts: boolean; accounts: boolean; cart: boolean; checkout: boolean }\n imageLoading: Required<StorefrontImageLoadingConfig>\n /** Where the full product list lives ('/' without a home page, '/catalog' with one, the menu in delivery mode) */\n catalogPath: string\n nav: NavLink[]\n /** `pages` with the legacy `home` short form folded in — always read this one. */\n pages: StorefrontPagesConfig\n search: Required<Omit<StorefrontSearchConfig, 'renderSuggestion'>> &\n Pick<StorefrontSearchConfig, 'renderSuggestion'>\n}\n\n/**\n * Header search. Defaults reproduce the inline live-filter the storefront has\n * always had, so turning this on is opt-in; every label and limit is a knob\n * because \"what a search feels like\" is a per-store decision, not the SDK's.\n */\nexport interface StorefrontSearchConfig {\n /**\n * 'inline' filters the catalogue as you type (the original behaviour).\n * 'overlay' dims the page and shows suggestions under the field, with a\n * link through to the full result page.\n */\n mode?: 'inline' | 'overlay'\n placeholder?: string\n /** Where \"see all results\" lands, carrying `?q=`. */\n resultsPath?: string\n /** Suggestions shown under the field before the shopper commits. */\n suggestionsLimit?: number\n /** Characters before anything is queried — 1 matches everything, which is noise. */\n minChars?: number\n ctaLabel?: string\n emptyLabel?: string\n /** Full control of a suggestion row when the default card is wrong for the store. */\n renderSuggestion?: (product: Product) => ReactNode\n}\n\n/** Upper-cased, de-duplicated, never empty; the default is always one of them. */\nfunction resolveCountries(config: StorefrontConfig): { countries: string[]; defaultCountry: string } {\n const countries = [...new Set((config.countries ?? []).map((c) => c.trim().toUpperCase()).filter(Boolean))]\n if (countries.length === 0) countries.push('BR')\n const wanted = config.defaultCountry?.trim().toUpperCase()\n return { countries, defaultCountry: wanted && countries.includes(wanted) ? wanted : countries[0]! }\n}\n\nexport function resolveConfig(config: StorefrontConfig): ResolvedStorefrontConfig {\n // `home` and `pages.home` are the same page written two ways. Collapse them\n // here so nothing downstream has to check both, and so the legacy short form\n // keeps deciding where the catalog lives exactly as it did before.\n const homePage = config.pages?.home ?? (config.home ? { blocks: config.home.sections } : undefined)\n const commerceMode = config.commerceMode ?? 'checkout'\n // In a delivery store the menu IS the catalogue: «Continuar comprando» and\n // «Voltar ao catálogo» on a product page sent buyers to the old e-commerce\n // shelf at /catalog instead of the menu they order from.\n const catalogPath = commerceMode === 'delivery'\n ? (config.delivery?.menuPath ?? '/menu')\n : homePage ? '/catalog' : '/'\n // 'delivery' compra tudo que 'checkout' liga. Escrever `=== 'checkout'` em\n // cada feature abaixo teria desligado carrinho e conta no modo novo — o modo\n // que mais precisa dos dois.\n const checkoutEnabled = commerceMode === 'checkout' || commerceMode === 'delivery'\n return {\n ...config,\n pages: { ...config.pages, ...(homePage ? { home: homePage } : {}) },\n currency: config.currency ?? 'BRL',\n locale: config.locale ?? 'pt-BR',\n language: normalizeLanguage(config.language) ?? 'pt-BR',\n ...resolveCountries(config),\n shipping: { flatRate: config.shipping?.flatRate ?? 0, freeAbove: config.shipping?.freeAbove },\n payments: {\n mode: config.payments?.mode ?? 'mock',\n methods: config.payments?.methods?.length ? config.payments.methods : ['pix', 'credit_card', 'cash'],\n // Rebuilding `payments` key by key silently dropped `terms`, so the Pix\n // price and the instalment line never reached a component even when the\n // store had configured them.\n terms: config.payments?.terms,\n },\n commerceMode,\n // Só existe no modo delivery. Fora dele o objeto inteiro é undefined, e é\n // isso que a rota /menu consulta para decidir se existe.\n delivery: commerceMode === 'delivery'\n ? {\n menuPath: config.delivery?.menuPath ?? '/menu',\n coverImage: config.delivery?.coverImage,\n logoImage: config.delivery?.logoImage,\n coverSize: config.delivery?.coverSize,\n locality: config.delivery?.locality,\n highlightSlugs: config.delivery?.highlightSlugs,\n // A ORDEM é a do seletor na tela. Um Set aqui perderia isso.\n fulfillmentModes: config.delivery?.fulfillmentModes?.length\n ? config.delivery.fulfillmentModes\n : (['delivery'] as const satisfies readonly FulfillmentMode[]).slice(),\n // Agendamento é opt-in duas vezes: aqui e na loja (0094 devolve zero\n // slots quando scheduling_enabled é falso). A tela só oferece quando\n // as duas concordam.\n scheduling: config.delivery?.scheduling ?? false,\n pickupAddress: config.delivery?.pickupAddress,\n }\n : undefined,\n enquiry: {\n label: config.enquiry?.label ?? 'Contact me',\n successMessage: config.enquiry?.successMessage ?? 'Thanks. We received your enquiry.',\n subjectPrefix: config.enquiry?.subjectPrefix ?? 'Product enquiry',\n email: config.enquiry?.email,\n whatsappUrl: config.enquiry?.whatsappUrl,\n requirePhone: config.enquiry?.requirePhone,\n },\n features: {\n // Auto-enable the coupon UI when the store actually ships discount codes\n // (config.discounts, a seeded catalog, or a rule-engine promotion with a\n // code — M6), unless explicitly overridden — otherwise a store can\n // advertise a coupon with no field to enter it, which is exactly the\n // figurinhas pilot failure this milestone exists to end.\n discounts:\n config.features?.discounts ??\n Boolean(\n config.discounts?.length ||\n config.catalog?.discounts?.length ||\n config.promotions?.some((p) => p.code) ||\n config.catalog?.promotions?.some((p) => p.code),\n ),\n accounts: config.features?.accounts ?? checkoutEnabled,\n cart: config.features?.cart ?? checkoutEnabled,\n checkout: config.features?.checkout ?? checkoutEnabled,\n },\n imageLoading: {\n mode: config.imageLoading?.mode ?? 'fade',\n durationMs: config.imageLoading?.durationMs ?? 420,\n easing: config.imageLoading?.easing ?? 'cubic-bezier(0.22, 1, 0.36, 1)',\n blur: config.imageLoading?.blur ?? true,\n transform: config.imageLoading?.transform ?? 'none',\n },\n catalogPath,\n search: {\n mode: config.search?.mode ?? 'inline',\n placeholder: config.search?.placeholder ?? 'Buscar produtos...',\n resultsPath: config.search?.resultsPath ?? '/search',\n suggestionsLimit: config.search?.suggestionsLimit ?? 4,\n minChars: config.search?.minChars ?? 2,\n ctaLabel: config.search?.ctaLabel ?? 'Ver todos resultados',\n emptyLabel: config.search?.emptyLabel ?? 'Nada encontrado para',\n renderSuggestion: config.search?.renderSuggestion,\n },\n nav:\n config.nav ??\n (homePage\n ? [\n { label: 'Início', to: '/' },\n { label: 'Loja', to: '/catalog' },\n ]\n : [{ label: 'Loja', to: '/' }]),\n }\n}\n\nconst StorefrontConfigContext = createContext<ResolvedStorefrontConfig | null>(null)\n\nexport const StorefrontConfigProvider = StorefrontConfigContext.Provider\n\nexport function useStorefrontConfig(): ResolvedStorefrontConfig {\n const ctx = useContext(StorefrontConfigContext)\n if (!ctx) throw new Error('useStorefrontConfig must be used inside createStorefrontApp')\n return ctx\n}\n\nexport function useStorefrontConfigOptional(): ResolvedStorefrontConfig | null {\n return useContext(StorefrontConfigContext)\n}\n\nexport function getStorefrontComponents(config: ResolvedStorefrontConfig): StorefrontComponents {\n return config.components ?? {}\n}\n","import React, { createContext, useContext, useEffect, useRef, useSyncExternalStore } from 'react'\nimport { defaultRouterAdapter, staticRouterAdapter, type RouterAdapter } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Storefront routing.\n//\n// The storefront owns a handful of flat routes, so it resolves them itself\n// rather than depending on a router package — that dependency is what created\n// the duplicate-singleton hazards under source-alias dev. What it does NOT own\n// is the *addressing scheme*: whether a page lives at `#/product/x` or at\n// `/product/x`, and who controls history.\n//\n// That is injected as a RouterAdapter, which is what lets the same components\n// render under a hash SPA, a real-URL SPA, and a static render. It matters\n// beyond convenience: a fragment is never sent to the server, so a\n// hash-addressed page has no URL of its own to index, share or prerender —\n// `renderStore` can produce perfect HTML for a page that no crawler can reach\n// as a distinct address.\n//\n// Hash remains the default, so an app that never mentions routing behaves\n// exactly as it does today.\n// ---------------------------------------------------------------------------\n\nconst RouterAdapterContext = createContext<RouterAdapter | null>(null)\n\nexport const StorefrontRouterProvider = RouterAdapterContext.Provider\n\n/**\n * `navigateTo` is a module function called from event handlers. Handlers only\n * run in a browser, after the provider has mounted, so a module-level reference\n * to the active adapter is safe here in a way it would not be during render.\n * Render paths use `useNavigate()` / `useRouterAdapter()` so a static render\n * reads the adapter for the path it is rendering, not this process-wide one.\n */\nlet _activeAdapter: RouterAdapter | null = null\nlet _fallback: RouterAdapter | null = null\n\n/**\n * One shared fallback instance, not one per component: an adapter owns its\n * subscriber list, so N instances would mean N event bindings and — for history\n * addressing — navigations that only notify their own subscribers. Constructing\n * one touches no browser API; only its methods do.\n */\nfunction fallbackAdapter(): RouterAdapter {\n if (!_fallback) _fallback = defaultRouterAdapter('hash')\n return _fallback\n}\n\nexport function useRouterAdapter(): RouterAdapter {\n const injected = useContext(RouterAdapterContext)\n const adapter = injected ?? fallbackAdapter()\n useEffect(() => {\n // Only an INJECTED adapter becomes the active one. The fallback is what a\n // read outside any provider gets — and `StorefrontShell` itself makes such\n // a read, for the ambient adapter, before installing the router it was\n // given. Being the parent, its effect runs after every child's; if it\n // wrote the fallback here, a store served by a host router (TanStack,\n // history) would have every Link go through the host and every\n // `navigateTo` from an event handler go through hash addressing. That is\n // exactly what a header search did on the first SSR store: /#/catalog.\n if (injected) _activeAdapter = injected\n }, [injected])\n return adapter\n}\n\n/** The current in-app path, re-rendering on every navigation. */\nexport function useRoutePath(): string {\n const adapter = useRouterAdapter()\n return useSyncExternalStore(\n (onChange) => adapter.onPathChange(onChange),\n () => adapter.getCurrentPath() || '/',\n () => adapter.getCurrentPath() || '/',\n )\n}\n\n/** Scroll to top on route change. Separate from path tracking so a host that\n * manages its own scroll restoration can simply not call it. */\nexport function useScrollToTopOnNavigate(path: string): void {\n const mounted = useRef(false)\n useEffect(() => {\n // Not on the first pass. That one is not a navigation — it is the store\n // arriving, either as the server's HTML being hydrated or as a reload the\n // browser has already positioned. Scrolling there takes the page away from\n // a shopper who started reading during hydration, and on a host with its\n // own scroll restoration it races that host's restore.\n if (!mounted.current) {\n mounted.current = true\n return\n }\n if (typeof window !== 'undefined') window.scrollTo(0, 0)\n }, [path])\n}\n\nexport function useNavigate(): (to: string) => void {\n const adapter = useRouterAdapter()\n return adapter.navigate.bind(adapter)\n}\n\n/** @deprecated Use `useRoutePath()`. Kept so existing imports keep compiling. */\nexport const useHashPath = useRoutePath\n\n/** Imperative navigation from an event handler. See `_activeAdapter` above. */\nexport function navigateTo(to: string): void {\n ;(_activeAdapter ?? fallbackAdapter()).navigate(to)\n}\n\n/**\n * The adapter a shell should install for a given render.\n *\n * A `path` override means a static render (`renderStore`, the preview server, a\n * node test): there is no history to own, but anchors must still carry real,\n * crawlable hrefs — which is the whole point of rendering headlessly.\n */\nexport function shellRouterAdapter(pathOverride: string | undefined, live: RouterAdapter): RouterAdapter {\n if (pathOverride == null) return live\n // Inherit the ambient scheme's href writer: a store served as a hash SPA must\n // still emit `#/…` links when rendered headlessly, or `renderStore` would\n // describe a page whose links do not exist. Pass an explicit `router` to the\n // shell to render a store served at real URLs.\n return staticRouterAdapter(pathOverride, { href: (to) => live.href(to) })\n}\n\n/** Match '/product/:slug' against '/product/leather-backpack' → { slug: 'leather-backpack' } */\nexport function matchPath(pattern: string, path: string): Record<string, string> | null {\n const cleanPath = (path.split('?')[0] ?? '').replace(/\\/+$/, '') || '/'\n const patternParts = pattern.split('/').filter(Boolean)\n const pathParts = cleanPath.split('/').filter(Boolean)\n if (patternParts.length !== pathParts.length) return null\n const params: Record<string, string> = {}\n for (let i = 0; i < patternParts.length; i++) {\n const pat = patternParts[i]!\n const part = pathParts[i]!\n if (pat.startsWith(':')) params[pat.slice(1)] = decodeURIComponent(part)\n else if (pat !== part) return null\n }\n return params\n}\n\nexport interface LinkProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {\n to: string\n}\n\n/**\n * A real anchor, always — middle-click, cmd-click, \"copy link address\" and\n * Playwright all keep working, and a crawler sees a real href.\n *\n * Under hash addressing the browser handles the fragment itself, so the click\n * is left alone. Under real-URL addressing a plain left-click must be\n * intercepted or the browser would do a full document load; modified clicks and\n * explicit targets are still handed to the browser.\n */\nexport function Link({ to, children, onClick, target, ...rest }: LinkProps) {\n const adapter = useRouterAdapter()\n\n const handleClick = (event: React.MouseEvent<HTMLAnchorElement>) => {\n onClick?.(event)\n if (!adapter.interceptsLinkClicks) return\n if (event.defaultPrevented) return\n if (target && target !== '_self') return\n if (event.button !== 0) return\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return\n event.preventDefault()\n adapter.navigate(to)\n }\n\n return React.createElement(\n 'a',\n { href: adapter.href(to), onClick: handleClick, target, ...rest },\n children,\n )\n}\n","import type { BlockNode } from '@fayz-ai/core'\nimport type { PageDataEntry, PageDataNeed } from '../blocks/page-data'\n\n// Effects do not run under `renderToStaticMarkup`, so a headless render would\n// produce loading states with no title. Instead of reimplementing routing on the\n// server — a second mechanism to keep in sync — components REPORT to the pass\n// rendering them, and the renderer re-renders with the answers seeded.\n//\n// Module-scoped rather than a React context because `renderToStaticMarkup` is\n// synchronous: there is exactly one pass in flight, and a context would force\n// every reporting call site to be a hook (`PageDataScope`'s useState initialiser\n// cannot be one). Null in every browser render.\n\n/**\n * What a route declared for the document head during a static render.\n *\n * Title and description are the client-rendered baseline. The rest is what a\n * page needs to be worth anything once it HAS its own URL: a canonical so the\n * engine knows which address is authoritative, an image and type so a share in\n * a messaging app is not a grey rectangle, and JSON-LD so a product is eligible\n * for a rich result instead of a plain blue link.\n */\nexport interface StaticHeadInput {\n title?: string\n description?: string | null\n /** Absolute URL. A relative canonical is ignored by search engines. */\n canonical?: string\n /** Absolute URL of the image a share should show. */\n image?: string\n /** OpenGraph type — 'website', 'article', 'product'. */\n type?: string\n /** schema.org objects, emitted as <script type=\"application/ld+json\">. */\n jsonLd?: Array<Record<string, unknown>>\n}\n\nexport interface StaticRenderPass {\n /** Called once per scope, so a page plus its slots report the whole rendered\n * composition — including forced-layout repairs (I7). */\n tree(nodes: readonly BlockNode[]): void\n needs(needs: readonly PageDataNeed[]): void\n head(input: StaticHeadInput): void\n /** Resolved by an earlier pass, keyed by `dataNeedKey`. A key present here is\n * served instead of being fetched. */\n entries: Readonly<Record<string, PageDataEntry>>\n /**\n * Absolute origin the rendered page will be served from, when the caller\n * knows it. Pages need it to declare a canonical or an og:image, and a static\n * render has no `window.location` to infer one from — so it travels with the\n * pass rather than being guessed per page.\n */\n origin?: string\n}\n\nlet active: StaticRenderPass | null = null\n\n/** The pass currently rendering, or null — which is every browser render. */\nexport function currentStaticRenderPass(): StaticRenderPass | null {\n return active\n}\n\n/** Run one synchronous render with `pass` installed. Nesting restores the\n * previous pass, so a renderer inside a renderer cannot strand the global. */\nexport function withStaticRenderPass<T>(pass: StaticRenderPass, render: () => T): T {\n const previous = active\n active = pass\n try {\n return render()\n } finally {\n active = previous\n }\n}\n"]}