@elytracms/next 0.0.65 → 0.0.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components.ts","../src/payloads.ts","../src/canvas-renderer.tsx","../src/source.ts","../src/source-payloads.ts","../src/snapshot.ts","../src/route-core.ts","../src/cache.ts","../src/metadata.ts","../src/route.tsx","../src/sitemap.ts","../src/revalidate-core.ts","../src/revalidate.ts","../src/image.tsx","../src/full-bleed.ts","../src/host-env.ts","../src/host-content.ts","../src/host-globals.ts","../src/preview-core.ts","../src/preview.ts","../src/host-kit.ts","../src/index.ts"],"names":["record","splitPath","cacheTags","jsx","outcome","z","str","draftMode","redirect"],"mappings":"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","file":"index.js","sourcesContent":["import type { ComponentType } from 'react'\nimport { ComponentRegistry } from '@elytracms/core/component-registry'\nimport type { ComponentIssue, ComponentManifest } from '@elytracms/core/component-registry'\nimport { basePrimitives, getImplementation } from '@elytracms/core/runtime-renderer'\nimport type { ComponentImplementations } from '@elytracms/core/runtime-renderer'\n\n/**\n * One host-repo component: the manifest the builder edits against plus the\n * real React implementation that renders it (vision AD-2 — project components\n * are real code in the host repo, never generated).\n */\nexport interface HostComponent {\n manifest: ComponentManifest\n implementation: ComponentType<Record<string, unknown>>\n}\n\n/**\n * The registered component surface a host app hands to `<CanvasRenderer />`\n * and the catch-all route helper: a manifest registry plus the implementation\n * map, with registration problems surfaced as structured issues (never\n * thrown — an unknown component renders the EC-015 fallback).\n */\nexport interface HostComponents {\n registry: ComponentRegistry\n implementations: ComponentImplementations\n /** Structural registration issues (duplicate ids, invalid namespaces). */\n issues: readonly ComponentIssue[]\n}\n\nexport interface DefineHostComponentsOptions {\n /**\n * Include the platform primitives (`base.*`) that ship with\n * `@elytracms/core/runtime-renderer`. Defaults to `true` — graphs authored in the\n * builder assume them.\n */\n includeBasePrimitives?: boolean\n}\n\n/**\n * Component registration API for the embedded runtime (EC-144). The host repo\n * supplies real implementations + manifests; base primitives are included by\n * default. A host implementation registered under a primitive id replaces the\n * default implementation (the manifest of the first registration wins, which\n * is the primitive's — by design, so prop schemas stay canonical).\n */\nexport function defineHostComponents(\n components: readonly HostComponent[] = [],\n options: DefineHostComponentsOptions = {},\n): HostComponents {\n const includeBase = options.includeBasePrimitives !== false\n const base = includeBase ? basePrimitives() : { manifests: [], implementations: {} }\n\n const registry = new ComponentRegistry([...base.manifests, ...components.map((c) => c.manifest)])\n\n const implementations: Record<string, ComponentType<Record<string, unknown>>> = {}\n for (const manifest of base.manifests) {\n const implementation = getImplementation(base.implementations, manifest.id)\n if (implementation) implementations[manifest.id] = implementation\n }\n for (const component of components) {\n implementations[component.manifest.id] = component.implementation\n }\n\n return { registry, implementations, issues: registry.issues }\n}\n","import type { BindingReference } from '@elytracms/core/project-graph'\nimport type { ItemContext, ResolveBinding } from '@elytracms/core/runtime-renderer'\n\n/**\n * Binding payloads for the embedded runtime (EC-144): one payload value per\n * binding `sourceId`. The catch-all route helper provides `document` (the\n * route-bound resolved document) and `params` (dynamic route params) by\n * default; hosts add more through the route helper's `payloads` factory\n * (e.g. a `listDocuments` result for a posts repeater).\n *\n * This is a deliberately small, pure resolver — the embedded runtime never\n * imports `@elytracms/core/data-binding` (a builder-side package). Semantics mirror\n * EC-023 tokens: a binding token is a JSON Pointer (RFC 6901) into the\n * payload; a miss resolves to `undefined`, never a throw (the renderer turns\n * unresolvable bindings into visible fallback behavior, EC-015).\n */\nexport type BindingPayloads = Record<string, unknown>\n\n/**\n * Marker key of an {@link SourcePayloadError} payload. A plain string property\n * (not a Symbol) on purpose: the route helper's cached path JSON-serializes\n * payloads through `unstable_cache`, and the marker must survive that\n * round-trip.\n */\nconst SOURCE_PAYLOAD_ERROR_KEY = '__elytraSourcePayloadError'\n\n/**\n * Explicit issue payload for a source whose stored query was REJECTED at\n * delivery (EC-177 gap 3) — e.g. a sort/filter field that is no longer\n * filterable in the live schema. Materialization stores this instead of a\n * silently-absent payload; `createBindingResolver` throws on it, which the\n * renderer converts into its visible per-node render-error fallback (EC-015).\n * Validation principle: a broken stored query is a visible state, never an\n * empty section.\n */\nexport interface SourcePayloadError {\n [SOURCE_PAYLOAD_ERROR_KEY]: true\n sourceId: string\n /** Human-readable messages of the structured query errors. */\n messages: string[]\n}\n\n/** Build the explicit issue payload for one failed source query. */\nexport function sourcePayloadError(\n sourceId: string,\n messages: readonly string[],\n): SourcePayloadError {\n return { [SOURCE_PAYLOAD_ERROR_KEY]: true, sourceId, messages: [...messages] }\n}\n\n/** `true` when a payload value is an explicit {@link SourcePayloadError}. */\nexport function isSourcePayloadError(value: unknown): value is SourcePayloadError {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as Record<string, unknown>)[SOURCE_PAYLOAD_ERROR_KEY] === true &&\n typeof (value as { sourceId?: unknown }).sourceId === 'string' &&\n Array.isArray((value as { messages?: unknown }).messages)\n )\n}\n\n/** Unescape one RFC 6901 reference token (`~1` → `/`, `~0` → `~`). */\nfunction unescapeRefToken(token: string): string {\n return token.replace(/~1/g, '/').replace(/~0/g, '~')\n}\n\n/** Parse a JSON Pointer into segments; `''`/`'/'` is the root. `undefined` = malformed. */\nfunction pathFromToken(token: string): string[] | undefined {\n if (token === '' || token === '/') return []\n if (!token.startsWith('/')) return undefined\n return token.slice(1).split('/').map(unescapeRefToken)\n}\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\n/**\n * Resolve a JSON Pointer token within a payload value. Numeric segments index\n * arrays; string segments index plain objects. Any miss (unknown key,\n * out-of-range index, traversal through a primitive) yields `undefined`.\n */\nexport function resolvePayloadToken(payload: unknown, token: string): unknown {\n const path = pathFromToken(token)\n if (path === undefined) return undefined\n let current: unknown = payload\n for (const segment of path) {\n if (Array.isArray(current)) {\n if (!/^(0|[1-9][0-9]*)$/.test(segment)) return undefined\n const index = Number(segment)\n if (index >= current.length) return undefined\n current = current[index]\n continue\n }\n if (isPlainObject(current)) {\n if (!Object.prototype.hasOwnProperty.call(current, segment)) return undefined\n current = current[segment]\n continue\n }\n return undefined\n }\n return current\n}\n\n/**\n * Create the renderer's `ResolveBinding` over a payload map. Mode semantics\n * (brief §4.6, uniform binding model):\n *\n * - `value` / `object` / `condition` — the value at the token within the\n * payload named by `sourceId`.\n * - `spread` — same lookup; the renderer spreads the resulting object.\n * - `repeaterItem` — the token resolves against the active repeater item,\n * not the root payload.\n *\n * Total for data misses: an unknown `sourceId` or missing path resolves to\n * `undefined` — the renderer (EC-015) degrades visibly instead of crashing.\n * An explicit {@link SourcePayloadError} payload (a REJECTED stored query, not\n * merely missing data) throws instead: the renderer catches per node and\n * renders its visible render-error fallback with the query error message;\n * conditions treat the throw as `false` (the node hides) — never a page crash.\n */\nexport function createBindingResolver(payloads: BindingPayloads): ResolveBinding {\n return (ref: BindingReference, item?: ItemContext): unknown => {\n if (ref.mode === 'repeaterItem') {\n return item === undefined ? undefined : resolvePayloadToken(item.item, ref.token)\n }\n if (!Object.prototype.hasOwnProperty.call(payloads, ref.sourceId)) return undefined\n const payload = payloads[ref.sourceId]\n if (isSourcePayloadError(payload)) {\n throw new Error(\n `Source \"${payload.sourceId}\" query was rejected: ${payload.messages.join('; ')}`,\n )\n }\n return resolvePayloadToken(payload, ref.token)\n }\n}\n","import { isValidElement } from 'react'\nimport type { ReactNode } from 'react'\nimport type { ResolvedAsset, ResolvePageResult } from '@elytracms/core/content'\nimport type { ComponentNode } from '@elytracms/core/project-graph'\nimport {\n RenderErrorBoundary,\n renderComposition,\n serializeListingQuery,\n} from '@elytracms/core/runtime-renderer'\nimport type {\n RelationTarget,\n RenderAsset,\n RenderContext,\n ResolveBinding,\n ResolveLink,\n ResolveListing,\n ResolveRelation,\n} from '@elytracms/core/runtime-renderer'\nimport type { HostComponents } from './components'\nimport { createBindingResolver } from './payloads'\nimport type { BindingPayloads } from './payloads'\n\n/**\n * `<CanvasRenderer />` (EC-144, vision AD-1): an async React Server Component\n * that renders a resolved page (from `resolvePage`, EC-143) through\n * `@elytracms/core/runtime-renderer` with the host app's component registry. EC-015\n * fallback behavior is identical to the builder: a missing component, invalid\n * prop, or missing required slot renders a visible fallback — a page never\n * crashes and never silently omits a node.\n */\nexport interface CanvasRendererProps {\n /** The `resolvePage` result for the current URL. */\n result: ResolvePageResult\n /** Host component surface from `defineHostComponents`. */\n components: HostComponents\n /**\n * Binding payloads keyed by `sourceId`. Defaults to\n * `{ document, params }` derived from the result.\n */\n payloads?: BindingPayloads\n /** Full custom binding resolver — overrides `payloads` when provided. */\n resolveBinding?: ResolveBinding\n /**\n * Delivery-shaped assets the page may reference (EC-195, from the render\n * outcome). An `asset`-typed Image prop resolves through these to a url +\n * intrinsic dimensions; an unknown id degrades to the visible fallback.\n */\n assets?: readonly ResolvedAsset[]\n /**\n * Populated composition-node `relation` props, keyed `collection:id` (EC-254,\n * from the render outcome). A block's `relation` prop (e.g. a ProductGrid's\n * picked products) resolves through these to the populated target; an unknown\n * key degrades to the block's own empty state. Absent → relation props pass\n * through unresolved (raw ref), the same degradation as a missing asset list.\n */\n relations?: Record<string, RelationTarget>\n /**\n * Documents each `listing` block resolved to, keyed by serialized query (EC-255,\n * from the render outcome). A ProductGrid keyed to a picked `category` reads its\n * products through this; an unknown key (or absent map) degrades to the block's\n * own empty state — the same degradation as a missing relation.\n */\n listings?: Record<string, RelationTarget[]>\n /**\n * URL paths for the documents this page's rich-text props LINK to, keyed\n * `collection:id` (EC-291, from the render outcome). A self-typed internal link\n * (`attrs.ref = {type:'reference',…}`) resolves through this to a real `href`; an\n * unknown key (or absent map) degrades to the renderer's visible `unresolved-ref`\n * issue (EC-290), never a silent `#`.\n */\n links?: Record<string, string>\n}\n\n/** Build the renderer's relation resolver from the baked, populated targets (EC-254). */\nfunction relationResolver(relations: Record<string, RelationTarget>): ResolveRelation {\n return (ref) => relations[`${ref.collection}:${ref.id}`] ?? null\n}\n\n/** Build the renderer's link resolver from the baked, doc-keyed URL paths (EC-291). */\nfunction linkResolver(links: Record<string, string>): ResolveLink {\n return (ref) => links[`${ref.collection}:${ref.id}`] ?? null\n}\n\n/** Build the renderer's listing resolver from the baked, query-keyed documents (EC-255). */\nfunction listingResolver(listings: Record<string, RelationTarget[]>): ResolveListing {\n return (query) => listings[serializeListingQuery(query)] ?? null\n}\n\n/** Build the renderer's asset resolver from the baked delivery assets (EC-195). */\nfunction assetResolver(assets: readonly ResolvedAsset[]): (id: string) => RenderAsset | null {\n const byId = new Map(assets.map((asset) => [asset.id, asset]))\n return (id) => {\n const asset = byId.get(id)\n return asset\n ? {\n url: asset.url,\n width: asset.width,\n height: asset.height,\n alt: asset.alt,\n focalPoint: asset.focalPoint,\n // EC-420: carry the LQIP so a placed base.Image blurs up on delivery.\n lqip: asset.lqip,\n meta: asset.meta,\n }\n : null\n }\n}\n\n/** Visible fallback when the renderer is handed a non-`ok` resolution. */\nfunction UnresolvedPageFallback(props: { status: string }): ReactNode {\n return (\n <div data-ec-fallback=\"unresolved-page\" data-ec-status={props.status}>\n {`This URL did not resolve to a page (status: ${props.status}).`}\n </div>\n )\n}\n\n/** Visible fallback when an `ok` resolution carries no renderable document. */\nfunction MissingDocumentFallback(): ReactNode {\n return (\n <div data-ec-fallback=\"missing-document\">\n {`Route resolved but carried no page document to render.`}\n </div>\n )\n}\n\n/**\n * Server-side per-node decorator: unwrap the renderer's client error\n * boundary. React Server Components cannot render class components, and a\n * boundary cannot recover during server rendering anyway (the renderer\n * already converts resolution errors into visible fallbacks before this\n * point). The wrapped element keeps its key, so output is unchanged.\n */\nfunction stripServerErrorBoundary(_node: ComponentNode, rendered: ReactNode): ReactNode {\n if (isValidElement(rendered) && rendered.type === RenderErrorBoundary) {\n return (rendered.props as { children?: ReactNode }).children ?? null\n }\n return rendered\n}\n\n/** Default payloads: the route-bound document and the dynamic route params. */\nexport function defaultBindingPayloads(result: ResolvePageResult): BindingPayloads {\n return { document: result.document, params: result.dynamicParams }\n}\n\n/**\n * Render a resolved page server-side. Async so hosts can compose it like any\n * other RSC; resolution itself is synchronous (the content was prefetched by\n * the `ContentSource`).\n */\nexport async function CanvasRenderer(props: CanvasRendererProps): Promise<ReactNode> {\n const { result, components } = props\n\n if (result.status !== 'ok') {\n // The route helper answers redirect/notFound before rendering; direct\n // users of <CanvasRenderer /> still get a visible state, never a crash.\n return <UnresolvedPageFallback status={result.status} />\n }\n\n const resolveBinding =\n props.resolveBinding ?? createBindingResolver(props.payloads ?? defaultBindingPayloads(result))\n\n const ctx: RenderContext = {\n registry: components.registry,\n implementations: components.implementations,\n resolveBinding,\n resolveAsset: assetResolver(props.assets ?? []),\n // EC-254: wire relation population only when the host baked the populated\n // targets, so a host that did not opt in keeps the raw-ref passthrough.\n ...(props.relations ? { resolveRelation: relationResolver(props.relations) } : {}),\n // EC-255: wire the listing resolver only when the host baked the query results,\n // so a host that did not opt in keeps listing props empty (the block's own state).\n ...(props.listings ? { resolveListing: listingResolver(props.listings) } : {}),\n // EC-291: wire the rich-text link resolver only when the host baked the link map,\n // so a host that did not opt in degrades a reference link to the visible\n // `unresolved-ref` issue (EC-290) rather than a wrong href.\n ...(props.links ? { resolveLink: linkResolver(props.links) } : {}),\n decorateNode: stripServerErrorBoundary,\n }\n\n const document = result.document\n\n // EC-187/EC-287: a routed document delivers a composition field directly — a\n // `page`-collection document uses its `body` field; a content-collection\n // document routed for delivery uses its `content` composition field (e.g. a\n // post's `content`). There is no graph or layout indirection: shared chrome is\n // composed in the host's `app/layout.tsx`. A page renders its blocks directly;\n // with no document at all, a visible fallback.\n if (document) {\n const composition = compositionOf(document)\n return <>{renderComposition(composition, ctx)}</>\n }\n\n return <MissingDocumentFallback />\n}\n\n/**\n * Select the delivery composition from a resolved document (EC-187). The\n * composition field can be named anything the host's collection schema chooses:\n * the conventional `body` (a `page`) or `content` (a routed content collection\n * like a `post`), but ALSO a host-specific name such as Konditorei's\n * `pageBuilder` (migrated faithfully from Sanity, EC-263). So the field is chosen\n * by VALUE — a composition is a `ComponentNode` or an array of them — NEVER by\n * name: a `body ?? content` name heuristic both picks a post's rich-text `body`\n * string over its `content` composition AND misses a `pageBuilder` entirely,\n * rendering nothing.\n *\n * `body` then `content` keep priority (so a content document's unrelated rich-text\n * `body` never shadows the conventional `content` composition); any other\n * composition-valued field is the generalized fallback.\n */\nfunction compositionOf(document: Record<string, unknown>): unknown {\n const body = document['body']\n if (Array.isArray(body) || isComponentNodeValue(body)) return body\n const content = document['content']\n if (Array.isArray(content) || isComponentNodeValue(content)) return content\n // Generalized (EC-263): the first field whose value is a composition — a node or\n // a non-empty array of nodes. `body`/`content` already took priority above.\n for (const value of Object.values(document)) {\n if (isComponentNodeValue(value)) return value\n if (Array.isArray(value) && value.length > 0 && value.every(isComponentNodeValue)) return value\n }\n return undefined\n}\n\n/**\n * The routed document's composition as a `ComponentNode[]` (EC-205): the same\n * `body`-or-`content` selection the renderer uses, normalized to an array so a\n * delivery host can walk it (e.g. to page-scope baked assets). Non-node values\n * are dropped. `null`/no-document yields an empty array.\n */\nexport function compositionNodesOf(\n document: Record<string, unknown> | null | undefined,\n): ComponentNode[] {\n if (!document) return []\n const composition = compositionOf(document)\n const candidates = Array.isArray(composition) ? composition : [composition]\n return candidates.filter((node): node is ComponentNode => isComponentNodeValue(node))\n}\n\n/** Structural `ComponentNode` guard — a resolved field value is opaque at the type level. */\nfunction isComponentNodeValue(value: unknown): boolean {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { id?: unknown }).id === 'string' &&\n typeof (value as { componentId?: unknown }).componentId === 'string'\n )\n}\n","import type { Locale, LocaleConfig, RouteRecord } from '@elytracms/core/cms-core'\nimport { cacheTags } from '@elytracms/core/content'\nimport type { CacheTags, ContentClient, Perspective, ResolvedAsset } from '@elytracms/core/content'\n\n/**\n * The content seam of the embedded runtime (EC-144, vision AD-1/AD-4): the\n * catch-all route helper consumes this interface, so where the content comes\n * from is swappable. EC-144 ships the in-memory snapshot bridge\n * (`createContentSnapshot` over a `PersistenceAdapter`); EC-145/146 plug a\n * Convex-backed source into the exact same seam.\n *\n * Accessors are synchronous over a prefetched `ContentLookup` (vision AD-4);\n * any fetching happens when the source is loaded, before clients are minted.\n */\n/**\n * One data-source definition the published graph's bindings reference\n * (EC-166 delivery): the structural shape of an `@elytracms/core/data-binding`\n * `DataSource`, declared here so the embedded runtime stays free of\n * builder-side packages. Only `cms`-kind sources with the EC-166 per-scope id\n * prefixes (`cms.section.<nodeId>` / `cms.template.<pageId>`) participate in\n * automatic payload materialization; everything else is ignored.\n */\nexport interface CanvasDataSource {\n kind: string\n id: string\n label?: string\n /** Kind-specific config; cms query configs parse via `@elytracms/core/content`. */\n config?: unknown\n}\n\nexport interface ContentSource {\n /** The project's locale configuration (default + supported set, EC-018). */\n readonly locales: LocaleConfig\n /**\n * Mint a typed accessor client (EC-143) bound to a perspective. The locale\n * defaults to the project default; the route helper overrides it per\n * request from the URL's locale prefix.\n */\n client(init: { perspective: Perspective; locale?: Locale }): ContentClient\n /**\n * The route records the source's clients resolve against (EC-171, additive).\n * Lets enumerating consumers — the sitemap helper — walk the same route\n * table `resolvePage` uses, instead of keeping a second list. Optional so\n * existing custom sources stay valid; without it the sitemap helper needs\n * explicit routes.\n */\n readonly routes?: readonly RouteRecord[]\n /**\n * Data-source definitions the graph's bindings reference (EC-166 delivery,\n * additive). When present, the route helper materializes per-section list\n * sources automatically by replaying their stored where/sort/limit through\n * `listDocuments` — see `materializeSourcePayloads`. Optional so existing\n * custom sources stay valid; absent definitions degrade to unresolved\n * bindings (the renderer's visible fallbacks), never a crash.\n */\n readonly sources?: readonly CanvasDataSource[]\n /**\n * The project's delivery-shaped assets (EC-195, additive). Lets the route\n * helper bake the assets a page may reference into the (serializable) render\n * outcome, so the renderer can resolve an `asset`-typed Image prop to a usable\n * url + intrinsic dimensions — and a cached page keeps its images during a\n * backend outage. Optional so existing custom sources stay valid; without it,\n * asset-typed props fall back to their raw value (the renderer's visible\n * degradation), never a crash.\n */\n assets?(): readonly ResolvedAsset[]\n}\n\n/**\n * Merge accessor cache tags into one deterministic set (sorted, deduplicated)\n * — used by the route helper to combine the `resolvePage` tags with tags\n * added by the host's payload factory (e.g. a `listDocuments` call). The\n * merged set is what the EC-146 `onTags` hook receives.\n */\nexport function mergeCacheTags(first: CacheTags, ...rest: readonly CacheTags[]): CacheTags {\n const all = [first, ...rest]\n return cacheTags({\n docs: all.flatMap((t) => t.docs),\n collections: all.flatMap((t) => t.collections),\n routes: all.flatMap((t) => t.routes),\n assets: all.flatMap((t) => t.assets),\n locale: first.locale,\n })\n}\n","import {\n isSectionSourceId,\n listQueryOfCmsConfig,\n parseCmsSourceQueryConfig,\n} from '@elytracms/core/content'\nimport type { CacheTags, ContentClient, ResolvePageResult } from '@elytracms/core/content'\nimport type { ComponentNode } from '@elytracms/core/project-graph'\nimport { sourcePayloadError } from './payloads'\nimport type { BindingPayloads } from './payloads'\nimport type { CanvasDataSource } from './source'\n\n/**\n * Automatic payload materialization for EC-166 repeating sections — the\n * delivery half of the builder's collection-driven LAYOUTS (EC-187: layouts\n * are the only graph trees that can bind section sources now). A published\n * layout may carry bindings against per-scope CMS sources; the renderer needs\n * the source PAYLOADS:\n *\n * - **Repeating sections** (`cms.section.<nodeId>`): the stored source config\n * carries the closed AD-3 query. For every section source a referenced\n * layout tree actually binds, the stored where/sort/limit replays through\n * the request client's `listDocuments` — published perspective and ambient\n * locale come from the client itself. The list result's `CacheTags` (the\n * fetch-time doc tags of what was actually returned plus the coarse\n * collection tag — the EC-146 contract) are surfaced so the route helper\n * merges them into the request tag set.\n *\n * The `cms.template.<pageId>` \"current document\" source is RETIRED (EC-187):\n * there is no template page, and a routed page document's `body` uses static\n * props (v1). A collection detail route's document is read by the dev route\n * component directly via the route's `document` ref.\n *\n * Everything degrades visibly, never a crash:\n *\n * - a missing source definition, a non-cms kind, or a malformed config leaves\n * the payload absent, so the binding resolves to `undefined` and the\n * renderer shows its EC-015 fallback (an empty list renders the section's\n * empty state);\n * - a structured query error (the stored query was REJECTED at delivery, e.g.\n * a sort field no longer filterable in the live schema) stores an explicit\n * {@link sourcePayloadError} payload instead — the binding resolver throws\n * on it and the renderer shows its visible per-node render-error fallback,\n * not a silently empty section (EC-177 gap 3).\n */\n\n/** Collect every binding `sourceId` referenced in a node tree (props, conditions, slots). */\nexport function collectBindingSourceIds(\n node: ComponentNode,\n into: Set<string> = new Set(),\n): Set<string> {\n for (const value of Object.values(node.props ?? {})) {\n if (value.kind === 'binding') into.add(value.binding.sourceId)\n }\n if (node.condition) into.add(node.condition.source.sourceId)\n for (const children of Object.values(node.slots ?? {})) {\n for (const child of children) collectBindingSourceIds(child, into)\n }\n return into\n}\n\nexport interface MaterializeSourcePayloadsInput {\n /** Accessor client bound to this request's perspective + locale. */\n client: ContentClient\n result: ResolvePageResult\n /** Source definitions from the `ContentSource` (absent ones simply skip). */\n sources: readonly CanvasDataSource[]\n}\n\nexport interface MaterializedSourcePayloads {\n payloads: BindingPayloads\n /** `CacheTags` of every accessor call made here (one entry per section list). */\n tags: CacheTags[]\n}\n\n/**\n * Materialize the EC-166 source payloads for one resolved page. Pure over the\n * prefetched source — `listDocuments` is synchronous; tags are returned (not\n * applied) so the caller owns the merge.\n */\nexport function materializeSourcePayloads(\n input: MaterializeSourcePayloadsInput,\n): MaterializedSourcePayloads {\n const { client, result, sources } = input\n const payloads: BindingPayloads = {}\n const tags: CacheTags[] = []\n\n if (result.status !== 'ok') return { payloads, tags }\n\n // --- Repeating sections: replay each referenced section source -----------\n // EC-187/EC-287: page bodies use static props (v1, bindings parked) and there\n // is no project graph or layout tree, so no composition currently binds a\n // section source — `referenced` stays empty. The section-source plumbing is\n // kept dormant for when editor bindings return.\n const referenced = new Set<string>()\n\n const byId = new Map(sources.map((source) => [source.id, source]))\n for (const sourceId of [...referenced].sort()) {\n if (!isSectionSourceId(sourceId)) continue\n const definition = byId.get(sourceId)\n if (!definition || definition.kind !== 'cms') continue\n const config = parseCmsSourceQueryConfig(definition.config)\n // Single-document configs are not lists; leave the binding unresolved.\n if (!config || config.documentId !== undefined) continue\n\n const list = client.listDocuments(config.collectionId, listQueryOfCmsConfig(config))\n // Both arms carry at least the collection tag; the ok arm additionally\n // tags every document actually returned (fetch-time tagging, EC-146).\n tags.push(list.tags)\n if (list.ok) {\n payloads[sourceId] = list.documents\n } else {\n // A rejected stored query is a VISIBLE state: the explicit issue\n // payload makes the binding resolver throw, which the renderer turns\n // into its per-node render-error fallback — never a silent empty list.\n payloads[sourceId] = sourcePayloadError(\n sourceId,\n list.errors.map((error) => error.message),\n )\n }\n }\n\n return { payloads, tags }\n}\n","import { documentKey, splitPath } from '@elytracms/core/cms-core'\nimport type {\n CmsDocument,\n CollectionDef,\n DocumentRef,\n Locale,\n LocaleConfig,\n RedirectRecord,\n RouteRecord,\n} from '@elytracms/core/cms-core'\nimport {\n createContentClient,\n createContentContext,\n isDocumentHistory,\n resolvedAsset,\n} from '@elytracms/core/content'\nimport type {\n ContentClient,\n ContentDocumentSource,\n ContentLookup,\n Perspective,\n ResolvedAsset,\n} from '@elytracms/core/content'\nimport type { AssetRecord, PersistenceAdapter } from '@elytracms/core/persistence'\nimport type { CanvasDataSource, ContentSource } from './source'\n\n/**\n * Bridge from a `PersistenceAdapter` to the synchronous `ContentLookup` the\n * accessors (EC-143) read through: prefetch the project's collections,\n * documents, assets, and graphs ONCE (async), then serve every accessor call\n * synchronously from memory. This is how `apps/example-site` reads the seeded\n * in-memory fixture project; a Convex-backed `ContentSource` (EC-145/146)\n * replaces this bridge without touching the route helper.\n *\n * The assembly half is exposed separately as {@link createStaticContentSource}\n * (EC-156): a host that already holds the prefetched data as plain values —\n * e.g. a delivery-snapshot payload fetched over Convex's public HTTP query\n * API — assembles the exact same `ContentSource` without faking an adapter.\n */\n\nconst DEFAULT_LOCALES: LocaleConfig = { default: 'en', locales: ['en'] }\n\nexport interface ContentSnapshotOptions {\n /** Route records served by `resolvePage` (EC-019). */\n routes?: readonly RouteRecord[]\n /** Redirect records served by `resolvePage` (EC-019/020). */\n redirects?: readonly RedirectRecord[]\n /** Locale configuration; defaults to English-only. */\n locales?: LocaleConfig\n /**\n * Data-source definitions the graph's bindings reference (EC-166): section\n * sources (`cms.section.<nodeId>`) carry their stored where/sort/limit, and\n * the route helper materializes their payloads automatically.\n */\n sources?: readonly CanvasDataSource[]\n}\n\nexport interface ContentSnapshot extends ContentSource {\n readonly projectId: string\n}\n\n/**\n * Plain prefetched data for {@link createStaticContentSource} (EC-156): the\n * same inputs `createContentSnapshot` reads from a `PersistenceAdapter`, as\n * already-loaded values. Everything content-bearing is optional — an absent\n * piece simply resolves to \"not visible\", with the runtime's explicit\n * fallbacks (never a crash).\n */\nexport interface StaticContentData {\n projectId: string\n /** Locale configuration; defaults to English-only. */\n locales?: LocaleConfig\n /** Route records served by `resolvePage` (EC-019). */\n routes?: readonly RouteRecord[]\n /** Redirect records served by `resolvePage` (EC-019/020). */\n redirects?: readonly RedirectRecord[]\n collections?: readonly CollectionDef[]\n /**\n * Stored document sources. Either a bare `CmsDocument` (gated by its own\n * `state`) or a `DocumentHistory` carrying the live draft + the pinned\n * published snapshot (EC-224). Perspective gating happens in the pure\n * accessors (`selectPerspective`, EC-142): a `published` client sees a\n * history's pinned snapshot (or nothing), and never a bare `draft` row.\n */\n documents?: readonly ContentDocumentSource[]\n assets?: readonly AssetRecord[]\n /**\n * Resolve a serve URL for assets without a stored `url`. Defaults to an\n * explicit unresolved-placeholder scheme (never a silent empty string).\n */\n assetUrl?: (asset: AssetRecord) => string\n /**\n * Data-source definitions section bindings reference (EC-166 delivery).\n * Absent definitions degrade to unresolved bindings, never a crash.\n */\n sources?: readonly CanvasDataSource[]\n}\n\n/** Normalized pattern key: `/blog//x/` and `/blog/x` address the same URLs. */\nfunction patternKey(pattern: string): string {\n return '/' + splitPath(pattern).join('/')\n}\n\n/**\n * Merge stored route records with derived fallback routes (EC-177 gap 2):\n * stored records win per pattern+locale; fallback routes only fill patterns\n * the stored set does not cover. Never XOR — the first stored route must not\n * drop the implicit per-locale home-page fallback (or vice versa).\n *\n * Coverage rules mirror the router's locale matching (EC-018/019): a stored\n * locale-agnostic route (no `locale`) covers its pattern for every locale; a\n * locale-specific stored route covers only that locale, so fallbacks for the\n * other locales still apply.\n */\nexport function mergeRouteRecords(\n stored: readonly RouteRecord[],\n fallback: readonly RouteRecord[],\n): RouteRecord[] {\n const agnostic = new Set<string>()\n const localized = new Set<string>()\n for (const route of stored) {\n if (route.locale === undefined) agnostic.add(patternKey(route.pattern))\n else localized.add(`${route.locale}|${patternKey(route.pattern)}`)\n }\n const covered = (route: RouteRecord): boolean => {\n const key = patternKey(route.pattern)\n if (agnostic.has(key)) return true\n return route.locale !== undefined && localized.has(`${route.locale}|${key}`)\n }\n // Stored first: on equal specificity the router prefers earlier records.\n return [...stored, ...fallback.filter((route) => !covered(route))]\n}\n\n/**\n * Assemble a `ContentSource` from plain prefetched data — the pure half of\n * {@link createContentSnapshot}, shared with hosts that fetched the data\n * themselves (e.g. the EC-156 live delivery snapshot). Accessor semantics are\n * byte-identical across both paths: the same `ContentLookup` feeds the same\n * pure `@elytracms/core/content` client.\n */\nexport function createStaticContentSource(data: StaticContentData): ContentSnapshot {\n const locales = data.locales ?? DEFAULT_LOCALES\n const routes = data.routes ?? []\n const redirects = data.redirects ?? []\n const assetUrl =\n data.assetUrl ?? ((asset: AssetRecord) => `asset://unresolved/${asset.storageKey}`)\n\n const collections = new Map<string, CollectionDef>()\n for (const collection of data.collections ?? []) collections.set(collection.id, collection)\n\n const documents = new Map<string, ContentDocumentSource>()\n const byCollection = new Map<string, ContentDocumentSource[]>()\n for (const source of data.documents ?? []) {\n const doc = isDocumentHistory(source) ? source.draft : source\n documents.set(documentKey(doc), source)\n const list = byCollection.get(doc.collection) ?? []\n list.push(source)\n byCollection.set(doc.collection, list)\n }\n\n const assets = new Map<string, AssetRecord>()\n for (const record of data.assets ?? []) assets.set(record.id, record)\n\n const lookupFor = (_perspective: Perspective): ContentLookup => ({\n collection: (id) => collections.get(id),\n document: (ref: DocumentRef) => documents.get(documentKey(ref)),\n documents: (collectionId) => byCollection.get(collectionId) ?? [],\n asset: (id) => assets.get(id),\n assetUrl: (asset) => asset.url ?? assetUrl(asset),\n })\n\n const client = (init: { perspective: Perspective; locale?: Locale }): ContentClient =>\n createContentClient({\n lookup: lookupFor(init.perspective),\n context: createContentContext({\n locale: init.locale ?? locales.default,\n perspective: init.perspective,\n locales,\n }),\n routes,\n redirects,\n })\n\n return {\n projectId: data.projectId,\n locales,\n client,\n routes,\n // EC-195: the delivery-shaped assets, so the renderer can resolve an\n // `asset`-typed Image prop (an asset id) to a usable url + intrinsic\n // dimensions. Baked into the (serializable) render outcome by the route\n // helper, so a cached page keeps its images during a backend outage.\n assets: () =>\n [...assets.values()].map((record) => resolvedAsset(record, record.url ?? assetUrl(record))),\n ...(data.sources ? { sources: data.sources } : {}),\n }\n}\n\n/**\n * Prefetch a project's content from a `PersistenceAdapter` into an in-memory\n * `ContentSource`. The snapshot is a point-in-time view: load once per\n * request (or memoize across requests for fixture-backed sites) — accessors\n * never reach back to the adapter.\n */\nexport async function createContentSnapshot(\n adapter: PersistenceAdapter,\n projectId: string,\n options: ContentSnapshotOptions = {},\n): Promise<ContentSnapshot> {\n // --- Prefetch (the only async part) ------------------------------------\n const schema = await adapter.cms.findSchema(projectId)\n const documentRecords = await adapter.cms.listDocuments(projectId)\n const versionRecords = await adapter.cms.listAllDocumentVersions(projectId)\n const assetRecords = await adapter.assets.listAssets(projectId)\n // Redirects are editorial DATA (EC-303): read the ENABLED ones from the adapter's\n // redirects rail (projected to the routing `RedirectRecord`), like documents/assets\n // — NOT from config. An explicit `options.redirects` still overrides (fixtures/tests).\n const redirectRecords = await adapter.redirects.listRedirects(projectId)\n const redirects: RedirectRecord[] = redirectRecords\n .filter((record) => record.enabled)\n .map((record) => ({\n id: record.id,\n from: record.from,\n to: record.to,\n permanent: record.permanent,\n }))\n\n // Hybrid sources (EC-224): a `publishedVersion` pointer yields a\n // `DocumentHistory` (draft = the live row, published = the pinned snapshot);\n // an unpinned record stays a bare `CmsDocument` gated by its `state`.\n // Backward-compatible — pre-pointer data resolves exactly as before.\n const versionsByKey = new Map<string, Map<number, CmsDocument>>()\n for (const record of versionRecords) {\n const key = `${record.collection}:${record.docId}`\n let byVersion = versionsByKey.get(key)\n if (!byVersion) {\n byVersion = new Map()\n versionsByKey.set(key, byVersion)\n }\n byVersion.set(record.version, record.snapshot)\n }\n const documents: ContentDocumentSource[] = documentRecords.map((record) => {\n if (record.publishedVersion === undefined) return record.document\n // A dangling pin under-serves to `null` for `published` — never the draft.\n const published = versionsByKey\n .get(`${record.document.collection}:${record.document.id}`)\n ?.get(record.publishedVersion)\n return { draft: record.document, published, versions: [] }\n })\n\n // --- Assemble via the shared pure path ----------------------------------\n // Captured once: `BlobStorageAdapter.url` is synchronous by contract.\n return createStaticContentSource({\n projectId,\n ...(options.locales ? { locales: options.locales } : {}),\n ...(options.routes ? { routes: options.routes } : {}),\n redirects: options.redirects ? [...options.redirects] : redirects,\n ...(options.sources ? { sources: options.sources } : {}),\n ...(schema ? { collections: schema.collections } : {}),\n documents,\n assets: assetRecords,\n assetUrl: (asset) => adapter.blobs.url(asset.storageKey),\n })\n}\n","import { splitPath } from '@elytracms/core/cms-core'\nimport type { Locale, LocaleConfig } from '@elytracms/core/cms-core'\nimport { cacheTags } from '@elytracms/core/content'\nimport type {\n CacheTags,\n ContentClient,\n Perspective,\n ResolvedAsset,\n ResolvePageResult,\n} from '@elytracms/core/content'\nimport type { ComponentNode } from '@elytracms/core/project-graph'\nimport type { ComponentRegistry } from '@elytracms/core/component-registry'\nimport {\n collectReferencedAssetIds,\n collectReferencedListings,\n collectReferencedRelations,\n collectReferencedRichTextLinks,\n} from '@elytracms/core/runtime-renderer'\nimport type { ListingQuery, RelationTarget, ResolveRelation } from '@elytracms/core/runtime-renderer'\nimport type { BindingPayloads } from './payloads'\nimport { mergeCacheTags } from './source'\nimport type { ContentSource } from './source'\nimport { materializeSourcePayloads } from './source-payloads'\nimport { compositionNodesOf, defaultBindingPayloads } from './canvas-renderer'\n\n/**\n * The pure half of the catch-all route helper (EC-144): URL → outcome, with\n * no Next.js imports — so redirects, 404s, locale handling, payload assembly,\n * and tag merging are all unit-testable as plain functions. `route.tsx` maps\n * each outcome onto `redirect()` / `permanentRedirect()` / `notFound()` /\n * `<CanvasRenderer />`.\n */\n\n/** What the host's payload factory sees for one request. */\nexport interface CanvasPayloadContext {\n /** Accessor client bound to this request's perspective + locale. */\n client: ContentClient\n result: ResolvePageResult\n perspective: Perspective\n /** The normalized request path (locale prefix stripped). */\n path: string\n params: Record<string, string>\n /**\n * Register the `CacheTags` of any extra accessor call this factory makes\n * (e.g. `listDocuments`) so they join the request's merged tag set — the\n * EC-146 invalidation hook sees everything the request actually read.\n */\n addTags(tags: CacheTags): void\n}\n\n/**\n * Builds the binding payloads for a page render. The defaults\n * (`document`, `params`) are always present; factory entries win on conflict.\n */\nexport type CanvasPayloadsFactory = (\n ctx: CanvasPayloadContext,\n) => BindingPayloads | Promise<BindingPayloads>\n\nexport type CanvasPageOutcome =\n | { kind: 'redirect'; target: string; permanent: boolean; tags: CacheTags }\n | { kind: 'not-found'; tags: CacheTags }\n | {\n kind: 'render'\n result: ResolvePageResult\n payloads: BindingPayloads\n /**\n * The delivery-shaped assets the page may reference (EC-195). Baked into\n * the outcome (serializable) so the renderer resolves `asset`-typed Image\n * props to a url + intrinsic dimensions, and a cached page keeps its\n * images during a backend outage.\n */\n assets: readonly ResolvedAsset[]\n /**\n * The composition-node `relation` props this page references, populated to\n * depth-1 delivery shape and keyed `collection:id` (EC-254). Baked into the\n * outcome (serializable) so `<CanvasRenderer />` rebuilds\n * `RenderContext.resolveRelation` from it inside the RSC — a function (the\n * content client) cannot ride the data cache or cross the RSC boundary, so\n * the data is baked exactly as the page-scoped `assets` list is.\n */\n relations: Record<string, RelationTarget>\n /**\n * The documents each `listing` block on this page resolved to (EC-255),\n * keyed by serialized query. Baked into the outcome (serializable) so\n * `<CanvasRenderer />` rebuilds `RenderContext.resolveListing` from it inside\n * the RSC — like `relations`, because the content client that runs the query\n * cannot ride the data cache or cross the RSC boundary. A listing depends on\n * collection MEMBERSHIP (a product joining/leaving the category), so its\n * invalidation rides the per-query `listDocuments` tags merged into `tags`.\n */\n listings: Record<string, RelationTarget[]>\n /**\n * The public URL path of every document a rich-text prop on this page LINKS\n * to (EC-291), keyed `collection:id`. Baked into the outcome (serializable) so\n * `<CanvasRenderer />` rebuilds `RenderContext.resolveLink` from it inside the\n * RSC — like `relations`, because the content client that derives the URL\n * (`resolveLink` → `urlForDocument`) cannot ride the data cache or cross the\n * RSC boundary. A link depends on the target's IDENTITY (its slug/parent →\n * path), so its invalidation rides the per-link doc tags merged into `tags`:\n * renaming, re-parenting, or first-publishing a linked document re-bakes the\n * embedding page's href.\n */\n links: Record<string, string>\n tags: CacheTags\n }\n\n/** Build the request path from a Next catch-all `slug` param. */\nexport function pathFromSlug(slug: readonly string[] | undefined): string {\n return '/' + (slug ?? []).join('/')\n}\n\n/**\n * Derive the request locale from a leading URL segment (`/de/about` → locale\n * `de`, path `/about`) and return the remaining path. No prefix (or the\n * default locale's own content at root) falls back to the default locale.\n */\nexport function splitLocalePath(\n url: string,\n locales: LocaleConfig,\n): { locale: Locale; path: string } {\n const segments = splitPath(url)\n const first = segments[0]\n if (first !== undefined && first !== locales.default && locales.locales.includes(first)) {\n return { locale: first, path: '/' + segments.slice(1).join('/') }\n }\n return { locale: locales.default, path: '/' + segments.join('/') }\n}\n\nexport interface ResolveCanvasPageOptions {\n payloads?: CanvasPayloadsFactory\n /**\n * Component registry (EC-205): when provided, the baked {@link CanvasPageOutcome}\n * `assets` are PAGE-SCOPED to exactly the asset ids this page's composition +\n * layout resolve through `resolveAsset` — not the whole project asset list,\n * which otherwise rides in every page's cache entry + RSC payload. Omitted →\n * all source assets (back-compat). Scoping mirrors the renderer's asset\n * resolution exactly, so no referenced image is ever dropped.\n */\n registry?: ComponentRegistry\n}\n\n/**\n * Page-scope the baked assets to those the page actually resolves (EC-205): the\n * static `asset`-typed props of its composition + selected layout tree. Document\n * asset FIELDS resolve into the document payload separately, and bound asset\n * props resolve through bindings — neither uses this list, so neither widens it.\n */\nfunction scopeAssetsToPage(\n allAssets: readonly ResolvedAsset[],\n registry: ComponentRegistry,\n result: ResolvePageResult,\n resolveRelation: ResolveRelation,\n): readonly ResolvedAsset[] {\n if (allAssets.length === 0) return allAssets\n const ids = new Set<string>()\n // EC-270: pass `resolveRelation` so the collector follows a Reusable block's\n // `element` pick into the referenced document and page-scopes the asset ids\n // inside its transcluded `content` — otherwise a transcluded image is baked\n // nowhere and renders empty on the host (the relation bake already transcludes).\n const seen = new Set<string>()\n for (const node of compositionNodesOf(result.document)) {\n collectReferencedAssetIds(node, registry, ids, resolveRelation, seen)\n }\n // EC-202: the OG image is an asset the page uses (for its `og:image` meta), so\n // it joins the page-scoped set — (EC-227) tagged for invalidation when that\n // asset record is edited. EC-266: a `type:'asset'` seoOgImage field is delivered\n // as a ResolvedAsset OBJECT ({ id, url }); a string is a raw id (or a passthrough\n // URL, which has no asset id to tag). Take the id from whichever shape.\n const ogImage = result.document?.['seoOgImage']\n const ogImageId =\n typeof ogImage === 'string'\n ? ogImage\n : ogImage && typeof ogImage === 'object' && typeof (ogImage as { id?: unknown }).id === 'string'\n ? (ogImage as { id: string }).id\n : null\n if (ogImageId) ids.add(ogImageId)\n return ids.size === 0 ? [] : allAssets.filter((asset) => ids.has(asset.id))\n}\n\n/** The page's composition nodes (EC-254 relation scan). EC-287: no layout root. */\nfunction pageCompositionNodes(result: ResolvePageResult): ComponentNode[] {\n return [...compositionNodesOf(result.document)]\n}\n\n/**\n * Populate every composition-node `relation` prop the page references to depth-1,\n * keyed `collection:id` (EC-254). Walks the page composition + layout (and, through\n * `collectReferencedRelations`, transcluded reusable content) and resolves each ref\n * through the request's client. Empty when no registry is supplied (the collector\n * needs manifests to know which props are relations) — relation props then pass\n * through raw, the graceful degradation a host without a registry already gets.\n *\n * `docKeys` carries the `collection:id` of every referenced pick (resolved or not),\n * so the caller cache-tags the page by them (EC-146): editing/publishing a picked\n * document — including a previously-unpublished one that should now appear — drops\n * exactly the pages that embed it. A fixed pick depends on the document's identity,\n * not on its collection's membership, so no coarse collection tag is added.\n */\nfunction populatePageRelations(\n result: ResolvePageResult,\n client: ContentClient,\n registry: ComponentRegistry | undefined,\n): { relations: Record<string, RelationTarget>; docKeys: string[] } {\n if (!registry) return { relations: {}, docKeys: [] }\n const refKeys = new Set<string>()\n const relations = collectReferencedRelations(\n pageCompositionNodes(result),\n registry,\n (ref) => client.resolveRelation(ref),\n {},\n refKeys,\n )\n return { relations, docKeys: [...refKeys] }\n}\n\n/**\n * Resolve every `listing` block on the page to its matching documents (EC-255),\n * keyed by serialized query for `<CanvasRenderer />` to rebuild `resolveListing`.\n * Runs each listing's query through the request's client (so perspective + locale\n * match the rest of the resolution — published-only on a live page, per AD-5), and\n * returns the per-query `listDocuments` `CacheTags` so the caller folds them into\n * the page's tag set: those carry both the COLLECTION tag (membership — a product\n * joining/leaving the category re-renders the grid) and the listed documents' own\n * tags (a member's content edit re-renders it). Empty when no registry is supplied\n * (the collector needs manifests to know which blocks declare a listing).\n */\nfunction populatePageListings(\n result: ResolvePageResult,\n client: ContentClient,\n registry: ComponentRegistry | undefined,\n): { listings: Record<string, RelationTarget[]>; tags: CacheTags[] } {\n if (!registry) return { listings: {}, tags: [] }\n const tags: CacheTags[] = []\n const listings = collectReferencedListings(\n pageCompositionNodes(result),\n registry,\n (query: ListingQuery) => {\n const listed = client.listDocuments(query.collection, {\n where: query.where,\n ...(query.sort ? { sort: query.sort } : {}),\n ...(query.limit !== undefined ? { limit: query.limit } : {}),\n })\n tags.push(listed.tags)\n return listed.ok ? (listed.documents as RelationTarget[]) : []\n },\n // EC-255: reach listings nested inside transcluded reusable content (the same\n // depth-1 populate the relation bake uses), so a grid inside a reusable bakes —\n // and its membership tag is folded in — instead of rendering empty on the host.\n (ref) => client.resolveRelation(ref),\n )\n return { listings, tags }\n}\n\n/**\n * Resolve every internal rich-text LINK on the page to its target document's URL\n * path (EC-291), keyed `collection:id` for `<CanvasRenderer />` to rebuild\n * `resolveLink`. Collects the referenced doc refs from the page's rich-text props\n * (transclusion-aware) and derives each URL through the request's client\n * (`resolveLink` → `urlForDocument`), so the path matches what the same routes serve.\n * A ref that resolves to no live URL (unpublished target / no addressing route) is\n * simply omitted — the renderer then shows the EC-290 `unresolved-ref` issue.\n *\n * `docKeys` carries EVERY referenced target (resolved or not), so the caller cache-\n * tags the page by them (EC-146): publishing or renaming a linked document — including\n * one not yet published when the page was baked — drops exactly the embedding pages.\n * Empty when no registry is supplied (the collector needs no manifest, but the bake\n * stays consistent with its relation/listing siblings, which do).\n */\nfunction populatePageLinks(\n result: ResolvePageResult,\n client: ContentClient,\n registry: ComponentRegistry | undefined,\n): { links: Record<string, string>; docKeys: string[] } {\n if (!registry) return { links: {}, docKeys: [] }\n const refs = collectReferencedRichTextLinks(\n pageCompositionNodes(result),\n registry,\n (ref) => client.resolveRelation(ref),\n )\n const links: Record<string, string> = {}\n for (const [key, ref] of Object.entries(refs)) {\n const url = client.resolveLink(ref)\n if (url !== null) links[key] = url\n }\n return { links, docKeys: Object.keys(refs) }\n}\n\n/**\n * Resolve one request URL against a content source: split the locale, run\n * `resolvePage` in the requested perspective, assemble binding payloads, and\n * merge every accessor's `CacheTags` into one deterministic set. Pure — all\n * data was prefetched by the source.\n */\nexport async function resolveCanvasPage(\n source: ContentSource,\n url: string,\n perspective: Perspective,\n options: ResolveCanvasPageOptions = {},\n): Promise<CanvasPageOutcome> {\n const { locale, path } = splitLocalePath(url, source.locales)\n const client = source.client({ perspective, locale })\n const result = client.resolvePage(path)\n\n if (result.status === 'redirect' && result.redirect) {\n return {\n kind: 'redirect',\n target: result.redirect.target,\n permanent: result.redirect.permanent,\n tags: result.tags,\n }\n }\n\n if (result.status !== 'ok') {\n return { kind: 'not-found', tags: result.tags }\n }\n\n const extraTags: CacheTags[] = []\n let payloads: BindingPayloads = defaultBindingPayloads(result)\n\n // EC-166 delivery: materialize template-page documents and replay each\n // referenced repeating-section query (stored where/sort/limit) through this\n // request's client — published perspective and ambient locale included.\n // Section list tags join the merged set (fetch-time doc tags + collection).\n const materialized = materializeSourcePayloads({\n client,\n result,\n sources: source.sources ?? [],\n })\n payloads = { ...payloads, ...materialized.payloads }\n extraTags.push(...materialized.tags)\n\n if (options.payloads) {\n const custom = await options.payloads({\n client,\n result,\n perspective,\n path,\n params: result.dynamicParams,\n addTags: (tags) => extraTags.push(tags),\n })\n payloads = { ...payloads, ...custom }\n }\n\n const allAssets = source.assets?.() ?? []\n // EC-205: page-scope the baked assets when a registry is supplied (the route\n // helper passes it); else keep the full list (back-compat).\n const bakedAssets = options.registry\n ? scopeAssetsToPage(allAssets, options.registry, result, (ref) =>\n client.resolveRelation(ref),\n )\n : allAssets\n // EC-227: tag the cache entry with every asset it baked, so editing an asset\n // record (alt/dimensions/re-upload) drops exactly the pages carrying it. The\n // locale is irrelevant for asset tags (an asset record is locale-agnostic) —\n // `cacheTags` just needs one; `result.tags.locale` is the page's.\n const assetTags = cacheTags({\n assets: bakedAssets.map((asset) => asset.id),\n locale: result.tags.locale,\n })\n // EC-254: populate the relation props of the nodes inside the page's blocks\n // (e.g. a ProductGrid's picked products), keyed for `<CanvasRenderer />` to\n // rebuild `resolveRelation`. Reuses the request's client, so perspective +\n // locale match the rest of the resolution.\n const { relations, docKeys: relationDocKeys } = populatePageRelations(\n result,\n client,\n options.registry,\n )\n // EC-146: tag the page by every picked document so editing/publishing one drops\n // the embedding page (the locale is the page's; doc tags are locale-agnostic).\n const relationTags = cacheTags({ docs: relationDocKeys, locale: result.tags.locale })\n // EC-255: resolve every listing block's query (e.g. a ProductGrid keyed to a\n // category) and bake the result keyed by serialized query. The per-query\n // `listDocuments` tags (collection membership + listed docs) join the merged set,\n // so adding/removing a member or editing one invalidates the embedding page.\n const { listings, tags: listingTags } = populatePageListings(\n result,\n client,\n options.registry,\n )\n // EC-291: resolve every internal rich-text link to its target's URL path and bake\n // it for `<CanvasRenderer />` to rebuild `resolveLink`. Tag the page by each linked\n // document so renaming/re-parenting/first-publishing a target re-bakes the href.\n const { links, docKeys: linkDocKeys } = populatePageLinks(result, client, options.registry)\n const linkTags = cacheTags({ docs: linkDocKeys, locale: result.tags.locale })\n return {\n kind: 'render',\n result,\n payloads,\n assets: bakedAssets,\n relations,\n listings,\n links,\n tags: mergeCacheTags(\n result.tags,\n ...extraTags,\n ...listingTags,\n assetTags,\n relationTags,\n linkTags,\n ),\n }\n}\n","import type { CacheTags } from '@elytracms/core/content'\n\n/**\n * Cache-tag pipeline (EC-146, vision AD-5) — the pure half.\n *\n * This module defines (a) the **canonical Next.js tag string format** mapping\n * the accessor-level `CacheTags` (EC-143) onto `revalidateTag` keys, and (b)\n * the **tag-discovery caching logic** the catch-all route helper runs inside\n * `unstable_cache`. No Next.js imports — everything here is unit-testable;\n * `route.tsx` injects the real `unstable_cache` via {@link CacheWrapper}.\n *\n * ## Tag format\n *\n * - `doc:<collection>:<id>` — one per document whose content was actually in\n * the response (fetch-time tagging: includes depth-1 populated relation\n * targets, and documents inside filtered/dynamic lists *after* the filter\n * ran).\n * - `collection:<name>:<locale>` — the coarse membership tag: every response\n * that read from a collection carries it, so create/delete/newly-matching\n * documents sweep cached lists without read-set tracking.\n * - `route:<pattern>:<locale>` — the resolved URL path plus every hop of a\n * redirect chain.\n * - `asset:<id>` — one per asset whose delivery shape the page *baked*\n * (page-scoped images + `seoOgImage`, EC-227); editing that asset record\n * (alt/dimensions/re-upload) drops exactly the pages that baked it. Not\n * locale-scoped — an asset record is locale-agnostic.\n * - `project` — the whole-project sweep tag attached to **every** cached\n * entry; graph publish/unpublish emits it (a layout or route change can\n * affect any page, so the honest v1 fallback is a full project sweep).\n *\n * ## Project scope\n *\n * Every tag is prefixed `p:<projectId>:` when a scope is configured (e.g.\n * `p:prj_aurora:doc:post:post-1`). The cost is a few bytes per tag and it\n * keeps multi-project hosts (one Next app serving several builder projects)\n * from cross-invalidating, so the prefix is **on whenever the host knows its\n * project id** — decision: include it. The emitter (the studio's webhook\n * dispatcher, `apps/builder/src/lib/webhooks`) always scopes with the\n * operation's `projectId`; a host that omits `cache.scope` therefore will not\n * match studio-emitted tags. Configure `cache.scope` with the same project id\n * the studio publishes under.\n *\n * The studio-side emitter cannot depend on this package (it would drag the\n * `next` peer dependency into the builder), so\n * `apps/builder/src/lib/webhooks/tags.ts` mirrors these formatters; tests on\n * both sides pin the exact literal strings to keep them in lock-step.\n */\n\n/** Apply the optional multi-project scope prefix to one tag. */\nexport function scopeCacheTag(tag: string, scope?: string): string {\n return scope === undefined || scope.length === 0 ? tag : `p:${scope}:${tag}`\n}\n\n/**\n * Tag for one document identity. `docKey` is the EC-143 `documentKey` string\n * (`<collection>:<id>`), exactly as found in `CacheTags.docs`.\n */\nexport function docCacheTag(docKey: string, scope?: string): string {\n return scopeCacheTag(`doc:${docKey}`, scope)\n}\n\n/** The coarse membership tag of one collection in one locale. */\nexport function collectionCacheTag(collection: string, locale: string, scope?: string): string {\n return scopeCacheTag(`collection:${collection}:${locale}`, scope)\n}\n\n/** Tag for one resolved route path (or redirect-chain hop) in one locale. */\nexport function routeCacheTag(pattern: string, locale: string, scope?: string): string {\n return scopeCacheTag(`route:${pattern}:${locale}`, scope)\n}\n\n/**\n * Tag for one baked asset (EC-227). `assetId` is the bare asset id, as found in\n * `CacheTags.assets`. Not locale-scoped: an asset record is one row shared\n * across locales, so an edit invalidates the baking pages in every locale.\n */\nexport function assetCacheTag(assetId: string, scope?: string): string {\n return scopeCacheTag(`asset:${assetId}`, scope)\n}\n\n/**\n * The whole-project sweep tag. Attached to every cached page entry; emitted\n * on graph publish/unpublish (and as the emitter's honest fallback when a\n * change's precise tag set is unknowable).\n */\nexport function projectSweepTag(scope?: string): string {\n return scopeCacheTag('project', scope)\n}\n\n/**\n * Map an accessor-level `CacheTags` (what one request actually read) onto the\n * full, deterministic (sorted, deduplicated) set of Next tag strings for the\n * cache entry — including the project sweep tag.\n */\nexport function nextCacheTags(tags: CacheTags, scope?: string): string[] {\n const all = new Set<string>()\n all.add(projectSweepTag(scope))\n for (const docKey of tags.docs) all.add(docCacheTag(docKey, scope))\n for (const collection of tags.collections) {\n all.add(collectionCacheTag(collection, tags.locale, scope))\n }\n for (const route of tags.routes) all.add(routeCacheTag(route, tags.locale, scope))\n for (const assetId of tags.assets) all.add(assetCacheTag(assetId, scope))\n return [...all].sort()\n}\n\n// --- Tag-discovery caching over `unstable_cache` ------------------------------\n\n/**\n * The slice of `unstable_cache` the discovery logic needs, injectable so the\n * logic is testable against a faithful in-memory model (and so the test model\n * can mirror the real semantics this design depends on — see below).\n */\nexport interface CacheWrapperOptions {\n tags: string[]\n /** `false` = never expire by time (tag-driven invalidation only). */\n revalidate: number | false\n}\n\nexport type CacheWrapper = <T>(\n cb: () => Promise<T>,\n keyParts: string[],\n options: CacheWrapperOptions,\n) => () => Promise<T>\n\n/** What one cached request stores: the outcome plus its own discovered tags. */\nexport interface CachedEntry<T> {\n value: T\n /** The Next tag strings discovered at fetch time by the run that wrote this entry. */\n tags: string[]\n}\n\n/**\n * Internal sentinel: thrown by the probe callback after a cache **miss** ran\n * the loader, so `unstable_cache` never persists the entry under the\n * incomplete baseline tag set (a thrown callback caches nothing).\n */\nclass CacheDiscoveryBail extends Error {\n constructor() {\n super('elytra cache discovery bail (never user-visible)')\n this.name = 'CacheDiscoveryBail'\n }\n}\n\n/**\n * Both the probe and the write wrapper get their callback from this single\n * factory, so the two callbacks have **identical source text**. This matters:\n * `unstable_cache` derives its cache key from `cb.toString()` + `keyParts`,\n * so identical source is what makes the write pass store the entry under the\n * exact key future probe passes read.\n */\nfunction passthrough<T>(impl: () => Promise<T>): () => Promise<T> {\n return async () => impl()\n}\n\n/**\n * Fetch-time tag discovery over `unstable_cache` — the heart of EC-146.\n *\n * The problem: `unstable_cache` fixes an entry's tags when the *wrapper* is\n * created (`options.tags` is validated and **copied** at construction time in\n * Next 15 — mutating the array during the callback does not propagate), but\n * the correct tags are only known *after* the loader resolved the page. So a\n * single wrapper can never both (a) run the loader and (b) store the result\n * under the tags that run discovered.\n *\n * The design (\"resolve once, cache with discovered tags, serve cached\n * thereafter\") uses two wrapper constructions per request around **one**\n * cache entry:\n *\n * 1. **Probe pass** — a wrapper keyed by `keyParts` whose callback runs the\n * loader, captures the result + its discovered tags into the closure, and\n * then throws an internal sentinel.\n * - Cache **hit**: the stored entry (written by a previous request with\n * its full discovered tags) is returned; the callback — and therefore\n * the loader and any backend access — never runs. This is the outage\n * story: fully cached routes keep serving when the backend is down.\n * - Cache **miss**: the loader runs exactly once; the sentinel throw\n * prevents `unstable_cache` from persisting the entry under the\n * incomplete baseline tags (thrown callbacks cache nothing).\n * 2. **Write pass** (miss only) — a second wrapper is constructed *now that\n * the tags are known*, with `options.tags` = the discovered set, same key.\n * Its callback just returns the already-loaded entry, so the backend is\n * not hit again; `unstable_cache` persists the entry under the full\n * fetch-time tag set. `revalidateTag` on any of those tags drops the\n * entry and the next request repeats the cycle with fresh data.\n *\n * The loader runs **once per revalidation cycle** (per key), never once per\n * request. Time-based revalidation is intentionally not exposed: a\n * stale-while-revalidate background refresh would re-run the probe callback\n * (whose bail aborts the refresh), so this design is tag-driven only —\n * `revalidate: false` — which is exactly the AD-5 model.\n *\n * Concurrency: wrappers and the captured closure are per-request, so there is\n * no cross-request mutation; two racing first requests both resolve and the\n * last write wins (deterministic content ⇒ identical entries).\n */\nexport async function loadCachedEntry<T>(\n cache: CacheWrapper,\n keyParts: string[],\n baselineTags: readonly string[],\n load: () => Promise<CachedEntry<T>>,\n): Promise<CachedEntry<T>> {\n let fresh: CachedEntry<T> | undefined\n\n const probe = cache(\n passthrough(async (): Promise<CachedEntry<T>> => {\n fresh = await load()\n throw new CacheDiscoveryBail()\n }),\n keyParts,\n { tags: [...baselineTags], revalidate: false },\n )\n\n try {\n return await probe()\n } catch (error) {\n // Loader failures (backend down on a cold cache) propagate to the caller\n // — explicit, never silently cached. Only our own sentinel is absorbed.\n if (!(error instanceof CacheDiscoveryBail)) throw error\n }\n\n // Miss path: `fresh` was assigned before the sentinel was thrown.\n const entry = fresh as CachedEntry<T>\n const write = cache(\n passthrough(async () => entry),\n keyParts,\n { tags: entry.tags, revalidate: false },\n )\n return write()\n}\n","import type { Metadata } from 'next'\nimport type { ResolvedAsset, ResolvePageResult } from '@elytracms/core/content'\n\n/**\n * Resolved page → Next.js `Metadata` (EC-171, reshaped by EC-187). SEO now\n * lives on the resolved **document**: a `page`-collection document carries flat\n * `seo*` fields (`seoTitle`, `seoDescription`, `seoOgTitle`, `seoOgImage`,\n * `seoNoindex`); a content-collection document falls back to its `title`. There\n * is no separate page-graph `seo` block anymore.\n *\n * ```ts\n * // app/[[...slug]]/page.tsx — generateMetadata already applies this helper:\n * export const generateMetadata = route.generateMetadata\n * ```\n *\n * Mapping (in fallback order):\n * - `title`: `seoTitle` → document `name`/`title`.\n * - `description`: `seoDescription`.\n * - `openGraph`: OG title (`seoOgTitle` → effective title), description, and the\n * OG image URL (`seoOgImage`).\n * - `robots`: `seoNoindex` → `{ index: false }`.\n * - `alternates.canonical`: `seoCanonical` (EC-228) — an absolute or\n * root-relative URL, passed through verbatim. Real Sanity sites declare one per\n * page; omitted when unset so Next applies its own default.\n *\n * `hreflang` language alternates are intentionally NOT derived here: correct\n * hreflang needs a per-page translation map (which locale variants actually\n * exist), and auto-deriving from configured locales would emit alternates for\n * translations that don't exist — an SEO anti-pattern. Tracked as a follow-up.\n *\n * `seoOgImage` resolution (EC-202): the field holds either an absolute URL or\n * an **asset id**. An asset id is resolved to its delivery URL against the\n * page's baked `assets` (the same page-scoped set the renderer gets, widened to\n * include the OG asset in `route-core`). An asset id that can't be resolved is\n * **dropped** rather than emitted — an `<meta property=\"og:image\">` must carry a\n * real URL, never leak an internal id.\n *\n * Pure data-in/data-out — safe inside `generateMetadata` on both the cached\n * and uncached paths.\n */\nfunction str(value: unknown): string | null {\n return typeof value === 'string' && value.length > 0 ? value : null\n}\n\n/** An already-resolvable image URL (absolute or root-relative), not an asset id. */\nfunction looksLikeUrl(value: string): boolean {\n return /^(https?:)?\\/\\//.test(value) || value.startsWith('/')\n}\n\n/**\n * Resolve a `seoOgImage` field value to a URL: a delivery-resolved asset OBJECT →\n * its `url` (EC-266); a URL string → passed through; a raw asset-id string →\n * resolved against the baked assets; anything unresolvable → dropped (EC-202).\n */\nfunction resolveOgImage(value: unknown, assets: readonly ResolvedAsset[]): string | null {\n // EC-266: a `seoOgImage` modelled as a `type:'asset'` FIELD (e.g. Konditorei,\n // migrated from Sanity) is resolved by delivery to a ResolvedAsset OBJECT\n // ({ id, url, … }), NOT a string — so read its `url`. A string value is the\n // legacy shape: a passthrough URL, or a raw asset id resolved against the baked\n // assets. A `str()`-only path turned the object into null, dropping og:image.\n if (value && typeof value === 'object') {\n const url = (value as { url?: unknown }).url\n return typeof url === 'string' && url.length > 0 ? url : null\n }\n if (typeof value !== 'string' || value.length === 0) return null\n if (looksLikeUrl(value)) return value\n return assets.find((asset) => asset.id === value)?.url ?? null\n}\n\nexport function canvasPageMetadata(\n result: ResolvePageResult,\n assets: readonly ResolvedAsset[] = [],\n): Metadata {\n const doc = result.document\n\n const seoTitle = str(doc?.['seoTitle'])\n const seoDescription = str(doc?.['seoDescription'])\n const seoOgTitle = str(doc?.['seoOgTitle'])\n const seoOgImage = resolveOgImage(doc?.['seoOgImage'], assets)\n const seoNoindex = doc?.['seoNoindex'] === true\n const seoCanonical = str(doc?.['seoCanonical'])\n\n // Fallback title: the page document's `name`, or a content document's `title`.\n const docTitle = str(doc?.['name']) ?? str(doc?.['title'])\n const title = seoTitle ?? docTitle\n\n const metadata: Metadata = {}\n if (title !== null) metadata.title = title\n if (seoDescription) metadata.description = seoDescription\n\n const ogTitle = seoOgTitle ?? title\n if (ogTitle !== null || seoDescription || seoOgImage) {\n metadata.openGraph = {\n ...(ogTitle !== null ? { title: ogTitle } : {}),\n ...(seoDescription ? { description: seoDescription } : {}),\n ...(seoOgImage ? { images: [{ url: seoOgImage }] } : {}),\n }\n }\n\n if (seoNoindex) metadata.robots = { index: false }\n\n // EC-228: a page-declared canonical URL. Passed through verbatim (absolute or\n // root-relative); Next resolves it against `metadataBase` when relative.\n if (seoCanonical) metadata.alternates = { canonical: seoCanonical }\n\n return metadata\n}\n","import type { Metadata } from 'next'\nimport { unstable_cache } from 'next/cache'\nimport { draftMode } from 'next/headers'\nimport { notFound, permanentRedirect, redirect } from 'next/navigation'\nimport type { ReactNode } from 'react'\nimport type { CacheTags, Perspective, ResolvedAsset, ResolvePageResult } from '@elytracms/core/content'\nimport { loadCachedEntry, nextCacheTags, projectSweepTag } from './cache'\nimport type { CacheWrapper } from './cache'\nimport { CanvasRenderer } from './canvas-renderer'\nimport { canvasPageMetadata } from './metadata'\nimport type { HostComponents } from './components'\nimport { pathFromSlug, resolveCanvasPage } from './route-core'\nimport type { CanvasPageOutcome, CanvasPayloadsFactory } from './route-core'\nimport type { ContentSource } from './source'\n\n/**\n * Catch-all route helper (EC-144): the factory a host app calls once in\n * `app/[[...slug]]/page.tsx` to wire `resolvePage` → `<CanvasRenderer />`,\n * with redirects answered by Next's `redirect()`/`permanentRedirect()` (per\n * the route's `permanent` flag), unknown URLs answered by `notFound()` (the\n * host's 404 renders), and the perspective chosen by Next `draftMode()` —\n * draft when enabled (via the token-gated preview route), published\n * otherwise.\n *\n * With `cache` configured (EC-146), the published-perspective resolve+render\n * data work runs inside `unstable_cache`, keyed by URL and tagged with the\n * fetch-time tag set of what the response actually contained (see\n * `cache.ts`). Publishing in the studio then invalidates exactly the affected\n * entries via the signed `/api/revalidate` webhook — and while the content\n * backend is unreachable, cached entries keep serving because a cache hit\n * never invokes `loadContent`.\n */\n\nexport interface CanvasRequestInfo {\n /** The raw request path (including any locale prefix). */\n url: string\n perspective: Perspective\n}\n\nexport interface CanvasCacheOptions {\n /**\n * Project scope prefix for every tag (`p:<scope>:…`) — must be the project\n * id the studio publishes under, so the webhook dispatcher's tags match.\n * Omit only when the emitter also emits unscoped tags (see `cache.ts`).\n */\n scope?: string\n}\n\n/**\n * What the route helper tells the content loader about the request it is\n * loading for (EC-156). Loaders that serve both perspectives from one\n * prefetched source (the fixture snapshot) can ignore it; a live loader uses\n * it to fetch the draft-perspective snapshot only for draft-mode requests —\n * it must NOT call request APIs like `draftMode()` itself, because on the\n * cached published path the loader runs inside `unstable_cache`, where\n * dynamic request APIs are unavailable.\n */\nexport interface CanvasContentRequest {\n perspective: Perspective\n}\n\nexport interface CanvasRouteOptions {\n /**\n * Async content loader — the seam EC-145/146 plug Convex into. For the\n * fixture-backed example this memoizes a `createContentSnapshot` call.\n * Invoked per request; cache/memoize inside the loader as appropriate.\n * With `cache` configured it only runs on a cache miss (once per\n * revalidation cycle) — cache hits never touch the content backend.\n * Receives the request's perspective (see {@link CanvasContentRequest});\n * zero-arg loaders remain valid.\n */\n loadContent: (request: CanvasContentRequest) => Promise<ContentSource>\n /** Host component surface from `defineHostComponents`. */\n components: HostComponents\n /** Extra binding payloads per request (e.g. `listDocuments` for a list page). */\n payloads?: CanvasPayloadsFactory\n /**\n * EC-146 instant publish: cache the published-perspective resolution in\n * Next's data cache (`unstable_cache`), tagged with the response's own\n * fetch-time tags, invalidated by the `/api/revalidate` webhook. Draft mode\n * always bypasses this cache entirely. Tag-driven only — no time-based\n * revalidation (the AD-5 model). Cached values are JSON-serialized, so\n * payload factories must return plain data on the cached path.\n */\n cache?: CanvasCacheOptions\n /**\n * EC-146 hook: receives the merged `CacheTags` of everything this request\n * read (the `resolvePage` tags plus any tags the payload factory\n * registered via `addTags`). On a cache hit these are the stored tags of\n * the run that wrote the entry.\n */\n onTags?: (tags: CacheTags, info: CanvasRequestInfo) => void\n /** Override the generated `<head>` metadata for a resolved page. */\n metadata?: (result: ResolvePageResult, info: CanvasRequestInfo) => Metadata\n}\n\nexport interface CanvasRouteProps {\n params: Promise<{ slug?: string[] }>\n}\n\nexport interface CanvasRoute {\n /** The page component: `export default route.Page`. */\n Page: (props: CanvasRouteProps) => Promise<ReactNode>\n /** Next metadata hook: `export const generateMetadata = route.generateMetadata`. */\n generateMetadata: (props: CanvasRouteProps) => Promise<Metadata>\n}\n\n/**\n * Default metadata (EC-171): the page's canonical SEO fields — title,\n * description, OG tags, robots noindex — with document-title / page-name\n * fallbacks. `export const generateMetadata = route.generateMetadata` is the\n * one line a host needs; a custom `metadata` option overrides this entirely.\n */\nfunction defaultMetadata(result: ResolvePageResult, assets: readonly ResolvedAsset[]): Metadata {\n return canvasPageMetadata(result, assets)\n}\n\nasync function requestPerspective(): Promise<Perspective> {\n const { isEnabled } = await draftMode()\n return isEnabled ? 'draft' : 'published'\n}\n\n/** `unstable_cache` narrowed to the injectable seam the pure logic consumes. */\nconst nextCacheWrapper: CacheWrapper = (cb, keyParts, options) =>\n unstable_cache(cb, keyParts, { tags: options.tags, revalidate: options.revalidate })\n\n/** Create the `{ Page, generateMetadata }` pair for `app/[[...slug]]/page.tsx`. */\nexport function createCanvasRoute(options: CanvasRouteOptions): CanvasRoute {\n /**\n * Resolve one request, optionally through the tagged data cache. Shared by\n * `Page` and `generateMetadata` from a single call site, so both read (and\n * on a miss, write) the same cache entry.\n */\n const loadOutcome = async (url: string, perspective: Perspective): Promise<CanvasPageOutcome> => {\n const resolveFresh = async (): Promise<CanvasPageOutcome> => {\n const source = await options.loadContent({ perspective })\n return resolveCanvasPage(source, url, perspective, {\n ...(options.payloads ? { payloads: options.payloads } : {}),\n // EC-205: page-scope the baked assets to what the page actually uses.\n registry: options.components.registry,\n })\n }\n\n // Draft mode BYPASSES the cache entirely: draft content is per-editor,\n // changes on every keystroke, and must never be persisted into (or served\n // from) the shared published-data cache.\n //\n // `next dev` ALSO bypasses it: the tag-based instant-publish webhook (the\n // only cache invalidation, AD-5) can't reach a localhost host, so a\n // published change would stay stale until the dev server restarts (which\n // clears `.next`). Scoped to `development` so tests (`NODE_ENV=test`) and\n // production (`next build`/`start`) keep the tag-driven cache unchanged.\n const devBypass = process.env.NODE_ENV === 'development'\n if (!options.cache || perspective !== 'published' || devBypass) return resolveFresh()\n\n const scope = options.cache.scope\n const entry = await loadCachedEntry(\n nextCacheWrapper,\n ['elytra-route', scope ?? '', url],\n [projectSweepTag(scope)],\n async () => {\n const outcome = await resolveFresh()\n return { value: outcome, tags: nextCacheTags(outcome.tags, scope) }\n },\n )\n return entry.value\n }\n\n const Page = async (props: CanvasRouteProps): Promise<ReactNode> => {\n const { slug } = await props.params\n const url = pathFromSlug(slug)\n const perspective = await requestPerspective()\n\n const outcome = await loadOutcome(url, perspective)\n options.onTags?.(outcome.tags, { url, perspective })\n\n switch (outcome.kind) {\n case 'redirect':\n // 301 vs 302 per the redirect record's `permanent` flag (EC-019/020).\n return outcome.permanent ? permanentRedirect(outcome.target) : redirect(outcome.target)\n case 'not-found':\n return notFound()\n case 'render':\n return (\n <CanvasRenderer\n result={outcome.result}\n components={options.components}\n payloads={outcome.payloads}\n assets={outcome.assets}\n relations={outcome.relations}\n listings={outcome.listings}\n links={outcome.links}\n />\n )\n }\n }\n\n const generateMetadata = async (props: CanvasRouteProps): Promise<Metadata> => {\n const { slug } = await props.params\n const url = pathFromSlug(slug)\n const perspective = await requestPerspective()\n\n // Cached path: shares `Page`'s entry (same call site/key), so metadata is\n // a cache read, not a second resolution. Uncached path: resolve without\n // the payload factory — metadata only needs the resolution itself, and\n // side effects (addTags/onTags) must fire exactly once per request, in Page.\n if (options.cache && perspective === 'published') {\n const outcome = await loadOutcome(url, perspective)\n if (outcome.kind !== 'render') return {}\n return options.metadata\n ? options.metadata(outcome.result, { url, perspective })\n : defaultMetadata(outcome.result, outcome.assets)\n }\n\n const source = await options.loadContent({ perspective })\n const outcome = await resolveCanvasPage(source, url, perspective)\n if (outcome.kind !== 'render') return {}\n return options.metadata\n ? options.metadata(outcome.result, { url, perspective })\n : defaultMetadata(outcome.result, outcome.assets)\n }\n\n return { Page, generateMetadata }\n}\n","import type { MetadataRoute } from 'next'\nimport { composePath, hierarchyMount, splitPath } from '@elytracms/core/cms-core'\nimport type { CmsDocument, Locale, RouteRecord } from '@elytracms/core/cms-core'\nimport type { ContentClient } from '@elytracms/core/content'\nimport type { ContentSource } from './source'\n\n/**\n * `sitemap.xml` from published routes (EC-171): walk the same route records\n * `resolvePage` resolves against, resolve every candidate URL in the\n * **published** perspective, and emit `MetadataRoute.Sitemap` entries per\n * locale — Next's `app/sitemap.ts` convention. Pages marked `noindex` (and\n * URLs that do not resolve, e.g. a page that was never published) are\n * omitted.\n *\n * Dynamic routes (`/blog/:slug`): a route record does not declare which\n * collection feeds its params, so enumeration is delegated to the host's\n * {@link SitemapParamsProvider} — it gets a published-perspective accessor\n * client and returns one param record per concrete URL (typically from\n * `listDocuments`). **Honest limit:** parameterized routes without a provider\n * (or provider entries missing a param) are skipped and reported in\n * `skipped`, never guessed. `lastModified` is omitted — the delivery shape\n * carries no per-page timestamps today.\n *\n * Hierarchy mounts (`/:path*`, EC-218): a page-tree mount self-describes its\n * URLs, so it is enumerated automatically from the collection's published\n * documents (composing each page's nested path from its parent chain) — no\n * params provider entry needed.\n *\n * Host usage (`app/sitemap.ts`):\n *\n * ```ts\n * import { createCanvasSitemap } from '@elytracms/next'\n * import { loadContent } from '../lib/content'\n *\n * export default createCanvasSitemap({\n * loadContent,\n * baseUrl: 'https://example.com',\n * params: ({ route, client }) =>\n * route.id === 'r-post'\n * ? (client.listDocuments('post').ok ? … : []) // slug per published post\n * : null,\n * })\n * ```\n */\n\nexport interface SitemapRouteContext {\n route: RouteRecord\n locale: Locale\n /** Published-perspective accessor client bound to `locale`. */\n client: ContentClient\n}\n\n/**\n * Enumerate the param sets of one dynamic route — one record per concrete\n * URL (e.g. `[{ slug: 'hello-world' }, …]`). Return `null`/`undefined` to\n * skip the route (reported in `skipped`).\n */\nexport type SitemapParamsProvider = (\n ctx: SitemapRouteContext,\n) => readonly Record<string, string>[] | null | undefined\n\nexport interface CanvasSitemapOptions {\n /** Absolute site origin, e.g. `https://example.com` (no trailing slash needed). */\n baseUrl: string\n /** Route records to enumerate; defaults to the source's own route table. */\n routes?: readonly RouteRecord[]\n /** Param enumeration for dynamic routes (see {@link SitemapParamsProvider}). */\n params?: SitemapParamsProvider\n}\n\nexport interface SitemapSkippedRoute {\n routeId: string\n pattern: string\n reason: string\n}\n\nexport interface CanvasSitemapResult {\n entries: MetadataRoute.Sitemap\n /** Routes that could not be enumerated — explicit, never silent. */\n skipped: SitemapSkippedRoute[]\n}\n\nfunction paramNamesOf(pattern: string): string[] {\n return splitPath(pattern)\n .filter((segment) => segment.startsWith(':'))\n .map((segment) => segment.slice(1))\n}\n\n/** Substitute `:name` segments; `null` when a param is missing from the record. */\nfunction fillPattern(pattern: string, params: Record<string, string>): string | null {\n const segments: string[] = []\n for (const segment of splitPath(pattern)) {\n if (!segment.startsWith(':')) {\n segments.push(segment)\n continue\n }\n const value = params[segment.slice(1)]\n if (value === undefined || value.length === 0) return null\n segments.push(encodeURIComponent(value))\n }\n return '/' + segments.join('/')\n}\n\n/** Default locale serves the root; other locales get a `/locale` prefix. */\nfunction absoluteUrl(baseUrl: string, locale: Locale, defaultLocale: Locale, path: string): string {\n const origin = baseUrl.replace(/\\/+$/, '')\n if (locale === defaultLocale) return origin + path\n return origin + (path === '/' ? `/${locale}` : `/${locale}${path}`)\n}\n\n/**\n * Enumerate the sitemap entries of one content source (published\n * perspective). Pure over the prefetched source — synchronous accessors,\n * deterministic ordering (sorted by URL).\n */\nexport function canvasSitemapEntries(\n source: ContentSource,\n options: CanvasSitemapOptions,\n): CanvasSitemapResult {\n const routes = options.routes ?? source.routes ?? []\n const locales = source.locales\n const skipped: SitemapSkippedRoute[] = []\n const skip = (route: RouteRecord, reason: string): void => {\n if (!skipped.some((s) => s.routeId === route.id && s.reason === reason)) {\n skipped.push({ routeId: route.id, pattern: route.pattern, reason })\n }\n }\n\n const clients = new Map<Locale, ContentClient>()\n const clientFor = (locale: Locale): ContentClient => {\n let client = clients.get(locale)\n if (!client) {\n client = source.client({ perspective: 'published', locale })\n clients.set(locale, client)\n }\n return client\n }\n\n // path → locale → absolute URL (alternates group per concrete path).\n const byPath = new Map<string, Map<Locale, string>>()\n\n for (const route of routes) {\n const paramNames = paramNamesOf(route.pattern)\n // EC-218: a hierarchy mount (`/:path*`) serves a collection's pages by their\n // COMPOSED nested path — it self-describes its tree, so it is enumerated from\n // the collection's published documents, not the host's params provider.\n const mount = hierarchyMount(route)\n const routeLocales = route.locale ? [route.locale] : locales.locales\n\n for (const locale of routeLocales) {\n const client = clientFor(locale)\n\n let paths: string[]\n if (mount) {\n const listed = client.listDocuments(mount.collection)\n if (!listed.ok) {\n skip(route, `hierarchy collection \"${mount.collection}\" could not be listed`)\n continue\n }\n // Delivery docs are flat (`{ id, slug, parent, … }`); rebuild the minimal\n // CmsDocument shape composePath reads. Published perspective already\n // filtered to published rows, so a child whose parent is unpublished has a\n // dangling chain and drops out — exactly as live resolution would 404 it.\n const rows: CmsDocument[] = listed.documents.map((doc) => ({\n collection: mount.collection,\n id: doc.id,\n values: { slug: doc['slug'], parent: doc['parent'] },\n }))\n const byId = new Map(rows.map((row) => [row.id, row]))\n paths = []\n for (const row of rows) {\n // Only documents with their own slug are addressed through the mount\n // (a page routed explicitly elsewhere carries none).\n if (typeof row.values['slug'] !== 'string' || row.values['slug'] === '') continue\n const composed = composePath(row, (id) => byId.get(id))\n if (!composed.ok) continue\n paths.push('/' + [...mount.prefix, ...composed.segments].join('/'))\n }\n } else if (paramNames.length === 0) {\n paths = [route.pattern]\n } else {\n const paramSets = options.params?.({ route, locale, client })\n if (paramSets == null) {\n skip(route, 'dynamic route not enumerated (no params provider entry)')\n continue\n }\n paths = []\n for (const paramSet of paramSets) {\n const path = fillPattern(route.pattern, paramSet)\n if (path === null) {\n skip(route, `params entry missing one of :${paramNames.join(', :')}`)\n continue\n }\n paths.push(path)\n }\n }\n\n for (const path of paths) {\n // Same resolution the live request performs: only URLs that resolve\n // `ok` in the published perspective — and are not noindex — qualify.\n // Redirect-shadowed paths drop out (their targets are listed via\n // their own routes), and so do routes whose bound page/template is\n // not visible in the published graph (never published).\n const result = client.resolvePage(path, locale)\n // A document-bound route whose document is not published already\n // resolves `notFound` (EC-177 gap 6), so `status !== 'ok'` covers the\n // never-published case. A `page`-collection document carries its own\n // `seoNoindex` flat field (EC-187); honor it for the page sitemap.\n if (result.status !== 'ok') continue\n if (result.document?.['seoNoindex'] === true) continue\n const perLocale = byPath.get(path) ?? new Map<Locale, string>()\n perLocale.set(locale, absoluteUrl(options.baseUrl, locale, locales.default, path))\n byPath.set(path, perLocale)\n }\n }\n }\n\n const entries: MetadataRoute.Sitemap = []\n for (const perLocale of byPath.values()) {\n const languages = Object.fromEntries(perLocale)\n for (const url of perLocale.values()) {\n entries.push({\n url,\n ...(perLocale.size > 1 ? { alternates: { languages } } : {}),\n })\n }\n }\n entries.sort((a, b) => (a.url < b.url ? -1 : a.url > b.url ? 1 : 0))\n\n return { entries, skipped }\n}\n\nexport interface CreateCanvasSitemapOptions extends CanvasSitemapOptions {\n /** The same content loader the catch-all route uses (published perspective). */\n loadContent: (request: { perspective: 'published' }) => Promise<ContentSource>\n}\n\n/**\n * The `app/sitemap.ts` one-liner: `export default createCanvasSitemap({ … })`.\n * Loads the published content source and returns the enumerated entries\n * (skipped routes are dropped here — use {@link canvasSitemapEntries} to\n * inspect them).\n */\nexport function createCanvasSitemap(\n options: CreateCanvasSitemapOptions,\n): () => Promise<MetadataRoute.Sitemap> {\n return async () => {\n const source = await options.loadContent({ perspective: 'published' })\n return canvasSitemapEntries(source, options).entries\n }\n}\n","import { createHmac, timingSafeEqual } from 'node:crypto'\nimport { z } from 'zod'\n\n/**\n * Pure signature/payload logic of the revalidation webhook receiver (EC-146),\n * kept free of Next.js imports so it is unit-testable. `revalidate.ts` wires\n * it into a route handler with `revalidateTag`.\n *\n * Scheme: HMAC-SHA256 over the **raw request body** with a shared secret,\n * carried as `x-elytra-signature: sha256=<hex>`. The emitter (the studio's\n * webhook dispatcher) signs the exact JSON string it sends; the receiver\n * verifies over the raw text *before* parsing, with a timing-safe compare.\n */\n\n/** Header carrying the HMAC signature. */\nexport const REVALIDATE_SIGNATURE_HEADER = 'x-elytra-signature'\n\n/** The webhook body: which tags to revalidate, and why. */\nexport const revalidatePayloadSchema = z.object({\n projectId: z.string().min(1),\n /** The operation that fired, e.g. `documents.setState`, `publishing.publish`. */\n event: z.string().min(1),\n /** Fully-formatted Next tag strings (already scoped) — revalidated verbatim. */\n tags: z.array(z.string().min(1)),\n /** ISO timestamp of emission. Informational in v1 (no replay window). */\n timestamp: z.string().min(1),\n})\nexport type RevalidatePayload = z.infer<typeof revalidatePayloadSchema>\n\n/** Compute the signature header value for a raw body (emitter/test side). */\nexport function signRevalidateBody(rawBody: string, secret: string): string {\n return `sha256=${createHmac('sha256', secret).update(rawBody, 'utf8').digest('hex')}`\n}\n\nexport type RevalidateEvaluation =\n | { ok: true; payload: RevalidatePayload }\n | { ok: false; status: 400 | 401; message: string }\n\nconst SIGNATURE_PREFIX = 'sha256='\nconst HEX_PATTERN = /^[0-9a-f]+$/\n\n/**\n * Evaluate one webhook request: verify the HMAC first (auth before parsing),\n * then validate the payload shape.\n *\n * - unconfigured (empty) secret → 401 for every request: the endpoint stays\n * closed until a secret is deliberately configured (mirrors EC-144 preview);\n * - missing/malformed/mismatched signature → 401 (timing-safe compare);\n * - unparseable or schema-invalid body → 400 with no tag revalidated.\n */\nexport function evaluateRevalidateRequest(\n rawBody: string,\n signature: string | null | undefined,\n secret: string | undefined,\n): RevalidateEvaluation {\n if (secret === undefined || secret.length === 0) {\n return { ok: false, status: 401, message: 'Revalidation webhook is not configured.' }\n }\n\n if (signature === null || signature === undefined || !signature.startsWith(SIGNATURE_PREFIX)) {\n return { ok: false, status: 401, message: 'Missing or malformed webhook signature.' }\n }\n\n const providedHex = signature.slice(SIGNATURE_PREFIX.length).toLowerCase()\n const expectedHex = createHmac('sha256', secret).update(rawBody, 'utf8').digest('hex')\n // Length must match before `timingSafeEqual` (it throws otherwise); the\n // digest length is public knowledge, so this comparison leaks nothing.\n if (\n providedHex.length !== expectedHex.length ||\n !HEX_PATTERN.test(providedHex) ||\n !timingSafeEqual(Buffer.from(providedHex, 'hex'), Buffer.from(expectedHex, 'hex'))\n ) {\n return { ok: false, status: 401, message: 'Invalid webhook signature.' }\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(rawBody)\n } catch {\n return { ok: false, status: 400, message: 'Webhook body is not valid JSON.' }\n }\n\n const payload = revalidatePayloadSchema.safeParse(parsed)\n if (!payload.success) {\n return { ok: false, status: 400, message: 'Webhook payload has an invalid shape.' }\n }\n\n return { ok: true, payload: payload.data }\n}\n","import { revalidateTag } from 'next/cache'\nimport { REVALIDATE_SIGNATURE_HEADER, evaluateRevalidateRequest } from './revalidate-core'\n\n/**\n * Revalidation webhook route handler (EC-146): the receiving end of the\n * publish → live-in-seconds pipeline. The studio's dispatcher POSTs a signed\n * `{projectId, event, tags, timestamp}` payload; this handler verifies the\n * HMAC over the raw body and calls `revalidateTag` for each tag, dropping\n * exactly the cached entries whose fetch-time tag sets contained them.\n *\n * Server-only by construction — consumed from an App Router route handler\n * file, never from client bundles.\n */\n\nexport interface RevalidateRouteOptions {\n /**\n * Shared HMAC secret. An empty/undefined secret rejects every request with\n * 401 — the endpoint stays closed until deliberately configured.\n */\n secret: string | undefined\n /**\n * CORS origin allowed to call this endpoint (e.g. the studio's origin).\n * The v1 dispatcher is a browser `fetch` from the studio, and the custom\n * signature header always triggers a CORS preflight — so cross-origin\n * studio → host dispatch only works when this is set. Server-side emitters\n * (the Convex action variant, CLIs, CI) need no CORS and may leave it\n * unset. Never use `*` with a real secret-bearing deployment unless you\n * accept that any origin may *attempt* deliveries (they still need the\n * secret to have any effect).\n */\n allowOrigin?: string\n}\n\nexport interface RevalidateRouteHandlers {\n POST(request: Request): Promise<Response>\n OPTIONS(): Promise<Response>\n}\n\nfunction corsHeaders(allowOrigin: string | undefined): Record<string, string> {\n if (allowOrigin === undefined || allowOrigin.length === 0) return {}\n return {\n 'access-control-allow-origin': allowOrigin,\n 'access-control-allow-methods': 'POST, OPTIONS',\n 'access-control-allow-headers': `content-type, ${REVALIDATE_SIGNATURE_HEADER}`,\n }\n}\n\n/**\n * Create the webhook route handlers for `app/api/revalidate/route.ts`:\n *\n * ```ts\n * export const { POST, OPTIONS } = createRevalidateRoute({\n * secret: process.env.REVALIDATE_SECRET,\n * })\n * ```\n *\n * Unsigned/invalid requests are rejected with 401 (timing-safe HMAC check,\n * see `evaluateRevalidateRequest`); valid requests revalidate every carried\n * tag and answer `{ revalidated: tags }`.\n */\nexport function createRevalidateRoute(options: RevalidateRouteOptions): RevalidateRouteHandlers {\n const cors = corsHeaders(options.allowOrigin)\n return {\n async POST(request: Request): Promise<Response> {\n const rawBody = await request.text()\n const signature = request.headers.get(REVALIDATE_SIGNATURE_HEADER)\n const evaluation = evaluateRevalidateRequest(rawBody, signature, options.secret)\n if (!evaluation.ok) {\n return Response.json(\n { error: evaluation.message },\n { status: evaluation.status, headers: cors },\n )\n }\n // Next 16 requires a cache-life profile as the second argument; `'max'`\n // is the documented drop-in that preserves the legacy \"drop every entry\n // carrying this tag\" semantics our `unstable_cache` flow relies on (the\n // one-arg form is deprecated). `updateTag` is not an option here — it is\n // Server-Action-only and throws from a route handler.\n for (const tag of evaluation.payload.tags) revalidateTag(tag, 'max')\n return Response.json({ revalidated: evaluation.payload.tags }, { headers: cors })\n },\n async OPTIONS(): Promise<Response> {\n // Preflight for the browser-dispatch path; 204 either way, CORS headers\n // only when an origin is configured.\n return new Response(null, { status: 204, headers: cors })\n },\n }\n}\n","import NextImage from 'next/image'\nimport type { ImageLoader } from 'next/image'\nimport type { ReactNode } from 'react'\nimport type { ResolvedAsset } from '@elytracms/core/content'\nimport { ImageManifest, normalizeImageSource } from '@elytracms/core/runtime-renderer'\nimport type { HostComponent } from './components'\n// TYPE-ONLY by design: importing `./host-image` at runtime would bundle a second\n// singleton instance into the server entry (see host-image.ts module docs).\nimport type { HostImageRenderer } from './host-image'\n\n/**\n * Image delivery for the embedded runtime (EC-152).\n *\n * ## The honest v1 design\n *\n * Stored asset bytes are served from plain blob-storage URLs (Convex file\n * storage serve URLs in production). Those URLs do **not** transform — there\n * is no `?w=`/`?q=` resizing service behind them, and no image CDN build-out\n * in v1. The standard, no-CDN path is therefore `next/image` with its\n * **default loader**: the host app's own Next.js optimizer fetches the remote\n * asset URL, resizes/re-encodes it, and serves the variants same-origin from\n * `/_next/image`. That is exactly what {@link ElytraImage} does.\n *\n * For that to work the host app must allowlist the asset origin in\n * `next.config.mjs`:\n *\n * ```js\n * const nextConfig = {\n * images: {\n * remotePatterns: [\n * // Convex file storage serve URLs:\n * { protocol: 'https', hostname: '*.convex.cloud' },\n * ],\n * },\n * }\n * ```\n *\n * {@link createAssetImageLoader} exists for the day the asset URLs sit behind\n * a CDN that *does* honor width/quality query params — it appends them and\n * nothing more. Pointing it at raw Convex serve URLs would silently serve\n * full-size bytes while pretending to resize, so it is **not** the default.\n */\n\n/**\n * The slice of the {@link ResolvedAsset} delivery shape an image needs:\n * the resolvable URL, intrinsic dimensions for layout stability, and alt\n * text. Structurally satisfied by every `ResolvedAsset`.\n */\nexport type ElytraImageAsset = Pick<\n ResolvedAsset,\n 'url' | 'width' | 'height' | 'alt' | 'focalPoint'\n> & {\n /**\n * LQIP blur-placeholder data URI (EC-420) → `next/image` `blurDataURL`. Optional\n * so existing call sites are unaffected; when present, the optimized image blurs\n * up while loading. `null`/absent = today's behaviour (no placeholder).\n */\n lqip?: string | null\n}\n\nexport interface ElytraImageProps {\n /** The resolved asset (delivery shape). `null` renders nothing. */\n asset: ElytraImageAsset | null | undefined\n /** `sizes` hint forwarded to `next/image` for responsive variants. */\n sizes?: string\n /** Preload hint forwarded to `next/image` (above-the-fold images). */\n priority?: boolean\n /** Quality (1–100) forwarded to `next/image`; Next defaults to 75. */\n quality?: number\n className?: string\n /**\n * Custom `next/image` loader (e.g. from {@link createAssetImageLoader})\n * when assets sit behind a transforming CDN. Omit for the v1 default:\n * Next's own optimizer.\n */\n loader?: ImageLoader\n}\n\n/**\n * Render a resolved asset through `next/image` (EC-152).\n *\n * - With known intrinsic dimensions the optimizer serves resized variants\n * and the reserved width/height prevent layout shift.\n * - Without dimensions `next/image` cannot render (it requires `width` +\n * `height` or `fill`), so the component degrades to a plain `<img>` —\n * un-optimized but visible, never a crash. Records written by the EC-151\n * upload flow always carry detected dimensions.\n * - A `null`/empty asset renders nothing (missing assets surface as\n * structured `unknown-asset` validation issues upstream, not here).\n */\nexport function ElytraImage(props: ElytraImageProps): ReactNode {\n const { asset, sizes, priority, quality, className, loader } = props\n if (!asset || asset.url.length === 0) return null\n const alt = asset.alt ?? ''\n // EC-230: a focal point becomes CSS `object-position`, so an art-directed image\n // keeps its subject in frame when a layout crops it (`object-fit: cover`).\n // Inert under the default fit — harmless to set, correct once a layout crops.\n const objectPosition = asset.focalPoint\n ? `${asset.focalPoint.x * 100}% ${asset.focalPoint.y * 100}%`\n : undefined\n // EC-420 (AD-2): a resolved LQIP data URI becomes a next/image blur-up placeholder\n // — the image blurs while the optimized bytes stream in. Only on the optimized\n // path (the plain-`<img>` fallback can't consume a blurDataURL); absent lqip =\n // today's behaviour exactly (no placeholder). Batteries-included, zero new deps.\n const blur = asset.lqip\n ? { placeholder: 'blur' as const, blurDataURL: asset.lqip }\n : {}\n if (asset.width === null || asset.height === null) {\n // Honest fallback: next/image requires intrinsic dimensions; a\n // dimensionless record degrades to an unoptimized <img> instead of\n // crashing the page.\n return (\n <img\n data-ec-image=\"fallback\"\n src={asset.url}\n alt={alt}\n className={className}\n {...(objectPosition ? { style: { objectPosition } } : {})}\n />\n )\n }\n return (\n <NextImage\n data-ec-image=\"next\"\n src={asset.url}\n alt={alt}\n width={asset.width}\n height={asset.height}\n {...(sizes !== undefined ? { sizes } : {})}\n {...(priority !== undefined ? { priority } : {})}\n {...(quality !== undefined ? { quality } : {})}\n {...(className !== undefined ? { className } : {})}\n {...(loader !== undefined ? { loader } : {})}\n {...blur}\n {...(objectPosition ? { style: { objectPosition } } : {})}\n />\n )\n}\n\nexport interface AssetImageLoaderOptions {\n /** Query param name for the requested width. Default `\"w\"`. */\n widthParam?: string\n /** Query param name for the requested quality. Default `\"q\"`. */\n qualityParam?: string\n /** Quality used when `next/image` passes none. Default `75`. */\n defaultQuality?: number\n}\n\n/**\n * A `next/image` loader for asset URLs served through a transforming CDN:\n * it appends width/quality query params to the asset URL and returns it.\n *\n * Be honest about what this does: it only *requests* a transform. Plain\n * Convex file-storage serve URLs ignore these params and return the original\n * bytes, so this loader is only correct once the asset origin actually\n * resizes (e.g. an image CDN in front of storage). Until then, use the\n * default `next/image` loader (see module docs) — that is the v1 path.\n */\nexport function createAssetImageLoader(options: AssetImageLoaderOptions = {}): ImageLoader {\n const widthParam = options.widthParam ?? 'w'\n const qualityParam = options.qualityParam ?? 'q'\n const defaultQuality = options.defaultQuality ?? 75\n return ({ src, width, quality }) => {\n const separator = src.includes('?') ? '&' : '?'\n return `${src}${separator}${widthParam}=${width}&${qualityParam}=${quality ?? defaultQuality}`\n }\n}\n\n/**\n * The `base.Image` implementation for Next.js host apps: same\n * canonical manifest, rendered optimized through {@link ElytraImage}. The\n * renderer resolves an `asset`-typed `src` (EC-195) to `{ url, width, height,\n * alt }` before this runs, so `normalizeImageSource` yields intrinsic dimensions\n * (→ no layout shift, sized variants) whether the editor picked an uploaded asset\n * or pasted a URL. `priority` opts an above-the-fold image out of lazy-loading.\n */\n/**\n * Per-deployment image-delivery options for {@link nextImagePrimitive} (EC-271).\n * The default is the host's own Next.js optimizer (Vercel) — zero config. A host\n * on a different CDN supplies its own `loader` (a plain function) to route variants\n * through that CDN instead, without touching component code.\n */\nexport interface NextImagePrimitiveOptions {\n /**\n * Custom `next/image` loader — the override seam for non-Vercel hosting. Omit\n * for the Vercel default (Next's own `/_next/image` optimizer). Supply a\n * function to delegate resizing to another CDN:\n *\n * - a CDN that honors `?w=&q=` query params → {@link createAssetImageLoader};\n * - Cloudflare Images / Imgix / a bespoke transform → your own `ImageLoader`\n * (e.g. rewrite to `/cdn-cgi/image/width=<w>,quality=<q>/<src>`).\n *\n * The loader receives `{ src, width, quality }` and returns the variant URL.\n */\n loader?: ImageLoader\n /** Default responsive `sizes` hint when a block doesn't set one. */\n sizes?: string\n /** Default quality (1–100) when a block doesn't set one (Next defaults to 75). */\n quality?: number\n}\n\nfunction createNextImagePrimitive(options: NextImagePrimitiveOptions) {\n return function NextImagePrimitive(props: Record<string, unknown>): ReactNode {\n const { url, width, height, alt, focalPoint, lqip } = normalizeImageSource(props)\n if (url.length === 0) return null\n return (\n <ElytraImage\n asset={{ url, width: width ?? null, height: height ?? null, alt, focalPoint, lqip }}\n {...(props.priority === true ? { priority: true } : {})}\n {...(options.loader !== undefined ? { loader: options.loader } : {})}\n {...(options.sizes !== undefined ? { sizes: options.sizes } : {})}\n {...(options.quality !== undefined ? { quality: options.quality } : {})}\n />\n )\n }\n}\n\n/**\n * Host registration that swaps the `base.Image` implementation\n * for {@link ElytraImage} while keeping the primitive's canonical manifest\n * (the first registration's manifest wins in `defineHostComponents` — by\n * design, so prop schemas stay canonical; the duplicate-id registry issue it\n * reports is the documented override signal, not an error):\n *\n * ```ts\n * export const hostComponents = defineHostComponents([\n * nextImagePrimitive(), // Vercel default optimizer\n * // ...project components\n * ])\n * ```\n *\n * Pass {@link NextImagePrimitiveOptions} to delegate image delivery to another\n * CDN (EC-271) — the v1 default is Vercel, with room to grow:\n *\n * ```ts\n * nextImagePrimitive({ loader: createAssetImageLoader() }) // ?w=&q= CDN\n * nextImagePrimitive({ loader: cloudflareImageLoader }) // Cloudflare Images\n * ```\n */\nexport function nextImagePrimitive(options: NextImagePrimitiveOptions = {}): HostComponent {\n return {\n manifest: ImageManifest,\n implementation: createNextImagePrimitive(options),\n }\n}\n\n/** Per-deployment options for {@link elytraHostImage} (the EC-271 loader seam). */\nexport interface ElytraHostImageOptions {\n /** Custom `next/image` loader for non-Vercel CDNs (see {@link NextImagePrimitiveOptions}). */\n loader?: ImageLoader\n /** Default quality (1–100) when a call site doesn't set one (Next defaults to 75). */\n quality?: number\n}\n\n/**\n * The `next/image`-backed {@link HostImageRenderer} (EC-368 image defaults): the\n * renderer a Next host registers on the `@elytracms/next/host-image` bridge so\n * DUAL-RENDERED project components (which can't import `next/image` themselves)\n * deliver optimized images — resized/modern-format variants, intrinsic\n * dimensions (no layout shift), focal-point `object-position`. A dimensionless\n * record degrades to a plain `<img>` (honest, never a crash), exactly like\n * {@link ElytraImage}.\n *\n * ```ts\n * import { elytraHostImage } from '@elytracms/next'\n * import { setHostImage } from '@elytracms/next/host-image'\n *\n * setHostImage(elytraHostImage()) // once, at host boot (never in the studio)\n * ```\n */\nexport function elytraHostImage(options: ElytraHostImageOptions = {}): HostImageRenderer {\n return ({ asset, alt, className, priority, sizes }) => (\n <ElytraImage\n asset={{ ...asset, alt }}\n {...(className !== undefined ? { className } : {})}\n {...(priority ? { priority: true } : {})}\n {...(sizes !== undefined ? { sizes } : {})}\n {...(options.loader !== undefined ? { loader: options.loader } : {})}\n {...(options.quality !== undefined ? { quality: options.quality } : {})}\n />\n )\n}\n","import type { ComponentRegistry } from '@elytracms/core/component-registry'\nimport { compositionNodesOf } from './canvas-renderer'\n\n/**\n * Manifest-driven header clearance (EC-368): does this page OPEN full-bleed?\n *\n * A host with a floating header (occupying no flow space) must pad a page's\n * content down by the header height — unless the page's FIRST canvas block is a\n * structural hero that deliberately bleeds to the viewport top and renders\n * under the header. Which components bleed is declared on their OWN manifest\n * (`presentation: { fullBleed: true }`, `@elytracms/core/component-registry`),\n * so the host derives the decision from the registry instead of keeping a\n * parallel hand-maintained component-id set that silently drifts when a new\n * hero ships.\n *\n * Pure over the delivery-shaped document: the composition field is found by\n * VALUE (the same `compositionNodesOf` selection the renderer uses), so hosts\n * with `body`, `content`, or bespoke composition field names all work. Absent\n * document, empty composition, unknown component, or an undeclared hint all\n * answer `false` — the safe default is clearance.\n *\n * ```tsx\n * const outcome = client.resolvePage(path)\n * const fullBleed = firstBlockFullBleed(outcome.document, components.registry)\n * return fullBleed ? page : <div className=\"pt-[var(--header-clearance)]\">{page}</div>\n * ```\n *\n * The host kit wires the resolution half for you: `elytra.pageOpensFullBleed(slug)`.\n */\nexport function firstBlockFullBleed(\n document: Record<string, unknown> | null | undefined,\n registry: ComponentRegistry,\n): boolean {\n const first = compositionNodesOf(document)[0]\n if (!first) return false\n return registry.getManifest(first.componentId)?.presentation?.fullBleed === true\n}\n","/**\n * Env resolution for the delivery host kit (EC-368). ONE documented name per\n * concern — every kit surface reads the same resolved bag, so the two-\n * disconnected-secrets class of bug (a preview route gating on one env var\n * while the draft loader reads another) is structurally impossible: there is\n * exactly one `DRAFT_PREVIEW_TOKEN`, consumed by BOTH the preview-enable route\n * and the draft snapshot fetch.\n *\n * | Env var | Concern |\n * | --------------------- | ---------------------------------------------------- |\n * | `ELYTRA_CONVEX_URL` | Convex deployment URL — presence (with the project |\n * | | id) switches the loader to LIVE mode |\n * | `ELYTRA_PROJECT_ID` | The project the studio publishes under (= tag scope) |\n * | `DRAFT_PREVIEW_TOKEN` | The ONE draft secret: gates the preview-enable route |\n * | | AND authenticates the draft snapshot fetch (must |\n * | | equal the Convex deployment's own env var) |\n * | `REVALIDATE_SECRET` | Instant-publish webhook HMAC secret (must equal the |\n * | | deployment's `CANVAS_REVALIDATE_SECRET`) |\n * | `STUDIO_ORIGIN` | CORS origin for the studio's browser-dispatch path |\n */\n\n/** The kit's documented env names (single source of truth, also used in docs/tests). */\nexport const ELYTRA_HOST_ENV_KEYS = {\n convexUrl: 'ELYTRA_CONVEX_URL',\n projectId: 'ELYTRA_PROJECT_ID',\n draftToken: 'DRAFT_PREVIEW_TOKEN',\n revalidateSecret: 'REVALIDATE_SECRET',\n studioOrigin: 'STUDIO_ORIGIN',\n} as const\n\nexport interface ElytraHostEnv {\n convexUrl?: string\n projectId?: string\n draftToken?: string\n revalidateSecret?: string\n studioOrigin?: string\n}\n\nfunction cleaned(value: string | undefined): string | undefined {\n const trimmed = value?.trim()\n return trimmed !== undefined && trimmed.length > 0 ? trimmed : undefined\n}\n\n/**\n * Resolve the kit's env bag from a raw env record (`process.env` by default at\n * the factory). Values are trimmed; empty strings resolve to `undefined` — an\n * env var set to `\"\"` must behave exactly like an unset one (endpoints stay\n * closed, live mode stays off), never like a configured empty secret.\n */\nexport function resolveHostEnv(env: Record<string, string | undefined>): ElytraHostEnv {\n const resolved: ElytraHostEnv = {}\n for (const [key, name] of Object.entries(ELYTRA_HOST_ENV_KEYS)) {\n const value = cleaned(env[name])\n if (value !== undefined) resolved[key as keyof ElytraHostEnv] = value\n }\n return resolved\n}\n","import { documentSchema, redirectRecordSchema } from '@elytracms/core/cms-core'\nimport type {\n CmsDocument,\n CollectionDef,\n LocaleConfig,\n RedirectRecord,\n RouteRecord,\n} from '@elytracms/core/cms-core'\nimport type { ContentDocumentSource, Perspective } from '@elytracms/core/content'\nimport type { AssetRecord } from '@elytracms/core/persistence'\nimport { z } from 'zod'\nimport { createStaticContentSource, mergeRouteRecords } from './snapshot'\nimport type { CanvasDataSource, ContentSource } from './source'\n\n/**\n * The LIVE half of the delivery host kit (EC-368): fetch the delivery snapshot\n * from a Convex deployment (`convex/delivery.ts` in the builder app) over\n * Convex's public HTTP query API — a plain `fetch` to\n * `POST {deployment}/api/query`, no Convex npm dependency — and assemble it\n * through the same `createStaticContentSource` path the fixture snapshot uses,\n * so accessor and rendering semantics are byte-identical across seeded, empty,\n * and live modes. This engine-izes the ~300-line `live-content.ts` both real\n * consumers hand-copied (EC-369 finding #5); the fetch + Zod-validation logic\n * now lives in exactly one place.\n *\n * Perspective handling: published requests fetch the PUBLIC `delivery:snapshot`\n * (published documents only — the standing live-is-published-only invariant).\n * Draft-mode requests fetch `delivery:draftSnapshot`, gated by the deployment's\n * `DRAFT_PREVIEW_TOKEN` — the same single secret that gates the kit's\n * preview-enable route (see `host-env.ts`).\n *\n * Routes: config-sourced route records (AD-3/AD-11, EC-207 — the host repo's\n * own `cms/`, passed via options) and the implicit per-locale home fallback are\n * MERGED (EC-177 gap 2), never XOR'd — config records win per pattern+locale.\n * The backend never carries route data.\n */\n\nexport interface LiveContentOptions {\n /** Convex deployment URL, e.g. `https://your-deployment-123.convex.cloud`. */\n convexUrl: string\n projectId: string\n /** Project locale config — config-owned (AD-11), never read from the snapshot. */\n locales: LocaleConfig\n /** CMS collection schema — config-owned (AD-11); drives depth-1 relation population. */\n collections: readonly CollectionDef[]\n /** Route records — config-owned (AD-3/AD-11); merged with the home fallback. */\n routes: readonly RouteRecord[]\n /** `DRAFT_PREVIEW_TOKEN` — required for draft-perspective loads. */\n draftToken?: string\n /** Fetch implementation override (tests, custom agents). Defaults to global fetch. */\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * The `delivery.ts` payload shape (validated field-by-field below). A\n * deployment IS one environment (EC-179); the snapshot carries content only\n * (EC-287) — documents, assets, editorial redirects (EC-303), and persisted\n * data-source definitions (EC-166).\n */\ninterface DeliverySnapshotPayload {\n projectId: string\n redirects?: unknown[]\n sources?: unknown\n documents: unknown[]\n assets: unknown[]\n}\n\n/**\n * Run one query through Convex's public HTTP API. Response envelope (verified\n * against live deployments): `{ status: 'success', value }` or\n * `{ status: 'error', errorMessage }`. `cache: 'no-store'` keeps Next's fetch\n * cache out of the loop — the route helper's tagged data cache is the only\n * cache layer, so tag revalidation always reaches the deployment.\n */\nasync function runConvexQuery(\n fetchImpl: typeof globalThis.fetch,\n convexUrl: string,\n path: string,\n args: Record<string, unknown>,\n): Promise<unknown> {\n const response = await fetchImpl(`${convexUrl.replace(/\\/$/, '')}/api/query`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ path, args, format: 'json' }),\n cache: 'no-store',\n })\n const body = (await response.json().catch(() => undefined)) as\n | { status?: string; value?: unknown; errorMessage?: string; message?: string }\n | undefined\n if (!response.ok || body?.status !== 'success') {\n throw new Error(\n `Convex query \"${path}\" failed (${response.status}): ${\n body?.errorMessage ?? body?.message ?? 'no error message'\n }`,\n )\n }\n return body.value\n}\n\n/** Canonical-schema validation: invalid stored rows are skipped, not fatal. */\nfunction parseDocuments(rows: unknown[]): CmsDocument[] {\n const documents: CmsDocument[] = []\n for (const row of rows) {\n const parsed = documentSchema.safeParse(row)\n if (parsed.success) documents.push(parsed.data)\n }\n return documents\n}\n\n/** Validate the snapshot's editorial redirects (EC-303); malformed rows drop out. */\nfunction parseRedirects(rows: unknown[]): RedirectRecord[] {\n const redirects: RedirectRecord[] = []\n for (const row of rows) {\n const parsed = redirectRecordSchema.safeParse(row)\n if (parsed.success) redirects.push(parsed.data)\n }\n return redirects\n}\n\n/**\n * The snapshot's data-source envelope — the structural `CanvasDataSource` shape\n * `materializeSourcePayloads` consumes (cms query configs themselves are\n * re-validated by the content module's lenient parser inside the route helper).\n */\nconst canvasDataSourceSchema = z.object({\n kind: z.string().min(1),\n id: z.string().min(1),\n label: z.string().optional(),\n config: z.unknown().optional(),\n})\n\n/**\n * Parse the snapshot's `sources` array (EC-166 LIVE mode). Tolerant by design:\n * an older deployment without the field — or an invalid entry — degrades to no\n * source definitions, which the runtime renders as unresolved-binding\n * fallbacks, never a crash.\n */\nfunction parseSources(rows: unknown): CanvasDataSource[] {\n if (!Array.isArray(rows)) return []\n const sources: CanvasDataSource[] = []\n for (const row of rows) {\n const parsed = canvasDataSourceSchema.safeParse(row)\n if (parsed.success) sources.push(parsed.data)\n }\n return sources\n}\n\n/**\n * Implicit fallback route table (EC-187): `/` → the first `page`-collection\n * document (lowest id), once per configured locale. Merged UNDER the stored\n * records. The delivery snapshot is already perspective-filtered server-side,\n * so in draft mode this correctly previews the draft home even when\n * unpublished.\n */\nexport function fallbackHomeRoutes(\n documents: readonly CmsDocument[],\n locales: LocaleConfig,\n): RouteRecord[] {\n const homePage = [...documents]\n .filter((doc) => doc.collection === 'page')\n .sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))[0]\n if (!homePage) return []\n return locales.locales.map((locale) => ({\n id: `r-live-home-${locale}`,\n pattern: '/',\n locale,\n document: { collection: 'page', id: homePage.id },\n }))\n}\n\n/**\n * Assemble a fetched delivery-snapshot payload into a `ContentSource` — the\n * pure half of {@link loadLiveContent}, exported so the parsing/assembly rules\n * are directly testable against fixture payloads (no network).\n */\nexport function assembleLiveSource(\n payload: DeliverySnapshotPayload,\n options: Pick<LiveContentOptions, 'locales' | 'collections' | 'routes'>,\n perspective: Perspective,\n): ContentSource {\n // Locales/collections/routes are config-owned (AD-11): from the host repo's\n // own `cms/`, passed in via options — never from the snapshot.\n const locales = options.locales\n const documents = parseDocuments(payload.documents)\n\n // MERGE, not XOR (EC-177 gap 2): config route records win per pattern+locale;\n // the implicit per-locale home fallback fills the rest.\n const routes = mergeRouteRecords([...options.routes], fallbackHomeRoutes(documents, locales))\n\n // EC-224 B-1: the published snapshot ships each document as its PINNED\n // published content (delivery resolved the version pointer server-side). Wrap\n // those rows as a `DocumentHistory` so the pure published gate\n // (`selectPerspective`) serves `.published` directly.\n //\n // TRUST CONTRACT: the wrap treats whatever the published fetch returned AS\n // published and deliberately does NOT re-gate — it cannot, the wire carries\n // no version pointer. Correctness rests ENTIRELY on `delivery:snapshot`\n // shipping published-only content (pinned version snapshots, never a draft —\n // see the builder's `convex/delivery.ts`). Guard the invariant in delivery,\n // not here. Draft-fetch rows stay bare: `selectPerspective('draft')` serves\n // them as-is.\n const documentSources: ContentDocumentSource[] =\n perspective === 'published'\n ? documents.map((doc) => ({ draft: doc, published: doc, versions: [] }))\n : documents\n\n return createStaticContentSource({\n projectId: payload.projectId,\n locales,\n routes,\n // Redirects are editorial DATA (EC-303): the ENABLED ones ship in the\n // snapshot, so they change dynamically (no redeploy). Native next.config\n // redirects run before this.\n redirects: parseRedirects(payload.redirects ?? []),\n collections: [...options.collections],\n documents: documentSources,\n assets: payload.assets as AssetRecord[],\n // EC-166 LIVE mode: the builder's persisted section/template sources, so\n // the route helper materializes their payloads.\n sources: parseSources(payload.sources),\n })\n}\n\n/** Fetch the live delivery snapshot and assemble the `ContentSource` for one request. */\nexport async function loadLiveContent(\n options: LiveContentOptions,\n perspective: Perspective,\n): Promise<ContentSource> {\n const fetchImpl = options.fetch ?? globalThis.fetch\n const args: Record<string, unknown> = { projectId: options.projectId }\n\n let payload: DeliverySnapshotPayload\n if (perspective === 'draft') {\n if (!options.draftToken) {\n // Explicit, visible failure: draft mode without a configured token must\n // never silently fall back to published content.\n throw new Error(\n 'Draft preview requested but DRAFT_PREVIEW_TOKEN is not configured on the host.',\n )\n }\n payload = (await runConvexQuery(fetchImpl, options.convexUrl, 'delivery:draftSnapshot', {\n ...args,\n token: options.draftToken,\n })) as DeliverySnapshotPayload\n } else {\n payload = (await runConvexQuery(\n fetchImpl,\n options.convexUrl,\n 'delivery:snapshot',\n args,\n )) as DeliverySnapshotPayload\n }\n\n return assembleLiveSource(payload, options, perspective)\n}\n","import type { DocumentRef, Locale } from '@elytracms/core/cms-core'\nimport type { ContentClient, Perspective, ResolvedDocument } from '@elytracms/core/content'\nimport type { ContentSource } from './source'\n\n/**\n * Site-chrome globals for delivery hosts (EC-368, from EC-369 finding #5): the\n * layout, header, and footer are NOT rendered through the canvas, so they read\n * the `settings` singleton + `navigation` documents straight from the\n * `ContentSource` and pre-resolve everything — keeping the chrome components\n * pure presentational, with no `ContentClient` or `@elytracms/*` knowledge.\n * Both real consumers hand-authored this ~200-line layer independently; the\n * MECHANISM now lives here, while the per-project projection (which settings\n * fields exist, what the chrome looks like) stays consumer-owned:\n *\n * - **settings**: the singleton collection's lone document (EC-274) — no\n * document id is ever named.\n * - **navigation by slot**: menus are addressed by their EC-284 alias slot\n * (`main`, `footer`), never a document id — delivery shape carries `alias`\n * since EC-364.\n * - **link resolution**: link-object values (`linkType: href | page | file`)\n * resolve through `client.resolveLink` — the same `urlForDocument` authority\n * the router serves, so a nav link to a nested page carries its FULL composed\n * path (`/krippe/tagesablauf`, EC-218/EC-360), and `home → '/'` needs no\n * special-casing.\n * - **asset resolution**: asset field values (stored ids) resolve to serve URLs\n * through the source's delivery-shaped asset list.\n *\n * Everything degrades explicitly: a missing settings document is `null`, a\n * missing slot is `null`/`[]`, an unresolvable link drops out (never a silent\n * `#`), an unknown asset id is `undefined` — the host renders sensible empties\n * for the empty-source build and surfaces gaps honestly.\n */\n\nexport interface GlobalsConventions {\n /** The settings singleton's collection id. Default `'settings'`. */\n settingsCollection?: string\n /** The navigation documents' collection id. Default `'navigation'`. */\n navigationCollection?: string\n /**\n * Field names probed (in order) for a navigation document's entry list.\n * Default `['items', 'links']` — the two shapes the shipped consumers and the\n * starter template use.\n */\n navigationItemsFields?: readonly string[]\n}\n\n/** A fully-resolved link: the composed href plus the new-tab flag. */\nexport interface ResolvedLink {\n href: string\n openInNewTab: boolean\n}\n\n/** A leaf navigation link (children of a dropdown / footer column). */\nexport interface ResolvedNavLink extends ResolvedLink {\n label: string\n /** Optional subline shown under the label (wide header dropdowns). */\n description?: string\n}\n\n/** A top-level navigation entry; `href` is absent for pure group headings. */\nexport interface ResolvedNavEntry {\n label: string\n href?: string\n openInNewTab: boolean\n description?: string\n children: ResolvedNavLink[]\n}\n\n/** The resolved chrome-globals surface `loadGlobals` yields (EC-368). */\nexport interface SiteGlobals {\n /** The settings singleton, delivery-shaped, or `null` (empty build / not published). */\n settings: ResolvedDocument | null\n /** The navigation document filling a slot alias (EC-284/EC-364), or `null`. */\n navigation(slot: string): ResolvedDocument | null\n /**\n * A slot's entry list, fully resolved: labels, composed hrefs (nested paths\n * included), new-tab flags, sublines, one level of children. Entries whose\n * link cannot resolve to an href are kept only when they carry children (a\n * group heading); leaf entries without a resolvable href drop out.\n */\n navigationEntries(slot: string): ResolvedNavEntry[]\n /** Resolve a link-object field value to an href + new-tab flag, or `null`. */\n resolveLink(value: unknown): ResolvedLink | null\n /** Resolve an asset field value (stored id / URL / `{ url }`) to a URL, or `undefined`. */\n assetUrl(value: unknown): string | undefined\n /** The accessor client behind the globals — for bespoke projections. */\n client: ContentClient\n /** The underlying content source (assets(), locales, routes). */\n source: ContentSource\n}\n\nexport interface ResolveGlobalsOptions {\n /** Perspective of the chrome read. Default `'published'` (live is published-only). */\n perspective?: Perspective\n locale?: Locale\n conventions?: GlobalsConventions\n}\n\nconst DEFAULT_ITEMS_FIELDS = ['items', 'links'] as const\n\nfunction record(value: unknown): Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {}\n}\n\nfunction str(value: unknown): string {\n return typeof value === 'string' ? value : ''\n}\n\nfunction items(value: unknown): Record<string, unknown>[] {\n return Array.isArray(value) ? value.map(record) : []\n}\n\n/**\n * Resolve the chrome globals over an already-loaded `ContentSource` — the pure\n * core of the host kit's `loadGlobals` (directly testable over fixture\n * sources).\n */\nexport function resolveGlobals(\n source: ContentSource,\n options: ResolveGlobalsOptions = {},\n): SiteGlobals {\n const perspective = options.perspective ?? 'published'\n const conventions = options.conventions ?? {}\n const settingsCollection = conventions.settingsCollection ?? 'settings'\n const navigationCollection = conventions.navigationCollection ?? 'navigation'\n const itemsFields = conventions.navigationItemsFields ?? DEFAULT_ITEMS_FIELDS\n\n const client = source.client({ perspective, ...(options.locale ? { locale: options.locale } : {}) })\n const assets = source.assets?.() ?? []\n const assetById = new Map(assets.map((asset) => [asset.id, asset] as const))\n\n const listDocs = (collection: string): ResolvedDocument[] => {\n const result = client.listDocuments(collection)\n return result.ok ? result.documents : []\n }\n\n // EC-274: `settings` is a singleton — the lone document of its collection.\n const settings = listDocs(settingsCollection)[0] ?? null\n\n // EC-284/EC-364: menus are addressed by slot alias through the content client\n // (delivery shape carries `alias`), never by document id.\n const navDocs = listDocs(navigationCollection)\n const navigation = (slot: string): ResolvedDocument | null =>\n navDocs.find((doc) => (doc as Record<string, unknown>).alias === slot) ?? null\n\n /** Asset field value → serve URL. The stored value is the asset id (or already a URL). */\n const assetUrl = (value: unknown): string | undefined => {\n if (typeof value === 'string') {\n const found = assetById.get(value)\n if (found) return found.url\n // A passthrough URL (external image / public asset path) — not an id.\n return value.startsWith('http') || value.startsWith('/') ? value : undefined\n }\n const url = record(value).url\n return typeof url === 'string' && url.length > 0 ? url : undefined\n }\n\n /** A raw or populated relation value's `{ collection, id }` identity, if present. */\n const refOf = (value: unknown): DocumentRef | null => {\n const ref = record(value)\n return typeof ref.collection === 'string' && typeof ref.id === 'string'\n ? { collection: ref.collection, id: ref.id }\n : null\n }\n\n /** Resolve a link-object value (`linkType: href | page | file`) to an href. */\n const resolveLink = (value: unknown): ResolvedLink | null => {\n const link = record(value)\n const openInNewTab = link.openInNewTab === true\n const href = str(link.href) || str(link.url)\n const linkType = str(link.linkType) || (href ? 'href' : '')\n\n if (linkType === 'href' || linkType === 'external') {\n return href ? { href, openInNewTab } : null\n }\n if (linkType === 'file') {\n const url = assetUrl(link.file)\n return url ? { href: url, openInNewTab } : null\n }\n if (linkType === 'page') {\n const page = link.page\n // The reverse-router authority (EC-291/EC-360): the SAME `urlForDocument`\n // the routes serve — composed nested paths, `home → '/'`, locale prefix.\n const ref = refOf(page)\n if (ref) {\n const path = client.resolveLink(ref)\n if (path !== null) return { href: path, openInNewTab }\n }\n // Degraded fallbacks for partially-shaped values; else explicit null.\n const shaped = record(page)\n if (typeof shaped.path === 'string' && shaped.path.startsWith('/')) {\n return { href: shaped.path, openInNewTab }\n }\n const slug = str(shaped.slug)\n if (slug) return { href: `/${slug}`, openInNewTab }\n return null\n }\n return null\n }\n\n const toNavLink = (entry: Record<string, unknown>): ResolvedNavLink | null => {\n const label = str(entry.label)\n // Structured shape: the link object lives under `link`; flat starter shape:\n // the entry itself carries `href` (resolveLink's href fallback picks it up).\n const resolved = resolveLink('link' in entry ? entry.link : entry)\n if (!label || !resolved) return null\n const description = str(entry.description)\n return { label, ...resolved, ...(description ? { description } : {}) }\n }\n\n const toNavEntry = (entry: Record<string, unknown>): ResolvedNavEntry | null => {\n const label = str(entry.label)\n if (!label) return null\n const resolved = resolveLink('link' in entry ? entry.link : entry)\n const description = str(entry.description)\n const children = items(entry.children)\n .map(toNavLink)\n .filter((child): child is ResolvedNavLink => child !== null)\n // A leaf entry needs a resolvable target; an entry with children stands as a\n // group heading even without one (footer columns, pure dropdowns).\n if (!resolved && children.length === 0) return null\n return {\n label,\n ...(resolved ? { href: resolved.href } : {}),\n openInNewTab: resolved?.openInNewTab ?? false,\n ...(description ? { description } : {}),\n children,\n }\n }\n\n const navigationEntries = (slot: string): ResolvedNavEntry[] => {\n const doc = navigation(slot)\n if (!doc) return []\n const values = doc as Record<string, unknown>\n const field = itemsFields.find((name) => Array.isArray(values[name]))\n if (!field) return []\n return items(values[field])\n .map(toNavEntry)\n .filter((entry): entry is ResolvedNavEntry => entry !== null)\n }\n\n return {\n settings,\n navigation,\n navigationEntries,\n resolveLink,\n assetUrl,\n client,\n source,\n }\n}\n","/**\n * Pure token/target logic of the draft-preview routes (EC-144), kept free of\n * Next.js imports so it is unit-testable. `preview.ts` wires it into route\n * handlers with `draftMode()`.\n */\n\nexport type PreviewEvaluation =\n | { ok: true; redirectTo: string }\n | { ok: false; status: 400 | 401; message: string }\n\n/**\n * Only same-site path targets are accepted (`/...` but not `//host`), so the\n * preview endpoint can never be used as an open redirect.\n */\nexport function safeRedirectTarget(\n value: string | null | undefined,\n fallback = '/',\n): string | null {\n if (value === null || value === undefined || value === '') return fallback\n if (!value.startsWith('/') || value.startsWith('//')) return null\n return value\n}\n\n/**\n * Evaluate a preview-enable request. Drafts are token-gated (EC-144\n * acceptance: without the token, drafts are never reachable):\n *\n * - an unconfigured (empty) expected token rejects every request — preview\n * cannot be accidentally left open;\n * - a missing or mismatched `token` query param is a 401;\n * - an off-site `redirect` target is a 400.\n */\nexport function evaluatePreviewRequest(\n requestUrl: string | URL,\n expectedToken: string | undefined,\n): PreviewEvaluation {\n if (expectedToken === undefined || expectedToken.length === 0) {\n return { ok: false, status: 401, message: 'Draft preview is not configured.' }\n }\n\n let url: URL\n try {\n url = typeof requestUrl === 'string' ? new URL(requestUrl, 'http://localhost') : requestUrl\n } catch {\n return { ok: false, status: 400, message: 'Malformed preview request URL.' }\n }\n\n const token = url.searchParams.get('token')\n if (token !== expectedToken) {\n return { ok: false, status: 401, message: 'Invalid preview token.' }\n }\n\n const redirectTo = safeRedirectTarget(url.searchParams.get('redirect'))\n if (redirectTo === null) {\n return { ok: false, status: 400, message: 'Preview redirect target must be a same-site path.' }\n }\n\n return { ok: true, redirectTo }\n}\n","import { draftMode } from 'next/headers'\nimport { redirect } from 'next/navigation'\nimport { evaluatePreviewRequest, safeRedirectTarget } from './preview-core'\n\n/**\n * Draft preview route handlers (EC-144): Next.js `draftMode()` integration.\n * Server-only by construction — these factories are consumed from App Router\n * route handler files, never from client bundles.\n */\n\nexport interface PreviewRouteOptions {\n /**\n * The shared secret gating draft preview. An empty/undefined token means\n * every request is rejected with 401 — drafts stay unreachable until a\n * token is configured.\n */\n token: string | undefined\n}\n\n/** The shape an `app/api/.../route.ts` file re-exports. */\nexport interface PreviewRouteHandlers {\n GET(request: Request): Promise<Response>\n}\n\n/**\n * Create the preview-enable route handler for\n * `app/api/preview/route.ts`:\n *\n * ```ts\n * export const { GET } = createPreviewRoute({ token: process.env.PREVIEW_TOKEN })\n * ```\n *\n * `GET /api/preview?token=...&redirect=/some/path` checks the token, enables\n * Next draft mode (the catch-all helper then renders the `draft`\n * perspective), and redirects to the target path. Wrong/missing token → 401.\n */\nexport function createPreviewRoute(options: PreviewRouteOptions): PreviewRouteHandlers {\n return {\n async GET(request: Request): Promise<Response> {\n const evaluation = evaluatePreviewRequest(request.url, options.token)\n if (!evaluation.ok) {\n return new Response(evaluation.message, { status: evaluation.status })\n }\n const draft = await draftMode()\n draft.enable()\n redirect(evaluation.redirectTo)\n },\n }\n}\n\n/**\n * Create the preview-disable route handler (e.g.\n * `app/api/preview/disable/route.ts`). Disabling needs no token — it only\n * ever reduces visibility back to the published perspective.\n */\nexport function createPreviewDisableRoute(): PreviewRouteHandlers {\n return {\n async GET(request: Request): Promise<Response> {\n const draft = await draftMode()\n draft.disable()\n let target: string | null\n try {\n target = safeRedirectTarget(new URL(request.url).searchParams.get('redirect'))\n } catch {\n target = '/'\n }\n redirect(target ?? '/')\n },\n }\n}\n","import { draftMode } from 'next/headers'\nimport type { CollectionDef, LocaleConfig, RouteRecord } from '@elytracms/core/cms-core'\nimport type { Perspective } from '@elytracms/core/content'\nimport type { Metadata } from 'next'\nimport { defineHostComponents } from './components'\nimport type { HostComponent, HostComponents } from './components'\nimport { firstBlockFullBleed } from './full-bleed'\nimport { resolveHostEnv } from './host-env'\nimport type { ElytraHostEnv } from './host-env'\nimport { loadLiveContent } from './host-content'\nimport { resolveGlobals } from './host-globals'\nimport type { GlobalsConventions, SiteGlobals } from './host-globals'\nimport { nextImagePrimitive } from './image'\nimport type { NextImagePrimitiveOptions } from './image'\nimport { createPreviewDisableRoute, createPreviewRoute } from './preview'\nimport type { PreviewRouteHandlers } from './preview'\nimport { createRevalidateRoute } from './revalidate'\nimport type { RevalidateRouteHandlers, RevalidateRouteOptions } from './revalidate'\nimport { createCanvasRoute } from './route'\nimport type {\n CanvasCacheOptions,\n CanvasContentRequest,\n CanvasRequestInfo,\n CanvasRoute,\n} from './route'\nimport { pathFromSlug, splitLocalePath } from './route-core'\nimport type { CanvasPayloadsFactory } from './route-core'\nimport { createStaticContentSource } from './snapshot'\nimport type { ContentSource } from './source'\nimport type { CacheTags, ResolvePageResult } from '@elytracms/core/content'\n\n/**\n * The delivery host kit (EC-368): ONE factory over (env, project config) that\n * yields every engine-shaped delivery surface a Next.js host mounts — content\n * loading (live snapshot / build-safe empty / token-gated draft), the catch-all\n * canvas route, the instant-publish revalidate webhook, draft-mode plumbing,\n * chrome globals, and the full-bleed layout hint. A consumer wires env + ~5\n * lines per surface; no engine logic is ever copied into a host repo again\n * (EC-369 findings #4/#5/#6/#11).\n *\n * ```ts\n * // frontend/lib/elytra.ts — the ONE seam file\n * import { createElytraHost } from '@elytracms/next'\n * import { collections, routes } from '../../cms'\n * import { siteComponents } from '../../components'\n *\n * export const elytra = createElytraHost({\n * slug: 'my-site',\n * locales: { default: 'en', locales: ['en'] },\n * collections,\n * routes,\n * components: siteComponents,\n * })\n * ```\n *\n * ```ts\n * // app/[[...slug]]/page.tsx\n * const route = elytra.canvasRoute()\n * export default route.Page\n * export const generateMetadata = route.generateMetadata\n *\n * // app/api/revalidate/route.ts\n * export const { POST, OPTIONS } = elytra.revalidateRoute()\n *\n * // app/api/draft/route.ts — GET /api/draft?token=…&redirect=/path\n * export const { GET } = elytra.previewRoute()\n *\n * // app/api/draft/disable/route.ts\n * export const { GET } = elytra.previewDisableRoute()\n * ```\n *\n * Trust boundaries are unchanged: live surfaces read the PUBLISHED snapshot;\n * draft is reachable only through explicit Next draft mode behind the ONE\n * `DRAFT_PREVIEW_TOKEN` (which also authenticates the draft snapshot fetch —\n * see `host-env.ts`); the revalidate webhook stays HMAC-signed. The consumer\n * keeps ownership of project config (AD-11), host components, form endpoints,\n * and anything genuinely bespoke.\n */\n\nexport interface ElytraHostOptions {\n /**\n * The project slug (config-as-code identity, mirrors `elytra.config.ts`).\n * Used as the content scope when no live backend is configured.\n */\n slug: string\n /** Locale config — config-owned (AD-11), never read from the snapshot. */\n locales: LocaleConfig\n /** CMS collection schema — config-owned (AD-11). */\n collections: readonly CollectionDef[]\n /** Routes as code (AD-3/AD-11): records, or the `(collections) => records` derive. */\n routes: readonly RouteRecord[] | ((collections: CollectionDef[]) => RouteRecord[])\n /**\n * The repo's page-builder components (manifest + implementation pairs — the\n * SAME modules the studio composes with). Base primitives are always\n * included; `base.Image` is swapped for `next/image` delivery by default\n * (see `image`).\n */\n components?: readonly HostComponent[]\n /**\n * `base.Image` delivery options (loader/sizes/quality — the non-Vercel CDN\n * seam), or `false` to keep the plain-`<img>` primitive. Default: Next's own\n * optimizer, registered out of the box.\n */\n image?: NextImagePrimitiveOptions | false\n /**\n * The public base URL of the delivery site (mirrors the config's\n * `frontendUrl`) — exposed on the handle for sitemap/canonical use.\n */\n frontendUrl?: string\n /**\n * Env bag; defaults to `process.env`. Documented names (see `host-env.ts`):\n * `ELYTRA_CONVEX_URL`, `ELYTRA_PROJECT_ID`, `DRAFT_PREVIEW_TOKEN`,\n * `REVALIDATE_SECRET`, `STUDIO_ORIGIN`.\n */\n env?: Record<string, string | undefined>\n /**\n * The no-backend content fallback, used whenever `ELYTRA_CONVEX_URL` +\n * `ELYTRA_PROJECT_ID` are not both set. Default: a build-safe EMPTY source —\n * consumer CI builds green with no backend, and every URL is a clean 404\n * until content exists. The starter template overrides this with its seeded\n * in-memory world.\n */\n fallbackContent?: (request: CanvasContentRequest) => Promise<ContentSource>\n /** Chrome-globals conventions (settings/navigation collection ids, items fields). */\n globals?: GlobalsConventions\n /** Fetch implementation override for the live snapshot loader (tests, proxies). */\n fetch?: typeof globalThis.fetch\n}\n\n/** Pass-through canvas-route options the kit does not own. */\nexport interface HostCanvasRouteOptions {\n /** Extra binding payloads per request (see `CanvasRouteOptions.payloads`). */\n payloads?: CanvasPayloadsFactory\n /** Tag observation hook (see `CanvasRouteOptions.onTags`). */\n onTags?: (tags: CacheTags, info: CanvasRequestInfo) => void\n /** Metadata override (see `CanvasRouteOptions.metadata`). */\n metadata?: (result: ResolvePageResult, info: CanvasRequestInfo) => Metadata\n /**\n * Tagged data cache (instant publish). Default: enabled, scoped to the\n * kit's content scope so the studio's webhook tags match. `false` disables\n * caching entirely; an explicit `CanvasCacheOptions` overrides the scope.\n */\n cache?: CanvasCacheOptions | false\n}\n\nexport interface LoadGlobalsOptions {\n /** Perspective of the chrome read. Default `'published'` (live is published-only). */\n perspective?: Perspective\n}\n\n/** The delivery host handle {@link createElytraHost} yields. */\nexport interface ElytraHost {\n /**\n * The cache-tag scope: `ELYTRA_PROJECT_ID` in live mode (matching the\n * studio's webhook tags), else the config slug.\n */\n contentScope: string\n /** The resolved env bag (documented names, trimmed, empty = unset). */\n env: ElytraHostEnv\n /** Materialized route records (a derive is run once, at factory time). */\n routes: RouteRecord[]\n /** The registered component surface (base primitives + image swap + project components). */\n components: HostComponents\n /** The public base URL of the delivery site, when configured. */\n frontendUrl?: string\n /**\n * The content loader (the seam every kit surface reads through): live\n * delivery snapshot when env is configured — published, or the token-gated\n * draft for draft-mode requests — else the fallback source.\n */\n loadContent(request: CanvasContentRequest): Promise<ContentSource>\n /**\n * Load + resolve the site-chrome globals (settings singleton, navigation by\n * slot alias, link/asset resolution — see `host-globals.ts`). One content\n * load per call; published perspective by default.\n */\n loadGlobals(options?: LoadGlobalsOptions): Promise<SiteGlobals>\n /** The catch-all canvas route pair for `app/[[...slug]]/page.tsx`. */\n canvasRoute(options?: HostCanvasRouteOptions): CanvasRoute\n /**\n * The instant-publish webhook handlers for `app/api/revalidate/route.ts`,\n * wired to `REVALIDATE_SECRET` (+ `STUDIO_ORIGIN` CORS). Unset secret =\n * endpoint closed (401), never a default secret.\n */\n revalidateRoute(overrides?: Partial<RevalidateRouteOptions>): RevalidateRouteHandlers\n /**\n * The draft-mode ENABLE route for e.g. `app/api/draft/route.ts` —\n * `GET /api/draft?token=…&redirect=/path`, gated by the ONE\n * `DRAFT_PREVIEW_TOKEN` (the same secret the draft snapshot fetch sends, so\n * the two can never disconnect). Unset token = drafts unreachable.\n */\n previewRoute(): PreviewRouteHandlers\n /** The draft-mode DISABLE route (no token — it only reduces visibility). */\n previewDisableRoute(): PreviewRouteHandlers\n /**\n * Does the page for this catch-all `slug` OPEN full-bleed? Manifest-driven\n * (`presentation.fullBleed`, EC-368) and draft-mode aware — the host lays out\n * header clearance from data instead of a hand-kept component-id set.\n */\n pageOpensFullBleed(slug: readonly string[] | undefined): Promise<boolean>\n}\n\n/** Materialize a config `routes` value (EC-207): run a derive or copy the array. */\nfunction materializeRoutes(\n routes: ElytraHostOptions['routes'],\n collections: readonly CollectionDef[],\n): RouteRecord[] {\n return typeof routes === 'function' ? routes([...collections]) : [...routes]\n}\n\n/** Create the delivery host handle — see the module docs for the full wiring. */\nexport function createElytraHost(options: ElytraHostOptions): ElytraHost {\n const env = resolveHostEnv(options.env ?? process.env)\n const routes = materializeRoutes(options.routes, options.collections)\n const live = env.convexUrl !== undefined && env.projectId !== undefined\n const contentScope = live ? (env.projectId as string) : options.slug\n\n const components = defineHostComponents([\n // Batteries included (EC-368 image defaults): graph `base.Image` nodes render\n // through next/image — resized variants via the host's own optimizer. The\n // canonical manifest stays (first registration wins in defineHostComponents).\n ...(options.image === false ? [] : [nextImagePrimitive(options.image ?? {})]),\n ...(options.components ?? []),\n ])\n\n // The build-safe default fallback: an EMPTY source over the config's own\n // structure. Constructed once — it is fully static.\n const emptySource: ContentSource = createStaticContentSource({\n projectId: contentScope,\n locales: options.locales,\n routes,\n // Redirects are editorial DATA (EC-303) — the no-backend build has none.\n redirects: [],\n collections: [...options.collections],\n documents: [],\n assets: [],\n sources: [],\n })\n\n const loadContent = (request: CanvasContentRequest): Promise<ContentSource> => {\n if (live) {\n return loadLiveContent(\n {\n convexUrl: env.convexUrl as string,\n projectId: env.projectId as string,\n locales: options.locales,\n collections: options.collections,\n routes,\n ...(env.draftToken ? { draftToken: env.draftToken } : {}),\n ...(options.fetch ? { fetch: options.fetch } : {}),\n },\n request.perspective,\n )\n }\n if (options.fallbackContent) return options.fallbackContent(request)\n return Promise.resolve(emptySource)\n }\n\n const loadGlobals = async (globalsOptions: LoadGlobalsOptions = {}): Promise<SiteGlobals> => {\n const perspective = globalsOptions.perspective ?? 'published'\n const source = await loadContent({ perspective })\n return resolveGlobals(source, {\n perspective,\n ...(options.globals ? { conventions: options.globals } : {}),\n })\n }\n\n const canvasRoute = (routeOptions: HostCanvasRouteOptions = {}): CanvasRoute => {\n const { cache, ...rest } = routeOptions\n return createCanvasRoute({\n loadContent,\n components,\n // Tag scope = the project id the studio publishes under, so its webhook\n // tags match this site's cached entries.\n ...(cache === false ? {} : { cache: cache ?? { scope: contentScope } }),\n ...rest,\n })\n }\n\n const revalidateRoute = (\n overrides: Partial<RevalidateRouteOptions> = {},\n ): RevalidateRouteHandlers =>\n createRevalidateRoute({\n // An unset secret keeps the endpoint CLOSED (401) — the kit never ships a\n // default secret (an auth-shaped no-op is worse than an explicit gap).\n secret: 'secret' in overrides ? overrides.secret : env.revalidateSecret,\n ...(overrides.allowOrigin !== undefined\n ? { allowOrigin: overrides.allowOrigin }\n : env.studioOrigin !== undefined\n ? { allowOrigin: env.studioOrigin }\n : {}),\n })\n\n // ONE secret by construction: the preview gate and the draft snapshot fetch\n // both read env.draftToken — they cannot disconnect (EC-369 finding #4).\n const previewRoute = (): PreviewRouteHandlers => createPreviewRoute({ token: env.draftToken })\n const previewDisableRoute = (): PreviewRouteHandlers => createPreviewDisableRoute()\n\n const pageOpensFullBleed = async (slug: readonly string[] | undefined): Promise<boolean> => {\n const { isEnabled } = await draftMode()\n const perspective: Perspective = isEnabled ? 'draft' : 'published'\n const source = await loadContent({ perspective })\n const { locale, path } = splitLocalePath(pathFromSlug(slug), source.locales)\n const client = source.client({ perspective, locale })\n const resolved = client.resolvePage(path)\n return firstBlockFullBleed(resolved.document, components.registry)\n }\n\n return {\n contentScope,\n env,\n routes,\n components,\n ...(options.frontendUrl !== undefined ? { frontendUrl: options.frontendUrl } : {}),\n loadContent,\n loadGlobals,\n canvasRoute,\n revalidateRoute,\n previewRoute,\n previewDisableRoute,\n pageOpensFullBleed,\n }\n}\n","/**\n * @elytracms/next — the embedded runtime (EC-144, vision AD-1): render\n * builder-managed pages inside the user's own Next.js App Router repo with\n * the user's own components. Drop `createCanvasRoute` into a catch-all\n * route, register components with `defineHostComponents`, done.\n *\n * Nothing here imports builder-only code (no studio, no operations, no\n * TanStack) — only the runtime packages: content accessors, the component\n * registry, and the runtime renderer.\n */\nexport const PACKAGE = '@elytracms/next'\n\n// Component registration (host components + base primitives).\nexport { defineHostComponents } from './components'\nexport type { DefineHostComponentsOptions, HostComponent, HostComponents } from './components'\n\n// The server component.\nexport { CanvasRenderer, defaultBindingPayloads } from './canvas-renderer'\nexport type { CanvasRendererProps } from './canvas-renderer'\n\n// Binding payloads (embedded-runtime binding resolution). The explicit\n// source-payload issue value makes rejected stored queries render visibly.\nexport {\n createBindingResolver,\n isSourcePayloadError,\n resolvePayloadToken,\n sourcePayloadError,\n} from './payloads'\nexport type { BindingPayloads, SourcePayloadError } from './payloads'\n\n// Content source seam + cache-tag merging (EC-145/146 plug in here).\nexport { mergeCacheTags } from './source'\nexport type { CanvasDataSource, ContentSource } from './source'\n\n// EC-166 delivery: automatic payload materialization for repeating sections\n// (replayed stored queries) and template pages (the route-bound document).\nexport { collectBindingSourceIds, materializeSourcePayloads } from './source-payloads'\nexport type {\n MaterializeSourcePayloadsInput,\n MaterializedSourcePayloads,\n} from './source-payloads'\n\n// PersistenceAdapter → ContentLookup snapshot bridge, plus the plain-data\n// assembler for hosts that prefetched the content themselves (EC-156).\nexport {\n createContentSnapshot,\n createStaticContentSource,\n mergeRouteRecords,\n} from './snapshot'\nexport type { ContentSnapshot, ContentSnapshotOptions, StaticContentData } from './snapshot'\n\n// Catch-all route helper (pure core + Next wiring).\nexport { pathFromSlug, resolveCanvasPage, splitLocalePath } from './route-core'\nexport type {\n CanvasPageOutcome,\n CanvasPayloadContext,\n CanvasPayloadsFactory,\n ResolveCanvasPageOptions,\n} from './route-core'\nexport { createCanvasRoute } from './route'\nexport type {\n CanvasCacheOptions,\n CanvasContentRequest,\n CanvasRequestInfo,\n CanvasRoute,\n CanvasRouteOptions,\n CanvasRouteProps,\n} from './route'\n\n// Per-page SEO → Next metadata, and sitemap.xml from published routes (EC-171).\nexport { canvasPageMetadata } from './metadata'\nexport { canvasSitemapEntries, createCanvasSitemap } from './sitemap'\nexport type {\n CanvasSitemapOptions,\n CanvasSitemapResult,\n CreateCanvasSitemapOptions,\n SitemapParamsProvider,\n SitemapRouteContext,\n SitemapSkippedRoute,\n} from './sitemap'\n\n// Cache tags & instant publish (EC-146): tag format, tag-discovery caching,\n// and the signed revalidation webhook receiver.\nexport {\n collectionCacheTag,\n docCacheTag,\n loadCachedEntry,\n nextCacheTags,\n projectSweepTag,\n routeCacheTag,\n scopeCacheTag,\n} from './cache'\nexport type { CacheWrapper, CacheWrapperOptions, CachedEntry } from './cache'\nexport {\n REVALIDATE_SIGNATURE_HEADER,\n evaluateRevalidateRequest,\n revalidatePayloadSchema,\n signRevalidateBody,\n} from './revalidate-core'\nexport type { RevalidateEvaluation, RevalidatePayload } from './revalidate-core'\nexport { createRevalidateRoute } from './revalidate'\nexport type { RevalidateRouteHandlers, RevalidateRouteOptions } from './revalidate'\n\n// Asset-pipeline image primitive (EC-147) + the host-image renderer (EC-368):\n// the next/image-backed implementation a host registers on the\n// `@elytracms/next/host-image` bridge (the bridge itself is its OWN subpath —\n// importing it from here would bundle a second singleton instance).\nexport { ElytraImage, createAssetImageLoader, elytraHostImage, nextImagePrimitive } from './image'\nexport type {\n AssetImageLoaderOptions,\n ElytraHostImageOptions,\n ElytraImageAsset,\n ElytraImageProps,\n NextImagePrimitiveOptions,\n} from './image'\n\n// The delivery host kit (EC-368): one factory over (env, project config)\n// yielding every engine-shaped host surface — content loading, the catch-all\n// route, revalidate, draft-mode plumbing, chrome globals, layout hints.\nexport { createElytraHost } from './host-kit'\nexport type {\n ElytraHost,\n ElytraHostOptions,\n HostCanvasRouteOptions,\n LoadGlobalsOptions,\n} from './host-kit'\nexport { ELYTRA_HOST_ENV_KEYS, resolveHostEnv } from './host-env'\nexport type { ElytraHostEnv } from './host-env'\nexport { assembleLiveSource, fallbackHomeRoutes, loadLiveContent } from './host-content'\nexport type { LiveContentOptions } from './host-content'\nexport { resolveGlobals } from './host-globals'\nexport type {\n GlobalsConventions,\n ResolveGlobalsOptions,\n ResolvedLink,\n ResolvedNavEntry,\n ResolvedNavLink,\n SiteGlobals,\n} from './host-globals'\nexport { firstBlockFullBleed } from './full-bleed'\n\n// Draft preview (token-gated draftMode integration).\nexport { evaluatePreviewRequest, safeRedirectTarget } from './preview-core'\nexport type { PreviewEvaluation } from './preview-core'\nexport { createPreviewDisableRoute, createPreviewRoute } from './preview'\nexport type { PreviewRouteHandlers, PreviewRouteOptions } from './preview'\n\n// Re-exports so host apps can author manifests, declare their config, and shape\n// content WITHOUT depending on the internal packages (or on zod) directly — a\n// consuming repo installs ONLY `@elytracms/next` for delivery (EC-193).\nexport { defineComponent } from '@elytracms/core/component-registry'\n// EC-190: component props are field-defs (`PropField`), not the retired `PropSpec`.\nexport type { ComponentManifest, PropField, SlotSpec } from '@elytracms/core/component-registry'\nexport type { ComponentImplementations, RenderAsset } from '@elytracms/core/runtime-renderer'\nexport { z } from 'zod'\n\n// Config + content shapes a host declares (collections, locales, routes,\n// documents) — the public surface of the structure that lives in the repo\n// (AD-11). Re-exported here so the host imports one package (EC-193).\nexport {\n documentSchema,\n routeRecordSchema,\n redirectRecordSchema,\n localeConfigSchema,\n} from '@elytracms/core/cms-core'\nexport type {\n CollectionDef,\n CmsDocument,\n FieldDef,\n LocaleConfig,\n Locale,\n RouteRecord,\n RedirectRecord,\n} from '@elytracms/core/cms-core'\n// Composition node shape (a page document's `body` is a ComponentNode list, per AD-12).\nexport type { ComponentNode } from '@elytracms/core/project-graph'\n// The delivery perspective (draft | published).\nexport type { Perspective } from '@elytracms/core/content'\n// The delivery shape of an asset (resolved url + metadata).\nexport type { AssetRecord } from '@elytracms/core/persistence'\n"]}
1
+ {"version":3,"sources":["../src/components.ts","../src/payloads.ts","../src/canvas-renderer.tsx","../src/source.ts","../src/source-payloads.ts","../src/snapshot.ts","../src/route-core.ts","../src/cache.ts","../src/metadata.ts","../src/route.tsx","../src/sitemap.ts","../src/revalidate-core.ts","../src/revalidate.ts","../src/image.tsx","../src/full-bleed.ts","../src/host-env.ts","../src/host-content.ts","../src/host-globals.ts","../src/preview-core.ts","../src/preview.ts","../src/host-kit.ts","../src/index.ts"],"names":["record","cacheTags","jsx","outcome","splitPath","z","str","draftMode","redirect"],"mappings":"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","file":"index.js","sourcesContent":["import type { ComponentType } from 'react'\nimport { ComponentRegistry } from '@elytracms/core/component-registry'\nimport type { ComponentIssue, ComponentManifest } from '@elytracms/core/component-registry'\nimport { basePrimitives, getImplementation } from '@elytracms/core/runtime-renderer'\nimport type { ComponentImplementations } from '@elytracms/core/runtime-renderer'\n\n/**\n * One host-repo component: the manifest the builder edits against plus the\n * real React implementation that renders it (vision AD-2 — project components\n * are real code in the host repo, never generated).\n */\nexport interface HostComponent {\n manifest: ComponentManifest\n implementation: ComponentType<Record<string, unknown>>\n}\n\n/**\n * The registered component surface a host app hands to `<CanvasRenderer />`\n * and the catch-all route helper: a manifest registry plus the implementation\n * map, with registration problems surfaced as structured issues (never\n * thrown — an unknown component renders the EC-015 fallback).\n */\nexport interface HostComponents {\n registry: ComponentRegistry\n implementations: ComponentImplementations\n /** Structural registration issues (duplicate ids, invalid namespaces). */\n issues: readonly ComponentIssue[]\n}\n\nexport interface DefineHostComponentsOptions {\n /**\n * Include the platform primitives (`base.*`) that ship with\n * `@elytracms/core/runtime-renderer`. Defaults to `true` — graphs authored in the\n * builder assume them.\n */\n includeBasePrimitives?: boolean\n}\n\n/**\n * Component registration API for the embedded runtime (EC-144). The host repo\n * supplies real implementations + manifests; base primitives are included by\n * default. A host implementation registered under a primitive id replaces the\n * default implementation (the manifest of the first registration wins, which\n * is the primitive's — by design, so prop schemas stay canonical).\n */\nexport function defineHostComponents(\n components: readonly HostComponent[] = [],\n options: DefineHostComponentsOptions = {},\n): HostComponents {\n const includeBase = options.includeBasePrimitives !== false\n const base = includeBase ? basePrimitives() : { manifests: [], implementations: {} }\n\n const registry = new ComponentRegistry([...base.manifests, ...components.map((c) => c.manifest)])\n\n const implementations: Record<string, ComponentType<Record<string, unknown>>> = {}\n for (const manifest of base.manifests) {\n const implementation = getImplementation(base.implementations, manifest.id)\n if (implementation) implementations[manifest.id] = implementation\n }\n for (const component of components) {\n implementations[component.manifest.id] = component.implementation\n }\n\n return { registry, implementations, issues: registry.issues }\n}\n","import type { BindingReference } from '@elytracms/core/project-graph'\nimport type { ItemContext, ResolveBinding } from '@elytracms/core/runtime-renderer'\n\n/**\n * Binding payloads for the embedded runtime (EC-144): one payload value per\n * binding `sourceId`. The catch-all route helper provides `document` (the\n * route-bound resolved document) and `params` (dynamic route params) by\n * default; hosts add more through the route helper's `payloads` factory\n * (e.g. a `listDocuments` result for a posts repeater).\n *\n * This is a deliberately small, pure resolver — the embedded runtime never\n * imports `@elytracms/core/data-binding` (a builder-side package). Semantics mirror\n * EC-023 tokens: a binding token is a JSON Pointer (RFC 6901) into the\n * payload; a miss resolves to `undefined`, never a throw (the renderer turns\n * unresolvable bindings into visible fallback behavior, EC-015).\n */\nexport type BindingPayloads = Record<string, unknown>\n\n/**\n * Marker key of an {@link SourcePayloadError} payload. A plain string property\n * (not a Symbol) on purpose: the route helper's cached path JSON-serializes\n * payloads through `unstable_cache`, and the marker must survive that\n * round-trip.\n */\nconst SOURCE_PAYLOAD_ERROR_KEY = '__elytraSourcePayloadError'\n\n/**\n * Explicit issue payload for a source whose stored query was REJECTED at\n * delivery (EC-177 gap 3) — e.g. a sort/filter field that is no longer\n * filterable in the live schema. Materialization stores this instead of a\n * silently-absent payload; `createBindingResolver` throws on it, which the\n * renderer converts into its visible per-node render-error fallback (EC-015).\n * Validation principle: a broken stored query is a visible state, never an\n * empty section.\n */\nexport interface SourcePayloadError {\n [SOURCE_PAYLOAD_ERROR_KEY]: true\n sourceId: string\n /** Human-readable messages of the structured query errors. */\n messages: string[]\n}\n\n/** Build the explicit issue payload for one failed source query. */\nexport function sourcePayloadError(\n sourceId: string,\n messages: readonly string[],\n): SourcePayloadError {\n return { [SOURCE_PAYLOAD_ERROR_KEY]: true, sourceId, messages: [...messages] }\n}\n\n/** `true` when a payload value is an explicit {@link SourcePayloadError}. */\nexport function isSourcePayloadError(value: unknown): value is SourcePayloadError {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as Record<string, unknown>)[SOURCE_PAYLOAD_ERROR_KEY] === true &&\n typeof (value as { sourceId?: unknown }).sourceId === 'string' &&\n Array.isArray((value as { messages?: unknown }).messages)\n )\n}\n\n/** Unescape one RFC 6901 reference token (`~1` → `/`, `~0` → `~`). */\nfunction unescapeRefToken(token: string): string {\n return token.replace(/~1/g, '/').replace(/~0/g, '~')\n}\n\n/** Parse a JSON Pointer into segments; `''`/`'/'` is the root. `undefined` = malformed. */\nfunction pathFromToken(token: string): string[] | undefined {\n if (token === '' || token === '/') return []\n if (!token.startsWith('/')) return undefined\n return token.slice(1).split('/').map(unescapeRefToken)\n}\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\n/**\n * Resolve a JSON Pointer token within a payload value. Numeric segments index\n * arrays; string segments index plain objects. Any miss (unknown key,\n * out-of-range index, traversal through a primitive) yields `undefined`.\n */\nexport function resolvePayloadToken(payload: unknown, token: string): unknown {\n const path = pathFromToken(token)\n if (path === undefined) return undefined\n let current: unknown = payload\n for (const segment of path) {\n if (Array.isArray(current)) {\n if (!/^(0|[1-9][0-9]*)$/.test(segment)) return undefined\n const index = Number(segment)\n if (index >= current.length) return undefined\n current = current[index]\n continue\n }\n if (isPlainObject(current)) {\n if (!Object.prototype.hasOwnProperty.call(current, segment)) return undefined\n current = current[segment]\n continue\n }\n return undefined\n }\n return current\n}\n\n/**\n * Create the renderer's `ResolveBinding` over a payload map. Mode semantics\n * (brief §4.6, uniform binding model):\n *\n * - `value` / `object` / `condition` — the value at the token within the\n * payload named by `sourceId`.\n * - `spread` — same lookup; the renderer spreads the resulting object.\n * - `repeaterItem` — the token resolves against the active repeater item,\n * not the root payload.\n *\n * Total for data misses: an unknown `sourceId` or missing path resolves to\n * `undefined` — the renderer (EC-015) degrades visibly instead of crashing.\n * An explicit {@link SourcePayloadError} payload (a REJECTED stored query, not\n * merely missing data) throws instead: the renderer catches per node and\n * renders its visible render-error fallback with the query error message;\n * conditions treat the throw as `false` (the node hides) — never a page crash.\n */\nexport function createBindingResolver(payloads: BindingPayloads): ResolveBinding {\n return (ref: BindingReference, item?: ItemContext): unknown => {\n if (ref.mode === 'repeaterItem') {\n return item === undefined ? undefined : resolvePayloadToken(item.item, ref.token)\n }\n if (!Object.prototype.hasOwnProperty.call(payloads, ref.sourceId)) return undefined\n const payload = payloads[ref.sourceId]\n if (isSourcePayloadError(payload)) {\n throw new Error(\n `Source \"${payload.sourceId}\" query was rejected: ${payload.messages.join('; ')}`,\n )\n }\n return resolvePayloadToken(payload, ref.token)\n }\n}\n","import { isValidElement } from 'react'\nimport type { ReactNode } from 'react'\nimport type { ResolvedAsset, ResolvePageResult } from '@elytracms/core/content'\nimport type { ComponentNode } from '@elytracms/core/project-graph'\nimport {\n RenderErrorBoundary,\n renderComposition,\n serializeListingQuery,\n} from '@elytracms/core/runtime-renderer'\nimport type {\n RelationTarget,\n RenderAsset,\n RenderContext,\n ResolveBinding,\n ResolveLink,\n ResolveListing,\n ResolveRelation,\n} from '@elytracms/core/runtime-renderer'\nimport type { HostComponents } from './components'\nimport { createBindingResolver } from './payloads'\nimport type { BindingPayloads } from './payloads'\n\n/**\n * `<CanvasRenderer />` (EC-144, vision AD-1): an async React Server Component\n * that renders a resolved page (from `resolvePage`, EC-143) through\n * `@elytracms/core/runtime-renderer` with the host app's component registry. EC-015\n * fallback behavior is identical to the builder: a missing component, invalid\n * prop, or missing required slot renders a visible fallback — a page never\n * crashes and never silently omits a node.\n */\nexport interface CanvasRendererProps {\n /** The `resolvePage` result for the current URL. */\n result: ResolvePageResult\n /** Host component surface from `defineHostComponents`. */\n components: HostComponents\n /**\n * Binding payloads keyed by `sourceId`. Defaults to\n * `{ document, params }` derived from the result.\n */\n payloads?: BindingPayloads\n /** Full custom binding resolver — overrides `payloads` when provided. */\n resolveBinding?: ResolveBinding\n /**\n * Delivery-shaped assets the page may reference (EC-195, from the render\n * outcome). An `asset`-typed Image prop resolves through these to a url +\n * intrinsic dimensions; an unknown id degrades to the visible fallback.\n */\n assets?: readonly ResolvedAsset[]\n /**\n * Populated composition-node `relation` props, keyed `collection:id` (EC-254,\n * from the render outcome). A block's `relation` prop (e.g. a ProductGrid's\n * picked products) resolves through these to the populated target; an unknown\n * key degrades to the block's own empty state. Absent → relation props pass\n * through unresolved (raw ref), the same degradation as a missing asset list.\n */\n relations?: Record<string, RelationTarget>\n /**\n * Documents each `listing` block resolved to, keyed by serialized query (EC-255,\n * from the render outcome). A ProductGrid keyed to a picked `category` reads its\n * products through this; an unknown key (or absent map) degrades to the block's\n * own empty state — the same degradation as a missing relation.\n */\n listings?: Record<string, RelationTarget[]>\n /**\n * URL paths for the documents this page's rich-text props LINK to, keyed\n * `collection:id` (EC-291, from the render outcome). A self-typed internal link\n * (`attrs.ref = {type:'reference',…}`) resolves through this to a real `href`; an\n * unknown key (or absent map) degrades to the renderer's visible `unresolved-ref`\n * issue (EC-290), never a silent `#`.\n */\n links?: Record<string, string>\n}\n\n/** Build the renderer's relation resolver from the baked, populated targets (EC-254). */\nfunction relationResolver(relations: Record<string, RelationTarget>): ResolveRelation {\n return (ref) => relations[`${ref.collection}:${ref.id}`] ?? null\n}\n\n/** Build the renderer's link resolver from the baked, doc-keyed URL paths (EC-291). */\nfunction linkResolver(links: Record<string, string>): ResolveLink {\n return (ref) => links[`${ref.collection}:${ref.id}`] ?? null\n}\n\n/** Build the renderer's listing resolver from the baked, query-keyed documents (EC-255). */\nfunction listingResolver(listings: Record<string, RelationTarget[]>): ResolveListing {\n return (query) => listings[serializeListingQuery(query)] ?? null\n}\n\n/** Build the renderer's asset resolver from the baked delivery assets (EC-195). */\nfunction assetResolver(assets: readonly ResolvedAsset[]): (id: string) => RenderAsset | null {\n const byId = new Map(assets.map((asset) => [asset.id, asset]))\n return (id) => {\n const asset = byId.get(id)\n return asset\n ? {\n url: asset.url,\n width: asset.width,\n height: asset.height,\n alt: asset.alt,\n focalPoint: asset.focalPoint,\n // EC-420: carry the LQIP so a placed base.Image blurs up on delivery.\n lqip: asset.lqip,\n meta: asset.meta,\n }\n : null\n }\n}\n\n/** Visible fallback when the renderer is handed a non-`ok` resolution. */\nfunction UnresolvedPageFallback(props: { status: string }): ReactNode {\n return (\n <div data-ec-fallback=\"unresolved-page\" data-ec-status={props.status}>\n {`This URL did not resolve to a page (status: ${props.status}).`}\n </div>\n )\n}\n\n/** Visible fallback when an `ok` resolution carries no renderable document. */\nfunction MissingDocumentFallback(): ReactNode {\n return (\n <div data-ec-fallback=\"missing-document\">\n {`Route resolved but carried no page document to render.`}\n </div>\n )\n}\n\n/**\n * Server-side per-node decorator: unwrap the renderer's client error\n * boundary. React Server Components cannot render class components, and a\n * boundary cannot recover during server rendering anyway (the renderer\n * already converts resolution errors into visible fallbacks before this\n * point). The wrapped element keeps its key, so output is unchanged.\n */\nfunction stripServerErrorBoundary(_node: ComponentNode, rendered: ReactNode): ReactNode {\n if (isValidElement(rendered) && rendered.type === RenderErrorBoundary) {\n return (rendered.props as { children?: ReactNode }).children ?? null\n }\n return rendered\n}\n\n/** Default payloads: the route-bound document and the dynamic route params. */\nexport function defaultBindingPayloads(result: ResolvePageResult): BindingPayloads {\n return { document: result.document, params: result.dynamicParams }\n}\n\n/**\n * Render a resolved page server-side. Async so hosts can compose it like any\n * other RSC; resolution itself is synchronous (the content was prefetched by\n * the `ContentSource`).\n */\nexport async function CanvasRenderer(props: CanvasRendererProps): Promise<ReactNode> {\n const { result, components } = props\n\n if (result.status !== 'ok') {\n // The route helper answers redirect/notFound before rendering; direct\n // users of <CanvasRenderer /> still get a visible state, never a crash.\n return <UnresolvedPageFallback status={result.status} />\n }\n\n const resolveBinding =\n props.resolveBinding ?? createBindingResolver(props.payloads ?? defaultBindingPayloads(result))\n\n const ctx: RenderContext = {\n registry: components.registry,\n implementations: components.implementations,\n resolveBinding,\n resolveAsset: assetResolver(props.assets ?? []),\n // EC-254: wire relation population only when the host baked the populated\n // targets, so a host that did not opt in keeps the raw-ref passthrough.\n ...(props.relations ? { resolveRelation: relationResolver(props.relations) } : {}),\n // EC-255: wire the listing resolver only when the host baked the query results,\n // so a host that did not opt in keeps listing props empty (the block's own state).\n ...(props.listings ? { resolveListing: listingResolver(props.listings) } : {}),\n // EC-291: wire the rich-text link resolver only when the host baked the link map,\n // so a host that did not opt in degrades a reference link to the visible\n // `unresolved-ref` issue (EC-290) rather than a wrong href.\n ...(props.links ? { resolveLink: linkResolver(props.links) } : {}),\n decorateNode: stripServerErrorBoundary,\n }\n\n const document = result.document\n\n // EC-187/EC-287: a routed document delivers a composition field directly — a\n // `page`-collection document uses its `body` field; a content-collection\n // document routed for delivery uses its `content` composition field (e.g. a\n // post's `content`). There is no graph or layout indirection: shared chrome is\n // composed in the host's `app/layout.tsx`. A page renders its blocks directly;\n // with no document at all, a visible fallback.\n if (document) {\n const composition = compositionOf(document)\n return <>{renderComposition(composition, ctx)}</>\n }\n\n return <MissingDocumentFallback />\n}\n\n/**\n * Select the delivery composition from a resolved document (EC-187). The\n * composition field can be named anything the host's collection schema chooses:\n * the conventional `body` (a `page`) or `content` (a routed content collection\n * like a `post`), but ALSO a host-specific name such as Konditorei's\n * `pageBuilder` (migrated faithfully from Sanity, EC-263). So the field is chosen\n * by VALUE — a composition is a `ComponentNode` or an array of them — NEVER by\n * name: a `body ?? content` name heuristic both picks a post's rich-text `body`\n * string over its `content` composition AND misses a `pageBuilder` entirely,\n * rendering nothing.\n *\n * `body` then `content` keep priority (so a content document's unrelated rich-text\n * `body` never shadows the conventional `content` composition); any other\n * composition-valued field is the generalized fallback.\n */\nfunction compositionOf(document: Record<string, unknown>): unknown {\n const body = document['body']\n if (Array.isArray(body) || isComponentNodeValue(body)) return body\n const content = document['content']\n if (Array.isArray(content) || isComponentNodeValue(content)) return content\n // Generalized (EC-263): the first field whose value is a composition — a node or\n // a non-empty array of nodes. `body`/`content` already took priority above.\n for (const value of Object.values(document)) {\n if (isComponentNodeValue(value)) return value\n if (Array.isArray(value) && value.length > 0 && value.every(isComponentNodeValue)) return value\n }\n return undefined\n}\n\n/**\n * The routed document's composition as a `ComponentNode[]` (EC-205): the same\n * `body`-or-`content` selection the renderer uses, normalized to an array so a\n * delivery host can walk it (e.g. to page-scope baked assets). Non-node values\n * are dropped. `null`/no-document yields an empty array.\n */\nexport function compositionNodesOf(\n document: Record<string, unknown> | null | undefined,\n): ComponentNode[] {\n if (!document) return []\n const composition = compositionOf(document)\n const candidates = Array.isArray(composition) ? composition : [composition]\n return candidates.filter((node): node is ComponentNode => isComponentNodeValue(node))\n}\n\n/** Structural `ComponentNode` guard — a resolved field value is opaque at the type level. */\nfunction isComponentNodeValue(value: unknown): boolean {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { id?: unknown }).id === 'string' &&\n typeof (value as { componentId?: unknown }).componentId === 'string'\n )\n}\n","import type { Locale, LocaleConfig, RouteRecord } from '@elytracms/core/cms-core'\nimport { cacheTags } from '@elytracms/core/content'\nimport type { CacheTags, ContentClient, Perspective, ResolvedAsset } from '@elytracms/core/content'\n\n/**\n * The content seam of the embedded runtime (EC-144, vision AD-1/AD-4): the\n * catch-all route helper consumes this interface, so where the content comes\n * from is swappable. EC-144 ships the in-memory snapshot bridge\n * (`createContentSnapshot` over a `PersistenceAdapter`); EC-145/146 plug a\n * Convex-backed source into the exact same seam.\n *\n * Accessors are synchronous over a prefetched `ContentLookup` (vision AD-4);\n * any fetching happens when the source is loaded, before clients are minted.\n */\n/**\n * One data-source definition the published graph's bindings reference\n * (EC-166 delivery): the structural shape of an `@elytracms/core/data-binding`\n * `DataSource`, declared here so the embedded runtime stays free of\n * builder-side packages. Only `cms`-kind sources with the EC-166 per-scope id\n * prefixes (`cms.section.<nodeId>` / `cms.template.<pageId>`) participate in\n * automatic payload materialization; everything else is ignored.\n */\nexport interface CanvasDataSource {\n kind: string\n id: string\n label?: string\n /** Kind-specific config; cms query configs parse via `@elytracms/core/content`. */\n config?: unknown\n}\n\nexport interface ContentSource {\n /** The project's locale configuration (default + supported set, EC-018). */\n readonly locales: LocaleConfig\n /**\n * Mint a typed accessor client (EC-143) bound to a perspective. The locale\n * defaults to the project default; the route helper overrides it per\n * request from the URL's locale prefix.\n */\n client(init: { perspective: Perspective; locale?: Locale }): ContentClient\n /**\n * The route records the source's clients resolve against (EC-171, additive).\n * Lets enumerating consumers — the sitemap helper — walk the same route\n * table `resolvePage` uses, instead of keeping a second list. Optional so\n * existing custom sources stay valid; without it the sitemap helper needs\n * explicit routes.\n */\n readonly routes?: readonly RouteRecord[]\n /**\n * Data-source definitions the graph's bindings reference (EC-166 delivery,\n * additive). When present, the route helper materializes per-section list\n * sources automatically by replaying their stored where/sort/limit through\n * `listDocuments` — see `materializeSourcePayloads`. Optional so existing\n * custom sources stay valid; absent definitions degrade to unresolved\n * bindings (the renderer's visible fallbacks), never a crash.\n */\n readonly sources?: readonly CanvasDataSource[]\n /**\n * The project's delivery-shaped assets (EC-195, additive). Lets the route\n * helper bake the assets a page may reference into the (serializable) render\n * outcome, so the renderer can resolve an `asset`-typed Image prop to a usable\n * url + intrinsic dimensions — and a cached page keeps its images during a\n * backend outage. Optional so existing custom sources stay valid; without it,\n * asset-typed props fall back to their raw value (the renderer's visible\n * degradation), never a crash.\n */\n assets?(): readonly ResolvedAsset[]\n}\n\n/**\n * Merge accessor cache tags into one deterministic set (sorted, deduplicated)\n * — used by the route helper to combine the `resolvePage` tags with tags\n * added by the host's payload factory (e.g. a `listDocuments` call). The\n * merged set is what the EC-146 `onTags` hook receives.\n */\nexport function mergeCacheTags(first: CacheTags, ...rest: readonly CacheTags[]): CacheTags {\n const all = [first, ...rest]\n return cacheTags({\n docs: all.flatMap((t) => t.docs),\n collections: all.flatMap((t) => t.collections),\n routes: all.flatMap((t) => t.routes),\n assets: all.flatMap((t) => t.assets),\n locale: first.locale,\n })\n}\n","import {\n isSectionSourceId,\n listQueryOfCmsConfig,\n parseCmsSourceQueryConfig,\n} from '@elytracms/core/content'\nimport type { CacheTags, ContentClient, ResolvePageResult } from '@elytracms/core/content'\nimport type { ComponentNode } from '@elytracms/core/project-graph'\nimport { sourcePayloadError } from './payloads'\nimport type { BindingPayloads } from './payloads'\nimport type { CanvasDataSource } from './source'\n\n/**\n * Automatic payload materialization for EC-166 repeating sections — the\n * delivery half of the builder's collection-driven LAYOUTS (EC-187: layouts\n * are the only graph trees that can bind section sources now). A published\n * layout may carry bindings against per-scope CMS sources; the renderer needs\n * the source PAYLOADS:\n *\n * - **Repeating sections** (`cms.section.<nodeId>`): the stored source config\n * carries the closed AD-3 query. For every section source a referenced\n * layout tree actually binds, the stored where/sort/limit replays through\n * the request client's `listDocuments` — published perspective and ambient\n * locale come from the client itself. The list result's `CacheTags` (the\n * fetch-time doc tags of what was actually returned plus the coarse\n * collection tag — the EC-146 contract) are surfaced so the route helper\n * merges them into the request tag set.\n *\n * The `cms.template.<pageId>` \"current document\" source is RETIRED (EC-187):\n * there is no template page, and a routed page document's `body` uses static\n * props (v1). A collection detail route's document is read by the dev route\n * component directly via the route's `document` ref.\n *\n * Everything degrades visibly, never a crash:\n *\n * - a missing source definition, a non-cms kind, or a malformed config leaves\n * the payload absent, so the binding resolves to `undefined` and the\n * renderer shows its EC-015 fallback (an empty list renders the section's\n * empty state);\n * - a structured query error (the stored query was REJECTED at delivery, e.g.\n * a sort field no longer filterable in the live schema) stores an explicit\n * {@link sourcePayloadError} payload instead — the binding resolver throws\n * on it and the renderer shows its visible per-node render-error fallback,\n * not a silently empty section (EC-177 gap 3).\n */\n\n/** Collect every binding `sourceId` referenced in a node tree (props, conditions, slots). */\nexport function collectBindingSourceIds(\n node: ComponentNode,\n into: Set<string> = new Set(),\n): Set<string> {\n for (const value of Object.values(node.props ?? {})) {\n if (value.kind === 'binding') into.add(value.binding.sourceId)\n }\n if (node.condition) into.add(node.condition.source.sourceId)\n for (const children of Object.values(node.slots ?? {})) {\n for (const child of children) collectBindingSourceIds(child, into)\n }\n return into\n}\n\nexport interface MaterializeSourcePayloadsInput {\n /** Accessor client bound to this request's perspective + locale. */\n client: ContentClient\n result: ResolvePageResult\n /** Source definitions from the `ContentSource` (absent ones simply skip). */\n sources: readonly CanvasDataSource[]\n}\n\nexport interface MaterializedSourcePayloads {\n payloads: BindingPayloads\n /** `CacheTags` of every accessor call made here (one entry per section list). */\n tags: CacheTags[]\n}\n\n/**\n * Materialize the EC-166 source payloads for one resolved page. Pure over the\n * prefetched source — `listDocuments` is synchronous; tags are returned (not\n * applied) so the caller owns the merge.\n */\nexport function materializeSourcePayloads(\n input: MaterializeSourcePayloadsInput,\n): MaterializedSourcePayloads {\n const { client, result, sources } = input\n const payloads: BindingPayloads = {}\n const tags: CacheTags[] = []\n\n if (result.status !== 'ok') return { payloads, tags }\n\n // --- Repeating sections: replay each referenced section source -----------\n // EC-187/EC-287: page bodies use static props (v1, bindings parked) and there\n // is no project graph or layout tree, so no composition currently binds a\n // section source — `referenced` stays empty. The section-source plumbing is\n // kept dormant for when editor bindings return.\n const referenced = new Set<string>()\n\n const byId = new Map(sources.map((source) => [source.id, source]))\n for (const sourceId of [...referenced].sort()) {\n if (!isSectionSourceId(sourceId)) continue\n const definition = byId.get(sourceId)\n if (!definition || definition.kind !== 'cms') continue\n const config = parseCmsSourceQueryConfig(definition.config)\n // Single-document configs are not lists; leave the binding unresolved.\n if (!config || config.documentId !== undefined) continue\n\n const list = client.listDocuments(config.collectionId, listQueryOfCmsConfig(config))\n // Both arms carry at least the collection tag; the ok arm additionally\n // tags every document actually returned (fetch-time tagging, EC-146).\n tags.push(list.tags)\n if (list.ok) {\n payloads[sourceId] = list.documents\n } else {\n // A rejected stored query is a VISIBLE state: the explicit issue\n // payload makes the binding resolver throw, which the renderer turns\n // into its per-node render-error fallback — never a silent empty list.\n payloads[sourceId] = sourcePayloadError(\n sourceId,\n list.errors.map((error) => error.message),\n )\n }\n }\n\n return { payloads, tags }\n}\n","import { documentKey, mergeRouteRecords } from '@elytracms/core/cms-core'\nimport type {\n CmsDocument,\n CollectionDef,\n DocumentRef,\n Locale,\n LocaleConfig,\n RedirectRecord,\n RouteRecord,\n} from '@elytracms/core/cms-core'\nimport {\n createContentClient,\n createContentContext,\n isDocumentHistory,\n resolvedAsset,\n} from '@elytracms/core/content'\nimport type {\n ContentClient,\n ContentDocumentSource,\n ContentLookup,\n Perspective,\n ResolvedAsset,\n} from '@elytracms/core/content'\nimport type { AssetRecord, PersistenceAdapter } from '@elytracms/core/persistence'\nimport type { CanvasDataSource, ContentSource } from './source'\n\n/**\n * Bridge from a `PersistenceAdapter` to the synchronous `ContentLookup` the\n * accessors (EC-143) read through: prefetch the project's collections,\n * documents, assets, and graphs ONCE (async), then serve every accessor call\n * synchronously from memory. This is how `apps/example-site` reads the seeded\n * in-memory fixture project; a Convex-backed `ContentSource` (EC-145/146)\n * replaces this bridge without touching the route helper.\n *\n * The assembly half is exposed separately as {@link createStaticContentSource}\n * (EC-156): a host that already holds the prefetched data as plain values —\n * e.g. a delivery-snapshot payload fetched over Convex's public HTTP query\n * API — assembles the exact same `ContentSource` without faking an adapter.\n */\n\nconst DEFAULT_LOCALES: LocaleConfig = { default: 'en', locales: ['en'] }\n\nexport interface ContentSnapshotOptions {\n /** Route records served by `resolvePage` (EC-019). */\n routes?: readonly RouteRecord[]\n /** Redirect records served by `resolvePage` (EC-019/020). */\n redirects?: readonly RedirectRecord[]\n /** Locale configuration; defaults to English-only. */\n locales?: LocaleConfig\n /**\n * Data-source definitions the graph's bindings reference (EC-166): section\n * sources (`cms.section.<nodeId>`) carry their stored where/sort/limit, and\n * the route helper materializes their payloads automatically.\n */\n sources?: readonly CanvasDataSource[]\n}\n\nexport interface ContentSnapshot extends ContentSource {\n readonly projectId: string\n}\n\n/**\n * Plain prefetched data for {@link createStaticContentSource} (EC-156): the\n * same inputs `createContentSnapshot` reads from a `PersistenceAdapter`, as\n * already-loaded values. Everything content-bearing is optional — an absent\n * piece simply resolves to \"not visible\", with the runtime's explicit\n * fallbacks (never a crash).\n */\nexport interface StaticContentData {\n projectId: string\n /** Locale configuration; defaults to English-only. */\n locales?: LocaleConfig\n /** Route records served by `resolvePage` (EC-019). */\n routes?: readonly RouteRecord[]\n /** Redirect records served by `resolvePage` (EC-019/020). */\n redirects?: readonly RedirectRecord[]\n collections?: readonly CollectionDef[]\n /**\n * Stored document sources. Either a bare `CmsDocument` (gated by its own\n * `state`) or a `DocumentHistory` carrying the live draft + the pinned\n * published snapshot (EC-224). Perspective gating happens in the pure\n * accessors (`selectPerspective`, EC-142): a `published` client sees a\n * history's pinned snapshot (or nothing), and never a bare `draft` row.\n */\n documents?: readonly ContentDocumentSource[]\n assets?: readonly AssetRecord[]\n /**\n * Resolve a serve URL for assets without a stored `url`. Defaults to an\n * explicit unresolved-placeholder scheme (never a silent empty string).\n */\n assetUrl?: (asset: AssetRecord) => string\n /**\n * Data-source definitions section bindings reference (EC-166 delivery).\n * Absent definitions degrade to unresolved bindings, never a crash.\n */\n sources?: readonly CanvasDataSource[]\n}\n\n// `mergeRouteRecords` moved to `@elytracms/core/cms-core` (EC-384) so the studio's\n// document-URL preview can merge stored routes with the home fallback through the\n// exact same rule the delivery resolver below uses — re-exported here (imported\n// above) to keep this module's/`@elytracms/next`'s existing public surface.\nexport { mergeRouteRecords }\n\n/**\n * Assemble a `ContentSource` from plain prefetched data — the pure half of\n * {@link createContentSnapshot}, shared with hosts that fetched the data\n * themselves (e.g. the EC-156 live delivery snapshot). Accessor semantics are\n * byte-identical across both paths: the same `ContentLookup` feeds the same\n * pure `@elytracms/core/content` client.\n */\nexport function createStaticContentSource(data: StaticContentData): ContentSnapshot {\n const locales = data.locales ?? DEFAULT_LOCALES\n const routes = data.routes ?? []\n const redirects = data.redirects ?? []\n const assetUrl =\n data.assetUrl ?? ((asset: AssetRecord) => `asset://unresolved/${asset.storageKey}`)\n\n const collections = new Map<string, CollectionDef>()\n for (const collection of data.collections ?? []) collections.set(collection.id, collection)\n\n const documents = new Map<string, ContentDocumentSource>()\n const byCollection = new Map<string, ContentDocumentSource[]>()\n for (const source of data.documents ?? []) {\n const doc = isDocumentHistory(source) ? source.draft : source\n documents.set(documentKey(doc), source)\n const list = byCollection.get(doc.collection) ?? []\n list.push(source)\n byCollection.set(doc.collection, list)\n }\n\n const assets = new Map<string, AssetRecord>()\n for (const record of data.assets ?? []) assets.set(record.id, record)\n\n const lookupFor = (_perspective: Perspective): ContentLookup => ({\n collection: (id) => collections.get(id),\n document: (ref: DocumentRef) => documents.get(documentKey(ref)),\n documents: (collectionId) => byCollection.get(collectionId) ?? [],\n asset: (id) => assets.get(id),\n assetUrl: (asset) => asset.url ?? assetUrl(asset),\n })\n\n const client = (init: { perspective: Perspective; locale?: Locale }): ContentClient =>\n createContentClient({\n lookup: lookupFor(init.perspective),\n context: createContentContext({\n locale: init.locale ?? locales.default,\n perspective: init.perspective,\n locales,\n }),\n routes,\n redirects,\n })\n\n return {\n projectId: data.projectId,\n locales,\n client,\n routes,\n // EC-195: the delivery-shaped assets, so the renderer can resolve an\n // `asset`-typed Image prop (an asset id) to a usable url + intrinsic\n // dimensions. Baked into the (serializable) render outcome by the route\n // helper, so a cached page keeps its images during a backend outage.\n assets: () =>\n [...assets.values()].map((record) => resolvedAsset(record, record.url ?? assetUrl(record))),\n ...(data.sources ? { sources: data.sources } : {}),\n }\n}\n\n/**\n * Prefetch a project's content from a `PersistenceAdapter` into an in-memory\n * `ContentSource`. The snapshot is a point-in-time view: load once per\n * request (or memoize across requests for fixture-backed sites) — accessors\n * never reach back to the adapter.\n */\nexport async function createContentSnapshot(\n adapter: PersistenceAdapter,\n projectId: string,\n options: ContentSnapshotOptions = {},\n): Promise<ContentSnapshot> {\n // --- Prefetch (the only async part) ------------------------------------\n const schema = await adapter.cms.findSchema(projectId)\n const documentRecords = await adapter.cms.listDocuments(projectId)\n const versionRecords = await adapter.cms.listAllDocumentVersions(projectId)\n const assetRecords = await adapter.assets.listAssets(projectId)\n // Redirects are editorial DATA (EC-303): read the ENABLED ones from the adapter's\n // redirects rail (projected to the routing `RedirectRecord`), like documents/assets\n // — NOT from config. An explicit `options.redirects` still overrides (fixtures/tests).\n const redirectRecords = await adapter.redirects.listRedirects(projectId)\n const redirects: RedirectRecord[] = redirectRecords\n .filter((record) => record.enabled)\n .map((record) => ({\n id: record.id,\n from: record.from,\n to: record.to,\n permanent: record.permanent,\n }))\n\n // Hybrid sources (EC-224): a `publishedVersion` pointer yields a\n // `DocumentHistory` (draft = the live row, published = the pinned snapshot);\n // an unpinned record stays a bare `CmsDocument` gated by its `state`.\n // Backward-compatible — pre-pointer data resolves exactly as before.\n const versionsByKey = new Map<string, Map<number, CmsDocument>>()\n for (const record of versionRecords) {\n const key = `${record.collection}:${record.docId}`\n let byVersion = versionsByKey.get(key)\n if (!byVersion) {\n byVersion = new Map()\n versionsByKey.set(key, byVersion)\n }\n byVersion.set(record.version, record.snapshot)\n }\n const documents: ContentDocumentSource[] = documentRecords.map((record) => {\n if (record.publishedVersion === undefined) return record.document\n // A dangling pin under-serves to `null` for `published` — never the draft.\n const published = versionsByKey\n .get(`${record.document.collection}:${record.document.id}`)\n ?.get(record.publishedVersion)\n return { draft: record.document, published, versions: [] }\n })\n\n // --- Assemble via the shared pure path ----------------------------------\n // Captured once: `BlobStorageAdapter.url` is synchronous by contract.\n return createStaticContentSource({\n projectId,\n ...(options.locales ? { locales: options.locales } : {}),\n ...(options.routes ? { routes: options.routes } : {}),\n redirects: options.redirects ? [...options.redirects] : redirects,\n ...(options.sources ? { sources: options.sources } : {}),\n ...(schema ? { collections: schema.collections } : {}),\n documents,\n assets: assetRecords,\n assetUrl: (asset) => adapter.blobs.url(asset.storageKey),\n })\n}\n","import { splitPath } from '@elytracms/core/cms-core'\nimport type { Locale, LocaleConfig } from '@elytracms/core/cms-core'\nimport { cacheTags } from '@elytracms/core/content'\nimport type {\n CacheTags,\n ContentClient,\n Perspective,\n ResolvedAsset,\n ResolvePageResult,\n} from '@elytracms/core/content'\nimport type { ComponentNode } from '@elytracms/core/project-graph'\nimport type { ComponentRegistry } from '@elytracms/core/component-registry'\nimport {\n collectReferencedAssetIds,\n collectReferencedListings,\n collectReferencedRelations,\n collectReferencedRichTextLinks,\n} from '@elytracms/core/runtime-renderer'\nimport type { ListingQuery, RelationTarget, ResolveRelation } from '@elytracms/core/runtime-renderer'\nimport type { BindingPayloads } from './payloads'\nimport { mergeCacheTags } from './source'\nimport type { ContentSource } from './source'\nimport { materializeSourcePayloads } from './source-payloads'\nimport { compositionNodesOf, defaultBindingPayloads } from './canvas-renderer'\n\n/**\n * The pure half of the catch-all route helper (EC-144): URL → outcome, with\n * no Next.js imports — so redirects, 404s, locale handling, payload assembly,\n * and tag merging are all unit-testable as plain functions. `route.tsx` maps\n * each outcome onto `redirect()` / `permanentRedirect()` / `notFound()` /\n * `<CanvasRenderer />`.\n */\n\n/** What the host's payload factory sees for one request. */\nexport interface CanvasPayloadContext {\n /** Accessor client bound to this request's perspective + locale. */\n client: ContentClient\n result: ResolvePageResult\n perspective: Perspective\n /** The normalized request path (locale prefix stripped). */\n path: string\n params: Record<string, string>\n /**\n * Register the `CacheTags` of any extra accessor call this factory makes\n * (e.g. `listDocuments`) so they join the request's merged tag set — the\n * EC-146 invalidation hook sees everything the request actually read.\n */\n addTags(tags: CacheTags): void\n}\n\n/**\n * Builds the binding payloads for a page render. The defaults\n * (`document`, `params`) are always present; factory entries win on conflict.\n */\nexport type CanvasPayloadsFactory = (\n ctx: CanvasPayloadContext,\n) => BindingPayloads | Promise<BindingPayloads>\n\nexport type CanvasPageOutcome =\n | { kind: 'redirect'; target: string; permanent: boolean; tags: CacheTags }\n | { kind: 'not-found'; tags: CacheTags }\n | {\n kind: 'render'\n result: ResolvePageResult\n payloads: BindingPayloads\n /**\n * The delivery-shaped assets the page may reference (EC-195). Baked into\n * the outcome (serializable) so the renderer resolves `asset`-typed Image\n * props to a url + intrinsic dimensions, and a cached page keeps its\n * images during a backend outage.\n */\n assets: readonly ResolvedAsset[]\n /**\n * The composition-node `relation` props this page references, populated to\n * depth-1 delivery shape and keyed `collection:id` (EC-254). Baked into the\n * outcome (serializable) so `<CanvasRenderer />` rebuilds\n * `RenderContext.resolveRelation` from it inside the RSC — a function (the\n * content client) cannot ride the data cache or cross the RSC boundary, so\n * the data is baked exactly as the page-scoped `assets` list is.\n */\n relations: Record<string, RelationTarget>\n /**\n * The documents each `listing` block on this page resolved to (EC-255),\n * keyed by serialized query. Baked into the outcome (serializable) so\n * `<CanvasRenderer />` rebuilds `RenderContext.resolveListing` from it inside\n * the RSC — like `relations`, because the content client that runs the query\n * cannot ride the data cache or cross the RSC boundary. A listing depends on\n * collection MEMBERSHIP (a product joining/leaving the category), so its\n * invalidation rides the per-query `listDocuments` tags merged into `tags`.\n */\n listings: Record<string, RelationTarget[]>\n /**\n * The public URL path of every document a rich-text prop on this page LINKS\n * to (EC-291), keyed `collection:id`. Baked into the outcome (serializable) so\n * `<CanvasRenderer />` rebuilds `RenderContext.resolveLink` from it inside the\n * RSC — like `relations`, because the content client that derives the URL\n * (`resolveLink` → `urlForDocument`) cannot ride the data cache or cross the\n * RSC boundary. A link depends on the target's IDENTITY (its slug/parent →\n * path), so its invalidation rides the per-link doc tags merged into `tags`:\n * renaming, re-parenting, or first-publishing a linked document re-bakes the\n * embedding page's href.\n */\n links: Record<string, string>\n tags: CacheTags\n }\n\n/** Build the request path from a Next catch-all `slug` param. */\nexport function pathFromSlug(slug: readonly string[] | undefined): string {\n return '/' + (slug ?? []).join('/')\n}\n\n/**\n * Derive the request locale from a leading URL segment (`/de/about` → locale\n * `de`, path `/about`) and return the remaining path. No prefix (or the\n * default locale's own content at root) falls back to the default locale.\n */\nexport function splitLocalePath(\n url: string,\n locales: LocaleConfig,\n): { locale: Locale; path: string } {\n const segments = splitPath(url)\n const first = segments[0]\n if (first !== undefined && first !== locales.default && locales.locales.includes(first)) {\n return { locale: first, path: '/' + segments.slice(1).join('/') }\n }\n return { locale: locales.default, path: '/' + segments.join('/') }\n}\n\nexport interface ResolveCanvasPageOptions {\n payloads?: CanvasPayloadsFactory\n /**\n * Component registry (EC-205): when provided, the baked {@link CanvasPageOutcome}\n * `assets` are PAGE-SCOPED to exactly the asset ids this page's composition +\n * layout resolve through `resolveAsset` — not the whole project asset list,\n * which otherwise rides in every page's cache entry + RSC payload. Omitted →\n * all source assets (back-compat). Scoping mirrors the renderer's asset\n * resolution exactly, so no referenced image is ever dropped.\n */\n registry?: ComponentRegistry\n}\n\n/**\n * Page-scope the baked assets to those the page actually resolves (EC-205): the\n * static `asset`-typed props of its composition + selected layout tree. Document\n * asset FIELDS resolve into the document payload separately, and bound asset\n * props resolve through bindings — neither uses this list, so neither widens it.\n */\nfunction scopeAssetsToPage(\n allAssets: readonly ResolvedAsset[],\n registry: ComponentRegistry,\n result: ResolvePageResult,\n resolveRelation: ResolveRelation,\n): readonly ResolvedAsset[] {\n if (allAssets.length === 0) return allAssets\n const ids = new Set<string>()\n // EC-270: pass `resolveRelation` so the collector follows a Reusable block's\n // `element` pick into the referenced document and page-scopes the asset ids\n // inside its transcluded `content` — otherwise a transcluded image is baked\n // nowhere and renders empty on the host (the relation bake already transcludes).\n const seen = new Set<string>()\n for (const node of compositionNodesOf(result.document)) {\n collectReferencedAssetIds(node, registry, ids, resolveRelation, seen)\n }\n // EC-202: the OG image is an asset the page uses (for its `og:image` meta), so\n // it joins the page-scoped set — (EC-227) tagged for invalidation when that\n // asset record is edited. EC-266: a `type:'asset'` seoOgImage field is delivered\n // as a ResolvedAsset OBJECT ({ id, url }); a string is a raw id (or a passthrough\n // URL, which has no asset id to tag). Take the id from whichever shape.\n const ogImage = result.document?.['seoOgImage']\n const ogImageId =\n typeof ogImage === 'string'\n ? ogImage\n : ogImage && typeof ogImage === 'object' && typeof (ogImage as { id?: unknown }).id === 'string'\n ? (ogImage as { id: string }).id\n : null\n if (ogImageId) ids.add(ogImageId)\n return ids.size === 0 ? [] : allAssets.filter((asset) => ids.has(asset.id))\n}\n\n/** The page's composition nodes (EC-254 relation scan). EC-287: no layout root. */\nfunction pageCompositionNodes(result: ResolvePageResult): ComponentNode[] {\n return [...compositionNodesOf(result.document)]\n}\n\n/**\n * Populate every composition-node `relation` prop the page references to depth-1,\n * keyed `collection:id` (EC-254). Walks the page composition + layout (and, through\n * `collectReferencedRelations`, transcluded reusable content) and resolves each ref\n * through the request's client. Empty when no registry is supplied (the collector\n * needs manifests to know which props are relations) — relation props then pass\n * through raw, the graceful degradation a host without a registry already gets.\n *\n * `docKeys` carries the `collection:id` of every referenced pick (resolved or not),\n * so the caller cache-tags the page by them (EC-146): editing/publishing a picked\n * document — including a previously-unpublished one that should now appear — drops\n * exactly the pages that embed it. A fixed pick depends on the document's identity,\n * not on its collection's membership, so no coarse collection tag is added.\n */\nfunction populatePageRelations(\n result: ResolvePageResult,\n client: ContentClient,\n registry: ComponentRegistry | undefined,\n): { relations: Record<string, RelationTarget>; docKeys: string[] } {\n if (!registry) return { relations: {}, docKeys: [] }\n const refKeys = new Set<string>()\n const relations = collectReferencedRelations(\n pageCompositionNodes(result),\n registry,\n (ref) => client.resolveRelation(ref),\n {},\n refKeys,\n )\n return { relations, docKeys: [...refKeys] }\n}\n\n/**\n * Resolve every `listing` block on the page to its matching documents (EC-255),\n * keyed by serialized query for `<CanvasRenderer />` to rebuild `resolveListing`.\n * Runs each listing's query through the request's client (so perspective + locale\n * match the rest of the resolution — published-only on a live page, per AD-5), and\n * returns the per-query `listDocuments` `CacheTags` so the caller folds them into\n * the page's tag set: those carry both the COLLECTION tag (membership — a product\n * joining/leaving the category re-renders the grid) and the listed documents' own\n * tags (a member's content edit re-renders it). Empty when no registry is supplied\n * (the collector needs manifests to know which blocks declare a listing).\n */\nfunction populatePageListings(\n result: ResolvePageResult,\n client: ContentClient,\n registry: ComponentRegistry | undefined,\n): { listings: Record<string, RelationTarget[]>; tags: CacheTags[] } {\n if (!registry) return { listings: {}, tags: [] }\n const tags: CacheTags[] = []\n const listings = collectReferencedListings(\n pageCompositionNodes(result),\n registry,\n (query: ListingQuery) => {\n const listed = client.listDocuments(query.collection, {\n where: query.where,\n ...(query.sort ? { sort: query.sort } : {}),\n ...(query.limit !== undefined ? { limit: query.limit } : {}),\n })\n tags.push(listed.tags)\n return listed.ok ? (listed.documents as RelationTarget[]) : []\n },\n // EC-255: reach listings nested inside transcluded reusable content (the same\n // depth-1 populate the relation bake uses), so a grid inside a reusable bakes —\n // and its membership tag is folded in — instead of rendering empty on the host.\n (ref) => client.resolveRelation(ref),\n )\n return { listings, tags }\n}\n\n/**\n * Resolve every internal rich-text LINK on the page to its target document's URL\n * path (EC-291), keyed `collection:id` for `<CanvasRenderer />` to rebuild\n * `resolveLink`. Collects the referenced doc refs from the page's rich-text props\n * (transclusion-aware) and derives each URL through the request's client\n * (`resolveLink` → `urlForDocument`), so the path matches what the same routes serve.\n * A ref that resolves to no live URL (unpublished target / no addressing route) is\n * simply omitted — the renderer then shows the EC-290 `unresolved-ref` issue.\n *\n * `docKeys` carries EVERY referenced target (resolved or not), so the caller cache-\n * tags the page by them (EC-146): publishing or renaming a linked document — including\n * one not yet published when the page was baked — drops exactly the embedding pages.\n * Empty when no registry is supplied (the collector needs no manifest, but the bake\n * stays consistent with its relation/listing siblings, which do).\n */\nfunction populatePageLinks(\n result: ResolvePageResult,\n client: ContentClient,\n registry: ComponentRegistry | undefined,\n): { links: Record<string, string>; docKeys: string[] } {\n if (!registry) return { links: {}, docKeys: [] }\n const refs = collectReferencedRichTextLinks(\n pageCompositionNodes(result),\n registry,\n (ref) => client.resolveRelation(ref),\n )\n const links: Record<string, string> = {}\n for (const [key, ref] of Object.entries(refs)) {\n const url = client.resolveLink(ref)\n if (url !== null) links[key] = url\n }\n return { links, docKeys: Object.keys(refs) }\n}\n\n/**\n * Resolve one request URL against a content source: split the locale, run\n * `resolvePage` in the requested perspective, assemble binding payloads, and\n * merge every accessor's `CacheTags` into one deterministic set. Pure — all\n * data was prefetched by the source.\n */\nexport async function resolveCanvasPage(\n source: ContentSource,\n url: string,\n perspective: Perspective,\n options: ResolveCanvasPageOptions = {},\n): Promise<CanvasPageOutcome> {\n const { locale, path } = splitLocalePath(url, source.locales)\n const client = source.client({ perspective, locale })\n const result = client.resolvePage(path)\n\n if (result.status === 'redirect' && result.redirect) {\n return {\n kind: 'redirect',\n target: result.redirect.target,\n permanent: result.redirect.permanent,\n tags: result.tags,\n }\n }\n\n if (result.status !== 'ok') {\n return { kind: 'not-found', tags: result.tags }\n }\n\n const extraTags: CacheTags[] = []\n let payloads: BindingPayloads = defaultBindingPayloads(result)\n\n // EC-166 delivery: materialize template-page documents and replay each\n // referenced repeating-section query (stored where/sort/limit) through this\n // request's client — published perspective and ambient locale included.\n // Section list tags join the merged set (fetch-time doc tags + collection).\n const materialized = materializeSourcePayloads({\n client,\n result,\n sources: source.sources ?? [],\n })\n payloads = { ...payloads, ...materialized.payloads }\n extraTags.push(...materialized.tags)\n\n if (options.payloads) {\n const custom = await options.payloads({\n client,\n result,\n perspective,\n path,\n params: result.dynamicParams,\n addTags: (tags) => extraTags.push(tags),\n })\n payloads = { ...payloads, ...custom }\n }\n\n const allAssets = source.assets?.() ?? []\n // EC-205: page-scope the baked assets when a registry is supplied (the route\n // helper passes it); else keep the full list (back-compat).\n const bakedAssets = options.registry\n ? scopeAssetsToPage(allAssets, options.registry, result, (ref) =>\n client.resolveRelation(ref),\n )\n : allAssets\n // EC-227: tag the cache entry with every asset it baked, so editing an asset\n // record (alt/dimensions/re-upload) drops exactly the pages carrying it. The\n // locale is irrelevant for asset tags (an asset record is locale-agnostic) —\n // `cacheTags` just needs one; `result.tags.locale` is the page's.\n const assetTags = cacheTags({\n assets: bakedAssets.map((asset) => asset.id),\n locale: result.tags.locale,\n })\n // EC-254: populate the relation props of the nodes inside the page's blocks\n // (e.g. a ProductGrid's picked products), keyed for `<CanvasRenderer />` to\n // rebuild `resolveRelation`. Reuses the request's client, so perspective +\n // locale match the rest of the resolution.\n const { relations, docKeys: relationDocKeys } = populatePageRelations(\n result,\n client,\n options.registry,\n )\n // EC-146: tag the page by every picked document so editing/publishing one drops\n // the embedding page (the locale is the page's; doc tags are locale-agnostic).\n const relationTags = cacheTags({ docs: relationDocKeys, locale: result.tags.locale })\n // EC-255: resolve every listing block's query (e.g. a ProductGrid keyed to a\n // category) and bake the result keyed by serialized query. The per-query\n // `listDocuments` tags (collection membership + listed docs) join the merged set,\n // so adding/removing a member or editing one invalidates the embedding page.\n const { listings, tags: listingTags } = populatePageListings(\n result,\n client,\n options.registry,\n )\n // EC-291: resolve every internal rich-text link to its target's URL path and bake\n // it for `<CanvasRenderer />` to rebuild `resolveLink`. Tag the page by each linked\n // document so renaming/re-parenting/first-publishing a target re-bakes the href.\n const { links, docKeys: linkDocKeys } = populatePageLinks(result, client, options.registry)\n const linkTags = cacheTags({ docs: linkDocKeys, locale: result.tags.locale })\n return {\n kind: 'render',\n result,\n payloads,\n assets: bakedAssets,\n relations,\n listings,\n links,\n tags: mergeCacheTags(\n result.tags,\n ...extraTags,\n ...listingTags,\n assetTags,\n relationTags,\n linkTags,\n ),\n }\n}\n","import type { CacheTags } from '@elytracms/core/content'\n\n/**\n * Cache-tag pipeline (EC-146, vision AD-5) — the pure half.\n *\n * This module defines (a) the **canonical Next.js tag string format** mapping\n * the accessor-level `CacheTags` (EC-143) onto `revalidateTag` keys, and (b)\n * the **tag-discovery caching logic** the catch-all route helper runs inside\n * `unstable_cache`. No Next.js imports — everything here is unit-testable;\n * `route.tsx` injects the real `unstable_cache` via {@link CacheWrapper}.\n *\n * ## Tag format\n *\n * - `doc:<collection>:<id>` — one per document whose content was actually in\n * the response (fetch-time tagging: includes depth-1 populated relation\n * targets, and documents inside filtered/dynamic lists *after* the filter\n * ran).\n * - `collection:<name>:<locale>` — the coarse membership tag: every response\n * that read from a collection carries it, so create/delete/newly-matching\n * documents sweep cached lists without read-set tracking.\n * - `route:<pattern>:<locale>` — the resolved URL path plus every hop of a\n * redirect chain.\n * - `asset:<id>` — one per asset whose delivery shape the page *baked*\n * (page-scoped images + `seoOgImage`, EC-227); editing that asset record\n * (alt/dimensions/re-upload) drops exactly the pages that baked it. Not\n * locale-scoped — an asset record is locale-agnostic.\n * - `project` — the whole-project sweep tag attached to **every** cached\n * entry; graph publish/unpublish emits it (a layout or route change can\n * affect any page, so the honest v1 fallback is a full project sweep).\n *\n * ## Project scope\n *\n * Every tag is prefixed `p:<projectId>:` when a scope is configured (e.g.\n * `p:prj_aurora:doc:post:post-1`). The cost is a few bytes per tag and it\n * keeps multi-project hosts (one Next app serving several builder projects)\n * from cross-invalidating, so the prefix is **on whenever the host knows its\n * project id** — decision: include it. The emitter (the studio's webhook\n * dispatcher, `apps/builder/src/lib/webhooks`) always scopes with the\n * operation's `projectId`; a host that omits `cache.scope` therefore will not\n * match studio-emitted tags. Configure `cache.scope` with the same project id\n * the studio publishes under.\n *\n * The studio-side emitter cannot depend on this package (it would drag the\n * `next` peer dependency into the builder), so\n * `apps/builder/src/lib/webhooks/tags.ts` mirrors these formatters; tests on\n * both sides pin the exact literal strings to keep them in lock-step.\n */\n\n/** Apply the optional multi-project scope prefix to one tag. */\nexport function scopeCacheTag(tag: string, scope?: string): string {\n return scope === undefined || scope.length === 0 ? tag : `p:${scope}:${tag}`\n}\n\n/**\n * Tag for one document identity. `docKey` is the EC-143 `documentKey` string\n * (`<collection>:<id>`), exactly as found in `CacheTags.docs`.\n */\nexport function docCacheTag(docKey: string, scope?: string): string {\n return scopeCacheTag(`doc:${docKey}`, scope)\n}\n\n/** The coarse membership tag of one collection in one locale. */\nexport function collectionCacheTag(collection: string, locale: string, scope?: string): string {\n return scopeCacheTag(`collection:${collection}:${locale}`, scope)\n}\n\n/** Tag for one resolved route path (or redirect-chain hop) in one locale. */\nexport function routeCacheTag(pattern: string, locale: string, scope?: string): string {\n return scopeCacheTag(`route:${pattern}:${locale}`, scope)\n}\n\n/**\n * Tag for one baked asset (EC-227). `assetId` is the bare asset id, as found in\n * `CacheTags.assets`. Not locale-scoped: an asset record is one row shared\n * across locales, so an edit invalidates the baking pages in every locale.\n */\nexport function assetCacheTag(assetId: string, scope?: string): string {\n return scopeCacheTag(`asset:${assetId}`, scope)\n}\n\n/**\n * The whole-project sweep tag. Attached to every cached page entry; emitted\n * on graph publish/unpublish (and as the emitter's honest fallback when a\n * change's precise tag set is unknowable).\n */\nexport function projectSweepTag(scope?: string): string {\n return scopeCacheTag('project', scope)\n}\n\n/**\n * Map an accessor-level `CacheTags` (what one request actually read) onto the\n * full, deterministic (sorted, deduplicated) set of Next tag strings for the\n * cache entry — including the project sweep tag.\n */\nexport function nextCacheTags(tags: CacheTags, scope?: string): string[] {\n const all = new Set<string>()\n all.add(projectSweepTag(scope))\n for (const docKey of tags.docs) all.add(docCacheTag(docKey, scope))\n for (const collection of tags.collections) {\n all.add(collectionCacheTag(collection, tags.locale, scope))\n }\n for (const route of tags.routes) all.add(routeCacheTag(route, tags.locale, scope))\n for (const assetId of tags.assets) all.add(assetCacheTag(assetId, scope))\n return [...all].sort()\n}\n\n// --- Tag-discovery caching over `unstable_cache` ------------------------------\n\n/**\n * The slice of `unstable_cache` the discovery logic needs, injectable so the\n * logic is testable against a faithful in-memory model (and so the test model\n * can mirror the real semantics this design depends on — see below).\n */\nexport interface CacheWrapperOptions {\n tags: string[]\n /** `false` = never expire by time (tag-driven invalidation only). */\n revalidate: number | false\n}\n\nexport type CacheWrapper = <T>(\n cb: () => Promise<T>,\n keyParts: string[],\n options: CacheWrapperOptions,\n) => () => Promise<T>\n\n/** What one cached request stores: the outcome plus its own discovered tags. */\nexport interface CachedEntry<T> {\n value: T\n /** The Next tag strings discovered at fetch time by the run that wrote this entry. */\n tags: string[]\n}\n\n/**\n * Internal sentinel: thrown by the probe callback after a cache **miss** ran\n * the loader, so `unstable_cache` never persists the entry under the\n * incomplete baseline tag set (a thrown callback caches nothing).\n */\nclass CacheDiscoveryBail extends Error {\n constructor() {\n super('elytra cache discovery bail (never user-visible)')\n this.name = 'CacheDiscoveryBail'\n }\n}\n\n/**\n * Both the probe and the write wrapper get their callback from this single\n * factory, so the two callbacks have **identical source text**. This matters:\n * `unstable_cache` derives its cache key from `cb.toString()` + `keyParts`,\n * so identical source is what makes the write pass store the entry under the\n * exact key future probe passes read.\n */\nfunction passthrough<T>(impl: () => Promise<T>): () => Promise<T> {\n return async () => impl()\n}\n\n/**\n * Fetch-time tag discovery over `unstable_cache` — the heart of EC-146.\n *\n * The problem: `unstable_cache` fixes an entry's tags when the *wrapper* is\n * created (`options.tags` is validated and **copied** at construction time in\n * Next 15 — mutating the array during the callback does not propagate), but\n * the correct tags are only known *after* the loader resolved the page. So a\n * single wrapper can never both (a) run the loader and (b) store the result\n * under the tags that run discovered.\n *\n * The design (\"resolve once, cache with discovered tags, serve cached\n * thereafter\") uses two wrapper constructions per request around **one**\n * cache entry:\n *\n * 1. **Probe pass** — a wrapper keyed by `keyParts` whose callback runs the\n * loader, captures the result + its discovered tags into the closure, and\n * then throws an internal sentinel.\n * - Cache **hit**: the stored entry (written by a previous request with\n * its full discovered tags) is returned; the callback — and therefore\n * the loader and any backend access — never runs. This is the outage\n * story: fully cached routes keep serving when the backend is down.\n * - Cache **miss**: the loader runs exactly once; the sentinel throw\n * prevents `unstable_cache` from persisting the entry under the\n * incomplete baseline tags (thrown callbacks cache nothing).\n * 2. **Write pass** (miss only) — a second wrapper is constructed *now that\n * the tags are known*, with `options.tags` = the discovered set, same key.\n * Its callback just returns the already-loaded entry, so the backend is\n * not hit again; `unstable_cache` persists the entry under the full\n * fetch-time tag set. `revalidateTag` on any of those tags drops the\n * entry and the next request repeats the cycle with fresh data.\n *\n * The loader runs **once per revalidation cycle** (per key), never once per\n * request. Time-based revalidation is intentionally not exposed: a\n * stale-while-revalidate background refresh would re-run the probe callback\n * (whose bail aborts the refresh), so this design is tag-driven only —\n * `revalidate: false` — which is exactly the AD-5 model.\n *\n * Concurrency: wrappers and the captured closure are per-request, so there is\n * no cross-request mutation; two racing first requests both resolve and the\n * last write wins (deterministic content ⇒ identical entries).\n */\nexport async function loadCachedEntry<T>(\n cache: CacheWrapper,\n keyParts: string[],\n baselineTags: readonly string[],\n load: () => Promise<CachedEntry<T>>,\n): Promise<CachedEntry<T>> {\n let fresh: CachedEntry<T> | undefined\n\n const probe = cache(\n passthrough(async (): Promise<CachedEntry<T>> => {\n fresh = await load()\n throw new CacheDiscoveryBail()\n }),\n keyParts,\n { tags: [...baselineTags], revalidate: false },\n )\n\n try {\n return await probe()\n } catch (error) {\n // Loader failures (backend down on a cold cache) propagate to the caller\n // — explicit, never silently cached. Only our own sentinel is absorbed.\n if (!(error instanceof CacheDiscoveryBail)) throw error\n }\n\n // Miss path: `fresh` was assigned before the sentinel was thrown.\n const entry = fresh as CachedEntry<T>\n const write = cache(\n passthrough(async () => entry),\n keyParts,\n { tags: entry.tags, revalidate: false },\n )\n return write()\n}\n","import type { Metadata } from 'next'\nimport type { ResolvedAsset, ResolvePageResult } from '@elytracms/core/content'\n\n/**\n * Resolved page → Next.js `Metadata` (EC-171, reshaped by EC-187). SEO now\n * lives on the resolved **document**: a `page`-collection document carries flat\n * `seo*` fields (`seoTitle`, `seoDescription`, `seoOgTitle`, `seoOgImage`,\n * `seoNoindex`); a content-collection document falls back to its `title`. There\n * is no separate page-graph `seo` block anymore.\n *\n * ```ts\n * // app/[[...slug]]/page.tsx — generateMetadata already applies this helper:\n * export const generateMetadata = route.generateMetadata\n * ```\n *\n * Mapping (in fallback order):\n * - `title`: `seoTitle` → document `name`/`title`.\n * - `description`: `seoDescription`.\n * - `openGraph`: OG title (`seoOgTitle` → effective title), description, and the\n * OG image URL (`seoOgImage`).\n * - `robots`: `seoNoindex` → `{ index: false }`.\n * - `alternates.canonical`: `seoCanonical` (EC-228) — an absolute or\n * root-relative URL, passed through verbatim. Real Sanity sites declare one per\n * page; omitted when unset so Next applies its own default.\n *\n * `hreflang` language alternates are intentionally NOT derived here: correct\n * hreflang needs a per-page translation map (which locale variants actually\n * exist), and auto-deriving from configured locales would emit alternates for\n * translations that don't exist — an SEO anti-pattern. Tracked as a follow-up.\n *\n * `seoOgImage` resolution (EC-202): the field holds either an absolute URL or\n * an **asset id**. An asset id is resolved to its delivery URL against the\n * page's baked `assets` (the same page-scoped set the renderer gets, widened to\n * include the OG asset in `route-core`). An asset id that can't be resolved is\n * **dropped** rather than emitted — an `<meta property=\"og:image\">` must carry a\n * real URL, never leak an internal id.\n *\n * Pure data-in/data-out — safe inside `generateMetadata` on both the cached\n * and uncached paths.\n */\nfunction str(value: unknown): string | null {\n return typeof value === 'string' && value.length > 0 ? value : null\n}\n\n/** An already-resolvable image URL (absolute or root-relative), not an asset id. */\nfunction looksLikeUrl(value: string): boolean {\n return /^(https?:)?\\/\\//.test(value) || value.startsWith('/')\n}\n\n/**\n * Resolve a `seoOgImage` field value to a URL: a delivery-resolved asset OBJECT →\n * its `url` (EC-266); a URL string → passed through; a raw asset-id string →\n * resolved against the baked assets; anything unresolvable → dropped (EC-202).\n */\nfunction resolveOgImage(value: unknown, assets: readonly ResolvedAsset[]): string | null {\n // EC-266: a `seoOgImage` modelled as a `type:'asset'` FIELD (e.g. Konditorei,\n // migrated from Sanity) is resolved by delivery to a ResolvedAsset OBJECT\n // ({ id, url, … }), NOT a string — so read its `url`. A string value is the\n // legacy shape: a passthrough URL, or a raw asset id resolved against the baked\n // assets. A `str()`-only path turned the object into null, dropping og:image.\n if (value && typeof value === 'object') {\n const url = (value as { url?: unknown }).url\n return typeof url === 'string' && url.length > 0 ? url : null\n }\n if (typeof value !== 'string' || value.length === 0) return null\n if (looksLikeUrl(value)) return value\n return assets.find((asset) => asset.id === value)?.url ?? null\n}\n\nexport function canvasPageMetadata(\n result: ResolvePageResult,\n assets: readonly ResolvedAsset[] = [],\n): Metadata {\n const doc = result.document\n\n const seoTitle = str(doc?.['seoTitle'])\n const seoDescription = str(doc?.['seoDescription'])\n const seoOgTitle = str(doc?.['seoOgTitle'])\n const seoOgImage = resolveOgImage(doc?.['seoOgImage'], assets)\n const seoNoindex = doc?.['seoNoindex'] === true\n const seoCanonical = str(doc?.['seoCanonical'])\n\n // Fallback title: the page document's `name`, or a content document's `title`.\n const docTitle = str(doc?.['name']) ?? str(doc?.['title'])\n const title = seoTitle ?? docTitle\n\n const metadata: Metadata = {}\n if (title !== null) metadata.title = title\n if (seoDescription) metadata.description = seoDescription\n\n const ogTitle = seoOgTitle ?? title\n if (ogTitle !== null || seoDescription || seoOgImage) {\n metadata.openGraph = {\n ...(ogTitle !== null ? { title: ogTitle } : {}),\n ...(seoDescription ? { description: seoDescription } : {}),\n ...(seoOgImage ? { images: [{ url: seoOgImage }] } : {}),\n }\n }\n\n if (seoNoindex) metadata.robots = { index: false }\n\n // EC-228: a page-declared canonical URL. Passed through verbatim (absolute or\n // root-relative); Next resolves it against `metadataBase` when relative.\n if (seoCanonical) metadata.alternates = { canonical: seoCanonical }\n\n return metadata\n}\n","import type { Metadata } from 'next'\nimport { unstable_cache } from 'next/cache'\nimport { draftMode } from 'next/headers'\nimport { notFound, permanentRedirect, redirect } from 'next/navigation'\nimport type { ReactNode } from 'react'\nimport type { CacheTags, Perspective, ResolvedAsset, ResolvePageResult } from '@elytracms/core/content'\nimport { loadCachedEntry, nextCacheTags, projectSweepTag } from './cache'\nimport type { CacheWrapper } from './cache'\nimport { CanvasRenderer } from './canvas-renderer'\nimport { canvasPageMetadata } from './metadata'\nimport type { HostComponents } from './components'\nimport { pathFromSlug, resolveCanvasPage } from './route-core'\nimport type { CanvasPageOutcome, CanvasPayloadsFactory } from './route-core'\nimport type { ContentSource } from './source'\n\n/**\n * Catch-all route helper (EC-144): the factory a host app calls once in\n * `app/[[...slug]]/page.tsx` to wire `resolvePage` → `<CanvasRenderer />`,\n * with redirects answered by Next's `redirect()`/`permanentRedirect()` (per\n * the route's `permanent` flag), unknown URLs answered by `notFound()` (the\n * host's 404 renders), and the perspective chosen by Next `draftMode()` —\n * draft when enabled (via the token-gated preview route), published\n * otherwise.\n *\n * With `cache` configured (EC-146), the published-perspective resolve+render\n * data work runs inside `unstable_cache`, keyed by URL and tagged with the\n * fetch-time tag set of what the response actually contained (see\n * `cache.ts`). Publishing in the studio then invalidates exactly the affected\n * entries via the signed `/api/revalidate` webhook — and while the content\n * backend is unreachable, cached entries keep serving because a cache hit\n * never invokes `loadContent`.\n */\n\nexport interface CanvasRequestInfo {\n /** The raw request path (including any locale prefix). */\n url: string\n perspective: Perspective\n}\n\nexport interface CanvasCacheOptions {\n /**\n * Project scope prefix for every tag (`p:<scope>:…`) — must be the project\n * id the studio publishes under, so the webhook dispatcher's tags match.\n * Omit only when the emitter also emits unscoped tags (see `cache.ts`).\n */\n scope?: string\n}\n\n/**\n * What the route helper tells the content loader about the request it is\n * loading for (EC-156). Loaders that serve both perspectives from one\n * prefetched source (the fixture snapshot) can ignore it; a live loader uses\n * it to fetch the draft-perspective snapshot only for draft-mode requests —\n * it must NOT call request APIs like `draftMode()` itself, because on the\n * cached published path the loader runs inside `unstable_cache`, where\n * dynamic request APIs are unavailable.\n */\nexport interface CanvasContentRequest {\n perspective: Perspective\n}\n\nexport interface CanvasRouteOptions {\n /**\n * Async content loader — the seam EC-145/146 plug Convex into. For the\n * fixture-backed example this memoizes a `createContentSnapshot` call.\n * Invoked per request; cache/memoize inside the loader as appropriate.\n * With `cache` configured it only runs on a cache miss (once per\n * revalidation cycle) — cache hits never touch the content backend.\n * Receives the request's perspective (see {@link CanvasContentRequest});\n * zero-arg loaders remain valid.\n */\n loadContent: (request: CanvasContentRequest) => Promise<ContentSource>\n /** Host component surface from `defineHostComponents`. */\n components: HostComponents\n /** Extra binding payloads per request (e.g. `listDocuments` for a list page). */\n payloads?: CanvasPayloadsFactory\n /**\n * EC-146 instant publish: cache the published-perspective resolution in\n * Next's data cache (`unstable_cache`), tagged with the response's own\n * fetch-time tags, invalidated by the `/api/revalidate` webhook. Draft mode\n * always bypasses this cache entirely. Tag-driven only — no time-based\n * revalidation (the AD-5 model). Cached values are JSON-serialized, so\n * payload factories must return plain data on the cached path.\n */\n cache?: CanvasCacheOptions\n /**\n * EC-146 hook: receives the merged `CacheTags` of everything this request\n * read (the `resolvePage` tags plus any tags the payload factory\n * registered via `addTags`). On a cache hit these are the stored tags of\n * the run that wrote the entry.\n */\n onTags?: (tags: CacheTags, info: CanvasRequestInfo) => void\n /** Override the generated `<head>` metadata for a resolved page. */\n metadata?: (result: ResolvePageResult, info: CanvasRequestInfo) => Metadata\n}\n\nexport interface CanvasRouteProps {\n params: Promise<{ slug?: string[] }>\n}\n\nexport interface CanvasRoute {\n /** The page component: `export default route.Page`. */\n Page: (props: CanvasRouteProps) => Promise<ReactNode>\n /** Next metadata hook: `export const generateMetadata = route.generateMetadata`. */\n generateMetadata: (props: CanvasRouteProps) => Promise<Metadata>\n}\n\n/**\n * Default metadata (EC-171): the page's canonical SEO fields — title,\n * description, OG tags, robots noindex — with document-title / page-name\n * fallbacks. `export const generateMetadata = route.generateMetadata` is the\n * one line a host needs; a custom `metadata` option overrides this entirely.\n */\nfunction defaultMetadata(result: ResolvePageResult, assets: readonly ResolvedAsset[]): Metadata {\n return canvasPageMetadata(result, assets)\n}\n\nasync function requestPerspective(): Promise<Perspective> {\n const { isEnabled } = await draftMode()\n return isEnabled ? 'draft' : 'published'\n}\n\n/** `unstable_cache` narrowed to the injectable seam the pure logic consumes. */\nconst nextCacheWrapper: CacheWrapper = (cb, keyParts, options) =>\n unstable_cache(cb, keyParts, { tags: options.tags, revalidate: options.revalidate })\n\n/** Create the `{ Page, generateMetadata }` pair for `app/[[...slug]]/page.tsx`. */\nexport function createCanvasRoute(options: CanvasRouteOptions): CanvasRoute {\n /**\n * Resolve one request, optionally through the tagged data cache. Shared by\n * `Page` and `generateMetadata` from a single call site, so both read (and\n * on a miss, write) the same cache entry.\n */\n const loadOutcome = async (url: string, perspective: Perspective): Promise<CanvasPageOutcome> => {\n const resolveFresh = async (): Promise<CanvasPageOutcome> => {\n const source = await options.loadContent({ perspective })\n return resolveCanvasPage(source, url, perspective, {\n ...(options.payloads ? { payloads: options.payloads } : {}),\n // EC-205: page-scope the baked assets to what the page actually uses.\n registry: options.components.registry,\n })\n }\n\n // Draft mode BYPASSES the cache entirely: draft content is per-editor,\n // changes on every keystroke, and must never be persisted into (or served\n // from) the shared published-data cache.\n //\n // `next dev` ALSO bypasses it: the tag-based instant-publish webhook (the\n // only cache invalidation, AD-5) can't reach a localhost host, so a\n // published change would stay stale until the dev server restarts (which\n // clears `.next`). Scoped to `development` so tests (`NODE_ENV=test`) and\n // production (`next build`/`start`) keep the tag-driven cache unchanged.\n const devBypass = process.env.NODE_ENV === 'development'\n if (!options.cache || perspective !== 'published' || devBypass) return resolveFresh()\n\n const scope = options.cache.scope\n const entry = await loadCachedEntry(\n nextCacheWrapper,\n ['elytra-route', scope ?? '', url],\n [projectSweepTag(scope)],\n async () => {\n const outcome = await resolveFresh()\n return { value: outcome, tags: nextCacheTags(outcome.tags, scope) }\n },\n )\n return entry.value\n }\n\n const Page = async (props: CanvasRouteProps): Promise<ReactNode> => {\n const { slug } = await props.params\n const url = pathFromSlug(slug)\n const perspective = await requestPerspective()\n\n const outcome = await loadOutcome(url, perspective)\n options.onTags?.(outcome.tags, { url, perspective })\n\n switch (outcome.kind) {\n case 'redirect':\n // 301 vs 302 per the redirect record's `permanent` flag (EC-019/020).\n return outcome.permanent ? permanentRedirect(outcome.target) : redirect(outcome.target)\n case 'not-found':\n return notFound()\n case 'render':\n return (\n <CanvasRenderer\n result={outcome.result}\n components={options.components}\n payloads={outcome.payloads}\n assets={outcome.assets}\n relations={outcome.relations}\n listings={outcome.listings}\n links={outcome.links}\n />\n )\n }\n }\n\n const generateMetadata = async (props: CanvasRouteProps): Promise<Metadata> => {\n const { slug } = await props.params\n const url = pathFromSlug(slug)\n const perspective = await requestPerspective()\n\n // Cached path: shares `Page`'s entry (same call site/key), so metadata is\n // a cache read, not a second resolution. Uncached path: resolve without\n // the payload factory — metadata only needs the resolution itself, and\n // side effects (addTags/onTags) must fire exactly once per request, in Page.\n if (options.cache && perspective === 'published') {\n const outcome = await loadOutcome(url, perspective)\n if (outcome.kind !== 'render') return {}\n return options.metadata\n ? options.metadata(outcome.result, { url, perspective })\n : defaultMetadata(outcome.result, outcome.assets)\n }\n\n const source = await options.loadContent({ perspective })\n const outcome = await resolveCanvasPage(source, url, perspective)\n if (outcome.kind !== 'render') return {}\n return options.metadata\n ? options.metadata(outcome.result, { url, perspective })\n : defaultMetadata(outcome.result, outcome.assets)\n }\n\n return { Page, generateMetadata }\n}\n","import type { MetadataRoute } from 'next'\nimport { composePath, hierarchyMount, splitPath } from '@elytracms/core/cms-core'\nimport type { CmsDocument, Locale, RouteRecord } from '@elytracms/core/cms-core'\nimport type { ContentClient } from '@elytracms/core/content'\nimport type { ContentSource } from './source'\n\n/**\n * `sitemap.xml` from published routes (EC-171): walk the same route records\n * `resolvePage` resolves against, resolve every candidate URL in the\n * **published** perspective, and emit `MetadataRoute.Sitemap` entries per\n * locale — Next's `app/sitemap.ts` convention. Pages marked `noindex` (and\n * URLs that do not resolve, e.g. a page that was never published) are\n * omitted.\n *\n * Dynamic routes (`/blog/:slug`): a route record does not declare which\n * collection feeds its params, so enumeration is delegated to the host's\n * {@link SitemapParamsProvider} — it gets a published-perspective accessor\n * client and returns one param record per concrete URL (typically from\n * `listDocuments`). **Honest limit:** parameterized routes without a provider\n * (or provider entries missing a param) are skipped and reported in\n * `skipped`, never guessed. `lastModified` is omitted — the delivery shape\n * carries no per-page timestamps today.\n *\n * Hierarchy mounts (`/:path*`, EC-218): a page-tree mount self-describes its\n * URLs, so it is enumerated automatically from the collection's published\n * documents (composing each page's nested path from its parent chain) — no\n * params provider entry needed.\n *\n * Host usage (`app/sitemap.ts`):\n *\n * ```ts\n * import { createCanvasSitemap } from '@elytracms/next'\n * import { loadContent } from '../lib/content'\n *\n * export default createCanvasSitemap({\n * loadContent,\n * baseUrl: 'https://example.com',\n * params: ({ route, client }) =>\n * route.id === 'r-post'\n * ? (client.listDocuments('post').ok ? … : []) // slug per published post\n * : null,\n * })\n * ```\n */\n\nexport interface SitemapRouteContext {\n route: RouteRecord\n locale: Locale\n /** Published-perspective accessor client bound to `locale`. */\n client: ContentClient\n}\n\n/**\n * Enumerate the param sets of one dynamic route — one record per concrete\n * URL (e.g. `[{ slug: 'hello-world' }, …]`). Return `null`/`undefined` to\n * skip the route (reported in `skipped`).\n */\nexport type SitemapParamsProvider = (\n ctx: SitemapRouteContext,\n) => readonly Record<string, string>[] | null | undefined\n\nexport interface CanvasSitemapOptions {\n /** Absolute site origin, e.g. `https://example.com` (no trailing slash needed). */\n baseUrl: string\n /** Route records to enumerate; defaults to the source's own route table. */\n routes?: readonly RouteRecord[]\n /** Param enumeration for dynamic routes (see {@link SitemapParamsProvider}). */\n params?: SitemapParamsProvider\n}\n\nexport interface SitemapSkippedRoute {\n routeId: string\n pattern: string\n reason: string\n}\n\nexport interface CanvasSitemapResult {\n entries: MetadataRoute.Sitemap\n /** Routes that could not be enumerated — explicit, never silent. */\n skipped: SitemapSkippedRoute[]\n}\n\nfunction paramNamesOf(pattern: string): string[] {\n return splitPath(pattern)\n .filter((segment) => segment.startsWith(':'))\n .map((segment) => segment.slice(1))\n}\n\n/** Substitute `:name` segments; `null` when a param is missing from the record. */\nfunction fillPattern(pattern: string, params: Record<string, string>): string | null {\n const segments: string[] = []\n for (const segment of splitPath(pattern)) {\n if (!segment.startsWith(':')) {\n segments.push(segment)\n continue\n }\n const value = params[segment.slice(1)]\n if (value === undefined || value.length === 0) return null\n segments.push(encodeURIComponent(value))\n }\n return '/' + segments.join('/')\n}\n\n/** Default locale serves the root; other locales get a `/locale` prefix. */\nfunction absoluteUrl(baseUrl: string, locale: Locale, defaultLocale: Locale, path: string): string {\n const origin = baseUrl.replace(/\\/+$/, '')\n if (locale === defaultLocale) return origin + path\n return origin + (path === '/' ? `/${locale}` : `/${locale}${path}`)\n}\n\n/**\n * Enumerate the sitemap entries of one content source (published\n * perspective). Pure over the prefetched source — synchronous accessors,\n * deterministic ordering (sorted by URL).\n */\nexport function canvasSitemapEntries(\n source: ContentSource,\n options: CanvasSitemapOptions,\n): CanvasSitemapResult {\n const routes = options.routes ?? source.routes ?? []\n const locales = source.locales\n const skipped: SitemapSkippedRoute[] = []\n const skip = (route: RouteRecord, reason: string): void => {\n if (!skipped.some((s) => s.routeId === route.id && s.reason === reason)) {\n skipped.push({ routeId: route.id, pattern: route.pattern, reason })\n }\n }\n\n const clients = new Map<Locale, ContentClient>()\n const clientFor = (locale: Locale): ContentClient => {\n let client = clients.get(locale)\n if (!client) {\n client = source.client({ perspective: 'published', locale })\n clients.set(locale, client)\n }\n return client\n }\n\n // path → locale → absolute URL (alternates group per concrete path).\n const byPath = new Map<string, Map<Locale, string>>()\n\n for (const route of routes) {\n const paramNames = paramNamesOf(route.pattern)\n // EC-218: a hierarchy mount (`/:path*`) serves a collection's pages by their\n // COMPOSED nested path — it self-describes its tree, so it is enumerated from\n // the collection's published documents, not the host's params provider.\n const mount = hierarchyMount(route)\n const routeLocales = route.locale ? [route.locale] : locales.locales\n\n for (const locale of routeLocales) {\n const client = clientFor(locale)\n\n let paths: string[]\n if (mount) {\n const listed = client.listDocuments(mount.collection)\n if (!listed.ok) {\n skip(route, `hierarchy collection \"${mount.collection}\" could not be listed`)\n continue\n }\n // Delivery docs are flat (`{ id, slug, parent, … }`); rebuild the minimal\n // CmsDocument shape composePath reads. Published perspective already\n // filtered to published rows, so a child whose parent is unpublished has a\n // dangling chain and drops out — exactly as live resolution would 404 it.\n const rows: CmsDocument[] = listed.documents.map((doc) => ({\n collection: mount.collection,\n id: doc.id,\n values: { slug: doc['slug'], parent: doc['parent'] },\n }))\n const byId = new Map(rows.map((row) => [row.id, row]))\n paths = []\n for (const row of rows) {\n // Only documents with their own slug are addressed through the mount\n // (a page routed explicitly elsewhere carries none).\n if (typeof row.values['slug'] !== 'string' || row.values['slug'] === '') continue\n const composed = composePath(row, (id) => byId.get(id))\n if (!composed.ok) continue\n paths.push('/' + [...mount.prefix, ...composed.segments].join('/'))\n }\n } else if (paramNames.length === 0) {\n paths = [route.pattern]\n } else {\n const paramSets = options.params?.({ route, locale, client })\n if (paramSets == null) {\n skip(route, 'dynamic route not enumerated (no params provider entry)')\n continue\n }\n paths = []\n for (const paramSet of paramSets) {\n const path = fillPattern(route.pattern, paramSet)\n if (path === null) {\n skip(route, `params entry missing one of :${paramNames.join(', :')}`)\n continue\n }\n paths.push(path)\n }\n }\n\n for (const path of paths) {\n // Same resolution the live request performs: only URLs that resolve\n // `ok` in the published perspective — and are not noindex — qualify.\n // Redirect-shadowed paths drop out (their targets are listed via\n // their own routes), and so do routes whose bound page/template is\n // not visible in the published graph (never published).\n const result = client.resolvePage(path, locale)\n // A document-bound route whose document is not published already\n // resolves `notFound` (EC-177 gap 6), so `status !== 'ok'` covers the\n // never-published case. A `page`-collection document carries its own\n // `seoNoindex` flat field (EC-187); honor it for the page sitemap.\n if (result.status !== 'ok') continue\n if (result.document?.['seoNoindex'] === true) continue\n const perLocale = byPath.get(path) ?? new Map<Locale, string>()\n perLocale.set(locale, absoluteUrl(options.baseUrl, locale, locales.default, path))\n byPath.set(path, perLocale)\n }\n }\n }\n\n const entries: MetadataRoute.Sitemap = []\n for (const perLocale of byPath.values()) {\n const languages = Object.fromEntries(perLocale)\n for (const url of perLocale.values()) {\n entries.push({\n url,\n ...(perLocale.size > 1 ? { alternates: { languages } } : {}),\n })\n }\n }\n entries.sort((a, b) => (a.url < b.url ? -1 : a.url > b.url ? 1 : 0))\n\n return { entries, skipped }\n}\n\nexport interface CreateCanvasSitemapOptions extends CanvasSitemapOptions {\n /** The same content loader the catch-all route uses (published perspective). */\n loadContent: (request: { perspective: 'published' }) => Promise<ContentSource>\n}\n\n/**\n * The `app/sitemap.ts` one-liner: `export default createCanvasSitemap({ … })`.\n * Loads the published content source and returns the enumerated entries\n * (skipped routes are dropped here — use {@link canvasSitemapEntries} to\n * inspect them).\n */\nexport function createCanvasSitemap(\n options: CreateCanvasSitemapOptions,\n): () => Promise<MetadataRoute.Sitemap> {\n return async () => {\n const source = await options.loadContent({ perspective: 'published' })\n return canvasSitemapEntries(source, options).entries\n }\n}\n","import { createHmac, timingSafeEqual } from 'node:crypto'\nimport { z } from 'zod'\n\n/**\n * Pure signature/payload logic of the revalidation webhook receiver (EC-146),\n * kept free of Next.js imports so it is unit-testable. `revalidate.ts` wires\n * it into a route handler with `revalidateTag`.\n *\n * Scheme: HMAC-SHA256 over the **raw request body** with a shared secret,\n * carried as `x-elytra-signature: sha256=<hex>`. The emitter (the studio's\n * webhook dispatcher) signs the exact JSON string it sends; the receiver\n * verifies over the raw text *before* parsing, with a timing-safe compare.\n */\n\n/** Header carrying the HMAC signature. */\nexport const REVALIDATE_SIGNATURE_HEADER = 'x-elytra-signature'\n\n/** The webhook body: which tags to revalidate, and why. */\nexport const revalidatePayloadSchema = z.object({\n projectId: z.string().min(1),\n /** The operation that fired, e.g. `documents.setState`, `publishing.publish`. */\n event: z.string().min(1),\n /** Fully-formatted Next tag strings (already scoped) — revalidated verbatim. */\n tags: z.array(z.string().min(1)),\n /** ISO timestamp of emission. Informational in v1 (no replay window). */\n timestamp: z.string().min(1),\n})\nexport type RevalidatePayload = z.infer<typeof revalidatePayloadSchema>\n\n/** Compute the signature header value for a raw body (emitter/test side). */\nexport function signRevalidateBody(rawBody: string, secret: string): string {\n return `sha256=${createHmac('sha256', secret).update(rawBody, 'utf8').digest('hex')}`\n}\n\nexport type RevalidateEvaluation =\n | { ok: true; payload: RevalidatePayload }\n | { ok: false; status: 400 | 401; message: string }\n\nconst SIGNATURE_PREFIX = 'sha256='\nconst HEX_PATTERN = /^[0-9a-f]+$/\n\n/**\n * Evaluate one webhook request: verify the HMAC first (auth before parsing),\n * then validate the payload shape.\n *\n * - unconfigured (empty) secret → 401 for every request: the endpoint stays\n * closed until a secret is deliberately configured (mirrors EC-144 preview);\n * - missing/malformed/mismatched signature → 401 (timing-safe compare);\n * - unparseable or schema-invalid body → 400 with no tag revalidated.\n */\nexport function evaluateRevalidateRequest(\n rawBody: string,\n signature: string | null | undefined,\n secret: string | undefined,\n): RevalidateEvaluation {\n if (secret === undefined || secret.length === 0) {\n return { ok: false, status: 401, message: 'Revalidation webhook is not configured.' }\n }\n\n if (signature === null || signature === undefined || !signature.startsWith(SIGNATURE_PREFIX)) {\n return { ok: false, status: 401, message: 'Missing or malformed webhook signature.' }\n }\n\n const providedHex = signature.slice(SIGNATURE_PREFIX.length).toLowerCase()\n const expectedHex = createHmac('sha256', secret).update(rawBody, 'utf8').digest('hex')\n // Length must match before `timingSafeEqual` (it throws otherwise); the\n // digest length is public knowledge, so this comparison leaks nothing.\n if (\n providedHex.length !== expectedHex.length ||\n !HEX_PATTERN.test(providedHex) ||\n !timingSafeEqual(Buffer.from(providedHex, 'hex'), Buffer.from(expectedHex, 'hex'))\n ) {\n return { ok: false, status: 401, message: 'Invalid webhook signature.' }\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(rawBody)\n } catch {\n return { ok: false, status: 400, message: 'Webhook body is not valid JSON.' }\n }\n\n const payload = revalidatePayloadSchema.safeParse(parsed)\n if (!payload.success) {\n return { ok: false, status: 400, message: 'Webhook payload has an invalid shape.' }\n }\n\n return { ok: true, payload: payload.data }\n}\n","import { revalidateTag } from 'next/cache'\nimport { REVALIDATE_SIGNATURE_HEADER, evaluateRevalidateRequest } from './revalidate-core'\n\n/**\n * Revalidation webhook route handler (EC-146): the receiving end of the\n * publish → live-in-seconds pipeline. The studio's dispatcher POSTs a signed\n * `{projectId, event, tags, timestamp}` payload; this handler verifies the\n * HMAC over the raw body and calls `revalidateTag` for each tag, dropping\n * exactly the cached entries whose fetch-time tag sets contained them.\n *\n * Server-only by construction — consumed from an App Router route handler\n * file, never from client bundles.\n */\n\nexport interface RevalidateRouteOptions {\n /**\n * Shared HMAC secret. An empty/undefined secret rejects every request with\n * 401 — the endpoint stays closed until deliberately configured.\n */\n secret: string | undefined\n /**\n * CORS origin allowed to call this endpoint (e.g. the studio's origin).\n * The v1 dispatcher is a browser `fetch` from the studio, and the custom\n * signature header always triggers a CORS preflight — so cross-origin\n * studio → host dispatch only works when this is set. Server-side emitters\n * (the Convex action variant, CLIs, CI) need no CORS and may leave it\n * unset. Never use `*` with a real secret-bearing deployment unless you\n * accept that any origin may *attempt* deliveries (they still need the\n * secret to have any effect).\n */\n allowOrigin?: string\n}\n\nexport interface RevalidateRouteHandlers {\n POST(request: Request): Promise<Response>\n OPTIONS(): Promise<Response>\n}\n\nfunction corsHeaders(allowOrigin: string | undefined): Record<string, string> {\n if (allowOrigin === undefined || allowOrigin.length === 0) return {}\n return {\n 'access-control-allow-origin': allowOrigin,\n 'access-control-allow-methods': 'POST, OPTIONS',\n 'access-control-allow-headers': `content-type, ${REVALIDATE_SIGNATURE_HEADER}`,\n }\n}\n\n/**\n * Create the webhook route handlers for `app/api/revalidate/route.ts`:\n *\n * ```ts\n * export const { POST, OPTIONS } = createRevalidateRoute({\n * secret: process.env.REVALIDATE_SECRET,\n * })\n * ```\n *\n * Unsigned/invalid requests are rejected with 401 (timing-safe HMAC check,\n * see `evaluateRevalidateRequest`); valid requests revalidate every carried\n * tag and answer `{ revalidated: tags }`.\n */\nexport function createRevalidateRoute(options: RevalidateRouteOptions): RevalidateRouteHandlers {\n const cors = corsHeaders(options.allowOrigin)\n return {\n async POST(request: Request): Promise<Response> {\n const rawBody = await request.text()\n const signature = request.headers.get(REVALIDATE_SIGNATURE_HEADER)\n const evaluation = evaluateRevalidateRequest(rawBody, signature, options.secret)\n if (!evaluation.ok) {\n return Response.json(\n { error: evaluation.message },\n { status: evaluation.status, headers: cors },\n )\n }\n // Next 16 requires a cache-life profile as the second argument; `'max'`\n // is the documented drop-in that preserves the legacy \"drop every entry\n // carrying this tag\" semantics our `unstable_cache` flow relies on (the\n // one-arg form is deprecated). `updateTag` is not an option here — it is\n // Server-Action-only and throws from a route handler.\n for (const tag of evaluation.payload.tags) revalidateTag(tag, 'max')\n return Response.json({ revalidated: evaluation.payload.tags }, { headers: cors })\n },\n async OPTIONS(): Promise<Response> {\n // Preflight for the browser-dispatch path; 204 either way, CORS headers\n // only when an origin is configured.\n return new Response(null, { status: 204, headers: cors })\n },\n }\n}\n","import NextImage from 'next/image'\nimport type { ImageLoader } from 'next/image'\nimport type { ReactNode } from 'react'\nimport type { ResolvedAsset } from '@elytracms/core/content'\nimport { ImageManifest, normalizeImageSource } from '@elytracms/core/runtime-renderer'\nimport type { HostComponent } from './components'\n// TYPE-ONLY by design: importing `./host-image` at runtime would bundle a second\n// singleton instance into the server entry (see host-image.ts module docs).\nimport type { HostImageRenderer } from './host-image'\n\n/**\n * Image delivery for the embedded runtime (EC-152).\n *\n * ## The honest v1 design\n *\n * Stored asset bytes are served from plain blob-storage URLs (Convex file\n * storage serve URLs in production). Those URLs do **not** transform — there\n * is no `?w=`/`?q=` resizing service behind them, and no image CDN build-out\n * in v1. The standard, no-CDN path is therefore `next/image` with its\n * **default loader**: the host app's own Next.js optimizer fetches the remote\n * asset URL, resizes/re-encodes it, and serves the variants same-origin from\n * `/_next/image`. That is exactly what {@link ElytraImage} does.\n *\n * For that to work the host app must allowlist the asset origin in\n * `next.config.mjs`:\n *\n * ```js\n * const nextConfig = {\n * images: {\n * remotePatterns: [\n * // Convex file storage serve URLs:\n * { protocol: 'https', hostname: '*.convex.cloud' },\n * ],\n * },\n * }\n * ```\n *\n * {@link createAssetImageLoader} exists for the day the asset URLs sit behind\n * a CDN that *does* honor width/quality query params — it appends them and\n * nothing more. Pointing it at raw Convex serve URLs would silently serve\n * full-size bytes while pretending to resize, so it is **not** the default.\n */\n\n/**\n * The slice of the {@link ResolvedAsset} delivery shape an image needs:\n * the resolvable URL, intrinsic dimensions for layout stability, and alt\n * text. Structurally satisfied by every `ResolvedAsset`.\n */\nexport type ElytraImageAsset = Pick<\n ResolvedAsset,\n 'url' | 'width' | 'height' | 'alt' | 'focalPoint'\n> & {\n /**\n * LQIP blur-placeholder data URI (EC-420) → `next/image` `blurDataURL`. Optional\n * so existing call sites are unaffected; when present, the optimized image blurs\n * up while loading. `null`/absent = today's behaviour (no placeholder).\n */\n lqip?: string | null\n}\n\nexport interface ElytraImageProps {\n /** The resolved asset (delivery shape). `null` renders nothing. */\n asset: ElytraImageAsset | null | undefined\n /** `sizes` hint forwarded to `next/image` for responsive variants. */\n sizes?: string\n /** Preload hint forwarded to `next/image` (above-the-fold images). */\n priority?: boolean\n /** Quality (1–100) forwarded to `next/image`; Next defaults to 75. */\n quality?: number\n className?: string\n /**\n * Loading strategy forwarded to `next/image` (EC-428/NK-026). `'eager'` opts an\n * image out of lazy-loading without the preload `priority` implies. Next throws\n * on `priority` + `loading='lazy'` together, so {@link ElytraImage} drops `lazy`\n * when `priority` is set (priority wins) — delivery never crashes.\n */\n loading?: 'eager' | 'lazy'\n /**\n * Custom `next/image` loader (e.g. from {@link createAssetImageLoader})\n * when assets sit behind a transforming CDN. Omit for the v1 default:\n * Next's own optimizer.\n */\n loader?: ImageLoader\n}\n\n/** LQIP raster long edge (EC-420). MUST equal studio `LQIP_MAX_EDGE` (thumbnail.ts). */\nconst LQIP_MAX_EDGE = 24\n\n/**\n * Recompute the EC-420 LQIP raster's pixel dimensions from the asset's intrinsic\n * size — the SAME `fitLongEdge` math the generator uses\n * (`packages/studio/src/lib/assets/thumbnail.ts:64-67`), duplicated here (3 lines)\n * because `packages/next` must NOT import studio internals (EC-428 AD-3). Fits the\n * long edge to {@link LQIP_MAX_EDGE}, rounds, floors each edge to ≥1px, and NEVER\n * upscales — so a ≤24px source keeps its own dims (the case the aspect-ratio\n * approximation gets wrong). Deterministic from `width`/`height`, non-null on the\n * NextImage path (the only place the wrap runs).\n */\nfunction fitLqipLongEdge(width: number, height: number): { width: number; height: number } {\n const scale = Math.min(1, LQIP_MAX_EDGE / Math.max(width, height))\n return { width: Math.max(1, Math.round(width * scale)), height: Math.max(1, Math.round(height * scale)) }\n}\n\n/**\n * Pre-wrap a raster LQIP data URI in an SVG that reproduces Next's OWN\n * static-import blur strength (EC-428 AD-2, ported from the NK-029 reference).\n *\n * Next's `getImageBlurSvg` only scales its blur (`blurWidth * 40` viewBox) for\n * **static imports** that carry `blurWidth`/`blurHeight`; a runtime `blurDataURL`\n * falls back to `stdDeviation=20` over the image's INTRINSIC-size viewBox — on a\n * large hero that is effectively no blur, so the ≤24px LQIP shows raw pixel blocks.\n * There is no public API to pass `blurWidth`/`blurHeight` for runtime URLs, so we\n * reproduce the scaled path ourselves: `viewBox = lqipDims * 40`, Next's identical\n * alpha-safe filter chain (feGaussianBlur → alpha-clamp feColorMatrix → feFlood/\n * feComposite `out` → composite over SourceGraphic → feGaussianBlur), and an\n * `<image preserveAspectRatio='none'>` over the original LQIP.\n *\n * Base64-encoded (`data:image/svg+xml;base64,`), NEVER percent-encoding: Next nests\n * this whole URI as its outer SVG's `<image href>`, and the browser percent-decodes\n * the outer data URI exactly once — percent-encoded nested `%xx` would corrupt. The\n * SVG string is pure ASCII (the inner `href` is itself a base64 data URI), so `btoa`\n * (a global in every runtime this targets — browser, Node ≥16, edge) is safe.\n */\nexport function scaledLqipBlur(lqip: string, width: number, height: number): string {\n const { width: lqipW, height: lqipH } = fitLqipLongEdge(width, height)\n const svg = `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 ${lqipW * 40} ${lqipH * 40}'><filter id='b' color-interpolation-filters='sRGB'><feGaussianBlur stdDeviation='20'/><feColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/><feFlood x='0' y='0' width='100%' height='100%'/><feComposite operator='out' in='s'/><feComposite in2='SourceGraphic'/><feGaussianBlur stdDeviation='20'/></filter><image width='100%' height='100%' x='0' y='0' preserveAspectRatio='none' style='filter:url(#b)' href='${lqip}'/></svg>`\n return `data:image/svg+xml;base64,${btoa(svg)}`\n}\n\n/**\n * Render a resolved asset through `next/image` (EC-152).\n *\n * - With known intrinsic dimensions the optimizer serves resized variants\n * and the reserved width/height prevent layout shift.\n * - Without dimensions `next/image` cannot render (it requires `width` +\n * `height` or `fill`), so the component degrades to a plain `<img>` —\n * un-optimized but visible, never a crash. Records written by the EC-151\n * upload flow always carry detected dimensions.\n * - A `null`/empty asset renders nothing (missing assets surface as\n * structured `unknown-asset` validation issues upstream, not here).\n */\nexport function ElytraImage(props: ElytraImageProps): ReactNode {\n const { asset, sizes, priority, quality, className, loader, loading } = props\n if (!asset || asset.url.length === 0) return null\n const alt = asset.alt ?? ''\n // EC-230: a focal point becomes CSS `object-position`, so an art-directed image\n // keeps its subject in frame when a layout crops it (`object-fit: cover`).\n // Inert under the default fit — harmless to set, correct once a layout crops.\n const objectPosition = asset.focalPoint\n ? `${asset.focalPoint.x * 100}% ${asset.focalPoint.y * 100}%`\n : undefined\n if (asset.width === null || asset.height === null) {\n // Honest fallback: next/image requires intrinsic dimensions; a\n // dimensionless record degrades to an unoptimized <img> instead of\n // crashing the page. No placeholder here — a plain <img> can't consume a\n // blurDataURL — and the wrap needs non-null dims, so it stays below this guard.\n return (\n <img\n data-ec-image=\"fallback\"\n src={asset.url}\n alt={alt}\n className={className}\n {...(objectPosition ? { style: { objectPosition } } : {})}\n />\n )\n }\n // EC-420 (AD-2): a resolved LQIP data URI becomes a next/image blur-up\n // placeholder — the image blurs while the optimized bytes stream in.\n // EC-428 (AD-2/AD-3): but Next only scales its blur for static imports; a runtime\n // blurDataURL under-blurs a large image to raw pixel blocks — so pre-wrap the\n // raster LQIP in a viewBox-scaled SVG using the recomputed LQIP dims. AD-4: an\n // lqip that is ALREADY an SVG (a future engine that pre-blurs, or NK's interim\n // consumer wrapper) passes through untouched. Absent lqip = pre-EC-420 behaviour.\n const blurDataURL =\n asset.lqip == null\n ? null\n : asset.lqip.startsWith('data:image/svg')\n ? asset.lqip\n : scaledLqipBlur(asset.lqip, asset.width, asset.height)\n const blur = blurDataURL ? { placeholder: 'blur' as const, blurDataURL } : {}\n // EC-428 (AD-5): forward `loading`, but Next throws when `priority` +\n // `loading='lazy'` arrive together (get-img-props.js). Priority wins; drop the\n // conflicting `lazy` so a priority image never crashes delivery.\n const loadingProp = priority && loading === 'lazy' ? undefined : loading\n return (\n <NextImage\n data-ec-image=\"next\"\n src={asset.url}\n alt={alt}\n width={asset.width}\n height={asset.height}\n {...(sizes !== undefined ? { sizes } : {})}\n {...(priority !== undefined ? { priority } : {})}\n {...(loadingProp !== undefined ? { loading: loadingProp } : {})}\n {...(quality !== undefined ? { quality } : {})}\n {...(className !== undefined ? { className } : {})}\n {...(loader !== undefined ? { loader } : {})}\n {...blur}\n {...(objectPosition ? { style: { objectPosition } } : {})}\n />\n )\n}\n\nexport interface AssetImageLoaderOptions {\n /** Query param name for the requested width. Default `\"w\"`. */\n widthParam?: string\n /** Query param name for the requested quality. Default `\"q\"`. */\n qualityParam?: string\n /** Quality used when `next/image` passes none. Default `75`. */\n defaultQuality?: number\n}\n\n/**\n * A `next/image` loader for asset URLs served through a transforming CDN:\n * it appends width/quality query params to the asset URL and returns it.\n *\n * Be honest about what this does: it only *requests* a transform. Plain\n * Convex file-storage serve URLs ignore these params and return the original\n * bytes, so this loader is only correct once the asset origin actually\n * resizes (e.g. an image CDN in front of storage). Until then, use the\n * default `next/image` loader (see module docs) — that is the v1 path.\n */\nexport function createAssetImageLoader(options: AssetImageLoaderOptions = {}): ImageLoader {\n const widthParam = options.widthParam ?? 'w'\n const qualityParam = options.qualityParam ?? 'q'\n const defaultQuality = options.defaultQuality ?? 75\n return ({ src, width, quality }) => {\n const separator = src.includes('?') ? '&' : '?'\n return `${src}${separator}${widthParam}=${width}&${qualityParam}=${quality ?? defaultQuality}`\n }\n}\n\n/**\n * The `base.Image` implementation for Next.js host apps: same\n * canonical manifest, rendered optimized through {@link ElytraImage}. The\n * renderer resolves an `asset`-typed `src` (EC-195) to `{ url, width, height,\n * alt }` before this runs, so `normalizeImageSource` yields intrinsic dimensions\n * (→ no layout shift, sized variants) whether the editor picked an uploaded asset\n * or pasted a URL. `priority` opts an above-the-fold image out of lazy-loading.\n */\n/**\n * Per-deployment image-delivery options for {@link nextImagePrimitive} (EC-271).\n * The default is the host's own Next.js optimizer (Vercel) — zero config. A host\n * on a different CDN supplies its own `loader` (a plain function) to route variants\n * through that CDN instead, without touching component code.\n */\nexport interface NextImagePrimitiveOptions {\n /**\n * Custom `next/image` loader — the override seam for non-Vercel hosting. Omit\n * for the Vercel default (Next's own `/_next/image` optimizer). Supply a\n * function to delegate resizing to another CDN:\n *\n * - a CDN that honors `?w=&q=` query params → {@link createAssetImageLoader};\n * - Cloudflare Images / Imgix / a bespoke transform → your own `ImageLoader`\n * (e.g. rewrite to `/cdn-cgi/image/width=<w>,quality=<q>/<src>`).\n *\n * The loader receives `{ src, width, quality }` and returns the variant URL.\n */\n loader?: ImageLoader\n /** Default responsive `sizes` hint when a block doesn't set one. */\n sizes?: string\n /** Default quality (1–100) when a block doesn't set one (Next defaults to 75). */\n quality?: number\n}\n\nfunction createNextImagePrimitive(options: NextImagePrimitiveOptions) {\n return function NextImagePrimitive(props: Record<string, unknown>): ReactNode {\n const { url, width, height, alt, focalPoint, lqip } = normalizeImageSource(props)\n if (url.length === 0) return null\n return (\n <ElytraImage\n asset={{ url, width: width ?? null, height: height ?? null, alt, focalPoint, lqip }}\n {...(props.priority === true ? { priority: true } : {})}\n {...(options.loader !== undefined ? { loader: options.loader } : {})}\n {...(options.sizes !== undefined ? { sizes: options.sizes } : {})}\n {...(options.quality !== undefined ? { quality: options.quality } : {})}\n />\n )\n }\n}\n\n/**\n * Host registration that swaps the `base.Image` implementation\n * for {@link ElytraImage} while keeping the primitive's canonical manifest\n * (the first registration's manifest wins in `defineHostComponents` — by\n * design, so prop schemas stay canonical; the duplicate-id registry issue it\n * reports is the documented override signal, not an error):\n *\n * ```ts\n * export const hostComponents = defineHostComponents([\n * nextImagePrimitive(), // Vercel default optimizer\n * // ...project components\n * ])\n * ```\n *\n * Pass {@link NextImagePrimitiveOptions} to delegate image delivery to another\n * CDN (EC-271) — the v1 default is Vercel, with room to grow:\n *\n * ```ts\n * nextImagePrimitive({ loader: createAssetImageLoader() }) // ?w=&q= CDN\n * nextImagePrimitive({ loader: cloudflareImageLoader }) // Cloudflare Images\n * ```\n */\nexport function nextImagePrimitive(options: NextImagePrimitiveOptions = {}): HostComponent {\n return {\n manifest: ImageManifest,\n implementation: createNextImagePrimitive(options),\n }\n}\n\n/** Per-deployment options for {@link elytraHostImage} (the EC-271 loader seam). */\nexport interface ElytraHostImageOptions {\n /** Custom `next/image` loader for non-Vercel CDNs (see {@link NextImagePrimitiveOptions}). */\n loader?: ImageLoader\n /** Default quality (1–100) when a call site doesn't set one (Next defaults to 75). */\n quality?: number\n}\n\n/**\n * The `next/image`-backed {@link HostImageRenderer} (EC-368 image defaults): the\n * renderer a Next host registers on the `@elytracms/next/host-image` bridge so\n * DUAL-RENDERED project components (which can't import `next/image` themselves)\n * deliver optimized images — resized/modern-format variants, intrinsic\n * dimensions (no layout shift), focal-point `object-position`. A dimensionless\n * record degrades to a plain `<img>` (honest, never a crash), exactly like\n * {@link ElytraImage}.\n *\n * ```ts\n * import { elytraHostImage } from '@elytracms/next'\n * import { setHostImage } from '@elytracms/next/host-image'\n *\n * setHostImage(elytraHostImage()) // once, at host boot (never in the studio)\n * ```\n */\nexport function elytraHostImage(options: ElytraHostImageOptions = {}): HostImageRenderer {\n // EC-428 (AD-5/NK-026): forward `loading` — before this the renderer destructured\n // only asset/alt/className/priority/sizes, so a non-priority eager image silently\n // fell back to lazy. ElytraImage resolves the priority + loading='lazy' conflict.\n return ({ asset, alt, className, priority, sizes, loading }) => (\n <ElytraImage\n asset={{ ...asset, alt }}\n {...(className !== undefined ? { className } : {})}\n {...(priority ? { priority: true } : {})}\n {...(sizes !== undefined ? { sizes } : {})}\n {...(loading !== undefined ? { loading } : {})}\n {...(options.loader !== undefined ? { loader: options.loader } : {})}\n {...(options.quality !== undefined ? { quality: options.quality } : {})}\n />\n )\n}\n","import type { ComponentRegistry } from '@elytracms/core/component-registry'\nimport { compositionNodesOf } from './canvas-renderer'\n\n/**\n * Manifest-driven header clearance (EC-368): does this page OPEN full-bleed?\n *\n * A host with a floating header (occupying no flow space) must pad a page's\n * content down by the header height — unless the page's FIRST canvas block is a\n * structural hero that deliberately bleeds to the viewport top and renders\n * under the header. Which components bleed is declared on their OWN manifest\n * (`presentation: { fullBleed: true }`, `@elytracms/core/component-registry`),\n * so the host derives the decision from the registry instead of keeping a\n * parallel hand-maintained component-id set that silently drifts when a new\n * hero ships.\n *\n * Pure over the delivery-shaped document: the composition field is found by\n * VALUE (the same `compositionNodesOf` selection the renderer uses), so hosts\n * with `body`, `content`, or bespoke composition field names all work. Absent\n * document, empty composition, unknown component, or an undeclared hint all\n * answer `false` — the safe default is clearance.\n *\n * ```tsx\n * const outcome = client.resolvePage(path)\n * const fullBleed = firstBlockFullBleed(outcome.document, components.registry)\n * return fullBleed ? page : <div className=\"pt-[var(--header-clearance)]\">{page}</div>\n * ```\n *\n * The host kit wires the resolution half for you: `elytra.pageOpensFullBleed(slug)`.\n */\nexport function firstBlockFullBleed(\n document: Record<string, unknown> | null | undefined,\n registry: ComponentRegistry,\n): boolean {\n const first = compositionNodesOf(document)[0]\n if (!first) return false\n return registry.getManifest(first.componentId)?.presentation?.fullBleed === true\n}\n","/**\n * Env resolution for the delivery host kit (EC-368). ONE documented name per\n * concern — every kit surface reads the same resolved bag, so the two-\n * disconnected-secrets class of bug (a preview route gating on one env var\n * while the draft loader reads another) is structurally impossible: there is\n * exactly one `DRAFT_PREVIEW_TOKEN`, consumed by BOTH the preview-enable route\n * and the draft snapshot fetch.\n *\n * | Env var | Concern |\n * | --------------------- | ---------------------------------------------------- |\n * | `ELYTRA_CONVEX_URL` | Convex deployment URL — presence (with the project |\n * | | id) switches the loader to LIVE mode |\n * | `ELYTRA_PROJECT_ID` | The project the studio publishes under (= tag scope) |\n * | `DRAFT_PREVIEW_TOKEN` | The ONE draft secret: gates the preview-enable route |\n * | | AND authenticates the draft snapshot fetch (must |\n * | | equal the Convex deployment's own env var) |\n * | `REVALIDATE_SECRET` | Instant-publish webhook HMAC secret (must equal the |\n * | | deployment's `CANVAS_REVALIDATE_SECRET`) |\n * | `STUDIO_ORIGIN` | CORS origin for the studio's browser-dispatch path |\n */\n\n/** The kit's documented env names (single source of truth, also used in docs/tests). */\nexport const ELYTRA_HOST_ENV_KEYS = {\n convexUrl: 'ELYTRA_CONVEX_URL',\n projectId: 'ELYTRA_PROJECT_ID',\n draftToken: 'DRAFT_PREVIEW_TOKEN',\n revalidateSecret: 'REVALIDATE_SECRET',\n studioOrigin: 'STUDIO_ORIGIN',\n} as const\n\nexport interface ElytraHostEnv {\n convexUrl?: string\n projectId?: string\n draftToken?: string\n revalidateSecret?: string\n studioOrigin?: string\n}\n\nfunction cleaned(value: string | undefined): string | undefined {\n const trimmed = value?.trim()\n return trimmed !== undefined && trimmed.length > 0 ? trimmed : undefined\n}\n\n/**\n * Resolve the kit's env bag from a raw env record (`process.env` by default at\n * the factory). Values are trimmed; empty strings resolve to `undefined` — an\n * env var set to `\"\"` must behave exactly like an unset one (endpoints stay\n * closed, live mode stays off), never like a configured empty secret.\n */\nexport function resolveHostEnv(env: Record<string, string | undefined>): ElytraHostEnv {\n const resolved: ElytraHostEnv = {}\n for (const [key, name] of Object.entries(ELYTRA_HOST_ENV_KEYS)) {\n const value = cleaned(env[name])\n if (value !== undefined) resolved[key as keyof ElytraHostEnv] = value\n }\n return resolved\n}\n","import { documentSchema, fallbackHomeRoutes, redirectRecordSchema } from '@elytracms/core/cms-core'\nimport type {\n CmsDocument,\n CollectionDef,\n LocaleConfig,\n RedirectRecord,\n RouteRecord,\n} from '@elytracms/core/cms-core'\nimport type { ContentDocumentSource, Perspective } from '@elytracms/core/content'\nimport type { AssetRecord } from '@elytracms/core/persistence'\nimport { z } from 'zod'\nimport { createStaticContentSource, mergeRouteRecords } from './snapshot'\nimport type { CanvasDataSource, ContentSource } from './source'\n\n/**\n * The LIVE half of the delivery host kit (EC-368): fetch the delivery snapshot\n * from a Convex deployment (`convex/delivery.ts` in the builder app) over\n * Convex's public HTTP query API — a plain `fetch` to\n * `POST {deployment}/api/query`, no Convex npm dependency — and assemble it\n * through the same `createStaticContentSource` path the fixture snapshot uses,\n * so accessor and rendering semantics are byte-identical across seeded, empty,\n * and live modes. This engine-izes the ~300-line `live-content.ts` both real\n * consumers hand-copied (EC-369 finding #5); the fetch + Zod-validation logic\n * now lives in exactly one place.\n *\n * Perspective handling: published requests fetch the PUBLIC `delivery:snapshot`\n * (published documents only — the standing live-is-published-only invariant).\n * Draft-mode requests fetch `delivery:draftSnapshot`, gated by the deployment's\n * `DRAFT_PREVIEW_TOKEN` — the same single secret that gates the kit's\n * preview-enable route (see `host-env.ts`).\n *\n * Routes: config-sourced route records (AD-3/AD-11, EC-207 — the host repo's\n * own `cms/`, passed via options) and the implicit per-locale home fallback are\n * MERGED (EC-177 gap 2), never XOR'd — config records win per pattern+locale.\n * The backend never carries route data.\n */\n\nexport interface LiveContentOptions {\n /** Convex deployment URL, e.g. `https://your-deployment-123.convex.cloud`. */\n convexUrl: string\n projectId: string\n /** Project locale config — config-owned (AD-11), never read from the snapshot. */\n locales: LocaleConfig\n /** CMS collection schema — config-owned (AD-11); drives depth-1 relation population. */\n collections: readonly CollectionDef[]\n /** Route records — config-owned (AD-3/AD-11); merged with the home fallback. */\n routes: readonly RouteRecord[]\n /** `DRAFT_PREVIEW_TOKEN` — required for draft-perspective loads. */\n draftToken?: string\n /** Fetch implementation override (tests, custom agents). Defaults to global fetch. */\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * The `delivery.ts` payload shape (validated field-by-field below). A\n * deployment IS one environment (EC-179); the snapshot carries content only\n * (EC-287) — documents, assets, editorial redirects (EC-303), and persisted\n * data-source definitions (EC-166).\n */\ninterface DeliverySnapshotPayload {\n projectId: string\n redirects?: unknown[]\n sources?: unknown\n documents: unknown[]\n assets: unknown[]\n}\n\n/**\n * Run one query through Convex's public HTTP API. Response envelope (verified\n * against live deployments): `{ status: 'success', value }` or\n * `{ status: 'error', errorMessage }`. `cache: 'no-store'` keeps Next's fetch\n * cache out of the loop — the route helper's tagged data cache is the only\n * cache layer, so tag revalidation always reaches the deployment.\n */\nasync function runConvexQuery(\n fetchImpl: typeof globalThis.fetch,\n convexUrl: string,\n path: string,\n args: Record<string, unknown>,\n): Promise<unknown> {\n const response = await fetchImpl(`${convexUrl.replace(/\\/$/, '')}/api/query`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ path, args, format: 'json' }),\n cache: 'no-store',\n })\n const body = (await response.json().catch(() => undefined)) as\n | { status?: string; value?: unknown; errorMessage?: string; message?: string }\n | undefined\n if (!response.ok || body?.status !== 'success') {\n throw new Error(\n `Convex query \"${path}\" failed (${response.status}): ${\n body?.errorMessage ?? body?.message ?? 'no error message'\n }`,\n )\n }\n return body.value\n}\n\n/** Canonical-schema validation: invalid stored rows are skipped, not fatal. */\nfunction parseDocuments(rows: unknown[]): CmsDocument[] {\n const documents: CmsDocument[] = []\n for (const row of rows) {\n const parsed = documentSchema.safeParse(row)\n if (parsed.success) documents.push(parsed.data)\n }\n return documents\n}\n\n/** Validate the snapshot's editorial redirects (EC-303); malformed rows drop out. */\nfunction parseRedirects(rows: unknown[]): RedirectRecord[] {\n const redirects: RedirectRecord[] = []\n for (const row of rows) {\n const parsed = redirectRecordSchema.safeParse(row)\n if (parsed.success) redirects.push(parsed.data)\n }\n return redirects\n}\n\n/**\n * The snapshot's data-source envelope — the structural `CanvasDataSource` shape\n * `materializeSourcePayloads` consumes (cms query configs themselves are\n * re-validated by the content module's lenient parser inside the route helper).\n */\nconst canvasDataSourceSchema = z.object({\n kind: z.string().min(1),\n id: z.string().min(1),\n label: z.string().optional(),\n config: z.unknown().optional(),\n})\n\n/**\n * Parse the snapshot's `sources` array (EC-166 LIVE mode). Tolerant by design:\n * an older deployment without the field — or an invalid entry — degrades to no\n * source definitions, which the runtime renders as unresolved-binding\n * fallbacks, never a crash.\n */\nfunction parseSources(rows: unknown): CanvasDataSource[] {\n if (!Array.isArray(rows)) return []\n const sources: CanvasDataSource[] = []\n for (const row of rows) {\n const parsed = canvasDataSourceSchema.safeParse(row)\n if (parsed.success) sources.push(parsed.data)\n }\n return sources\n}\n\n// `fallbackHomeRoutes` moved to `@elytracms/core/cms-core` (EC-384) so the\n// studio's document-URL preview (`urlForDocument`) can derive the SAME implicit\n// `/` → first-page-document fallback the delivery resolver below applies — one\n// rule, not a studio-side reimplementation. Re-exported here (imported above)\n// to keep this module's/`@elytracms/next`'s existing public surface. The\n// delivery snapshot is already perspective-filtered server-side, so in draft\n// mode this correctly previews the draft home even when unpublished.\nexport { fallbackHomeRoutes }\n\n/**\n * Assemble a fetched delivery-snapshot payload into a `ContentSource` — the\n * pure half of {@link loadLiveContent}, exported so the parsing/assembly rules\n * are directly testable against fixture payloads (no network).\n */\nexport function assembleLiveSource(\n payload: DeliverySnapshotPayload,\n options: Pick<LiveContentOptions, 'locales' | 'collections' | 'routes'>,\n perspective: Perspective,\n): ContentSource {\n // Locales/collections/routes are config-owned (AD-11): from the host repo's\n // own `cms/`, passed in via options — never from the snapshot.\n const locales = options.locales\n const documents = parseDocuments(payload.documents)\n\n // MERGE, not XOR (EC-177 gap 2): config route records win per pattern+locale;\n // the implicit per-locale home fallback fills the rest.\n const routes = mergeRouteRecords([...options.routes], fallbackHomeRoutes(documents, locales))\n\n // EC-224 B-1: the published snapshot ships each document as its PINNED\n // published content (delivery resolved the version pointer server-side). Wrap\n // those rows as a `DocumentHistory` so the pure published gate\n // (`selectPerspective`) serves `.published` directly.\n //\n // TRUST CONTRACT: the wrap treats whatever the published fetch returned AS\n // published and deliberately does NOT re-gate — it cannot, the wire carries\n // no version pointer. Correctness rests ENTIRELY on `delivery:snapshot`\n // shipping published-only content (pinned version snapshots, never a draft —\n // see the builder's `convex/delivery.ts`). Guard the invariant in delivery,\n // not here. Draft-fetch rows stay bare: `selectPerspective('draft')` serves\n // them as-is.\n const documentSources: ContentDocumentSource[] =\n perspective === 'published'\n ? documents.map((doc) => ({ draft: doc, published: doc, versions: [] }))\n : documents\n\n return createStaticContentSource({\n projectId: payload.projectId,\n locales,\n routes,\n // Redirects are editorial DATA (EC-303): the ENABLED ones ship in the\n // snapshot, so they change dynamically (no redeploy). Native next.config\n // redirects run before this.\n redirects: parseRedirects(payload.redirects ?? []),\n collections: [...options.collections],\n documents: documentSources,\n assets: payload.assets as AssetRecord[],\n // EC-166 LIVE mode: the builder's persisted section/template sources, so\n // the route helper materializes their payloads.\n sources: parseSources(payload.sources),\n })\n}\n\n/** Fetch the live delivery snapshot and assemble the `ContentSource` for one request. */\nexport async function loadLiveContent(\n options: LiveContentOptions,\n perspective: Perspective,\n): Promise<ContentSource> {\n const fetchImpl = options.fetch ?? globalThis.fetch\n const args: Record<string, unknown> = { projectId: options.projectId }\n\n let payload: DeliverySnapshotPayload\n if (perspective === 'draft') {\n if (!options.draftToken) {\n // Explicit, visible failure: draft mode without a configured token must\n // never silently fall back to published content.\n throw new Error(\n 'Draft preview requested but DRAFT_PREVIEW_TOKEN is not configured on the host.',\n )\n }\n payload = (await runConvexQuery(fetchImpl, options.convexUrl, 'delivery:draftSnapshot', {\n ...args,\n token: options.draftToken,\n })) as DeliverySnapshotPayload\n } else {\n payload = (await runConvexQuery(\n fetchImpl,\n options.convexUrl,\n 'delivery:snapshot',\n args,\n )) as DeliverySnapshotPayload\n }\n\n return assembleLiveSource(payload, options, perspective)\n}\n","import type { DocumentRef, Locale } from '@elytracms/core/cms-core'\nimport type { ContentClient, Perspective, ResolvedDocument } from '@elytracms/core/content'\nimport type { ContentSource } from './source'\n\n/**\n * Site-chrome globals for delivery hosts (EC-368, from EC-369 finding #5): the\n * layout, header, and footer are NOT rendered through the canvas, so they read\n * the `settings` singleton + `navigation` documents straight from the\n * `ContentSource` and pre-resolve everything — keeping the chrome components\n * pure presentational, with no `ContentClient` or `@elytracms/*` knowledge.\n * Both real consumers hand-authored this ~200-line layer independently; the\n * MECHANISM now lives here, while the per-project projection (which settings\n * fields exist, what the chrome looks like) stays consumer-owned:\n *\n * - **settings**: the singleton collection's lone document (EC-274) — no\n * document id is ever named.\n * - **navigation by slot**: menus are addressed by their EC-284 alias slot\n * (`main`, `footer`), never a document id — delivery shape carries `alias`\n * since EC-364.\n * - **link resolution**: link-object values (`linkType: href | page | file`)\n * resolve through `client.resolveLink` — the same `urlForDocument` authority\n * the router serves, so a nav link to a nested page carries its FULL composed\n * path (`/krippe/tagesablauf`, EC-218/EC-360), and `home → '/'` needs no\n * special-casing.\n * - **asset resolution**: asset field values (stored ids) resolve to serve URLs\n * through the source's delivery-shaped asset list.\n *\n * Everything degrades explicitly: a missing settings document is `null`, a\n * missing slot is `null`/`[]`, an unresolvable link drops out (never a silent\n * `#`), an unknown asset id is `undefined` — the host renders sensible empties\n * for the empty-source build and surfaces gaps honestly.\n */\n\nexport interface GlobalsConventions {\n /** The settings singleton's collection id. Default `'settings'`. */\n settingsCollection?: string\n /** The navigation documents' collection id. Default `'navigation'`. */\n navigationCollection?: string\n /**\n * Field names probed (in order) for a navigation document's entry list.\n * Default `['items', 'links']` — the two shapes the shipped consumers and the\n * starter template use.\n */\n navigationItemsFields?: readonly string[]\n}\n\n/** A fully-resolved link: the composed href plus the new-tab flag. */\nexport interface ResolvedLink {\n href: string\n openInNewTab: boolean\n}\n\n/** A leaf navigation link (children of a dropdown / footer column). */\nexport interface ResolvedNavLink extends ResolvedLink {\n label: string\n /** Optional subline shown under the label (wide header dropdowns). */\n description?: string\n}\n\n/** A top-level navigation entry; `href` is absent for pure group headings. */\nexport interface ResolvedNavEntry {\n label: string\n href?: string\n openInNewTab: boolean\n description?: string\n children: ResolvedNavLink[]\n}\n\n/** The resolved chrome-globals surface `loadGlobals` yields (EC-368). */\nexport interface SiteGlobals {\n /** The settings singleton, delivery-shaped, or `null` (empty build / not published). */\n settings: ResolvedDocument | null\n /** The navigation document filling a slot alias (EC-284/EC-364), or `null`. */\n navigation(slot: string): ResolvedDocument | null\n /**\n * A slot's entry list, fully resolved: labels, composed hrefs (nested paths\n * included), new-tab flags, sublines, one level of children. Entries whose\n * link cannot resolve to an href are kept only when they carry children (a\n * group heading); leaf entries without a resolvable href drop out.\n */\n navigationEntries(slot: string): ResolvedNavEntry[]\n /** Resolve a link-object field value to an href + new-tab flag, or `null`. */\n resolveLink(value: unknown): ResolvedLink | null\n /** Resolve an asset field value (stored id / URL / `{ url }`) to a URL, or `undefined`. */\n assetUrl(value: unknown): string | undefined\n /** The accessor client behind the globals — for bespoke projections. */\n client: ContentClient\n /** The underlying content source (assets(), locales, routes). */\n source: ContentSource\n}\n\nexport interface ResolveGlobalsOptions {\n /** Perspective of the chrome read. Default `'published'` (live is published-only). */\n perspective?: Perspective\n locale?: Locale\n conventions?: GlobalsConventions\n}\n\nconst DEFAULT_ITEMS_FIELDS = ['items', 'links'] as const\n\nfunction record(value: unknown): Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {}\n}\n\nfunction str(value: unknown): string {\n return typeof value === 'string' ? value : ''\n}\n\nfunction items(value: unknown): Record<string, unknown>[] {\n return Array.isArray(value) ? value.map(record) : []\n}\n\n/**\n * Resolve the chrome globals over an already-loaded `ContentSource` — the pure\n * core of the host kit's `loadGlobals` (directly testable over fixture\n * sources).\n */\nexport function resolveGlobals(\n source: ContentSource,\n options: ResolveGlobalsOptions = {},\n): SiteGlobals {\n const perspective = options.perspective ?? 'published'\n const conventions = options.conventions ?? {}\n const settingsCollection = conventions.settingsCollection ?? 'settings'\n const navigationCollection = conventions.navigationCollection ?? 'navigation'\n const itemsFields = conventions.navigationItemsFields ?? DEFAULT_ITEMS_FIELDS\n\n const client = source.client({ perspective, ...(options.locale ? { locale: options.locale } : {}) })\n const assets = source.assets?.() ?? []\n const assetById = new Map(assets.map((asset) => [asset.id, asset] as const))\n\n const listDocs = (collection: string): ResolvedDocument[] => {\n const result = client.listDocuments(collection)\n return result.ok ? result.documents : []\n }\n\n // EC-274: `settings` is a singleton — the lone document of its collection.\n const settings = listDocs(settingsCollection)[0] ?? null\n\n // EC-284/EC-364: menus are addressed by slot alias through the content client\n // (delivery shape carries `alias`), never by document id.\n const navDocs = listDocs(navigationCollection)\n const navigation = (slot: string): ResolvedDocument | null =>\n navDocs.find((doc) => (doc as Record<string, unknown>).alias === slot) ?? null\n\n /** Asset field value → serve URL. The stored value is the asset id (or already a URL). */\n const assetUrl = (value: unknown): string | undefined => {\n if (typeof value === 'string') {\n const found = assetById.get(value)\n if (found) return found.url\n // A passthrough URL (external image / public asset path) — not an id.\n return value.startsWith('http') || value.startsWith('/') ? value : undefined\n }\n const url = record(value).url\n return typeof url === 'string' && url.length > 0 ? url : undefined\n }\n\n /** A raw or populated relation value's `{ collection, id }` identity, if present. */\n const refOf = (value: unknown): DocumentRef | null => {\n const ref = record(value)\n return typeof ref.collection === 'string' && typeof ref.id === 'string'\n ? { collection: ref.collection, id: ref.id }\n : null\n }\n\n /** Resolve a link-object value (`linkType: href | page | file`) to an href. */\n const resolveLink = (value: unknown): ResolvedLink | null => {\n const link = record(value)\n const openInNewTab = link.openInNewTab === true\n const href = str(link.href) || str(link.url)\n const linkType = str(link.linkType) || (href ? 'href' : '')\n\n if (linkType === 'href' || linkType === 'external') {\n return href ? { href, openInNewTab } : null\n }\n if (linkType === 'file') {\n const url = assetUrl(link.file)\n return url ? { href: url, openInNewTab } : null\n }\n if (linkType === 'page') {\n const page = link.page\n // The reverse-router authority (EC-291/EC-360): the SAME `urlForDocument`\n // the routes serve — composed nested paths, `home → '/'`, locale prefix.\n const ref = refOf(page)\n if (ref) {\n const path = client.resolveLink(ref)\n if (path !== null) return { href: path, openInNewTab }\n }\n // Degraded fallbacks for partially-shaped values; else explicit null.\n const shaped = record(page)\n if (typeof shaped.path === 'string' && shaped.path.startsWith('/')) {\n return { href: shaped.path, openInNewTab }\n }\n const slug = str(shaped.slug)\n if (slug) return { href: `/${slug}`, openInNewTab }\n return null\n }\n return null\n }\n\n const toNavLink = (entry: Record<string, unknown>): ResolvedNavLink | null => {\n const label = str(entry.label)\n // Structured shape: the link object lives under `link`; flat starter shape:\n // the entry itself carries `href` (resolveLink's href fallback picks it up).\n const resolved = resolveLink('link' in entry ? entry.link : entry)\n if (!label || !resolved) return null\n const description = str(entry.description)\n return { label, ...resolved, ...(description ? { description } : {}) }\n }\n\n const toNavEntry = (entry: Record<string, unknown>): ResolvedNavEntry | null => {\n const label = str(entry.label)\n if (!label) return null\n const resolved = resolveLink('link' in entry ? entry.link : entry)\n const description = str(entry.description)\n const children = items(entry.children)\n .map(toNavLink)\n .filter((child): child is ResolvedNavLink => child !== null)\n // A leaf entry needs a resolvable target; an entry with children stands as a\n // group heading even without one (footer columns, pure dropdowns).\n if (!resolved && children.length === 0) return null\n return {\n label,\n ...(resolved ? { href: resolved.href } : {}),\n openInNewTab: resolved?.openInNewTab ?? false,\n ...(description ? { description } : {}),\n children,\n }\n }\n\n const navigationEntries = (slot: string): ResolvedNavEntry[] => {\n const doc = navigation(slot)\n if (!doc) return []\n const values = doc as Record<string, unknown>\n const field = itemsFields.find((name) => Array.isArray(values[name]))\n if (!field) return []\n return items(values[field])\n .map(toNavEntry)\n .filter((entry): entry is ResolvedNavEntry => entry !== null)\n }\n\n return {\n settings,\n navigation,\n navigationEntries,\n resolveLink,\n assetUrl,\n client,\n source,\n }\n}\n","/**\n * Pure token/target logic of the draft-preview routes (EC-144), kept free of\n * Next.js imports so it is unit-testable. `preview.ts` wires it into route\n * handlers with `draftMode()`.\n */\n\nexport type PreviewEvaluation =\n | { ok: true; redirectTo: string }\n | { ok: false; status: 400 | 401; message: string }\n\n/**\n * Only same-site path targets are accepted (`/...` but not `//host`), so the\n * preview endpoint can never be used as an open redirect.\n */\nexport function safeRedirectTarget(\n value: string | null | undefined,\n fallback = '/',\n): string | null {\n if (value === null || value === undefined || value === '') return fallback\n if (!value.startsWith('/') || value.startsWith('//')) return null\n return value\n}\n\n/**\n * Evaluate a preview-enable request. Drafts are token-gated (EC-144\n * acceptance: without the token, drafts are never reachable):\n *\n * - an unconfigured (empty) expected token rejects every request — preview\n * cannot be accidentally left open;\n * - a missing or mismatched `token` query param is a 401;\n * - an off-site `redirect` target is a 400.\n */\nexport function evaluatePreviewRequest(\n requestUrl: string | URL,\n expectedToken: string | undefined,\n): PreviewEvaluation {\n if (expectedToken === undefined || expectedToken.length === 0) {\n return { ok: false, status: 401, message: 'Draft preview is not configured.' }\n }\n\n let url: URL\n try {\n url = typeof requestUrl === 'string' ? new URL(requestUrl, 'http://localhost') : requestUrl\n } catch {\n return { ok: false, status: 400, message: 'Malformed preview request URL.' }\n }\n\n const token = url.searchParams.get('token')\n if (token !== expectedToken) {\n return { ok: false, status: 401, message: 'Invalid preview token.' }\n }\n\n const redirectTo = safeRedirectTarget(url.searchParams.get('redirect'))\n if (redirectTo === null) {\n return { ok: false, status: 400, message: 'Preview redirect target must be a same-site path.' }\n }\n\n return { ok: true, redirectTo }\n}\n","import { draftMode } from 'next/headers'\nimport { redirect } from 'next/navigation'\nimport { evaluatePreviewRequest, safeRedirectTarget } from './preview-core'\n\n/**\n * Draft preview route handlers (EC-144): Next.js `draftMode()` integration.\n * Server-only by construction — these factories are consumed from App Router\n * route handler files, never from client bundles.\n */\n\nexport interface PreviewRouteOptions {\n /**\n * The shared secret gating draft preview. An empty/undefined token means\n * every request is rejected with 401 — drafts stay unreachable until a\n * token is configured.\n */\n token: string | undefined\n}\n\n/** The shape an `app/api/.../route.ts` file re-exports. */\nexport interface PreviewRouteHandlers {\n GET(request: Request): Promise<Response>\n}\n\n/**\n * Create the preview-enable route handler for\n * `app/api/preview/route.ts`:\n *\n * ```ts\n * export const { GET } = createPreviewRoute({ token: process.env.PREVIEW_TOKEN })\n * ```\n *\n * `GET /api/preview?token=...&redirect=/some/path` checks the token, enables\n * Next draft mode (the catch-all helper then renders the `draft`\n * perspective), and redirects to the target path. Wrong/missing token → 401.\n */\nexport function createPreviewRoute(options: PreviewRouteOptions): PreviewRouteHandlers {\n return {\n async GET(request: Request): Promise<Response> {\n const evaluation = evaluatePreviewRequest(request.url, options.token)\n if (!evaluation.ok) {\n return new Response(evaluation.message, { status: evaluation.status })\n }\n const draft = await draftMode()\n draft.enable()\n redirect(evaluation.redirectTo)\n },\n }\n}\n\n/**\n * Create the preview-disable route handler (e.g.\n * `app/api/preview/disable/route.ts`). Disabling needs no token — it only\n * ever reduces visibility back to the published perspective.\n */\nexport function createPreviewDisableRoute(): PreviewRouteHandlers {\n return {\n async GET(request: Request): Promise<Response> {\n const draft = await draftMode()\n draft.disable()\n let target: string | null\n try {\n target = safeRedirectTarget(new URL(request.url).searchParams.get('redirect'))\n } catch {\n target = '/'\n }\n redirect(target ?? '/')\n },\n }\n}\n","import { draftMode } from 'next/headers'\nimport type { CollectionDef, LocaleConfig, RouteRecord } from '@elytracms/core/cms-core'\nimport type { Perspective } from '@elytracms/core/content'\nimport type { Metadata } from 'next'\nimport { defineHostComponents } from './components'\nimport type { HostComponent, HostComponents } from './components'\nimport { firstBlockFullBleed } from './full-bleed'\nimport { resolveHostEnv } from './host-env'\nimport type { ElytraHostEnv } from './host-env'\nimport { loadLiveContent } from './host-content'\nimport { resolveGlobals } from './host-globals'\nimport type { GlobalsConventions, SiteGlobals } from './host-globals'\nimport { nextImagePrimitive } from './image'\nimport type { NextImagePrimitiveOptions } from './image'\nimport { createPreviewDisableRoute, createPreviewRoute } from './preview'\nimport type { PreviewRouteHandlers } from './preview'\nimport { createRevalidateRoute } from './revalidate'\nimport type { RevalidateRouteHandlers, RevalidateRouteOptions } from './revalidate'\nimport { createCanvasRoute } from './route'\nimport type {\n CanvasCacheOptions,\n CanvasContentRequest,\n CanvasRequestInfo,\n CanvasRoute,\n} from './route'\nimport { pathFromSlug, splitLocalePath } from './route-core'\nimport type { CanvasPayloadsFactory } from './route-core'\nimport { createStaticContentSource } from './snapshot'\nimport type { ContentSource } from './source'\nimport type { CacheTags, ResolvePageResult } from '@elytracms/core/content'\n\n/**\n * The delivery host kit (EC-368): ONE factory over (env, project config) that\n * yields every engine-shaped delivery surface a Next.js host mounts — content\n * loading (live snapshot / build-safe empty / token-gated draft), the catch-all\n * canvas route, the instant-publish revalidate webhook, draft-mode plumbing,\n * chrome globals, and the full-bleed layout hint. A consumer wires env + ~5\n * lines per surface; no engine logic is ever copied into a host repo again\n * (EC-369 findings #4/#5/#6/#11).\n *\n * ```ts\n * // frontend/lib/elytra.ts — the ONE seam file\n * import { createElytraHost } from '@elytracms/next'\n * import { collections, routes } from '../../cms'\n * import { siteComponents } from '../../components'\n *\n * export const elytra = createElytraHost({\n * slug: 'my-site',\n * locales: { default: 'en', locales: ['en'] },\n * collections,\n * routes,\n * components: siteComponents,\n * })\n * ```\n *\n * ```ts\n * // app/[[...slug]]/page.tsx\n * const route = elytra.canvasRoute()\n * export default route.Page\n * export const generateMetadata = route.generateMetadata\n *\n * // app/api/revalidate/route.ts\n * export const { POST, OPTIONS } = elytra.revalidateRoute()\n *\n * // app/api/draft/route.ts — GET /api/draft?token=…&redirect=/path\n * export const { GET } = elytra.previewRoute()\n *\n * // app/api/draft/disable/route.ts\n * export const { GET } = elytra.previewDisableRoute()\n * ```\n *\n * Trust boundaries are unchanged: live surfaces read the PUBLISHED snapshot;\n * draft is reachable only through explicit Next draft mode behind the ONE\n * `DRAFT_PREVIEW_TOKEN` (which also authenticates the draft snapshot fetch —\n * see `host-env.ts`); the revalidate webhook stays HMAC-signed. The consumer\n * keeps ownership of project config (AD-11), host components, form endpoints,\n * and anything genuinely bespoke.\n */\n\nexport interface ElytraHostOptions {\n /**\n * The project slug (config-as-code identity, mirrors `elytra.config.ts`).\n * Used as the content scope when no live backend is configured.\n */\n slug: string\n /** Locale config — config-owned (AD-11), never read from the snapshot. */\n locales: LocaleConfig\n /** CMS collection schema — config-owned (AD-11). */\n collections: readonly CollectionDef[]\n /** Routes as code (AD-3/AD-11): records, or the `(collections) => records` derive. */\n routes: readonly RouteRecord[] | ((collections: CollectionDef[]) => RouteRecord[])\n /**\n * The repo's page-builder components (manifest + implementation pairs — the\n * SAME modules the studio composes with). Base primitives are always\n * included; `base.Image` is swapped for `next/image` delivery by default\n * (see `image`).\n */\n components?: readonly HostComponent[]\n /**\n * `base.Image` delivery options (loader/sizes/quality — the non-Vercel CDN\n * seam), or `false` to keep the plain-`<img>` primitive. Default: Next's own\n * optimizer, registered out of the box.\n */\n image?: NextImagePrimitiveOptions | false\n /**\n * The public base URL of the delivery site (mirrors the config's\n * `frontendUrl`) — exposed on the handle for sitemap/canonical use.\n */\n frontendUrl?: string\n /**\n * Env bag; defaults to `process.env`. Documented names (see `host-env.ts`):\n * `ELYTRA_CONVEX_URL`, `ELYTRA_PROJECT_ID`, `DRAFT_PREVIEW_TOKEN`,\n * `REVALIDATE_SECRET`, `STUDIO_ORIGIN`.\n */\n env?: Record<string, string | undefined>\n /**\n * The no-backend content fallback, used whenever `ELYTRA_CONVEX_URL` +\n * `ELYTRA_PROJECT_ID` are not both set. Default: a build-safe EMPTY source —\n * consumer CI builds green with no backend, and every URL is a clean 404\n * until content exists. The starter template overrides this with its seeded\n * in-memory world.\n */\n fallbackContent?: (request: CanvasContentRequest) => Promise<ContentSource>\n /** Chrome-globals conventions (settings/navigation collection ids, items fields). */\n globals?: GlobalsConventions\n /** Fetch implementation override for the live snapshot loader (tests, proxies). */\n fetch?: typeof globalThis.fetch\n}\n\n/** Pass-through canvas-route options the kit does not own. */\nexport interface HostCanvasRouteOptions {\n /** Extra binding payloads per request (see `CanvasRouteOptions.payloads`). */\n payloads?: CanvasPayloadsFactory\n /** Tag observation hook (see `CanvasRouteOptions.onTags`). */\n onTags?: (tags: CacheTags, info: CanvasRequestInfo) => void\n /** Metadata override (see `CanvasRouteOptions.metadata`). */\n metadata?: (result: ResolvePageResult, info: CanvasRequestInfo) => Metadata\n /**\n * Tagged data cache (instant publish). Default: enabled, scoped to the\n * kit's content scope so the studio's webhook tags match. `false` disables\n * caching entirely; an explicit `CanvasCacheOptions` overrides the scope.\n */\n cache?: CanvasCacheOptions | false\n}\n\nexport interface LoadGlobalsOptions {\n /** Perspective of the chrome read. Default `'published'` (live is published-only). */\n perspective?: Perspective\n}\n\n/** The delivery host handle {@link createElytraHost} yields. */\nexport interface ElytraHost {\n /**\n * The cache-tag scope: `ELYTRA_PROJECT_ID` in live mode (matching the\n * studio's webhook tags), else the config slug.\n */\n contentScope: string\n /** The resolved env bag (documented names, trimmed, empty = unset). */\n env: ElytraHostEnv\n /** Materialized route records (a derive is run once, at factory time). */\n routes: RouteRecord[]\n /** The registered component surface (base primitives + image swap + project components). */\n components: HostComponents\n /** The public base URL of the delivery site, when configured. */\n frontendUrl?: string\n /**\n * The content loader (the seam every kit surface reads through): live\n * delivery snapshot when env is configured — published, or the token-gated\n * draft for draft-mode requests — else the fallback source.\n */\n loadContent(request: CanvasContentRequest): Promise<ContentSource>\n /**\n * Load + resolve the site-chrome globals (settings singleton, navigation by\n * slot alias, link/asset resolution — see `host-globals.ts`). One content\n * load per call; published perspective by default.\n */\n loadGlobals(options?: LoadGlobalsOptions): Promise<SiteGlobals>\n /** The catch-all canvas route pair for `app/[[...slug]]/page.tsx`. */\n canvasRoute(options?: HostCanvasRouteOptions): CanvasRoute\n /**\n * The instant-publish webhook handlers for `app/api/revalidate/route.ts`,\n * wired to `REVALIDATE_SECRET` (+ `STUDIO_ORIGIN` CORS). Unset secret =\n * endpoint closed (401), never a default secret.\n */\n revalidateRoute(overrides?: Partial<RevalidateRouteOptions>): RevalidateRouteHandlers\n /**\n * The draft-mode ENABLE route for e.g. `app/api/draft/route.ts` —\n * `GET /api/draft?token=…&redirect=/path`, gated by the ONE\n * `DRAFT_PREVIEW_TOKEN` (the same secret the draft snapshot fetch sends, so\n * the two can never disconnect). Unset token = drafts unreachable.\n */\n previewRoute(): PreviewRouteHandlers\n /** The draft-mode DISABLE route (no token — it only reduces visibility). */\n previewDisableRoute(): PreviewRouteHandlers\n /**\n * Does the page for this catch-all `slug` OPEN full-bleed? Manifest-driven\n * (`presentation.fullBleed`, EC-368) and draft-mode aware — the host lays out\n * header clearance from data instead of a hand-kept component-id set.\n */\n pageOpensFullBleed(slug: readonly string[] | undefined): Promise<boolean>\n}\n\n/** Materialize a config `routes` value (EC-207): run a derive or copy the array. */\nfunction materializeRoutes(\n routes: ElytraHostOptions['routes'],\n collections: readonly CollectionDef[],\n): RouteRecord[] {\n return typeof routes === 'function' ? routes([...collections]) : [...routes]\n}\n\n/** Create the delivery host handle — see the module docs for the full wiring. */\nexport function createElytraHost(options: ElytraHostOptions): ElytraHost {\n const env = resolveHostEnv(options.env ?? process.env)\n const routes = materializeRoutes(options.routes, options.collections)\n const live = env.convexUrl !== undefined && env.projectId !== undefined\n const contentScope = live ? (env.projectId as string) : options.slug\n\n const components = defineHostComponents([\n // Batteries included (EC-368 image defaults): graph `base.Image` nodes render\n // through next/image — resized variants via the host's own optimizer. The\n // canonical manifest stays (first registration wins in defineHostComponents).\n ...(options.image === false ? [] : [nextImagePrimitive(options.image ?? {})]),\n ...(options.components ?? []),\n ])\n\n // The build-safe default fallback: an EMPTY source over the config's own\n // structure. Constructed once — it is fully static.\n const emptySource: ContentSource = createStaticContentSource({\n projectId: contentScope,\n locales: options.locales,\n routes,\n // Redirects are editorial DATA (EC-303) — the no-backend build has none.\n redirects: [],\n collections: [...options.collections],\n documents: [],\n assets: [],\n sources: [],\n })\n\n const loadContent = (request: CanvasContentRequest): Promise<ContentSource> => {\n if (live) {\n return loadLiveContent(\n {\n convexUrl: env.convexUrl as string,\n projectId: env.projectId as string,\n locales: options.locales,\n collections: options.collections,\n routes,\n ...(env.draftToken ? { draftToken: env.draftToken } : {}),\n ...(options.fetch ? { fetch: options.fetch } : {}),\n },\n request.perspective,\n )\n }\n if (options.fallbackContent) return options.fallbackContent(request)\n return Promise.resolve(emptySource)\n }\n\n const loadGlobals = async (globalsOptions: LoadGlobalsOptions = {}): Promise<SiteGlobals> => {\n const perspective = globalsOptions.perspective ?? 'published'\n const source = await loadContent({ perspective })\n return resolveGlobals(source, {\n perspective,\n ...(options.globals ? { conventions: options.globals } : {}),\n })\n }\n\n const canvasRoute = (routeOptions: HostCanvasRouteOptions = {}): CanvasRoute => {\n const { cache, ...rest } = routeOptions\n return createCanvasRoute({\n loadContent,\n components,\n // Tag scope = the project id the studio publishes under, so its webhook\n // tags match this site's cached entries.\n ...(cache === false ? {} : { cache: cache ?? { scope: contentScope } }),\n ...rest,\n })\n }\n\n const revalidateRoute = (\n overrides: Partial<RevalidateRouteOptions> = {},\n ): RevalidateRouteHandlers =>\n createRevalidateRoute({\n // An unset secret keeps the endpoint CLOSED (401) — the kit never ships a\n // default secret (an auth-shaped no-op is worse than an explicit gap).\n secret: 'secret' in overrides ? overrides.secret : env.revalidateSecret,\n ...(overrides.allowOrigin !== undefined\n ? { allowOrigin: overrides.allowOrigin }\n : env.studioOrigin !== undefined\n ? { allowOrigin: env.studioOrigin }\n : {}),\n })\n\n // ONE secret by construction: the preview gate and the draft snapshot fetch\n // both read env.draftToken — they cannot disconnect (EC-369 finding #4).\n const previewRoute = (): PreviewRouteHandlers => createPreviewRoute({ token: env.draftToken })\n const previewDisableRoute = (): PreviewRouteHandlers => createPreviewDisableRoute()\n\n const pageOpensFullBleed = async (slug: readonly string[] | undefined): Promise<boolean> => {\n const { isEnabled } = await draftMode()\n const perspective: Perspective = isEnabled ? 'draft' : 'published'\n const source = await loadContent({ perspective })\n const { locale, path } = splitLocalePath(pathFromSlug(slug), source.locales)\n const client = source.client({ perspective, locale })\n const resolved = client.resolvePage(path)\n return firstBlockFullBleed(resolved.document, components.registry)\n }\n\n return {\n contentScope,\n env,\n routes,\n components,\n ...(options.frontendUrl !== undefined ? { frontendUrl: options.frontendUrl } : {}),\n loadContent,\n loadGlobals,\n canvasRoute,\n revalidateRoute,\n previewRoute,\n previewDisableRoute,\n pageOpensFullBleed,\n }\n}\n","/**\n * @elytracms/next — the embedded runtime (EC-144, vision AD-1): render\n * builder-managed pages inside the user's own Next.js App Router repo with\n * the user's own components. Drop `createCanvasRoute` into a catch-all\n * route, register components with `defineHostComponents`, done.\n *\n * Nothing here imports builder-only code (no studio, no operations, no\n * TanStack) — only the runtime packages: content accessors, the component\n * registry, and the runtime renderer.\n */\nexport const PACKAGE = '@elytracms/next'\n\n// Component registration (host components + base primitives).\nexport { defineHostComponents } from './components'\nexport type { DefineHostComponentsOptions, HostComponent, HostComponents } from './components'\n\n// The server component.\nexport { CanvasRenderer, defaultBindingPayloads } from './canvas-renderer'\nexport type { CanvasRendererProps } from './canvas-renderer'\n\n// Binding payloads (embedded-runtime binding resolution). The explicit\n// source-payload issue value makes rejected stored queries render visibly.\nexport {\n createBindingResolver,\n isSourcePayloadError,\n resolvePayloadToken,\n sourcePayloadError,\n} from './payloads'\nexport type { BindingPayloads, SourcePayloadError } from './payloads'\n\n// Content source seam + cache-tag merging (EC-145/146 plug in here).\nexport { mergeCacheTags } from './source'\nexport type { CanvasDataSource, ContentSource } from './source'\n\n// EC-166 delivery: automatic payload materialization for repeating sections\n// (replayed stored queries) and template pages (the route-bound document).\nexport { collectBindingSourceIds, materializeSourcePayloads } from './source-payloads'\nexport type {\n MaterializeSourcePayloadsInput,\n MaterializedSourcePayloads,\n} from './source-payloads'\n\n// PersistenceAdapter → ContentLookup snapshot bridge, plus the plain-data\n// assembler for hosts that prefetched the content themselves (EC-156).\nexport {\n createContentSnapshot,\n createStaticContentSource,\n mergeRouteRecords,\n} from './snapshot'\nexport type { ContentSnapshot, ContentSnapshotOptions, StaticContentData } from './snapshot'\n\n// Catch-all route helper (pure core + Next wiring).\nexport { pathFromSlug, resolveCanvasPage, splitLocalePath } from './route-core'\nexport type {\n CanvasPageOutcome,\n CanvasPayloadContext,\n CanvasPayloadsFactory,\n ResolveCanvasPageOptions,\n} from './route-core'\nexport { createCanvasRoute } from './route'\nexport type {\n CanvasCacheOptions,\n CanvasContentRequest,\n CanvasRequestInfo,\n CanvasRoute,\n CanvasRouteOptions,\n CanvasRouteProps,\n} from './route'\n\n// Per-page SEO → Next metadata, and sitemap.xml from published routes (EC-171).\nexport { canvasPageMetadata } from './metadata'\nexport { canvasSitemapEntries, createCanvasSitemap } from './sitemap'\nexport type {\n CanvasSitemapOptions,\n CanvasSitemapResult,\n CreateCanvasSitemapOptions,\n SitemapParamsProvider,\n SitemapRouteContext,\n SitemapSkippedRoute,\n} from './sitemap'\n\n// Cache tags & instant publish (EC-146): tag format, tag-discovery caching,\n// and the signed revalidation webhook receiver.\nexport {\n collectionCacheTag,\n docCacheTag,\n loadCachedEntry,\n nextCacheTags,\n projectSweepTag,\n routeCacheTag,\n scopeCacheTag,\n} from './cache'\nexport type { CacheWrapper, CacheWrapperOptions, CachedEntry } from './cache'\nexport {\n REVALIDATE_SIGNATURE_HEADER,\n evaluateRevalidateRequest,\n revalidatePayloadSchema,\n signRevalidateBody,\n} from './revalidate-core'\nexport type { RevalidateEvaluation, RevalidatePayload } from './revalidate-core'\nexport { createRevalidateRoute } from './revalidate'\nexport type { RevalidateRouteHandlers, RevalidateRouteOptions } from './revalidate'\n\n// Asset-pipeline image primitive (EC-147) + the host-image renderer (EC-368):\n// the next/image-backed implementation a host registers on the\n// `@elytracms/next/host-image` bridge (the bridge itself is its OWN subpath —\n// importing it from here would bundle a second singleton instance).\nexport { ElytraImage, createAssetImageLoader, elytraHostImage, nextImagePrimitive } from './image'\nexport type {\n AssetImageLoaderOptions,\n ElytraHostImageOptions,\n ElytraImageAsset,\n ElytraImageProps,\n NextImagePrimitiveOptions,\n} from './image'\n\n// The delivery host kit (EC-368): one factory over (env, project config)\n// yielding every engine-shaped host surface — content loading, the catch-all\n// route, revalidate, draft-mode plumbing, chrome globals, layout hints.\nexport { createElytraHost } from './host-kit'\nexport type {\n ElytraHost,\n ElytraHostOptions,\n HostCanvasRouteOptions,\n LoadGlobalsOptions,\n} from './host-kit'\nexport { ELYTRA_HOST_ENV_KEYS, resolveHostEnv } from './host-env'\nexport type { ElytraHostEnv } from './host-env'\nexport { assembleLiveSource, fallbackHomeRoutes, loadLiveContent } from './host-content'\nexport type { LiveContentOptions } from './host-content'\nexport { resolveGlobals } from './host-globals'\nexport type {\n GlobalsConventions,\n ResolveGlobalsOptions,\n ResolvedLink,\n ResolvedNavEntry,\n ResolvedNavLink,\n SiteGlobals,\n} from './host-globals'\nexport { firstBlockFullBleed } from './full-bleed'\n\n// Draft preview (token-gated draftMode integration).\nexport { evaluatePreviewRequest, safeRedirectTarget } from './preview-core'\nexport type { PreviewEvaluation } from './preview-core'\nexport { createPreviewDisableRoute, createPreviewRoute } from './preview'\nexport type { PreviewRouteHandlers, PreviewRouteOptions } from './preview'\n\n// Re-exports so host apps can author manifests, declare their config, and shape\n// content WITHOUT depending on the internal packages (or on zod) directly — a\n// consuming repo installs ONLY `@elytracms/next` for delivery (EC-193).\nexport { defineComponent } from '@elytracms/core/component-registry'\n// EC-190: component props are field-defs (`PropField`), not the retired `PropSpec`.\nexport type { ComponentManifest, PropField, SlotSpec } from '@elytracms/core/component-registry'\nexport type { ComponentImplementations, RenderAsset } from '@elytracms/core/runtime-renderer'\nexport { z } from 'zod'\n\n// Config + content shapes a host declares (collections, locales, routes,\n// documents) — the public surface of the structure that lives in the repo\n// (AD-11). Re-exported here so the host imports one package (EC-193).\nexport {\n documentSchema,\n routeRecordSchema,\n redirectRecordSchema,\n localeConfigSchema,\n} from '@elytracms/core/cms-core'\nexport type {\n CollectionDef,\n CmsDocument,\n FieldDef,\n LocaleConfig,\n Locale,\n RouteRecord,\n RedirectRecord,\n} from '@elytracms/core/cms-core'\n// Composition node shape (a page document's `body` is a ComponentNode list, per AD-12).\nexport type { ComponentNode } from '@elytracms/core/project-graph'\n// The delivery perspective (draft | published).\nexport type { Perspective } from '@elytracms/core/content'\n// The delivery shape of an asset (resolved url + metadata).\nexport type { AssetRecord } from '@elytracms/core/persistence'\n"]}