@elytracms/next 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,677 +1,21 @@
1
1
  import { ComponentType, ReactNode } from 'react';
2
+ import { ComponentRegistry, ComponentIssue, ComponentManifest } from '@elytracms/component-registry';
3
+ export { ComponentManifest, PropField, SlotSpec, defineComponent } from '@elytracms/component-registry';
4
+ import { ComponentImplementations, ResolveBinding, RelationTarget } from '@elytracms/runtime-renderer';
5
+ export { ComponentImplementations, RenderAsset } from '@elytracms/runtime-renderer';
6
+ import { ResolvePageResult, ResolvedAsset, Perspective, ContentClient, CacheTags, ContentDocumentSource } from '@elytracms/content';
7
+ export { Perspective } from '@elytracms/content';
8
+ import { ProjectGraph, ComponentNode } from '@elytracms/project-graph';
9
+ export { ComponentNode, PROJECT_GRAPH_SCHEMA_VERSION, ProjectGraph, parseProjectGraph } from '@elytracms/project-graph';
10
+ import { LocaleConfig, Locale, RouteRecord, RedirectRecord, CollectionDef } from '@elytracms/cms-core';
11
+ export { CmsDocument, CollectionDef, FieldDef, Locale, LocaleConfig, RedirectRecord, RouteRecord, documentSchema, localeConfigSchema, redirectRecordSchema, routeRecordSchema } from '@elytracms/cms-core';
12
+ import { AssetRecord, PersistenceAdapter } from '@elytracms/persistence';
13
+ export { AssetRecord } from '@elytracms/persistence';
14
+ import { Metadata, MetadataRoute } from 'next';
2
15
  import { z } from 'zod';
3
16
  export { z } from 'zod';
4
- import { Metadata, MetadataRoute } from 'next';
5
17
  import { ImageLoader } from 'next/image';
6
18
 
7
- /**
8
- * A structured CMS validation issue. Same conventions as
9
- * `@elytracms/project-graph`'s `ValidationIssue`: a path locating the offending
10
- * data, optional document/collection identity, and free-form metadata.
11
- */
12
- declare const cmsValidationIssueSchema: z.ZodObject<{
13
- code: z.ZodEnum<{
14
- "duplicate-collection": "duplicate-collection";
15
- "duplicate-field": "duplicate-field";
16
- "unknown-collection": "unknown-collection";
17
- "invalid-collection-config": "invalid-collection-config";
18
- "invalid-field-config": "invalid-field-config";
19
- "missing-required-field": "missing-required-field";
20
- "invalid-field-value": "invalid-field-value";
21
- "unknown-relation-target": "unknown-relation-target";
22
- "unpublished-relation-target": "unpublished-relation-target";
23
- "cardinality-violation": "cardinality-violation";
24
- "unknown-asset": "unknown-asset";
25
- "duplicate-document": "duplicate-document";
26
- "unknown-locale": "unknown-locale";
27
- "missing-localized-value": "missing-localized-value";
28
- "route-conflict": "route-conflict";
29
- "redirect-loop": "redirect-loop";
30
- "unknown-route-target": "unknown-route-target";
31
- "hierarchy-cycle": "hierarchy-cycle";
32
- "unknown-version": "unknown-version";
33
- }>;
34
- severity: z.ZodEnum<{
35
- error: "error";
36
- warning: "warning";
37
- }>;
38
- message: z.ZodString;
39
- path: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
40
- collectionId: z.ZodOptional<z.ZodString>;
41
- documentId: z.ZodOptional<z.ZodString>;
42
- meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
43
- }, z.core.$strip>;
44
- type CmsValidationIssue = z.infer<typeof cmsValidationIssueSchema>;
45
- type CmsPath = ReadonlyArray<string | number>;
46
-
47
- /** How many related documents a relation field points at. */
48
- declare const cardinalitySchema: z.ZodEnum<{
49
- one: "one";
50
- many: "many";
51
- }>;
52
- type Cardinality = z.infer<typeof cardinalitySchema>;
53
- /** A single allowed option for a `select` field. */
54
- declare const selectOptionSchema: z.ZodObject<{
55
- value: z.ZodString;
56
- label: z.ZodOptional<z.ZodString>;
57
- }, z.core.$strip>;
58
- type SelectOption = z.infer<typeof selectOptionSchema>;
59
- /** A schema of just the shared base attributes — the source for {@link BaseFieldDef}. */
60
- declare const baseFieldObjectSchema: z.ZodObject<{
61
- name: z.ZodString;
62
- localized: z.ZodOptional<z.ZodBoolean>;
63
- filterable: z.ZodOptional<z.ZodBoolean>;
64
- context: z.ZodOptional<z.ZodEnum<{
65
- document: "document";
66
- prop: "prop";
67
- both: "both";
68
- }>>;
69
- default: z.ZodOptional<z.ZodUnknown>;
70
- form: z.ZodOptional<z.ZodObject<{
71
- label: z.ZodOptional<z.ZodString>;
72
- description: z.ZodOptional<z.ZodString>;
73
- placeholder: z.ZodOptional<z.ZodString>;
74
- group: z.ZodOptional<z.ZodString>;
75
- tab: z.ZodOptional<z.ZodString>;
76
- order: z.ZodOptional<z.ZodNumber>;
77
- readOnly: z.ZodOptional<z.ZodBoolean>;
78
- hidden: z.ZodOptional<z.ZodBoolean>;
79
- control: z.ZodOptional<z.ZodEnum<{
80
- input: "input";
81
- textarea: "textarea";
82
- color: "color";
83
- json: "json";
84
- }>>;
85
- inlineEditable: z.ZodOptional<z.ZodBoolean>;
86
- }, z.core.$strip>>;
87
- validation: z.ZodOptional<z.ZodObject<{
88
- required: z.ZodOptional<z.ZodBoolean>;
89
- min: z.ZodOptional<z.ZodNumber>;
90
- max: z.ZodOptional<z.ZodNumber>;
91
- pattern: z.ZodOptional<z.ZodString>;
92
- unique: z.ZodOptional<z.ZodBoolean>;
93
- }, z.core.$strip>>;
94
- }, z.core.$strip>;
95
- /** Attributes every field-def carries, derived from {@link baseFieldShape}. */
96
- type BaseFieldDef = z.infer<typeof baseFieldObjectSchema>;
97
- /**
98
- * A field definition (the shape {@link fieldDefSchema} parses to). Written
99
- * explicitly rather than via `z.infer` because the `object` variant is recursive
100
- * — its `fields` reference `FieldDef` itself — and TypeScript cannot infer a
101
- * self-referential `z.infer`. The schema below is annotated with this type and the
102
- * two are kept in lock-step (`object-field.test.ts` round-trips against drift).
103
- *
104
- * A discriminated union on `type` so relation/asset/select/object carry exactly
105
- * the extra config they need and nothing more.
106
- */
107
- type FieldDef = (BaseFieldDef & {
108
- type: 'text';
109
- }) | (BaseFieldDef & {
110
- type: 'number';
111
- }) | (BaseFieldDef & {
112
- type: 'boolean';
113
- }) | (BaseFieldDef & {
114
- type: 'date';
115
- }) | (BaseFieldDef & {
116
- type: 'select';
117
- options: SelectOption[];
118
- multiple?: boolean;
119
- }) | (BaseFieldDef & {
120
- type: 'richText';
121
- allow?: string[];
122
- }) | (BaseFieldDef & {
123
- type: 'relation';
124
- target: string;
125
- cardinality: Cardinality;
126
- populate?: boolean;
127
- strict?: boolean;
128
- }) | (BaseFieldDef & {
129
- type: 'asset';
130
- cardinality: Cardinality;
131
- accept?: string[];
132
- }) | (BaseFieldDef & {
133
- type: 'blocks';
134
- allow?: string[];
135
- cardinality: Cardinality;
136
- }) | (BaseFieldDef & {
137
- type: 'object';
138
- fields: FieldDef[];
139
- cardinality: Cardinality;
140
- });
141
-
142
- /**
143
- * A collection definition: an id, a kind, an ordered list of fields, and
144
- * optional form metadata. The field whose value identifies a document for
145
- * routing/display defaults to `title` when present (see `titleFieldOf`).
146
- */
147
- declare const collectionDefSchema: z.ZodObject<{
148
- id: z.ZodString;
149
- kind: z.ZodDefault<z.ZodEnum<{
150
- asset: "asset";
151
- document: "document";
152
- }>>;
153
- fields: z.ZodDefault<z.ZodArray<z.ZodType<FieldDef, unknown, z.core.$ZodTypeInternals<FieldDef, unknown>>>>;
154
- form: z.ZodOptional<z.ZodObject<{
155
- label: z.ZodOptional<z.ZodString>;
156
- labelSingular: z.ZodOptional<z.ZodString>;
157
- description: z.ZodOptional<z.ZodString>;
158
- groups: z.ZodOptional<z.ZodArray<z.ZodString>>;
159
- tabs: z.ZodOptional<z.ZodArray<z.ZodString>>;
160
- }, z.core.$strip>>;
161
- localized: z.ZodOptional<z.ZodBoolean>;
162
- titleField: z.ZodOptional<z.ZodString>;
163
- singleton: z.ZodOptional<z.ZodBoolean>;
164
- }, z.core.$strip>;
165
- type CollectionDef = z.infer<typeof collectionDefSchema>;
166
-
167
- /**
168
- * A locale code (BCP-47-ish, e.g. `en`, `en-US`, `de`). Kept as a plain
169
- * non-empty string so unusual locales still parse; validity against a project's
170
- * declared locale set is checked semantically (EC-018).
171
- */
172
- declare const localeSchema: z.ZodString;
173
- type Locale = z.infer<typeof localeSchema>;
174
- /**
175
- * A document identity (EC-017): the stable pointer to a piece of content. A
176
- * document belongs to exactly one collection and has a stable id. For localized
177
- * content the *identity* is collection+id; a specific localized variant is
178
- * addressed by additionally carrying a locale (see `LocaleAwareDocumentRef`).
179
- */
180
- declare const documentRefSchema: z.ZodObject<{
181
- collection: z.ZodString;
182
- id: z.ZodString;
183
- }, z.core.$strip>;
184
- type DocumentRef = z.infer<typeof documentRefSchema>;
185
- /**
186
- * A stored document (EC-016/017/018). The live row is the continuous DRAFT
187
- * (the Sanity model, EC-224). Holds:
188
- * - identity (`collection` + `id`),
189
- * - non-localized field values in `values`,
190
- * - per-locale field values in `localized` (only for localized fields).
191
- *
192
- * Publish-ness is NOT a field here: a document is published when an append-only
193
- * version is pinned via the record's `publishedVersion` pointer (EC-224). The
194
- * delivery `published` perspective serves that pinned snapshot; this live row
195
- * is always the working draft.
196
- */
197
- declare const documentSchema: z.ZodObject<{
198
- collection: z.ZodString;
199
- id: z.ZodString;
200
- values: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
201
- localized: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
202
- defaultLocale: z.ZodOptional<z.ZodString>;
203
- }, z.core.$strip>;
204
- type CmsDocument = z.infer<typeof documentSchema>;
205
-
206
- /**
207
- * Locale configuration for a project (EC-018): the set of supported locales and
208
- * the default used for fallback. Provider-neutral.
209
- */
210
- declare const localeConfigSchema: z.ZodObject<{
211
- default: z.ZodString;
212
- locales: z.ZodArray<z.ZodString>;
213
- }, z.core.$strip>;
214
- type LocaleConfig = z.infer<typeof localeConfigSchema>;
215
-
216
- /** A JSON-serializable value. The project graph contains only these — never functions or runtime handles. */
217
- type JsonValue = string | number | boolean | null | JsonValue[] | {
218
- [key: string]: JsonValue;
219
- };
220
-
221
- /** A pointer from the graph into a data source via a stable path token. */
222
- declare const bindingReferenceSchema: z.ZodObject<{
223
- sourceId: z.ZodString;
224
- token: z.ZodString;
225
- mode: z.ZodEnum<{
226
- object: "object";
227
- value: "value";
228
- spread: "spread";
229
- repeaterItem: "repeaterItem";
230
- condition: "condition";
231
- }>;
232
- }, z.core.$strip>;
233
- type BindingReference = z.infer<typeof bindingReferenceSchema>;
234
- /** Gates whether a node renders. The left operand is resolved from a binding. */
235
- declare const conditionSchema: z.ZodObject<{
236
- source: z.ZodObject<{
237
- sourceId: z.ZodString;
238
- token: z.ZodString;
239
- mode: z.ZodEnum<{
240
- object: "object";
241
- value: "value";
242
- spread: "spread";
243
- repeaterItem: "repeaterItem";
244
- condition: "condition";
245
- }>;
246
- }, z.core.$strip>;
247
- operator: z.ZodEnum<{
248
- truthy: "truthy";
249
- exists: "exists";
250
- eq: "eq";
251
- neq: "neq";
252
- gt: "gt";
253
- gte: "gte";
254
- lt: "lt";
255
- lte: "lte";
256
- }>;
257
- value: z.ZodOptional<z.ZodType<JsonValue, unknown, z.core.$ZodTypeInternals<JsonValue, unknown>>>;
258
- }, z.core.$strip>;
259
- type Condition = z.infer<typeof conditionSchema>;
260
-
261
- /** A prop value is either a static JSON value or a binding into a data source. */
262
- declare const propValueSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
263
- kind: z.ZodLiteral<"static">;
264
- value: z.ZodType<JsonValue, unknown, z.core.$ZodTypeInternals<JsonValue, unknown>>;
265
- }, z.core.$strip>, z.ZodObject<{
266
- kind: z.ZodLiteral<"binding">;
267
- binding: z.ZodObject<{
268
- sourceId: z.ZodString;
269
- token: z.ZodString;
270
- mode: z.ZodEnum<{
271
- object: "object";
272
- value: "value";
273
- spread: "spread";
274
- repeaterItem: "repeaterItem";
275
- condition: "condition";
276
- }>;
277
- }, z.core.$strip>;
278
- }, z.core.$strip>], "kind">;
279
- type PropValue = z.infer<typeof propValueSchema>;
280
- /**
281
- * An instance of a registered component. Recursive via `slots`: each named slot
282
- * holds an ordered list of child nodes. The reserved slot `children` is the default
283
- * insertion point.
284
- */
285
- interface ComponentNode {
286
- id: string;
287
- /** Namespaced registered component id (validated semantically, not at parse time). */
288
- componentId: string;
289
- props?: Record<string, PropValue>;
290
- slots?: Record<string, ComponentNode[]>;
291
- condition?: Condition;
292
- }
293
-
294
- /**
295
- * Schema version 2 (EC-187): the graph is LAYOUTS-ONLY. Version 1 carried a
296
- * `pages` array (page-as-graph-node); v2 removes it — a page is now a document
297
- * in the `page` collection whose `body` composition renders into a layout via
298
- * `renderCompositionInLayout`. A deployment NOT reseeded to v2 serves a null
299
- * graph, so the host degrades to its visible fallback rather than crashing.
300
- */
301
- declare const PROJECT_GRAPH_SCHEMA_VERSION = 2;
302
- /**
303
- * The canonical project graph — LAYOUTS-ONLY (EC-187). The single source of
304
- * truth for the dev-frame layout scaffolding; page content lives in the `page`
305
- * collection.
306
- */
307
- declare const projectGraphSchema: z.ZodObject<{
308
- id: z.ZodString;
309
- schemaVersion: z.ZodNumber;
310
- metadata: z.ZodOptional<z.ZodObject<{
311
- name: z.ZodOptional<z.ZodString>;
312
- }, z.core.$strip>>;
313
- settingsRef: z.ZodOptional<z.ZodString>;
314
- layouts: z.ZodDefault<z.ZodArray<z.ZodObject<{
315
- id: z.ZodString;
316
- name: z.ZodString;
317
- root: z.ZodType<ComponentNode, unknown, z.core.$ZodTypeInternals<ComponentNode, unknown>>;
318
- }, z.core.$strip>>>;
319
- }, z.core.$strip>;
320
- type ProjectGraph = z.infer<typeof projectGraphSchema>;
321
-
322
- /** A structured validation issue carrying a JSON path into the graph. */
323
- declare const validationIssueSchema: z.ZodObject<{
324
- code: z.ZodEnum<{
325
- "route-conflict": "route-conflict";
326
- "invalid-component-name": "invalid-component-name";
327
- "unknown-component": "unknown-component";
328
- "duplicate-node-id": "duplicate-node-id";
329
- "unknown-prop": "unknown-prop";
330
- "invalid-prop": "invalid-prop";
331
- "binding-not-allowed": "binding-not-allowed";
332
- "unresolved-binding": "unresolved-binding";
333
- "missing-required-slot": "missing-required-slot";
334
- "unknown-slot": "unknown-slot";
335
- "forbidden-component": "forbidden-component";
336
- "server-only-component": "server-only-component";
337
- "unknown-layout": "unknown-layout";
338
- "invalid-container-direction": "invalid-container-direction";
339
- "invalid-container-alignment": "invalid-container-alignment";
340
- "invalid-container-gap": "invalid-container-gap";
341
- "invalid-container-columns": "invalid-container-columns";
342
- "invalid-container-responsive": "invalid-container-responsive";
343
- }>;
344
- severity: z.ZodEnum<{
345
- error: "error";
346
- warning: "warning";
347
- }>;
348
- message: z.ZodString;
349
- path: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
350
- nodeId: z.ZodOptional<z.ZodString>;
351
- meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodType<JsonValue, unknown, z.core.$ZodTypeInternals<JsonValue, unknown>>>>;
352
- }, z.core.$strip>;
353
- type ValidationIssue = z.infer<typeof validationIssueSchema>;
354
-
355
- /**
356
- * Structural views of a component manifest, supplied by the registry. The graph
357
- * package depends only on these shapes (not on `@elytracms/component-registry`) so it
358
- * stays free of cycles. The registry's Manifest satisfies these structurally.
359
- */
360
- interface PropView {
361
- /** Whether this prop accepts a binding. Defaults to allowed when omitted. */
362
- bindable?: boolean;
363
- /** Optional static-value validator (typically backed by the manifest's Zod schema). */
364
- validate?: (value: unknown) => boolean;
365
- }
366
- interface SlotView {
367
- name: string;
368
- required?: boolean;
369
- /**
370
- * Allowed child component ids (EC-186). Omit to allow any registered
371
- * component; when present, a child whose `componentId` is not listed is a
372
- * `forbidden-component` error. Mirrors the registry's `SlotSpec.allow`.
373
- */
374
- allow?: readonly string[];
375
- }
376
- interface ManifestView {
377
- id: string;
378
- props?: Record<string, PropView>;
379
- slots?: SlotView[];
380
- /**
381
- * Canvas-eligibility (EC-191). `false` marks a server-only / RSC component that
382
- * is NOT client-renderable, so it may not appear in an editor composition (the
383
- * canvas is client-rendered). Omitted/true = canvas-eligible. Only enforced when
384
- * `requireCanvasEligible` is set (i.e. validating a composition value, not a
385
- * dev-authored page/layout frame).
386
- */
387
- clientRenderable?: boolean;
388
- }
389
- interface ComponentLookup {
390
- has(componentId: string): boolean;
391
- get(componentId: string): ManifestView | undefined;
392
- }
393
-
394
- type ParseResult = {
395
- ok: true;
396
- graph: ProjectGraph;
397
- } | {
398
- ok: false;
399
- error: z.ZodError;
400
- };
401
- /** Parse a project graph from a JSON string or already-parsed value. Never throws on invalid input. */
402
- declare function parseProjectGraph(input: string | unknown): ParseResult;
403
-
404
- /**
405
- * A route record (EC-019, reshaped by EC-187). A path pattern may contain
406
- * dynamic segments written `:name` (e.g. `/blog/:slug`). A route maps a concrete
407
- * URL to a **render target = a collection + document** via its `document` ref
408
- * — `/` → `{ collection: 'page', id: 'home' }`, `/blog/:slug` →
409
- * `{ collection: 'post', id: ':slug' }`. The catch-all dispatches on the
410
- * resolved document's collection. There is no `templateId`/`pageId` anymore:
411
- * page content is a `page`-collection document, not a graph page.
412
- */
413
- declare const routeRecordSchema: z.ZodObject<{
414
- id: z.ZodString;
415
- pattern: z.ZodString;
416
- locale: z.ZodOptional<z.ZodString>;
417
- document: z.ZodOptional<z.ZodObject<{
418
- collection: z.ZodString;
419
- id: z.ZodString;
420
- }, z.core.$strip>>;
421
- }, z.core.$strip>;
422
- type RouteRecord = z.infer<typeof routeRecordSchema>;
423
- /** A redirect record (EC-019/020). */
424
- declare const redirectRecordSchema: z.ZodObject<{
425
- id: z.ZodString;
426
- from: z.ZodString;
427
- to: z.ZodString;
428
- permanent: z.ZodDefault<z.ZodBoolean>;
429
- }, z.core.$strip>;
430
- type RedirectRecord = z.infer<typeof redirectRecordSchema>;
431
- /** Result of `resolveUrl` (EC-019). */
432
- type ResolveStatus = 'ok' | 'redirect' | 'notFound';
433
-
434
- /**
435
- * A snapshot of a document at a point in time (EC-021 version history). Stores a
436
- * full copy of the document's stored state plus bookkeeping. Snapshots are
437
- * immutable records of prior states.
438
- */
439
- declare const documentVersionSchema: z.ZodObject<{
440
- version: z.ZodNumber;
441
- snapshot: z.ZodObject<{
442
- collection: z.ZodString;
443
- id: z.ZodString;
444
- values: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
445
- localized: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
446
- defaultLocale: z.ZodOptional<z.ZodString>;
447
- }, z.core.$strip>;
448
- createdAt: z.ZodNumber;
449
- label: z.ZodOptional<z.ZodString>;
450
- }, z.core.$strip>;
451
- type DocumentVersion = z.infer<typeof documentVersionSchema>;
452
- /**
453
- * Draft/published primitives + version history for a single document (EC-021).
454
- *
455
- * Holds the live `draft` state, the last `published` state (if any), and an
456
- * ordered history of recorded versions. All mutations return new states or
457
- * append history; nothing is silently dropped, and retrieving an unknown
458
- * version yields a structured issue rather than throwing.
459
- */
460
- interface DocumentHistory {
461
- /** The current working draft. */
462
- readonly draft: CmsDocument;
463
- /** The last published snapshot, if the document has ever been published. */
464
- readonly published: CmsDocument | undefined;
465
- /** Recorded versions, oldest first. */
466
- readonly versions: readonly DocumentVersion[];
467
- }
468
-
469
- /** Distributive `Omit` that preserves a discriminated union (one variant per member). */
470
- type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
471
- /**
472
- * A component prop is a **field-def** (EC-190 "props as fields", AD-12): the SAME
473
- * vocabulary the CMS uses for document fields (`@elytracms/cms-core` `FieldDef`) —
474
- * text/number/boolean/select/date/relation/asset/richText/blocks — minus the
475
- * `name` (the record key on `ComponentManifest.props` IS the prop name). One
476
- * schema vocabulary, one inspector/form engine, recursively: a prop of type
477
- * `blocks` carries a nested composition. Authoring metadata (label, default,
478
- * inline-editing, control hint) lives on the field-def's `form` and `default`.
479
- * Use `context: 'prop'` (or `'both'`); document-only attributes (`filterable`,
480
- * `unique`) are flagged by cms-core's `assertPropFieldDef`, never silently honoured.
481
- */
482
- type PropField = DistributiveOmit<FieldDef, 'name'>;
483
- /** A named child insertion point. */
484
- interface SlotSpec {
485
- name: string;
486
- label?: string;
487
- required?: boolean;
488
- /** Restrict which component ids may be inserted (omit to allow any). */
489
- allow?: string[];
490
- }
491
- /** A deterministic preview fixture for a component state. */
492
- interface ComponentFixture {
493
- name: string;
494
- props?: Record<string, JsonValue>;
495
- /** Named slots rendered with literal child component ids for preview. */
496
- slotChildren?: Record<string, string[]>;
497
- }
498
- /** Declares that a component iterates a list prop over an item slot (e.g. Repeater). */
499
- interface IterateSpec {
500
- itemsProp: string;
501
- itemSlot: string;
502
- }
503
- /**
504
- * Declares that a component renders a composition FIELD VALUE (EC-188, AD-12): the
505
- * `valueProp` carries a stored composition (one `ComponentNode` root or an ordered
506
- * list — a `blocks` field's value), which the renderer renders as the component's
507
- * children via `renderComposition`, with the live `RenderContext`. The mirror of
508
- * `IterateSpec`: a manifest opts a host component into rendering a composition tree
509
- * wherever it is placed (e.g. a post template's body), so the same renderer/export
510
- * pipeline that renders pages renders block fields too.
511
- */
512
- interface CompositionSpec {
513
- valueProp: string;
514
- }
515
- /**
516
- * Declares that a component renders a LISTING — a live, query-resolved set of
517
- * documents (EC-255, un-parks AD-9 "this section repeats over a collection,
518
- * filtered, sorted"). The `prop` receives the matching documents (delivery-shaped),
519
- * injected by the host exactly like a composition's children — NOT a static
520
- * relation pick the editor maintains by hand. The filter binds the listed
521
- * collection's `field` to the ref a SIBLING authored prop (`fromProp`) carries:
522
- * a ProductGrid picks one `category`, and the listing lists `product` where its
523
- * `categories` (a `many` relation) contains that pick. `sort`/`limit` are the
524
- * closed AD-3 query envelope. The mirror of {@link CompositionSpec} for a
525
- * query-resolved prop — so the same renderer/export pipeline that renders pages
526
- * renders dynamic grids, and adding/removing a member re-renders them.
527
- */
528
- interface ListingSpec {
529
- /** Prop the resolved documents are injected as (read by the implementation). */
530
- prop: string;
531
- /** Collection to list (e.g. `product`). */
532
- collection: string;
533
- /**
534
- * The membership filter: the listed collection's `field` must contain the ref
535
- * the sibling authored prop `fromProp` holds (a relation pick, reduced to its
536
- * target id). Closed to a single equality/contains term — the AD-3 vocabulary.
537
- */
538
- filter: {
539
- field: string;
540
- fromProp: string;
541
- };
542
- /** Optional single-field sort (ties break by id, like every list — EC-143). */
543
- sort?: {
544
- field: string;
545
- direction?: 'asc' | 'desc';
546
- };
547
- /** Optional page-size cap. */
548
- limit?: number;
549
- }
550
- /** The typed manifest each editable component declares (brief §7.2). */
551
- interface ComponentManifest {
552
- /** Namespaced id, e.g. `base.primitives.Stack` or `project.MarketingHero`. */
553
- id: string;
554
- /** Source namespace: `base.primitives` for platform primitives, `project` for project code. */
555
- namespace: string;
556
- title?: string;
557
- description?: string;
558
- category?: string;
559
- /** Editable props as field-defs (EC-190), keyed by prop name. */
560
- props: Record<string, PropField>;
561
- slots: SlotSpec[];
562
- /** Design-token usage hints (e.g. `['color.surface', 'space.gap']`). */
563
- designTokens?: string[];
564
- fixtures?: ComponentFixture[];
565
- iterate?: IterateSpec;
566
- /** Marks the component as a composition host: `valueProp` holds a block-field tree (EC-188). */
567
- composition?: CompositionSpec;
568
- /** Marks the component as a listing host: `prop` receives a live query's documents (EC-255). */
569
- listing?: ListingSpec;
570
- /**
571
- * Canvas-eligibility (EC-191). Editors place components on a **client-rendered**
572
- * canvas, so a placeable component must be client-renderable (isomorphic React).
573
- * Defaults to eligible; set `clientRenderable: false` for a server-only / RSC
574
- * component — it stays usable in dev frames (`page.tsx` / `layout.tsx`) but the
575
- * blocks panel won't offer it and a composition that contains it is invalid.
576
- */
577
- clientRenderable?: boolean;
578
- }
579
- /** Identity helper that infers nothing but documents intent at call sites. */
580
- declare function defineComponent(manifest: ComponentManifest): ComponentManifest;
581
-
582
- /** Structured issues surfaced by the registry itself (distinct from graph issues). */
583
- interface ComponentIssue {
584
- code: 'duplicate-id' | 'invalid-namespace' | 'invalid-id';
585
- componentId: string;
586
- message: string;
587
- }
588
-
589
- interface ListFilter {
590
- namespace?: string;
591
- category?: string;
592
- /** Case-insensitive substring match over id / title / category. */
593
- query?: string;
594
- }
595
- /**
596
- * The component registry serves the Builder, renderer, AI tools, export pipeline, and
597
- * CLI. It distinguishes platform primitives from project components, supports lookup,
598
- * filtering, required lookups, and reports duplicate ids as structured issues.
599
- */
600
- declare class ComponentRegistry {
601
- private readonly byId;
602
- private readonly viewCache;
603
- readonly issues: ComponentIssue[];
604
- constructor(manifests?: Iterable<ComponentManifest>);
605
- register(manifest: ComponentManifest): void;
606
- has(id: string): boolean;
607
- getManifest(id: string): ComponentManifest | undefined;
608
- /** Required lookup — throws when the component is not registered. */
609
- require(id: string): ComponentManifest;
610
- list(filter?: ListFilter): ComponentManifest[];
611
- /** Platform primitives (`base.primitives.*`). */
612
- primitives(): ComponentManifest[];
613
- /** Project-level components (everything not under `base.primitives.*`). */
614
- projectComponents(): ComponentManifest[];
615
- get size(): number;
616
- /** A `ComponentLookup` view for the project-graph validator. */
617
- get lookup(): ComponentLookup;
618
- }
619
-
620
- /**
621
- * A single repeater item scope. When set, `repeaterItem`-mode bindings resolve against
622
- * `item` rather than the root data source (brief §4.6 — uniform binding model).
623
- */
624
- interface ItemContext {
625
- item: unknown;
626
- index: number;
627
- }
628
- /**
629
- * Resolves a binding to a runtime value. INJECTED by the host (builder preview, export
630
- * runtime, tests) so the renderer never imports `@elytracms/data-binding`. When an
631
- * `ItemContext` is active, it is passed through so `repeaterItem` bindings resolve
632
- * relative to the current item.
633
- */
634
- type ResolveBinding = (ref: BindingReference, item?: ItemContext) => unknown;
635
- /**
636
- * A resolved asset, ready to hand to an image implementation (EC-195). The
637
- * delivery-shaped subset of `@elytracms/content`'s `ResolvedAsset` the renderer
638
- * needs — kept minimal so the renderer takes no dependency on the content or
639
- * persistence packages. `width`/`height` are intrinsic dimensions (so the host
640
- * can reserve space and `next/image` can size variants); `null` when unknown.
641
- */
642
- interface RenderAsset {
643
- url: string;
644
- width: number | null;
645
- height: number | null;
646
- alt: string | null;
647
- /**
648
- * Normalized focal point `{ x, y }` in 0–1 (EC-230) → CSS `object-position` so
649
- * an art-directed image keeps its subject in frame when cropped; `null` when
650
- * none. Kept as a plain pair so the renderer stays free of content/persistence.
651
- */
652
- focalPoint: {
653
- x: number;
654
- y: number;
655
- } | null;
656
- }
657
- /**
658
- * A relation target populated to delivery shape (EC-254): identity plus the
659
- * target document's resolved fields (relations inside stay `{ id, collection }`
660
- * stubs at depth-1; assets inside resolve to objects). Opaque to the renderer —
661
- * the host's content layer produces it, the component implementation reads its
662
- * fields. The minimal structural face is `{ id, collection }`.
663
- */
664
- type RelationTarget = {
665
- id: string;
666
- collection: string;
667
- } & Record<string, unknown>;
668
- /**
669
- * Maps namespaced component ids to their React implementations. Implementations receive
670
- * resolved props plus rendered slot children: the default slot `children` maps to React
671
- * `children`, and every other named slot is passed as a prop named after the slot.
672
- */
673
- type ComponentImplementations = Record<string, ComponentType<Record<string, unknown>>> | Map<string, ComponentType<Record<string, unknown>>>;
674
-
675
19
  /**
676
20
  * One host-repo component: the manifest the builder edits against plus the
677
21
  * real React implementation that renders it (vision AD-2 — project components
@@ -710,884 +54,6 @@ interface DefineHostComponentsOptions {
710
54
  */
711
55
  declare function defineHostComponents(components?: readonly HostComponent[], options?: DefineHostComponentsOptions): HostComponents;
712
56
 
713
- /**
714
- * Which side of the draft/published split a delivery request reads from
715
- * (EC-021, vision AD-4). `published` never exposes draft content; `draft` is
716
- * the editor/preview view.
717
- */
718
- declare const perspectiveSchema: z.ZodEnum<{
719
- draft: "draft";
720
- published: "published";
721
- }>;
722
- type Perspective = z.infer<typeof perspectiveSchema>;
723
- /**
724
- * Ambient request context (vision AD-4): locale and perspective are set once
725
- * per request and threaded through every resolution function — never per-call
726
- * ceremony. The locale config travels along so EC-018 fallback needs no extra
727
- * arguments either.
728
- */
729
- interface ContentContext {
730
- /** The locale requested for this delivery (EC-018 fallback applies). */
731
- readonly locale: Locale;
732
- /** Draft or published perspective (EC-021). */
733
- readonly perspective: Perspective;
734
- /** The project's locale configuration (default + supported set). */
735
- readonly locales: LocaleConfig;
736
- }
737
-
738
- /**
739
- * What delivery resolution accepts as a document source: either a bare stored
740
- * row (`CmsDocument`, always a working draft — EC-224 retired the `state` flag)
741
- * or the full draft/published history (`DocumentHistory`, EC-021) whose
742
- * `published` field carries the pinned snapshot. Lookups hand these in;
743
- * resolution stays pure — no fetching at this layer.
744
- */
745
- type ContentDocumentSource = CmsDocument | DocumentHistory;
746
-
747
- /**
748
- * A report entry for one field whose value was served from a different locale
749
- * than the one requested (EC-018 default-locale fallback). Paths are rooted at
750
- * the resolved document, e.g. `['title']` or `['author', 'bio']` for a field
751
- * inside a populated relation.
752
- */
753
- interface FieldLocaleFallback {
754
- path: CmsPath;
755
- /** The field name (last path segment, repeated for convenience). */
756
- field: string;
757
- /** The locale the request asked for. */
758
- requestedLocale: Locale;
759
- /** The locale the value was actually read from. */
760
- sourceLocale: Locale;
761
- }
762
-
763
- /**
764
- * Which backend a persistence adapter is talking to, and whether it's reachable.
765
- * Lets the Studio surface degraded/offline states without leaking provider types.
766
- */
767
- declare const backendKindSchema: z.ZodEnum<{
768
- convex: "convex";
769
- "in-memory": "in-memory";
770
- }>;
771
- type BackendKind = z.infer<typeof backendKindSchema>;
772
- interface BackendStatus {
773
- backend: BackendKind;
774
- available: boolean;
775
- detail?: string;
776
- }
777
-
778
- /**
779
- * An immutable record of one saved graph state (brief §7.1, §10). Each save
780
- * appends a revision; the highest revision is the latest. The graph is stored
781
- * serialized so reload is provably lossless (serialize → parse round-trip).
782
- */
783
- declare const graphRevisionRecordSchema: z.ZodObject<{
784
- id: z.ZodString;
785
- projectId: z.ZodString;
786
- revision: z.ZodNumber;
787
- serializedGraph: z.ZodString;
788
- schemaVersion: z.ZodNumber;
789
- createdAt: z.ZodString;
790
- label: z.ZodOptional<z.ZodString>;
791
- message: z.ZodOptional<z.ZodString>;
792
- }, z.core.$strip>;
793
- type GraphRevisionRecord = z.infer<typeof graphRevisionRecordSchema>;
794
- /** A revision paired with its parsed graph. */
795
- interface LoadedGraph {
796
- graph: ProjectGraph;
797
- revision: GraphRevisionRecord;
798
- }
799
- interface SaveGraphOptions {
800
- label?: string;
801
- message?: string;
802
- }
803
- /**
804
- * Persists project graphs and their revision history (brief §7.1, §10).
805
- * Provider-neutral: an in-memory and a Convex implementation both satisfy it.
806
- */
807
- interface GraphRepository {
808
- /** Append a new revision for the project's graph and return it. */
809
- saveGraph(projectId: string, graph: ProjectGraph, options?: SaveGraphOptions): Promise<GraphRevisionRecord>;
810
- /** Load the latest graph + revision. Throws `RecordNotFoundError` if none. */
811
- getLatest(projectId: string): Promise<LoadedGraph>;
812
- /** Load a specific revision. Throws `RecordNotFoundError` if absent. */
813
- getRevision(projectId: string, revision: number): Promise<LoadedGraph>;
814
- /** All revisions for a project, newest first. */
815
- listRevisions(projectId: string): Promise<GraphRevisionRecord[]>;
816
- /** Whether any graph revision exists for the project. */
817
- hasGraph(projectId: string): Promise<boolean>;
818
- }
819
-
820
- /** The persisted CMS schema for a project: its collection definitions (brief §7.4, §10). */
821
- declare const cmsSchemaRecordSchema: z.ZodObject<{
822
- createdAt: z.ZodString;
823
- updatedAt: z.ZodString;
824
- projectId: z.ZodString;
825
- collections: z.ZodArray<z.ZodObject<{
826
- id: z.ZodString;
827
- kind: z.ZodDefault<z.ZodEnum<{
828
- asset: "asset";
829
- document: "document";
830
- }>>;
831
- fields: z.ZodDefault<z.ZodArray<z.ZodType<FieldDef, unknown, z.core.$ZodTypeInternals<FieldDef, unknown>>>>;
832
- form: z.ZodOptional<z.ZodObject<{
833
- label: z.ZodOptional<z.ZodString>;
834
- labelSingular: z.ZodOptional<z.ZodString>;
835
- description: z.ZodOptional<z.ZodString>;
836
- groups: z.ZodOptional<z.ZodArray<z.ZodString>>;
837
- tabs: z.ZodOptional<z.ZodArray<z.ZodString>>;
838
- }, z.core.$strip>>;
839
- localized: z.ZodOptional<z.ZodBoolean>;
840
- titleField: z.ZodOptional<z.ZodString>;
841
- singleton: z.ZodOptional<z.ZodBoolean>;
842
- }, z.core.$strip>>;
843
- }, z.core.$strip>;
844
- type CmsSchemaRecord = z.infer<typeof cmsSchemaRecordSchema>;
845
- /**
846
- * A persisted CMS document. The stored `document` is the continuous working
847
- * **draft** (every edit updates it); `publishedVersion` pins which recorded
848
- * version is currently live (the Sanity draft/published model, EC-224). Absent
849
- * `publishedVersion` means the document has never been published / is unpublished.
850
- * Localized variants ride along on the `CmsDocument` itself.
851
- */
852
- declare const cmsDocumentRecordSchema: z.ZodObject<{
853
- createdAt: z.ZodString;
854
- updatedAt: z.ZodString;
855
- projectId: z.ZodString;
856
- document: z.ZodObject<{
857
- collection: z.ZodString;
858
- id: z.ZodString;
859
- values: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
860
- localized: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
861
- defaultLocale: z.ZodOptional<z.ZodString>;
862
- }, z.core.$strip>;
863
- publishedVersion: z.ZodOptional<z.ZodNumber>;
864
- }, z.core.$strip>;
865
- type CmsDocumentRecord = z.infer<typeof cmsDocumentRecordSchema>;
866
- /**
867
- * An immutable snapshot of a document at one recorded version (EC-224). Append-only,
868
- * mirroring {@link GraphRevisionRecord} but document-scoped: one row per version,
869
- * keyed by (projectId, collection, docId, version). Created on publish (the promoted
870
- * draft) and by an explicit pre-restore snapshot, never on a plain draft edit.
871
- */
872
- declare const documentVersionRecordSchema: z.ZodObject<{
873
- projectId: z.ZodString;
874
- collection: z.ZodString;
875
- docId: z.ZodString;
876
- version: z.ZodNumber;
877
- snapshot: z.ZodObject<{
878
- collection: z.ZodString;
879
- id: z.ZodString;
880
- values: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
881
- localized: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
882
- defaultLocale: z.ZodOptional<z.ZodString>;
883
- }, z.core.$strip>;
884
- createdAt: z.ZodString;
885
- label: z.ZodOptional<z.ZodString>;
886
- }, z.core.$strip>;
887
- type DocumentVersionRecord = z.infer<typeof documentVersionRecordSchema>;
888
- interface SaveDocumentVersionOptions {
889
- label?: string;
890
- }
891
- /**
892
- * Persists CMS collection schemas and documents (brief §7.4, §10). Localized
893
- * variants and draft/published state ride along on the `CmsDocument` itself.
894
- */
895
- interface CmsRepository {
896
- /** Persist (replace) the project's collection schema; validates structural shape. */
897
- saveSchema(projectId: string, collections: readonly CollectionDef[]): Promise<CmsSchemaRecord>;
898
- getSchema(projectId: string): Promise<CmsSchemaRecord>;
899
- findSchema(projectId: string): Promise<CmsSchemaRecord | undefined>;
900
- /** Insert or update a document (keyed by collection + id). */
901
- upsertDocument(projectId: string, document: CmsDocument): Promise<CmsDocumentRecord>;
902
- getDocument(projectId: string, ref: DocumentRef): Promise<CmsDocumentRecord>;
903
- findDocument(projectId: string, ref: DocumentRef): Promise<CmsDocumentRecord | undefined>;
904
- /** All documents for a project, optionally filtered to one collection. */
905
- listDocuments(projectId: string, collection?: string): Promise<CmsDocumentRecord[]>;
906
- deleteDocument(projectId: string, ref: DocumentRef): Promise<void>;
907
- /**
908
- * Append a snapshot of a document as a new monotonic version (EC-224). Used by
909
- * publish (the promoted draft) and the pre-restore snapshot so a rollback is
910
- * itself undoable. The (collection, docId) is derived from the snapshot.
911
- */
912
- saveDocumentVersion(projectId: string, snapshot: CmsDocument, options?: SaveDocumentVersionOptions): Promise<DocumentVersionRecord>;
913
- /** All recorded versions for a document, newest first. Empty when none. */
914
- listDocumentVersions(projectId: string, ref: DocumentRef): Promise<DocumentVersionRecord[]>;
915
- /**
916
- * Every recorded version across all documents in a project (EC-224). Backs the
917
- * delivery feeders, which reconstruct each document's `DocumentHistory` from
918
- * one bulk fetch rather than a per-document query. Order is deterministic
919
- * (by document key, then version ascending).
920
- */
921
- listAllDocumentVersions(projectId: string): Promise<DocumentVersionRecord[]>;
922
- /** A specific recorded version. Throws `RecordNotFoundError` if absent. */
923
- getDocumentVersion(projectId: string, ref: DocumentRef, version: number): Promise<DocumentVersionRecord>;
924
- /**
925
- * Pin an existing recorded version live (EC-224 publish). Throws
926
- * `RecordNotFoundError` if the document or the version is unknown.
927
- */
928
- publishDocumentVersion(projectId: string, ref: DocumentRef, version: number): Promise<CmsDocumentRecord>;
929
- /**
930
- * Clear the live pin (EC-224 unpublish). Throws `PersistenceValidationError`
931
- * if the document is not currently published.
932
- */
933
- unpublishDocument(projectId: string, ref: DocumentRef): Promise<CmsDocumentRecord>;
934
- }
935
-
936
- /**
937
- * Persisted asset metadata (brief §7.4, §8.6, §10). The bytes themselves live in
938
- * a {@link BlobStorageAdapter}; this record is the queryable metadata that CMS
939
- * `asset` fields point at by id.
940
- */
941
- declare const assetRecordSchema: z.ZodObject<{
942
- createdAt: z.ZodString;
943
- updatedAt: z.ZodString;
944
- id: z.ZodString;
945
- projectId: z.ZodString;
946
- filename: z.ZodString;
947
- contentType: z.ZodString;
948
- byteSize: z.ZodNumber;
949
- width: z.ZodOptional<z.ZodNumber>;
950
- height: z.ZodOptional<z.ZodNumber>;
951
- alt: z.ZodOptional<z.ZodString>;
952
- title: z.ZodOptional<z.ZodString>;
953
- storageKey: z.ZodString;
954
- url: z.ZodOptional<z.ZodString>;
955
- focalPoint: z.ZodOptional<z.ZodObject<{
956
- x: z.ZodNumber;
957
- y: z.ZodNumber;
958
- }, z.core.$strip>>;
959
- }, z.core.$strip>;
960
- type AssetRecord = z.infer<typeof assetRecordSchema>;
961
- interface NewAssetInput {
962
- id?: string;
963
- filename: string;
964
- contentType: string;
965
- byteSize: number;
966
- width?: number;
967
- height?: number;
968
- alt?: string;
969
- /** Editable display title (EC-152 asset library metadata). */
970
- title?: string;
971
- /** Defaults to a key derived from the asset id. */
972
- storageKey?: string;
973
- /** Resolvable serve URL for the stored bytes (EC-151). */
974
- url?: string;
975
- /** Normalized image focal point `{ x, y }` in 0–1 (EC-230). */
976
- focalPoint?: {
977
- x: number;
978
- y: number;
979
- };
980
- }
981
- /**
982
- * Storage boundary for asset *bytes* (brief §8.6). Project-owned and swappable
983
- * (Convex file storage, S3, etc.); the in-memory implementation backs tests and
984
- * local inspection. Metadata stays in the {@link AssetRepository}.
985
- */
986
- interface BlobStorageAdapter {
987
- put(key: string, data: Uint8Array, contentType?: string): Promise<void>;
988
- get(key: string): Promise<Uint8Array | undefined>;
989
- /** A resolvable locator for the blob (e.g. a CDN/file URL). */
990
- url(key: string): string;
991
- has(key: string): Promise<boolean>;
992
- delete(key: string): Promise<void>;
993
- /**
994
- * Store bytes under a backend-assigned key and return it (EC-151). Backends
995
- * like Convex file storage mint their own ids, so callers cannot choose the
996
- * key up front the way {@link put} assumes. Optional; in-memory implements it
997
- * deterministically.
998
- */
999
- store?(data: Uint8Array, contentType?: string): Promise<string>;
1000
- /**
1001
- * Mint a short-lived URL the client can POST bytes to directly (EC-151,
1002
- * Convex `storage.generateUploadUrl()`). Optional — backends without
1003
- * client-direct uploads omit it and callers fall back to {@link store}/{@link put}.
1004
- */
1005
- createUploadUrl?(): Promise<string>;
1006
- /**
1007
- * Resolve the serve URL for a stored blob asynchronously (EC-151, Convex
1008
- * `storage.getUrl()`). Returns `undefined` when the blob does not exist.
1009
- * Optional; backends with synchronous stable URLs can rely on {@link url}.
1010
- */
1011
- resolveUrl?(key: string): Promise<string | undefined>;
1012
- }
1013
- /** Persists asset metadata records (brief §7.4, §8.6, §10). */
1014
- interface AssetRepository {
1015
- upsertAsset(projectId: string, input: NewAssetInput): Promise<AssetRecord>;
1016
- getAsset(projectId: string, id: string): Promise<AssetRecord>;
1017
- findAsset(projectId: string, id: string): Promise<AssetRecord | undefined>;
1018
- listAssets(projectId: string): Promise<AssetRecord[]>;
1019
- removeAsset(projectId: string, id: string): Promise<void>;
1020
- /** Resolve persisted metadata for the asset ids referenced by CMS fields. */
1021
- resolveMany(projectId: string, ids: readonly string[]): Promise<Map<string, AssetRecord>>;
1022
- }
1023
-
1024
- /**
1025
- * Publishing state (brief §10). Single-environment (EC-179, vision AD-8): a
1026
- * deployment IS one environment, so there is exactly ONE publishing-state
1027
- * record per project. A `published` record pins the graph revision that is
1028
- * live. Moving a release between environments is a deployment/code-pipeline
1029
- * concern, not an in-deployment dimension — see `env-is-deployment-boundary`.
1030
- */
1031
- declare const publishingStateRecordSchema: z.ZodObject<{
1032
- createdAt: z.ZodString;
1033
- updatedAt: z.ZodString;
1034
- projectId: z.ZodString;
1035
- status: z.ZodEnum<{
1036
- draft: "draft";
1037
- published: "published";
1038
- }>;
1039
- publishedRevisionId: z.ZodOptional<z.ZodString>;
1040
- publishedRevision: z.ZodOptional<z.ZodNumber>;
1041
- publishedAt: z.ZodOptional<z.ZodString>;
1042
- }, z.core.$strip>;
1043
- type PublishingStateRecord = z.infer<typeof publishingStateRecordSchema>;
1044
- interface PublishInput {
1045
- revisionId: string;
1046
- revision: number;
1047
- }
1048
- /**
1049
- * Persists and transitions publishing state (brief §10). Transitions are
1050
- * validated: publishing requires a revision; unpublishing requires a
1051
- * currently-published deployment.
1052
- */
1053
- interface PublishingRepository {
1054
- getState(projectId: string): Promise<PublishingStateRecord>;
1055
- findState(projectId: string): Promise<PublishingStateRecord | undefined>;
1056
- /** Publish a graph revision. */
1057
- publish(projectId: string, input: PublishInput): Promise<PublishingStateRecord>;
1058
- /** Revert to draft (must currently be published). */
1059
- unpublish(projectId: string): Promise<PublishingStateRecord>;
1060
- }
1061
-
1062
- /**
1063
- * Reference-index substrate (EC-155, vision AD-6 / pillar 3.6).
1064
- *
1065
- * On every write the operations layer extracts *outbound* references — relation
1066
- * fields, rich-text link marks and inline refs, page-graph bindings and
1067
- * component usage, asset usages — into this index, for draft and published
1068
- * variants separately. One index powers many features: "used by" panels, safe
1069
- * unpublish (the queryable answer to Sanity's hidden-draft-reference failure),
1070
- * component/asset where-used, and broken-link audits (UX lands in Milestone B).
1071
- *
1072
- * Records are **derived data**: they carry no timestamps and are deterministic
1073
- * functions of the indexed content, so backfill is idempotent and two runs over
1074
- * the same data are byte-for-byte identical.
1075
- */
1076
- /** Which content variant an entry was extracted from (the Sanity failure-case axis). */
1077
- declare const referenceVariantSchema: z.ZodEnum<{
1078
- draft: "draft";
1079
- published: "published";
1080
- }>;
1081
- type ReferenceVariant = z.infer<typeof referenceVariantSchema>;
1082
- /**
1083
- * What kind of entity *holds* the reference. Documents are keyed by their
1084
- * `documentKey` (`collection:id`); pages/layouts by their graph ids.
1085
- */
1086
- declare const referenceSourceTypeSchema: z.ZodEnum<{
1087
- document: "document";
1088
- page: "page";
1089
- layout: "layout";
1090
- }>;
1091
- type ReferenceSourceType = z.infer<typeof referenceSourceTypeSchema>;
1092
- declare const referenceSourceSchema: z.ZodObject<{
1093
- type: z.ZodEnum<{
1094
- document: "document";
1095
- page: "page";
1096
- layout: "layout";
1097
- }>;
1098
- id: z.ZodString;
1099
- }, z.core.$strip>;
1100
- type ReferenceSource = z.infer<typeof referenceSourceSchema>;
1101
- declare const referenceTargetSchema: z.ZodObject<{
1102
- type: z.ZodEnum<{
1103
- asset: "asset";
1104
- document: "document";
1105
- component: "component";
1106
- }>;
1107
- id: z.ZodString;
1108
- }, z.core.$strip>;
1109
- type ReferenceTarget = z.infer<typeof referenceTargetSchema>;
1110
- /**
1111
- * One outbound reference found *inside* a source, before it is attributed to
1112
- * that source: the exact field/node path, the target, and which structure
1113
- * produced it. `path` is a `/`-joined token path into the stored value, e.g.
1114
- * `values/author`, `localized/en/body/doc/content/0/marks/0`,
1115
- * `root/slots/children/2/props/items/binding`.
1116
- */
1117
- declare const outboundReferenceSchema: z.ZodObject<{
1118
- path: z.ZodString;
1119
- target: z.ZodObject<{
1120
- type: z.ZodEnum<{
1121
- asset: "asset";
1122
- document: "document";
1123
- component: "component";
1124
- }>;
1125
- id: z.ZodString;
1126
- }, z.core.$strip>;
1127
- kind: z.ZodEnum<{
1128
- "relation-field": "relation-field";
1129
- "asset-field": "asset-field";
1130
- "rich-text-link": "rich-text-link";
1131
- "rich-text-node": "rich-text-node";
1132
- "component-usage": "component-usage";
1133
- "prop-binding": "prop-binding";
1134
- "condition-binding": "condition-binding";
1135
- }>;
1136
- }, z.core.$strip>;
1137
- type OutboundReference = z.infer<typeof outboundReferenceSchema>;
1138
- /** An outbound reference attributed to its holding source entity. */
1139
- declare const referenceEntrySchema: z.ZodObject<{
1140
- path: z.ZodString;
1141
- target: z.ZodObject<{
1142
- type: z.ZodEnum<{
1143
- asset: "asset";
1144
- document: "document";
1145
- component: "component";
1146
- }>;
1147
- id: z.ZodString;
1148
- }, z.core.$strip>;
1149
- kind: z.ZodEnum<{
1150
- "relation-field": "relation-field";
1151
- "asset-field": "asset-field";
1152
- "rich-text-link": "rich-text-link";
1153
- "rich-text-node": "rich-text-node";
1154
- "component-usage": "component-usage";
1155
- "prop-binding": "prop-binding";
1156
- "condition-binding": "condition-binding";
1157
- }>;
1158
- source: z.ZodObject<{
1159
- type: z.ZodEnum<{
1160
- document: "document";
1161
- page: "page";
1162
- layout: "layout";
1163
- }>;
1164
- id: z.ZodString;
1165
- }, z.core.$strip>;
1166
- }, z.core.$strip>;
1167
- type ReferenceEntry = z.infer<typeof referenceEntrySchema>;
1168
- /** The persisted index record: entry + project + variant. Derived, timestamp-free. */
1169
- declare const referenceEntryRecordSchema: z.ZodObject<{
1170
- path: z.ZodString;
1171
- target: z.ZodObject<{
1172
- type: z.ZodEnum<{
1173
- asset: "asset";
1174
- document: "document";
1175
- component: "component";
1176
- }>;
1177
- id: z.ZodString;
1178
- }, z.core.$strip>;
1179
- kind: z.ZodEnum<{
1180
- "relation-field": "relation-field";
1181
- "asset-field": "asset-field";
1182
- "rich-text-link": "rich-text-link";
1183
- "rich-text-node": "rich-text-node";
1184
- "component-usage": "component-usage";
1185
- "prop-binding": "prop-binding";
1186
- "condition-binding": "condition-binding";
1187
- }>;
1188
- source: z.ZodObject<{
1189
- type: z.ZodEnum<{
1190
- document: "document";
1191
- page: "page";
1192
- layout: "layout";
1193
- }>;
1194
- id: z.ZodString;
1195
- }, z.core.$strip>;
1196
- projectId: z.ZodString;
1197
- variant: z.ZodEnum<{
1198
- draft: "draft";
1199
- published: "published";
1200
- }>;
1201
- }, z.core.$strip>;
1202
- type ReferenceEntryRecord = z.infer<typeof referenceEntryRecordSchema>;
1203
- interface ReferenceLookupOptions {
1204
- /** Restrict the lookup to one variant; omit for both (draft + published). */
1205
- variant?: ReferenceVariant;
1206
- }
1207
- /**
1208
- * Persists the reference index (EC-155). Writes are **replace-all-for-source**:
1209
- * saving an entity recomputes every outbound reference it holds and replaces the
1210
- * previous set atomically, so edits/deletes/unpublishes can never leave stale
1211
- * entries behind. Lookups work in both directions with field/node-path
1212
- * granularity and are variant-aware.
1213
- */
1214
- interface ReferenceIndexRepository {
1215
- /**
1216
- * Replace all entries held by `source` in `variant` with the given outbound
1217
- * references. An empty list removes the source's entries entirely.
1218
- */
1219
- replaceForSource(projectId: string, variant: ReferenceVariant, source: ReferenceSource, references: readonly OutboundReference[]): Promise<ReferenceEntryRecord[]>;
1220
- /**
1221
- * Replace all entries held by sources of the given types in `variant` (the
1222
- * graph recompute path: one revision yields entries across many pages/layouts,
1223
- * and pages removed from the graph must drop their entries too).
1224
- */
1225
- replaceForSourceTypes(projectId: string, variant: ReferenceVariant, sourceTypes: readonly ReferenceSourceType[], entries: readonly ReferenceEntry[]): Promise<ReferenceEntryRecord[]>;
1226
- /** Remove all entries held by `source` (in one variant, or both when omitted). */
1227
- removeForSource(projectId: string, source: ReferenceSource, variant?: ReferenceVariant): Promise<void>;
1228
- /** Outbound: what does `source` reference? */
1229
- outbound(projectId: string, source: ReferenceSource, options?: ReferenceLookupOptions): Promise<ReferenceEntryRecord[]>;
1230
- /** Inbound: what references `target`? (The "used by" / safe-unpublish direction.) */
1231
- inbound(projectId: string, target: ReferenceTarget, options?: ReferenceLookupOptions): Promise<ReferenceEntryRecord[]>;
1232
- /** Every entry of a project (optionally one variant), deterministically ordered. */
1233
- listEntries(projectId: string, variant?: ReferenceVariant): Promise<ReferenceEntryRecord[]>;
1234
- /** Drop the whole index of a project (backfill starts from a clean slate). */
1235
- clearProject(projectId: string): Promise<void>;
1236
- }
1237
-
1238
- /**
1239
- * Per-project membership records (EC-150, vision AD-7). The role model is
1240
- * deliberately minimal for v1 — three roles, project-scoped, no field-level
1241
- * permissions. Workspace-level grants (who may create projects, default
1242
- * memberships) land with EC-154; everything here stays project-scoped.
1243
- *
1244
- * Roles:
1245
- * - `viewer` — read-only: queries succeed, every command is denied.
1246
- * - `editor` — edits and publishes content, but cannot administer the project
1247
- * (lifecycle, settings, members, CLI tokens).
1248
- * - `admin` — everything within the project.
1249
- *
1250
- * Enforcement lives at the operations chokepoint
1251
- * (`@elytracms/operations` `createRoleAuthorization`) and server-side in the
1252
- * Convex functions (`apps/builder/convex/guard.ts`); this module only defines
1253
- * the storage contract.
1254
- */
1255
- declare const projectRoleSchema: z.ZodEnum<{
1256
- admin: "admin";
1257
- editor: "editor";
1258
- viewer: "viewer";
1259
- }>;
1260
- type ProjectRole = z.infer<typeof projectRoleSchema>;
1261
- declare const projectMemberRecordSchema: z.ZodObject<{
1262
- projectId: z.ZodString;
1263
- userId: z.ZodString;
1264
- role: z.ZodEnum<{
1265
- admin: "admin";
1266
- editor: "editor";
1267
- viewer: "viewer";
1268
- }>;
1269
- createdAt: z.ZodString;
1270
- updatedAt: z.ZodString;
1271
- }, z.core.$strip>;
1272
- type ProjectMemberRecord = z.infer<typeof projectMemberRecordSchema>;
1273
- /**
1274
- * Membership storage boundary. Mirrors the other repository contracts: the
1275
- * in-memory implementation below and the Convex-backed implementation in
1276
- * `apps/builder` both satisfy it.
1277
- */
1278
- interface MembersRepository {
1279
- /** Upsert a membership (add a member or change their role). */
1280
- setMember(projectId: string, userId: string, role: ProjectRole): Promise<ProjectMemberRecord>;
1281
- /** Look up one membership; `undefined` when the user is not a member. */
1282
- findMember(projectId: string, userId: string): Promise<ProjectMemberRecord | undefined>;
1283
- /** All members of a project, ordered by userId for determinism. */
1284
- listMembers(projectId: string): Promise<ProjectMemberRecord[]>;
1285
- /** All memberships of a user across projects, ordered by projectId. */
1286
- listMembershipsForUser(userId: string): Promise<ProjectMemberRecord[]>;
1287
- /** Remove a membership. Throws `RecordNotFoundError` when absent. */
1288
- removeMember(projectId: string, userId: string): Promise<void>;
1289
- }
1290
-
1291
- /**
1292
- * Revocable per-project CLI tokens (EC-150). The EC-147 push CLI authenticates
1293
- * with `Authorization: Bearer <token>`; the builder stores only a SHA-256 hash
1294
- * of the token (`tokenHash`) — the plaintext is shown exactly once at issuance
1295
- * and never persisted. Verification (`verifyCliToken` in `@elytracms/operations`)
1296
- * hashes the presented token and looks it up here; revoked tokens stay stored
1297
- * (with `revokedAt`) so revocation is auditable and ids stay stable.
1298
- */
1299
- declare const cliTokenRecordSchema: z.ZodObject<{
1300
- id: z.ZodString;
1301
- label: z.ZodString;
1302
- tokenHash: z.ZodString;
1303
- createdAt: z.ZodString;
1304
- revokedAt: z.ZodOptional<z.ZodString>;
1305
- }, z.core.$strip>;
1306
- type CliTokenRecord = z.infer<typeof cliTokenRecordSchema>;
1307
- interface NewCliTokenInput {
1308
- label: string;
1309
- tokenHash: string;
1310
- }
1311
- /**
1312
- * Token storage boundary. The in-memory implementation below and the
1313
- * Convex-backed implementation in `apps/builder` both satisfy it.
1314
- */
1315
- interface CliTokenRepository {
1316
- /** Persist a freshly issued token (hash only). */
1317
- createToken(input: NewCliTokenInput): Promise<CliTokenRecord>;
1318
- /** All tokens of this deployment (revoked included), ordered by id. */
1319
- listTokens(): Promise<CliTokenRecord[]>;
1320
- /** Mark a token revoked (idempotent). Throws `RecordNotFoundError` when absent. */
1321
- revokeToken(tokenId: string): Promise<CliTokenRecord>;
1322
- /** Look a token up by its hash — the verification path. */
1323
- findByHash(tokenHash: string): Promise<CliTokenRecord | undefined>;
1324
- }
1325
-
1326
- /**
1327
- * Inputs to the backend validation service (brief §4.11, §10). Any subset may be
1328
- * provided; only supplied domains are validated.
1329
- */
1330
- interface BackendValidationInput {
1331
- graph?: ProjectGraph;
1332
- /** Registry lookup for component/prop/slot checks against the graph. */
1333
- components?: ComponentLookup;
1334
- /** Known data-source ids for binding resolution. */
1335
- knownSourceIds?: ReadonlySet<string>;
1336
- collections?: readonly CollectionDef[];
1337
- routes?: readonly RouteRecord[];
1338
- redirects?: readonly RedirectRecord[];
1339
- defaultLocale?: string;
1340
- }
1341
- /** Structured, typed validation results returned to clients (brief §4.11). */
1342
- interface BackendValidationResult {
1343
- ok: boolean;
1344
- /** Graph + binding + component issues (from `@elytracms/project-graph`). */
1345
- graphIssues: ValidationIssue[];
1346
- /** Collection/field schema issues (from `@elytracms/cms-core`). */
1347
- schemaIssues: CmsValidationIssue[];
1348
- /** Route conflict + redirect loop issues (from `@elytracms/cms-core`). */
1349
- routeIssues: CmsValidationIssue[];
1350
- /** Count of error-severity issues across all domains. */
1351
- errorCount: number;
1352
- }
1353
-
1354
- /**
1355
- * The aggregate persistence boundary (brief §4.10, §10). Core packages depend on
1356
- * this interface — never on Convex directly. A Convex-backed implementation and
1357
- * the in-memory implementation below both satisfy it, so the Studio, seeds, and
1358
- * tests are provider-agnostic.
1359
- */
1360
- interface PersistenceAdapter {
1361
- readonly graphs: GraphRepository;
1362
- readonly cms: CmsRepository;
1363
- readonly assets: AssetRepository;
1364
- readonly publishing: PublishingRepository;
1365
- /** Reference index — outbound/inbound reference entries per variant (EC-155, AD-6). */
1366
- readonly references: ReferenceIndexRepository;
1367
- /** Per-project membership roles — admin/editor/viewer (EC-150, AD-7). */
1368
- readonly members: MembersRepository;
1369
- /** Revocable per-project CLI sync tokens, stored hashed (EC-150). */
1370
- readonly cliTokens: CliTokenRepository;
1371
- /** Blob storage boundary for asset bytes. */
1372
- readonly blobs: BlobStorageAdapter;
1373
- /** Backend identity + reachability, for degraded-state UI. */
1374
- status(): Promise<BackendStatus>;
1375
- /** Server-side validation service (brief §4.11, EC-047). */
1376
- validate(input: BackendValidationInput): BackendValidationResult;
1377
- }
1378
-
1379
- /**
1380
- * The delivery shape of an asset (vision AD-4): a directly usable object, not
1381
- * an id. Optional metadata that the stored record lacks is `null` (never
1382
- * `undefined`) so resolved documents stay JSON-stable.
1383
- */
1384
- interface ResolvedAsset {
1385
- /** The asset id the field stored (kept for cache keys and re-lookup). */
1386
- id: string;
1387
- /** Resolvable URL for the asset bytes (EC-044 blob storage locator). */
1388
- url: string;
1389
- width: number | null;
1390
- height: number | null;
1391
- alt: string | null;
1392
- mimeType: string;
1393
- /**
1394
- * Normalized image focal point `{ x, y }` in 0–1 (EC-230), or `null`. Threaded
1395
- * to the image primitive's CSS `object-position` so a migrated hotspot keeps
1396
- * the subject in frame when a layout crops the image (`object-fit: cover`).
1397
- */
1398
- focalPoint: {
1399
- x: number;
1400
- y: number;
1401
- } | null;
1402
- }
1403
-
1404
- /**
1405
- * A document in delivery shape: identity plus resolved field values, flat —
1406
- * `post.title`, `post.author.name`, `post.cover.url`. The precise per-collection
1407
- * shape is what `generateDeliveryTypes` emits (EC-142 codegen).
1408
- */
1409
- type ResolvedDocument = {
1410
- id: string;
1411
- collection: string;
1412
- } & Record<string, unknown>;
1413
- /**
1414
- * The minimal structural face of any delivery-shaped document — what the typed
1415
- * accessors (EC-143) constrain their per-collection generics against. The
1416
- * generated interfaces from `generateDeliveryTypes` (e.g. `Post`) satisfy this
1417
- * where they cannot satisfy `ResolvedDocument`'s index signature.
1418
- */
1419
- interface DeliveryDocument {
1420
- id: string;
1421
- collection: string;
1422
- }
1423
- /**
1424
- * Structured information about *how* a document was resolved — most notably
1425
- * which fields served their value via EC-018 locale fallback.
1426
- */
1427
- interface ResolutionInfo {
1428
- locale: Locale;
1429
- perspective: Perspective;
1430
- localeFallbacks: FieldLocaleFallback[];
1431
- }
1432
-
1433
- /** A scalar a filter can compare against (relation/asset filters use the id). */
1434
- type FilterScalar = string | number | boolean;
1435
- /** One field's filter: every present operator must hold (AND). */
1436
- interface FilterCondition {
1437
- eq?: FilterScalar;
1438
- gt?: FilterScalar;
1439
- gte?: FilterScalar;
1440
- in?: readonly FilterScalar[];
1441
- lt?: FilterScalar;
1442
- lte?: FilterScalar;
1443
- }
1444
- /**
1445
- * The `where` input: field name → condition. A bare scalar is shorthand for
1446
- * `{ eq: value }`. Generated per-collection types (`PostWhere`) narrow the
1447
- * keys to the fields declared `filterable` in the schema.
1448
- */
1449
- type WhereInput = Readonly<Record<string, FilterScalar | FilterCondition | undefined>>;
1450
- type SortDirection = 'asc' | 'desc';
1451
- /** Single-field sort; ties always break by document id ascending. */
1452
- interface SortInput {
1453
- field: string;
1454
- direction?: SortDirection;
1455
- }
1456
- /** The full `listDocuments` query envelope (vision AD-3, rung 3). */
1457
- interface ListDocumentsQuery<TWhere extends WhereInput = WhereInput> {
1458
- where?: TWhere;
1459
- sort?: SortInput;
1460
- limit?: number;
1461
- cursor?: string;
1462
- }
1463
- /**
1464
- * Codes for structured accessor query errors (EC-143). These describe *caller*
1465
- * mistakes (bad filter, bad cursor), as opposed to `CmsValidationIssue`s which
1466
- * describe content/schema problems. Accessors never throw — invalid queries
1467
- * come back as an error result carrying these.
1468
- */
1469
- type ContentQueryErrorCode = 'unknown-collection' | 'list-not-supported' | 'non-filterable-field' | 'invalid-filter' | 'invalid-sort' | 'invalid-limit' | 'invalid-cursor';
1470
- interface ContentQueryError {
1471
- code: ContentQueryErrorCode;
1472
- message: string;
1473
- /** Path into the query input, e.g. ['where', 'title'] or ['sort', 'field']. */
1474
- path: CmsPath;
1475
- meta?: Record<string, unknown>;
1476
- }
1477
-
1478
- /**
1479
- * Cache-tag metadata carried by every accessor result (EC-143, vision AD-5):
1480
- * fetch-time tagging of what was *actually returned*, so EC-146 can map each
1481
- * entry to a `revalidateTag` call. Deterministic by construction — every list
1482
- * is sorted and deduplicated.
1483
- */
1484
- interface CacheTags {
1485
- /**
1486
- * Identities of every document whose content is present in the result —
1487
- * the returned documents themselves plus their depth-1 populated relation
1488
- * targets. Entries are `documentKey` strings (`collection:id`), sorted.
1489
- */
1490
- docs: string[];
1491
- /**
1492
- * Collections the accessor read from (the coarse membership tags of AD-5:
1493
- * create/delete/publish in a collection sweeps them). Sorted.
1494
- */
1495
- collections: string[];
1496
- /**
1497
- * Normalized URL paths the accessor touched (`resolvePage` only): the
1498
- * requested path, plus every hop of a redirect chain — editing any hop
1499
- * changes the result. Sorted.
1500
- */
1501
- routes: string[];
1502
- /**
1503
- * Asset ids the result *baked* its delivery shape from (EC-227): the page's
1504
- * page-scoped `ResolvedAsset` set (url/dimensions/alt) + its `seoOgImage`.
1505
- * Editing the asset record (alt/dimensions/re-upload) must drop the page that
1506
- * baked it — without this dimension the only invalidation triggers are
1507
- * unrelated (doc/collection/project), so an asset-only edit serves stale
1508
- * until one of those fires. Sorted.
1509
- */
1510
- assets: string[];
1511
- /** The locale the result was resolved for. */
1512
- locale: Locale;
1513
- }
1514
-
1515
- /**
1516
- * The closed-form v1 query surface (EC-143, vision AD-3): `resolvePage`,
1517
- * `getDocument`, `listDocuments` — no query language. Every result is
1518
- * delivery-shaped (EC-142) and carries deterministic `CacheTags` for EC-146.
1519
- *
1520
- * Pure and synchronous like the rest of the package: the client reads through
1521
- * a `ContentLookup`; EC-144/EC-145 bind it to Convex/Next later. The ambient
1522
- * `{ locale, perspective }` context is taken once at creation — never per-call
1523
- * ceremony (per-call `locale` overrides exist for route-level needs only).
1524
- */
1525
- interface ResolvePageResult {
1526
- /** Route resolution status (EC-019 parity): ok | redirect | notFound. */
1527
- status: ResolveStatus;
1528
- /** The matched route record, when status is `ok`. */
1529
- route: RouteRecord | null;
1530
- /** Extracted dynamic params, e.g. `{ slug: 'hello-world' }`. */
1531
- dynamicParams: Record<string, string>;
1532
- /** True when route matching fell back to the default locale (EC-018). */
1533
- localeFallback: boolean;
1534
- /** Terminal redirect target + permanence, when status is `redirect`. */
1535
- redirect: {
1536
- target: string;
1537
- permanent: boolean;
1538
- } | null;
1539
- /**
1540
- * The document this URL resolves to, delivery-shaped (EC-142, EC-187). A
1541
- * `page`-collection document (its `body` composition renders into a layout)
1542
- * or a content-collection document (rendered by a dev route component). SEO
1543
- * for a page is read from this document's flat `seo*` fields — there is no
1544
- * separate page-graph `seo` block anymore.
1545
- */
1546
- document: ResolvedDocument | null;
1547
- issues: CmsValidationIssue[];
1548
- tags: CacheTags;
1549
- }
1550
- interface GetDocumentResult<TDoc extends DeliveryDocument = ResolvedDocument> {
1551
- /**
1552
- * The delivery-shaped document, or `null` when not found / not visible in
1553
- * the context perspective (correct behavior, not an error — see EC-142).
1554
- */
1555
- document: TDoc | null;
1556
- info: ResolutionInfo | null;
1557
- issues: CmsValidationIssue[];
1558
- tags: CacheTags;
1559
- }
1560
- type ListDocumentsResult<TDoc extends DeliveryDocument = ResolvedDocument> = {
1561
- ok: true;
1562
- documents: TDoc[];
1563
- /** Cursor for the next page, `null` when this page exhausts the list. */
1564
- nextCursor: string | null;
1565
- issues: CmsValidationIssue[];
1566
- tags: CacheTags;
1567
- } | {
1568
- /** The query itself was invalid (never thrown — structured errors). */
1569
- ok: false;
1570
- errors: ContentQueryError[];
1571
- tags: CacheTags;
1572
- };
1573
- interface ContentClient {
1574
- readonly context: ContentContext;
1575
- /** Structural route issues from construction (conflicts, redirect loops). */
1576
- readonly routerIssues: readonly CmsValidationIssue[];
1577
- resolvePage(url: string, locale?: Locale): ResolvePageResult;
1578
- getDocument<TDoc extends DeliveryDocument = ResolvedDocument>(collection: string, idOrSlug: string, locale?: Locale): GetDocumentResult<TDoc>;
1579
- listDocuments<TDoc extends DeliveryDocument = ResolvedDocument, TWhere extends WhereInput = WhereInput>(collection: string, query?: ListDocumentsQuery<TWhere>): ListDocumentsResult<TDoc>;
1580
- /**
1581
- * Populate a relation reference to depth-1 delivery shape (EC-254), or `null`
1582
- * when the target is missing or not visible in the active perspective. A
1583
- * renderer host wires this as `RenderContext.resolveRelation` to populate the
1584
- * COMPOSITION-NODE relation props of the nodes inside a page's `blocks` field
1585
- * (e.g. a ProductGrid block's picked `product`s) — which `resolvePage` leaves
1586
- * raw, since document resolution does not descend into a composition value.
1587
- */
1588
- resolveRelation(ref: DocumentRef): ResolvedDocument | null;
1589
- }
1590
-
1591
57
  /**
1592
58
  * Binding payloads for the embedded runtime (EC-144): one payload value per
1593
59
  * binding `sourceId`. The catch-all route helper provides `document` (the
@@ -2613,4 +1079,4 @@ declare function createPreviewDisableRoute(): PreviewRouteHandlers;
2613
1079
  */
2614
1080
  declare const PACKAGE = "@elytracms/next";
2615
1081
 
2616
- export { type AssetImageLoaderOptions, type AssetRecord, type BindingPayloads, type CacheWrapper, type CacheWrapperOptions, type CachedEntry, type CanvasCacheOptions, type CanvasContentRequest, type CanvasDataSource, type CanvasPageOutcome, type CanvasPayloadContext, type CanvasPayloadsFactory, CanvasRenderer, type CanvasRendererProps, type CanvasRequestInfo, type CanvasRoute, type CanvasRouteOptions, type CanvasRouteProps, type CanvasSitemapOptions, type CanvasSitemapResult, type CmsDocument, type CollectionDef, type ComponentImplementations, type ComponentManifest, type ComponentNode, type ContentSnapshot, type ContentSnapshotOptions, type ContentSource, type CreateCanvasSitemapOptions, type DefineHostComponentsOptions, ElytraImage, type ElytraImageAsset, type ElytraImageProps, type FieldDef, type HostComponent, type HostComponents, type Locale, type LocaleConfig, type MaterializeSourcePayloadsInput, type MaterializedSourcePayloads, PACKAGE, PROJECT_GRAPH_SCHEMA_VERSION, type Perspective, type PreviewEvaluation, type PreviewRouteHandlers, type PreviewRouteOptions, type ProjectGraph, type PropField, REVALIDATE_SIGNATURE_HEADER, type RedirectRecord, type RenderAsset, type ResolveCanvasPageOptions, type RevalidateEvaluation, type RevalidatePayload, type RevalidateRouteHandlers, type RevalidateRouteOptions, type RouteRecord, type SitemapParamsProvider, type SitemapRouteContext, type SitemapSkippedRoute, type SlotSpec, type SourcePayloadError, type StaticContentData, canvasPageMetadata, canvasSitemapEntries, collectBindingSourceIds, collectionCacheTag, createAssetImageLoader, createBindingResolver, createCanvasRoute, createCanvasSitemap, createContentSnapshot, createPreviewDisableRoute, createPreviewRoute, createRevalidateRoute, createStaticContentSource, defaultBindingPayloads, defineComponent, defineHostComponents, docCacheTag, documentSchema, evaluatePreviewRequest, evaluateRevalidateRequest, isSourcePayloadError, loadCachedEntry, localeConfigSchema, materializeSourcePayloads, mergeCacheTags, mergeRouteRecords, nextCacheTags, nextImagePrimitive, parseProjectGraph, pathFromSlug, projectSweepTag, redirectRecordSchema, resolveCanvasPage, resolvePayloadToken, revalidatePayloadSchema, routeCacheTag, routeRecordSchema, safeRedirectTarget, scopeCacheTag, signRevalidateBody, sourcePayloadError, splitLocalePath };
1082
+ export { type AssetImageLoaderOptions, type BindingPayloads, type CacheWrapper, type CacheWrapperOptions, type CachedEntry, type CanvasCacheOptions, type CanvasContentRequest, type CanvasDataSource, type CanvasPageOutcome, type CanvasPayloadContext, type CanvasPayloadsFactory, CanvasRenderer, type CanvasRendererProps, type CanvasRequestInfo, type CanvasRoute, type CanvasRouteOptions, type CanvasRouteProps, type CanvasSitemapOptions, type CanvasSitemapResult, type ContentSnapshot, type ContentSnapshotOptions, type ContentSource, type CreateCanvasSitemapOptions, type DefineHostComponentsOptions, ElytraImage, type ElytraImageAsset, type ElytraImageProps, type HostComponent, type HostComponents, type MaterializeSourcePayloadsInput, type MaterializedSourcePayloads, PACKAGE, type PreviewEvaluation, type PreviewRouteHandlers, type PreviewRouteOptions, REVALIDATE_SIGNATURE_HEADER, type ResolveCanvasPageOptions, type RevalidateEvaluation, type RevalidatePayload, type RevalidateRouteHandlers, type RevalidateRouteOptions, type SitemapParamsProvider, type SitemapRouteContext, type SitemapSkippedRoute, type SourcePayloadError, type StaticContentData, canvasPageMetadata, canvasSitemapEntries, collectBindingSourceIds, collectionCacheTag, createAssetImageLoader, createBindingResolver, createCanvasRoute, createCanvasSitemap, createContentSnapshot, createPreviewDisableRoute, createPreviewRoute, createRevalidateRoute, createStaticContentSource, defaultBindingPayloads, defineHostComponents, docCacheTag, evaluatePreviewRequest, evaluateRevalidateRequest, isSourcePayloadError, loadCachedEntry, materializeSourcePayloads, mergeCacheTags, mergeRouteRecords, nextCacheTags, nextImagePrimitive, pathFromSlug, projectSweepTag, resolveCanvasPage, resolvePayloadToken, revalidatePayloadSchema, routeCacheTag, safeRedirectTarget, scopeCacheTag, signRevalidateBody, sourcePayloadError, splitLocalePath };