@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,67 @@
1
+ import { getAuthUserId } from '@convex-dev/auth/server'
2
+ import type { QueryCtx } from './functions'
3
+
4
+ /**
5
+ * Server-side authorization guards (EC-150). The operations chokepoint in the
6
+ * app enforces the role model for UX, but Convex functions are the actual
7
+ * trust boundary — every mutation and read re-checks here, so a hand-crafted
8
+ * client cannot bypass the rules.
9
+ *
10
+ * Single-tenant (EC-179): a deployment IS one project, so roles are
11
+ * deployment-scoped — a `members` row grants a user a role on this deployment.
12
+ * No `projectId` is threaded.
13
+ *
14
+ * Role ranks mirror `@elytracms/persistence`'s `roleAtLeast`:
15
+ * viewer (0) < editor (1) < admin (2).
16
+ *
17
+ * Failures throw plain `Error('unauthorized: …')` — Convex transports the
18
+ * message; the app's adapters normalize thrown backend errors onto the
19
+ * persistence error taxonomy, and the operations pipeline turns them into
20
+ * structured `OperationError`s (never crashes).
21
+ */
22
+
23
+ export type ProjectRole = 'admin' | 'editor' | 'viewer'
24
+
25
+ const ROLE_RANK: Record<ProjectRole, number> = { viewer: 0, editor: 1, admin: 2 }
26
+
27
+ /**
28
+ * The ctx slice the guards need: identity + a readable `members` table.
29
+ * Both `QueryCtx` and `MutationCtx` satisfy it (a writer is a reader).
30
+ */
31
+ export type GuardCtx = Pick<QueryCtx, 'auth' | 'db'>
32
+
33
+ /** Resolve the authenticated user id or reject. */
34
+ export async function requireUserId(ctx: GuardCtx): Promise<string> {
35
+ const userId = await getAuthUserId(ctx)
36
+ if (userId === null) {
37
+ throw new Error('unauthorized: this function requires an authenticated user')
38
+ }
39
+ return userId
40
+ }
41
+
42
+ /** Look up the caller's role on this deployment; `null` when not a member. */
43
+ export async function memberRole(ctx: GuardCtx, userId: string): Promise<ProjectRole | null> {
44
+ const membership = await ctx.db
45
+ .query('members')
46
+ .withIndex('by_user', (q) => q.eq('userId', userId))
47
+ .first()
48
+ return membership?.role ?? null
49
+ }
50
+
51
+ /**
52
+ * Require an authenticated caller with at least `role` on this deployment.
53
+ * Returns the user id so handlers can attribute writes.
54
+ */
55
+ export async function requireRole(ctx: GuardCtx, role: ProjectRole): Promise<string> {
56
+ const userId = await requireUserId(ctx)
57
+ const actual = await memberRole(ctx, userId)
58
+ if (actual === null) {
59
+ throw new Error('unauthorized: not a member of this deployment')
60
+ }
61
+ if (ROLE_RANK[actual] < ROLE_RANK[role]) {
62
+ throw new Error(
63
+ `unauthorized: this deployment requires the "${role}" role (caller is "${actual}")`,
64
+ )
65
+ }
66
+ return userId
67
+ }
package/convex/http.ts ADDED
@@ -0,0 +1,30 @@
1
+ import { httpRouter } from 'convex/server'
2
+ import type { HttpRouter } from 'convex/server'
3
+ import { registrySync } from './sync'
4
+
5
+ /** The slice of the Convex Auth object the studio's HTTP routes need. */
6
+ interface AuthHttpRoutes {
7
+ addHttpRoutes(http: HttpRouter): void
8
+ }
9
+
10
+ /**
11
+ * EC-252 — the studio's HTTP routes as a factory. `http`/`sync` are pure engine
12
+ * infra, so they ship in the package; only the consumer's `auth` (provider choice)
13
+ * is injected. The consumer's `convex/http.ts` is a two-liner:
14
+ *
15
+ * ```ts
16
+ * import { auth } from './auth'
17
+ * export default defineStudioHttp({ auth })
18
+ * ```
19
+ *
20
+ * Registers Convex Auth's JWT discovery endpoints (`/.well-known/*`, EC-150) plus the
21
+ * EC-157 Bearer-token registry-sync endpoint. Convex routes by exact path or prefix
22
+ * only, so the dynamic `/api/projects/:projectId/registry-sync/snapshot` segment is
23
+ * parsed inside the action (`sync.ts`).
24
+ */
25
+ export function defineStudioHttp({ auth }: { auth: AuthHttpRoutes }): HttpRouter {
26
+ const http = httpRouter()
27
+ auth.addHttpRoutes(http)
28
+ http.route({ pathPrefix: '/api/projects/', method: 'GET', handler: registrySync })
29
+ return http
30
+ }
@@ -0,0 +1,83 @@
1
+ import { v } from 'convex/values'
2
+ import { mutation, query } from './functions'
3
+ import { requireRole, requireUserId } from './guard'
4
+
5
+ /**
6
+ * Deployment membership persistence (EC-150, single-tenant per EC-179). The
7
+ * Convex side of the `MembersRepository` contract; the app's
8
+ * `ConvexMembersRepository` maps these onto `@elytracms/persistence` records.
9
+ * Member *management* is admin-only, server-side — UI gating alone is never
10
+ * trusted. One row per user grants their role on this deployment's one project.
11
+ */
12
+
13
+ const roleValidator = v.union(v.literal('admin'), v.literal('editor'), v.literal('viewer'))
14
+
15
+ export const list = query({
16
+ args: {},
17
+ handler: async (ctx) => {
18
+ await requireRole(ctx, 'viewer')
19
+ const rows = await ctx.db.query('members').collect()
20
+ return rows.sort((a, b) => (a.userId < b.userId ? -1 : a.userId > b.userId ? 1 : 0))
21
+ },
22
+ })
23
+
24
+ export const get = query({
25
+ args: { userId: v.string() },
26
+ handler: async (ctx, { userId }) => {
27
+ // Members may look up memberships of this deployment; everyone may look up
28
+ // their *own* membership (the studio needs it to render the role badge).
29
+ const caller = await requireUserId(ctx)
30
+ if (caller !== userId) await requireRole(ctx, 'viewer')
31
+ return ctx.db
32
+ .query('members')
33
+ .withIndex('by_user', (q) => q.eq('userId', userId))
34
+ .first()
35
+ },
36
+ })
37
+
38
+ /** The authenticated caller's membership on this deployment (studio bootstrap). */
39
+ export const mine = query({
40
+ args: {},
41
+ handler: async (ctx) => {
42
+ const userId = await requireUserId(ctx)
43
+ return ctx.db
44
+ .query('members')
45
+ .withIndex('by_user', (q) => q.eq('userId', userId))
46
+ .first()
47
+ },
48
+ })
49
+
50
+ export const set = mutation({
51
+ args: {
52
+ userId: v.string(),
53
+ role: roleValidator,
54
+ createdAt: v.string(),
55
+ updatedAt: v.string(),
56
+ },
57
+ handler: async (ctx, args) => {
58
+ await requireRole(ctx, 'admin')
59
+ const existing = await ctx.db
60
+ .query('members')
61
+ .withIndex('by_user', (q) => q.eq('userId', args.userId))
62
+ .first()
63
+ if (existing) {
64
+ await ctx.db.patch(existing._id, { role: args.role, updatedAt: args.updatedAt })
65
+ return ctx.db.get(existing._id)
66
+ }
67
+ const id = await ctx.db.insert('members', args)
68
+ return ctx.db.get(id)
69
+ },
70
+ })
71
+
72
+ export const remove = mutation({
73
+ args: { userId: v.string() },
74
+ handler: async (ctx, { userId }) => {
75
+ await requireRole(ctx, 'admin')
76
+ const existing = await ctx.db
77
+ .query('members')
78
+ .withIndex('by_user', (q) => q.eq('userId', userId))
79
+ .first()
80
+ if (!existing) throw new Error(`not-found: member "${userId}"`)
81
+ await ctx.db.delete(existing._id)
82
+ },
83
+ })
@@ -0,0 +1,102 @@
1
+ import { makeFunctionReference } from 'convex/server'
2
+ import { v } from 'convex/values'
3
+ import { mutation, query } from './functions'
4
+ import type { MutationCtx } from './functions'
5
+ import { requireRole } from './guard'
6
+
7
+ // EC-223: the studio's convex functions are package-shipped and deployment-agnostic
8
+ // — they address each other by STRING ref (resolved against the consumer's deployment),
9
+ // never the per-deployment `_generated/api`. Mirrors the lib's `queryRef`/`actionRef`.
10
+ const webhooksDeliver = makeFunctionReference<'action'>('webhooks:deliver')
11
+
12
+ /**
13
+ * Publishing state (EC-045). Single-environment (EC-179, vision AD-8): a
14
+ * deployment IS one environment, so there is exactly ONE publishingState row —
15
+ * see `env-is-deployment-boundary`.
16
+ */
17
+
18
+ /**
19
+ * EC-180 / EC-146 — fire the host revalidation webhook on a publish-state change.
20
+ *
21
+ * A mutation cannot `fetch`, so we hand off to the `webhooks.deliver` internal
22
+ * action (it signs + POSTs server-side; the secret never leaves Convex). A graph
23
+ * publish/unpublish can affect any page, so the honest v1 invalidation is the
24
+ * whole-project sweep tag `p:<scope>:project` — a mirror of
25
+ * `projectSweepWebhookTag` (`src/lib/webhooks/tags.ts`) / `@elytracms/next`'s
26
+ * `projectSweepTag`; the tests on those two sides pin the literal.
27
+ *
28
+ * `scope` must equal the host's `cache.scope` (its `ELYTRA_PROJECT_ID`) for the
29
+ * tag to match what the host stamped on its cached fetches; it comes from the
30
+ * `CANVAS_PROJECT_SCOPE` Convex env var. Unconfigured deployments (local dev,
31
+ * no env) are a silent no-op — publishing must never depend on a reachable host.
32
+ */
33
+ async function scheduleRevalidate(
34
+ ctx: MutationCtx,
35
+ event: 'publishing.publish' | 'publishing.unpublish',
36
+ ): Promise<void> {
37
+ const env =
38
+ (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env ?? {}
39
+ const scope = env['CANVAS_PROJECT_SCOPE']
40
+ if (!scope) return
41
+ await ctx.scheduler.runAfter(0, webhooksDeliver, {
42
+ projectId: scope,
43
+ event,
44
+ tags: [`p:${scope}:project`],
45
+ })
46
+ }
47
+
48
+ export const publish = mutation({
49
+ args: {
50
+ revisionId: v.string(),
51
+ revision: v.number(),
52
+ publishedAt: v.string(),
53
+ },
54
+ handler: async (ctx, args) => {
55
+ await requireRole(ctx, 'editor') // EC-150
56
+ const existing = await ctx.db.query('publishingState').first()
57
+ const record = {
58
+ status: 'published' as const,
59
+ publishedRevisionId: args.revisionId,
60
+ publishedRevision: args.revision,
61
+ publishedAt: args.publishedAt,
62
+ createdAt: existing?.createdAt ?? args.publishedAt,
63
+ updatedAt: args.publishedAt,
64
+ }
65
+ // EC-153 parity: republish preserves `createdAt`; return the stored record.
66
+ const id = existing ? existing._id : await ctx.db.insert('publishingState', record)
67
+ if (existing) await ctx.db.patch(existing._id, record)
68
+ // EC-180: drop the host's cached pages for this project (fire-and-forget).
69
+ await scheduleRevalidate(ctx, 'publishing.publish')
70
+ return ctx.db.get(id)
71
+ },
72
+ })
73
+
74
+ export const unpublish = mutation({
75
+ args: { updatedAt: v.string() },
76
+ handler: async (ctx, args) => {
77
+ await requireRole(ctx, 'editor') // EC-150
78
+ const existing = await ctx.db.query('publishingState').first()
79
+ if (!existing || existing.status !== 'published') {
80
+ throw new Error('invalid-transition: nothing is currently published')
81
+ }
82
+ await ctx.db.patch(existing._id, {
83
+ status: 'draft',
84
+ publishedRevisionId: undefined,
85
+ publishedRevision: undefined,
86
+ publishedAt: undefined,
87
+ updatedAt: args.updatedAt,
88
+ })
89
+ // EC-180: a graph going dark must also drop the host's cached pages.
90
+ await scheduleRevalidate(ctx, 'publishing.unpublish')
91
+ // EC-153 parity: return the stored record (createdAt preserved).
92
+ return ctx.db.get(existing._id)
93
+ },
94
+ })
95
+
96
+ export const getState = query({
97
+ args: {},
98
+ handler: async (ctx) => {
99
+ await requireRole(ctx, 'viewer') // EC-150
100
+ return ctx.db.query('publishingState').first()
101
+ },
102
+ })
@@ -0,0 +1,168 @@
1
+ import { v } from 'convex/values'
2
+ import { mutation, query } from './functions'
3
+ import { requireRole } from './guard'
4
+ import type { MutationCtx } from './functions'
5
+
6
+ /**
7
+ * Reference-index persistence (EC-155, vision AD-6). Entries are derived data
8
+ * maintained replace-all-for-source by the operations layer; both lookup
9
+ * directions are index-backed (`by_source` outbound, `by_target` inbound).
10
+ */
11
+
12
+ const variantValidator = v.union(v.literal('draft'), v.literal('published'))
13
+ const sourceTypeValidator = v.union(v.literal('document'), v.literal('page'), v.literal('layout'))
14
+ const targetTypeValidator = v.union(
15
+ v.literal('document'),
16
+ v.literal('component'),
17
+ v.literal('asset'),
18
+ )
19
+
20
+ /** One outbound reference, before attribution to its source. */
21
+ const outboundReferenceValidator = v.object({
22
+ path: v.string(),
23
+ targetType: targetTypeValidator,
24
+ targetId: v.string(),
25
+ kind: v.string(),
26
+ })
27
+
28
+ /** An outbound reference attributed to its holding source. */
29
+ const entryValidator = v.object({
30
+ sourceType: sourceTypeValidator,
31
+ sourceId: v.string(),
32
+ path: v.string(),
33
+ targetType: targetTypeValidator,
34
+ targetId: v.string(),
35
+ kind: v.string(),
36
+ })
37
+
38
+ async function deleteForSource(
39
+ ctx: MutationCtx,
40
+ variant: 'draft' | 'published',
41
+ sourceType: 'document' | 'page' | 'layout',
42
+ sourceId?: string,
43
+ ): Promise<void> {
44
+ const existing = await ctx.db
45
+ .query('referenceEntries')
46
+ .withIndex('by_source', (q) => {
47
+ const scoped = q.eq('variant', variant).eq('sourceType', sourceType)
48
+ return sourceId === undefined ? scoped : scoped.eq('sourceId', sourceId)
49
+ })
50
+ .collect()
51
+ for (const doc of existing) await ctx.db.delete(doc._id)
52
+ }
53
+
54
+ export const replaceForSource = mutation({
55
+ args: {
56
+ variant: variantValidator,
57
+ sourceType: sourceTypeValidator,
58
+ sourceId: v.string(),
59
+ references: v.array(outboundReferenceValidator),
60
+ },
61
+ handler: async (ctx, args) => {
62
+ await requireRole(ctx, 'editor') // EC-150
63
+ await deleteForSource(ctx, args.variant, args.sourceType, args.sourceId)
64
+ for (const reference of args.references) {
65
+ await ctx.db.insert('referenceEntries', {
66
+ variant: args.variant,
67
+ sourceType: args.sourceType,
68
+ sourceId: args.sourceId,
69
+ ...reference,
70
+ })
71
+ }
72
+ },
73
+ })
74
+
75
+ export const replaceForSourceTypes = mutation({
76
+ args: {
77
+ variant: variantValidator,
78
+ sourceTypes: v.array(sourceTypeValidator),
79
+ entries: v.array(entryValidator),
80
+ },
81
+ handler: async (ctx, args) => {
82
+ await requireRole(ctx, 'editor') // EC-150
83
+ for (const sourceType of args.sourceTypes) {
84
+ await deleteForSource(ctx, args.variant, sourceType)
85
+ }
86
+ for (const entry of args.entries) {
87
+ await ctx.db.insert('referenceEntries', {
88
+ variant: args.variant,
89
+ ...entry,
90
+ })
91
+ }
92
+ },
93
+ })
94
+
95
+ export const removeForSource = mutation({
96
+ args: {
97
+ sourceType: sourceTypeValidator,
98
+ sourceId: v.string(),
99
+ variant: v.optional(variantValidator),
100
+ },
101
+ handler: async (ctx, args) => {
102
+ await requireRole(ctx, 'editor') // EC-150
103
+ const variants = args.variant ? [args.variant] : (['draft', 'published'] as const)
104
+ for (const variant of variants) {
105
+ await deleteForSource(ctx, variant, args.sourceType, args.sourceId)
106
+ }
107
+ },
108
+ })
109
+
110
+ export const clearProject = mutation({
111
+ args: {},
112
+ handler: async (ctx) => {
113
+ await requireRole(ctx, 'editor') // EC-150
114
+ const existing = await ctx.db.query('referenceEntries').collect()
115
+ for (const doc of existing) await ctx.db.delete(doc._id)
116
+ },
117
+ })
118
+
119
+ export const outbound = query({
120
+ args: {
121
+ sourceType: sourceTypeValidator,
122
+ sourceId: v.string(),
123
+ variant: v.optional(variantValidator),
124
+ },
125
+ handler: async (ctx, args) => {
126
+ await requireRole(ctx, 'viewer') // EC-150
127
+ const variants = args.variant ? [args.variant] : (['draft', 'published'] as const)
128
+ const out = []
129
+ for (const variant of variants) {
130
+ out.push(
131
+ ...(await ctx.db
132
+ .query('referenceEntries')
133
+ .withIndex('by_source', (q) =>
134
+ q.eq('variant', variant).eq('sourceType', args.sourceType).eq('sourceId', args.sourceId),
135
+ )
136
+ .collect()),
137
+ )
138
+ }
139
+ return out
140
+ },
141
+ })
142
+
143
+ export const inbound = query({
144
+ args: {
145
+ targetType: targetTypeValidator,
146
+ targetId: v.string(),
147
+ variant: v.optional(variantValidator),
148
+ },
149
+ handler: async (ctx, args) => {
150
+ await requireRole(ctx, 'viewer') // EC-150
151
+ return ctx.db
152
+ .query('referenceEntries')
153
+ .withIndex('by_target', (q) => {
154
+ const scoped = q.eq('targetType', args.targetType).eq('targetId', args.targetId)
155
+ return args.variant ? scoped.eq('variant', args.variant) : scoped
156
+ })
157
+ .collect()
158
+ },
159
+ })
160
+
161
+ export const list = query({
162
+ args: { variant: v.optional(variantValidator) },
163
+ handler: async (ctx, args) => {
164
+ await requireRole(ctx, 'viewer') // EC-150
165
+ const docs = await ctx.db.query('referenceEntries').collect()
166
+ return args.variant ? docs.filter((d) => d.variant === args.variant) : docs
167
+ },
168
+ })
@@ -0,0 +1,173 @@
1
+ import { defineSchema, defineTable } from 'convex/server'
2
+ import { v } from 'convex/values'
3
+ import { authTables } from '@convex-dev/auth/server'
4
+
5
+ /**
6
+ * Convex schema for the Elytra hosted builder (brief §10).
7
+ *
8
+ * ## Single-tenant: one deployment = one project (EC-179, vision AD-8)
9
+ *
10
+ * Project identity lives in `elytra.config.ts` (EC-178); a Convex deployment
11
+ * hosts exactly ONE project, so content tables carry NO `projectId` — the
12
+ * deployment itself IS the scope (the Payload model). Membership is likewise
13
+ * deployment-scoped: a `members` row grants a user a role on this deployment.
14
+ * Multiple projects = multiple config entries + multiple deployments.
15
+ *
16
+ * Tables mirror the persisted record shapes defined (and Zod-validated) in
17
+ * `@elytracms/persistence`; nested structures (graph JSON, documents) are stored
18
+ * as validated blobs (`v.any()`) since the Zod schemas in the packages are the
19
+ * canonical source of truth for their shape.
20
+ *
21
+ * ## Backend is data-only (AD-11, C0: EC-181/182/183)
22
+ *
23
+ * Project **structure is code**, not backend rows: component manifests live in
24
+ * the repo registry (EC-181), project identity/settings/locales/routes and CMS
25
+ * **collection schemas** all live in `elytra.config.ts` (EC-182/EC-183). So
26
+ * there is no `projects`, `componentManifests`, or `cmsSchemas` table — the
27
+ * remaining tables hold **data only**: CMS documents, assets, graph revisions
28
+ * (the page composition is a field value — data, per AD-12), publishing state,
29
+ * the derived reference index, deployment membership, CLI tokens, and auth.
30
+ *
31
+ * This schema is provider configuration only — the Studio and tests talk to the
32
+ * provider-neutral `PersistenceAdapter`, never to Convex directly (brief §4.10).
33
+ */
34
+ export default defineSchema({
35
+ /**
36
+ * Convex Auth tables (EC-150): `users`, `authAccounts`, `authSessions`,
37
+ * `authRefreshTokens`, `authVerificationCodes`, `authVerifiers`,
38
+ * `authRateLimits`. Required by `convexAuth` in `auth.ts`; see
39
+ * https://labs.convex.dev/auth/setup/schema.
40
+ */
41
+ ...authTables,
42
+
43
+ /**
44
+ * Deployment membership roles (EC-150, vision AD-7). Single-tenant: one row
45
+ * per user grants their role on THIS deployment's one project. `userId` is the
46
+ * Convex Auth `users` id (stored as a string so the table shape matches the
47
+ * provider-neutral `@elytracms/persistence` record). Server-side enforcement
48
+ * happens in `guard.ts`; the operations chokepoint enforces the same rules
49
+ * client-side.
50
+ */
51
+ members: defineTable({
52
+ userId: v.string(),
53
+ role: v.union(v.literal('admin'), v.literal('editor'), v.literal('viewer')),
54
+ createdAt: v.string(),
55
+ updatedAt: v.string(),
56
+ }).index('by_user', ['userId']),
57
+
58
+ /**
59
+ * Revocable CLI sync tokens (EC-150, consumed by the EC-147 push CLI).
60
+ * Only the SHA-256 hash of a token is ever stored; revoked tokens keep
61
+ * their row (with `revokedAt`) for auditability.
62
+ *
63
+ * Single-tenant (EC-182/EC-183): a deployment hosts one project, so a token
64
+ * carries no per-project scope — `projectId` is gone (it was `optional`
65
+ * through EC-182; this drops the field now that both deployments are migrated).
66
+ */
67
+ cliTokens: defineTable({
68
+ tokenId: v.string(),
69
+ label: v.string(),
70
+ tokenHash: v.string(),
71
+ createdAt: v.string(),
72
+ revokedAt: v.optional(v.string()),
73
+ })
74
+ .index('by_token', ['tokenId'])
75
+ .index('by_hash', ['tokenHash']),
76
+
77
+ /** Project graph revision records — append-only (EC-041). */
78
+ graphRevisions: defineTable({
79
+ revision: v.number(),
80
+ serializedGraph: v.string(),
81
+ schemaVersion: v.number(),
82
+ label: v.optional(v.string()),
83
+ message: v.optional(v.string()),
84
+ createdAt: v.string(),
85
+ }).index('by_revision', ['revision']),
86
+
87
+ /**
88
+ * CMS documents (EC-043). The stored `document` is the continuous working
89
+ * **draft**; `publishedVersion` pins which `documentVersions` row is live
90
+ * (the Sanity draft/published model, EC-224). Absent = never published.
91
+ * Localized variants ride on the document itself.
92
+ */
93
+ cmsDocuments: defineTable({
94
+ collection: v.string(),
95
+ docId: v.string(),
96
+ document: v.any(),
97
+ publishedVersion: v.optional(v.number()),
98
+ createdAt: v.string(),
99
+ updatedAt: v.string(),
100
+ })
101
+ .index('by_collection', ['collection'])
102
+ .index('by_doc', ['collection', 'docId']),
103
+
104
+ /**
105
+ * CMS document version snapshots — append-only (EC-224), the document-scoped
106
+ * analogue of `graphRevisions`. One row per recorded version (created on
107
+ * publish or a pre-restore snapshot, never on a plain draft edit), keyed per
108
+ * document via `by_doc`. `cmsDocuments.publishedVersion` points at the live one.
109
+ */
110
+ documentVersions: defineTable({
111
+ collection: v.string(),
112
+ docId: v.string(),
113
+ version: v.number(),
114
+ snapshot: v.any(),
115
+ label: v.optional(v.string()),
116
+ createdAt: v.string(),
117
+ }).index('by_doc', ['collection', 'docId']),
118
+
119
+ /** Asset metadata; bytes live in Convex/file storage behind the blob adapter (EC-044). */
120
+ assets: defineTable({
121
+ assetId: v.string(),
122
+ filename: v.string(),
123
+ contentType: v.string(),
124
+ byteSize: v.number(),
125
+ width: v.optional(v.number()),
126
+ height: v.optional(v.number()),
127
+ alt: v.optional(v.string()),
128
+ /** Editable display title (EC-152; persisted for parity with in-memory — EC-153). */
129
+ title: v.optional(v.string()),
130
+ storageKey: v.string(),
131
+ /** Stable serve URL resolved from Convex file storage on upload (EC-151). */
132
+ url: v.optional(v.string()),
133
+ /** Normalized image focal point `{ x, y }` in 0–1 (EC-230); CSS object-position. */
134
+ focalPoint: v.optional(v.object({ x: v.number(), y: v.number() })),
135
+ createdAt: v.string(),
136
+ updatedAt: v.string(),
137
+ }).index('by_asset', ['assetId']),
138
+
139
+ /**
140
+ * Reference index entries (EC-155, vision AD-6) — derived data, recomputed
141
+ * replace-all-for-source on every write. Indexed for efficient lookup in both
142
+ * directions: outbound ("what does X reference") via `by_source`, inbound
143
+ * ("what references X") via `by_target`.
144
+ */
145
+ referenceEntries: defineTable({
146
+ variant: v.union(v.literal('draft'), v.literal('published')),
147
+ sourceType: v.union(v.literal('document'), v.literal('page'), v.literal('layout')),
148
+ sourceId: v.string(),
149
+ /** Exact field/node path inside the source, e.g. `values/author`. */
150
+ path: v.string(),
151
+ targetType: v.union(v.literal('document'), v.literal('component'), v.literal('asset')),
152
+ targetId: v.string(),
153
+ /** Which reference-bearing structure produced the entry. */
154
+ kind: v.string(),
155
+ })
156
+ // `by_source` also serves source-type prefix scans (the graph recompute path).
157
+ .index('by_source', ['variant', 'sourceType', 'sourceId'])
158
+ .index('by_target', ['targetType', 'targetId', 'variant']),
159
+
160
+ /**
161
+ * Publishing state (EC-045). Single-environment (EC-179, vision AD-8): a
162
+ * deployment IS one environment, so this is a single-row table — no
163
+ * `environment`, no index.
164
+ */
165
+ publishingState: defineTable({
166
+ status: v.union(v.literal('draft'), v.literal('published')),
167
+ publishedRevisionId: v.optional(v.string()),
168
+ publishedRevision: v.optional(v.number()),
169
+ publishedAt: v.optional(v.string()),
170
+ createdAt: v.string(),
171
+ updatedAt: v.string(),
172
+ }),
173
+ })