@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.
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/convex/assets.ts +107 -0
- package/convex/auth.config.ts +15 -0
- package/convex/auth.ts +50 -0
- package/convex/cliTokens.ts +63 -0
- package/convex/cms.ts +174 -0
- package/convex/content.ts +316 -0
- package/convex/delivery.ts +266 -0
- package/convex/functions.ts +35 -0
- package/convex/graphs.ts +51 -0
- package/convex/guard.ts +67 -0
- package/convex/http.ts +30 -0
- package/convex/members.ts +83 -0
- package/convex/publishing.ts +102 -0
- package/convex/references.ts +168 -0
- package/convex/schema.ts +173 -0
- package/convex/sync.ts +322 -0
- package/convex/tsconfig.json +12 -0
- package/convex/users.ts +23 -0
- package/convex/webhooks.ts +85 -0
- package/dist/components/assets/asset-library.d.ts +14 -0
- package/dist/components/assets/asset-library.js +191 -0
- package/dist/components/assets/asset-library.js.map +1 -0
- package/dist/components/assets/asset-metadata.d.ts +34 -0
- package/dist/components/assets/asset-metadata.js +40 -0
- package/dist/components/assets/asset-metadata.js.map +1 -0
- package/dist/components/assets/asset-search.d.ts +7 -0
- package/dist/components/assets/asset-search.js +12 -0
- package/dist/components/assets/asset-search.js.map +1 -0
- package/dist/components/assets/asset-selection.d.ts +17 -0
- package/dist/components/assets/asset-selection.js +33 -0
- package/dist/components/assets/asset-selection.js.map +1 -0
- package/dist/components/assets/assets-store.d.ts +51 -0
- package/dist/components/assets/assets-store.js +153 -0
- package/dist/components/assets/assets-store.js.map +1 -0
- package/dist/components/auth-context.d.ts +38 -0
- package/dist/components/auth-context.js +88 -0
- package/dist/components/auth-context.js.map +1 -0
- package/dist/components/backend-gate.d.ts +19 -0
- package/dist/components/backend-gate.js +63 -0
- package/dist/components/backend-gate.js.map +1 -0
- package/dist/components/breadcrumb-context.d.ts +39 -0
- package/dist/components/breadcrumb-context.js +38 -0
- package/dist/components/breadcrumb-context.js.map +1 -0
- package/dist/components/builder/blocks-model.d.ts +80 -0
- package/dist/components/builder/blocks-model.js +181 -0
- package/dist/components/builder/blocks-model.js.map +1 -0
- package/dist/components/builder/blocks-panel.d.ts +44 -0
- package/dist/components/builder/blocks-panel.js +147 -0
- package/dist/components/builder/blocks-panel.js.map +1 -0
- package/dist/components/builder/builder-store.d.ts +69 -0
- package/dist/components/builder/builder-store.js +294 -0
- package/dist/components/builder/builder-store.js.map +1 -0
- package/dist/components/builder/canvas-stylesheet.d.ts +4 -0
- package/dist/components/builder/canvas-stylesheet.js +24 -0
- package/dist/components/builder/canvas-stylesheet.js.map +1 -0
- package/dist/components/builder/canvas.d.ts +8 -0
- package/dist/components/builder/canvas.js +723 -0
- package/dist/components/builder/canvas.js.map +1 -0
- package/dist/components/builder/clipboard-actions.d.ts +93 -0
- package/dist/components/builder/clipboard-actions.js +246 -0
- package/dist/components/builder/clipboard-actions.js.map +1 -0
- package/dist/components/builder/composition-field-editor.d.ts +11 -0
- package/dist/components/builder/composition-field-editor.js +150 -0
- package/dist/components/builder/composition-field-editor.js.map +1 -0
- package/dist/components/builder/composition-scope.d.ts +16 -0
- package/dist/components/builder/composition-scope.js +7 -0
- package/dist/components/builder/composition-scope.js.map +1 -0
- package/dist/components/builder/drag-session.d.ts +41 -0
- package/dist/components/builder/drag-session.js +51 -0
- package/dist/components/builder/drag-session.js.map +1 -0
- package/dist/components/builder/fixture-thumbnail.d.ts +18 -0
- package/dist/components/builder/fixture-thumbnail.js +97 -0
- package/dist/components/builder/fixture-thumbnail.js.map +1 -0
- package/dist/components/builder/inline-edit.d.ts +142 -0
- package/dist/components/builder/inline-edit.js +136 -0
- package/dist/components/builder/inline-edit.js.map +1 -0
- package/dist/components/builder/insert-context.d.ts +14 -0
- package/dist/components/builder/insert-context.js +65 -0
- package/dist/components/builder/insert-context.js.map +1 -0
- package/dist/components/builder/insert-menu.d.ts +9 -0
- package/dist/components/builder/insert-menu.js +9 -0
- package/dist/components/builder/insert-menu.js.map +1 -0
- package/dist/components/builder/layout-inspector.d.ts +14 -0
- package/dist/components/builder/layout-inspector.js +84 -0
- package/dist/components/builder/layout-inspector.js.map +1 -0
- package/dist/components/builder/node-factory.d.ts +17 -0
- package/dist/components/builder/node-factory.js +90 -0
- package/dist/components/builder/node-factory.js.map +1 -0
- package/dist/components/builder/page-tree.d.ts +3 -0
- package/dist/components/builder/page-tree.js +207 -0
- package/dist/components/builder/page-tree.js.map +1 -0
- package/dist/components/builder/property-inspector.d.ts +1 -0
- package/dist/components/builder/property-inspector.js +233 -0
- package/dist/components/builder/property-inspector.js.map +1 -0
- package/dist/components/builder/rich-text-toolbar.d.ts +4 -0
- package/dist/components/builder/rich-text-toolbar.js +104 -0
- package/dist/components/builder/rich-text-toolbar.js.map +1 -0
- package/dist/components/builder/spacing-handles.d.ts +22 -0
- package/dist/components/builder/spacing-handles.js +213 -0
- package/dist/components/builder/spacing-handles.js.map +1 -0
- package/dist/components/cms/asset-picker.d.ts +12 -0
- package/dist/components/cms/asset-picker.js +60 -0
- package/dist/components/cms/asset-picker.js.map +1 -0
- package/dist/components/cms/bulk-actions.d.ts +60 -0
- package/dist/components/cms/bulk-actions.js +95 -0
- package/dist/components/cms/bulk-actions.js.map +1 -0
- package/dist/components/cms/bulk-bar.d.ts +23 -0
- package/dist/components/cms/bulk-bar.js +26 -0
- package/dist/components/cms/bulk-bar.js.map +1 -0
- package/dist/components/cms/cell-edit.d.ts +91 -0
- package/dist/components/cms/cell-edit.js +144 -0
- package/dist/components/cms/cell-edit.js.map +1 -0
- package/dist/components/cms/cell.d.ts +29 -0
- package/dist/components/cms/cell.js +127 -0
- package/dist/components/cms/cell.js.map +1 -0
- package/dist/components/cms/cms-index.d.ts +8 -0
- package/dist/components/cms/cms-index.js +23 -0
- package/dist/components/cms/cms-index.js.map +1 -0
- package/dist/components/cms/cms-store.d.ts +188 -0
- package/dist/components/cms/cms-store.js +702 -0
- package/dist/components/cms/cms-store.js.map +1 -0
- package/dist/components/cms/collection-table.d.ts +6 -0
- package/dist/components/cms/collection-table.js +250 -0
- package/dist/components/cms/collection-table.js.map +1 -0
- package/dist/components/cms/collections-sidebar.d.ts +9 -0
- package/dist/components/cms/collections-sidebar.js +25 -0
- package/dist/components/cms/collections-sidebar.js.map +1 -0
- package/dist/components/cms/detail-editor.d.ts +7 -0
- package/dist/components/cms/detail-editor.js +386 -0
- package/dist/components/cms/detail-editor.js.map +1 -0
- package/dist/components/cms/doc-state.d.ts +13 -0
- package/dist/components/cms/doc-state.js +18 -0
- package/dist/components/cms/doc-state.js.map +1 -0
- package/dist/components/cms/document-editor-context.d.ts +48 -0
- package/dist/components/cms/document-editor-context.js +23 -0
- package/dist/components/cms/document-editor-context.js.map +1 -0
- package/dist/components/cms/editable-cell.d.ts +22 -0
- package/dist/components/cms/editable-cell.js +176 -0
- package/dist/components/cms/editable-cell.js.map +1 -0
- package/dist/components/cms/field-control.d.ts +8 -0
- package/dist/components/cms/field-control.js +149 -0
- package/dist/components/cms/field-control.js.map +1 -0
- package/dist/components/cms/filter-builder.d.ts +12 -0
- package/dist/components/cms/filter-builder.js +84 -0
- package/dist/components/cms/filter-builder.js.map +1 -0
- package/dist/components/cms/import-export.d.ts +6 -0
- package/dist/components/cms/import-export.js +33 -0
- package/dist/components/cms/import-export.js.map +1 -0
- package/dist/components/cms/new-page-dialog.d.ts +22 -0
- package/dist/components/cms/new-page-dialog.js +42 -0
- package/dist/components/cms/new-page-dialog.js.map +1 -0
- package/dist/components/cms/reference-confirm.d.ts +25 -0
- package/dist/components/cms/reference-confirm.js +124 -0
- package/dist/components/cms/reference-confirm.js.map +1 -0
- package/dist/components/cms/relation-picker.d.ts +16 -0
- package/dist/components/cms/relation-picker.js +47 -0
- package/dist/components/cms/relation-picker.js.map +1 -0
- package/dist/components/cms/use-cell-edit.d.ts +33 -0
- package/dist/components/cms/use-cell-edit.js +125 -0
- package/dist/components/cms/use-cell-edit.js.map +1 -0
- package/dist/components/cms/versions-model.d.ts +15 -0
- package/dist/components/cms/versions-model.js +23 -0
- package/dist/components/cms/versions-model.js.map +1 -0
- package/dist/components/cms/versions-pane.d.ts +14 -0
- package/dist/components/cms/versions-pane.js +86 -0
- package/dist/components/cms/versions-pane.js.map +1 -0
- package/dist/components/cms/view-bar.d.ts +11 -0
- package/dist/components/cms/view-bar.js +80 -0
- package/dist/components/cms/view-bar.js.map +1 -0
- package/dist/components/collab/collab-context.d.ts +34 -0
- package/dist/components/collab/collab-context.js +52 -0
- package/dist/components/collab/collab-context.js.map +1 -0
- package/dist/components/collab/collab-seed.d.ts +27 -0
- package/dist/components/collab/collab-seed.js +42 -0
- package/dist/components/collab/collab-seed.js.map +1 -0
- package/dist/components/components/component-detail.d.ts +9 -0
- package/dist/components/components/component-detail.js +30 -0
- package/dist/components/components/component-detail.js.map +1 -0
- package/dist/components/components/component-status.d.ts +10 -0
- package/dist/components/components/component-status.js +30 -0
- package/dist/components/components/component-status.js.map +1 -0
- package/dist/components/components/components-index.d.ts +8 -0
- package/dist/components/components/components-index.js +42 -0
- package/dist/components/components/components-index.js.map +1 -0
- package/dist/components/components/field-inspector.d.ts +9 -0
- package/dist/components/components/field-inspector.js +38 -0
- package/dist/components/components/field-inspector.js.map +1 -0
- package/dist/components/components/fixture-runner.d.ts +10 -0
- package/dist/components/components/fixture-runner.js +24 -0
- package/dist/components/components/fixture-runner.js.map +1 -0
- package/dist/components/components/registry-browser.d.ts +4 -0
- package/dist/components/components/registry-browser.js +64 -0
- package/dist/components/components/registry-browser.js.map +1 -0
- package/dist/components/current-user-menu.d.ts +13 -0
- package/dist/components/current-user-menu.js +31 -0
- package/dist/components/current-user-menu.js.map +1 -0
- package/dist/components/dev-login-badge.d.ts +9 -0
- package/dist/components/dev-login-badge.js +18 -0
- package/dist/components/dev-login-badge.js.map +1 -0
- package/dist/components/extensions/extensions-view.d.ts +7 -0
- package/dist/components/extensions/extensions-view.js +126 -0
- package/dist/components/extensions/extensions-view.js.map +1 -0
- package/dist/components/guards.d.ts +27 -0
- package/dist/components/guards.js +46 -0
- package/dist/components/guards.js.map +1 -0
- package/dist/components/inspector/inspector-sidebar.d.ts +26 -0
- package/dist/components/inspector/inspector-sidebar.js +17 -0
- package/dist/components/inspector/inspector-sidebar.js.map +1 -0
- package/dist/components/operation-error.d.ts +17 -0
- package/dist/components/operation-error.js +54 -0
- package/dist/components/operation-error.js.map +1 -0
- package/dist/components/playground-badge.d.ts +10 -0
- package/dist/components/playground-badge.js +19 -0
- package/dist/components/playground-badge.js.map +1 -0
- package/dist/components/project-list.d.ts +15 -0
- package/dist/components/project-list.js +52 -0
- package/dist/components/project-list.js.map +1 -0
- package/dist/components/project-session.d.ts +46 -0
- package/dist/components/project-session.js +107 -0
- package/dist/components/project-session.js.map +1 -0
- package/dist/components/project-switcher.d.ts +11 -0
- package/dist/components/project-switcher.js +44 -0
- package/dist/components/project-switcher.js.map +1 -0
- package/dist/components/references/builder-deep-link.d.ts +12 -0
- package/dist/components/references/builder-deep-link.js +53 -0
- package/dist/components/references/builder-deep-link.js.map +1 -0
- package/dist/components/references/references-panel.d.ts +17 -0
- package/dist/components/references/references-panel.js +66 -0
- package/dist/components/references/references-panel.js.map +1 -0
- package/dist/components/routes/redirect-chain.d.ts +9 -0
- package/dist/components/routes/redirect-chain.js +16 -0
- package/dist/components/routes/redirect-chain.js.map +1 -0
- package/dist/components/routes/redirect-manager.d.ts +13 -0
- package/dist/components/routes/redirect-manager.js +24 -0
- package/dist/components/routes/redirect-manager.js.map +1 -0
- package/dist/components/routes/route-list.d.ts +35 -0
- package/dist/components/routes/route-list.js +69 -0
- package/dist/components/routes/route-list.js.map +1 -0
- package/dist/components/routes/routes-shell.d.ts +14 -0
- package/dist/components/routes/routes-shell.js +68 -0
- package/dist/components/routes/routes-shell.js.map +1 -0
- package/dist/components/section-nav.d.ts +17 -0
- package/dist/components/section-nav.js +33 -0
- package/dist/components/section-nav.js.map +1 -0
- package/dist/components/section-state.d.ts +24 -0
- package/dist/components/section-state.js +78 -0
- package/dist/components/section-state.js.map +1 -0
- package/dist/components/section-surface.d.ts +31 -0
- package/dist/components/section-surface.js +46 -0
- package/dist/components/section-surface.js.map +1 -0
- package/dist/components/sections.d.ts +38 -0
- package/dist/components/sections.js +72 -0
- package/dist/components/sections.js.map +1 -0
- package/dist/components/settings-form.d.ts +10 -0
- package/dist/components/settings-form.js +17 -0
- package/dist/components/settings-form.js.map +1 -0
- package/dist/components/studio-context.d.ts +22 -0
- package/dist/components/studio-context.js +48 -0
- package/dist/components/studio-context.js.map +1 -0
- package/dist/components/studio-project-screen.d.ts +19 -0
- package/dist/components/studio-project-screen.js +195 -0
- package/dist/components/studio-project-screen.js.map +1 -0
- package/dist/components/studio-shell.d.ts +18 -0
- package/dist/components/studio-shell.js +64 -0
- package/dist/components/studio-shell.js.map +1 -0
- package/dist/components/theme-context.d.ts +17 -0
- package/dist/components/theme-context.js +26 -0
- package/dist/components/theme-context.js.map +1 -0
- package/dist/components/workspace-gate.d.ts +12 -0
- package/dist/components/workspace-gate.js +27 -0
- package/dist/components/workspace-gate.js.map +1 -0
- package/dist/components/workspace-projects.d.ts +13 -0
- package/dist/components/workspace-projects.js +18 -0
- package/dist/components/workspace-projects.js.map +1 -0
- package/dist/lib/assets/delete-asset.d.ts +34 -0
- package/dist/lib/assets/delete-asset.js +34 -0
- package/dist/lib/assets/delete-asset.js.map +1 -0
- package/dist/lib/assets/image-dimensions.d.ts +18 -0
- package/dist/lib/assets/image-dimensions.js +26 -0
- package/dist/lib/assets/image-dimensions.js.map +1 -0
- package/dist/lib/assets/index.d.ts +9 -0
- package/dist/lib/assets/index.js +10 -0
- package/dist/lib/assets/index.js.map +1 -0
- package/dist/lib/assets/upload-state.d.ts +53 -0
- package/dist/lib/assets/upload-state.js +59 -0
- package/dist/lib/assets/upload-state.js.map +1 -0
- package/dist/lib/assets/upload.d.ts +56 -0
- package/dist/lib/assets/upload.js +125 -0
- package/dist/lib/assets/upload.js.map +1 -0
- package/dist/lib/auth/auth-adapter.d.ts +57 -0
- package/dist/lib/auth/auth-adapter.js +13 -0
- package/dist/lib/auth/auth-adapter.js.map +1 -0
- package/dist/lib/auth/convex-auth-adapter.d.ts +39 -0
- package/dist/lib/auth/convex-auth-adapter.js +171 -0
- package/dist/lib/auth/convex-auth-adapter.js.map +1 -0
- package/dist/lib/auth/dev-auto-login-adapter.d.ts +25 -0
- package/dist/lib/auth/dev-auto-login-adapter.js +40 -0
- package/dist/lib/auth/dev-auto-login-adapter.js.map +1 -0
- package/dist/lib/auth/index.d.ts +28 -0
- package/dist/lib/auth/index.js +61 -0
- package/dist/lib/auth/index.js.map +1 -0
- package/dist/lib/auth/local-auth-adapter.d.ts +57 -0
- package/dist/lib/auth/local-auth-adapter.js +78 -0
- package/dist/lib/auth/local-auth-adapter.js.map +1 -0
- package/dist/lib/auth/route-guard.d.ts +33 -0
- package/dist/lib/auth/route-guard.js +51 -0
- package/dist/lib/auth/route-guard.js.map +1 -0
- package/dist/lib/auth-errors.d.ts +42 -0
- package/dist/lib/auth-errors.js +74 -0
- package/dist/lib/auth-errors.js.map +1 -0
- package/dist/lib/bindings/section-bindings.d.ts +24 -0
- package/dist/lib/bindings/section-bindings.js +9 -0
- package/dist/lib/bindings/section-bindings.js.map +1 -0
- package/dist/lib/clipboard/index.d.ts +7 -0
- package/dist/lib/clipboard/index.js +8 -0
- package/dist/lib/clipboard/index.js.map +1 -0
- package/dist/lib/clipboard/os-clipboard.d.ts +46 -0
- package/dist/lib/clipboard/os-clipboard.js +105 -0
- package/dist/lib/clipboard/os-clipboard.js.map +1 -0
- package/dist/lib/clipboard/paste-issues.d.ts +34 -0
- package/dist/lib/clipboard/paste-issues.js +67 -0
- package/dist/lib/clipboard/paste-issues.js.map +1 -0
- package/dist/lib/clipboard/paste-target.d.ts +20 -0
- package/dist/lib/clipboard/paste-target.js +28 -0
- package/dist/lib/clipboard/paste-target.js.map +1 -0
- package/dist/lib/cms/published-documents.d.ts +30 -0
- package/dist/lib/cms/published-documents.js +75 -0
- package/dist/lib/cms/published-documents.js.map +1 -0
- package/dist/lib/cms-views/index.d.ts +9 -0
- package/dist/lib/cms-views/index.js +10 -0
- package/dist/lib/cms-views/index.js.map +1 -0
- package/dist/lib/cms-views/selection.d.ts +29 -0
- package/dist/lib/cms-views/selection.js +46 -0
- package/dist/lib/cms-views/selection.js.map +1 -0
- package/dist/lib/cms-views/view-model.d.ts +192 -0
- package/dist/lib/cms-views/view-model.js +353 -0
- package/dist/lib/cms-views/view-model.js.map +1 -0
- package/dist/lib/cms-views/views-store.d.ts +70 -0
- package/dist/lib/cms-views/views-store.js +129 -0
- package/dist/lib/cms-views/views-store.js.map +1 -0
- package/dist/lib/data/collection-content.d.ts +105 -0
- package/dist/lib/data/collection-content.js +196 -0
- package/dist/lib/data/collection-content.js.map +1 -0
- package/dist/lib/data/data-store.d.ts +97 -0
- package/dist/lib/data/data-store.js +205 -0
- package/dist/lib/data/data-store.js.map +1 -0
- package/dist/lib/data/index.d.ts +4 -0
- package/dist/lib/data/index.js +8 -0
- package/dist/lib/data/index.js.map +1 -0
- package/dist/lib/data/providers.d.ts +143 -0
- package/dist/lib/data/providers.js +255 -0
- package/dist/lib/data/providers.js.map +1 -0
- package/dist/lib/data/sample-capture.d.ts +30 -0
- package/dist/lib/data/sample-capture.js +70 -0
- package/dist/lib/data/sample-capture.js.map +1 -0
- package/dist/lib/data/sources-store.d.ts +42 -0
- package/dist/lib/data/sources-store.js +120 -0
- package/dist/lib/data/sources-store.js.map +1 -0
- package/dist/lib/dnd/drop-rules.d.ts +219 -0
- package/dist/lib/dnd/drop-rules.js +257 -0
- package/dist/lib/dnd/drop-rules.js.map +1 -0
- package/dist/lib/dnd/gap-drag.d.ts +66 -0
- package/dist/lib/dnd/gap-drag.js +95 -0
- package/dist/lib/dnd/gap-drag.js.map +1 -0
- package/dist/lib/locale/binding-fallback.d.ts +28 -0
- package/dist/lib/locale/binding-fallback.js +66 -0
- package/dist/lib/locale/binding-fallback.js.map +1 -0
- package/dist/lib/locale/fallback.d.ts +43 -0
- package/dist/lib/locale/fallback.js +52 -0
- package/dist/lib/locale/fallback.js.map +1 -0
- package/dist/lib/locale/index.d.ts +6 -0
- package/dist/lib/locale/index.js +7 -0
- package/dist/lib/locale/index.js.map +1 -0
- package/dist/lib/locale/locale-store.d.ts +40 -0
- package/dist/lib/locale/locale-store.js +61 -0
- package/dist/lib/locale/locale-store.js.map +1 -0
- package/dist/lib/locale/locale-switcher.d.ts +10 -0
- package/dist/lib/locale/locale-switcher.js +24 -0
- package/dist/lib/locale/locale-switcher.js.map +1 -0
- package/dist/lib/locale/route-variant.d.ts +14 -0
- package/dist/lib/locale/route-variant.js +11 -0
- package/dist/lib/locale/route-variant.js.map +1 -0
- package/dist/lib/locale/use-studio-locale.d.ts +10 -0
- package/dist/lib/locale/use-studio-locale.js +8 -0
- package/dist/lib/locale/use-studio-locale.js.map +1 -0
- package/dist/lib/operations/asset-repository.d.ts +15 -0
- package/dist/lib/operations/asset-repository.js +56 -0
- package/dist/lib/operations/asset-repository.js.map +1 -0
- package/dist/lib/operations/cms-persistence.d.ts +35 -0
- package/dist/lib/operations/cms-persistence.js +75 -0
- package/dist/lib/operations/cms-persistence.js.map +1 -0
- package/dist/lib/operations/graph-commands.d.ts +140 -0
- package/dist/lib/operations/graph-commands.js +86 -0
- package/dist/lib/operations/graph-commands.js.map +1 -0
- package/dist/lib/operations/graph-persistence.d.ts +27 -0
- package/dist/lib/operations/graph-persistence.js +35 -0
- package/dist/lib/operations/graph-persistence.js.map +1 -0
- package/dist/lib/operations/index.d.ts +13 -0
- package/dist/lib/operations/index.js +14 -0
- package/dist/lib/operations/index.js.map +1 -0
- package/dist/lib/operations/operations-package.d.ts +6 -0
- package/dist/lib/operations/operations-package.js +7 -0
- package/dist/lib/operations/operations-package.js.map +1 -0
- package/dist/lib/operations/persist-queue.d.ts +16 -0
- package/dist/lib/operations/persist-queue.js +18 -0
- package/dist/lib/operations/persist-queue.js.map +1 -0
- package/dist/lib/operations/session-hydration.d.ts +84 -0
- package/dist/lib/operations/session-hydration.js +112 -0
- package/dist/lib/operations/session-hydration.js.map +1 -0
- package/dist/lib/operations/studio-operations.d.ts +59 -0
- package/dist/lib/operations/studio-operations.js +92 -0
- package/dist/lib/operations/studio-operations.js.map +1 -0
- package/dist/lib/persistence/backend-mode.d.ts +69 -0
- package/dist/lib/persistence/backend-mode.js +120 -0
- package/dist/lib/persistence/backend-mode.js.map +1 -0
- package/dist/lib/persistence/convex-adapter.d.ts +34 -0
- package/dist/lib/persistence/convex-adapter.js +681 -0
- package/dist/lib/persistence/convex-adapter.js.map +1 -0
- package/dist/lib/persistence/convex-blob-storage.d.ts +57 -0
- package/dist/lib/persistence/convex-blob-storage.js +97 -0
- package/dist/lib/persistence/convex-blob-storage.js.map +1 -0
- package/dist/lib/persistence/convex-client.d.ts +19 -0
- package/dist/lib/persistence/convex-client.js +40 -0
- package/dist/lib/persistence/convex-client.js.map +1 -0
- package/dist/lib/persistence/index.d.ts +30 -0
- package/dist/lib/persistence/index.js +60 -0
- package/dist/lib/persistence/index.js.map +1 -0
- package/dist/lib/persona/labels.d.ts +23 -0
- package/dist/lib/persona/labels.js +122 -0
- package/dist/lib/persona/labels.js.map +1 -0
- package/dist/lib/rail.d.ts +11 -0
- package/dist/lib/rail.js +26 -0
- package/dist/lib/rail.js.map +1 -0
- package/dist/lib/references/impact.d.ts +64 -0
- package/dist/lib/references/impact.js +62 -0
- package/dist/lib/references/impact.js.map +1 -0
- package/dist/lib/references/index.d.ts +7 -0
- package/dist/lib/references/index.js +8 -0
- package/dist/lib/references/index.js.map +1 -0
- package/dist/lib/references/reference-model.d.ts +125 -0
- package/dist/lib/references/reference-model.js +242 -0
- package/dist/lib/references/reference-model.js.map +1 -0
- package/dist/lib/references/references-store.d.ts +65 -0
- package/dist/lib/references/references-store.js +221 -0
- package/dist/lib/references/references-store.js.map +1 -0
- package/dist/lib/registry/index.d.ts +65 -0
- package/dist/lib/registry/index.js +114 -0
- package/dist/lib/registry/index.js.map +1 -0
- package/dist/lib/registry/preview.d.ts +15 -0
- package/dist/lib/registry/preview.js +110 -0
- package/dist/lib/registry/preview.js.map +1 -0
- package/dist/lib/registry/project-components.d.ts +16 -0
- package/dist/lib/registry/project-components.js +152 -0
- package/dist/lib/registry/project-components.js.map +1 -0
- package/dist/lib/routing/index.d.ts +10 -0
- package/dist/lib/routing/index.js +11 -0
- package/dist/lib/routing/index.js.map +1 -0
- package/dist/lib/routing/routing-analysis.d.ts +26 -0
- package/dist/lib/routing/routing-analysis.js +37 -0
- package/dist/lib/routing/routing-analysis.js.map +1 -0
- package/dist/lib/routing/routing-store.d.ts +50 -0
- package/dist/lib/routing/routing-store.js +72 -0
- package/dist/lib/routing/routing-store.js.map +1 -0
- package/dist/lib/starters/kit-session.d.ts +5 -0
- package/dist/lib/starters/kit-session.js +17 -0
- package/dist/lib/starters/kit-session.js.map +1 -0
- package/dist/lib/theme.d.ts +21 -0
- package/dist/lib/theme.js +32 -0
- package/dist/lib/theme.js.map +1 -0
- package/dist/lib/utils.d.ts +11 -0
- package/dist/lib/utils.js +28 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/webhooks/config.d.ts +15 -0
- package/dist/lib/webhooks/config.js +64 -0
- package/dist/lib/webhooks/config.js.map +1 -0
- package/dist/lib/webhooks/dispatcher.d.ts +67 -0
- package/dist/lib/webhooks/dispatcher.js +61 -0
- package/dist/lib/webhooks/dispatcher.js.map +1 -0
- package/dist/lib/webhooks/index.d.ts +11 -0
- package/dist/lib/webhooks/index.js +10 -0
- package/dist/lib/webhooks/index.js.map +1 -0
- package/dist/lib/webhooks/signing.d.ts +15 -0
- package/dist/lib/webhooks/signing.js +24 -0
- package/dist/lib/webhooks/signing.js.map +1 -0
- package/dist/lib/webhooks/tags.d.ts +25 -0
- package/dist/lib/webhooks/tags.js +173 -0
- package/dist/lib/webhooks/tags.js.map +1 -0
- package/dist/lib/working-graph.d.ts +82 -0
- package/dist/lib/working-graph.js +113 -0
- package/dist/lib/working-graph.js.map +1 -0
- package/dist/lib/workspace/index.d.ts +109 -0
- package/dist/lib/workspace/index.js +206 -0
- package/dist/lib/workspace/index.js.map +1 -0
- package/dist/lib/workspace/switcher-source.d.ts +39 -0
- package/dist/lib/workspace/switcher-source.js +23 -0
- package/dist/lib/workspace/switcher-source.js.map +1 -0
- package/dist/lib/workspace/workspace-source.d.ts +47 -0
- package/dist/lib/workspace/workspace-source.js +67 -0
- package/dist/lib/workspace/workspace-source.js.map +1 -0
- package/dist/router/index.d.ts +32 -0
- package/dist/router/index.js +32 -0
- package/dist/router/index.js.map +1 -0
- package/dist/router/match.d.ts +75 -0
- package/dist/router/match.js +87 -0
- package/dist/router/match.js.map +1 -0
- package/dist/router/search.d.ts +22 -0
- package/dist/router/search.js +16 -0
- package/dist/router/search.js.map +1 -0
- package/dist/ui/avatar.d.ts +17 -0
- package/dist/ui/avatar.js +38 -0
- package/dist/ui/avatar.js.map +1 -0
- package/dist/ui/badge.d.ts +9 -0
- package/dist/ui/badge.js +23 -0
- package/dist/ui/badge.js.map +1 -0
- package/dist/ui/button.d.ts +11 -0
- package/dist/ui/button.js +30 -0
- package/dist/ui/button.js.map +1 -0
- package/dist/ui/card.d.ts +11 -0
- package/dist/ui/card.js +23 -0
- package/dist/ui/card.js.map +1 -0
- package/dist/ui/dialog.d.ts +12 -0
- package/dist/ui/dialog.js +27 -0
- package/dist/ui/dialog.js.map +1 -0
- package/dist/ui/dropdown-menu.d.ts +15 -0
- package/dist/ui/dropdown-menu.js +24 -0
- package/dist/ui/dropdown-menu.js.map +1 -0
- package/dist/ui/field.d.ts +15 -0
- package/dist/ui/field.js +14 -0
- package/dist/ui/field.js.map +1 -0
- package/dist/ui/index.d.ts +14 -0
- package/dist/ui/index.js +15 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/input.d.ts +3 -0
- package/dist/ui/input.js +7 -0
- package/dist/ui/input.js.map +1 -0
- package/dist/ui/inspector.d.ts +18 -0
- package/dist/ui/inspector.js +14 -0
- package/dist/ui/inspector.js.map +1 -0
- package/dist/ui/layout.d.ts +45 -0
- package/dist/ui/layout.js +48 -0
- package/dist/ui/layout.js.map +1 -0
- package/dist/ui/panel.d.ts +12 -0
- package/dist/ui/panel.js +20 -0
- package/dist/ui/panel.js.map +1 -0
- package/dist/ui/separator.d.ts +6 -0
- package/dist/ui/separator.js +7 -0
- package/dist/ui/separator.js.map +1 -0
- package/dist/ui/toolbar.d.ts +9 -0
- package/dist/ui/toolbar.js +16 -0
- package/dist/ui/toolbar.js.map +1 -0
- package/dist/ui/typography.d.ts +50 -0
- package/dist/ui/typography.js +43 -0
- package/dist/ui/typography.js.map +1 -0
- package/package.json +149 -0
- package/src/styles/studio.css +101 -0
- 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
|
package/convex/graphs.ts
ADDED
|
@@ -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
|
+
})
|