@elytracms/studio 0.0.29 → 0.0.32

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 (61) hide show
  1. package/convex/redirects.ts +3 -0
  2. package/convex/schema.ts +2 -0
  3. package/dist/components/app-views/default-modules.d.ts +3 -1
  4. package/dist/components/app-views/default-modules.js +63 -19
  5. package/dist/components/app-views/default-modules.js.map +1 -1
  6. package/dist/components/app-views/studio-config.d.ts +10 -0
  7. package/dist/components/app-views/studio-config.js.map +1 -1
  8. package/dist/components/builder/property-inspector.js +3 -2
  9. package/dist/components/builder/property-inspector.js.map +1 -1
  10. package/dist/components/builder/reuse-context.js +2 -1
  11. package/dist/components/builder/reuse-context.js.map +1 -1
  12. package/dist/components/cms/cms-index.js +2 -1
  13. package/dist/components/cms/cms-index.js.map +1 -1
  14. package/dist/components/cms/cms-store.d.ts +11 -2
  15. package/dist/components/cms/cms-store.js +17 -4
  16. package/dist/components/cms/cms-store.js.map +1 -1
  17. package/dist/components/cms/collection-table.js +5 -4
  18. package/dist/components/cms/collection-table.js.map +1 -1
  19. package/dist/components/cms/detail-editor.js +5 -4
  20. package/dist/components/cms/detail-editor.js.map +1 -1
  21. package/dist/components/cms/editable-cell.js +3 -2
  22. package/dist/components/cms/editable-cell.js.map +1 -1
  23. package/dist/components/cms/field-control.js +6 -5
  24. package/dist/components/cms/field-control.js.map +1 -1
  25. package/dist/components/cms/scalar-value-editor.js +2 -1
  26. package/dist/components/cms/scalar-value-editor.js.map +1 -1
  27. package/dist/components/components/field-inspector.js +3 -2
  28. package/dist/components/components/field-inspector.js.map +1 -1
  29. package/dist/components/current-user-menu.js +4 -2
  30. package/dist/components/current-user-menu.js.map +1 -1
  31. package/dist/components/redirects/redirects-collection-view-source.d.ts +4 -3
  32. package/dist/components/redirects/redirects-collection-view-source.js +23 -3
  33. package/dist/components/redirects/redirects-collection-view-source.js.map +1 -1
  34. package/dist/components/redirects/redirects-store.js +1 -0
  35. package/dist/components/redirects/redirects-store.js.map +1 -1
  36. package/dist/customization.d.ts +7 -0
  37. package/dist/customization.js +6 -0
  38. package/dist/customization.js.map +1 -1
  39. package/dist/lib/cms-views/view-model.js +2 -2
  40. package/dist/lib/cms-views/view-model.js.map +1 -1
  41. package/dist/lib/i18n/i18n.d.ts +59 -0
  42. package/dist/lib/i18n/i18n.js +131 -0
  43. package/dist/lib/i18n/i18n.js.map +1 -0
  44. package/dist/lib/i18n/index.d.ts +12 -0
  45. package/dist/lib/i18n/index.js +4 -0
  46. package/dist/lib/i18n/index.js.map +1 -0
  47. package/dist/lib/i18n/messages.en.d.ts +15 -0
  48. package/dist/lib/i18n/messages.en.js +39 -0
  49. package/dist/lib/i18n/messages.en.js.map +1 -0
  50. package/dist/lib/i18n/types.d.ts +45 -0
  51. package/dist/lib/i18n/types.js +19 -0
  52. package/dist/lib/i18n/types.js.map +1 -0
  53. package/dist/lib/persistence/convex-adapter.js +2 -0
  54. package/dist/lib/persistence/convex-adapter.js.map +1 -1
  55. package/dist/lib/references/reference-model.js +4 -3
  56. package/dist/lib/references/reference-model.js.map +1 -1
  57. package/dist/lib/workspace/index.d.ts +8 -0
  58. package/dist/lib/workspace/index.js +10 -0
  59. package/dist/lib/workspace/index.js.map +1 -1
  60. package/dist/ui/badge.d.ts +1 -1
  61. package/package.json +6 -2
@@ -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 highestRole,\n isKnownRole,\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 RedirectEntry,\n RedirectRepository,\n SaveRedirectInput,\n SaveUserInput,\n UserRecord,\n UserRepository,\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 listPublishedDocuments(projectId: string, collection?: string): Promise<CmsDocument[]> {\n // EC-307: one bulk read for the published pool (collapses the per-document\n // `listVersions` fan-out). The handler resolves each pin to its snapshot.\n const snapshots = (await this.client.query(queryRef('cms:listPublishedDocuments'), {\n ...(collection ? { collection } : {}),\n })) as CmsDocument[]\n // Deterministic document-key order (parity with the in-memory adapter).\n return snapshots\n .map((doc) => documentSchema.parse(doc))\n .sort((a, b) => (documentKey(a) < documentKey(b) ? -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 inboundMany(\n projectId: string,\n targets: readonly ReferenceTarget[],\n options: ReferenceLookupOptions = {},\n ): Promise<ReferenceEntryRecord[][]> {\n // EC-308: one round-trip for all targets (the handler loops the by_target\n // index server-side), replacing the client's per-target inbound fan-out.\n if (targets.length === 0) return []\n const groups = (await this.client.query(queryRef('references:inboundMany'), {\n targets: targets.map((target) => ({ targetType: target.type, targetId: target.id })),\n ...(options.variant ? { variant: options.variant } : {}),\n })) as ReferenceEntryDoc[][]\n return groups.map((docs) => 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\n// --- Users rail (EC-240, 240a) -----------------------------------------------\n\n/** The wire shape returned by the `users:list`/`users:get` join handlers. */\ninterface UserDoc {\n id: string\n email: string\n name?: string\n avatar?: string\n role: ProjectRole\n meta?: Record<string, unknown>\n createdAt: string\n updatedAt: string\n}\n\n/** Map a joined user doc onto the contract record; stamp the bound project. */\nfunction userRecordFromDoc(doc: UserDoc, projectId: string): UserRecord {\n return {\n id: doc.id,\n projectId,\n email: doc.email,\n ...(doc.name !== undefined ? { name: doc.name } : {}),\n ...(doc.avatar !== undefined ? { avatar: doc.avatar } : {}),\n // 240a bridge: the single `members.role` column ⇒ the 240c-ready `roles[]`.\n roles: [doc.role],\n ...(doc.meta !== undefined ? { meta: doc.meta } : {}),\n createdAt: doc.createdAt,\n updatedAt: doc.updatedAt,\n }\n}\n\n/**\n * Collapse the 240c-ready `roles[]` to the single `members.role` column by\n * applying the strongest role (the 240a→240c enforcement bridge). Unknown\n * strings are ignored; an empty/unknown set floors to `viewer`.\n */\nfunction strongestRole(roles: readonly string[]): ProjectRole {\n // Validate against the active role policy (EC-240c) rather than a hardcoded\n // enum, then take the canonical rank max; floor an empty/unknown set to `viewer`.\n const valid = roles.filter((r) => isKnownRole(r))\n return highestRole(valid) ?? 'viewer'\n}\n\n/**\n * Convex-backed {@link UserRepository} (EC-240, 240a). Reads are the admin-gated\n * `users:*` **join** handlers (members row + auth identity); the role write\n * reuses the member write path (`members:set`, extended with the `meta` bag) so\n * there is one source for role writes — 240c collapses enforcement onto it.\n */\nclass ConvexUserRepository implements UserRepository {\n constructor(\n private readonly client: ConvexHttpClient,\n private readonly clock: Clock = realClock,\n ) {}\n\n async listUsers(projectId: string): Promise<UserRecord[]> {\n const docs = (await this.client.query(queryRef('users:list'), {})) as UserDoc[]\n return docs.map((doc) => userRecordFromDoc(doc, projectId))\n }\n\n async findUser(projectId: string, id: string): Promise<UserRecord | undefined> {\n const doc = (await this.client.query(queryRef('users:get'), { userId: id })) as UserDoc | null\n return doc ? userRecordFromDoc(doc, projectId) : undefined\n }\n\n async getUser(projectId: string, id: string): Promise<UserRecord> {\n const found = await this.findUser(projectId, id)\n if (!found) throw new RecordNotFoundError('user', `${projectId}/${id}`)\n return found\n }\n\n async saveUser(projectId: string, input: SaveUserInput): Promise<UserRecord> {\n const now = this.clock()\n await this.client.mutation(mutationRef('members:set'), {\n userId: input.id,\n role: strongestRole(input.roles),\n ...(input.meta !== undefined ? { meta: input.meta } : {}),\n createdAt: now,\n updatedAt: now,\n })\n // Return the full joined projection (identity + role + custom fields).\n return this.getUser(projectId, input.id)\n }\n\n async removeUser(projectId: string, id: string): Promise<void> {\n try {\n await this.client.mutation(mutationRef('members:remove'), { userId: id })\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n if (/not-found/i.test(message)) {\n throw new RecordNotFoundError('user', `${projectId}/${id}`)\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/** The `redirects` table row shape (EC-303). Single-tenant: no `projectId` column. */\ninterface RedirectDoc {\n redirectId: string\n from: string\n to: string\n permanent: boolean\n enabled: boolean\n createdAt: string\n updatedAt: string\n}\n\nfunction redirectEntryFromDoc(doc: RedirectDoc, projectId: string): RedirectEntry {\n return {\n id: doc.redirectId,\n projectId,\n from: doc.from,\n to: doc.to,\n permanent: doc.permanent,\n enabled: doc.enabled,\n createdAt: doc.createdAt,\n updatedAt: doc.updatedAt,\n }\n}\n\n/**\n * Convex-backed {@link RedirectRepository} (EC-303) — editorial redirects as data\n * (not config). Content-gated CRUD over the `redirects` table; the studio's\n * editorial surface + the delivery snapshot both read through here. The editorial\n * surface sends a full record on save, so create-defaults (permanent/enabled) also\n * cover edits.\n */\nclass ConvexRedirectRepository implements RedirectRepository {\n constructor(\n private readonly client: ConvexHttpClient,\n private readonly clock: Clock = realClock,\n ) {}\n\n async saveRedirect(projectId: string, input: SaveRedirectInput): Promise<RedirectEntry> {\n const now = this.clock()\n const id = input.id ?? newId('redirect')\n const doc = (await this.client.mutation(mutationRef('redirects:save'), {\n redirectId: id,\n from: input.from,\n to: input.to,\n permanent: input.permanent ?? true,\n enabled: input.enabled ?? true,\n createdAt: now,\n updatedAt: now,\n })) as RedirectDoc\n return redirectEntryFromDoc(doc, projectId)\n }\n\n async getRedirect(projectId: string, id: string): Promise<RedirectEntry> {\n const found = await this.findRedirect(projectId, id)\n if (!found) throw new RecordNotFoundError('redirect', `${projectId}/${id}`)\n return found\n }\n\n async findRedirect(projectId: string, id: string): Promise<RedirectEntry | undefined> {\n const doc = (await this.client.query(queryRef('redirects:get'), {\n redirectId: id,\n })) as RedirectDoc | null\n return doc ? redirectEntryFromDoc(doc, projectId) : undefined\n }\n\n async listRedirects(projectId: string): Promise<RedirectEntry[]> {\n const docs = (await this.client.query(queryRef('redirects:list'), {})) as RedirectDoc[]\n return docs\n .map((doc) => redirectEntryFromDoc(doc, projectId))\n .sort((a, b) => (a.from < b.from ? -1 : a.from > b.from ? 1 : 0))\n }\n\n async removeRedirect(projectId: string, id: string): Promise<void> {\n await this.getRedirect(projectId, id) // not-found parity with the in-memory rail\n await this.client.mutation(mutationRef('redirects:remove'), { redirectId: id })\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 /** Studio users rail — role + custom fields joined to auth identity (EC-240). */\n readonly users: UserRepository\n /** Editorial redirects rail — data-backed 301/302 forwards (EC-303). */\n readonly redirects: RedirectRepository\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.users = new ConvexUserRepository(client)\n this.redirects = new ConvexRedirectRepository(client)\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 highestRole,\n isKnownRole,\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 RedirectEntry,\n RedirectRepository,\n SaveRedirectInput,\n SaveUserInput,\n UserRecord,\n UserRepository,\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 listPublishedDocuments(projectId: string, collection?: string): Promise<CmsDocument[]> {\n // EC-307: one bulk read for the published pool (collapses the per-document\n // `listVersions` fan-out). The handler resolves each pin to its snapshot.\n const snapshots = (await this.client.query(queryRef('cms:listPublishedDocuments'), {\n ...(collection ? { collection } : {}),\n })) as CmsDocument[]\n // Deterministic document-key order (parity with the in-memory adapter).\n return snapshots\n .map((doc) => documentSchema.parse(doc))\n .sort((a, b) => (documentKey(a) < documentKey(b) ? -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 inboundMany(\n projectId: string,\n targets: readonly ReferenceTarget[],\n options: ReferenceLookupOptions = {},\n ): Promise<ReferenceEntryRecord[][]> {\n // EC-308: one round-trip for all targets (the handler loops the by_target\n // index server-side), replacing the client's per-target inbound fan-out.\n if (targets.length === 0) return []\n const groups = (await this.client.query(queryRef('references:inboundMany'), {\n targets: targets.map((target) => ({ targetType: target.type, targetId: target.id })),\n ...(options.variant ? { variant: options.variant } : {}),\n })) as ReferenceEntryDoc[][]\n return groups.map((docs) => 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\n// --- Users rail (EC-240, 240a) -----------------------------------------------\n\n/** The wire shape returned by the `users:list`/`users:get` join handlers. */\ninterface UserDoc {\n id: string\n email: string\n name?: string\n avatar?: string\n role: ProjectRole\n meta?: Record<string, unknown>\n createdAt: string\n updatedAt: string\n}\n\n/** Map a joined user doc onto the contract record; stamp the bound project. */\nfunction userRecordFromDoc(doc: UserDoc, projectId: string): UserRecord {\n return {\n id: doc.id,\n projectId,\n email: doc.email,\n ...(doc.name !== undefined ? { name: doc.name } : {}),\n ...(doc.avatar !== undefined ? { avatar: doc.avatar } : {}),\n // 240a bridge: the single `members.role` column ⇒ the 240c-ready `roles[]`.\n roles: [doc.role],\n ...(doc.meta !== undefined ? { meta: doc.meta } : {}),\n createdAt: doc.createdAt,\n updatedAt: doc.updatedAt,\n }\n}\n\n/**\n * Collapse the 240c-ready `roles[]` to the single `members.role` column by\n * applying the strongest role (the 240a→240c enforcement bridge). Unknown\n * strings are ignored; an empty/unknown set floors to `viewer`.\n */\nfunction strongestRole(roles: readonly string[]): ProjectRole {\n // Validate against the active role policy (EC-240c) rather than a hardcoded\n // enum, then take the canonical rank max; floor an empty/unknown set to `viewer`.\n const valid = roles.filter((r) => isKnownRole(r))\n return highestRole(valid) ?? 'viewer'\n}\n\n/**\n * Convex-backed {@link UserRepository} (EC-240, 240a). Reads are the admin-gated\n * `users:*` **join** handlers (members row + auth identity); the role write\n * reuses the member write path (`members:set`, extended with the `meta` bag) so\n * there is one source for role writes — 240c collapses enforcement onto it.\n */\nclass ConvexUserRepository implements UserRepository {\n constructor(\n private readonly client: ConvexHttpClient,\n private readonly clock: Clock = realClock,\n ) {}\n\n async listUsers(projectId: string): Promise<UserRecord[]> {\n const docs = (await this.client.query(queryRef('users:list'), {})) as UserDoc[]\n return docs.map((doc) => userRecordFromDoc(doc, projectId))\n }\n\n async findUser(projectId: string, id: string): Promise<UserRecord | undefined> {\n const doc = (await this.client.query(queryRef('users:get'), { userId: id })) as UserDoc | null\n return doc ? userRecordFromDoc(doc, projectId) : undefined\n }\n\n async getUser(projectId: string, id: string): Promise<UserRecord> {\n const found = await this.findUser(projectId, id)\n if (!found) throw new RecordNotFoundError('user', `${projectId}/${id}`)\n return found\n }\n\n async saveUser(projectId: string, input: SaveUserInput): Promise<UserRecord> {\n const now = this.clock()\n await this.client.mutation(mutationRef('members:set'), {\n userId: input.id,\n role: strongestRole(input.roles),\n ...(input.meta !== undefined ? { meta: input.meta } : {}),\n createdAt: now,\n updatedAt: now,\n })\n // Return the full joined projection (identity + role + custom fields).\n return this.getUser(projectId, input.id)\n }\n\n async removeUser(projectId: string, id: string): Promise<void> {\n try {\n await this.client.mutation(mutationRef('members:remove'), { userId: id })\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n if (/not-found/i.test(message)) {\n throw new RecordNotFoundError('user', `${projectId}/${id}`)\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/** The `redirects` table row shape (EC-303). Single-tenant: no `projectId` column. */\ninterface RedirectDoc {\n redirectId: string\n from: string\n to: string\n permanent: boolean\n enabled: boolean\n /** Schema-driven additive-field bag (EC-311 Tier 2). */\n meta?: Record<string, unknown>\n createdAt: string\n updatedAt: string\n}\n\nfunction redirectEntryFromDoc(doc: RedirectDoc, projectId: string): RedirectEntry {\n return {\n id: doc.redirectId,\n projectId,\n from: doc.from,\n to: doc.to,\n permanent: doc.permanent,\n enabled: doc.enabled,\n ...(doc.meta !== undefined ? { meta: doc.meta } : {}),\n createdAt: doc.createdAt,\n updatedAt: doc.updatedAt,\n }\n}\n\n/**\n * Convex-backed {@link RedirectRepository} (EC-303) — editorial redirects as data\n * (not config). Content-gated CRUD over the `redirects` table; the studio's\n * editorial surface + the delivery snapshot both read through here. The editorial\n * surface sends a full record on save, so create-defaults (permanent/enabled) also\n * cover edits.\n */\nclass ConvexRedirectRepository implements RedirectRepository {\n constructor(\n private readonly client: ConvexHttpClient,\n private readonly clock: Clock = realClock,\n ) {}\n\n async saveRedirect(projectId: string, input: SaveRedirectInput): Promise<RedirectEntry> {\n const now = this.clock()\n const id = input.id ?? newId('redirect')\n const doc = (await this.client.mutation(mutationRef('redirects:save'), {\n redirectId: id,\n from: input.from,\n to: input.to,\n permanent: input.permanent ?? true,\n enabled: input.enabled ?? true,\n ...(input.meta !== undefined ? { meta: input.meta } : {}),\n createdAt: now,\n updatedAt: now,\n })) as RedirectDoc\n return redirectEntryFromDoc(doc, projectId)\n }\n\n async getRedirect(projectId: string, id: string): Promise<RedirectEntry> {\n const found = await this.findRedirect(projectId, id)\n if (!found) throw new RecordNotFoundError('redirect', `${projectId}/${id}`)\n return found\n }\n\n async findRedirect(projectId: string, id: string): Promise<RedirectEntry | undefined> {\n const doc = (await this.client.query(queryRef('redirects:get'), {\n redirectId: id,\n })) as RedirectDoc | null\n return doc ? redirectEntryFromDoc(doc, projectId) : undefined\n }\n\n async listRedirects(projectId: string): Promise<RedirectEntry[]> {\n const docs = (await this.client.query(queryRef('redirects:list'), {})) as RedirectDoc[]\n return docs\n .map((doc) => redirectEntryFromDoc(doc, projectId))\n .sort((a, b) => (a.from < b.from ? -1 : a.from > b.from ? 1 : 0))\n }\n\n async removeRedirect(projectId: string, id: string): Promise<void> {\n await this.getRedirect(projectId, id) // not-found parity with the in-memory rail\n await this.client.mutation(mutationRef('redirects:remove'), { redirectId: id })\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 /** Studio users rail — role + custom fields joined to auth identity (EC-240). */\n readonly users: UserRepository\n /** Editorial redirects rail — data-backed 301/302 forwards (EC-303). */\n readonly redirects: RedirectRepository\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.users = new ConvexUserRepository(client)\n this.redirects = new ConvexRedirectRepository(client)\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,4 +1,4 @@
1
- import { resolveDocumentTitle } from '@elytracms/core/cms-core';
1
+ import { resolveDocumentTitle, resolveLabel } from '@elytracms/core/cms-core';
2
2
  /**
3
3
  * Pure presentation model for the EC-172 references panels.
4
4
  *
@@ -73,10 +73,11 @@ export const REFERENCE_KIND_LABELS = {
73
73
  };
74
74
  function fieldLabelOf(collection, fieldName) {
75
75
  const field = collection?.fields.find((f) => f.name === fieldName);
76
- return field?.form?.label ?? fieldName;
76
+ // Pure/lib site: resolves to the default-language label (no active UI locale here).
77
+ return resolveLabel(field?.form?.label) ?? fieldName;
77
78
  }
78
79
  function collectionLabelOf(collection, collectionId) {
79
- return collection?.form?.labelSingular ?? collection?.form?.label ?? collectionId;
80
+ return resolveLabel(collection?.form?.labelSingular) ?? resolveLabel(collection?.form?.label) ?? collectionId;
80
81
  }
81
82
  /** Resolve a document's display title (titleField value, default locale first). */
82
83
  export function documentTitleOf(collection, document, fallback) {
@@ -1 +1 @@
1
- {"version":3,"file":"reference-model.js","sourceRoot":"","sources":["../../../src/lib/references/reference-model.ts"],"names":[],"mappings":"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","sourcesContent":["import { resolveDocumentTitle } from '@elytracms/core/cms-core'\nimport type { CmsDocument, CollectionDef } from '@elytracms/core/cms-core'\nimport type {\n ReferenceEntryRecord,\n ReferenceKind,\n ReferenceSource,\n ReferenceTarget,\n} from '@elytracms/core/persistence'\n\n/**\n * Pure presentation model for the EC-172 references panels.\n *\n * The EC-155 index stores entries as `(source, path, target, kind)` per\n * variant; this module turns those records into renderable rows: variants\n * merged onto one row (draft/published badges), human-readable source/\n * location/target labels, and deep-link descriptors that pinpoint the exact\n * field (CMS) or graph node (builder) a path identifies. No data fetching, no\n * React — everything here is a deterministic function of its inputs, so it is\n * fully testable in the node environment.\n */\n\n// --- Path parsing -------------------------------------------------------------\n\n/** Split a `collection:id` document key (the index's document source/target id). */\nexport function parseDocumentKey(key: string): { collection: string; id: string } | null {\n const separator = key.indexOf(':')\n if (separator <= 0 || separator === key.length - 1) return null\n return { collection: key.slice(0, separator), id: key.slice(separator + 1) }\n}\n\nexport interface DocumentFieldPath {\n /** Present for `localized/<locale>/<field>` paths. */\n locale?: string\n field: string\n /** Tokens below the field value (array indices, rich-text node paths). */\n rest: readonly string[]\n}\n\n/**\n * Parse a document index path (`values/<field>/…` or\n * `localized/<locale>/<field>/…`) onto the owning field.\n */\nexport function parseDocumentFieldPath(path: string): DocumentFieldPath | null {\n const tokens = path.split('/')\n if (tokens[0] === 'values' && tokens[1]) {\n return { field: tokens[1], rest: tokens.slice(2) }\n }\n if (tokens[0] === 'localized' && tokens[1] && tokens[2]) {\n return { locale: tokens[1], field: tokens[2], rest: tokens.slice(3) }\n }\n return null\n}\n\n// --- Variant merging ----------------------------------------------------------\n\n/** One panel row: the same logical entry across both variants, with flags. */\nexport interface MergedReferenceEntry {\n /** Stable row key (source + path + target + kind). */\n key: string\n source: ReferenceSource\n path: string\n target: ReferenceTarget\n kind: ReferenceKind\n /** Present in the draft variant of the index. */\n draft: boolean\n /** Present in the published variant (a live reference). */\n published: boolean\n}\n\n/**\n * Merge per-variant index records onto one row per logical entry. A\n * draft-only row (`draft && !published`) is the Sanity hidden-draft-reference\n * case the panel must make visible. Order is deterministic:\n * source type → source id → path → target type → target id → kind.\n */\nexport function mergeReferenceVariants(\n records: readonly ReferenceEntryRecord[],\n): MergedReferenceEntry[] {\n const byKey = new Map<string, MergedReferenceEntry>()\n for (const record of records) {\n const key = `${record.source.type} ${record.source.id} ${record.path} ${record.target.type} ${record.target.id} ${record.kind}`\n const existing = byKey.get(key)\n if (existing) {\n if (record.variant === 'draft') existing.draft = true\n else existing.published = true\n continue\n }\n byKey.set(key, {\n key,\n source: record.source,\n path: record.path,\n target: record.target,\n kind: record.kind,\n draft: record.variant === 'draft',\n published: record.variant === 'published',\n })\n }\n return [...byKey.values()].sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0))\n}\n\n// --- Labels & deep links --------------------------------------------------------\n\n/** Human label per reference kind (entry-row badge). */\nexport const REFERENCE_KIND_LABELS: Record<ReferenceKind, string> = {\n 'relation-field': 'relation',\n 'asset-field': 'asset field',\n 'rich-text-link': 'rich-text link',\n 'rich-text-node': 'rich-text node',\n 'component-usage': 'component usage',\n}\n\n/**\n * A deep-link descriptor the panel renders as a router link. `cms-field`\n * carries the full index path so the document editor can highlight the exact\n * field control; `builder-node` carries the resolved node id so the builder\n * can select + scroll to the node.\n */\nexport type ReferenceDeepLink =\n | { kind: 'cms-field'; collectionId: string; documentId: string; fieldPath?: string }\n | { kind: 'builder-node'; pageId?: string; nodeId?: string }\n | { kind: 'component'; componentId: string }\n | { kind: 'asset'; assetId: string }\n\n/** Everything the model needs to label entries (loaded once per panel). */\nexport interface ReferenceLabelContext {\n collections: readonly CollectionDef[]\n /** Live documents keyed by `collection:id`. */\n documents: ReadonlyMap<string, CmsDocument>\n /** Asset metadata keyed by asset id. */\n assets: ReadonlyMap<string, { filename: string; title?: string | undefined }>\n /** Resolves a component id to its manifest title (live registry lookup). */\n componentTitle: (componentId: string) => string | undefined\n}\n\n/** One fully-labelled panel row. */\nexport interface ReferenceEntryView extends MergedReferenceEntry {\n kindLabel: string\n /** The holding entity, e.g. `Post · Hello World` or `Page · Home`. */\n sourceLabel: string\n /** The exact location inside the source, e.g. `Author` or `Text (n-post-title)`. */\n locationLabel: string\n /** The referenced entity, e.g. `Ada Lovelace` or `cover.jpg`. */\n targetLabel: string\n /** Deep link to the exact source location (field control / graph node). */\n sourceLink: ReferenceDeepLink | null\n /** Link to the referenced entity's surface. */\n targetLink: ReferenceDeepLink | null\n}\n\nfunction fieldLabelOf(collection: CollectionDef | undefined, fieldName: string): string {\n const field = collection?.fields.find((f) => f.name === fieldName)\n return field?.form?.label ?? fieldName\n}\n\nfunction collectionLabelOf(collection: CollectionDef | undefined, collectionId: string): string {\n return collection?.form?.labelSingular ?? collection?.form?.label ?? collectionId\n}\n\n/** Resolve a document's display title (titleField value, default locale first). */\nexport function documentTitleOf(\n collection: CollectionDef | undefined,\n document: CmsDocument | undefined,\n fallback: string,\n): string {\n if (!collection || !document) return fallback\n // EC-242: a function `titleField` (title pattern) has no single source field —\n // resolve it from the base values via the shared identity resolver.\n if (typeof collection.titleField === 'function') {\n return resolveDocumentTitle(collection, document.values, fallback)\n }\n const field = typeof collection.titleField === 'string' ? collection.titleField : 'title'\n const direct = document.values[field]\n if (typeof direct === 'string' && direct.length > 0) return direct\n const locales = Object.keys(document.localized ?? {}).sort()\n const preferred = document.defaultLocale\n for (const locale of [preferred, ...locales]) {\n if (!locale) continue\n const value = document.localized?.[locale]?.[field]\n if (typeof value === 'string' && value.length > 0) return value\n }\n return fallback\n}\n\n/** Strip the namespace off a component id for compact labels. */\nexport function shortComponentId(componentId: string): string {\n return componentId.replace('base.primitives.', '').replace('project.', '')\n}\n\ninterface DocumentParts {\n collection: CollectionDef | undefined\n collectionId: string\n documentId: string\n title: string\n}\n\nfunction documentParts(context: ReferenceLabelContext, key: string): DocumentParts | null {\n const ref = parseDocumentKey(key)\n if (!ref) return null\n const collection = context.collections.find((c) => c.id === ref.collection)\n return {\n collection,\n collectionId: ref.collection,\n documentId: ref.id,\n title: documentTitleOf(collection, context.documents.get(key), ref.id),\n }\n}\n\nfunction describeDocumentSource(\n context: ReferenceLabelContext,\n entry: MergedReferenceEntry,\n): { sourceLabel: string; locationLabel: string; sourceLink: ReferenceDeepLink | null } {\n const parts = documentParts(context, entry.source.id)\n if (!parts) {\n return { sourceLabel: entry.source.id, locationLabel: entry.path, sourceLink: null }\n }\n const parsed = parseDocumentFieldPath(entry.path)\n const fieldLabel = parsed ? fieldLabelOf(parts.collection, parsed.field) : entry.path\n const qualifiers: string[] = []\n if (parsed?.locale) qualifiers.push(parsed.locale)\n if (entry.kind === 'rich-text-link') qualifiers.push('link')\n if (entry.kind === 'rich-text-node') qualifiers.push('embedded node')\n if (\n entry.kind === 'relation-field' &&\n parsed &&\n parsed.rest.length === 1 &&\n /^\\d+$/.test(parsed.rest[0]!)\n ) {\n qualifiers.push(`item ${parsed.rest[0]}`)\n }\n return {\n sourceLabel: `${collectionLabelOf(parts.collection, parts.collectionId)} · ${parts.title}`,\n locationLabel: qualifiers.length > 0 ? `${fieldLabel} (${qualifiers.join(', ')})` : fieldLabel,\n sourceLink: {\n kind: 'cms-field',\n collectionId: parts.collectionId,\n documentId: parts.documentId,\n fieldPath: entry.path,\n },\n }\n}\n\n\nfunction describeTarget(\n context: ReferenceLabelContext,\n target: ReferenceTarget,\n): { targetLabel: string; targetLink: ReferenceDeepLink | null } {\n switch (target.type) {\n case 'document': {\n const parts = documentParts(context, target.id)\n if (!parts) return { targetLabel: target.id, targetLink: null }\n return {\n targetLabel: `${collectionLabelOf(parts.collection, parts.collectionId)} · ${parts.title}`,\n targetLink: {\n kind: 'cms-field',\n collectionId: parts.collectionId,\n documentId: parts.documentId,\n },\n }\n }\n case 'component':\n return {\n targetLabel: context.componentTitle(target.id) ?? shortComponentId(target.id),\n targetLink: { kind: 'component', componentId: target.id },\n }\n case 'asset': {\n const asset = context.assets.get(target.id)\n return {\n targetLabel: asset ? (asset.title ?? asset.filename) : target.id,\n targetLink: { kind: 'asset', assetId: target.id },\n }\n }\n }\n}\n\n/** Label + link one merged entry (see {@link buildReferenceEntryViews}). */\nexport function buildReferenceEntryView(\n entry: MergedReferenceEntry,\n context: ReferenceLabelContext,\n): ReferenceEntryView {\n // EC-287: a reference source is only ever a CMS document (structure is code).\n const sourceParts = describeDocumentSource(context, entry)\n return {\n ...entry,\n kindLabel: REFERENCE_KIND_LABELS[entry.kind],\n ...sourceParts,\n ...describeTarget(context, entry.target),\n }\n}\n\n/** Merge variants and label every record — the panel's full render model. */\nexport function buildReferenceEntryViews(\n records: readonly ReferenceEntryRecord[],\n context: ReferenceLabelContext,\n): ReferenceEntryView[] {\n return mergeReferenceVariants(records).map((entry) => buildReferenceEntryView(entry, context))\n}\n"]}
1
+ {"version":3,"file":"reference-model.js","sourceRoot":"","sources":["../../../src/lib/references/reference-model.ts"],"names":[],"mappings":"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","sourcesContent":["import { resolveDocumentTitle, resolveLabel } from '@elytracms/core/cms-core'\nimport type { CmsDocument, CollectionDef } from '@elytracms/core/cms-core'\nimport type {\n ReferenceEntryRecord,\n ReferenceKind,\n ReferenceSource,\n ReferenceTarget,\n} from '@elytracms/core/persistence'\n\n/**\n * Pure presentation model for the EC-172 references panels.\n *\n * The EC-155 index stores entries as `(source, path, target, kind)` per\n * variant; this module turns those records into renderable rows: variants\n * merged onto one row (draft/published badges), human-readable source/\n * location/target labels, and deep-link descriptors that pinpoint the exact\n * field (CMS) or graph node (builder) a path identifies. No data fetching, no\n * React — everything here is a deterministic function of its inputs, so it is\n * fully testable in the node environment.\n */\n\n// --- Path parsing -------------------------------------------------------------\n\n/** Split a `collection:id` document key (the index's document source/target id). */\nexport function parseDocumentKey(key: string): { collection: string; id: string } | null {\n const separator = key.indexOf(':')\n if (separator <= 0 || separator === key.length - 1) return null\n return { collection: key.slice(0, separator), id: key.slice(separator + 1) }\n}\n\nexport interface DocumentFieldPath {\n /** Present for `localized/<locale>/<field>` paths. */\n locale?: string\n field: string\n /** Tokens below the field value (array indices, rich-text node paths). */\n rest: readonly string[]\n}\n\n/**\n * Parse a document index path (`values/<field>/…` or\n * `localized/<locale>/<field>/…`) onto the owning field.\n */\nexport function parseDocumentFieldPath(path: string): DocumentFieldPath | null {\n const tokens = path.split('/')\n if (tokens[0] === 'values' && tokens[1]) {\n return { field: tokens[1], rest: tokens.slice(2) }\n }\n if (tokens[0] === 'localized' && tokens[1] && tokens[2]) {\n return { locale: tokens[1], field: tokens[2], rest: tokens.slice(3) }\n }\n return null\n}\n\n// --- Variant merging ----------------------------------------------------------\n\n/** One panel row: the same logical entry across both variants, with flags. */\nexport interface MergedReferenceEntry {\n /** Stable row key (source + path + target + kind). */\n key: string\n source: ReferenceSource\n path: string\n target: ReferenceTarget\n kind: ReferenceKind\n /** Present in the draft variant of the index. */\n draft: boolean\n /** Present in the published variant (a live reference). */\n published: boolean\n}\n\n/**\n * Merge per-variant index records onto one row per logical entry. A\n * draft-only row (`draft && !published`) is the Sanity hidden-draft-reference\n * case the panel must make visible. Order is deterministic:\n * source type → source id → path → target type → target id → kind.\n */\nexport function mergeReferenceVariants(\n records: readonly ReferenceEntryRecord[],\n): MergedReferenceEntry[] {\n const byKey = new Map<string, MergedReferenceEntry>()\n for (const record of records) {\n const key = `${record.source.type} ${record.source.id} ${record.path} ${record.target.type} ${record.target.id} ${record.kind}`\n const existing = byKey.get(key)\n if (existing) {\n if (record.variant === 'draft') existing.draft = true\n else existing.published = true\n continue\n }\n byKey.set(key, {\n key,\n source: record.source,\n path: record.path,\n target: record.target,\n kind: record.kind,\n draft: record.variant === 'draft',\n published: record.variant === 'published',\n })\n }\n return [...byKey.values()].sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0))\n}\n\n// --- Labels & deep links --------------------------------------------------------\n\n/** Human label per reference kind (entry-row badge). */\nexport const REFERENCE_KIND_LABELS: Record<ReferenceKind, string> = {\n 'relation-field': 'relation',\n 'asset-field': 'asset field',\n 'rich-text-link': 'rich-text link',\n 'rich-text-node': 'rich-text node',\n 'component-usage': 'component usage',\n}\n\n/**\n * A deep-link descriptor the panel renders as a router link. `cms-field`\n * carries the full index path so the document editor can highlight the exact\n * field control; `builder-node` carries the resolved node id so the builder\n * can select + scroll to the node.\n */\nexport type ReferenceDeepLink =\n | { kind: 'cms-field'; collectionId: string; documentId: string; fieldPath?: string }\n | { kind: 'builder-node'; pageId?: string; nodeId?: string }\n | { kind: 'component'; componentId: string }\n | { kind: 'asset'; assetId: string }\n\n/** Everything the model needs to label entries (loaded once per panel). */\nexport interface ReferenceLabelContext {\n collections: readonly CollectionDef[]\n /** Live documents keyed by `collection:id`. */\n documents: ReadonlyMap<string, CmsDocument>\n /** Asset metadata keyed by asset id. */\n assets: ReadonlyMap<string, { filename: string; title?: string | undefined }>\n /** Resolves a component id to its manifest title (live registry lookup). */\n componentTitle: (componentId: string) => string | undefined\n}\n\n/** One fully-labelled panel row. */\nexport interface ReferenceEntryView extends MergedReferenceEntry {\n kindLabel: string\n /** The holding entity, e.g. `Post · Hello World` or `Page · Home`. */\n sourceLabel: string\n /** The exact location inside the source, e.g. `Author` or `Text (n-post-title)`. */\n locationLabel: string\n /** The referenced entity, e.g. `Ada Lovelace` or `cover.jpg`. */\n targetLabel: string\n /** Deep link to the exact source location (field control / graph node). */\n sourceLink: ReferenceDeepLink | null\n /** Link to the referenced entity's surface. */\n targetLink: ReferenceDeepLink | null\n}\n\nfunction fieldLabelOf(collection: CollectionDef | undefined, fieldName: string): string {\n const field = collection?.fields.find((f) => f.name === fieldName)\n // Pure/lib site: resolves to the default-language label (no active UI locale here).\n return resolveLabel(field?.form?.label) ?? fieldName\n}\n\nfunction collectionLabelOf(collection: CollectionDef | undefined, collectionId: string): string {\n return resolveLabel(collection?.form?.labelSingular) ?? resolveLabel(collection?.form?.label) ?? collectionId\n}\n\n/** Resolve a document's display title (titleField value, default locale first). */\nexport function documentTitleOf(\n collection: CollectionDef | undefined,\n document: CmsDocument | undefined,\n fallback: string,\n): string {\n if (!collection || !document) return fallback\n // EC-242: a function `titleField` (title pattern) has no single source field —\n // resolve it from the base values via the shared identity resolver.\n if (typeof collection.titleField === 'function') {\n return resolveDocumentTitle(collection, document.values, fallback)\n }\n const field = typeof collection.titleField === 'string' ? collection.titleField : 'title'\n const direct = document.values[field]\n if (typeof direct === 'string' && direct.length > 0) return direct\n const locales = Object.keys(document.localized ?? {}).sort()\n const preferred = document.defaultLocale\n for (const locale of [preferred, ...locales]) {\n if (!locale) continue\n const value = document.localized?.[locale]?.[field]\n if (typeof value === 'string' && value.length > 0) return value\n }\n return fallback\n}\n\n/** Strip the namespace off a component id for compact labels. */\nexport function shortComponentId(componentId: string): string {\n return componentId.replace('base.primitives.', '').replace('project.', '')\n}\n\ninterface DocumentParts {\n collection: CollectionDef | undefined\n collectionId: string\n documentId: string\n title: string\n}\n\nfunction documentParts(context: ReferenceLabelContext, key: string): DocumentParts | null {\n const ref = parseDocumentKey(key)\n if (!ref) return null\n const collection = context.collections.find((c) => c.id === ref.collection)\n return {\n collection,\n collectionId: ref.collection,\n documentId: ref.id,\n title: documentTitleOf(collection, context.documents.get(key), ref.id),\n }\n}\n\nfunction describeDocumentSource(\n context: ReferenceLabelContext,\n entry: MergedReferenceEntry,\n): { sourceLabel: string; locationLabel: string; sourceLink: ReferenceDeepLink | null } {\n const parts = documentParts(context, entry.source.id)\n if (!parts) {\n return { sourceLabel: entry.source.id, locationLabel: entry.path, sourceLink: null }\n }\n const parsed = parseDocumentFieldPath(entry.path)\n const fieldLabel = parsed ? fieldLabelOf(parts.collection, parsed.field) : entry.path\n const qualifiers: string[] = []\n if (parsed?.locale) qualifiers.push(parsed.locale)\n if (entry.kind === 'rich-text-link') qualifiers.push('link')\n if (entry.kind === 'rich-text-node') qualifiers.push('embedded node')\n if (\n entry.kind === 'relation-field' &&\n parsed &&\n parsed.rest.length === 1 &&\n /^\\d+$/.test(parsed.rest[0]!)\n ) {\n qualifiers.push(`item ${parsed.rest[0]}`)\n }\n return {\n sourceLabel: `${collectionLabelOf(parts.collection, parts.collectionId)} · ${parts.title}`,\n locationLabel: qualifiers.length > 0 ? `${fieldLabel} (${qualifiers.join(', ')})` : fieldLabel,\n sourceLink: {\n kind: 'cms-field',\n collectionId: parts.collectionId,\n documentId: parts.documentId,\n fieldPath: entry.path,\n },\n }\n}\n\n\nfunction describeTarget(\n context: ReferenceLabelContext,\n target: ReferenceTarget,\n): { targetLabel: string; targetLink: ReferenceDeepLink | null } {\n switch (target.type) {\n case 'document': {\n const parts = documentParts(context, target.id)\n if (!parts) return { targetLabel: target.id, targetLink: null }\n return {\n targetLabel: `${collectionLabelOf(parts.collection, parts.collectionId)} · ${parts.title}`,\n targetLink: {\n kind: 'cms-field',\n collectionId: parts.collectionId,\n documentId: parts.documentId,\n },\n }\n }\n case 'component':\n return {\n targetLabel: context.componentTitle(target.id) ?? shortComponentId(target.id),\n targetLink: { kind: 'component', componentId: target.id },\n }\n case 'asset': {\n const asset = context.assets.get(target.id)\n return {\n targetLabel: asset ? (asset.title ?? asset.filename) : target.id,\n targetLink: { kind: 'asset', assetId: target.id },\n }\n }\n }\n}\n\n/** Label + link one merged entry (see {@link buildReferenceEntryViews}). */\nexport function buildReferenceEntryView(\n entry: MergedReferenceEntry,\n context: ReferenceLabelContext,\n): ReferenceEntryView {\n // EC-287: a reference source is only ever a CMS document (structure is code).\n const sourceParts = describeDocumentSource(context, entry)\n return {\n ...entry,\n kindLabel: REFERENCE_KIND_LABELS[entry.kind],\n ...sourceParts,\n ...describeTarget(context, entry.target),\n }\n}\n\n/** Merge variants and label every record — the panel's full render model. */\nexport function buildReferenceEntryViews(\n records: readonly ReferenceEntryRecord[],\n context: ReferenceLabelContext,\n): ReferenceEntryView[] {\n return mergeReferenceVariants(records).map((entry) => buildReferenceEntryView(entry, context))\n}\n"]}
@@ -91,6 +91,14 @@ export declare function resolveDeploymentBreakpoints(): BreakpointConfig[] | und
91
91
  * renderers customize the studio, not one backend.
92
92
  */
93
93
  export declare function resolveDeploymentFieldRenderers(): Record<string, CustomFieldRenderer> | undefined;
94
+ /**
95
+ * The studio-UI localization config from the studio config (EC-241): the default
96
+ * locale + imported translation catalogs. Studio-only live code (from `defineStudio`,
97
+ * never the project schema or the delivery bundle); `undefined` when none — the
98
+ * studio then renders its built-in English chrome. Studio-wide, like the rail and
99
+ * field renderers (localizes the studio, not one backend).
100
+ */
101
+ export declare function resolveDeploymentI18n(): StudioConfig['i18n'];
94
102
  /**
95
103
  * The configurable section rail from the studio config (EC-237): an ordered list of
96
104
  * `nav.*` nodes (views / groups / separators). Studio-only live code (carries view
@@ -179,6 +179,16 @@ export function resolveDeploymentBreakpoints() {
179
179
  export function resolveDeploymentFieldRenderers() {
180
180
  return studioConfig?.fieldRenderers;
181
181
  }
182
+ /**
183
+ * The studio-UI localization config from the studio config (EC-241): the default
184
+ * locale + imported translation catalogs. Studio-only live code (from `defineStudio`,
185
+ * never the project schema or the delivery bundle); `undefined` when none — the
186
+ * studio then renders its built-in English chrome. Studio-wide, like the rail and
187
+ * field renderers (localizes the studio, not one backend).
188
+ */
189
+ export function resolveDeploymentI18n() {
190
+ return studioConfig?.i18n;
191
+ }
182
192
  /**
183
193
  * The configurable section rail from the studio config (EC-237): an ordered list of
184
194
  * `nav.*` nodes (views / groups / separators). Studio-only live code (carries view
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/workspace/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { frontendUrlForEnvironment } from '@elytracms/core/studio-core'\nimport type {\n BreakpointConfig,\n ElytraConfigInput,\n ResolvedWorkspaceProject,\n} from '@elytracms/core/studio-core'\nimport type { CollectionDef, RouteRecord } from '@elytracms/core/cms-core'\nimport type { SidebarNode } from '../../components/app-views/module'\nimport type { CustomFieldRenderer, StudioConfig } from '../../components/app-views/studio-config'\nimport { resolveWorkspaceState } from './workspace-source'\nimport type { WorkspaceState } from './workspace-source'\n\nexport { resolveWorkspaceState, WORKSPACE_ENV_VAR } from './workspace-source'\nexport type { WorkspaceSources, WorkspaceState } from './workspace-source'\nexport { persistedProjects, selectSwitcherProjects, unprovisionedProjects } from './switcher-source'\nexport type { SwitcherEntry, SwitcherSourceInput } from './switcher-source'\n\nlet cached: WorkspaceState | null = null\nlet studioConfig: StudioConfig | null = null\n\n/**\n * Mount the studio against a project config (EC-223 mount contract) and an\n * optional studio-only customization config (EC-236). The consumer's entry point\n * does `import config from './elytra.config'` + `import studio from\n * './studio.config'` and calls this — an explicit init, NOT an `import.meta.glob`\n * autoload that reaches into the consumer's filesystem (Oli, 2026-06-19: \"there's\n * always an entry point that can trigger a function call\").\n *\n * Two configs, deliberately: `config` (`elytra.config.ts`) is the project\n * definition, shared with the `frontend/` delivery bundle and projected to data;\n * `studio` (`studio.config.tsx` via `defineStudio`) is live builder UI code — the\n * section rail, custom field renderers, branding — that must NEVER reach delivery.\n * Keeping them separate is the customization boundary principle in the mount\n * signature. Seeds the workspace state + the studio-config holder every later\n * query (`getActiveProjectSlug`, `resolveDeployment*`) reads.\n */\nexport function createStudio(config: ElytraConfigInput, studio?: StudioConfig): void {\n cached = resolveWorkspaceState({\n fileModule: { default: config },\n fileName: 'elytra.config.ts',\n })\n studioConfig = studio ?? null\n}\n\n/** Test seam: set/clear the studio customization config. Never used by app code. */\nexport function setStudioConfigForTests(next: StudioConfig | null): void {\n studioConfig = next\n}\n\n/**\n * The active project slug (EC-179, vision AD-8). One project per backend, so the\n * active project selects which Convex deployment the studio talks to. The root\n * layout sets this from the URL (`/<slug>`) — or, on the sign-in screen, from\n * the `redirect` target's slug — before the auth/persistence adapters are\n * selected, so the *initial* sign-in authenticates against the project the user\n * is heading for (Sanity-style: authenticate to one workspace, then the full\n * config-based switcher is available). `null` at the launcher → the default\n * (first) configured project's deployment.\n */\nlet activeProjectSlug: string | null = null\n\n/** Set the active project slug; returns whether the resolved deployment changed. */\nexport function setActiveProjectSlug(slug: string | null): boolean {\n const before = resolveDeploymentUrl('')\n activeProjectSlug = slug && slug.trim() !== '' ? slug : null\n return resolveDeploymentUrl('') !== before\n}\n\nexport function getActiveProjectSlug(): string | null {\n return activeProjectSlug\n}\n\n/** Test seam: reset the active project slug. Never used by app code. */\nexport function setActiveProjectSlugForTests(slug: string | null): void {\n activeProjectSlug = slug\n}\n\n/**\n * Reserved first-path segments that are NOT project slugs: the studio's own\n * root routes (EC-220). Project surfaces now live at `/<slug>/...` (no `/p/`\n * prefix), so the studio's root namespace is shared between project slugs and\n * these fixed routes — they must be excluded from slug extraction. Keep in\n * sync with the non-`$projectId` files in `src/routes/`; the launcher (`/`) is\n * the empty segment, excluded by the regex requiring one path char.\n */\nconst RESERVED_ROOT_SEGMENTS: ReadonlySet<string> = new Set(['sign-in', 'styleguide'])\n\n/** Extract a project slug from a studio path (`/<slug>/...`), else `null`. */\nexport function projectSlugFromPath(pathname: string): string | null {\n const match = /^\\/([^/?#]+)/.exec(pathname)\n if (!match) return null\n const segment = decodeURIComponent(match[1]!)\n return RESERVED_ROOT_SEGMENTS.has(segment) ? null : segment\n}\n\n/**\n * The project whose backend the studio should bind for a given location\n * (EC-179). A project path (`/<slug>`) binds that project; the sign-in screen\n * binds the project from its `redirect` target so the *initial* sign-in\n * authenticates against the backend the user is heading for (Sanity-style).\n * Anywhere else (the launcher) → `null`, i.e. the default/first project.\n */\nexport function activeSlugForLocation(pathname: string, redirect?: string): string | null {\n const direct = projectSlugFromPath(pathname)\n if (direct) return direct\n if (pathname === '/sign-in' && redirect) return projectSlugFromPath(redirect)\n return null\n}\n\n/** The active config project (by slug), or the first configured project. */\nfunction activeConfigProject() {\n const state = getWorkspaceState()\n if (state.kind !== 'config') return undefined\n if (activeProjectSlug) {\n const match = state.projects.find((p) => p.slug === activeProjectSlug)\n if (match) return match\n }\n return state.projects[0]\n}\n\n/**\n * The studio's resolved workspace state. Deterministic per boot: the config is\n * static input (bundled file or deployment env), so it is resolved once and\n * cached — every consumer (gate, switcher, launcher) sees the same state.\n */\nexport function getWorkspaceState(): WorkspaceState {\n // Seeded by `createStudio(config)` at the entry point. Until then — or when the\n // consumer wires no config — resolve to the empty `none` state (the single-project\n // golden path), rather than reaching for the filesystem.\n if (!cached) cached = resolveWorkspaceState({})\n return cached\n}\n\n/** Test seam: clear/replace the cached state. Never used by app code. */\nexport function setWorkspaceStateForTests(next: WorkspaceState | null): void {\n cached = next\n}\n\n/**\n * Resolve the Convex deployment URL the studio should connect to (vision AD-8:\n * the backend is wired in config). One project per backend, so the **active**\n * project (see {@link setActiveProjectSlug}) selects the deployment via its\n * `convex.deployment` (or its production environment's). At the launcher (no\n * active project) the first configured project is the default backend. Absent\n * config — or a project without a wired deployment — falls back to\n * `VITE_CONVEX_URL` (`fallbackUrl`) for local single-deployment development.\n */\nexport function resolveDeploymentUrl(fallbackUrl: string): string {\n return projectDeploymentUrl(activeConfigProject(), fallbackUrl)\n}\n\n/** The deployment URL for a specific project slug (per-backend auth checks). */\nexport function deploymentUrlForSlug(slug: string, fallbackUrl: string): string {\n const state = getWorkspaceState()\n const project = state.kind === 'config' ? state.projects.find((p) => p.slug === slug) : undefined\n return projectDeploymentUrl(project, fallbackUrl)\n}\n\n/** A project's wired deployment: per-environment ref → project ref → env fallback. */\nfunction projectDeploymentUrl(\n project: ResolvedWorkspaceProject | undefined,\n fallbackUrl: string,\n): string {\n if (!project) return fallbackUrl\n const envDeployment = project.environments.find((e) => e.convex?.deployment)?.convex?.deployment\n return envDeployment ?? project.convex?.deployment ?? fallbackUrl\n}\n\n/**\n * The slug of the project bound to the active deployment (EC-179). One project\n * per backend, so the active config project's slug identifies the deployment's\n * one project; the Convex adapter stamps it onto deployment-scoped records.\n * Absent config falls back to `fallbackId` (used only when wired by env alone).\n */\nexport function resolveDeploymentProjectId(fallbackId: string): string {\n return activeConfigProject()?.slug ?? fallbackId\n}\n\n/**\n * The CMS collections of the active config project (AD-11, EC-183). CMS\n * collection schemas are config-owned: the studio reads the model from\n * `elytra.config.ts` (served through the persistence port — the backend has no\n * `cmsSchemas` table). `[]` when the active project declares none, or when the\n * studio is wired by env alone with no config.\n */\nexport function resolveDeploymentCollections(): CollectionDef[] {\n return activeConfigProject()?.collections ?? []\n}\n\n/**\n * The canvas preview breakpoints of the active config project (EC-250).\n * Config-sourced (config-as-code, derived from the site's Tailwind `screens`);\n * `undefined` when the project declares none — the canvas then falls back to\n * Tailwind's default screens (see `resolveCanvasViewports`), never a baked-in triple.\n */\nexport function resolveDeploymentBreakpoints(): BreakpointConfig[] | undefined {\n return activeConfigProject()?.breakpoints\n}\n\n/**\n * The custom field renderers from the studio config (EC-238): control name →\n * component. Studio-only live code (from `defineStudio`, never the project schema\n * or the delivery bundle); `undefined` when none — the document editor then uses\n * its built-in control for every field. Studio-wide (not per-project): the rail and\n * renderers customize the studio, not one backend.\n */\nexport function resolveDeploymentFieldRenderers(): Record<string, CustomFieldRenderer> | undefined {\n return studioConfig?.fieldRenderers\n}\n\n/**\n * The configurable section rail from the studio config (EC-237): an ordered list of\n * `nav.*` nodes (views / groups / separators). Studio-only live code (carries view\n * objects + icons); `undefined` when none — the studio then derives the default\n * rail from its built-in views. Invalid entries surface as visible issues at\n * resolution, never silent.\n */\nexport function resolveDeploymentSidebar(): SidebarNode[] | undefined {\n return studioConfig?.sidebar\n}\n\n/**\n * The resolved URL routes of the active config project (EC-207, \"routes as\n * code\"). Routes are config-sourced: the studio reads the materialized\n * `RouteRecord[]` from the active `elytra.config.ts` project — never from the\n * backend (the `routes` system collection is retired). The Routes surface and\n * the per-page URL preview both read through here. `[]` when the active project\n * declares none, or when the studio is wired by env alone with no config.\n */\nexport function resolveDeploymentRoutes(): RouteRecord[] {\n return activeConfigProject()?.routes ?? []\n}\n\n// Redirects are editorial DATA now (EC-303), managed in the studio Redirects rail\n// and served dynamically — no longer resolved from config. `resolveDeploymentRedirects`\n// is retired; static/infra redirects are the dev's job via native next.config/vercel.\n\n/**\n * The configured locales of the active config project (AD-8). The same locale\n * set the host stamps onto its per-locale cache tags — used by the revalidation\n * webhook layer (EC-192) so a publish always invalidates EVERY configured locale\n * (e.g. `/de`, `/fr`), never just the default. `[]` when wired by env alone.\n */\nexport function resolveDeploymentLocales(): string[] {\n return activeConfigProject()?.locales ?? []\n}\n\n/**\n * The active project's components reference (EC-194, AD-11): where the consuming\n * repo's OWN real components live (`{ package }` or `{ dir }`). When set, the\n * studio registry composes with the repo's components instead of the built-in\n * demo fixtures — so the page builder edits the repo's actual component library.\n * `undefined` → the project ships no code components; the studio falls back to the\n * golden-path fixtures.\n */\nexport function resolveDeploymentComponents() {\n return activeConfigProject()?.components\n}\n\n/**\n * The active project's public site URL (EC-215): the live site's base URL the\n * studio links to (a document's live URL + open-live button, EC-216). Resolved\n * in lockstep with {@link resolveDeploymentUrl} — the environment bound to the\n * active deployment (the first with a wired deployment) provides the URL, falling\n * back to the project-level `frontendUrl`. No active-environment selector exists\n * yet, so the bound environment is the active one. `undefined` when the active\n * project (or env-only wiring) configures no frontend URL.\n */\nexport function resolveDeploymentFrontendUrl(): string | undefined {\n const project = activeConfigProject()\n if (!project) return undefined\n const boundEnv = project.environments.find((e) => e.convex?.deployment)\n return frontendUrlForEnvironment(project, boundEnv?.key)\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/workspace/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { frontendUrlForEnvironment } from '@elytracms/core/studio-core'\nimport type {\n BreakpointConfig,\n ElytraConfigInput,\n ResolvedWorkspaceProject,\n} from '@elytracms/core/studio-core'\nimport type { CollectionDef, RouteRecord } from '@elytracms/core/cms-core'\nimport type { SidebarNode } from '../../components/app-views/module'\nimport type { CustomFieldRenderer, StudioConfig } from '../../components/app-views/studio-config'\nimport { resolveWorkspaceState } from './workspace-source'\nimport type { WorkspaceState } from './workspace-source'\n\nexport { resolveWorkspaceState, WORKSPACE_ENV_VAR } from './workspace-source'\nexport type { WorkspaceSources, WorkspaceState } from './workspace-source'\nexport { persistedProjects, selectSwitcherProjects, unprovisionedProjects } from './switcher-source'\nexport type { SwitcherEntry, SwitcherSourceInput } from './switcher-source'\n\nlet cached: WorkspaceState | null = null\nlet studioConfig: StudioConfig | null = null\n\n/**\n * Mount the studio against a project config (EC-223 mount contract) and an\n * optional studio-only customization config (EC-236). The consumer's entry point\n * does `import config from './elytra.config'` + `import studio from\n * './studio.config'` and calls this — an explicit init, NOT an `import.meta.glob`\n * autoload that reaches into the consumer's filesystem (Oli, 2026-06-19: \"there's\n * always an entry point that can trigger a function call\").\n *\n * Two configs, deliberately: `config` (`elytra.config.ts`) is the project\n * definition, shared with the `frontend/` delivery bundle and projected to data;\n * `studio` (`studio.config.tsx` via `defineStudio`) is live builder UI code — the\n * section rail, custom field renderers, branding — that must NEVER reach delivery.\n * Keeping them separate is the customization boundary principle in the mount\n * signature. Seeds the workspace state + the studio-config holder every later\n * query (`getActiveProjectSlug`, `resolveDeployment*`) reads.\n */\nexport function createStudio(config: ElytraConfigInput, studio?: StudioConfig): void {\n cached = resolveWorkspaceState({\n fileModule: { default: config },\n fileName: 'elytra.config.ts',\n })\n studioConfig = studio ?? null\n}\n\n/** Test seam: set/clear the studio customization config. Never used by app code. */\nexport function setStudioConfigForTests(next: StudioConfig | null): void {\n studioConfig = next\n}\n\n/**\n * The active project slug (EC-179, vision AD-8). One project per backend, so the\n * active project selects which Convex deployment the studio talks to. The root\n * layout sets this from the URL (`/<slug>`) — or, on the sign-in screen, from\n * the `redirect` target's slug — before the auth/persistence adapters are\n * selected, so the *initial* sign-in authenticates against the project the user\n * is heading for (Sanity-style: authenticate to one workspace, then the full\n * config-based switcher is available). `null` at the launcher → the default\n * (first) configured project's deployment.\n */\nlet activeProjectSlug: string | null = null\n\n/** Set the active project slug; returns whether the resolved deployment changed. */\nexport function setActiveProjectSlug(slug: string | null): boolean {\n const before = resolveDeploymentUrl('')\n activeProjectSlug = slug && slug.trim() !== '' ? slug : null\n return resolveDeploymentUrl('') !== before\n}\n\nexport function getActiveProjectSlug(): string | null {\n return activeProjectSlug\n}\n\n/** Test seam: reset the active project slug. Never used by app code. */\nexport function setActiveProjectSlugForTests(slug: string | null): void {\n activeProjectSlug = slug\n}\n\n/**\n * Reserved first-path segments that are NOT project slugs: the studio's own\n * root routes (EC-220). Project surfaces now live at `/<slug>/...` (no `/p/`\n * prefix), so the studio's root namespace is shared between project slugs and\n * these fixed routes — they must be excluded from slug extraction. Keep in\n * sync with the non-`$projectId` files in `src/routes/`; the launcher (`/`) is\n * the empty segment, excluded by the regex requiring one path char.\n */\nconst RESERVED_ROOT_SEGMENTS: ReadonlySet<string> = new Set(['sign-in', 'styleguide'])\n\n/** Extract a project slug from a studio path (`/<slug>/...`), else `null`. */\nexport function projectSlugFromPath(pathname: string): string | null {\n const match = /^\\/([^/?#]+)/.exec(pathname)\n if (!match) return null\n const segment = decodeURIComponent(match[1]!)\n return RESERVED_ROOT_SEGMENTS.has(segment) ? null : segment\n}\n\n/**\n * The project whose backend the studio should bind for a given location\n * (EC-179). A project path (`/<slug>`) binds that project; the sign-in screen\n * binds the project from its `redirect` target so the *initial* sign-in\n * authenticates against the backend the user is heading for (Sanity-style).\n * Anywhere else (the launcher) → `null`, i.e. the default/first project.\n */\nexport function activeSlugForLocation(pathname: string, redirect?: string): string | null {\n const direct = projectSlugFromPath(pathname)\n if (direct) return direct\n if (pathname === '/sign-in' && redirect) return projectSlugFromPath(redirect)\n return null\n}\n\n/** The active config project (by slug), or the first configured project. */\nfunction activeConfigProject() {\n const state = getWorkspaceState()\n if (state.kind !== 'config') return undefined\n if (activeProjectSlug) {\n const match = state.projects.find((p) => p.slug === activeProjectSlug)\n if (match) return match\n }\n return state.projects[0]\n}\n\n/**\n * The studio's resolved workspace state. Deterministic per boot: the config is\n * static input (bundled file or deployment env), so it is resolved once and\n * cached — every consumer (gate, switcher, launcher) sees the same state.\n */\nexport function getWorkspaceState(): WorkspaceState {\n // Seeded by `createStudio(config)` at the entry point. Until then — or when the\n // consumer wires no config — resolve to the empty `none` state (the single-project\n // golden path), rather than reaching for the filesystem.\n if (!cached) cached = resolveWorkspaceState({})\n return cached\n}\n\n/** Test seam: clear/replace the cached state. Never used by app code. */\nexport function setWorkspaceStateForTests(next: WorkspaceState | null): void {\n cached = next\n}\n\n/**\n * Resolve the Convex deployment URL the studio should connect to (vision AD-8:\n * the backend is wired in config). One project per backend, so the **active**\n * project (see {@link setActiveProjectSlug}) selects the deployment via its\n * `convex.deployment` (or its production environment's). At the launcher (no\n * active project) the first configured project is the default backend. Absent\n * config — or a project without a wired deployment — falls back to\n * `VITE_CONVEX_URL` (`fallbackUrl`) for local single-deployment development.\n */\nexport function resolveDeploymentUrl(fallbackUrl: string): string {\n return projectDeploymentUrl(activeConfigProject(), fallbackUrl)\n}\n\n/** The deployment URL for a specific project slug (per-backend auth checks). */\nexport function deploymentUrlForSlug(slug: string, fallbackUrl: string): string {\n const state = getWorkspaceState()\n const project = state.kind === 'config' ? state.projects.find((p) => p.slug === slug) : undefined\n return projectDeploymentUrl(project, fallbackUrl)\n}\n\n/** A project's wired deployment: per-environment ref → project ref → env fallback. */\nfunction projectDeploymentUrl(\n project: ResolvedWorkspaceProject | undefined,\n fallbackUrl: string,\n): string {\n if (!project) return fallbackUrl\n const envDeployment = project.environments.find((e) => e.convex?.deployment)?.convex?.deployment\n return envDeployment ?? project.convex?.deployment ?? fallbackUrl\n}\n\n/**\n * The slug of the project bound to the active deployment (EC-179). One project\n * per backend, so the active config project's slug identifies the deployment's\n * one project; the Convex adapter stamps it onto deployment-scoped records.\n * Absent config falls back to `fallbackId` (used only when wired by env alone).\n */\nexport function resolveDeploymentProjectId(fallbackId: string): string {\n return activeConfigProject()?.slug ?? fallbackId\n}\n\n/**\n * The CMS collections of the active config project (AD-11, EC-183). CMS\n * collection schemas are config-owned: the studio reads the model from\n * `elytra.config.ts` (served through the persistence port — the backend has no\n * `cmsSchemas` table). `[]` when the active project declares none, or when the\n * studio is wired by env alone with no config.\n */\nexport function resolveDeploymentCollections(): CollectionDef[] {\n return activeConfigProject()?.collections ?? []\n}\n\n/**\n * The canvas preview breakpoints of the active config project (EC-250).\n * Config-sourced (config-as-code, derived from the site's Tailwind `screens`);\n * `undefined` when the project declares none — the canvas then falls back to\n * Tailwind's default screens (see `resolveCanvasViewports`), never a baked-in triple.\n */\nexport function resolveDeploymentBreakpoints(): BreakpointConfig[] | undefined {\n return activeConfigProject()?.breakpoints\n}\n\n/**\n * The custom field renderers from the studio config (EC-238): control name →\n * component. Studio-only live code (from `defineStudio`, never the project schema\n * or the delivery bundle); `undefined` when none — the document editor then uses\n * its built-in control for every field. Studio-wide (not per-project): the rail and\n * renderers customize the studio, not one backend.\n */\nexport function resolveDeploymentFieldRenderers(): Record<string, CustomFieldRenderer> | undefined {\n return studioConfig?.fieldRenderers\n}\n\n/**\n * The studio-UI localization config from the studio config (EC-241): the default\n * locale + imported translation catalogs. Studio-only live code (from `defineStudio`,\n * never the project schema or the delivery bundle); `undefined` when none — the\n * studio then renders its built-in English chrome. Studio-wide, like the rail and\n * field renderers (localizes the studio, not one backend).\n */\nexport function resolveDeploymentI18n(): StudioConfig['i18n'] {\n return studioConfig?.i18n\n}\n\n/**\n * The configurable section rail from the studio config (EC-237): an ordered list of\n * `nav.*` nodes (views / groups / separators). Studio-only live code (carries view\n * objects + icons); `undefined` when none — the studio then derives the default\n * rail from its built-in views. Invalid entries surface as visible issues at\n * resolution, never silent.\n */\nexport function resolveDeploymentSidebar(): SidebarNode[] | undefined {\n return studioConfig?.sidebar\n}\n\n/**\n * The resolved URL routes of the active config project (EC-207, \"routes as\n * code\"). Routes are config-sourced: the studio reads the materialized\n * `RouteRecord[]` from the active `elytra.config.ts` project — never from the\n * backend (the `routes` system collection is retired). The Routes surface and\n * the per-page URL preview both read through here. `[]` when the active project\n * declares none, or when the studio is wired by env alone with no config.\n */\nexport function resolveDeploymentRoutes(): RouteRecord[] {\n return activeConfigProject()?.routes ?? []\n}\n\n// Redirects are editorial DATA now (EC-303), managed in the studio Redirects rail\n// and served dynamically — no longer resolved from config. `resolveDeploymentRedirects`\n// is retired; static/infra redirects are the dev's job via native next.config/vercel.\n\n/**\n * The configured locales of the active config project (AD-8). The same locale\n * set the host stamps onto its per-locale cache tags — used by the revalidation\n * webhook layer (EC-192) so a publish always invalidates EVERY configured locale\n * (e.g. `/de`, `/fr`), never just the default. `[]` when wired by env alone.\n */\nexport function resolveDeploymentLocales(): string[] {\n return activeConfigProject()?.locales ?? []\n}\n\n/**\n * The active project's components reference (EC-194, AD-11): where the consuming\n * repo's OWN real components live (`{ package }` or `{ dir }`). When set, the\n * studio registry composes with the repo's components instead of the built-in\n * demo fixtures — so the page builder edits the repo's actual component library.\n * `undefined` → the project ships no code components; the studio falls back to the\n * golden-path fixtures.\n */\nexport function resolveDeploymentComponents() {\n return activeConfigProject()?.components\n}\n\n/**\n * The active project's public site URL (EC-215): the live site's base URL the\n * studio links to (a document's live URL + open-live button, EC-216). Resolved\n * in lockstep with {@link resolveDeploymentUrl} — the environment bound to the\n * active deployment (the first with a wired deployment) provides the URL, falling\n * back to the project-level `frontendUrl`. No active-environment selector exists\n * yet, so the bound environment is the active one. `undefined` when the active\n * project (or env-only wiring) configures no frontend URL.\n */\nexport function resolveDeploymentFrontendUrl(): string | undefined {\n const project = activeConfigProject()\n if (!project) return undefined\n const boundEnv = project.environments.find((e) => e.convex?.deployment)\n return frontendUrlForEnvironment(project, boundEnv?.key)\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { type VariantProps } from 'class-variance-authority';
2
2
  import type { HTMLAttributes } from 'react';
3
3
  export declare const badgeVariants: (props?: ({
4
- variant?: "error" | "default" | "primary" | "outline" | "success" | "warning" | "info" | null | undefined;
4
+ variant?: "error" | "default" | "warning" | "primary" | "outline" | "success" | "info" | null | undefined;
5
5
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
6
6
  export interface BadgeProps extends HTMLAttributes<HTMLSpanElement>, VariantProps<typeof badgeVariants> {
7
7
  }
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.29",
4
+ "version": "0.0.32",
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",
@@ -52,6 +52,10 @@
52
52
  "types": "./dist/lib/workspace/index.d.ts",
53
53
  "default": "./dist/lib/workspace/index.js"
54
54
  },
55
+ "./lib/i18n": {
56
+ "types": "./dist/lib/i18n/index.d.ts",
57
+ "default": "./dist/lib/i18n/index.js"
58
+ },
55
59
  "./lib/registry": {
56
60
  "types": "./dist/lib/registry/index.d.ts",
57
61
  "default": "./dist/lib/registry/index.js"
@@ -123,7 +127,7 @@
123
127
  "lucide-react": "^1.17.0",
124
128
  "tailwind-merge": "^3.6.0",
125
129
  "zod": "^4.0.0",
126
- "@elytracms/core": "^0.0.29"
130
+ "@elytracms/core": "^0.0.32"
127
131
  },
128
132
  "peerDependencies": {
129
133
  "@tanstack/react-router": "^1.170.0",