@elytracms/studio 0.0.86 → 0.0.88

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 (248) hide show
  1. package/convex/asset-revalidate.test.ts +186 -0
  2. package/convex/assets.ts +53 -19
  3. package/convex/cms.ts +22 -0
  4. package/convex/delivery.ts +33 -116
  5. package/convex/functions.ts +3 -3
  6. package/convex/rail-write-parity.test.ts +180 -0
  7. package/convex/redirects.ts +33 -11
  8. package/convex/revalidate.ts +7 -5
  9. package/convex/triggers.ts +53 -3
  10. package/dist/components/ai/ai-chat-panel.js +8 -1
  11. package/dist/components/ai/ai-chat-panel.js.map +1 -1
  12. package/dist/components/app-views/default-modules.d.ts +20 -20
  13. package/dist/components/app-views/default-modules.js +27 -48
  14. package/dist/components/app-views/default-modules.js.map +1 -1
  15. package/dist/components/app-views/studio-config.d.ts +5 -6
  16. package/dist/components/app-views/studio-config.js.map +1 -1
  17. package/dist/components/assets/asset-metadata.d.ts +28 -19
  18. package/dist/components/assets/asset-metadata.js +24 -31
  19. package/dist/components/assets/asset-metadata.js.map +1 -1
  20. package/dist/components/assets/asset-selection.d.ts +24 -5
  21. package/dist/components/assets/asset-selection.js +39 -9
  22. package/dist/components/assets/asset-selection.js.map +1 -1
  23. package/dist/components/assets/assets-collection-view-source.d.ts +17 -14
  24. package/dist/components/assets/assets-collection-view-source.js +25 -31
  25. package/dist/components/assets/assets-collection-view-source.js.map +1 -1
  26. package/dist/components/assets/assets-store.d.ts +11 -1
  27. package/dist/components/assets/assets-store.js +10 -0
  28. package/dist/components/assets/assets-store.js.map +1 -1
  29. package/dist/components/assets/focal-point.d.ts +0 -7
  30. package/dist/components/assets/focal-point.js +0 -10
  31. package/dist/components/assets/focal-point.js.map +1 -1
  32. package/dist/components/builder/blocks-panel.js +3 -3
  33. package/dist/components/builder/blocks-panel.js.map +1 -1
  34. package/dist/components/builder/builder-store.d.ts +25 -1
  35. package/dist/components/builder/builder-store.js +3 -2
  36. package/dist/components/builder/builder-store.js.map +1 -1
  37. package/dist/components/builder/canvas-chrome-css.js +0 -17
  38. package/dist/components/builder/canvas-chrome-css.js.map +1 -1
  39. package/dist/components/builder/canvas-chrome.d.ts +10 -12
  40. package/dist/components/builder/canvas-chrome.js +12 -13
  41. package/dist/components/builder/canvas-chrome.js.map +1 -1
  42. package/dist/components/builder/canvas-dnd.d.ts +8 -0
  43. package/dist/components/builder/canvas-dnd.js +5 -3
  44. package/dist/components/builder/canvas-dnd.js.map +1 -1
  45. package/dist/components/builder/canvas-render-context.d.ts +23 -24
  46. package/dist/components/builder/canvas-render-context.js +35 -60
  47. package/dist/components/builder/canvas-render-context.js.map +1 -1
  48. package/dist/components/builder/canvas.js +5 -11
  49. package/dist/components/builder/canvas.js.map +1 -1
  50. package/dist/components/builder/clipboard-actions.d.ts +14 -6
  51. package/dist/components/builder/clipboard-actions.js +29 -20
  52. package/dist/components/builder/clipboard-actions.js.map +1 -1
  53. package/dist/components/builder/composition-field-editor.d.ts +19 -26
  54. package/dist/components/builder/composition-field-editor.js +30 -52
  55. package/dist/components/builder/composition-field-editor.js.map +1 -1
  56. package/dist/components/builder/insert-context.d.ts +3 -1
  57. package/dist/components/builder/insert-context.js +15 -10
  58. package/dist/components/builder/insert-context.js.map +1 -1
  59. package/dist/components/builder/page-tree.d.ts +29 -0
  60. package/dist/components/builder/page-tree.js +56 -58
  61. package/dist/components/builder/page-tree.js.map +1 -1
  62. package/dist/components/builder/reuse.js +5 -2
  63. package/dist/components/builder/reuse.js.map +1 -1
  64. package/dist/components/cms/asset-field.d.ts +2 -1
  65. package/dist/components/cms/asset-field.js +39 -83
  66. package/dist/components/cms/asset-field.js.map +1 -1
  67. package/dist/components/cms/asset-picker-core.d.ts +77 -40
  68. package/dist/components/cms/asset-picker-core.js +73 -46
  69. package/dist/components/cms/asset-picker-core.js.map +1 -1
  70. package/dist/components/cms/asset-picker.d.ts +48 -19
  71. package/dist/components/cms/asset-picker.js +69 -30
  72. package/dist/components/cms/asset-picker.js.map +1 -1
  73. package/dist/components/cms/cell-edit.d.ts +3 -1
  74. package/dist/components/cms/cell-edit.js +2 -2
  75. package/dist/components/cms/cell-edit.js.map +1 -1
  76. package/dist/components/cms/cms-composition-validators.js +11 -2
  77. package/dist/components/cms/cms-composition-validators.js.map +1 -1
  78. package/dist/components/cms/cms-store.js +15 -23
  79. package/dist/components/cms/cms-store.js.map +1 -1
  80. package/dist/components/cms/editable-cell.js +3 -3
  81. package/dist/components/cms/editable-cell.js.map +1 -1
  82. package/dist/components/cms/gate-validation.d.ts +27 -2
  83. package/dist/components/cms/gate-validation.js +19 -1
  84. package/dist/components/cms/gate-validation.js.map +1 -1
  85. package/dist/components/cms/rich-text/editor.js +2 -2
  86. package/dist/components/cms/rich-text/editor.js.map +1 -1
  87. package/dist/components/cms/rich-text/insert.d.ts +7 -0
  88. package/dist/components/cms/rich-text/insert.js +7 -0
  89. package/dist/components/cms/rich-text/insert.js.map +1 -1
  90. package/dist/components/cms/use-document-versions.js +1 -0
  91. package/dist/components/cms/use-document-versions.js.map +1 -1
  92. package/dist/components/cms/versions-model.d.ts +0 -12
  93. package/dist/components/cms/versions-model.js +3 -15
  94. package/dist/components/cms/versions-model.js.map +1 -1
  95. package/dist/components/components/component-detail.js +1 -1
  96. package/dist/components/components/component-detail.js.map +1 -1
  97. package/dist/components/components/transfer-dialog.js +2 -4
  98. package/dist/components/components/transfer-dialog.js.map +1 -1
  99. package/dist/components/components/transfer.d.ts +13 -10
  100. package/dist/components/components/transfer.js +21 -19
  101. package/dist/components/components/transfer.js.map +1 -1
  102. package/dist/components/nav-issues.d.ts +23 -3
  103. package/dist/components/nav-issues.js +38 -2
  104. package/dist/components/nav-issues.js.map +1 -1
  105. package/dist/components/project-session.d.ts +9 -0
  106. package/dist/components/project-session.js +1 -1
  107. package/dist/components/project-session.js.map +1 -1
  108. package/dist/components/redirects/redirects-collection-view-source.d.ts +17 -2
  109. package/dist/components/redirects/redirects-collection-view-source.js +20 -6
  110. package/dist/components/redirects/redirects-collection-view-source.js.map +1 -1
  111. package/dist/components/section-nav.js +26 -2
  112. package/dist/components/section-nav.js.map +1 -1
  113. package/dist/components/section-surface.js +3 -2
  114. package/dist/components/section-surface.js.map +1 -1
  115. package/dist/components/settings-form.js +1 -2
  116. package/dist/components/settings-form.js.map +1 -1
  117. package/dist/components/studio-context.js +1 -18
  118. package/dist/components/studio-context.js.map +1 -1
  119. package/dist/components/studio-project-screen.js +3 -5
  120. package/dist/components/studio-project-screen.js.map +1 -1
  121. package/dist/lib/ai/apply-content.js +73 -29
  122. package/dist/lib/ai/apply-content.js.map +1 -1
  123. package/dist/lib/ai/constraints.d.ts +35 -0
  124. package/dist/lib/ai/constraints.js +104 -4
  125. package/dist/lib/ai/constraints.js.map +1 -1
  126. package/dist/lib/ai/route.js +4 -1
  127. package/dist/lib/ai/route.js.map +1 -1
  128. package/dist/lib/ai/shape.d.ts +3 -2
  129. package/dist/lib/ai/shape.js +16 -24
  130. package/dist/lib/ai/shape.js.map +1 -1
  131. package/dist/lib/ai/tools.d.ts +10 -4
  132. package/dist/lib/ai/tools.js +12 -4
  133. package/dist/lib/ai/tools.js.map +1 -1
  134. package/dist/lib/ai/types.d.ts +8 -0
  135. package/dist/lib/ai/types.js.map +1 -1
  136. package/dist/lib/ai/update-fields.js +33 -12
  137. package/dist/lib/ai/update-fields.js.map +1 -1
  138. package/dist/lib/assets/asset-placements.d.ts +35 -0
  139. package/dist/lib/assets/asset-placements.js +74 -0
  140. package/dist/lib/assets/asset-placements.js.map +1 -0
  141. package/dist/lib/assets/backfill-thumbs.d.ts +9 -8
  142. package/dist/lib/assets/backfill-thumbs.js +13 -25
  143. package/dist/lib/assets/backfill-thumbs.js.map +1 -1
  144. package/dist/lib/clipboard/paste-issues.d.ts +17 -15
  145. package/dist/lib/clipboard/paste-issues.js +8 -45
  146. package/dist/lib/clipboard/paste-issues.js.map +1 -1
  147. package/dist/lib/clipboard/paste-target.d.ts +25 -1
  148. package/dist/lib/clipboard/paste-target.js +13 -6
  149. package/dist/lib/clipboard/paste-target.js.map +1 -1
  150. package/dist/lib/cms/published-documents.js +1 -0
  151. package/dist/lib/cms/published-documents.js.map +1 -1
  152. package/dist/lib/cms-views/view-model.d.ts +3 -3
  153. package/dist/lib/data/collection-content.d.ts +22 -1
  154. package/dist/lib/data/collection-content.js +15 -0
  155. package/dist/lib/data/collection-content.js.map +1 -1
  156. package/dist/lib/data/index.d.ts +0 -3
  157. package/dist/lib/data/index.js +4 -6
  158. package/dist/lib/data/index.js.map +1 -1
  159. package/dist/lib/dnd/drop-rules.d.ts +45 -2
  160. package/dist/lib/dnd/drop-rules.js +64 -9
  161. package/dist/lib/dnd/drop-rules.js.map +1 -1
  162. package/dist/lib/engine-version.d.ts +3 -3
  163. package/dist/lib/engine-version.js +3 -3
  164. package/dist/lib/engine-version.js.map +1 -1
  165. package/dist/lib/i18n/messages.de.js +9 -56
  166. package/dist/lib/i18n/messages.de.js.map +1 -1
  167. package/dist/lib/i18n/messages.en.d.ts +8 -53
  168. package/dist/lib/i18n/messages.en.js +14 -57
  169. package/dist/lib/i18n/messages.en.js.map +1 -1
  170. package/dist/lib/locale/fallback.js +8 -2
  171. package/dist/lib/locale/fallback.js.map +1 -1
  172. package/dist/lib/locale/index.d.ts +0 -1
  173. package/dist/lib/locale/index.js +0 -1
  174. package/dist/lib/locale/index.js.map +1 -1
  175. package/dist/lib/locale/locale-store.d.ts +10 -3
  176. package/dist/lib/locale/locale-store.js +12 -5
  177. package/dist/lib/locale/locale-store.js.map +1 -1
  178. package/dist/lib/operations/session-hydration.d.ts +24 -22
  179. package/dist/lib/operations/session-hydration.js +15 -53
  180. package/dist/lib/operations/session-hydration.js.map +1 -1
  181. package/dist/lib/persistence/convex-adapter.js +63 -75
  182. package/dist/lib/persistence/convex-adapter.js.map +1 -1
  183. package/dist/lib/persona/labels.d.ts +0 -2
  184. package/dist/lib/persona/labels.js +1 -7
  185. package/dist/lib/persona/labels.js.map +1 -1
  186. package/dist/lib/registry/index.d.ts +4 -2
  187. package/dist/lib/registry/index.js +26 -21
  188. package/dist/lib/registry/index.js.map +1 -1
  189. package/dist/lib/registry/project-components.js +0 -3
  190. package/dist/lib/registry/project-components.js.map +1 -1
  191. package/dist/lib/routes/route-issues.js +4 -5
  192. package/dist/lib/routes/route-issues.js.map +1 -1
  193. package/dist/lib/theme.js +3 -2
  194. package/dist/lib/theme.js.map +1 -1
  195. package/dist/lib/webhooks/tags.js +11 -14
  196. package/dist/lib/webhooks/tags.js.map +1 -1
  197. package/dist/lib/workspace/config-issues.d.ts +6 -0
  198. package/dist/lib/workspace/config-issues.js +8 -4
  199. package/dist/lib/workspace/config-issues.js.map +1 -1
  200. package/dist/lib/workspace/index.d.ts +2 -2
  201. package/dist/lib/workspace/index.js +2 -2
  202. package/dist/lib/workspace/index.js.map +1 -1
  203. package/dist/previews/enumerate.d.ts +27 -9
  204. package/dist/previews/enumerate.js +27 -6
  205. package/dist/previews/enumerate.js.map +1 -1
  206. package/dist/previews/manifest-format.d.ts +9 -0
  207. package/dist/previews/manifest-format.js.map +1 -1
  208. package/dist/router/match.d.ts +0 -2
  209. package/dist/router/match.js +0 -2
  210. package/dist/router/match.js.map +1 -1
  211. package/dist/router/navigate-once.d.ts +19 -4
  212. package/dist/router/navigate-once.js +22 -5
  213. package/dist/router/navigate-once.js.map +1 -1
  214. package/dist/ui/badge.d.ts +1 -1
  215. package/package.json +3 -3
  216. package/src/styles/studio.css +5 -4
  217. package/src/styles/tokens.css +72 -55
  218. package/convex/content.ts +0 -291
  219. package/dist/components/collab/collab-context.d.ts +0 -27
  220. package/dist/components/collab/collab-context.js +0 -39
  221. package/dist/components/collab/collab-context.js.map +0 -1
  222. package/dist/components/collab/collab-seed.d.ts +0 -15
  223. package/dist/components/collab/collab-seed.js +0 -20
  224. package/dist/components/collab/collab-seed.js.map +0 -1
  225. package/dist/components/extensions/extensions-view.d.ts +0 -7
  226. package/dist/components/extensions/extensions-view.js +0 -127
  227. package/dist/components/extensions/extensions-view.js.map +0 -1
  228. package/dist/lib/bindings/section-bindings.d.ts +0 -24
  229. package/dist/lib/bindings/section-bindings.js +0 -9
  230. package/dist/lib/bindings/section-bindings.js.map +0 -1
  231. package/dist/lib/data/data-store.d.ts +0 -98
  232. package/dist/lib/data/data-store.js +0 -211
  233. package/dist/lib/data/data-store.js.map +0 -1
  234. package/dist/lib/data/providers.d.ts +0 -143
  235. package/dist/lib/data/providers.js +0 -255
  236. package/dist/lib/data/providers.js.map +0 -1
  237. package/dist/lib/data/sample-capture.d.ts +0 -30
  238. package/dist/lib/data/sample-capture.js +0 -70
  239. package/dist/lib/data/sample-capture.js.map +0 -1
  240. package/dist/lib/data/sources-store.d.ts +0 -42
  241. package/dist/lib/data/sources-store.js +0 -120
  242. package/dist/lib/data/sources-store.js.map +0 -1
  243. package/dist/lib/locale/binding-fallback.d.ts +0 -35
  244. package/dist/lib/locale/binding-fallback.js +0 -73
  245. package/dist/lib/locale/binding-fallback.js.map +0 -1
  246. package/dist/lib/starters/kit-session.d.ts +0 -5
  247. package/dist/lib/starters/kit-session.js +0 -17
  248. package/dist/lib/starters/kit-session.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"data-store.js","sourceRoot":"","sources":["../../../src/lib/data/data-store.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useCallback, useEffect, useMemo, useReducer, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport {\n SourceRegistry,\n captureSample,\n inferSchema,\n resolveBinding,\n resolveCondition,\n tokensForSchema,\n} from '@elytracms/core/data-binding'\nimport type {\n BindingResolution,\n ConditionResolution,\n DataSource,\n InferredSchema,\n PayloadStore,\n RepeaterItemContext,\n} from '@elytracms/core/data-binding'\nimport type { BindingReference, Condition, JsonValue } from '@elytracms/core/project-graph'\nimport { getStudioOperations } from '../operations'\nimport type { OperationResult, OperationsClient } from '../operations'\nimport { useOperationCache, useOperationQuery } from '@elytracms/studio/lib/query'\nimport { createRequiredContext } from '@elytracms/studio/lib/required-context'\nimport { STUDIO_SYSTEM_COLLECTION_IDS } from '../operations/session-hydration'\nimport { resolveDeploymentCollections } from '../workspace'\nimport { hasContentSession } from './collection-content'\nimport { captureSourceSample, cmsSourceForCollection } from './sample-capture'\nimport { deleteDataSource, loadDataSources, saveDataSource } from './sources-store'\n\n/**\n * The project's live data layer (brief §4.6, §7.5, EC-167). Holds the source\n * registry the Builder's Content tab binds through, plus the captured payloads\n * that drive binding resolution. One uniform model across CMS queries, data\n * providers, and the built-in REST/Convex kinds — resolution, sampling,\n * inference and tokenization treat them all identically.\n *\n * There is no source-authoring UI (EC-167): sources exist because code declared\n * them (registered data providers), the schema implied them (per-collection CMS\n * queries), or an editor flow provisioned them (repeating sections, template\n * pages).\n *\n * Persistence: when mounted with a `projectId`, the store hydrates the\n * project's persisted source records (the `cms-data-sources` system collection,\n * see `sources-store.ts`) over the deterministic playground seeds — persisted\n * wins by id, but never over a source provisioned/removed in THIS session —\n * and every provision/remove writes through `@elytracms/core/operations`. Without a\n * `projectId` (tests, fixtures) the store is pure session state, exactly as\n * before.\n */\nexport interface DataStore {\n sources: DataSource[]\n registry: SourceRegistry\n payloads: PayloadStore\n knownSourceIds: ReadonlySet<string>\n\n getSource: (id: string) => DataSource | undefined\n removeSource: (id: string) => void\n /**\n * Create or replace a source with a known id + config and capture its sample\n * immediately (EC-166/EC-167): repeating sections and template pages\n * provision their per-scope CMS query / provider sources through this.\n */\n provisionSource: (source: DataSource) => void\n\n /**\n * The latest persistence failure in plain language, or `null`. Persistence\n * is best-effort on top of the live session (the canvas keeps working on\n * session state), but a failure is recorded here — visible, never silent.\n */\n persistError: string | null\n\n /** The stable path tokens a source exposes from its inferred schema (EC-085). */\n tokensOf: (id: string) => string[]\n schemaOf: (id: string) => InferredSchema | undefined\n sampleOf: (id: string) => JsonValue | undefined\n\n /** Resolve a binding to a renderer-ready resolution (value/props/condition/issue). */\n resolve: (ref: BindingReference, item?: RepeaterItemContext) => BindingResolution\n /** Resolve a binding to the concrete value the renderer injects (EC-086–089). */\n resolveValue: (ref: BindingReference, item?: RepeaterItemContext) => JsonValue | undefined\n /** Evaluate a condition against the captured payloads (EC-088). */\n resolveCondition: (condition: Condition, item?: RepeaterItemContext) => ConditionResolution\n}\n\nexport interface DataState {\n sources: DataSource[]\n /**\n * Ids provisioned or removed in THIS session. Hydration (which resolves\n * asynchronously) never overrides them — the editor's latest action wins\n * over whatever was persisted before it.\n */\n sessionIds: ReadonlySet<string>\n}\n\nexport type DataAction =\n | { type: 'remove'; id: string }\n | { type: 'provision'; source: DataSource }\n /** Merge the project's persisted source records in (persisted wins over seeds). */\n | { type: 'hydrate'; sources: DataSource[] }\n\nfunction upsert(sources: DataSource[], source: DataSource): DataSource[] {\n const exists = sources.some((s) => s.id === source.id)\n return exists ? sources.map((s) => (s.id === source.id ? source : s)) : [...sources, source]\n}\n\n/**\n * A persisted record hydrates as-is when it carries its captured sample;\n * otherwise recapture. Exception (EC-177 gap 1): with a hydrated content\n * session configured (Convex mode), CMS sources ALWAYS recapture by replaying\n * their stored query over the live documents — a sample captured by an earlier\n * session may carry stale (or fixture-derived) entries.\n */\nfunction withSample(source: DataSource): DataSource {\n if (source.kind === 'cms' && hasContentSession()) {\n const sample = captureSourceSample(source)\n return sample !== undefined ? captureSample(source, sample) : source\n }\n if (source.sample !== undefined) return source\n // No persisted sample: try an honest capture (a provider runs; anything the\n // studio can't fetch returns undefined) — never fabricate.\n const sample = captureSourceSample(source)\n return sample !== undefined ? captureSample(source, sample) : source\n}\n\n/**\n * The store's reducer, exported because hydration/session-precedence semantics\n * live here and the app's test harness has no DOM to drive effects through.\n */\nexport function dataStateReducer(state: DataState, action: DataAction): DataState {\n switch (action.type) {\n case 'remove':\n return {\n ...state,\n sources: state.sources.filter((s) => s.id !== action.id),\n sessionIds: new Set([...state.sessionIds, action.id]),\n }\n case 'provision': {\n // Upsert by id; attach a sample only if one can be captured honestly (a\n // provider run, or live CMS content) — otherwise the source carries none.\n const sample = captureSourceSample(action.source)\n const provisioned = sample !== undefined ? captureSample(action.source, sample) : action.source\n return {\n ...state,\n sources: upsert(state.sources, provisioned),\n sessionIds: new Set([...state.sessionIds, provisioned.id]),\n }\n }\n case 'hydrate': {\n let sources = state.sources\n for (const source of action.sources) {\n if (state.sessionIds.has(source.id)) continue // this session already decided\n sources = upsert(sources, withSample(source))\n }\n return sources === state.sources ? state : { ...state, sources }\n }\n default:\n return state\n }\n}\n\nconst { Context: DataContext, useRequired: useData } = createRequiredContext<DataStore>('Data')\n\n/**\n * The session's starting state: EMPTY. The studio seeds no sample sources (Oli,\n * 2026-06-19) — real sources arrive from the project's config collections (the\n * hydrate effect, Convex mode) or are added by the author. Nothing is faked.\n */\nexport function initialDataState(): DataState {\n return { sources: [], sessionIds: new Set() }\n}\n\nexport interface DataProviderProps {\n children: ReactNode\n /**\n * When set, the store hydrates from and persists to this project's\n * `cms-data-sources` system collection (through `@elytracms/core/operations`).\n * Without it the store is pure session state (tests, fixtures).\n */\n projectId?: string\n}\n\nexport function DataProvider({ children, projectId }: DataProviderProps) {\n const [state, dispatch] = useReducer(dataStateReducer, undefined, initialDataState)\n const [persistError, setPersistError] = useState<string | null>(null)\n\n // EC-192: surface every config-driven content collection as a pickable CMS\n // source, so the binding/condition pickers list what actually exists — the\n // same collection set the CMS uses (`resolveDeploymentCollections`) — rather\n // than only the demo fixture sources. Merged additively (the `hydrate` upsert\n // skips session-decided ids and recaptures live samples in Convex mode); studio\n // SYSTEM collections (routes/redirects/saved views/data sources) are excluded.\n useEffect(() => {\n if (projectId === undefined) return\n const collections = resolveDeploymentCollections().filter(\n (collection) => !STUDIO_SYSTEM_COLLECTION_IDS.has(collection.id),\n )\n if (collections.length === 0) return\n dispatch({ type: 'hydrate', sources: collections.map(cmsSourceForCollection) })\n }, [projectId])\n\n // Hydrate the project's persisted sources through the one operations-backed\n // query cache (EC-308/AD-17). Sources provisioned by other sessions on the\n // same project show up here; the playground seeds stay for everything not\n // persisted. The reducer's `hydrate` keeps session precedence — a source\n // provisioned/removed in THIS session always wins over the hydrated list.\n const cache = useOperationCache()\n const sourcesQuery = useOperationQuery<DataSource[]>({\n queryKey: ['dataSources', projectId ?? '∅'],\n loader: async (operations) => {\n const result = await loadDataSources(operations, projectId as string)\n if (!result.ok) throw new Error(result.error.message)\n return result.value\n },\n enabled: projectId !== undefined,\n })\n const hydratedSources = sourcesQuery.data\n useEffect(() => {\n if (hydratedSources) dispatch({ type: 'hydrate', sources: hydratedSources })\n }, [hydratedSources])\n const sourcesError = sourcesQuery.isError ? sourcesQuery.error : null\n useEffect(() => {\n if (sourcesError)\n setPersistError(sourcesError instanceof Error ? sourcesError.message : 'Loading data sources failed.')\n }, [sourcesError])\n\n // Best-effort persistence on top of the live session: the canvas keeps\n // working on session state; a failed write surfaces via `persistError`. On a\n // confirmed write, invalidate the hydration query so a later remount\n // re-hydrates the provisioned/removed source rather than a stale list.\n const persist = useCallback(\n (write: (operations: OperationsClient, projectId: string) => Promise<OperationResult<void>>) => {\n if (projectId === undefined) return\n void getStudioOperations()\n .then(({ operations }) => write(operations, projectId))\n .then((result) => {\n if (!result.ok) {\n setPersistError(result.error.message)\n return\n }\n void cache.invalidate(['dataSources', projectId])\n })\n .catch((error: unknown) => {\n setPersistError(error instanceof Error ? error.message : 'Saving the data source failed.')\n })\n },\n [projectId, cache],\n )\n\n const store = useMemo<DataStore>(() => {\n const registry = SourceRegistry.from(state.sources)\n const payloads: Record<string, JsonValue> = {}\n for (const source of state.sources) {\n if (source.sample !== undefined) payloads[source.id] = source.sample\n }\n const knownSourceIds = registry.knownSourceIds()\n const ctx = { payloads, registry }\n\n const getSource = (id: string) => registry.get(id)\n const resolve = (ref: BindingReference, item?: RepeaterItemContext) =>\n resolveBinding(ref, ctx, item)\n\n return {\n sources: state.sources,\n registry,\n payloads,\n knownSourceIds,\n getSource,\n removeSource: (id) => {\n dispatch({ type: 'remove', id })\n persist((operations, pid) => deleteDataSource(operations, pid, id))\n },\n provisionSource: (source) => {\n dispatch({ type: 'provision', source })\n // Persist exactly what the session resolves: the source plus any sample\n // that can be captured honestly (a provider run / live CMS content) —\n // never a fabricated one. Matches the `provision` reducer.\n const sample = captureSourceSample(source)\n const provisioned = sample !== undefined ? captureSample(source, sample) : source\n persist((operations, pid) => saveDataSource(operations, pid, provisioned))\n },\n persistError,\n tokensOf: (id) => {\n const schema = getSource(id)?.schema\n return schema ? tokensForSchema(schema) : []\n },\n schemaOf: (id) => {\n const source = getSource(id)\n if (source?.schema) return source.schema\n if (source?.sample !== undefined) return inferSchema(source.sample)\n return undefined\n },\n sampleOf: (id) => getSource(id)?.sample,\n resolve,\n resolveValue: (ref, item) => {\n const r = resolve(ref, item)\n switch (r.kind) {\n case 'value':\n return r.value\n case 'props':\n return r.props\n case 'condition':\n return r.pass\n case 'issue':\n return undefined\n default: {\n const never: never = r\n return never\n }\n }\n },\n resolveCondition: (condition, item) => resolveCondition(condition, ctx, item),\n }\n }, [state, persist, persistError])\n\n return <DataContext.Provider value={store}>{children}</DataContext.Provider>\n}\n\nexport { useData }\n"]}
@@ -1,143 +0,0 @@
1
- import { z } from 'zod';
2
- import type { ConvexSource, DataSource } from '@elytracms/core/data-binding';
3
- import type { JsonValue } from '@elytracms/core/project-graph';
4
- /**
5
- * Typed data providers (EC-167, vision AD-9). External data is a developer
6
- * concern expressed exactly like a component: a provider is a plain function
7
- * plus a manifest (id, title, description, output schema, optional params)
8
- * registered in code. Editors never see providers as anything technical — the
9
- * Content tab offers them next to CMS collections, labeled by their
10
- * plain-language titles, and provider results resolve through the unchanged
11
- * `@elytracms/core/data-binding` engine.
12
- *
13
- * Registration mirrors how component manifests register: project code defines
14
- * providers and registers them in-process here. In a host repository the same
15
- * definitions would be extracted into synced manifests (the EC-147 component
16
- * manifest sync path) with the function itself executed behind the
17
- * project-owned adapter — an honest gap today: this playground registry IS the
18
- * project code, so "sync" is a direct import.
19
- *
20
- * Bridging into the engine: a provider is addressed as a `convex`-kind data
21
- * source whose `functionRef` is `provider:<id>` — a provider is exactly a
22
- * typed server function, and the engine's source vocabulary already models
23
- * that. Resolution, sampling, inference, tokens, and broken-binding issues all
24
- * apply unchanged. (See NOTES: the engine could gain a first-class `provider`
25
- * source kind as a purely additive change.)
26
- */
27
- /** A scalar an editor can put into a provider param control. */
28
- export type ProviderParamValue = string | number | boolean;
29
- /** One choice of a `choice`-kind param. */
30
- export interface ProviderParamChoice {
31
- value: string;
32
- label: string;
33
- }
34
- /**
35
- * A provider param, surfaced to editors as one plain control (no syntax, no
36
- * JSON): `choice` renders a select over {@link choices}; the scalar kinds
37
- * render a matching input.
38
- */
39
- export interface ProviderParamSpec {
40
- name: string;
41
- /** Plain-language control label, e.g. "Department". */
42
- label: string;
43
- kind: 'text' | 'number' | 'boolean' | 'choice';
44
- /** For `choice` params: the closed set of offered values. */
45
- choices?: ProviderParamChoice[];
46
- defaultValue: ProviderParamValue;
47
- }
48
- /** Arguments a provider runs with (param name → value). */
49
- export type ProviderArgs = Record<string, JsonValue>;
50
- /** The manifest half of a provider — everything the builder surfaces. */
51
- export interface DataProviderManifest {
52
- /** Stable provider id, e.g. `pricing-plans`. */
53
- id: string;
54
- /** Plain-language title editors pick, e.g. "Pricing plans". */
55
- title: string;
56
- description: string;
57
- /** Zod schema of the payload; every run is validated against it. */
58
- output: z.ZodType<JsonValue>;
59
- params?: ProviderParamSpec[];
60
- }
61
- /** A data provider: a typed function plus its manifest. */
62
- export interface DataProvider {
63
- manifest: DataProviderManifest;
64
- /** Produce the payload. Deterministic here; a host repo may make this async behind its adapter. */
65
- fetch: (args: ProviderArgs) => JsonValue;
66
- }
67
- /**
68
- * Define a provider with the output type checked against the schema — the
69
- * provider-side mirror of `defineDataSourceAdapter` (EC-132) and component
70
- * `ComponentManifest` definitions.
71
- */
72
- export declare function defineDataProvider<T extends JsonValue>(provider: {
73
- manifest: Omit<DataProviderManifest, 'output'> & {
74
- output: z.ZodType<T>;
75
- };
76
- fetch: (args: ProviderArgs) => T;
77
- }): DataProvider;
78
- /** A structured registration issue — duplicates are reported, never thrown. */
79
- export interface ProviderRegistrationIssue {
80
- code: 'duplicate' | 'invalid-id';
81
- message: string;
82
- ref: string;
83
- }
84
- /**
85
- * Registry of data providers keyed by id. First registration wins; duplicates
86
- * and malformed ids are recorded as structured issues (component-registry
87
- * semantics).
88
- */
89
- export declare class DataProviderRegistry {
90
- private readonly byId;
91
- readonly issues: ProviderRegistrationIssue[];
92
- constructor(providers?: Iterable<DataProvider>);
93
- register(provider: DataProvider): void;
94
- get(id: string): DataProvider | undefined;
95
- list(): DataProvider[];
96
- get size(): number;
97
- }
98
- /** The outcome of one provider run: a validated payload or a plain-language issue. */
99
- export type ProviderRun = {
100
- ok: true;
101
- value: JsonValue;
102
- } | {
103
- ok: false;
104
- message: string;
105
- };
106
- /** Default args of a provider (its params' declared defaults). */
107
- export declare function defaultProviderArgs(manifest: DataProviderManifest): ProviderArgs;
108
- /**
109
- * Run a provider and validate the result against its output schema. A thrown
110
- * error or a schema mismatch comes back as a plain-language issue — the
111
- * binding layer renders a visible fallback, never a crash.
112
- */
113
- export declare function runProvider(provider: DataProvider, args?: ProviderArgs): ProviderRun;
114
- /** Shared project-wide provider sources: `provider.<providerId>`. */
115
- export declare const PROVIDER_SOURCE_PREFIX = "provider.";
116
- export declare function providerSourceIdFor(providerId: string): string;
117
- /** The provider a source is backed by, or undefined for non-provider sources. */
118
- export declare function providerIdOfSource(source: DataSource | undefined): string | undefined;
119
- /**
120
- * The engine-shaped source addressing a provider. `args` carry the editor's
121
- * param choices; `id` defaults to the shared project-wide source.
122
- */
123
- export declare function providerSourceFor(provider: DataProvider, args?: ProviderArgs, id?: string, label?: string): ConvexSource;
124
- /** Example provider: a static, code-owned pricing table (think Stripe prices). */
125
- export declare const pricingPlansProvider: DataProvider;
126
- /** Example provider with a param: job listings filterable by department. */
127
- export declare const jobListingsProvider: DataProvider;
128
- /**
129
- * The project's provider registry. In a deployed studio this hydrates from
130
- * synced provider manifests (the component-manifest sync path); in the
131
- * playground the project code registers directly.
132
- */
133
- export declare const projectDataProviders: DataProviderRegistry;
134
- export declare function listDataProviders(): DataProvider[];
135
- export declare function getDataProvider(id: string): DataProvider | undefined;
136
- /**
137
- * The payload a provider-backed source serves, or `null` when the provider is
138
- * unregistered or failing — a `null` sample makes every binding against it a
139
- * visible plain-language issue instead of a crash.
140
- */
141
- export declare function providerPayload(providerId: string, args?: ProviderArgs): JsonValue;
142
- /** A provider's canonical sample (its default-args run), or undefined when failing. */
143
- export declare function providerSample(provider: DataProvider): JsonValue | undefined;
@@ -1,255 +0,0 @@
1
- import { z } from 'zod';
2
- /**
3
- * Define a provider with the output type checked against the schema — the
4
- * provider-side mirror of `defineDataSourceAdapter` (EC-132) and component
5
- * `ComponentManifest` definitions.
6
- */
7
- export function defineDataProvider(provider) {
8
- return provider;
9
- }
10
- const PROVIDER_ID_PATTERN = /^[a-z][a-z0-9-]*$/;
11
- /**
12
- * Registry of data providers keyed by id. First registration wins; duplicates
13
- * and malformed ids are recorded as structured issues (component-registry
14
- * semantics).
15
- */
16
- export class DataProviderRegistry {
17
- byId = new Map();
18
- issues = [];
19
- constructor(providers = []) {
20
- for (const provider of providers)
21
- this.register(provider);
22
- }
23
- register(provider) {
24
- const id = provider.manifest.id;
25
- if (!PROVIDER_ID_PATTERN.test(id)) {
26
- this.issues.push({
27
- code: 'invalid-id',
28
- ref: id,
29
- message: `Provider id "${id}" must be lower-case and dash-separated (e.g. "pricing-plans").`,
30
- });
31
- return;
32
- }
33
- if (this.byId.has(id)) {
34
- this.issues.push({
35
- code: 'duplicate',
36
- ref: id,
37
- message: `Duplicate provider id "${id}" — keeping the first registration.`,
38
- });
39
- return;
40
- }
41
- this.byId.set(id, provider);
42
- }
43
- get(id) {
44
- return this.byId.get(id);
45
- }
46
- list() {
47
- return [...this.byId.values()];
48
- }
49
- get size() {
50
- return this.byId.size;
51
- }
52
- }
53
- /** Default args of a provider (its params' declared defaults). */
54
- export function defaultProviderArgs(manifest) {
55
- return Object.fromEntries((manifest.params ?? []).map((p) => [p.name, p.defaultValue]));
56
- }
57
- /**
58
- * Run a provider and validate the result against its output schema. A thrown
59
- * error or a schema mismatch comes back as a plain-language issue — the
60
- * binding layer renders a visible fallback, never a crash.
61
- */
62
- export function runProvider(provider, args) {
63
- const title = provider.manifest.title;
64
- let raw;
65
- try {
66
- raw = provider.fetch(args ?? defaultProviderArgs(provider.manifest));
67
- }
68
- catch {
69
- return {
70
- ok: false,
71
- message: `“${title}” couldn't load right now — the project code reported a problem. Anything showing it stays empty until it's fixed.`,
72
- };
73
- }
74
- const parsed = provider.manifest.output.safeParse(raw);
75
- if (!parsed.success) {
76
- return {
77
- ok: false,
78
- message: `“${title}” returned data in an unexpected shape, so it can't be shown. The project code and its declared output no longer agree.`,
79
- };
80
- }
81
- return { ok: true, value: parsed.data };
82
- }
83
- // ---------------------------------------------------------------------------
84
- // Bridging providers into the binding engine's source vocabulary
85
- // ---------------------------------------------------------------------------
86
- /** Shared project-wide provider sources: `provider.<providerId>`. */
87
- export const PROVIDER_SOURCE_PREFIX = 'provider.';
88
- /** The functionRef namespace marking a source as provider-backed. */
89
- const PROVIDER_FUNCTION_PREFIX = 'provider:';
90
- export function providerSourceIdFor(providerId) {
91
- return `${PROVIDER_SOURCE_PREFIX}${providerId}`;
92
- }
93
- /** The provider a source is backed by, or undefined for non-provider sources. */
94
- export function providerIdOfSource(source) {
95
- if (source === undefined || source.kind !== 'convex')
96
- return undefined;
97
- const ref = source.config.functionRef;
98
- return ref.startsWith(PROVIDER_FUNCTION_PREFIX)
99
- ? ref.slice(PROVIDER_FUNCTION_PREFIX.length)
100
- : undefined;
101
- }
102
- /**
103
- * The engine-shaped source addressing a provider. `args` carry the editor's
104
- * param choices; `id` defaults to the shared project-wide source.
105
- */
106
- export function providerSourceFor(provider, args, id, label) {
107
- return {
108
- kind: 'convex',
109
- id: id ?? providerSourceIdFor(provider.manifest.id),
110
- label: label ?? provider.manifest.title,
111
- config: {
112
- operation: 'query',
113
- functionRef: `${PROVIDER_FUNCTION_PREFIX}${provider.manifest.id}`,
114
- args: args ?? defaultProviderArgs(provider.manifest),
115
- },
116
- };
117
- }
118
- // ---------------------------------------------------------------------------
119
- // The project's registered providers (project-owned, code-first)
120
- // ---------------------------------------------------------------------------
121
- const pricingPlanSchema = z.object({
122
- id: z.string(),
123
- name: z.string(),
124
- monthlyPrice: z.number(),
125
- summary: z.string(),
126
- featured: z.boolean(),
127
- });
128
- /** Example provider: a static, code-owned pricing table (think Stripe prices). */
129
- export const pricingPlansProvider = defineDataProvider({
130
- manifest: {
131
- id: 'pricing-plans',
132
- title: 'Pricing plans',
133
- description: 'The pricing tiers exactly as the billing code defines them.',
134
- output: z.array(pricingPlanSchema),
135
- },
136
- fetch: () => [
137
- {
138
- id: 'starter',
139
- name: 'Starter',
140
- monthlyPrice: 19,
141
- summary: 'For solo builders shipping their first site.',
142
- featured: false,
143
- },
144
- {
145
- id: 'studio',
146
- name: 'Studio',
147
- monthlyPrice: 49,
148
- summary: 'For teams that publish every week.',
149
- featured: true,
150
- },
151
- {
152
- id: 'enterprise',
153
- name: 'Enterprise',
154
- monthlyPrice: 199,
155
- summary: 'For organizations with compliance needs.',
156
- featured: false,
157
- },
158
- ],
159
- });
160
- const jobListingSchema = z.object({
161
- id: z.string(),
162
- title: z.string(),
163
- department: z.string(),
164
- location: z.string(),
165
- remote: z.boolean(),
166
- });
167
- const JOB_LISTINGS = [
168
- {
169
- id: 'job-fe',
170
- title: 'Frontend Engineer',
171
- department: 'Engineering',
172
- location: 'Berlin',
173
- remote: true,
174
- },
175
- {
176
- id: 'job-be',
177
- title: 'Backend Engineer',
178
- department: 'Engineering',
179
- location: 'Amsterdam',
180
- remote: true,
181
- },
182
- {
183
- id: 'job-pd',
184
- title: 'Product Designer',
185
- department: 'Design',
186
- location: 'Berlin',
187
- remote: false,
188
- },
189
- {
190
- id: 'job-cm',
191
- title: 'Content Marketer',
192
- department: 'Marketing',
193
- location: 'Remote',
194
- remote: true,
195
- },
196
- ];
197
- /** Example provider with a param: job listings filterable by department. */
198
- export const jobListingsProvider = defineDataProvider({
199
- manifest: {
200
- id: 'job-listings',
201
- title: 'Job listings',
202
- description: 'Open roles from the hiring system, optionally narrowed to one department.',
203
- output: z.array(jobListingSchema),
204
- params: [
205
- {
206
- name: 'department',
207
- label: 'Department',
208
- kind: 'choice',
209
- choices: [
210
- { value: 'all', label: 'All departments' },
211
- { value: 'Engineering', label: 'Engineering' },
212
- { value: 'Design', label: 'Design' },
213
- { value: 'Marketing', label: 'Marketing' },
214
- ],
215
- defaultValue: 'all',
216
- },
217
- ],
218
- },
219
- fetch: ({ department }) => typeof department === 'string' && department !== 'all'
220
- ? JOB_LISTINGS.filter((job) => job.department === department)
221
- : [...JOB_LISTINGS],
222
- });
223
- /**
224
- * The project's provider registry. In a deployed studio this hydrates from
225
- * synced provider manifests (the component-manifest sync path); in the
226
- * playground the project code registers directly.
227
- */
228
- export const projectDataProviders = new DataProviderRegistry([
229
- pricingPlansProvider,
230
- jobListingsProvider,
231
- ]);
232
- export function listDataProviders() {
233
- return projectDataProviders.list();
234
- }
235
- export function getDataProvider(id) {
236
- return projectDataProviders.get(id);
237
- }
238
- /**
239
- * The payload a provider-backed source serves, or `null` when the provider is
240
- * unregistered or failing — a `null` sample makes every binding against it a
241
- * visible plain-language issue instead of a crash.
242
- */
243
- export function providerPayload(providerId, args) {
244
- const provider = getDataProvider(providerId);
245
- if (provider === undefined)
246
- return null;
247
- const run = runProvider(provider, args);
248
- return run.ok ? run.value : null;
249
- }
250
- /** A provider's canonical sample (its default-args run), or undefined when failing. */
251
- export function providerSample(provider) {
252
- const run = runProvider(provider);
253
- return run.ok ? run.value : undefined;
254
- }
255
- //# sourceMappingURL=providers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"providers.js","sourceRoot":"","sources":["../../../src/lib/data/providers.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod'\nimport type { ConvexSource, DataSource } from '@elytracms/core/data-binding'\nimport type { JsonValue } from '@elytracms/core/project-graph'\n\n/**\n * Typed data providers (EC-167, vision AD-9). External data is a developer\n * concern expressed exactly like a component: a provider is a plain function\n * plus a manifest (id, title, description, output schema, optional params)\n * registered in code. Editors never see providers as anything technical — the\n * Content tab offers them next to CMS collections, labeled by their\n * plain-language titles, and provider results resolve through the unchanged\n * `@elytracms/core/data-binding` engine.\n *\n * Registration mirrors how component manifests register: project code defines\n * providers and registers them in-process here. In a host repository the same\n * definitions would be extracted into synced manifests (the EC-147 component\n * manifest sync path) with the function itself executed behind the\n * project-owned adapter — an honest gap today: this playground registry IS the\n * project code, so \"sync\" is a direct import.\n *\n * Bridging into the engine: a provider is addressed as a `convex`-kind data\n * source whose `functionRef` is `provider:<id>` — a provider is exactly a\n * typed server function, and the engine's source vocabulary already models\n * that. Resolution, sampling, inference, tokens, and broken-binding issues all\n * apply unchanged. (See NOTES: the engine could gain a first-class `provider`\n * source kind as a purely additive change.)\n */\n\n/** A scalar an editor can put into a provider param control. */\nexport type ProviderParamValue = string | number | boolean\n\n/** One choice of a `choice`-kind param. */\nexport interface ProviderParamChoice {\n value: string\n label: string\n}\n\n/**\n * A provider param, surfaced to editors as one plain control (no syntax, no\n * JSON): `choice` renders a select over {@link choices}; the scalar kinds\n * render a matching input.\n */\nexport interface ProviderParamSpec {\n name: string\n /** Plain-language control label, e.g. \"Department\". */\n label: string\n kind: 'text' | 'number' | 'boolean' | 'choice'\n /** For `choice` params: the closed set of offered values. */\n choices?: ProviderParamChoice[]\n defaultValue: ProviderParamValue\n}\n\n/** Arguments a provider runs with (param name → value). */\nexport type ProviderArgs = Record<string, JsonValue>\n\n/** The manifest half of a provider — everything the builder surfaces. */\nexport interface DataProviderManifest {\n /** Stable provider id, e.g. `pricing-plans`. */\n id: string\n /** Plain-language title editors pick, e.g. \"Pricing plans\". */\n title: string\n description: string\n /** Zod schema of the payload; every run is validated against it. */\n output: z.ZodType<JsonValue>\n params?: ProviderParamSpec[]\n}\n\n/** A data provider: a typed function plus its manifest. */\nexport interface DataProvider {\n manifest: DataProviderManifest\n /** Produce the payload. Deterministic here; a host repo may make this async behind its adapter. */\n fetch: (args: ProviderArgs) => JsonValue\n}\n\n/**\n * Define a provider with the output type checked against the schema — the\n * provider-side mirror of `defineDataSourceAdapter` (EC-132) and component\n * `ComponentManifest` definitions.\n */\nexport function defineDataProvider<T extends JsonValue>(provider: {\n manifest: Omit<DataProviderManifest, 'output'> & { output: z.ZodType<T> }\n fetch: (args: ProviderArgs) => T\n}): DataProvider {\n return provider as DataProvider\n}\n\n// ---------------------------------------------------------------------------\n// Registration (mirrors the component-registry contract)\n// ---------------------------------------------------------------------------\n\n/** A structured registration issue — duplicates are reported, never thrown. */\nexport interface ProviderRegistrationIssue {\n code: 'duplicate' | 'invalid-id'\n message: string\n ref: string\n}\n\nconst PROVIDER_ID_PATTERN = /^[a-z][a-z0-9-]*$/\n\n/**\n * Registry of data providers keyed by id. First registration wins; duplicates\n * and malformed ids are recorded as structured issues (component-registry\n * semantics).\n */\nexport class DataProviderRegistry {\n private readonly byId = new Map<string, DataProvider>()\n readonly issues: ProviderRegistrationIssue[] = []\n\n constructor(providers: Iterable<DataProvider> = []) {\n for (const provider of providers) this.register(provider)\n }\n\n register(provider: DataProvider): void {\n const id = provider.manifest.id\n if (!PROVIDER_ID_PATTERN.test(id)) {\n this.issues.push({\n code: 'invalid-id',\n ref: id,\n message: `Provider id \"${id}\" must be lower-case and dash-separated (e.g. \"pricing-plans\").`,\n })\n return\n }\n if (this.byId.has(id)) {\n this.issues.push({\n code: 'duplicate',\n ref: id,\n message: `Duplicate provider id \"${id}\" — keeping the first registration.`,\n })\n return\n }\n this.byId.set(id, provider)\n }\n\n get(id: string): DataProvider | undefined {\n return this.byId.get(id)\n }\n\n list(): DataProvider[] {\n return [...this.byId.values()]\n }\n\n get size(): number {\n return this.byId.size\n }\n}\n\n// ---------------------------------------------------------------------------\n// Running a provider (never throws, never crashes a surface)\n// ---------------------------------------------------------------------------\n\n/** The outcome of one provider run: a validated payload or a plain-language issue. */\nexport type ProviderRun =\n | { ok: true; value: JsonValue }\n | { ok: false; message: string }\n\n/** Default args of a provider (its params' declared defaults). */\nexport function defaultProviderArgs(manifest: DataProviderManifest): ProviderArgs {\n return Object.fromEntries((manifest.params ?? []).map((p) => [p.name, p.defaultValue]))\n}\n\n/**\n * Run a provider and validate the result against its output schema. A thrown\n * error or a schema mismatch comes back as a plain-language issue — the\n * binding layer renders a visible fallback, never a crash.\n */\nexport function runProvider(provider: DataProvider, args?: ProviderArgs): ProviderRun {\n const title = provider.manifest.title\n let raw: JsonValue\n try {\n raw = provider.fetch(args ?? defaultProviderArgs(provider.manifest))\n } catch {\n return {\n ok: false,\n message: `“${title}” couldn't load right now — the project code reported a problem. Anything showing it stays empty until it's fixed.`,\n }\n }\n const parsed = provider.manifest.output.safeParse(raw)\n if (!parsed.success) {\n return {\n ok: false,\n message: `“${title}” returned data in an unexpected shape, so it can't be shown. The project code and its declared output no longer agree.`,\n }\n }\n return { ok: true, value: parsed.data }\n}\n\n// ---------------------------------------------------------------------------\n// Bridging providers into the binding engine's source vocabulary\n// ---------------------------------------------------------------------------\n\n/** Shared project-wide provider sources: `provider.<providerId>`. */\nexport const PROVIDER_SOURCE_PREFIX = 'provider.'\n\n/** The functionRef namespace marking a source as provider-backed. */\nconst PROVIDER_FUNCTION_PREFIX = 'provider:'\n\nexport function providerSourceIdFor(providerId: string): string {\n return `${PROVIDER_SOURCE_PREFIX}${providerId}`\n}\n\n/** The provider a source is backed by, or undefined for non-provider sources. */\nexport function providerIdOfSource(source: DataSource | undefined): string | undefined {\n if (source === undefined || source.kind !== 'convex') return undefined\n const ref = source.config.functionRef\n return ref.startsWith(PROVIDER_FUNCTION_PREFIX)\n ? ref.slice(PROVIDER_FUNCTION_PREFIX.length)\n : undefined\n}\n\n/**\n * The engine-shaped source addressing a provider. `args` carry the editor's\n * param choices; `id` defaults to the shared project-wide source.\n */\nexport function providerSourceFor(\n provider: DataProvider,\n args?: ProviderArgs,\n id?: string,\n label?: string,\n): ConvexSource {\n return {\n kind: 'convex',\n id: id ?? providerSourceIdFor(provider.manifest.id),\n label: label ?? provider.manifest.title,\n config: {\n operation: 'query',\n functionRef: `${PROVIDER_FUNCTION_PREFIX}${provider.manifest.id}`,\n args: args ?? defaultProviderArgs(provider.manifest),\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// The project's registered providers (project-owned, code-first)\n// ---------------------------------------------------------------------------\n\nconst pricingPlanSchema = z.object({\n id: z.string(),\n name: z.string(),\n monthlyPrice: z.number(),\n summary: z.string(),\n featured: z.boolean(),\n})\n\n/** Example provider: a static, code-owned pricing table (think Stripe prices). */\nexport const pricingPlansProvider = defineDataProvider({\n manifest: {\n id: 'pricing-plans',\n title: 'Pricing plans',\n description: 'The pricing tiers exactly as the billing code defines them.',\n output: z.array(pricingPlanSchema),\n },\n fetch: () => [\n {\n id: 'starter',\n name: 'Starter',\n monthlyPrice: 19,\n summary: 'For solo builders shipping their first site.',\n featured: false,\n },\n {\n id: 'studio',\n name: 'Studio',\n monthlyPrice: 49,\n summary: 'For teams that publish every week.',\n featured: true,\n },\n {\n id: 'enterprise',\n name: 'Enterprise',\n monthlyPrice: 199,\n summary: 'For organizations with compliance needs.',\n featured: false,\n },\n ],\n})\n\nconst jobListingSchema = z.object({\n id: z.string(),\n title: z.string(),\n department: z.string(),\n location: z.string(),\n remote: z.boolean(),\n})\n\nconst JOB_LISTINGS = [\n {\n id: 'job-fe',\n title: 'Frontend Engineer',\n department: 'Engineering',\n location: 'Berlin',\n remote: true,\n },\n {\n id: 'job-be',\n title: 'Backend Engineer',\n department: 'Engineering',\n location: 'Amsterdam',\n remote: true,\n },\n {\n id: 'job-pd',\n title: 'Product Designer',\n department: 'Design',\n location: 'Berlin',\n remote: false,\n },\n {\n id: 'job-cm',\n title: 'Content Marketer',\n department: 'Marketing',\n location: 'Remote',\n remote: true,\n },\n] as const\n\n/** Example provider with a param: job listings filterable by department. */\nexport const jobListingsProvider = defineDataProvider({\n manifest: {\n id: 'job-listings',\n title: 'Job listings',\n description: 'Open roles from the hiring system, optionally narrowed to one department.',\n output: z.array(jobListingSchema),\n params: [\n {\n name: 'department',\n label: 'Department',\n kind: 'choice',\n choices: [\n { value: 'all', label: 'All departments' },\n { value: 'Engineering', label: 'Engineering' },\n { value: 'Design', label: 'Design' },\n { value: 'Marketing', label: 'Marketing' },\n ],\n defaultValue: 'all',\n },\n ],\n },\n fetch: ({ department }) =>\n typeof department === 'string' && department !== 'all'\n ? JOB_LISTINGS.filter((job) => job.department === department)\n : [...JOB_LISTINGS],\n})\n\n/**\n * The project's provider registry. In a deployed studio this hydrates from\n * synced provider manifests (the component-manifest sync path); in the\n * playground the project code registers directly.\n */\nexport const projectDataProviders = new DataProviderRegistry([\n pricingPlansProvider,\n jobListingsProvider,\n])\n\nexport function listDataProviders(): DataProvider[] {\n return projectDataProviders.list()\n}\n\nexport function getDataProvider(id: string): DataProvider | undefined {\n return projectDataProviders.get(id)\n}\n\n/**\n * The payload a provider-backed source serves, or `null` when the provider is\n * unregistered or failing — a `null` sample makes every binding against it a\n * visible plain-language issue instead of a crash.\n */\nexport function providerPayload(providerId: string, args?: ProviderArgs): JsonValue {\n const provider = getDataProvider(providerId)\n if (provider === undefined) return null\n const run = runProvider(provider, args)\n return run.ok ? run.value : null\n}\n\n/** A provider's canonical sample (its default-args run), or undefined when failing. */\nexport function providerSample(provider: DataProvider): JsonValue | undefined {\n const run = runProvider(provider)\n return run.ok ? run.value : undefined\n}\n"]}
@@ -1,30 +0,0 @@
1
- import type { DataSource } from '@elytracms/core/data-binding';
2
- import type { JsonValue } from '@elytracms/core/project-graph';
3
- import type { CollectionDef } from '@elytracms/core/cms-core';
4
- /**
5
- * Data-source sample capture (EC-083/EC-166/EC-167). The hosted builder is
6
- * separate from the site it exports: actually performing a REST fetch / external
7
- * query happens behind the project-owned adapters in the deployed site, NOT here.
8
- * So the studio captures a sample ONLY when it can do so honestly — it never
9
- * fabricates data (Oli, 2026-06-19; cf. backend-mode's "never silently swap in
10
- * in-memory storage", and the v1 "static props, bindings parked" direction):
11
- *
12
- * - a provider-backed source runs its registered provider (real project code);
13
- * - a CMS source replays its stored query over the live content session (Convex
14
- * mode — EC-177 gap 1), so section/template previews show what delivery serves;
15
- * - anything else — an external source with no in-studio data path — returns
16
- * `undefined`. The source then carries no sample, and the binding UI shows an
17
- * honest "no sample yet" state instead of inventing rows that aren't there.
18
- */
19
- export declare function captureSourceSample(source: DataSource): JsonValue | undefined;
20
- /**
21
- * A live CMS data source for one config-driven collection (EC-192). The binding
22
- * and condition pickers enumerate `data.sources`; deriving one source per
23
- * configured content collection — the same set the CMS uses
24
- * (`resolveDeploymentCollections`) — means what an editor can bind matches what
25
- * actually exists. The sample is captured by replaying the collection's list
26
- * query through the canonical content engine, so when a content session is
27
- * configured (Convex mode) the inferred field tokens are the collection's real
28
- * fields; with no session the source is listed but carries no sample.
29
- */
30
- export declare function cmsSourceForCollection(collection: CollectionDef): DataSource;
@@ -1,70 +0,0 @@
1
- import { captureSample } from '@elytracms/core/data-binding';
2
- import { humanizeName } from '../utils.js';
3
- import { listQueryOfConfig } from '../bindings/section-bindings.js';
4
- import { getCollectionDocument, hasContentSession, playgroundCollection, runCollectionListQuery, } from './collection-content.js';
5
- import { providerIdOfSource, providerPayload } from './providers.js';
6
- /**
7
- * Data-source sample capture (EC-083/EC-166/EC-167). The hosted builder is
8
- * separate from the site it exports: actually performing a REST fetch / external
9
- * query happens behind the project-owned adapters in the deployed site, NOT here.
10
- * So the studio captures a sample ONLY when it can do so honestly — it never
11
- * fabricates data (Oli, 2026-06-19; cf. backend-mode's "never silently swap in
12
- * in-memory storage", and the v1 "static props, bindings parked" direction):
13
- *
14
- * - a provider-backed source runs its registered provider (real project code);
15
- * - a CMS source replays its stored query over the live content session (Convex
16
- * mode — EC-177 gap 1), so section/template previews show what delivery serves;
17
- * - anything else — an external source with no in-studio data path — returns
18
- * `undefined`. The source then carries no sample, and the binding UI shows an
19
- * honest "no sample yet" state instead of inventing rows that aren't there.
20
- */
21
- export function captureSourceSample(source) {
22
- const providerId = providerIdOfSource(source);
23
- if (providerId !== undefined) {
24
- return providerPayload(providerId, source.kind === 'convex' ? source.config.args : undefined);
25
- }
26
- if (source.kind === 'cms') {
27
- return cmsDeliverySample(source.config);
28
- }
29
- return undefined;
30
- }
31
- /**
32
- * A live CMS data source for one config-driven collection (EC-192). The binding
33
- * and condition pickers enumerate `data.sources`; deriving one source per
34
- * configured content collection — the same set the CMS uses
35
- * (`resolveDeploymentCollections`) — means what an editor can bind matches what
36
- * actually exists. The sample is captured by replaying the collection's list
37
- * query through the canonical content engine, so when a content session is
38
- * configured (Convex mode) the inferred field tokens are the collection's real
39
- * fields; with no session the source is listed but carries no sample.
40
- */
41
- export function cmsSourceForCollection(collection) {
42
- const source = {
43
- kind: 'cms',
44
- id: `cms.${collection.id}`,
45
- label: humanizeName(collection.id),
46
- config: { collectionId: collection.id, filter: {}, limit: 20 },
47
- };
48
- const sample = captureSourceSample(source);
49
- return sample !== undefined ? captureSample(source, sample) : source;
50
- }
51
- /**
52
- * Replay a CMS source's stored query over the configured content session, in
53
- * delivery shape (EC-166). Returns `undefined` when no session serves the
54
- * collection (playground / no backend) — the caller then leaves the source
55
- * sample-less rather than fabricating one. A query the engine rejects — or one
56
- * matching nothing — yields an empty list / `null`, never a crash.
57
- */
58
- function cmsDeliverySample(config) {
59
- if (!hasContentSession())
60
- return undefined;
61
- if (playgroundCollection(config.collectionId) === undefined)
62
- return undefined;
63
- if (config.documentId !== undefined) {
64
- const result = getCollectionDocument(config.collectionId, config.documentId);
65
- return result.document ?? null;
66
- }
67
- const result = runCollectionListQuery(config.collectionId, listQueryOfConfig(config));
68
- return result.ok ? result.documents : [];
69
- }
70
- //# sourceMappingURL=sample-capture.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sample-capture.js","sourceRoot":"","sources":["../../../src/lib/data/sample-capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAI5D,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAEhE,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAEjE;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAkB;IACpD,MAAM,UAAU,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAA;IAC7C,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,eAAe,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IAC/F,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QAC1B,OAAO,iBAAiB,CAAC,MAAM,CAAC,MAAwB,CAAC,CAAA;IAC3D,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB,CAAC,UAAyB;IAC9D,MAAM,MAAM,GAAe;QACzB,IAAI,EAAE,KAAK;QACX,EAAE,EAAE,OAAO,UAAU,CAAC,EAAE,EAAE;QAC1B,KAAK,EAAE,YAAY,CAAC,UAAU,CAAC,EAAE,CAAC;QAClC,MAAM,EAAE,EAAE,YAAY,EAAE,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;KAC/D,CAAA;IACD,MAAM,MAAM,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAA;IAC1C,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAA;AACtE,CAAC;AAED;;;;;;GAMG;AACH,SAAS,iBAAiB,CAAC,MAAsB;IAC/C,IAAI,CAAC,iBAAiB,EAAE;QAAE,OAAO,SAAS,CAAA;IAC1C,IAAI,oBAAoB,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IAC7E,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,qBAAqB,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,UAAU,CAAC,CAAA;QAC5E,OAAQ,MAAM,CAAC,QAAiC,IAAI,IAAI,CAAA;IAC1D,CAAC;IACD,MAAM,MAAM,GAAG,sBAAsB,CAAC,MAAM,CAAC,YAAY,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAA;IACrF,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAE,MAAM,CAAC,SAAkC,CAAC,CAAC,CAAC,EAAE,CAAA;AACpE,CAAC","sourcesContent":["import { captureSample } from '@elytracms/core/data-binding'\nimport type { DataSource } from '@elytracms/core/data-binding'\nimport type { JsonValue } from '@elytracms/core/project-graph'\nimport type { CollectionDef } from '@elytracms/core/cms-core'\nimport { humanizeName } from '../utils'\nimport { listQueryOfConfig } from '../bindings/section-bindings'\nimport type { QueryCmsConfig } from '../bindings/section-bindings'\nimport {\n getCollectionDocument,\n hasContentSession,\n playgroundCollection,\n runCollectionListQuery,\n} from './collection-content'\nimport { providerIdOfSource, providerPayload } from './providers'\n\n/**\n * Data-source sample capture (EC-083/EC-166/EC-167). The hosted builder is\n * separate from the site it exports: actually performing a REST fetch / external\n * query happens behind the project-owned adapters in the deployed site, NOT here.\n * So the studio captures a sample ONLY when it can do so honestly — it never\n * fabricates data (Oli, 2026-06-19; cf. backend-mode's \"never silently swap in\n * in-memory storage\", and the v1 \"static props, bindings parked\" direction):\n *\n * - a provider-backed source runs its registered provider (real project code);\n * - a CMS source replays its stored query over the live content session (Convex\n * mode — EC-177 gap 1), so section/template previews show what delivery serves;\n * - anything else — an external source with no in-studio data path — returns\n * `undefined`. The source then carries no sample, and the binding UI shows an\n * honest \"no sample yet\" state instead of inventing rows that aren't there.\n */\nexport function captureSourceSample(source: DataSource): JsonValue | undefined {\n const providerId = providerIdOfSource(source)\n if (providerId !== undefined) {\n return providerPayload(providerId, source.kind === 'convex' ? source.config.args : undefined)\n }\n if (source.kind === 'cms') {\n return cmsDeliverySample(source.config as QueryCmsConfig)\n }\n return undefined\n}\n\n/**\n * A live CMS data source for one config-driven collection (EC-192). The binding\n * and condition pickers enumerate `data.sources`; deriving one source per\n * configured content collection — the same set the CMS uses\n * (`resolveDeploymentCollections`) — means what an editor can bind matches what\n * actually exists. The sample is captured by replaying the collection's list\n * query through the canonical content engine, so when a content session is\n * configured (Convex mode) the inferred field tokens are the collection's real\n * fields; with no session the source is listed but carries no sample.\n */\nexport function cmsSourceForCollection(collection: CollectionDef): DataSource {\n const source: DataSource = {\n kind: 'cms',\n id: `cms.${collection.id}`,\n label: humanizeName(collection.id),\n config: { collectionId: collection.id, filter: {}, limit: 20 },\n }\n const sample = captureSourceSample(source)\n return sample !== undefined ? captureSample(source, sample) : source\n}\n\n/**\n * Replay a CMS source's stored query over the configured content session, in\n * delivery shape (EC-166). Returns `undefined` when no session serves the\n * collection (playground / no backend) — the caller then leaves the source\n * sample-less rather than fabricating one. A query the engine rejects — or one\n * matching nothing — yields an empty list / `null`, never a crash.\n */\nfunction cmsDeliverySample(config: QueryCmsConfig): JsonValue | undefined {\n if (!hasContentSession()) return undefined\n if (playgroundCollection(config.collectionId) === undefined) return undefined\n if (config.documentId !== undefined) {\n const result = getCollectionDocument(config.collectionId, config.documentId)\n return (result.document as unknown as JsonValue) ?? null\n }\n const result = runCollectionListQuery(config.collectionId, listQueryOfConfig(config))\n return result.ok ? (result.documents as unknown as JsonValue) : []\n}\n"]}
@@ -1,42 +0,0 @@
1
- import type { DataSource } from '@elytracms/core/data-binding';
2
- import type { CmsDocument, CollectionDef } from '@elytracms/core/cms-core';
3
- import type { OperationResult, OperationsClient } from '../operations/index.js';
4
- /**
5
- * Data-source persistence for the Builder's data layer (LIVE-mode gap fix).
6
- *
7
- * EC-166/EC-167 made the builder provision per-section (`cms.section.<nodeId>`)
8
- * and per-template (`cms.template.<pageId>`) CMS sources, but only as session
9
- * state — the live delivery chain (`convex/delivery.ts` →
10
- * `apps/example-site/lib/live-content.ts`) had nothing to carry. Following the
11
- * EC-170 routing-store / EC-169 views-store pattern, sources persist as
12
- * documents in ONE system collection, one document per source, and every
13
- * mutation goes through the *existing* `@elytracms/core/operations` commands
14
- * (`schema.upsertCollection`, `documents.upsert`, `documents.delete`) — no new
15
- * operations surface, no direct repository access.
16
- *
17
- * The record round-trips the FULL canonical `DataSource` shape (including the
18
- * captured `sample` + inferred `schema` envelope and the cms config's `sort`):
19
- * `@elytracms/core/data-binding`'s `dataSourceSchema` is the source of truth, applied
20
- * on both write and read, so a malformed stored record is dropped on load —
21
- * never a crash, never a half-parsed source.
22
- */
23
- export declare const DATA_SOURCES_COLLECTION = "cms-data-sources";
24
- /** System collection holding one document per persisted {@link DataSource}. */
25
- export declare const dataSourcesCollectionDef: CollectionDef;
26
- export declare function sourceToDocument(source: DataSource): CmsDocument;
27
- export declare function documentToSource(document: CmsDocument): DataSource | undefined;
28
- /** Load every persisted data source of a project (malformed records dropped). */
29
- export declare function loadDataSources(operations: OperationsClient, projectId: string): Promise<OperationResult<DataSource[]>>;
30
- /**
31
- * Make sure the system collection exists in the project's CMS schema so
32
- * `documents.upsert` accepts source documents. Idempotent.
33
- */
34
- export declare function ensureDataSourcesCollection(_operations: OperationsClient, _projectId: string): Promise<OperationResult<void>>;
35
- /** Create or update a persisted data source (operations command). */
36
- export declare function saveDataSource(operations: OperationsClient, projectId: string, source: DataSource): Promise<OperationResult<void>>;
37
- /**
38
- * Delete a persisted data source. A source that was never persisted (pure
39
- * session state, e.g. a seed) deletes as a no-op — `not-found` is success
40
- * here, since the goal state ("no persisted record") already holds.
41
- */
42
- export declare function deleteDataSource(operations: OperationsClient, projectId: string, sourceId: string): Promise<OperationResult<void>>;