@elytracms/studio 0.0.20 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/convex/assets.ts +2 -0
  2. package/convex/content.ts +6 -0
  3. package/convex/delivery.ts +5 -0
  4. package/convex/schema.ts +2 -0
  5. package/dist/components/assets/asset-metadata.d.ts +7 -0
  6. package/dist/components/assets/asset-metadata.js +3 -0
  7. package/dist/components/assets/asset-metadata.js.map +1 -1
  8. package/dist/components/assets/assets-store.js +9 -3
  9. package/dist/components/assets/assets-store.js.map +1 -1
  10. package/dist/components/builder/canvas.d.ts +7 -1
  11. package/dist/components/builder/canvas.js +63 -6
  12. package/dist/components/builder/canvas.js.map +1 -1
  13. package/dist/components/builder/composition-field-editor.js +1 -1
  14. package/dist/components/builder/composition-field-editor.js.map +1 -1
  15. package/dist/components/builder/property-inspector.js +2 -1
  16. package/dist/components/builder/property-inspector.js.map +1 -1
  17. package/dist/components/builder/reuse-context.js +21 -8
  18. package/dist/components/builder/reuse-context.js.map +1 -1
  19. package/dist/components/builder/reuse.d.ts +14 -1
  20. package/dist/components/builder/reuse.js +33 -1
  21. package/dist/components/builder/reuse.js.map +1 -1
  22. package/dist/components/cms/asset-picker.d.ts +6 -2
  23. package/dist/components/cms/asset-picker.js +56 -12
  24. package/dist/components/cms/asset-picker.js.map +1 -1
  25. package/dist/components/cms/detail-editor.js +78 -7
  26. package/dist/components/cms/detail-editor.js.map +1 -1
  27. package/dist/components/cms/field-control.js +125 -32
  28. package/dist/components/cms/field-control.js.map +1 -1
  29. package/dist/components/cms/field-density.d.ts +14 -0
  30. package/dist/components/cms/field-density.js +10 -0
  31. package/dist/components/cms/field-density.js.map +1 -0
  32. package/dist/lib/data/collection-content.d.ts +12 -3
  33. package/dist/lib/data/collection-content.js +20 -17
  34. package/dist/lib/data/collection-content.js.map +1 -1
  35. package/dist/lib/persistence/convex-adapter.js +2 -0
  36. package/dist/lib/persistence/convex-adapter.js.map +1 -1
  37. package/package.json +2 -2
@@ -58,6 +58,15 @@ export interface ContentSessionState {
58
58
  * collections + documents arrive via {@link configureContentSession} (Convex mode).
59
59
  */
60
60
  export declare const playgroundCollections: readonly CollectionDef[];
61
+ /**
62
+ * The perspective a canvas preview resolves references against (EC-300/AD-16). The
63
+ * canvas is draft-coherent: the editable Draft view resolves references to their
64
+ * `'draft'` targets (so a just-made reusable shows immediately), the read-only
65
+ * Published view resolves `'published'` (an honest preview of what delivery serves;
66
+ * an unpublished hard ref shows the in-canvas placeholder). Delivery stays
67
+ * published-only — this does not weaken `live-is-published-only`.
68
+ */
69
+ export type CanvasPerspective = 'draft' | 'published';
61
70
  /**
62
71
  * Point the preview engine at a project's hydrated content (Convex mode), or
63
72
  * back at the deterministic playground fixtures (`null` — the default, and
@@ -93,7 +102,7 @@ export declare function getCollectionDocument(collectionId: string, idOrSlug: st
93
102
  * Reusable's element) exactly as delivery renders them. `null` when the target is
94
103
  * missing or not visible → the block degrades to its own empty state.
95
104
  */
96
- export declare function resolveCanvasRelation(ref: DocumentRef, locale?: Locale): ResolvedDocument | null;
105
+ export declare function resolveCanvasRelation(ref: DocumentRef, locale?: Locale, perspective?: CanvasPerspective): ResolvedDocument | null;
97
106
  /**
98
107
  * Resolve a listing block's query to its documents for the canvas (EC-255) — the
99
108
  * studio analog of the host's baked listings map. Runs the query (collection +
@@ -103,7 +112,7 @@ export declare function resolveCanvasRelation(ref: DocumentRef, locale?: Locale)
103
112
  * (structured, never thrown) or a non-list lookup yields `[]` → the block's empty
104
113
  * state. Reuses the same `listDocuments` path as `runCollectionListQuery`.
105
114
  */
106
- export declare function resolveCanvasListing(query: ListingQuery, locale?: Locale): ResolvedDocument[];
115
+ export declare function resolveCanvasListing(query: ListingQuery, locale?: Locale, perspective?: CanvasPerspective): ResolvedDocument[];
107
116
  /**
108
117
  * Resolve a rich-text internal link's target document to its URL path for the canvas
109
118
  * (EC-291) — the studio analog of the host's baked links map. Derives the URL through
@@ -113,7 +122,7 @@ export declare function resolveCanvasListing(query: ListingQuery, locale?: Local
113
122
  * no route → the rich-text renderer shows the EC-290 `unresolved-ref` issue. Reuses
114
123
  * the same `resolveLink` path as the host bake, so both agree on the derived URL.
115
124
  */
116
- export declare function resolveCanvasLink(ref: DocumentRef, locale?: Locale): string | null;
125
+ export declare function resolveCanvasLink(ref: DocumentRef, locale?: Locale, perspective?: CanvasPerspective): string | null;
117
126
  /** A pickable entry of a collection (the template-page preview switcher). */
118
127
  export interface CollectionEntrySummary {
119
128
  id: string;
@@ -10,6 +10,7 @@ import { getStudioLocale } from '../locale/locale-store';
10
10
  export const playgroundCollections = [];
11
11
  let contentSession = null;
12
12
  let lookup = createLookup(playgroundCollections, [], []);
13
+ // Keyed by `${locale}:${perspective}` (EC-300) — one deterministic client per pair.
13
14
  const clients = new Map();
14
15
  /**
15
16
  * Point the preview engine at a project's hydrated content (Convex mode), or
@@ -121,28 +122,30 @@ function createLookup(collectionDefs, documents, publishedKeys, assetRecords) {
121
122
  };
122
123
  }
123
124
  /**
124
- * One deterministic client per locale: published perspective, EC-018 locale
125
- * fallback. The studio's ambient active locale (EC-176, `lib/locale`) picks
126
- * the client at query time, so the canvas previews follow the locale switcher
127
- * exactly like delivery would. The cache resets whenever the content session changes.
125
+ * One deterministic client per (locale, perspective): EC-018 locale fallback,
126
+ * draft-or-published perspective (EC-300/AD-16, default `'published'`). The studio's
127
+ * ambient active locale (EC-176, `lib/locale`) picks the locale at query time, so the
128
+ * canvas previews follow the locale switcher exactly like delivery would; the canvas's
129
+ * Draft/Published view picks the perspective. The cache resets whenever the content
130
+ * session changes.
128
131
  */
129
- function clientFor(locale) {
130
- const existing = clients.get(locale);
132
+ function clientFor(locale, perspective = 'published') {
133
+ const key = `${locale}:${perspective}`;
134
+ const existing = clients.get(key);
131
135
  if (existing)
132
136
  return existing;
133
137
  const client = createContentClient({
134
138
  lookup,
135
139
  context: createContentContext({
136
140
  locale,
137
- perspective: 'published',
141
+ perspective,
138
142
  locales: activeLocaleConfig(),
139
143
  }),
140
- // EC-291: the routes a rich-text link resolves against (config-sourced). The
141
- // canvas previews PUBLISHED content, so a link derives the live URL — matching
142
- // the host's baked link map.
144
+ // EC-291: the routes a rich-text link resolves against (config-sourced) — the
145
+ // studio-live half of the host link bake.
143
146
  routes: contentSession?.routes ?? [],
144
147
  });
145
- clients.set(locale, client);
148
+ clients.set(key, client);
146
149
  return client;
147
150
  }
148
151
  /**
@@ -166,8 +169,8 @@ export function getCollectionDocument(collectionId, idOrSlug, locale = getStudio
166
169
  * Reusable's element) exactly as delivery renders them. `null` when the target is
167
170
  * missing or not visible → the block degrades to its own empty state.
168
171
  */
169
- export function resolveCanvasRelation(ref, locale = getStudioLocale()) {
170
- return clientFor(locale).resolveRelation(ref);
172
+ export function resolveCanvasRelation(ref, locale = getStudioLocale(), perspective = 'published') {
173
+ return clientFor(locale, perspective).resolveRelation(ref);
171
174
  }
172
175
  /**
173
176
  * Resolve a listing block's query to its documents for the canvas (EC-255) — the
@@ -178,8 +181,8 @@ export function resolveCanvasRelation(ref, locale = getStudioLocale()) {
178
181
  * (structured, never thrown) or a non-list lookup yields `[]` → the block's empty
179
182
  * state. Reuses the same `listDocuments` path as `runCollectionListQuery`.
180
183
  */
181
- export function resolveCanvasListing(query, locale = getStudioLocale()) {
182
- const result = clientFor(locale).listDocuments(query.collection, {
184
+ export function resolveCanvasListing(query, locale = getStudioLocale(), perspective = 'published') {
185
+ const result = clientFor(locale, perspective).listDocuments(query.collection, {
183
186
  where: query.where,
184
187
  ...(query.sort ? { sort: query.sort } : {}),
185
188
  ...(query.limit !== undefined ? { limit: query.limit } : {}),
@@ -195,8 +198,8 @@ export function resolveCanvasListing(query, locale = getStudioLocale()) {
195
198
  * no route → the rich-text renderer shows the EC-290 `unresolved-ref` issue. Reuses
196
199
  * the same `resolveLink` path as the host bake, so both agree on the derived URL.
197
200
  */
198
- export function resolveCanvasLink(ref, locale = getStudioLocale()) {
199
- return clientFor(locale).resolveLink(ref);
201
+ export function resolveCanvasLink(ref, locale = getStudioLocale(), perspective = 'published') {
202
+ return clientFor(locale, perspective).resolveLink(ref);
200
203
  }
201
204
  /** Published entries of a collection, labeled by the schema's title field. */
202
205
  export function listCollectionEntries(collectionId) {
@@ -1 +1 @@
1
- {"version":3,"file":"collection-content.js","sourceRoot":"","sources":["../../../src/lib/data/collection-content.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createContentClient,\n createContentContext,\n} from '@elytracms/core/content'\nimport type {\n ContentClient,\n ContentDocumentSource,\n ContentLookup,\n GetDocumentResult,\n ListDocumentsQuery,\n ListDocumentsResult,\n ResolvedDocument,\n} from '@elytracms/core/content'\nimport { documentKey, sampleLocaleConfig } from '@elytracms/core/cms-core'\nimport type {\n CmsDocument,\n CollectionDef,\n DocumentRef,\n Locale,\n LocaleConfig,\n RouteRecord,\n} from '@elytracms/core/cms-core'\nimport type { AssetRecord } from '@elytracms/core/persistence'\nimport type { ListingQuery } from '@elytracms/core/runtime-renderer'\nimport { getStudioLocale } from '../locale/locale-store'\n\n/**\n * The studio's content delivery engine for canvas previews (EC-166).\n *\n * Repeating sections and template pages preview *delivery-shaped* documents —\n * the exact shape `@elytracms/core/content` serves in production — so the canvas\n * shows what publishing will show. This module wires the canonical content\n * client (closed AD-3 query vocabulary, published perspective, EC-018 locale\n * fallback, depth-1 population, resolved assets) over a **content session**:\n *\n * - Playground mode (and tests): the deterministic EC-145 sample fixtures —\n * byte-identical to the pre-hydration behavior, no backend.\n * - Convex mode: the project-session gate (`components/studio/project-session`)\n * configures the session with the project's HYDRATED schema + documents, so\n * \"Preview with\" lists and section previews show the live content — never\n * fixture titles (EC-177 gap 1).\n *\n * Nothing here invents query semantics; both shapes go through the same\n * canonical client.\n */\n\n/** The schema + documents the preview engine serves (one project session). */\nexport interface ContentSessionState {\n collections: readonly CollectionDef[]\n documents: readonly CmsDocument[]\n /**\n * Published document keys via the version POINTER (EC-224). When present, the\n * preview's published perspective resolves by the pin — never the flat\n * `state` enum — so it matches what delivery serves. Absent (playground\n * fixtures / tests) → the rows' own `state` gates the perspective, unchanged.\n */\n publishedKeys?: readonly string[]\n /** Locale config of the session content; defaults to the sample config. */\n localeConfig?: LocaleConfig\n /**\n * The project's config-sourced routes (EC-207). Wired into the content client so\n * the canvas preview's `resolveLink` (EC-291) derives a rich-text link's URL from\n * the SAME routes delivery serves — the studio-live half of the host link bake.\n * Absent (playground/tests) → no routes, so `resolveLink` returns null and a\n * reference link degrades to the visible `unresolved-ref` issue.\n */\n routes?: readonly RouteRecord[]\n /**\n * The project's asset records (assets table). Wired into the lookup so the\n * content client resolves `asset`-typed FIELDS on listing/relation results\n * (e.g. a ProductGrid product's `gallery`) to delivery shape — the same assets\n * the renderer's `resolveAsset` reads for static props (EC-262). Absent\n * (playground/tests) → assets come only from `asset`-collection fixture docs.\n */\n assets?: readonly AssetRecord[]\n}\n\n/**\n * Default (no-session) collection schema: EMPTY. The studio ships no demo content\n * (Oli, 2026-06-19) — with no backend/content session configured, there is nothing\n * to preview, and the studio says so rather than serving fixtures. A real project's\n * collections + documents arrive via {@link configureContentSession} (Convex mode).\n */\nexport const playgroundCollections: readonly CollectionDef[] = []\n\nlet contentSession: ContentSessionState | null = null\nlet lookup: ContentLookup = createLookup(playgroundCollections, [], [])\nconst clients = new Map<Locale, ContentClient>()\n\n/**\n * Point the preview engine at a project's hydrated content (Convex mode), or\n * back at the deterministic playground fixtures (`null` — the default, and\n * the only state playground mode ever sees).\n */\nexport function configureContentSession(next: ContentSessionState | null): void {\n contentSession = next\n lookup = next\n ? createLookup(next.collections, next.documents, next.publishedKeys, next.assets)\n : createLookup(playgroundCollections, [], [])\n clients.clear()\n}\n\n/** Whether a hydrated content session is configured (Convex mode). */\nexport function hasContentSession(): boolean {\n return contentSession !== null\n}\n\n/** The collections the preview engine currently serves (session or fixtures). */\nfunction activeCollections(): readonly CollectionDef[] {\n return contentSession?.collections ?? playgroundCollections\n}\n\nfunction activeLocaleConfig(): LocaleConfig {\n return contentSession?.localeConfig ?? sampleLocaleConfig\n}\n\n/** Resolve a collection in the active content session (fixtures in playground). */\nexport function playgroundCollection(id: string): CollectionDef | undefined {\n return activeCollections().find((collection) => collection.id === id)\n}\n\n/**\n * Overlay the active session's canonical `filterable` declarations onto a\n * schema that doesn't carry any of its own. The inspector hands the Content\n * tab fixture collection defs; the filter/sort pickers must offer exactly the\n * EC-143 declaration set the delivery engine enforces, so both ends agree. A\n * collection that declares its own filterable fields is left untouched.\n */\nexport function withPlaygroundFilterable(\n collections: readonly CollectionDef[],\n): readonly CollectionDef[] {\n return collections.map((collection) => {\n if (collection.fields.some((field) => field.filterable === true)) return collection\n const counterpart = playgroundCollection(collection.id)\n if (counterpart === undefined) return collection\n const flagged = new Set(\n counterpart.fields.filter((field) => field.filterable === true).map((field) => field.name),\n )\n if (flagged.size === 0) return collection\n return {\n ...collection,\n fields: collection.fields.map((field) =>\n flagged.has(field.name) ? { ...field, filterable: true } : field,\n ),\n }\n })\n}\n\n/** Synthesize the persistence-shaped asset record the asset resolver reads. */\nfunction assetRecordOf(doc: CmsDocument): AssetRecord {\n const values = doc.values\n const alt = doc.localized?.en?.alt\n return {\n id: doc.id,\n projectId: 'playground',\n filename: typeof values.filename === 'string' ? values.filename : doc.id,\n contentType: 'image/png',\n byteSize: 0,\n alt: typeof alt === 'string' ? alt : undefined,\n storageKey: typeof values.url === 'string' ? values.url : doc.id,\n createdAt: '2026-01-01T00:00:00.000Z',\n updatedAt: '2026-01-01T00:00:00.000Z',\n }\n}\n\nfunction createLookup(\n collectionDefs: readonly CollectionDef[],\n documents: readonly CmsDocument[],\n publishedKeys?: readonly string[],\n assetRecords?: readonly AssetRecord[],\n): ContentLookup {\n const collections = new Map(collectionDefs.map((c) => [c.id, c]))\n // EC-224: published-ness is the version POINTER, not the flat `state` enum.\n // A hydrated session hands `publishedKeys` (the pinned set) → wrap each row as\n // a `DocumentHistory` so the published perspective resolves by the pin (the\n // live row is always a draft now) with ZERO dependence on `state`. Without a\n // pointer set (playground fixtures / tests) we keep bare rows, whose own\n // `state` gates the published perspective — byte-identical to before.\n const published = publishedKeys ? new Set(publishedKeys) : null\n const toSource = (doc: CmsDocument): ContentDocumentSource => {\n if (!published) return doc\n return published.has(documentKey({ collection: doc.collection, id: doc.id }))\n ? { draft: doc, published: doc, versions: [] }\n : { draft: doc, published: undefined, versions: [] }\n }\n const byKey = new Map(\n documents.map((doc) => [`${doc.collection}:${doc.id}`, toSource(doc)] as const),\n )\n // Asset resolution source for `asset`-typed FIELDS on resolved documents\n // (listing/relation results, e.g. a product's `gallery`). Two sources, real\n // records last so they win: (1) `asset`-collection fixture documents — how\n // playground/tests model assets; (2) the project's real asset-table records\n // (EC-262) — a Convex session has its assets here, NOT as `asset` documents,\n // so without these the content client resolves no nested image.\n const assets = new Map<string, AssetRecord>()\n for (const doc of documents) {\n if (doc.collection === 'asset') assets.set(doc.id, assetRecordOf(doc))\n }\n for (const record of assetRecords ?? []) assets.set(record.id, record)\n return {\n collection: (id) => collections.get(id),\n document: (ref) => byKey.get(`${ref.collection}:${ref.id}`),\n documents: (collectionId) =>\n documents.filter((doc) => doc.collection === collectionId).map(toSource),\n asset: (id) => assets.get(id),\n // Prefer the record's resolved servable `url` — the one the renderer's\n // resolveAsset reads (EC-262). Real asset-table records carry a Convex blob\n // locator in `storageKey` and the servable URL in `url`; fixture/`asset`-document\n // records (assetRecordOf) leave `url` unset and store the servable url in\n // `storageKey`. Falling back keeps both correct.\n assetUrl: (asset) => asset.url ?? asset.storageKey,\n }\n}\n\n/**\n * One deterministic client per locale: published perspective, EC-018 locale\n * fallback. The studio's ambient active locale (EC-176, `lib/locale`) picks\n * the client at query time, so the canvas previews follow the locale switcher\n * exactly like delivery would. The cache resets whenever the content session changes.\n */\nfunction clientFor(locale: Locale): ContentClient {\n const existing = clients.get(locale)\n if (existing) return existing\n const client = createContentClient({\n lookup,\n context: createContentContext({\n locale,\n perspective: 'published',\n locales: activeLocaleConfig(),\n }),\n // EC-291: the routes a rich-text link resolves against (config-sourced). The\n // canvas previews PUBLISHED content, so a link derives the live URL — matching\n // the host's baked link map.\n routes: contentSession?.routes ?? [],\n })\n clients.set(locale, client)\n return client\n}\n\n/**\n * Run a closed-vocabulary list query (AD-3: eq/in/lt/lte/gt/gte, AND-only,\n * filterable fields only) and return the delivery-shaped result. Invalid\n * queries come back as structured errors — never thrown, never silently\n * widened. Resolves in the studio's active locale unless one is passed.\n */\nexport function runCollectionListQuery(\n collectionId: string,\n query: ListDocumentsQuery = {},\n locale: Locale = getStudioLocale(),\n): ListDocumentsResult {\n return clientFor(locale).listDocuments(collectionId, query)\n}\n\n/** Resolve one document (by id or slug) into delivery shape. */\nexport function getCollectionDocument(\n collectionId: string,\n idOrSlug: string,\n locale: Locale = getStudioLocale(),\n): GetDocumentResult {\n return clientFor(locale).getDocument(collectionId, idOrSlug)\n}\n\n/**\n * Populate a composition-node `relation` prop to delivery shape for the canvas\n * (EC-254) — the studio analog of the host's baked relations map. Resolves the\n * ref through the active session's client (published perspective, active locale),\n * so the canvas previews a block's picked documents (a ProductGrid's products, a\n * Reusable's element) exactly as delivery renders them. `null` when the target is\n * missing or not visible → the block degrades to its own empty state.\n */\nexport function resolveCanvasRelation(\n ref: DocumentRef,\n locale: Locale = getStudioLocale(),\n): ResolvedDocument | null {\n return clientFor(locale).resolveRelation(ref)\n}\n\n/**\n * Resolve a listing block's query to its documents for the canvas (EC-255) — the\n * studio analog of the host's baked listings map. Runs the query (collection +\n * AND-only filter, optional sort/limit) through the active session's client\n * (published perspective, active locale), so the canvas previews a dynamic grid (a\n * ProductGrid keyed to a category) exactly as delivery renders it. An invalid query\n * (structured, never thrown) or a non-list lookup yields `[]` → the block's empty\n * state. Reuses the same `listDocuments` path as `runCollectionListQuery`.\n */\nexport function resolveCanvasListing(\n query: ListingQuery,\n locale: Locale = getStudioLocale(),\n): ResolvedDocument[] {\n const result = clientFor(locale).listDocuments(query.collection, {\n where: query.where,\n ...(query.sort ? { sort: query.sort } : {}),\n ...(query.limit !== undefined ? { limit: query.limit } : {}),\n })\n return result.ok ? result.documents : []\n}\n\n/**\n * Resolve a rich-text internal link's target document to its URL path for the canvas\n * (EC-291) — the studio analog of the host's baked links map. Derives the URL through\n * the active session's client (published perspective, active locale, config-sourced\n * routes), so the canvas previews a `{type:'reference'}` link's `href` exactly as\n * delivery serves it. `null` when the target is unpublished, missing, or addressed by\n * no route → the rich-text renderer shows the EC-290 `unresolved-ref` issue. Reuses\n * the same `resolveLink` path as the host bake, so both agree on the derived URL.\n */\nexport function resolveCanvasLink(\n ref: DocumentRef,\n locale: Locale = getStudioLocale(),\n): string | null {\n return clientFor(locale).resolveLink(ref)\n}\n\n/** A pickable entry of a collection (the template-page preview switcher). */\nexport interface CollectionEntrySummary {\n id: string\n label: string\n}\n\n/** Published entries of a collection, labeled by the schema's title field. */\nexport function listCollectionEntries(collectionId: string): CollectionEntrySummary[] {\n const collection = playgroundCollection(collectionId)\n const result = runCollectionListQuery(collectionId)\n if (!result.ok) return []\n return result.documents.map((doc) => {\n const title = collection?.titleField ? doc[collection.titleField] : undefined\n return { id: doc.id, label: typeof title === 'string' && title.length > 0 ? title : doc.id }\n })\n}\n"]}
1
+ {"version":3,"file":"collection-content.js","sourceRoot":"","sources":["../../../src/lib/data/collection-content.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createContentClient,\n createContentContext,\n} from '@elytracms/core/content'\nimport type {\n ContentClient,\n ContentDocumentSource,\n ContentLookup,\n GetDocumentResult,\n ListDocumentsQuery,\n ListDocumentsResult,\n ResolvedDocument,\n} from '@elytracms/core/content'\nimport { documentKey, sampleLocaleConfig } from '@elytracms/core/cms-core'\nimport type {\n CmsDocument,\n CollectionDef,\n DocumentRef,\n Locale,\n LocaleConfig,\n RouteRecord,\n} from '@elytracms/core/cms-core'\nimport type { AssetRecord } from '@elytracms/core/persistence'\nimport type { ListingQuery } from '@elytracms/core/runtime-renderer'\nimport { getStudioLocale } from '../locale/locale-store'\n\n/**\n * The studio's content delivery engine for canvas previews (EC-166).\n *\n * Repeating sections and template pages preview *delivery-shaped* documents —\n * the exact shape `@elytracms/core/content` serves in production — so the canvas\n * shows what publishing will show. This module wires the canonical content\n * client (closed AD-3 query vocabulary, published perspective, EC-018 locale\n * fallback, depth-1 population, resolved assets) over a **content session**:\n *\n * - Playground mode (and tests): the deterministic EC-145 sample fixtures —\n * byte-identical to the pre-hydration behavior, no backend.\n * - Convex mode: the project-session gate (`components/studio/project-session`)\n * configures the session with the project's HYDRATED schema + documents, so\n * \"Preview with\" lists and section previews show the live content — never\n * fixture titles (EC-177 gap 1).\n *\n * Nothing here invents query semantics; both shapes go through the same\n * canonical client.\n */\n\n/** The schema + documents the preview engine serves (one project session). */\nexport interface ContentSessionState {\n collections: readonly CollectionDef[]\n documents: readonly CmsDocument[]\n /**\n * Published document keys via the version POINTER (EC-224). When present, the\n * preview's published perspective resolves by the pin — never the flat\n * `state` enum — so it matches what delivery serves. Absent (playground\n * fixtures / tests) → the rows' own `state` gates the perspective, unchanged.\n */\n publishedKeys?: readonly string[]\n /** Locale config of the session content; defaults to the sample config. */\n localeConfig?: LocaleConfig\n /**\n * The project's config-sourced routes (EC-207). Wired into the content client so\n * the canvas preview's `resolveLink` (EC-291) derives a rich-text link's URL from\n * the SAME routes delivery serves — the studio-live half of the host link bake.\n * Absent (playground/tests) → no routes, so `resolveLink` returns null and a\n * reference link degrades to the visible `unresolved-ref` issue.\n */\n routes?: readonly RouteRecord[]\n /**\n * The project's asset records (assets table). Wired into the lookup so the\n * content client resolves `asset`-typed FIELDS on listing/relation results\n * (e.g. a ProductGrid product's `gallery`) to delivery shape — the same assets\n * the renderer's `resolveAsset` reads for static props (EC-262). Absent\n * (playground/tests) → assets come only from `asset`-collection fixture docs.\n */\n assets?: readonly AssetRecord[]\n}\n\n/**\n * Default (no-session) collection schema: EMPTY. The studio ships no demo content\n * (Oli, 2026-06-19) — with no backend/content session configured, there is nothing\n * to preview, and the studio says so rather than serving fixtures. A real project's\n * collections + documents arrive via {@link configureContentSession} (Convex mode).\n */\nexport const playgroundCollections: readonly CollectionDef[] = []\n\n/**\n * The perspective a canvas preview resolves references against (EC-300/AD-16). The\n * canvas is draft-coherent: the editable Draft view resolves references to their\n * `'draft'` targets (so a just-made reusable shows immediately), the read-only\n * Published view resolves `'published'` (an honest preview of what delivery serves;\n * an unpublished hard ref shows the in-canvas placeholder). Delivery stays\n * published-only — this does not weaken `live-is-published-only`.\n */\nexport type CanvasPerspective = 'draft' | 'published'\n\nlet contentSession: ContentSessionState | null = null\nlet lookup: ContentLookup = createLookup(playgroundCollections, [], [])\n// Keyed by `${locale}:${perspective}` (EC-300) — one deterministic client per pair.\nconst clients = new Map<string, ContentClient>()\n\n/**\n * Point the preview engine at a project's hydrated content (Convex mode), or\n * back at the deterministic playground fixtures (`null` — the default, and\n * the only state playground mode ever sees).\n */\nexport function configureContentSession(next: ContentSessionState | null): void {\n contentSession = next\n lookup = next\n ? createLookup(next.collections, next.documents, next.publishedKeys, next.assets)\n : createLookup(playgroundCollections, [], [])\n clients.clear()\n}\n\n/** Whether a hydrated content session is configured (Convex mode). */\nexport function hasContentSession(): boolean {\n return contentSession !== null\n}\n\n/** The collections the preview engine currently serves (session or fixtures). */\nfunction activeCollections(): readonly CollectionDef[] {\n return contentSession?.collections ?? playgroundCollections\n}\n\nfunction activeLocaleConfig(): LocaleConfig {\n return contentSession?.localeConfig ?? sampleLocaleConfig\n}\n\n/** Resolve a collection in the active content session (fixtures in playground). */\nexport function playgroundCollection(id: string): CollectionDef | undefined {\n return activeCollections().find((collection) => collection.id === id)\n}\n\n/**\n * Overlay the active session's canonical `filterable` declarations onto a\n * schema that doesn't carry any of its own. The inspector hands the Content\n * tab fixture collection defs; the filter/sort pickers must offer exactly the\n * EC-143 declaration set the delivery engine enforces, so both ends agree. A\n * collection that declares its own filterable fields is left untouched.\n */\nexport function withPlaygroundFilterable(\n collections: readonly CollectionDef[],\n): readonly CollectionDef[] {\n return collections.map((collection) => {\n if (collection.fields.some((field) => field.filterable === true)) return collection\n const counterpart = playgroundCollection(collection.id)\n if (counterpart === undefined) return collection\n const flagged = new Set(\n counterpart.fields.filter((field) => field.filterable === true).map((field) => field.name),\n )\n if (flagged.size === 0) return collection\n return {\n ...collection,\n fields: collection.fields.map((field) =>\n flagged.has(field.name) ? { ...field, filterable: true } : field,\n ),\n }\n })\n}\n\n/** Synthesize the persistence-shaped asset record the asset resolver reads. */\nfunction assetRecordOf(doc: CmsDocument): AssetRecord {\n const values = doc.values\n const alt = doc.localized?.en?.alt\n return {\n id: doc.id,\n projectId: 'playground',\n filename: typeof values.filename === 'string' ? values.filename : doc.id,\n contentType: 'image/png',\n byteSize: 0,\n alt: typeof alt === 'string' ? alt : undefined,\n storageKey: typeof values.url === 'string' ? values.url : doc.id,\n createdAt: '2026-01-01T00:00:00.000Z',\n updatedAt: '2026-01-01T00:00:00.000Z',\n }\n}\n\nfunction createLookup(\n collectionDefs: readonly CollectionDef[],\n documents: readonly CmsDocument[],\n publishedKeys?: readonly string[],\n assetRecords?: readonly AssetRecord[],\n): ContentLookup {\n const collections = new Map(collectionDefs.map((c) => [c.id, c]))\n // EC-224: published-ness is the version POINTER, not the flat `state` enum.\n // A hydrated session hands `publishedKeys` (the pinned set) → wrap each row as\n // a `DocumentHistory` so the published perspective resolves by the pin (the\n // live row is always a draft now) with ZERO dependence on `state`. Without a\n // pointer set (playground fixtures / tests) we keep bare rows, whose own\n // `state` gates the published perspective — byte-identical to before.\n const published = publishedKeys ? new Set(publishedKeys) : null\n const toSource = (doc: CmsDocument): ContentDocumentSource => {\n if (!published) return doc\n return published.has(documentKey({ collection: doc.collection, id: doc.id }))\n ? { draft: doc, published: doc, versions: [] }\n : { draft: doc, published: undefined, versions: [] }\n }\n const byKey = new Map(\n documents.map((doc) => [`${doc.collection}:${doc.id}`, toSource(doc)] as const),\n )\n // Asset resolution source for `asset`-typed FIELDS on resolved documents\n // (listing/relation results, e.g. a product's `gallery`). Two sources, real\n // records last so they win: (1) `asset`-collection fixture documents — how\n // playground/tests model assets; (2) the project's real asset-table records\n // (EC-262) — a Convex session has its assets here, NOT as `asset` documents,\n // so without these the content client resolves no nested image.\n const assets = new Map<string, AssetRecord>()\n for (const doc of documents) {\n if (doc.collection === 'asset') assets.set(doc.id, assetRecordOf(doc))\n }\n for (const record of assetRecords ?? []) assets.set(record.id, record)\n return {\n collection: (id) => collections.get(id),\n document: (ref) => byKey.get(`${ref.collection}:${ref.id}`),\n documents: (collectionId) =>\n documents.filter((doc) => doc.collection === collectionId).map(toSource),\n asset: (id) => assets.get(id),\n // Prefer the record's resolved servable `url` — the one the renderer's\n // resolveAsset reads (EC-262). Real asset-table records carry a Convex blob\n // locator in `storageKey` and the servable URL in `url`; fixture/`asset`-document\n // records (assetRecordOf) leave `url` unset and store the servable url in\n // `storageKey`. Falling back keeps both correct.\n assetUrl: (asset) => asset.url ?? asset.storageKey,\n }\n}\n\n/**\n * One deterministic client per (locale, perspective): EC-018 locale fallback,\n * draft-or-published perspective (EC-300/AD-16, default `'published'`). The studio's\n * ambient active locale (EC-176, `lib/locale`) picks the locale at query time, so the\n * canvas previews follow the locale switcher exactly like delivery would; the canvas's\n * Draft/Published view picks the perspective. The cache resets whenever the content\n * session changes.\n */\nfunction clientFor(locale: Locale, perspective: CanvasPerspective = 'published'): ContentClient {\n const key = `${locale}:${perspective}`\n const existing = clients.get(key)\n if (existing) return existing\n const client = createContentClient({\n lookup,\n context: createContentContext({\n locale,\n perspective,\n locales: activeLocaleConfig(),\n }),\n // EC-291: the routes a rich-text link resolves against (config-sourced) — the\n // studio-live half of the host link bake.\n routes: contentSession?.routes ?? [],\n })\n clients.set(key, client)\n return client\n}\n\n/**\n * Run a closed-vocabulary list query (AD-3: eq/in/lt/lte/gt/gte, AND-only,\n * filterable fields only) and return the delivery-shaped result. Invalid\n * queries come back as structured errors — never thrown, never silently\n * widened. Resolves in the studio's active locale unless one is passed.\n */\nexport function runCollectionListQuery(\n collectionId: string,\n query: ListDocumentsQuery = {},\n locale: Locale = getStudioLocale(),\n): ListDocumentsResult {\n return clientFor(locale).listDocuments(collectionId, query)\n}\n\n/** Resolve one document (by id or slug) into delivery shape. */\nexport function getCollectionDocument(\n collectionId: string,\n idOrSlug: string,\n locale: Locale = getStudioLocale(),\n): GetDocumentResult {\n return clientFor(locale).getDocument(collectionId, idOrSlug)\n}\n\n/**\n * Populate a composition-node `relation` prop to delivery shape for the canvas\n * (EC-254) — the studio analog of the host's baked relations map. Resolves the\n * ref through the active session's client (published perspective, active locale),\n * so the canvas previews a block's picked documents (a ProductGrid's products, a\n * Reusable's element) exactly as delivery renders them. `null` when the target is\n * missing or not visible → the block degrades to its own empty state.\n */\nexport function resolveCanvasRelation(\n ref: DocumentRef,\n locale: Locale = getStudioLocale(),\n perspective: CanvasPerspective = 'published',\n): ResolvedDocument | null {\n return clientFor(locale, perspective).resolveRelation(ref)\n}\n\n/**\n * Resolve a listing block's query to its documents for the canvas (EC-255) — the\n * studio analog of the host's baked listings map. Runs the query (collection +\n * AND-only filter, optional sort/limit) through the active session's client\n * (published perspective, active locale), so the canvas previews a dynamic grid (a\n * ProductGrid keyed to a category) exactly as delivery renders it. An invalid query\n * (structured, never thrown) or a non-list lookup yields `[]` → the block's empty\n * state. Reuses the same `listDocuments` path as `runCollectionListQuery`.\n */\nexport function resolveCanvasListing(\n query: ListingQuery,\n locale: Locale = getStudioLocale(),\n perspective: CanvasPerspective = 'published',\n): ResolvedDocument[] {\n const result = clientFor(locale, perspective).listDocuments(query.collection, {\n where: query.where,\n ...(query.sort ? { sort: query.sort } : {}),\n ...(query.limit !== undefined ? { limit: query.limit } : {}),\n })\n return result.ok ? result.documents : []\n}\n\n/**\n * Resolve a rich-text internal link's target document to its URL path for the canvas\n * (EC-291) — the studio analog of the host's baked links map. Derives the URL through\n * the active session's client (published perspective, active locale, config-sourced\n * routes), so the canvas previews a `{type:'reference'}` link's `href` exactly as\n * delivery serves it. `null` when the target is unpublished, missing, or addressed by\n * no route → the rich-text renderer shows the EC-290 `unresolved-ref` issue. Reuses\n * the same `resolveLink` path as the host bake, so both agree on the derived URL.\n */\nexport function resolveCanvasLink(\n ref: DocumentRef,\n locale: Locale = getStudioLocale(),\n perspective: CanvasPerspective = 'published',\n): string | null {\n return clientFor(locale, perspective).resolveLink(ref)\n}\n\n/** A pickable entry of a collection (the template-page preview switcher). */\nexport interface CollectionEntrySummary {\n id: string\n label: string\n}\n\n/** Published entries of a collection, labeled by the schema's title field. */\nexport function listCollectionEntries(collectionId: string): CollectionEntrySummary[] {\n const collection = playgroundCollection(collectionId)\n const result = runCollectionListQuery(collectionId)\n if (!result.ok) return []\n return result.documents.map((doc) => {\n const title = collection?.titleField ? doc[collection.titleField] : undefined\n return { id: doc.id, label: typeof title === 'string' && title.length > 0 ? title : doc.id }\n })\n}\n"]}
@@ -206,6 +206,7 @@ function assetRecordFromDoc(doc) {
206
206
  ...(doc.title !== undefined ? { title: doc.title } : {}),
207
207
  ...(doc.url !== undefined ? { url: doc.url } : {}),
208
208
  ...(doc.focalPoint !== undefined ? { focalPoint: doc.focalPoint } : {}),
209
+ ...(doc.meta !== undefined ? { meta: doc.meta } : {}),
209
210
  storageKey: doc.storageKey,
210
211
  createdAt: doc.createdAt,
211
212
  updatedAt: doc.updatedAt,
@@ -233,6 +234,7 @@ class ConvexAssetRepository {
233
234
  ...(input.title !== undefined ? { title: input.title } : {}),
234
235
  ...(input.url !== undefined ? { url: input.url } : {}),
235
236
  ...(input.focalPoint !== undefined ? { focalPoint: input.focalPoint } : {}),
237
+ ...(input.meta !== undefined ? { meta: input.meta } : {}),
236
238
  storageKey: input.storageKey ?? `${projectId}/${id}`,
237
239
  createdAt: now,
238
240
  updatedAt: now,
@@ -1 +1 @@
1
- {"version":3,"file":"convex-adapter.js","sourceRoot":"","sources":["../../../src/lib/persistence/convex-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ConvexHttpClient } from 'convex/browser'\nimport { documentKey, documentSchema } from '@elytracms/core/cms-core'\nimport type { CmsDocument, CollectionDef, DocumentRef } from '@elytracms/core/cms-core'\nimport {\n RecordNotFoundError,\n PersistenceValidationError,\n compareReferenceEntries,\n validateForPersistence,\n} from '@elytracms/core/persistence'\nimport type {\n AssetRecord,\n AssetRepository,\n BackendStatus,\n BackendValidationInput,\n BackendValidationResult,\n BlobStorageAdapter,\n CliTokenRecord,\n CliTokenRepository,\n CmsRepository,\n CmsSchemaRecord,\n CmsDocumentRecord,\n DocumentVersionRecord,\n SaveDocumentVersionOptions,\n MembersRepository,\n NewAssetInput,\n NewCliTokenInput,\n PersistenceAdapter,\n OutboundReference,\n ProjectMemberRecord,\n ProjectRole,\n ReferenceEntry,\n ReferenceEntryRecord,\n ReferenceIndexBuildMarker,\n ReferenceIndexRepository,\n ReferenceLookupOptions,\n ReferenceSource,\n ReferenceSourceType,\n ReferenceTarget,\n ReferenceVariant,\n} from '@elytracms/core/persistence'\nimport { queryRef, mutationRef } from './convex-client'\nimport { ConvexBlobStorage } from './convex-blob-storage'\n\n/** Wall-clock for runtime writes (deterministic seeds use a fixed clock instead). */\ntype Clock = () => string\nconst realClock: Clock = () => new Date().toISOString()\n\nfunction newId(prefix: string): string {\n const rand =\n typeof globalThis.crypto?.randomUUID === 'function'\n ? globalThis.crypto.randomUUID()\n : Math.abs(Date.parse(new Date().toISOString())).toString(36)\n return `${prefix}_${rand}`\n}\n\n// --- CMS, Assets ----------------------------------------------------------\n\n/**\n * Deterministic, config-owned schema timestamps (EC-183). CMS collections live\n * in `elytra.config.ts`, not the backend, so the synthesized `CmsSchemaRecord`\n * carries a stable placeholder rather than DB-row timestamps.\n */\nconst CONFIG_SCHEMA_TIMESTAMP = '2026-01-01T00:00:00.000Z'\n\ninterface DocumentDoc {\n projectId: string\n document: CmsDocument\n publishedVersion?: number\n createdAt: string\n updatedAt: string\n}\nfunction docRecordFromDoc(doc: DocumentDoc): CmsDocumentRecord {\n return {\n projectId: doc.projectId,\n document: doc.document,\n ...(doc.publishedVersion !== undefined ? { publishedVersion: doc.publishedVersion } : {}),\n createdAt: doc.createdAt,\n updatedAt: doc.updatedAt,\n }\n}\n\ninterface VersionDoc {\n collection: string\n docId: string\n version: number\n snapshot: CmsDocument\n label?: string\n createdAt: string\n}\n/** The backend row carries no `projectId` (single-tenant); stamp it from the call. */\nfunction versionRecordFromDoc(doc: VersionDoc, projectId: string): DocumentVersionRecord {\n return {\n projectId,\n collection: doc.collection,\n docId: doc.docId,\n version: doc.version,\n snapshot: doc.snapshot,\n createdAt: doc.createdAt,\n ...(doc.label ? { label: doc.label } : {}),\n }\n}\n\nclass ConvexCmsRepository implements CmsRepository {\n /**\n * @param collections the active project's config-owned CMS collections\n * (EC-183, AD-11), injected from `elytra.config.ts`. The Convex backend has\n * no `cmsSchemas` table — `findSchema`/`getSchema` serve these instead.\n */\n constructor(\n private readonly client: ConvexHttpClient,\n private readonly collections: readonly CollectionDef[] = [],\n private readonly clock: Clock = realClock,\n ) {}\n\n async saveSchema(\n _projectId: string,\n _collections: readonly CollectionDef[],\n ): Promise<CmsSchemaRecord> {\n // Read-only (EC-183, AD-11): the CMS collection schema is owned by\n // `elytra.config.ts`; the backend stores documents only. A write here is a\n // visible, structured error rather than a silent no-op (the studio's CMS\n // schema surfaces are read-only; legitimate writers were removed in EC-183).\n throw new PersistenceValidationError(\n 'CMS collection schema is owned by elytra.config.ts and cannot be written to the backend.',\n [\n {\n code: 'schema-config-owned',\n message:\n 'Edit elytra.config.ts to change collections; the backend stores documents only.',\n path: [],\n domain: 'cms',\n },\n ],\n )\n }\n\n /** Config-owned schema (EC-183): the active project's collections from config. */\n private configSchema(projectId: string): CmsSchemaRecord {\n return {\n projectId,\n collections: [...this.collections],\n createdAt: CONFIG_SCHEMA_TIMESTAMP,\n updatedAt: CONFIG_SCHEMA_TIMESTAMP,\n }\n }\n\n async getSchema(projectId: string): Promise<CmsSchemaRecord> {\n return this.configSchema(projectId)\n }\n\n async findSchema(projectId: string): Promise<CmsSchemaRecord | undefined> {\n return this.configSchema(projectId)\n }\n\n async upsertDocument(projectId: string, document: CmsDocument): Promise<CmsDocumentRecord> {\n // The backend is a pure document store (EC-183, AD-11): collection-membership\n // validation lives in `@elytracms/core/cms-core` `validateDocument`, which the studio\n // runs pre-dispatch (cell edits, imports). We still parse the canonical\n // document shape so malformed blobs never reach storage.\n const parsedDoc = documentSchema.parse(document)\n const now = this.clock()\n const doc = (await this.client.mutation(mutationRef('cms:upsertDocument'), {\n collection: parsedDoc.collection,\n docId: parsedDoc.id,\n document: parsedDoc,\n createdAt: now,\n updatedAt: now,\n })) as DocumentDoc\n return docRecordFromDoc(doc)\n }\n\n async getDocument(projectId: string, ref: DocumentRef): Promise<CmsDocumentRecord> {\n const found = await this.findDocument(projectId, ref)\n if (!found)\n throw new RecordNotFoundError('cms-document', `${projectId}/${ref.collection}:${ref.id}`)\n return found\n }\n\n async findDocument(projectId: string, ref: DocumentRef): Promise<CmsDocumentRecord | undefined> {\n const doc = (await this.client.query(queryRef('cms:getDocument'), {\n collection: ref.collection,\n docId: ref.id,\n })) as DocumentDoc | null\n return doc ? docRecordFromDoc(doc) : undefined\n }\n\n async listDocuments(projectId: string, collection?: string): Promise<CmsDocumentRecord[]> {\n const docs = (await this.client.query(queryRef('cms:listDocuments'), {\n ...(collection ? { collection } : {}),\n })) as DocumentDoc[]\n // EC-153 parity: deterministic document-key ordering (Convex index order\n // within a project is insertion order, so we sort client-side).\n return docs\n .map(docRecordFromDoc)\n .sort((a, b) => (documentKey(a.document) < documentKey(b.document) ? -1 : 1))\n }\n\n async deleteDocument(projectId: string, ref: DocumentRef): Promise<void> {\n // EC-153 parity: deleting a missing document is not-found, never a no-op.\n await this.getDocument(projectId, ref)\n await this.client.mutation(mutationRef('cms:deleteDocument'), {\n collection: ref.collection,\n docId: ref.id,\n })\n }\n\n async saveDocumentVersion(\n projectId: string,\n snapshot: CmsDocument,\n options: SaveDocumentVersionOptions = {},\n ): Promise<DocumentVersionRecord> {\n const parsed = documentSchema.parse(snapshot)\n const doc = (await this.client.mutation(mutationRef('cms:saveDocumentVersion'), {\n collection: parsed.collection,\n docId: parsed.id,\n snapshot: parsed,\n createdAt: this.clock(),\n ...(options.label ? { label: options.label } : {}),\n })) as VersionDoc\n return versionRecordFromDoc(doc, projectId)\n }\n\n async listDocumentVersions(\n projectId: string,\n ref: DocumentRef,\n ): Promise<DocumentVersionRecord[]> {\n const docs = (await this.client.query(queryRef('cms:listDocumentVersions'), {\n collection: ref.collection,\n docId: ref.id,\n })) as VersionDoc[]\n return docs.map((doc) => versionRecordFromDoc(doc, projectId))\n }\n\n async listAllDocumentVersions(projectId: string): Promise<DocumentVersionRecord[]> {\n const docs = (await this.client.query(\n queryRef('cms:listAllDocumentVersions'),\n {},\n )) as VersionDoc[]\n return docs.map((doc) => versionRecordFromDoc(doc, projectId))\n }\n\n async getDocumentVersion(\n projectId: string,\n ref: DocumentRef,\n version: number,\n ): Promise<DocumentVersionRecord> {\n const doc = (await this.client.query(queryRef('cms:getDocumentVersion'), {\n collection: ref.collection,\n docId: ref.id,\n version,\n })) as VersionDoc | null\n if (!doc) {\n throw new RecordNotFoundError(\n 'cms-document-version',\n `${projectId}/${ref.collection}:${ref.id}#${version}`,\n )\n }\n return versionRecordFromDoc(doc, projectId)\n }\n\n async publishDocumentVersion(\n projectId: string,\n ref: DocumentRef,\n version: number,\n ): Promise<CmsDocumentRecord> {\n // Taxonomy enforced adapter-side (the handler is lenient): the document and\n // the pinned version must both exist (each throws RecordNotFoundError).\n await this.getDocument(projectId, ref)\n await this.getDocumentVersion(projectId, ref, version)\n const doc = (await this.client.mutation(mutationRef('cms:publishDocumentVersion'), {\n collection: ref.collection,\n docId: ref.id,\n version,\n updatedAt: this.clock(),\n })) as DocumentDoc\n return docRecordFromDoc(doc)\n }\n\n async unpublishDocument(projectId: string, ref: DocumentRef): Promise<CmsDocumentRecord> {\n const existing = await this.getDocument(projectId, ref)\n if (existing.publishedVersion === undefined) {\n throw new PersistenceValidationError('Document is not currently published.', [\n {\n code: 'invalid-transition',\n message: 'Cannot unpublish: the document has no published version.',\n domain: 'cms',\n },\n ])\n }\n const doc = (await this.client.mutation(mutationRef('cms:unpublishDocument'), {\n collection: ref.collection,\n docId: ref.id,\n updatedAt: this.clock(),\n })) as DocumentDoc\n return docRecordFromDoc(doc)\n }\n}\n\ninterface AssetDoc {\n projectId: string\n assetId: string\n filename: string\n contentType: string\n byteSize: number\n width?: number\n height?: number\n alt?: string\n /** Editable display title (EC-152). */\n title?: string\n storageKey: string\n url?: string\n /** Normalized image focal point `{ x, y }` in 0–1 (EC-230). */\n focalPoint?: { x: number; y: number }\n createdAt: string\n updatedAt: string\n}\n\n/** Map a Convex asset doc onto the contract record (assetId → id, drop _id/_creationTime). */\nfunction assetRecordFromDoc(doc: AssetDoc): AssetRecord {\n return {\n id: doc.assetId,\n projectId: doc.projectId,\n filename: doc.filename,\n contentType: doc.contentType,\n byteSize: doc.byteSize,\n ...(doc.width !== undefined ? { width: doc.width } : {}),\n ...(doc.height !== undefined ? { height: doc.height } : {}),\n ...(doc.alt !== undefined ? { alt: doc.alt } : {}),\n ...(doc.title !== undefined ? { title: doc.title } : {}),\n ...(doc.url !== undefined ? { url: doc.url } : {}),\n ...(doc.focalPoint !== undefined ? { focalPoint: doc.focalPoint } : {}),\n storageKey: doc.storageKey,\n createdAt: doc.createdAt,\n updatedAt: doc.updatedAt,\n }\n}\n\nclass ConvexAssetRepository implements AssetRepository {\n constructor(\n private readonly client: ConvexHttpClient,\n private readonly clock: Clock = realClock,\n ) {}\n\n async upsertAsset(projectId: string, input: NewAssetInput): Promise<AssetRecord> {\n const now = this.clock()\n const id = input.id ?? newId('asset')\n const doc = (await this.client.mutation(mutationRef('assets:upsert'), {\n assetId: id,\n filename: input.filename,\n contentType: input.contentType,\n byteSize: input.byteSize,\n ...(input.width !== undefined ? { width: input.width } : {}),\n ...(input.height !== undefined ? { height: input.height } : {}),\n ...(input.alt !== undefined ? { alt: input.alt } : {}),\n // EC-153 parity: `title` (EC-152 metadata) must persist, not silently drop.\n ...(input.title !== undefined ? { title: input.title } : {}),\n ...(input.url !== undefined ? { url: input.url } : {}),\n ...(input.focalPoint !== undefined ? { focalPoint: input.focalPoint } : {}),\n storageKey: input.storageKey ?? `${projectId}/${id}`,\n createdAt: now,\n updatedAt: now,\n })) as AssetDoc\n return assetRecordFromDoc(doc)\n }\n\n async getAsset(projectId: string, id: string): Promise<AssetRecord> {\n const found = await this.findAsset(projectId, id)\n if (!found) throw new RecordNotFoundError('asset', `${projectId}/${id}`)\n return found\n }\n\n async findAsset(projectId: string, id: string): Promise<AssetRecord | undefined> {\n const doc = (await this.client.query(queryRef('assets:get'), {\n assetId: id,\n })) as AssetDoc | null\n return doc ? assetRecordFromDoc(doc) : undefined\n }\n\n async listAssets(projectId: string): Promise<AssetRecord[]> {\n const docs = (await this.client.query(queryRef('assets:list'), {})) as AssetDoc[]\n return docs.map(assetRecordFromDoc)\n }\n\n async removeAsset(projectId: string, id: string): Promise<void> {\n // EC-153 parity: removing an unknown asset is not-found, never a no-op.\n await this.getAsset(projectId, id)\n await this.client.mutation(mutationRef('assets:remove'), { assetId: id })\n }\n\n async resolveMany(projectId: string, ids: readonly string[]): Promise<Map<string, AssetRecord>> {\n const all = await this.listAssets(projectId)\n const out = new Map<string, AssetRecord>()\n for (const asset of all) if (ids.includes(asset.id)) out.set(asset.id, asset)\n return out\n }\n}\n\n// --- Reference index (EC-155) ------------------------------------------------\n\n/** A Convex reference-entry doc (flattened source/target for index-backed lookups). */\ninterface ReferenceEntryDoc {\n projectId: string\n variant: ReferenceVariant\n sourceType: ReferenceSourceType\n sourceId: string\n path: string\n targetType: ReferenceTarget['type']\n targetId: string\n kind: ReferenceEntryRecord['kind']\n}\n\nfunction referenceRecordFromDoc(doc: ReferenceEntryDoc): ReferenceEntryRecord {\n return {\n projectId: doc.projectId,\n variant: doc.variant,\n source: { type: doc.sourceType, id: doc.sourceId },\n path: doc.path,\n target: { type: doc.targetType, id: doc.targetId },\n kind: doc.kind,\n }\n}\n\n/** Deterministic ordering is a repository contract; Convex docs sort client-side. */\nfunction sortedReferenceRecords(docs: ReferenceEntryDoc[]): ReferenceEntryRecord[] {\n return docs.map(referenceRecordFromDoc).sort(compareReferenceEntries)\n}\n\nclass ConvexReferenceIndexRepository implements ReferenceIndexRepository {\n constructor(private readonly client: ConvexHttpClient) {}\n\n async replaceForSource(\n projectId: string,\n variant: ReferenceVariant,\n source: ReferenceSource,\n references: readonly OutboundReference[],\n ): Promise<ReferenceEntryRecord[]> {\n await this.client.mutation(mutationRef('references:replaceForSource'), {\n variant,\n sourceType: source.type,\n sourceId: source.id,\n references: references.map((r) => ({\n path: r.path,\n targetType: r.target.type,\n targetId: r.target.id,\n kind: r.kind,\n })),\n })\n return this.outbound(projectId, source, { variant })\n }\n\n async replaceForSourceTypes(\n projectId: string,\n variant: ReferenceVariant,\n sourceTypes: readonly ReferenceSourceType[],\n entries: readonly ReferenceEntry[],\n ): Promise<ReferenceEntryRecord[]> {\n await this.client.mutation(mutationRef('references:replaceForSourceTypes'), {\n variant,\n sourceTypes: [...sourceTypes],\n entries: entries.map((e) => ({\n sourceType: e.source.type,\n sourceId: e.source.id,\n path: e.path,\n targetType: e.target.type,\n targetId: e.target.id,\n kind: e.kind,\n })),\n })\n const all = await this.listEntries(projectId, variant)\n const types = new Set(sourceTypes)\n return all.filter((record) => types.has(record.source.type))\n }\n\n async removeForSource(\n projectId: string,\n source: ReferenceSource,\n variant?: ReferenceVariant,\n ): Promise<void> {\n await this.client.mutation(mutationRef('references:removeForSource'), {\n sourceType: source.type,\n sourceId: source.id,\n ...(variant ? { variant } : {}),\n })\n }\n\n async outbound(\n projectId: string,\n source: ReferenceSource,\n options: ReferenceLookupOptions = {},\n ): Promise<ReferenceEntryRecord[]> {\n const docs = (await this.client.query(queryRef('references:outbound'), {\n sourceType: source.type,\n sourceId: source.id,\n ...(options.variant ? { variant: options.variant } : {}),\n })) as ReferenceEntryDoc[]\n return sortedReferenceRecords(docs)\n }\n\n async inbound(\n projectId: string,\n target: ReferenceTarget,\n options: ReferenceLookupOptions = {},\n ): Promise<ReferenceEntryRecord[]> {\n const docs = (await this.client.query(queryRef('references:inbound'), {\n targetType: target.type,\n targetId: target.id,\n ...(options.variant ? { variant: options.variant } : {}),\n })) as ReferenceEntryDoc[]\n return sortedReferenceRecords(docs)\n }\n\n async listEntries(\n projectId: string,\n variant?: ReferenceVariant,\n ): Promise<ReferenceEntryRecord[]> {\n const docs = (await this.client.query(queryRef('references:list'), {\n ...(variant ? { variant } : {}),\n })) as ReferenceEntryDoc[]\n return sortedReferenceRecords(docs)\n }\n\n async getBuildMarker(projectId: string): Promise<ReferenceIndexBuildMarker | null> {\n return (await this.client.query(queryRef('references:buildMarker'), {})) as\n | ReferenceIndexBuildMarker\n | null\n }\n\n async setBuildMarker(projectId: string, marker: ReferenceIndexBuildMarker): Promise<void> {\n await this.client.mutation(mutationRef('references:setBuildMarker'), {\n entryCount: marker.entryCount,\n })\n }\n\n async clearProject(projectId: string): Promise<void> {\n await this.client.mutation(mutationRef('references:clearProject'), {})\n }\n}\n\n// --- Members + CLI tokens (EC-150) -------------------------------------------\n\ninterface MemberDoc {\n userId: string\n role: ProjectRole\n createdAt: string\n updatedAt: string\n}\n\n/**\n * Single-tenant (EC-179): membership is deployment-scoped, so the backend rows\n * carry no `projectId`. The contract record still does — this adapter is bound\n * to its deployment's project, so it stamps that slug onto every record.\n */\nfunction memberRecordFromDoc(doc: MemberDoc, projectId: string): ProjectMemberRecord {\n return {\n projectId,\n userId: doc.userId,\n role: doc.role,\n createdAt: doc.createdAt,\n updatedAt: doc.updatedAt,\n }\n}\n\nclass ConvexMembersRepository implements MembersRepository {\n constructor(\n private readonly client: ConvexHttpClient,\n /** The slug of this deployment's one project — stamped onto records. */\n private readonly boundProjectId: string,\n private readonly clock: Clock = realClock,\n ) {}\n\n async setMember(\n projectId: string,\n userId: string,\n role: ProjectRole,\n ): Promise<ProjectMemberRecord> {\n const now = this.clock()\n const doc = (await this.client.mutation(mutationRef('members:set'), {\n userId,\n role,\n createdAt: now,\n updatedAt: now,\n })) as MemberDoc\n return memberRecordFromDoc(doc, projectId)\n }\n\n async findMember(projectId: string, userId: string): Promise<ProjectMemberRecord | undefined> {\n const doc = (await this.client.query(queryRef('members:get'), {\n userId,\n })) as MemberDoc | null\n return doc ? memberRecordFromDoc(doc, projectId) : undefined\n }\n\n async listMembers(projectId: string): Promise<ProjectMemberRecord[]> {\n const docs = (await this.client.query(queryRef('members:list'), {})) as MemberDoc[]\n return docs.map((d) => memberRecordFromDoc(d, projectId))\n }\n\n async listMembershipsForUser(userId: string): Promise<ProjectMemberRecord[]> {\n // `members:mine` is caller-scoped server-side and returns the caller's single\n // deployment membership (or null). The studio only ever asks about the\n // session user; records are stamped with this deployment's bound project.\n const doc = (await this.client.query(queryRef('members:mine'), {})) as MemberDoc | null\n return doc && doc.userId === userId ? [memberRecordFromDoc(doc, this.boundProjectId)] : []\n }\n\n async removeMember(projectId: string, userId: string): Promise<void> {\n try {\n await this.client.mutation(mutationRef('members:remove'), { userId })\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n if (/not-found/i.test(message)) {\n throw new RecordNotFoundError('project-member', `${projectId}/${userId}`)\n }\n throw error\n }\n }\n}\n\ninterface CliTokenDoc {\n /** Retired (EC-182): optional only because live rows may still carry it until the migration clears it. */\n projectId?: string\n tokenId: string\n label: string\n tokenHash: string\n createdAt: string\n revokedAt?: string\n}\n\nfunction cliTokenRecordFromDoc(doc: CliTokenDoc): CliTokenRecord {\n return {\n id: doc.tokenId,\n label: doc.label,\n tokenHash: doc.tokenHash,\n createdAt: doc.createdAt,\n ...(doc.revokedAt ? { revokedAt: doc.revokedAt } : {}),\n }\n}\n\nclass ConvexCliTokenRepository implements CliTokenRepository {\n constructor(\n private readonly client: ConvexHttpClient,\n private readonly clock: Clock = realClock,\n ) {}\n\n async createToken(input: NewCliTokenInput): Promise<CliTokenRecord> {\n const doc = (await this.client.mutation(mutationRef('cliTokens:create'), {\n tokenId: newId('tok'),\n label: input.label,\n tokenHash: input.tokenHash,\n createdAt: this.clock(),\n })) as CliTokenDoc\n return cliTokenRecordFromDoc(doc)\n }\n\n async listTokens(): Promise<CliTokenRecord[]> {\n const docs = (await this.client.query(queryRef('cliTokens:list'), {})) as CliTokenDoc[]\n return docs.map(cliTokenRecordFromDoc)\n }\n\n async revokeToken(tokenId: string): Promise<CliTokenRecord> {\n try {\n const doc = (await this.client.mutation(mutationRef('cliTokens:revoke'), {\n tokenId,\n revokedAt: this.clock(),\n })) as CliTokenDoc\n return cliTokenRecordFromDoc(doc)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n if (/not-found/i.test(message)) {\n throw new RecordNotFoundError('cli-token', tokenId)\n }\n throw error\n }\n }\n\n async findByHash(tokenHash: string): Promise<CliTokenRecord | undefined> {\n const doc = (await this.client.query(queryRef('cliTokens:byHash'), {\n tokenHash,\n })) as CliTokenDoc | null\n return doc ? cliTokenRecordFromDoc(doc) : undefined\n }\n}\n\n/**\n * Convex-backed {@link PersistenceAdapter} (brief §10, EC-039). Every repository\n * is implemented against the Convex functions in `apps/builder/convex/*`, mapping\n * results and failures onto the provider-neutral contracts + error taxonomies.\n */\nexport class ConvexPersistenceAdapter implements PersistenceAdapter {\n readonly cms: CmsRepository\n readonly assets: AssetRepository\n /** Reference index — outbound/inbound entries per variant (EC-155, AD-6). */\n readonly references: ReferenceIndexRepository\n /** Per-project membership roles (EC-150). */\n readonly members: MembersRepository\n /** Revocable CLI sync tokens, stored hashed (EC-150). */\n readonly cliTokens: CliTokenRepository\n /** Convex file storage behind the EC-133 blob boundary (EC-151). */\n readonly blobs: BlobStorageAdapter\n /**\n * EC-277: the Convex mutations maintain the reference index in-transaction\n * (`convex/referenceMaintenance.ts`), so every writer — studio, CLI, webhook,\n * raw `convex run` — is caught at the source. The studio bootstrap therefore does\n * NOT attach the client-side `attachReferenceIndex` subscriber for this provider.\n */\n readonly maintainsReferenceIndex = true\n\n /**\n * @param client the Convex client bound to this deployment (one project).\n * @param projectId the slug of this deployment's one project (EC-179). Used to\n * stamp deployment-scoped member records onto the still-project-keyed contract.\n * @param collections the active project's config-owned CMS collections (EC-183,\n * AD-11), from `elytra.config.ts`. The backend has no `cmsSchemas` table, so\n * the CMS repository serves the schema from these.\n */\n constructor(\n private readonly client: ConvexHttpClient,\n projectId: string,\n collections: readonly CollectionDef[] = [],\n ) {\n this.cms = new ConvexCmsRepository(client, collections)\n this.assets = new ConvexAssetRepository(client)\n this.references = new ConvexReferenceIndexRepository(client)\n this.members = new ConvexMembersRepository(client, projectId)\n this.cliTokens = new ConvexCliTokenRepository(client)\n this.blobs = new ConvexBlobStorage(client)\n }\n\n async status(): Promise<BackendStatus> {\n try {\n // Lightweight connectivity probe (EC-182: no `projects` table). `members:mine`\n // takes no args and is soft-guarded (EC-279): it answers `null` for an\n // unauthenticated caller rather than throwing, so the pre-sign-in boot probe\n // resolves cleanly — backend answered ⇒ `available: true` — with no scary\n // `Uncaught Error` in the Convex log.\n await this.client.query(queryRef('members:mine'), {})\n return { backend: 'convex', available: true }\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error)\n // EC-153: an `unauthorized` rejection *is* a healthy backend — the\n // deployment answered and enforced auth. Now that `members:mine` is\n // soft-guarded this branch is a defensive fallback (a protected probe could\n // still throw); only transport/server failures count as unavailable, so the\n // BackendGate surfaces those visibly instead of falling back to in-memory.\n if (/unauthorized/i.test(detail)) return { backend: 'convex', available: true }\n return { backend: 'convex', available: false, detail }\n }\n }\n\n validate(input: BackendValidationInput): BackendValidationResult {\n return validateForPersistence(input)\n }\n}\n"]}
1
+ {"version":3,"file":"convex-adapter.js","sourceRoot":"","sources":["../../../src/lib/persistence/convex-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ConvexHttpClient } from 'convex/browser'\nimport { documentKey, documentSchema } from '@elytracms/core/cms-core'\nimport type { CmsDocument, CollectionDef, DocumentRef } from '@elytracms/core/cms-core'\nimport {\n RecordNotFoundError,\n PersistenceValidationError,\n compareReferenceEntries,\n validateForPersistence,\n} from '@elytracms/core/persistence'\nimport type {\n AssetRecord,\n AssetRepository,\n BackendStatus,\n BackendValidationInput,\n BackendValidationResult,\n BlobStorageAdapter,\n CliTokenRecord,\n CliTokenRepository,\n CmsRepository,\n CmsSchemaRecord,\n CmsDocumentRecord,\n DocumentVersionRecord,\n SaveDocumentVersionOptions,\n MembersRepository,\n NewAssetInput,\n NewCliTokenInput,\n PersistenceAdapter,\n OutboundReference,\n ProjectMemberRecord,\n ProjectRole,\n ReferenceEntry,\n ReferenceEntryRecord,\n ReferenceIndexBuildMarker,\n ReferenceIndexRepository,\n ReferenceLookupOptions,\n ReferenceSource,\n ReferenceSourceType,\n ReferenceTarget,\n ReferenceVariant,\n} from '@elytracms/core/persistence'\nimport { queryRef, mutationRef } from './convex-client'\nimport { ConvexBlobStorage } from './convex-blob-storage'\n\n/** Wall-clock for runtime writes (deterministic seeds use a fixed clock instead). */\ntype Clock = () => string\nconst realClock: Clock = () => new Date().toISOString()\n\nfunction newId(prefix: string): string {\n const rand =\n typeof globalThis.crypto?.randomUUID === 'function'\n ? globalThis.crypto.randomUUID()\n : Math.abs(Date.parse(new Date().toISOString())).toString(36)\n return `${prefix}_${rand}`\n}\n\n// --- CMS, Assets ----------------------------------------------------------\n\n/**\n * Deterministic, config-owned schema timestamps (EC-183). CMS collections live\n * in `elytra.config.ts`, not the backend, so the synthesized `CmsSchemaRecord`\n * carries a stable placeholder rather than DB-row timestamps.\n */\nconst CONFIG_SCHEMA_TIMESTAMP = '2026-01-01T00:00:00.000Z'\n\ninterface DocumentDoc {\n projectId: string\n document: CmsDocument\n publishedVersion?: number\n createdAt: string\n updatedAt: string\n}\nfunction docRecordFromDoc(doc: DocumentDoc): CmsDocumentRecord {\n return {\n projectId: doc.projectId,\n document: doc.document,\n ...(doc.publishedVersion !== undefined ? { publishedVersion: doc.publishedVersion } : {}),\n createdAt: doc.createdAt,\n updatedAt: doc.updatedAt,\n }\n}\n\ninterface VersionDoc {\n collection: string\n docId: string\n version: number\n snapshot: CmsDocument\n label?: string\n createdAt: string\n}\n/** The backend row carries no `projectId` (single-tenant); stamp it from the call. */\nfunction versionRecordFromDoc(doc: VersionDoc, projectId: string): DocumentVersionRecord {\n return {\n projectId,\n collection: doc.collection,\n docId: doc.docId,\n version: doc.version,\n snapshot: doc.snapshot,\n createdAt: doc.createdAt,\n ...(doc.label ? { label: doc.label } : {}),\n }\n}\n\nclass ConvexCmsRepository implements CmsRepository {\n /**\n * @param collections the active project's config-owned CMS collections\n * (EC-183, AD-11), injected from `elytra.config.ts`. The Convex backend has\n * no `cmsSchemas` table — `findSchema`/`getSchema` serve these instead.\n */\n constructor(\n private readonly client: ConvexHttpClient,\n private readonly collections: readonly CollectionDef[] = [],\n private readonly clock: Clock = realClock,\n ) {}\n\n async saveSchema(\n _projectId: string,\n _collections: readonly CollectionDef[],\n ): Promise<CmsSchemaRecord> {\n // Read-only (EC-183, AD-11): the CMS collection schema is owned by\n // `elytra.config.ts`; the backend stores documents only. A write here is a\n // visible, structured error rather than a silent no-op (the studio's CMS\n // schema surfaces are read-only; legitimate writers were removed in EC-183).\n throw new PersistenceValidationError(\n 'CMS collection schema is owned by elytra.config.ts and cannot be written to the backend.',\n [\n {\n code: 'schema-config-owned',\n message:\n 'Edit elytra.config.ts to change collections; the backend stores documents only.',\n path: [],\n domain: 'cms',\n },\n ],\n )\n }\n\n /** Config-owned schema (EC-183): the active project's collections from config. */\n private configSchema(projectId: string): CmsSchemaRecord {\n return {\n projectId,\n collections: [...this.collections],\n createdAt: CONFIG_SCHEMA_TIMESTAMP,\n updatedAt: CONFIG_SCHEMA_TIMESTAMP,\n }\n }\n\n async getSchema(projectId: string): Promise<CmsSchemaRecord> {\n return this.configSchema(projectId)\n }\n\n async findSchema(projectId: string): Promise<CmsSchemaRecord | undefined> {\n return this.configSchema(projectId)\n }\n\n async upsertDocument(projectId: string, document: CmsDocument): Promise<CmsDocumentRecord> {\n // The backend is a pure document store (EC-183, AD-11): collection-membership\n // validation lives in `@elytracms/core/cms-core` `validateDocument`, which the studio\n // runs pre-dispatch (cell edits, imports). We still parse the canonical\n // document shape so malformed blobs never reach storage.\n const parsedDoc = documentSchema.parse(document)\n const now = this.clock()\n const doc = (await this.client.mutation(mutationRef('cms:upsertDocument'), {\n collection: parsedDoc.collection,\n docId: parsedDoc.id,\n document: parsedDoc,\n createdAt: now,\n updatedAt: now,\n })) as DocumentDoc\n return docRecordFromDoc(doc)\n }\n\n async getDocument(projectId: string, ref: DocumentRef): Promise<CmsDocumentRecord> {\n const found = await this.findDocument(projectId, ref)\n if (!found)\n throw new RecordNotFoundError('cms-document', `${projectId}/${ref.collection}:${ref.id}`)\n return found\n }\n\n async findDocument(projectId: string, ref: DocumentRef): Promise<CmsDocumentRecord | undefined> {\n const doc = (await this.client.query(queryRef('cms:getDocument'), {\n collection: ref.collection,\n docId: ref.id,\n })) as DocumentDoc | null\n return doc ? docRecordFromDoc(doc) : undefined\n }\n\n async listDocuments(projectId: string, collection?: string): Promise<CmsDocumentRecord[]> {\n const docs = (await this.client.query(queryRef('cms:listDocuments'), {\n ...(collection ? { collection } : {}),\n })) as DocumentDoc[]\n // EC-153 parity: deterministic document-key ordering (Convex index order\n // within a project is insertion order, so we sort client-side).\n return docs\n .map(docRecordFromDoc)\n .sort((a, b) => (documentKey(a.document) < documentKey(b.document) ? -1 : 1))\n }\n\n async deleteDocument(projectId: string, ref: DocumentRef): Promise<void> {\n // EC-153 parity: deleting a missing document is not-found, never a no-op.\n await this.getDocument(projectId, ref)\n await this.client.mutation(mutationRef('cms:deleteDocument'), {\n collection: ref.collection,\n docId: ref.id,\n })\n }\n\n async saveDocumentVersion(\n projectId: string,\n snapshot: CmsDocument,\n options: SaveDocumentVersionOptions = {},\n ): Promise<DocumentVersionRecord> {\n const parsed = documentSchema.parse(snapshot)\n const doc = (await this.client.mutation(mutationRef('cms:saveDocumentVersion'), {\n collection: parsed.collection,\n docId: parsed.id,\n snapshot: parsed,\n createdAt: this.clock(),\n ...(options.label ? { label: options.label } : {}),\n })) as VersionDoc\n return versionRecordFromDoc(doc, projectId)\n }\n\n async listDocumentVersions(\n projectId: string,\n ref: DocumentRef,\n ): Promise<DocumentVersionRecord[]> {\n const docs = (await this.client.query(queryRef('cms:listDocumentVersions'), {\n collection: ref.collection,\n docId: ref.id,\n })) as VersionDoc[]\n return docs.map((doc) => versionRecordFromDoc(doc, projectId))\n }\n\n async listAllDocumentVersions(projectId: string): Promise<DocumentVersionRecord[]> {\n const docs = (await this.client.query(\n queryRef('cms:listAllDocumentVersions'),\n {},\n )) as VersionDoc[]\n return docs.map((doc) => versionRecordFromDoc(doc, projectId))\n }\n\n async getDocumentVersion(\n projectId: string,\n ref: DocumentRef,\n version: number,\n ): Promise<DocumentVersionRecord> {\n const doc = (await this.client.query(queryRef('cms:getDocumentVersion'), {\n collection: ref.collection,\n docId: ref.id,\n version,\n })) as VersionDoc | null\n if (!doc) {\n throw new RecordNotFoundError(\n 'cms-document-version',\n `${projectId}/${ref.collection}:${ref.id}#${version}`,\n )\n }\n return versionRecordFromDoc(doc, projectId)\n }\n\n async publishDocumentVersion(\n projectId: string,\n ref: DocumentRef,\n version: number,\n ): Promise<CmsDocumentRecord> {\n // Taxonomy enforced adapter-side (the handler is lenient): the document and\n // the pinned version must both exist (each throws RecordNotFoundError).\n await this.getDocument(projectId, ref)\n await this.getDocumentVersion(projectId, ref, version)\n const doc = (await this.client.mutation(mutationRef('cms:publishDocumentVersion'), {\n collection: ref.collection,\n docId: ref.id,\n version,\n updatedAt: this.clock(),\n })) as DocumentDoc\n return docRecordFromDoc(doc)\n }\n\n async unpublishDocument(projectId: string, ref: DocumentRef): Promise<CmsDocumentRecord> {\n const existing = await this.getDocument(projectId, ref)\n if (existing.publishedVersion === undefined) {\n throw new PersistenceValidationError('Document is not currently published.', [\n {\n code: 'invalid-transition',\n message: 'Cannot unpublish: the document has no published version.',\n domain: 'cms',\n },\n ])\n }\n const doc = (await this.client.mutation(mutationRef('cms:unpublishDocument'), {\n collection: ref.collection,\n docId: ref.id,\n updatedAt: this.clock(),\n })) as DocumentDoc\n return docRecordFromDoc(doc)\n }\n}\n\ninterface AssetDoc {\n projectId: string\n assetId: string\n filename: string\n contentType: string\n byteSize: number\n width?: number\n height?: number\n alt?: string\n /** Editable display title (EC-152). */\n title?: string\n storageKey: string\n url?: string\n /** Normalized image focal point `{ x, y }` in 0–1 (EC-230). */\n focalPoint?: { x: number; y: number }\n /** Schema-driven asset metadata bag (EC-301). */\n meta?: Record<string, unknown>\n createdAt: string\n updatedAt: string\n}\n\n/** Map a Convex asset doc onto the contract record (assetId → id, drop _id/_creationTime). */\nfunction assetRecordFromDoc(doc: AssetDoc): AssetRecord {\n return {\n id: doc.assetId,\n projectId: doc.projectId,\n filename: doc.filename,\n contentType: doc.contentType,\n byteSize: doc.byteSize,\n ...(doc.width !== undefined ? { width: doc.width } : {}),\n ...(doc.height !== undefined ? { height: doc.height } : {}),\n ...(doc.alt !== undefined ? { alt: doc.alt } : {}),\n ...(doc.title !== undefined ? { title: doc.title } : {}),\n ...(doc.url !== undefined ? { url: doc.url } : {}),\n ...(doc.focalPoint !== undefined ? { focalPoint: doc.focalPoint } : {}),\n ...(doc.meta !== undefined ? { meta: doc.meta } : {}),\n storageKey: doc.storageKey,\n createdAt: doc.createdAt,\n updatedAt: doc.updatedAt,\n }\n}\n\nclass ConvexAssetRepository implements AssetRepository {\n constructor(\n private readonly client: ConvexHttpClient,\n private readonly clock: Clock = realClock,\n ) {}\n\n async upsertAsset(projectId: string, input: NewAssetInput): Promise<AssetRecord> {\n const now = this.clock()\n const id = input.id ?? newId('asset')\n const doc = (await this.client.mutation(mutationRef('assets:upsert'), {\n assetId: id,\n filename: input.filename,\n contentType: input.contentType,\n byteSize: input.byteSize,\n ...(input.width !== undefined ? { width: input.width } : {}),\n ...(input.height !== undefined ? { height: input.height } : {}),\n ...(input.alt !== undefined ? { alt: input.alt } : {}),\n // EC-153 parity: `title` (EC-152 metadata) must persist, not silently drop.\n ...(input.title !== undefined ? { title: input.title } : {}),\n ...(input.url !== undefined ? { url: input.url } : {}),\n ...(input.focalPoint !== undefined ? { focalPoint: input.focalPoint } : {}),\n ...(input.meta !== undefined ? { meta: input.meta } : {}),\n storageKey: input.storageKey ?? `${projectId}/${id}`,\n createdAt: now,\n updatedAt: now,\n })) as AssetDoc\n return assetRecordFromDoc(doc)\n }\n\n async getAsset(projectId: string, id: string): Promise<AssetRecord> {\n const found = await this.findAsset(projectId, id)\n if (!found) throw new RecordNotFoundError('asset', `${projectId}/${id}`)\n return found\n }\n\n async findAsset(projectId: string, id: string): Promise<AssetRecord | undefined> {\n const doc = (await this.client.query(queryRef('assets:get'), {\n assetId: id,\n })) as AssetDoc | null\n return doc ? assetRecordFromDoc(doc) : undefined\n }\n\n async listAssets(projectId: string): Promise<AssetRecord[]> {\n const docs = (await this.client.query(queryRef('assets:list'), {})) as AssetDoc[]\n return docs.map(assetRecordFromDoc)\n }\n\n async removeAsset(projectId: string, id: string): Promise<void> {\n // EC-153 parity: removing an unknown asset is not-found, never a no-op.\n await this.getAsset(projectId, id)\n await this.client.mutation(mutationRef('assets:remove'), { assetId: id })\n }\n\n async resolveMany(projectId: string, ids: readonly string[]): Promise<Map<string, AssetRecord>> {\n const all = await this.listAssets(projectId)\n const out = new Map<string, AssetRecord>()\n for (const asset of all) if (ids.includes(asset.id)) out.set(asset.id, asset)\n return out\n }\n}\n\n// --- Reference index (EC-155) ------------------------------------------------\n\n/** A Convex reference-entry doc (flattened source/target for index-backed lookups). */\ninterface ReferenceEntryDoc {\n projectId: string\n variant: ReferenceVariant\n sourceType: ReferenceSourceType\n sourceId: string\n path: string\n targetType: ReferenceTarget['type']\n targetId: string\n kind: ReferenceEntryRecord['kind']\n}\n\nfunction referenceRecordFromDoc(doc: ReferenceEntryDoc): ReferenceEntryRecord {\n return {\n projectId: doc.projectId,\n variant: doc.variant,\n source: { type: doc.sourceType, id: doc.sourceId },\n path: doc.path,\n target: { type: doc.targetType, id: doc.targetId },\n kind: doc.kind,\n }\n}\n\n/** Deterministic ordering is a repository contract; Convex docs sort client-side. */\nfunction sortedReferenceRecords(docs: ReferenceEntryDoc[]): ReferenceEntryRecord[] {\n return docs.map(referenceRecordFromDoc).sort(compareReferenceEntries)\n}\n\nclass ConvexReferenceIndexRepository implements ReferenceIndexRepository {\n constructor(private readonly client: ConvexHttpClient) {}\n\n async replaceForSource(\n projectId: string,\n variant: ReferenceVariant,\n source: ReferenceSource,\n references: readonly OutboundReference[],\n ): Promise<ReferenceEntryRecord[]> {\n await this.client.mutation(mutationRef('references:replaceForSource'), {\n variant,\n sourceType: source.type,\n sourceId: source.id,\n references: references.map((r) => ({\n path: r.path,\n targetType: r.target.type,\n targetId: r.target.id,\n kind: r.kind,\n })),\n })\n return this.outbound(projectId, source, { variant })\n }\n\n async replaceForSourceTypes(\n projectId: string,\n variant: ReferenceVariant,\n sourceTypes: readonly ReferenceSourceType[],\n entries: readonly ReferenceEntry[],\n ): Promise<ReferenceEntryRecord[]> {\n await this.client.mutation(mutationRef('references:replaceForSourceTypes'), {\n variant,\n sourceTypes: [...sourceTypes],\n entries: entries.map((e) => ({\n sourceType: e.source.type,\n sourceId: e.source.id,\n path: e.path,\n targetType: e.target.type,\n targetId: e.target.id,\n kind: e.kind,\n })),\n })\n const all = await this.listEntries(projectId, variant)\n const types = new Set(sourceTypes)\n return all.filter((record) => types.has(record.source.type))\n }\n\n async removeForSource(\n projectId: string,\n source: ReferenceSource,\n variant?: ReferenceVariant,\n ): Promise<void> {\n await this.client.mutation(mutationRef('references:removeForSource'), {\n sourceType: source.type,\n sourceId: source.id,\n ...(variant ? { variant } : {}),\n })\n }\n\n async outbound(\n projectId: string,\n source: ReferenceSource,\n options: ReferenceLookupOptions = {},\n ): Promise<ReferenceEntryRecord[]> {\n const docs = (await this.client.query(queryRef('references:outbound'), {\n sourceType: source.type,\n sourceId: source.id,\n ...(options.variant ? { variant: options.variant } : {}),\n })) as ReferenceEntryDoc[]\n return sortedReferenceRecords(docs)\n }\n\n async inbound(\n projectId: string,\n target: ReferenceTarget,\n options: ReferenceLookupOptions = {},\n ): Promise<ReferenceEntryRecord[]> {\n const docs = (await this.client.query(queryRef('references:inbound'), {\n targetType: target.type,\n targetId: target.id,\n ...(options.variant ? { variant: options.variant } : {}),\n })) as ReferenceEntryDoc[]\n return sortedReferenceRecords(docs)\n }\n\n async listEntries(\n projectId: string,\n variant?: ReferenceVariant,\n ): Promise<ReferenceEntryRecord[]> {\n const docs = (await this.client.query(queryRef('references:list'), {\n ...(variant ? { variant } : {}),\n })) as ReferenceEntryDoc[]\n return sortedReferenceRecords(docs)\n }\n\n async getBuildMarker(projectId: string): Promise<ReferenceIndexBuildMarker | null> {\n return (await this.client.query(queryRef('references:buildMarker'), {})) as\n | ReferenceIndexBuildMarker\n | null\n }\n\n async setBuildMarker(projectId: string, marker: ReferenceIndexBuildMarker): Promise<void> {\n await this.client.mutation(mutationRef('references:setBuildMarker'), {\n entryCount: marker.entryCount,\n })\n }\n\n async clearProject(projectId: string): Promise<void> {\n await this.client.mutation(mutationRef('references:clearProject'), {})\n }\n}\n\n// --- Members + CLI tokens (EC-150) -------------------------------------------\n\ninterface MemberDoc {\n userId: string\n role: ProjectRole\n createdAt: string\n updatedAt: string\n}\n\n/**\n * Single-tenant (EC-179): membership is deployment-scoped, so the backend rows\n * carry no `projectId`. The contract record still does — this adapter is bound\n * to its deployment's project, so it stamps that slug onto every record.\n */\nfunction memberRecordFromDoc(doc: MemberDoc, projectId: string): ProjectMemberRecord {\n return {\n projectId,\n userId: doc.userId,\n role: doc.role,\n createdAt: doc.createdAt,\n updatedAt: doc.updatedAt,\n }\n}\n\nclass ConvexMembersRepository implements MembersRepository {\n constructor(\n private readonly client: ConvexHttpClient,\n /** The slug of this deployment's one project — stamped onto records. */\n private readonly boundProjectId: string,\n private readonly clock: Clock = realClock,\n ) {}\n\n async setMember(\n projectId: string,\n userId: string,\n role: ProjectRole,\n ): Promise<ProjectMemberRecord> {\n const now = this.clock()\n const doc = (await this.client.mutation(mutationRef('members:set'), {\n userId,\n role,\n createdAt: now,\n updatedAt: now,\n })) as MemberDoc\n return memberRecordFromDoc(doc, projectId)\n }\n\n async findMember(projectId: string, userId: string): Promise<ProjectMemberRecord | undefined> {\n const doc = (await this.client.query(queryRef('members:get'), {\n userId,\n })) as MemberDoc | null\n return doc ? memberRecordFromDoc(doc, projectId) : undefined\n }\n\n async listMembers(projectId: string): Promise<ProjectMemberRecord[]> {\n const docs = (await this.client.query(queryRef('members:list'), {})) as MemberDoc[]\n return docs.map((d) => memberRecordFromDoc(d, projectId))\n }\n\n async listMembershipsForUser(userId: string): Promise<ProjectMemberRecord[]> {\n // `members:mine` is caller-scoped server-side and returns the caller's single\n // deployment membership (or null). The studio only ever asks about the\n // session user; records are stamped with this deployment's bound project.\n const doc = (await this.client.query(queryRef('members:mine'), {})) as MemberDoc | null\n return doc && doc.userId === userId ? [memberRecordFromDoc(doc, this.boundProjectId)] : []\n }\n\n async removeMember(projectId: string, userId: string): Promise<void> {\n try {\n await this.client.mutation(mutationRef('members:remove'), { userId })\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n if (/not-found/i.test(message)) {\n throw new RecordNotFoundError('project-member', `${projectId}/${userId}`)\n }\n throw error\n }\n }\n}\n\ninterface CliTokenDoc {\n /** Retired (EC-182): optional only because live rows may still carry it until the migration clears it. */\n projectId?: string\n tokenId: string\n label: string\n tokenHash: string\n createdAt: string\n revokedAt?: string\n}\n\nfunction cliTokenRecordFromDoc(doc: CliTokenDoc): CliTokenRecord {\n return {\n id: doc.tokenId,\n label: doc.label,\n tokenHash: doc.tokenHash,\n createdAt: doc.createdAt,\n ...(doc.revokedAt ? { revokedAt: doc.revokedAt } : {}),\n }\n}\n\nclass ConvexCliTokenRepository implements CliTokenRepository {\n constructor(\n private readonly client: ConvexHttpClient,\n private readonly clock: Clock = realClock,\n ) {}\n\n async createToken(input: NewCliTokenInput): Promise<CliTokenRecord> {\n const doc = (await this.client.mutation(mutationRef('cliTokens:create'), {\n tokenId: newId('tok'),\n label: input.label,\n tokenHash: input.tokenHash,\n createdAt: this.clock(),\n })) as CliTokenDoc\n return cliTokenRecordFromDoc(doc)\n }\n\n async listTokens(): Promise<CliTokenRecord[]> {\n const docs = (await this.client.query(queryRef('cliTokens:list'), {})) as CliTokenDoc[]\n return docs.map(cliTokenRecordFromDoc)\n }\n\n async revokeToken(tokenId: string): Promise<CliTokenRecord> {\n try {\n const doc = (await this.client.mutation(mutationRef('cliTokens:revoke'), {\n tokenId,\n revokedAt: this.clock(),\n })) as CliTokenDoc\n return cliTokenRecordFromDoc(doc)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n if (/not-found/i.test(message)) {\n throw new RecordNotFoundError('cli-token', tokenId)\n }\n throw error\n }\n }\n\n async findByHash(tokenHash: string): Promise<CliTokenRecord | undefined> {\n const doc = (await this.client.query(queryRef('cliTokens:byHash'), {\n tokenHash,\n })) as CliTokenDoc | null\n return doc ? cliTokenRecordFromDoc(doc) : undefined\n }\n}\n\n/**\n * Convex-backed {@link PersistenceAdapter} (brief §10, EC-039). Every repository\n * is implemented against the Convex functions in `apps/builder/convex/*`, mapping\n * results and failures onto the provider-neutral contracts + error taxonomies.\n */\nexport class ConvexPersistenceAdapter implements PersistenceAdapter {\n readonly cms: CmsRepository\n readonly assets: AssetRepository\n /** Reference index — outbound/inbound entries per variant (EC-155, AD-6). */\n readonly references: ReferenceIndexRepository\n /** Per-project membership roles (EC-150). */\n readonly members: MembersRepository\n /** Revocable CLI sync tokens, stored hashed (EC-150). */\n readonly cliTokens: CliTokenRepository\n /** Convex file storage behind the EC-133 blob boundary (EC-151). */\n readonly blobs: BlobStorageAdapter\n /**\n * EC-277: the Convex mutations maintain the reference index in-transaction\n * (`convex/referenceMaintenance.ts`), so every writer — studio, CLI, webhook,\n * raw `convex run` — is caught at the source. The studio bootstrap therefore does\n * NOT attach the client-side `attachReferenceIndex` subscriber for this provider.\n */\n readonly maintainsReferenceIndex = true\n\n /**\n * @param client the Convex client bound to this deployment (one project).\n * @param projectId the slug of this deployment's one project (EC-179). Used to\n * stamp deployment-scoped member records onto the still-project-keyed contract.\n * @param collections the active project's config-owned CMS collections (EC-183,\n * AD-11), from `elytra.config.ts`. The backend has no `cmsSchemas` table, so\n * the CMS repository serves the schema from these.\n */\n constructor(\n private readonly client: ConvexHttpClient,\n projectId: string,\n collections: readonly CollectionDef[] = [],\n ) {\n this.cms = new ConvexCmsRepository(client, collections)\n this.assets = new ConvexAssetRepository(client)\n this.references = new ConvexReferenceIndexRepository(client)\n this.members = new ConvexMembersRepository(client, projectId)\n this.cliTokens = new ConvexCliTokenRepository(client)\n this.blobs = new ConvexBlobStorage(client)\n }\n\n async status(): Promise<BackendStatus> {\n try {\n // Lightweight connectivity probe (EC-182: no `projects` table). `members:mine`\n // takes no args and is soft-guarded (EC-279): it answers `null` for an\n // unauthenticated caller rather than throwing, so the pre-sign-in boot probe\n // resolves cleanly — backend answered ⇒ `available: true` — with no scary\n // `Uncaught Error` in the Convex log.\n await this.client.query(queryRef('members:mine'), {})\n return { backend: 'convex', available: true }\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error)\n // EC-153: an `unauthorized` rejection *is* a healthy backend — the\n // deployment answered and enforced auth. Now that `members:mine` is\n // soft-guarded this branch is a defensive fallback (a protected probe could\n // still throw); only transport/server failures count as unavailable, so the\n // BackendGate surfaces those visibly instead of falling back to in-memory.\n if (/unauthorized/i.test(detail)) return { backend: 'convex', available: true }\n return { backend: 'convex', available: false, detail }\n }\n }\n\n validate(input: BackendValidationInput): BackendValidationResult {\n return validateForPersistence(input)\n }\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elytracms/studio",
3
3
  "author": "finaldream <hi@finaldream.de>",
4
- "version": "0.0.20",
4
+ "version": "0.0.22",
5
5
  "private": false,
6
6
  "description": "The Elytra studio engine (UI + lib + routes + data-only Convex schema) as an importable package. Extraction staged in EXTRACTION.md (EC-223); Stages 1-2 = UI primitives + router-free lib leaves.",
7
7
  "license": "MIT",
@@ -117,7 +117,7 @@
117
117
  "lucide-react": "^1.17.0",
118
118
  "tailwind-merge": "^3.6.0",
119
119
  "zod": "^4.0.0",
120
- "@elytracms/core": "^0.0.20"
120
+ "@elytracms/core": "^0.0.22"
121
121
  },
122
122
  "peerDependencies": {
123
123
  "@tanstack/react-router": "^1.170.0",