@fayz-ai/storefront 0.18.0 → 0.19.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 (68) hide show
  1. package/dist/app/createStorefrontApp.d.ts.map +1 -1
  2. package/dist/app/prerender.d.ts.map +1 -1
  3. package/dist/app/serving.d.ts +2 -0
  4. package/dist/app/serving.d.ts.map +1 -1
  5. package/dist/blocks/page-data.d.ts.map +1 -1
  6. package/dist/{chunk-ORKXSAZ6.js → chunk-77V5ZAF5.js} +1845 -264
  7. package/dist/chunk-77V5ZAF5.js.map +1 -0
  8. package/dist/components/cart/CartDrawer.d.ts.map +1 -1
  9. package/dist/components/checkout/CheckoutSteps.d.ts +10 -1
  10. package/dist/components/checkout/CheckoutSteps.d.ts.map +1 -1
  11. package/dist/components/delivery/AddressSheet.d.ts +22 -0
  12. package/dist/components/delivery/AddressSheet.d.ts.map +1 -0
  13. package/dist/components/delivery/AddressStrip.d.ts +18 -0
  14. package/dist/components/delivery/AddressStrip.d.ts.map +1 -0
  15. package/dist/components/delivery/ItemSheet.d.ts +42 -0
  16. package/dist/components/delivery/ItemSheet.d.ts.map +1 -0
  17. package/dist/components/delivery/MenuItemRow.d.ts +29 -0
  18. package/dist/components/delivery/MenuItemRow.d.ts.map +1 -0
  19. package/dist/components/delivery/MenuToolbar.d.ts +29 -0
  20. package/dist/components/delivery/MenuToolbar.d.ts.map +1 -0
  21. package/dist/components/delivery/ScheduleSheet.d.ts +14 -0
  22. package/dist/components/delivery/ScheduleSheet.d.ts.map +1 -0
  23. package/dist/components/delivery/ServiceStatus.d.ts +15 -0
  24. package/dist/components/delivery/ServiceStatus.d.ts.map +1 -0
  25. package/dist/components/delivery/StoreCover.d.ts +22 -0
  26. package/dist/components/delivery/StoreCover.d.ts.map +1 -0
  27. package/dist/components/delivery/store-time.d.ts +15 -0
  28. package/dist/components/delivery/store-time.d.ts.map +1 -0
  29. package/dist/components/layout/StorefrontHeader.d.ts +4 -1
  30. package/dist/components/layout/StorefrontHeader.d.ts.map +1 -1
  31. package/dist/components/layout/Toaster.d.ts.map +1 -1
  32. package/dist/components/marketing/FormBlock.d.ts.map +1 -1
  33. package/dist/components/product/ProductEnquiryForm.d.ts.map +1 -1
  34. package/dist/document/config.d.ts +101 -2
  35. package/dist/document/config.d.ts.map +1 -1
  36. package/dist/document/round-trip.d.ts.map +1 -1
  37. package/dist/document/sections.d.ts +2 -2
  38. package/dist/document/sections.d.ts.map +1 -1
  39. package/dist/document/upgrade.d.ts.map +1 -1
  40. package/dist/extend/component-contracts.d.ts +7 -1
  41. package/dist/extend/component-contracts.d.ts.map +1 -1
  42. package/dist/hooks/use-address.d.ts.map +1 -1
  43. package/dist/hooks/use-checkout.d.ts.map +1 -1
  44. package/dist/hooks/use-order.d.ts.map +1 -1
  45. package/dist/hooks/use-products.d.ts.map +1 -1
  46. package/dist/index.d.ts +11 -0
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +11 -17
  49. package/dist/index.js.map +1 -1
  50. package/dist/lib/testids.d.ts +36 -0
  51. package/dist/lib/testids.d.ts.map +1 -1
  52. package/dist/render.js +3 -3
  53. package/dist/render.js.map +1 -1
  54. package/dist/stores/cart.store.d.ts +22 -1
  55. package/dist/stores/cart.store.d.ts.map +1 -1
  56. package/dist/stores/delivery.store.d.ts +54 -1
  57. package/dist/stores/delivery.store.d.ts.map +1 -1
  58. package/dist/stores/service.store.d.ts +35 -0
  59. package/dist/stores/service.store.d.ts.map +1 -0
  60. package/dist/stores/toast.store.d.ts +14 -0
  61. package/dist/stores/toast.store.d.ts.map +1 -1
  62. package/dist/views/CheckoutPage.d.ts.map +1 -1
  63. package/dist/views/MenuPage.d.ts +23 -0
  64. package/dist/views/MenuPage.d.ts.map +1 -0
  65. package/dist/workflows/checkout.d.ts +15 -2
  66. package/dist/workflows/checkout.d.ts.map +1 -1
  67. package/package.json +6 -6
  68. package/dist/chunk-ORKXSAZ6.js.map +0 -1
@@ -102,6 +102,42 @@ export declare const TID: {
102
102
  readonly cartTotal: "cart-total";
103
103
  readonly goCheckout: "go-checkout";
104
104
  readonly cartEmpty: "cart-empty";
105
+ readonly menuPage: "menu-page";
106
+ readonly menuSection: (slug: string) => string;
107
+ readonly menuItem: (slug: string) => string;
108
+ readonly menuQuickAdd: (slug: string) => string;
109
+ readonly devPlaceOrderWithoutCharge: "dev-place-order-without-charge";
110
+ readonly menuCartBar: "menu-cart-bar";
111
+ readonly menuItemSoldOut: "menu-sold-out";
112
+ readonly itemSheet: "item-sheet";
113
+ readonly itemSheetNotes: "item-sheet-notes";
114
+ readonly itemSheetNotesCount: "item-sheet-notes-count";
115
+ readonly itemSheetQty: "item-sheet-qty";
116
+ readonly itemSheetAdd: "item-sheet-add";
117
+ readonly serviceStatus: "service-status";
118
+ readonly serviceHoursModal: "service-hours-modal";
119
+ readonly serviceClosedGate: "service-closed-gate";
120
+ readonly fulfillmentMode: (mode: string) => string;
121
+ readonly scheduleSheet: "schedule-sheet";
122
+ readonly scheduleSlot: (iso: string) => string;
123
+ readonly storeCover: "store-cover";
124
+ readonly menuSearch: "menu-search";
125
+ readonly menuCategoryNav: "menu-category-nav";
126
+ readonly menuCategoryLink: (slug: string) => string;
127
+ readonly menuHighlights: "menu-highlights";
128
+ readonly menuItemBadge: (slug: string) => string;
129
+ readonly deliveryTabBar: "delivery-tab-bar";
130
+ readonly deliveryTab: (key: string) => string;
131
+ readonly addressStrip: "address-strip";
132
+ readonly addressSheet: "address-sheet";
133
+ readonly addressCep: "address-cep";
134
+ readonly addressNumber: "address-number";
135
+ readonly addressComplement: "address-complement";
136
+ readonly addressReference: "address-reference";
137
+ readonly addressSave: "address-save";
138
+ readonly addressAddNew: "address-add-new";
139
+ readonly savedAddress: (id: string) => string;
140
+ readonly itemSheetGroup: (label: string) => string;
105
141
  readonly deliveryEstimator: "delivery-estimator";
106
142
  readonly deliveryCepInput: "delivery-cep-input";
107
143
  readonly deliveryCepSubmit: "delivery-cep-submit";
@@ -1 +1 @@
1
- {"version":3,"file":"testids.d.ts","sourceRoot":"","sources":["../../src/lib/testids.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,GAAG;;;;;;;;;;;;;8BAcG,MAAM;iCACH,MAAM;;;;;;;;;;;;;;;;;;;;;;;;kCAyBL,MAAM;;;;;;;;;;;;;;;;;;oCAqBJ,MAAM;;;;;;;;;;sCAWJ,MAAM;sCACN,MAAM,SAAS,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BA4D5B,MAAM;;;;;;;;;;;;;;;uCAiBE,MAAM;;;;;;;;;;;;;;;;;;;;CAqBxB,CAAA"}
1
+ {"version":3,"file":"testids.d.ts","sourceRoot":"","sources":["../../src/lib/testids.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,GAAG;;;;;;;;;;;;;8BAcG,MAAM;iCACH,MAAM;;;;;;;;;;;;;;;;;;;;;;;;kCAyBL,MAAM;;;;;;;;;;;;;;;;;;oCAqBJ,MAAM;;;;;;;;;;sCAWJ,MAAM;sCACN,MAAM,SAAS,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iCAwC1B,MAAM;8BACT,MAAM;kCACF,MAAM;;;;;;;;;;;;qCAYH,MAAM;;iCAEV,MAAM;;;;sCAID,MAAM;;mCAET,MAAM;;gCAET,MAAM;;;;;;;;;gCASN,MAAM;qCACD,MAAM;;;;;;;;;;;;;;;;;;;;+BAuBZ,MAAM;;;;;;;;;;;;;;;uCAiBE,MAAM;;;;;;;;;;;;;;;;;;;;CAqBxB,CAAA"}
package/dist/render.js CHANGED
@@ -1,6 +1,6 @@
1
- import { validateStore, resolveConfig, registerStorefrontBlocks, registerStorefrontEntities, resetPageDiagnostics, withStaticRenderPass, StorefrontConfigProvider, StorefrontShell, resolvePageData, themeToCss, serializePageData, hydrateStoreDocument, storefrontPaths, isPublicPath, resolveStorefrontProvider } from './chunk-ORKXSAZ6.js';
1
+ import { validateStore, resolveConfig, registerStorefrontBlocks, registerStorefrontEntities, resetPageDiagnostics, withStaticRenderPass, StorefrontConfigProvider, StorefrontShell, resolvePageData, themeToCss, serializePageData, hydrateStoreDocument, storefrontPaths, isPublicPath, resolveStorefrontProvider } from './chunk-77V5ZAF5.js';
2
2
  import { renderToStaticMarkup } from 'react-dom/server';
3
- import { historyRouterAdapter, setBlockErrorVisibility, setBlockEditorMode, staticRouterAdapter, buildSeoTags } from '@fayz-ai/core';
3
+ import { historyRouterAdapter, setBlockErrorVisibility, setBlockEditorMode, staticRouterAdapter, buildSeoTags, errorMessage } from '@fayz-ai/core';
4
4
  import { createMockShopProvider } from '@fayz-ai/shop/mock';
5
5
  import { getShopProvider, setShopProvider } from '@fayz-ai/shop/runtime';
6
6
  import { jsx } from 'react/jsx-runtime';
@@ -324,7 +324,7 @@ async function prerenderStore(document, options) {
324
324
  router: staticRouterAdapter(path)
325
325
  });
326
326
  } catch (error) {
327
- skipped.push({ path, reason: error instanceof Error ? error.message : String(error) });
327
+ skipped.push({ path, reason: errorMessage(error) });
328
328
  return null;
329
329
  }
330
330
  const page = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/document/render.tsx","../src/app/prerender.ts"],"names":["staticRouterAdapter"],"mappings":"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","file":"render.js","sourcesContent":["import React from 'react'\nimport { renderToStaticMarkup } from 'react-dom/server'\nimport { buildSeoTags, setBlockEditorMode, setBlockErrorVisibility, staticRouterAdapter } from '@fayz-ai/core'\nimport { serializePageData } from '../app/hydration'\nimport type { RouterAdapter } from '@fayz-ai/core'\nimport type { BlockNode } from '@fayz-ai/core'\nimport { createMockShopProvider } from '@fayz-ai/shop/mock'\nimport { getShopProvider, setShopProvider } from '@fayz-ai/shop/runtime'\nimport type { ShopProvider } from '@fayz-ai/shop/provider'\nimport { registerStorefrontBlocks } from '../blocks/registry'\nimport { StorefrontConfigProvider, resolveConfig } from './config'\nimport type { StorefrontConfig } from './config'\nimport {\n StorefrontShell,\n registerStorefrontEntities,\n resolveStorefrontProvider,\n} from '../app/createStorefrontApp'\nimport { resetPageDiagnostics } from '../views/StorefrontPage'\nimport { resolvePageData } from '../blocks/page-data'\nimport type { PageDataEntry, PageDataNeed } from '../blocks/page-data'\nimport { withStaticRenderPass } from '../app/static-render'\nimport type { StaticHeadInput, StaticRenderPass } from '../app/static-render'\nimport { hydrateStoreDocument } from './round-trip'\nimport type { StoreDocument } from './sections'\nimport { themeToCss } from '../lib/theme'\nimport { validateStore } from './validate'\nimport type { StoreValidationReport } from './validate'\n\n// ---------------------------------------------------------------------------\n// renderStore — the third ability, and the one M8 exists for (spine §5).\n//\n// The bet the whole spine rests on is that an AI can author a store. An author\n// that cannot SEE what it authored is guessing: it can be told the document is\n// valid (validateStore) and what the vocabulary is (describeStore) and still\n// place a hero above a header, leave a rail empty because its loader returned\n// nothing, or ship a page whose only content is an error card. This closes\n// that loop without a human driving a browser.\n//\n// Three decisions worth stating, because each has a cheaper wrong version:\n//\n// 1. It renders the REAL shell, driven by path. Not a server-side\n// reimplementation of routing and page composition — that would be a\n// second mechanism silently drifting from the first, which is the exact\n// failure §4 lists for WooCommerce's template overrides (\"227 @version\n// headers, the loader never reads one\"). The components report what they\n// need through the static-render pass; nothing here knows the route table.\n//\n// 2. Data is resolved BETWEEN passes, not faked. `PageDataScope` publishes\n// the needs it would fetch, `resolvePageData` answers them through the\n// ShopProvider port (I11 — no backend is named here), and the next pass\n// renders with the answers seeded. So a rail that is empty in the output\n// is empty in the shopper's browser too, and the report says which loader\n// returned what.\n//\n// 3. The return value is a REPORT, not a string. HTML alone makes an agent\n// parse markup to answer \"did my change land\". `text`, `outline`,\n// `blocks`, `data` and `diagnostics` answer it directly, and\n// `diagnostics` is where the M2 error-isolation machinery (crashed block,\n// unknown block, misplaced block, forced-layout repair) finally becomes\n// readable by the thing that caused it.\n// ---------------------------------------------------------------------------\n\nexport interface StoreRenderDataEntry {\n /** Canonical `dataNeedKey` — the same key the browser would dedupe on. */\n key: string\n loader: string\n params: Record<string, unknown>\n status: 'ready' | 'error' | 'unresolved'\n /** Item count for an array result, so \"the rail is empty\" is one field. */\n count?: number\n error?: string\n}\n\nexport interface StoreRenderDiagnostic {\n level: 'error' | 'warn'\n /** Where it came from: 'blocks' (core), 'storefront', or 'render'. */\n source: string\n message: string\n}\n\nexport interface StoreRenderHeading {\n level: number\n text: string\n}\n\nexport interface StoreRenderBlock {\n type: string\n id?: string\n /** Ancestor block types, outermost first — empty for a top-level block. */\n within?: string[]\n}\n\nexport interface RenderStoreOptions {\n /** Route to render, in the storefront's own path space ('/', '/catalog',\n * '/product/anel-de-ouro', '/biography'). Default '/'. */\n path?: string\n /**\n * Where catalog data comes from.\n *\n * - `'config'` (default): the provider the config implies — its explicit\n * provider, or a mock seeded from its catalog. What the shopper sees.\n * - `'document'`: a mock seeded from the document's own `catalog` section.\n * Deterministic and network-free, which is what you want while iterating\n * on a document whose store is backed by a live database.\n * - a `ShopProvider`: bring your own.\n */\n provider?: ShopProvider | 'config' | 'document'\n /**\n * 'report' (default) renders an invalid document anyway and returns the\n * findings — an agent fixing a broken store needs to see the broken store.\n * 'throw' refuses, for a caller using this as a gate.\n */\n onError?: 'throw' | 'report'\n /** 'document' (default) wraps the markup in a full HTML document with the\n * theme CSS and the route's title; 'fragment' returns the shell markup. */\n html?: 'document' | 'fragment'\n /**\n * How many render/resolve rounds to run. One page's data can reveal the\n * next need (a route param feeding a rail), so the loop repeats until no new\n * need appears. Reaching the cap is reported as a diagnostic rather than\n * silently truncating the page. Default 4.\n */\n maxPasses?: number\n /** Stylesheet URLs to link from the emitted document — how a preview server\n * hands in the app's real (Tailwind) CSS. */\n stylesheets?: readonly string[]\n /** Extra markup for the emitted `<head>`. */\n head?: string\n /**\n * How the rendered store is ADDRESSED when served.\n *\n * Defaults to hash, matching how storefronts ship today, so a headless render\n * describes links that actually resolve. Pass `historyRouterAdapter()` (or any\n * adapter) for a store served at real URLs — that is what makes each page\n * come out with a crawlable href of its own, which is the difference between\n * prerendered HTML that can be indexed and prerendered HTML that cannot.\n */\n router?: RouterAdapter\n /**\n * Absolute origin, e.g. 'https://loja.example.com'. Required for canonical\n * and OpenGraph URLs — without it they are omitted rather than emitted\n * relative, because a relative canonical is ignored.\n */\n origin?: string\n /** `<html lang>`. Defaults to the document's locale, then 'pt-BR'. */\n lang?: string\n /**\n * Stamp every block with its document path (`data-fayz-block`).\n *\n * Off by default, because a shopper's page must not carry it. On, the emitted\n * HTML says which document node produced which part of the page — which lets\n * an editor resolve a click to a path, and lets a test assert the identity\n * seam without a browser.\n */\n editor?: boolean\n}\n\nexport interface StoreRenderResult {\n /** True when the document validates, the path resolved, and nothing on the\n * page reported an error. The one field a gate should read. */\n ok: boolean\n path: string\n /** The title this route declared through `useStorefrontHead`. */\n title: string\n description?: string\n /** The path resolved to a real page (false = the 404 page rendered). */\n found: boolean\n html: string\n /** Visible text, tags stripped and whitespace collapsed — what a reader sees. */\n text: string\n /** h1–h6 in document order: the page's shape in one glance. */\n outline: StoreRenderHeading[]\n /** Every block that rendered, in order, including forced-layout repairs. */\n blocks: StoreRenderBlock[]\n /** Outbound hrefs, deduped — how an agent checks its nav actually links. */\n links: string[]\n images: number\n data: StoreRenderDataEntry[]\n diagnostics: StoreRenderDiagnostic[]\n validation: StoreValidationReport\n /** Render/resolve rounds actually run. */\n passes: number\n bytes: number\n}\n\n// --- HTML reading -------------------------------------------------------------\n\nconst VOID_TEXT_TAGS = /<(script|style)\\b[^>]*>[\\s\\S]*?<\\/\\1>/gi\n\nconst ENTITIES: Record<string, string> = {\n amp: '&',\n lt: '<',\n gt: '>',\n quot: '\"',\n apos: \"'\",\n nbsp: ' ',\n '#39': \"'\",\n '#x27': \"'\",\n '#x2F': '/',\n}\n\nfunction decodeEntities(text: string): string {\n return text.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z]+);/g, (match, name: string) => {\n const direct = ENTITIES[name]\n if (direct !== undefined) return direct\n if (name.startsWith('#x') || name.startsWith('#X')) {\n return String.fromCodePoint(Number.parseInt(name.slice(2), 16))\n }\n if (name.startsWith('#')) return String.fromCodePoint(Number(name.slice(1)))\n return match\n })\n}\n\n/** Visible text of a markup string. Regex rather than a DOM because the\n * workspace has no jsdom and the question — \"what words are on this page\" —\n * does not need one. */\nexport function htmlToText(html: string): string {\n return decodeEntities(html.replace(VOID_TEXT_TAGS, ' ').replace(/<[^>]*>/g, ' '))\n .replace(/\\s+/g, ' ')\n .trim()\n}\n\nfunction readOutline(html: string): StoreRenderHeading[] {\n const found: StoreRenderHeading[] = []\n const pattern = /<h([1-6])\\b[^>]*>([\\s\\S]*?)<\\/h\\1>/gi\n let match: RegExpExecArray | null\n while ((match = pattern.exec(html)) !== null) {\n const text = htmlToText(match[2] ?? '')\n if (text) found.push({ level: Number(match[1]), text })\n }\n return found\n}\n\nfunction readLinks(html: string): string[] {\n const found = new Set<string>()\n const pattern = /<a\\b[^>]*\\bhref=\"([^\"]*)\"/gi\n let match: RegExpExecArray | null\n while ((match = pattern.exec(html)) !== null) {\n const href = decodeEntities(match[1] ?? '')\n if (href) found.add(href)\n }\n return [...found]\n}\n\nfunction escapeHtml(text: string): string {\n return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;')\n}\n\n// --- Block inventory ----------------------------------------------------------\n\nfunction flattenBlocks(nodes: readonly BlockNode[], within: string[], out: StoreRenderBlock[]): void {\n for (const node of nodes) {\n out.push({ type: node.type, ...(node.id ? { id: node.id } : {}), ...(within.length ? { within: [...within] } : {}) })\n if (node.children?.length) flattenBlocks(node.children, [...within, node.type], out)\n }\n}\n\n// --- Console capture ----------------------------------------------------------\n\n/**\n * Run a synchronous render with console.error/warn captured.\n *\n * Everything the M2/M3 machinery reports about a broken page — a crashed\n * block, an unknown block type, a misplaced block, a forced-layout repair, a\n * page-body omission — is already logged, deliberately, and in production too.\n * Capturing it is what turns \"the console would have told a developer\" into a\n * field the agent that authored the page can read.\n */\nfunction captureConsole<T>(sink: StoreRenderDiagnostic[], render: () => T): T {\n const originalError = console.error\n const originalWarn = console.warn\n const record = (level: 'error' | 'warn') => (...args: unknown[]) => {\n const message = args\n .map((arg) => (arg instanceof Error ? arg.message : typeof arg === 'string' ? arg : safeStringify(arg)))\n .join(' ')\n .trim()\n if (!message) return\n const source = message.startsWith('[blocks]') ? 'blocks' : message.startsWith('[storefront]') ? 'storefront' : 'render'\n sink.push({ level, source, message })\n }\n console.error = record('error')\n console.warn = record('warn')\n try {\n return render()\n } finally {\n console.error = originalError\n console.warn = originalWarn\n }\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value) ?? String(value)\n } catch {\n return String(value)\n }\n}\n\n// --- The renderer -------------------------------------------------------------\n\nfunction providerFor(\n option: RenderStoreOptions['provider'],\n config: StorefrontConfig,\n doc: Record<string, unknown>,\n): ShopProvider {\n if (option && typeof option === 'object') return option\n if (option === 'document') {\n const catalog = doc.catalog as Record<string, unknown> | undefined\n const promotions = (doc.promotions as Record<string, unknown> | undefined)?.promotions\n const { version: _version, ...seed } = catalog ?? {}\n return createMockShopProvider({\n ...seed,\n ...(Array.isArray(promotions) ? { promotions } : {}),\n } as Parameters<typeof createMockShopProvider>[0])\n }\n return resolveStorefrontProvider(config)\n}\n\n/**\n * Render a Store Document to HTML, headless, plus everything an agent needs to\n * understand the result.\n *\n * const result = await renderStore(doc, { path: '/biography' })\n * result.ok // did anything on the page go wrong\n * result.outline // [{ level: 1, text: 'Biography' }, …]\n * result.data // [{ loader: 'products.list', status: 'ready', count: 12 }]\n * result.diagnostics\n */\nexport async function renderStore(\n input: StoreDocument | Record<string, unknown>,\n options: RenderStoreOptions = {},\n): Promise<StoreRenderResult> {\n const path = options.path ?? '/'\n const maxPasses = Math.max(1, options.maxPasses ?? 4)\n const doc = input as Record<string, unknown>\n\n const validation = validateStore(input)\n if (!validation.ok && (options.onError ?? 'report') === 'throw') {\n throw new Error(\n `renderStore: the document failed validation:\\n${validation.errors\n .map((e) => ` - ${e.path || '(document)'}: ${e.message}${e.valid ? ` (valid: ${e.valid.join(', ')})` : ''}`)\n .join('\\n')}`,\n )\n }\n\n const diagnostics: StoreRenderDiagnostic[] = []\n\n // Hydration reports rather than throws: a document with one unresolvable\n // handle should still render the other 95% of the page, which is the whole\n // point of looking at it (I7). Its validation echo is dropped — `validation`\n // already carries it, structured — but a dropped code handle is kept, because\n // nothing else reports that.\n const hydrationLog: StoreRenderDiagnostic[] = []\n const config = captureConsole(hydrationLog, () => hydrateStoreDocument(input, { onError: 'report' }))\n diagnostics.push(...hydrationLog.filter((d) => !d.message.includes('Store document failed validation')))\n // Images at their settled frame. The reveal is a client entrance — a static\n // render has no load event to wait for, and `SmoothImage` no longer applies\n // the from-state on the server anyway; turning the mode off here keeps the\n // emitted HTML free of a transition nothing will ever run.\n const resolved = resolveConfig({ ...config, imageLoading: { ...config.imageLoading, mode: 'none' } })\n\n registerStorefrontBlocks()\n registerStorefrontEntities(config)\n\n const previousProvider = getShopProvider()\n setShopProvider(providerFor(options.provider, config, doc))\n // A preview is for the author, so a block that failed shows its error card\n // instead of vanishing — the shopper-facing 'silent' rule would hide exactly\n // what the loop exists to surface.\n setBlockErrorVisibility('visible')\n // Opt-in, and restored in the same `finally` as the provider — a render that\n // stamped and then threw must not leave the flag on for the next caller,\n // which in a preview server is the next request.\n if (options.editor) setBlockEditorMode(true)\n\n // Bound to the path being rendered, in the scheme the store is served under.\n // One adapter for the whole render: it is stateless here, and rebuilding it\n // per pass would only churn.\n const renderRouter = options.router\n ? staticRouterAdapter(path, { href: (to) => options.router!.href(to) })\n : staticRouterAdapter(path, { href: (to) => `#${to.startsWith('/') ? to : `/${to}`}` })\n\n const entries: Record<string, PageDataEntry> = {}\n let html = ''\n let passes = 0\n let head: StaticHeadInput = {}\n let blocks: StoreRenderBlock[] = []\n /** Needs the returned HTML still shows as loading — non-empty only when the\n * pass cap was reached, and reported rather than hidden. */\n let stale: PageDataNeed[] = []\n\n try {\n for (let round = 0; round < maxPasses; round++) {\n passes = round + 1\n const seenNeeds = new Map<string, PageDataNeed>()\n const trees: BlockNode[][] = []\n const heads: StaticHeadInput[] = []\n\n const pass: StaticRenderPass = {\n tree: (nodes) => void trees.push([...nodes]),\n needs: (needs) => {\n for (const need of needs) if (!seenNeeds.has(need.key)) seenNeeds.set(need.key, need)\n },\n head: (input_) => void heads.push(input_),\n entries,\n origin: options.origin,\n }\n\n // Reset PER PASS, not once. Page diagnostics are memoised per tree so a\n // shopper's console is not spammed by a re-render — but only the final\n // pass's console describes the page being returned, so without this a\n // multi-pass render would report a broken block on the pass whose output\n // was thrown away and stay silent on the one that was kept.\n resetPageDiagnostics()\n const roundDiagnostics: StoreRenderDiagnostic[] = []\n html = captureConsole(roundDiagnostics, () =>\n withStaticRenderPass(pass, () =>\n renderToStaticMarkup(\n <StorefrontConfigProvider value={resolved}>\n <StorefrontShell path={path} router={renderRouter} />\n </StorefrontConfigProvider>,\n ),\n ),\n )\n\n blocks = []\n for (const tree of trees) flattenBlocks(tree, [], blocks)\n // The LAST head declaration wins, matching the effect order a browser\n // would run: the route's own page declares after the chrome around it.\n head = heads.reduce<StaticHeadInput>(\n (acc, entry) => ({\n title: entry.title ?? acc.title,\n description: entry.description ?? acc.description,\n canonical: entry.canonical ?? acc.canonical,\n image: entry.image ?? acc.image,\n type: entry.type ?? acc.type,\n // Concatenated, not overwritten: a product page declares its Product\n // object and the chrome around it its BreadcrumbList, and a page is\n // allowed to carry both.\n jsonLd: [...(acc.jsonLd ?? []), ...(entry.jsonLd ?? [])],\n }),\n {},\n )\n\n const pending = [...seenNeeds.values()].filter((need) => !(need.key in entries))\n if (pending.length === 0) {\n // Only the final round's console output describes the page actually\n // being returned; earlier rounds are the same page with loading states,\n // and their diagnostics would double every message.\n diagnostics.push(...roundDiagnostics)\n break\n }\n if (round === maxPasses - 1) {\n // Resolving now would put answers in `entries` that this HTML does not\n // show. Report the gap instead of pretending the page is complete.\n stale = pending\n diagnostics.push(...roundDiagnostics)\n diagnostics.push({\n level: 'warn',\n source: 'render',\n message: `render stopped after ${maxPasses} passes with ${pending.length} data need(s) still loading — raise maxPasses if a page legitimately chains this deep`,\n })\n break\n }\n Object.assign(entries, await resolvePageData(pending))\n }\n } finally {\n setShopProvider(previousProvider)\n setBlockErrorVisibility(null)\n if (options.editor) setBlockEditorMode(false)\n }\n\n const data: StoreRenderDataEntry[] = Object.entries(entries).map(([key, entry]) => {\n const [loader, params] = splitNeedKey(key)\n return {\n key,\n loader,\n params,\n status: entry.status === 'ready' ? ('ready' as const) : ('error' as const),\n ...(Array.isArray(entry.data) ? { count: entry.data.length } : {}),\n ...(entry.error ? { error: entry.error } : {}),\n }\n })\n for (const need of stale) {\n data.push({ key: need.key, loader: need.loader, params: need.params, status: 'unresolved' })\n }\n\n const found = !html.includes('data-storefront-page=\"not-found\"')\n const title = head.title ?? resolved.name\n const text = htmlToText(html)\n const outline = readOutline(html)\n\n const body =\n (options.html ?? 'document') === 'fragment'\n ? html\n : wrapDocument(html + serializePageData({ entries, path }), {\n title,\n description: head.description ?? undefined,\n seo: { canonical: head.canonical, image: head.image, type: head.type, jsonLd: head.jsonLd },\n siteName: resolved.name,\n lang: options.lang ?? config.locale ?? 'pt-BR',\n themeCss: resolved.theme ? themeToCss(resolved.theme) : '',\n stylesheets: options.stylesheets ?? [],\n head: options.head ?? '',\n })\n\n return {\n ok:\n validation.ok &&\n found &&\n !diagnostics.some((d) => d.level === 'error') &&\n !data.some((d) => d.status !== 'ready'),\n path,\n title,\n ...(head.description ? { description: head.description } : {}),\n found,\n html: body,\n text,\n outline,\n blocks,\n links: readLinks(html),\n images: (html.match(/<img\\b/gi) ?? []).length,\n data,\n diagnostics,\n validation,\n passes,\n bytes: new TextEncoder().encode(body).length,\n }\n}\n\n/** `dataNeedKey` is `<loader> <canonical-json>`; recover both halves. */\nfunction splitNeedKey(key: string): [string, Record<string, unknown>] {\n const space = key.indexOf(' ')\n if (space === -1) return [key, {}]\n try {\n return [key.slice(0, space), JSON.parse(key.slice(space + 1)) as Record<string, unknown>]\n } catch {\n return [key.slice(0, space), {}]\n }\n}\n\ninterface WrapOptions {\n title: string\n description?: string\n lang: string\n themeCss: string\n stylesheets: readonly string[]\n head: string\n /** Canonical / OpenGraph / JSON-LD declared by the route being rendered. */\n seo?: Pick<StaticHeadInput, 'canonical' | 'image' | 'type' | 'jsonLd'>\n siteName?: string\n}\n\n/**\n * The HTML document around the shell markup.\n *\n * Deliberately minimal and self-contained: the theme's CSS variables ride\n * inline (they are already data — M2's brand tokens), and any real stylesheet\n * is LINKED rather than inlined, because the only thing that can produce the\n * app's utility CSS is the app's own build. A caller with no stylesheet gets\n * honest unstyled markup instead of a page that pretends to be styled.\n */\nexport function wrapDocument(markup: string, options: WrapOptions): string {\n const links = options.stylesheets.map((href) => `<link rel=\"stylesheet\" href=\"${escapeHtml(href)}\">`).join('')\n const themeStyle = options.themeCss ? `<style>${options.themeCss}</style>` : ''\n\n // Tag computation lives in core's `buildSeoTags`, shared with the client-side\n // `applySeo`, so a page's head is identical whichever side wrote it.\n const tags = buildSeoTags({\n title: options.title,\n description: options.description,\n canonical: options.seo?.canonical,\n image: options.seo?.image,\n type: options.seo?.type,\n siteName: options.siteName,\n jsonLd: options.seo?.jsonLd,\n })\n const meta = tags.meta\n .map((t) =>\n t.name\n ? `<meta name=\"${escapeHtml(t.name)}\" content=\"${escapeHtml(t.content)}\">`\n : `<meta property=\"${escapeHtml(t.property ?? '')}\" content=\"${escapeHtml(t.content)}\">`,\n )\n .join('')\n const seoLinks = tags.links\n .map((l) => `<link rel=\"${escapeHtml(l.rel)}\" href=\"${escapeHtml(l.href)}\">`)\n .join('')\n // JSON-LD is script content, not an attribute: `<` is escaped so a product\n // name containing markup cannot close the script tag early.\n const jsonLd = tags.jsonLd\n .map(\n (obj) =>\n `<script type=\"application/ld+json\">${JSON.stringify(obj).replace(/</g, '\\\\u003c')}</script>`,\n )\n .join('')\n\n return (\n `<!doctype html><html lang=\"${escapeHtml(options.lang)}\"><head><meta charset=\"utf-8\">` +\n `<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">` +\n `<title>${escapeHtml(tags.title)}</title>${meta}${seoLinks}${links}${themeStyle}${jsonLd}${options.head}` +\n `</head><body>${markup}</body></html>`\n )\n}\n","import { historyRouterAdapter, staticRouterAdapter } from '@fayz-ai/core'\nimport type { ShopProvider } from '@fayz-ai/shop/provider'\nimport { renderStore } from '../document/render'\nimport type { RenderStoreOptions, StoreRenderResult } from '../document/render'\nimport { storefrontPaths, isPublicPath } from './serving'\nimport { resolveConfig } from '../document/config'\nimport { hydrateStoreDocument } from '../document/round-trip'\nimport type { StoreDocument } from '../document/sections'\n\n// ---------------------------------------------------------------------------\n// Every page of a store, rendered.\n//\n// `storefrontPaths` says which URLs exist and `renderStore` renders one; this\n// is the loop between them, plus the two files a crawler looks for before it\n// looks at any page. Kept here rather than in each host because the ordering\n// rules are not obvious: only public paths may be written (a prerendered\n// /checkout is one shopper's cart served to everyone), a page that rendered\n// not-found must not be written at all (it would be indexed as real content),\n// and concurrency has to be bounded or a 400-product catalogue opens 400\n// provider connections at once.\n// ---------------------------------------------------------------------------\n\nexport interface PrerenderPage {\n path: string\n html: string\n /** Where a file-writing host should put it: `/product/x` → `product/x/index.html`. */\n outputPath: string\n title: string\n /** False when the path rendered the not-found page — excluded from `pages`. */\n found: boolean\n ok: boolean\n}\n\nexport interface PrerenderResult {\n pages: PrerenderPage[]\n /** Paths that rendered not-found or errored, with the reason. */\n skipped: Array<{ path: string; reason: string }>\n sitemapXml: string\n robotsTxt: string\n}\n\nexport interface PrerenderOptions\n extends Omit<RenderStoreOptions, 'path' | 'router' | 'html'> {\n provider: ShopProvider\n /** Absolute origin. Required for a sitemap — its URLs must be absolute. */\n origin: string\n /** Defaults to every public path the store has. */\n paths?: readonly string[]\n /** Bounded so a large catalogue does not open one connection per product. */\n concurrency?: number\n /** Reported per page, so a long run is observable rather than silent. */\n onPage?: (page: PrerenderPage) => void\n}\n\n/** `/` → `index.html`; `/product/x` → `product/x/index.html`. */\nexport function outputPathFor(path: string): string {\n const clean = (path.split('?')[0] ?? '/').replace(/^\\/+|\\/+$/g, '')\n return clean === '' ? 'index.html' : `${clean}/index.html`\n}\n\nfunction xmlEscape(value: string): string {\n return value\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n}\n\nexport function buildSitemapXml(origin: string, paths: readonly string[]): string {\n const base = origin.replace(/\\/$/, '')\n const urls = paths\n .map((p) => ` <url><loc>${xmlEscape(`${base}${p}`)}</loc></url>`)\n .join('\\n')\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\\n${urls}\\n</urlset>\\n`\n}\n\n/**\n * Disallows the per-shopper routes explicitly.\n *\n * They are not linked from anywhere crawlable, but a crawler that finds one\n * anyway would index a checkout — and crawl budget spent there is budget not\n * spent on products.\n */\nexport function buildRobotsTxt(origin: string): string {\n const base = origin.replace(/\\/$/, '')\n return [\n 'User-agent: *',\n 'Allow: /',\n 'Disallow: /checkout',\n 'Disallow: /account',\n 'Disallow: /order/',\n '',\n `Sitemap: ${base}/sitemap.xml`,\n '',\n ].join('\\n')\n}\n\nasync function mapWithLimit<T, R>(\n items: readonly T[],\n limit: number,\n fn: (item: T) => Promise<R>,\n): Promise<R[]> {\n const results = new Array<R>(items.length)\n let next = 0\n const workers = Array.from({ length: Math.min(limit, items.length) }, async () => {\n for (;;) {\n const i = next++\n if (i >= items.length) return\n results[i] = await fn(items[i]!)\n }\n })\n await Promise.all(workers)\n return results\n}\n\n/**\n * Render every public page of a store.\n *\n * The router is fixed to real-URL addressing: prerendering a hash-addressed\n * store would write files no URL can reach, which is the whole reason the\n * addressing seam exists.\n */\nexport async function prerenderStore(\n document: StoreDocument | Record<string, unknown>,\n options: PrerenderOptions,\n): Promise<PrerenderResult> {\n // Hydrated the same way renderStore does, so path enumeration and rendering\n // agree about what the store contains.\n const config = resolveConfig(hydrateStoreDocument(document, { onError: 'report' }))\n const paths =\n options.paths ??\n (await storefrontPaths({ config, provider: options.provider }))\n\n // Belt and braces: `storefrontPaths` already filters, but an explicit list\n // from a caller has not been through it, and a prerendered /checkout is one\n // shopper's cart served to everyone.\n const publicPaths = paths.filter((p) => isPublicPath(config, p))\n\n const skipped: Array<{ path: string; reason: string }> = []\n const rendered = await mapWithLimit(publicPaths, options.concurrency ?? 8, async (path) => {\n let result: StoreRenderResult\n try {\n result = await renderStore(document, {\n ...options,\n path,\n router: staticRouterAdapter(path),\n })\n } catch (error) {\n skipped.push({ path, reason: error instanceof Error ? error.message : String(error) })\n return null\n }\n const page: PrerenderPage = {\n path,\n html: result.html,\n outputPath: outputPathFor(path),\n title: result.title,\n found: result.found,\n ok: result.ok,\n }\n if (!result.found) {\n // Writing it would publish a not-found page at a real URL, which is then\n // indexed as content. Reported rather than silently dropped.\n skipped.push({ path, reason: 'rendered the not-found page' })\n return null\n }\n options.onPage?.(page)\n return page\n })\n\n const pages = rendered.filter((p): p is PrerenderPage => p !== null)\n return {\n pages,\n skipped,\n sitemapXml: buildSitemapXml(options.origin, pages.map((p) => p.path)),\n robotsTxt: buildRobotsTxt(options.origin),\n }\n}\n\n/** The adapter a browser app should use to serve a prerendered store. */\nexport const prerenderClientRouter = historyRouterAdapter\n"]}
1
+ {"version":3,"sources":["../src/document/render.tsx","../src/app/prerender.ts"],"names":["staticRouterAdapter"],"mappings":";;;;;;;AA2LA,IAAM,cAAA,GAAiB,yCAAA;AAEvB,IAAM,QAAA,GAAmC;AAAA,EACvC,GAAA,EAAK,GAAA;AAAA,EACL,EAAA,EAAI,GAAA;AAAA,EACJ,EAAA,EAAI,GAAA;AAAA,EACJ,IAAA,EAAM,GAAA;AAAA,EACN,IAAA,EAAM,GAAA;AAAA,EACN,IAAA,EAAM,GAAA;AAAA,EACN,KAAA,EAAO,GAAA;AAAA,EACP,MAAA,EAAQ,GAAA;AAAA,EACR,MAAA,EAAQ;AACV,CAAA;AAEA,SAAS,eAAe,IAAA,EAAsB;AAC5C,EAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,gCAAA,EAAkC,CAAC,OAAO,IAAA,KAAiB;AAC7E,IAAA,MAAM,MAAA,GAAS,SAAS,IAAI,CAAA;AAC5B,IAAA,IAAI,MAAA,KAAW,QAAW,OAAO,MAAA;AACjC,IAAA,IAAI,KAAK,UAAA,CAAW,IAAI,KAAK,IAAA,CAAK,UAAA,CAAW,IAAI,CAAA,EAAG;AAClD,MAAA,OAAO,MAAA,CAAO,cAAc,MAAA,CAAO,QAAA,CAAS,KAAK,KAAA,CAAM,CAAC,CAAA,EAAG,EAAE,CAAC,CAAA;AAAA,IAChE;AACA,IAAA,IAAI,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA,EAAG,OAAO,MAAA,CAAO,aAAA,CAAc,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,CAAC,CAAC,CAAC,CAAA;AAC3E,IAAA,OAAO,KAAA;AAAA,EACT,CAAC,CAAA;AACH;AAKO,SAAS,WAAW,IAAA,EAAsB;AAC/C,EAAA,OAAO,cAAA,CAAe,IAAA,CAAK,OAAA,CAAQ,cAAA,EAAgB,GAAG,CAAA,CAAE,OAAA,CAAQ,UAAA,EAAY,GAAG,CAAC,CAAA,CAC7E,OAAA,CAAQ,MAAA,EAAQ,GAAG,EACnB,IAAA,EAAK;AACV;AAEA,SAAS,YAAY,IAAA,EAAoC;AACvD,EAAA,MAAM,QAA8B,EAAC;AACrC,EAAA,MAAM,OAAA,GAAU,sCAAA;AAChB,EAAA,IAAI,KAAA;AACJ,EAAA,OAAA,CAAQ,KAAA,GAAQ,OAAA,CAAQ,IAAA,CAAK,IAAI,OAAO,IAAA,EAAM;AAC5C,IAAA,MAAM,IAAA,GAAO,UAAA,CAAW,KAAA,CAAM,CAAC,KAAK,EAAE,CAAA;AACtC,IAAA,IAAI,IAAA,EAAM,KAAA,CAAM,IAAA,CAAK,EAAE,KAAA,EAAO,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA,EAAG,IAAA,EAAM,CAAA;AAAA,EACxD;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,UAAU,IAAA,EAAwB;AACzC,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAY;AAC9B,EAAA,MAAM,OAAA,GAAU,6BAAA;AAChB,EAAA,IAAI,KAAA;AACJ,EAAA,OAAA,CAAQ,KAAA,GAAQ,OAAA,CAAQ,IAAA,CAAK,IAAI,OAAO,IAAA,EAAM;AAC5C,IAAA,MAAM,IAAA,GAAO,cAAA,CAAe,KAAA,CAAM,CAAC,KAAK,EAAE,CAAA;AAC1C,IAAA,IAAI,IAAA,EAAM,KAAA,CAAM,GAAA,CAAI,IAAI,CAAA;AAAA,EAC1B;AACA,EAAA,OAAO,CAAC,GAAG,KAAK,CAAA;AAClB;AAEA,SAAS,WAAW,IAAA,EAAsB;AACxC,EAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,IAAA,EAAM,OAAO,EAAE,OAAA,CAAQ,IAAA,EAAM,MAAM,CAAA,CAAE,QAAQ,IAAA,EAAM,MAAM,CAAA,CAAE,OAAA,CAAQ,MAAM,QAAQ,CAAA;AACvG;AAIA,SAAS,aAAA,CAAc,KAAA,EAA6B,MAAA,EAAkB,GAAA,EAA+B;AACnG,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,GAAA,CAAI,IAAA,CAAK,EAAE,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,GAAI,IAAA,CAAK,EAAA,GAAK,EAAE,EAAA,EAAI,IAAA,CAAK,EAAA,EAAG,GAAI,EAAC,EAAI,GAAI,MAAA,CAAO,MAAA,GAAS,EAAE,MAAA,EAAQ,CAAC,GAAG,MAAM,CAAA,EAAE,GAAI,EAAC,EAAI,CAAA;AACpH,IAAA,IAAI,IAAA,CAAK,QAAA,EAAU,MAAA,EAAQ,aAAA,CAAc,IAAA,CAAK,QAAA,EAAU,CAAC,GAAG,MAAA,EAAQ,IAAA,CAAK,IAAI,CAAA,EAAG,GAAG,CAAA;AAAA,EACrF;AACF;AAaA,SAAS,cAAA,CAAkB,MAA+B,MAAA,EAAoB;AAC5E,EAAA,MAAM,gBAAgB,OAAA,CAAQ,KAAA;AAC9B,EAAA,MAAM,eAAe,OAAA,CAAQ,IAAA;AAC7B,EAAA,MAAM,MAAA,GAAS,CAAC,KAAA,KAA4B,CAAA,GAAI,IAAA,KAAoB;AAClE,IAAA,MAAM,OAAA,GAAU,KACb,GAAA,CAAI,CAAC,QAAS,GAAA,YAAe,KAAA,GAAQ,IAAI,OAAA,GAAU,OAAO,QAAQ,QAAA,GAAW,GAAA,GAAM,cAAc,GAAG,CAAE,EACtG,IAAA,CAAK,GAAG,EACR,IAAA,EAAK;AACR,IAAA,IAAI,CAAC,OAAA,EAAS;AACd,IAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,UAAA,CAAW,UAAU,CAAA,GAAI,WAAW,OAAA,CAAQ,UAAA,CAAW,cAAc,CAAA,GAAI,YAAA,GAAe,QAAA;AAC/G,IAAA,IAAA,CAAK,IAAA,CAAK,EAAE,KAAA,EAAO,MAAA,EAAQ,SAAS,CAAA;AAAA,EACtC,CAAA;AACA,EAAA,OAAA,CAAQ,KAAA,GAAQ,OAAO,OAAO,CAAA;AAC9B,EAAA,OAAA,CAAQ,IAAA,GAAO,OAAO,MAAM,CAAA;AAC5B,EAAA,IAAI;AACF,IAAA,OAAO,MAAA,EAAO;AAAA,EAChB,CAAA,SAAE;AACA,IAAA,OAAA,CAAQ,KAAA,GAAQ,aAAA;AAChB,IAAA,OAAA,CAAQ,IAAA,GAAO,YAAA;AAAA,EACjB;AACF;AAEA,SAAS,cAAc,KAAA,EAAwB;AAC7C,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,IAAK,OAAO,KAAK,CAAA;AAAA,EAC9C,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,OAAO,KAAK,CAAA;AAAA,EACrB;AACF;AAIA,SAAS,WAAA,CACP,MAAA,EACA,MAAA,EACA,GAAA,EACc;AACd,EAAA,IAAI,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,EAAU,OAAO,MAAA;AACjD,EAAA,IAAI,WAAW,UAAA,EAAY;AACzB,IAAA,MAAM,UAAU,GAAA,CAAI,OAAA;AACpB,IAAA,MAAM,UAAA,GAAc,IAAI,UAAA,EAAoD,UAAA;AAC5E,IAAA,MAAM,EAAE,OAAA,EAAS,QAAA,EAAU,GAAG,IAAA,EAAK,GAAI,WAAW,EAAC;AACnD,IAAA,OAAO,sBAAA,CAAuB;AAAA,MAC5B,GAAG,IAAA;AAAA,MACH,GAAI,MAAM,OAAA,CAAQ,UAAU,IAAI,EAAE,UAAA,KAAe;AAAC,KACH,CAAA;AAAA,EACnD;AACA,EAAA,OAAO,0BAA0B,MAAM,CAAA;AACzC;AAYA,eAAsB,WAAA,CACpB,KAAA,EACA,OAAA,GAA8B,EAAC,EACH;AAC5B,EAAA,MAAM,IAAA,GAAO,QAAQ,IAAA,IAAQ,GAAA;AAC7B,EAAA,MAAM,YAAY,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAA,CAAQ,aAAa,CAAC,CAAA;AACpD,EAAA,MAAM,GAAA,GAAM,KAAA;AAEZ,EAAA,MAAM,UAAA,GAAa,cAAc,KAAK,CAAA;AACtC,EAAA,IAAI,CAAC,UAAA,CAAW,EAAA,IAAA,CAAO,OAAA,CAAQ,OAAA,IAAW,cAAc,OAAA,EAAS;AAC/D,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA;AAAA,EAAiD,UAAA,CAAW,MAAA,CACzD,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,GAAA,EAAM,CAAA,CAAE,IAAA,IAAQ,YAAY,CAAA,EAAA,EAAK,CAAA,CAAE,OAAO,CAAA,EAAG,CAAA,CAAE,KAAA,GAAQ,CAAA,SAAA,EAAY,CAAA,CAAE,KAAA,CAAM,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAA,GAAM,EAAE,CAAA,CAAE,CAAA,CAC1G,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,KACf;AAAA,EACF;AAEA,EAAA,MAAM,cAAuC,EAAC;AAO9C,EAAA,MAAM,eAAwC,EAAC;AAC/C,EAAA,MAAM,MAAA,GAAS,cAAA,CAAe,YAAA,EAAc,MAAM,oBAAA,CAAqB,OAAO,EAAE,OAAA,EAAS,QAAA,EAAU,CAAC,CAAA;AACpG,EAAA,WAAA,CAAY,IAAA,CAAK,GAAG,YAAA,CAAa,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,OAAA,CAAQ,QAAA,CAAS,kCAAkC,CAAC,CAAC,CAAA;AAKvG,EAAA,MAAM,QAAA,GAAW,aAAA,CAAc,EAAE,GAAG,MAAA,EAAQ,YAAA,EAAc,EAAE,GAAG,MAAA,CAAO,YAAA,EAAc,IAAA,EAAM,MAAA,IAAU,CAAA;AAEpG,EAAA,wBAAA,EAAyB;AACzB,EAAA,0BAAA,CAA2B,MAAM,CAAA;AAEjC,EAAA,MAAM,mBAAmB,eAAA,EAAgB;AACzC,EAAA,eAAA,CAAgB,WAAA,CAAY,OAAA,CAAQ,QAAA,EAAU,MAAA,EAAQ,GAAG,CAAC,CAAA;AAI1D,EAAA,uBAAA,CAAwB,SAAS,CAAA;AAIjC,EAAA,IAAI,OAAA,CAAQ,MAAA,EAAQ,kBAAA,CAAmB,IAAI,CAAA;AAK3C,EAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,MAAA,GACzB,mBAAA,CAAoB,MAAM,EAAE,IAAA,EAAM,CAAC,EAAA,KAAO,OAAA,CAAQ,MAAA,CAAQ,IAAA,CAAK,EAAE,GAAG,CAAA,GACpE,mBAAA,CAAoB,IAAA,EAAM,EAAE,IAAA,EAAM,CAAC,EAAA,KAAO,IAAI,EAAA,CAAG,UAAA,CAAW,GAAG,CAAA,GAAI,EAAA,GAAK,CAAA,CAAA,EAAI,EAAE,CAAA,CAAE,IAAI,CAAA;AAExF,EAAA,MAAM,UAAyC,EAAC;AAChD,EAAA,IAAI,IAAA,GAAO,EAAA;AACX,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,IAAI,OAAwB,EAAC;AAC7B,EAAA,IAAI,SAA6B,EAAC;AAGlC,EAAA,IAAI,QAAwB,EAAC;AAE7B,EAAA,IAAI;AACF,IAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,SAAA,EAAW,KAAA,EAAA,EAAS;AAC9C,MAAA,MAAA,GAAS,KAAA,GAAQ,CAAA;AACjB,MAAA,MAAM,SAAA,uBAAgB,GAAA,EAA0B;AAChD,MAAA,MAAM,QAAuB,EAAC;AAC9B,MAAA,MAAM,QAA2B,EAAC;AAElC,MAAA,MAAM,IAAA,GAAyB;AAAA,QAC7B,IAAA,EAAM,CAAC,KAAA,KAAU,KAAK,MAAM,IAAA,CAAK,CAAC,GAAG,KAAK,CAAC,CAAA;AAAA,QAC3C,KAAA,EAAO,CAAC,KAAA,KAAU;AAChB,UAAA,KAAA,MAAW,IAAA,IAAQ,KAAA,EAAO,IAAI,CAAC,SAAA,CAAU,GAAA,CAAI,IAAA,CAAK,GAAG,CAAA,EAAG,SAAA,CAAU,GAAA,CAAI,IAAA,CAAK,KAAK,IAAI,CAAA;AAAA,QACtF,CAAA;AAAA,QACA,MAAM,CAAC,MAAA,KAAW,KAAK,KAAA,CAAM,KAAK,MAAM,CAAA;AAAA,QACxC,OAAA;AAAA,QACA,QAAQ,OAAA,CAAQ;AAAA,OAClB;AAOA,MAAA,oBAAA,EAAqB;AACrB,MAAA,MAAM,mBAA4C,EAAC;AACnD,MAAA,IAAA,GAAO,cAAA;AAAA,QAAe,gBAAA;AAAA,QAAkB,MACtC,oBAAA;AAAA,UAAqB,IAAA;AAAA,UAAM,MACzB,oBAAA;AAAA,4BACE,GAAA,CAAC,4BAAyB,KAAA,EAAO,QAAA,EAC/B,8BAAC,eAAA,EAAA,EAAgB,IAAA,EAAY,MAAA,EAAQ,YAAA,EAAc,CAAA,EACrD;AAAA;AACF;AACF,OACF;AAEA,MAAA,MAAA,GAAS,EAAC;AACV,MAAA,KAAA,MAAW,QAAQ,KAAA,EAAO,aAAA,CAAc,IAAA,EAAM,IAAI,MAAM,CAAA;AAGxD,MAAA,IAAA,GAAO,KAAA,CAAM,MAAA;AAAA,QACX,CAAC,KAAK,KAAA,MAAW;AAAA,UACf,KAAA,EAAO,KAAA,CAAM,KAAA,IAAS,GAAA,CAAI,KAAA;AAAA,UAC1B,WAAA,EAAa,KAAA,CAAM,WAAA,IAAe,GAAA,CAAI,WAAA;AAAA,UACtC,SAAA,EAAW,KAAA,CAAM,SAAA,IAAa,GAAA,CAAI,SAAA;AAAA,UAClC,KAAA,EAAO,KAAA,CAAM,KAAA,IAAS,GAAA,CAAI,KAAA;AAAA,UAC1B,IAAA,EAAM,KAAA,CAAM,IAAA,IAAQ,GAAA,CAAI,IAAA;AAAA;AAAA;AAAA;AAAA,UAIxB,MAAA,EAAQ,CAAC,GAAI,GAAA,CAAI,MAAA,IAAU,EAAC,EAAI,GAAI,KAAA,CAAM,MAAA,IAAU,EAAG;AAAA,SACzD,CAAA;AAAA,QACA;AAAC,OACH;AAEA,MAAA,MAAM,OAAA,GAAU,CAAC,GAAG,SAAA,CAAU,MAAA,EAAQ,CAAA,CAAE,MAAA,CAAO,CAAC,IAAA,KAAS,EAAE,IAAA,CAAK,OAAO,OAAA,CAAQ,CAAA;AAC/E,MAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AAIxB,QAAA,WAAA,CAAY,IAAA,CAAK,GAAG,gBAAgB,CAAA;AACpC,QAAA;AAAA,MACF;AACA,MAAA,IAAI,KAAA,KAAU,YAAY,CAAA,EAAG;AAG3B,QAAA,KAAA,GAAQ,OAAA;AACR,QAAA,WAAA,CAAY,IAAA,CAAK,GAAG,gBAAgB,CAAA;AACpC,QAAA,WAAA,CAAY,IAAA,CAAK;AAAA,UACf,KAAA,EAAO,MAAA;AAAA,UACP,MAAA,EAAQ,QAAA;AAAA,UACR,OAAA,EAAS,CAAA,qBAAA,EAAwB,SAAS,CAAA,aAAA,EAAgB,QAAQ,MAAM,CAAA,0FAAA;AAAA,SACzE,CAAA;AACD,QAAA;AAAA,MACF;AACA,MAAA,MAAA,CAAO,MAAA,CAAO,OAAA,EAAS,MAAM,eAAA,CAAgB,OAAO,CAAC,CAAA;AAAA,IACvD;AAAA,EACF,CAAA,SAAE;AACA,IAAA,eAAA,CAAgB,gBAAgB,CAAA;AAChC,IAAA,uBAAA,CAAwB,IAAI,CAAA;AAC5B,IAAA,IAAI,OAAA,CAAQ,MAAA,EAAQ,kBAAA,CAAmB,KAAK,CAAA;AAAA,EAC9C;AAEA,EAAA,MAAM,IAAA,GAA+B,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAA,CAAE,IAAI,CAAC,CAAC,GAAA,EAAK,KAAK,CAAA,KAAM;AACjF,IAAA,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,GAAI,aAAa,GAAG,CAAA;AACzC,IAAA,OAAO;AAAA,MACL,GAAA;AAAA,MACA,MAAA;AAAA,MACA,MAAA;AAAA,MACA,MAAA,EAAQ,KAAA,CAAM,MAAA,KAAW,OAAA,GAAW,OAAA,GAAqB,OAAA;AAAA,MACzD,GAAI,KAAA,CAAM,OAAA,CAAQ,KAAA,CAAM,IAAI,CAAA,GAAI,EAAE,KAAA,EAAO,KAAA,CAAM,IAAA,CAAK,MAAA,EAAO,GAAI,EAAC;AAAA,MAChE,GAAI,MAAM,KAAA,GAAQ,EAAE,OAAO,KAAA,CAAM,KAAA,KAAU;AAAC,KAC9C;AAAA,EACF,CAAC,CAAA;AACD,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,IAAA,CAAK,IAAA,CAAK,EAAE,GAAA,EAAK,IAAA,CAAK,GAAA,EAAK,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAQ,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAQ,MAAA,EAAQ,cAAc,CAAA;AAAA,EAC7F;AAEA,EAAA,MAAM,KAAA,GAAQ,CAAC,IAAA,CAAK,QAAA,CAAS,kCAAkC,CAAA;AAC/D,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,IAAS,QAAA,CAAS,IAAA;AACrC,EAAA,MAAM,IAAA,GAAO,WAAW,IAAI,CAAA;AAC5B,EAAA,MAAM,OAAA,GAAU,YAAY,IAAI,CAAA;AAEhC,EAAA,MAAM,IAAA,GAAA,CACH,OAAA,CAAQ,IAAA,IAAQ,UAAA,MAAgB,UAAA,GAC7B,IAAA,GACA,YAAA,CAAa,IAAA,GAAO,iBAAA,CAAkB,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA,EAAG;AAAA,IACxD,KAAA;AAAA,IACA,WAAA,EAAa,KAAK,WAAA,IAAe,MAAA;AAAA,IACjC,GAAA,EAAK,EAAE,SAAA,EAAW,IAAA,CAAK,SAAA,EAAW,KAAA,EAAO,IAAA,CAAK,KAAA,EAAO,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,MAAA,EAAQ,KAAK,MAAA,EAAO;AAAA,IAC1F,UAAU,QAAA,CAAS,IAAA;AAAA,IACnB,IAAA,EAAM,OAAA,CAAQ,IAAA,IAAQ,MAAA,CAAO,MAAA,IAAU,OAAA;AAAA,IACvC,UAAU,QAAA,CAAS,KAAA,GAAQ,UAAA,CAAW,QAAA,CAAS,KAAK,CAAA,GAAI,EAAA;AAAA,IACxD,WAAA,EAAa,OAAA,CAAQ,WAAA,IAAe,EAAC;AAAA,IACrC,IAAA,EAAM,QAAQ,IAAA,IAAQ;AAAA,GACvB,CAAA;AAEP,EAAA,OAAO;AAAA,IACL,EAAA,EACE,WAAW,EAAA,IACX,KAAA,IACA,CAAC,WAAA,CAAY,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,OAAO,CAAA,IAC5C,CAAC,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,OAAO,CAAA;AAAA,IACxC,IAAA;AAAA,IACA,KAAA;AAAA,IACA,GAAI,KAAK,WAAA,GAAc,EAAE,aAAa,IAAA,CAAK,WAAA,KAAgB,EAAC;AAAA,IAC5D,KAAA;AAAA,IACA,IAAA,EAAM,IAAA;AAAA,IACN,IAAA;AAAA,IACA,OAAA;AAAA,IACA,MAAA;AAAA,IACA,KAAA,EAAO,UAAU,IAAI,CAAA;AAAA,IACrB,SAAS,IAAA,CAAK,KAAA,CAAM,UAAU,CAAA,IAAK,EAAC,EAAG,MAAA;AAAA,IACvC,IAAA;AAAA,IACA,WAAA;AAAA,IACA,UAAA;AAAA,IACA,MAAA;AAAA,IACA,OAAO,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,IAAI,CAAA,CAAE;AAAA,GACxC;AACF;AAGA,SAAS,aAAa,GAAA,EAAgD;AACpE,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAC7B,EAAA,IAAI,UAAU,EAAA,EAAI,OAAO,CAAC,GAAA,EAAK,EAAE,CAAA;AACjC,EAAA,IAAI;AACF,IAAA,OAAO,CAAC,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,KAAA,CAAM,KAAA,GAAQ,CAAC,CAAC,CAA4B,CAAA;AAAA,EAC1F,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,CAAC,GAAA,CAAI,KAAA,CAAM,GAAG,KAAK,CAAA,EAAG,EAAE,CAAA;AAAA,EACjC;AACF;AAuBO,SAAS,YAAA,CAAa,QAAgB,OAAA,EAA8B;AACzE,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,WAAA,CAAY,GAAA,CAAI,CAAC,IAAA,KAAS,CAAA,6BAAA,EAAgC,UAAA,CAAW,IAAI,CAAC,CAAA,EAAA,CAAI,CAAA,CAAE,KAAK,EAAE,CAAA;AAC7G,EAAA,MAAM,aAAa,OAAA,CAAQ,QAAA,GAAW,CAAA,OAAA,EAAU,OAAA,CAAQ,QAAQ,CAAA,QAAA,CAAA,GAAa,EAAA;AAI7E,EAAA,MAAM,OAAO,YAAA,CAAa;AAAA,IACxB,OAAO,OAAA,CAAQ,KAAA;AAAA,IACf,aAAa,OAAA,CAAQ,WAAA;AAAA,IACrB,SAAA,EAAW,QAAQ,GAAA,EAAK,SAAA;AAAA,IACxB,KAAA,EAAO,QAAQ,GAAA,EAAK,KAAA;AAAA,IACpB,IAAA,EAAM,QAAQ,GAAA,EAAK,IAAA;AAAA,IACnB,UAAU,OAAA,CAAQ,QAAA;AAAA,IAClB,MAAA,EAAQ,QAAQ,GAAA,EAAK;AAAA,GACtB,CAAA;AACD,EAAA,MAAM,IAAA,GAAO,KAAK,IAAA,CACf,GAAA;AAAA,IAAI,CAAC,CAAA,KACJ,CAAA,CAAE,IAAA,GACE,CAAA,YAAA,EAAe,WAAW,CAAA,CAAE,IAAI,CAAC,CAAA,WAAA,EAAc,UAAA,CAAW,CAAA,CAAE,OAAO,CAAC,CAAA,EAAA,CAAA,GACpE,CAAA,gBAAA,EAAmB,UAAA,CAAW,CAAA,CAAE,QAAA,IAAY,EAAE,CAAC,CAAA,WAAA,EAAc,UAAA,CAAW,CAAA,CAAE,OAAO,CAAC,CAAA,EAAA;AAAA,GACxF,CACC,KAAK,EAAE,CAAA;AACV,EAAA,MAAM,WAAW,IAAA,CAAK,KAAA,CACnB,IAAI,CAAC,CAAA,KAAM,cAAc,UAAA,CAAW,CAAA,CAAE,GAAG,CAAC,CAAA,QAAA,EAAW,WAAW,CAAA,CAAE,IAAI,CAAC,CAAA,EAAA,CAAI,CAAA,CAC3E,KAAK,EAAE,CAAA;AAGV,EAAA,MAAM,MAAA,GAAS,KAAK,MAAA,CACjB,GAAA;AAAA,IACC,CAAC,GAAA,KACC,CAAA,mCAAA,EAAsC,IAAA,CAAK,SAAA,CAAU,GAAG,CAAA,CAAE,OAAA,CAAQ,IAAA,EAAM,SAAS,CAAC,CAAA,SAAA;AAAA,GACtF,CACC,KAAK,EAAE,CAAA;AAEV,EAAA,OACE,CAAA,2BAAA,EAA8B,UAAA,CAAW,OAAA,CAAQ,IAAI,CAAC,4GAE5C,UAAA,CAAW,IAAA,CAAK,KAAK,CAAC,CAAA,QAAA,EAAW,IAAI,GAAG,QAAQ,CAAA,EAAG,KAAK,CAAA,EAAG,UAAU,CAAA,EAAG,MAAM,CAAA,EAAG,OAAA,CAAQ,IAAI,CAAA,aAAA,EACvF,MAAM,CAAA,cAAA,CAAA;AAE1B;ACliBO,SAAS,cAAc,IAAA,EAAsB;AAClD,EAAA,MAAM,KAAA,GAAA,CAAS,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,IAAK,GAAA,EAAK,OAAA,CAAQ,YAAA,EAAc,EAAE,CAAA;AAClE,EAAA,OAAO,KAAA,KAAU,EAAA,GAAK,YAAA,GAAe,CAAA,EAAG,KAAK,CAAA,WAAA,CAAA;AAC/C;AAEA,SAAS,UAAU,KAAA,EAAuB;AACxC,EAAA,OAAO,KAAA,CACJ,OAAA,CAAQ,IAAA,EAAM,OAAO,EACrB,OAAA,CAAQ,IAAA,EAAM,MAAM,CAAA,CACpB,QAAQ,IAAA,EAAM,MAAM,CAAA,CACpB,OAAA,CAAQ,MAAM,QAAQ,CAAA;AAC3B;AAEO,SAAS,eAAA,CAAgB,QAAgB,KAAA,EAAkC;AAChF,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AACrC,EAAA,MAAM,OAAO,KAAA,CACV,GAAA,CAAI,CAAC,CAAA,KAAM,eAAe,SAAA,CAAU,CAAA,EAAG,IAAI,CAAA,EAAG,CAAC,CAAA,CAAE,CAAC,CAAA,YAAA,CAAc,CAAA,CAChE,KAAK,IAAI,CAAA;AACZ,EAAA,OAAO,CAAA;AAAA;AAAA,EAAyG,IAAI;AAAA;AAAA,CAAA;AACtH;AASO,SAAS,eAAe,MAAA,EAAwB;AACrD,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AACrC,EAAA,OAAO;AAAA,IACL,eAAA;AAAA,IACA,UAAA;AAAA,IACA,qBAAA;AAAA,IACA,oBAAA;AAAA,IACA,mBAAA;AAAA,IACA,EAAA;AAAA,IACA,YAAY,IAAI,CAAA,YAAA,CAAA;AAAA,IAChB;AAAA,GACF,CAAE,KAAK,IAAI,CAAA;AACb;AAEA,eAAe,YAAA,CACb,KAAA,EACA,KAAA,EACA,EAAA,EACc;AACd,EAAA,MAAM,OAAA,GAAU,IAAI,KAAA,CAAS,KAAA,CAAM,MAAM,CAAA;AACzC,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,MAAM,OAAA,GAAU,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,KAAA,CAAM,MAAM,CAAA,EAAE,EAAG,YAAY;AAChF,IAAA,WAAS;AACP,MAAA,MAAM,CAAA,GAAI,IAAA,EAAA;AACV,MAAA,IAAI,CAAA,IAAK,MAAM,MAAA,EAAQ;AACvB,MAAA,OAAA,CAAQ,CAAC,CAAA,GAAI,MAAM,EAAA,CAAG,KAAA,CAAM,CAAC,CAAE,CAAA;AAAA,IACjC;AAAA,EACF,CAAC,CAAA;AACD,EAAA,MAAM,OAAA,CAAQ,IAAI,OAAO,CAAA;AACzB,EAAA,OAAO,OAAA;AACT;AASA,eAAsB,cAAA,CACpB,UACA,OAAA,EAC0B;AAG1B,EAAA,MAAM,MAAA,GAAS,cAAc,oBAAA,CAAqB,QAAA,EAAU,EAAE,OAAA,EAAS,QAAA,EAAU,CAAC,CAAA;AAClF,EAAA,MAAM,KAAA,GACJ,OAAA,CAAQ,KAAA,IACP,MAAM,eAAA,CAAgB,EAAE,MAAA,EAAQ,QAAA,EAAU,OAAA,CAAQ,QAAA,EAAU,CAAA;AAK/D,EAAA,MAAM,WAAA,GAAc,MAAM,MAAA,CAAO,CAAC,MAAM,YAAA,CAAa,MAAA,EAAQ,CAAC,CAAC,CAAA;AAE/D,EAAA,MAAM,UAAmD,EAAC;AAC1D,EAAA,MAAM,QAAA,GAAW,MAAM,YAAA,CAAa,WAAA,EAAa,QAAQ,WAAA,IAAe,CAAA,EAAG,OAAO,IAAA,KAAS;AACzF,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI;AACF,MAAA,MAAA,GAAS,MAAM,YAAY,QAAA,EAAU;AAAA,QACnC,GAAG,OAAA;AAAA,QACH,IAAA;AAAA,QACA,MAAA,EAAQA,oBAAoB,IAAI;AAAA,OACjC,CAAA;AAAA,IACH,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,KAAK,EAAE,IAAA,EAAM,QAAQ,YAAA,CAAa,KAAK,GAAG,CAAA;AAClD,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,MAAM,IAAA,GAAsB;AAAA,MAC1B,IAAA;AAAA,MACA,MAAM,MAAA,CAAO,IAAA;AAAA,MACb,UAAA,EAAY,cAAc,IAAI,CAAA;AAAA,MAC9B,OAAO,MAAA,CAAO,KAAA;AAAA,MACd,OAAO,MAAA,CAAO,KAAA;AAAA,MACd,IAAI,MAAA,CAAO;AAAA,KACb;AACA,IAAA,IAAI,CAAC,OAAO,KAAA,EAAO;AAGjB,MAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,IAAA,EAAM,MAAA,EAAQ,+BAA+B,CAAA;AAC5D,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAA,CAAQ,SAAS,IAAI,CAAA;AACrB,IAAA,OAAO,IAAA;AAAA,EACT,CAAC,CAAA;AAED,EAAA,MAAM,QAAQ,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAA0B,MAAM,IAAI,CAAA;AACnE,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,OAAA;AAAA,IACA,UAAA,EAAY,eAAA,CAAgB,OAAA,CAAQ,MAAA,EAAQ,KAAA,CAAM,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAI,CAAC,CAAA;AAAA,IACpE,SAAA,EAAW,cAAA,CAAe,OAAA,CAAQ,MAAM;AAAA,GAC1C;AACF;AAGO,IAAM,qBAAA,GAAwB","file":"render.js","sourcesContent":["import React from 'react'\nimport { renderToStaticMarkup } from 'react-dom/server'\nimport { buildSeoTags, setBlockEditorMode, setBlockErrorVisibility, staticRouterAdapter } from '@fayz-ai/core'\nimport { serializePageData } from '../app/hydration'\nimport type { RouterAdapter } from '@fayz-ai/core'\nimport type { BlockNode } from '@fayz-ai/core'\nimport { createMockShopProvider } from '@fayz-ai/shop/mock'\nimport { getShopProvider, setShopProvider } from '@fayz-ai/shop/runtime'\nimport type { ShopProvider } from '@fayz-ai/shop/provider'\nimport { registerStorefrontBlocks } from '../blocks/registry'\nimport { StorefrontConfigProvider, resolveConfig } from './config'\nimport type { StorefrontConfig } from './config'\nimport {\n StorefrontShell,\n registerStorefrontEntities,\n resolveStorefrontProvider,\n} from '../app/createStorefrontApp'\nimport { resetPageDiagnostics } from '../views/StorefrontPage'\nimport { resolvePageData } from '../blocks/page-data'\nimport type { PageDataEntry, PageDataNeed } from '../blocks/page-data'\nimport { withStaticRenderPass } from '../app/static-render'\nimport type { StaticHeadInput, StaticRenderPass } from '../app/static-render'\nimport { hydrateStoreDocument } from './round-trip'\nimport type { StoreDocument } from './sections'\nimport { themeToCss } from '../lib/theme'\nimport { validateStore } from './validate'\nimport type { StoreValidationReport } from './validate'\n\n// ---------------------------------------------------------------------------\n// renderStore — the third ability, and the one M8 exists for (spine §5).\n//\n// The bet the whole spine rests on is that an AI can author a store. An author\n// that cannot SEE what it authored is guessing: it can be told the document is\n// valid (validateStore) and what the vocabulary is (describeStore) and still\n// place a hero above a header, leave a rail empty because its loader returned\n// nothing, or ship a page whose only content is an error card. This closes\n// that loop without a human driving a browser.\n//\n// Three decisions worth stating, because each has a cheaper wrong version:\n//\n// 1. It renders the REAL shell, driven by path. Not a server-side\n// reimplementation of routing and page composition — that would be a\n// second mechanism silently drifting from the first, which is the exact\n// failure §4 lists for WooCommerce's template overrides (\"227 @version\n// headers, the loader never reads one\"). The components report what they\n// need through the static-render pass; nothing here knows the route table.\n//\n// 2. Data is resolved BETWEEN passes, not faked. `PageDataScope` publishes\n// the needs it would fetch, `resolvePageData` answers them through the\n// ShopProvider port (I11 — no backend is named here), and the next pass\n// renders with the answers seeded. So a rail that is empty in the output\n// is empty in the shopper's browser too, and the report says which loader\n// returned what.\n//\n// 3. The return value is a REPORT, not a string. HTML alone makes an agent\n// parse markup to answer \"did my change land\". `text`, `outline`,\n// `blocks`, `data` and `diagnostics` answer it directly, and\n// `diagnostics` is where the M2 error-isolation machinery (crashed block,\n// unknown block, misplaced block, forced-layout repair) finally becomes\n// readable by the thing that caused it.\n// ---------------------------------------------------------------------------\n\nexport interface StoreRenderDataEntry {\n /** Canonical `dataNeedKey` — the same key the browser would dedupe on. */\n key: string\n loader: string\n params: Record<string, unknown>\n status: 'ready' | 'error' | 'unresolved'\n /** Item count for an array result, so \"the rail is empty\" is one field. */\n count?: number\n error?: string\n}\n\nexport interface StoreRenderDiagnostic {\n level: 'error' | 'warn'\n /** Where it came from: 'blocks' (core), 'storefront', or 'render'. */\n source: string\n message: string\n}\n\nexport interface StoreRenderHeading {\n level: number\n text: string\n}\n\nexport interface StoreRenderBlock {\n type: string\n id?: string\n /** Ancestor block types, outermost first — empty for a top-level block. */\n within?: string[]\n}\n\nexport interface RenderStoreOptions {\n /** Route to render, in the storefront's own path space ('/', '/catalog',\n * '/product/anel-de-ouro', '/biography'). Default '/'. */\n path?: string\n /**\n * Where catalog data comes from.\n *\n * - `'config'` (default): the provider the config implies — its explicit\n * provider, or a mock seeded from its catalog. What the shopper sees.\n * - `'document'`: a mock seeded from the document's own `catalog` section.\n * Deterministic and network-free, which is what you want while iterating\n * on a document whose store is backed by a live database.\n * - a `ShopProvider`: bring your own.\n */\n provider?: ShopProvider | 'config' | 'document'\n /**\n * 'report' (default) renders an invalid document anyway and returns the\n * findings — an agent fixing a broken store needs to see the broken store.\n * 'throw' refuses, for a caller using this as a gate.\n */\n onError?: 'throw' | 'report'\n /** 'document' (default) wraps the markup in a full HTML document with the\n * theme CSS and the route's title; 'fragment' returns the shell markup. */\n html?: 'document' | 'fragment'\n /**\n * How many render/resolve rounds to run. One page's data can reveal the\n * next need (a route param feeding a rail), so the loop repeats until no new\n * need appears. Reaching the cap is reported as a diagnostic rather than\n * silently truncating the page. Default 4.\n */\n maxPasses?: number\n /** Stylesheet URLs to link from the emitted document — how a preview server\n * hands in the app's real (Tailwind) CSS. */\n stylesheets?: readonly string[]\n /** Extra markup for the emitted `<head>`. */\n head?: string\n /**\n * How the rendered store is ADDRESSED when served.\n *\n * Defaults to hash, matching how storefronts ship today, so a headless render\n * describes links that actually resolve. Pass `historyRouterAdapter()` (or any\n * adapter) for a store served at real URLs — that is what makes each page\n * come out with a crawlable href of its own, which is the difference between\n * prerendered HTML that can be indexed and prerendered HTML that cannot.\n */\n router?: RouterAdapter\n /**\n * Absolute origin, e.g. 'https://loja.example.com'. Required for canonical\n * and OpenGraph URLs — without it they are omitted rather than emitted\n * relative, because a relative canonical is ignored.\n */\n origin?: string\n /** `<html lang>`. Defaults to the document's locale, then 'pt-BR'. */\n lang?: string\n /**\n * Stamp every block with its document path (`data-fayz-block`).\n *\n * Off by default, because a shopper's page must not carry it. On, the emitted\n * HTML says which document node produced which part of the page — which lets\n * an editor resolve a click to a path, and lets a test assert the identity\n * seam without a browser.\n */\n editor?: boolean\n}\n\nexport interface StoreRenderResult {\n /** True when the document validates, the path resolved, and nothing on the\n * page reported an error. The one field a gate should read. */\n ok: boolean\n path: string\n /** The title this route declared through `useStorefrontHead`. */\n title: string\n description?: string\n /** The path resolved to a real page (false = the 404 page rendered). */\n found: boolean\n html: string\n /** Visible text, tags stripped and whitespace collapsed — what a reader sees. */\n text: string\n /** h1–h6 in document order: the page's shape in one glance. */\n outline: StoreRenderHeading[]\n /** Every block that rendered, in order, including forced-layout repairs. */\n blocks: StoreRenderBlock[]\n /** Outbound hrefs, deduped — how an agent checks its nav actually links. */\n links: string[]\n images: number\n data: StoreRenderDataEntry[]\n diagnostics: StoreRenderDiagnostic[]\n validation: StoreValidationReport\n /** Render/resolve rounds actually run. */\n passes: number\n bytes: number\n}\n\n// --- HTML reading -------------------------------------------------------------\n\nconst VOID_TEXT_TAGS = /<(script|style)\\b[^>]*>[\\s\\S]*?<\\/\\1>/gi\n\nconst ENTITIES: Record<string, string> = {\n amp: '&',\n lt: '<',\n gt: '>',\n quot: '\"',\n apos: \"'\",\n nbsp: ' ',\n '#39': \"'\",\n '#x27': \"'\",\n '#x2F': '/',\n}\n\nfunction decodeEntities(text: string): string {\n return text.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z]+);/g, (match, name: string) => {\n const direct = ENTITIES[name]\n if (direct !== undefined) return direct\n if (name.startsWith('#x') || name.startsWith('#X')) {\n return String.fromCodePoint(Number.parseInt(name.slice(2), 16))\n }\n if (name.startsWith('#')) return String.fromCodePoint(Number(name.slice(1)))\n return match\n })\n}\n\n/** Visible text of a markup string. Regex rather than a DOM because the\n * workspace has no jsdom and the question — \"what words are on this page\" —\n * does not need one. */\nexport function htmlToText(html: string): string {\n return decodeEntities(html.replace(VOID_TEXT_TAGS, ' ').replace(/<[^>]*>/g, ' '))\n .replace(/\\s+/g, ' ')\n .trim()\n}\n\nfunction readOutline(html: string): StoreRenderHeading[] {\n const found: StoreRenderHeading[] = []\n const pattern = /<h([1-6])\\b[^>]*>([\\s\\S]*?)<\\/h\\1>/gi\n let match: RegExpExecArray | null\n while ((match = pattern.exec(html)) !== null) {\n const text = htmlToText(match[2] ?? '')\n if (text) found.push({ level: Number(match[1]), text })\n }\n return found\n}\n\nfunction readLinks(html: string): string[] {\n const found = new Set<string>()\n const pattern = /<a\\b[^>]*\\bhref=\"([^\"]*)\"/gi\n let match: RegExpExecArray | null\n while ((match = pattern.exec(html)) !== null) {\n const href = decodeEntities(match[1] ?? '')\n if (href) found.add(href)\n }\n return [...found]\n}\n\nfunction escapeHtml(text: string): string {\n return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;')\n}\n\n// --- Block inventory ----------------------------------------------------------\n\nfunction flattenBlocks(nodes: readonly BlockNode[], within: string[], out: StoreRenderBlock[]): void {\n for (const node of nodes) {\n out.push({ type: node.type, ...(node.id ? { id: node.id } : {}), ...(within.length ? { within: [...within] } : {}) })\n if (node.children?.length) flattenBlocks(node.children, [...within, node.type], out)\n }\n}\n\n// --- Console capture ----------------------------------------------------------\n\n/**\n * Run a synchronous render with console.error/warn captured.\n *\n * Everything the M2/M3 machinery reports about a broken page — a crashed\n * block, an unknown block type, a misplaced block, a forced-layout repair, a\n * page-body omission — is already logged, deliberately, and in production too.\n * Capturing it is what turns \"the console would have told a developer\" into a\n * field the agent that authored the page can read.\n */\nfunction captureConsole<T>(sink: StoreRenderDiagnostic[], render: () => T): T {\n const originalError = console.error\n const originalWarn = console.warn\n const record = (level: 'error' | 'warn') => (...args: unknown[]) => {\n const message = args\n .map((arg) => (arg instanceof Error ? arg.message : typeof arg === 'string' ? arg : safeStringify(arg)))\n .join(' ')\n .trim()\n if (!message) return\n const source = message.startsWith('[blocks]') ? 'blocks' : message.startsWith('[storefront]') ? 'storefront' : 'render'\n sink.push({ level, source, message })\n }\n console.error = record('error')\n console.warn = record('warn')\n try {\n return render()\n } finally {\n console.error = originalError\n console.warn = originalWarn\n }\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value) ?? String(value)\n } catch {\n return String(value)\n }\n}\n\n// --- The renderer -------------------------------------------------------------\n\nfunction providerFor(\n option: RenderStoreOptions['provider'],\n config: StorefrontConfig,\n doc: Record<string, unknown>,\n): ShopProvider {\n if (option && typeof option === 'object') return option\n if (option === 'document') {\n const catalog = doc.catalog as Record<string, unknown> | undefined\n const promotions = (doc.promotions as Record<string, unknown> | undefined)?.promotions\n const { version: _version, ...seed } = catalog ?? {}\n return createMockShopProvider({\n ...seed,\n ...(Array.isArray(promotions) ? { promotions } : {}),\n } as Parameters<typeof createMockShopProvider>[0])\n }\n return resolveStorefrontProvider(config)\n}\n\n/**\n * Render a Store Document to HTML, headless, plus everything an agent needs to\n * understand the result.\n *\n * const result = await renderStore(doc, { path: '/biography' })\n * result.ok // did anything on the page go wrong\n * result.outline // [{ level: 1, text: 'Biography' }, …]\n * result.data // [{ loader: 'products.list', status: 'ready', count: 12 }]\n * result.diagnostics\n */\nexport async function renderStore(\n input: StoreDocument | Record<string, unknown>,\n options: RenderStoreOptions = {},\n): Promise<StoreRenderResult> {\n const path = options.path ?? '/'\n const maxPasses = Math.max(1, options.maxPasses ?? 4)\n const doc = input as Record<string, unknown>\n\n const validation = validateStore(input)\n if (!validation.ok && (options.onError ?? 'report') === 'throw') {\n throw new Error(\n `renderStore: the document failed validation:\\n${validation.errors\n .map((e) => ` - ${e.path || '(document)'}: ${e.message}${e.valid ? ` (valid: ${e.valid.join(', ')})` : ''}`)\n .join('\\n')}`,\n )\n }\n\n const diagnostics: StoreRenderDiagnostic[] = []\n\n // Hydration reports rather than throws: a document with one unresolvable\n // handle should still render the other 95% of the page, which is the whole\n // point of looking at it (I7). Its validation echo is dropped — `validation`\n // already carries it, structured — but a dropped code handle is kept, because\n // nothing else reports that.\n const hydrationLog: StoreRenderDiagnostic[] = []\n const config = captureConsole(hydrationLog, () => hydrateStoreDocument(input, { onError: 'report' }))\n diagnostics.push(...hydrationLog.filter((d) => !d.message.includes('Store document failed validation')))\n // Images at their settled frame. The reveal is a client entrance — a static\n // render has no load event to wait for, and `SmoothImage` no longer applies\n // the from-state on the server anyway; turning the mode off here keeps the\n // emitted HTML free of a transition nothing will ever run.\n const resolved = resolveConfig({ ...config, imageLoading: { ...config.imageLoading, mode: 'none' } })\n\n registerStorefrontBlocks()\n registerStorefrontEntities(config)\n\n const previousProvider = getShopProvider()\n setShopProvider(providerFor(options.provider, config, doc))\n // A preview is for the author, so a block that failed shows its error card\n // instead of vanishing — the shopper-facing 'silent' rule would hide exactly\n // what the loop exists to surface.\n setBlockErrorVisibility('visible')\n // Opt-in, and restored in the same `finally` as the provider — a render that\n // stamped and then threw must not leave the flag on for the next caller,\n // which in a preview server is the next request.\n if (options.editor) setBlockEditorMode(true)\n\n // Bound to the path being rendered, in the scheme the store is served under.\n // One adapter for the whole render: it is stateless here, and rebuilding it\n // per pass would only churn.\n const renderRouter = options.router\n ? staticRouterAdapter(path, { href: (to) => options.router!.href(to) })\n : staticRouterAdapter(path, { href: (to) => `#${to.startsWith('/') ? to : `/${to}`}` })\n\n const entries: Record<string, PageDataEntry> = {}\n let html = ''\n let passes = 0\n let head: StaticHeadInput = {}\n let blocks: StoreRenderBlock[] = []\n /** Needs the returned HTML still shows as loading — non-empty only when the\n * pass cap was reached, and reported rather than hidden. */\n let stale: PageDataNeed[] = []\n\n try {\n for (let round = 0; round < maxPasses; round++) {\n passes = round + 1\n const seenNeeds = new Map<string, PageDataNeed>()\n const trees: BlockNode[][] = []\n const heads: StaticHeadInput[] = []\n\n const pass: StaticRenderPass = {\n tree: (nodes) => void trees.push([...nodes]),\n needs: (needs) => {\n for (const need of needs) if (!seenNeeds.has(need.key)) seenNeeds.set(need.key, need)\n },\n head: (input_) => void heads.push(input_),\n entries,\n origin: options.origin,\n }\n\n // Reset PER PASS, not once. Page diagnostics are memoised per tree so a\n // shopper's console is not spammed by a re-render — but only the final\n // pass's console describes the page being returned, so without this a\n // multi-pass render would report a broken block on the pass whose output\n // was thrown away and stay silent on the one that was kept.\n resetPageDiagnostics()\n const roundDiagnostics: StoreRenderDiagnostic[] = []\n html = captureConsole(roundDiagnostics, () =>\n withStaticRenderPass(pass, () =>\n renderToStaticMarkup(\n <StorefrontConfigProvider value={resolved}>\n <StorefrontShell path={path} router={renderRouter} />\n </StorefrontConfigProvider>,\n ),\n ),\n )\n\n blocks = []\n for (const tree of trees) flattenBlocks(tree, [], blocks)\n // The LAST head declaration wins, matching the effect order a browser\n // would run: the route's own page declares after the chrome around it.\n head = heads.reduce<StaticHeadInput>(\n (acc, entry) => ({\n title: entry.title ?? acc.title,\n description: entry.description ?? acc.description,\n canonical: entry.canonical ?? acc.canonical,\n image: entry.image ?? acc.image,\n type: entry.type ?? acc.type,\n // Concatenated, not overwritten: a product page declares its Product\n // object and the chrome around it its BreadcrumbList, and a page is\n // allowed to carry both.\n jsonLd: [...(acc.jsonLd ?? []), ...(entry.jsonLd ?? [])],\n }),\n {},\n )\n\n const pending = [...seenNeeds.values()].filter((need) => !(need.key in entries))\n if (pending.length === 0) {\n // Only the final round's console output describes the page actually\n // being returned; earlier rounds are the same page with loading states,\n // and their diagnostics would double every message.\n diagnostics.push(...roundDiagnostics)\n break\n }\n if (round === maxPasses - 1) {\n // Resolving now would put answers in `entries` that this HTML does not\n // show. Report the gap instead of pretending the page is complete.\n stale = pending\n diagnostics.push(...roundDiagnostics)\n diagnostics.push({\n level: 'warn',\n source: 'render',\n message: `render stopped after ${maxPasses} passes with ${pending.length} data need(s) still loading — raise maxPasses if a page legitimately chains this deep`,\n })\n break\n }\n Object.assign(entries, await resolvePageData(pending))\n }\n } finally {\n setShopProvider(previousProvider)\n setBlockErrorVisibility(null)\n if (options.editor) setBlockEditorMode(false)\n }\n\n const data: StoreRenderDataEntry[] = Object.entries(entries).map(([key, entry]) => {\n const [loader, params] = splitNeedKey(key)\n return {\n key,\n loader,\n params,\n status: entry.status === 'ready' ? ('ready' as const) : ('error' as const),\n ...(Array.isArray(entry.data) ? { count: entry.data.length } : {}),\n ...(entry.error ? { error: entry.error } : {}),\n }\n })\n for (const need of stale) {\n data.push({ key: need.key, loader: need.loader, params: need.params, status: 'unresolved' })\n }\n\n const found = !html.includes('data-storefront-page=\"not-found\"')\n const title = head.title ?? resolved.name\n const text = htmlToText(html)\n const outline = readOutline(html)\n\n const body =\n (options.html ?? 'document') === 'fragment'\n ? html\n : wrapDocument(html + serializePageData({ entries, path }), {\n title,\n description: head.description ?? undefined,\n seo: { canonical: head.canonical, image: head.image, type: head.type, jsonLd: head.jsonLd },\n siteName: resolved.name,\n lang: options.lang ?? config.locale ?? 'pt-BR',\n themeCss: resolved.theme ? themeToCss(resolved.theme) : '',\n stylesheets: options.stylesheets ?? [],\n head: options.head ?? '',\n })\n\n return {\n ok:\n validation.ok &&\n found &&\n !diagnostics.some((d) => d.level === 'error') &&\n !data.some((d) => d.status !== 'ready'),\n path,\n title,\n ...(head.description ? { description: head.description } : {}),\n found,\n html: body,\n text,\n outline,\n blocks,\n links: readLinks(html),\n images: (html.match(/<img\\b/gi) ?? []).length,\n data,\n diagnostics,\n validation,\n passes,\n bytes: new TextEncoder().encode(body).length,\n }\n}\n\n/** `dataNeedKey` is `<loader> <canonical-json>`; recover both halves. */\nfunction splitNeedKey(key: string): [string, Record<string, unknown>] {\n const space = key.indexOf(' ')\n if (space === -1) return [key, {}]\n try {\n return [key.slice(0, space), JSON.parse(key.slice(space + 1)) as Record<string, unknown>]\n } catch {\n return [key.slice(0, space), {}]\n }\n}\n\ninterface WrapOptions {\n title: string\n description?: string\n lang: string\n themeCss: string\n stylesheets: readonly string[]\n head: string\n /** Canonical / OpenGraph / JSON-LD declared by the route being rendered. */\n seo?: Pick<StaticHeadInput, 'canonical' | 'image' | 'type' | 'jsonLd'>\n siteName?: string\n}\n\n/**\n * The HTML document around the shell markup.\n *\n * Deliberately minimal and self-contained: the theme's CSS variables ride\n * inline (they are already data — M2's brand tokens), and any real stylesheet\n * is LINKED rather than inlined, because the only thing that can produce the\n * app's utility CSS is the app's own build. A caller with no stylesheet gets\n * honest unstyled markup instead of a page that pretends to be styled.\n */\nexport function wrapDocument(markup: string, options: WrapOptions): string {\n const links = options.stylesheets.map((href) => `<link rel=\"stylesheet\" href=\"${escapeHtml(href)}\">`).join('')\n const themeStyle = options.themeCss ? `<style>${options.themeCss}</style>` : ''\n\n // Tag computation lives in core's `buildSeoTags`, shared with the client-side\n // `applySeo`, so a page's head is identical whichever side wrote it.\n const tags = buildSeoTags({\n title: options.title,\n description: options.description,\n canonical: options.seo?.canonical,\n image: options.seo?.image,\n type: options.seo?.type,\n siteName: options.siteName,\n jsonLd: options.seo?.jsonLd,\n })\n const meta = tags.meta\n .map((t) =>\n t.name\n ? `<meta name=\"${escapeHtml(t.name)}\" content=\"${escapeHtml(t.content)}\">`\n : `<meta property=\"${escapeHtml(t.property ?? '')}\" content=\"${escapeHtml(t.content)}\">`,\n )\n .join('')\n const seoLinks = tags.links\n .map((l) => `<link rel=\"${escapeHtml(l.rel)}\" href=\"${escapeHtml(l.href)}\">`)\n .join('')\n // JSON-LD is script content, not an attribute: `<` is escaped so a product\n // name containing markup cannot close the script tag early.\n const jsonLd = tags.jsonLd\n .map(\n (obj) =>\n `<script type=\"application/ld+json\">${JSON.stringify(obj).replace(/</g, '\\\\u003c')}</script>`,\n )\n .join('')\n\n return (\n `<!doctype html><html lang=\"${escapeHtml(options.lang)}\"><head><meta charset=\"utf-8\">` +\n `<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">` +\n `<title>${escapeHtml(tags.title)}</title>${meta}${seoLinks}${links}${themeStyle}${jsonLd}${options.head}` +\n `</head><body>${markup}</body></html>`\n )\n}\n","import { errorMessage } from '@fayz-ai/core'\nimport { historyRouterAdapter, staticRouterAdapter } from '@fayz-ai/core'\nimport type { ShopProvider } from '@fayz-ai/shop/provider'\nimport { renderStore } from '../document/render'\nimport type { RenderStoreOptions, StoreRenderResult } from '../document/render'\nimport { storefrontPaths, isPublicPath } from './serving'\nimport { resolveConfig } from '../document/config'\nimport { hydrateStoreDocument } from '../document/round-trip'\nimport type { StoreDocument } from '../document/sections'\n\n// ---------------------------------------------------------------------------\n// Every page of a store, rendered.\n//\n// `storefrontPaths` says which URLs exist and `renderStore` renders one; this\n// is the loop between them, plus the two files a crawler looks for before it\n// looks at any page. Kept here rather than in each host because the ordering\n// rules are not obvious: only public paths may be written (a prerendered\n// /checkout is one shopper's cart served to everyone), a page that rendered\n// not-found must not be written at all (it would be indexed as real content),\n// and concurrency has to be bounded or a 400-product catalogue opens 400\n// provider connections at once.\n// ---------------------------------------------------------------------------\n\nexport interface PrerenderPage {\n path: string\n html: string\n /** Where a file-writing host should put it: `/product/x` → `product/x/index.html`. */\n outputPath: string\n title: string\n /** False when the path rendered the not-found page — excluded from `pages`. */\n found: boolean\n ok: boolean\n}\n\nexport interface PrerenderResult {\n pages: PrerenderPage[]\n /** Paths that rendered not-found or errored, with the reason. */\n skipped: Array<{ path: string; reason: string }>\n sitemapXml: string\n robotsTxt: string\n}\n\nexport interface PrerenderOptions\n extends Omit<RenderStoreOptions, 'path' | 'router' | 'html'> {\n provider: ShopProvider\n /** Absolute origin. Required for a sitemap — its URLs must be absolute. */\n origin: string\n /** Defaults to every public path the store has. */\n paths?: readonly string[]\n /** Bounded so a large catalogue does not open one connection per product. */\n concurrency?: number\n /** Reported per page, so a long run is observable rather than silent. */\n onPage?: (page: PrerenderPage) => void\n}\n\n/** `/` → `index.html`; `/product/x` → `product/x/index.html`. */\nexport function outputPathFor(path: string): string {\n const clean = (path.split('?')[0] ?? '/').replace(/^\\/+|\\/+$/g, '')\n return clean === '' ? 'index.html' : `${clean}/index.html`\n}\n\nfunction xmlEscape(value: string): string {\n return value\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n}\n\nexport function buildSitemapXml(origin: string, paths: readonly string[]): string {\n const base = origin.replace(/\\/$/, '')\n const urls = paths\n .map((p) => ` <url><loc>${xmlEscape(`${base}${p}`)}</loc></url>`)\n .join('\\n')\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\\n${urls}\\n</urlset>\\n`\n}\n\n/**\n * Disallows the per-shopper routes explicitly.\n *\n * They are not linked from anywhere crawlable, but a crawler that finds one\n * anyway would index a checkout — and crawl budget spent there is budget not\n * spent on products.\n */\nexport function buildRobotsTxt(origin: string): string {\n const base = origin.replace(/\\/$/, '')\n return [\n 'User-agent: *',\n 'Allow: /',\n 'Disallow: /checkout',\n 'Disallow: /account',\n 'Disallow: /order/',\n '',\n `Sitemap: ${base}/sitemap.xml`,\n '',\n ].join('\\n')\n}\n\nasync function mapWithLimit<T, R>(\n items: readonly T[],\n limit: number,\n fn: (item: T) => Promise<R>,\n): Promise<R[]> {\n const results = new Array<R>(items.length)\n let next = 0\n const workers = Array.from({ length: Math.min(limit, items.length) }, async () => {\n for (;;) {\n const i = next++\n if (i >= items.length) return\n results[i] = await fn(items[i]!)\n }\n })\n await Promise.all(workers)\n return results\n}\n\n/**\n * Render every public page of a store.\n *\n * The router is fixed to real-URL addressing: prerendering a hash-addressed\n * store would write files no URL can reach, which is the whole reason the\n * addressing seam exists.\n */\nexport async function prerenderStore(\n document: StoreDocument | Record<string, unknown>,\n options: PrerenderOptions,\n): Promise<PrerenderResult> {\n // Hydrated the same way renderStore does, so path enumeration and rendering\n // agree about what the store contains.\n const config = resolveConfig(hydrateStoreDocument(document, { onError: 'report' }))\n const paths =\n options.paths ??\n (await storefrontPaths({ config, provider: options.provider }))\n\n // Belt and braces: `storefrontPaths` already filters, but an explicit list\n // from a caller has not been through it, and a prerendered /checkout is one\n // shopper's cart served to everyone.\n const publicPaths = paths.filter((p) => isPublicPath(config, p))\n\n const skipped: Array<{ path: string; reason: string }> = []\n const rendered = await mapWithLimit(publicPaths, options.concurrency ?? 8, async (path) => {\n let result: StoreRenderResult\n try {\n result = await renderStore(document, {\n ...options,\n path,\n router: staticRouterAdapter(path),\n })\n } catch (error) {\n skipped.push({ path, reason: errorMessage(error) })\n return null\n }\n const page: PrerenderPage = {\n path,\n html: result.html,\n outputPath: outputPathFor(path),\n title: result.title,\n found: result.found,\n ok: result.ok,\n }\n if (!result.found) {\n // Writing it would publish a not-found page at a real URL, which is then\n // indexed as content. Reported rather than silently dropped.\n skipped.push({ path, reason: 'rendered the not-found page' })\n return null\n }\n options.onPage?.(page)\n return page\n })\n\n const pages = rendered.filter((p): p is PrerenderPage => p !== null)\n return {\n pages,\n skipped,\n sitemapXml: buildSitemapXml(options.origin, pages.map((p) => p.path)),\n robotsTxt: buildRobotsTxt(options.origin),\n }\n}\n\n/** The adapter a browser app should use to serve a prerendered store. */\nexport const prerenderClientRouter = historyRouterAdapter\n"]}
@@ -38,6 +38,14 @@ export interface CartLine {
38
38
  /** Em que embalagem da loja o lojista despacha este produto (0047). Do
39
39
  * PRODUTO, nunca da variante — a variante carrega medida, não caixa. */
40
40
  packageId?: string | null;
41
+ /**
42
+ * O que o comprador pediu NESTA linha — "sem cebola" (0094). Até 250
43
+ * caracteres, que é o que o banco aceita e o que a tela conta.
44
+ *
45
+ * Participa do `lineId`: ver addItem. Duas unidades do mesmo prato com
46
+ * pedidos diferentes são duas linhas, não uma de quantidade 2.
47
+ */
48
+ notes?: string;
41
49
  }
42
50
  export interface CartState {
43
51
  lines: CartLine[];
@@ -50,7 +58,20 @@ export interface CartState {
50
58
  isOpen: boolean;
51
59
  /** Line most recently added — lets the drawer briefly highlight it. */
52
60
  justAddedLineId: string | null;
53
- addItem(product: Product, qty?: number, options?: ProductOptionSelection): void;
61
+ /** `notes` (0094) é a observação da linha — participa da identidade dela. */
62
+ /**
63
+ * `openDrawer` decide se a gaveta abre sozinha. Default `true`, que é o
64
+ * comportamento de sempre: numa loja de catálogo você compra uma ou duas
65
+ * coisas e a gaveta deslizando é a confirmação.
66
+ *
67
+ * Num CARDÁPIO isso está errado. A pessoa monta uma cesta de oito itens, e
68
+ * abrir a gaveta a cada "+" interrompe a montagem oito vezes — cada uma
69
+ * exigindo um toque para voltar ao ponto da lista onde ela estava. Lá o
70
+ * cardápio passa `false` e avisa com um toast que oferece as duas saídas.
71
+ */
72
+ addItem(product: Product, qty?: number, options?: ProductOptionSelection, notes?: string, opts?: {
73
+ openDrawer?: boolean;
74
+ }): void;
54
75
  setQuantity(lineId: string, qty: number): void;
55
76
  removeItem(lineId: string): void;
56
77
  applyDiscount(code: string, percent: number, options?: {
@@ -1 +1 @@
1
- {"version":3,"file":"cart.store.d.ts","sourceRoot":"","sources":["../../src/stores/cart.store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cart.store.d.ts","sourceRoot":"","sources":["../../src/stores/cart.store.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { type PostalAddress } from '@fayz-ai/core';
2
- import type { ShippingQuoteOption } from '@fayz-ai/shop/types';
2
+ import type { FulfillmentType, ShippingQuoteOption } from '@fayz-ai/shop/types';
3
3
  /**
4
4
  * Where the shopper wants it delivered, decided before the cart exists.
5
5
  *
@@ -17,6 +17,35 @@ import type { ShippingQuoteOption } from '@fayz-ai/shop/types';
17
17
  * zones and ignores anything the client sends.
18
18
  */
19
19
  export type DeliveryStatus = 'idle' | 'loading' | 'served' | 'unserved' | 'error';
20
+ /**
21
+ * Um endereço que o comprador salvou NESTE navegador.
22
+ *
23
+ * Existe porque o caderno de endereços do `plugin-shop` é de quem tem conta, e
24
+ * num delivery a pessoa tem endereço antes de ter login — é a primeira coisa
25
+ * que ela informa e a última que quer digitar de novo. O CEP resolve rua,
26
+ * bairro e cidade; o que NENHUMA consulta de CEP sabe é o número, o
27
+ * complemento e "o portão azul ao lado da padaria". É exatamente isso que se
28
+ * perde a cada visita quando não se guarda nada.
29
+ *
30
+ * Fica no navegador e só nele. Não é conta, não sincroniza entre aparelhos e
31
+ * não vai para o servidor por conta própria — quem grava endereço no pedido é
32
+ * o checkout, com o que a pessoa confirmou na hora.
33
+ */
34
+ export interface SavedDeliveryAddress {
35
+ id: string;
36
+ /** "Casa", "Trabalho"… Opcional: a maioria salva um só e não nomeia nada. */
37
+ label: string | null;
38
+ postalCode: string;
39
+ street: string;
40
+ number: string;
41
+ complement: string | null;
42
+ /** O ponto de referência — "portão azul", "prédio ao lado do mercado". */
43
+ reference: string | null;
44
+ district: string;
45
+ city: string;
46
+ state: string;
47
+ createdAt: string;
48
+ }
20
49
  export interface DeliveryState {
21
50
  postalCode: string;
22
51
  address: PostalAddress | null;
@@ -47,12 +76,33 @@ export interface DeliveryState {
47
76
  resolve: (postalCode: string, subtotal: number) => Promise<void>;
48
77
  selectZone: (zoneId: string) => void;
49
78
  clear: () => void;
79
+ savedAddresses: SavedDeliveryAddress[];
80
+ selectedAddressId: string | null;
81
+ /** Grava e passa a ser o endereço corrente. Devolve o id gravado. */
82
+ saveAddress: (input: Omit<SavedDeliveryAddress, 'id' | 'createdAt'>) => string;
83
+ /** Escolhe um já gravado e recota o frete para ele. */
84
+ selectAddress: (id: string, subtotal: number) => Promise<void>;
85
+ removeAddress: (id: string) => void;
86
+ /**
87
+ * Mora AQUI e não numa store nova de propósito: esta já é a store do "para
88
+ * onde e como isso chega", já persiste o endereço e já é lida pelo checkout.
89
+ * Uma segunda store com a metade da resposta acabaria discordando desta na
90
+ * primeira tela que lesse só uma das duas.
91
+ */
92
+ fulfillmentType: FulfillmentType;
93
+ /** Início da janela escolhida (ISO). null = o quanto antes. */
94
+ scheduledFor: string | null;
95
+ setFulfillmentType: (type: FulfillmentType) => void;
96
+ setScheduledFor: (startsAt: string | null) => void;
50
97
  }
51
98
  export declare const useDeliveryStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<DeliveryState>, "persist"> & {
52
99
  persist: {
53
100
  setOptions: (options: Partial<import("zustand/middleware").PersistOptions<DeliveryState, {
54
101
  postalCode: string;
55
102
  address: PostalAddress | null;
103
+ fulfillmentType: FulfillmentType;
104
+ savedAddresses: SavedDeliveryAddress[];
105
+ selectedAddressId: string | null;
56
106
  }>>) => void;
57
107
  clearStorage: () => void;
58
108
  rehydrate: () => Promise<void> | void;
@@ -62,6 +112,9 @@ export declare const useDeliveryStore: import("zustand").UseBoundStore<Omit<impo
62
112
  getOptions: () => Partial<import("zustand/middleware").PersistOptions<DeliveryState, {
63
113
  postalCode: string;
64
114
  address: PostalAddress | null;
115
+ fulfillmentType: FulfillmentType;
116
+ savedAddresses: SavedDeliveryAddress[];
117
+ selectedAddressId: string | null;
65
118
  }>>;
66
119
  };
67
120
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"delivery.store.d.ts","sourceRoot":"","sources":["../../src/stores/delivery.store.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyC,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAEzF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAE9D;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAA;AAMjF,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,aAAa,GAAG,IAAI,CAAA;IAC7B,OAAO,EAAE,mBAAmB,EAAE,CAAA;IAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,MAAM,EAAE,cAAc,CAAA;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB;;;;;;;OAOG;IACH,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAE1B;;;;;;;;OAQG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAEzB,8EAA8E;IAC9E,OAAO,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAChE,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB;AAaD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;EAuH5B,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGvF;AAED,eAAO,MAAM,oBAAoB,GAC/B,OAAO,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,gBAAgB,GAAG,QAAQ,CAAC,EACnE,UAAU,MAAM,KACf,MAAM,GAAG,IAIX,CAAA"}
1
+ {"version":3,"file":"delivery.store.d.ts","sourceRoot":"","sources":["../../src/stores/delivery.store.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyC,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAEzF,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAE/E;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAA;AAEjF;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAA;IACV,6EAA6E;IAC7E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,0EAA0E;IAC1E,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;CAClB;AAMD,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,aAAa,GAAG,IAAI,CAAA;IAC7B,OAAO,EAAE,mBAAmB,EAAE,CAAA;IAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,MAAM,EAAE,cAAc,CAAA;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB;;;;;;;OAOG;IACH,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAE1B;;;;;;;;OAQG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAEzB,8EAA8E;IAC9E,OAAO,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAChE,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,KAAK,EAAE,MAAM,IAAI,CAAA;IAKjB,cAAc,EAAE,oBAAoB,EAAE,CAAA;IACtC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,qEAAqE;IACrE,WAAW,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,oBAAoB,EAAE,IAAI,GAAG,WAAW,CAAC,KAAK,MAAM,CAAA;IAC9E,uDAAuD;IACvD,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9D,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAKnC;;;;;OAKG;IACH,eAAe,EAAE,eAAe,CAAA;IAChC,+DAA+D;IAC/D,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,kBAAkB,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAA;IACnD,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;CACnD;AAwBD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;EAgM5B,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGvF;AAED,eAAO,MAAM,oBAAoB,GAC/B,OAAO,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,gBAAgB,GAAG,QAAQ,CAAC,EACnE,UAAU,MAAM,KACf,MAAM,GAAG,IAIX,CAAA"}
@@ -0,0 +1,35 @@
1
+ import type { FulfillmentType, ServiceStatus } from '@fayz-ai/shop/types';
2
+ /**
3
+ * A loja está aberta agora? (0094)
4
+ *
5
+ * NÃO é persistido, e essa é a decisão central deste arquivo. "Aberta" tem
6
+ * validade de minutos: um estado restaurado do localStorage abriria uma loja
7
+ * fechada só porque o comprador deixou a aba aberta desde ontem — e, pior,
8
+ * seria editável pelo devtools. É perguntado ao servidor e reperguntado quando
9
+ * a janela atual termina.
10
+ *
11
+ * Nada aqui autoriza um pedido. O que esta store pinta na tela é cortesia — o
12
+ * bloqueio de verdade é o trigger da 0094, no banco, que recusa o INSERT venha
13
+ * ele de onde vier. Se algum dia as duas discordarem, quem manda é o banco.
14
+ */
15
+ export type ServiceStoreStatus = 'idle' | 'loading' | 'ready';
16
+ export interface ServiceState {
17
+ status: ServiceStoreStatus;
18
+ /** null = ainda não perguntamos, ou a loja não implementa (base pré-0094). */
19
+ service: ServiceStatus | null;
20
+ fulfillmentType: FulfillmentType;
21
+ refresh: (fulfillmentType?: FulfillmentType) => Promise<void>;
22
+ }
23
+ /**
24
+ * A pergunta que a tela realmente faz.
25
+ *
26
+ * Uma loja que não declarou horário responde `configured: false`, e aqui isso
27
+ * lê como ABERTA — o comportamento anterior à 0094, e o único seguro para as
28
+ * outras vitrines do pool. `null` (provider sem o método, base sem a migration)
29
+ * é o mesmo caso e recebe a mesma resposta.
30
+ */
31
+ export declare function selectIsOpen(state: ServiceState): boolean;
32
+ /** Devemos desenhar selo de horário? Só quando a loja declarou um. */
33
+ export declare function selectShowsHours(state: ServiceState): boolean;
34
+ export declare const useServiceStore: import("zustand").UseBoundStore<import("zustand").StoreApi<ServiceState>>;
35
+ //# sourceMappingURL=service.store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.store.d.ts","sourceRoot":"","sources":["../../src/stores/service.store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEzE;;;;;;;;;;;;GAYG;AAEH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAA;AAE7D,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,kBAAkB,CAAA;IAC1B,8EAA8E;IAC9E,OAAO,EAAE,aAAa,GAAG,IAAI,CAAA;IAC7B,eAAe,EAAE,eAAe,CAAA;IAChC,OAAO,EAAE,CAAC,eAAe,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC9D;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAIzD;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAE7D;AAED,eAAO,MAAM,eAAe,2EAqBzB,CAAA"}
@@ -1,10 +1,23 @@
1
1
  export type ToastVariant = 'success' | 'error' | 'info';
2
+ /**
3
+ * Uma ação no aviso.
4
+ *
5
+ * Existe porque "adicionado ao carrinho" sem saída é uma notificação que
6
+ * informa e some: quem quer fechar o pedido agora tem de ir procurar o
7
+ * carrinho. Com ação, o aviso É o caminho — e continuar comprando é não fazer
8
+ * nada, que é o que a maioria vai fazer.
9
+ */
10
+ export interface ToastAction {
11
+ label: string;
12
+ onClick: () => void;
13
+ }
2
14
  export interface Toast {
3
15
  id: string;
4
16
  title: string;
5
17
  description?: string;
6
18
  variant: ToastVariant;
7
19
  durationMs: number;
20
+ action?: ToastAction;
8
21
  }
9
22
  interface ToastState {
10
23
  toasts: Toast[];
@@ -13,6 +26,7 @@ interface ToastState {
13
26
  description?: string;
14
27
  variant?: ToastVariant;
15
28
  durationMs?: number;
29
+ action?: ToastAction;
16
30
  }): string;
17
31
  dismiss(id: string): void;
18
32
  }
@@ -1 +1 @@
1
- {"version":3,"file":"toast.store.d.ts","sourceRoot":"","sources":["../../src/stores/toast.store.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAA;AAEvD,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,YAAY,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,UAAU,UAAU;IAClB,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,IAAI,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,YAAY,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAA;IACzG,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAID,eAAO,MAAM,aAAa,yEAevB,CAAA;AAEH,oFAAoF;AACpF,eAAO,MAAM,KAAK;qBACC,MAAM,gBAAgB,MAAM;mBAC9B,MAAM,gBAAgB,MAAM;kBAC7B,MAAM,gBAAgB,MAAM;CAC3C,CAAA"}
1
+ {"version":3,"file":"toast.store.d.ts","sourceRoot":"","sources":["../../src/stores/toast.store.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAA;AAEvD;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,YAAY,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,UAAU,UAAU;IAClB,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,IAAI,CAAC,KAAK,EAAE;QACV,KAAK,EAAE,MAAM,CAAA;QACb,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,OAAO,CAAC,EAAE,YAAY,CAAA;QACtB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,MAAM,CAAC,EAAE,WAAW,CAAA;KACrB,GAAG,MAAM,CAAA;IACV,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAID,eAAO,MAAM,aAAa,yEAgBvB,CAAA;AAEH,oFAAoF;AACpF,eAAO,MAAM,KAAK;qBACC,MAAM,gBAAgB,MAAM;mBAC9B,MAAM,gBAAgB,MAAM;kBAC7B,MAAM,gBAAgB,MAAM;CAC3C,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"CheckoutPage.d.ts","sourceRoot":"","sources":["../../src/views/CheckoutPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAmHlD,wBAAgB,YAAY,sBAkrC3B"}
1
+ {"version":3,"file":"CheckoutPage.d.ts","sourceRoot":"","sources":["../../src/views/CheckoutPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAuIlD,wBAAgB,YAAY,sBAw1C3B"}
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ /**
3
+ * O cardápio — a vitrine do modo delivery (0094).
4
+ *
5
+ * A ordem da página é a ordem das perguntas, e ela é fixa: quem é a loja e se
6
+ * está aberta (capa) → como isso chega e quanto custa (faixa de endereço) →
7
+ * onde está o que eu quero (busca + categorias) → o que tem (seções). É o
8
+ * esqueleto que os cinco produtos medidos compartilham
9
+ * (`docs/artorius/delivery-reference/patterns/`), e cada passo depende da
10
+ * resposta do anterior: descobrir a taxa de entrega depois de montar o
11
+ * carrinho é a pior hora possível para descobrir.
12
+ *
13
+ * Categorias como SEÇÕES numa página só, e não como um filtro que troca a
14
+ * página. Um cardápio se lê rolando: a pessoa quer ver que existe sobremesa
15
+ * sem ter decidido antes que quer sobremesa. Um filtro esconde exatamente essa
16
+ * descoberta, e é por isso que nenhum app de delivery usa um.
17
+ *
18
+ * A `/catalog` com grade e facetas continua existindo e não foi tocada. As duas
19
+ * respondem perguntas diferentes: o catálogo é para quem procura, o cardápio é
20
+ * para quem escolhe.
21
+ */
22
+ export declare function MenuPage(): React.JSX.Element;
23
+ //# sourceMappingURL=MenuPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MenuPage.d.ts","sourceRoot":"","sources":["../../src/views/MenuPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAuBzB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,QAAQ,sBAuUvB"}
@@ -1,4 +1,4 @@
1
- import type { Order, ShippingAddressInput, PaymentMethodKind } from '@fayz-ai/shop/types';
1
+ import type { Order, ShippingAddressInput, PaymentMethodKind, FulfillmentType } from '@fayz-ai/shop/types';
2
2
  import type { ResolvedStorefrontConfig } from '../document/config';
3
3
  import type { CartState } from '../stores/cart.store';
4
4
  import type { SessionState } from '../stores/session.store';
@@ -22,6 +22,19 @@ export interface PlaceStorefrontOrderInput {
22
22
  shippingAddress?: ShippingAddressInput;
23
23
  paymentMethod?: PaymentMethodKind;
24
24
  markPaid?: boolean;
25
+ /**
26
+ * Entrega ou retirada (0094). Ausente lê como entrega — que é o que todo
27
+ * checkout anterior a esta migration fazia.
28
+ *
29
+ * Na RETIRADA quem chama manda o endereço da PRÓPRIA LOJA em
30
+ * `shippingAddress`. Não é contorno: `shop_place_order` exige CEP quando a
31
+ * loja tem zonas, e essa checagem roda antes de qualquer trigger de linha —
32
+ * então o pedido precisa de um endereço válido, e o endereço válido de uma
33
+ * retirada é o balcão. O trigger reconhece o modo e zera o frete.
34
+ */
35
+ fulfillmentType?: FulfillmentType;
36
+ /** Início da janela agendada (ISO). O servidor recusa fora de janela real. */
37
+ scheduledFor?: string;
25
38
  }
26
39
  export interface PlaceStorefrontOrderResult {
27
40
  order: Order;
@@ -32,5 +45,5 @@ export interface PlaceStorefrontOrderResult {
32
45
  * It owns the order payload math and customer-session handshake so app-owned
33
46
  * routes can customize UX without copying provider/business logic.
34
47
  */
35
- export declare function placeStorefrontOrder({ config, cart, session, customer, address, shippingAddress, paymentMethod, markPaid, }: PlaceStorefrontOrderInput): Promise<PlaceStorefrontOrderResult>;
48
+ export declare function placeStorefrontOrder({ config, cart, session, customer, address, shippingAddress, fulfillmentType, scheduledFor, paymentMethod, markPaid, }: PlaceStorefrontOrderInput): Promise<PlaceStorefrontOrderResult>;
36
49
  //# sourceMappingURL=checkout.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"checkout.d.ts","sourceRoot":"","sources":["../../src/workflows/checkout.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAGzF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAA;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAErD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAI3D,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,wBAAwB,CAAA;IAChC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,GAAG,cAAc,GAAG,iBAAiB,CAAC,GAC/D,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC,CAAA;IACpD,OAAO,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,CAAA;IACpD,QAAQ,EAAE,0BAA0B,CAAA;IACpC,OAAO,CAAC,EAAE,yBAAyB,CAAA;IACnC,8EAA8E;IAC9E,eAAe,CAAC,EAAE,oBAAoB,CAAA;IACtC,aAAa,CAAC,EAAE,iBAAiB,CAAA;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,KAAK,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;CACnB;AAoCD;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,EACzC,MAAM,EACN,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,OAAO,EACP,eAAe,EACf,aAAa,EACb,QAAgB,GACjB,EAAE,yBAAyB,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAiGjE"}
1
+ {"version":3,"file":"checkout.d.ts","sourceRoot":"","sources":["../../src/workflows/checkout.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAG1G,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAA;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAErD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAI3D,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,wBAAwB,CAAA;IAChC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,GAAG,cAAc,GAAG,iBAAiB,CAAC,GAC/D,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC,CAAA;IACpD,OAAO,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,CAAA;IACpD,QAAQ,EAAE,0BAA0B,CAAA;IACpC,OAAO,CAAC,EAAE,yBAAyB,CAAA;IACnC,8EAA8E;IAC9E,eAAe,CAAC,EAAE,oBAAoB,CAAA;IACtC,aAAa,CAAC,EAAE,iBAAiB,CAAA;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,KAAK,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;CACnB;AAoCD;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,EACzC,MAAM,EACN,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,OAAO,EACP,eAAe,EACf,eAAe,EACf,YAAY,EACZ,aAAa,EACb,QAAgB,GACjB,EAAE,yBAAyB,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAyGjE"}