@elytracms/studio 0.0.92 → 0.0.94
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/convex/analytics-cost.test.ts +817 -0
- package/convex/asset-alt-migration.test.ts +127 -0
- package/convex/asset-replace.test.ts +168 -0
- package/convex/asset-revalidate.test.ts +6 -6
- package/convex/assets.ts +41 -5
- package/convex/auth.ts +5 -2
- package/convex/authority.ts +35 -11
- package/convex/cms.ts +25 -11
- package/convex/contract-parity.test.ts +25 -3
- package/convex/delivery.ts +12 -9
- package/convex/document-revalidate.test.ts +10 -12
- package/convex/guard.ts +9 -7
- package/convex/http-routes.test.ts +18 -8
- package/convex/http.ts +23 -17
- package/convex/ingest.test.ts +326 -0
- package/convex/ingest.ts +281 -0
- package/convex/invites.ts +13 -5
- package/convex/members.ts +10 -4
- package/convex/orphan-hydration.test.ts +116 -0
- package/convex/rail-write-parity.test.ts +11 -8
- package/convex/record-functions.ts +325 -0
- package/convex/records.test.ts +156 -0
- package/convex/redirect-migration.test.ts +205 -0
- package/convex/redirect-revalidate.test.ts +5 -1
- package/convex/redirects.ts +120 -79
- package/convex/role-policy.test.ts +315 -0
- package/convex/roles.ts +83 -0
- package/convex/schema.ts +36 -0
- package/convex/triggers.ts +21 -1
- package/dist/addon.d.ts +71 -0
- package/dist/addon.js +67 -0
- package/dist/addon.js.map +1 -0
- package/dist/components/account/account-settings.js +2 -2
- package/dist/components/account/account-settings.js.map +1 -1
- package/dist/components/account/credential-panel.js +2 -2
- package/dist/components/account/credential-panel.js.map +1 -1
- package/dist/components/account/self-account-schema.d.ts +6 -15
- package/dist/components/account/self-account-schema.js +52 -34
- package/dist/components/account/self-account-schema.js.map +1 -1
- package/dist/components/account/self-account-view-source.d.ts +1 -1
- package/dist/components/account/self-account-view-source.js +6 -4
- package/dist/components/account/self-account-view-source.js.map +1 -1
- package/dist/components/ai/ai-chat-panel-lazy.js +1 -1
- package/dist/components/ai/ai-chat-panel-lazy.js.map +1 -1
- package/dist/components/ai/ai-chat-panel.js +6 -6
- package/dist/components/ai/ai-chat-panel.js.map +1 -1
- package/dist/components/ai/ai-cms-panel.js +2 -2
- package/dist/components/ai/ai-cms-panel.js.map +1 -1
- package/dist/components/ai/ai-panel-toggle.js +4 -4
- package/dist/components/ai/ai-panel-toggle.js.map +1 -1
- package/dist/components/ai/chat-ui.js +2 -2
- package/dist/components/ai/chat-ui.js.map +1 -1
- package/dist/components/ai/proposal-card.d.ts +2 -2
- package/dist/components/ai/proposal-card.js +4 -3
- package/dist/components/ai/proposal-card.js.map +1 -1
- package/dist/components/ai/proposal-issues.js +2 -2
- package/dist/components/ai/proposal-issues.js.map +1 -1
- package/dist/components/ai/translate-document-action.js +2 -2
- package/dist/components/ai/translate-document-action.js.map +1 -1
- package/dist/components/ai/translate-document-dialog.js +10 -8
- package/dist/components/ai/translate-document-dialog.js.map +1 -1
- package/dist/components/ai/translate-skipped.d.ts +19 -0
- package/dist/components/ai/translate-skipped.js +46 -0
- package/dist/components/ai/translate-skipped.js.map +1 -0
- package/dist/components/app-views/default-modules.d.ts +50 -2
- package/dist/components/app-views/default-modules.js +65 -20
- package/dist/components/app-views/default-modules.js.map +1 -1
- package/dist/components/app-views/module.d.ts +53 -3
- package/dist/components/app-views/module.js +14 -7
- package/dist/components/app-views/module.js.map +1 -1
- package/dist/components/app-views/sidebar.js +1 -1
- package/dist/components/app-views/sidebar.js.map +1 -1
- package/dist/components/app-views/studio-config.d.ts +11 -2
- package/dist/components/app-views/studio-config.js.map +1 -1
- package/dist/components/assets/asset-detail.js +20 -10
- package/dist/components/assets/asset-detail.js.map +1 -1
- package/dist/components/assets/asset-grid.js +2 -2
- package/dist/components/assets/asset-grid.js.map +1 -1
- package/dist/components/assets/asset-metadata.d.ts +15 -4
- package/dist/components/assets/asset-metadata.js +15 -2
- package/dist/components/assets/asset-metadata.js.map +1 -1
- package/dist/components/assets/asset-search.js +4 -1
- package/dist/components/assets/asset-search.js.map +1 -1
- package/dist/components/assets/asset-selection.d.ts +0 -8
- package/dist/components/assets/asset-selection.js +4 -23
- package/dist/components/assets/asset-selection.js.map +1 -1
- package/dist/components/assets/asset-thumb.js +6 -5
- package/dist/components/assets/asset-thumb.js.map +1 -1
- package/dist/components/assets/assets-collection-view-source.d.ts +5 -5
- package/dist/components/assets/assets-collection-view-source.js +9 -5
- package/dist/components/assets/assets-collection-view-source.js.map +1 -1
- package/dist/components/assets/assets-module.js +1 -1
- package/dist/components/assets/assets-module.js.map +1 -1
- package/dist/components/assets/assets-store.d.ts +16 -2
- package/dist/components/assets/assets-store.js +28 -6
- package/dist/components/assets/assets-store.js.map +1 -1
- package/dist/components/assets/assets-view-preference.js +1 -1
- package/dist/components/assets/assets-view-preference.js.map +1 -1
- package/dist/components/assets/replace-file.d.ts +22 -0
- package/dist/components/assets/replace-file.js +59 -0
- package/dist/components/assets/replace-file.js.map +1 -0
- package/dist/components/auth-context.d.ts +1 -1
- package/dist/components/auth-context.js +6 -6
- package/dist/components/auth-context.js.map +1 -1
- package/dist/components/builder/blocks-model.d.ts +15 -27
- package/dist/components/builder/blocks-model.js +38 -44
- package/dist/components/builder/blocks-model.js.map +1 -1
- package/dist/components/builder/blocks-panel.d.ts +8 -4
- package/dist/components/builder/blocks-panel.js +10 -9
- package/dist/components/builder/blocks-panel.js.map +1 -1
- package/dist/components/builder/builder-store.d.ts +104 -15
- package/dist/components/builder/builder-store.js +157 -32
- package/dist/components/builder/builder-store.js.map +1 -1
- package/dist/components/builder/canvas-body.d.ts +30 -0
- package/dist/components/builder/canvas-body.js +38 -0
- package/dist/components/builder/canvas-body.js.map +1 -0
- package/dist/components/builder/canvas-breakpoints.js +1 -1
- package/dist/components/builder/canvas-breakpoints.js.map +1 -1
- package/dist/components/builder/canvas-chrome-css.js +7 -0
- package/dist/components/builder/canvas-chrome-css.js.map +1 -1
- package/dist/components/builder/canvas-dnd.d.ts +9 -9
- package/dist/components/builder/canvas-dnd.js +6 -6
- package/dist/components/builder/canvas-dnd.js.map +1 -1
- package/dist/components/builder/canvas-inline-editing.d.ts +1 -1
- package/dist/components/builder/canvas-inline-editing.js.map +1 -1
- package/dist/components/builder/canvas-overlay-geometry.d.ts +1 -1
- package/dist/components/builder/canvas-overlay-geometry.js.map +1 -1
- package/dist/components/builder/canvas-render-context.d.ts +28 -20
- package/dist/components/builder/canvas-render-context.js +46 -47
- package/dist/components/builder/canvas-render-context.js.map +1 -1
- package/dist/components/builder/canvas-runs.d.ts +45 -0
- package/dist/components/builder/canvas-runs.js +51 -0
- package/dist/components/builder/canvas-runs.js.map +1 -0
- package/dist/components/builder/canvas-theme-notice.js +2 -2
- package/dist/components/builder/canvas-theme-notice.js.map +1 -1
- package/dist/components/builder/canvas.js +35 -8
- package/dist/components/builder/canvas.js.map +1 -1
- package/dist/components/builder/clipboard-actions.d.ts +16 -1
- package/dist/components/builder/clipboard-actions.js +48 -11
- package/dist/components/builder/clipboard-actions.js.map +1 -1
- package/dist/components/builder/composition-field-editor-lazy.js +1 -1
- package/dist/components/builder/composition-field-editor-lazy.js.map +1 -1
- package/dist/components/builder/composition-field-editor.d.ts +4 -16
- package/dist/components/builder/composition-field-editor.js +32 -43
- package/dist/components/builder/composition-field-editor.js.map +1 -1
- package/dist/components/builder/delete-key.d.ts +5 -0
- package/dist/components/builder/delete-key.js +4 -0
- package/dist/components/builder/delete-key.js.map +1 -1
- package/dist/components/builder/drag-session.d.ts +1 -1
- package/dist/components/builder/drag-session.js.map +1 -1
- package/dist/components/builder/fixture-thumbnail.js +1 -1
- package/dist/components/builder/fixture-thumbnail.js.map +1 -1
- package/dist/components/builder/insert-context.d.ts +18 -26
- package/dist/components/builder/insert-context.js +47 -94
- package/dist/components/builder/insert-context.js.map +1 -1
- package/dist/components/builder/layout-inspector.js +1 -1
- package/dist/components/builder/layout-inspector.js.map +1 -1
- package/dist/components/builder/node-title.js +1 -1
- package/dist/components/builder/node-title.js.map +1 -1
- package/dist/components/builder/page-tree.d.ts +4 -4
- package/dist/components/builder/page-tree.js +8 -8
- package/dist/components/builder/page-tree.js.map +1 -1
- package/dist/components/builder/placement-refusal.d.ts +18 -0
- package/dist/components/builder/placement-refusal.js +46 -0
- package/dist/components/builder/placement-refusal.js.map +1 -0
- package/dist/components/builder/property-inspector.js +8 -4
- package/dist/components/builder/property-inspector.js.map +1 -1
- package/dist/components/builder/reuse-context.js +68 -30
- package/dist/components/builder/reuse-context.js.map +1 -1
- package/dist/components/builder/reuse.d.ts +79 -1
- package/dist/components/builder/reuse.js +70 -3
- package/dist/components/builder/reuse.js.map +1 -1
- package/dist/components/builder/rich-text-toolbar.js +1 -1
- package/dist/components/builder/rich-text-toolbar.js.map +1 -1
- package/dist/components/builder/run-inspector.d.ts +11 -0
- package/dist/components/builder/run-inspector.js +33 -0
- package/dist/components/builder/run-inspector.js.map +1 -0
- package/dist/components/builder/selection-overlay.js +3 -3
- package/dist/components/builder/selection-overlay.js.map +1 -1
- package/dist/components/builder/spacing-handles.d.ts +2 -2
- package/dist/components/builder/spacing-handles.js +3 -3
- package/dist/components/builder/spacing-handles.js.map +1 -1
- package/dist/components/cms/asset-field.d.ts +38 -1
- package/dist/components/cms/asset-field.js +184 -60
- package/dist/components/cms/asset-field.js.map +1 -1
- package/dist/components/cms/asset-picker-core.d.ts +16 -0
- package/dist/components/cms/asset-picker-core.js +20 -0
- package/dist/components/cms/asset-picker-core.js.map +1 -1
- package/dist/components/cms/asset-picker.js +14 -20
- package/dist/components/cms/asset-picker.js.map +1 -1
- package/dist/components/cms/bulk-actions.d.ts +4 -20
- package/dist/components/cms/bulk-actions.js +5 -26
- package/dist/components/cms/bulk-actions.js.map +1 -1
- package/dist/components/cms/bulk-bar.d.ts +2 -2
- package/dist/components/cms/bulk-bar.js +2 -2
- package/dist/components/cms/bulk-bar.js.map +1 -1
- package/dist/components/cms/cell-edit.d.ts +1 -1
- package/dist/components/cms/cell-edit.js +1 -1
- package/dist/components/cms/cell-edit.js.map +1 -1
- package/dist/components/cms/cell.d.ts +1 -1
- package/dist/components/cms/cell.js +3 -3
- package/dist/components/cms/cell.js.map +1 -1
- package/dist/components/cms/cms-index.js +2 -2
- package/dist/components/cms/cms-index.js.map +1 -1
- package/dist/components/cms/cms-labels.js +2 -2
- package/dist/components/cms/cms-labels.js.map +1 -1
- package/dist/components/cms/cms-store.d.ts +7 -6
- package/dist/components/cms/cms-store.js +23 -43
- package/dist/components/cms/cms-store.js.map +1 -1
- package/dist/components/cms/collection-table.js +7 -7
- package/dist/components/cms/collection-table.js.map +1 -1
- package/dist/components/cms/detail-editor.d.ts +5 -2
- package/dist/components/cms/detail-editor.js +20 -15
- package/dist/components/cms/detail-editor.js.map +1 -1
- package/dist/components/cms/details-pane.js +1 -1
- package/dist/components/cms/details-pane.js.map +1 -1
- package/dist/components/cms/doc-state.js +1 -1
- package/dist/components/cms/doc-state.js.map +1 -1
- package/dist/components/cms/document-diff-view.d.ts +3 -1
- package/dist/components/cms/document-diff-view.js +17 -12
- package/dist/components/cms/document-diff-view.js.map +1 -1
- package/dist/components/cms/document-editor-context.js +1 -1
- package/dist/components/cms/document-editor-context.js.map +1 -1
- package/dist/components/cms/document-staging.js +1 -1
- package/dist/components/cms/document-staging.js.map +1 -1
- package/dist/components/cms/document-url-path.js +2 -2
- package/dist/components/cms/document-url-path.js.map +1 -1
- package/dist/components/cms/duplicate-document.d.ts +1 -1
- package/dist/components/cms/duplicate-document.js.map +1 -1
- package/dist/components/cms/editable-cell.js +3 -3
- package/dist/components/cms/editable-cell.js.map +1 -1
- package/dist/components/cms/field-anchors.d.ts +7 -4
- package/dist/components/cms/field-anchors.js +9 -7
- package/dist/components/cms/field-anchors.js.map +1 -1
- package/dist/components/cms/field-collaboration.d.ts +1 -1
- package/dist/components/cms/field-collaboration.js +1 -1
- package/dist/components/cms/field-collaboration.js.map +1 -1
- package/dist/components/cms/field-connection.d.ts +1 -1
- package/dist/components/cms/field-connection.js +2 -2
- package/dist/components/cms/field-connection.js.map +1 -1
- package/dist/components/cms/field-control-lib.d.ts +15 -1
- package/dist/components/cms/field-control-lib.js +23 -4
- package/dist/components/cms/field-control-lib.js.map +1 -1
- package/dist/components/cms/field-control.js +4 -4
- package/dist/components/cms/field-control.js.map +1 -1
- package/dist/components/cms/field-renderer.d.ts +1 -1
- package/dist/components/cms/field-renderer.js +2 -2
- package/dist/components/cms/field-renderer.js.map +1 -1
- package/dist/components/cms/filter-builder.d.ts +1 -1
- package/dist/components/cms/filter-builder.js +3 -3
- package/dist/components/cms/filter-builder.js.map +1 -1
- package/dist/components/cms/gate-validation.d.ts +21 -30
- package/dist/components/cms/gate-validation.js +11 -32
- package/dist/components/cms/gate-validation.js.map +1 -1
- package/dist/components/cms/import-export.js +2 -2
- package/dist/components/cms/import-export.js.map +1 -1
- package/dist/components/cms/issue-copy.js +1 -1
- package/dist/components/cms/issue-copy.js.map +1 -1
- package/dist/components/cms/issues-pane.js +3 -3
- package/dist/components/cms/issues-pane.js.map +1 -1
- package/dist/components/cms/object-array-field.js +6 -6
- package/dist/components/cms/object-array-field.js.map +1 -1
- package/dist/components/cms/prop-fields.d.ts +7 -2
- package/dist/components/cms/prop-fields.js +14 -7
- package/dist/components/cms/prop-fields.js.map +1 -1
- package/dist/components/cms/reference-confirm.d.ts +1 -1
- package/dist/components/cms/reference-confirm.js +2 -2
- package/dist/components/cms/reference-confirm.js.map +1 -1
- package/dist/components/cms/relation-picker.js +2 -2
- package/dist/components/cms/relation-picker.js.map +1 -1
- package/dist/components/cms/rich-text/block-style.js +1 -1
- package/dist/components/cms/rich-text/block-style.js.map +1 -1
- package/dist/components/cms/rich-text/component-embed.js +4 -4
- package/dist/components/cms/rich-text/component-embed.js.map +1 -1
- package/dist/components/cms/rich-text/editor.js +3 -3
- package/dist/components/cms/rich-text/editor.js.map +1 -1
- package/dist/components/cms/rich-text/embed-picker.d.ts +1 -1
- package/dist/components/cms/rich-text/embed-picker.js +3 -3
- package/dist/components/cms/rich-text/embed-picker.js.map +1 -1
- package/dist/components/cms/rich-text/embed-props.js +3 -3
- package/dist/components/cms/rich-text/embed-props.js.map +1 -1
- package/dist/components/cms/rich-text/extensions.js +1 -1
- package/dist/components/cms/rich-text/extensions.js.map +1 -1
- package/dist/components/cms/rich-text/font-size-control.d.ts +1 -1
- package/dist/components/cms/rich-text/font-size-control.js +2 -2
- package/dist/components/cms/rich-text/font-size-control.js.map +1 -1
- package/dist/components/cms/rich-text/insert.d.ts +20 -9
- package/dist/components/cms/rich-text/insert.js +25 -17
- package/dist/components/cms/rich-text/insert.js.map +1 -1
- package/dist/components/cms/rich-text/lazy.js +1 -1
- package/dist/components/cms/rich-text/lazy.js.map +1 -1
- package/dist/components/cms/rich-text/link-control.js +2 -2
- package/dist/components/cms/rich-text/link-control.js.map +1 -1
- package/dist/components/cms/rich-text/slash-command.js +3 -3
- package/dist/components/cms/rich-text/slash-command.js.map +1 -1
- package/dist/components/cms/rich-text/toolbar.js +1 -1
- package/dist/components/cms/rich-text/toolbar.js.map +1 -1
- package/dist/components/cms/rich-text/unknown-node.js +2 -2
- package/dist/components/cms/rich-text/unknown-node.js.map +1 -1
- package/dist/components/cms/rich-text-preview.js +2 -2
- package/dist/components/cms/rich-text-preview.js.map +1 -1
- package/dist/components/cms/row-actions.d.ts +1 -1
- package/dist/components/cms/row-actions.js.map +1 -1
- package/dist/components/cms/scalar-value-editor.d.ts +1 -1
- package/dist/components/cms/scalar-value-editor.js +2 -2
- package/dist/components/cms/scalar-value-editor.js.map +1 -1
- package/dist/components/cms/use-discard-controller.d.ts +1 -1
- package/dist/components/cms/use-discard-controller.js +1 -1
- package/dist/components/cms/use-discard-controller.js.map +1 -1
- package/dist/components/cms/use-document-draft.d.ts +7 -1
- package/dist/components/cms/use-document-draft.js +16 -2
- package/dist/components/cms/use-document-draft.js.map +1 -1
- package/dist/components/cms/use-document-versions.js +1 -1
- package/dist/components/cms/use-document-versions.js.map +1 -1
- package/dist/components/cms/use-field-focus.d.ts +1 -1
- package/dist/components/cms/use-field-focus.js +2 -2
- package/dist/components/cms/use-field-focus.js.map +1 -1
- package/dist/components/cms/use-live-url.d.ts +1 -1
- package/dist/components/cms/use-live-url.js +3 -3
- package/dist/components/cms/use-live-url.js.map +1 -1
- package/dist/components/cms/use-publish-controller.d.ts +2 -3
- package/dist/components/cms/use-publish-controller.js +8 -20
- package/dist/components/cms/use-publish-controller.js.map +1 -1
- package/dist/components/cms/use-published-perspective.d.ts +1 -1
- package/dist/components/cms/use-published-perspective.js.map +1 -1
- package/dist/components/cms/use-restore-version.d.ts +1 -1
- package/dist/components/cms/use-restore-version.js +1 -1
- package/dist/components/cms/use-restore-version.js.map +1 -1
- package/dist/components/cms/version-compare-lazy.js +1 -1
- package/dist/components/cms/version-compare-lazy.js.map +1 -1
- package/dist/components/cms/version-compare.js +1 -1
- package/dist/components/cms/version-compare.js.map +1 -1
- package/dist/components/cms/versions-pane.js +11 -4
- package/dist/components/cms/versions-pane.js.map +1 -1
- package/dist/components/cms/view-bar.js +3 -3
- package/dist/components/cms/view-bar.js.map +1 -1
- package/dist/components/collection-view/cms-collection-view-source.d.ts +1 -1
- package/dist/components/collection-view/cms-collection-view-source.js +5 -3
- package/dist/components/collection-view/cms-collection-view-source.js.map +1 -1
- package/dist/components/collection-view/collection-view-context.d.ts +1 -1
- package/dist/components/collection-view/collection-view-context.js +1 -1
- package/dist/components/collection-view/collection-view-context.js.map +1 -1
- package/dist/components/collection-view/collection-view-surface.d.ts +13 -0
- package/dist/components/collection-view/collection-view-surface.js +18 -0
- package/dist/components/collection-view/collection-view-surface.js.map +1 -0
- package/dist/components/components/component-detail.js +10 -10
- package/dist/components/components/component-detail.js.map +1 -1
- package/dist/components/components/component-preview.d.ts +2 -2
- package/dist/components/components/component-preview.js +5 -5
- package/dist/components/components/component-preview.js.map +1 -1
- package/dist/components/components/component-status.d.ts +1 -1
- package/dist/components/components/component-status.js +1 -1
- package/dist/components/components/component-status.js.map +1 -1
- package/dist/components/components/components-index.js +2 -2
- package/dist/components/components/components-index.js.map +1 -1
- package/dist/components/components/field-inspector.js +1 -1
- package/dist/components/components/field-inspector.js.map +1 -1
- package/dist/components/components/registry-browser.js +3 -3
- package/dist/components/components/registry-browser.js.map +1 -1
- package/dist/components/components/taxonomy.d.ts +1 -1
- package/dist/components/components/taxonomy.js.map +1 -1
- package/dist/components/components/transfer-dialog.js +4 -3
- package/dist/components/components/transfer-dialog.js.map +1 -1
- package/dist/components/components/transfer.d.ts +10 -10
- package/dist/components/components/transfer.js +13 -12
- package/dist/components/components/transfer.js.map +1 -1
- package/dist/components/current-user-menu.js +1 -1
- package/dist/components/current-user-menu.js.map +1 -1
- package/dist/components/delivery-health-banner.js +2 -2
- package/dist/components/delivery-health-banner.js.map +1 -1
- package/dist/components/deployment-setup-gate.js +3 -3
- package/dist/components/deployment-setup-gate.js.map +1 -1
- package/dist/components/dev-login-badge.js +2 -2
- package/dist/components/dev-login-badge.js.map +1 -1
- package/dist/components/guards.js +1 -1
- package/dist/components/guards.js.map +1 -1
- package/dist/components/inspector/document-panes.d.ts +54 -0
- package/dist/components/inspector/document-panes.js +41 -0
- package/dist/components/inspector/document-panes.js.map +1 -0
- package/dist/components/inspector/inspector-sidebar.js +1 -1
- package/dist/components/inspector/inspector-sidebar.js.map +1 -1
- package/dist/components/nav-issues-registry.d.ts +53 -0
- package/dist/components/nav-issues-registry.js +69 -0
- package/dist/components/nav-issues-registry.js.map +1 -0
- package/dist/components/nav-issues.js +4 -4
- package/dist/components/nav-issues.js.map +1 -1
- package/dist/components/operation-error.d.ts +1 -1
- package/dist/components/operation-error.js +4 -4
- package/dist/components/operation-error.js.map +1 -1
- package/dist/components/playground-badge.js +2 -2
- package/dist/components/playground-badge.js.map +1 -1
- package/dist/components/project-list.js +3 -3
- package/dist/components/project-list.js.map +1 -1
- package/dist/components/project-session.d.ts +2 -2
- package/dist/components/project-session.js +5 -5
- package/dist/components/project-session.js.map +1 -1
- package/dist/components/project-switcher.js +2 -2
- package/dist/components/project-switcher.js.map +1 -1
- package/dist/components/rail-store-status.js +1 -1
- package/dist/components/rail-store-status.js.map +1 -1
- package/dist/components/rail-view-source.d.ts +6 -5
- package/dist/components/rail-view-source.js +4 -3
- package/dist/components/rail-view-source.js.map +1 -1
- package/dist/components/records/record-lens.d.ts +51 -0
- package/dist/components/records/record-lens.js +156 -0
- package/dist/components/records/record-lens.js.map +1 -0
- package/dist/components/records/record-rail.d.ts +86 -0
- package/dist/components/records/record-rail.js +241 -0
- package/dist/components/records/record-rail.js.map +1 -0
- package/dist/components/redirects/redirects-schema.js +1 -1
- package/dist/components/redirects/redirects-schema.js.map +1 -1
- package/dist/components/references/references-panel.js +2 -2
- package/dist/components/references/references-panel.js.map +1 -1
- package/dist/components/section-nav.js +27 -11
- package/dist/components/section-nav.js.map +1 -1
- package/dist/components/section-state.js +2 -2
- package/dist/components/section-state.js.map +1 -1
- package/dist/components/section-surface.js +2 -2
- package/dist/components/section-surface.js.map +1 -1
- package/dist/components/session-expired-overlay.js +3 -3
- package/dist/components/session-expired-overlay.js.map +1 -1
- package/dist/components/settings-form.js +1 -1
- package/dist/components/settings-form.js.map +1 -1
- package/dist/components/sign-in-needed-badge.js +1 -1
- package/dist/components/sign-in-needed-badge.js.map +1 -1
- package/dist/components/sign-in-view.d.ts +2 -2
- package/dist/components/sign-in-view.js +5 -5
- package/dist/components/sign-in-view.js.map +1 -1
- package/dist/components/studio-context.js +3 -3
- package/dist/components/studio-context.js.map +1 -1
- package/dist/components/studio-project-screen.js +30 -3
- package/dist/components/studio-project-screen.js.map +1 -1
- package/dist/components/studio-shell.js +6 -5
- package/dist/components/studio-shell.js.map +1 -1
- package/dist/components/theme-context.d.ts +1 -1
- package/dist/components/theme-context.js +2 -2
- package/dist/components/theme-context.js.map +1 -1
- package/dist/components/use-hydration-phase.d.ts +1 -1
- package/dist/components/use-hydration-phase.js +1 -1
- package/dist/components/use-hydration-phase.js.map +1 -1
- package/dist/components/users/invite-user-bar.d.ts +27 -0
- package/dist/components/users/invite-user-bar.js +25 -9
- package/dist/components/users/invite-user-bar.js.map +1 -1
- package/dist/components/users/role-policy-drift-issues.d.ts +38 -0
- package/dist/components/users/role-policy-drift-issues.js +71 -0
- package/dist/components/users/role-policy-drift-issues.js.map +1 -0
- package/dist/components/users/users-collection-view-source.d.ts +1 -1
- package/dist/components/users/users-collection-view-source.js +4 -2
- package/dist/components/users/users-collection-view-source.js.map +1 -1
- package/dist/components/users/users-module.js +1 -1
- package/dist/components/users/users-module.js.map +1 -1
- package/dist/components/users/users-schema.d.ts +10 -1
- package/dist/components/users/users-schema.js +45 -25
- package/dist/components/users/users-schema.js.map +1 -1
- package/dist/components/users/users-store.js +3 -3
- package/dist/components/users/users-store.js.map +1 -1
- package/dist/components/workspace-projects.d.ts +1 -1
- package/dist/components/workspace-projects.js +1 -1
- package/dist/components/workspace-projects.js.map +1 -1
- package/dist/lib/ai/apply-content.js +56 -116
- package/dist/lib/ai/apply-content.js.map +1 -1
- package/dist/lib/ai/chat-context.d.ts +8 -0
- package/dist/lib/ai/chat-context.js +37 -6
- package/dist/lib/ai/chat-context.js.map +1 -1
- package/dist/lib/ai/chat-state.d.ts +6 -0
- package/dist/lib/ai/chat-state.js.map +1 -1
- package/dist/lib/ai/constraints.d.ts +20 -5
- package/dist/lib/ai/constraints.js +125 -33
- package/dist/lib/ai/constraints.js.map +1 -1
- package/dist/lib/ai/fake-provider.d.ts +16 -3
- package/dist/lib/ai/fake-provider.js +22 -6
- package/dist/lib/ai/fake-provider.js.map +1 -1
- package/dist/lib/ai/index.d.ts +3 -1
- package/dist/lib/ai/index.js +3 -1
- package/dist/lib/ai/index.js.map +1 -1
- package/dist/lib/ai/leash.d.ts +34 -0
- package/dist/lib/ai/leash.js +28 -0
- package/dist/lib/ai/leash.js.map +1 -0
- package/dist/lib/ai/node-handler.d.ts +1 -1
- package/dist/lib/ai/node-handler.js.map +1 -1
- package/dist/lib/ai/rich-text-input.d.ts +8 -8
- package/dist/lib/ai/rich-text-input.js +2 -1
- package/dist/lib/ai/rich-text-input.js.map +1 -1
- package/dist/lib/ai/rich-text-translate.d.ts +27 -4
- package/dist/lib/ai/rich-text-translate.js +28 -10
- package/dist/lib/ai/rich-text-translate.js.map +1 -1
- package/dist/lib/ai/shape.d.ts +13 -13
- package/dist/lib/ai/shape.js +69 -93
- package/dist/lib/ai/shape.js.map +1 -1
- package/dist/lib/ai/tools.d.ts +36 -41
- package/dist/lib/ai/tools.js +83 -87
- package/dist/lib/ai/tools.js.map +1 -1
- package/dist/lib/ai/translate-document.d.ts +32 -4
- package/dist/lib/ai/translate-document.js +145 -47
- package/dist/lib/ai/translate-document.js.map +1 -1
- package/dist/lib/ai/types.d.ts +34 -23
- package/dist/lib/ai/types.js.map +1 -1
- package/dist/lib/ai/update-fields.d.ts +15 -12
- package/dist/lib/ai/update-fields.js +112 -188
- package/dist/lib/ai/update-fields.js.map +1 -1
- package/dist/lib/ai/writer-form.d.ts +116 -0
- package/dist/lib/ai/writer-form.js +429 -0
- package/dist/lib/ai/writer-form.js.map +1 -0
- package/dist/lib/assets/upload.d.ts +31 -2
- package/dist/lib/assets/upload.js +61 -6
- package/dist/lib/assets/upload.js.map +1 -1
- package/dist/lib/clipboard/os-clipboard.d.ts +10 -2
- package/dist/lib/clipboard/os-clipboard.js +8 -4
- package/dist/lib/clipboard/os-clipboard.js.map +1 -1
- package/dist/lib/clipboard/paste-issues.js +1 -1
- package/dist/lib/clipboard/paste-issues.js.map +1 -1
- package/dist/lib/clipboard/paste-target.d.ts +18 -9
- package/dist/lib/clipboard/paste-target.js +10 -9
- package/dist/lib/clipboard/paste-target.js.map +1 -1
- package/dist/lib/cms/field-patch.d.ts +0 -10
- package/dist/lib/cms/field-patch.js +4 -30
- package/dist/lib/cms/field-patch.js.map +1 -1
- package/dist/lib/cms/published-documents.js +1 -1
- package/dist/lib/cms/published-documents.js.map +1 -1
- package/dist/lib/cms-views/view-model.d.ts +9 -9
- package/dist/lib/cms-views/view-model.js +2 -2
- package/dist/lib/cms-views/view-model.js.map +1 -1
- package/dist/lib/collection-view/collection-view-source.d.ts +14 -5
- package/dist/lib/collection-view/collection-view-source.js.map +1 -1
- package/dist/lib/data/collection-content.js +3 -2
- package/dist/lib/data/collection-content.js.map +1 -1
- package/dist/lib/data/content-session-refresh.d.ts +1 -1
- package/dist/lib/data/content-session-refresh.js.map +1 -1
- package/dist/lib/data/playground-unload-guard.d.ts +1 -1
- package/dist/lib/data/playground-unload-guard.js +1 -1
- package/dist/lib/data/playground-unload-guard.js.map +1 -1
- package/dist/lib/dnd/drop-rules.d.ts +25 -31
- package/dist/lib/dnd/drop-rules.js +53 -59
- package/dist/lib/dnd/drop-rules.js.map +1 -1
- package/dist/lib/engine-version.d.ts +1 -1
- package/dist/lib/engine-version.js +1 -1
- package/dist/lib/engine-version.js.map +1 -1
- package/dist/lib/i18n/i18n.js +1 -1
- package/dist/lib/i18n/i18n.js.map +1 -1
- package/dist/lib/i18n/messages.de.js +44 -3
- package/dist/lib/i18n/messages.de.js.map +1 -1
- package/dist/lib/i18n/messages.en.d.ts +38 -2
- package/dist/lib/i18n/messages.en.js +51 -3
- package/dist/lib/i18n/messages.en.js.map +1 -1
- package/dist/lib/operations/project-runtime-config.d.ts +34 -6
- package/dist/lib/operations/project-runtime-config.js +50 -10
- package/dist/lib/operations/project-runtime-config.js.map +1 -1
- package/dist/lib/operations/publish-with-revision.d.ts +33 -1
- package/dist/lib/operations/publish-with-revision.js +32 -0
- package/dist/lib/operations/publish-with-revision.js.map +1 -1
- package/dist/lib/operations/runtime-validator.d.ts +19 -68
- package/dist/lib/operations/runtime-validator.js +12 -138
- package/dist/lib/operations/runtime-validator.js.map +1 -1
- package/dist/lib/operations/studio-operations.d.ts +17 -2
- package/dist/lib/operations/studio-operations.js +18 -11
- package/dist/lib/operations/studio-operations.js.map +1 -1
- package/dist/lib/persistence/convex-adapter.d.ts +16 -3
- package/dist/lib/persistence/convex-adapter.js +83 -47
- package/dist/lib/persistence/convex-adapter.js.map +1 -1
- package/dist/lib/persistence/index.js +14 -1
- package/dist/lib/persistence/index.js.map +1 -1
- package/dist/lib/persona/labels.js +4 -2
- package/dist/lib/persona/labels.js.map +1 -1
- package/dist/lib/query/operations-query.d.ts +1 -1
- package/dist/lib/query/operations-query.js +1 -1
- package/dist/lib/query/operations-query.js.map +1 -1
- package/dist/lib/references/reference-model.js +1 -1
- package/dist/lib/references/reference-model.js.map +1 -1
- package/dist/lib/references/references-store.js +1 -1
- package/dist/lib/references/references-store.js.map +1 -1
- package/dist/lib/workspace/index.d.ts +14 -11
- package/dist/lib/workspace/index.js +20 -24
- package/dist/lib/workspace/index.js.map +1 -1
- package/dist/mount.d.ts +28 -0
- package/dist/mount.js +27 -0
- package/dist/mount.js.map +1 -0
- package/dist/router/root.js +10 -10
- package/dist/router/root.js.map +1 -1
- package/dist/ui/badge.d.ts +1 -1
- package/dist/ui/button.d.ts +2 -2
- package/package.json +15 -11
- package/dist/components/cms/cms-composition-validators.d.ts +0 -16
- package/dist/components/cms/cms-composition-validators.js +0 -133
- package/dist/components/cms/cms-composition-validators.js.map +0 -1
- package/dist/components/cms/publish-clean.d.ts +0 -28
- package/dist/components/cms/publish-clean.js +0 -38
- package/dist/components/cms/publish-clean.js.map +0 -1
- package/dist/components/redirects/redirects-collection-view-source.d.ts +0 -53
- package/dist/components/redirects/redirects-collection-view-source.js +0 -146
- package/dist/components/redirects/redirects-collection-view-source.js.map +0 -1
- package/dist/components/redirects/redirects-module.d.ts +0 -21
- package/dist/components/redirects/redirects-module.js +0 -40
- package/dist/components/redirects/redirects-module.js.map +0 -1
- package/dist/components/redirects/redirects-store.d.ts +0 -68
- package/dist/components/redirects/redirects-store.js +0 -132
- package/dist/components/redirects/redirects-store.js.map +0 -1
- package/dist/lib/assets/asset-placements.d.ts +0 -28
- package/dist/lib/assets/asset-placements.js +0 -83
- package/dist/lib/assets/asset-placements.js.map +0 -1
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { activeDeploymentKey, selectPersistenceAdapter } from '../persistence/index.js';
|
|
2
|
-
import { resolveProjectCollections } from '../workspace/index.js';
|
|
3
2
|
import { attachSessionExpiryReporting } from '../session-expiry.js';
|
|
4
3
|
import { projectManifestLookup } from './config-manifest-lookup.js';
|
|
5
|
-
import { configProjectFor, projectLocaleConfig } from './project-runtime-config.js';
|
|
4
|
+
import { configProjectFor, projectCollections, projectComponentRegistry, projectLocaleConfig, projectRolePolicyFor, } from './project-runtime-config.js';
|
|
6
5
|
import { createRuntimeDocumentValidator } from './runtime-validator.js';
|
|
7
6
|
import { attachReferenceIndex, createChangesets, createOperations, createRoleAuthorization, summarizeInput, toOperationError, } from './operations-package.js';
|
|
8
7
|
/**
|
|
@@ -15,31 +14,38 @@ function noopReferenceIndexAttachment() {
|
|
|
15
14
|
}
|
|
16
15
|
/** Build a studio operations bundle over an adapter (exported for tests). */
|
|
17
16
|
export function createStudioOperations(adapter, options = {}) {
|
|
17
|
+
// EC-605: the role hook is built WITHOUT a fixed policy — it grants by the policy the
|
|
18
|
+
// runtime resolves for each operation's project (`rolePolicy` below), the same one the
|
|
19
|
+
// operation's roles were validated against: one injection point, not two copies.
|
|
18
20
|
const authorized = options.actor
|
|
19
21
|
? { actor: options.actor, authorize: createRoleAuthorization(adapter.members) }
|
|
20
22
|
: {};
|
|
21
23
|
// EC-583: the collections come from the config (never the store), per project id;
|
|
22
24
|
// EC-595 A1: so does the manifest lookup. Both ride the changesets runtime too.
|
|
23
|
-
|
|
25
|
+
// EC-585: every per-project fact below is read from ONE source — the config project
|
|
26
|
+
// with the operation's slug (`configProjectFor`): collections, manifests, locales.
|
|
27
|
+
const collections = options.collections ?? projectCollections;
|
|
28
|
+
const locales = options.locales ?? projectLocaleConfig;
|
|
29
|
+
const rolePolicy = options.rolePolicy ?? projectRolePolicyFor;
|
|
24
30
|
const idFactory = options.idFactory ? { idFactory: options.idFactory } : {};
|
|
25
31
|
const manifestLookup = options.manifestLookup ?? projectManifestLookup((projectId) => configProjectFor(projectId)?.components);
|
|
26
|
-
// EC-595 A2 (F23): the publish gate's validator is bound to THIS bundle —
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
// (`gateValidateOptions`, EC-497), loaded lazily so the registry behind the
|
|
31
|
-
// composition leashes stays out of this bootstrap's static graph.
|
|
32
|
+
// EC-595 A2 (F23) → EC-582: the publish gate's validator is bound to THIS bundle —
|
|
33
|
+
// core's canonical gate (`@elytracms/core/validation`) over the OPERATION's project:
|
|
34
|
+
// its collections, locales and component registry (never the active project's) +
|
|
35
|
+
// oracles prefetched through the adapter — never whichever CMS session is mounted.
|
|
32
36
|
const validateDocument = options.validateDocument ??
|
|
33
37
|
createRuntimeDocumentValidator({
|
|
34
38
|
collections,
|
|
35
|
-
localeConfig:
|
|
36
|
-
|
|
39
|
+
localeConfig: locales,
|
|
40
|
+
registry: projectComponentRegistry,
|
|
37
41
|
});
|
|
38
42
|
const operations = createOperations({
|
|
39
43
|
adapter,
|
|
40
44
|
collections,
|
|
41
45
|
validateDocument,
|
|
42
46
|
manifestLookup,
|
|
47
|
+
locales,
|
|
48
|
+
rolePolicy,
|
|
43
49
|
...idFactory,
|
|
44
50
|
...authorized,
|
|
45
51
|
});
|
|
@@ -60,6 +66,7 @@ export function createStudioOperations(adapter, options = {}) {
|
|
|
60
66
|
// runtime validator, prefetching through the step's own (scratch or real) adapter.
|
|
61
67
|
validateDocument,
|
|
62
68
|
manifestLookup,
|
|
69
|
+
locales,
|
|
63
70
|
...idFactory,
|
|
64
71
|
...authorized,
|
|
65
72
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"studio-operations.js","sourceRoot":"","sources":["../../../src/lib/operations/studio-operations.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AAC9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAA;AAChE,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAChF,OAAO,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAA;AACpE,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,EACvB,cAAc,EACd,gBAAgB,GACjB,MAAM,sBAAsB,CAAA;AA8F7B;;;;GAIG;AACH,SAAS,4BAA4B;IACnC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,EAAE,CAAA;AACpD,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,sBAAsB,CACpC,OAA2B,EAC3B,UAAyC,EAAE;IAE3C,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK;QAC9B,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,uBAAuB,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;QAC/E,CAAC,CAAC,EAAE,CAAA;IACN,kFAAkF;IAClF,gFAAgF;IAChF,MAAM,WAAW,GACf,OAAO,CAAC,WAAW,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,yBAAyB,CAAC,SAAS,CAAC,CAAC,CAAA;IAC9E,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC3E,MAAM,cAAc,GAClB,OAAO,CAAC,cAAc,IAAI,qBAAqB,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,EAAE,UAAU,CAAC,CAAA;IACzG,8EAA8E;IAC9E,iFAAiF;IACjF,sFAAsF;IACtF,gFAAgF;IAChF,4EAA4E;IAC5E,kEAAkE;IAClE,MAAM,gBAAgB,GACpB,OAAO,CAAC,gBAAgB;QACxB,8BAA8B,CAAC;YAC7B,WAAW;YACX,YAAY,EAAE,mBAAmB;YACjC,OAAO,EAAE,GAAG,EAAE,CACZ,MAAM,CAAC,sCAAsC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC;SAC9F,CAAC,CAAA;IACJ,MAAM,UAAU,GAAG,gBAAgB,CAAC;QAClC,OAAO;QACP,WAAW;QACX,gBAAgB;QAChB,cAAc;QACd,GAAG,SAAS;QACZ,GAAG,UAAU;KACd,CAAC,CAAA;IACF,mFAAmF;IACnF,gFAAgF;IAChF,gFAAgF;IAChF,kFAAkF;IAClF,+EAA+E;IAC/E,0EAA0E;IAC1E,MAAM,UAAU,GAAG,OAAO,CAAC,uBAAuB;QAChD,CAAC,CAAC,4BAA4B,EAAE;QAChC,CAAC,CAAC,oBAAoB,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACpD,MAAM,UAAU,GAAG,gBAAgB,CAAC;QAClC,OAAO;QACP,WAAW;QACX,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,iFAAiF;QACjF,mFAAmF;QACnF,gBAAgB;QAChB,cAAc;QACd,GAAG,SAAS;QACZ,GAAG,UAAU;KACd,CAAC,CAAA;IACF,iFAAiF;IACjF,8EAA8E;IAC9E,mFAAmF;IACnF,4EAA4E;IAC5E,+EAA+E;IAC/E,2EAA2E;IAC3E,+EAA+E;IAC/E,6EAA6E;IAC7E,mCAAmC;IACnC,4BAA4B,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;IAE/C,gGAAgG;IAChG,MAAM,aAAa,GAAG,CAAC,SAAiB,EAAE,KAAc,EAAE,KAAc,EAAE,EAAE;QAC1E,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC;YACrB,SAAS;YACT,MAAM,EAAE,WAAW;YACnB,IAAI,EAAE,OAAO;YACb,MAAM,EAAE,QAAQ;YAChB,YAAY,EAAE,cAAc,CAAC,KAAK,CAAC;YACnC,KAAK,EAAE,gBAAgB,CAAC,KAAK,CAAC;SAC/B,CAAC,CAAA;IACJ,CAAC,CAAA;IACD,OAAO;QACL,UAAU;QACV,UAAU;QACV,OAAO;QACP,UAAU;QACV,iBAAiB,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,CAC9C,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,SAAS,EAAE,GAAG,EAAE;YAC5C,UAAU,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC;YACvD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,aAAa,CAAC,qBAAqB,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,KAAK,CAAC,CAAA;gBAC/D,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAA;YAC3B,CAAC;SACF,CAAC;QACJ,cAAc,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE;YACjD,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,SAAS,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAA;YAC5D,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,aAAa,CAAC,oBAAoB,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,KAAK,CAAC,CAAA;gBAC9D,MAAM,KAAK,CAAA;YACb,CAAC;QACH,CAAC;QACD,aAAa,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,SAAS,EAAE,GAAG,EAAE,SAAS,CAAC;KACnG,CAAA;AACH,CAAC;AAED,gFAAgF;AAChF,gFAAgF;AAChF,2EAA2E;AAC3E,MAAM,aAAa,GAAG,IAAI,GAAG,EAAuC,CAAA;AACpE,MAAM,cAAc,GAAG,IAAI,GAAG,EAAqC,CAAA;AACnE,IAAI,YAAY,GAAqB,IAAI,CAAA;AAEzC;;;;;GAKG;AACH,SAAS,aAAa;IACpB,IAAI,CAAC;QACH,OAAO,mBAAmB,EAAE,CAAA;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,kBAAkB,CAAA;IAC3B,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,GAAW;IAC7B,IAAI,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACpC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,GAAG,wBAAwB,EAAE,CAAA;QACpC,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IACjC,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,GAAG,GAAG,aAAa,EAAE,CAAA;IAC3B,IAAI,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACtC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,KAAK,GAAG,YAAY,CAAA;QAC1B,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAC1C,sBAAsB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CACxD,CAAA;QACD,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAA;IACnC,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAuB;IACtD,IAAI,YAAY,EAAE,EAAE,KAAK,KAAK,EAAE,EAAE;QAAE,OAAM,CAAC,8CAA8C;IACzF,YAAY,GAAG,KAAK,CAAA;IACpB,cAAc,CAAC,KAAK,EAAE,CAAA;AACxB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,YAAY,CAAA;AACrB,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,2BAA2B,CAAC,IAA6B;IACvE,IAAI,IAAI,EAAE,CAAC;QACT,cAAc,CAAC,GAAG,CAAC,aAAa,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;QAC1D,OAAM;IACR,CAAC;IACD,cAAc,CAAC,KAAK,EAAE,CAAA;IACtB,aAAa,CAAC,KAAK,EAAE,CAAA;IACrB,YAAY,GAAG,IAAI,CAAA;AACrB,CAAC","sourcesContent":["import type {\n DocumentListener,\n IdFactory,\n PersistenceAdapter,\n PresenceInput,\n} from '@elytracms/core/persistence'\nimport type { DocumentRef } from '@elytracms/core/cms-core'\nimport { activeDeploymentKey, selectPersistenceAdapter } from '../persistence'\nimport { resolveProjectCollections } from '../workspace'\nimport { attachSessionExpiryReporting } from '../session-expiry'\nimport { projectManifestLookup } from './config-manifest-lookup'\nimport { configProjectFor, projectLocaleConfig } from './project-runtime-config'\nimport { createRuntimeDocumentValidator } from './runtime-validator'\nimport {\n attachReferenceIndex,\n createChangesets,\n createOperations,\n createRoleAuthorization,\n summarizeInput,\n toOperationError,\n} from './operations-package'\nimport type {\n ChangesetOperations,\n CollectionsResolver,\n DocumentValidator,\n ManifestLookupResolver,\n OperationsClient,\n Principal,\n ReferenceIndexAttachment,\n} from './operations-package'\n\n/**\n * The studio's single operations bootstrap (EC-141, vision AD-7).\n *\n * One `OperationsClient` + one `ChangesetOperations` instance, built over the\n * selected persistence adapter, shared by every store and surface in the app.\n * The UI never talks to a repository for writes — every mutation is a typed\n * operation command (validate → authorize → mutate → event), so the studio\n * dogfoods the same seam plugins, AI changesets, and the CLI use.\n *\n * The EC-155 reference index is attached to the shared event bus here, so any\n * document/graph/publishing command issued anywhere in the studio keeps the\n * index maintained.\n */\nexport interface StudioOperations {\n readonly operations: OperationsClient\n readonly changesets: ChangesetOperations\n /**\n * The raw adapter, exposed for *transport and read paths only*: blob byte\n * upload/download (`adapter.blobs`) and existing read stores. Studio code\n * must not call repository write methods on it — writes go through\n * `operations`.\n */\n readonly adapter: PersistenceAdapter\n /** EC-155 maintained-on-write index attachment (flushable in tests). */\n readonly references: ReferenceIndexAttachment\n /**\n * EC-595 binding point 7 — subscribe to ONE document (the narrow EC-309 slice): the\n * listener gets the current row + the presence on it, then one snapshot per change\n * (Convex: the reactive client's server push; playground: the in-memory store's own\n * writes). An adapter capability exposed through the in-process bundle — the UI never\n * holds a reactive Convex client. A subscription failure is ALSO emitted as a failed\n * `documents.subscribe` event on the operations bus, so an expired session reaches\n * EC-403's one session-expiry chokepoint like any failed operation (never a silently\n * stopped stream). Returns the unsubscribe function.\n */\n subscribeDocument(projectId: string, ref: DocumentRef, listener: DocumentListener): () => void\n /** EC-595 — this session's field-presence heartbeat on a document (thin presence, Stage A). */\n reportPresence(projectId: string, ref: DocumentRef, presence: PresenceInput): Promise<void>\n /** EC-595 — remove this session's presence from a document. */\n clearPresence(projectId: string, ref: DocumentRef, sessionId: string): Promise<void>\n}\n\nexport interface CreateStudioOperationsOptions {\n /**\n * The signed-in principal (EC-150). When present, the EC-150 role hook\n * (`createRoleAuthorization` over `adapter.members`) becomes the\n * authorization chokepoint for every command and query — viewers get\n * structured denials on mutations, editors on administration. Without an\n * actor the client runs pass-through (seeds, fixtures, tests that exercise\n * domain logic rather than permissions); the route guard keeps\n * unauthenticated users away from every operation surface.\n */\n actor?: Principal\n /**\n * EC-583 / EC-559 — the collection definitions on the operations context, resolved for\n * each operation's OWN project id. Defaults to the workspace config's project with that\n * slug (`resolveProjectCollections` — the resolved `elytra.config.ts`, functions\n * included), read on every call: the bundle is cached per deployment KEY (EC-179) and\n * one deployment may serve several config projects, so capturing one project's\n * collections at build time would canonicalise another project's documents against\n * them (operator correction to phase 1). The store holds no schema.\n */\n collections?: CollectionsResolver\n /** EC-578 — the document-id factory (`documents.create`); UUIDs by default. */\n idFactory?: IdFactory\n /**\n * EC-595 A1 (critic correction 4) → A2 — the manifest half of the write canonicaliser\n * on the operations context, resolved for each operation's OWN project. Defaults to a\n * lookup over that config project's component entries (`projectManifestLookup`), so\n * every patch / replace canonicalises a composition's props with its project's\n * manifests — never the active project's (A1 found-but-left #1).\n */\n manifestLookup?: ManifestLookupResolver\n /**\n * EC-595 A2 (F23) — the publish gate's validator, bound to THIS bundle. Defaults to\n * the runtime validator (`createRuntimeDocumentValidator`: the operation's project's\n * config + oracles prefetched through the adapter). Tests that pin persistence\n * routing rather than gate strength inject their own here — at construction, never\n * through a mount.\n */\n validateDocument?: DocumentValidator\n}\n\n/**\n * A no-op {@link ReferenceIndexAttachment} for self-maintaining adapters (EC-277):\n * nothing is subscribed, so `detach` and `flush` are trivially satisfied (the index\n * is kept current in the adapter's write path, not by a queued subscriber).\n */\nfunction noopReferenceIndexAttachment(): ReferenceIndexAttachment {\n return { detach: () => {}, flush: async () => {} }\n}\n\n/** Build a studio operations bundle over an adapter (exported for tests). */\nexport function createStudioOperations(\n adapter: PersistenceAdapter,\n options: CreateStudioOperationsOptions = {},\n): StudioOperations {\n const authorized = options.actor\n ? { actor: options.actor, authorize: createRoleAuthorization(adapter.members) }\n : {}\n // EC-583: the collections come from the config (never the store), per project id;\n // EC-595 A1: so does the manifest lookup. Both ride the changesets runtime too.\n const collections: CollectionsResolver =\n options.collections ?? ((projectId) => resolveProjectCollections(projectId))\n const idFactory = options.idFactory ? { idFactory: options.idFactory } : {}\n const manifestLookup =\n options.manifestLookup ?? projectManifestLookup((projectId) => configProjectFor(projectId)?.components)\n // EC-595 A2 (F23): the publish gate's validator is bound to THIS bundle — the\n // operation's project config + oracles prefetched through the adapter — never to\n // whichever CMS session happens to be mounted (the retired `lib/cms/document-gate.ts`\n // stack, where the innermost provider won). The option bag is the session's own\n // (`gateValidateOptions`, EC-497), loaded lazily so the registry behind the\n // composition leashes stays out of this bootstrap's static graph.\n const validateDocument =\n options.validateDocument ??\n createRuntimeDocumentValidator({\n collections,\n localeConfig: projectLocaleConfig,\n loadBag: () =>\n import('../../components/cms/gate-validation').then((module) => module.gateValidateOptions),\n })\n const operations = createOperations({\n adapter,\n collections,\n validateDocument,\n manifestLookup,\n ...idFactory,\n ...authorized,\n })\n // EC-277: when the adapter maintains the index in its own write path (AD-6 \"at the\n // source\" — the Convex provider does this server-side, so a raw `convex run` is\n // caught too), the client-side subscriber would only double the work. Attach it\n // ONLY for providers that don't self-maintain. Where it does run, extraction is a\n // schema-free, manifest-free walk over self-describing content, so it needs no\n // registry (compositions self-typed their relation/asset props on write).\n const references = adapter.maintainsReferenceIndex\n ? noopReferenceIndexAttachment()\n : attachReferenceIndex(operations.events, adapter)\n const changesets = createChangesets({\n adapter,\n collections,\n events: operations.events,\n // EC-497 / EC-595 A2: a changeset-driven publish is gated identically — the same\n // runtime validator, prefetching through the step's own (scratch or real) adapter.\n validateDocument,\n manifestLookup,\n ...idFactory,\n ...authorized,\n })\n // EC-579: no revalidation emitter attaches here. Host revalidation is a property\n // of the Convex write chokepoint (`convex/triggers.ts`), the one emitter — it\n // catches every writer, keeps the signing secret server-side, and the playground's\n // in-browser adapter is read by no host, so there is nothing to emit there.\n // EC-403: session-expiry detection rides the SAME lifecycle bus — every failed\n // command/query/changeset operation is checked against the session-expired\n // predicate here, so expiry raises the ONE app-level blocking re-auth state no\n // matter which surface issued the operation (per-surface banners can't cover\n // surfaces that render no banner).\n attachSessionExpiryReporting(operations.events)\n\n /** Report a capability failure on the bus (EC-403 sees an expiry like any failed operation). */\n const reportFailure = (operation: string, input: unknown, error: unknown) => {\n operations.events.emit({\n operation,\n domain: 'documents',\n kind: 'query',\n status: 'failed',\n inputSummary: summarizeInput(input),\n error: toOperationError(error),\n })\n }\n return {\n operations,\n changesets,\n adapter,\n references,\n subscribeDocument: (projectId, ref, listener) =>\n adapter.cms.subscribeDocument(projectId, ref, {\n onSnapshot: (snapshot) => listener.onSnapshot(snapshot),\n onError: (error) => {\n reportFailure('documents.subscribe', { projectId, ref }, error)\n listener.onError?.(error)\n },\n }),\n reportPresence: async (projectId, ref, presence) => {\n try {\n await adapter.cms.reportPresence(projectId, ref, presence)\n } catch (error) {\n reportFailure('documents.presence', { projectId, ref }, error)\n throw error\n }\n },\n clearPresence: (projectId, ref, sessionId) => adapter.cms.clearPresence(projectId, ref, sessionId),\n }\n}\n\n// One adapter + one operations bundle per backend (EC-179): keyed by the active\n// deployment so switching to a project on another Convex deployment selects (or\n// lazily builds) that backend's client, rather than reusing the first one.\nconst adaptersByKey = new Map<string, Promise<PersistenceAdapter>>()\nconst instancesByKey = new Map<string, Promise<StudioOperations>>()\nlet currentActor: Principal | null = null\n\n/**\n * The active backend key, tolerant of an unconfigured env: the real app never\n * reaches `getStudioOperations` while misconfigured (the `DeploymentSetupGate` renders a\n * boot error first), but tests inject a bundle directly via the seam below — so\n * a missing backend resolves to one stable key rather than throwing.\n */\nfunction deploymentKey(): string {\n try {\n return activeDeploymentKey()\n } catch {\n return '__unconfigured__'\n }\n}\n\nfunction getAdapter(key: string): Promise<PersistenceAdapter> {\n let adapter = adaptersByKey.get(key)\n if (!adapter) {\n adapter = selectPersistenceAdapter()\n adaptersByKey.set(key, adapter)\n }\n return adapter\n}\n\n/**\n * The shared studio operations client for the active backend (lazily\n * bootstrapped, cached per deployment). In-memory mode this owns the one seeded\n * adapter the whole session mutates; against Convex it owns one client per\n * deployment — the active project (EC-179) selects which.\n */\nexport function getStudioOperations(): Promise<StudioOperations> {\n const key = deploymentKey()\n let instance = instancesByKey.get(key)\n if (!instance) {\n const actor = currentActor\n instance = getAdapter(key).then((adapter) =>\n createStudioOperations(adapter, actor ? { actor } : {}),\n )\n instancesByKey.set(key, instance)\n }\n return instance\n}\n\n/**\n * Bind (or clear) the session principal (EC-150). Called by the auth context\n * on sign-in/sign-out. Rebuilds the operations clients over the *same* adapters\n * — the persisted state (and, in-memory, the whole session's edits) survives;\n * only the authorization identity changes. All cached backends are rebuilt so a\n * later switch picks up the new actor too.\n */\nexport function setStudioSession(actor: Principal | null): void {\n if (currentActor?.id === actor?.id) return // same user (or both null) — keep the clients\n currentActor = actor\n instancesByKey.clear()\n}\n\n/**\n * EC-595 A2 — the signed-in principal the operations clients act as (`null` signed out):\n * what this session's presence heartbeat names (\"X is in this field\") and how a conflict\n * tells \"you, in another tab\" from a colleague. Read-only; set by {@link setStudioSession}.\n */\nexport function getStudioActor(): Principal | null {\n return currentActor\n}\n\n/** Test seam: replace (or clear) the singleton for the active backend. */\nexport function setStudioOperationsForTests(next: StudioOperations | null): void {\n if (next) {\n instancesByKey.set(deploymentKey(), Promise.resolve(next))\n return\n }\n instancesByKey.clear()\n adaptersByKey.clear()\n currentActor = null\n}\n"]}
|
|
1
|
+
{"version":3,"file":"studio-operations.js","sourceRoot":"","sources":["../../../src/lib/operations/studio-operations.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DocumentListener,\n IdFactory,\n PersistenceAdapter,\n PresenceInput,\n} from '@elytracms/core/persistence'\nimport type { DocumentRef } from '@elytracms/core/cms-core'\nimport { activeDeploymentKey, selectPersistenceAdapter } from '../persistence'\nimport { attachSessionExpiryReporting } from '../session-expiry'\nimport { projectManifestLookup } from './config-manifest-lookup'\nimport {\n configProjectFor,\n projectCollections,\n projectComponentRegistry,\n projectLocaleConfig,\n projectRolePolicyFor,\n} from './project-runtime-config'\nimport { createRuntimeDocumentValidator } from './runtime-validator'\nimport {\n attachReferenceIndex,\n createChangesets,\n createOperations,\n createRoleAuthorization,\n summarizeInput,\n toOperationError,\n} from './operations-package'\nimport type {\n ChangesetOperations,\n CollectionsResolver,\n DocumentValidator,\n LocalesResolver,\n ManifestLookupResolver,\n OperationsClient,\n Principal,\n ReferenceIndexAttachment,\n RolePolicyResolver,\n} from './operations-package'\n\n/**\n * The studio's single operations bootstrap (EC-141, vision AD-7).\n *\n * One `OperationsClient` + one `ChangesetOperations` instance, built over the\n * selected persistence adapter, shared by every store and surface in the app.\n * The UI never talks to a repository for writes — every mutation is a typed\n * operation command (validate → authorize → mutate → event), so the studio\n * dogfoods the same seam plugins, AI changesets, and the CLI use.\n *\n * The EC-155 reference index is attached to the shared event bus here, so any\n * document/graph/publishing command issued anywhere in the studio keeps the\n * index maintained.\n */\nexport interface StudioOperations {\n readonly operations: OperationsClient\n readonly changesets: ChangesetOperations\n /**\n * The raw adapter, exposed for *transport and read paths only*: blob byte\n * upload/download (`adapter.blobs`) and existing read stores. Studio code\n * must not call repository write methods on it — writes go through\n * `operations`.\n */\n readonly adapter: PersistenceAdapter\n /** EC-155 maintained-on-write index attachment (flushable in tests). */\n readonly references: ReferenceIndexAttachment\n /**\n * EC-595 binding point 7 — subscribe to ONE document (the narrow EC-309 slice): the\n * listener gets the current row + the presence on it, then one snapshot per change\n * (Convex: the reactive client's server push; playground: the in-memory store's own\n * writes). An adapter capability exposed through the in-process bundle — the UI never\n * holds a reactive Convex client. A subscription failure is ALSO emitted as a failed\n * `documents.subscribe` event on the operations bus, so an expired session reaches\n * EC-403's one session-expiry chokepoint like any failed operation (never a silently\n * stopped stream). Returns the unsubscribe function.\n */\n subscribeDocument(projectId: string, ref: DocumentRef, listener: DocumentListener): () => void\n /** EC-595 — this session's field-presence heartbeat on a document (thin presence, Stage A). */\n reportPresence(projectId: string, ref: DocumentRef, presence: PresenceInput): Promise<void>\n /** EC-595 — remove this session's presence from a document. */\n clearPresence(projectId: string, ref: DocumentRef, sessionId: string): Promise<void>\n}\n\nexport interface CreateStudioOperationsOptions {\n /**\n * The signed-in principal (EC-150). When present, the EC-150 role hook\n * (`createRoleAuthorization` over `adapter.members`) becomes the\n * authorization chokepoint for every command and query — viewers get\n * structured denials on mutations, editors on administration. Without an\n * actor the client runs pass-through (seeds, fixtures, tests that exercise\n * domain logic rather than permissions); the route guard keeps\n * unauthenticated users away from every operation surface.\n */\n actor?: Principal\n /**\n * EC-583 / EC-559 — the collection definitions on the operations context, resolved for\n * each operation's OWN project id. Defaults to the workspace config's project with that\n * slug (`projectCollections` — the resolved `elytra.config.ts`, functions\n * included), read on every call: the bundle is cached per deployment KEY (EC-179) and\n * one deployment may serve several config projects, so capturing one project's\n * collections at build time would canonicalise another project's documents against\n * them (operator correction to phase 1). The store holds no schema.\n */\n collections?: CollectionsResolver\n /** EC-578 — the document-id factory (`documents.create`); UUIDs by default. */\n idFactory?: IdFactory\n /**\n * EC-595 A1 (critic correction 4) → A2 — the manifest half of the write canonicaliser\n * on the operations context, resolved for each operation's OWN project. Defaults to a\n * lookup over that config project's component entries (`projectManifestLookup`), so\n * every patch / replace canonicalises a composition's props with its project's\n * manifests — never the active project's (A1 found-but-left #1).\n */\n manifestLookup?: ManifestLookupResolver\n /**\n * EC-595 A2 (F23) — the publish gate's validator, bound to THIS bundle. Defaults to\n * the runtime validator (`createRuntimeDocumentValidator`: the operation's project's\n * config + oracles prefetched through the adapter). Tests that pin persistence\n * routing rather than gate strength inject their own here — at construction, never\n * through a mount.\n */\n validateDocument?: DocumentValidator\n /**\n * EC-585 — the locale config on the operations context, per project: the view\n * `documents.publish` runs its hidden-clear in. Defaults to that config project's\n * `locales` (`projectLocaleConfig`) — the same project, read the same way, as the\n * collections, the manifests and the gate's validator.\n */\n locales?: LocalesResolver\n /**\n * EC-605 — the role policy, per project: what a role an operation grants is validated\n * against and what the role hook (`createRoleAuthorization`, which reads it from the\n * runtime) grants by. Defaults to that config project's `roles` declaration\n * (`projectRolePolicyFor`; the default policy when it declares none) — read the same\n * way as the collections and locales.\n */\n rolePolicy?: RolePolicyResolver\n}\n\n/**\n * A no-op {@link ReferenceIndexAttachment} for self-maintaining adapters (EC-277):\n * nothing is subscribed, so `detach` and `flush` are trivially satisfied (the index\n * is kept current in the adapter's write path, not by a queued subscriber).\n */\nfunction noopReferenceIndexAttachment(): ReferenceIndexAttachment {\n return { detach: () => {}, flush: async () => {} }\n}\n\n/** Build a studio operations bundle over an adapter (exported for tests). */\nexport function createStudioOperations(\n adapter: PersistenceAdapter,\n options: CreateStudioOperationsOptions = {},\n): StudioOperations {\n // EC-605: the role hook is built WITHOUT a fixed policy — it grants by the policy the\n // runtime resolves for each operation's project (`rolePolicy` below), the same one the\n // operation's roles were validated against: one injection point, not two copies.\n const authorized = options.actor\n ? { actor: options.actor, authorize: createRoleAuthorization(adapter.members) }\n : {}\n // EC-583: the collections come from the config (never the store), per project id;\n // EC-595 A1: so does the manifest lookup. Both ride the changesets runtime too.\n // EC-585: every per-project fact below is read from ONE source — the config project\n // with the operation's slug (`configProjectFor`): collections, manifests, locales.\n const collections: CollectionsResolver = options.collections ?? projectCollections\n const locales: LocalesResolver = options.locales ?? projectLocaleConfig\n const rolePolicy: RolePolicyResolver = options.rolePolicy ?? projectRolePolicyFor\n const idFactory = options.idFactory ? { idFactory: options.idFactory } : {}\n const manifestLookup =\n options.manifestLookup ?? projectManifestLookup((projectId) => configProjectFor(projectId)?.components)\n // EC-595 A2 (F23) → EC-582: the publish gate's validator is bound to THIS bundle —\n // core's canonical gate (`@elytracms/core/validation`) over the OPERATION's project:\n // its collections, locales and component registry (never the active project's) +\n // oracles prefetched through the adapter — never whichever CMS session is mounted.\n const validateDocument =\n options.validateDocument ??\n createRuntimeDocumentValidator({\n collections,\n localeConfig: locales,\n registry: projectComponentRegistry,\n })\n const operations = createOperations({\n adapter,\n collections,\n validateDocument,\n manifestLookup,\n locales,\n rolePolicy,\n ...idFactory,\n ...authorized,\n })\n // EC-277: when the adapter maintains the index in its own write path (AD-6 \"at the\n // source\" — the Convex provider does this server-side, so a raw `convex run` is\n // caught too), the client-side subscriber would only double the work. Attach it\n // ONLY for providers that don't self-maintain. Where it does run, extraction is a\n // schema-free, manifest-free walk over self-describing content, so it needs no\n // registry (compositions self-typed their relation/asset props on write).\n const references = adapter.maintainsReferenceIndex\n ? noopReferenceIndexAttachment()\n : attachReferenceIndex(operations.events, adapter)\n const changesets = createChangesets({\n adapter,\n collections,\n events: operations.events,\n // EC-497 / EC-595 A2: a changeset-driven publish is gated identically — the same\n // runtime validator, prefetching through the step's own (scratch or real) adapter.\n validateDocument,\n manifestLookup,\n locales,\n ...idFactory,\n ...authorized,\n })\n // EC-579: no revalidation emitter attaches here. Host revalidation is a property\n // of the Convex write chokepoint (`convex/triggers.ts`), the one emitter — it\n // catches every writer, keeps the signing secret server-side, and the playground's\n // in-browser adapter is read by no host, so there is nothing to emit there.\n // EC-403: session-expiry detection rides the SAME lifecycle bus — every failed\n // command/query/changeset operation is checked against the session-expired\n // predicate here, so expiry raises the ONE app-level blocking re-auth state no\n // matter which surface issued the operation (per-surface banners can't cover\n // surfaces that render no banner).\n attachSessionExpiryReporting(operations.events)\n\n /** Report a capability failure on the bus (EC-403 sees an expiry like any failed operation). */\n const reportFailure = (operation: string, input: unknown, error: unknown) => {\n operations.events.emit({\n operation,\n domain: 'documents',\n kind: 'query',\n status: 'failed',\n inputSummary: summarizeInput(input),\n error: toOperationError(error),\n })\n }\n return {\n operations,\n changesets,\n adapter,\n references,\n subscribeDocument: (projectId, ref, listener) =>\n adapter.cms.subscribeDocument(projectId, ref, {\n onSnapshot: (snapshot) => listener.onSnapshot(snapshot),\n onError: (error) => {\n reportFailure('documents.subscribe', { projectId, ref }, error)\n listener.onError?.(error)\n },\n }),\n reportPresence: async (projectId, ref, presence) => {\n try {\n await adapter.cms.reportPresence(projectId, ref, presence)\n } catch (error) {\n reportFailure('documents.presence', { projectId, ref }, error)\n throw error\n }\n },\n clearPresence: (projectId, ref, sessionId) => adapter.cms.clearPresence(projectId, ref, sessionId),\n }\n}\n\n// One adapter + one operations bundle per backend (EC-179): keyed by the active\n// deployment so switching to a project on another Convex deployment selects (or\n// lazily builds) that backend's client, rather than reusing the first one.\nconst adaptersByKey = new Map<string, Promise<PersistenceAdapter>>()\nconst instancesByKey = new Map<string, Promise<StudioOperations>>()\nlet currentActor: Principal | null = null\n\n/**\n * The active backend key, tolerant of an unconfigured env: the real app never\n * reaches `getStudioOperations` while misconfigured (the `DeploymentSetupGate` renders a\n * boot error first), but tests inject a bundle directly via the seam below — so\n * a missing backend resolves to one stable key rather than throwing.\n */\nfunction deploymentKey(): string {\n try {\n return activeDeploymentKey()\n } catch {\n return '__unconfigured__'\n }\n}\n\nfunction getAdapter(key: string): Promise<PersistenceAdapter> {\n let adapter = adaptersByKey.get(key)\n if (!adapter) {\n adapter = selectPersistenceAdapter()\n adaptersByKey.set(key, adapter)\n }\n return adapter\n}\n\n/**\n * The shared studio operations client for the active backend (lazily\n * bootstrapped, cached per deployment). In-memory mode this owns the one seeded\n * adapter the whole session mutates; against Convex it owns one client per\n * deployment — the active project (EC-179) selects which.\n */\nexport function getStudioOperations(): Promise<StudioOperations> {\n const key = deploymentKey()\n let instance = instancesByKey.get(key)\n if (!instance) {\n const actor = currentActor\n instance = getAdapter(key).then((adapter) =>\n createStudioOperations(adapter, actor ? { actor } : {}),\n )\n instancesByKey.set(key, instance)\n }\n return instance\n}\n\n/**\n * Bind (or clear) the session principal (EC-150). Called by the auth context\n * on sign-in/sign-out. Rebuilds the operations clients over the *same* adapters\n * — the persisted state (and, in-memory, the whole session's edits) survives;\n * only the authorization identity changes. All cached backends are rebuilt so a\n * later switch picks up the new actor too.\n */\nexport function setStudioSession(actor: Principal | null): void {\n if (currentActor?.id === actor?.id) return // same user (or both null) — keep the clients\n currentActor = actor\n instancesByKey.clear()\n}\n\n/**\n * EC-595 A2 — the signed-in principal the operations clients act as (`null` signed out):\n * what this session's presence heartbeat names (\"X is in this field\") and how a conflict\n * tells \"you, in another tab\" from a colleague. Read-only; set by {@link setStudioSession}.\n */\nexport function getStudioActor(): Principal | null {\n return currentActor\n}\n\n/** Test seam: replace (or clear) the singleton for the active backend. */\nexport function setStudioOperationsForTests(next: StudioOperations | null): void {\n if (next) {\n instancesByKey.set(deploymentKey(), Promise.resolve(next))\n return\n }\n instancesByKey.clear()\n adaptersByKey.clear()\n currentActor = null\n}\n"]}
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import type { ConvexHttpClient } from 'convex/browser';
|
|
2
|
-
import type { AssetRepository, BackendStatus, BackendValidationInput, BackendValidationResult, BlobStorageAdapter, CmsRepository, DeliveryRepository, MembersRepository, PersistenceAdapter,
|
|
2
|
+
import type { RecordStore, AssetRepository, BackendStatus, BackendValidationInput, BackendValidationResult, BlobStorageAdapter, CmsRepository, DeliveryRepository, MembersRepository, PersistenceAdapter, ProjectRole, ReferenceIndexRepository, UserRepository, InviteRepository } from '@elytracms/core/persistence';
|
|
3
3
|
import type { ReactiveDocumentClient } from './convex-client.js';
|
|
4
|
+
/**
|
|
5
|
+
* The single `members.role` column a deployment stores for the 240c-ready `roles[]`
|
|
6
|
+
* (the 240a→240c bridge). EC-605: exactly ONE role, passed through as given — the
|
|
7
|
+
* operations layer validated it against the project's policy, and `members:set`
|
|
8
|
+
* refuses one the DEPLOYED policy does not declare, visibly. This used to filter
|
|
9
|
+
* against the default policy and floor an unknown or empty set to `viewer` — a silent
|
|
10
|
+
* rewrite that turned a project's own role into a viewer. Several roles cannot be
|
|
11
|
+
* collapsed here without a policy, so they are refused rather than guessed at.
|
|
12
|
+
*/
|
|
13
|
+
export declare function singleStoredRole(roles: readonly string[]): ProjectRole;
|
|
4
14
|
/**
|
|
5
15
|
* Convex-backed {@link PersistenceAdapter} (brief §10, EC-039). Every repository
|
|
6
16
|
* is implemented against the Convex functions in `apps/builder/convex/*`, mapping
|
|
@@ -17,8 +27,11 @@ export declare class ConvexPersistenceAdapter implements PersistenceAdapter {
|
|
|
17
27
|
readonly invites: InviteRepository;
|
|
18
28
|
/** Studio users rail — role + custom fields joined to auth identity (EC-240). */
|
|
19
29
|
readonly users: UserRepository;
|
|
20
|
-
/**
|
|
21
|
-
|
|
30
|
+
/**
|
|
31
|
+
* EC-616 — the generic record store: one repository per declared kind, each over its
|
|
32
|
+
* kind's Convex module (cached per kind object, so a rail and its foot share one).
|
|
33
|
+
*/
|
|
34
|
+
readonly records: RecordStore;
|
|
22
35
|
/** Convex file storage behind the EC-133 blob boundary (EC-151). */
|
|
23
36
|
readonly blobs: BlobStorageAdapter;
|
|
24
37
|
/** Delivery-pipeline (instant-publish) health, read-only (EC-268/EC-329). */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ConvexError } from 'convex/values';
|
|
2
2
|
import { DRAFT_VARIANT, documentKey, documentSchema } from '@elytracms/core/cms-core';
|
|
3
|
-
import { PRESENCE_TTL_MS, RecordNotFoundError, PersistenceValidationError, presenceInputSchema, assetCreateDefaults, assetRecordFromRow, compareReferenceEntries,
|
|
3
|
+
import { PRESENCE_TTL_MS, RecordNotFoundError, PersistenceValidationError, presenceInputSchema, assetCreateDefaults, assetRecordFromRow, compareReferenceEntries, persistenceIssueSchema, presentWriteKeys, recordEntryFromWire, validateForPersistence, versionNotPinnableError, } from '@elytracms/core/persistence';
|
|
4
4
|
import { normalizeInviteEmail } from '@elytracms/core/persistence';
|
|
5
5
|
import { createUuidIdFactory } from '@elytracms/core/determinism';
|
|
6
6
|
import { SUBSCRIPTION_UNAUTHENTICATED_MESSAGE, queryRef, mutationRef } from './convex-client.js';
|
|
@@ -52,6 +52,7 @@ function versionRecordFromDoc(doc, projectId) {
|
|
|
52
52
|
createdAt: doc.createdAt,
|
|
53
53
|
...(doc.label ? { label: doc.label } : {}),
|
|
54
54
|
...(doc.origin ? { origin: doc.origin } : {}),
|
|
55
|
+
...(doc.kind ? { kind: doc.kind } : {}),
|
|
55
56
|
};
|
|
56
57
|
}
|
|
57
58
|
/**
|
|
@@ -312,6 +313,10 @@ class ConvexCmsRepository {
|
|
|
312
313
|
if (result.status === 'missing-version') {
|
|
313
314
|
throw new RecordNotFoundError('cms-document-version', `${projectId}/${documentKey(ref)}#${version}`);
|
|
314
315
|
}
|
|
316
|
+
// EC-585: the version was recorded by a snapshot, never by a publish — the same
|
|
317
|
+
// refusal the in-memory store raises.
|
|
318
|
+
if (result.status === 'not-pinnable')
|
|
319
|
+
throw versionNotPinnableError(`${projectId}/${documentKey(ref)}`, version);
|
|
315
320
|
return docRecordFromDoc(result.row, projectId);
|
|
316
321
|
}
|
|
317
322
|
async unpublishDocument(projectId, ref) {
|
|
@@ -589,15 +594,26 @@ function userRecordFromDoc(doc, projectId) {
|
|
|
589
594
|
};
|
|
590
595
|
}
|
|
591
596
|
/**
|
|
592
|
-
*
|
|
593
|
-
*
|
|
594
|
-
*
|
|
597
|
+
* The single `members.role` column a deployment stores for the 240c-ready `roles[]`
|
|
598
|
+
* (the 240a→240c bridge). EC-605: exactly ONE role, passed through as given — the
|
|
599
|
+
* operations layer validated it against the project's policy, and `members:set`
|
|
600
|
+
* refuses one the DEPLOYED policy does not declare, visibly. This used to filter
|
|
601
|
+
* against the default policy and floor an unknown or empty set to `viewer` — a silent
|
|
602
|
+
* rewrite that turned a project's own role into a viewer. Several roles cannot be
|
|
603
|
+
* collapsed here without a policy, so they are refused rather than guessed at.
|
|
595
604
|
*/
|
|
596
|
-
function
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
605
|
+
export function singleStoredRole(roles) {
|
|
606
|
+
if (roles.length !== 1) {
|
|
607
|
+
throw new PersistenceValidationError('A deployment stores exactly one role per member.', [
|
|
608
|
+
{
|
|
609
|
+
code: 'invalid-role-count',
|
|
610
|
+
message: `Expected exactly one role, got ${roles.length} (${roles.join(', ') || 'none'}).`,
|
|
611
|
+
path: ['roles'],
|
|
612
|
+
domain: 'users',
|
|
613
|
+
},
|
|
614
|
+
]);
|
|
615
|
+
}
|
|
616
|
+
return roles[0];
|
|
601
617
|
}
|
|
602
618
|
/**
|
|
603
619
|
* Convex-backed {@link UserRepository} (EC-240, 240a). Reads are the admin-gated
|
|
@@ -638,7 +654,7 @@ class ConvexUserRepository {
|
|
|
638
654
|
const now = this.clock();
|
|
639
655
|
await this.client.mutation(mutationRef('members:set'), {
|
|
640
656
|
userId: input.id,
|
|
641
|
-
role:
|
|
657
|
+
role: singleStoredRole(input.roles),
|
|
642
658
|
...(input.meta !== undefined ? { meta: input.meta } : {}),
|
|
643
659
|
createdAt: now,
|
|
644
660
|
updatedAt: now,
|
|
@@ -717,56 +733,65 @@ class ConvexInviteRepository {
|
|
|
717
733
|
}
|
|
718
734
|
}
|
|
719
735
|
/**
|
|
720
|
-
* Convex-backed {@link
|
|
721
|
-
* (
|
|
722
|
-
*
|
|
723
|
-
*
|
|
724
|
-
*
|
|
736
|
+
* Convex-backed {@link RecordRepository} (EC-616) — one record kind over its own Convex
|
|
737
|
+
* module (`<kind.module>:save|get|list|remove`, built by `defineRecordFunctions(kind)`),
|
|
738
|
+
* stored in the one `records` table. The write is sent as written (EC-577): the handler
|
|
739
|
+
* resolves it against the stored record in its transaction with the rule the in-memory
|
|
740
|
+
* store uses. Reads come back in the ONE order (`orderRecords`, applied server-side), and
|
|
741
|
+
* a refused query or write arrives as the same `PersistenceValidationError` the in-memory
|
|
742
|
+
* store throws.
|
|
725
743
|
*/
|
|
726
|
-
class
|
|
744
|
+
class ConvexRecordRepository {
|
|
727
745
|
client;
|
|
746
|
+
kind;
|
|
728
747
|
clock;
|
|
729
|
-
constructor(client, clock = realClock) {
|
|
748
|
+
constructor(client, kind, clock = realClock) {
|
|
730
749
|
this.client = client;
|
|
750
|
+
this.kind = kind;
|
|
731
751
|
this.clock = clock;
|
|
732
752
|
}
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
const
|
|
738
|
-
.
|
|
739
|
-
redirectId: id,
|
|
740
|
-
...presentWriteKeys(write),
|
|
741
|
-
createdAt: now,
|
|
742
|
-
updatedAt: now,
|
|
743
|
-
})
|
|
753
|
+
ref(fn) {
|
|
754
|
+
return `${this.kind.module}:${fn}`;
|
|
755
|
+
}
|
|
756
|
+
async list(projectId, query = {}) {
|
|
757
|
+
const rows = (await this.client
|
|
758
|
+
.query(queryRef(this.ref('list')), presentWriteKeys({ ...query }))
|
|
744
759
|
.catch((error) => {
|
|
745
760
|
throw asRailWriteError(error);
|
|
746
761
|
}));
|
|
747
|
-
return
|
|
762
|
+
return rows.map((row) => recordEntryFromWire(this.kind, row, projectId));
|
|
748
763
|
}
|
|
749
|
-
async
|
|
750
|
-
const found = await this.
|
|
764
|
+
async get(projectId, id) {
|
|
765
|
+
const found = await this.find(projectId, id);
|
|
751
766
|
if (!found)
|
|
752
|
-
throw new RecordNotFoundError(
|
|
767
|
+
throw new RecordNotFoundError(this.kind.kind, `${projectId}/${id}`);
|
|
753
768
|
return found;
|
|
754
769
|
}
|
|
755
|
-
async
|
|
756
|
-
const
|
|
757
|
-
|
|
770
|
+
async find(projectId, id) {
|
|
771
|
+
const row = (await this.client.query(queryRef(this.ref('get')), {
|
|
772
|
+
[this.kind.idKey]: id,
|
|
758
773
|
}));
|
|
759
|
-
return
|
|
774
|
+
return row ? recordEntryFromWire(this.kind, row, projectId) : undefined;
|
|
760
775
|
}
|
|
761
|
-
async
|
|
762
|
-
const
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
776
|
+
async save(projectId, input) {
|
|
777
|
+
const now = this.clock();
|
|
778
|
+
const { id: givenId, ...write } = input;
|
|
779
|
+
const id = givenId ?? newId(this.kind.idPrefix);
|
|
780
|
+
const row = (await this.client
|
|
781
|
+
.mutation(mutationRef(this.ref('save')), {
|
|
782
|
+
[this.kind.idKey]: id,
|
|
783
|
+
...presentWriteKeys(write),
|
|
784
|
+
createdAt: now,
|
|
785
|
+
updatedAt: now,
|
|
786
|
+
})
|
|
787
|
+
.catch((error) => {
|
|
788
|
+
throw asRailWriteError(error);
|
|
789
|
+
}));
|
|
790
|
+
return recordEntryFromWire(this.kind, row, projectId);
|
|
766
791
|
}
|
|
767
|
-
async
|
|
768
|
-
await this.
|
|
769
|
-
await this.client.mutation(mutationRef('
|
|
792
|
+
async remove(projectId, id) {
|
|
793
|
+
await this.get(projectId, id); // not-found parity with the in-memory store
|
|
794
|
+
await this.client.mutation(mutationRef(this.ref('remove')), { [this.kind.idKey]: id });
|
|
770
795
|
}
|
|
771
796
|
}
|
|
772
797
|
/**
|
|
@@ -802,8 +827,11 @@ export class ConvexPersistenceAdapter {
|
|
|
802
827
|
invites;
|
|
803
828
|
/** Studio users rail — role + custom fields joined to auth identity (EC-240). */
|
|
804
829
|
users;
|
|
805
|
-
/**
|
|
806
|
-
|
|
830
|
+
/**
|
|
831
|
+
* EC-616 — the generic record store: one repository per declared kind, each over its
|
|
832
|
+
* kind's Convex module (cached per kind object, so a rail and its foot share one).
|
|
833
|
+
*/
|
|
834
|
+
records;
|
|
807
835
|
/** Convex file storage behind the EC-133 blob boundary (EC-151). */
|
|
808
836
|
blobs;
|
|
809
837
|
/** Delivery-pipeline (instant-publish) health, read-only (EC-268/EC-329). */
|
|
@@ -837,7 +865,15 @@ export class ConvexPersistenceAdapter {
|
|
|
837
865
|
this.members = new ConvexMembersRepository(client, projectId);
|
|
838
866
|
this.users = new ConvexUserRepository(client);
|
|
839
867
|
this.invites = new ConvexInviteRepository(client);
|
|
840
|
-
|
|
868
|
+
const recordRepositories = new Map();
|
|
869
|
+
this.records = (kind) => {
|
|
870
|
+
let repository = recordRepositories.get(kind);
|
|
871
|
+
if (!repository) {
|
|
872
|
+
repository = new ConvexRecordRepository(client, kind);
|
|
873
|
+
recordRepositories.set(kind, repository);
|
|
874
|
+
}
|
|
875
|
+
return repository;
|
|
876
|
+
};
|
|
841
877
|
this.blobs = new ConvexBlobStorage(client);
|
|
842
878
|
this.delivery = new ConvexDeliveryRepository(client);
|
|
843
879
|
}
|