@snowcone-app/canvas 0.40.0 → 0.40.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"embed-BY6gMPTK.js","sources":["../src/components/embed-realtime/context.ts","../src/design/bundle-config.ts","../src/components/embed-realtime/validateEmbed.ts","../src/components/editor/placementLinks.ts","../src/components/editor/editorAudit.ts","../src/components/editor/EditorRoot.tsx","../src/components/editor/EditorCanvas.tsx","../src/components/editor/usePlacements.ts","../src/components/editor/EditorPlacements.tsx","../src/components/editor/PreviewPrismOverlay.tsx","../src/components/editor/EditorPreview.tsx","../src/components/editor/EditorTextField.tsx","../src/components/editor/EditorBuy.tsx","../src/components/editor/EditorControls.tsx","../src/components/editor/EditorLoadingOverlay.tsx","../src/components/editor/useProductSelection.ts","../src/components/editor/index.ts","../src/components/embed-realtime/RealtimeEmbed.tsx","../src/components/embed-realtime/RealtimeCanvas.tsx","../src/components/embed-realtime/RealtimeMockup.tsx","../src/components/embed-realtime/useRealtimeMockups.ts","../src/design/product-config.ts","../src/default-editor/SnowconeEditor.tsx","../src/api/embed.ts"],"sourcesContent":["'use client';\n\n/**\n * Shared context for the realtime embed primitives. `<RealtimeEmbed>` owns the\n * single {@link RenderSession} and the live mockup state; `<RealtimeCanvas>` and\n * `<RealtimeMockup>` read it from here so the editor and the preview can be laid\n * out freely yet can never desync (they share one session, one design, one\n * placement).\n */\n\nimport { createContext, useContext } from 'react';\nimport type { RenderSession, RenderProduct, RenderState, MockupResult } from '@snowcone-app/sdk';\nimport type { AnyDesign } from '../../design/design-builder.js';\nimport type { PieceGuidesConfig } from '../embed/SnowconeCanvas.js';\nimport type { DesignStateStore } from '../editor/designStateStore.js';\n\nexport interface EmbedContextValue {\n /** The single session the editor pushes renders to. `null` if the session\n * failed to construct (a config fail-fast, surfaced via `error`). Escape\n * hatch for advanced use. */\n session: RenderSession | null;\n /** The design the embed was seeded with — single source of truth for both the\n * canvas seed and the seed render. */\n design: AnyDesign;\n /** The ACTIVE placement name (= the design's currently-edited artboard).\n * The canvas follows it as its controlled artboard. Initially the design's\n * active artboard; moved by {@link selectPlacement} (ADR-0088). For a\n * single-placement design this never changes — the pre-0088 behavior. */\n placement: string;\n /** Every artboard name in the LIVE design state, in author order — the\n * first is the base (ADR-0101). A single-placement design has exactly one\n * entry (ADR-0088). Linked placements are NOT in here; see\n * `requiredPlacements` and `usePlacements()`. */\n placements: string[];\n /** Switch the active placement. Throws `EditorError E_UNKNOWN_PLACEMENT`\n * for a label that is neither a required placement nor a design artboard\n * (ADR-0088). Selecting a LINKED placement edits the base — the artboard\n * it renders (ADR-0101). Costs zero session work — renders already target\n * every artboard per placement. */\n selectPlacement: (label: string) => void;\n /** The product's required image placement labels, in product order\n * (`requiredPlacementLabels(product)`). Empty for a variant-axis product\n * without `requiredPlacements` — then `placements` is the whole story.\n * ADR-0101. */\n requiredPlacements: string[];\n /** ADR-0101 split: give `label` its own artboard, cloned from the base, and\n * make it active. No-op when already split. Throws `E_UNKNOWN_PLACEMENT`\n * for a label that is not a required placement. */\n splitPlacement: (label: string) => void;\n /** ADR-0101 link: drop `label`'s own artboard so it inherits the base\n * again. No-op when already linked. Throws `E_LINK_BASE` for the base. */\n linkPlacement: (label: string) => void;\n /** The product being rendered against. */\n product: RenderProduct;\n /** Latest mockups from the session. Reactive — updates re-render consumers. */\n mockups: MockupResult[];\n /** True between a render dispatch and the next mockup / error. */\n isRendering: boolean;\n /** Last render error message, or null. */\n error: string | null;\n /** Default edit→render throttle (ms). */\n throttleMs: number;\n /**\n * The product's printable-area guides (dead zones, safe areas) — fetched by\n * `<RealtimeEmbed>` and already gated on the design's artboard matching the\n * print-file frame they were authored in. `null` when the product has none,\n * the fetch failed, or the dims don't line up. `<RealtimeCanvas>` forwards\n * this to the editor so embedders get the same overlay snowcone.app shows.\n */\n pieceGuides: PieceGuidesConfig | null;\n /** Dispatch a server render for the embed's placement. Sets `isRendering`. */\n pushRender: (state: RenderState, throttleMs?: number) => void;\n /**\n * The ONE live design state under this Root (ADR-0085 §3 / T2): seeded from\n * `design`, updated by every canvas change and every `Editor.TextField`\n * write, last-write-wins. Commerce parts read THIS, never the seed. Stable\n * identity; subscribe for updates (`useSyncExternalStore`-shaped).\n *\n * Stable since ADR-0085 P4; additive-only from here.\n */\n stateStore: DesignStateStore;\n}\n\nexport const EmbedContext = createContext<EmbedContextValue | undefined>(undefined);\n\n/**\n * Read the embed context. Throws a clear error when called outside\n * `<RealtimeEmbed>` — the most common wiring mistake.\n */\nexport function useEmbedContext(): EmbedContextValue {\n const ctx = useContext(EmbedContext);\n if (!ctx) {\n throw new Error(\n 'useRealtimeMockups / <RealtimeCanvas> / <RealtimeMockup> must be rendered ' +\n 'inside <RealtimeEmbed>. Wrap them: ' +\n '<RealtimeEmbed shop=… product=… design=… grantUrl=…>…</RealtimeEmbed>'\n );\n }\n return ctx;\n}\n","/**\n * `bundleToRenderConfig` — the bundle counterpart of `productToRenderConfig`\n * (ADR-0099 slice 4, client half). A BUNDLE is a catalog product whose\n * payload carries a `bundle` block: several products photographed in one\n * mockup, each a SLOT (`role`) with one or more alternative products.\n *\n * A bundle is a DISTINCT shape, not a flag on the single-product config,\n * because every single-product assumption is wrong on it:\n *\n * - placements are role-scoped keys (`top.front`, `shorts.front`) — two\n * members both have a \"Front\", so the bare label is never the identity.\n * Artboard names, `renderState(placement)` and the server's\n * `requiredPlacements` all use the KEY.\n * - there is no single `variantId`: the variant is named per ROLE\n * (`variants: { top: 'oPz7RC', shorts: 'GNpkMR' }`); a bare `variantId`\n * on a bundle is refused by the server (`E_BUNDLE_ROLE_REQUIRED`).\n * - `picks` choose which alternative fills each slot (default: the slot's\n * first product). A pick change is a NEW config message — the server\n * re-validates it and re-derives the required placement set.\n *\n * Every wrong input throws a typed `EditorError` with the valid values in\n * `data.validNames` and the fix in the message — the server would refuse the\n * same input with the same code, but a mount-time throw beats a socket error\n * after connect. The single-product adapter refuses a bundle\n * (`E_BUNDLE_CONFIG_REQUIRED`) and this one refuses a single product\n * (`E_NOT_A_BUNDLE`), so neither path can ever silently render the wrong thing.\n */\n\nimport type { CatalogProduct, RenderProduct } from '@snowcone-app/sdk';\nimport { EditorError } from '../errors/editorError.js';\n\n/** The `bundle` block of a catalog product (ADR-0099). */\nexport type CatalogBundleBlock = NonNullable<CatalogProduct['bundle']>;\n/** One slot of a bundle. */\nexport type CatalogBundleMember = CatalogBundleBlock['members'][number];\n/** One alternative product of a slot. */\nexport type CatalogBundleAlternative = CatalogBundleMember['products'][number];\n\n/** A catalog product that IS a bundle — `bundle.members` is present and non-empty. */\nexport type CatalogBundleProduct = CatalogProduct & { bundle: CatalogBundleBlock };\n\n/** True when the catalog product carries a non-empty `bundle` block. */\nexport function isBundleProduct(product: CatalogProduct): product is CatalogBundleProduct {\n return Array.isArray(product.bundle?.members) && product.bundle.members.length > 0;\n}\n\nexport interface BundleRenderConfigOptions {\n /** Which alternative fills each slot, `role → member product code`.\n * Omitted roles take the slot's first alternative. Unknown roles throw\n * `E_BUNDLE_ROLE_NOT_FOUND`; a product outside the slot throws\n * `E_BUNDLE_PICK_NOT_FOUND` (both list the valid values). */\n picks?: Record<string, string>;\n /** The variant per slot, `role → gvid`. Omitted roles take the picked\n * alternative's `defaultGvid` (else its first variant). A gvid outside the\n * alternative's variant list throws `E_BUNDLE_VARIANT_NOT_FOUND`. */\n variants?: Record<string, string>;\n /** Role-scoped placement KEY to edit first (e.g. `\"top.front\"`). Defaults\n * to the first renderable placement of the picked alternatives. A bare\n * label (`\"Front\"`) throws `E_BUNDLE_ROLE_REQUIRED`; an unknown key throws\n * `E_PRODUCT_NOT_RENDERABLE` — both list the valid keys. */\n placement?: string;\n /** Render width passthrough (`product.width`). */\n width?: number;\n}\n\n/** Geometry of one role-scoped placement of the picked alternatives. */\nexport interface BundlePlacementConfig {\n /** The role-scoped wire key — the artboard NAME and the `renderState`\n * placement on a bundle (`\"top.front\"`). */\n key: string;\n role: string;\n /** The member's own placement label (`\"Front\"`) — display only, never an\n * identity on a bundle. */\n label: string;\n /** The member product this placement belongs to (the slot's pick). */\n memberProductId: string;\n width: number;\n height: number;\n aspectRatio: number;\n}\n\n/** One selectable variant of a slot's picked alternative. */\nexport interface BundleVariantChoice {\n gvid: string;\n /** Human label from the alternative's `options.combinations` row (e.g.\n * `\"Size M\"`); falls back to the gvid when the row is unknown. */\n label: string;\n}\n\n/** One slot of the bundle, resolved for the current picks + variants. */\nexport interface BundleRoleConfig {\n role: string;\n required: boolean;\n /** The alternatives' product codes, in catalog order (first = default). */\n alternatives: string[];\n /** The alternative currently filling the slot. */\n pick: string;\n /** The variant the slot renders (`variants[role]`). */\n variantId: string;\n /** Every variant the picked alternative accepts for `variants[role]`. */\n variantChoices: BundleVariantChoice[];\n /** The slot's renderable placements for the pick, in catalog order. */\n placements: BundlePlacementConfig[];\n}\n\nexport interface BundleRenderConfig {\n /** Discriminant — a bundle config is never confusable with a\n * `ProductRenderConfig`. */\n kind: 'bundle';\n /** Ready for `<Editor.Root product={…}>`: `picks` + `variants` set,\n * `variantId` absent, `placements` / `requiredPlacements` carry the\n * role-scoped KEYS (the placement names the server demands). */\n product: RenderProduct;\n /** The resolved pick per role — every role present. */\n picks: Record<string, string>;\n /** The resolved variant per role — every role present. */\n variants: Record<string, string>;\n /** `role:renderGvid,…` sorted by role — the bundle scene identity the\n * catalog publishes as a bundle mockup's `gvids` entry and the server keys\n * the composite on. */\n variantToken: string;\n /** Every slot, resolved. */\n roles: BundleRoleConfig[];\n /** The placement being edited first — seed `design({ name: key, width, height })`. */\n placement: BundlePlacementConfig;\n /** Every renderable placement of the picked alternatives, in catalog order. */\n placements: BundlePlacementConfig[];\n /** `placements.map(p => p.key)` — the artboard names / renderState placements. */\n placementKeys: string[];\n /** The bundle's roles in catalog order. */\n roleNames: string[];\n /** First scene that photographs the picked alternatives — the default\n * `<Editor.Preview mockupId>`. */\n primaryMockupId: string;\n}\n\nconst DOC = 'bundles';\n\n/** `role:renderGvid,…` sorted by role — deterministic, matches the box and the catalog. */\nexport function bundleVariantToken(variantByRole: Record<string, string>): string {\n return Object.keys(variantByRole)\n .sort()\n .map((role) => `${role}:${variantByRole[role]}`)\n .join(',');\n}\n\n/** Split a role-scoped key (`\"top.front\"`) into `{ role, key }`; `null` when it carries no role. */\nexport function splitRoleKey(name: string): { role: string; key: string } | null {\n const dot = name.indexOf('.');\n if (dot <= 0 || dot === name.length - 1) return null;\n return { role: name.slice(0, dot), key: name.slice(dot + 1) };\n}\n\ntype CatalogPlacement = NonNullable<CatalogProduct['placements']>[number];\n\nfunction isRenderablePlacement(p: CatalogPlacement): p is CatalogPlacement & { width: number; height: number } {\n return p.type !== 'color' && typeof p.width === 'number' && p.width > 0 && typeof p.height === 'number' && p.height > 0;\n}\n\nfunction variantLabel(alt: CatalogBundleAlternative, gvid: string): string {\n const row = alt.options?.combinations?.find((c) => c.variantId === gvid);\n if (!row) return gvid;\n const parts = Object.entries(row)\n .filter(([k, v]) => k !== 'variantId' && k !== 'price' && (typeof v === 'string' || typeof v === 'number'))\n .map(([k, v]) => `${k} ${String(v)}`);\n return parts.length > 0 ? parts.join(' · ') : gvid;\n}\n\n/**\n * Derive the full bundle embed wiring from one `getProduct()` payload.\n *\n * ```ts\n * const config = bundleToRenderConfig(await getProduct('V9NNNH'), { width: 2000 });\n * const seed = design({ name: config.placement.key, ...config.placement })\n * .image(artworkUrl, { anchor: 'center' }); // ONE artboard → broadcast to every member\n *\n * <Editor.Root shop={SHOP} product={config.product} design={seed} grantUrl=\"/api/realtime-grant\">\n *\n * // A pick or variant change is a NEW config: rebuild and pass the new product.\n * const next = bundleToRenderConfig(product, { picks: { top: 'TANKXA' }, variants: config.variants });\n * ```\n *\n * @throws EditorError `E_NOT_A_BUNDLE` — the product has no `bundle` block.\n * @throws EditorError `E_BUNDLE_ROLE_NOT_FOUND` — `picks` / `variants` name an unknown role.\n * @throws EditorError `E_BUNDLE_PICK_NOT_FOUND` — a pick is not one of the slot's alternatives.\n * @throws EditorError `E_BUNDLE_VARIANT_NOT_FOUND` — a variant is not one of the pick's gvids, or the pick has none.\n * @throws EditorError `E_BUNDLE_ROLE_REQUIRED` — `options.placement` is a bare label, not `<role>.<key>`.\n * @throws EditorError `E_PRODUCT_NOT_RENDERABLE` — no renderable placement / scene, or an unknown placement key.\n */\nexport function bundleToRenderConfig(\n catalogProduct: CatalogProduct,\n options: BundleRenderConfigOptions = {},\n): BundleRenderConfig {\n if (!isBundleProduct(catalogProduct)) {\n throw new EditorError(\n 'E_NOT_A_BUNDLE',\n `product ${catalogProduct.id} has no bundle block — picks / variants are bundle parameters ` +\n 'the server refuses on a single product (E_NOT_A_BUNDLE). Use productToRenderConfig() for it.',\n { productId: catalogProduct.id, docSlug: DOC },\n );\n }\n const members = catalogProduct.bundle.members;\n const roleNames = members.map((m) => m.role);\n\n for (const [field, map] of [\n ['picks', options.picks],\n ['variants', options.variants],\n ] as const) {\n for (const role of Object.keys(map ?? {})) {\n if (!roleNames.includes(role)) {\n throw new EditorError(\n 'E_BUNDLE_ROLE_NOT_FOUND',\n `bundle ${catalogProduct.id} has no role \"${role}\" (in ${field}). Roles: [${roleNames.join(', ')}].`,\n { productId: catalogProduct.id, field, role, validNames: roleNames, docSlug: DOC },\n );\n }\n }\n }\n\n const picks: Record<string, string> = {};\n const variants: Record<string, string> = {};\n const renderByRole: Record<string, string> = {};\n const catalogPlacements = catalogProduct.placements ?? [];\n const roles: BundleRoleConfig[] = [];\n\n for (const member of members) {\n const alternatives = member.products.map((p) => p.productId);\n const wanted = options.picks?.[member.role];\n const alt = wanted === undefined ? member.products[0] : member.products.find((p) => p.productId === wanted);\n if (!alt) {\n throw new EditorError(\n 'E_BUNDLE_PICK_NOT_FOUND',\n `bundle ${catalogProduct.id} role \"${member.role}\" has no alternative \"${wanted}\". ` +\n `Alternatives: [${alternatives.join(', ')}] — pass picks: { ${member.role}: \"${alternatives[0]}\" }.`,\n { productId: catalogProduct.id, role: member.role, requested: wanted, validNames: alternatives, docSlug: DOC },\n );\n }\n picks[member.role] = alt.productId;\n\n // The variant set the SERVER accepts for this slot: the alternative's\n // published `variants[].gvid`; with none published only the default gvid\n // exists. (The alternative's `options.combinations` may list more SKUs —\n // those are cart identities, not session variants, see the ADR ledger.)\n const gvids = (alt.variants ?? []).map((v) => v.gvid).filter((g): g is string => typeof g === 'string' && g !== '');\n const accepted = gvids.length > 0 ? gvids : alt.defaultGvid ? [alt.defaultGvid] : [];\n const chosen = options.variants?.[member.role] ?? alt.defaultGvid ?? gvids[0];\n if (!chosen || !accepted.includes(chosen)) {\n const requested = options.variants?.[member.role];\n throw new EditorError(\n 'E_BUNDLE_VARIANT_NOT_FOUND',\n accepted.length === 0\n ? `bundle ${catalogProduct.id} role \"${member.role}\": alternative ${alt.productId} publishes no variant — ` +\n 'nothing can render this slot (catalog data is incomplete).'\n : `bundle ${catalogProduct.id} role \"${member.role}\" (${alt.productId}) has no variant \"${requested}\". ` +\n `Variants: [${accepted.join(', ')}] — pass variants: { ${member.role}: \"${accepted[0]}\" }.`,\n {\n productId: catalogProduct.id,\n role: member.role,\n memberProductId: alt.productId,\n requested,\n validNames: accepted,\n docSlug: DOC,\n },\n );\n }\n variants[member.role] = chosen;\n renderByRole[member.role] = alt.variants?.find((v) => v.gvid === chosen)?.gvidForMockup || chosen;\n\n const placements: BundlePlacementConfig[] = catalogPlacements\n .filter(\n (p): p is CatalogPlacement & { key: string; width: number; height: number } =>\n p.role === member.role &&\n p.memberProductId === alt.productId &&\n typeof p.key === 'string' &&\n p.key !== '' &&\n isRenderablePlacement(p),\n )\n .map((p) => ({\n key: p.key,\n role: member.role,\n label: p.label,\n memberProductId: alt.productId,\n width: p.width,\n height: p.height,\n aspectRatio: p.width / p.height,\n }));\n\n roles.push({\n role: member.role,\n required: member.required !== false,\n alternatives,\n pick: alt.productId,\n variantId: chosen,\n variantChoices: accepted.map((gvid) => ({ gvid, label: variantLabel(alt, gvid) })),\n placements,\n });\n }\n\n // Renderable placements of the PICKED alternatives, in catalog order (the\n // order the server's requiredPlacements uses).\n const pickedKeys = new Set(roles.flatMap((r) => r.placements.map((p) => p.key)));\n const byKey = new Map(roles.flatMap((r) => r.placements.map((p) => [p.key, p] as const)));\n const placements: BundlePlacementConfig[] = [];\n for (const p of catalogPlacements) {\n if (typeof p.key !== 'string' || !pickedKeys.has(p.key)) continue;\n const cfg = byKey.get(p.key);\n if (cfg && !placements.includes(cfg)) placements.push(cfg);\n }\n const placementKeys = placements.map((p) => p.key);\n\n let placement: BundlePlacementConfig | undefined;\n if (options.placement !== undefined) {\n if (!splitRoleKey(options.placement)) {\n throw new EditorError(\n 'E_BUNDLE_ROLE_REQUIRED',\n `placement \"${options.placement}\" names no role — on bundle ${catalogProduct.id} a placement is ` +\n `addressed by its role-scoped key. Keys: [${placementKeys.join(', ')}].`,\n { productId: catalogProduct.id, requested: options.placement, validNames: placementKeys, docSlug: DOC },\n );\n }\n placement = placements.find((p) => p.key === options.placement);\n if (!placement) {\n throw new EditorError(\n 'E_PRODUCT_NOT_RENDERABLE',\n `bundle ${catalogProduct.id} has no renderable placement \"${options.placement}\" for picks ` +\n `${JSON.stringify(picks)}. Keys: [${placementKeys.join(', ')}].`,\n { productId: catalogProduct.id, requested: options.placement, picks, validNames: placementKeys, docSlug: DOC },\n );\n }\n } else {\n placement = placements[0];\n }\n if (!placement) {\n throw new EditorError(\n 'E_PRODUCT_NOT_RENDERABLE',\n `bundle ${catalogProduct.id} has no renderable image placement for picks ${JSON.stringify(picks)} ` +\n '(a role-scoped, non-color placement with width/height). The catalog payload may be incomplete — ' +\n 'fetch it via getProduct(), not a search hit.',\n { productId: catalogProduct.id, picks, docSlug: DOC },\n );\n }\n\n // Scenes photograph a PICK SET: keep the mockups whose `picks` agree with\n // ours on every role they name (a scene with no picks metadata is kept).\n // None match → all scenes (stale metadata beats an empty embed — the same\n // fallback the single-product adapter makes for gvid-split scenes).\n const mockups = catalogProduct.mockups ?? [];\n const matching = mockups.filter(\n (m) => !m.picks || Object.entries(m.picks).every(([role, productId]) => picks[role] === productId),\n );\n const mockupIds = (matching.length > 0 ? matching : mockups).map((m) => m.id);\n if (mockupIds.length === 0) {\n throw new EditorError(\n 'E_PRODUCT_NOT_RENDERABLE',\n `bundle ${catalogProduct.id} has no mockup scenes — nothing to render a preview into.`,\n { productId: catalogProduct.id, docSlug: DOC },\n );\n }\n\n // Advisory contracts on the RenderProduct use the role-scoped KEY as the\n // placement name — that is what the server's requiredPlacements are on a\n // bundle, and what every renderState / artboard must be called.\n const requiredPlacements = (catalogProduct.requiredPlacements ?? [])\n .filter((p) => typeof p.key === 'string' && p.key !== '' && pickedKeys.has(p.key))\n .map((p) => ({ label: p.key as string, key: p.key as string, type: p.type, autoFilledByVariant: p.autoFilledByVariant }));\n\n const product: RenderProduct = {\n productId: catalogProduct.id,\n mockupIds,\n picks,\n variants,\n placements: placementKeys,\n mockups,\n ...(requiredPlacements.length > 0 ? { requiredPlacements } : {}),\n ...(typeof options.width === 'number' ? { width: options.width } : {}),\n };\n\n return {\n kind: 'bundle',\n product,\n picks,\n variants,\n variantToken: bundleVariantToken(renderByRole),\n roles,\n placement,\n placements,\n placementKeys,\n roleNames,\n primaryMockupId: mockupIds[0],\n };\n}\n","'use client';\n\n/**\n * Mount-time assertions for the realtime embed. Catches the silent-break wiring\n * mistakes that otherwise produce a blank canvas or a mockup that never renders:\n *\n * - no grant source (the session can't authorize → silent hang)\n * - a variant product with no `variantId` (→ ~30s render hang), AND the\n * can't-even-tell case: neither `variantId` nor `options` passed\n * - empty `mockupIds` (nothing to render)\n * - a design artboard that isn't one of the product's placements (renderState\n * targets a placement the product doesn't have → silent blank mockup)\n * - a multi-placement product whose required placements the design doesn't\n * COVER (the server waits on the missing canvas_states and the render times\n * out ~15s in — add the missing `.artboard()`s, ADR-0088, or eject)\n * - duplicate layer names (binding hooks resolve to the wrong element)\n *\n * Two consumption modes (ADR-0085 / F3):\n * - `validateEmbed` — the legacy advisory API: logs `console.warn` /\n * `console.error` and never throws, so a partly-wired `<RealtimeEmbed>`\n * still mounts and renders what it can. Dev-only at the call site.\n * - `collectEmbedIssues` — the structured list; `Editor.Root` THROWS on the\n * error-severity issues (console.error is invisible to headless agents).\n */\n\nimport { assertVariantSelected, type RenderProduct } from '@snowcone-app/sdk';\nimport type { AnyDesign } from '../../design/design-builder.js';\nimport { splitRoleKey } from '../../design/bundle-config.js';\n\nexport interface ValidateEmbedInput {\n shop: string;\n product: RenderProduct;\n design: AnyDesign;\n hasGrant: boolean;\n}\n\n/** One wiring problem found at mount, or a runtime stall. `error`-severity\n * issues break the embed (no render will ever arrive / it targets the wrong\n * thing); `warn`-severity issues are advisory. Every issue also reaches the\n * host through `Editor.Root`'s `onIssue` — the machine-readable channel\n * (console.warn is as invisible to a headless agent as console.error). */\nexport interface EmbedIssue {\n severity: 'error' | 'warn';\n /** Stable issue key, carried into `EditorError.data.issue` in throw mode. */\n issue:\n /** No `shop` (the publishable shop id) was passed. */\n | 'missing-shop'\n /** No grant source (`grantUrl`/`grant`) — the session can never\n * authorize, so no mockup ever renders. */\n | 'missing-grant'\n /** `product.mockupIds` is empty — nothing to render. */\n | 'empty-mockup-ids'\n /** The product has a variant axis but no `variantId` — the render\n * would hang ~30s waiting on a color blob that never comes. */\n | 'variant-required'\n /** ADR-0101 advisory: the design authors 2+ artboards but leaves some\n * required placements without one — those placements INHERIT the base\n * (the first artboard), re-fit per placement. Not an error: base +\n * overrides is the model. Assert on this to catch a half-finished\n * per-placement seed. */\n | 'placements-inherit-base'\n /** The design's placement isn't one of the product's placements —\n * the server renders a blank mockup. */\n | 'placement-mismatch'\n /** Two layers share a name — name-bound hooks bind the FIRST match,\n * so a control may edit the wrong layer. */\n | 'duplicate-layer-names'\n /** BUNDLE session (ADR-0099): a design artboard is a bare label\n * (`\"Front\"`) instead of a role-scoped key (`\"top.front\"`), or a bare\n * `variantId` is set — the server refuses both\n * (`E_BUNDLE_ROLE_REQUIRED`): two members can both have a \"Front\". */\n | 'bundle-role-required'\n /** BUNDLE session (ADR-0099): a role has no entry in\n * `product.variants` — the server keys the render on the per-role\n * variant set, so every role needs one (`bundleToRenderConfig` fills\n * defaults; hand-written configs must too). */\n | 'bundle-variant-required'\n /** Runtime (not mount-time): a render has been in flight past\n * `SLOW_RENDER_HINT_MS` with no mockup and no error — the silent-hang\n * class. The render may still arrive; this is a heads-up. */\n | 'slow-render';\n message: string;\n}\n\nconst TAG = '[RealtimeEmbed]';\n\n/**\n * The placement labels this product demands a canvas_state for. Prefers the\n * catalog's `requiredPlacements` contract; variant-auto-filled (color)\n * placements don't count — `variantId` satisfies them (the missing-variantId\n * case has its own guard above). Falls back to the bare `placements` label\n * list ONLY when the product has no variant in play: a label list can't say\n * which entries are auto-filled colors, but without a variant none are.\n */\nexport function requiredPlacementLabels(product: RenderProduct): string[] {\n if (product?.requiredPlacements?.length) {\n return product.requiredPlacements.filter((p) => !p.autoFilledByVariant).map((p) => p.label);\n }\n const variantIds = new Set(\n (product?.options?.combinations ?? [])\n .map((c) => c.variantId)\n .filter((id): id is string => typeof id === 'string' && id !== '')\n );\n const hasVariantAxis = Boolean(product?.variantId) || variantIds.size > 1;\n return hasVariantAxis ? [] : (product?.placements ?? []);\n}\n\n/** True when the product is wired as a BUNDLE session (ADR-0099): it\n * carries per-role `picks` and/or `variants`. */\nexport function isBundleRenderProduct(product: RenderProduct): boolean {\n return Boolean(product?.picks) || Boolean(product?.variants);\n}\n\n/** The bundle's roles as far as the RenderProduct reveals them: the role\n * prefixes of its placement keys plus every role named in picks/variants. */\nfunction bundleRolesOf(product: RenderProduct): string[] {\n const roles = new Set<string>();\n for (const key of product.placements ?? []) {\n const split = splitRoleKey(key);\n if (split) roles.add(split.role);\n }\n for (const role of Object.keys(product.picks ?? {})) roles.add(role);\n for (const role of Object.keys(product.variants ?? {})) roles.add(role);\n return [...roles];\n}\n\n/** Find every wiring problem. Pure — no logging, no throwing. */\nexport function collectEmbedIssues({ shop, product, design, hasGrant }: ValidateEmbedInput): EmbedIssue[] {\n const issues: EmbedIssue[] = [];\n\n if (!shop) {\n issues.push({\n severity: 'error',\n issue: 'missing-shop',\n message: '`shop` is required (your publishable shop id).',\n });\n }\n\n if (!hasGrant) {\n issues.push({\n severity: 'error',\n issue: 'missing-grant',\n message:\n 'no grant source — pass `grantUrl` (a proxy to mintRealtimeGrant) ' +\n 'or `grant`. Without it the session can never authorize and no mockup renders.',\n });\n }\n\n if (!product?.mockupIds?.length) {\n issues.push({\n severity: 'error',\n issue: 'empty-mockup-ids',\n message:\n 'product.mockupIds is empty — pass the catalog scene codes ' +\n '(product.mockups[].id) you want rendered, e.g. [\"FV1qjO\"].',\n });\n }\n\n // Variant axis: a product with a color/size option REQUIRES a variantId or the\n // render hangs ~30s waiting for a color blob that never comes. When `options`\n // (the catalog combinations) is passed we can detect the axis and fail fast\n // before the session's constructor throws. When `options` is NOT passed we\n // can't see the axis — so we DON'T warn here (a no-`options` product might\n // genuinely have no variants; warning would false-fire on every valid\n // single-variant embed). That stall is instead caught at runtime by\n // the embed's slow-render backstop (`slowRenderHint`), which fires only\n // when a render actually hangs — no false positives, and it covers every\n // silent-hang cause, not just this one.\n if (product?.options) {\n try {\n assertVariantSelected(product);\n } catch (err) {\n issues.push({\n severity: 'error',\n issue: 'variant-required',\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n const json = design.toJSON();\n const artboardNames = json.artboards.map((a) => a.name);\n\n // BUNDLE session (ADR-0099): placements are role-scoped keys and the\n // variant is per role. A bare label or a bare variantId is refused by the\n // server (E_BUNDLE_ROLE_REQUIRED) and a role with no variant has no render\n // identity — knowable at mount, so say so here with the valid keys.\n const bundle = isBundleRenderProduct(product);\n let roleless: string[] = [];\n if (bundle) {\n const keys = product.placements ?? [];\n roleless = artboardNames.filter((name) => !splitRoleKey(name));\n if (roleless.length > 0) {\n issues.push({\n severity: 'error',\n issue: 'bundle-role-required',\n message:\n `product ${product.productId} is a bundle, but the design's artboard(s) [${roleless.join(', ')}] ` +\n 'name no role. On a bundle every placement is addressed by its role-scoped key ' +\n `(<role>.<key>)${keys.length ? ` — keys: [${keys.join(', ')}]` : ''}. Seed the design from ` +\n 'bundleToRenderConfig(product).placement.key, not from a bare label.',\n });\n }\n if (product.variantId) {\n issues.push({\n severity: 'error',\n issue: 'bundle-role-required',\n message:\n `product ${product.productId} is a bundle, but product.variantId (\"${product.variantId}\") names no ` +\n 'slot — the server refuses it (E_BUNDLE_ROLE_REQUIRED). Name the variant per role instead: ' +\n 'product.variants = { <role>: <gvid> } (bundleToRenderConfig fills it), and leave variantId unset.',\n });\n }\n const roles = bundleRolesOf(product);\n const missingVariant = roles.filter((role) => !product.variants?.[role]);\n if (missingVariant.length > 0) {\n issues.push({\n severity: 'error',\n issue: 'bundle-variant-required',\n message:\n `product ${product.productId} is a bundle, but role(s) [${missingVariant.join(', ')}] have no entry in ` +\n `product.variants (${JSON.stringify(product.variants ?? {})}). Every role needs a variant — the ` +\n 'server keys the render on the per-role set. Build the product with bundleToRenderConfig(product, ' +\n '{ picks, variants }), which fills each slot\\'s default.',\n });\n }\n }\n\n // ADR-0101: every required image placement renders SOMETHING — its own\n // artboard when split, the base (first artboard) when linked. A single\n // artboard is the fully-linked default (ADR-0089 §5) and stays silent. Once\n // a SECOND artboard is authored, placements still inheriting the base get\n // an advisory so a half-finished per-placement seed is visible to hosts\n // and agents (`onIssue`), never a mount error — base + overrides is the\n // model, the same as `asset=` + `asset.<key>` on the URL surface.\n const required = requiredPlacementLabels(product);\n const inheriting = required.filter((label) => !artboardNames.includes(label));\n if (required.length > 1 && artboardNames.length > 1 && inheriting.length > 0) {\n issues.push({\n severity: 'warn',\n issue: 'placements-inherit-base',\n message:\n `product ${product.productId} requires placements ` +\n `[${required.join(', ')}]; the design authors [${artboardNames.join(', ')}], so ` +\n `[${inheriting.join(', ')}] inherit the base artboard \"${artboardNames[0]}\" ` +\n '(re-fit per placement, ADR-0101). Intended? Otherwise split them: ' +\n \"design(…).artboard('\" + inheriting[0] + \"', { width, height })… or \" +\n \"usePlacements().split('\" + inheriting[0] + \"') at runtime.\",\n });\n }\n\n const foreign = product?.placements?.length\n ? artboardNames.filter((name) => !product.placements!.includes(name) && !roleless.includes(name))\n : [];\n if (foreign.length > 0) {\n issues.push({\n severity: 'error',\n issue: 'placement-mismatch',\n message:\n `the design's artboard(s) [${foreign.join(', ')}] are not in ` +\n `product.placements [${product.placements!.join(', ')}]. Every artboard ` +\n 'name must equal a real product placement label (renderState targets ' +\n 'placements by that name), or the server renders a blank mockup. Fix the ' +\n '`name` passed to design({ name }) / design().artboard(name, …).',\n });\n }\n\n const names = json.elements.map((el) => (el as { name?: string }).name).filter((n): n is string => Boolean(n));\n const dupes = names.filter((n, i) => names.indexOf(n) !== i);\n if (dupes.length) {\n issues.push({\n severity: 'warn',\n issue: 'duplicate-layer-names',\n message:\n `duplicate layer name(s) [${[...new Set(dupes)].join(', ')}] — ` +\n 'useTextBinding(name) / useImageBinding(name) bind to the FIRST match, ' +\n 'so a duplicate name makes a control edit the wrong layer. Keep names unique.',\n });\n }\n\n return issues;\n}\n\n/** Legacy advisory API: log everything, never throw. (`placement-mismatch`\n * keeps its historical `console.warn` level here; in `Editor.Root`'s throw\n * mode it is error-severity per F3.) */\nexport function validateEmbed(input: ValidateEmbedInput): void {\n for (const issue of collectEmbedIssues(input)) {\n const log =\n issue.severity === 'error' && issue.issue !== 'placement-mismatch' ? console.error : console.warn;\n log(`${TAG} ${issue.message}`);\n }\n}\n","/**\n * Linked placements (ADR-0101): the ONE place that decides which artboard\n * fills each of a product's required image placements.\n *\n * - The design's FIRST artboard is the base.\n * - A required placement with an artboard of its own name is SPLIT — that\n * artboard renders there and nowhere else.\n * - A required placement with no artboard of its own is LINKED — it\n * inherits the base, re-fit to its own print geometry by the server.\n *\n * A fresh single-artboard design is therefore linked on every area (the\n * ADR-0089 §5 broadcast), and authoring / splitting a second artboard is an\n * additive override, never all-or-nothing. `Editor.Root`'s render push,\n * `Editor.Buy`'s payload, and `validateEmbed` all read this file; nothing\n * else re-derives the rule.\n */\n\n/** The minimum a request needs for expansion — both `ServerRenderRequest`\n * and the SDK's looser `RenderState` satisfy it. */\nexport interface ExpandableRequest {\n artboards?: Array<{ name?: string } & Record<string, unknown>>;\n}\n\nexport interface PlacementLinkInfo {\n /** The product placement label (= the artboard name when split). */\n label: string;\n /** True when this placement has no artboard of its own and renders the\n * base. Always false for the base's own label. */\n inherited: boolean;\n}\n\n/**\n * Per-placement link state for a design against the product's required\n * placements, in product order. Authored artboards that are NOT required\n * placements (bundle roleless slots, legacy extras) are appended after, never\n * inherited. With no required placements (a variant-axis product without\n * `requiredPlacements`) the design's own artboards are the list, none\n * inherited — the pre-0101 behavior.\n */\nexport function resolvePlacementLinks(\n artboardNames: readonly string[],\n requiredLabels: readonly string[],\n): PlacementLinkInfo[] {\n const authored = new Set(artboardNames);\n if (requiredLabels.length === 0) {\n return artboardNames.map((label) => ({ label, inherited: false }));\n }\n const out: PlacementLinkInfo[] = requiredLabels.map((label) => ({\n label,\n inherited: !authored.has(label),\n }));\n for (const name of artboardNames) {\n if (!requiredLabels.includes(name)) out.push({ label: name, inherited: false });\n }\n return out;\n}\n\n/** The base artboard name (the first authored artboard), or undefined for an\n * artboard-less state. */\nexport function baseArtboardName(artboardNames: readonly string[]): string | undefined {\n return artboardNames[0];\n}\n\n/**\n * Expand a serialized render request so EVERY required placement carries an\n * artboard: split placements keep their own, linked placements get the base\n * relabelled (the server re-fits it per placement). Order = required\n * placements first (product order), then any extra authored artboards.\n *\n * Returns the SAME object when nothing inherits (no required placements, or\n * every one is split) so callers can rely on identity for \"unchanged\".\n */\nexport function expandRequestForPlacements<T extends ExpandableRequest>(\n request: T,\n requiredLabels: readonly string[],\n): T {\n const artboards = request.artboards ?? [];\n const base = artboards[0];\n if (!base || requiredLabels.length === 0) return request;\n const names = artboards.map((ab) => (typeof ab.name === 'string' ? ab.name : ''));\n const byName = new Map(artboards.map((ab, i) => [names[i]!, ab] as const));\n const links = resolvePlacementLinks(names, requiredLabels);\n if (links.every((l) => !l.inherited)) return request;\n const expanded = links.map((l) =>\n l.inherited ? { ...base, name: l.label } : byName.get(l.label)!,\n );\n return { ...request, artboards: expanded };\n}\n","/**\n * `Editor.audit()` — the machine-checkable \"is my composition complete?\"\n * oracle for the `Editor.*` primitives (agentic-DX finding #10).\n *\n * `validateEmbed` covers WIRING (shop/grant/product/placement); the audit\n * covers COMPOSITION: parts that are mounted but inert, ambiguous fan-out,\n * personalization with no commerce gate, dead bindings, empty designs. Two\n * consumption modes, both dev AND prod:\n *\n * - `<Editor.Root onAudit={(report) => …}>` — fires ONCE after mount\n * settles (every part's layout-effect registration is in, the design\n * store holds its first snapshot). Like `onIssue`, this is the\n * machine-readable channel: console output is invisible to a headless\n * agent; assert on the callback.\n * - `auditEditor()` — the imperative dev helper: computes a FRESH report\n * from the most-recent mounted Root's registry + live design state, so an\n * agent can re-audit after interacting. Throws `E_AUDIT_NO_ROOT` when no\n * Root is mounted.\n *\n * Finding style follows the EditorError house rules (E2): verifiable facts\n * from data in hand only; `message` names the violated contract and the\n * offending parts, `fix` names the exact prop/part to change. Codes are the\n * stable contract (`A_*` — advisory, distinct from the throwing `E_*` space);\n * messages may be reworded.\n */\n\nimport type { RenderProduct } from '@snowcone-app/sdk';\nimport { EditorError } from '../../errors/editorError.js';\nimport type { DesignStateStore } from './designStateStore.js';\nimport type { EditorPartsRegistry } from './RootInternals.js';\n\n/** Stable audit finding codes — the test/agent contract. */\nexport type EditorAuditFindingCode =\n /** Requires-canvas parts (Controls/History/Menu/Add) are mounted with no\n * `Editor.Canvas` — the same composition `E_REQUIRES_CANVAS` throws on. */\n | 'A_REQUIRES_CANVAS'\n /** A docked `Editor.Controls` is mounted while `Editor.Canvas` still has\n * `floatingToolbar` true (the default) — contextual-zone ownership is\n * implied by mount order (spooky), not declared in the type surface. */\n | 'A_CONTROLS_INERT'\n /** `Editor.Preview` without `mockupId` while the product renders more than\n * one mockup scene — which scene the preview shows is ambiguous. */\n | 'A_PREVIEW_AMBIGUOUS'\n /** `Editor.TextField` parts are mounted but no `Editor.Buy` — there is no\n * commerce gate enforcing completeness before checkout. */\n | 'A_NO_BUY'\n /** A mounted `Editor.TextField`'s layer matches zero elements in the\n * CURRENT design snapshot — the binding is dead; writes will fail. */\n | 'A_LAYER_UNMATCHED'\n /** Every required (non-`optional`) `Editor.TextField` still equals its\n * seed value — Buy's completeness rule C3 gates checkout until edited. */\n | 'A_TEXT_AT_SEED'\n /** Zero renderable elements in the design — every mockup renders blank. */\n | 'A_EMPTY_DESIGN';\n\nexport interface EditorAuditFinding {\n code: EditorAuditFindingCode;\n severity: 'error' | 'warn' | 'info';\n /** What is wrong, with the facts (part names, layer names, scene ids). */\n message: string;\n /** The exact prop/part change that resolves the finding. */\n fix: string;\n}\n\nexport interface EditorAuditReport {\n findings: EditorAuditFinding[];\n /** Census of mounted parts, e.g. `{ name: 'Editor.Preview', count: 2 }`.\n * Sorted by name for determinism. */\n parts: Array<{ name: string; count: number }>;\n}\n\n/** @internal */\nexport interface EditorAuditInput {\n registry: EditorPartsRegistry;\n store: DesignStateStore;\n product: RenderProduct;\n}\n\n/** Compute the audit report from a Root's live registry + design state.\n * Pure — no logging, no throwing. @internal */\nexport function computeEditorAudit({ registry, store, product }: EditorAuditInput): EditorAuditReport {\n const findings: EditorAuditFinding[] = [];\n const parts = registry.getParts();\n const textFields = registry.getTextFields();\n\n // ── A_REQUIRES_CANVAS — parts that will throw/no-op without a canvas ──────\n const requiresCanvas = registry.requiresCanvasPartNames();\n if (requiresCanvas.length > 0 && !registry.hasCanvas()) {\n findings.push({\n code: 'A_REQUIRES_CANVAS',\n severity: 'error',\n message:\n `${requiresCanvas.join(', ')} ${requiresCanvas.length === 1 ? 'is' : 'are'} mounted with no ` +\n `<Editor.Canvas> under this Root — they operate on the editable artboard (selection, ` +\n `editor commands) and throw E_REQUIRES_CANVAS.`,\n fix:\n `Mount <Editor.Canvas/> under the same <Editor.Root>, or remove ${requiresCanvas.join(', ')}. ` +\n `Canvas-free parts: Editor.Preview, Editor.Buy, Editor.TextField, Editor.Layers.`,\n });\n }\n\n // ── A_CONTROLS_INERT — docked Controls while the canvas keeps the default\n // floating toolbar: suppression happens as a side effect of MOUNTING the\n // docked Controls (ADR-0085 §5), invisible in the type surface, and\n // unmounting the Controls silently re-enables the floating zone. ────────\n const canvasKeepsFloating = parts\n .filter((p) => p.name === 'Editor.Canvas')\n .some((p) => p.meta.floatingToolbar !== false);\n if (registry.hasDockedControls() && canvasKeepsFloating) {\n findings.push({\n code: 'A_CONTROLS_INERT',\n severity: 'warn',\n message:\n `a docked <Editor.Controls> is mounted while <Editor.Canvas> still has ` +\n `floatingToolbar={true} (the default) — both contextual zones are armed, and the ` +\n `floating toolbar is suppressed only as a side effect of the docked Controls being ` +\n `mounted this frame (it silently reappears when the Controls unmounts).`,\n fix:\n `Declare contextual-zone ownership in the type surface: pass floatingToolbar={false} on ` +\n `<Editor.Canvas> when a <Editor.Controls placement=\"docked\"> owns the zone.`,\n });\n }\n\n // ── A_PREVIEW_AMBIGUOUS — Preview with no mockupId on a multi-scene product\n const sceneIds = product?.mockupIds ?? [];\n if (sceneIds.length > 1) {\n const unpinned = parts.filter((p) => p.name === 'Editor.Preview' && p.meta.mockupId === undefined);\n if (unpinned.length > 0) {\n findings.push({\n code: 'A_PREVIEW_AMBIGUOUS',\n severity: 'warn',\n message:\n `${unpinned.length} <Editor.Preview> part${unpinned.length === 1 ? ' has' : 's have'} no ` +\n `mockupId while the product renders ${sceneIds.length} mockup scenes ` +\n `[${sceneIds.join(', ')}] — each shows whichever scene renders first, an ambiguous fan-out.`,\n fix:\n `Pin each <Editor.Preview> to a scene: mockupId=\"${sceneIds[0]}\" ` +\n `(one of product.mockupIds).`,\n });\n }\n }\n\n // ── A_NO_BUY — personalization with no commerce gate ──────────────────────\n const hasBuy = parts.some((p) => p.name === 'Editor.Buy');\n if (textFields.length > 0 && !hasBuy) {\n const names = textFields.map((tf) => tf.name);\n findings.push({\n code: 'A_NO_BUY',\n severity: 'info',\n message:\n `<Editor.TextField> parts are mounted (layers [${names.join(', ')}]) but no <Editor.Buy> — ` +\n `personalization has no commerce gate, so nothing enforces completeness (C2/C3) before ` +\n `the design is bought.`,\n fix:\n `Mount <Editor.Buy onAddToCart={…}/> under the same <Editor.Root> (it assembles the ` +\n `payload and gates on completeness), or ignore if this composition is deliberately ` +\n `non-commerce.`,\n });\n }\n\n // ── A_LAYER_UNMATCHED — a mounted TextField bound to a layer that matches\n // zero elements in the CURRENT snapshot (removed/renamed after mount —\n // mount-time validation already threw on never-existed names). ──────────\n const matched: typeof textFields = [];\n for (const tf of textFields) {\n if (store.layerKindOf(tf.name) === undefined) {\n findings.push({\n code: 'A_LAYER_UNMATCHED',\n severity: 'error',\n message:\n `<Editor.TextField layer={design.layer(\"${tf.name}\")}> matches zero elements in the ` +\n `current design state — the layer was removed or renamed after the field mounted, so ` +\n `the binding is dead and writes will fail. Bindable layers now: ` +\n `${JSON.stringify(store.bindableLayerNames())}.`,\n fix:\n `Restore a text layer named \"${tf.name}\" to the design, or bind the field to an ` +\n `existing layer: layer={design.layer(<one of ${JSON.stringify(store.bindableLayerNames())}>)}.`,\n });\n } else {\n matched.push(tf);\n }\n }\n\n // ── A_TEXT_AT_SEED — every required field still placeholder text ──────────\n const required = matched.filter((tf) => !tf.optional);\n if (\n required.length > 0 &&\n required.every((tf) => store.textOf(tf.name) === store.seedTextOf(tf.name))\n ) {\n const names = required.map((tf) => tf.name);\n findings.push({\n code: 'A_TEXT_AT_SEED',\n severity: 'info',\n message:\n `every required <Editor.TextField> still equals its seed value (layers ` +\n `[${names.join(', ')}]) — <Editor.Buy>'s completeness rule C3 gates checkout until the ` +\n `shopper's text differs from the seed (placeholder text must not be bought).`,\n fix:\n `Nothing to change for a fresh mount — this clears when the shopper edits the fields. ` +\n `For a field that should NOT gate Buy, pass optional on that <Editor.TextField>.`,\n });\n }\n\n // ── A_EMPTY_DESIGN — zero renderable elements ─────────────────────────────\n if (!store.hasRenderableElement()) {\n findings.push({\n code: 'A_EMPTY_DESIGN',\n severity: 'warn',\n message:\n `the design state has zero renderable elements (no non-empty text, no image with a URL, ` +\n `no shape) — every mockup renders blank.`,\n fix:\n `Seed content on the builder passed to <Editor.Root design={…}> — ` +\n `design({…}).text(…)/.background(…)/.shape(…) — or add elements through <Editor.Add>.`,\n });\n }\n\n // ── Part census ───────────────────────────────────────────────────────────\n const counts = new Map<string, number>();\n for (const p of parts) counts.set(p.name, (counts.get(p.name) ?? 0) + 1);\n const census = [...counts.entries()]\n .map(([name, count]) => ({ name, count }))\n .sort((a, b) => a.name.localeCompare(b.name));\n\n return { findings, parts: census };\n}\n\n// ── The imperative helper's Root registry ────────────────────────────────────\n\ninterface RootAuditEntry {\n compute: () => EditorAuditReport;\n}\n\nconst mountedRoots: RootAuditEntry[] = [];\n\n/** Register a mounted Root as an audit target (most-recent wins). @internal */\nexport function registerRootForAudit(entry: RootAuditEntry): () => void {\n mountedRoots.push(entry);\n return () => {\n const index = mountedRoots.indexOf(entry);\n if (index !== -1) mountedRoots.splice(index, 1);\n };\n}\n\n/**\n * Audit the most-recent mounted `<Editor.Root>`'s composition NOW — a fresh\n * report from the live part registry + design state, so it reflects whatever\n * has happened since mount (fields edited, parts mounted/unmounted).\n *\n * Throws `E_AUDIT_NO_ROOT` when no Root is mounted.\n */\nexport function auditEditor(): EditorAuditReport {\n const current = mountedRoots[mountedRoots.length - 1];\n if (!current) {\n throw new EditorError(\n 'E_AUDIT_NO_ROOT',\n 'auditEditor() found no mounted <Editor.Root>. Mount a Root first — or, to audit at ' +\n 'mount time, pass onAudit on the Root: <Editor.Root onAudit={(report) => …}>.',\n { docSlug: 'embed-mode' },\n );\n }\n return current.compute();\n}\n","'use client';\n\n/**\n * `<Editor.Root>` — the one provider boundary of the composable editor\n * primitives (ADR-0085). Owns the realtime {@link RenderSession}, the design,\n * the live mockups, the ONE design-state store, the part registry, and the\n * built-in error boundary. Parts (`Editor.Canvas/Preview/TextField/Buy/…`)\n * carry behavior + state subscription only; the HOST owns all layout.\n *\n * STATE MODEL (D9 — state always, renderer lazy):\n *\n * Editor.Root (one provider boundary · error boundary · applies .sc-root once)\n * │\n * ├── STATE — always mounted, renderer-free\n * │ └── EmbedContext design · product · render session · mockups ·\n * │ pushRender · stateStore (the ONE live design state)\n * │ (EditorProvider joins here in P1's inversion — until then the\n * │ editor document still mounts inside Editor.Canvas's chunk)\n * │\n * ├── <Editor.Canvas/> dynamic import ──→ [HEAVY RENDERER CHUNK]\n * ├── <Editor.Preview/> ←─ mockups (×N under one Root is VALID)\n * ├── <Editor.TextField/> ─→ stateStore (by layer token) ─→ pushRender\n * └── <Editor.Buy/> ←─ stateStore + required-TextField registry\n *\n * This file is the EXTRACTION of `<RealtimeEmbed>`'s internals (D5 — not a\n * copy): `RealtimeEmbed` is now `<EditorRoot>` plus the legacy advisory\n * validation mode, so the existing realtime tests exercise this Root.\n *\n * The legacy embed had no DOM of its own; Root must apply `.sc-root` once\n * (parts never self-apply, ADR-0085). `display: contents` squares the two —\n * the scope div generates no box, so host grid/flex layouts see the children\n * directly and the legacy wrapper stays layout-identical.\n */\n\nimport React, {\n Component,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n type ReactNode,\n} from 'react';\nimport {\n RenderSession,\n type RenderProduct,\n type RenderState,\n type MockupResult,\n type RealtimeGrant,\n} from '@snowcone-app/sdk';\nimport type { AnyDesign } from '../../design/design-builder.js';\nimport { CanvasServicesProvider, type CanvasServices } from '../../contexts/CanvasServicesContext.js';\nimport { EditorProvider } from '../../contexts/EditorContext.js';\nimport { BoundLayerGuardContext } from '../../contexts/BoundLayerGuardContext.js';\nimport { EmbedContext, type EmbedContextValue } from '../embed-realtime/context.js';\nimport { usePieceGuideBundle, pieceGuidesForArtboard } from '../embed-realtime/usePieceGuideBundle.js';\nimport {\n collectEmbedIssues,\n requiredPlacementLabels,\n validateEmbed,\n type EmbedIssue,\n} from '../embed-realtime/validateEmbed.js';\nimport { expandRequestForPlacements } from './placementLinks.js';\nimport { EditorError, isEditorError } from '../../errors/editorError.js';\nimport { recordContainedEditorError } from '../../testing/editorErrors.js';\nimport { serializeStateForServer } from '../../rendering/serialize-for-server.js';\nimport { DesignStateStore } from './designStateStore.js';\nimport { CommerceStateStore } from './commerceStore.js';\nimport { computeEditorAudit, registerRootForAudit, type EditorAuditReport } from './editorAudit.js';\nimport {\n EditorPartsRegistry,\n EditorRootInternalsContext,\n makeInvariantReporter,\n type EditorRootInternals,\n} from './RootInternals.js';\n\n/**\n * How the session authorizes. Provide exactly one — the discriminated union makes\n * \"I forgot the grant\" a compile error rather than a silent runtime hang.\n *\n * Member order is load-bearing: when NEITHER prop is supplied (the common\n * mistake) TS reports the missing property of the LAST union member, so the\n * `grantUrl` arm is kept last on purpose — the error then reads \"Property\n * 'grantUrl' is missing\", pointing at the recommended prop instead of `grant`.\n * Don't reorder these.\n */\nexport type GrantSource =\n | {\n /** Full control over fetching the grant: a token or a token factory. */\n grant: RealtimeGrant | (() => Promise<RealtimeGrant>);\n grantUrl?: never;\n }\n | {\n /** Your endpoint returning `{ token, expiresAt }` for `POST { shop }` —\n * a same-origin proxy to `mintRealtimeGrant`. Recommended. */\n grantUrl: string;\n grant?: never;\n };\n\nexport type EditorRootBaseProps = {\n /** Publishable shop id (= shop.id, like a Stripe pk_). Billing target. */\n shop: string;\n /** Product to render against (catalog ids). `mockupIds` are scene codes\n * (product.mockups[].id), NOT placement names. Pass `placements`, `options`\n * + `requiredPlacements` so wiring mistakes (including a multi-placement\n * product, which the embed can't render) fail loud at mount instead of\n * hanging. */\n product: RenderProduct;\n /** Single source of truth — seeds the canvas AND the first render. Build it\n * with `design({ name, width, height })…`. Its artboard `name` is the\n * placement every render targets. */\n design: AnyDesign;\n /** Edit→render throttle in ms (default 200). */\n throttleMs?: number;\n /** Called whenever new mockups arrive. */\n onMockups?: (results: MockupResult[]) => void;\n /** Called on a render/timeout error. */\n onRenderError?: (message: string) => void;\n /**\n * The machine-readable advisory channel (F3's other half): every non-fatal\n * issue — warn-severity wiring problems at mount, the runtime `slow-render`\n * stall — is delivered here, in dev AND prod. Console output is as\n * invisible to a headless agent as it is to production telemetry; assert on\n * this callback instead of scraping logs. (Error-severity wiring issues\n * don't arrive here — they throw `EditorError E_EMBED_CONFIG` into Root's\n * boundary.)\n */\n onIssue?: (issue: EmbedIssue) => void;\n /**\n * The composition-audit channel (`Editor.audit()`, agentic-DX #10): fires\n * ONCE after mount settles (every part's layout-effect registration is in,\n * the design store holds its first snapshot), dev AND prod — like\n * `onIssue`, a machine-readable callback, never console output. The report\n * lists structured findings (stable `A_*` codes, each with the fix) plus a\n * census of mounted parts. It fires even when a composition mistake throws\n * into Root's boundary, carrying the registry state the throw saw. For a\n * fresh report after interacting, call `auditEditor()`.\n */\n onAudit?: (report: EditorAuditReport) => void;\n /** Override the realtime WS endpoint (defaults to the SDK's prod URL). */\n wsUrl?: string;\n /**\n * Privileged-service wiring for the editor chrome (the Image Browser's\n * stock-image search and AI generation tabs). Same pattern as `grantUrl`:\n * host these URLs on your server; your vendor keys live there.\n */\n services?: CanvasServices;\n children?: ReactNode;\n /**\n * Wiring-validation mode. `Editor.Root` defaults to `'throw'` (F3:\n * console.error is invisible to headless agents — error-severity wiring\n * issues throw `EditorError E_EMBED_CONFIG` into Root's boundary). The\n * legacy `<RealtimeEmbed>` wrapper passes `'warn'` for back-compat\n * (dev-only console diagnostics, never throws).\n * @internal\n */\n __validation?: 'throw' | 'warn';\n};\n\nexport type EditorRootProps = GrantSource & EditorRootBaseProps;\n\n/**\n * How long a render may be in flight before the embed assumes something is wrong\n * and surfaces a diagnostic. A healthy render returns in ~2s; the session's own\n * watchdog is ~30s. 8s sits in between — long enough not to false-fire on a\n * genuinely slow render, short enough to spare a first-timer the full 30s of\n * silence.\n */\nexport const SLOW_RENDER_HINT_MS = 8000;\n\n/**\n * The dev-console message shown when a render hasn't produced a mockup in\n * {@link SLOW_RENDER_HINT_MS}. A general backstop for the whole silent-hang\n * class — not just the missing-`variantId` trap — so a stuck embed always says\n * *something* actionable instead of hanging quietly.\n */\nexport function slowRenderHint(placement: string): string {\n return (\n `[RealtimeEmbed] No mockup after ${Math.round(SLOW_RENDER_HINT_MS / 1000)}s. ` +\n `Common causes: a variant product missing \\`variantId\\` (pass \\`product.options\\` ` +\n `so the embed can flag it up front), a multi-placement product (the server waits ` +\n `for every required placement but <RealtimeEmbed> sends only \"${placement}\" — pass ` +\n `\\`product.requiredPlacements\\` so this is flagged at mount; such products need ` +\n `the eject path), an unreachable or non-public asset URL in the design, or the ` +\n `placement \"${placement}\" not existing on the product. ` +\n `The render may still arrive — this is a heads-up, not a failure.`\n );\n}\n\nfunction toGetToken(props: EditorRootProps): { grantUrl: string } | { getToken: () => Promise<RealtimeGrant> } {\n if ('grantUrl' in props && props.grantUrl) {\n return { grantUrl: props.grantUrl };\n }\n const grant = (props as { grant: RealtimeGrant | (() => Promise<RealtimeGrant>) }).grant;\n if (typeof grant === 'function') return { getToken: grant };\n return { getToken: () => Promise.resolve(grant) };\n}\n\n// ── The error card (D11): contained, loud, in the widget slot ───────────────\n\nfunction ErrorCard({ error, onRetry }: { error: Error; onRetry?: () => void }): React.ReactElement {\n const code = isEditorError(error) ? error.code : 'EDITOR_ERROR';\n return (\n <div\n data-sc-part=\"error\"\n role=\"alert\"\n style={{\n padding: '16px',\n borderRadius: '12px',\n border: '1px solid var(--sc-color-destructive, #b91c1c)',\n background: 'var(--sc-color-surface, #fef2f2)',\n color: 'var(--sc-color-foreground, #7f1d1d)',\n fontFamily: 'ui-sans-serif, system-ui, sans-serif',\n fontSize: '13px',\n lineHeight: 1.5,\n }}\n >\n <p style={{ margin: 0, fontWeight: 700 }}>Editor failed: {code}</p>\n <p style={{ margin: '4px 0 0' }}>{error.message}</p>\n {onRetry ? (\n <button\n type=\"button\"\n data-sc-part=\"error-retry\"\n onClick={onRetry}\n style={{\n marginTop: '10px',\n padding: '6px 14px',\n borderRadius: '9999px',\n border: '1px solid currentColor',\n background: 'transparent',\n color: 'inherit',\n font: 'inherit',\n fontWeight: 600,\n cursor: 'pointer',\n }}\n >\n Retry\n </button>\n ) : null}\n </div>\n );\n}\n\ninterface BoundaryProps {\n /** Imperatively-reported error (handler/async path) — same card. */\n reportedError: EditorError | null;\n onRetry: () => void;\n children: ReactNode;\n}\n\ninterface BoundaryState {\n caught: Error | null;\n}\n\n/**\n * The catching half of Root's boundary (D11): render/lifecycle/effect throws\n * from the parts show an error card in the widget slot while the host page\n * survives.\n *\n * Test containment-bypass (the D11 review concern — \"an agent's mounts-\n * without-crashing test passes green on a broken composition\"): under\n * NODE_ENV=test/dev every contained error is RECORDED, and\n * `expectNoEditorErrors()` from `@snowcone-app/canvas/testing` fails the\n * test. (A literal rethrow-from-the-boundary was tried and rejected: an\n * uncaught throw from a layout effect corrupts React 18's work loop and\n * poisons every later render in the test file — \"Should not already be\n * working\".)\n */\nclass CatchingBoundary extends Component<BoundaryProps, BoundaryState> {\n state: BoundaryState = { caught: null };\n\n static getDerivedStateFromError(error: Error): BoundaryState {\n return { caught: error };\n }\n\n componentDidCatch(error: Error): void {\n recordContainedEditorError(error);\n if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {\n console.error('[Editor.Root] contained a composition error:', error);\n }\n }\n\n render(): ReactNode {\n if (this.state.caught) {\n // Composition mistakes need a code change; a retry would just re-throw.\n return <ErrorCard error={this.state.caught} />;\n }\n return this.props.children;\n }\n}\n\n/**\n * Root's built-in boundary (D11): the imperatively-REPORTED channel\n * (handler/async failures like the lazy chunk failing to load) renders the\n * card directly, with retry when the failure is retryable; everything else\n * goes through the catching class boundary above.\n */\nfunction EditorBoundary({ reportedError, onRetry, children }: BoundaryProps): React.ReactElement {\n if (reportedError) {\n const retryable = isEditorError(reportedError) && reportedError.code === 'E_CHUNK_LOAD_FAILED';\n return <ErrorCard error={reportedError} onRetry={retryable ? onRetry : undefined} />;\n }\n return <CatchingBoundary reportedError={null} onRetry={onRetry}>{children}</CatchingBoundary>;\n}\n\n// ── The state-owning inner (everything here is INSIDE the boundary) ─────────\n\nfunction EditorRootInner(\n props: EditorRootProps & {\n internals: EditorRootInternals;\n /** Stash the latest audit report on the OUTER Root (which survives a\n * boundary catch) — see the audit memo below. */\n recordAudit: (report: EditorAuditReport) => void;\n },\n): React.ReactElement {\n const {\n shop,\n product,\n design,\n throttleMs = 200,\n onMockups,\n onRenderError,\n onIssue,\n wsUrl,\n services,\n children,\n internals,\n recordAudit,\n __validation = 'throw',\n } = props;\n\n // The design's INITIAL placement (its active artboard) — keys the session\n // and anchors validation. The placement being EDITED is `activePlacement`\n // below (ADR-0088); the two coincide for single-placement designs.\n const placement = useMemo(() => design.toJSON().activeArtboard, [design]);\n // ADR-0101: the artboard list is LIVE — split/link add and remove artboards\n // at runtime — so it derives from the one design-state store, not the seed.\n const liveState = useSyncExternalStore(internals.store.subscribe, internals.store.getState, internals.store.getState);\n const artboardNamesKey = liveState.artboards.map((a) => a.name).join('\\u0000');\n /** Every artboard name in the live design, in author order; the first is the base. */\n const placements = useMemo(\n () => (artboardNamesKey ? artboardNamesKey.split('\\u0000') : []),\n [artboardNamesKey],\n );\n /** The product's required image placements (product order). Keyed on the\n * label list, not `product` identity (embedders pass inline objects). */\n const requiredKey = JSON.stringify(requiredPlacementLabels(product));\n const requiredPlacements = useMemo<string[]>(() => JSON.parse(requiredKey) as string[], [requiredKey]);\n\n // Active placement (ADR-0088): Root-owned UI state, derived-on-mismatch so a\n // NEW design never renders a frame with the old design's placement. Switching\n // costs zero session work — the session is keyed on the design's identity,\n // and per-placement renders already target every artboard by name.\n const [placementChoice, setPlacementChoice] = useState<{ design: AnyDesign; label: string } | null>(null);\n const activePlacement =\n placementChoice && placementChoice.design === design ? placementChoice.label : placement;\n const selectPlacement = useMemo(\n () => (label: string) => {\n const valid = [...new Set([...requiredPlacements, ...placements])];\n if (!valid.includes(label)) {\n throw new EditorError(\n 'E_UNKNOWN_PLACEMENT',\n `no placement \"${label}\" — the product's placements are ` +\n `${JSON.stringify(requiredPlacements)} and the design's artboards are ` +\n `${JSON.stringify(placements)} (ADR-0088 / ADR-0101).`,\n { placement: label, validNames: valid, docSlug: 'embed-mode' },\n );\n }\n // A LINKED placement (no artboard of its own) renders the base, so\n // selecting it edits the base — never a silent split (ADR-0101 §3).\n const base = placements[0] ?? label;\n setPlacementChoice({ design, label: placements.includes(label) ? label : base });\n },\n [design, placements, requiredPlacements],\n );\n /** Latest pushRender for the canvas-free split/link path (defined below). */\n const pushRenderRef = useRef<((state: RenderState, throttle?: number) => void) | null>(null);\n // ADR-0101 split / link. With a mounted Editor.Canvas the editor document\n // is the write authority (the op goes through the CanvasBridge command\n // path and lands in the store via onChange); without one the store applies\n // the same immutable update itself and re-pushes the render.\n const splitPlacement = useMemo(\n () => (label: string) => {\n if (!requiredPlacements.includes(label) && !placements.includes(label)) {\n throw new EditorError(\n 'E_UNKNOWN_PLACEMENT',\n `cannot split \"${label}\" — the product's placements are ` +\n `${JSON.stringify(requiredPlacements)} (ADR-0101).`,\n { placement: label, validNames: requiredPlacements, docSlug: 'embed-mode' },\n );\n }\n if (!placements.includes(label)) {\n const bridge = internals.registry.getCanvasBridge();\n if (bridge) bridge.splitArtboard(label);\n else {\n internals.store.splitArtboard(label);\n pushRenderRef.current?.(serializeStateForServer(internals.store.getState()));\n }\n }\n setPlacementChoice({ design, label });\n },\n [design, placements, requiredPlacements, internals],\n );\n const linkPlacement = useMemo(\n () => (label: string) => {\n const base = placements[0];\n if (label === base) {\n throw new EditorError(\n 'E_LINK_BASE',\n `\"${label}\" is the base artboard — every linked placement inherits it, so it ` +\n `cannot be re-linked. Link a split placement instead, or call linkAll(). ` +\n `Artboards: ${JSON.stringify(placements)}.`,\n { artboardName: label, validNames: placements.slice(1), docSlug: 'embed-mode' },\n );\n }\n if (!placements.includes(label)) return;\n const bridge = internals.registry.getCanvasBridge();\n if (bridge) bridge.removeArtboard(label);\n else {\n internals.store.removeArtboard(label);\n pushRenderRef.current?.(serializeStateForServer(internals.store.getState()));\n }\n if (activePlacement === label && base) setPlacementChoice({ design, label: base });\n },\n [design, placements, internals, activePlacement],\n );\n\n // Seed the editor document's artboard from the DESIGN, not EditorProvider's\n // \"Artboard 1\" 1000×1000 default. The document mounts with Root (D9) and a\n // render can fire before Editor.Canvas's chunk rebuilds it from the live\n // seed — with the default it briefly serializes an artboard named\n // \"Artboard 1\" against placement \"Front\" and the SDK warns \"no matching\n // artboard in the state\" twice at every mount. Seeding from the design\n // makes the pre-canvas document correct from the first frame (and is what\n // a no-canvas composition's document should look like anyway).\n const initialArtboardConfig = useMemo(() => {\n const artboard = design.toJSON().artboards[0];\n if (!artboard) return undefined;\n return {\n name: artboard.name,\n width: artboard.width,\n height: artboard.height,\n ...(artboard.backgroundColor ? { backgroundColor: artboard.backgroundColor } : {}),\n };\n }, [design]);\n\n // Buy-owned variant selection (ADR-0085 §2, P2): subscribe to the commerce\n // store so a host's `select()` re-renders this component with the newly\n // resolved variant. The resolved variant NEVER re-keys the session — it is\n // applied to the LIVE session below (`setProduct` + a re-push of the\n // current design state), so a color click costs one config message + one\n // render, not a WS teardown/re-grant/reconnect.\n useSyncExternalStore(\n internals.commerce.subscribe,\n internals.commerce.getVersion,\n internals.commerce.getVersion,\n );\n // RENDER with the best match for the current (possibly partial) selection —\n // NOT the strict `resolvedVariantId()` Buy gates on. The strict one is\n // `undefined` until every required axis is picked, and rendering through it\n // meant a color-swatch click did nothing until the shopper had also picked\n // size/pocket/etc. — the photo must follow the pick immediately.\n const selectedVariantId = internals.commerce.renderVariantId();\n\n // #566: fetch the product's printable-area guides (camera cutouts, safe\n // areas) so the editor shows them automatically — without this, a buyer can\n // edit artwork that sits under hardware and the mockup never changes, with\n // no signal anywhere. variantId IS a gvid; fall back to the catalog's\n // default variant. Gated below on the design's artboard matching the\n // print-file frame the guides were authored in (same gate as snowcone.app).\n // The SELECTED variant wins — guides follow the variant being rendered.\n const guideBundle = usePieceGuideBundle(selectedVariantId ?? product.variantId ?? product.defaultGvid);\n const pieceGuides = useMemo(() => {\n if (!guideBundle) return null;\n // The artboard being EDITED (ADR-0088 switching; ADR-0101 split\n // placements) — its name lets a separate-mode product draw only that\n // placement's piece. Falls back to the base for a linked label.\n const artboards = design.toJSON().artboards;\n const artboard = artboards.find((a) => a.name === activePlacement) ?? artboards[0];\n return pieceGuidesForArtboard(guideBundle, artboard) ?? null;\n }, [guideBundle, design, activePlacement]);\n\n // Keep the latest callbacks reachable without re-creating the session.\n const onMockupsRef = useRef(onMockups);\n const onRenderErrorRef = useRef(onRenderError);\n const onIssueRef = useRef(onIssue);\n onMockupsRef.current = onMockups;\n onRenderErrorRef.current = onRenderError;\n onIssueRef.current = onIssue;\n\n const [mockups, setMockups] = useState<MockupResult[]>([]);\n const [isRendering, setIsRendering] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const hasGrant = Boolean(('grantUrl' in props && props.grantUrl) || ('grant' in props && props.grant));\n\n // One session per (shop, product, placement, auth). Key it on the product's\n // identity-BEARING fields, not the object reference — so an embedder passing\n // an inline `product={{…}}` (the natural way to write it) doesn't rebuild the\n // session and reconnect on every render. A real change (different product,\n // mockups, or variant) still re-keys it. `options`/`placements` are advisory\n // (fail-fast validation) so they don't need to force a rebuild.\n const auth = toGetToken(props);\n const authKey = 'grantUrl' in auth ? auth.grantUrl : 'getToken';\n const productKey = `${product.productId}|${product.mockupIds.join(',')}|${product.variantId ?? ''}`;\n // ADR-0099 bundle session: the per-role picks + variants are the variant\n // identity. They are NOT part of the session key — a change is a NEW config\n // message on the open socket (below), exactly like a Buy-owned variant\n // change — but they ARE part of the validation key, so a wrong pick set is\n // re-checked at mount time, not just at the server.\n const bundleKey = product.picks || product.variants ? JSON.stringify([product.picks ?? null, product.variants ?? null]) : '';\n\n // Wiring validation. Editor.Root throws (F3 — fails loud into the boundary,\n // visible to headless agents); the legacy <RealtimeEmbed> wrapper keeps the\n // advisory dev-only console diagnostics. The ref-based dedup survives\n // StrictMode's deliberate unmount/remount cycle.\n const validationKey = `${shop}|${productKey}|${bundleKey}|${placement}|${hasGrant}`;\n // Render-time on purpose: in throw mode a wiring mistake must throw into\n // Root's boundary, not log (F3 — console.error is invisible to headless\n // agents). Memoized so it runs once per meaningful change. The surviving\n // (non-fatal) issues are returned for the `onIssue` machine channel below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const advisoryIssues = useMemo<EmbedIssue[]>(() => {\n const issues = collectEmbedIssues({ shop, product, design, hasGrant });\n if (__validation !== 'throw') return issues;\n const fatal = issues.find((i) => i.severity === 'error');\n if (fatal) {\n throw new EditorError('E_EMBED_CONFIG', fatal.message, {\n issue: fatal.issue,\n docSlug: 'embed-mode',\n });\n }\n for (const issue of issues) {\n if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {\n console.warn(`[Editor.Root] ${issue.message}`);\n }\n }\n return issues;\n }, [validationKey, __validation]);\n // Deliver advisory issues through `onIssue` — in an effect (a host callback\n // may set state), deduped per wiring identity, dev AND prod.\n const reportedIssuesKeyRef = useRef<string | null>(null);\n useEffect(() => {\n if (advisoryIssues.length === 0) return;\n if (reportedIssuesKeyRef.current === validationKey) return;\n reportedIssuesKeyRef.current = validationKey;\n for (const issue of advisoryIssues) onIssueRef.current?.(issue);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [advisoryIssues, validationKey]);\n const validatedKeyRef = useRef<string | null>(null);\n useEffect(() => {\n if (__validation !== 'warn') return;\n if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {\n if (validatedKeyRef.current === validationKey) return;\n validatedKeyRef.current = validationKey;\n validateEmbed({ shop, product, design, hasGrant });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [validationKey, __validation]);\n\n // RenderSession's constructor fail-fasts (e.g. a variant product with no\n // variantId) by THROWING. Catch it here so a config mistake surfaces through\n // `onRenderError` + the error state instead of throwing during render and\n // white-screening the whole host page.\n const sessionResult = useMemo<{ session: RenderSession } | { error: string }>(\n () => {\n try {\n return { session: new RenderSession({ shop, product, wsUrl, ...auth }) };\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) };\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [shop, productKey, placement, wsUrl, authKey]\n );\n const session = 'session' in sessionResult ? sessionResult.session : null;\n const constructError = 'error' in sessionResult ? sessionResult.error : null;\n\n const pushRender = useMemo(() => {\n return (state: RenderState, throttle = throttleMs) => {\n if (!session) return;\n setError(null);\n setIsRendering(true);\n const handleSendError = (err: unknown) => {\n const message = err instanceof Error ? err.message : String(err);\n setError(message);\n setIsRendering(false);\n onRenderErrorRef.current?.(message);\n };\n const sendSlice = (label: string, ab: Record<string, unknown>) =>\n void session\n .renderState(label, { schemaVersion: state.schemaVersion, artboards: [ab] }, throttle)\n .catch(handleSendError);\n\n // ADR-0101: resolve base + per-placement overrides ONCE (placementLinks)\n // — every required placement gets an artboard: its own when split, the\n // base relabelled when linked (the server re-fits it per placement).\n // Then ADR-0088: one renderState per artboard — the documented\n // multi-placement wire pattern. The server renders once it has a state\n // for EVERY required placement; throttle, dedup, and response\n // versioning are per-placement in the SDK, so the sends never starve\n // each other. A single-placement product degenerates to one send.\n const expanded = expandRequestForPlacements(state, requiredPlacementLabels(product));\n const artboards = (expanded.artboards ?? []) as Array<Record<string, unknown> & { name?: string }>;\n if (artboards.length > 1) {\n for (const ab of artboards) {\n // The artboard NAME inside the sent state must equal the placement\n // arg (warnPlacementArtboardMismatch) — expansion already relabelled\n // inherited slices.\n sendSlice(typeof ab.name === 'string' && ab.name ? ab.name : placement, ab);\n }\n return;\n }\n\n void session.renderState(placement, state, throttle).catch(handleSendError);\n };\n }, [session, placement, product, throttleMs]);\n pushRenderRef.current = pushRender;\n\n useEffect(() => {\n // Construction fail-fast (caught above) — surface it instead of rendering.\n if (constructError) {\n setError(constructError);\n setIsRendering(false);\n onRenderErrorRef.current?.(constructError);\n return;\n }\n if (!session) return;\n\n session.onMockups((results) => {\n setMockups(results);\n setIsRendering(false);\n onMockupsRef.current?.(results);\n });\n session.onError((message) => {\n setError(message);\n setIsRendering(false);\n onRenderErrorRef.current?.(message);\n });\n\n // Seed the first mockup from the design before any edit, so a freshly\n // mounted embed shows a real mockup immediately (no duplicate seed state —\n // the design is the single source).\n pushRender(design.toServerRequest());\n\n return () => session.close();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [session, constructError]);\n\n // Apply a Buy-owned variant change to the LIVE session (no re-key). The\n // baseline per session is the prop variant it was constructed with; a\n // selection that resolves elsewhere sends `setProduct` (config on the open\n // socket) and re-pushes the CURRENT design state so every Preview updates.\n const appliedVariantRef = useRef<{ session: RenderSession | null; variantId: string | undefined }>({\n session: null,\n variantId: undefined,\n });\n useEffect(() => {\n if (!session || !selectedVariantId) return;\n const applied = appliedVariantRef.current;\n const baseline = applied.session === session ? applied.variantId : product.variantId;\n if (selectedVariantId === baseline) {\n appliedVariantRef.current = { session, variantId: baseline };\n return;\n }\n appliedVariantRef.current = { session, variantId: selectedVariantId };\n session.setProduct({ ...product, variantId: selectedVariantId });\n pushRender(serializeStateForServer(internals.store.getState()));\n // `product` identity is deliberately NOT a dep (embedders pass inline\n // objects); a REAL product change re-keys the session above, which resets\n // the baseline through `applied.session !== session`.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [session, selectedVariantId]);\n\n // ADR-0099: a bundle pick / per-role variant change is a NEW config message\n // on the LIVE session (the server re-validates it — typed refusals arrive on\n // onError — and re-derives the required placement set), then the CURRENT\n // design state is re-pushed so every Preview shows the new member set.\n // Same shape as the Buy-owned variant effect above: no session re-key.\n const appliedBundleRef = useRef<{ session: RenderSession | null; key: string }>({ session: null, key: '' });\n useEffect(() => {\n if (!session || !bundleKey) return;\n const applied = appliedBundleRef.current;\n if (applied.session === session && applied.key === bundleKey) return;\n const first = applied.session !== session;\n appliedBundleRef.current = { session, key: bundleKey };\n if (first) return; // the session was constructed with this pick set\n session.setProduct(product);\n pushRender(serializeStateForServer(internals.store.getState()));\n // `product` identity is deliberately NOT a dep (embedders pass inline\n // objects); only the pick/variant content re-sends.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [session, bundleKey]);\n\n // Runtime silent-hang backstop. While a render is in flight, arm a timer; if no\n // mockup (or error) lands within SLOW_RENDER_HINT_MS, surface an actionable\n // hint. Unlike the mount-time wiring guard this fires ONLY on an actual stall,\n // so it never nags a working embed — and it covers every silent-hang cause, not\n // just missing variantId. The console hint stays dev-only; `onIssue` gets the\n // structured `slow-render` issue in every env (agents and telemetry don't read\n // the console); cleared the moment `isRendering` flips false.\n useEffect(() => {\n if (!isRendering) return;\n const timer = setTimeout(() => {\n const message = slowRenderHint(placement);\n if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {\n console.warn(message);\n }\n onIssueRef.current?.({ severity: 'warn', issue: 'slow-render', message });\n }, SLOW_RENDER_HINT_MS);\n return () => clearTimeout(timer);\n }, [isRendering, placement]);\n\n const value = useMemo<EmbedContextValue>(\n () => ({\n session,\n design,\n // The ACTIVE placement (ADR-0088): Editor.Canvas follows it as its\n // controlled artboard; single-placement designs never see it move.\n placement: activePlacement,\n placements,\n selectPlacement,\n requiredPlacements,\n splitPlacement,\n linkPlacement,\n product,\n mockups,\n isRendering,\n error,\n throttleMs,\n pieceGuides,\n pushRender,\n stateStore: internals.store,\n }),\n [session, design, activePlacement, placements, selectPlacement, requiredPlacements, splitPlacement, linkPlacement, product, mockups, isRendering, error, throttleMs, pieceGuides, pushRender, internals.store]\n );\n\n // Single validation point for the part registry (ADR-0085 §4). Parts\n // register in their layout effects (so a whole commit's registrations\n // arrive together — no race against the lazy canvas chunk); each change\n // re-renders this component, and validation throws RENDER-side, where\n // Root's boundary reliably contains it (layout-effect throws are not\n // dependably boundary-caught across React 18 + DOM test environments).\n const registryVersion = useSyncExternalStore(\n internals.registry.subscribe,\n internals.registry.getVersion,\n internals.registry.getVersion,\n );\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useMemo(() => {\n // Snapshot the audit BEFORE validating: a composition that throws\n // (E_REQUIRES_CANVAS, E_DUPLICATE_CANVAS) unmounts the parts and empties\n // the registry, so `onAudit` must report from the registry state the\n // throw saw — recorded here, fired by the outer Root (outside the\n // boundary) once mount settles.\n recordAudit(\n computeEditorAudit({ registry: internals.registry, store: internals.store, product }),\n );\n internals.registry.validate();\n }, [internals.registry, registryVersion]);\n\n const body = (\n <EditorRootInternalsContext.Provider value={internals}>\n <EmbedContext.Provider value={value}>\n {/* P1 provider inversion (D9: state always, renderer lazy): Root owns\n BOTH provider boundaries — EmbedContext above, and the editor\n document (EditorProvider) here, mounted in EVERY composition.\n Its graph is renderer-free (element/renderer split), CI-gated by\n the import-graph check. `Editor.Canvas`'s inner SnowconeCanvas\n mounts with `externalProvider` and writes into THIS document.\n The bound-layer guard sits ABOVE EditorProvider so the command\n layer can consult the parts registry (E_BOUND_LAYER_MUTATION). */}\n <BoundLayerGuardContext.Provider value={internals.registry}>\n <EditorProvider\n {...(initialArtboardConfig ? { initialArtboardConfig } : {})}\n >\n {children}\n </EditorProvider>\n </BoundLayerGuardContext.Provider>\n </EmbedContext.Provider>\n </EditorRootInternalsContext.Provider>\n );\n\n // Only mount a services provider when configured — `<Editor.Canvas>`'s\n // inner SnowconeCanvas inherits it through context.\n if (services) {\n return <CanvasServicesProvider services={services}>{body}</CanvasServicesProvider>;\n }\n return body;\n}\n\n/**\n * The root of an `Editor.*` composition. See the module doc for the state\n * model; see `RealtimeEmbed` for the legacy turnkey wrapper this was\n * extracted from.\n *\n * Stable since ADR-0085 P4 (the default editor is rebuilt from this public\n * surface, CI-gated); additive-only from here.\n */\nexport function EditorRoot(props: EditorRootProps): React.ReactElement {\n const { design, product, onAudit } = props;\n\n // One store + registry per (design) — remounting with a new design reseeds.\n // The commerce store is keyed on the PRODUCT's identity instead (a new\n // product or a host-driven `variantId` prop change reseeds the selection;\n // design edits never touch it).\n const productIdentity = `${product.productId}|${product.variantId ?? ''}`;\n const internalsRef = useRef<{ design: AnyDesign; internals: Omit<EditorRootInternals, 'reportInvariant' | 'reportRuntimeError' | 'commerce'> } | null>(null);\n const commerceRef = useRef<{ productIdentity: string; commerce: CommerceStateStore } | null>(null);\n const [reportedError, setReportedError] = useState<EditorError | null>(null);\n if (internalsRef.current === null || internalsRef.current.design !== design) {\n internalsRef.current = {\n design,\n internals: {\n store: new DesignStateStore(design.toJSON()),\n registry: new EditorPartsRegistry(),\n },\n };\n }\n if (commerceRef.current === null || commerceRef.current.productIdentity !== productIdentity) {\n commerceRef.current = { productIdentity, commerce: new CommerceStateStore(product) };\n }\n\n const internals = useMemo<EditorRootInternals>(\n () => ({\n ...internalsRef.current!.internals,\n commerce: commerceRef.current!.commerce,\n ...makeInvariantReporter(setReportedError),\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [internalsRef.current.internals, commerceRef.current.commerce]\n );\n\n // ── Composition audit (`Editor.audit()`, agentic-DX #10) ──────────────────\n // The inner component records a snapshot every time the registry changes\n // (render-side, BEFORE registry validation can throw); this outer component\n // — which survives a boundary catch — fires `onAudit` once after mount\n // settles and answers the imperative `auditEditor()` with a FRESH report.\n const productRef = useRef(product);\n productRef.current = product;\n const onAuditRef = useRef(onAudit);\n onAuditRef.current = onAudit;\n const auditSnapshotRef = useRef<EditorAuditReport | null>(null);\n const recordAudit = useCallback((report: EditorAuditReport) => {\n auditSnapshotRef.current = report;\n }, []);\n const computeAudit = useCallback(\n () =>\n computeEditorAudit({\n registry: internalsRef.current!.internals.registry,\n store: internalsRef.current!.internals.store,\n product: productRef.current,\n }),\n [],\n );\n // Most-recent mounted Root answers `auditEditor()`.\n useLayoutEffect(() => registerRootForAudit({ compute: computeAudit }), [computeAudit]);\n // Fire once after mount settles. Parts register in the first commit's\n // layout effects; the registry bump re-renders the inner component, which\n // records the full snapshot — but React may flush this passive effect\n // BEFORE that re-render (it flushes pending passive effects when a layout\n // effect schedules a sync update), so the fire is deferred one microtask:\n // by then every synchronous settle step — registrations, the snapshot\n // re-render, even a composition throw into the boundary — has happened.\n // Dev AND prod, like `onIssue`.\n const auditFiredRef = useRef(false);\n useEffect(() => {\n let cancelled = false;\n queueMicrotask(() => {\n if (cancelled || auditFiredRef.current) return;\n auditFiredRef.current = true;\n onAuditRef.current?.(auditSnapshotRef.current ?? computeAudit());\n });\n return () => {\n cancelled = true;\n };\n }, [computeAudit]);\n\n return (\n // `display: contents` — the .sc-root scope without a layout box, so the\n // host's grid/flex sees the parts directly (and the legacy RealtimeEmbed\n // wrapper, which had no DOM at all, stays layout-identical).\n <div className=\"sc-root\" style={{ display: 'contents' }} data-sc-part=\"root\">\n <EditorBoundary reportedError={reportedError} onRetry={() => setReportedError(null)}>\n <EditorRootInner {...props} internals={internals} recordAudit={recordAudit} />\n </EditorBoundary>\n </div>\n );\n}\n","'use client';\n\n/**\n * `<Editor.Canvas>` — the editable artboard, and the ONE lazy boundary of the\n * primitives (D9): all state mounts with `Editor.Root`; the heavy rendering\n * engine lives in {@link EditorCanvasImpl}'s chunk and loads only when this\n * part mounts. A no-canvas composition (Preview + TextField + Buy) never\n * fetches it — CI-asserted by the import-graph check.\n *\n * A failed chunk load (network/CDN) is a RUNTIME failure, not a composition\n * mistake: it routes to Root's error card with a retry affordance\n * (`E_CHUNK_LOAD_FAILED`) in every env. Retry clears the card, which remounts\n * this part and re-attempts the import.\n */\n\nimport React, { forwardRef, useEffect, useId, useLayoutEffect, useState, type CSSProperties, type ReactNode } from 'react';\nimport { EditorError } from '../../errors/editorError.js';\nimport { useEditorRootInternals, useRegisterEditorPart } from './RootInternals.js';\nimport type { EditorCanvasImplProps } from './EditorCanvasImpl.js';\nimport type { SnowconeCanvasHandle } from '../embed/SnowconeCanvas.js';\n\ntype ImplComponent = (typeof import('./EditorCanvasImpl.js'))['EditorCanvasImpl'];\n\nlet implLoader: () => Promise<ImplComponent> = () =>\n import('./EditorCanvasImpl.js').then((m) => m.EditorCanvasImpl);\n\n/** Load the heavy impl chunk. Exposed for the legacy `<RealtimeCanvas>`\n * wrapper so both share ONE lazy boundary (one chunk). @internal */\nexport function loadCanvasImpl(): Promise<ImplComponent> {\n return implLoader();\n}\n\n/** Swap the chunk loader — TEST-ONLY seam for the chunk-load-failure → error\n * card → retry contract (a real `import()` can't be made to fail once and\n * then succeed under the module cache). Returns a restore function.\n * @internal */\nexport function __setCanvasImplLoaderForTests(loader: () => Promise<ImplComponent>): () => void {\n const previous = implLoader;\n implLoader = loader;\n return () => {\n implLoader = previous;\n };\n}\n\nexport interface EditorCanvasProps {\n /** Your overlay controls — rendered inside the editor context, so the\n * binding hooks (`useTextBinding` …) resolve against live elements. */\n children?: ReactNode;\n /** Cap the canvas height in px. */\n maxHeight?: number;\n /**\n * The canvas's built-in selection-anchored floating toolbar (default\n * `true`). Pass `false` when your composition owns the contextual zone —\n * e.g. a conditionally-rendered `<Editor.Controls placement=\"docked\"/>` —\n * so suppression is declared HERE, in the type surface, rather than implied\n * by whether a docked Controls happens to be mounted this frame (a mounted\n * docked Controls still suppresses it either way, ADR-0085 §5).\n */\n floatingToolbar?: boolean;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * The editable artboard. Mount at most one under a Root\n * (`E_DUPLICATE_CANVAS`); mount none for the no-canvas personalization\n * composition.\n *\n * Stable since ADR-0085 P4 (the default editor is rebuilt from this public\n * surface, CI-gated); additive-only from here.\n */\nexport const EditorCanvas = forwardRef<SnowconeCanvasHandle, EditorCanvasProps>(function EditorCanvas(\n { children, maxHeight, floatingToolbar = true, className, style }: EditorCanvasProps,\n ref,\n): React.ReactElement {\n const internals = useEditorRootInternals('Editor.Canvas');\n // Census + the `floatingToolbar` declaration the audit's A_CONTROLS_INERT\n // check reads (`Editor.audit()`, #10).\n useRegisterEditorPart('Editor.Canvas', { floatingToolbar });\n const instanceId = useId();\n\n // Registration is by THIS component's mount, not the chunk's arrival — so\n // duplicate detection and requires-canvas validation never race the lazy\n // load (ADR-0085 §4).\n useLayoutEffect(() => {\n return internals.registry.registerCanvas(instanceId);\n }, [internals.registry, instanceId]);\n\n const [Impl, setImpl] = useState<ImplComponent | null>(null);\n useEffect(() => {\n let cancelled = false;\n loadCanvasImpl().then(\n (component) => {\n if (!cancelled) setImpl(() => component);\n },\n (err) => {\n if (cancelled) return;\n internals.reportRuntimeError(\n new EditorError(\n 'E_CHUNK_LOAD_FAILED',\n `the editor's rendering chunk failed to load (${err instanceof Error ? err.message : String(err)}). ` +\n 'This is a network/CDN failure, not a composition mistake — retry, or check the deployment ' +\n 'serves the @snowcone-app/canvas lazy chunks.',\n { cause: err instanceof Error ? err.message : String(err), docSlug: 'embed-mode' },\n ),\n );\n },\n );\n return () => {\n cancelled = true;\n };\n }, [internals]);\n\n if (!Impl) {\n // Lightweight placeholder while the chunk loads — keeps the host layout\n // stable; themed via .sc-root tokens like every part.\n return (\n <div\n data-sc-part=\"canvas\"\n data-sc-state=\"loading\"\n className={className}\n style={{ minHeight: maxHeight ?? 200, ...style }}\n aria-busy=\"true\"\n />\n );\n }\n\n return (\n // `builtinControls`: the canvas owns the floating contextual toolbar\n // unless the host opts out via `floatingToolbar={false}` or a docked\n // <Editor.Controls> is mounted (ADR-0085 §5). Only here — the legacy\n // <RealtimeCanvas> wrapper stays chrome-less.\n <Impl\n ref={ref}\n kit=\"embed-only\"\n partAttr=\"canvas\"\n builtinControls={floatingToolbar}\n maxHeight={maxHeight}\n className={className}\n style={style}\n >\n {children}\n </Impl>\n );\n});\n\nexport type { EditorCanvasImplProps };\n","'use client';\n\n/**\n * `usePlacements()` — the headless floor under `<Editor.Placements/>`\n * (ADR-0088, ADR-0101): the product's placements, which one is active,\n * which ones are LINKED (inherit the base design), and the switches.\n *\n * Linked by default: a design with one artboard renders it on every required\n * placement. `split(label)` gives a placement its own artboard (cloned from\n * the base); `link(label)` collapses it back. Every value derives from the\n * LIVE design state, so split/link at runtime re-render consumers.\n *\n * Works in EVERY composition under `Editor.Root`, canvas-free ones included —\n * switching there just re-targets which artboard the (future) canvas would\n * show; bindings and renders already span all placements. Switching never\n * re-keys the render session.\n */\n\nimport { useMemo } from 'react';\nimport { useEmbedContext } from '../embed-realtime/context.js';\nimport { resolvePlacementLinks } from './placementLinks.js';\n\nexport interface PlacementInfo {\n /** The placement label (= the design artboard name when split, e.g. 'Front'). */\n label: string;\n /** True when this placement is the one being edited. For a linked\n * placement this is true while its BASE is active (that is the artboard\n * it renders). */\n active: boolean;\n /** True when this placement has no artboard of its own and renders the\n * base design (ADR-0101). The base's own label is never inherited. */\n inherited: boolean;\n}\n\nexport interface UsePlacementsReturn {\n /** Every placement, in product order (then any extra authored artboards). */\n placements: PlacementInfo[];\n /** The artboard being edited — a real artboard name, never a linked label. */\n activePlacement: string;\n /** The base artboard (the first one) — what linked placements inherit. */\n basePlacement: string;\n /** True when the product has 2+ placements and ALL of them render the base\n * (no placement is split): \"one design on every area\". */\n linked: boolean;\n /** Switch the active placement. A linked label activates the base (that is\n * what it renders — editing it edits every linked area). Throws\n * `EditorError E_UNKNOWN_PLACEMENT` for a label that is neither a product\n * placement nor a design artboard. */\n select: (label: string) => void;\n /** Give `label` its own artboard, cloned from the base, and activate it.\n * No-op when already split. Throws `E_UNKNOWN_PLACEMENT`. */\n split: (label: string) => void;\n /** Drop `label`'s own artboard so it inherits the base again. No-op when\n * already linked. Throws `E_LINK_BASE` for the base itself. */\n link: (label: string) => void;\n /** \"Customize separately\": split every placement that still inherits. */\n splitAll: () => void;\n /** \"Use one design for all\": link every split placement back to the base. */\n linkAll: () => void;\n}\n\nexport function usePlacements(): UsePlacementsReturn {\n const { placements: artboardNames, requiredPlacements, placement, selectPlacement, splitPlacement, linkPlacement } =\n useEmbedContext();\n return useMemo(() => {\n const links = resolvePlacementLinks(artboardNames, requiredPlacements);\n const base = artboardNames[0] ?? placement;\n const infos: PlacementInfo[] = links.map((l) => ({\n label: l.label,\n inherited: l.inherited,\n active: l.inherited ? placement === base : placement === l.label,\n }));\n const linked = infos.length > 1 && infos.every((p) => p.inherited || p.label === base);\n return {\n placements: infos,\n activePlacement: placement,\n basePlacement: base,\n linked,\n select: selectPlacement,\n split: splitPlacement,\n link: linkPlacement,\n splitAll: () => {\n for (const p of infos) if (p.inherited) splitPlacement(p.label);\n },\n linkAll: () => {\n for (const p of infos) if (!p.inherited && p.label !== base) linkPlacement(p.label);\n },\n };\n }, [artboardNames, requiredPlacements, placement, selectPlacement, splitPlacement, linkPlacement]);\n}\n","'use client';\n\n/**\n * `<Editor.Placements>` — the placement switcher (ADR-0088) and the link\n * switch (ADR-0101). The minimal styled part over {@link usePlacements} —\n * hosts wanting bespoke UI use the hook directly.\n *\n * - LINKED (the default — one design on every area): one non-interactive\n * pill naming the set (\"Both sides\" / \"All 4 areas\") and one action,\n * \"Customize separately\" (`splitAll`). No tabs: there is nothing to switch.\n * - SPLIT (any placement has its own artboard): one tab per placement —\n * a still-linked tab is marked `data-sc-linked=\"true\"` and activates the\n * base when clicked (that is what it renders) — plus one action, \"Use one\n * design for all\" (`linkAll`).\n *\n * Renders NOTHING for a single-placement product (no dead chrome) — mount it\n * unconditionally and it appears exactly when the product has a second side.\n *\n * Canvas-free compositions may mount it too (it operates on Root state, not\n * the renderer).\n */\n\nimport React, { type CSSProperties } from 'react';\nimport { usePlacements } from './usePlacements.js';\n\nexport interface EditorPlacementsLabels {\n /** Pill text while linked. Default: \"Both sides\" for two placements,\n * \"All N areas\" otherwise. Receives the placement labels. */\n linked?: (labels: string[]) => string;\n /** The split action. Default \"Customize separately\". */\n customizeSeparately?: string;\n /** The re-link action. Default \"Use one design for all\". */\n useOneDesign?: string;\n}\n\nexport interface EditorPlacementsProps {\n className?: string;\n style?: CSSProperties;\n /** Override the built-in copy (localization). */\n labels?: EditorPlacementsLabels;\n}\n\nconst defaultLinkedLabel = (labels: string[]): string =>\n labels.length === 2 ? 'Both sides' : `All ${labels.length} areas`;\n\nconst actionStyle: CSSProperties = {\n font: 'inherit',\n fontSize: '12px',\n color: 'var(--sc-color-muted-foreground, inherit)',\n background: 'transparent',\n border: 'none',\n padding: '2px 8px',\n cursor: 'pointer',\n textDecoration: 'underline',\n textUnderlineOffset: '4px',\n};\n\n/**\n * Placement tabs + link switch for a multi-placement product.\n *\n * Styling contract: `data-sc-part=\"placements\"` on the row (with\n * `data-sc-linked=\"true|false\"`), `data-sc-part=\"placements-item\"` +\n * `data-sc-active=\"true|false\"` + `data-sc-linked=\"true|false\"` +\n * `aria-pressed` per tab, `data-sc-part=\"placements-link-toggle\"` on the\n * split / re-link action — restyle via those hooks and the `.sc-root`\n * tokens; the built-in styling is deliberately minimal.\n */\nexport function EditorPlacements({ className, style, labels }: EditorPlacementsProps): React.ReactElement | null {\n const { placements, linked, select, splitAll, linkAll } = usePlacements();\n if (placements.length < 2) return null;\n const names = placements.map((p) => p.label);\n\n return (\n <div\n data-sc-part=\"placements\"\n data-sc-linked={linked ? 'true' : 'false'}\n className={className}\n style={{ display: 'flex', alignItems: 'center', gap: '4px', ...style }}\n >\n {linked ? (\n <span\n data-sc-part=\"placements-item\"\n data-sc-active=\"true\"\n data-sc-linked=\"true\"\n title={names.join(' · ')}\n style={{ fontSize: '13px', fontWeight: 700, padding: '2px 8px', color: 'var(--sc-color-foreground, inherit)' }}\n >\n {(labels?.linked ?? defaultLinkedLabel)(names)}\n </span>\n ) : (\n placements.map(({ label, active, inherited }) => (\n <button\n key={label}\n type=\"button\"\n data-sc-part=\"placements-item\"\n data-sc-active={active ? 'true' : 'false'}\n data-sc-linked={inherited ? 'true' : 'false'}\n aria-pressed={active}\n onClick={() => select(label)}\n style={{\n font: 'inherit',\n fontSize: '13px',\n fontWeight: active ? 700 : 400,\n color: 'var(--sc-color-foreground, inherit)',\n opacity: inherited ? 0.6 : 1,\n background: 'transparent',\n border: 'none',\n borderRadius: '9999px',\n padding: '2px 8px',\n cursor: active ? 'default' : 'pointer',\n textDecoration: active ? 'underline' : 'none',\n textUnderlineOffset: '4px',\n }}\n >\n {label}\n </button>\n ))\n )}\n <button\n type=\"button\"\n data-sc-part=\"placements-link-toggle\"\n data-sc-linked={linked ? 'true' : 'false'}\n onClick={linked ? splitAll : linkAll}\n style={actionStyle}\n >\n {linked\n ? (labels?.customizeSeparately ?? 'Customize separately')\n : (labels?.useOneDesign ?? 'Use one design for all')}\n </button>\n </div>\n );\n}\n","'use client';\n\n/**\n * The snowcone rainbow render-in-flight overlay for `Editor.Preview`\n * (`loadingOverlay` prop) — the sc-namespaced port of the www PDP's candy\n * loader (`LoadingOverlayPrismCandy` in @snowcone-app/ui; the canvas package\n * is dependency-free of `ui`, hence the port). Styles live in `embed.css`\n * (`.sc-prism-*`); see the block comment there for the blend-mode rules that\n * make the bands tint the artwork instead of collapsing to dark bars.\n *\n * Choreography (mirrors the PDP's `useLoadingOverlay` + linger):\n * - `useRenderLoadingOverlay(isRendering)` waits 200ms before mounting, so\n * a fast/cached render never flashes the loader.\n * - When the render lands it holds for 400ms (the new mockup image is\n * usually decoding right then), then fades out over 400ms and unmounts.\n */\n\nimport React, { memo, useCallback, useEffect, useRef, useState } from 'react';\n\nconst SHOW_DELAY_MS = 200;\nconst LINGER_MS = 400;\n\ntype Particle = {\n left: number;\n top: number;\n delay: string;\n duration: string;\n size: number;\n};\n\nfunction generateParticles(): Particle[] {\n return Array.from({ length: 10 }, () => ({\n left: 2 + Math.random() * 96,\n top: 2 + Math.random() * 96,\n delay: (Math.random() * 3.5).toFixed(1),\n duration: (3 + Math.random() * 2).toFixed(1),\n size: 3 + Math.random() * 5,\n }));\n}\n\nlet propertiesRegistered = false;\n/**\n * Belt-and-suspenders re-registration of the `@property` declarations in\n * embed.css: iOS Safari silently ignores `@property` inside dynamically\n * inserted stylesheets (which is how many host bundlers inject CSS), and\n * without registration the custom-property transitions snap instead of\n * interpolating — the rainbow vanishes instantly rather than fading.\n */\nfunction ensurePrismProperties(): void {\n if (propertiesRegistered || typeof CSS === 'undefined' || typeof CSS.registerProperty !== 'function') {\n return;\n }\n propertiesRegistered = true;\n try {\n CSS.registerProperty({ name: '--sc-prism-mount', syntax: '<number>', initialValue: '0', inherits: true });\n } catch {\n // Already registered (embed.css @property took, or an HMR remount) — fine.\n }\n try {\n CSS.registerProperty({ name: '--sc-prism-band', syntax: '<number>', initialValue: '0', inherits: false });\n } catch {\n // Already registered — fine.\n }\n}\n\nexport interface PreviewPrismOverlayProps {\n /** When false, fade out then call onExited (use it to unmount). */\n visible?: boolean;\n onExited?: () => void;\n /** \"dark\" (default): screen-blended neon bands for image/dark stages.\n * \"light\": multiply-blended candy bands on an opaque light plate. */\n variant?: 'dark' | 'light';\n}\n\nexport const PreviewPrismOverlay = memo(function PreviewPrismOverlay({\n visible = true,\n onExited,\n variant = 'dark',\n}: PreviewPrismOverlayProps): React.ReactElement {\n ensurePrismProperties();\n\n // Empty on first render (SSR-safe); fresh random field per show.\n const [particles, setParticles] = useState<Particle[]>([]);\n useEffect(() => {\n setParticles(generateParticles());\n }, []);\n\n // Apply the fade-in class one frame after mount so the transition plays.\n const [mounted, setMounted] = useState(false);\n useEffect(() => {\n const raf = requestAnimationFrame(() => setMounted(true));\n return () => cancelAnimationFrame(raf);\n }, []);\n\n const handleTransitionEnd = useCallback(\n (e: React.TransitionEvent<HTMLDivElement>) => {\n // background-color transitions in lockstep with --sc-prism-mount; fire\n // onExited only when the fade-out finishes.\n if (e.propertyName !== 'background-color') return;\n if (!visible) onExited?.();\n },\n [visible, onExited],\n );\n\n let fadeClass = '';\n if (!visible) fadeClass = 'sc-prism-fade-out';\n else if (mounted) fadeClass = 'sc-prism-fade-in';\n\n return (\n <div\n data-sc-part=\"preview-loading\"\n className={['sc-prism-overlay', variant === 'light' ? 'sc-prism-on-light' : '', fadeClass]\n .filter(Boolean)\n .join(' ')}\n onTransitionEnd={handleTransitionEnd}\n aria-hidden=\"true\"\n >\n {Array.from({ length: 6 }, (_, i) => (\n <div key={`b-${i}`} className=\"sc-prism-band\" />\n ))}\n {particles.map((p, i) => (\n <div\n key={`p-${i}`}\n className=\"sc-prism-particle\"\n style={{\n left: `${p.left}%`,\n top: `${p.top}%`,\n animationDelay: `${p.delay}s`,\n animationDuration: `${p.duration}s`,\n width: `${p.size}px`,\n height: `${p.size}px`,\n }}\n />\n ))}\n </div>\n );\n});\n\n/**\n * Show/hide choreography for a render-in-flight overlay: show-delayed mount\n * (fast renders never flash it), post-render linger, fade-out unmount.\n * Mirrors @snowcone-app/ui's `useLoadingOverlay` + the PDP hero's linger.\n */\nexport function useRenderLoadingOverlay(isLoading: boolean): {\n /** Mount the overlay? */\n showOverlay: boolean;\n /** The overlay's `visible` prop (false starts the fade-out). */\n overlayVisible: boolean;\n /** Pass as `onExited` — unmounts after the fade. */\n handleExited: () => void;\n} {\n const [showOverlay, setShowOverlay] = useState(false);\n const [lingering, setLingering] = useState(false);\n const showTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const lingerTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const shownRef = useRef(false);\n shownRef.current = showOverlay;\n\n useEffect(() => {\n if (isLoading) {\n setLingering(false);\n if (lingerTimerRef.current) clearTimeout(lingerTimerRef.current);\n showTimerRef.current = setTimeout(() => setShowOverlay(true), SHOW_DELAY_MS);\n } else {\n if (showTimerRef.current) {\n clearTimeout(showTimerRef.current);\n showTimerRef.current = null;\n }\n // Linger only if the overlay actually made it on screen — a render that\n // beat the show delay should never flash the loader afterwards.\n if (shownRef.current) {\n setLingering(true);\n lingerTimerRef.current = setTimeout(() => setLingering(false), LINGER_MS);\n }\n }\n return () => {\n if (showTimerRef.current) clearTimeout(showTimerRef.current);\n if (lingerTimerRef.current) clearTimeout(lingerTimerRef.current);\n };\n }, [isLoading]);\n\n const handleExited = useCallback(() => setShowOverlay(false), []);\n\n return {\n showOverlay,\n overlayVisible: isLoading || lingering,\n handleExited,\n };\n}\n","'use client';\n\n/**\n * `<Editor.Preview>` — the live product mockup (the buyable thing), extracted\n * from the legacy `<RealtimeMockup>` (which now wraps this).\n *\n * Reads the shared session's mockups from context and renders the rendered\n * image, updating as the shopper edits. Because every Preview shares one\n * session with the rest of the composition, it can never desync — and\n * MULTIPLE Previews under one Root are explicitly VALID (front/back; mockup\n * scenes via `mockupId`). Canvas-free by design: the no-canvas\n * personalization widget is Preview + TextField + Buy.\n */\n\nimport React, {\n isValidElement,\n useRef,\n type CSSProperties,\n type ReactElement,\n type ReactNode,\n type SyntheticEvent,\n} from 'react';\nimport { useEmbedContext } from '../embed-realtime/context.js';\nimport { useRegisterEditorPart } from './RootInternals.js';\nimport { PreviewPrismOverlay, useRenderLoadingOverlay } from '../editor/PreviewPrismOverlay.js';\nimport { EditorError } from '../../errors/editorError.js';\n\nexport interface EditorPreviewProps {\n /** Which mockup scene to show (a `product.mockupIds` entry). Defaults to the\n * first mockup that has rendered. */\n mockupId?: string;\n /** Shown before the first mockup arrives / while a render is in flight with no\n * prior image. Defaults to nothing. */\n fallback?: ReactNode;\n /** Alt text for the rendered image. */\n alt?: string;\n /**\n * The render-in-flight loading treatment. A mockup preview ALWAYS has one:\n * a server render takes real time, and the loader paints OVER the\n * still-visible previous mockup — it never blanks or replaces it.\n *\n * **Defaults to `\"dark\"`** — the snowcone rainbow (the www PDP's prism\n * loader): screen-blended neon bands shimmering over the previous mockup,\n * with a 200ms show-delay (cached/instant renders never flash it) and a\n * 400ms post-render linger. `\"light\"`: multiply-blended candy bands on an\n * opaque light plate, for previews on light cards. Pass a custom\n * `ReactElement` to render your own indicator instead — it mounts inside\n * the frame (absolutely positioned over the image) with the same\n * show-delay/linger choreography.\n *\n * In all of the above the part is a positioned stage:\n * `data-sc-part=\"preview\"` is a `.sc-preview-frame` div (which receives\n * `className`/`style`), the `<img>` inside is\n * `data-sc-part=\"preview-image\"`, and the loading layer is\n * `data-sc-part=\"preview-loading\"`.\n *\n * `\"host-owned\"` reverts to the bare `<img>` DOM with no overlay — pass it\n * ONLY when the host renders its own indicator, via the styling contract\n * (`data-sc-preview-state=\"rendering\"`) or the standalone\n * `<Editor.LoadingOverlay>` part.\n *\n * Anything else (`false`, `\"none\"`, …) throws `E_PREVIEW_NO_LOADER`, dev\n * AND prod: a mockup surface with no loading affordance is a composition\n * mistake (silent emptiness, then pop-in), not a preference.\n */\n loadingOverlay?: true | 'dark' | 'light' | 'host-owned' | ReactElement;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * How far the displayed device-pixel width may exceed the delivered mockup's\n * natural width before {@link resolutionMismatchHint} fires. Renders default to\n * 1000px wide, so a 1000px image inside a ~1100 device-px slot is fine (browser\n * downscale slack), but stretched across 2000 device px it looks soft and the\n * developer deserves to hear why.\n */\nexport const RESOLUTION_MISMATCH_RATIO = 1.2;\n\n/**\n * The render-width ladder a mismatch suggestion rounds UP to. Mirrors the\n * `product.width` guidance (\"bump to ~2000 for a crisp preview\") with sensible\n * steps — suggesting the exact device-px count would invite over-precise\n * configs that re-trigger on the next viewport.\n */\nconst SUGGESTED_WIDTHS = [1200, 1400, 1600, 1800, 2000, 2500, 3000, 4000] as const;\n\n/** Rounds a device-pixel width up to the next {@link SUGGESTED_WIDTHS} step\n * (capped at the top step). */\nexport function suggestRenderWidth(devicePx: number): number {\n for (const step of SUGGESTED_WIDTHS) {\n if (step >= devicePx) return step;\n }\n return SUGGESTED_WIDTHS[SUGGESTED_WIDTHS.length - 1];\n}\n\n/**\n * Builds the dev-console warning shown when a delivered mockup's natural width\n * is meaningfully below the width it's displayed at in DEVICE pixels (CSS width\n * × `devicePixelRatio`) — the \"my preview looks soft and nothing says why\"\n * trap: renders default to 1000px wide, which blurs on a large or high-density\n * display. Returns `null` when the resolution is adequate (within\n * {@link RESOLUTION_MISMATCH_RATIO}) or either measurement is unusable.\n */\nexport function resolutionMismatchHint(naturalWidth: number, devicePx: number): string | null {\n if (!(naturalWidth > 0) || !(devicePx > 0)) return null;\n if (devicePx <= naturalWidth * RESOLUTION_MISMATCH_RATIO) return null;\n const suggestion = suggestRenderWidth(devicePx);\n return (\n `[RealtimeMockup] mockup rendered at ${naturalWidth}px but displayed at ` +\n `~${devicePx} device px — the preview will look soft. Pass ` +\n `\\`product.width\\` (e.g. ${suggestion}) on the embed for a crisp preview.`\n );\n}\n\n/**\n * The live product mockup. Mount as many as you need under one Root.\n *\n * Stable since ADR-0085 P4 (the default editor is rebuilt from this public\n * surface, CI-gated); additive-only from here.\n */\ntype ResolvedLoadingOverlay = 'dark' | 'light' | 'host-owned' | ReactElement;\n\n/** The valid `loadingOverlay` states. Default ON; removal must be said in\n * words (`\"host-owned\"`); everything else is a loud mount error. */\nfunction resolveLoadingOverlay(\n value: EditorPreviewProps['loadingOverlay'],\n): ResolvedLoadingOverlay {\n if (value === undefined || value === true || value === 'dark') return 'dark';\n if (value === 'light' || value === 'host-owned') return value;\n if (isValidElement(value)) return value;\n throw new EditorError(\n 'E_PREVIEW_NO_LOADER',\n `Editor.Preview: invalid loadingOverlay value ${JSON.stringify(value)}. ` +\n 'A mockup preview always has a render-in-flight treatment (the loader ' +\n 'paints over the still-visible previous mockup). Omit the prop for the ' +\n 'default rainbow overlay, pass \"dark\" | \"light\", pass a custom ' +\n 'ReactElement, or declare \"host-owned\" if the host renders its own ' +\n 'indicator off data-sc-preview-state / <Editor.LoadingOverlay>.',\n { docSlug: 'preview-loading-overlay' },\n );\n}\n\nexport function EditorPreview({\n mockupId,\n fallback = null,\n alt = 'Live product mockup',\n loadingOverlay,\n className,\n style,\n}: EditorPreviewProps): React.ReactElement {\n const { mockups, error, isRendering } = useEmbedContext();\n // Census + the scene pin the audit's A_PREVIEW_AMBIGUOUS check reads\n // (`Editor.audit()`, #10). Tolerant of a missing Root by design — the\n // legacy <RealtimeMockup> wrapper mounts this part too.\n useRegisterEditorPart('Editor.Preview', { ...(mockupId !== undefined ? { mockupId } : {}) });\n\n // A preview always has a loading treatment — resolve (and validate) what\n // kind. Invalid values throw E_PREVIEW_NO_LOADER here, at mount, dev AND\n // prod, with the valid options in the message.\n const resolved = resolveLoadingOverlay(loadingOverlay);\n const overlayVariant: 'dark' | 'light' | null =\n resolved === 'dark' || resolved === 'light' ? resolved : null;\n const customOverlay = isValidElement(resolved) ? resolved : null;\n const overlayActive = resolved !== 'host-owned';\n\n // Render-in-flight overlay choreography (inert in host-owned mode — the\n // hook itself is unconditional, per the rules of hooks). \"As fast as\n // possible\" with a 200ms show-delay: a cached/instant render never flashes\n // the loader.\n const { showOverlay, overlayVisible, handleExited } = useRenderLoadingOverlay(\n overlayActive && isRendering,\n );\n\n // Mockup ids already warned about this mount — re-renders and repeated loads\n // of the same scene stay quiet; a different scene gets its own one warning.\n const warnedMockupIdsRef = useRef<Set<string>>(new Set());\n\n const result = mockupId\n ? mockups.find((m) => m.mockupId === mockupId && m.imageUrl)\n : mockups.find((m) => m.imageUrl);\n\n // Dev-only resolution check (the `process` reference is typeof-guarded on the\n // same line — non-Node bundlers don't define it). Runs on load because only a\n // decoded image knows its natural width; skips SSR (no `window`) and\n // unmeasurable (zero-width) elements.\n const handleLoad = (event: SyntheticEvent<HTMLImageElement>) => {\n if (!result) return;\n if (typeof process === 'undefined' || process.env?.NODE_ENV === 'production') return;\n if (typeof window === 'undefined') return;\n if (warnedMockupIdsRef.current.has(result.mockupId)) return;\n const img = event.currentTarget;\n const cssWidth = img.getBoundingClientRect().width;\n if (cssWidth <= 0) return;\n const devicePx = Math.round(cssWidth * (window.devicePixelRatio || 1));\n const hint = resolutionMismatchHint(img.naturalWidth, devicePx);\n if (hint) {\n warnedMockupIdsRef.current.add(result.mockupId);\n console.warn(hint);\n }\n };\n\n if (overlayActive) {\n // Overlay mode (the DEFAULT): the part is a positioned stage\n // (`.sc-preview-frame`) the loader fills; the previous mockup keeps\n // painting underneath while a render is in flight, exactly like the PDP\n // hero. Error/fallback render INSIDE the frame so the stage (and the\n // overlay over it) keeps the host-given size before the first mockup\n // lands.\n // The frame carries the same `data-sc-preview-state` verification\n // contract as the bare-img mode (#703): agents await the attribute, not\n // the DOM shape.\n const frameState = result?.imageUrl\n ? isRendering\n ? 'rendering'\n : 'ready'\n : error\n ? 'error'\n : 'rendering';\n return (\n <div\n data-sc-part=\"preview\"\n data-sc-preview-state={frameState}\n aria-busy={frameState === 'rendering' || undefined}\n className={`sc-preview-frame${className ? ` ${className}` : ''}`}\n style={style}\n >\n {result?.imageUrl ? (\n // eslint-disable-next-line @next/next/no-img-element\n <img data-sc-part=\"preview-image\" src={result.imageUrl} alt={alt} onLoad={handleLoad} />\n ) : error ? (\n <div data-sc-part=\"preview-error\" role=\"alert\" data-sc-error={error}>\n {fallback ?? `Render failed: ${error}`}\n </div>\n ) : (\n fallback\n )}\n {customOverlay ? (\n // Custom indicator: same show-delay + linger window; no exit fade\n // (the host owns its animation), so it unmounts when the window\n // closes.\n showOverlay && overlayVisible ? (\n <div\n data-sc-part=\"preview-loading\"\n className=\"sc-preview-custom-loading\"\n aria-hidden=\"true\"\n >\n {customOverlay}\n </div>\n ) : null\n ) : showOverlay && overlayVariant ? (\n <PreviewPrismOverlay\n visible={overlayVisible}\n variant={overlayVariant}\n onExited={handleExited}\n />\n ) : null}\n </div>\n );\n }\n\n if (!result?.imageUrl) {\n // A render/grant/transport failure with nothing to show must SURFACE, not\n // blank (ADR-0085 failure-modes table: \"error state, no silent blank\").\n // Machine-readable for agents; hosts style or replace it via the\n // `data-sc-part` hook. Once a mockup exists we keep showing it (stale\n // beats blank) and the failure stays on the session's onRenderError.\n if (error) {\n return (\n <div\n data-sc-part=\"preview-error\"\n data-sc-preview-state=\"error\"\n role=\"alert\"\n data-sc-error={error}\n className={className}\n style={style}\n >\n {fallback ?? `Render failed: ${error}`}\n </div>\n );\n }\n // Nothing to show yet — still machine-visible: the wrapper generates no\n // box (`display: contents`) but carries the part + state attributes, so an\n // agent can await `[data-sc-part=\"preview\"][data-sc-preview-state=\"ready\"]`\n // from mount onward instead of heuristically watching for an <img>.\n return (\n <div data-sc-part=\"preview\" data-sc-preview-state=\"rendering\" aria-busy=\"true\" style={{ display: 'contents' }}>\n {fallback}\n </div>\n );\n }\n\n return (\n // eslint-disable-next-line @next/next/no-img-element\n <img\n data-sc-part=\"preview\"\n // The verification contract (agents assert on this, not screenshots):\n // `rendering` = a newer render is in flight (the shown image is stale),\n // `ready` = this image reflects the latest pushed design state.\n data-sc-preview-state={isRendering ? 'rendering' : 'ready'}\n src={result.imageUrl}\n alt={alt}\n className={className}\n style={style}\n onLoad={handleLoad}\n />\n );\n}\n","'use client';\n\n/**\n * `<Editor.TextField>` — a form input bound to a design text layer by TYPED\n * TOKEN (ADR-0085 §1 / T1). Canvas-free by design: in the no-canvas\n * personalization widget it writes the Root's design state directly and the\n * preview re-renders live; with a mounted `Editor.Canvas` the same writes\n * route through the editor command path (undo/redo, repaint) via the canvas\n * bridge — the editor document stays the single write authority (§3). The\n * routing is internal; the API is identical in both compositions.\n *\n * Contract (D10):\n * - `layer` accepts ONLY a `design.layer(\"name\")` token — a bare string\n * throws `E_LAYER_TOKEN_REQUIRED` (today's silent no-op binding became a\n * throw when entering `Editor.*`).\n * - Mount-time revalidation is the authority: the token's name is re-resolved\n * against the mounted Root's CURRENT design state — a token minted from a\n * different design throws `E_LAYER_NOT_FOUND` (dev AND prod).\n * - Mounted + non-`optional` ⇒ required for `Editor.Buy` completeness\n * (non-empty after trim AND differs from seed — C2/C3); unmounted (incl.\n * conditionally hidden) ⇒ not required. Registration lives in Root context.\n * - Reconciliation with canvas edits of the same layer is by construction:\n * one store, last-write-wins; this is a controlled input subscribed to the\n * store, so a canvas edit updates the field.\n */\n\nimport React, { useCallback, useId, useLayoutEffect, useRef, useSyncExternalStore, type CSSProperties } from 'react';\nimport { serializeStateForServer } from '../../rendering/serialize-for-server.js';\nimport { isLayerToken, type LayerToken } from '../../design/design-builder.js';\nimport { EditorError } from '../../errors/editorError.js';\nimport { useEmbedContext } from '../embed-realtime/context.js';\nimport { useEditorRootInternals, useRegisterEditorPart } from './RootInternals.js';\n\nexport interface EditorTextFieldProps {\n /** The text layer this input edits — mint with `design.layer(\"name\")`.\n * Type-checked against the design's TEXT-layer names when the design is\n * statically built; runtime-validated always. */\n layer: LayerToken<'text'>;\n /** Marked optional ⇒ Buy completeness does not require it (C2/C3). */\n optional?: boolean;\n placeholder?: string;\n /** Accessible label. Defaults to the layer name. */\n 'aria-label'?: string;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * A text input bound to a design layer. Works with or without a mounted\n * `Editor.Canvas`.\n *\n * Stable since ADR-0085 P4 (the default editor is rebuilt from this public\n * surface, CI-gated); additive-only from here.\n */\nexport function EditorTextField(props: EditorTextFieldProps): React.ReactElement {\n const { layer, optional = false, placeholder, className, style } = props;\n const internals = useEditorRootInternals('Editor.TextField');\n useRegisterEditorPart('Editor.TextField'); // census (`Editor.audit()`, #10)\n const { pushRender, throttleMs, stateStore } = useEmbedContext();\n const instanceId = useId();\n\n // ── Token + MOUNT-time revalidation (render-time on purpose: a bad layer\n // prop is a composition mistake → Root's boundary, dev AND prod). Validated\n // once per layer name, against the state AT MOUNT — later state churn (the\n // user emptying the canvas, teardown ordering) is user state, not a\n // composition mistake; the write path reports it if a write ever misses. ──\n const validatedNameRef = useRef<string | null>(null);\n if (!isLayerToken(layer)) {\n throw new EditorError(\n 'E_LAYER_TOKEN_REQUIRED',\n `the \\`layer\\` prop must be a token minted by the design — pass ` +\n `layer={design.layer(\"name\")}, not ${typeof layer === 'string' ? `the bare string \"${layer}\"` : 'a plain value'}. ` +\n `Tokens validate the name against the design's layers at mint time.`,\n { received: typeof layer === 'string' ? layer : typeof layer, docSlug: 'embed-mode' },\n );\n }\n if (validatedNameRef.current !== layer.name) {\n const kindNow = stateStore.layerKindOf(layer.name);\n if (kindNow === undefined) {\n throw new EditorError(\n 'E_LAYER_NOT_FOUND',\n `no layer \"${layer.name}\" in this Root's design — the token was minted from a ` +\n `different design than the one passed to <Editor.Root design={…}>. Bindable layers ` +\n `here: ${JSON.stringify(stateStore.bindableLayerNames())}.`,\n { layerName: layer.name, validNames: stateStore.bindableLayerNames(), docSlug: 'embed-mode' },\n );\n }\n if (kindNow !== 'text') {\n throw new EditorError(\n 'E_LAYER_WRONG_KIND',\n `layer \"${layer.name}\" is ${kindNow === null ? 'not a bindable kind' : `an ${kindNow} layer`} — ` +\n `<Editor.TextField> binds text layers only.`,\n { layerName: layer.name, actualKind: kindNow, docSlug: 'embed-mode' },\n );\n }\n validatedNameRef.current = layer.name;\n }\n\n // ── Required-layer registration for Buy completeness (C2/C3) ─────────────\n useLayoutEffect(() => {\n return internals.registry.registerTextField(instanceId, { name: layer.name, optional });\n }, [internals.registry, instanceId, layer.name, optional]);\n\n // ── Controlled value from the ONE store (a canvas edit updates the field) ─\n const value = useSyncExternalStore(\n stateStore.subscribe,\n () => stateStore.textOf(layer.name) ?? '',\n () => stateStore.textOf(layer.name) ?? '',\n );\n\n const handleChange = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n const next = event.target.value;\n const bridge = internals.registry.getCanvasBridge();\n if (bridge) {\n // Canvas mounted: the editor document is the write authority — route\n // through commands; the canvas onChange lands the new state back in\n // the store and pushes the render.\n if (!bridge.setTextByName(layer.name, next)) {\n internals.reportInvariant(\n new EditorError(\n 'E_LAYER_NOT_FOUND',\n `layer \"${layer.name}\" no longer exists in the mounted canvas — it was removed ` +\n `or renamed after this <Editor.TextField> bound to it. Bound layers must not be ` +\n `renamed or deleted while a field is mounted (ADR-0085 §3).`,\n { layerName: layer.name, docSlug: 'embed-mode' },\n ),\n );\n }\n return;\n }\n // No canvas: the store IS the authority. Trailing-edge throttle in the\n // session keeps the last keystroke always rendering.\n stateStore.updateTextLayer(layer.name, next);\n pushRender(serializeStateForServer(stateStore.getState()), throttleMs);\n },\n [internals, layer.name, stateStore, pushRender, throttleMs],\n );\n\n return (\n <input\n data-sc-part=\"textfield\"\n data-sc-layer={layer.name}\n type=\"text\"\n value={value}\n onChange={handleChange}\n placeholder={placeholder}\n aria-label={props['aria-label'] ?? layer.name}\n className={className}\n style={style}\n />\n );\n}\n","'use client';\n\n/**\n * `<Editor.Buy>` — the SMART commerce part (ADR-0085 §2; plan decision: thin\n * callback-Buy was rejected). OWNS variant selection + quantity (P2 — they\n * live in the Root's commerce store, host-visible via `useProductSelection()`,\n * never on Root props where a change would re-key the RenderSession), runs\n * design-completeness validation, and assembles the cart payload; only the\n * final submit is the host's callback — their one line.\n *\n * Completeness rules (v1, C1–C5):\n * - C1 variant resolution — FULL selection resolution (the P2 amendment:\n * `validateProductSelection`/`findBestCombination` replace the old\n * color-axis-only gate). Each unselected required attribute gates with\n * reason `option:<key>`; a complete-but-invalid combination gates with\n * reason `variant`.\n * - C2 every MOUNTED non-`optional` `Editor.TextField` layer non-empty\n * after trim.\n * - C3 those layers must DIFFER from their seed value (F4 — placeholder\n * text like 'YOUR NAME' must not pass).\n * - C4 the design has ≥1 renderable element.\n * - C5 quantity is an integer ≥ 1.\n *\n * Incompleteness is USER state, not a composition error — the button renders\n * disabled with machine-readable `data-sc-buy-state` / `data-sc-buy-missing`\n * reason codes; it never throws. Throws are reserved for composition\n * violations (`E_BUY_NO_PRODUCT`, outside-Root, `E_UNKNOWN_OPTION`).\n *\n * The payload is assembled from DESIGN STATE (the Root's live store — never\n * the seed, never rendered pixels) plus the COMMERCE state (selection,\n * resolved variant, quantity), so render staleness cannot corrupt an order;\n * the preview is just preview (D10).\n */\n\nimport React, { useCallback, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore, type CSSProperties, type ReactNode } from 'react';\nimport {\n createCartDetail,\n type CartDetail,\n type OptionSelection,\n type RenderProduct,\n} from '@snowcone-app/sdk';\nimport { serializeStateForServer, type ServerRenderRequest } from '../../rendering/serialize-for-server.js';\nimport { expandRequestForPlacements } from './placementLinks.js';\nimport { requiredPlacementLabels } from '../embed-realtime/validateEmbed.js';\nimport { EditorError } from '../../errors/editorError.js';\nimport { useEmbedContext } from '../embed-realtime/context.js';\nimport type { DesignState } from './designStateStore.js';\nimport { choiceLabelsOf, type CommerceStateStore } from './commerceStore.js';\nimport { useEditorRootInternals, useRegisterEditorPart } from './RootInternals.js';\n\n/** A structured incompleteness reason — also serialized (comma-joined) into\n * the button's `data-sc-buy-missing` attribute for agents and styling. */\nexport type BuyMissingReason =\n | `option:${string}`\n | 'variant'\n | `layer:${string}`\n | `layer-seed:${string}`\n | 'empty-design'\n | 'quantity';\n\nexport interface EditorBuyPayload {\n productId: string;\n /** The variant (gvid) the selection resolves to. */\n variantId?: string;\n quantity: number;\n /** The variant choices at click time, e.g. `{ Color: 'Black', Size: 'M' }`. */\n selection: OptionSelection;\n /** SDK cart detail (variant resolution + price) when the product carries\n * catalog `options`; `null` for option-less products. */\n cartDetail: CartDetail | null;\n /** The DESIGN STATE at click time (editor shape) — persist this; it is the\n * re-renderable source of truth for the purchased design. */\n designState: DesignState;\n /** The same state serialized for the server render path. */\n serverRequest: ServerRenderRequest;\n}\n\nexport interface EditorBuyProps {\n /** The final submit — the host's one line. Everything before it (variant,\n * quantity, completeness, payload assembly) is this part's job. */\n onAddToCart: (payload: EditorBuyPayload) => void | Promise<void>;\n /**\n * Seeds the Buy-owned quantity once on mount (integer ≥ 1; the store\n * defaults to 1). Live reads/writes go through `useProductSelection()` —\n * this is deliberately NOT a controlled prop, so two Buy parts under one\n * Root can never disagree about quantity.\n */\n defaultQuantity?: number;\n /** Button label. Defaults to \"Add to cart\". */\n children?: ReactNode;\n className?: string;\n style?: CSSProperties;\n}\n\n/** Pure completeness evaluation — exported for tests. @internal */\nexport function evaluateBuyCompleteness(input: {\n quantity: number;\n /** Required attribute keys still unselected (C1 — `option:<key>`). */\n missingOptionKeys: string[];\n /** Full-resolution validity of the selection (C1 — `variant`). */\n selectionValid: boolean;\n textFields: Array<{ name: string; optional: boolean }>;\n textOf: (name: string) => string | undefined;\n seedTextOf: (name: string) => string | undefined;\n hasRenderableElement: boolean;\n}): BuyMissingReason[] {\n const missing: BuyMissingReason[] = [];\n\n // C1 — full selection resolution (P2 amendment). Unselected axes first;\n // `variant` only for a complete selection that matches no combination.\n for (const key of input.missingOptionKeys) {\n missing.push(`option:${key}`);\n }\n if (input.missingOptionKeys.length === 0 && !input.selectionValid) {\n missing.push('variant');\n }\n\n // C2 + C3 — mounted required TextField layers.\n for (const field of input.textFields) {\n if (field.optional) continue;\n const value = (input.textOf(field.name) ?? '').trim();\n if (value.length === 0) {\n missing.push(`layer:${field.name}`);\n continue;\n }\n const seed = (input.seedTextOf(field.name) ?? '').trim();\n if (seed.length > 0 && value === seed) {\n missing.push(`layer-seed:${field.name}`);\n }\n }\n\n // C4 — something to print.\n if (!input.hasRenderableElement) {\n missing.push('empty-design');\n }\n\n // C5 — sane quantity.\n if (!Number.isInteger(input.quantity) || input.quantity < 1) {\n missing.push('quantity');\n }\n\n return missing;\n}\n\n/** Assemble the SDK cart detail from the commerce store's selection. */\nfunction buildCartDetail(product: RenderProduct, commerce: CommerceStateStore): CartDetail | null {\n const combinations = commerce.getCombinations();\n const attributes = commerce.getAttributes();\n if (Object.keys(attributes).length === 0 || combinations.length === 0) return null;\n\n // createCartDetail's selection math speaks label-string choices (the SDK\n // currency); the store hands out object choices — convert.\n const stringAttrs: Parameters<typeof createCartDetail>[0]['attributes'] = Object.fromEntries(\n Object.entries(attributes).map(([key, attr]) => [key, { ...attr, choices: choiceLabelsOf(attr) }]),\n );\n\n return createCartDetail({\n productId: product.productId,\n quantity: commerce.getQuantity(),\n selection: commerce.getSelection(),\n combinations: combinations as Parameters<typeof createCartDetail>[0]['combinations'],\n attributes: stringAttrs,\n });\n}\n\n/**\n * The add-to-cart button, completeness-gated and payload-assembling.\n *\n * Stable since ADR-0085 P4 (the default editor is rebuilt from this public\n * surface, CI-gated); additive-only from here.\n */\nexport function EditorBuy(props: EditorBuyProps): React.ReactElement {\n const { onAddToCart, defaultQuantity, children, className, style } = props;\n const internals = useEditorRootInternals('Editor.Buy');\n useRegisterEditorPart('Editor.Buy'); // census (`Editor.audit()`, #10)\n const { product, stateStore } = useEmbedContext();\n const commerce = internals.commerce;\n\n // Composition violation — not user state: throw into Root's boundary.\n if (!product?.productId) {\n throw new EditorError(\n 'E_BUY_NO_PRODUCT',\n '<Editor.Buy> has no product context — pass `product` (with `productId`) on ' +\n '<Editor.Root product={…}>. Buy assembles its cart payload from the Root product ' +\n 'and the live design state.',\n { docSlug: 'embed-mode' },\n );\n }\n\n // Seed the Buy-owned quantity once per mount (the prop is a seed, not a\n // controlled value — see the prop doc).\n const seededRef = useRef(false);\n useLayoutEffect(() => {\n if (seededRef.current) return;\n seededRef.current = true;\n if (typeof defaultQuantity === 'number') commerce.setQuantity(defaultQuantity);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [commerce]);\n\n // Subscribe narrowly: design state + commerce state + part registry.\n const stateVersion = useSyncExternalStore(stateStore.subscribe, stateStore.getState, stateStore.getState);\n const commerceVersion = useSyncExternalStore(commerce.subscribe, commerce.getVersion, commerce.getVersion);\n const registryVersion = useSyncExternalStore(\n internals.registry.subscribe,\n internals.registry.getVersion,\n internals.registry.getVersion,\n );\n\n const quantity = commerce.getQuantity();\n const missing = useMemo(\n () =>\n evaluateBuyCompleteness({\n quantity,\n missingOptionKeys: commerce.missingOptionKeys(),\n selectionValid: commerce.selectionValid(),\n textFields: internals.registry.getTextFields(),\n textOf: (name) => stateStore.textOf(name),\n seedTextOf: (name) => stateStore.seedTextOf(name),\n hasRenderableElement: stateStore.hasRenderableElement(),\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [commerce, quantity, stateVersion, commerceVersion, registryVersion],\n );\n const complete = missing.length === 0;\n\n // Double-click inert: the callback fires exactly once per click while\n // assembling/submitting (P2 test contract).\n const [busy, setBusy] = useState(false);\n const busyRef = useRef(false);\n\n const handleClick = useCallback(() => {\n if (busyRef.current || !complete) return;\n busyRef.current = true;\n setBusy(true);\n\n const designState = stateStore.getState();\n const variantId = commerce.resolvedVariantId();\n const payload: EditorBuyPayload = {\n productId: product.productId,\n ...(variantId ? { variantId } : {}),\n quantity: commerce.getQuantity(),\n selection: commerce.getSelection(),\n cartDetail: buildCartDetail(product, commerce),\n designState,\n // ADR-0101: one artboard per REQUIRED placement — linked placements\n // carry the base relabelled — so buy and preview are the same bytes\n // and the order pipeline never re-derives the link rule.\n serverRequest: expandRequestForPlacements(\n serializeStateForServer(designState),\n requiredPlacementLabels(product),\n ),\n };\n\n // Invoke synchronously (predictable for hosts and tests); only the\n // SETTLING of an async callback is awaited for the busy window.\n let result: void | Promise<void>;\n try {\n result = onAddToCart(payload);\n } catch (err) {\n busyRef.current = false;\n setBusy(false);\n throw err;\n }\n void Promise.resolve(result).finally(() => {\n busyRef.current = false;\n setBusy(false);\n });\n }, [complete, product, commerce, stateStore, onAddToCart]);\n\n return (\n <button\n type=\"button\"\n data-sc-part=\"buy\"\n data-sc-buy-state={busy ? 'busy' : complete ? 'ready' : 'incomplete'}\n data-sc-buy-missing={missing.join(',') || undefined}\n disabled={!complete || busy}\n aria-busy={busy || undefined}\n onClick={handleClick}\n className={className}\n style={style}\n >\n {children ?? 'Add to cart'}\n </button>\n );\n}\n","'use client';\n\n/**\n * `<Editor.Controls>` — the morphing contextual zone, ONE coarse part in v1\n * (ADR-0085 §5). Wraps the existing `ContextualToolbars` chrome:\n *\n * - `placement=\"docked\"` (default): the host-docked (class-1) contextual\n * zone, rendered exactly where the host mounts it — today's\n * `ContextualToolbars` embedded mode. Mounting a docked Controls\n * SUPPRESSES the canvas's built-in floating toolbar (one contextual zone\n * at a time), via the part registry.\n * - `placement=\"floating\"`: renders nothing in place and declares the\n * class-3 floating body-portal variant explicitly — the built-in floating\n * toolbar that `Editor.Canvas` mounts by default stays active.\n * - No `Editor.Controls` mounted at all: `Editor.Canvas` defaults to the\n * floating toolbar.\n *\n * Requires a mounted `Editor.Canvas` (`E_REQUIRES_CANVAS`, ADR-0085 §4): the\n * zone morphs on canvas selection; no selection exists without a canvas.\n *\n * The chrome itself statically imports the paint pipeline (panels, effects),\n * so the docked impl loads through a dynamic import — this module's static\n * graph stays renderer-free (import-graph gate), and in any valid\n * composition the renderer is already loading behind `Editor.Canvas`'s\n * boundary. A failed chrome chunk load routes to Root's error card with\n * retry (`E_CHUNK_LOAD_FAILED`), exactly like the canvas chunk.\n */\n\nimport React, { useEffect, useId, useLayoutEffect, useState, type CSSProperties } from 'react';\nimport { EditorError } from '../../errors/editorError.js';\nimport { useEditorRootInternals, useRegisterEditorPart, useRequiresCanvas } from './RootInternals.js';\n\ntype ControlsImpl = (typeof import('../ContextualToolbars.js'))['ContextualToolbars'];\n\nexport interface EditorControlsProps {\n /** Where the contextual zone lives (ADR-0085 §5). The host docks the part\n * by where it renders it — there is deliberately no \"bottom\"/\"top\" value. */\n placement?: 'docked' | 'floating';\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * The contextual controls zone.\n *\n * Stable since ADR-0085 P4 (the default editor is rebuilt from this public\n * surface, CI-gated); additive-only from here.\n */\nexport function EditorControls({\n placement = 'docked',\n className,\n style,\n}: EditorControlsProps): React.ReactElement | null {\n const internals = useEditorRootInternals('Editor.Controls');\n useRequiresCanvas('Editor.Controls');\n useRegisterEditorPart('Editor.Controls'); // census (`Editor.audit()`, #10)\n const instanceId = useId();\n\n // Registration is by THIS component's mount (layout effect, like every\n // part) — suppression of the built-in floating toolbar never races the\n // chrome chunk's arrival.\n useLayoutEffect(\n () => internals.registry.registerControls(instanceId, placement),\n [internals.registry, instanceId, placement],\n );\n\n const docked = placement === 'docked';\n const [Impl, setImpl] = useState<ControlsImpl | null>(null);\n useEffect(() => {\n if (!docked) return;\n let cancelled = false;\n import('../ContextualToolbars.js').then(\n (m) => {\n if (!cancelled) setImpl(() => m.ContextualToolbars);\n },\n (err) => {\n if (cancelled) return;\n internals.reportRuntimeError(\n new EditorError(\n 'E_CHUNK_LOAD_FAILED',\n `the editor's controls chunk failed to load (${err instanceof Error ? err.message : String(err)}). ` +\n 'This is a network/CDN failure, not a composition mistake — retry, or check the deployment ' +\n 'serves the @snowcone-app/canvas lazy chunks.',\n { cause: err instanceof Error ? err.message : String(err), docSlug: 'embed-mode' },\n ),\n );\n },\n );\n return () => {\n cancelled = true;\n };\n }, [docked, internals]);\n\n if (!docked) {\n // The floating variant is the canvas's built-in body portal (class-3) —\n // this part only declares it; there is nothing to render in place.\n return null;\n }\n\n return (\n <div\n data-sc-part=\"controls\"\n data-sc-placement=\"docked\"\n className={className}\n style={style}\n aria-busy={Impl ? undefined : 'true'}\n >\n {Impl ? <Impl mode=\"embedded\" /> : null}\n </div>\n );\n}\n","'use client';\n\n/**\n * `<Editor.LoadingOverlay>` — the standalone render-in-flight rainbow for\n * HOST-OWNED preview surfaces: custom mockup panels built on\n * `useRealtimeMockups`, or an `<Editor.Preview loadingOverlay=\"host-owned\">`\n * whose host wants the house loader somewhere else in its own DOM.\n *\n * Mount it inside any `position: relative` container; it fills the container\n * (`.sc-loading-overlay-host`, absolute inset-0, pointer-events none) and\n * paints the same prism choreography `Editor.Preview` runs by default —\n * 200ms show-delay (instant renders never flash it), 400ms post-render\n * linger, fade-out — whenever this Root's session has a render in flight.\n *\n * Requires `<Editor.Root>` (throws `E_OUTSIDE_ROOT` otherwise). Does NOT\n * require `Editor.Canvas` — it rides the session, not the editor.\n */\n\nimport React, { type CSSProperties } from 'react';\nimport { useEmbedContext } from '../embed-realtime/context.js';\nimport { PreviewPrismOverlay, useRenderLoadingOverlay } from './PreviewPrismOverlay.js';\n\nexport interface EditorLoadingOverlayProps {\n /** \"dark\" (default): screen-blended neon bands for image/dark surfaces.\n * \"light\": multiply-blended candy bands for light cards. */\n variant?: 'dark' | 'light';\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * Stable since ADR-0085 P4 (additive); part name: `loading-overlay`.\n */\nexport function EditorLoadingOverlay({\n variant = 'dark',\n className,\n style,\n}: EditorLoadingOverlayProps): React.ReactElement | null {\n const { isRendering } = useEmbedContext();\n const { showOverlay, overlayVisible, handleExited } = useRenderLoadingOverlay(isRendering);\n\n if (!showOverlay) return null;\n return (\n <div\n data-sc-part=\"loading-overlay\"\n className={`sc-loading-overlay-host${className ? ` ${className}` : ''}`}\n style={style}\n aria-hidden=\"true\"\n >\n <PreviewPrismOverlay visible={overlayVisible} variant={variant} onExited={handleExited} />\n </div>\n );\n}\n","'use client';\n\n/**\n * `useProductSelection()` — the host's window into `Editor.Buy`'s commerce\n * state (ADR-0085 §2, P2: Buy-owned variant + quantity).\n *\n * The DIVISION OF LABOR (the rendering contract): the HOST renders the\n * variant-selection UI — swatches, dropdowns, steppers, its brand — and this\n * hook supplies the state + transitions. `Editor.Buy` owns that state: it\n * gates completeness on it (C1/C5) and assembles the cart payload from it.\n * Neither side ever touches Root props for selection, so picking a color\n * costs one live config message + one render — never a session re-key.\n *\n * ```tsx\n * function VariantPicker() {\n * const { attributes, selection, select, disabledChoices } = useProductSelection();\n * // choices are ALWAYS `{ label, hex? }` objects; the label STRING is the\n * // currency for select()/selection/disabledChoices.\n * return Object.entries(attributes).map(([key, attr]) => (\n * <div key={key}>\n * {attr.choices.map(({ label = '', hex }) => (\n * <button\n * key={label}\n * style={hex ? { background: hex } : undefined}\n * disabled={disabledChoices[key]?.includes(label)}\n * aria-pressed={selection[key] === label}\n * onClick={() => select(key, label)}\n * >\n * {label}\n * </button>\n * ))}\n * </div>\n * ));\n * }\n * ```\n *\n * Mount it anywhere under the same `<Editor.Root>` (outside one throws\n * `E_OUTSIDE_ROOT`). `select()` with an unknown key/choice throws structured\n * `E_UNKNOWN_OPTION` listing the valid ones (D4/E3 — wiring mistakes are\n * loud, not silently ignored).\n */\n\nimport { useCallback, useMemo, useSyncExternalStore } from 'react';\nimport type { OptionSelection } from '@snowcone-app/sdk';\nimport type { ProductSelectionAttribute } from './commerceStore.js';\nimport { useEditorRootInternals } from './RootInternals.js';\n\nexport interface ProductSelectionApi {\n /** The product's variant attributes (normalized catalog `options.attributes`).\n * Choices are ALWAYS `{ label, hex?, … }` OBJECTS — render `choice.label`,\n * use `hex` for color swatches. Empty object for an option-less product. */\n attributes: Record<string, ProductSelectionAttribute>;\n /** Current choices BY LABEL STRING, e.g. `{ Color: 'Black', Size: 'M' }` —\n * the label is the currency everywhere selection is read or written.\n * Seeded from the Root product's `variantId` combination when present. */\n selection: OptionSelection;\n /** Select a choice by its LABEL string (`select('Color', choice.label)`).\n * Unknown key/choice → throws `E_UNKNOWN_OPTION` listing the valid ones. */\n select: (key: string, choice: string) => void;\n /** Choice LABELS invalid given the rest of the selection — disable these. */\n disabledChoices: Record<string, string[]>;\n /** The variant (gvid) the selection resolves to; `undefined` while\n * incomplete/invalid. This is what renders and what Buy submits. */\n variantId: string | undefined;\n /** Resolved combination's price, when the catalog carries one. */\n price: number | undefined;\n /** Buy-owned quantity (completeness rule C5 gates on it). */\n quantity: number;\n /** Set the Buy-owned quantity. Values that are not integers ≥ 1 are stored\n * as-is and GATE Buy with the `quantity` reason code (user state, never a\n * throw) — clamp in your stepper if you never want that state. */\n setQuantity: (quantity: number) => void;\n /** True when every required attribute is selected and the combination is\n * valid — the C1 component of Buy's completeness. */\n complete: boolean;\n /** Required attribute keys still unselected (Buy's `option:<key>` codes). */\n missing: string[];\n}\n\n/**\n * Read/write the Buy-owned product selection under this `Editor.Root`.\n *\n * Stable since ADR-0085 P4 (the default editor is rebuilt from this public\n * surface, CI-gated); additive-only from here.\n */\nexport function useProductSelection(): ProductSelectionApi {\n const internals = useEditorRootInternals('useProductSelection');\n const commerce = internals.commerce;\n\n const version = useSyncExternalStore(commerce.subscribe, commerce.getVersion, commerce.getVersion);\n\n const select = useCallback((key: string, choice: string) => commerce.select(key, choice), [commerce]);\n const setQuantity = useCallback((quantity: number) => commerce.setQuantity(quantity), [commerce]);\n\n return useMemo<ProductSelectionApi>(\n () => ({\n attributes: commerce.getAttributes(),\n selection: commerce.getSelection(),\n select,\n disabledChoices: commerce.disabledChoices(),\n variantId: commerce.resolvedVariantId(),\n price: commerce.resolvedPrice(),\n quantity: commerce.getQuantity(),\n setQuantity,\n complete: commerce.selectionValid(),\n missing: commerce.missingOptionKeys(),\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [commerce, select, setQuantity, version],\n );\n}\n","'use client';\n\n/**\n * `Editor.*` — composable editor primitives over one `Editor.Root`\n * (ADR-0085). Parts carry behavior + state subscription; the HOST owns all\n * layout (with the documented exception of the canvas's selection-anchored\n * overlays — anchoring contract, ADR-0085 §5).\n *\n * ```tsx\n * import { Editor, design } from '@snowcone-app/canvas/embed';\n *\n * const d = design({ name: 'Front', width: 1480, height: 2328 })\n * .background(artUrl, { aspectRatio: 1480 / 2328, name: 'art' })\n * .text('YOUR NAME', { anchor: 'top', name: 'headline' });\n *\n * // No-canvas personalization widget — the rendering engine never loads:\n * <Editor.Root shop={SHOP_KEY} product={product} design={d} grantUrl=\"/api/grant\">\n * <Editor.Preview />\n * <Editor.TextField layer={d.layer('headline')} placeholder=\"Your name\" />\n * <Editor.Buy onAddToCart={({ designState }) => persist(designState)} />\n * </Editor.Root>\n *\n * // Full editor — same surface, plus the lazy canvas:\n * <Editor.Root shop={SHOP_KEY} product={product} design={d} grantUrl=\"/api/grant\">\n * <Editor.Canvas />\n * <Editor.Preview />\n * <Editor.Buy onAddToCart={…} />\n * </Editor.Root>\n * ```\n *\n * Stable since the ADR-0085 P4 gate passed: the default editor\n * (`SnowconeEditor`) is rebuilt from exactly these parts, CI-enforced, so the\n * surface is additive-only from here.\n */\n\nimport { EditorRoot } from './EditorRoot.js';\nimport { EditorCanvas } from './EditorCanvas.js';\nimport { EditorPlacements } from './EditorPlacements.js';\nimport { EditorPreview } from './EditorPreview.js';\nimport { EditorTextField } from './EditorTextField.js';\nimport { EditorBuy } from './EditorBuy.js';\nimport { EditorLayers } from './EditorLayers.js';\nimport { EditorControls } from './EditorControls.js';\nimport { EditorHistory } from './EditorHistory.js';\nimport { EditorMenu } from './EditorMenu.js';\nimport { EditorAdd } from './EditorAdd.js';\nimport { EditorLoadingOverlay } from './EditorLoadingOverlay.js';\n\nexport const Editor = {\n /** The one provider boundary — session, design, live state, error boundary. */\n Root: EditorRoot,\n /** The editable artboard (the ONE lazy renderer boundary — D9). */\n Canvas: EditorCanvas,\n /** Live product mockup. ×N under one Root is valid. */\n Preview: EditorPreview,\n /** Placement switcher tabs (ADR-0088). Renders nothing for a\n * single-placement design; headless floor = usePlacements(). */\n Placements: EditorPlacements,\n /** Form input bound to a design text layer by typed token (T1). */\n TextField: EditorTextField,\n /** Smart commerce part: completeness + payload assembly; submit = host callback. */\n Buy: EditorBuy,\n /** Layer list. The one editor part that works canvas-free (ADR-0085 §4). */\n Layers: EditorLayers,\n /** Morphing contextual zone — ONE coarse part; placement docked|floating (§5). */\n Controls: EditorControls,\n /** Undo/redo controls. Requires Editor.Canvas. */\n History: EditorHistory,\n /** The one ⋯ overflow menu. Requires Editor.Canvas. */\n Menu: EditorMenu,\n /** The ⊕ add-element menu. Requires Editor.Canvas. */\n Add: EditorAdd,\n /** Standalone render-in-flight rainbow for host-owned preview surfaces.\n * Fills its positioned parent; rides the session (canvas-free). */\n LoadingOverlay: EditorLoadingOverlay,\n} as const;\n\nexport type { EditorRootProps, EditorRootBaseProps, GrantSource } from './EditorRoot.js';\nexport type { EditorCanvasProps } from './EditorCanvas.js';\nexport type { EditorPlacementsProps, EditorPlacementsLabels } from './EditorPlacements.js';\nexport { usePlacements } from './usePlacements.js';\nexport type { PlacementInfo, UsePlacementsReturn } from './usePlacements.js';\n// ADR-0101 linked placements — the ONE resolution rule (base + overrides),\n// exported so hosts/agents can assert what the render push and Buy send.\nexport { resolvePlacementLinks, expandRequestForPlacements } from './placementLinks.js';\nexport type { PlacementLinkInfo } from './placementLinks.js';\nexport type { EditorPreviewProps } from './EditorPreview.js';\nexport type { EditorLoadingOverlayProps } from './EditorLoadingOverlay.js';\nexport type { EditorTextFieldProps } from './EditorTextField.js';\nexport type { EditorBuyProps, EditorBuyPayload, BuyMissingReason } from './EditorBuy.js';\nexport type { DesignState } from './designStateStore.js';\nexport { DesignStateStore } from './designStateStore.js';\n// Buy-owned commerce state (ADR-0085 §2, P2) — the host's variant-UI hook.\nexport { useProductSelection } from './useProductSelection.js';\nexport type { ProductSelectionApi } from './useProductSelection.js';\nexport { CommerceStateStore } from './commerceStore.js';\nexport type { ProductOptionChoice, ProductSelectionAttribute } from './commerceStore.js';\n// Composition audit (`Editor.audit()`, agentic-DX #10) — the imperative dev\n// helper; the once-at-mount channel is `<Editor.Root onAudit>`.\nexport { auditEditor } from './editorAudit.js';\nexport type { EditorAuditReport, EditorAuditFinding, EditorAuditFindingCode } from './editorAudit.js';\nexport type { EditorLayersProps } from './EditorLayers.js';\nexport type { EditorControlsProps } from './EditorControls.js';\nexport type { EditorHistoryProps } from './EditorHistory.js';\nexport type { EditorMenuProps } from './EditorMenu.js';\nexport type { EditorAddProps } from './EditorAdd.js';\n","'use client';\n\n/**\n * `<RealtimeEmbed>` — the legacy turnkey wrapper around `<Editor.Root>`.\n *\n * Everything it used to own (the single RenderSession, the design seed, the\n * live mockups, the context) was EXTRACTED into `EditorRoot` (ADR-0085 / D5 —\n * extraction, not copy): this component is `<EditorRoot>` plus the legacy\n * advisory validation mode (dev-only `console.error` diagnostics instead of\n * `Editor.Root`'s throw-on-misconfiguration, F3). The existing realtime\n * surface — `<RealtimeCanvas>`, `<RealtimeMockup>`, `useRealtimeMockups` —\n * reads the same context `EditorRoot` provides, so nothing existing changes\n * meaning, and the existing realtime tests exercise the new Root.\n *\n * @example\n * ```tsx\n * const d = design({ name: 'Front', width: 1480, height: 2328 })\n * .background(artUrl, { aspectRatio: 1480 / 2328, name: 'art' })\n * .text('YOUR NAME', { anchor: 'top', name: 'headline' });\n *\n * <RealtimeEmbed\n * shop=\"YOUR_SHOP_ID\"\n * grantUrl=\"/api/realtime/grant\"\n * // variantId is REQUIRED for a product with a color/variant axis (BEEB77 has\n * // a Frame color) — omit it and the render hangs. Pass `options` too so a\n * // wrong/missing variantId fails fast instead of timing out. Read both from\n * // getProduct(productId) (its options.combinations[].variantId).\n * product={{ productId: 'BEEB77', mockupIds: ['FV1qjO'], variantId: 'Pv1sLC', placements: ['Front'] }}\n * design={d}\n * >\n * <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr' }}>\n * <RealtimeCanvas /> {/* editor *\\/}\n * <RealtimeMockup /> {/* live preview *\\/}\n * </div>\n * </RealtimeEmbed>\n * ```\n */\n\nimport React from 'react';\nimport {\n EditorRoot,\n type EditorRootBaseProps,\n type EditorRootProps,\n type GrantSource,\n} from '../editor/EditorRoot.js';\n\n// Re-exported from the extraction home so existing imports keep working.\nexport { SLOW_RENDER_HINT_MS, slowRenderHint } from '../editor/EditorRoot.js';\nexport type { GrantSource };\n\n// Omit only from the non-union half — Omit over the GrantSource union would\n// collapse the exactly-one-of grant/grantUrl discrimination.\nexport type RealtimeEmbedProps = GrantSource & Omit<EditorRootBaseProps, '__validation'>;\n\nexport function RealtimeEmbed(props: RealtimeEmbedProps): React.ReactElement {\n return <EditorRoot {...(props as EditorRootProps)} __validation=\"warn\" />;\n}\n","'use client';\n\n/**\n * `<RealtimeCanvas>` — the interactive editor half of a realtime embed\n * (legacy turnkey API; `Editor.Canvas` is the primitives-era equivalent).\n *\n * Mounts a `<SnowconeCanvas>` seeded from the embed's `design`, and forwards\n * every edit to the shared RenderSession as a server render. All the\n * load-bearing wiring an embedder used to copy by hand is internal: the\n * `sc-root` class, `inheritTheme`, edit→`serializeStateForServer`→\n * `renderState`, and the artboard/placement match.\n *\n * Since ADR-0085 (D9) the implementation lives in the shared lazy renderer\n * chunk ({@link EditorCanvasImpl}) behind a dynamic import — the embed\n * entry's static import graph stays renderer-free, so a no-canvas\n * composition never downloads the rendering engine. The canvas therefore\n * mounts one micro-beat after first paint (a chunk fetch on cold cache); the\n * forwarded ref attaches when it does.\n *\n * Defaults to the chrome-less `kit=\"embed-only\"` — bring your own controls as\n * `children` (they render as an overlay INSIDE the canvas's editor context, so\n * `useTextBinding(name)` / `useImageBinding(name)` resolve against the live\n * elements). For a full in-canvas editor pass `kit=\"compact-customizer\"` or\n * `kit=\"pro-studio\"`.\n *\n * Must be rendered inside `<RealtimeEmbed>` (or any `EmbedContext` provider).\n */\n\nimport React, { forwardRef, useEffect, useState, type CSSProperties, type ReactNode } from 'react';\nimport type { CanvasState, SnowconeCanvasHandle } from '../embed/SnowconeCanvas.js';\nimport type { KitPresetId, KitDefinition } from '../../kits/types.js';\nimport type { CanvasServices } from '../../contexts/CanvasServicesContext.js';\nimport { loadCanvasImpl } from '../editor/EditorCanvas.js';\n\nexport interface RealtimeCanvasProps {\n /** Your controls (toolbar, inputs). Rendered as an overlay inside the editor\n * context so binding hooks work. */\n children?: ReactNode;\n /**\n * Editor chrome to mount. The default `'embed-only'` is a chrome-less canvas —\n * the host supplies every control as `children` (text inputs, image swap)\n * through `useTextBinding` / `useImageBinding`. That's the right call for a\n * fill-in-the-blanks personalizer, but it gives the shopper NO way to select a\n * layer and change its font size, add an element, or reorder layers.\n *\n * To ship a real editor through the turnkey realtime path, pass a richer\n * preset — `'compact-customizer'` (a trimmed toolbar) or `'pro-studio'` (full\n * panels). Every edit still flows to the shared RenderSession as a\n * server render automatically; you get add-element / font-size / layers for\n * free without ejecting to a raw `SnowconeCanvas` + `RenderSession`.\n *\n * Pair a chrome'd kit with `children` only when your overlay adds to — not\n * duplicates — the kit's controls, or you'll get double chrome.\n *\n * @default 'embed-only'\n */\n kit?: KitPresetId | KitDefinition;\n /** Inherit the host app's theme instead of managing its own (default true). */\n inheritTheme?: boolean;\n /** Cap the canvas height in px. */\n maxHeight?: number;\n /**\n * Privileged-service wiring for the editor chrome (Image Browser search /\n * AI tabs). Usually set once on `<RealtimeEmbed services={…}>` and inherited;\n * pass it here only to override for this canvas. Host the URLs on your\n * server — your vendor keys live there.\n */\n services?: CanvasServices;\n /**\n * Observe the live design state. Fires with the full {@link CanvasState}\n * (elements stamped with their artboard name) whenever the canvas content\n * changes — including once after the initial seed loads — in addition to the\n * embed's internal edit→server-render flow, which is unaffected. This is the\n * state you persist at add-to-cart / checkout so the purchased design can be\n * re-rendered server-side later.\n *\n * Safe to pass inline: the underlying canvas reads the callback from a ref,\n * so a new identity each render never re-fires or loops.\n */\n onChange?: (state: CanvasState) => void;\n className?: string;\n style?: CSSProperties;\n}\n\ntype ImplComponent = Awaited<ReturnType<typeof loadCanvasImpl>>;\n\n/**\n * Note the export naming wart, kept for backwards compatibility:\n * - The ref handle's {@link SnowconeCanvasHandle.exportArtboards} resolves a\n * record keyed by artboard **name** (e.g. `'Front'`) — names match the\n * `placements` you configured on the embed.\n * - The lower-level `useExport().exportArtboard(id)` hook takes an artboard\n * **ID** (get one from `useArtboards()`).\n * For print-res exports at checkout, the ref handle is the intended path:\n * `ref.current.exportArtboards({ all: true, scale: 4, format: 'blob' })`.\n */\nexport const RealtimeCanvas = forwardRef<SnowconeCanvasHandle, RealtimeCanvasProps>(\n function RealtimeCanvas(props: RealtimeCanvasProps, ref): React.ReactElement {\n const { children, className, style, maxHeight, ...rest } = props;\n\n const [Impl, setImpl] = useState<ImplComponent | null>(null);\n useEffect(() => {\n let cancelled = false;\n loadCanvasImpl().then(\n (component) => {\n if (!cancelled) setImpl(() => component);\n },\n (err) => {\n // Legacy surface keeps the advisory console contract (no Root\n // boundary is guaranteed to exist here).\n console.error('[RealtimeCanvas] failed to load the rendering chunk:', err);\n },\n );\n return () => {\n cancelled = true;\n };\n }, []);\n\n if (!Impl) {\n return (\n <div\n className={`sc-root${className ? ` ${className}` : ''}`}\n style={{ minHeight: maxHeight ?? 200, ...style }}\n aria-busy=\"true\"\n />\n );\n }\n\n return (\n <Impl ref={ref} selfScope maxHeight={maxHeight} className={className} style={style} {...rest}>\n {children}\n </Impl>\n );\n },\n);\n","'use client';\n\n/**\n * `<RealtimeMockup>` — the live preview half of a realtime embed (legacy\n * turnkey API). The implementation was EXTRACTED to `Editor.Preview`\n * (ADR-0085 / D5); this wrapper keeps the original name and props. (The\n * rendered `<img>` now carries `data-sc-part=\"preview\"` — additive only.)\n *\n * Because it shares one session with the rest of the embed, the preview can\n * never desync from the editor and needs no wiring of its own. Place it\n * anywhere inside `<RealtimeEmbed>`.\n */\n\nimport React from 'react';\nimport { EditorPreview, type EditorPreviewProps } from '../editor/EditorPreview.js';\n\n// Re-exported from the extraction home so existing imports keep working.\nexport {\n RESOLUTION_MISMATCH_RATIO,\n resolutionMismatchHint,\n suggestRenderWidth,\n} from '../editor/EditorPreview.js';\n\nexport type RealtimeMockupProps = EditorPreviewProps;\n\nexport function RealtimeMockup(props: RealtimeMockupProps): React.ReactElement {\n return <EditorPreview {...props} />;\n}\n","'use client';\n\nimport type { MockupResult } from '@snowcone-app/sdk';\nimport { useEmbedContext } from './context.js';\n\nexport interface UseRealtimeMockupsResult {\n /** All mockups from the latest render (one per requested mockupId). */\n mockups: MockupResult[];\n /** True between a render dispatch and the next mockup / error. */\n isRendering: boolean;\n /** Last render/timeout error message, or null. */\n error: string | null;\n}\n\n/**\n * Read the live mockups for a custom preview UI. Reactive: re-renders when new\n * mockups arrive. Must be called inside `<RealtimeEmbed>`.\n *\n * For the common case (just show the rendered image) use `<RealtimeMockup>`\n * instead — this hook is for building your own gallery / loading treatment.\n */\nexport function useRealtimeMockups(): UseRealtimeMockupsResult {\n const { mockups, isRendering, error } = useEmbedContext();\n return { mockups, isRendering, error };\n}\n","/**\n * `productToRenderConfig` — the one-call adapter from a catalog payload\n * (`getProduct()` / Meilisearch document) to everything `Editor.Root` and the\n * `design()` seed need.\n *\n * This logic used to live in every host as ~100 lines of tribal knowledge,\n * and each rule has a silent failure mode when hand-rolled wrong:\n *\n * - a COLOR axis (any option choice carrying `hex`) is the one variant kind\n * that gates rendering — it requires a `variantId` (the server auto-fills\n * the color placement from it); non-color axes render on the default\n * variant. Forget it → ~30s render hang.\n * - mockup scenes can be split across variants: a scene whose `gvids` don't\n * include the rendered variant composites NO artwork. Prefer scenes that\n * photograph the variant being rendered. Pick wrong → blank product photo.\n * - only `type !== \"color\"` placements with real width/height are editable\n * artboards. Seed against a color placement → blank mockup.\n *\n * Every advisory field is passed through (`options`, `placements`, `mockups`,\n * `requiredPlacements`, `defaultGvid`) so `Editor.Root`'s fail-fast contracts\n * stay armed. Unrenderable input throws a structured\n * `EditorError('E_PRODUCT_NOT_RENDERABLE')` — loud, typed, agent-visible —\n * never a null for the host to forget to check.\n */\n\nimport type { CatalogProduct, RenderProduct } from '@snowcone-app/sdk';\nimport { EditorError } from '../errors/editorError.js';\nimport { isBundleProduct } from './bundle-config.js';\n\nexport interface ProductRenderConfigOptions {\n /** Placement label to edit (e.g. \"Back\"). Defaults to the product's first\n * renderable image placement. Unknown labels throw with `validNames`. */\n placement?: string;\n /** Render width passthrough (`product.width`) — bump to ~2000 for a crisp\n * full-bleed preview. `Editor.Preview` hints in dev when it's too low. */\n width?: number;\n}\n\nexport interface ProductRenderConfig {\n /** Ready for `<Editor.Root product={…}>` — advisory fields included so\n * wiring mistakes fail loud at mount. */\n product: RenderProduct;\n /** The placement being edited — seed `design({ name: label, width, height })`\n * from exactly these values. */\n placement: {\n label: string;\n /** Artboard pixel dimensions (the placement's print-file geometry). */\n width: number;\n height: number;\n /** width / height — for sizing the host's canvas stage. */\n aspectRatio: number;\n };\n /** Every editable (non-color) placement label — placement pickers. */\n placementLabels: string[];\n /** Geometry of EVERY renderable image placement, in catalog order — seed a\n * multi-placement design mechanically (ADR-0088):\n * `config.placements.reduce((d, p) => d.artboard(p.label, p), …)`. The\n * entry matching `placement` is the same object shape. */\n placements: Array<{ label: string; width: number; height: number; aspectRatio: number }>;\n /** First mockup scene that photographs the rendered variant — the default\n * `<Editor.Preview mockupId>`. */\n primaryMockupId: string;\n /** The variant the config renders against (`undefined` when no color axis\n * gates rendering). Already set on `product`. */\n variantId: string | undefined;\n}\n\ntype CatalogPlacement = NonNullable<CatalogProduct['placements']>[number];\n\nfunction isRenderablePlacement(p: CatalogPlacement): p is CatalogPlacement & { width: number; height: number } {\n return p.type !== 'color' && typeof p.width === 'number' && p.width > 0 && typeof p.height === 'number' && p.height > 0;\n}\n\n/**\n * Derive the full embed wiring from one `getProduct()` payload.\n *\n * ```ts\n * const config = productToRenderConfig(await getProduct('BEEB77'));\n * const seed = design({ name: config.placement.label, ...config.placement })\n * .text('hello', { anchor: 'center', name: 'headline' });\n *\n * <Editor.Root shop={SHOP} product={config.product} design={seed} grantUrl=\"/api/realtime-grant\">\n * ```\n *\n * @throws EditorError `E_PRODUCT_NOT_RENDERABLE` when the product has no\n * renderable image placement, no mockup scenes, or `options.placement`\n * names a placement that doesn't exist (`data.validNames` lists the real ones).\n * @throws EditorError `E_BUNDLE_CONFIG_REQUIRED` when the product is a BUNDLE\n * (ADR-0099: a `bundle` block) — it has no single variantId and role-scoped\n * placements, so this adapter cannot describe it; use `bundleToRenderConfig()`.\n */\nexport function productToRenderConfig(\n catalogProduct: CatalogProduct,\n options: ProductRenderConfigOptions = {},\n): ProductRenderConfig {\n // A bundle is a different shape (per-role variants, role-scoped placement\n // keys). Building the single-product config from it would send a bare\n // variantId and bare labels the server refuses — or, with no color axis,\n // open a session that renders nothing. Refuse up front, naming the fix.\n if (isBundleProduct(catalogProduct)) {\n throw new EditorError(\n 'E_BUNDLE_CONFIG_REQUIRED',\n `product ${catalogProduct.id} is a bundle (roles: [${catalogProduct.bundle.members.map((m) => m.role).join(', ')}]) — ` +\n 'it has per-role variants and role-scoped placement keys, which the single-product config cannot ' +\n 'describe. Use bundleToRenderConfig(product, { picks?, variants?, placement?, width? }) instead.',\n {\n productId: catalogProduct.id,\n validNames: catalogProduct.bundle.members.map((m) => m.role),\n docSlug: 'bundles',\n },\n );\n }\n\n const renderable = (catalogProduct.placements ?? []).filter(isRenderablePlacement);\n const renderableLabels = renderable.map((p) => p.label);\n\n const placement = options.placement\n ? renderable.find((p) => p.label === options.placement)\n : renderable[0];\n if (!placement) {\n if (options.placement) {\n throw new EditorError(\n 'E_PRODUCT_NOT_RENDERABLE',\n `product ${catalogProduct.id} has no renderable placement \"${options.placement}\". ` +\n `Renderable image placements: [${renderableLabels.join(', ')}].`,\n { productId: catalogProduct.id, requested: options.placement, validNames: renderableLabels, docSlug: 'embed-mode' },\n );\n }\n throw new EditorError(\n 'E_PRODUCT_NOT_RENDERABLE',\n `product ${catalogProduct.id} has no renderable image placement (a non-color ` +\n 'placement with width/height). The catalog payload may be incomplete — fetch it ' +\n 'via getProduct(), not a search hit.',\n { productId: catalogProduct.id, docSlug: 'embed-mode' },\n );\n }\n\n // A COLOR axis (choices carrying `hex`) is the one variant kind that gates\n // rendering — it REQUIRES a variantId. Non-color axes render on the default\n // variant. (A color axis with no resolvable variantId is left undefined here\n // so Editor.Root's mount validation reports it as the wiring error it is.)\n const attributes = catalogProduct.options?.attributes ?? {};\n const hasColorAxis = Object.values(attributes).some((attr) =>\n attr?.choices?.some((choice) => choice?.hex),\n );\n const variantId = hasColorAxis\n ? catalogProduct.options?.combinations?.find(\n (combo) => typeof combo.variantId === 'string' && combo.variantId !== '',\n )?.variantId as string | undefined\n : undefined;\n\n // Scenes can be split across variants — a mockup whose `gvids` don't include\n // the rendered variant composites NO artwork. Prefer scenes that photograph\n // the variant we render; fall back to all scenes when none match (stale gvid\n // data beats an empty embed).\n const mockups = catalogProduct.mockups ?? [];\n const scoped = variantId ? mockups.filter((m) => m.gvids?.includes(variantId)) : mockups;\n const mockupIds = (scoped.length > 0 ? scoped : mockups).map((m) => m.id);\n if (mockupIds.length === 0) {\n throw new EditorError(\n 'E_PRODUCT_NOT_RENDERABLE',\n `product ${catalogProduct.id} has no mockup scenes — nothing to render a preview into.`,\n { productId: catalogProduct.id, docSlug: 'embed-mode' },\n );\n }\n\n const product: RenderProduct = {\n productId: catalogProduct.id,\n mockupIds,\n ...(typeof variantId === 'string' ? { variantId } : {}),\n options: catalogProduct.options,\n placements: catalogProduct.placements?.map((p) => p.label),\n mockups,\n requiredPlacements: catalogProduct.requiredPlacements,\n ...(catalogProduct.defaultGvid ? { defaultGvid: catalogProduct.defaultGvid } : {}),\n ...(typeof options.width === 'number' ? { width: options.width } : {}),\n };\n\n return {\n product,\n placement: {\n label: placement.label,\n width: placement.width,\n height: placement.height,\n aspectRatio: placement.width / placement.height,\n },\n placementLabels: renderableLabels,\n placements: renderable.map((p) => ({\n label: p.label,\n width: p.width,\n height: p.height,\n aspectRatio: p.width / p.height,\n })),\n primaryMockupId: mockupIds[0],\n variantId,\n };\n}\n","'use client';\n\n/**\n * `<SnowconeEditor>` — the turnkey default editor, REBUILT FROM THE PUBLIC\n * PARTS (ADR-0085, P4). Visual spec: `canvas-default-chrome-new-v1`\n * (`/design-system/page/canvas-default-chrome-new-v1` in apps/www) — the\n * PDP-editor grammar: calm surface, an \"Editor\" header (undo/redo · ⋯ ·\n * Buy-instead-of-Done), nothing floating over the artwork, a morphing\n * control zone BELOW the stage, and the buyable 2:3 mockup in a PiP that\n * swaps with the stage.\n *\n * THE LOAD-BEARING CONSTRAINT: this module imports ONLY the public embed\n * entry (`../api/embed.js` — the same surface a host gets from\n * `@snowcone-app/canvas/embed`) plus react. No `../` imports into internals,\n * mechanically gated (publicSurfaceGate test + verify typecheck). The day\n * this default needs a private API, the primitives are wrong — restyling to\n * a future chrome (e.g. the v2 bar-less mock) must be a composition tweak.\n *\n * PART COMPOSITION MAP (the plan's inline-diagram home for P4):\n *\n * SnowconeEditor\n * └── Editor.Root session · design · stores · boundary\n * └── frame (embed card ⇄ fullscreen takeover — same chrome, only the\n * │ frame changes; both directions live in the ⋯ menu)\n * ├── header\n * │ ├── \"Editor\" title\n * │ ├── Editor.History undo/redo\n * │ ├── ⋯ menu (own DOM) fullscreen · view switch · export PNG\n * │ │ (export via the Editor.Canvas ref\n * │ │ handle — runtime, not a static import)\n * │ └── Editor.Buy \"Add to cart · $price\" pill\n * │ └── useProductSelection() price + completeness\n * ├── stage\n * │ ├── Editor.Canvas the editable artboard (center)\n * │ └── Editor.Preview buyable mockup PiP (top-right,\n * │ tap to swap with the stage)\n * └── control zone (morphs below the stage; nothing floats)\n * ├── selected → Editor.Controls placement=\"docked\"\n * │ (registering docked Controls suppresses the\n * │ canvas's built-in floating toolbar — §5)\n * └── idle → Editor.Add ⊕ + layer thumbnails\n * (useLayers(): previews + select — public\n * headless floor, no private API)\n *\n * Stable since ADR-0085 P4 (this component IS the gate artifact — composed\n * only from the public embed entry); additive-only from here.\n */\n\nimport React, {\n useCallback,\n useEffect,\n useRef,\n useState,\n type CSSProperties,\n} from 'react';\nimport {\n Editor,\n useProductSelection,\n useSelectedElement,\n useLayers,\n type EditorRootBaseProps,\n type EditorBuyPayload,\n type GrantSource,\n type SnowconeCanvasHandle,\n} from '../api/embed.js';\n\nexport type SnowconeEditorProps = GrantSource &\n Omit<EditorRootBaseProps, 'children' | '__validation'> & {\n /** The final submit — your one line. Variant/quantity/completeness and\n * payload assembly are `Editor.Buy`'s job. */\n onAddToCart: (payload: EditorBuyPayload) => void | Promise<void>;\n /** Seeds the Buy-owned quantity once on mount (default 1). */\n defaultQuantity?: number;\n /** Header title. Default \"Editor\". */\n title?: string;\n /** Embedded-card height (px or CSS length). Fullscreen ignores it. */\n height?: number | string;\n className?: string;\n style?: CSSProperties;\n };\n\n/** Price label for the Buy pill — catalog prices are cents. Whole dollars\n * render without cents (\"$24\"), like the PDP. */\nexport function formatBuyPrice(cents: number): string {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: 'USD',\n minimumFractionDigits: cents % 100 === 0 ? 0 : 2,\n maximumFractionDigits: cents % 100 === 0 ? 0 : 2,\n }).format(cents / 100);\n}\n\n// ── Shared inline styles (themed via .sc-root tokens, like every part) ──────\n\nconst iconButtonStyle: CSSProperties = {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 32,\n height: 32,\n padding: 0,\n borderRadius: 9999,\n border: 'none',\n background: 'transparent',\n color: 'var(--sc-color-foreground, #111)',\n font: 'inherit',\n fontSize: 16,\n lineHeight: 1,\n cursor: 'pointer',\n};\n\nconst menuItemStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n width: '100%',\n padding: '8px 10px',\n borderRadius: 8,\n border: 'none',\n background: 'transparent',\n color: 'inherit',\n font: 'inherit',\n fontSize: 12,\n fontWeight: 500,\n textAlign: 'left',\n cursor: 'pointer',\n};\n\nfunction MenuItem({\n label,\n onSelect,\n}: {\n label: string;\n onSelect: () => void;\n}): React.ReactElement {\n return (\n <button\n type=\"button\"\n role=\"menuitem\"\n data-sc-part=\"snowcone-editor-menu-item\"\n style={menuItemStyle}\n onClick={onSelect}\n >\n {label}\n </button>\n );\n}\n\n// ── The ⋯ menu (own DOM — the turnkey ARRANGEMENT owns fullscreen/view/export;\n// they are modes of this composition, not editor-document commands) ───────\n\nfunction OverflowMenu({\n fullscreen,\n onToggleFullscreen,\n viewCount,\n viewIndex,\n onSelectView,\n onExport,\n}: {\n fullscreen: boolean;\n onToggleFullscreen: () => void;\n viewCount: number;\n viewIndex: number;\n onSelectView: (index: number) => void;\n onExport: () => void;\n}): React.ReactElement {\n const [open, setOpen] = useState(false);\n const close = (): void => setOpen(false);\n return (\n <div style={{ position: 'relative' }}>\n <button\n type=\"button\"\n aria-label=\"Editor menu\"\n aria-haspopup=\"menu\"\n aria-expanded={open}\n data-sc-part=\"snowcone-editor-menu\"\n style={iconButtonStyle}\n onClick={() => setOpen((o) => !o)}\n >\n ⋮\n </button>\n {open ? (\n <>\n {/* click-away backdrop */}\n <div\n style={{ position: 'fixed', inset: 0, zIndex: 39 }}\n onClick={close}\n aria-hidden=\"true\"\n />\n <div\n role=\"menu\"\n data-sc-part=\"snowcone-editor-menu-list\"\n style={{\n position: 'absolute',\n right: 0,\n top: '100%',\n marginTop: 4,\n minWidth: 176,\n padding: 4,\n borderRadius: 12,\n background: 'var(--sc-color-surface, #fff)',\n boxShadow: '0 8px 24px rgba(0,0,0,0.14)',\n border: '1px solid rgba(0,0,0,0.08)',\n zIndex: 40,\n }}\n >\n <MenuItem\n label={fullscreen ? 'Exit fullscreen' : 'Fullscreen'}\n onSelect={() => {\n close();\n onToggleFullscreen();\n }}\n />\n {viewCount > 1\n ? Array.from({ length: viewCount }, (_, i) => (\n <MenuItem\n key={i}\n label={`View ${i + 1}${i === viewIndex ? ' ✓' : ''}`}\n onSelect={() => {\n close();\n onSelectView(i);\n }}\n />\n ))\n : null}\n <MenuItem\n label=\"Export PNG\"\n onSelect={() => {\n close();\n onExport();\n }}\n />\n </div>\n </>\n ) : null}\n </div>\n );\n}\n\n// ── Idle dock: ⊕ + layer thumbnails (public headless floor) ─────────────────\n\nfunction IdleDock(): React.ReactElement {\n const { flatLayers, selectLayer, generateAllPreviews } = useLayers({ previewSize: 96 });\n\n useEffect(() => {\n if (flatLayers.length > 0) void generateAllPreviews();\n }, [flatLayers.length, generateAllPreviews]);\n\n return (\n <div\n data-sc-part=\"snowcone-editor-idle-dock\"\n style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8, minHeight: 44 }}\n >\n <Editor.Add />\n {flatLayers.length > 0 ? (\n <div style={{ width: 1, height: 28, background: 'rgba(0,0,0,0.1)', flexShrink: 0 }} aria-hidden=\"true\" />\n ) : null}\n {flatLayers.map((layer) => (\n <button\n key={layer.id}\n type=\"button\"\n data-sc-part=\"snowcone-editor-layer-thumb\"\n aria-label={`Select ${layer.name}`}\n onClick={() => selectLayer(layer.id)}\n style={{\n width: 44,\n height: 44,\n padding: 2,\n borderRadius: 12,\n border: '1px solid rgba(0,0,0,0.1)',\n background: 'var(--sc-color-surface, #fff)',\n overflow: 'hidden',\n cursor: 'pointer',\n flexShrink: 0,\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n {layer.previewUrl ? (\n // eslint-disable-next-line @next/next/no-img-element\n <img src={layer.previewUrl} alt=\"\" style={{ width: '100%', height: '100%', objectFit: 'contain' }} />\n ) : (\n <span\n style={{\n fontSize: 10,\n fontWeight: 600,\n maxWidth: '100%',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {layer.name}\n </span>\n )}\n </button>\n ))}\n </div>\n );\n}\n\n// ── Buy pill (label = \"Add to cart · $price\" when the catalog has one) ──────\n\nfunction BuyPill({\n onAddToCart,\n defaultQuantity,\n}: {\n onAddToCart: (payload: EditorBuyPayload) => void | Promise<void>;\n defaultQuantity?: number;\n}): React.ReactElement {\n const { price, complete } = useProductSelection();\n return (\n <Editor.Buy\n onAddToCart={onAddToCart}\n {...(typeof defaultQuantity === 'number' ? { defaultQuantity } : {})}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: 6,\n padding: '7px 16px',\n marginLeft: 4,\n borderRadius: 9999,\n border: 'none',\n background: 'var(--sc-color-foreground, #111)',\n color: 'var(--sc-color-surface, #fff)',\n font: 'inherit',\n fontSize: 12,\n fontWeight: 700,\n whiteSpace: 'nowrap',\n cursor: complete ? 'pointer' : 'not-allowed',\n opacity: complete ? 1 : 0.5,\n }}\n >\n Add to cart{typeof price === 'number' ? ` · ${formatBuyPrice(price)}` : ''}\n </Editor.Buy>\n );\n}\n\n// ── The chrome (everything inside Editor.Root) ──────────────────────────────\n\nfunction DefaultChrome({\n title,\n height,\n mockupIds,\n onAddToCart,\n defaultQuantity,\n className,\n style,\n}: {\n title: string;\n height: number | string;\n mockupIds: string[];\n onAddToCart: (payload: EditorBuyPayload) => void | Promise<void>;\n defaultQuantity?: number;\n className?: string;\n style?: CSSProperties;\n}): React.ReactElement {\n const [fullscreen, setFullscreen] = useState(false);\n const [viewIndex, setViewIndex] = useState(0);\n const [swapped, setSwapped] = useState(false);\n const canvasRef = useRef<SnowconeCanvasHandle>(null);\n const selected = useSelectedElement();\n\n const mockupId = mockupIds[Math.min(viewIndex, mockupIds.length - 1)];\n\n // Export through the mounted canvas's public ref handle — runtime-only, so\n // this module's static graph stays renderer-free (the heavy export path\n // lives behind Editor.Canvas's lazy chunk, where it already is).\n const handleExport = useCallback(async () => {\n const exports = await canvasRef.current?.exportArtboards({ format: 'dataUrl' });\n if (!exports) return;\n const [name, dataUrl] = Object.entries(exports)[0] ?? [];\n if (typeof dataUrl !== 'string') return;\n const anchor = document.createElement('a');\n anchor.href = dataUrl;\n anchor.download = `${name ?? 'design'}.png`;\n anchor.click();\n }, []);\n\n const frameStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n background: 'var(--sc-color-surface, #fff)',\n color: 'var(--sc-color-foreground, #111)',\n fontFamily: 'ui-sans-serif, system-ui, sans-serif',\n ...(fullscreen\n ? {\n position: 'fixed',\n inset: 0,\n zIndex: 9999,\n height: '100dvh',\n paddingBottom: 'env(safe-area-inset-bottom)',\n }\n : {\n position: 'relative',\n height,\n borderRadius: 16,\n border: '1px solid rgba(0,0,0,0.08)',\n boxShadow: '0 1px 3px rgba(0,0,0,0.08)',\n }),\n ...style,\n };\n\n const pipBoxStyle: CSSProperties = {\n position: 'absolute',\n top: 8,\n right: 12,\n width: 96,\n aspectRatio: '2 / 3',\n borderRadius: 12,\n overflow: 'hidden',\n border: '1px solid rgba(0,0,0,0.1)',\n boxShadow: '0 4px 12px rgba(0,0,0,0.12)',\n background: 'var(--sc-color-surface, #fff)',\n padding: 0,\n cursor: 'pointer',\n zIndex: 2,\n };\n\n return (\n <div\n data-sc-part=\"snowcone-editor\"\n data-sc-fullscreen={fullscreen ? 'true' : undefined}\n className={className}\n style={frameStyle}\n >\n {/* Header — title · undo/redo · ⋯ · Buy (the PDP header, Done → Buy) */}\n <div\n data-sc-part=\"snowcone-editor-header\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 2,\n padding: '10px 12px 4px 16px',\n flexShrink: 0,\n }}\n >\n <span style={{ fontSize: 14, fontWeight: 700, marginRight: 'auto' }}>{title}</span>\n <Editor.History />\n <OverflowMenu\n fullscreen={fullscreen}\n onToggleFullscreen={() => setFullscreen((f) => !f)}\n viewCount={mockupIds.length}\n viewIndex={viewIndex}\n onSelectView={setViewIndex}\n onExport={() => void handleExport()}\n />\n <BuyPill onAddToCart={onAddToCart} defaultQuantity={defaultQuantity} />\n </div>\n\n {/* Stage — artboard center; buyable mockup PiP top-right, tap to swap */}\n <div\n data-sc-part=\"snowcone-editor-stage\"\n style={{ position: 'relative', flex: 1, minHeight: 0, padding: '4px 12px' }}\n >\n <Editor.Canvas ref={canvasRef} style={{ height: '100%' }} />\n\n {swapped ? (\n // Swapped: the mockup IS the stage; the corner chip returns to the\n // artwork. The canvas stays mounted underneath (no document\n // teardown), just covered.\n <div\n data-sc-part=\"snowcone-editor-swap-stage\"\n style={{\n position: 'absolute',\n inset: 0,\n zIndex: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'var(--sc-color-surface, #fff)',\n padding: 8,\n }}\n >\n <Editor.Preview\n mockupId={mockupId}\n alt=\"Product mockup\"\n loadingOverlay\n fallback={<div aria-busy=\"true\">Rendering…</div>}\n style={{ maxWidth: '100%', maxHeight: '100%', borderRadius: 12 }}\n />\n <button\n type=\"button\"\n aria-label=\"Back to artwork\"\n data-sc-part=\"snowcone-editor-swap-back\"\n onClick={() => setSwapped(false)}\n style={{\n ...pipBoxStyle,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: 11,\n fontWeight: 600,\n color: 'inherit',\n border: '1px dashed rgba(0,0,0,0.25)',\n }}\n >\n artwork\n </button>\n </div>\n ) : (\n <button\n type=\"button\"\n aria-label=\"Show product mockup\"\n data-sc-part=\"snowcone-editor-pip\"\n onClick={() => setSwapped(true)}\n style={pipBoxStyle}\n >\n <Editor.Preview\n mockupId={mockupId}\n alt=\"Product mockup preview\"\n loadingOverlay\n fallback={<span style={{ fontSize: 10, opacity: 0.5 }} aria-busy=\"true\">mockup…</span>}\n style={{ width: '100%', height: '100%', display: 'block' }}\n />\n </button>\n )}\n </div>\n\n {/* Control zone — morphs BELOW the stage (PDP grammar): idle → ⊕ +\n layer thumbs; selected → the docked contextual zone (which also\n suppresses the canvas's floating toolbar — nothing floats). */}\n <div\n data-sc-part=\"snowcone-editor-zone\"\n data-sc-zone-state={selected ? 'selected' : 'idle'}\n style={{ flexShrink: 0, padding: '4px 16px 14px' }}\n >\n <div style={{ display: selected ? undefined : 'none' }}>\n <Editor.Controls placement=\"docked\" />\n </div>\n {selected ? null : <IdleDock />}\n </div>\n </div>\n );\n}\n\n/**\n * The turnkey Snowcone editor — the same public parts, our arrangement.\n *\n * ```tsx\n * import { SnowconeEditor, design } from '@snowcone-app/canvas/embed';\n *\n * <SnowconeEditor\n * shop={SHOP_KEY}\n * product={{ productId: 'BEEB77', mockupIds: ['FV1qjO'], variantId: 'Pv1sLC', placements: ['Front'] }}\n * design={design({ name: 'Front', width: 1480, height: 2328 }).text('hello', { name: 'headline' })}\n * grantUrl=\"/api/realtime/grant\"\n * onAddToCart={(payload) => persist(payload.designState)}\n * />\n * ```\n *\n * Customizing beyond the props means composing `Editor.*` yourself — this\n * component is ~300 lines of public-surface composition you can copy and own.\n *\n * Stable since ADR-0085 P4 (this component IS the gate artifact — composed\n * only from the public embed entry); additive-only from here.\n */\nexport function SnowconeEditor(props: SnowconeEditorProps): React.ReactElement {\n const {\n onAddToCart,\n defaultQuantity,\n title = 'Editor',\n height = 480,\n className,\n style,\n ...rootProps\n } = props;\n\n return (\n <Editor.Root {...rootProps}>\n <DefaultChrome\n title={title}\n height={height}\n mockupIds={rootProps.product.mockupIds}\n onAddToCart={onAddToCart}\n {...(typeof defaultQuantity === 'number' ? { defaultQuantity } : {})}\n className={className}\n style={style}\n />\n </Editor.Root>\n );\n}\n","/**\n * @snowcone-app/canvas/embed — Realtime embed primitives (Tier 2)\n *\n * The turnkey way to drop a live, server-rendered product editor into your app.\n * Three components that share one session so the editor and the preview can't\n * desync, plus the `design()` builder that seeds both:\n *\n * ```tsx\n * import { RealtimeEmbed, RealtimeCanvas, RealtimeMockup, design }\n * from '@snowcone-app/canvas/embed';\n * import '@snowcone-app/canvas/style.css';\n *\n * const d = design({ name: 'Front', width: 1480, height: 2328 })\n * .background(artUrl, { aspectRatio: 1480 / 2328, name: 'art' })\n * .text('YOUR NAME', { anchor: 'top', name: 'headline' });\n *\n * <RealtimeEmbed\n * shop=\"YOUR_SHOP_ID\"\n * grantUrl=\"/api/realtime/grant\"\n * // variantId is REQUIRED when the product has a color/variant axis (BEEB77\n * // does) — omit it and the render hangs. Read it + options from getProduct().\n * product={{ productId: 'BEEB77', mockupIds: ['FV1qjO'], variantId: 'Pv1sLC', placements: ['Front'] }}\n * design={d}\n * >\n * <RealtimeCanvas />\n * <RealtimeMockup />\n * </RealtimeEmbed>\n * ```\n *\n * Everything an embed needs is REQUIRED on `<RealtimeEmbed>` — there's no\n * silently-optional prop to forget. For full manual control (your own session,\n * custom layout, multi-placement, color variants) drop to `<SnowconeCanvas>` +\n * `RenderSession` directly; see the docs' \"eject\" section.\n *\n * @packageDocumentation\n */\n\n// Register icons on module load (the editor + overlay controls use them).\nimport { ensureIconsRegistered } from '../icons/registry.js';\nensureIconsRegistered();\n\n// === Editor.* composable primitives (ADR-0085) ===\n// STABLE: the P4 gate passed — SnowconeEditor (bottom of this file) is rebuilt\n// from exactly this surface, CI-enforced. Additive-only from here; renames and\n// removals are pinned by publicSurfaceGate.test.ts.\nexport { Editor, DesignStateStore, useProductSelection, usePlacements, auditEditor } from '../components/editor/index.js';\nexport type {\n EditorAuditReport,\n EditorAuditFinding,\n EditorAuditFindingCode,\n EditorRootProps,\n EditorRootBaseProps,\n EditorCanvasProps,\n EditorPlacementsProps,\n PlacementInfo,\n UsePlacementsReturn,\n EditorPreviewProps,\n EditorLoadingOverlayProps,\n EditorTextFieldProps,\n EditorBuyProps,\n EditorBuyPayload,\n BuyMissingReason,\n DesignState,\n EditorLayersProps,\n EditorControlsProps,\n EditorHistoryProps,\n EditorMenuProps,\n EditorAddProps,\n ProductSelectionApi,\n ProductOptionChoice,\n ProductSelectionAttribute,\n} from '../components/editor/index.js';\nexport { EditorError, isEditorError } from '../errors/editorError.js';\nexport type { EditorErrorCode, EditorErrorData } from '../errors/editorError.js';\n\n// === Embed primitives ===\nexport { RealtimeEmbed } from '../components/embed-realtime/RealtimeEmbed.js';\nexport type { RealtimeEmbedProps, GrantSource } from '../components/embed-realtime/RealtimeEmbed.js';\n\nexport { RealtimeCanvas } from '../components/embed-realtime/RealtimeCanvas.js';\nexport type { RealtimeCanvasProps } from '../components/embed-realtime/RealtimeCanvas.js';\n// `<RealtimeCanvas ref>` exposes the underlying canvas handle (print-res\n// `exportArtboards`, keyed by artboard NAME); `onChange` hands you the same\n// CanvasState shape — persist it at checkout, re-render it server-side later.\nexport type { SnowconeCanvasHandle, CanvasState } from '../components/embed/SnowconeCanvas.js';\n\nexport { RealtimeMockup } from '../components/embed-realtime/RealtimeMockup.js';\nexport type { RealtimeMockupProps } from '../components/embed-realtime/RealtimeMockup.js';\n\nexport { useRealtimeMockups } from '../components/embed-realtime/useRealtimeMockups.js';\nexport type { UseRealtimeMockupsResult } from '../components/embed-realtime/useRealtimeMockups.js';\n\nexport { validateEmbed, collectEmbedIssues } from '../components/embed-realtime/validateEmbed.js';\nexport type { ValidateEmbedInput, EmbedIssue } from '../components/embed-realtime/validateEmbed.js';\n\n// === Catalog → embed wiring (one call from a getProduct() payload) ===\nexport { productToRenderConfig } from '../design/product-config.js';\nexport type { ProductRenderConfig, ProductRenderConfigOptions } from '../design/product-config.js';\n// ADR-0099 bundles: several products in one mockup. A DISTINCT config shape —\n// role-scoped placement keys, per-role variants, picks per slot. The two\n// adapters refuse each other's input with typed errors.\nexport { bundleToRenderConfig, isBundleProduct, bundleVariantToken, splitRoleKey } from '../design/bundle-config.js';\nexport type {\n BundleRenderConfig,\n BundleRenderConfigOptions,\n BundleRoleConfig,\n BundlePlacementConfig,\n BundleVariantChoice,\n CatalogBundleProduct,\n CatalogBundleBlock,\n CatalogBundleMember,\n CatalogBundleAlternative,\n} from '../design/bundle-config.js';\nexport { isBundleRenderProduct } from '../components/embed-realtime/validateEmbed.js';\n\n// === Design builder — the single source of truth for an embed ===\nexport { design, DesignBuilder, isLayerToken, isColorToken } from '../design/design-builder.js';\nexport type {\n Anchor,\n ShapeKind,\n DesignArtboard,\n StateArtboard,\n FromStateOptions,\n AnyDesign,\n LayerKind,\n LayerToken,\n ColorToken,\n} from '../design/design-builder.js';\n\n// === Chrome-building hooks (build your own editor chrome inside <RealtimeCanvas>) ===\n// These run inside the canvas's editor context — render the component that\n// calls them as `children` of <RealtimeCanvas> (the overlay slot). Same\n// exports as the stable entry, so chrome built against `@snowcone-app/canvas`\n// ports to the embed entry unchanged.\n\nexport { useEditor } from '../contexts/EditorContext.js';\nexport type { EditorContextValue, EditorProviderProps } from '../contexts/EditorContext.js';\n\n// The element model (the headless floor's data type): `EditorElement` is the\n// union `useSelectedElement()` / `useEditor().elements` hand back; the\n// per-kind guards make `instanceof`-grade narrowing possible without the\n// internal classes (agentic-DX finding #11).\nexport type { EditorElement, AddElementSpec, ElementHandle } from '../contexts/EditorContext.js';\nexport {\n isTextElement,\n isImageElement,\n isShapeElement,\n isGroupElement,\n isPathElement,\n editorElementKind,\n} from '../core/elementGuards.js';\nexport type { EditorElementKind } from '../core/elementGuards.js';\n\nexport { useLayers } from '../hooks/useLayers.js';\nexport type { LayerInfo, UseLayersOptions, UseLayersReturn } from '../hooks/useLayers.js';\n\n// `useCommands().updateElement(target, patch)` — the declarative, validated,\n// undoable write path (agentic-DX finding #12); `addElement(spec)` returns a\n// handle and throws E_NO_ACTIVE_ARTBOARD instead of alerting (finding #13).\nexport { useCommands } from '../hooks/useCommands.js';\nexport type { UseCommandsReturn } from '../hooks/useCommands.js';\nexport type { ElementPatch, UpdateElementOptions } from '../hooks/elementPatch.js';\n\nexport { useArtboards } from '../hooks/useArtboards.js';\nexport type { ArtboardInfo, UseArtboardsReturn } from '../hooks/useArtboards.js';\n\n// NOTE the naming wart: `useExport().exportArtboard(id)` takes an artboard ID\n// (from `useArtboards()`), while the <RealtimeCanvas ref> handle's\n// `exportArtboards()` resolves a record keyed by artboard NAME.\nexport { useExport } from '../hooks/useExport.js';\nexport type { ExportProgress, ContinuousExportOptions, UseExportReturn } from '../hooks/useExport.js';\n\nexport { useSelectedElement } from '../hooks/useSelectedElement.js';\n\n// === State serialization (CanvasStateV1 — persist a design at checkout) ===\nexport { serializeState } from '../state/index.js';\nexport type {\n CanvasStateV1,\n SerializedArtboard,\n SerializedElement,\n} from '../state/index.js';\n\n// === Custom (brand) fonts (host-uploaded; `services.onFontUpload`) ===\nexport {\n loadCustomFont,\n registerCustomFonts,\n ensureCustomFontsLoaded,\n customFontRegistry,\n} from '../utils/custom-fonts.js';\nexport type { CustomFont, LoadCustomFontOptions } from '../utils/custom-fonts.js';\n\n// === Binding hooks (build your own controls inside <RealtimeCanvas>) ===\nexport { useTextBinding } from '../hooks/useTextBinding.js';\nexport { useImageBinding } from '../hooks/useImageBinding.js';\nexport { useColorBinding } from '../hooks/useColorBinding.js';\nexport type { ColorBindingResult } from '../hooks/useColorBinding.js';\nexport { useFontBinding } from '../hooks/useFontBinding.js';\nexport type { FontBindingResult } from '../hooks/useFontBinding.js';\nexport { useElementByName } from '../hooks/useElementByName.js';\n\n// === Editable templates (saved state + buyer-editable field manifest) ===\nexport {\n readTemplateFields,\n withTemplateFields,\n TEMPLATE_FIELDS_KEY,\n} from '../design/template-fields.js';\nexport type {\n TemplateField,\n TemplateTextField,\n TemplateImageField,\n TemplateColorField,\n TemplateSelectField,\n} from '../design/template-fields.js';\n\n// === Privileged services (Image Browser search / AI generation) ===\n// Same pattern as `grantUrl`: host the proxy routes on your server, your\n// vendor keys live there. Wire via `services` on <RealtimeEmbed>.\nexport { CanvasServicesProvider, useCanvasServices } from '../contexts/CanvasServicesContext.js';\nexport type { CanvasServices, ResolvedCanvasServices } from '../contexts/CanvasServicesContext.js';\nexport { createProxyImageSearch, createProxyGenerate } from '../services/imageSearch.js';\nexport type {\n ImageSearchProvider,\n ImageSearchResult,\n ImageSearchResponse,\n ImageSearchParams,\n GenerateProvider,\n GenerateParams,\n GenerateResponse,\n} from '../services/imageSearch.js';\n\n// === Re-exported SDK types embedders touch ===\nexport type {\n CatalogProduct,\n RenderProduct,\n RenderProductOptions,\n RenderProductCombination,\n RenderProductRequiredPlacement,\n MockupResult,\n RealtimeGrant,\n} from '@snowcone-app/sdk';\n\n// === The turnkey default editor — rebuilt from the public parts (P4) ===\n// Deliberately LAST: SnowconeEditor itself imports this entry (it compiles\n// against the public surface only — the ADR-0085 P4 gate), so its module\n// body evaluates after everything above is initialized.\nexport { SnowconeEditor, formatBuyPrice } from '../default-editor/SnowconeEditor.js';\nexport type { SnowconeEditorProps } from '../default-editor/SnowconeEditor.js';\n"],"names":["EmbedContext","createContext","useEmbedContext","ctx","useContext","isBundleProduct","product","_a","DOC","bundleVariantToken","variantByRole","role","splitRoleKey","name","dot","isRenderablePlacement","p","variantLabel","alt","gvid","row","_b","c","parts","k","v","bundleToRenderConfig","catalogProduct","options","EditorError","members","roleNames","m","field","map","picks","variants","renderByRole","catalogPlacements","roles","member","alternatives","wanted","gvids","g","accepted","chosen","requested","_c","_e","_d","placements","pickedKeys","r","byKey","cfg","placementKeys","placement","mockups","matching","productId","mockupIds","requiredPlacements","TAG","requiredPlacementLabels","variantIds","id","isBundleRenderProduct","bundleRolesOf","key","split","collectEmbedIssues","shop","design","hasGrant","issues","assertVariantSelected","err","json","artboardNames","a","bundle","roleless","keys","missingVariant","required","inheriting","label","foreign","names","el","n","dupes","i","validateEmbed","input","issue","resolvePlacementLinks","requiredLabels","authored","out","expandRequestForPlacements","request","artboards","base","ab","byName","links","l","expanded","computeEditorAudit","registry","store","findings","textFields","requiresCanvas","canvasKeepsFloating","sceneIds","unpinned","hasBuy","tf","matched","counts","census","count","b","mountedRoots","registerRootForAudit","entry","index","auditEditor","current","SLOW_RENDER_HINT_MS","slowRenderHint","toGetToken","props","grant","ErrorCard","error","onRetry","code","isEditorError","jsxs","jsx","CatchingBoundary","Component","recordContainedEditorError","process","EditorBoundary","reportedError","children","retryable","EditorRootInner","throttleMs","onMockups","onRenderError","onIssue","wsUrl","services","internals","recordAudit","__validation","useMemo","artboardNamesKey","useSyncExternalStore","requiredKey","placementChoice","setPlacementChoice","useState","activePlacement","selectPlacement","valid","pushRenderRef","useRef","splitPlacement","bridge","serializeStateForServer","linkPlacement","initialArtboardConfig","artboard","selectedVariantId","guideBundle","usePieceGuideBundle","pieceGuides","pieceGuidesForArtboard","onMockupsRef","onRenderErrorRef","onIssueRef","setMockups","isRendering","setIsRendering","setError","auth","authKey","productKey","bundleKey","validationKey","advisoryIssues","fatal","reportedIssuesKeyRef","useEffect","validatedKeyRef","sessionResult","RenderSession","session","constructError","pushRender","state","throttle","handleSendError","message","sendSlice","results","appliedVariantRef","applied","baseline","appliedBundleRef","first","timer","value","registryVersion","body","EditorRootInternalsContext","BoundLayerGuardContext","EditorProvider","CanvasServicesProvider","EditorRoot","onAudit","productIdentity","internalsRef","commerceRef","setReportedError","DesignStateStore","EditorPartsRegistry","CommerceStateStore","makeInvariantReporter","productRef","onAuditRef","auditSnapshotRef","useCallback","report","computeAudit","useLayoutEffect","auditFiredRef","cancelled","implLoader","loadCanvasImpl","EditorCanvas","forwardRef","maxHeight","floatingToolbar","className","style","ref","useEditorRootInternals","useRegisterEditorPart","instanceId","useId","Impl","setImpl","component","usePlacements","infos","linked","defaultLinkedLabel","labels","actionStyle","EditorPlacements","select","splitAll","linkAll","active","inherited","SHOW_DELAY_MS","LINGER_MS","generateParticles","propertiesRegistered","ensurePrismProperties","PreviewPrismOverlay","memo","visible","onExited","variant","particles","setParticles","mounted","setMounted","raf","handleTransitionEnd","e","fadeClass","_","useRenderLoadingOverlay","isLoading","showOverlay","setShowOverlay","lingering","setLingering","showTimerRef","lingerTimerRef","shownRef","handleExited","RESOLUTION_MISMATCH_RATIO","SUGGESTED_WIDTHS","suggestRenderWidth","devicePx","step","resolutionMismatchHint","naturalWidth","suggestion","resolveLoadingOverlay","isValidElement","EditorPreview","mockupId","fallback","loadingOverlay","resolved","overlayVariant","customOverlay","overlayActive","overlayVisible","warnedMockupIdsRef","result","handleLoad","event","img","cssWidth","hint","frameState","EditorTextField","layer","optional","placeholder","stateStore","validatedNameRef","isLayerToken","kindNow","handleChange","next","evaluateBuyCompleteness","missing","seed","buildCartDetail","commerce","combinations","attributes","stringAttrs","attr","choiceLabelsOf","createCartDetail","EditorBuy","onAddToCart","defaultQuantity","seededRef","stateVersion","commerceVersion","quantity","complete","busy","setBusy","busyRef","handleClick","designState","variantId","payload","EditorControls","useRequiresCanvas","docked","EditorLoadingOverlay","useProductSelection","version","choice","setQuantity","Editor","EditorLayers","EditorHistory","EditorMenu","EditorAdd","RealtimeEmbed","RealtimeCanvas","rest","RealtimeMockup","useRealtimeMockups","productToRenderConfig","renderable","renderableLabels","combo","scoped","formatBuyPrice","cents","iconButtonStyle","menuItemStyle","MenuItem","onSelect","OverflowMenu","fullscreen","onToggleFullscreen","viewCount","viewIndex","onSelectView","onExport","open","setOpen","close","o","Fragment","IdleDock","flatLayers","selectLayer","generateAllPreviews","useLayers","BuyPill","price","DefaultChrome","title","height","setFullscreen","setViewIndex","swapped","setSwapped","canvasRef","selected","useSelectedElement","handleExport","exports","dataUrl","anchor","frameStyle","pipBoxStyle","f","SnowconeEditor","rootProps","ensureIconsRegistered"],"mappings":"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"}
1
+ {"version":3,"file":"embed-BY6gMPTK.js","sources":["../src/components/embed-realtime/context.ts","../src/design/bundle-config.ts","../src/components/embed-realtime/validateEmbed.ts","../src/components/editor/placementLinks.ts","../src/components/editor/editorAudit.ts","../src/components/editor/EditorRoot.tsx","../src/components/editor/EditorCanvas.tsx","../src/components/editor/usePlacements.ts","../src/components/editor/EditorPlacements.tsx","../src/components/editor/PreviewPrismOverlay.tsx","../src/components/editor/EditorPreview.tsx","../src/components/editor/EditorTextField.tsx","../src/components/editor/EditorBuy.tsx","../src/components/editor/EditorControls.tsx","../src/components/editor/EditorLoadingOverlay.tsx","../src/components/editor/useProductSelection.ts","../src/components/editor/index.ts","../src/components/embed-realtime/RealtimeEmbed.tsx","../src/components/embed-realtime/RealtimeCanvas.tsx","../src/components/embed-realtime/RealtimeMockup.tsx","../src/components/embed-realtime/useRealtimeMockups.ts","../src/design/product-config.ts","../src/default-editor/SnowconeEditor.tsx","../src/api/embed.ts"],"sourcesContent":["'use client';\n\n/**\n * Shared context for the realtime embed primitives. `<RealtimeEmbed>` owns the\n * single {@link RenderSession} and the live mockup state; `<RealtimeCanvas>` and\n * `<RealtimeMockup>` read it from here so the editor and the preview can be laid\n * out freely yet can never desync (they share one session, one design, one\n * placement).\n */\n\nimport { createContext, useContext } from 'react';\nimport type { RenderSession, RenderProduct, RenderState, MockupResult } from '@snowcone-app/sdk';\nimport type { AnyDesign } from '../../design/design-builder.js';\nimport type { PieceGuidesConfig } from '../embed/SnowconeCanvas.js';\nimport type { DesignStateStore } from '../editor/designStateStore.js';\n\nexport interface EmbedContextValue {\n /** The single session the editor pushes renders to. `null` if the session\n * failed to construct (a config fail-fast, surfaced via `error`). Escape\n * hatch for advanced use. */\n session: RenderSession | null;\n /** The design the embed was seeded with — single source of truth for both the\n * canvas seed and the seed render. */\n design: AnyDesign;\n /** The ACTIVE placement name (= the design's currently-edited artboard).\n * The canvas follows it as its controlled artboard. Initially the design's\n * active artboard; moved by {@link selectPlacement} (ADR-0088). For a\n * single-placement design this never changes — the pre-0088 behavior. */\n placement: string;\n /** Every artboard name in the LIVE design state, in author order — the\n * first is the base (ADR-0101). A single-placement design has exactly one\n * entry (ADR-0088). Linked placements are NOT in here; see\n * `requiredPlacements` and `usePlacements()`. */\n placements: string[];\n /** Switch the active placement. Throws `EditorError E_UNKNOWN_PLACEMENT`\n * for a label that is neither a required placement nor a design artboard\n * (ADR-0088). Selecting a LINKED placement edits the base — the artboard\n * it renders (ADR-0101). Costs zero session work — renders already target\n * every artboard per placement. */\n selectPlacement: (label: string) => void;\n /** The product's required image placement labels, in product order\n * (`requiredPlacementLabels(product)`). Empty for a variant-axis product\n * without `requiredPlacements` — then `placements` is the whole story.\n * ADR-0101. */\n requiredPlacements: string[];\n /** ADR-0101 split: give `label` its own artboard, cloned from the base, and\n * make it active. No-op when already split. Throws `E_UNKNOWN_PLACEMENT`\n * for a label that is not a required placement. */\n splitPlacement: (label: string) => void;\n /** ADR-0101 link: drop `label`'s own artboard so it inherits the base\n * again. No-op when already linked. Throws `E_LINK_BASE` for the base. */\n linkPlacement: (label: string) => void;\n /** The product being rendered against. */\n product: RenderProduct;\n /** Latest mockups from the session. Reactive — updates re-render consumers. */\n mockups: MockupResult[];\n /** True between a render dispatch and the next mockup / error. */\n isRendering: boolean;\n /** Last render error message, or null. */\n error: string | null;\n /** Default edit→render throttle (ms). */\n throttleMs: number;\n /**\n * The product's printable-area guides (dead zones, safe areas) — fetched by\n * `<RealtimeEmbed>` and already gated on the design's artboard matching the\n * print-file frame they were authored in. `null` when the product has none,\n * the fetch failed, or the dims don't line up. `<RealtimeCanvas>` forwards\n * this to the editor so embedders get the same overlay snowcone.app shows.\n */\n pieceGuides: PieceGuidesConfig | null;\n /** Dispatch a server render for the embed's placement. Sets `isRendering`. */\n pushRender: (state: RenderState, throttleMs?: number) => void;\n /**\n * The ONE live design state under this Root (ADR-0085 §3 / T2): seeded from\n * `design`, updated by every canvas change and every `Editor.TextField`\n * write, last-write-wins. Commerce parts read THIS, never the seed. Stable\n * identity; subscribe for updates (`useSyncExternalStore`-shaped).\n *\n * Stable since ADR-0085 P4; additive-only from here.\n */\n stateStore: DesignStateStore;\n}\n\nexport const EmbedContext = createContext<EmbedContextValue | undefined>(undefined);\n\n/**\n * Read the embed context. Throws a clear error when called outside\n * `<RealtimeEmbed>` — the most common wiring mistake.\n */\nexport function useEmbedContext(): EmbedContextValue {\n const ctx = useContext(EmbedContext);\n if (!ctx) {\n throw new Error(\n 'useRealtimeMockups / <RealtimeCanvas> / <RealtimeMockup> must be rendered ' +\n 'inside <RealtimeEmbed>. Wrap them: ' +\n '<RealtimeEmbed shop=… product=… design=… grantUrl=…>…</RealtimeEmbed>'\n );\n }\n return ctx;\n}\n","/**\n * `bundleToRenderConfig` — the bundle counterpart of `productToRenderConfig`\n * (ADR-0099 slice 4, client half). A BUNDLE is a catalog product whose\n * payload carries a `bundle` block: several products photographed in one\n * mockup, each a SLOT (`role`) with one or more alternative products.\n *\n * A bundle is a DISTINCT shape, not a flag on the single-product config,\n * because every single-product assumption is wrong on it:\n *\n * - placements are role-scoped keys (`top.front`, `shorts.front`) — two\n * members both have a \"Front\", so the bare label is never the identity.\n * Artboard names, `renderState(placement)` and the server's\n * `requiredPlacements` all use the KEY.\n * - there is no single `variantId`: the variant is named per ROLE\n * (`variants: { top: 'oPz7RC', shorts: 'GNpkMR' }`); a bare `variantId`\n * on a bundle is refused by the server (`E_BUNDLE_ROLE_REQUIRED`).\n * - `picks` choose which alternative fills each slot (default: the slot's\n * first product). A pick change is a NEW config message — the server\n * re-validates it and re-derives the required placement set.\n *\n * Every wrong input throws a typed `EditorError` with the valid values in\n * `data.validNames` and the fix in the message — the server would refuse the\n * same input with the same code, but a mount-time throw beats a socket error\n * after connect. The single-product adapter refuses a bundle\n * (`E_BUNDLE_CONFIG_REQUIRED`) and this one refuses a single product\n * (`E_NOT_A_BUNDLE`), so neither path can ever silently render the wrong thing.\n */\n\nimport type { CatalogProduct, RenderProduct } from '@snowcone-app/sdk';\nimport { EditorError } from '../errors/editorError.js';\n\n/** The `bundle` block of a catalog product (ADR-0099). */\nexport type CatalogBundleBlock = NonNullable<CatalogProduct['bundle']>;\n/** One slot of a bundle. */\nexport type CatalogBundleMember = CatalogBundleBlock['members'][number];\n/** One alternative product of a slot. */\nexport type CatalogBundleAlternative = CatalogBundleMember['products'][number];\n\n/** A catalog product that IS a bundle — `bundle.members` is present and non-empty. */\nexport type CatalogBundleProduct = CatalogProduct & { bundle: CatalogBundleBlock };\n\n/** True when the catalog product carries a non-empty `bundle` block. */\nexport function isBundleProduct(product: CatalogProduct): product is CatalogBundleProduct {\n return Array.isArray(product.bundle?.members) && product.bundle.members.length > 0;\n}\n\nexport interface BundleRenderConfigOptions {\n /** Which alternative fills each slot, `role → member product code`.\n * Omitted roles take the slot's first alternative. Unknown roles throw\n * `E_BUNDLE_ROLE_NOT_FOUND`; a product outside the slot throws\n * `E_BUNDLE_PICK_NOT_FOUND` (both list the valid values). */\n picks?: Record<string, string>;\n /** The variant per slot, `role → gvid`. Omitted roles take the picked\n * alternative's `defaultGvid` (else its first variant). A gvid outside the\n * alternative's variant list throws `E_BUNDLE_VARIANT_NOT_FOUND`. */\n variants?: Record<string, string>;\n /** Role-scoped placement KEY to edit first (e.g. `\"top.front\"`). Defaults\n * to the first renderable placement of the picked alternatives. A bare\n * label (`\"Front\"`) throws `E_BUNDLE_ROLE_REQUIRED`; an unknown key throws\n * `E_PRODUCT_NOT_RENDERABLE` — both list the valid keys. */\n placement?: string;\n /** Render width passthrough (`product.width`). */\n width?: number;\n}\n\n/** Geometry of one role-scoped placement of the picked alternatives. */\nexport interface BundlePlacementConfig {\n /** The role-scoped wire key — the artboard NAME and the `renderState`\n * placement on a bundle (`\"top.front\"`). */\n key: string;\n role: string;\n /** The member's own placement label (`\"Front\"`) — display only, never an\n * identity on a bundle. */\n label: string;\n /** The member product this placement belongs to (the slot's pick). */\n memberProductId: string;\n width: number;\n height: number;\n aspectRatio: number;\n}\n\n/** One selectable variant of a slot's picked alternative. */\nexport interface BundleVariantChoice {\n gvid: string;\n /** Human label from the alternative's `options.combinations` row (e.g.\n * `\"Size M\"`); falls back to the gvid when the row is unknown. */\n label: string;\n}\n\n/** One slot of the bundle, resolved for the current picks + variants. */\nexport interface BundleRoleConfig {\n role: string;\n required: boolean;\n /** The alternatives' product codes, in catalog order (first = default). */\n alternatives: string[];\n /** The alternative currently filling the slot. */\n pick: string;\n /** The variant the slot renders (`variants[role]`). */\n variantId: string;\n /** Every variant the picked alternative accepts for `variants[role]`. */\n variantChoices: BundleVariantChoice[];\n /** The slot's renderable placements for the pick, in catalog order. */\n placements: BundlePlacementConfig[];\n}\n\nexport interface BundleRenderConfig {\n /** Discriminant — a bundle config is never confusable with a\n * `ProductRenderConfig`. */\n kind: 'bundle';\n /** Ready for `<Editor.Root product={…}>`: `picks` + `variants` set,\n * `variantId` absent, `placements` / `requiredPlacements` carry the\n * role-scoped KEYS (the placement names the server demands). */\n product: RenderProduct;\n /** The resolved pick per role — every role present. */\n picks: Record<string, string>;\n /** The resolved variant per role — every role present. */\n variants: Record<string, string>;\n /** `role:renderGvid,…` sorted by role — the bundle scene identity the\n * catalog publishes as a bundle mockup's `gvids` entry and the server keys\n * the composite on. */\n variantToken: string;\n /** Every slot, resolved. */\n roles: BundleRoleConfig[];\n /** The placement being edited first — seed `design({ name: key, width, height })`. */\n placement: BundlePlacementConfig;\n /** Every renderable placement of the picked alternatives, in catalog order. */\n placements: BundlePlacementConfig[];\n /** `placements.map(p => p.key)` — the artboard names / renderState placements. */\n placementKeys: string[];\n /** The bundle's roles in catalog order. */\n roleNames: string[];\n /** First scene that photographs the picked alternatives — the default\n * `<Editor.Preview mockupId>`. */\n primaryMockupId: string;\n}\n\nconst DOC = 'bundles';\n\n/** `role:renderGvid,…` sorted by role — deterministic, matches the box and the catalog. */\nexport function bundleVariantToken(variantByRole: Record<string, string>): string {\n return Object.keys(variantByRole)\n .sort()\n .map((role) => `${role}:${variantByRole[role]}`)\n .join(',');\n}\n\n/** Split a role-scoped key (`\"top.front\"`) into `{ role, key }`; `null` when it carries no role. */\nexport function splitRoleKey(name: string): { role: string; key: string } | null {\n const dot = name.indexOf('.');\n if (dot <= 0 || dot === name.length - 1) return null;\n return { role: name.slice(0, dot), key: name.slice(dot + 1) };\n}\n\ntype CatalogPlacement = NonNullable<CatalogProduct['placements']>[number];\n\nfunction isRenderablePlacement(p: CatalogPlacement): p is CatalogPlacement & { width: number; height: number } {\n return p.type !== 'color' && typeof p.width === 'number' && p.width > 0 && typeof p.height === 'number' && p.height > 0;\n}\n\nfunction variantLabel(alt: CatalogBundleAlternative, gvid: string): string {\n const row = alt.options?.combinations?.find((c) => c.variantId === gvid);\n if (!row) return gvid;\n const parts = Object.entries(row)\n .filter(([k, v]) => k !== 'variantId' && k !== 'price' && (typeof v === 'string' || typeof v === 'number'))\n .map(([k, v]) => `${k} ${String(v)}`);\n return parts.length > 0 ? parts.join(' · ') : gvid;\n}\n\n/**\n * Derive the full bundle embed wiring from one `getProduct()` payload.\n *\n * ```ts\n * const config = bundleToRenderConfig(await getProduct('V9NNNH'), { width: 2000 });\n * const seed = design({ name: config.placement.key, ...config.placement })\n * .image(artworkUrl, { anchor: 'center' }); // ONE artboard → broadcast to every member\n *\n * <Editor.Root shop={SHOP} product={config.product} design={seed} grantUrl=\"/api/realtime-grant\">\n *\n * // A pick or variant change is a NEW config: rebuild and pass the new product.\n * const next = bundleToRenderConfig(product, { picks: { top: 'TANKXA' }, variants: config.variants });\n * ```\n *\n * @throws EditorError `E_NOT_A_BUNDLE` — the product has no `bundle` block.\n * @throws EditorError `E_BUNDLE_ROLE_NOT_FOUND` — `picks` / `variants` name an unknown role.\n * @throws EditorError `E_BUNDLE_PICK_NOT_FOUND` — a pick is not one of the slot's alternatives.\n * @throws EditorError `E_BUNDLE_VARIANT_NOT_FOUND` — a variant is not one of the pick's gvids, or the pick has none.\n * @throws EditorError `E_BUNDLE_ROLE_REQUIRED` — `options.placement` is a bare label, not `<role>.<key>`.\n * @throws EditorError `E_PRODUCT_NOT_RENDERABLE` — no renderable placement / scene, or an unknown placement key.\n */\nexport function bundleToRenderConfig(\n catalogProduct: CatalogProduct,\n options: BundleRenderConfigOptions = {},\n): BundleRenderConfig {\n if (!isBundleProduct(catalogProduct)) {\n throw new EditorError(\n 'E_NOT_A_BUNDLE',\n `product ${catalogProduct.id} has no bundle block — picks / variants are bundle parameters ` +\n 'the server refuses on a single product (E_NOT_A_BUNDLE). Use productToRenderConfig() for it.',\n { productId: catalogProduct.id, docSlug: DOC },\n );\n }\n const members = catalogProduct.bundle.members;\n const roleNames = members.map((m) => m.role);\n\n for (const [field, map] of [\n ['picks', options.picks],\n ['variants', options.variants],\n ] as const) {\n for (const role of Object.keys(map ?? {})) {\n if (!roleNames.includes(role)) {\n throw new EditorError(\n 'E_BUNDLE_ROLE_NOT_FOUND',\n `bundle ${catalogProduct.id} has no role \"${role}\" (in ${field}). Roles: [${roleNames.join(', ')}].`,\n { productId: catalogProduct.id, field, role, validNames: roleNames, docSlug: DOC },\n );\n }\n }\n }\n\n const picks: Record<string, string> = {};\n const variants: Record<string, string> = {};\n const renderByRole: Record<string, string> = {};\n const catalogPlacements = catalogProduct.placements ?? [];\n const roles: BundleRoleConfig[] = [];\n\n for (const member of members) {\n const alternatives = member.products.map((p) => p.productId);\n const wanted = options.picks?.[member.role];\n const alt = wanted === undefined ? member.products[0] : member.products.find((p) => p.productId === wanted);\n if (!alt) {\n throw new EditorError(\n 'E_BUNDLE_PICK_NOT_FOUND',\n `bundle ${catalogProduct.id} role \"${member.role}\" has no alternative \"${wanted}\". ` +\n `Alternatives: [${alternatives.join(', ')}] — pass picks: { ${member.role}: \"${alternatives[0]}\" }.`,\n { productId: catalogProduct.id, role: member.role, requested: wanted, validNames: alternatives, docSlug: DOC },\n );\n }\n picks[member.role] = alt.productId;\n\n // The variant set the SERVER accepts for this slot: the alternative's\n // published `variants[].gvid`; with none published only the default gvid\n // exists. (The alternative's `options.combinations` may list more SKUs —\n // those are cart identities, not session variants, see the ADR ledger.)\n const gvids = (alt.variants ?? []).map((v) => v.gvid).filter((g): g is string => typeof g === 'string' && g !== '');\n const accepted = gvids.length > 0 ? gvids : alt.defaultGvid ? [alt.defaultGvid] : [];\n const chosen = options.variants?.[member.role] ?? alt.defaultGvid ?? gvids[0];\n if (!chosen || !accepted.includes(chosen)) {\n const requested = options.variants?.[member.role];\n throw new EditorError(\n 'E_BUNDLE_VARIANT_NOT_FOUND',\n accepted.length === 0\n ? `bundle ${catalogProduct.id} role \"${member.role}\": alternative ${alt.productId} publishes no variant — ` +\n 'nothing can render this slot (catalog data is incomplete).'\n : `bundle ${catalogProduct.id} role \"${member.role}\" (${alt.productId}) has no variant \"${requested}\". ` +\n `Variants: [${accepted.join(', ')}] — pass variants: { ${member.role}: \"${accepted[0]}\" }.`,\n {\n productId: catalogProduct.id,\n role: member.role,\n memberProductId: alt.productId,\n requested,\n validNames: accepted,\n docSlug: DOC,\n },\n );\n }\n variants[member.role] = chosen;\n renderByRole[member.role] = alt.variants?.find((v) => v.gvid === chosen)?.gvidForMockup || chosen;\n\n const placements: BundlePlacementConfig[] = catalogPlacements\n .filter(\n (p): p is CatalogPlacement & { key: string; width: number; height: number } =>\n p.role === member.role &&\n p.memberProductId === alt.productId &&\n typeof p.key === 'string' &&\n p.key !== '' &&\n isRenderablePlacement(p),\n )\n .map((p) => ({\n key: p.key,\n role: member.role,\n label: p.label,\n memberProductId: alt.productId,\n width: p.width,\n height: p.height,\n aspectRatio: p.width / p.height,\n }));\n\n roles.push({\n role: member.role,\n required: member.required !== false,\n alternatives,\n pick: alt.productId,\n variantId: chosen,\n variantChoices: accepted.map((gvid) => ({ gvid, label: variantLabel(alt, gvid) })),\n placements,\n });\n }\n\n // Renderable placements of the PICKED alternatives, in catalog order (the\n // order the server's requiredPlacements uses).\n const pickedKeys = new Set(roles.flatMap((r) => r.placements.map((p) => p.key)));\n const byKey = new Map(roles.flatMap((r) => r.placements.map((p) => [p.key, p] as const)));\n const placements: BundlePlacementConfig[] = [];\n for (const p of catalogPlacements) {\n if (typeof p.key !== 'string' || !pickedKeys.has(p.key)) continue;\n const cfg = byKey.get(p.key);\n if (cfg && !placements.includes(cfg)) placements.push(cfg);\n }\n const placementKeys = placements.map((p) => p.key);\n\n let placement: BundlePlacementConfig | undefined;\n if (options.placement !== undefined) {\n if (!splitRoleKey(options.placement)) {\n throw new EditorError(\n 'E_BUNDLE_ROLE_REQUIRED',\n `placement \"${options.placement}\" names no role — on bundle ${catalogProduct.id} a placement is ` +\n `addressed by its role-scoped key. Keys: [${placementKeys.join(', ')}].`,\n { productId: catalogProduct.id, requested: options.placement, validNames: placementKeys, docSlug: DOC },\n );\n }\n placement = placements.find((p) => p.key === options.placement);\n if (!placement) {\n throw new EditorError(\n 'E_PRODUCT_NOT_RENDERABLE',\n `bundle ${catalogProduct.id} has no renderable placement \"${options.placement}\" for picks ` +\n `${JSON.stringify(picks)}. Keys: [${placementKeys.join(', ')}].`,\n { productId: catalogProduct.id, requested: options.placement, picks, validNames: placementKeys, docSlug: DOC },\n );\n }\n } else {\n placement = placements[0];\n }\n if (!placement) {\n throw new EditorError(\n 'E_PRODUCT_NOT_RENDERABLE',\n `bundle ${catalogProduct.id} has no renderable image placement for picks ${JSON.stringify(picks)} ` +\n '(a role-scoped, non-color placement with width/height). The catalog payload may be incomplete — ' +\n 'fetch it via getProduct(), not a search hit.',\n { productId: catalogProduct.id, picks, docSlug: DOC },\n );\n }\n\n // Scenes photograph a PICK SET: keep the mockups whose `picks` agree with\n // ours on every role they name (a scene with no picks metadata is kept).\n // None match → all scenes (stale metadata beats an empty embed — the same\n // fallback the single-product adapter makes for gvid-split scenes).\n const mockups = catalogProduct.mockups ?? [];\n const matching = mockups.filter(\n (m) => !m.picks || Object.entries(m.picks).every(([role, productId]) => picks[role] === productId),\n );\n const mockupIds = (matching.length > 0 ? matching : mockups).map((m) => m.id);\n if (mockupIds.length === 0) {\n throw new EditorError(\n 'E_PRODUCT_NOT_RENDERABLE',\n `bundle ${catalogProduct.id} has no mockup scenes — nothing to render a preview into.`,\n { productId: catalogProduct.id, docSlug: DOC },\n );\n }\n\n // Advisory contracts on the RenderProduct use the role-scoped KEY as the\n // placement name — that is what the server's requiredPlacements are on a\n // bundle, and what every renderState / artboard must be called.\n const requiredPlacements = (catalogProduct.requiredPlacements ?? [])\n .filter((p) => typeof p.key === 'string' && p.key !== '' && pickedKeys.has(p.key))\n .map((p) => ({ label: p.key as string, key: p.key as string, type: p.type, autoFilledByVariant: p.autoFilledByVariant }));\n\n const product: RenderProduct = {\n productId: catalogProduct.id,\n mockupIds,\n picks,\n variants,\n placements: placementKeys,\n mockups,\n ...(requiredPlacements.length > 0 ? { requiredPlacements } : {}),\n ...(typeof options.width === 'number' ? { width: options.width } : {}),\n };\n\n return {\n kind: 'bundle',\n product,\n picks,\n variants,\n variantToken: bundleVariantToken(renderByRole),\n roles,\n placement,\n placements,\n placementKeys,\n roleNames,\n primaryMockupId: mockupIds[0],\n };\n}\n","'use client';\n\n/**\n * Mount-time assertions for the realtime embed. Catches the silent-break wiring\n * mistakes that otherwise produce a blank canvas or a mockup that never renders:\n *\n * - no grant source (the session can't authorize → silent hang)\n * - a variant product with no `variantId` (→ ~30s render hang), AND the\n * can't-even-tell case: neither `variantId` nor `options` passed\n * - empty `mockupIds` (nothing to render)\n * - a design artboard that isn't one of the product's placements (renderState\n * targets a placement the product doesn't have → silent blank mockup)\n * - a multi-placement product whose required placements the design doesn't\n * COVER (the server waits on the missing canvas_states and the render times\n * out ~15s in — add the missing `.artboard()`s, ADR-0088, or eject)\n * - duplicate layer names (binding hooks resolve to the wrong element)\n *\n * Two consumption modes (ADR-0085 / F3):\n * - `validateEmbed` — the legacy advisory API: logs `console.warn` /\n * `console.error` and never throws, so a partly-wired `<RealtimeEmbed>`\n * still mounts and renders what it can. Dev-only at the call site.\n * - `collectEmbedIssues` — the structured list; `Editor.Root` THROWS on the\n * error-severity issues (console.error is invisible to headless agents).\n */\n\nimport { assertVariantSelected, type RenderProduct } from '@snowcone-app/sdk';\nimport type { AnyDesign } from '../../design/design-builder.js';\nimport { splitRoleKey } from '../../design/bundle-config.js';\n\nexport interface ValidateEmbedInput {\n shop: string;\n product: RenderProduct;\n design: AnyDesign;\n hasGrant: boolean;\n}\n\n/** One wiring problem found at mount, or a runtime stall. `error`-severity\n * issues break the embed (no render will ever arrive / it targets the wrong\n * thing); `warn`-severity issues are advisory. Every issue also reaches the\n * host through `Editor.Root`'s `onIssue` — the machine-readable channel\n * (console.warn is as invisible to a headless agent as console.error). */\nexport interface EmbedIssue {\n severity: 'error' | 'warn';\n /** Stable issue key, carried into `EditorError.data.issue` in throw mode. */\n issue:\n /** No `shop` (the publishable shop id) was passed. */\n | 'missing-shop'\n /** No grant source (`grantUrl`/`grant`) — the session can never\n * authorize, so no mockup ever renders. */\n | 'missing-grant'\n /** `product.mockupIds` is empty — nothing to render. */\n | 'empty-mockup-ids'\n /** The product has a variant axis but no `variantId` — the render\n * would hang ~30s waiting on a color blob that never comes. */\n | 'variant-required'\n /** ADR-0101 advisory: the design authors 2+ artboards but leaves some\n * required placements without one — those placements INHERIT the base\n * (the first artboard), re-fit per placement. Not an error: base +\n * overrides is the model. Assert on this to catch a half-finished\n * per-placement seed. */\n | 'placements-inherit-base'\n /** The design's placement isn't one of the product's placements —\n * the server renders a blank mockup. */\n | 'placement-mismatch'\n /** Two layers share a name — name-bound hooks bind the FIRST match,\n * so a control may edit the wrong layer. */\n | 'duplicate-layer-names'\n /** BUNDLE session (ADR-0099): a design artboard is a bare label\n * (`\"Front\"`) instead of a role-scoped key (`\"top.front\"`), or a bare\n * `variantId` is set — the server refuses both\n * (`E_BUNDLE_ROLE_REQUIRED`): two members can both have a \"Front\". */\n | 'bundle-role-required'\n /** BUNDLE session (ADR-0099): a role has no entry in\n * `product.variants` — the server keys the render on the per-role\n * variant set, so every role needs one (`bundleToRenderConfig` fills\n * defaults; hand-written configs must too). */\n | 'bundle-variant-required'\n /** Runtime (not mount-time): a render has been in flight past\n * `SLOW_RENDER_HINT_MS` with no mockup and no error — the silent-hang\n * class. The render may still arrive; this is a heads-up. */\n | 'slow-render';\n message: string;\n}\n\nconst TAG = '[RealtimeEmbed]';\n\n/**\n * The placement labels this product demands a canvas_state for. Prefers the\n * catalog's `requiredPlacements` contract; variant-auto-filled (color)\n * placements don't count — `variantId` satisfies them (the missing-variantId\n * case has its own guard above). Falls back to the bare `placements` label\n * list ONLY when the product has no variant in play: a label list can't say\n * which entries are auto-filled colors, but without a variant none are.\n */\nexport function requiredPlacementLabels(product: RenderProduct): string[] {\n if (product?.requiredPlacements?.length) {\n return product.requiredPlacements.filter((p) => !p.autoFilledByVariant).map((p) => p.label);\n }\n const variantIds = new Set(\n (product?.options?.combinations ?? [])\n .map((c) => c.variantId)\n .filter((id): id is string => typeof id === 'string' && id !== '')\n );\n const hasVariantAxis = Boolean(product?.variantId) || variantIds.size > 1;\n return hasVariantAxis ? [] : (product?.placements ?? []);\n}\n\n/** True when the product is wired as a BUNDLE session (ADR-0099): it\n * carries per-role `picks` and/or `variants`. */\nexport function isBundleRenderProduct(product: RenderProduct): boolean {\n return Boolean(product?.picks) || Boolean(product?.variants);\n}\n\n/** The bundle's roles as far as the RenderProduct reveals them: the role\n * prefixes of its placement keys plus every role named in picks/variants. */\nfunction bundleRolesOf(product: RenderProduct): string[] {\n const roles = new Set<string>();\n for (const key of product.placements ?? []) {\n const split = splitRoleKey(key);\n if (split) roles.add(split.role);\n }\n for (const role of Object.keys(product.picks ?? {})) roles.add(role);\n for (const role of Object.keys(product.variants ?? {})) roles.add(role);\n return [...roles];\n}\n\n/** Find every wiring problem. Pure — no logging, no throwing. */\nexport function collectEmbedIssues({ shop, product, design, hasGrant }: ValidateEmbedInput): EmbedIssue[] {\n const issues: EmbedIssue[] = [];\n\n if (!shop) {\n issues.push({\n severity: 'error',\n issue: 'missing-shop',\n message: '`shop` is required (your publishable shop id).',\n });\n }\n\n if (!hasGrant) {\n issues.push({\n severity: 'error',\n issue: 'missing-grant',\n message:\n 'no grant source — pass `grantUrl` (a proxy to mintRealtimeGrant) ' +\n 'or `grant`. Without it the session can never authorize and no mockup renders.',\n });\n }\n\n if (!product?.mockupIds?.length) {\n issues.push({\n severity: 'error',\n issue: 'empty-mockup-ids',\n message:\n 'product.mockupIds is empty — pass the catalog scene codes ' +\n '(product.mockups[].id) you want rendered, e.g. [\"FV1qjO\"].',\n });\n }\n\n // Variant axis: a product with a color/size option REQUIRES a variantId or the\n // render hangs ~30s waiting for a color blob that never comes. When `options`\n // (the catalog combinations) is passed we can detect the axis and fail fast\n // before the session's constructor throws. When `options` is NOT passed we\n // can't see the axis — so we DON'T warn here (a no-`options` product might\n // genuinely have no variants; warning would false-fire on every valid\n // single-variant embed). That stall is instead caught at runtime by\n // the embed's slow-render backstop (`slowRenderHint`), which fires only\n // when a render actually hangs — no false positives, and it covers every\n // silent-hang cause, not just this one.\n if (product?.options) {\n try {\n assertVariantSelected(product);\n } catch (err) {\n issues.push({\n severity: 'error',\n issue: 'variant-required',\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n const json = design.toJSON();\n const artboardNames = json.artboards.map((a) => a.name);\n\n // BUNDLE session (ADR-0099): placements are role-scoped keys and the\n // variant is per role. A bare label or a bare variantId is refused by the\n // server (E_BUNDLE_ROLE_REQUIRED) and a role with no variant has no render\n // identity — knowable at mount, so say so here with the valid keys.\n const bundle = isBundleRenderProduct(product);\n let roleless: string[] = [];\n if (bundle) {\n const keys = product.placements ?? [];\n roleless = artboardNames.filter((name) => !splitRoleKey(name));\n if (roleless.length > 0) {\n issues.push({\n severity: 'error',\n issue: 'bundle-role-required',\n message:\n `product ${product.productId} is a bundle, but the design's artboard(s) [${roleless.join(', ')}] ` +\n 'name no role. On a bundle every placement is addressed by its role-scoped key ' +\n `(<role>.<key>)${keys.length ? ` — keys: [${keys.join(', ')}]` : ''}. Seed the design from ` +\n 'bundleToRenderConfig(product).placement.key, not from a bare label.',\n });\n }\n if (product.variantId) {\n issues.push({\n severity: 'error',\n issue: 'bundle-role-required',\n message:\n `product ${product.productId} is a bundle, but product.variantId (\"${product.variantId}\") names no ` +\n 'slot — the server refuses it (E_BUNDLE_ROLE_REQUIRED). Name the variant per role instead: ' +\n 'product.variants = { <role>: <gvid> } (bundleToRenderConfig fills it), and leave variantId unset.',\n });\n }\n const roles = bundleRolesOf(product);\n const missingVariant = roles.filter((role) => !product.variants?.[role]);\n if (missingVariant.length > 0) {\n issues.push({\n severity: 'error',\n issue: 'bundle-variant-required',\n message:\n `product ${product.productId} is a bundle, but role(s) [${missingVariant.join(', ')}] have no entry in ` +\n `product.variants (${JSON.stringify(product.variants ?? {})}). Every role needs a variant — the ` +\n 'server keys the render on the per-role set. Build the product with bundleToRenderConfig(product, ' +\n '{ picks, variants }), which fills each slot\\'s default.',\n });\n }\n }\n\n // ADR-0101: every required image placement renders SOMETHING — its own\n // artboard when split, the base (first artboard) when linked. A single\n // artboard is the fully-linked default (ADR-0089 §5) and stays silent. Once\n // a SECOND artboard is authored, placements still inheriting the base get\n // an advisory so a half-finished per-placement seed is visible to hosts\n // and agents (`onIssue`), never a mount error — base + overrides is the\n // model, the same as `asset=` + `asset.<key>` on the URL surface.\n const required = requiredPlacementLabels(product);\n const inheriting = required.filter((label) => !artboardNames.includes(label));\n if (required.length > 1 && artboardNames.length > 1 && inheriting.length > 0) {\n issues.push({\n severity: 'warn',\n issue: 'placements-inherit-base',\n message:\n `product ${product.productId} requires placements ` +\n `[${required.join(', ')}]; the design authors [${artboardNames.join(', ')}], so ` +\n `[${inheriting.join(', ')}] inherit the base artboard \"${artboardNames[0]}\" ` +\n '(re-fit per placement, ADR-0101). Intended? Otherwise split them: ' +\n \"design(…).artboard('\" + inheriting[0] + \"', { width, height })… or \" +\n \"usePlacements().split('\" + inheriting[0] + \"') at runtime.\",\n });\n }\n\n const foreign = product?.placements?.length\n ? artboardNames.filter((name) => !product.placements!.includes(name) && !roleless.includes(name))\n : [];\n if (foreign.length > 0) {\n issues.push({\n severity: 'error',\n issue: 'placement-mismatch',\n message:\n `the design's artboard(s) [${foreign.join(', ')}] are not in ` +\n `product.placements [${product.placements!.join(', ')}]. Every artboard ` +\n 'name must equal a real product placement label (renderState targets ' +\n 'placements by that name), or the server renders a blank mockup. Fix the ' +\n '`name` passed to design({ name }) / design().artboard(name, …).',\n });\n }\n\n const names = json.elements.map((el) => (el as { name?: string }).name).filter((n): n is string => Boolean(n));\n const dupes = names.filter((n, i) => names.indexOf(n) !== i);\n if (dupes.length) {\n issues.push({\n severity: 'warn',\n issue: 'duplicate-layer-names',\n message:\n `duplicate layer name(s) [${[...new Set(dupes)].join(', ')}] — ` +\n 'useTextBinding(name) / useImageBinding(name) bind to the FIRST match, ' +\n 'so a duplicate name makes a control edit the wrong layer. Keep names unique.',\n });\n }\n\n return issues;\n}\n\n/** Legacy advisory API: log everything, never throw. (`placement-mismatch`\n * keeps its historical `console.warn` level here; in `Editor.Root`'s throw\n * mode it is error-severity per F3.) */\nexport function validateEmbed(input: ValidateEmbedInput): void {\n for (const issue of collectEmbedIssues(input)) {\n const log =\n issue.severity === 'error' && issue.issue !== 'placement-mismatch' ? console.error : console.warn;\n log(`${TAG} ${issue.message}`);\n }\n}\n","/**\n * Linked placements (ADR-0101): the ONE place that decides which artboard\n * fills each of a product's required image placements.\n *\n * - The design's FIRST artboard is the base.\n * - A required placement with an artboard of its own name is SPLIT — that\n * artboard renders there and nowhere else.\n * - A required placement with no artboard of its own is LINKED — it\n * inherits the base, re-fit to its own print geometry by the server.\n *\n * A fresh single-artboard design is therefore linked on every area (the\n * ADR-0089 §5 broadcast), and authoring / splitting a second artboard is an\n * additive override, never all-or-nothing. `Editor.Root`'s render push,\n * `Editor.Buy`'s payload, and `validateEmbed` all read this file; nothing\n * else re-derives the rule.\n */\n\n/** The minimum a request needs for expansion — both `ServerRenderRequest`\n * and the SDK's looser `RenderState` satisfy it. */\nexport interface ExpandableRequest {\n artboards?: Array<{ name?: string } & Record<string, unknown>>;\n}\n\nexport interface PlacementLinkInfo {\n /** The product placement label (= the artboard name when split). */\n label: string;\n /** True when this placement has no artboard of its own and renders the\n * base. Always false for the base's own label. */\n inherited: boolean;\n}\n\n/**\n * Per-placement link state for a design against the product's required\n * placements, in product order. Authored artboards that are NOT required\n * placements (bundle roleless slots, legacy extras) are appended after, never\n * inherited. With no required placements (a variant-axis product without\n * `requiredPlacements`) the design's own artboards are the list, none\n * inherited — the pre-0101 behavior.\n */\nexport function resolvePlacementLinks(\n artboardNames: readonly string[],\n requiredLabels: readonly string[],\n): PlacementLinkInfo[] {\n const authored = new Set(artboardNames);\n if (requiredLabels.length === 0) {\n return artboardNames.map((label) => ({ label, inherited: false }));\n }\n const out: PlacementLinkInfo[] = requiredLabels.map((label) => ({\n label,\n inherited: !authored.has(label),\n }));\n for (const name of artboardNames) {\n if (!requiredLabels.includes(name)) out.push({ label: name, inherited: false });\n }\n return out;\n}\n\n/** The base artboard name (the first authored artboard), or undefined for an\n * artboard-less state. */\nexport function baseArtboardName(artboardNames: readonly string[]): string | undefined {\n return artboardNames[0];\n}\n\n/**\n * Expand a serialized render request so EVERY required placement carries an\n * artboard: split placements keep their own, linked placements get the base\n * relabelled (the server re-fits it per placement). Order = required\n * placements first (product order), then any extra authored artboards.\n *\n * Returns the SAME object when nothing inherits (no required placements, or\n * every one is split) so callers can rely on identity for \"unchanged\".\n */\nexport function expandRequestForPlacements<T extends ExpandableRequest>(\n request: T,\n requiredLabels: readonly string[],\n): T {\n const artboards = request.artboards ?? [];\n const base = artboards[0];\n if (!base || requiredLabels.length === 0) return request;\n const names = artboards.map((ab) => (typeof ab.name === 'string' ? ab.name : ''));\n const byName = new Map(artboards.map((ab, i) => [names[i]!, ab] as const));\n const links = resolvePlacementLinks(names, requiredLabels);\n if (links.every((l) => !l.inherited)) return request;\n const expanded = links.map((l) =>\n l.inherited ? { ...base, name: l.label } : byName.get(l.label)!,\n );\n return { ...request, artboards: expanded };\n}\n","/**\n * `Editor.audit()` — the machine-checkable \"is my composition complete?\"\n * oracle for the `Editor.*` primitives (agentic-DX finding #10).\n *\n * `validateEmbed` covers WIRING (shop/grant/product/placement); the audit\n * covers COMPOSITION: parts that are mounted but inert, ambiguous fan-out,\n * personalization with no commerce gate, dead bindings, empty designs. Two\n * consumption modes, both dev AND prod:\n *\n * - `<Editor.Root onAudit={(report) => …}>` — fires ONCE after mount\n * settles (every part's layout-effect registration is in, the design\n * store holds its first snapshot). Like `onIssue`, this is the\n * machine-readable channel: console output is invisible to a headless\n * agent; assert on the callback.\n * - `auditEditor()` — the imperative dev helper: computes a FRESH report\n * from the most-recent mounted Root's registry + live design state, so an\n * agent can re-audit after interacting. Throws `E_AUDIT_NO_ROOT` when no\n * Root is mounted.\n *\n * Finding style follows the EditorError house rules (E2): verifiable facts\n * from data in hand only; `message` names the violated contract and the\n * offending parts, `fix` names the exact prop/part to change. Codes are the\n * stable contract (`A_*` — advisory, distinct from the throwing `E_*` space);\n * messages may be reworded.\n */\n\nimport type { RenderProduct } from '@snowcone-app/sdk';\nimport { EditorError } from '../../errors/editorError.js';\nimport type { DesignStateStore } from './designStateStore.js';\nimport type { EditorPartsRegistry } from './RootInternals.js';\n\n/** Stable audit finding codes — the test/agent contract. */\nexport type EditorAuditFindingCode =\n /** Requires-canvas parts (Controls/History/Menu/Add) are mounted with no\n * `Editor.Canvas` — the same composition `E_REQUIRES_CANVAS` throws on. */\n | 'A_REQUIRES_CANVAS'\n /** A docked `Editor.Controls` is mounted while `Editor.Canvas` still has\n * `floatingToolbar` true (the default) — contextual-zone ownership is\n * implied by mount order (spooky), not declared in the type surface. */\n | 'A_CONTROLS_INERT'\n /** `Editor.Preview` without `mockupId` while the product renders more than\n * one mockup scene — which scene the preview shows is ambiguous. */\n | 'A_PREVIEW_AMBIGUOUS'\n /** `Editor.TextField` parts are mounted but no `Editor.Buy` — there is no\n * commerce gate enforcing completeness before checkout. */\n | 'A_NO_BUY'\n /** A mounted `Editor.TextField`'s layer matches zero elements in the\n * CURRENT design snapshot — the binding is dead; writes will fail. */\n | 'A_LAYER_UNMATCHED'\n /** Every required (non-`optional`) `Editor.TextField` still equals its\n * seed value — Buy's completeness rule C3 gates checkout until edited. */\n | 'A_TEXT_AT_SEED'\n /** Zero renderable elements in the design — every mockup renders blank. */\n | 'A_EMPTY_DESIGN';\n\nexport interface EditorAuditFinding {\n code: EditorAuditFindingCode;\n severity: 'error' | 'warn' | 'info';\n /** What is wrong, with the facts (part names, layer names, scene ids). */\n message: string;\n /** The exact prop/part change that resolves the finding. */\n fix: string;\n}\n\nexport interface EditorAuditReport {\n findings: EditorAuditFinding[];\n /** Census of mounted parts, e.g. `{ name: 'Editor.Preview', count: 2 }`.\n * Sorted by name for determinism. */\n parts: Array<{ name: string; count: number }>;\n}\n\n/** @internal */\nexport interface EditorAuditInput {\n registry: EditorPartsRegistry;\n store: DesignStateStore;\n product: RenderProduct;\n}\n\n/** Compute the audit report from a Root's live registry + design state.\n * Pure — no logging, no throwing. @internal */\nexport function computeEditorAudit({ registry, store, product }: EditorAuditInput): EditorAuditReport {\n const findings: EditorAuditFinding[] = [];\n const parts = registry.getParts();\n const textFields = registry.getTextFields();\n\n // ── A_REQUIRES_CANVAS — parts that will throw/no-op without a canvas ──────\n const requiresCanvas = registry.requiresCanvasPartNames();\n if (requiresCanvas.length > 0 && !registry.hasCanvas()) {\n findings.push({\n code: 'A_REQUIRES_CANVAS',\n severity: 'error',\n message:\n `${requiresCanvas.join(', ')} ${requiresCanvas.length === 1 ? 'is' : 'are'} mounted with no ` +\n `<Editor.Canvas> under this Root — they operate on the editable artboard (selection, ` +\n `editor commands) and throw E_REQUIRES_CANVAS.`,\n fix:\n `Mount <Editor.Canvas/> under the same <Editor.Root>, or remove ${requiresCanvas.join(', ')}. ` +\n `Canvas-free parts: Editor.Preview, Editor.Buy, Editor.TextField, Editor.Layers.`,\n });\n }\n\n // ── A_CONTROLS_INERT — docked Controls while the canvas keeps the default\n // floating toolbar: suppression happens as a side effect of MOUNTING the\n // docked Controls (ADR-0085 §5), invisible in the type surface, and\n // unmounting the Controls silently re-enables the floating zone. ────────\n const canvasKeepsFloating = parts\n .filter((p) => p.name === 'Editor.Canvas')\n .some((p) => p.meta.floatingToolbar !== false);\n if (registry.hasDockedControls() && canvasKeepsFloating) {\n findings.push({\n code: 'A_CONTROLS_INERT',\n severity: 'warn',\n message:\n `a docked <Editor.Controls> is mounted while <Editor.Canvas> still has ` +\n `floatingToolbar={true} (the default) — both contextual zones are armed, and the ` +\n `floating toolbar is suppressed only as a side effect of the docked Controls being ` +\n `mounted this frame (it silently reappears when the Controls unmounts).`,\n fix:\n `Declare contextual-zone ownership in the type surface: pass floatingToolbar={false} on ` +\n `<Editor.Canvas> when a <Editor.Controls placement=\"docked\"> owns the zone.`,\n });\n }\n\n // ── A_PREVIEW_AMBIGUOUS — Preview with no mockupId on a multi-scene product\n const sceneIds = product?.mockupIds ?? [];\n if (sceneIds.length > 1) {\n const unpinned = parts.filter((p) => p.name === 'Editor.Preview' && p.meta.mockupId === undefined);\n if (unpinned.length > 0) {\n findings.push({\n code: 'A_PREVIEW_AMBIGUOUS',\n severity: 'warn',\n message:\n `${unpinned.length} <Editor.Preview> part${unpinned.length === 1 ? ' has' : 's have'} no ` +\n `mockupId while the product renders ${sceneIds.length} mockup scenes ` +\n `[${sceneIds.join(', ')}] — each shows whichever scene renders first, an ambiguous fan-out.`,\n fix:\n `Pin each <Editor.Preview> to a scene: mockupId=\"${sceneIds[0]}\" ` +\n `(one of product.mockupIds).`,\n });\n }\n }\n\n // ── A_NO_BUY — personalization with no commerce gate ──────────────────────\n const hasBuy = parts.some((p) => p.name === 'Editor.Buy');\n if (textFields.length > 0 && !hasBuy) {\n const names = textFields.map((tf) => tf.name);\n findings.push({\n code: 'A_NO_BUY',\n severity: 'info',\n message:\n `<Editor.TextField> parts are mounted (layers [${names.join(', ')}]) but no <Editor.Buy> — ` +\n `personalization has no commerce gate, so nothing enforces completeness (C2/C3) before ` +\n `the design is bought.`,\n fix:\n `Mount <Editor.Buy onAddToCart={…}/> under the same <Editor.Root> (it assembles the ` +\n `payload and gates on completeness), or ignore if this composition is deliberately ` +\n `non-commerce.`,\n });\n }\n\n // ── A_LAYER_UNMATCHED — a mounted TextField bound to a layer that matches\n // zero elements in the CURRENT snapshot (removed/renamed after mount —\n // mount-time validation already threw on never-existed names). ──────────\n const matched: typeof textFields = [];\n for (const tf of textFields) {\n if (store.layerKindOf(tf.name) === undefined) {\n findings.push({\n code: 'A_LAYER_UNMATCHED',\n severity: 'error',\n message:\n `<Editor.TextField layer={design.layer(\"${tf.name}\")}> matches zero elements in the ` +\n `current design state — the layer was removed or renamed after the field mounted, so ` +\n `the binding is dead and writes will fail. Bindable layers now: ` +\n `${JSON.stringify(store.bindableLayerNames())}.`,\n fix:\n `Restore a text layer named \"${tf.name}\" to the design, or bind the field to an ` +\n `existing layer: layer={design.layer(<one of ${JSON.stringify(store.bindableLayerNames())}>)}.`,\n });\n } else {\n matched.push(tf);\n }\n }\n\n // ── A_TEXT_AT_SEED — every required field still placeholder text ──────────\n const required = matched.filter((tf) => !tf.optional);\n if (\n required.length > 0 &&\n required.every((tf) => store.textOf(tf.name) === store.seedTextOf(tf.name))\n ) {\n const names = required.map((tf) => tf.name);\n findings.push({\n code: 'A_TEXT_AT_SEED',\n severity: 'info',\n message:\n `every required <Editor.TextField> still equals its seed value (layers ` +\n `[${names.join(', ')}]) — <Editor.Buy>'s completeness rule C3 gates checkout until the ` +\n `shopper's text differs from the seed (placeholder text must not be bought).`,\n fix:\n `Nothing to change for a fresh mount — this clears when the shopper edits the fields. ` +\n `For a field that should NOT gate Buy, pass optional on that <Editor.TextField>.`,\n });\n }\n\n // ── A_EMPTY_DESIGN — zero renderable elements ─────────────────────────────\n if (!store.hasRenderableElement()) {\n findings.push({\n code: 'A_EMPTY_DESIGN',\n severity: 'warn',\n message:\n `the design state has zero renderable elements (no non-empty text, no image with a URL, ` +\n `no shape) — every mockup renders blank.`,\n fix:\n `Seed content on the builder passed to <Editor.Root design={…}> — ` +\n `design({…}).text(…)/.background(…)/.shape(…) — or add elements through <Editor.Add>.`,\n });\n }\n\n // ── Part census ───────────────────────────────────────────────────────────\n const counts = new Map<string, number>();\n for (const p of parts) counts.set(p.name, (counts.get(p.name) ?? 0) + 1);\n const census = [...counts.entries()]\n .map(([name, count]) => ({ name, count }))\n .sort((a, b) => a.name.localeCompare(b.name));\n\n return { findings, parts: census };\n}\n\n// ── The imperative helper's Root registry ────────────────────────────────────\n\ninterface RootAuditEntry {\n compute: () => EditorAuditReport;\n}\n\nconst mountedRoots: RootAuditEntry[] = [];\n\n/** Register a mounted Root as an audit target (most-recent wins). @internal */\nexport function registerRootForAudit(entry: RootAuditEntry): () => void {\n mountedRoots.push(entry);\n return () => {\n const index = mountedRoots.indexOf(entry);\n if (index !== -1) mountedRoots.splice(index, 1);\n };\n}\n\n/**\n * Audit the most-recent mounted `<Editor.Root>`'s composition NOW — a fresh\n * report from the live part registry + design state, so it reflects whatever\n * has happened since mount (fields edited, parts mounted/unmounted).\n *\n * Throws `E_AUDIT_NO_ROOT` when no Root is mounted.\n */\nexport function auditEditor(): EditorAuditReport {\n const current = mountedRoots[mountedRoots.length - 1];\n if (!current) {\n throw new EditorError(\n 'E_AUDIT_NO_ROOT',\n 'auditEditor() found no mounted <Editor.Root>. Mount a Root first — or, to audit at ' +\n 'mount time, pass onAudit on the Root: <Editor.Root onAudit={(report) => …}>.',\n { docSlug: 'embed-mode' },\n );\n }\n return current.compute();\n}\n","'use client';\n\n/**\n * `<Editor.Root>` — the one provider boundary of the composable editor\n * primitives (ADR-0085). Owns the realtime {@link RenderSession}, the design,\n * the live mockups, the ONE design-state store, the part registry, and the\n * built-in error boundary. Parts (`Editor.Canvas/Preview/TextField/Buy/…`)\n * carry behavior + state subscription only; the HOST owns all layout.\n *\n * STATE MODEL (D9 — state always, renderer lazy):\n *\n * Editor.Root (one provider boundary · error boundary · applies .sc-root once)\n * │\n * ├── STATE — always mounted, renderer-free\n * │ └── EmbedContext design · product · render session · mockups ·\n * │ pushRender · stateStore (the ONE live design state)\n * │ (EditorProvider joins here in P1's inversion — until then the\n * │ editor document still mounts inside Editor.Canvas's chunk)\n * │\n * ├── <Editor.Canvas/> dynamic import ──→ [HEAVY RENDERER CHUNK]\n * ├── <Editor.Preview/> ←─ mockups (×N under one Root is VALID)\n * ├── <Editor.TextField/> ─→ stateStore (by layer token) ─→ pushRender\n * └── <Editor.Buy/> ←─ stateStore + required-TextField registry\n *\n * This file is the EXTRACTION of `<RealtimeEmbed>`'s internals (D5 — not a\n * copy): `RealtimeEmbed` is now `<EditorRoot>` plus the legacy advisory\n * validation mode, so the existing realtime tests exercise this Root.\n *\n * The legacy embed had no DOM of its own; Root must apply `.sc-root` once\n * (parts never self-apply, ADR-0085). `display: contents` squares the two —\n * the scope div generates no box, so host grid/flex layouts see the children\n * directly and the legacy wrapper stays layout-identical.\n */\n\nimport React, {\n Component,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n type ReactNode,\n} from 'react';\nimport {\n RenderSession,\n type RenderProduct,\n type RenderState,\n type MockupResult,\n type RealtimeGrant,\n} from '@snowcone-app/sdk';\nimport type { AnyDesign } from '../../design/design-builder.js';\nimport { CanvasServicesProvider, type CanvasServices } from '../../contexts/CanvasServicesContext.js';\nimport { EditorProvider } from '../../contexts/EditorContext.js';\nimport { BoundLayerGuardContext } from '../../contexts/BoundLayerGuardContext.js';\nimport { EmbedContext, type EmbedContextValue } from '../embed-realtime/context.js';\nimport { usePieceGuideBundle, pieceGuidesForArtboard } from '../embed-realtime/usePieceGuideBundle.js';\nimport {\n collectEmbedIssues,\n requiredPlacementLabels,\n validateEmbed,\n type EmbedIssue,\n} from '../embed-realtime/validateEmbed.js';\nimport { expandRequestForPlacements } from './placementLinks.js';\nimport { EditorError, isEditorError } from '../../errors/editorError.js';\nimport { recordContainedEditorError } from '../../testing/editorErrors.js';\nimport { serializeStateForServer } from '../../rendering/serialize-for-server.js';\nimport { DesignStateStore } from './designStateStore.js';\nimport { CommerceStateStore } from './commerceStore.js';\nimport { computeEditorAudit, registerRootForAudit, type EditorAuditReport } from './editorAudit.js';\nimport {\n EditorPartsRegistry,\n EditorRootInternalsContext,\n makeInvariantReporter,\n type EditorRootInternals,\n} from './RootInternals.js';\n\n/**\n * How the session authorizes. Provide exactly one — the discriminated union makes\n * \"I forgot the grant\" a compile error rather than a silent runtime hang.\n *\n * Member order is load-bearing: when NEITHER prop is supplied (the common\n * mistake) TS reports the missing property of the LAST union member, so the\n * `grantUrl` arm is kept last on purpose — the error then reads \"Property\n * 'grantUrl' is missing\", pointing at the recommended prop instead of `grant`.\n * Don't reorder these.\n */\nexport type GrantSource =\n | {\n /** Full control over fetching the grant: a token or a token factory. */\n grant: RealtimeGrant | (() => Promise<RealtimeGrant>);\n grantUrl?: never;\n }\n | {\n /** Your endpoint returning `{ token, expiresAt }` for `POST { shop }` —\n * a same-origin proxy to `mintRealtimeGrant`. Recommended. */\n grantUrl: string;\n grant?: never;\n };\n\nexport type EditorRootBaseProps = {\n /** Publishable shop id (= shop.id, like a Stripe pk_). Billing target. */\n shop: string;\n /** Product to render against (catalog ids). `mockupIds` are scene codes\n * (product.mockups[].id), NOT placement names. Pass `placements`, `options`\n * + `requiredPlacements` so wiring mistakes (including a multi-placement\n * product, which the embed can't render) fail loud at mount instead of\n * hanging. */\n product: RenderProduct;\n /** Single source of truth — seeds the canvas AND the first render. Build it\n * with `design({ name, width, height })…`. Its artboard `name` is the\n * placement every render targets. */\n design: AnyDesign;\n /** Edit→render throttle in ms (default 200). */\n throttleMs?: number;\n /** Called whenever new mockups arrive. */\n onMockups?: (results: MockupResult[]) => void;\n /** Called on a render/timeout error. */\n onRenderError?: (message: string) => void;\n /**\n * The machine-readable advisory channel (F3's other half): every non-fatal\n * issue — warn-severity wiring problems at mount, the runtime `slow-render`\n * stall — is delivered here, in dev AND prod. Console output is as\n * invisible to a headless agent as it is to production telemetry; assert on\n * this callback instead of scraping logs. (Error-severity wiring issues\n * don't arrive here — they throw `EditorError E_EMBED_CONFIG` into Root's\n * boundary.)\n */\n onIssue?: (issue: EmbedIssue) => void;\n /**\n * The composition-audit channel (`Editor.audit()`, agentic-DX #10): fires\n * ONCE after mount settles (every part's layout-effect registration is in,\n * the design store holds its first snapshot), dev AND prod — like\n * `onIssue`, a machine-readable callback, never console output. The report\n * lists structured findings (stable `A_*` codes, each with the fix) plus a\n * census of mounted parts. It fires even when a composition mistake throws\n * into Root's boundary, carrying the registry state the throw saw. For a\n * fresh report after interacting, call `auditEditor()`.\n */\n onAudit?: (report: EditorAuditReport) => void;\n /** Override the realtime WS endpoint (defaults to the SDK's prod URL). */\n wsUrl?: string;\n /**\n * Privileged-service wiring for the editor chrome (the Image Browser's\n * stock-image search and AI generation tabs). Same pattern as `grantUrl`:\n * host these URLs on your server; your vendor keys live there.\n */\n services?: CanvasServices;\n children?: ReactNode;\n /**\n * Wiring-validation mode. `Editor.Root` defaults to `'throw'` (F3:\n * console.error is invisible to headless agents — error-severity wiring\n * issues throw `EditorError E_EMBED_CONFIG` into Root's boundary). The\n * legacy `<RealtimeEmbed>` wrapper passes `'warn'` for back-compat\n * (dev-only console diagnostics, never throws).\n * @internal\n */\n __validation?: 'throw' | 'warn';\n};\n\nexport type EditorRootProps = GrantSource & EditorRootBaseProps;\n\n/**\n * How long a render may be in flight before the embed assumes something is wrong\n * and surfaces a diagnostic. A healthy render returns in ~2s; the session's own\n * watchdog is ~30s. 8s sits in between — long enough not to false-fire on a\n * genuinely slow render, short enough to spare a first-timer the full 30s of\n * silence.\n */\nexport const SLOW_RENDER_HINT_MS = 8000;\n\n/**\n * The dev-console message shown when a render hasn't produced a mockup in\n * {@link SLOW_RENDER_HINT_MS}. A general backstop for the whole silent-hang\n * class — not just the missing-`variantId` trap — so a stuck embed always says\n * *something* actionable instead of hanging quietly.\n */\nexport function slowRenderHint(placement: string): string {\n return (\n `[RealtimeEmbed] No mockup after ${Math.round(SLOW_RENDER_HINT_MS / 1000)}s. ` +\n `Common causes: a variant product missing \\`variantId\\` (pass \\`product.options\\` ` +\n `so the embed can flag it up front), a multi-placement product (the server waits ` +\n `for every required placement but <RealtimeEmbed> sends only \"${placement}\" — pass ` +\n `\\`product.requiredPlacements\\` so this is flagged at mount; such products need ` +\n `the eject path), an unreachable or non-public asset URL in the design, or the ` +\n `placement \"${placement}\" not existing on the product. ` +\n `The render may still arrive — this is a heads-up, not a failure.`\n );\n}\n\nfunction toGetToken(props: EditorRootProps): { grantUrl: string } | { getToken: () => Promise<RealtimeGrant> } {\n if ('grantUrl' in props && props.grantUrl) {\n return { grantUrl: props.grantUrl };\n }\n const grant = (props as { grant: RealtimeGrant | (() => Promise<RealtimeGrant>) }).grant;\n if (typeof grant === 'function') return { getToken: grant };\n return { getToken: () => Promise.resolve(grant) };\n}\n\n// ── The error card (D11): contained, loud, in the widget slot ───────────────\n\nfunction ErrorCard({ error, onRetry }: { error: Error; onRetry?: () => void }): React.ReactElement {\n const code = isEditorError(error) ? error.code : 'EDITOR_ERROR';\n return (\n <div\n data-sc-part=\"error\"\n role=\"alert\"\n style={{\n padding: '16px',\n borderRadius: '12px',\n border: '1px solid var(--sc-color-destructive, #b91c1c)',\n background: 'var(--sc-color-surface, #fef2f2)',\n color: 'var(--sc-color-foreground, #7f1d1d)',\n fontFamily: 'ui-sans-serif, system-ui, sans-serif',\n fontSize: '13px',\n lineHeight: 1.5,\n }}\n >\n <p style={{ margin: 0, fontWeight: 700 }}>Editor failed: {code}</p>\n <p style={{ margin: '4px 0 0' }}>{error.message}</p>\n {onRetry ? (\n <button\n type=\"button\"\n data-sc-part=\"error-retry\"\n onClick={onRetry}\n style={{\n marginTop: '10px',\n padding: '6px 14px',\n borderRadius: '9999px',\n border: '1px solid currentColor',\n background: 'transparent',\n color: 'inherit',\n font: 'inherit',\n fontWeight: 600,\n cursor: 'pointer',\n }}\n >\n Retry\n </button>\n ) : null}\n </div>\n );\n}\n\ninterface BoundaryProps {\n /** Imperatively-reported error (handler/async path) — same card. */\n reportedError: EditorError | null;\n onRetry: () => void;\n children: ReactNode;\n}\n\ninterface BoundaryState {\n caught: Error | null;\n}\n\n/**\n * The catching half of Root's boundary (D11): render/lifecycle/effect throws\n * from the parts show an error card in the widget slot while the host page\n * survives.\n *\n * Test containment-bypass (the D11 review concern — \"an agent's mounts-\n * without-crashing test passes green on a broken composition\"): under\n * NODE_ENV=test/dev every contained error is RECORDED, and\n * `expectNoEditorErrors()` from `@snowcone-app/canvas/testing` fails the\n * test. (A literal rethrow-from-the-boundary was tried and rejected: an\n * uncaught throw from a layout effect corrupts React 18's work loop and\n * poisons every later render in the test file — \"Should not already be\n * working\".)\n */\nclass CatchingBoundary extends Component<BoundaryProps, BoundaryState> {\n state: BoundaryState = { caught: null };\n\n static getDerivedStateFromError(error: Error): BoundaryState {\n return { caught: error };\n }\n\n componentDidCatch(error: Error): void {\n recordContainedEditorError(error);\n if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {\n console.error('[Editor.Root] contained a composition error:', error);\n }\n }\n\n render(): ReactNode {\n if (this.state.caught) {\n // Composition mistakes need a code change; a retry would just re-throw.\n return <ErrorCard error={this.state.caught} />;\n }\n return this.props.children;\n }\n}\n\n/**\n * Root's built-in boundary (D11): the imperatively-REPORTED channel\n * (handler/async failures like the lazy chunk failing to load) renders the\n * card directly, with retry when the failure is retryable; everything else\n * goes through the catching class boundary above.\n */\nfunction EditorBoundary({ reportedError, onRetry, children }: BoundaryProps): React.ReactElement {\n if (reportedError) {\n const retryable = isEditorError(reportedError) && reportedError.code === 'E_CHUNK_LOAD_FAILED';\n return <ErrorCard error={reportedError} onRetry={retryable ? onRetry : undefined} />;\n }\n return <CatchingBoundary reportedError={null} onRetry={onRetry}>{children}</CatchingBoundary>;\n}\n\n// ── The state-owning inner (everything here is INSIDE the boundary) ─────────\n\nfunction EditorRootInner(\n props: EditorRootProps & {\n internals: EditorRootInternals;\n /** Stash the latest audit report on the OUTER Root (which survives a\n * boundary catch) — see the audit memo below. */\n recordAudit: (report: EditorAuditReport) => void;\n },\n): React.ReactElement {\n const {\n shop,\n product,\n design,\n throttleMs = 200,\n onMockups,\n onRenderError,\n onIssue,\n wsUrl,\n services,\n children,\n internals,\n recordAudit,\n __validation = 'throw',\n } = props;\n\n // The design's INITIAL placement (its active artboard) — keys the session\n // and anchors validation. The placement being EDITED is `activePlacement`\n // below (ADR-0088); the two coincide for single-placement designs.\n const placement = useMemo(() => design.toJSON().activeArtboard, [design]);\n // ADR-0101: the artboard list is LIVE — split/link add and remove artboards\n // at runtime — so it derives from the one design-state store, not the seed.\n const liveState = useSyncExternalStore(internals.store.subscribe, internals.store.getState, internals.store.getState);\n const artboardNamesKey = liveState.artboards.map((a) => a.name).join('\\u0000');\n /** Every artboard name in the live design, in author order; the first is the base. */\n const placements = useMemo(\n () => (artboardNamesKey ? artboardNamesKey.split('\\u0000') : []),\n [artboardNamesKey],\n );\n /** The product's required image placements (product order). Keyed on the\n * label list, not `product` identity (embedders pass inline objects). */\n const requiredKey = JSON.stringify(requiredPlacementLabels(product));\n const requiredPlacements = useMemo<string[]>(() => JSON.parse(requiredKey) as string[], [requiredKey]);\n\n // Active placement (ADR-0088): Root-owned UI state, derived-on-mismatch so a\n // NEW design never renders a frame with the old design's placement. Switching\n // costs zero session work — the session is keyed on the design's identity,\n // and per-placement renders already target every artboard by name.\n const [placementChoice, setPlacementChoice] = useState<{ design: AnyDesign; label: string } | null>(null);\n const activePlacement =\n placementChoice && placementChoice.design === design ? placementChoice.label : placement;\n const selectPlacement = useMemo(\n () => (label: string) => {\n const valid = [...new Set([...requiredPlacements, ...placements])];\n if (!valid.includes(label)) {\n throw new EditorError(\n 'E_UNKNOWN_PLACEMENT',\n `no placement \"${label}\" — the product's placements are ` +\n `${JSON.stringify(requiredPlacements)} and the design's artboards are ` +\n `${JSON.stringify(placements)} (ADR-0088 / ADR-0101).`,\n { placement: label, validNames: valid, docSlug: 'embed-mode' },\n );\n }\n // A LINKED placement (no artboard of its own) renders the base, so\n // selecting it edits the base — never a silent split (ADR-0101 §3).\n const base = placements[0] ?? label;\n setPlacementChoice({ design, label: placements.includes(label) ? label : base });\n },\n [design, placements, requiredPlacements],\n );\n /** Latest pushRender for the canvas-free split/link path (defined below). */\n const pushRenderRef = useRef<((state: RenderState, throttle?: number) => void) | null>(null);\n // ADR-0101 split / link. With a mounted Editor.Canvas the editor document\n // is the write authority (the op goes through the CanvasBridge command\n // path and lands in the store via onChange); without one the store applies\n // the same immutable update itself and re-pushes the render.\n const splitPlacement = useMemo(\n () => (label: string) => {\n if (!requiredPlacements.includes(label) && !placements.includes(label)) {\n throw new EditorError(\n 'E_UNKNOWN_PLACEMENT',\n `cannot split \"${label}\" — the product's placements are ` +\n `${JSON.stringify(requiredPlacements)} (ADR-0101).`,\n { placement: label, validNames: requiredPlacements, docSlug: 'embed-mode' },\n );\n }\n if (!placements.includes(label)) {\n const bridge = internals.registry.getCanvasBridge();\n if (bridge) bridge.splitArtboard(label);\n else {\n internals.store.splitArtboard(label);\n pushRenderRef.current?.(serializeStateForServer(internals.store.getState()));\n }\n }\n setPlacementChoice({ design, label });\n },\n [design, placements, requiredPlacements, internals],\n );\n const linkPlacement = useMemo(\n () => (label: string) => {\n const base = placements[0];\n if (label === base) {\n throw new EditorError(\n 'E_LINK_BASE',\n `\"${label}\" is the base artboard — every linked placement inherits it, so it ` +\n `cannot be re-linked. Link a split placement instead, or call linkAll(). ` +\n `Artboards: ${JSON.stringify(placements)}.`,\n { artboardName: label, validNames: placements.slice(1), docSlug: 'embed-mode' },\n );\n }\n if (!placements.includes(label)) return;\n const bridge = internals.registry.getCanvasBridge();\n if (bridge) bridge.removeArtboard(label);\n else {\n internals.store.removeArtboard(label);\n pushRenderRef.current?.(serializeStateForServer(internals.store.getState()));\n }\n if (activePlacement === label && base) setPlacementChoice({ design, label: base });\n },\n [design, placements, internals, activePlacement],\n );\n\n // Seed the editor document's artboard from the DESIGN, not EditorProvider's\n // \"Artboard 1\" 1000×1000 default. The document mounts with Root (D9) and a\n // render can fire before Editor.Canvas's chunk rebuilds it from the live\n // seed — with the default it briefly serializes an artboard named\n // \"Artboard 1\" against placement \"Front\" and the SDK warns \"no matching\n // artboard in the state\" twice at every mount. Seeding from the design\n // makes the pre-canvas document correct from the first frame (and is what\n // a no-canvas composition's document should look like anyway).\n const initialArtboardConfig = useMemo(() => {\n const artboard = design.toJSON().artboards[0];\n if (!artboard) return undefined;\n return {\n name: artboard.name,\n width: artboard.width,\n height: artboard.height,\n ...(artboard.backgroundColor ? { backgroundColor: artboard.backgroundColor } : {}),\n };\n }, [design]);\n\n // Buy-owned variant selection (ADR-0085 §2, P2): subscribe to the commerce\n // store so a host's `select()` re-renders this component with the newly\n // resolved variant. The resolved variant NEVER re-keys the session — it is\n // applied to the LIVE session below (`setProduct` + a re-push of the\n // current design state), so a color click costs one config message + one\n // render, not a WS teardown/re-grant/reconnect.\n useSyncExternalStore(\n internals.commerce.subscribe,\n internals.commerce.getVersion,\n internals.commerce.getVersion,\n );\n // RENDER with the best match for the current (possibly partial) selection —\n // NOT the strict `resolvedVariantId()` Buy gates on. The strict one is\n // `undefined` until every required axis is picked, and rendering through it\n // meant a color-swatch click did nothing until the shopper had also picked\n // size/pocket/etc. — the photo must follow the pick immediately.\n const selectedVariantId = internals.commerce.renderVariantId();\n\n // #566: fetch the product's printable-area guides (camera cutouts, safe\n // areas) so the editor shows them automatically — without this, a buyer can\n // edit artwork that sits under hardware and the mockup never changes, with\n // no signal anywhere. variantId IS a gvid; fall back to the catalog's\n // default variant. Gated below on the design's artboard matching the\n // print-file frame the guides were authored in (same gate as snowcone.app).\n // The SELECTED variant wins — guides follow the variant being rendered.\n const guideBundle = usePieceGuideBundle(selectedVariantId ?? product.variantId ?? product.defaultGvid);\n const pieceGuides = useMemo(() => {\n if (!guideBundle) return null;\n // The artboard being EDITED (ADR-0088 switching; ADR-0101 split\n // placements) — its name lets a separate-mode product draw only that\n // placement's piece. Falls back to the base for a linked label.\n const artboards = design.toJSON().artboards;\n const artboard = artboards.find((a) => a.name === activePlacement) ?? artboards[0];\n return pieceGuidesForArtboard(guideBundle, artboard) ?? null;\n }, [guideBundle, design, activePlacement]);\n\n // Keep the latest callbacks reachable without re-creating the session.\n const onMockupsRef = useRef(onMockups);\n const onRenderErrorRef = useRef(onRenderError);\n const onIssueRef = useRef(onIssue);\n onMockupsRef.current = onMockups;\n onRenderErrorRef.current = onRenderError;\n onIssueRef.current = onIssue;\n\n const [mockups, setMockups] = useState<MockupResult[]>([]);\n const [isRendering, setIsRendering] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const hasGrant = Boolean(('grantUrl' in props && props.grantUrl) || ('grant' in props && props.grant));\n\n // One session per (shop, product, placement, auth). Key it on the product's\n // identity-BEARING fields, not the object reference — so an embedder passing\n // an inline `product={{…}}` (the natural way to write it) doesn't rebuild the\n // session and reconnect on every render. A real change (different product,\n // mockups, or variant) still re-keys it. `options`/`placements` are advisory\n // (fail-fast validation) so they don't need to force a rebuild.\n const auth = toGetToken(props);\n const authKey = 'grantUrl' in auth ? auth.grantUrl : 'getToken';\n const productKey = `${product.productId}|${product.mockupIds.join(',')}|${product.variantId ?? ''}`;\n // ADR-0099 bundle session: the per-role picks + variants are the variant\n // identity. They are NOT part of the session key — a change is a NEW config\n // message on the open socket (below), exactly like a Buy-owned variant\n // change — but they ARE part of the validation key, so a wrong pick set is\n // re-checked at mount time, not just at the server.\n const bundleKey = product.picks || product.variants ? JSON.stringify([product.picks ?? null, product.variants ?? null]) : '';\n\n // Wiring validation. Editor.Root throws (F3 — fails loud into the boundary,\n // visible to headless agents); the legacy <RealtimeEmbed> wrapper keeps the\n // advisory dev-only console diagnostics. The ref-based dedup survives\n // StrictMode's deliberate unmount/remount cycle.\n const validationKey = `${shop}|${productKey}|${bundleKey}|${placement}|${hasGrant}`;\n // Render-time on purpose: in throw mode a wiring mistake must throw into\n // Root's boundary, not log (F3 — console.error is invisible to headless\n // agents). Memoized so it runs once per meaningful change. The surviving\n // (non-fatal) issues are returned for the `onIssue` machine channel below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const advisoryIssues = useMemo<EmbedIssue[]>(() => {\n const issues = collectEmbedIssues({ shop, product, design, hasGrant });\n if (__validation !== 'throw') return issues;\n const fatal = issues.find((i) => i.severity === 'error');\n if (fatal) {\n throw new EditorError('E_EMBED_CONFIG', fatal.message, {\n issue: fatal.issue,\n docSlug: 'embed-mode',\n });\n }\n for (const issue of issues) {\n if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {\n console.warn(`[Editor.Root] ${issue.message}`);\n }\n }\n return issues;\n }, [validationKey, __validation]);\n // Deliver advisory issues through `onIssue` — in an effect (a host callback\n // may set state), deduped per wiring identity, dev AND prod.\n const reportedIssuesKeyRef = useRef<string | null>(null);\n useEffect(() => {\n if (advisoryIssues.length === 0) return;\n if (reportedIssuesKeyRef.current === validationKey) return;\n reportedIssuesKeyRef.current = validationKey;\n for (const issue of advisoryIssues) onIssueRef.current?.(issue);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [advisoryIssues, validationKey]);\n const validatedKeyRef = useRef<string | null>(null);\n useEffect(() => {\n if (__validation !== 'warn') return;\n if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {\n if (validatedKeyRef.current === validationKey) return;\n validatedKeyRef.current = validationKey;\n validateEmbed({ shop, product, design, hasGrant });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [validationKey, __validation]);\n\n // RenderSession's constructor fail-fasts (e.g. a variant product with no\n // variantId) by THROWING. Catch it here so a config mistake surfaces through\n // `onRenderError` + the error state instead of throwing during render and\n // white-screening the whole host page.\n const sessionResult = useMemo<{ session: RenderSession } | { error: string }>(\n () => {\n try {\n return { session: new RenderSession({ shop, product, wsUrl, ...auth }) };\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) };\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [shop, productKey, placement, wsUrl, authKey]\n );\n const session = 'session' in sessionResult ? sessionResult.session : null;\n const constructError = 'error' in sessionResult ? sessionResult.error : null;\n\n const pushRender = useMemo(() => {\n return (state: RenderState, throttle = throttleMs) => {\n if (!session) return;\n setError(null);\n setIsRendering(true);\n const handleSendError = (err: unknown) => {\n const message = err instanceof Error ? err.message : String(err);\n setError(message);\n setIsRendering(false);\n onRenderErrorRef.current?.(message);\n };\n const sendSlice = (label: string, ab: Record<string, unknown>) =>\n void session\n .renderState(label, { schemaVersion: state.schemaVersion, artboards: [ab] }, throttle)\n .catch(handleSendError);\n\n // ADR-0101: resolve base + per-placement overrides ONCE (placementLinks)\n // — every required placement gets an artboard: its own when split, the\n // base relabelled when linked (the server re-fits it per placement).\n // Then ADR-0088: one renderState per artboard — the documented\n // multi-placement wire pattern. The server renders once it has a state\n // for EVERY required placement; throttle, dedup, and response\n // versioning are per-placement in the SDK, so the sends never starve\n // each other. A single-placement product degenerates to one send.\n const expanded = expandRequestForPlacements(state, requiredPlacementLabels(product));\n const artboards = (expanded.artboards ?? []) as Array<Record<string, unknown> & { name?: string }>;\n if (artboards.length > 1) {\n for (const ab of artboards) {\n // The artboard NAME inside the sent state must equal the placement\n // arg (warnPlacementArtboardMismatch) — expansion already relabelled\n // inherited slices.\n sendSlice(typeof ab.name === 'string' && ab.name ? ab.name : placement, ab);\n }\n return;\n }\n\n void session.renderState(placement, state, throttle).catch(handleSendError);\n };\n }, [session, placement, product, throttleMs]);\n pushRenderRef.current = pushRender;\n\n useEffect(() => {\n // Construction fail-fast (caught above) — surface it instead of rendering.\n if (constructError) {\n setError(constructError);\n setIsRendering(false);\n onRenderErrorRef.current?.(constructError);\n return;\n }\n if (!session) return;\n\n session.onMockups((results) => {\n setMockups(results);\n setIsRendering(false);\n onMockupsRef.current?.(results);\n });\n session.onError((message) => {\n setError(message);\n setIsRendering(false);\n onRenderErrorRef.current?.(message);\n });\n\n // Seed the first mockup from the design before any edit, so a freshly\n // mounted embed shows a real mockup immediately (no duplicate seed state —\n // the design is the single source).\n pushRender(design.toServerRequest());\n\n return () => session.close();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [session, constructError]);\n\n // Apply a Buy-owned variant change to the LIVE session (no re-key). The\n // baseline per session is the prop variant it was constructed with; a\n // selection that resolves elsewhere sends `setProduct` (config on the open\n // socket) and re-pushes the CURRENT design state so every Preview updates.\n const appliedVariantRef = useRef<{ session: RenderSession | null; variantId: string | undefined }>({\n session: null,\n variantId: undefined,\n });\n useEffect(() => {\n if (!session || !selectedVariantId) return;\n const applied = appliedVariantRef.current;\n const baseline = applied.session === session ? applied.variantId : product.variantId;\n if (selectedVariantId === baseline) {\n appliedVariantRef.current = { session, variantId: baseline };\n return;\n }\n appliedVariantRef.current = { session, variantId: selectedVariantId };\n session.setProduct({ ...product, variantId: selectedVariantId });\n pushRender(serializeStateForServer(internals.store.getState()));\n // `product` identity is deliberately NOT a dep (embedders pass inline\n // objects); a REAL product change re-keys the session above, which resets\n // the baseline through `applied.session !== session`.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [session, selectedVariantId]);\n\n // ADR-0099: a bundle pick / per-role variant change is a NEW config message\n // on the LIVE session (the server re-validates it — typed refusals arrive on\n // onError — and re-derives the required placement set), then the CURRENT\n // design state is re-pushed so every Preview shows the new member set.\n // Same shape as the Buy-owned variant effect above: no session re-key.\n const appliedBundleRef = useRef<{ session: RenderSession | null; key: string }>({ session: null, key: '' });\n useEffect(() => {\n if (!session || !bundleKey) return;\n const applied = appliedBundleRef.current;\n if (applied.session === session && applied.key === bundleKey) return;\n const first = applied.session !== session;\n appliedBundleRef.current = { session, key: bundleKey };\n if (first) return; // the session was constructed with this pick set\n session.setProduct(product);\n pushRender(serializeStateForServer(internals.store.getState()));\n // `product` identity is deliberately NOT a dep (embedders pass inline\n // objects); only the pick/variant content re-sends.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [session, bundleKey]);\n\n // Runtime silent-hang backstop. While a render is in flight, arm a timer; if no\n // mockup (or error) lands within SLOW_RENDER_HINT_MS, surface an actionable\n // hint. Unlike the mount-time wiring guard this fires ONLY on an actual stall,\n // so it never nags a working embed — and it covers every silent-hang cause, not\n // just missing variantId. The console hint stays dev-only; `onIssue` gets the\n // structured `slow-render` issue in every env (agents and telemetry don't read\n // the console); cleared the moment `isRendering` flips false.\n useEffect(() => {\n if (!isRendering) return;\n const timer = setTimeout(() => {\n const message = slowRenderHint(placement);\n if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {\n console.warn(message);\n }\n onIssueRef.current?.({ severity: 'warn', issue: 'slow-render', message });\n }, SLOW_RENDER_HINT_MS);\n return () => clearTimeout(timer);\n }, [isRendering, placement]);\n\n const value = useMemo<EmbedContextValue>(\n () => ({\n session,\n design,\n // The ACTIVE placement (ADR-0088): Editor.Canvas follows it as its\n // controlled artboard; single-placement designs never see it move.\n placement: activePlacement,\n placements,\n selectPlacement,\n requiredPlacements,\n splitPlacement,\n linkPlacement,\n product,\n mockups,\n isRendering,\n error,\n throttleMs,\n pieceGuides,\n pushRender,\n stateStore: internals.store,\n }),\n [session, design, activePlacement, placements, selectPlacement, requiredPlacements, splitPlacement, linkPlacement, product, mockups, isRendering, error, throttleMs, pieceGuides, pushRender, internals.store]\n );\n\n // Single validation point for the part registry (ADR-0085 §4). Parts\n // register in their layout effects (so a whole commit's registrations\n // arrive together — no race against the lazy canvas chunk); each change\n // re-renders this component, and validation throws RENDER-side, where\n // Root's boundary reliably contains it (layout-effect throws are not\n // dependably boundary-caught across React 18 + DOM test environments).\n const registryVersion = useSyncExternalStore(\n internals.registry.subscribe,\n internals.registry.getVersion,\n internals.registry.getVersion,\n );\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useMemo(() => {\n // Snapshot the audit BEFORE validating: a composition that throws\n // (E_REQUIRES_CANVAS, E_DUPLICATE_CANVAS) unmounts the parts and empties\n // the registry, so `onAudit` must report from the registry state the\n // throw saw — recorded here, fired by the outer Root (outside the\n // boundary) once mount settles.\n recordAudit(\n computeEditorAudit({ registry: internals.registry, store: internals.store, product }),\n );\n internals.registry.validate();\n }, [internals.registry, registryVersion]);\n\n const body = (\n <EditorRootInternalsContext.Provider value={internals}>\n <EmbedContext.Provider value={value}>\n {/* P1 provider inversion (D9: state always, renderer lazy): Root owns\n BOTH provider boundaries — EmbedContext above, and the editor\n document (EditorProvider) here, mounted in EVERY composition.\n Its graph is renderer-free (element/renderer split), CI-gated by\n the import-graph check. `Editor.Canvas`'s inner SnowconeCanvas\n mounts with `externalProvider` and writes into THIS document.\n The bound-layer guard sits ABOVE EditorProvider so the command\n layer can consult the parts registry (E_BOUND_LAYER_MUTATION). */}\n <BoundLayerGuardContext.Provider value={internals.registry}>\n <EditorProvider\n {...(initialArtboardConfig ? { initialArtboardConfig } : {})}\n >\n {children}\n </EditorProvider>\n </BoundLayerGuardContext.Provider>\n </EmbedContext.Provider>\n </EditorRootInternalsContext.Provider>\n );\n\n // Only mount a services provider when configured — `<Editor.Canvas>`'s\n // inner SnowconeCanvas inherits it through context.\n if (services) {\n return <CanvasServicesProvider services={services}>{body}</CanvasServicesProvider>;\n }\n return body;\n}\n\n/**\n * The root of an `Editor.*` composition. See the module doc for the state\n * model; see `RealtimeEmbed` for the legacy turnkey wrapper this was\n * extracted from.\n *\n * Stable since ADR-0085 P4 (the default editor is rebuilt from this public\n * surface, CI-gated); additive-only from here.\n */\nexport function EditorRoot(props: EditorRootProps): React.ReactElement {\n const { design, product, onAudit } = props;\n\n // One store + registry per (design) — remounting with a new design reseeds.\n // The commerce store is keyed on the PRODUCT's identity instead (a new\n // product or a host-driven `variantId` prop change reseeds the selection;\n // design edits never touch it).\n const productIdentity = `${product.productId}|${product.variantId ?? ''}`;\n const internalsRef = useRef<{ design: AnyDesign; internals: Omit<EditorRootInternals, 'reportInvariant' | 'reportRuntimeError' | 'commerce'> } | null>(null);\n const commerceRef = useRef<{ productIdentity: string; commerce: CommerceStateStore } | null>(null);\n const [reportedError, setReportedError] = useState<EditorError | null>(null);\n if (internalsRef.current === null || internalsRef.current.design !== design) {\n internalsRef.current = {\n design,\n internals: {\n store: new DesignStateStore(design.toJSON()),\n registry: new EditorPartsRegistry(),\n },\n };\n }\n if (commerceRef.current === null || commerceRef.current.productIdentity !== productIdentity) {\n commerceRef.current = { productIdentity, commerce: new CommerceStateStore(product) };\n }\n\n const internals = useMemo<EditorRootInternals>(\n () => ({\n ...internalsRef.current!.internals,\n commerce: commerceRef.current!.commerce,\n ...makeInvariantReporter(setReportedError),\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [internalsRef.current.internals, commerceRef.current.commerce]\n );\n\n // ── Composition audit (`Editor.audit()`, agentic-DX #10) ──────────────────\n // The inner component records a snapshot every time the registry changes\n // (render-side, BEFORE registry validation can throw); this outer component\n // — which survives a boundary catch — fires `onAudit` once after mount\n // settles and answers the imperative `auditEditor()` with a FRESH report.\n const productRef = useRef(product);\n productRef.current = product;\n const onAuditRef = useRef(onAudit);\n onAuditRef.current = onAudit;\n const auditSnapshotRef = useRef<EditorAuditReport | null>(null);\n const recordAudit = useCallback((report: EditorAuditReport) => {\n auditSnapshotRef.current = report;\n }, []);\n const computeAudit = useCallback(\n () =>\n computeEditorAudit({\n registry: internalsRef.current!.internals.registry,\n store: internalsRef.current!.internals.store,\n product: productRef.current,\n }),\n [],\n );\n // Most-recent mounted Root answers `auditEditor()`.\n useLayoutEffect(() => registerRootForAudit({ compute: computeAudit }), [computeAudit]);\n // Fire once after mount settles. Parts register in the first commit's\n // layout effects; the registry bump re-renders the inner component, which\n // records the full snapshot — but React may flush this passive effect\n // BEFORE that re-render (it flushes pending passive effects when a layout\n // effect schedules a sync update), so the fire is deferred one microtask:\n // by then every synchronous settle step — registrations, the snapshot\n // re-render, even a composition throw into the boundary — has happened.\n // Dev AND prod, like `onIssue`.\n const auditFiredRef = useRef(false);\n useEffect(() => {\n let cancelled = false;\n queueMicrotask(() => {\n if (cancelled || auditFiredRef.current) return;\n auditFiredRef.current = true;\n onAuditRef.current?.(auditSnapshotRef.current ?? computeAudit());\n });\n return () => {\n cancelled = true;\n };\n }, [computeAudit]);\n\n return (\n // `display: contents` — the .sc-root scope without a layout box, so the\n // host's grid/flex sees the parts directly (and the legacy RealtimeEmbed\n // wrapper, which had no DOM at all, stays layout-identical).\n <div className=\"sc-root\" style={{ display: 'contents' }} data-sc-part=\"root\">\n <EditorBoundary reportedError={reportedError} onRetry={() => setReportedError(null)}>\n <EditorRootInner {...props} internals={internals} recordAudit={recordAudit} />\n </EditorBoundary>\n </div>\n );\n}\n","'use client';\n\n/**\n * `<Editor.Canvas>` — the editable artboard, and the ONE lazy boundary of the\n * primitives (D9): all state mounts with `Editor.Root`; the heavy rendering\n * engine lives in {@link EditorCanvasImpl}'s chunk and loads only when this\n * part mounts. A no-canvas composition (Preview + TextField + Buy) never\n * fetches it — CI-asserted by the import-graph check.\n *\n * A failed chunk load (network/CDN) is a RUNTIME failure, not a composition\n * mistake: it routes to Root's error card with a retry affordance\n * (`E_CHUNK_LOAD_FAILED`) in every env. Retry clears the card, which remounts\n * this part and re-attempts the import.\n */\n\nimport React, { forwardRef, useEffect, useId, useLayoutEffect, useState, type CSSProperties, type ReactNode } from 'react';\nimport { EditorError } from '../../errors/editorError.js';\nimport { useEditorRootInternals, useRegisterEditorPart } from './RootInternals.js';\nimport type { EditorCanvasImplProps } from './EditorCanvasImpl.js';\nimport type { SnowconeCanvasHandle } from '../embed/SnowconeCanvas.js';\n\ntype ImplComponent = (typeof import('./EditorCanvasImpl.js'))['EditorCanvasImpl'];\n\nlet implLoader: () => Promise<ImplComponent> = () =>\n import('./EditorCanvasImpl.js').then((m) => m.EditorCanvasImpl);\n\n/** Load the heavy impl chunk. Exposed for the legacy `<RealtimeCanvas>`\n * wrapper so both share ONE lazy boundary (one chunk). @internal */\nexport function loadCanvasImpl(): Promise<ImplComponent> {\n return implLoader();\n}\n\n/** Swap the chunk loader — TEST-ONLY seam for the chunk-load-failure → error\n * card → retry contract (a real `import()` can't be made to fail once and\n * then succeed under the module cache). Returns a restore function.\n * @internal */\nexport function __setCanvasImplLoaderForTests(loader: () => Promise<ImplComponent>): () => void {\n const previous = implLoader;\n implLoader = loader;\n return () => {\n implLoader = previous;\n };\n}\n\nexport interface EditorCanvasProps {\n /** Your overlay controls — rendered inside the editor context, so the\n * binding hooks (`useTextBinding` …) resolve against live elements. */\n children?: ReactNode;\n /** Cap the canvas height in px. */\n maxHeight?: number;\n /**\n * The canvas's built-in selection-anchored floating toolbar (default\n * `true`). Pass `false` when your composition owns the contextual zone —\n * e.g. a conditionally-rendered `<Editor.Controls placement=\"docked\"/>` —\n * so suppression is declared HERE, in the type surface, rather than implied\n * by whether a docked Controls happens to be mounted this frame (a mounted\n * docked Controls still suppresses it either way, ADR-0085 §5).\n */\n floatingToolbar?: boolean;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * The editable artboard. Mount at most one under a Root\n * (`E_DUPLICATE_CANVAS`); mount none for the no-canvas personalization\n * composition.\n *\n * Stable since ADR-0085 P4 (the default editor is rebuilt from this public\n * surface, CI-gated); additive-only from here.\n */\nexport const EditorCanvas = forwardRef<SnowconeCanvasHandle, EditorCanvasProps>(function EditorCanvas(\n { children, maxHeight, floatingToolbar = true, className, style }: EditorCanvasProps,\n ref,\n): React.ReactElement {\n const internals = useEditorRootInternals('Editor.Canvas');\n // Census + the `floatingToolbar` declaration the audit's A_CONTROLS_INERT\n // check reads (`Editor.audit()`, #10).\n useRegisterEditorPart('Editor.Canvas', { floatingToolbar });\n const instanceId = useId();\n\n // Registration is by THIS component's mount, not the chunk's arrival — so\n // duplicate detection and requires-canvas validation never race the lazy\n // load (ADR-0085 §4).\n useLayoutEffect(() => {\n return internals.registry.registerCanvas(instanceId);\n }, [internals.registry, instanceId]);\n\n const [Impl, setImpl] = useState<ImplComponent | null>(null);\n useEffect(() => {\n let cancelled = false;\n loadCanvasImpl().then(\n (component) => {\n if (!cancelled) setImpl(() => component);\n },\n (err) => {\n if (cancelled) return;\n internals.reportRuntimeError(\n new EditorError(\n 'E_CHUNK_LOAD_FAILED',\n `the editor's rendering chunk failed to load (${err instanceof Error ? err.message : String(err)}). ` +\n 'This is a network/CDN failure, not a composition mistake — retry, or check the deployment ' +\n 'serves the @snowcone-app/canvas lazy chunks.',\n { cause: err instanceof Error ? err.message : String(err), docSlug: 'embed-mode' },\n ),\n );\n },\n );\n return () => {\n cancelled = true;\n };\n }, [internals]);\n\n if (!Impl) {\n // Lightweight placeholder while the chunk loads — keeps the host layout\n // stable; themed via .sc-root tokens like every part.\n return (\n <div\n data-sc-part=\"canvas\"\n data-sc-state=\"loading\"\n className={className}\n style={{ minHeight: maxHeight ?? 200, ...style }}\n aria-busy=\"true\"\n />\n );\n }\n\n return (\n // `builtinControls`: the canvas owns the floating contextual toolbar\n // unless the host opts out via `floatingToolbar={false}` or a docked\n // <Editor.Controls> is mounted (ADR-0085 §5). Only here — the legacy\n // <RealtimeCanvas> wrapper stays chrome-less.\n <Impl\n ref={ref}\n kit=\"embed-only\"\n partAttr=\"canvas\"\n builtinControls={floatingToolbar}\n maxHeight={maxHeight}\n className={className}\n style={style}\n >\n {children}\n </Impl>\n );\n});\n\nexport type { EditorCanvasImplProps };\n","'use client';\n\n/**\n * `usePlacements()` — the headless floor under `<Editor.Placements/>`\n * (ADR-0088, ADR-0101): the product's placements, which one is active,\n * which ones are LINKED (inherit the base design), and the switches.\n *\n * Linked by default: a design with one artboard renders it on every required\n * placement. `split(label)` gives a placement its own artboard (cloned from\n * the base); `link(label)` collapses it back. Every value derives from the\n * LIVE design state, so split/link at runtime re-render consumers.\n *\n * Works in EVERY composition under `Editor.Root`, canvas-free ones included —\n * switching there just re-targets which artboard the (future) canvas would\n * show; bindings and renders already span all placements. Switching never\n * re-keys the render session.\n */\n\nimport { useMemo } from 'react';\nimport { useEmbedContext } from '../embed-realtime/context.js';\nimport { resolvePlacementLinks } from './placementLinks.js';\n\nexport interface PlacementInfo {\n /** The placement label (= the design artboard name when split, e.g. 'Front'). */\n label: string;\n /** True when this placement is the one being edited. For a linked\n * placement this is true while its BASE is active (that is the artboard\n * it renders). */\n active: boolean;\n /** True when this placement has no artboard of its own and renders the\n * base design (ADR-0101). The base's own label is never inherited. */\n inherited: boolean;\n}\n\nexport interface UsePlacementsReturn {\n /** Every placement, in product order (then any extra authored artboards). */\n placements: PlacementInfo[];\n /** The artboard being edited — a real artboard name, never a linked label. */\n activePlacement: string;\n /** The base artboard (the first one) — what linked placements inherit. */\n basePlacement: string;\n /** True when the product has 2+ placements and ALL of them render the base\n * (no placement is split): \"one design on every area\". */\n linked: boolean;\n /** Switch the active placement. A linked label activates the base (that is\n * what it renders — editing it edits every linked area). Throws\n * `EditorError E_UNKNOWN_PLACEMENT` for a label that is neither a product\n * placement nor a design artboard. */\n select: (label: string) => void;\n /** Give `label` its own artboard, cloned from the base, and activate it.\n * No-op when already split. Throws `E_UNKNOWN_PLACEMENT`. */\n split: (label: string) => void;\n /** Drop `label`'s own artboard so it inherits the base again. No-op when\n * already linked. Throws `E_LINK_BASE` for the base itself. */\n link: (label: string) => void;\n /** \"Customize separately\": split every placement that still inherits. */\n splitAll: () => void;\n /** \"Use one design for all\": link every split placement back to the base. */\n linkAll: () => void;\n}\n\nexport function usePlacements(): UsePlacementsReturn {\n const { placements: artboardNames, requiredPlacements, placement, selectPlacement, splitPlacement, linkPlacement } =\n useEmbedContext();\n return useMemo(() => {\n const links = resolvePlacementLinks(artboardNames, requiredPlacements);\n const base = artboardNames[0] ?? placement;\n const infos: PlacementInfo[] = links.map((l) => ({\n label: l.label,\n inherited: l.inherited,\n active: l.inherited ? placement === base : placement === l.label,\n }));\n const linked = infos.length > 1 && infos.every((p) => p.inherited || p.label === base);\n return {\n placements: infos,\n activePlacement: placement,\n basePlacement: base,\n linked,\n select: selectPlacement,\n split: splitPlacement,\n link: linkPlacement,\n splitAll: () => {\n for (const p of infos) if (p.inherited) splitPlacement(p.label);\n },\n linkAll: () => {\n for (const p of infos) if (!p.inherited && p.label !== base) linkPlacement(p.label);\n },\n };\n }, [artboardNames, requiredPlacements, placement, selectPlacement, splitPlacement, linkPlacement]);\n}\n","'use client';\n\n/**\n * `<Editor.Placements>` — the placement switcher (ADR-0088) and the link\n * switch (ADR-0101). The minimal styled part over {@link usePlacements} —\n * hosts wanting bespoke UI use the hook directly.\n *\n * - LINKED (the default — one design on every area): one non-interactive\n * pill naming the set (\"Both sides\" / \"All 4 areas\") and one action,\n * \"Customize separately\" (`splitAll`). No tabs: there is nothing to switch.\n * - SPLIT (any placement has its own artboard): one tab per placement —\n * a still-linked tab is marked `data-sc-linked=\"true\"` and activates the\n * base when clicked (that is what it renders) — plus one action, \"Use one\n * design for all\" (`linkAll`).\n *\n * Renders NOTHING for a single-placement product (no dead chrome) — mount it\n * unconditionally and it appears exactly when the product has a second side.\n *\n * Canvas-free compositions may mount it too (it operates on Root state, not\n * the renderer).\n */\n\nimport React, { type CSSProperties } from 'react';\nimport { usePlacements } from './usePlacements.js';\n\nexport interface EditorPlacementsLabels {\n /** Pill text while linked. Default: \"Both sides\" for two placements,\n * \"All N areas\" otherwise. Receives the placement labels. */\n linked?: (labels: string[]) => string;\n /** The split action. Default \"Customize separately\". */\n customizeSeparately?: string;\n /** The re-link action. Default \"Use one design for all\". */\n useOneDesign?: string;\n}\n\nexport interface EditorPlacementsProps {\n className?: string;\n style?: CSSProperties;\n /** Override the built-in copy (localization). */\n labels?: EditorPlacementsLabels;\n}\n\nconst defaultLinkedLabel = (labels: string[]): string =>\n labels.length === 2 ? 'Both sides' : `All ${labels.length} areas`;\n\nconst actionStyle: CSSProperties = {\n font: 'inherit',\n fontSize: '12px',\n color: 'var(--sc-color-muted-foreground, inherit)',\n background: 'transparent',\n border: 'none',\n padding: '2px 8px',\n cursor: 'pointer',\n textDecoration: 'underline',\n textUnderlineOffset: '4px',\n};\n\n/**\n * Placement tabs + link switch for a multi-placement product.\n *\n * Styling contract: `data-sc-part=\"placements\"` on the row (with\n * `data-sc-linked=\"true|false\"`), `data-sc-part=\"placements-item\"` +\n * `data-sc-active=\"true|false\"` + `data-sc-linked=\"true|false\"` +\n * `aria-pressed` per tab, `data-sc-part=\"placements-link-toggle\"` on the\n * split / re-link action — restyle via those hooks and the `.sc-root`\n * tokens; the built-in styling is deliberately minimal.\n */\nexport function EditorPlacements({ className, style, labels }: EditorPlacementsProps): React.ReactElement | null {\n const { placements, linked, select, splitAll, linkAll } = usePlacements();\n if (placements.length < 2) return null;\n const names = placements.map((p) => p.label);\n\n return (\n <div\n data-sc-part=\"placements\"\n data-sc-linked={linked ? 'true' : 'false'}\n className={className}\n style={{ display: 'flex', alignItems: 'center', gap: '4px', ...style }}\n >\n {linked ? (\n <span\n data-sc-part=\"placements-item\"\n data-sc-active=\"true\"\n data-sc-linked=\"true\"\n title={names.join(' · ')}\n style={{ fontSize: '13px', fontWeight: 700, padding: '2px 8px', color: 'var(--sc-color-foreground, inherit)' }}\n >\n {(labels?.linked ?? defaultLinkedLabel)(names)}\n </span>\n ) : (\n placements.map(({ label, active, inherited }) => (\n <button\n key={label}\n type=\"button\"\n data-sc-part=\"placements-item\"\n data-sc-active={active ? 'true' : 'false'}\n data-sc-linked={inherited ? 'true' : 'false'}\n aria-pressed={active}\n onClick={() => select(label)}\n style={{\n font: 'inherit',\n fontSize: '13px',\n fontWeight: active ? 700 : 400,\n color: 'var(--sc-color-foreground, inherit)',\n opacity: inherited ? 0.6 : 1,\n background: 'transparent',\n border: 'none',\n borderRadius: '9999px',\n padding: '2px 8px',\n cursor: active ? 'default' : 'pointer',\n textDecoration: active ? 'underline' : 'none',\n textUnderlineOffset: '4px',\n }}\n >\n {label}\n </button>\n ))\n )}\n <button\n type=\"button\"\n data-sc-part=\"placements-link-toggle\"\n data-sc-linked={linked ? 'true' : 'false'}\n onClick={linked ? splitAll : linkAll}\n style={actionStyle}\n >\n {linked\n ? (labels?.customizeSeparately ?? 'Customize separately')\n : (labels?.useOneDesign ?? 'Use one design for all')}\n </button>\n </div>\n );\n}\n","'use client';\n\n/**\n * The snowcone rainbow render-in-flight overlay for `Editor.Preview`\n * (`loadingOverlay` prop) — the sc-namespaced port of the www PDP's candy\n * loader (`LoadingOverlayPrismCandy` in @snowcone-app/ui; the canvas package\n * is dependency-free of `ui`, hence the port). Styles live in `embed.css`\n * (`.sc-prism-*`); see the block comment there for the blend-mode rules that\n * make the bands tint the artwork instead of collapsing to dark bars.\n *\n * Choreography (mirrors the PDP's `useLoadingOverlay` + linger):\n * - `useRenderLoadingOverlay(isRendering)` waits 200ms before mounting, so\n * a fast/cached render never flashes the loader.\n * - When the render lands it holds for 400ms (the new mockup image is\n * usually decoding right then), then fades out over 400ms and unmounts.\n */\n\nimport React, { memo, useCallback, useEffect, useRef, useState } from 'react';\n\nconst SHOW_DELAY_MS = 200;\nconst LINGER_MS = 400;\n\ntype Particle = {\n left: number;\n top: number;\n delay: string;\n duration: string;\n size: number;\n};\n\nfunction generateParticles(): Particle[] {\n return Array.from({ length: 10 }, () => ({\n left: 2 + Math.random() * 96,\n top: 2 + Math.random() * 96,\n delay: (Math.random() * 3.5).toFixed(1),\n duration: (3 + Math.random() * 2).toFixed(1),\n size: 3 + Math.random() * 5,\n }));\n}\n\nlet propertiesRegistered = false;\n/**\n * Belt-and-suspenders re-registration of the `@property` declarations in\n * embed.css: iOS Safari silently ignores `@property` inside dynamically\n * inserted stylesheets (which is how many host bundlers inject CSS), and\n * without registration the custom-property transitions snap instead of\n * interpolating — the rainbow vanishes instantly rather than fading.\n */\nfunction ensurePrismProperties(): void {\n if (propertiesRegistered || typeof CSS === 'undefined' || typeof CSS.registerProperty !== 'function') {\n return;\n }\n propertiesRegistered = true;\n try {\n CSS.registerProperty({ name: '--sc-prism-mount', syntax: '<number>', initialValue: '0', inherits: true });\n } catch {\n // Already registered (embed.css @property took, or an HMR remount) — fine.\n }\n try {\n CSS.registerProperty({ name: '--sc-prism-band', syntax: '<number>', initialValue: '0', inherits: false });\n } catch {\n // Already registered — fine.\n }\n}\n\nexport interface PreviewPrismOverlayProps {\n /** When false, fade out then call onExited (use it to unmount). */\n visible?: boolean;\n onExited?: () => void;\n /** \"dark\" (default): screen-blended neon bands for image/dark stages.\n * \"light\": multiply-blended candy bands on an opaque light plate. */\n variant?: 'dark' | 'light';\n}\n\nexport const PreviewPrismOverlay = memo(function PreviewPrismOverlay({\n visible = true,\n onExited,\n variant = 'dark',\n}: PreviewPrismOverlayProps): React.ReactElement {\n ensurePrismProperties();\n\n // Empty on first render (SSR-safe); fresh random field per show.\n const [particles, setParticles] = useState<Particle[]>([]);\n useEffect(() => {\n setParticles(generateParticles());\n }, []);\n\n // Apply the fade-in class one frame after mount so the transition plays.\n const [mounted, setMounted] = useState(false);\n useEffect(() => {\n const raf = requestAnimationFrame(() => setMounted(true));\n return () => cancelAnimationFrame(raf);\n }, []);\n\n const handleTransitionEnd = useCallback(\n (e: React.TransitionEvent<HTMLDivElement>) => {\n // background-color transitions in lockstep with --sc-prism-mount; fire\n // onExited only when the fade-out finishes.\n if (e.propertyName !== 'background-color') return;\n if (!visible) onExited?.();\n },\n [visible, onExited],\n );\n\n let fadeClass = '';\n if (!visible) fadeClass = 'sc-prism-fade-out';\n else if (mounted) fadeClass = 'sc-prism-fade-in';\n\n return (\n <div\n data-sc-part=\"preview-loading\"\n className={['sc-prism-overlay', variant === 'light' ? 'sc-prism-on-light' : '', fadeClass]\n .filter(Boolean)\n .join(' ')}\n onTransitionEnd={handleTransitionEnd}\n aria-hidden=\"true\"\n >\n {Array.from({ length: 6 }, (_, i) => (\n <div key={`b-${i}`} className=\"sc-prism-band\" />\n ))}\n {particles.map((p, i) => (\n <div\n key={`p-${i}`}\n className=\"sc-prism-particle\"\n style={{\n left: `${p.left}%`,\n top: `${p.top}%`,\n animationDelay: `${p.delay}s`,\n animationDuration: `${p.duration}s`,\n width: `${p.size}px`,\n height: `${p.size}px`,\n }}\n />\n ))}\n </div>\n );\n});\n\n/**\n * Show/hide choreography for a render-in-flight overlay: show-delayed mount\n * (fast renders never flash it), post-render linger, fade-out unmount.\n * Mirrors @snowcone-app/ui's `useLoadingOverlay` + the PDP hero's linger.\n */\nexport function useRenderLoadingOverlay(isLoading: boolean): {\n /** Mount the overlay? */\n showOverlay: boolean;\n /** The overlay's `visible` prop (false starts the fade-out). */\n overlayVisible: boolean;\n /** Pass as `onExited` — unmounts after the fade. */\n handleExited: () => void;\n} {\n const [showOverlay, setShowOverlay] = useState(false);\n const [lingering, setLingering] = useState(false);\n const showTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const lingerTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const shownRef = useRef(false);\n shownRef.current = showOverlay;\n\n useEffect(() => {\n if (isLoading) {\n setLingering(false);\n if (lingerTimerRef.current) clearTimeout(lingerTimerRef.current);\n showTimerRef.current = setTimeout(() => setShowOverlay(true), SHOW_DELAY_MS);\n } else {\n if (showTimerRef.current) {\n clearTimeout(showTimerRef.current);\n showTimerRef.current = null;\n }\n // Linger only if the overlay actually made it on screen — a render that\n // beat the show delay should never flash the loader afterwards.\n if (shownRef.current) {\n setLingering(true);\n lingerTimerRef.current = setTimeout(() => setLingering(false), LINGER_MS);\n }\n }\n return () => {\n if (showTimerRef.current) clearTimeout(showTimerRef.current);\n if (lingerTimerRef.current) clearTimeout(lingerTimerRef.current);\n };\n }, [isLoading]);\n\n const handleExited = useCallback(() => setShowOverlay(false), []);\n\n return {\n showOverlay,\n overlayVisible: isLoading || lingering,\n handleExited,\n };\n}\n","'use client';\n\n/**\n * `<Editor.Preview>` — the live product mockup (the buyable thing), extracted\n * from the legacy `<RealtimeMockup>` (which now wraps this).\n *\n * Reads the shared session's mockups from context and renders the rendered\n * image, updating as the shopper edits. Because every Preview shares one\n * session with the rest of the composition, it can never desync — and\n * MULTIPLE Previews under one Root are explicitly VALID (front/back; mockup\n * scenes via `mockupId`). Canvas-free by design: the no-canvas\n * personalization widget is Preview + TextField + Buy.\n */\n\nimport React, {\n isValidElement,\n useRef,\n type CSSProperties,\n type ReactElement,\n type ReactNode,\n type SyntheticEvent,\n} from 'react';\nimport { useEmbedContext } from '../embed-realtime/context.js';\nimport { useRegisterEditorPart } from './RootInternals.js';\nimport { PreviewPrismOverlay, useRenderLoadingOverlay } from '../editor/PreviewPrismOverlay.js';\nimport { EditorError } from '../../errors/editorError.js';\n\nexport interface EditorPreviewProps {\n /** Which mockup scene to show (a `product.mockupIds` entry). Defaults to the\n * first mockup that has rendered. */\n mockupId?: string;\n /** Shown before the first mockup arrives / while a render is in flight with no\n * prior image. Defaults to nothing. */\n fallback?: ReactNode;\n /** Alt text for the rendered image. */\n alt?: string;\n /**\n * The render-in-flight loading treatment. A mockup preview ALWAYS has one:\n * a server render takes real time, and the loader paints OVER the\n * still-visible previous mockup — it never blanks or replaces it.\n *\n * **Defaults to `\"dark\"`** — the snowcone rainbow (the www PDP's prism\n * loader): screen-blended neon bands shimmering over the previous mockup,\n * with a 200ms show-delay (cached/instant renders never flash it) and a\n * 400ms post-render linger. `\"light\"`: multiply-blended candy bands on an\n * opaque light plate, for previews on light cards. Pass a custom\n * `ReactElement` to render your own indicator instead — it mounts inside\n * the frame (absolutely positioned over the image) with the same\n * show-delay/linger choreography.\n *\n * In all of the above the part is a positioned stage:\n * `data-sc-part=\"preview\"` is a `.sc-preview-frame` div (which receives\n * `className`/`style`), the `<img>` inside is\n * `data-sc-part=\"preview-image\"`, and the loading layer is\n * `data-sc-part=\"preview-loading\"`.\n *\n * `\"host-owned\"` reverts to the bare `<img>` DOM with no overlay — pass it\n * ONLY when the host renders its own indicator, via the styling contract\n * (`data-sc-preview-state=\"rendering\"`) or the standalone\n * `<Editor.LoadingOverlay>` part.\n *\n * Anything else (`false`, `\"none\"`, …) throws `E_PREVIEW_NO_LOADER`, dev\n * AND prod: a mockup surface with no loading affordance is a composition\n * mistake (silent emptiness, then pop-in), not a preference.\n */\n loadingOverlay?: true | 'dark' | 'light' | 'host-owned' | ReactElement;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * How far the displayed device-pixel width may exceed the delivered mockup's\n * natural width before {@link resolutionMismatchHint} fires. Renders default to\n * 1000px wide, so a 1000px image inside a ~1100 device-px slot is fine (browser\n * downscale slack), but stretched across 2000 device px it looks soft and the\n * developer deserves to hear why.\n */\nexport const RESOLUTION_MISMATCH_RATIO = 1.2;\n\n/**\n * The render-width ladder a mismatch suggestion rounds UP to. Mirrors the\n * `product.width` guidance (\"bump to ~2000 for a crisp preview\") with sensible\n * steps — suggesting the exact device-px count would invite over-precise\n * configs that re-trigger on the next viewport.\n */\nconst SUGGESTED_WIDTHS = [1200, 1400, 1600, 1800, 2000, 2500, 3000, 4000] as const;\n\n/** Rounds a device-pixel width up to the next {@link SUGGESTED_WIDTHS} step\n * (capped at the top step). */\nexport function suggestRenderWidth(devicePx: number): number {\n for (const step of SUGGESTED_WIDTHS) {\n if (step >= devicePx) return step;\n }\n return SUGGESTED_WIDTHS[SUGGESTED_WIDTHS.length - 1];\n}\n\n/**\n * Builds the dev-console warning shown when a delivered mockup's natural width\n * is meaningfully below the width it's displayed at in DEVICE pixels (CSS width\n * × `devicePixelRatio`) — the \"my preview looks soft and nothing says why\"\n * trap: renders default to 1000px wide, which blurs on a large or high-density\n * display. Returns `null` when the resolution is adequate (within\n * {@link RESOLUTION_MISMATCH_RATIO}) or either measurement is unusable.\n */\nexport function resolutionMismatchHint(naturalWidth: number, devicePx: number): string | null {\n if (!(naturalWidth > 0) || !(devicePx > 0)) return null;\n if (devicePx <= naturalWidth * RESOLUTION_MISMATCH_RATIO) return null;\n const suggestion = suggestRenderWidth(devicePx);\n return (\n `[RealtimeMockup] mockup rendered at ${naturalWidth}px but displayed at ` +\n `~${devicePx} device px — the preview will look soft. Pass ` +\n `\\`product.width\\` (e.g. ${suggestion}) on the embed for a crisp preview.`\n );\n}\n\n/**\n * The live product mockup. Mount as many as you need under one Root.\n *\n * Stable since ADR-0085 P4 (the default editor is rebuilt from this public\n * surface, CI-gated); additive-only from here.\n */\ntype ResolvedLoadingOverlay = 'dark' | 'light' | 'host-owned' | ReactElement;\n\n/** The valid `loadingOverlay` states. Default ON; removal must be said in\n * words (`\"host-owned\"`); everything else is a loud mount error. */\nfunction resolveLoadingOverlay(\n value: EditorPreviewProps['loadingOverlay'],\n): ResolvedLoadingOverlay {\n if (value === undefined || value === true || value === 'dark') return 'dark';\n if (value === 'light' || value === 'host-owned') return value;\n if (isValidElement(value)) return value;\n throw new EditorError(\n 'E_PREVIEW_NO_LOADER',\n `Editor.Preview: invalid loadingOverlay value ${JSON.stringify(value)}. ` +\n 'A mockup preview always has a render-in-flight treatment (the loader ' +\n 'paints over the still-visible previous mockup). Omit the prop for the ' +\n 'default rainbow overlay, pass \"dark\" | \"light\", pass a custom ' +\n 'ReactElement, or declare \"host-owned\" if the host renders its own ' +\n 'indicator off data-sc-preview-state / <Editor.LoadingOverlay>.',\n { docSlug: 'preview-loading-overlay' },\n );\n}\n\nexport function EditorPreview({\n mockupId,\n fallback = null,\n alt = 'Live product mockup',\n loadingOverlay,\n className,\n style,\n}: EditorPreviewProps): React.ReactElement {\n const { mockups, error, isRendering } = useEmbedContext();\n // Census + the scene pin the audit's A_PREVIEW_AMBIGUOUS check reads\n // (`Editor.audit()`, #10). Tolerant of a missing Root by design — the\n // legacy <RealtimeMockup> wrapper mounts this part too.\n useRegisterEditorPart('Editor.Preview', { ...(mockupId !== undefined ? { mockupId } : {}) });\n\n // A preview always has a loading treatment — resolve (and validate) what\n // kind. Invalid values throw E_PREVIEW_NO_LOADER here, at mount, dev AND\n // prod, with the valid options in the message.\n const resolved = resolveLoadingOverlay(loadingOverlay);\n const overlayVariant: 'dark' | 'light' | null =\n resolved === 'dark' || resolved === 'light' ? resolved : null;\n const customOverlay = isValidElement(resolved) ? resolved : null;\n const overlayActive = resolved !== 'host-owned';\n\n // Render-in-flight overlay choreography (inert in host-owned mode — the\n // hook itself is unconditional, per the rules of hooks). \"As fast as\n // possible\" with a 200ms show-delay: a cached/instant render never flashes\n // the loader.\n const { showOverlay, overlayVisible, handleExited } = useRenderLoadingOverlay(\n overlayActive && isRendering,\n );\n\n // Mockup ids already warned about this mount — re-renders and repeated loads\n // of the same scene stay quiet; a different scene gets its own one warning.\n const warnedMockupIdsRef = useRef<Set<string>>(new Set());\n\n const result = mockupId\n ? mockups.find((m) => m.mockupId === mockupId && m.imageUrl)\n : mockups.find((m) => m.imageUrl);\n\n // Dev-only resolution check (the `process` reference is typeof-guarded on the\n // same line — non-Node bundlers don't define it). Runs on load because only a\n // decoded image knows its natural width; skips SSR (no `window`) and\n // unmeasurable (zero-width) elements.\n const handleLoad = (event: SyntheticEvent<HTMLImageElement>) => {\n if (!result) return;\n if (typeof process === 'undefined' || process.env?.NODE_ENV === 'production') return;\n if (typeof window === 'undefined') return;\n if (warnedMockupIdsRef.current.has(result.mockupId)) return;\n const img = event.currentTarget;\n const cssWidth = img.getBoundingClientRect().width;\n if (cssWidth <= 0) return;\n const devicePx = Math.round(cssWidth * (window.devicePixelRatio || 1));\n const hint = resolutionMismatchHint(img.naturalWidth, devicePx);\n if (hint) {\n warnedMockupIdsRef.current.add(result.mockupId);\n console.warn(hint);\n }\n };\n\n if (overlayActive) {\n // Overlay mode (the DEFAULT): the part is a positioned stage\n // (`.sc-preview-frame`) the loader fills; the previous mockup keeps\n // painting underneath while a render is in flight, exactly like the PDP\n // hero. Error/fallback render INSIDE the frame so the stage (and the\n // overlay over it) keeps the host-given size before the first mockup\n // lands.\n // The frame carries the same `data-sc-preview-state` verification\n // contract as the bare-img mode (#703): agents await the attribute, not\n // the DOM shape.\n const frameState = result?.imageUrl\n ? isRendering\n ? 'rendering'\n : 'ready'\n : error\n ? 'error'\n : 'rendering';\n return (\n <div\n data-sc-part=\"preview\"\n data-sc-preview-state={frameState}\n aria-busy={frameState === 'rendering' || undefined}\n className={`sc-preview-frame${className ? ` ${className}` : ''}`}\n style={style}\n >\n {result?.imageUrl ? (\n // eslint-disable-next-line @next/next/no-img-element\n <img data-sc-part=\"preview-image\" src={result.imageUrl} alt={alt} onLoad={handleLoad} />\n ) : error ? (\n <div data-sc-part=\"preview-error\" role=\"alert\" data-sc-error={error}>\n {fallback ?? `Render failed: ${error}`}\n </div>\n ) : (\n fallback\n )}\n {customOverlay ? (\n // Custom indicator: same show-delay + linger window; no exit fade\n // (the host owns its animation), so it unmounts when the window\n // closes.\n showOverlay && overlayVisible ? (\n <div\n data-sc-part=\"preview-loading\"\n className=\"sc-preview-custom-loading\"\n aria-hidden=\"true\"\n >\n {customOverlay}\n </div>\n ) : null\n ) : showOverlay && overlayVariant ? (\n <PreviewPrismOverlay\n visible={overlayVisible}\n variant={overlayVariant}\n onExited={handleExited}\n />\n ) : null}\n </div>\n );\n }\n\n if (!result?.imageUrl) {\n // A render/grant/transport failure with nothing to show must SURFACE, not\n // blank (ADR-0085 failure-modes table: \"error state, no silent blank\").\n // Machine-readable for agents; hosts style or replace it via the\n // `data-sc-part` hook. Once a mockup exists we keep showing it (stale\n // beats blank) and the failure stays on the session's onRenderError.\n if (error) {\n return (\n <div\n data-sc-part=\"preview-error\"\n data-sc-preview-state=\"error\"\n role=\"alert\"\n data-sc-error={error}\n className={className}\n style={style}\n >\n {fallback ?? `Render failed: ${error}`}\n </div>\n );\n }\n // Nothing to show yet — still machine-visible: the wrapper generates no\n // box (`display: contents`) but carries the part + state attributes, so an\n // agent can await `[data-sc-part=\"preview\"][data-sc-preview-state=\"ready\"]`\n // from mount onward instead of heuristically watching for an <img>.\n return (\n <div data-sc-part=\"preview\" data-sc-preview-state=\"rendering\" aria-busy=\"true\" style={{ display: 'contents' }}>\n {fallback}\n </div>\n );\n }\n\n return (\n // eslint-disable-next-line @next/next/no-img-element\n <img\n data-sc-part=\"preview\"\n // The verification contract (agents assert on this, not screenshots):\n // `rendering` = a newer render is in flight (the shown image is stale),\n // `ready` = this image reflects the latest pushed design state.\n data-sc-preview-state={isRendering ? 'rendering' : 'ready'}\n src={result.imageUrl}\n alt={alt}\n className={className}\n style={style}\n onLoad={handleLoad}\n />\n );\n}\n","'use client';\n\n/**\n * `<Editor.TextField>` — a form input bound to a design text layer by TYPED\n * TOKEN (ADR-0085 §1 / T1). Canvas-free by design: in the no-canvas\n * personalization widget it writes the Root's design state directly and the\n * preview re-renders live; with a mounted `Editor.Canvas` the same writes\n * route through the editor command path (undo/redo, repaint) via the canvas\n * bridge — the editor document stays the single write authority (§3). The\n * routing is internal; the API is identical in both compositions.\n *\n * Contract (D10):\n * - `layer` accepts ONLY a `design.layer(\"name\")` token — a bare string\n * throws `E_LAYER_TOKEN_REQUIRED` (today's silent no-op binding became a\n * throw when entering `Editor.*`).\n * - Mount-time revalidation is the authority: the token's name is re-resolved\n * against the mounted Root's CURRENT design state — a token minted from a\n * different design throws `E_LAYER_NOT_FOUND` (dev AND prod).\n * - Mounted + non-`optional` ⇒ required for `Editor.Buy` completeness\n * (non-empty after trim AND differs from seed — C2/C3); unmounted (incl.\n * conditionally hidden) ⇒ not required. Registration lives in Root context.\n * - Reconciliation with canvas edits of the same layer is by construction:\n * one store, last-write-wins; this is a controlled input subscribed to the\n * store, so a canvas edit updates the field.\n */\n\nimport React, { useCallback, useId, useLayoutEffect, useRef, useSyncExternalStore, type CSSProperties } from 'react';\nimport { serializeStateForServer } from '../../rendering/serialize-for-server.js';\nimport { isLayerToken, type LayerToken } from '../../design/design-builder.js';\nimport { EditorError } from '../../errors/editorError.js';\nimport { useEmbedContext } from '../embed-realtime/context.js';\nimport { useEditorRootInternals, useRegisterEditorPart } from './RootInternals.js';\n\nexport interface EditorTextFieldProps {\n /** The text layer this input edits — mint with `design.layer(\"name\")`.\n * Type-checked against the design's TEXT-layer names when the design is\n * statically built; runtime-validated always. */\n layer: LayerToken<'text'>;\n /** Marked optional ⇒ Buy completeness does not require it (C2/C3). */\n optional?: boolean;\n placeholder?: string;\n /** Accessible label. Defaults to the layer name. */\n 'aria-label'?: string;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * A text input bound to a design layer. Works with or without a mounted\n * `Editor.Canvas`.\n *\n * Stable since ADR-0085 P4 (the default editor is rebuilt from this public\n * surface, CI-gated); additive-only from here.\n */\nexport function EditorTextField(props: EditorTextFieldProps): React.ReactElement {\n const { layer, optional = false, placeholder, className, style } = props;\n const internals = useEditorRootInternals('Editor.TextField');\n useRegisterEditorPart('Editor.TextField'); // census (`Editor.audit()`, #10)\n const { pushRender, throttleMs, stateStore } = useEmbedContext();\n const instanceId = useId();\n\n // ── Token + MOUNT-time revalidation (render-time on purpose: a bad layer\n // prop is a composition mistake → Root's boundary, dev AND prod). Validated\n // once per layer name, against the state AT MOUNT — later state churn (the\n // user emptying the canvas, teardown ordering) is user state, not a\n // composition mistake; the write path reports it if a write ever misses. ──\n const validatedNameRef = useRef<string | null>(null);\n if (!isLayerToken(layer)) {\n throw new EditorError(\n 'E_LAYER_TOKEN_REQUIRED',\n `the \\`layer\\` prop must be a token minted by the design — pass ` +\n `layer={design.layer(\"name\")}, not ${typeof layer === 'string' ? `the bare string \"${layer}\"` : 'a plain value'}. ` +\n `Tokens validate the name against the design's layers at mint time.`,\n { received: typeof layer === 'string' ? layer : typeof layer, docSlug: 'embed-mode' },\n );\n }\n if (validatedNameRef.current !== layer.name) {\n const kindNow = stateStore.layerKindOf(layer.name);\n if (kindNow === undefined) {\n throw new EditorError(\n 'E_LAYER_NOT_FOUND',\n `no layer \"${layer.name}\" in this Root's design — the token was minted from a ` +\n `different design than the one passed to <Editor.Root design={…}>. Bindable layers ` +\n `here: ${JSON.stringify(stateStore.bindableLayerNames())}.`,\n { layerName: layer.name, validNames: stateStore.bindableLayerNames(), docSlug: 'embed-mode' },\n );\n }\n if (kindNow !== 'text') {\n throw new EditorError(\n 'E_LAYER_WRONG_KIND',\n `layer \"${layer.name}\" is ${kindNow === null ? 'not a bindable kind' : `an ${kindNow} layer`} — ` +\n `<Editor.TextField> binds text layers only.`,\n { layerName: layer.name, actualKind: kindNow, docSlug: 'embed-mode' },\n );\n }\n validatedNameRef.current = layer.name;\n }\n\n // ── Required-layer registration for Buy completeness (C2/C3) ─────────────\n useLayoutEffect(() => {\n return internals.registry.registerTextField(instanceId, { name: layer.name, optional });\n }, [internals.registry, instanceId, layer.name, optional]);\n\n // ── Controlled value from the ONE store (a canvas edit updates the field) ─\n const value = useSyncExternalStore(\n stateStore.subscribe,\n () => stateStore.textOf(layer.name) ?? '',\n () => stateStore.textOf(layer.name) ?? '',\n );\n\n const handleChange = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n const next = event.target.value;\n const bridge = internals.registry.getCanvasBridge();\n if (bridge) {\n // Canvas mounted: the editor document is the write authority — route\n // through commands; the canvas onChange lands the new state back in\n // the store and pushes the render.\n if (!bridge.setTextByName(layer.name, next)) {\n internals.reportInvariant(\n new EditorError(\n 'E_LAYER_NOT_FOUND',\n `layer \"${layer.name}\" no longer exists in the mounted canvas — it was removed ` +\n `or renamed after this <Editor.TextField> bound to it. Bound layers must not be ` +\n `renamed or deleted while a field is mounted (ADR-0085 §3).`,\n { layerName: layer.name, docSlug: 'embed-mode' },\n ),\n );\n }\n return;\n }\n // No canvas: the store IS the authority. Trailing-edge throttle in the\n // session keeps the last keystroke always rendering.\n stateStore.updateTextLayer(layer.name, next);\n pushRender(serializeStateForServer(stateStore.getState()), throttleMs);\n },\n [internals, layer.name, stateStore, pushRender, throttleMs],\n );\n\n return (\n <input\n data-sc-part=\"textfield\"\n data-sc-layer={layer.name}\n type=\"text\"\n value={value}\n onChange={handleChange}\n placeholder={placeholder}\n aria-label={props['aria-label'] ?? layer.name}\n className={className}\n style={style}\n />\n );\n}\n","'use client';\n\n/**\n * `<Editor.Buy>` — the SMART commerce part (ADR-0085 §2; plan decision: thin\n * callback-Buy was rejected). OWNS variant selection + quantity (P2 — they\n * live in the Root's commerce store, host-visible via `useProductSelection()`,\n * never on Root props where a change would re-key the RenderSession), runs\n * design-completeness validation, and assembles the cart payload; only the\n * final submit is the host's callback — their one line.\n *\n * Completeness rules (v1, C1–C5):\n * - C1 variant resolution — FULL selection resolution (the P2 amendment:\n * `validateProductSelection`/`findBestCombination` replace the old\n * color-axis-only gate). Each unselected required attribute gates with\n * reason `option:<key>`; a complete-but-invalid combination gates with\n * reason `variant`.\n * - C2 every MOUNTED non-`optional` `Editor.TextField` layer non-empty\n * after trim.\n * - C3 those layers must DIFFER from their seed value (F4 — placeholder\n * text like 'YOUR NAME' must not pass).\n * - C4 the design has ≥1 renderable element.\n * - C5 quantity is an integer ≥ 1.\n *\n * Incompleteness is USER state, not a composition error — the button renders\n * disabled with machine-readable `data-sc-buy-state` / `data-sc-buy-missing`\n * reason codes; it never throws. Throws are reserved for composition\n * violations (`E_BUY_NO_PRODUCT`, outside-Root, `E_UNKNOWN_OPTION`).\n *\n * The payload is assembled from DESIGN STATE (the Root's live store — never\n * the seed, never rendered pixels) plus the COMMERCE state (selection,\n * resolved variant, quantity), so render staleness cannot corrupt an order;\n * the preview is just preview (D10).\n */\n\nimport React, { useCallback, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore, type CSSProperties, type ReactNode } from 'react';\nimport {\n createCartDetail,\n type CartDetail,\n type OptionSelection,\n type RenderProduct,\n} from '@snowcone-app/sdk';\nimport { serializeStateForServer, type ServerRenderRequest } from '../../rendering/serialize-for-server.js';\nimport { expandRequestForPlacements } from './placementLinks.js';\nimport { requiredPlacementLabels } from '../embed-realtime/validateEmbed.js';\nimport { EditorError } from '../../errors/editorError.js';\nimport { useEmbedContext } from '../embed-realtime/context.js';\nimport type { DesignState } from './designStateStore.js';\nimport { choiceLabelsOf, type CommerceStateStore } from './commerceStore.js';\nimport { useEditorRootInternals, useRegisterEditorPart } from './RootInternals.js';\n\n/** A structured incompleteness reason — also serialized (comma-joined) into\n * the button's `data-sc-buy-missing` attribute for agents and styling. */\nexport type BuyMissingReason =\n | `option:${string}`\n | 'variant'\n | `layer:${string}`\n | `layer-seed:${string}`\n | 'empty-design'\n | 'quantity';\n\nexport interface EditorBuyPayload {\n productId: string;\n /** The variant (gvid) the selection resolves to. */\n variantId?: string;\n quantity: number;\n /** The variant choices at click time, e.g. `{ Color: 'Black', Size: 'M' }`. */\n selection: OptionSelection;\n /** SDK cart detail (variant resolution + price) when the product carries\n * catalog `options`; `null` for option-less products. */\n cartDetail: CartDetail | null;\n /** The DESIGN STATE at click time (editor shape) — persist this; it is the\n * re-renderable source of truth for the purchased design. */\n designState: DesignState;\n /** The same state serialized for the server render path. */\n serverRequest: ServerRenderRequest;\n}\n\nexport interface EditorBuyProps {\n /** The final submit — the host's one line. Everything before it (variant,\n * quantity, completeness, payload assembly) is this part's job. */\n onAddToCart: (payload: EditorBuyPayload) => void | Promise<void>;\n /**\n * Seeds the Buy-owned quantity once on mount (integer ≥ 1; the store\n * defaults to 1). Live reads/writes go through `useProductSelection()` —\n * this is deliberately NOT a controlled prop, so two Buy parts under one\n * Root can never disagree about quantity.\n */\n defaultQuantity?: number;\n /** Button label. Defaults to \"Add to cart\". */\n children?: ReactNode;\n className?: string;\n style?: CSSProperties;\n}\n\n/** Pure completeness evaluation — exported for tests. @internal */\nexport function evaluateBuyCompleteness(input: {\n quantity: number;\n /** Required attribute keys still unselected (C1 — `option:<key>`). */\n missingOptionKeys: string[];\n /** Full-resolution validity of the selection (C1 — `variant`). */\n selectionValid: boolean;\n textFields: Array<{ name: string; optional: boolean }>;\n textOf: (name: string) => string | undefined;\n seedTextOf: (name: string) => string | undefined;\n hasRenderableElement: boolean;\n}): BuyMissingReason[] {\n const missing: BuyMissingReason[] = [];\n\n // C1 — full selection resolution (P2 amendment). Unselected axes first;\n // `variant` only for a complete selection that matches no combination.\n for (const key of input.missingOptionKeys) {\n missing.push(`option:${key}`);\n }\n if (input.missingOptionKeys.length === 0 && !input.selectionValid) {\n missing.push('variant');\n }\n\n // C2 + C3 — mounted required TextField layers.\n for (const field of input.textFields) {\n if (field.optional) continue;\n const value = (input.textOf(field.name) ?? '').trim();\n if (value.length === 0) {\n missing.push(`layer:${field.name}`);\n continue;\n }\n const seed = (input.seedTextOf(field.name) ?? '').trim();\n if (seed.length > 0 && value === seed) {\n missing.push(`layer-seed:${field.name}`);\n }\n }\n\n // C4 — something to print.\n if (!input.hasRenderableElement) {\n missing.push('empty-design');\n }\n\n // C5 — sane quantity.\n if (!Number.isInteger(input.quantity) || input.quantity < 1) {\n missing.push('quantity');\n }\n\n return missing;\n}\n\n/** Assemble the SDK cart detail from the commerce store's selection. */\nfunction buildCartDetail(product: RenderProduct, commerce: CommerceStateStore): CartDetail | null {\n const combinations = commerce.getCombinations();\n const attributes = commerce.getAttributes();\n if (Object.keys(attributes).length === 0 || combinations.length === 0) return null;\n\n // createCartDetail's selection math speaks label-string choices (the SDK\n // currency); the store hands out object choices — convert.\n const stringAttrs: Parameters<typeof createCartDetail>[0]['attributes'] = Object.fromEntries(\n Object.entries(attributes).map(([key, attr]) => [key, { ...attr, choices: choiceLabelsOf(attr) }]),\n );\n\n return createCartDetail({\n productId: product.productId,\n quantity: commerce.getQuantity(),\n selection: commerce.getSelection(),\n combinations: combinations as Parameters<typeof createCartDetail>[0]['combinations'],\n attributes: stringAttrs,\n });\n}\n\n/**\n * The add-to-cart button, completeness-gated and payload-assembling.\n *\n * Stable since ADR-0085 P4 (the default editor is rebuilt from this public\n * surface, CI-gated); additive-only from here.\n */\nexport function EditorBuy(props: EditorBuyProps): React.ReactElement {\n const { onAddToCart, defaultQuantity, children, className, style } = props;\n const internals = useEditorRootInternals('Editor.Buy');\n useRegisterEditorPart('Editor.Buy'); // census (`Editor.audit()`, #10)\n const { product, stateStore } = useEmbedContext();\n const commerce = internals.commerce;\n\n // Composition violation — not user state: throw into Root's boundary.\n if (!product?.productId) {\n throw new EditorError(\n 'E_BUY_NO_PRODUCT',\n '<Editor.Buy> has no product context — pass `product` (with `productId`) on ' +\n '<Editor.Root product={…}>. Buy assembles its cart payload from the Root product ' +\n 'and the live design state.',\n { docSlug: 'embed-mode' },\n );\n }\n\n // Seed the Buy-owned quantity once per mount (the prop is a seed, not a\n // controlled value — see the prop doc).\n const seededRef = useRef(false);\n useLayoutEffect(() => {\n if (seededRef.current) return;\n seededRef.current = true;\n if (typeof defaultQuantity === 'number') commerce.setQuantity(defaultQuantity);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [commerce]);\n\n // Subscribe narrowly: design state + commerce state + part registry.\n const stateVersion = useSyncExternalStore(stateStore.subscribe, stateStore.getState, stateStore.getState);\n const commerceVersion = useSyncExternalStore(commerce.subscribe, commerce.getVersion, commerce.getVersion);\n const registryVersion = useSyncExternalStore(\n internals.registry.subscribe,\n internals.registry.getVersion,\n internals.registry.getVersion,\n );\n\n const quantity = commerce.getQuantity();\n const missing = useMemo(\n () =>\n evaluateBuyCompleteness({\n quantity,\n missingOptionKeys: commerce.missingOptionKeys(),\n selectionValid: commerce.selectionValid(),\n textFields: internals.registry.getTextFields(),\n textOf: (name) => stateStore.textOf(name),\n seedTextOf: (name) => stateStore.seedTextOf(name),\n hasRenderableElement: stateStore.hasRenderableElement(),\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [commerce, quantity, stateVersion, commerceVersion, registryVersion],\n );\n const complete = missing.length === 0;\n\n // Double-click inert: the callback fires exactly once per click while\n // assembling/submitting (P2 test contract).\n const [busy, setBusy] = useState(false);\n const busyRef = useRef(false);\n\n const handleClick = useCallback(() => {\n if (busyRef.current || !complete) return;\n busyRef.current = true;\n setBusy(true);\n\n const designState = stateStore.getState();\n const variantId = commerce.resolvedVariantId();\n const payload: EditorBuyPayload = {\n productId: product.productId,\n ...(variantId ? { variantId } : {}),\n quantity: commerce.getQuantity(),\n selection: commerce.getSelection(),\n cartDetail: buildCartDetail(product, commerce),\n designState,\n // ADR-0101: one artboard per REQUIRED placement — linked placements\n // carry the base relabelled — so buy and preview are the same bytes\n // and the order pipeline never re-derives the link rule.\n serverRequest: expandRequestForPlacements(\n serializeStateForServer(designState),\n requiredPlacementLabels(product),\n ),\n };\n\n // Invoke synchronously (predictable for hosts and tests); only the\n // SETTLING of an async callback is awaited for the busy window.\n let result: void | Promise<void>;\n try {\n result = onAddToCart(payload);\n } catch (err) {\n busyRef.current = false;\n setBusy(false);\n throw err;\n }\n void Promise.resolve(result).finally(() => {\n busyRef.current = false;\n setBusy(false);\n });\n }, [complete, product, commerce, stateStore, onAddToCart]);\n\n return (\n <button\n type=\"button\"\n data-sc-part=\"buy\"\n data-sc-buy-state={busy ? 'busy' : complete ? 'ready' : 'incomplete'}\n data-sc-buy-missing={missing.join(',') || undefined}\n disabled={!complete || busy}\n aria-busy={busy || undefined}\n onClick={handleClick}\n className={className}\n style={style}\n >\n {children ?? 'Add to cart'}\n </button>\n );\n}\n","'use client';\n\n/**\n * `<Editor.Controls>` — the morphing contextual zone, ONE coarse part in v1\n * (ADR-0085 §5). Wraps the existing `ContextualToolbars` chrome:\n *\n * - `placement=\"docked\"` (default): the host-docked (class-1) contextual\n * zone, rendered exactly where the host mounts it — today's\n * `ContextualToolbars` embedded mode. Mounting a docked Controls\n * SUPPRESSES the canvas's built-in floating toolbar (one contextual zone\n * at a time), via the part registry.\n * - `placement=\"floating\"`: renders nothing in place and declares the\n * class-3 floating body-portal variant explicitly — the built-in floating\n * toolbar that `Editor.Canvas` mounts by default stays active.\n * - No `Editor.Controls` mounted at all: `Editor.Canvas` defaults to the\n * floating toolbar.\n *\n * Requires a mounted `Editor.Canvas` (`E_REQUIRES_CANVAS`, ADR-0085 §4): the\n * zone morphs on canvas selection; no selection exists without a canvas.\n *\n * The chrome itself statically imports the paint pipeline (panels, effects),\n * so the docked impl loads through a dynamic import — this module's static\n * graph stays renderer-free (import-graph gate), and in any valid\n * composition the renderer is already loading behind `Editor.Canvas`'s\n * boundary. A failed chrome chunk load routes to Root's error card with\n * retry (`E_CHUNK_LOAD_FAILED`), exactly like the canvas chunk.\n */\n\nimport React, { useEffect, useId, useLayoutEffect, useState, type CSSProperties } from 'react';\nimport { EditorError } from '../../errors/editorError.js';\nimport { useEditorRootInternals, useRegisterEditorPart, useRequiresCanvas } from './RootInternals.js';\n\ntype ControlsImpl = (typeof import('../ContextualToolbars.js'))['ContextualToolbars'];\n\nexport interface EditorControlsProps {\n /** Where the contextual zone lives (ADR-0085 §5). The host docks the part\n * by where it renders it — there is deliberately no \"bottom\"/\"top\" value. */\n placement?: 'docked' | 'floating';\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * The contextual controls zone.\n *\n * Stable since ADR-0085 P4 (the default editor is rebuilt from this public\n * surface, CI-gated); additive-only from here.\n */\nexport function EditorControls({\n placement = 'docked',\n className,\n style,\n}: EditorControlsProps): React.ReactElement | null {\n const internals = useEditorRootInternals('Editor.Controls');\n useRequiresCanvas('Editor.Controls');\n useRegisterEditorPart('Editor.Controls'); // census (`Editor.audit()`, #10)\n const instanceId = useId();\n\n // Registration is by THIS component's mount (layout effect, like every\n // part) — suppression of the built-in floating toolbar never races the\n // chrome chunk's arrival.\n useLayoutEffect(\n () => internals.registry.registerControls(instanceId, placement),\n [internals.registry, instanceId, placement],\n );\n\n const docked = placement === 'docked';\n const [Impl, setImpl] = useState<ControlsImpl | null>(null);\n useEffect(() => {\n if (!docked) return;\n let cancelled = false;\n import('../ContextualToolbars.js').then(\n (m) => {\n if (!cancelled) setImpl(() => m.ContextualToolbars);\n },\n (err) => {\n if (cancelled) return;\n internals.reportRuntimeError(\n new EditorError(\n 'E_CHUNK_LOAD_FAILED',\n `the editor's controls chunk failed to load (${err instanceof Error ? err.message : String(err)}). ` +\n 'This is a network/CDN failure, not a composition mistake — retry, or check the deployment ' +\n 'serves the @snowcone-app/canvas lazy chunks.',\n { cause: err instanceof Error ? err.message : String(err), docSlug: 'embed-mode' },\n ),\n );\n },\n );\n return () => {\n cancelled = true;\n };\n }, [docked, internals]);\n\n if (!docked) {\n // The floating variant is the canvas's built-in body portal (class-3) —\n // this part only declares it; there is nothing to render in place.\n return null;\n }\n\n return (\n <div\n data-sc-part=\"controls\"\n data-sc-placement=\"docked\"\n className={className}\n style={style}\n aria-busy={Impl ? undefined : 'true'}\n >\n {Impl ? <Impl mode=\"embedded\" /> : null}\n </div>\n );\n}\n","'use client';\n\n/**\n * `<Editor.LoadingOverlay>` — the standalone render-in-flight rainbow for\n * HOST-OWNED preview surfaces: custom mockup panels built on\n * `useRealtimeMockups`, or an `<Editor.Preview loadingOverlay=\"host-owned\">`\n * whose host wants the house loader somewhere else in its own DOM.\n *\n * Mount it inside any `position: relative` container; it fills the container\n * (`.sc-loading-overlay-host`, absolute inset-0, pointer-events none) and\n * paints the same prism choreography `Editor.Preview` runs by default —\n * 200ms show-delay (instant renders never flash it), 400ms post-render\n * linger, fade-out — whenever this Root's session has a render in flight.\n *\n * Requires `<Editor.Root>` (throws `E_OUTSIDE_ROOT` otherwise). Does NOT\n * require `Editor.Canvas` — it rides the session, not the editor.\n */\n\nimport React, { type CSSProperties } from 'react';\nimport { useEmbedContext } from '../embed-realtime/context.js';\nimport { PreviewPrismOverlay, useRenderLoadingOverlay } from './PreviewPrismOverlay.js';\n\nexport interface EditorLoadingOverlayProps {\n /** \"dark\" (default): screen-blended neon bands for image/dark surfaces.\n * \"light\": multiply-blended candy bands for light cards. */\n variant?: 'dark' | 'light';\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * Stable since ADR-0085 P4 (additive); part name: `loading-overlay`.\n */\nexport function EditorLoadingOverlay({\n variant = 'dark',\n className,\n style,\n}: EditorLoadingOverlayProps): React.ReactElement | null {\n const { isRendering } = useEmbedContext();\n const { showOverlay, overlayVisible, handleExited } = useRenderLoadingOverlay(isRendering);\n\n if (!showOverlay) return null;\n return (\n <div\n data-sc-part=\"loading-overlay\"\n className={`sc-loading-overlay-host${className ? ` ${className}` : ''}`}\n style={style}\n aria-hidden=\"true\"\n >\n <PreviewPrismOverlay visible={overlayVisible} variant={variant} onExited={handleExited} />\n </div>\n );\n}\n","'use client';\n\n/**\n * `useProductSelection()` — the host's window into `Editor.Buy`'s commerce\n * state (ADR-0085 §2, P2: Buy-owned variant + quantity).\n *\n * The DIVISION OF LABOR (the rendering contract): the HOST renders the\n * variant-selection UI — swatches, dropdowns, steppers, its brand — and this\n * hook supplies the state + transitions. `Editor.Buy` owns that state: it\n * gates completeness on it (C1/C5) and assembles the cart payload from it.\n * Neither side ever touches Root props for selection, so picking a color\n * costs one live config message + one render — never a session re-key.\n *\n * ```tsx\n * function VariantPicker() {\n * const { attributes, selection, select, disabledChoices } = useProductSelection();\n * // choices are ALWAYS `{ label, hex? }` objects; the label STRING is the\n * // currency for select()/selection/disabledChoices.\n * return Object.entries(attributes).map(([key, attr]) => (\n * <div key={key}>\n * {attr.choices.map(({ label = '', hex }) => (\n * <button\n * key={label}\n * style={hex ? { background: hex } : undefined}\n * disabled={disabledChoices[key]?.includes(label)}\n * aria-pressed={selection[key] === label}\n * onClick={() => select(key, label)}\n * >\n * {label}\n * </button>\n * ))}\n * </div>\n * ));\n * }\n * ```\n *\n * Mount it anywhere under the same `<Editor.Root>` (outside one throws\n * `E_OUTSIDE_ROOT`). `select()` with an unknown key/choice throws structured\n * `E_UNKNOWN_OPTION` listing the valid ones (D4/E3 — wiring mistakes are\n * loud, not silently ignored).\n */\n\nimport { useCallback, useMemo, useSyncExternalStore } from 'react';\nimport type { OptionSelection } from '@snowcone-app/sdk';\nimport type { ProductSelectionAttribute } from './commerceStore.js';\nimport { useEditorRootInternals } from './RootInternals.js';\n\nexport interface ProductSelectionApi {\n /** The product's variant attributes (normalized catalog `options.attributes`).\n * Choices are ALWAYS `{ label, hex?, … }` OBJECTS — render `choice.label`,\n * use `hex` for color swatches. Empty object for an option-less product. */\n attributes: Record<string, ProductSelectionAttribute>;\n /** Current choices BY LABEL STRING, e.g. `{ Color: 'Black', Size: 'M' }` —\n * the label is the currency everywhere selection is read or written.\n * Seeded from the Root product's `variantId` combination when present. */\n selection: OptionSelection;\n /** Select a choice by its LABEL string (`select('Color', choice.label)`).\n * Unknown key/choice → throws `E_UNKNOWN_OPTION` listing the valid ones. */\n select: (key: string, choice: string) => void;\n /** Choice LABELS invalid given the rest of the selection — disable these. */\n disabledChoices: Record<string, string[]>;\n /** The variant (gvid) the selection resolves to; `undefined` while\n * incomplete/invalid. This is what renders and what Buy submits. */\n variantId: string | undefined;\n /** Resolved combination's price, when the catalog carries one. */\n price: number | undefined;\n /** Buy-owned quantity (completeness rule C5 gates on it). */\n quantity: number;\n /** Set the Buy-owned quantity. Values that are not integers ≥ 1 are stored\n * as-is and GATE Buy with the `quantity` reason code (user state, never a\n * throw) — clamp in your stepper if you never want that state. */\n setQuantity: (quantity: number) => void;\n /** True when every required attribute is selected and the combination is\n * valid — the C1 component of Buy's completeness. */\n complete: boolean;\n /** Required attribute keys still unselected (Buy's `option:<key>` codes). */\n missing: string[];\n}\n\n/**\n * Read/write the Buy-owned product selection under this `Editor.Root`.\n *\n * Stable since ADR-0085 P4 (the default editor is rebuilt from this public\n * surface, CI-gated); additive-only from here.\n */\nexport function useProductSelection(): ProductSelectionApi {\n const internals = useEditorRootInternals('useProductSelection');\n const commerce = internals.commerce;\n\n const version = useSyncExternalStore(commerce.subscribe, commerce.getVersion, commerce.getVersion);\n\n const select = useCallback((key: string, choice: string) => commerce.select(key, choice), [commerce]);\n const setQuantity = useCallback((quantity: number) => commerce.setQuantity(quantity), [commerce]);\n\n return useMemo<ProductSelectionApi>(\n () => ({\n attributes: commerce.getAttributes(),\n selection: commerce.getSelection(),\n select,\n disabledChoices: commerce.disabledChoices(),\n variantId: commerce.resolvedVariantId(),\n price: commerce.resolvedPrice(),\n quantity: commerce.getQuantity(),\n setQuantity,\n complete: commerce.selectionValid(),\n missing: commerce.missingOptionKeys(),\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [commerce, select, setQuantity, version],\n );\n}\n","'use client';\n\n/**\n * `Editor.*` — composable editor primitives over one `Editor.Root`\n * (ADR-0085). Parts carry behavior + state subscription; the HOST owns all\n * layout (with the documented exception of the canvas's selection-anchored\n * overlays — anchoring contract, ADR-0085 §5).\n *\n * ```tsx\n * import { Editor, design } from '@snowcone-app/canvas/embed';\n *\n * const d = design({ name: 'Front', width: 1480, height: 2328 })\n * .background(artUrl, { aspectRatio: 1480 / 2328, name: 'art' })\n * .text('YOUR NAME', { anchor: 'top', name: 'headline' });\n *\n * // No-canvas personalization widget — the rendering engine never loads:\n * <Editor.Root shop={SHOP_KEY} product={product} design={d} grantUrl=\"/api/grant\">\n * <Editor.Preview />\n * <Editor.TextField layer={d.layer('headline')} placeholder=\"Your name\" />\n * <Editor.Buy onAddToCart={({ designState }) => persist(designState)} />\n * </Editor.Root>\n *\n * // Full editor — same surface, plus the lazy canvas:\n * <Editor.Root shop={SHOP_KEY} product={product} design={d} grantUrl=\"/api/grant\">\n * <Editor.Canvas />\n * <Editor.Preview />\n * <Editor.Buy onAddToCart={…} />\n * </Editor.Root>\n * ```\n *\n * Stable since the ADR-0085 P4 gate passed: the default editor\n * (`SnowconeEditor`) is rebuilt from exactly these parts, CI-enforced, so the\n * surface is additive-only from here.\n */\n\nimport { EditorRoot } from './EditorRoot.js';\nimport { EditorCanvas } from './EditorCanvas.js';\nimport { EditorPlacements } from './EditorPlacements.js';\nimport { EditorPreview } from './EditorPreview.js';\nimport { EditorTextField } from './EditorTextField.js';\nimport { EditorBuy } from './EditorBuy.js';\nimport { EditorLayers } from './EditorLayers.js';\nimport { EditorControls } from './EditorControls.js';\nimport { EditorHistory } from './EditorHistory.js';\nimport { EditorMenu } from './EditorMenu.js';\nimport { EditorAdd } from './EditorAdd.js';\nimport { EditorLoadingOverlay } from './EditorLoadingOverlay.js';\n\nexport const Editor = {\n /** The one provider boundary — session, design, live state, error boundary. */\n Root: EditorRoot,\n /** The editable artboard (the ONE lazy renderer boundary — D9). */\n Canvas: EditorCanvas,\n /** Live product mockup. ×N under one Root is valid. */\n Preview: EditorPreview,\n /** Placement switcher tabs (ADR-0088). Renders nothing for a\n * single-placement design; headless floor = usePlacements(). */\n Placements: EditorPlacements,\n /** Form input bound to a design text layer by typed token (T1). */\n TextField: EditorTextField,\n /** Smart commerce part: completeness + payload assembly; submit = host callback. */\n Buy: EditorBuy,\n /** Layer list. The one editor part that works canvas-free (ADR-0085 §4). */\n Layers: EditorLayers,\n /** Morphing contextual zone — ONE coarse part; placement docked|floating (§5). */\n Controls: EditorControls,\n /** Undo/redo controls. Requires Editor.Canvas. */\n History: EditorHistory,\n /** The one ⋯ overflow menu. Requires Editor.Canvas. */\n Menu: EditorMenu,\n /** The ⊕ add-element menu. Requires Editor.Canvas. */\n Add: EditorAdd,\n /** Standalone render-in-flight rainbow for host-owned preview surfaces.\n * Fills its positioned parent; rides the session (canvas-free). */\n LoadingOverlay: EditorLoadingOverlay,\n} as const;\n\nexport type { EditorRootProps, EditorRootBaseProps, GrantSource } from './EditorRoot.js';\nexport type { EditorCanvasProps } from './EditorCanvas.js';\nexport type { EditorPlacementsProps, EditorPlacementsLabels } from './EditorPlacements.js';\nexport { usePlacements } from './usePlacements.js';\nexport type { PlacementInfo, UsePlacementsReturn } from './usePlacements.js';\n// ADR-0101 linked placements — the ONE resolution rule (base + overrides),\n// exported so hosts/agents can assert what the render push and Buy send.\nexport { resolvePlacementLinks, expandRequestForPlacements } from './placementLinks.js';\nexport type { PlacementLinkInfo } from './placementLinks.js';\nexport type { EditorPreviewProps } from './EditorPreview.js';\nexport type { EditorLoadingOverlayProps } from './EditorLoadingOverlay.js';\nexport type { EditorTextFieldProps } from './EditorTextField.js';\nexport type { EditorBuyProps, EditorBuyPayload, BuyMissingReason } from './EditorBuy.js';\nexport type { DesignState } from './designStateStore.js';\nexport { DesignStateStore } from './designStateStore.js';\n// Buy-owned commerce state (ADR-0085 §2, P2) — the host's variant-UI hook.\nexport { useProductSelection } from './useProductSelection.js';\nexport type { ProductSelectionApi } from './useProductSelection.js';\nexport { CommerceStateStore } from './commerceStore.js';\nexport type { ProductOptionChoice, ProductSelectionAttribute } from './commerceStore.js';\n// Composition audit (`Editor.audit()`, agentic-DX #10) — the imperative dev\n// helper; the once-at-mount channel is `<Editor.Root onAudit>`.\nexport { auditEditor } from './editorAudit.js';\nexport type { EditorAuditReport, EditorAuditFinding, EditorAuditFindingCode } from './editorAudit.js';\nexport type { EditorLayersProps } from './EditorLayers.js';\nexport type { EditorControlsProps } from './EditorControls.js';\nexport type { EditorHistoryProps } from './EditorHistory.js';\nexport type { EditorMenuProps } from './EditorMenu.js';\nexport type { EditorAddProps } from './EditorAdd.js';\n","'use client';\n\n/**\n * `<RealtimeEmbed>` — the legacy turnkey wrapper around `<Editor.Root>`.\n *\n * Everything it used to own (the single RenderSession, the design seed, the\n * live mockups, the context) was EXTRACTED into `EditorRoot` (ADR-0085 / D5 —\n * extraction, not copy): this component is `<EditorRoot>` plus the legacy\n * advisory validation mode (dev-only `console.error` diagnostics instead of\n * `Editor.Root`'s throw-on-misconfiguration, F3). The existing realtime\n * surface — `<RealtimeCanvas>`, `<RealtimeMockup>`, `useRealtimeMockups` —\n * reads the same context `EditorRoot` provides, so nothing existing changes\n * meaning, and the existing realtime tests exercise the new Root.\n *\n * @example\n * ```tsx\n * const d = design({ name: 'Front', width: 1480, height: 2328 })\n * .background(artUrl, { aspectRatio: 1480 / 2328, name: 'art' })\n * .text('YOUR NAME', { anchor: 'top', name: 'headline' });\n *\n * <RealtimeEmbed\n * shop=\"YOUR_SHOP_ID\"\n * grantUrl=\"/api/realtime/grant\"\n * // variantId is REQUIRED for a product with a color/variant axis (a frame or\n * // garment colour) — omit it and the render hangs. Pass `options` too so a\n * // wrong/missing variantId fails fast instead of timing out. Read both from\n * // getProduct(productId) (its options.combinations[].variantId).\n * product={{ productId: 'BC43BE', mockupIds: ['947QAD'], variantId: 'e92f40', placements: ['Front'] }}\n * design={d}\n * >\n * <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr' }}>\n * <RealtimeCanvas /> {/* editor *\\/}\n * <RealtimeMockup /> {/* live preview *\\/}\n * </div>\n * </RealtimeEmbed>\n * ```\n */\n\nimport React from 'react';\nimport {\n EditorRoot,\n type EditorRootBaseProps,\n type EditorRootProps,\n type GrantSource,\n} from '../editor/EditorRoot.js';\n\n// Re-exported from the extraction home so existing imports keep working.\nexport { SLOW_RENDER_HINT_MS, slowRenderHint } from '../editor/EditorRoot.js';\nexport type { GrantSource };\n\n// Omit only from the non-union half — Omit over the GrantSource union would\n// collapse the exactly-one-of grant/grantUrl discrimination.\nexport type RealtimeEmbedProps = GrantSource & Omit<EditorRootBaseProps, '__validation'>;\n\nexport function RealtimeEmbed(props: RealtimeEmbedProps): React.ReactElement {\n return <EditorRoot {...(props as EditorRootProps)} __validation=\"warn\" />;\n}\n","'use client';\n\n/**\n * `<RealtimeCanvas>` — the interactive editor half of a realtime embed\n * (legacy turnkey API; `Editor.Canvas` is the primitives-era equivalent).\n *\n * Mounts a `<SnowconeCanvas>` seeded from the embed's `design`, and forwards\n * every edit to the shared RenderSession as a server render. All the\n * load-bearing wiring an embedder used to copy by hand is internal: the\n * `sc-root` class, `inheritTheme`, edit→`serializeStateForServer`→\n * `renderState`, and the artboard/placement match.\n *\n * Since ADR-0085 (D9) the implementation lives in the shared lazy renderer\n * chunk ({@link EditorCanvasImpl}) behind a dynamic import — the embed\n * entry's static import graph stays renderer-free, so a no-canvas\n * composition never downloads the rendering engine. The canvas therefore\n * mounts one micro-beat after first paint (a chunk fetch on cold cache); the\n * forwarded ref attaches when it does.\n *\n * Defaults to the chrome-less `kit=\"embed-only\"` — bring your own controls as\n * `children` (they render as an overlay INSIDE the canvas's editor context, so\n * `useTextBinding(name)` / `useImageBinding(name)` resolve against the live\n * elements). For a full in-canvas editor pass `kit=\"compact-customizer\"` or\n * `kit=\"pro-studio\"`.\n *\n * Must be rendered inside `<RealtimeEmbed>` (or any `EmbedContext` provider).\n */\n\nimport React, { forwardRef, useEffect, useState, type CSSProperties, type ReactNode } from 'react';\nimport type { CanvasState, SnowconeCanvasHandle } from '../embed/SnowconeCanvas.js';\nimport type { KitPresetId, KitDefinition } from '../../kits/types.js';\nimport type { CanvasServices } from '../../contexts/CanvasServicesContext.js';\nimport { loadCanvasImpl } from '../editor/EditorCanvas.js';\n\nexport interface RealtimeCanvasProps {\n /** Your controls (toolbar, inputs). Rendered as an overlay inside the editor\n * context so binding hooks work. */\n children?: ReactNode;\n /**\n * Editor chrome to mount. The default `'embed-only'` is a chrome-less canvas —\n * the host supplies every control as `children` (text inputs, image swap)\n * through `useTextBinding` / `useImageBinding`. That's the right call for a\n * fill-in-the-blanks personalizer, but it gives the shopper NO way to select a\n * layer and change its font size, add an element, or reorder layers.\n *\n * To ship a real editor through the turnkey realtime path, pass a richer\n * preset — `'compact-customizer'` (a trimmed toolbar) or `'pro-studio'` (full\n * panels). Every edit still flows to the shared RenderSession as a\n * server render automatically; you get add-element / font-size / layers for\n * free without ejecting to a raw `SnowconeCanvas` + `RenderSession`.\n *\n * Pair a chrome'd kit with `children` only when your overlay adds to — not\n * duplicates — the kit's controls, or you'll get double chrome.\n *\n * @default 'embed-only'\n */\n kit?: KitPresetId | KitDefinition;\n /** Inherit the host app's theme instead of managing its own (default true). */\n inheritTheme?: boolean;\n /** Cap the canvas height in px. */\n maxHeight?: number;\n /**\n * Privileged-service wiring for the editor chrome (Image Browser search /\n * AI tabs). Usually set once on `<RealtimeEmbed services={…}>` and inherited;\n * pass it here only to override for this canvas. Host the URLs on your\n * server — your vendor keys live there.\n */\n services?: CanvasServices;\n /**\n * Observe the live design state. Fires with the full {@link CanvasState}\n * (elements stamped with their artboard name) whenever the canvas content\n * changes — including once after the initial seed loads — in addition to the\n * embed's internal edit→server-render flow, which is unaffected. This is the\n * state you persist at add-to-cart / checkout so the purchased design can be\n * re-rendered server-side later.\n *\n * Safe to pass inline: the underlying canvas reads the callback from a ref,\n * so a new identity each render never re-fires or loops.\n */\n onChange?: (state: CanvasState) => void;\n className?: string;\n style?: CSSProperties;\n}\n\ntype ImplComponent = Awaited<ReturnType<typeof loadCanvasImpl>>;\n\n/**\n * Note the export naming wart, kept for backwards compatibility:\n * - The ref handle's {@link SnowconeCanvasHandle.exportArtboards} resolves a\n * record keyed by artboard **name** (e.g. `'Front'`) — names match the\n * `placements` you configured on the embed.\n * - The lower-level `useExport().exportArtboard(id)` hook takes an artboard\n * **ID** (get one from `useArtboards()`).\n * For print-res exports at checkout, the ref handle is the intended path:\n * `ref.current.exportArtboards({ all: true, scale: 4, format: 'blob' })`.\n */\nexport const RealtimeCanvas = forwardRef<SnowconeCanvasHandle, RealtimeCanvasProps>(\n function RealtimeCanvas(props: RealtimeCanvasProps, ref): React.ReactElement {\n const { children, className, style, maxHeight, ...rest } = props;\n\n const [Impl, setImpl] = useState<ImplComponent | null>(null);\n useEffect(() => {\n let cancelled = false;\n loadCanvasImpl().then(\n (component) => {\n if (!cancelled) setImpl(() => component);\n },\n (err) => {\n // Legacy surface keeps the advisory console contract (no Root\n // boundary is guaranteed to exist here).\n console.error('[RealtimeCanvas] failed to load the rendering chunk:', err);\n },\n );\n return () => {\n cancelled = true;\n };\n }, []);\n\n if (!Impl) {\n return (\n <div\n className={`sc-root${className ? ` ${className}` : ''}`}\n style={{ minHeight: maxHeight ?? 200, ...style }}\n aria-busy=\"true\"\n />\n );\n }\n\n return (\n <Impl ref={ref} selfScope maxHeight={maxHeight} className={className} style={style} {...rest}>\n {children}\n </Impl>\n );\n },\n);\n","'use client';\n\n/**\n * `<RealtimeMockup>` — the live preview half of a realtime embed (legacy\n * turnkey API). The implementation was EXTRACTED to `Editor.Preview`\n * (ADR-0085 / D5); this wrapper keeps the original name and props. (The\n * rendered `<img>` now carries `data-sc-part=\"preview\"` — additive only.)\n *\n * Because it shares one session with the rest of the embed, the preview can\n * never desync from the editor and needs no wiring of its own. Place it\n * anywhere inside `<RealtimeEmbed>`.\n */\n\nimport React from 'react';\nimport { EditorPreview, type EditorPreviewProps } from '../editor/EditorPreview.js';\n\n// Re-exported from the extraction home so existing imports keep working.\nexport {\n RESOLUTION_MISMATCH_RATIO,\n resolutionMismatchHint,\n suggestRenderWidth,\n} from '../editor/EditorPreview.js';\n\nexport type RealtimeMockupProps = EditorPreviewProps;\n\nexport function RealtimeMockup(props: RealtimeMockupProps): React.ReactElement {\n return <EditorPreview {...props} />;\n}\n","'use client';\n\nimport type { MockupResult } from '@snowcone-app/sdk';\nimport { useEmbedContext } from './context.js';\n\nexport interface UseRealtimeMockupsResult {\n /** All mockups from the latest render (one per requested mockupId). */\n mockups: MockupResult[];\n /** True between a render dispatch and the next mockup / error. */\n isRendering: boolean;\n /** Last render/timeout error message, or null. */\n error: string | null;\n}\n\n/**\n * Read the live mockups for a custom preview UI. Reactive: re-renders when new\n * mockups arrive. Must be called inside `<RealtimeEmbed>`.\n *\n * For the common case (just show the rendered image) use `<RealtimeMockup>`\n * instead — this hook is for building your own gallery / loading treatment.\n */\nexport function useRealtimeMockups(): UseRealtimeMockupsResult {\n const { mockups, isRendering, error } = useEmbedContext();\n return { mockups, isRendering, error };\n}\n","/**\n * `productToRenderConfig` — the one-call adapter from a catalog payload\n * (`getProduct()` / Meilisearch document) to everything `Editor.Root` and the\n * `design()` seed need.\n *\n * This logic used to live in every host as ~100 lines of tribal knowledge,\n * and each rule has a silent failure mode when hand-rolled wrong:\n *\n * - a COLOR axis (any option choice carrying `hex`) is the one variant kind\n * that gates rendering — it requires a `variantId` (the server auto-fills\n * the color placement from it); non-color axes render on the default\n * variant. Forget it → ~30s render hang.\n * - mockup scenes can be split across variants: a scene whose `gvids` don't\n * include the rendered variant composites NO artwork. Prefer scenes that\n * photograph the variant being rendered. Pick wrong → blank product photo.\n * - only `type !== \"color\"` placements with real width/height are editable\n * artboards. Seed against a color placement → blank mockup.\n *\n * Every advisory field is passed through (`options`, `placements`, `mockups`,\n * `requiredPlacements`, `defaultGvid`) so `Editor.Root`'s fail-fast contracts\n * stay armed. Unrenderable input throws a structured\n * `EditorError('E_PRODUCT_NOT_RENDERABLE')` — loud, typed, agent-visible —\n * never a null for the host to forget to check.\n */\n\nimport type { CatalogProduct, RenderProduct } from '@snowcone-app/sdk';\nimport { EditorError } from '../errors/editorError.js';\nimport { isBundleProduct } from './bundle-config.js';\n\nexport interface ProductRenderConfigOptions {\n /** Placement label to edit (e.g. \"Back\"). Defaults to the product's first\n * renderable image placement. Unknown labels throw with `validNames`. */\n placement?: string;\n /** Render width passthrough (`product.width`) — bump to ~2000 for a crisp\n * full-bleed preview. `Editor.Preview` hints in dev when it's too low. */\n width?: number;\n}\n\nexport interface ProductRenderConfig {\n /** Ready for `<Editor.Root product={…}>` — advisory fields included so\n * wiring mistakes fail loud at mount. */\n product: RenderProduct;\n /** The placement being edited — seed `design({ name: label, width, height })`\n * from exactly these values. */\n placement: {\n label: string;\n /** Artboard pixel dimensions (the placement's print-file geometry). */\n width: number;\n height: number;\n /** width / height — for sizing the host's canvas stage. */\n aspectRatio: number;\n };\n /** Every editable (non-color) placement label — placement pickers. */\n placementLabels: string[];\n /** Geometry of EVERY renderable image placement, in catalog order — seed a\n * multi-placement design mechanically (ADR-0088):\n * `config.placements.reduce((d, p) => d.artboard(p.label, p), …)`. The\n * entry matching `placement` is the same object shape. */\n placements: Array<{ label: string; width: number; height: number; aspectRatio: number }>;\n /** First mockup scene that photographs the rendered variant — the default\n * `<Editor.Preview mockupId>`. */\n primaryMockupId: string;\n /** The variant the config renders against (`undefined` when no color axis\n * gates rendering). Already set on `product`. */\n variantId: string | undefined;\n}\n\ntype CatalogPlacement = NonNullable<CatalogProduct['placements']>[number];\n\nfunction isRenderablePlacement(p: CatalogPlacement): p is CatalogPlacement & { width: number; height: number } {\n return p.type !== 'color' && typeof p.width === 'number' && p.width > 0 && typeof p.height === 'number' && p.height > 0;\n}\n\n/**\n * Derive the full embed wiring from one `getProduct()` payload.\n *\n * ```ts\n * const config = productToRenderConfig(await getProduct('BC43BE'));\n * const seed = design({ name: config.placement.label, ...config.placement })\n * .text('hello', { anchor: 'center', name: 'headline' });\n *\n * <Editor.Root shop={SHOP} product={config.product} design={seed} grantUrl=\"/api/realtime-grant\">\n * ```\n *\n * @throws EditorError `E_PRODUCT_NOT_RENDERABLE` when the product has no\n * renderable image placement, no mockup scenes, or `options.placement`\n * names a placement that doesn't exist (`data.validNames` lists the real ones).\n * @throws EditorError `E_BUNDLE_CONFIG_REQUIRED` when the product is a BUNDLE\n * (ADR-0099: a `bundle` block) — it has no single variantId and role-scoped\n * placements, so this adapter cannot describe it; use `bundleToRenderConfig()`.\n */\nexport function productToRenderConfig(\n catalogProduct: CatalogProduct,\n options: ProductRenderConfigOptions = {},\n): ProductRenderConfig {\n // A bundle is a different shape (per-role variants, role-scoped placement\n // keys). Building the single-product config from it would send a bare\n // variantId and bare labels the server refuses — or, with no color axis,\n // open a session that renders nothing. Refuse up front, naming the fix.\n if (isBundleProduct(catalogProduct)) {\n throw new EditorError(\n 'E_BUNDLE_CONFIG_REQUIRED',\n `product ${catalogProduct.id} is a bundle (roles: [${catalogProduct.bundle.members.map((m) => m.role).join(', ')}]) — ` +\n 'it has per-role variants and role-scoped placement keys, which the single-product config cannot ' +\n 'describe. Use bundleToRenderConfig(product, { picks?, variants?, placement?, width? }) instead.',\n {\n productId: catalogProduct.id,\n validNames: catalogProduct.bundle.members.map((m) => m.role),\n docSlug: 'bundles',\n },\n );\n }\n\n const renderable = (catalogProduct.placements ?? []).filter(isRenderablePlacement);\n const renderableLabels = renderable.map((p) => p.label);\n\n const placement = options.placement\n ? renderable.find((p) => p.label === options.placement)\n : renderable[0];\n if (!placement) {\n if (options.placement) {\n throw new EditorError(\n 'E_PRODUCT_NOT_RENDERABLE',\n `product ${catalogProduct.id} has no renderable placement \"${options.placement}\". ` +\n `Renderable image placements: [${renderableLabels.join(', ')}].`,\n { productId: catalogProduct.id, requested: options.placement, validNames: renderableLabels, docSlug: 'embed-mode' },\n );\n }\n throw new EditorError(\n 'E_PRODUCT_NOT_RENDERABLE',\n `product ${catalogProduct.id} has no renderable image placement (a non-color ` +\n 'placement with width/height). The catalog payload may be incomplete — fetch it ' +\n 'via getProduct(), not a search hit.',\n { productId: catalogProduct.id, docSlug: 'embed-mode' },\n );\n }\n\n // A COLOR axis (choices carrying `hex`) is the one variant kind that gates\n // rendering — it REQUIRES a variantId. Non-color axes render on the default\n // variant. (A color axis with no resolvable variantId is left undefined here\n // so Editor.Root's mount validation reports it as the wiring error it is.)\n const attributes = catalogProduct.options?.attributes ?? {};\n const hasColorAxis = Object.values(attributes).some((attr) =>\n attr?.choices?.some((choice) => choice?.hex),\n );\n const variantId = hasColorAxis\n ? catalogProduct.options?.combinations?.find(\n (combo) => typeof combo.variantId === 'string' && combo.variantId !== '',\n )?.variantId as string | undefined\n : undefined;\n\n // Scenes can be split across variants — a mockup whose `gvids` don't include\n // the rendered variant composites NO artwork. Prefer scenes that photograph\n // the variant we render; fall back to all scenes when none match (stale gvid\n // data beats an empty embed).\n const mockups = catalogProduct.mockups ?? [];\n const scoped = variantId ? mockups.filter((m) => m.gvids?.includes(variantId)) : mockups;\n const mockupIds = (scoped.length > 0 ? scoped : mockups).map((m) => m.id);\n if (mockupIds.length === 0) {\n throw new EditorError(\n 'E_PRODUCT_NOT_RENDERABLE',\n `product ${catalogProduct.id} has no mockup scenes — nothing to render a preview into.`,\n { productId: catalogProduct.id, docSlug: 'embed-mode' },\n );\n }\n\n const product: RenderProduct = {\n productId: catalogProduct.id,\n mockupIds,\n ...(typeof variantId === 'string' ? { variantId } : {}),\n options: catalogProduct.options,\n placements: catalogProduct.placements?.map((p) => p.label),\n mockups,\n requiredPlacements: catalogProduct.requiredPlacements,\n ...(catalogProduct.defaultGvid ? { defaultGvid: catalogProduct.defaultGvid } : {}),\n ...(typeof options.width === 'number' ? { width: options.width } : {}),\n };\n\n return {\n product,\n placement: {\n label: placement.label,\n width: placement.width,\n height: placement.height,\n aspectRatio: placement.width / placement.height,\n },\n placementLabels: renderableLabels,\n placements: renderable.map((p) => ({\n label: p.label,\n width: p.width,\n height: p.height,\n aspectRatio: p.width / p.height,\n })),\n primaryMockupId: mockupIds[0],\n variantId,\n };\n}\n","'use client';\n\n/**\n * `<SnowconeEditor>` — the turnkey default editor, REBUILT FROM THE PUBLIC\n * PARTS (ADR-0085, P4). Visual spec: `canvas-default-chrome-new-v1`\n * (`/design-system/page/canvas-default-chrome-new-v1` in apps/www) — the\n * PDP-editor grammar: calm surface, an \"Editor\" header (undo/redo · ⋯ ·\n * Buy-instead-of-Done), nothing floating over the artwork, a morphing\n * control zone BELOW the stage, and the buyable 2:3 mockup in a PiP that\n * swaps with the stage.\n *\n * THE LOAD-BEARING CONSTRAINT: this module imports ONLY the public embed\n * entry (`../api/embed.js` — the same surface a host gets from\n * `@snowcone-app/canvas/embed`) plus react. No `../` imports into internals,\n * mechanically gated (publicSurfaceGate test + verify typecheck). The day\n * this default needs a private API, the primitives are wrong — restyling to\n * a future chrome (e.g. the v2 bar-less mock) must be a composition tweak.\n *\n * PART COMPOSITION MAP (the plan's inline-diagram home for P4):\n *\n * SnowconeEditor\n * └── Editor.Root session · design · stores · boundary\n * └── frame (embed card ⇄ fullscreen takeover — same chrome, only the\n * │ frame changes; both directions live in the ⋯ menu)\n * ├── header\n * │ ├── \"Editor\" title\n * │ ├── Editor.History undo/redo\n * │ ├── ⋯ menu (own DOM) fullscreen · view switch · export PNG\n * │ │ (export via the Editor.Canvas ref\n * │ │ handle — runtime, not a static import)\n * │ └── Editor.Buy \"Add to cart · $price\" pill\n * │ └── useProductSelection() price + completeness\n * ├── stage\n * │ ├── Editor.Canvas the editable artboard (center)\n * │ └── Editor.Preview buyable mockup PiP (top-right,\n * │ tap to swap with the stage)\n * └── control zone (morphs below the stage; nothing floats)\n * ├── selected → Editor.Controls placement=\"docked\"\n * │ (registering docked Controls suppresses the\n * │ canvas's built-in floating toolbar — §5)\n * └── idle → Editor.Add ⊕ + layer thumbnails\n * (useLayers(): previews + select — public\n * headless floor, no private API)\n *\n * Stable since ADR-0085 P4 (this component IS the gate artifact — composed\n * only from the public embed entry); additive-only from here.\n */\n\nimport React, {\n useCallback,\n useEffect,\n useRef,\n useState,\n type CSSProperties,\n} from 'react';\nimport {\n Editor,\n useProductSelection,\n useSelectedElement,\n useLayers,\n type EditorRootBaseProps,\n type EditorBuyPayload,\n type GrantSource,\n type SnowconeCanvasHandle,\n} from '../api/embed.js';\n\nexport type SnowconeEditorProps = GrantSource &\n Omit<EditorRootBaseProps, 'children' | '__validation'> & {\n /** The final submit — your one line. Variant/quantity/completeness and\n * payload assembly are `Editor.Buy`'s job. */\n onAddToCart: (payload: EditorBuyPayload) => void | Promise<void>;\n /** Seeds the Buy-owned quantity once on mount (default 1). */\n defaultQuantity?: number;\n /** Header title. Default \"Editor\". */\n title?: string;\n /** Embedded-card height (px or CSS length). Fullscreen ignores it. */\n height?: number | string;\n className?: string;\n style?: CSSProperties;\n };\n\n/** Price label for the Buy pill — catalog prices are cents. Whole dollars\n * render without cents (\"$24\"), like the PDP. */\nexport function formatBuyPrice(cents: number): string {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: 'USD',\n minimumFractionDigits: cents % 100 === 0 ? 0 : 2,\n maximumFractionDigits: cents % 100 === 0 ? 0 : 2,\n }).format(cents / 100);\n}\n\n// ── Shared inline styles (themed via .sc-root tokens, like every part) ──────\n\nconst iconButtonStyle: CSSProperties = {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 32,\n height: 32,\n padding: 0,\n borderRadius: 9999,\n border: 'none',\n background: 'transparent',\n color: 'var(--sc-color-foreground, #111)',\n font: 'inherit',\n fontSize: 16,\n lineHeight: 1,\n cursor: 'pointer',\n};\n\nconst menuItemStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n width: '100%',\n padding: '8px 10px',\n borderRadius: 8,\n border: 'none',\n background: 'transparent',\n color: 'inherit',\n font: 'inherit',\n fontSize: 12,\n fontWeight: 500,\n textAlign: 'left',\n cursor: 'pointer',\n};\n\nfunction MenuItem({\n label,\n onSelect,\n}: {\n label: string;\n onSelect: () => void;\n}): React.ReactElement {\n return (\n <button\n type=\"button\"\n role=\"menuitem\"\n data-sc-part=\"snowcone-editor-menu-item\"\n style={menuItemStyle}\n onClick={onSelect}\n >\n {label}\n </button>\n );\n}\n\n// ── The ⋯ menu (own DOM — the turnkey ARRANGEMENT owns fullscreen/view/export;\n// they are modes of this composition, not editor-document commands) ───────\n\nfunction OverflowMenu({\n fullscreen,\n onToggleFullscreen,\n viewCount,\n viewIndex,\n onSelectView,\n onExport,\n}: {\n fullscreen: boolean;\n onToggleFullscreen: () => void;\n viewCount: number;\n viewIndex: number;\n onSelectView: (index: number) => void;\n onExport: () => void;\n}): React.ReactElement {\n const [open, setOpen] = useState(false);\n const close = (): void => setOpen(false);\n return (\n <div style={{ position: 'relative' }}>\n <button\n type=\"button\"\n aria-label=\"Editor menu\"\n aria-haspopup=\"menu\"\n aria-expanded={open}\n data-sc-part=\"snowcone-editor-menu\"\n style={iconButtonStyle}\n onClick={() => setOpen((o) => !o)}\n >\n ⋮\n </button>\n {open ? (\n <>\n {/* click-away backdrop */}\n <div\n style={{ position: 'fixed', inset: 0, zIndex: 39 }}\n onClick={close}\n aria-hidden=\"true\"\n />\n <div\n role=\"menu\"\n data-sc-part=\"snowcone-editor-menu-list\"\n style={{\n position: 'absolute',\n right: 0,\n top: '100%',\n marginTop: 4,\n minWidth: 176,\n padding: 4,\n borderRadius: 12,\n background: 'var(--sc-color-surface, #fff)',\n boxShadow: '0 8px 24px rgba(0,0,0,0.14)',\n border: '1px solid rgba(0,0,0,0.08)',\n zIndex: 40,\n }}\n >\n <MenuItem\n label={fullscreen ? 'Exit fullscreen' : 'Fullscreen'}\n onSelect={() => {\n close();\n onToggleFullscreen();\n }}\n />\n {viewCount > 1\n ? Array.from({ length: viewCount }, (_, i) => (\n <MenuItem\n key={i}\n label={`View ${i + 1}${i === viewIndex ? ' ✓' : ''}`}\n onSelect={() => {\n close();\n onSelectView(i);\n }}\n />\n ))\n : null}\n <MenuItem\n label=\"Export PNG\"\n onSelect={() => {\n close();\n onExport();\n }}\n />\n </div>\n </>\n ) : null}\n </div>\n );\n}\n\n// ── Idle dock: ⊕ + layer thumbnails (public headless floor) ─────────────────\n\nfunction IdleDock(): React.ReactElement {\n const { flatLayers, selectLayer, generateAllPreviews } = useLayers({ previewSize: 96 });\n\n useEffect(() => {\n if (flatLayers.length > 0) void generateAllPreviews();\n }, [flatLayers.length, generateAllPreviews]);\n\n return (\n <div\n data-sc-part=\"snowcone-editor-idle-dock\"\n style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8, minHeight: 44 }}\n >\n <Editor.Add />\n {flatLayers.length > 0 ? (\n <div style={{ width: 1, height: 28, background: 'rgba(0,0,0,0.1)', flexShrink: 0 }} aria-hidden=\"true\" />\n ) : null}\n {flatLayers.map((layer) => (\n <button\n key={layer.id}\n type=\"button\"\n data-sc-part=\"snowcone-editor-layer-thumb\"\n aria-label={`Select ${layer.name}`}\n onClick={() => selectLayer(layer.id)}\n style={{\n width: 44,\n height: 44,\n padding: 2,\n borderRadius: 12,\n border: '1px solid rgba(0,0,0,0.1)',\n background: 'var(--sc-color-surface, #fff)',\n overflow: 'hidden',\n cursor: 'pointer',\n flexShrink: 0,\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n {layer.previewUrl ? (\n // eslint-disable-next-line @next/next/no-img-element\n <img src={layer.previewUrl} alt=\"\" style={{ width: '100%', height: '100%', objectFit: 'contain' }} />\n ) : (\n <span\n style={{\n fontSize: 10,\n fontWeight: 600,\n maxWidth: '100%',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {layer.name}\n </span>\n )}\n </button>\n ))}\n </div>\n );\n}\n\n// ── Buy pill (label = \"Add to cart · $price\" when the catalog has one) ──────\n\nfunction BuyPill({\n onAddToCart,\n defaultQuantity,\n}: {\n onAddToCart: (payload: EditorBuyPayload) => void | Promise<void>;\n defaultQuantity?: number;\n}): React.ReactElement {\n const { price, complete } = useProductSelection();\n return (\n <Editor.Buy\n onAddToCart={onAddToCart}\n {...(typeof defaultQuantity === 'number' ? { defaultQuantity } : {})}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: 6,\n padding: '7px 16px',\n marginLeft: 4,\n borderRadius: 9999,\n border: 'none',\n background: 'var(--sc-color-foreground, #111)',\n color: 'var(--sc-color-surface, #fff)',\n font: 'inherit',\n fontSize: 12,\n fontWeight: 700,\n whiteSpace: 'nowrap',\n cursor: complete ? 'pointer' : 'not-allowed',\n opacity: complete ? 1 : 0.5,\n }}\n >\n Add to cart{typeof price === 'number' ? ` · ${formatBuyPrice(price)}` : ''}\n </Editor.Buy>\n );\n}\n\n// ── The chrome (everything inside Editor.Root) ──────────────────────────────\n\nfunction DefaultChrome({\n title,\n height,\n mockupIds,\n onAddToCart,\n defaultQuantity,\n className,\n style,\n}: {\n title: string;\n height: number | string;\n mockupIds: string[];\n onAddToCart: (payload: EditorBuyPayload) => void | Promise<void>;\n defaultQuantity?: number;\n className?: string;\n style?: CSSProperties;\n}): React.ReactElement {\n const [fullscreen, setFullscreen] = useState(false);\n const [viewIndex, setViewIndex] = useState(0);\n const [swapped, setSwapped] = useState(false);\n const canvasRef = useRef<SnowconeCanvasHandle>(null);\n const selected = useSelectedElement();\n\n const mockupId = mockupIds[Math.min(viewIndex, mockupIds.length - 1)];\n\n // Export through the mounted canvas's public ref handle — runtime-only, so\n // this module's static graph stays renderer-free (the heavy export path\n // lives behind Editor.Canvas's lazy chunk, where it already is).\n const handleExport = useCallback(async () => {\n const exports = await canvasRef.current?.exportArtboards({ format: 'dataUrl' });\n if (!exports) return;\n const [name, dataUrl] = Object.entries(exports)[0] ?? [];\n if (typeof dataUrl !== 'string') return;\n const anchor = document.createElement('a');\n anchor.href = dataUrl;\n anchor.download = `${name ?? 'design'}.png`;\n anchor.click();\n }, []);\n\n const frameStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n background: 'var(--sc-color-surface, #fff)',\n color: 'var(--sc-color-foreground, #111)',\n fontFamily: 'ui-sans-serif, system-ui, sans-serif',\n ...(fullscreen\n ? {\n position: 'fixed',\n inset: 0,\n zIndex: 9999,\n height: '100dvh',\n paddingBottom: 'env(safe-area-inset-bottom)',\n }\n : {\n position: 'relative',\n height,\n borderRadius: 16,\n border: '1px solid rgba(0,0,0,0.08)',\n boxShadow: '0 1px 3px rgba(0,0,0,0.08)',\n }),\n ...style,\n };\n\n const pipBoxStyle: CSSProperties = {\n position: 'absolute',\n top: 8,\n right: 12,\n width: 96,\n aspectRatio: '2 / 3',\n borderRadius: 12,\n overflow: 'hidden',\n border: '1px solid rgba(0,0,0,0.1)',\n boxShadow: '0 4px 12px rgba(0,0,0,0.12)',\n background: 'var(--sc-color-surface, #fff)',\n padding: 0,\n cursor: 'pointer',\n zIndex: 2,\n };\n\n return (\n <div\n data-sc-part=\"snowcone-editor\"\n data-sc-fullscreen={fullscreen ? 'true' : undefined}\n className={className}\n style={frameStyle}\n >\n {/* Header — title · undo/redo · ⋯ · Buy (the PDP header, Done → Buy) */}\n <div\n data-sc-part=\"snowcone-editor-header\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 2,\n padding: '10px 12px 4px 16px',\n flexShrink: 0,\n }}\n >\n <span style={{ fontSize: 14, fontWeight: 700, marginRight: 'auto' }}>{title}</span>\n <Editor.History />\n <OverflowMenu\n fullscreen={fullscreen}\n onToggleFullscreen={() => setFullscreen((f) => !f)}\n viewCount={mockupIds.length}\n viewIndex={viewIndex}\n onSelectView={setViewIndex}\n onExport={() => void handleExport()}\n />\n <BuyPill onAddToCart={onAddToCart} defaultQuantity={defaultQuantity} />\n </div>\n\n {/* Stage — artboard center; buyable mockup PiP top-right, tap to swap */}\n <div\n data-sc-part=\"snowcone-editor-stage\"\n style={{ position: 'relative', flex: 1, minHeight: 0, padding: '4px 12px' }}\n >\n <Editor.Canvas ref={canvasRef} style={{ height: '100%' }} />\n\n {swapped ? (\n // Swapped: the mockup IS the stage; the corner chip returns to the\n // artwork. The canvas stays mounted underneath (no document\n // teardown), just covered.\n <div\n data-sc-part=\"snowcone-editor-swap-stage\"\n style={{\n position: 'absolute',\n inset: 0,\n zIndex: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'var(--sc-color-surface, #fff)',\n padding: 8,\n }}\n >\n <Editor.Preview\n mockupId={mockupId}\n alt=\"Product mockup\"\n loadingOverlay\n fallback={<div aria-busy=\"true\">Rendering…</div>}\n style={{ maxWidth: '100%', maxHeight: '100%', borderRadius: 12 }}\n />\n <button\n type=\"button\"\n aria-label=\"Back to artwork\"\n data-sc-part=\"snowcone-editor-swap-back\"\n onClick={() => setSwapped(false)}\n style={{\n ...pipBoxStyle,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: 11,\n fontWeight: 600,\n color: 'inherit',\n border: '1px dashed rgba(0,0,0,0.25)',\n }}\n >\n artwork\n </button>\n </div>\n ) : (\n <button\n type=\"button\"\n aria-label=\"Show product mockup\"\n data-sc-part=\"snowcone-editor-pip\"\n onClick={() => setSwapped(true)}\n style={pipBoxStyle}\n >\n <Editor.Preview\n mockupId={mockupId}\n alt=\"Product mockup preview\"\n loadingOverlay\n fallback={<span style={{ fontSize: 10, opacity: 0.5 }} aria-busy=\"true\">mockup…</span>}\n style={{ width: '100%', height: '100%', display: 'block' }}\n />\n </button>\n )}\n </div>\n\n {/* Control zone — morphs BELOW the stage (PDP grammar): idle → ⊕ +\n layer thumbs; selected → the docked contextual zone (which also\n suppresses the canvas's floating toolbar — nothing floats). */}\n <div\n data-sc-part=\"snowcone-editor-zone\"\n data-sc-zone-state={selected ? 'selected' : 'idle'}\n style={{ flexShrink: 0, padding: '4px 16px 14px' }}\n >\n <div style={{ display: selected ? undefined : 'none' }}>\n <Editor.Controls placement=\"docked\" />\n </div>\n {selected ? null : <IdleDock />}\n </div>\n </div>\n );\n}\n\n/**\n * The turnkey Snowcone editor — the same public parts, our arrangement.\n *\n * ```tsx\n * import { SnowconeEditor, design } from '@snowcone-app/canvas/embed';\n *\n * <SnowconeEditor\n * shop={SHOP_KEY}\n * product={{ productId: 'BC43BE', mockupIds: ['947QAD'], variantId: 'e92f40', placements: ['Front'] }}\n * design={design({ name: 'Front', width: 1480, height: 2328 }).text('hello', { name: 'headline' })}\n * grantUrl=\"/api/realtime/grant\"\n * onAddToCart={(payload) => persist(payload.designState)}\n * />\n * ```\n *\n * Customizing beyond the props means composing `Editor.*` yourself — this\n * component is ~300 lines of public-surface composition you can copy and own.\n *\n * Stable since ADR-0085 P4 (this component IS the gate artifact — composed\n * only from the public embed entry); additive-only from here.\n */\nexport function SnowconeEditor(props: SnowconeEditorProps): React.ReactElement {\n const {\n onAddToCart,\n defaultQuantity,\n title = 'Editor',\n height = 480,\n className,\n style,\n ...rootProps\n } = props;\n\n return (\n <Editor.Root {...rootProps}>\n <DefaultChrome\n title={title}\n height={height}\n mockupIds={rootProps.product.mockupIds}\n onAddToCart={onAddToCart}\n {...(typeof defaultQuantity === 'number' ? { defaultQuantity } : {})}\n className={className}\n style={style}\n />\n </Editor.Root>\n );\n}\n","/**\n * @snowcone-app/canvas/embed — Realtime embed primitives (Tier 2)\n *\n * The turnkey way to drop a live, server-rendered product editor into your app.\n * Three components that share one session so the editor and the preview can't\n * desync, plus the `design()` builder that seeds both:\n *\n * ```tsx\n * import { RealtimeEmbed, RealtimeCanvas, RealtimeMockup, design }\n * from '@snowcone-app/canvas/embed';\n * import '@snowcone-app/canvas/style.css';\n *\n * const d = design({ name: 'Front', width: 1480, height: 2328 })\n * .background(artUrl, { aspectRatio: 1480 / 2328, name: 'art' })\n * .text('YOUR NAME', { anchor: 'top', name: 'headline' });\n *\n * <RealtimeEmbed\n * shop=\"YOUR_SHOP_ID\"\n * grantUrl=\"/api/realtime/grant\"\n * // variantId is REQUIRED when the product has a color/variant axis (a frame\n * // or garment colour) — omit it and the render hangs. Read it + options from getProduct().\n * product={{ productId: 'BC43BE', mockupIds: ['947QAD'], variantId: 'e92f40', placements: ['Front'] }}\n * design={d}\n * >\n * <RealtimeCanvas />\n * <RealtimeMockup />\n * </RealtimeEmbed>\n * ```\n *\n * Everything an embed needs is REQUIRED on `<RealtimeEmbed>` — there's no\n * silently-optional prop to forget. For full manual control (your own session,\n * custom layout, multi-placement, color variants) drop to `<SnowconeCanvas>` +\n * `RenderSession` directly; see the docs' \"eject\" section.\n *\n * @packageDocumentation\n */\n\n// Register icons on module load (the editor + overlay controls use them).\nimport { ensureIconsRegistered } from '../icons/registry.js';\nensureIconsRegistered();\n\n// === Editor.* composable primitives (ADR-0085) ===\n// STABLE: the P4 gate passed — SnowconeEditor (bottom of this file) is rebuilt\n// from exactly this surface, CI-enforced. Additive-only from here; renames and\n// removals are pinned by publicSurfaceGate.test.ts.\nexport { Editor, DesignStateStore, useProductSelection, usePlacements, auditEditor } from '../components/editor/index.js';\nexport type {\n EditorAuditReport,\n EditorAuditFinding,\n EditorAuditFindingCode,\n EditorRootProps,\n EditorRootBaseProps,\n EditorCanvasProps,\n EditorPlacementsProps,\n PlacementInfo,\n UsePlacementsReturn,\n EditorPreviewProps,\n EditorLoadingOverlayProps,\n EditorTextFieldProps,\n EditorBuyProps,\n EditorBuyPayload,\n BuyMissingReason,\n DesignState,\n EditorLayersProps,\n EditorControlsProps,\n EditorHistoryProps,\n EditorMenuProps,\n EditorAddProps,\n ProductSelectionApi,\n ProductOptionChoice,\n ProductSelectionAttribute,\n} from '../components/editor/index.js';\nexport { EditorError, isEditorError } from '../errors/editorError.js';\nexport type { EditorErrorCode, EditorErrorData } from '../errors/editorError.js';\n\n// === Embed primitives ===\nexport { RealtimeEmbed } from '../components/embed-realtime/RealtimeEmbed.js';\nexport type { RealtimeEmbedProps, GrantSource } from '../components/embed-realtime/RealtimeEmbed.js';\n\nexport { RealtimeCanvas } from '../components/embed-realtime/RealtimeCanvas.js';\nexport type { RealtimeCanvasProps } from '../components/embed-realtime/RealtimeCanvas.js';\n// `<RealtimeCanvas ref>` exposes the underlying canvas handle (print-res\n// `exportArtboards`, keyed by artboard NAME); `onChange` hands you the same\n// CanvasState shape — persist it at checkout, re-render it server-side later.\nexport type { SnowconeCanvasHandle, CanvasState } from '../components/embed/SnowconeCanvas.js';\n\nexport { RealtimeMockup } from '../components/embed-realtime/RealtimeMockup.js';\nexport type { RealtimeMockupProps } from '../components/embed-realtime/RealtimeMockup.js';\n\nexport { useRealtimeMockups } from '../components/embed-realtime/useRealtimeMockups.js';\nexport type { UseRealtimeMockupsResult } from '../components/embed-realtime/useRealtimeMockups.js';\n\nexport { validateEmbed, collectEmbedIssues } from '../components/embed-realtime/validateEmbed.js';\nexport type { ValidateEmbedInput, EmbedIssue } from '../components/embed-realtime/validateEmbed.js';\n\n// === Catalog → embed wiring (one call from a getProduct() payload) ===\nexport { productToRenderConfig } from '../design/product-config.js';\nexport type { ProductRenderConfig, ProductRenderConfigOptions } from '../design/product-config.js';\n// ADR-0099 bundles: several products in one mockup. A DISTINCT config shape —\n// role-scoped placement keys, per-role variants, picks per slot. The two\n// adapters refuse each other's input with typed errors.\nexport { bundleToRenderConfig, isBundleProduct, bundleVariantToken, splitRoleKey } from '../design/bundle-config.js';\nexport type {\n BundleRenderConfig,\n BundleRenderConfigOptions,\n BundleRoleConfig,\n BundlePlacementConfig,\n BundleVariantChoice,\n CatalogBundleProduct,\n CatalogBundleBlock,\n CatalogBundleMember,\n CatalogBundleAlternative,\n} from '../design/bundle-config.js';\nexport { isBundleRenderProduct } from '../components/embed-realtime/validateEmbed.js';\n\n// === Design builder — the single source of truth for an embed ===\nexport { design, DesignBuilder, isLayerToken, isColorToken } from '../design/design-builder.js';\nexport type {\n Anchor,\n ShapeKind,\n DesignArtboard,\n StateArtboard,\n FromStateOptions,\n AnyDesign,\n LayerKind,\n LayerToken,\n ColorToken,\n} from '../design/design-builder.js';\n\n// === Chrome-building hooks (build your own editor chrome inside <RealtimeCanvas>) ===\n// These run inside the canvas's editor context — render the component that\n// calls them as `children` of <RealtimeCanvas> (the overlay slot). Same\n// exports as the stable entry, so chrome built against `@snowcone-app/canvas`\n// ports to the embed entry unchanged.\n\nexport { useEditor } from '../contexts/EditorContext.js';\nexport type { EditorContextValue, EditorProviderProps } from '../contexts/EditorContext.js';\n\n// The element model (the headless floor's data type): `EditorElement` is the\n// union `useSelectedElement()` / `useEditor().elements` hand back; the\n// per-kind guards make `instanceof`-grade narrowing possible without the\n// internal classes (agentic-DX finding #11).\nexport type { EditorElement, AddElementSpec, ElementHandle } from '../contexts/EditorContext.js';\nexport {\n isTextElement,\n isImageElement,\n isShapeElement,\n isGroupElement,\n isPathElement,\n editorElementKind,\n} from '../core/elementGuards.js';\nexport type { EditorElementKind } from '../core/elementGuards.js';\n\nexport { useLayers } from '../hooks/useLayers.js';\nexport type { LayerInfo, UseLayersOptions, UseLayersReturn } from '../hooks/useLayers.js';\n\n// `useCommands().updateElement(target, patch)` — the declarative, validated,\n// undoable write path (agentic-DX finding #12); `addElement(spec)` returns a\n// handle and throws E_NO_ACTIVE_ARTBOARD instead of alerting (finding #13).\nexport { useCommands } from '../hooks/useCommands.js';\nexport type { UseCommandsReturn } from '../hooks/useCommands.js';\nexport type { ElementPatch, UpdateElementOptions } from '../hooks/elementPatch.js';\n\nexport { useArtboards } from '../hooks/useArtboards.js';\nexport type { ArtboardInfo, UseArtboardsReturn } from '../hooks/useArtboards.js';\n\n// NOTE the naming wart: `useExport().exportArtboard(id)` takes an artboard ID\n// (from `useArtboards()`), while the <RealtimeCanvas ref> handle's\n// `exportArtboards()` resolves a record keyed by artboard NAME.\nexport { useExport } from '../hooks/useExport.js';\nexport type { ExportProgress, ContinuousExportOptions, UseExportReturn } from '../hooks/useExport.js';\n\nexport { useSelectedElement } from '../hooks/useSelectedElement.js';\n\n// === State serialization (CanvasStateV1 — persist a design at checkout) ===\nexport { serializeState } from '../state/index.js';\nexport type {\n CanvasStateV1,\n SerializedArtboard,\n SerializedElement,\n} from '../state/index.js';\n\n// === Custom (brand) fonts (host-uploaded; `services.onFontUpload`) ===\nexport {\n loadCustomFont,\n registerCustomFonts,\n ensureCustomFontsLoaded,\n customFontRegistry,\n} from '../utils/custom-fonts.js';\nexport type { CustomFont, LoadCustomFontOptions } from '../utils/custom-fonts.js';\n\n// === Binding hooks (build your own controls inside <RealtimeCanvas>) ===\nexport { useTextBinding } from '../hooks/useTextBinding.js';\nexport { useImageBinding } from '../hooks/useImageBinding.js';\nexport { useColorBinding } from '../hooks/useColorBinding.js';\nexport type { ColorBindingResult } from '../hooks/useColorBinding.js';\nexport { useFontBinding } from '../hooks/useFontBinding.js';\nexport type { FontBindingResult } from '../hooks/useFontBinding.js';\nexport { useElementByName } from '../hooks/useElementByName.js';\n\n// === Editable templates (saved state + buyer-editable field manifest) ===\nexport {\n readTemplateFields,\n withTemplateFields,\n TEMPLATE_FIELDS_KEY,\n} from '../design/template-fields.js';\nexport type {\n TemplateField,\n TemplateTextField,\n TemplateImageField,\n TemplateColorField,\n TemplateSelectField,\n} from '../design/template-fields.js';\n\n// === Privileged services (Image Browser search / AI generation) ===\n// Same pattern as `grantUrl`: host the proxy routes on your server, your\n// vendor keys live there. Wire via `services` on <RealtimeEmbed>.\nexport { CanvasServicesProvider, useCanvasServices } from '../contexts/CanvasServicesContext.js';\nexport type { CanvasServices, ResolvedCanvasServices } from '../contexts/CanvasServicesContext.js';\nexport { createProxyImageSearch, createProxyGenerate } from '../services/imageSearch.js';\nexport type {\n ImageSearchProvider,\n ImageSearchResult,\n ImageSearchResponse,\n ImageSearchParams,\n GenerateProvider,\n GenerateParams,\n GenerateResponse,\n} from '../services/imageSearch.js';\n\n// === Re-exported SDK types embedders touch ===\nexport type {\n CatalogProduct,\n RenderProduct,\n RenderProductOptions,\n RenderProductCombination,\n RenderProductRequiredPlacement,\n MockupResult,\n RealtimeGrant,\n} from '@snowcone-app/sdk';\n\n// === The turnkey default editor — rebuilt from the public parts (P4) ===\n// Deliberately LAST: SnowconeEditor itself imports this entry (it compiles\n// against the public surface only — the ADR-0085 P4 gate), so its module\n// body evaluates after everything above is initialized.\nexport { SnowconeEditor, formatBuyPrice } from '../default-editor/SnowconeEditor.js';\nexport type { SnowconeEditorProps } from '../default-editor/SnowconeEditor.js';\n"],"names":["EmbedContext","createContext","useEmbedContext","ctx","useContext","isBundleProduct","product","_a","DOC","bundleVariantToken","variantByRole","role","splitRoleKey","name","dot","isRenderablePlacement","p","variantLabel","alt","gvid","row","_b","c","parts","k","v","bundleToRenderConfig","catalogProduct","options","EditorError","members","roleNames","m","field","map","picks","variants","renderByRole","catalogPlacements","roles","member","alternatives","wanted","gvids","g","accepted","chosen","requested","_c","_e","_d","placements","pickedKeys","r","byKey","cfg","placementKeys","placement","mockups","matching","productId","mockupIds","requiredPlacements","TAG","requiredPlacementLabels","variantIds","id","isBundleRenderProduct","bundleRolesOf","key","split","collectEmbedIssues","shop","design","hasGrant","issues","assertVariantSelected","err","json","artboardNames","a","bundle","roleless","keys","missingVariant","required","inheriting","label","foreign","names","el","n","dupes","i","validateEmbed","input","issue","resolvePlacementLinks","requiredLabels","authored","out","expandRequestForPlacements","request","artboards","base","ab","byName","links","l","expanded","computeEditorAudit","registry","store","findings","textFields","requiresCanvas","canvasKeepsFloating","sceneIds","unpinned","hasBuy","tf","matched","counts","census","count","b","mountedRoots","registerRootForAudit","entry","index","auditEditor","current","SLOW_RENDER_HINT_MS","slowRenderHint","toGetToken","props","grant","ErrorCard","error","onRetry","code","isEditorError","jsxs","jsx","CatchingBoundary","Component","recordContainedEditorError","process","EditorBoundary","reportedError","children","retryable","EditorRootInner","throttleMs","onMockups","onRenderError","onIssue","wsUrl","services","internals","recordAudit","__validation","useMemo","artboardNamesKey","useSyncExternalStore","requiredKey","placementChoice","setPlacementChoice","useState","activePlacement","selectPlacement","valid","pushRenderRef","useRef","splitPlacement","bridge","serializeStateForServer","linkPlacement","initialArtboardConfig","artboard","selectedVariantId","guideBundle","usePieceGuideBundle","pieceGuides","pieceGuidesForArtboard","onMockupsRef","onRenderErrorRef","onIssueRef","setMockups","isRendering","setIsRendering","setError","auth","authKey","productKey","bundleKey","validationKey","advisoryIssues","fatal","reportedIssuesKeyRef","useEffect","validatedKeyRef","sessionResult","RenderSession","session","constructError","pushRender","state","throttle","handleSendError","message","sendSlice","results","appliedVariantRef","applied","baseline","appliedBundleRef","first","timer","value","registryVersion","body","EditorRootInternalsContext","BoundLayerGuardContext","EditorProvider","CanvasServicesProvider","EditorRoot","onAudit","productIdentity","internalsRef","commerceRef","setReportedError","DesignStateStore","EditorPartsRegistry","CommerceStateStore","makeInvariantReporter","productRef","onAuditRef","auditSnapshotRef","useCallback","report","computeAudit","useLayoutEffect","auditFiredRef","cancelled","implLoader","loadCanvasImpl","EditorCanvas","forwardRef","maxHeight","floatingToolbar","className","style","ref","useEditorRootInternals","useRegisterEditorPart","instanceId","useId","Impl","setImpl","component","usePlacements","infos","linked","defaultLinkedLabel","labels","actionStyle","EditorPlacements","select","splitAll","linkAll","active","inherited","SHOW_DELAY_MS","LINGER_MS","generateParticles","propertiesRegistered","ensurePrismProperties","PreviewPrismOverlay","memo","visible","onExited","variant","particles","setParticles","mounted","setMounted","raf","handleTransitionEnd","e","fadeClass","_","useRenderLoadingOverlay","isLoading","showOverlay","setShowOverlay","lingering","setLingering","showTimerRef","lingerTimerRef","shownRef","handleExited","RESOLUTION_MISMATCH_RATIO","SUGGESTED_WIDTHS","suggestRenderWidth","devicePx","step","resolutionMismatchHint","naturalWidth","suggestion","resolveLoadingOverlay","isValidElement","EditorPreview","mockupId","fallback","loadingOverlay","resolved","overlayVariant","customOverlay","overlayActive","overlayVisible","warnedMockupIdsRef","result","handleLoad","event","img","cssWidth","hint","frameState","EditorTextField","layer","optional","placeholder","stateStore","validatedNameRef","isLayerToken","kindNow","handleChange","next","evaluateBuyCompleteness","missing","seed","buildCartDetail","commerce","combinations","attributes","stringAttrs","attr","choiceLabelsOf","createCartDetail","EditorBuy","onAddToCart","defaultQuantity","seededRef","stateVersion","commerceVersion","quantity","complete","busy","setBusy","busyRef","handleClick","designState","variantId","payload","EditorControls","useRequiresCanvas","docked","EditorLoadingOverlay","useProductSelection","version","choice","setQuantity","Editor","EditorLayers","EditorHistory","EditorMenu","EditorAdd","RealtimeEmbed","RealtimeCanvas","rest","RealtimeMockup","useRealtimeMockups","productToRenderConfig","renderable","renderableLabels","combo","scoped","formatBuyPrice","cents","iconButtonStyle","menuItemStyle","MenuItem","onSelect","OverflowMenu","fullscreen","onToggleFullscreen","viewCount","viewIndex","onSelectView","onExport","open","setOpen","close","o","Fragment","IdleDock","flatLayers","selectLayer","generateAllPreviews","useLayers","BuyPill","price","DefaultChrome","title","height","setFullscreen","setViewIndex","swapped","setSwapped","canvasRef","selected","useSelectedElement","handleExport","exports","dataUrl","anchor","frameStyle","pipBoxStyle","f","SnowconeEditor","rootProps","ensureIconsRegistered"],"mappings":"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"}