@elytracms/studio 0.0.1

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 (558) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/convex/assets.ts +107 -0
  4. package/convex/auth.config.ts +15 -0
  5. package/convex/auth.ts +50 -0
  6. package/convex/cliTokens.ts +63 -0
  7. package/convex/cms.ts +174 -0
  8. package/convex/content.ts +316 -0
  9. package/convex/delivery.ts +266 -0
  10. package/convex/functions.ts +35 -0
  11. package/convex/graphs.ts +51 -0
  12. package/convex/guard.ts +67 -0
  13. package/convex/http.ts +30 -0
  14. package/convex/members.ts +83 -0
  15. package/convex/publishing.ts +102 -0
  16. package/convex/references.ts +168 -0
  17. package/convex/schema.ts +173 -0
  18. package/convex/sync.ts +322 -0
  19. package/convex/tsconfig.json +12 -0
  20. package/convex/users.ts +23 -0
  21. package/convex/webhooks.ts +85 -0
  22. package/dist/components/assets/asset-library.d.ts +14 -0
  23. package/dist/components/assets/asset-library.js +191 -0
  24. package/dist/components/assets/asset-library.js.map +1 -0
  25. package/dist/components/assets/asset-metadata.d.ts +34 -0
  26. package/dist/components/assets/asset-metadata.js +40 -0
  27. package/dist/components/assets/asset-metadata.js.map +1 -0
  28. package/dist/components/assets/asset-search.d.ts +7 -0
  29. package/dist/components/assets/asset-search.js +12 -0
  30. package/dist/components/assets/asset-search.js.map +1 -0
  31. package/dist/components/assets/asset-selection.d.ts +17 -0
  32. package/dist/components/assets/asset-selection.js +33 -0
  33. package/dist/components/assets/asset-selection.js.map +1 -0
  34. package/dist/components/assets/assets-store.d.ts +51 -0
  35. package/dist/components/assets/assets-store.js +153 -0
  36. package/dist/components/assets/assets-store.js.map +1 -0
  37. package/dist/components/auth-context.d.ts +38 -0
  38. package/dist/components/auth-context.js +88 -0
  39. package/dist/components/auth-context.js.map +1 -0
  40. package/dist/components/backend-gate.d.ts +19 -0
  41. package/dist/components/backend-gate.js +63 -0
  42. package/dist/components/backend-gate.js.map +1 -0
  43. package/dist/components/breadcrumb-context.d.ts +39 -0
  44. package/dist/components/breadcrumb-context.js +38 -0
  45. package/dist/components/breadcrumb-context.js.map +1 -0
  46. package/dist/components/builder/blocks-model.d.ts +80 -0
  47. package/dist/components/builder/blocks-model.js +181 -0
  48. package/dist/components/builder/blocks-model.js.map +1 -0
  49. package/dist/components/builder/blocks-panel.d.ts +44 -0
  50. package/dist/components/builder/blocks-panel.js +147 -0
  51. package/dist/components/builder/blocks-panel.js.map +1 -0
  52. package/dist/components/builder/builder-store.d.ts +69 -0
  53. package/dist/components/builder/builder-store.js +294 -0
  54. package/dist/components/builder/builder-store.js.map +1 -0
  55. package/dist/components/builder/canvas-stylesheet.d.ts +4 -0
  56. package/dist/components/builder/canvas-stylesheet.js +24 -0
  57. package/dist/components/builder/canvas-stylesheet.js.map +1 -0
  58. package/dist/components/builder/canvas.d.ts +8 -0
  59. package/dist/components/builder/canvas.js +723 -0
  60. package/dist/components/builder/canvas.js.map +1 -0
  61. package/dist/components/builder/clipboard-actions.d.ts +93 -0
  62. package/dist/components/builder/clipboard-actions.js +246 -0
  63. package/dist/components/builder/clipboard-actions.js.map +1 -0
  64. package/dist/components/builder/composition-field-editor.d.ts +11 -0
  65. package/dist/components/builder/composition-field-editor.js +150 -0
  66. package/dist/components/builder/composition-field-editor.js.map +1 -0
  67. package/dist/components/builder/composition-scope.d.ts +16 -0
  68. package/dist/components/builder/composition-scope.js +7 -0
  69. package/dist/components/builder/composition-scope.js.map +1 -0
  70. package/dist/components/builder/drag-session.d.ts +41 -0
  71. package/dist/components/builder/drag-session.js +51 -0
  72. package/dist/components/builder/drag-session.js.map +1 -0
  73. package/dist/components/builder/fixture-thumbnail.d.ts +18 -0
  74. package/dist/components/builder/fixture-thumbnail.js +97 -0
  75. package/dist/components/builder/fixture-thumbnail.js.map +1 -0
  76. package/dist/components/builder/inline-edit.d.ts +142 -0
  77. package/dist/components/builder/inline-edit.js +136 -0
  78. package/dist/components/builder/inline-edit.js.map +1 -0
  79. package/dist/components/builder/insert-context.d.ts +14 -0
  80. package/dist/components/builder/insert-context.js +65 -0
  81. package/dist/components/builder/insert-context.js.map +1 -0
  82. package/dist/components/builder/insert-menu.d.ts +9 -0
  83. package/dist/components/builder/insert-menu.js +9 -0
  84. package/dist/components/builder/insert-menu.js.map +1 -0
  85. package/dist/components/builder/layout-inspector.d.ts +14 -0
  86. package/dist/components/builder/layout-inspector.js +84 -0
  87. package/dist/components/builder/layout-inspector.js.map +1 -0
  88. package/dist/components/builder/node-factory.d.ts +17 -0
  89. package/dist/components/builder/node-factory.js +90 -0
  90. package/dist/components/builder/node-factory.js.map +1 -0
  91. package/dist/components/builder/page-tree.d.ts +3 -0
  92. package/dist/components/builder/page-tree.js +207 -0
  93. package/dist/components/builder/page-tree.js.map +1 -0
  94. package/dist/components/builder/property-inspector.d.ts +1 -0
  95. package/dist/components/builder/property-inspector.js +233 -0
  96. package/dist/components/builder/property-inspector.js.map +1 -0
  97. package/dist/components/builder/rich-text-toolbar.d.ts +4 -0
  98. package/dist/components/builder/rich-text-toolbar.js +104 -0
  99. package/dist/components/builder/rich-text-toolbar.js.map +1 -0
  100. package/dist/components/builder/spacing-handles.d.ts +22 -0
  101. package/dist/components/builder/spacing-handles.js +213 -0
  102. package/dist/components/builder/spacing-handles.js.map +1 -0
  103. package/dist/components/cms/asset-picker.d.ts +12 -0
  104. package/dist/components/cms/asset-picker.js +60 -0
  105. package/dist/components/cms/asset-picker.js.map +1 -0
  106. package/dist/components/cms/bulk-actions.d.ts +60 -0
  107. package/dist/components/cms/bulk-actions.js +95 -0
  108. package/dist/components/cms/bulk-actions.js.map +1 -0
  109. package/dist/components/cms/bulk-bar.d.ts +23 -0
  110. package/dist/components/cms/bulk-bar.js +26 -0
  111. package/dist/components/cms/bulk-bar.js.map +1 -0
  112. package/dist/components/cms/cell-edit.d.ts +91 -0
  113. package/dist/components/cms/cell-edit.js +144 -0
  114. package/dist/components/cms/cell-edit.js.map +1 -0
  115. package/dist/components/cms/cell.d.ts +29 -0
  116. package/dist/components/cms/cell.js +127 -0
  117. package/dist/components/cms/cell.js.map +1 -0
  118. package/dist/components/cms/cms-index.d.ts +8 -0
  119. package/dist/components/cms/cms-index.js +23 -0
  120. package/dist/components/cms/cms-index.js.map +1 -0
  121. package/dist/components/cms/cms-store.d.ts +188 -0
  122. package/dist/components/cms/cms-store.js +702 -0
  123. package/dist/components/cms/cms-store.js.map +1 -0
  124. package/dist/components/cms/collection-table.d.ts +6 -0
  125. package/dist/components/cms/collection-table.js +250 -0
  126. package/dist/components/cms/collection-table.js.map +1 -0
  127. package/dist/components/cms/collections-sidebar.d.ts +9 -0
  128. package/dist/components/cms/collections-sidebar.js +25 -0
  129. package/dist/components/cms/collections-sidebar.js.map +1 -0
  130. package/dist/components/cms/detail-editor.d.ts +7 -0
  131. package/dist/components/cms/detail-editor.js +386 -0
  132. package/dist/components/cms/detail-editor.js.map +1 -0
  133. package/dist/components/cms/doc-state.d.ts +13 -0
  134. package/dist/components/cms/doc-state.js +18 -0
  135. package/dist/components/cms/doc-state.js.map +1 -0
  136. package/dist/components/cms/document-editor-context.d.ts +48 -0
  137. package/dist/components/cms/document-editor-context.js +23 -0
  138. package/dist/components/cms/document-editor-context.js.map +1 -0
  139. package/dist/components/cms/editable-cell.d.ts +22 -0
  140. package/dist/components/cms/editable-cell.js +176 -0
  141. package/dist/components/cms/editable-cell.js.map +1 -0
  142. package/dist/components/cms/field-control.d.ts +8 -0
  143. package/dist/components/cms/field-control.js +149 -0
  144. package/dist/components/cms/field-control.js.map +1 -0
  145. package/dist/components/cms/filter-builder.d.ts +12 -0
  146. package/dist/components/cms/filter-builder.js +84 -0
  147. package/dist/components/cms/filter-builder.js.map +1 -0
  148. package/dist/components/cms/import-export.d.ts +6 -0
  149. package/dist/components/cms/import-export.js +33 -0
  150. package/dist/components/cms/import-export.js.map +1 -0
  151. package/dist/components/cms/new-page-dialog.d.ts +22 -0
  152. package/dist/components/cms/new-page-dialog.js +42 -0
  153. package/dist/components/cms/new-page-dialog.js.map +1 -0
  154. package/dist/components/cms/reference-confirm.d.ts +25 -0
  155. package/dist/components/cms/reference-confirm.js +124 -0
  156. package/dist/components/cms/reference-confirm.js.map +1 -0
  157. package/dist/components/cms/relation-picker.d.ts +16 -0
  158. package/dist/components/cms/relation-picker.js +47 -0
  159. package/dist/components/cms/relation-picker.js.map +1 -0
  160. package/dist/components/cms/use-cell-edit.d.ts +33 -0
  161. package/dist/components/cms/use-cell-edit.js +125 -0
  162. package/dist/components/cms/use-cell-edit.js.map +1 -0
  163. package/dist/components/cms/versions-model.d.ts +15 -0
  164. package/dist/components/cms/versions-model.js +23 -0
  165. package/dist/components/cms/versions-model.js.map +1 -0
  166. package/dist/components/cms/versions-pane.d.ts +14 -0
  167. package/dist/components/cms/versions-pane.js +86 -0
  168. package/dist/components/cms/versions-pane.js.map +1 -0
  169. package/dist/components/cms/view-bar.d.ts +11 -0
  170. package/dist/components/cms/view-bar.js +80 -0
  171. package/dist/components/cms/view-bar.js.map +1 -0
  172. package/dist/components/collab/collab-context.d.ts +34 -0
  173. package/dist/components/collab/collab-context.js +52 -0
  174. package/dist/components/collab/collab-context.js.map +1 -0
  175. package/dist/components/collab/collab-seed.d.ts +27 -0
  176. package/dist/components/collab/collab-seed.js +42 -0
  177. package/dist/components/collab/collab-seed.js.map +1 -0
  178. package/dist/components/components/component-detail.d.ts +9 -0
  179. package/dist/components/components/component-detail.js +30 -0
  180. package/dist/components/components/component-detail.js.map +1 -0
  181. package/dist/components/components/component-status.d.ts +10 -0
  182. package/dist/components/components/component-status.js +30 -0
  183. package/dist/components/components/component-status.js.map +1 -0
  184. package/dist/components/components/components-index.d.ts +8 -0
  185. package/dist/components/components/components-index.js +42 -0
  186. package/dist/components/components/components-index.js.map +1 -0
  187. package/dist/components/components/field-inspector.d.ts +9 -0
  188. package/dist/components/components/field-inspector.js +38 -0
  189. package/dist/components/components/field-inspector.js.map +1 -0
  190. package/dist/components/components/fixture-runner.d.ts +10 -0
  191. package/dist/components/components/fixture-runner.js +24 -0
  192. package/dist/components/components/fixture-runner.js.map +1 -0
  193. package/dist/components/components/registry-browser.d.ts +4 -0
  194. package/dist/components/components/registry-browser.js +64 -0
  195. package/dist/components/components/registry-browser.js.map +1 -0
  196. package/dist/components/current-user-menu.d.ts +13 -0
  197. package/dist/components/current-user-menu.js +31 -0
  198. package/dist/components/current-user-menu.js.map +1 -0
  199. package/dist/components/dev-login-badge.d.ts +9 -0
  200. package/dist/components/dev-login-badge.js +18 -0
  201. package/dist/components/dev-login-badge.js.map +1 -0
  202. package/dist/components/extensions/extensions-view.d.ts +7 -0
  203. package/dist/components/extensions/extensions-view.js +126 -0
  204. package/dist/components/extensions/extensions-view.js.map +1 -0
  205. package/dist/components/guards.d.ts +27 -0
  206. package/dist/components/guards.js +46 -0
  207. package/dist/components/guards.js.map +1 -0
  208. package/dist/components/inspector/inspector-sidebar.d.ts +26 -0
  209. package/dist/components/inspector/inspector-sidebar.js +17 -0
  210. package/dist/components/inspector/inspector-sidebar.js.map +1 -0
  211. package/dist/components/operation-error.d.ts +17 -0
  212. package/dist/components/operation-error.js +54 -0
  213. package/dist/components/operation-error.js.map +1 -0
  214. package/dist/components/playground-badge.d.ts +10 -0
  215. package/dist/components/playground-badge.js +19 -0
  216. package/dist/components/playground-badge.js.map +1 -0
  217. package/dist/components/project-list.d.ts +15 -0
  218. package/dist/components/project-list.js +52 -0
  219. package/dist/components/project-list.js.map +1 -0
  220. package/dist/components/project-session.d.ts +46 -0
  221. package/dist/components/project-session.js +107 -0
  222. package/dist/components/project-session.js.map +1 -0
  223. package/dist/components/project-switcher.d.ts +11 -0
  224. package/dist/components/project-switcher.js +44 -0
  225. package/dist/components/project-switcher.js.map +1 -0
  226. package/dist/components/references/builder-deep-link.d.ts +12 -0
  227. package/dist/components/references/builder-deep-link.js +53 -0
  228. package/dist/components/references/builder-deep-link.js.map +1 -0
  229. package/dist/components/references/references-panel.d.ts +17 -0
  230. package/dist/components/references/references-panel.js +66 -0
  231. package/dist/components/references/references-panel.js.map +1 -0
  232. package/dist/components/routes/redirect-chain.d.ts +9 -0
  233. package/dist/components/routes/redirect-chain.js +16 -0
  234. package/dist/components/routes/redirect-chain.js.map +1 -0
  235. package/dist/components/routes/redirect-manager.d.ts +13 -0
  236. package/dist/components/routes/redirect-manager.js +24 -0
  237. package/dist/components/routes/redirect-manager.js.map +1 -0
  238. package/dist/components/routes/route-list.d.ts +35 -0
  239. package/dist/components/routes/route-list.js +69 -0
  240. package/dist/components/routes/route-list.js.map +1 -0
  241. package/dist/components/routes/routes-shell.d.ts +14 -0
  242. package/dist/components/routes/routes-shell.js +68 -0
  243. package/dist/components/routes/routes-shell.js.map +1 -0
  244. package/dist/components/section-nav.d.ts +17 -0
  245. package/dist/components/section-nav.js +33 -0
  246. package/dist/components/section-nav.js.map +1 -0
  247. package/dist/components/section-state.d.ts +24 -0
  248. package/dist/components/section-state.js +78 -0
  249. package/dist/components/section-state.js.map +1 -0
  250. package/dist/components/section-surface.d.ts +31 -0
  251. package/dist/components/section-surface.js +46 -0
  252. package/dist/components/section-surface.js.map +1 -0
  253. package/dist/components/sections.d.ts +38 -0
  254. package/dist/components/sections.js +72 -0
  255. package/dist/components/sections.js.map +1 -0
  256. package/dist/components/settings-form.d.ts +10 -0
  257. package/dist/components/settings-form.js +17 -0
  258. package/dist/components/settings-form.js.map +1 -0
  259. package/dist/components/studio-context.d.ts +22 -0
  260. package/dist/components/studio-context.js +48 -0
  261. package/dist/components/studio-context.js.map +1 -0
  262. package/dist/components/studio-project-screen.d.ts +19 -0
  263. package/dist/components/studio-project-screen.js +195 -0
  264. package/dist/components/studio-project-screen.js.map +1 -0
  265. package/dist/components/studio-shell.d.ts +18 -0
  266. package/dist/components/studio-shell.js +64 -0
  267. package/dist/components/studio-shell.js.map +1 -0
  268. package/dist/components/theme-context.d.ts +17 -0
  269. package/dist/components/theme-context.js +26 -0
  270. package/dist/components/theme-context.js.map +1 -0
  271. package/dist/components/workspace-gate.d.ts +12 -0
  272. package/dist/components/workspace-gate.js +27 -0
  273. package/dist/components/workspace-gate.js.map +1 -0
  274. package/dist/components/workspace-projects.d.ts +13 -0
  275. package/dist/components/workspace-projects.js +18 -0
  276. package/dist/components/workspace-projects.js.map +1 -0
  277. package/dist/lib/assets/delete-asset.d.ts +34 -0
  278. package/dist/lib/assets/delete-asset.js +34 -0
  279. package/dist/lib/assets/delete-asset.js.map +1 -0
  280. package/dist/lib/assets/image-dimensions.d.ts +18 -0
  281. package/dist/lib/assets/image-dimensions.js +26 -0
  282. package/dist/lib/assets/image-dimensions.js.map +1 -0
  283. package/dist/lib/assets/index.d.ts +9 -0
  284. package/dist/lib/assets/index.js +10 -0
  285. package/dist/lib/assets/index.js.map +1 -0
  286. package/dist/lib/assets/upload-state.d.ts +53 -0
  287. package/dist/lib/assets/upload-state.js +59 -0
  288. package/dist/lib/assets/upload-state.js.map +1 -0
  289. package/dist/lib/assets/upload.d.ts +56 -0
  290. package/dist/lib/assets/upload.js +125 -0
  291. package/dist/lib/assets/upload.js.map +1 -0
  292. package/dist/lib/auth/auth-adapter.d.ts +57 -0
  293. package/dist/lib/auth/auth-adapter.js +13 -0
  294. package/dist/lib/auth/auth-adapter.js.map +1 -0
  295. package/dist/lib/auth/convex-auth-adapter.d.ts +39 -0
  296. package/dist/lib/auth/convex-auth-adapter.js +171 -0
  297. package/dist/lib/auth/convex-auth-adapter.js.map +1 -0
  298. package/dist/lib/auth/dev-auto-login-adapter.d.ts +25 -0
  299. package/dist/lib/auth/dev-auto-login-adapter.js +40 -0
  300. package/dist/lib/auth/dev-auto-login-adapter.js.map +1 -0
  301. package/dist/lib/auth/index.d.ts +28 -0
  302. package/dist/lib/auth/index.js +61 -0
  303. package/dist/lib/auth/index.js.map +1 -0
  304. package/dist/lib/auth/local-auth-adapter.d.ts +57 -0
  305. package/dist/lib/auth/local-auth-adapter.js +78 -0
  306. package/dist/lib/auth/local-auth-adapter.js.map +1 -0
  307. package/dist/lib/auth/route-guard.d.ts +33 -0
  308. package/dist/lib/auth/route-guard.js +51 -0
  309. package/dist/lib/auth/route-guard.js.map +1 -0
  310. package/dist/lib/auth-errors.d.ts +42 -0
  311. package/dist/lib/auth-errors.js +74 -0
  312. package/dist/lib/auth-errors.js.map +1 -0
  313. package/dist/lib/bindings/section-bindings.d.ts +24 -0
  314. package/dist/lib/bindings/section-bindings.js +9 -0
  315. package/dist/lib/bindings/section-bindings.js.map +1 -0
  316. package/dist/lib/clipboard/index.d.ts +7 -0
  317. package/dist/lib/clipboard/index.js +8 -0
  318. package/dist/lib/clipboard/index.js.map +1 -0
  319. package/dist/lib/clipboard/os-clipboard.d.ts +46 -0
  320. package/dist/lib/clipboard/os-clipboard.js +105 -0
  321. package/dist/lib/clipboard/os-clipboard.js.map +1 -0
  322. package/dist/lib/clipboard/paste-issues.d.ts +34 -0
  323. package/dist/lib/clipboard/paste-issues.js +67 -0
  324. package/dist/lib/clipboard/paste-issues.js.map +1 -0
  325. package/dist/lib/clipboard/paste-target.d.ts +20 -0
  326. package/dist/lib/clipboard/paste-target.js +28 -0
  327. package/dist/lib/clipboard/paste-target.js.map +1 -0
  328. package/dist/lib/cms/published-documents.d.ts +30 -0
  329. package/dist/lib/cms/published-documents.js +75 -0
  330. package/dist/lib/cms/published-documents.js.map +1 -0
  331. package/dist/lib/cms-views/index.d.ts +9 -0
  332. package/dist/lib/cms-views/index.js +10 -0
  333. package/dist/lib/cms-views/index.js.map +1 -0
  334. package/dist/lib/cms-views/selection.d.ts +29 -0
  335. package/dist/lib/cms-views/selection.js +46 -0
  336. package/dist/lib/cms-views/selection.js.map +1 -0
  337. package/dist/lib/cms-views/view-model.d.ts +192 -0
  338. package/dist/lib/cms-views/view-model.js +353 -0
  339. package/dist/lib/cms-views/view-model.js.map +1 -0
  340. package/dist/lib/cms-views/views-store.d.ts +70 -0
  341. package/dist/lib/cms-views/views-store.js +129 -0
  342. package/dist/lib/cms-views/views-store.js.map +1 -0
  343. package/dist/lib/data/collection-content.d.ts +105 -0
  344. package/dist/lib/data/collection-content.js +196 -0
  345. package/dist/lib/data/collection-content.js.map +1 -0
  346. package/dist/lib/data/data-store.d.ts +97 -0
  347. package/dist/lib/data/data-store.js +205 -0
  348. package/dist/lib/data/data-store.js.map +1 -0
  349. package/dist/lib/data/index.d.ts +4 -0
  350. package/dist/lib/data/index.js +8 -0
  351. package/dist/lib/data/index.js.map +1 -0
  352. package/dist/lib/data/providers.d.ts +143 -0
  353. package/dist/lib/data/providers.js +255 -0
  354. package/dist/lib/data/providers.js.map +1 -0
  355. package/dist/lib/data/sample-capture.d.ts +30 -0
  356. package/dist/lib/data/sample-capture.js +70 -0
  357. package/dist/lib/data/sample-capture.js.map +1 -0
  358. package/dist/lib/data/sources-store.d.ts +42 -0
  359. package/dist/lib/data/sources-store.js +120 -0
  360. package/dist/lib/data/sources-store.js.map +1 -0
  361. package/dist/lib/dnd/drop-rules.d.ts +219 -0
  362. package/dist/lib/dnd/drop-rules.js +257 -0
  363. package/dist/lib/dnd/drop-rules.js.map +1 -0
  364. package/dist/lib/dnd/gap-drag.d.ts +66 -0
  365. package/dist/lib/dnd/gap-drag.js +95 -0
  366. package/dist/lib/dnd/gap-drag.js.map +1 -0
  367. package/dist/lib/locale/binding-fallback.d.ts +28 -0
  368. package/dist/lib/locale/binding-fallback.js +66 -0
  369. package/dist/lib/locale/binding-fallback.js.map +1 -0
  370. package/dist/lib/locale/fallback.d.ts +43 -0
  371. package/dist/lib/locale/fallback.js +52 -0
  372. package/dist/lib/locale/fallback.js.map +1 -0
  373. package/dist/lib/locale/index.d.ts +6 -0
  374. package/dist/lib/locale/index.js +7 -0
  375. package/dist/lib/locale/index.js.map +1 -0
  376. package/dist/lib/locale/locale-store.d.ts +40 -0
  377. package/dist/lib/locale/locale-store.js +61 -0
  378. package/dist/lib/locale/locale-store.js.map +1 -0
  379. package/dist/lib/locale/locale-switcher.d.ts +10 -0
  380. package/dist/lib/locale/locale-switcher.js +24 -0
  381. package/dist/lib/locale/locale-switcher.js.map +1 -0
  382. package/dist/lib/locale/route-variant.d.ts +14 -0
  383. package/dist/lib/locale/route-variant.js +11 -0
  384. package/dist/lib/locale/route-variant.js.map +1 -0
  385. package/dist/lib/locale/use-studio-locale.d.ts +10 -0
  386. package/dist/lib/locale/use-studio-locale.js +8 -0
  387. package/dist/lib/locale/use-studio-locale.js.map +1 -0
  388. package/dist/lib/operations/asset-repository.d.ts +15 -0
  389. package/dist/lib/operations/asset-repository.js +56 -0
  390. package/dist/lib/operations/asset-repository.js.map +1 -0
  391. package/dist/lib/operations/cms-persistence.d.ts +35 -0
  392. package/dist/lib/operations/cms-persistence.js +75 -0
  393. package/dist/lib/operations/cms-persistence.js.map +1 -0
  394. package/dist/lib/operations/graph-commands.d.ts +140 -0
  395. package/dist/lib/operations/graph-commands.js +86 -0
  396. package/dist/lib/operations/graph-commands.js.map +1 -0
  397. package/dist/lib/operations/graph-persistence.d.ts +27 -0
  398. package/dist/lib/operations/graph-persistence.js +35 -0
  399. package/dist/lib/operations/graph-persistence.js.map +1 -0
  400. package/dist/lib/operations/index.d.ts +13 -0
  401. package/dist/lib/operations/index.js +14 -0
  402. package/dist/lib/operations/index.js.map +1 -0
  403. package/dist/lib/operations/operations-package.d.ts +6 -0
  404. package/dist/lib/operations/operations-package.js +7 -0
  405. package/dist/lib/operations/operations-package.js.map +1 -0
  406. package/dist/lib/operations/persist-queue.d.ts +16 -0
  407. package/dist/lib/operations/persist-queue.js +18 -0
  408. package/dist/lib/operations/persist-queue.js.map +1 -0
  409. package/dist/lib/operations/session-hydration.d.ts +84 -0
  410. package/dist/lib/operations/session-hydration.js +112 -0
  411. package/dist/lib/operations/session-hydration.js.map +1 -0
  412. package/dist/lib/operations/studio-operations.d.ts +59 -0
  413. package/dist/lib/operations/studio-operations.js +92 -0
  414. package/dist/lib/operations/studio-operations.js.map +1 -0
  415. package/dist/lib/persistence/backend-mode.d.ts +69 -0
  416. package/dist/lib/persistence/backend-mode.js +120 -0
  417. package/dist/lib/persistence/backend-mode.js.map +1 -0
  418. package/dist/lib/persistence/convex-adapter.d.ts +34 -0
  419. package/dist/lib/persistence/convex-adapter.js +681 -0
  420. package/dist/lib/persistence/convex-adapter.js.map +1 -0
  421. package/dist/lib/persistence/convex-blob-storage.d.ts +57 -0
  422. package/dist/lib/persistence/convex-blob-storage.js +97 -0
  423. package/dist/lib/persistence/convex-blob-storage.js.map +1 -0
  424. package/dist/lib/persistence/convex-client.d.ts +19 -0
  425. package/dist/lib/persistence/convex-client.js +40 -0
  426. package/dist/lib/persistence/convex-client.js.map +1 -0
  427. package/dist/lib/persistence/index.d.ts +30 -0
  428. package/dist/lib/persistence/index.js +60 -0
  429. package/dist/lib/persistence/index.js.map +1 -0
  430. package/dist/lib/persona/labels.d.ts +23 -0
  431. package/dist/lib/persona/labels.js +122 -0
  432. package/dist/lib/persona/labels.js.map +1 -0
  433. package/dist/lib/rail.d.ts +11 -0
  434. package/dist/lib/rail.js +26 -0
  435. package/dist/lib/rail.js.map +1 -0
  436. package/dist/lib/references/impact.d.ts +64 -0
  437. package/dist/lib/references/impact.js +62 -0
  438. package/dist/lib/references/impact.js.map +1 -0
  439. package/dist/lib/references/index.d.ts +7 -0
  440. package/dist/lib/references/index.js +8 -0
  441. package/dist/lib/references/index.js.map +1 -0
  442. package/dist/lib/references/reference-model.d.ts +125 -0
  443. package/dist/lib/references/reference-model.js +242 -0
  444. package/dist/lib/references/reference-model.js.map +1 -0
  445. package/dist/lib/references/references-store.d.ts +65 -0
  446. package/dist/lib/references/references-store.js +221 -0
  447. package/dist/lib/references/references-store.js.map +1 -0
  448. package/dist/lib/registry/index.d.ts +65 -0
  449. package/dist/lib/registry/index.js +114 -0
  450. package/dist/lib/registry/index.js.map +1 -0
  451. package/dist/lib/registry/preview.d.ts +15 -0
  452. package/dist/lib/registry/preview.js +110 -0
  453. package/dist/lib/registry/preview.js.map +1 -0
  454. package/dist/lib/registry/project-components.d.ts +16 -0
  455. package/dist/lib/registry/project-components.js +152 -0
  456. package/dist/lib/registry/project-components.js.map +1 -0
  457. package/dist/lib/routing/index.d.ts +10 -0
  458. package/dist/lib/routing/index.js +11 -0
  459. package/dist/lib/routing/index.js.map +1 -0
  460. package/dist/lib/routing/routing-analysis.d.ts +26 -0
  461. package/dist/lib/routing/routing-analysis.js +37 -0
  462. package/dist/lib/routing/routing-analysis.js.map +1 -0
  463. package/dist/lib/routing/routing-store.d.ts +50 -0
  464. package/dist/lib/routing/routing-store.js +72 -0
  465. package/dist/lib/routing/routing-store.js.map +1 -0
  466. package/dist/lib/starters/kit-session.d.ts +5 -0
  467. package/dist/lib/starters/kit-session.js +17 -0
  468. package/dist/lib/starters/kit-session.js.map +1 -0
  469. package/dist/lib/theme.d.ts +21 -0
  470. package/dist/lib/theme.js +32 -0
  471. package/dist/lib/theme.js.map +1 -0
  472. package/dist/lib/utils.d.ts +11 -0
  473. package/dist/lib/utils.js +28 -0
  474. package/dist/lib/utils.js.map +1 -0
  475. package/dist/lib/webhooks/config.d.ts +15 -0
  476. package/dist/lib/webhooks/config.js +64 -0
  477. package/dist/lib/webhooks/config.js.map +1 -0
  478. package/dist/lib/webhooks/dispatcher.d.ts +67 -0
  479. package/dist/lib/webhooks/dispatcher.js +61 -0
  480. package/dist/lib/webhooks/dispatcher.js.map +1 -0
  481. package/dist/lib/webhooks/index.d.ts +11 -0
  482. package/dist/lib/webhooks/index.js +10 -0
  483. package/dist/lib/webhooks/index.js.map +1 -0
  484. package/dist/lib/webhooks/signing.d.ts +15 -0
  485. package/dist/lib/webhooks/signing.js +24 -0
  486. package/dist/lib/webhooks/signing.js.map +1 -0
  487. package/dist/lib/webhooks/tags.d.ts +25 -0
  488. package/dist/lib/webhooks/tags.js +173 -0
  489. package/dist/lib/webhooks/tags.js.map +1 -0
  490. package/dist/lib/working-graph.d.ts +82 -0
  491. package/dist/lib/working-graph.js +113 -0
  492. package/dist/lib/working-graph.js.map +1 -0
  493. package/dist/lib/workspace/index.d.ts +109 -0
  494. package/dist/lib/workspace/index.js +206 -0
  495. package/dist/lib/workspace/index.js.map +1 -0
  496. package/dist/lib/workspace/switcher-source.d.ts +39 -0
  497. package/dist/lib/workspace/switcher-source.js +23 -0
  498. package/dist/lib/workspace/switcher-source.js.map +1 -0
  499. package/dist/lib/workspace/workspace-source.d.ts +47 -0
  500. package/dist/lib/workspace/workspace-source.js +67 -0
  501. package/dist/lib/workspace/workspace-source.js.map +1 -0
  502. package/dist/router/index.d.ts +32 -0
  503. package/dist/router/index.js +32 -0
  504. package/dist/router/index.js.map +1 -0
  505. package/dist/router/match.d.ts +75 -0
  506. package/dist/router/match.js +87 -0
  507. package/dist/router/match.js.map +1 -0
  508. package/dist/router/search.d.ts +22 -0
  509. package/dist/router/search.js +16 -0
  510. package/dist/router/search.js.map +1 -0
  511. package/dist/ui/avatar.d.ts +17 -0
  512. package/dist/ui/avatar.js +38 -0
  513. package/dist/ui/avatar.js.map +1 -0
  514. package/dist/ui/badge.d.ts +9 -0
  515. package/dist/ui/badge.js +23 -0
  516. package/dist/ui/badge.js.map +1 -0
  517. package/dist/ui/button.d.ts +11 -0
  518. package/dist/ui/button.js +30 -0
  519. package/dist/ui/button.js.map +1 -0
  520. package/dist/ui/card.d.ts +11 -0
  521. package/dist/ui/card.js +23 -0
  522. package/dist/ui/card.js.map +1 -0
  523. package/dist/ui/dialog.d.ts +12 -0
  524. package/dist/ui/dialog.js +27 -0
  525. package/dist/ui/dialog.js.map +1 -0
  526. package/dist/ui/dropdown-menu.d.ts +15 -0
  527. package/dist/ui/dropdown-menu.js +24 -0
  528. package/dist/ui/dropdown-menu.js.map +1 -0
  529. package/dist/ui/field.d.ts +15 -0
  530. package/dist/ui/field.js +14 -0
  531. package/dist/ui/field.js.map +1 -0
  532. package/dist/ui/index.d.ts +14 -0
  533. package/dist/ui/index.js +15 -0
  534. package/dist/ui/index.js.map +1 -0
  535. package/dist/ui/input.d.ts +3 -0
  536. package/dist/ui/input.js +7 -0
  537. package/dist/ui/input.js.map +1 -0
  538. package/dist/ui/inspector.d.ts +18 -0
  539. package/dist/ui/inspector.js +14 -0
  540. package/dist/ui/inspector.js.map +1 -0
  541. package/dist/ui/layout.d.ts +45 -0
  542. package/dist/ui/layout.js +48 -0
  543. package/dist/ui/layout.js.map +1 -0
  544. package/dist/ui/panel.d.ts +12 -0
  545. package/dist/ui/panel.js +20 -0
  546. package/dist/ui/panel.js.map +1 -0
  547. package/dist/ui/separator.d.ts +6 -0
  548. package/dist/ui/separator.js +7 -0
  549. package/dist/ui/separator.js.map +1 -0
  550. package/dist/ui/toolbar.d.ts +9 -0
  551. package/dist/ui/toolbar.js +16 -0
  552. package/dist/ui/toolbar.js.map +1 -0
  553. package/dist/ui/typography.d.ts +50 -0
  554. package/dist/ui/typography.js +43 -0
  555. package/dist/ui/typography.js.map +1 -0
  556. package/package.json +149 -0
  557. package/src/styles/studio.css +101 -0
  558. package/src/styles/tokens.css +63 -0
@@ -0,0 +1,316 @@
1
+ import { documentKey, documentSchema } from '@elytracms/cms-core'
2
+ import type {
3
+ CmsDocument,
4
+ CmsValidationIssue,
5
+ CollectionDef,
6
+ Locale,
7
+ LocaleConfig,
8
+ RedirectRecord,
9
+ RouteRecord,
10
+ } from '@elytracms/cms-core'
11
+ import { createContentClient, createContentContext, isDocumentHistory, rawDocument } from '@elytracms/content'
12
+ import type {
13
+ ContentClient,
14
+ ContentContext,
15
+ ContentDocumentSource,
16
+ ContentLookup,
17
+ Perspective,
18
+ } from '@elytracms/content'
19
+ import type { AssetRecord } from '@elytracms/persistence'
20
+ import { parseProjectGraph } from '@elytracms/project-graph'
21
+ import type { ProjectGraph } from '@elytracms/project-graph'
22
+ import type { QueryCtx } from './functions'
23
+
24
+ /**
25
+ * EC-145 — the Convex-side content kit (vision AD-3/AD-4).
26
+ *
27
+ * Custom Convex functions are the query escape hatch ("our query language is
28
+ * TypeScript") — but only if developers never touch raw tables. `createContent`
29
+ * gives a Convex query function the same delivery surface as the Next-side
30
+ * accessors: `get`, `list`, `resolvePage`, plus the `raw` escape hatch, all
31
+ * with ambient `{ locale, perspective }` context.
32
+ *
33
+ * Byte-equivalence with the Next side is guaranteed by construction: the kit
34
+ * loads rows through `ctx.db`, builds the same synchronous `ContentLookup`
35
+ * that `@elytracms/next`'s snapshot builds from a `PersistenceAdapter`, and then
36
+ * runs the EXACT pure functions from `@elytracms/content`
37
+ * (`createContentClient` → `resolveDocument`, `query.ts` validation, cache
38
+ * tags). Nothing about resolution semantics is reimplemented here.
39
+ *
40
+ * Loading strategy (honest about v1 scale): the project's schema, documents,
41
+ * and asset metadata are prefetched ONCE per `createContent` call via the
42
+ * indexed `by_project` / `by_project_asset` scans, then every kit call is
43
+ * synchronous over memory — exactly like `createContentSnapshot` on the Next
44
+ * side. Filters and sorts therefore execute in-function over an indexed
45
+ * by-project fetch; see `contentIndexes.ts` for the index requirements this
46
+ * implies and the documented field-level-index upgrade path.
47
+ *
48
+ * Perspective isolation: the lookup holds the raw stored rows (draft state and
49
+ * all), and EVERY read path through `@elytracms/content` — `resolveDocument`,
50
+ * relation population, `listDocuments` filtering, slug fallback, and the `raw`
51
+ * escape hatch — applies the EC-142 perspective gate (`selectPerspective`)
52
+ * before any value is exposed. The kit never reads field values around that
53
+ * gate, so a `published` kit cannot observe draft values. (Pre-filtering draft
54
+ * rows out of the lookup would be redundant *and* would change structured
55
+ * issue messages — e.g. `unknown-relation-target` reasons — breaking
56
+ * byte-equivalence with the Next-side accessors.)
57
+ */
58
+
59
+ const DEFAULT_LOCALES: LocaleConfig = { default: 'en', locales: ['en'] }
60
+
61
+ /**
62
+ * Structured load-time problems (stored blobs that fail their canonical Zod
63
+ * schema, unparsable graph revisions). Never thrown — the kit degrades to the
64
+ * valid subset and reports what it skipped, mirroring the package-wide
65
+ * "structured issues, never crashes" stance.
66
+ *
67
+ * `invalid-stored-schema` is retained for wire/back-compat but is no longer
68
+ * produced: CMS collections are config-owned (EC-183, AD-11) and supplied by the
69
+ * caller (already validated), so there is no stored schema blob to reject.
70
+ */
71
+ export type ContentKitIssueCode =
72
+ | 'invalid-stored-schema'
73
+ | 'invalid-stored-document'
74
+ | 'invalid-stored-graph'
75
+
76
+ export interface ContentKitIssue {
77
+ code: ContentKitIssueCode
78
+ message: string
79
+ meta?: Record<string, unknown>
80
+ }
81
+
82
+ export interface CreateContentOptions {
83
+ projectId: string
84
+ /** Draft or published perspective (EC-021); ambient for every kit call. */
85
+ perspective: Perspective
86
+ /** Requested locale; defaults to the project's default locale. */
87
+ locale?: Locale
88
+ /** Override the locale config derived from the project settings. */
89
+ locales?: LocaleConfig
90
+ /**
91
+ * CMS collections (EC-183, AD-11), sourced from `elytra.config.ts` by the
92
+ * caller — the backend no longer stores a schema. Defaults to none (the kit
93
+ * then resolves documents with no collection structure).
94
+ */
95
+ collections?: readonly CollectionDef[]
96
+ /** Route records served by `resolvePage` (EC-019). */
97
+ routes?: readonly RouteRecord[]
98
+ /** Redirect records served by `resolvePage` (EC-019/020). */
99
+ redirects?: readonly RedirectRecord[]
100
+ }
101
+
102
+ export interface ContentKit {
103
+ /** The ambient `{ locale, perspective }` context every call resolves under. */
104
+ readonly context: ContentContext
105
+ /** Structured load-time issues (invalid stored blobs); never thrown. */
106
+ readonly loadIssues: readonly ContentKitIssue[]
107
+ /** Structural route issues from router construction (conflicts, loops). */
108
+ readonly routerIssues: readonly CmsValidationIssue[]
109
+ /** Delivery-shaped single-document accessor — same semantics as Next-side `getDocument`. */
110
+ readonly get: ContentClient['getDocument']
111
+ /** Delivery-shaped list accessor — same filter vocabulary as EC-143. */
112
+ readonly list: ContentClient['listDocuments']
113
+ /** Route → page/document resolution (EC-019), when routes were provided. */
114
+ readonly resolvePage: ContentClient['resolvePage']
115
+ /**
116
+ * Escape hatch (EC-142 `rawDocument`): the stored row, untouched — no locale
117
+ * fallback, no population, no asset resolution. The perspective gate still
118
+ * applies: a `published` kit never sees draft rows, even raw.
119
+ */
120
+ raw(collection: string, id: string): CmsDocument | null
121
+ }
122
+
123
+ /**
124
+ * Create the server-side content kit for one Convex query invocation.
125
+ *
126
+ * Usage inside a Convex query function:
127
+ * ```ts
128
+ * const content = await createContent(ctx, { projectId, perspective: 'published' })
129
+ * const { document: post } = content.get<Post>('post', slug)
130
+ * ```
131
+ */
132
+ export async function createContent(
133
+ ctx: QueryCtx,
134
+ options: CreateContentOptions,
135
+ ): Promise<ContentKit> {
136
+ const { projectId, perspective } = options
137
+ const routes = options.routes ?? []
138
+ const redirects = options.redirects ?? []
139
+ const loadIssues: ContentKitIssue[] = []
140
+
141
+ // --- Prefetch (the only async part; everything below is synchronous) -----
142
+
143
+ // Config-first identity (EC-182/EC-183, AD-11): locales AND collections are
144
+ // supplied by the caller (sourced from `elytra.config.ts`); the backend has
145
+ // no `projects` row and no `cmsSchemas` table — it stores documents only.
146
+ const locales = options.locales ?? DEFAULT_LOCALES
147
+ const collectionDefs: CollectionDef[] = options.collections ? [...options.collections] : []
148
+
149
+ // One indexed scan over the project's documents (v1 scale; see module doc).
150
+ // A row's `document` is the continuous working **draft**; `publishedVersion`
151
+ // (when set) pins which recorded version is live — the Sanity model (EC-224).
152
+ const documentRows = await ctx.db.query('cmsDocuments').collect()
153
+
154
+ // The recorded version snapshots, indexed by (collection, docId, version), so
155
+ // a published read can serve the *pinned* version rather than the live draft.
156
+ const versionsByKey = new Map<string, Map<number, CmsDocument>>()
157
+ for (const row of await ctx.db.query('documentVersions').collect()) {
158
+ const parsed = documentSchema.safeParse(row.snapshot)
159
+ if (!parsed.success) continue
160
+ const key = `${row.collection}:${row.docId}`
161
+ let byVersion = versionsByKey.get(key)
162
+ if (!byVersion) {
163
+ byVersion = new Map()
164
+ versionsByKey.set(key, byVersion)
165
+ }
166
+ byVersion.set(row.version, parsed.data)
167
+ }
168
+
169
+ // Hybrid source per row (EC-224 A1a): a `publishedVersion` pointer yields a
170
+ // `DocumentHistory` (draft = the live row, published = the pinned snapshot),
171
+ // so the published perspective serves the recorded version, decoupled from
172
+ // the continuously-edited draft. An unpinned row stays a bare `CmsDocument`
173
+ // (the EC-142 gate reads its `state`) — backward-compatible: pre-pointer data
174
+ // resolves exactly as before.
175
+ const parsedSources: { key: string; source: ContentDocumentSource }[] = []
176
+ for (const row of documentRows) {
177
+ const parsed = documentSchema.safeParse(row.document)
178
+ if (!parsed.success) {
179
+ loadIssues.push({
180
+ code: 'invalid-stored-document',
181
+ message: `Stored document "${row.collection}:${row.docId}" does not match the canonical document schema and was skipped.`,
182
+ meta: { projectId, collection: row.collection, docId: row.docId },
183
+ })
184
+ continue
185
+ }
186
+ const draft = parsed.data
187
+ const key = documentKey(draft)
188
+ if (row.publishedVersion === undefined) {
189
+ parsedSources.push({ key, source: draft })
190
+ continue
191
+ }
192
+ // Pinned: serve the recorded snapshot for `published`. A dangling pin
193
+ // (version missing/invalid) under-serves to `null` — never the live draft.
194
+ const published = versionsByKey.get(`${row.collection}:${row.docId}`)?.get(row.publishedVersion)
195
+ parsedSources.push({ key, source: { draft, published, versions: [] } })
196
+ }
197
+ // Deterministic iteration order regardless of row creation order.
198
+ parsedSources.sort((a, b) => (a.key < b.key ? -1 : 1))
199
+
200
+ const assetRows = await ctx.db.query('assets').withIndex('by_asset').collect()
201
+ const assetRecords: AssetRecord[] = []
202
+ for (const row of assetRows) {
203
+ // EC-151 stores a stable serve URL on upload; older rows fall back to a
204
+ // live storage lookup, then to the blob adapter's placeholder convention.
205
+ const url = row.url ?? (await ctx.storage.getUrl(row.storageKey)) ?? undefined
206
+ assetRecords.push({
207
+ id: row.assetId,
208
+ // Single-tenant: rows no longer store projectId; the kit's `projectId`
209
+ // option (the constant slug) satisfies the AssetRecord shape (EC-179).
210
+ projectId,
211
+ filename: row.filename,
212
+ contentType: row.contentType,
213
+ byteSize: row.byteSize,
214
+ ...(row.width !== undefined ? { width: row.width } : {}),
215
+ ...(row.height !== undefined ? { height: row.height } : {}),
216
+ ...(row.alt !== undefined ? { alt: row.alt } : {}),
217
+ storageKey: row.storageKey,
218
+ ...(url !== undefined ? { url } : {}),
219
+ createdAt: row.createdAt,
220
+ updatedAt: row.updatedAt,
221
+ })
222
+ }
223
+
224
+ // The page graph backs `resolvePage`'s page capability; it is only loaded
225
+ // when routes were provided (without routes, nothing can resolve to a page).
226
+ // Draft sees the latest revision; published sees the revision pinned to the
227
+ // publishing environment (EC-021 at the graph level).
228
+ let graph: ProjectGraph | null = null
229
+ if (routes.length > 0) {
230
+ let serialized: string | undefined
231
+ if (perspective === 'draft') {
232
+ const latest = await ctx.db
233
+ .query('graphRevisions')
234
+ .withIndex('by_revision')
235
+ .order('desc')
236
+ .first()
237
+ serialized = latest?.serializedGraph
238
+ } else {
239
+ const state = await ctx.db.query('publishingState').first()
240
+ const pinnedRevision = state?.status === 'published' ? state.publishedRevision : undefined
241
+ if (pinnedRevision !== undefined) {
242
+ const pinned = await ctx.db
243
+ .query('graphRevisions')
244
+ .withIndex('by_revision', (q) => q.eq('revision', pinnedRevision))
245
+ .first()
246
+ serialized = pinned?.serializedGraph
247
+ }
248
+ }
249
+ if (serialized !== undefined) {
250
+ const parsed = parseProjectGraph(serialized)
251
+ if (parsed.ok) {
252
+ graph = parsed.graph
253
+ } else {
254
+ loadIssues.push({
255
+ code: 'invalid-stored-graph',
256
+ message: `Stored graph revision for "${projectId}" (${perspective}) could not be parsed; pages are unavailable.`,
257
+ meta: { projectId, perspective },
258
+ })
259
+ }
260
+ }
261
+ }
262
+
263
+ // --- Index into the synchronous lookup the pure accessors read through ---
264
+
265
+ const collections = new Map<string, CollectionDef>()
266
+ for (const collection of collectionDefs) collections.set(collection.id, collection)
267
+
268
+ const documents = new Map<string, ContentDocumentSource>()
269
+ const byCollection = new Map<string, ContentDocumentSource[]>()
270
+ for (const { key, source } of parsedSources) {
271
+ documents.set(key, source)
272
+ const collection = isDocumentHistory(source) ? source.draft.collection : source.collection
273
+ const list = byCollection.get(collection) ?? []
274
+ list.push(source)
275
+ byCollection.set(collection, list)
276
+ }
277
+
278
+ const assets = new Map<string, AssetRecord>()
279
+ for (const record of assetRecords) assets.set(record.id, record)
280
+
281
+ const lookup: ContentLookup = {
282
+ collection: (id) => collections.get(id),
283
+ document: (ref) => documents.get(documentKey(ref)),
284
+ documents: (collectionId) => byCollection.get(collectionId) ?? [],
285
+ asset: (id) => assets.get(id),
286
+ // Same convention as `ConvexBlobStorage.url`: stored serve URL when
287
+ // available, otherwise the explicit unresolved-placeholder scheme.
288
+ assetUrl: (asset) => asset.url ?? `convex://storage/${asset.storageKey}`,
289
+ }
290
+
291
+ const context = createContentContext({
292
+ locale: options.locale ?? locales.default,
293
+ perspective,
294
+ locales,
295
+ })
296
+
297
+ // The EXACT pure client the Next-side accessors run — this is what makes
298
+ // results byte-equivalent across runtimes for the same inputs.
299
+ const client = createContentClient({ lookup, context, routes, redirects })
300
+
301
+ const raw = (collection: string, id: string): CmsDocument | null => {
302
+ const source = documents.get(documentKey({ collection, id }))
303
+ if (!source) return null
304
+ return rawDocument(context, source)
305
+ }
306
+
307
+ return {
308
+ context,
309
+ loadIssues,
310
+ routerIssues: client.routerIssues,
311
+ get: client.getDocument,
312
+ list: client.listDocuments,
313
+ resolvePage: client.resolvePage,
314
+ raw,
315
+ }
316
+ }
@@ -0,0 +1,266 @@
1
+ import { v } from 'convex/values'
2
+ import { dataSourceSchema } from '@elytracms/data-binding'
3
+ import { query } from './functions'
4
+ import type { QueryCtx } from './functions'
5
+
6
+ // EC-207: routes/redirects are config-sourced (authored in elytra.config.ts and
7
+ // resolved by studio-core), NOT backend data. The delivery snapshot no longer
8
+ // emits them and the `routes`/`redirects` CMS system collections are retired —
9
+ // the host reads its route table from its own config (see
10
+ // `apps/example-site/lib/content.ts` / `lib/live-content.ts`).
11
+
12
+ /**
13
+ * EC-156 — the live delivery snapshot: everything a host app (e.g. the
14
+ * `@elytracms/next` example site) needs to assemble a `ContentSource` for one
15
+ * project, in a single query, fetchable over Convex's public HTTP query API
16
+ * (`POST {deployment}/api/query`) with plain `fetch` — no Convex client
17
+ * dependency in the host.
18
+ *
19
+ * ## Why `snapshot` is PUBLIC (deliberate, EC-150 exception)
20
+ *
21
+ * Every other project-scoped function in this deployment is guarded by
22
+ * `requireRole`. This one is not, on purpose: it serves **published content
23
+ * only** — the exact data the production website renders to every anonymous
24
+ * visitor. Publishing IS the act of making it public. The invariants that
25
+ * keep this safe are enforced server-side in this module:
26
+ *
27
+ * - each document is served as its published form before it leaves the
28
+ * function — the EC-224 *pinned version snapshot* (decoupled from the live,
29
+ * continuously-edited draft). Publish-ness is the version pointer alone;
30
+ * drafts and unpinned rows are never returned;
31
+ * - the graph returned is ONLY the revision pinned by `publishingState` (the
32
+ * deployment's single environment) — the latest working revision is never exposed;
33
+ * - nothing else draft-only exists in the payload (asset metadata has no draft
34
+ * variant). CMS collection schema AND routes/redirects are config-owned
35
+ * (EC-183/EC-207, AD-11) — the host reads them from its own config, not this
36
+ * snapshot.
37
+ *
38
+ * `draftSnapshot` is the draft-perspective equivalent (latest graph revision,
39
+ * all stored document rows including drafts) and is gated by the deployment
40
+ * env var `DRAFT_PREVIEW_TOKEN` — set via `npx convex env set`. A missing or
41
+ * mismatching token throws `unauthorized`; an unset env var closes the
42
+ * endpoint entirely. The host server passes the token from its own env when
43
+ * Next draft mode is enabled (itself gated by the host's preview token).
44
+ */
45
+
46
+ interface GraphRevisionPayload {
47
+ revision: number
48
+ serializedGraph: string
49
+ }
50
+
51
+ interface DeliverySnapshot {
52
+ projectId: string
53
+ perspective: 'published' | 'draft'
54
+ /**
55
+ * Data-source definitions the published graph's bindings reference (EC-166
56
+ * delivery): the builder persists its provisioned sources (per-section
57
+ * queries, per-template "current document" sources, provider refs) as
58
+ * documents in the `cms-data-sources` system collection; this surfaces them
59
+ * in the structural `CanvasDataSource` shape (`kind`/`id`/`label`/`config`)
60
+ * the host's payload materialization consumes. Sources are config, not
61
+ * content — perspective rules don't apply — but exposure is deliberate:
62
+ * only cms-kind query configs and provider-backed refs are returned (a
63
+ * rest-kind source's headers stay inside the deployment), and the captured
64
+ * sample/schema envelope (builder preview state) is not delivery data.
65
+ */
66
+ sources: unknown[]
67
+ /** Stored document rows visible in the perspective (published: pinned versions only). */
68
+ documents: unknown[]
69
+ /** Asset metadata in the delivery `AssetRecord` shape (with serve URLs). */
70
+ assets: unknown[]
71
+ /**
72
+ * Graph revisions per perspective. `snapshot` NEVER fills `draft` — only
73
+ * `draftSnapshot` does. `published` is the `publishingState`-pinned
74
+ * revision, or `null` when never published.
75
+ */
76
+ graphs: { draft: GraphRevisionPayload | null; published: GraphRevisionPayload | null }
77
+ }
78
+
79
+ /** One document per persisted source — must match the studio's sources-store. */
80
+ const DATA_SOURCES_COLLECTION = 'cms-data-sources'
81
+
82
+ /** The functionRef namespace marking a convex-kind source as provider-backed. */
83
+ const PROVIDER_FUNCTION_PREFIX = 'provider:'
84
+
85
+ /**
86
+ * Map the persisted `cms-data-sources` documents to the delivery `sources`
87
+ * array. Each record's `config` field carries the FULL canonical
88
+ * `@elytracms/data-binding` source, JSON-serialized; it is validated against
89
+ * `dataSourceSchema` (malformed records drop out, never crash the snapshot)
90
+ * and then deliberately projected to the structural delivery envelope:
91
+ *
92
+ * - `cms`-kind sources pass with their full query config (collection,
93
+ * documentId, filter/sort/limit, locale) — exactly what
94
+ * `materializeSourcePayloads` replays through `listDocuments`;
95
+ * - `convex`-kind sources pass only when provider-backed
96
+ * (`functionRef: provider:<id>`) — a provider ref names project code, it
97
+ * carries no secret;
98
+ * - `rest`-kind sources never leave the deployment (their headers could hold
99
+ * credentials), and the captured sample/schema envelope (builder preview
100
+ * state, not delivery config) is stripped for every kind.
101
+ */
102
+ function dataSourcesFromSystemCollection(documents: unknown[]): unknown[] {
103
+ const sources: unknown[] = []
104
+ for (const document of documents) {
105
+ if (typeof document !== 'object' || document === null) continue
106
+ const row = document as { collection?: unknown; id?: unknown; values?: unknown }
107
+ if (row.collection !== DATA_SOURCES_COLLECTION) continue
108
+ const values = (typeof row.values === 'object' && row.values !== null ? row.values : {}) as {
109
+ config?: unknown
110
+ }
111
+ if (typeof values.config !== 'string') continue
112
+ let raw: unknown
113
+ try {
114
+ raw = JSON.parse(values.config)
115
+ } catch {
116
+ continue
117
+ }
118
+ const parsed = dataSourceSchema.safeParse(raw)
119
+ if (!parsed.success) continue
120
+ const source = parsed.data
121
+ if (source.kind === 'rest') continue
122
+ if (
123
+ source.kind === 'convex' &&
124
+ !source.config.functionRef.startsWith(PROVIDER_FUNCTION_PREFIX)
125
+ ) {
126
+ continue
127
+ }
128
+ sources.push({ kind: source.kind, id: source.id, label: source.label, config: source.config })
129
+ }
130
+ return sources
131
+ }
132
+
133
+ async function loadPinnedGraph(ctx: QueryCtx): Promise<GraphRevisionPayload | null> {
134
+ const state = await ctx.db.query('publishingState').first()
135
+ const pinned = state?.status === 'published' ? state.publishedRevision : undefined
136
+ if (pinned === undefined) return null
137
+ const row = await ctx.db
138
+ .query('graphRevisions')
139
+ .withIndex('by_revision', (q) => q.eq('revision', pinned))
140
+ .first()
141
+ return row ? { revision: row.revision, serializedGraph: row.serializedGraph } : null
142
+ }
143
+
144
+ async function loadLatestGraph(ctx: QueryCtx): Promise<GraphRevisionPayload | null> {
145
+ const row = await ctx.db.query('graphRevisions').withIndex('by_revision').order('desc').first()
146
+ return row ? { revision: row.revision, serializedGraph: row.serializedGraph } : null
147
+ }
148
+
149
+ export async function loadSnapshot(
150
+ ctx: QueryCtx,
151
+ args: { projectId: string },
152
+ perspective: 'published' | 'draft',
153
+ ): Promise<DeliverySnapshot> {
154
+ const { projectId } = args
155
+
156
+ const documentRows = await ctx.db.query('cmsDocuments').collect()
157
+ // THE published-content invariant (the trust boundary): the public snapshot
158
+ // ships ONLY published content — never a draft. Under the EC-224 pointer model
159
+ // a published row is served as its *pinned version snapshot* (decoupled from
160
+ // the continuously-edited draft); a row with no pin never leaves the
161
+ // deployment. Publish-ness is the pointer, full stop — there is no flat-state
162
+ // fallback (the `state` field is gone).
163
+ let documents: unknown[]
164
+ if (perspective === 'draft') {
165
+ documents = documentRows.map((row) => row.document as unknown)
166
+ } else {
167
+ const versionsByKey = new Map<string, Map<number, unknown>>()
168
+ for (const row of await ctx.db.query('documentVersions').collect()) {
169
+ const key = `${row.collection}:${row.docId}`
170
+ let byVersion = versionsByKey.get(key)
171
+ if (!byVersion) {
172
+ byVersion = new Map()
173
+ versionsByKey.set(key, byVersion)
174
+ }
175
+ byVersion.set(row.version, row.snapshot as unknown)
176
+ }
177
+ documents = []
178
+ for (const row of documentRows) {
179
+ if (row.publishedVersion === undefined) continue
180
+ // Serve the pinned recorded version, NOT the live draft. A dangling pin
181
+ // (version missing) is dropped — it never falls back to the draft.
182
+ const snapshot = versionsByKey
183
+ .get(`${row.collection}:${row.docId}`)
184
+ ?.get(row.publishedVersion)
185
+ if (snapshot !== undefined) documents.push(snapshot)
186
+ }
187
+ }
188
+
189
+ const assetRows = await ctx.db.query('assets').withIndex('by_asset').collect()
190
+ const assets: unknown[] = []
191
+ for (const row of assetRows) {
192
+ // Same URL convention as the EC-145 content kit: stored serve URL when
193
+ // available (EC-151), else a live storage lookup for older rows. Seeded
194
+ // rows carry a placeholder storage key that is not a real storage id —
195
+ // `getUrl` throws on those, so degrade to "no URL" instead of failing
196
+ // the whole snapshot (the host renders its explicit unresolved fallback).
197
+ const url = row.url ?? (await ctx.storage.getUrl(row.storageKey).catch(() => null)) ?? undefined
198
+ assets.push({
199
+ id: row.assetId,
200
+ // Wire-compat: the host still parses delivery assets with `projectId`
201
+ // (the constant slug from the snapshot args) until the host drops it (EC-179 §4).
202
+ projectId,
203
+ filename: row.filename,
204
+ contentType: row.contentType,
205
+ byteSize: row.byteSize,
206
+ ...(row.width !== undefined ? { width: row.width } : {}),
207
+ ...(row.height !== undefined ? { height: row.height } : {}),
208
+ ...(row.alt !== undefined ? { alt: row.alt } : {}),
209
+ storageKey: row.storageKey,
210
+ ...(url !== undefined ? { url } : {}),
211
+ createdAt: row.createdAt,
212
+ updatedAt: row.updatedAt,
213
+ })
214
+ }
215
+
216
+ const published = await loadPinnedGraph(ctx)
217
+ // The latest working revision is loaded ONLY for the token-gated draft path.
218
+ const draft = perspective === 'draft' ? await loadLatestGraph(ctx) : null
219
+
220
+ // LIVE-mode data sources: the builder's persisted source records, projected
221
+ // to the delivery envelope (config only — see the helper's exposure rules).
222
+ // Sources are project *config*, not perspective-gated content, so they are
223
+ // extracted from every stored row (independent of publish state) — published
224
+ // bindings must always resolve their definitions, even when the defining
225
+ // `cms-data-sources` row is not itself "published".
226
+ const sources = dataSourcesFromSystemCollection(
227
+ documentRows.map((row) => row.document as unknown),
228
+ )
229
+
230
+ return {
231
+ projectId,
232
+ perspective,
233
+ sources,
234
+ documents,
235
+ assets,
236
+ graphs: { draft, published },
237
+ }
238
+ }
239
+
240
+ /**
241
+ * PUBLIC published-content snapshot — see the module header for why this is
242
+ * unguarded. Never returns draft document rows or unpinned graph revisions.
243
+ */
244
+ export const snapshot = query({
245
+ args: { projectId: v.string() },
246
+ handler: async (ctx, args): Promise<DeliverySnapshot> => loadSnapshot(ctx, args, 'published'),
247
+ })
248
+
249
+ /**
250
+ * Draft-perspective snapshot for token-holding preview hosts: all stored
251
+ * document rows (drafts included) plus the latest working graph revision.
252
+ * Gated by the `DRAFT_PREVIEW_TOKEN` deployment env var.
253
+ */
254
+ export const draftSnapshot = query({
255
+ args: { projectId: v.string(), token: v.string() },
256
+ handler: async (ctx, args): Promise<DeliverySnapshot> => {
257
+ const expected = process.env['DRAFT_PREVIEW_TOKEN']
258
+ if (expected === undefined || expected.length === 0) {
259
+ throw new Error('unauthorized: draft preview is not configured on this deployment')
260
+ }
261
+ if (args.token !== expected) {
262
+ throw new Error('unauthorized: invalid draft preview token')
263
+ }
264
+ return loadSnapshot(ctx, { projectId: args.projectId }, 'draft')
265
+ },
266
+ })
@@ -0,0 +1,35 @@
1
+ import {
2
+ httpActionGeneric,
3
+ internalMutationGeneric,
4
+ internalQueryGeneric,
5
+ mutationGeneric,
6
+ queryGeneric,
7
+ } from 'convex/server'
8
+ import type {
9
+ DataModelFromSchemaDefinition,
10
+ GenericMutationCtx,
11
+ GenericQueryCtx,
12
+ MutationBuilder,
13
+ QueryBuilder,
14
+ } from 'convex/server'
15
+ import schema from './schema'
16
+
17
+ /**
18
+ * Typed function builders bound to our schema's data model. This is what Convex
19
+ * codegen normally writes into `_generated/server`; defining it explicitly lets
20
+ * the functions typecheck (and be reviewed in Git) without requiring a running
21
+ * deployment. `npx convex dev` will regenerate `_generated/*` for live use.
22
+ */
23
+ export type DataModel = DataModelFromSchemaDefinition<typeof schema>
24
+ export type QueryCtx = GenericQueryCtx<DataModel>
25
+ export type MutationCtx = GenericMutationCtx<DataModel>
26
+
27
+ export const query = queryGeneric as QueryBuilder<DataModel, 'public'>
28
+ export const mutation = mutationGeneric as MutationBuilder<DataModel, 'public'>
29
+ /** CLI-/scheduler-only functions (e.g. seeding) — not callable by clients (EC-150). */
30
+ export const internalMutation = internalMutationGeneric as MutationBuilder<DataModel, 'internal'>
31
+ /** Server-only reads (e.g. the EC-157 HTTP sync endpoints) — not callable by clients. */
32
+ export const internalQuery = internalQueryGeneric as QueryBuilder<DataModel, 'internal'>
33
+ /** HTTP action builder (EC-252) — used by the package's `http.ts`/`sync.ts`. Not
34
+ * DataModel-bound: an action reaches data only through `ctx.runQuery`/`runMutation`. */
35
+ export const httpAction = httpActionGeneric
@@ -0,0 +1,51 @@
1
+ import { v } from 'convex/values'
2
+ import { mutation, query } from './functions'
3
+ import { requireRole } from './guard'
4
+
5
+ /** Project graph + revision persistence (EC-041). Revisions are append-only. */
6
+
7
+ export const saveRevision = mutation({
8
+ args: {
9
+ serializedGraph: v.string(),
10
+ schemaVersion: v.number(),
11
+ createdAt: v.string(),
12
+ label: v.optional(v.string()),
13
+ message: v.optional(v.string()),
14
+ },
15
+ handler: async (ctx, args) => {
16
+ await requireRole(ctx, 'editor') // EC-150
17
+ // Compute the next revision atomically inside the mutation.
18
+ const last = await ctx.db.query('graphRevisions').withIndex('by_revision').order('desc').first()
19
+ const revision = (last?.revision ?? 0) + 1
20
+ const id = await ctx.db.insert('graphRevisions', { ...args, revision })
21
+ const record = await ctx.db.get(id)
22
+ return record
23
+ },
24
+ })
25
+
26
+ export const latest = query({
27
+ args: {},
28
+ handler: async (ctx) => {
29
+ await requireRole(ctx, 'viewer') // EC-150
30
+ return ctx.db.query('graphRevisions').withIndex('by_revision').order('desc').first()
31
+ },
32
+ })
33
+
34
+ export const revision = query({
35
+ args: { revision: v.number() },
36
+ handler: async (ctx, args) => {
37
+ await requireRole(ctx, 'viewer') // EC-150
38
+ return ctx.db
39
+ .query('graphRevisions')
40
+ .withIndex('by_revision', (q) => q.eq('revision', args.revision))
41
+ .first()
42
+ },
43
+ })
44
+
45
+ export const listRevisions = query({
46
+ args: {},
47
+ handler: async (ctx) => {
48
+ await requireRole(ctx, 'viewer') // EC-150
49
+ return ctx.db.query('graphRevisions').withIndex('by_revision').order('desc').collect()
50
+ },
51
+ })