@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
package/convex/schema.ts
CHANGED
|
@@ -222,6 +222,12 @@ export default defineSchema({
|
|
|
222
222
|
// EC-199 provenance: authoring origin ('assistant' for AI-authored content).
|
|
223
223
|
// Additive scalar, outside the folded snapshot — invisible when unset.
|
|
224
224
|
origin: v.optional(v.string()),
|
|
225
|
+
// EC-585: which mutation recorded the row — 'publish' (`publishDocument`, the only
|
|
226
|
+
// kind `publishDocumentVersion` pins) or 'snapshot' (`saveDocumentVersion`: a restore
|
|
227
|
+
// point). Optional ONLY for rows recorded before EC-585 (read through
|
|
228
|
+
// `isPinnableVersion`, which keeps a kind-less `label: 'published'` row pinnable). A
|
|
229
|
+
// top-level scalar beside the folded snapshot: it adds no nesting depth.
|
|
230
|
+
kind: v.optional(v.union(v.literal('publish'), v.literal('snapshot'))),
|
|
225
231
|
createdAt: v.string(),
|
|
226
232
|
})
|
|
227
233
|
.index('by_doc', ['collection', 'docId'])
|
|
@@ -293,6 +299,36 @@ export default defineSchema({
|
|
|
293
299
|
updatedAt: v.string(),
|
|
294
300
|
}).index('by_redirect', ['redirectId']),
|
|
295
301
|
|
|
302
|
+
/**
|
|
303
|
+
* The generic RECORD STORE (EC-616) — one row per record of a DECLARED record kind
|
|
304
|
+
* (`defineRecordKind` in `@elytracms/core/persistence`): the engine's own kinds and
|
|
305
|
+
* every addon's. `data` holds the kind's columns + its open `meta` bag, validated by
|
|
306
|
+
* the kind's schema in the write path (`defineRecordFunctions`, `record-functions.ts`)
|
|
307
|
+
* — the data SHAPE, never project structure (EC-585 1e).
|
|
308
|
+
*
|
|
309
|
+
* The index slots are STATIC (a consumer re-exports this schema, so an addon can never
|
|
310
|
+
* add an index); a kind fills them from its own declared columns: `key1`/`key2` from
|
|
311
|
+
* its `keys`, `at` from its `time` column (else `createdAt`). The indexes are the
|
|
312
|
+
* known access paths: one record by id; a kind by time (recent-first lists, a TTL
|
|
313
|
+
* sweep); by either key + time (submissions by form or by status, newest first); by
|
|
314
|
+
* both keys + time (an aggregate by day + document).
|
|
315
|
+
*/
|
|
316
|
+
records: defineTable({
|
|
317
|
+
kind: v.string(),
|
|
318
|
+
recordId: v.string(),
|
|
319
|
+
data: v.any(),
|
|
320
|
+
key1: v.optional(v.string()),
|
|
321
|
+
key2: v.optional(v.string()),
|
|
322
|
+
at: v.string(),
|
|
323
|
+
createdAt: v.string(),
|
|
324
|
+
updatedAt: v.string(),
|
|
325
|
+
})
|
|
326
|
+
.index('by_kind_record', ['kind', 'recordId'])
|
|
327
|
+
.index('by_kind_at', ['kind', 'at'])
|
|
328
|
+
.index('by_kind_key1', ['kind', 'key1', 'at'])
|
|
329
|
+
.index('by_kind_key2', ['kind', 'key2', 'at'])
|
|
330
|
+
.index('by_kind_keys', ['kind', 'key1', 'key2', 'at']),
|
|
331
|
+
|
|
296
332
|
/**
|
|
297
333
|
* Reference index entries (EC-155, vision AD-6) — derived data, recomputed
|
|
298
334
|
* replace-all-for-source on every write. Indexed for efficient lookup in both
|
package/convex/triggers.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { unfoldDocument } from '@elytracms/core/cms-core'
|
|
2
2
|
import type { CmsDocument } from '@elytracms/core/cms-core'
|
|
3
|
+
import { redirectRecordKind } from '@elytracms/core/persistence'
|
|
3
4
|
import { Triggers } from 'convex-helpers/server/triggers'
|
|
4
5
|
import type { DataModel } from './functions'
|
|
5
6
|
import { maintainDocumentReferences, removeDocumentReferences } from './referenceMaintenance'
|
|
@@ -33,7 +34,8 @@ import { scheduleRevalidate } from './revalidate'
|
|
|
33
34
|
*
|
|
34
35
|
* - `cmsDocuments` — only when the live pin (`publishedVersion`) moves
|
|
35
36
|
* (`publish` / `unpublish`), or a pinned row is deleted (`delete`);
|
|
36
|
-
* - `
|
|
37
|
+
* - `records` of the redirect kind (EC-616; EC-510 before it on the `redirects` table) —
|
|
38
|
+
* every write (`redirects`; the row IS the live state); no other record kind;
|
|
37
39
|
* - `assets` (EC-579) — every edit and delete (`asset`); a create fires nothing.
|
|
38
40
|
*
|
|
39
41
|
* The snapshot reads one more table, `documentVersions`, but only the version a
|
|
@@ -129,6 +131,24 @@ triggers.register('redirects', async (ctx) => {
|
|
|
129
131
|
await scheduleRevalidate(ctx, { kind: 'redirects' })
|
|
130
132
|
})
|
|
131
133
|
|
|
134
|
+
/**
|
|
135
|
+
* The generic record store (EC-616). Of all record kinds, ONLY the engine's redirect
|
|
136
|
+
* kind is projected onto the live wire (`delivery.ts` reads it through
|
|
137
|
+
* `loadRedirectEntries`), so only a write to a `redirect` row revalidates — with exactly
|
|
138
|
+
* the event the legacy `redirects` table fired above (EC-510: every write, the receiver
|
|
139
|
+
* answers with the sweep). Every other kind — an addon's submissions, analytics rows —
|
|
140
|
+
* is never on the wire and fires nothing; a kind that starts reaching the snapshot
|
|
141
|
+
* belongs in this check.
|
|
142
|
+
*
|
|
143
|
+
* Since the move, a redirect write is a `records` write; the legacy table's trigger
|
|
144
|
+
* above still fires for the transitional deletes (a save lifting a legacy-only redirect
|
|
145
|
+
* deletes its legacy row: two sweeps for that one save, until the migration ran).
|
|
146
|
+
*/
|
|
147
|
+
triggers.register('records', async (ctx, change) => {
|
|
148
|
+
const kind = (change.newDoc ?? change.oldDoc)?.kind
|
|
149
|
+
if (kind === redirectRecordKind.kind) await scheduleRevalidate(ctx, { kind: 'redirects' })
|
|
150
|
+
})
|
|
151
|
+
|
|
132
152
|
/**
|
|
133
153
|
* Asset records (EC-579). The delivery snapshot projects every asset row onto
|
|
134
154
|
* the live wire field by field (url, dimensions, alt, focal point, lqip, the
|
package/dist/addon.d.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@elytracms/studio/addon` — THE public addon API (EC-616, ruling EC-565 § 6b item 2).
|
|
3
|
+
*
|
|
4
|
+
* An addon (`@elytracms/forms`, `@elytracms/analytics`, or your own) is an optional
|
|
5
|
+
* package whose studio half contributes navigation items to a project's
|
|
6
|
+
* `defineStudio({ sidebar })` — a rail bound to a record kind, or a view with its own
|
|
7
|
+
* component — and whose backend half is a record kind in the generic record store
|
|
8
|
+
* (`defineRecordKind` / `adapter.records(kind)` in `@elytracms/core/persistence`, its
|
|
9
|
+
* Convex functions from `defineRecordFunctions` in `@elytracms/studio/convex/
|
|
10
|
+
* record-functions`). Everything an addon's studio code touches is exported HERE; the
|
|
11
|
+
* studio's internals (`lib/*`, `components/*`) are not part of the published package.
|
|
12
|
+
* `@elytracms/studio/ui` stays the primitive set (Button, Panel, Text, …).
|
|
13
|
+
*
|
|
14
|
+
* ## The chrome contract
|
|
15
|
+
*
|
|
16
|
+
* The SHELL draws the top bar, the breadcrumb (its section crumb is the view's `label`;
|
|
17
|
+
* deeper crumbs are contributed with {@link useSetBreadcrumb}), the rail with its issues
|
|
18
|
+
* foot (findings contributed with {@link useNavIssues}, or always-on through a view's
|
|
19
|
+
* `useIssues`), the banners and the theme. A VIEW owns the whole scrollable content area
|
|
20
|
+
* under it — including its own title header: the shell adds no frame, title or padding.
|
|
21
|
+
* A view reaches the studio through its {@link AppViewContext}: the project, its deep
|
|
22
|
+
* link and search, the operations client (every read and write goes through the one
|
|
23
|
+
* authorized chokepoint), the query hooks over the one cache, the content locale, and
|
|
24
|
+
* the signed-in user with their role.
|
|
25
|
+
*
|
|
26
|
+
* ## The two navigation items
|
|
27
|
+
*
|
|
28
|
+
* ```tsx
|
|
29
|
+
* import { nav } from '@elytracms/studio/addon'
|
|
30
|
+
* import { submissionRecordKind } from './kinds'
|
|
31
|
+
*
|
|
32
|
+
* // a rail bound to a record kind — the portable list/edit surfaces, no component to write
|
|
33
|
+
* nav.rail(submissionRecordKind, { label: 'Submissions' })
|
|
34
|
+
* // a custom component — the whole content area is yours
|
|
35
|
+
* nav.view({ id: 'forms-stats', label: 'Form stats', render: (ctx) => <Stats ctx={ctx} /> })
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export { nav } from './components/app-views/default-modules.js';
|
|
39
|
+
export type { CustomViewConfig, RailViewConfig, BuiltinViewConfig, } from './components/app-views/default-modules.js';
|
|
40
|
+
export type { AppViewContext, AppViewDeepLink, AppViewModule, AppViewQueryHooks, NavIssuesHook, NavPermission, NavPermissionContext, SidebarNode, SidebarViewNode, } from './components/app-views/module.js';
|
|
41
|
+
/** A record rail's pieces, for an addon composing its own view around one. */
|
|
42
|
+
export { RECORD_RAIL_CAPABILITIES, RecordRailModule, RecordRailProvider, useRecordCollectionViewSource, useRecordList, useRecordRail, } from './components/records/record-rail.js';
|
|
43
|
+
export type { RecordRailModuleProps, RecordRailPaths, RecordRailStore } from './components/records/record-rail.js';
|
|
44
|
+
export { lensDocumentToRecordWrite, recordLensDef, recordToLensDocument } from './components/records/record-lens.js';
|
|
45
|
+
/** The portable list/edit surfaces over any source, and the scaffold that assembles one. */
|
|
46
|
+
export { CollectionViewSurface } from './components/collection-view/collection-view-surface.js';
|
|
47
|
+
export { assembleRailViewSource, metaBagProjection, normalizeOkResult, useRailViewSource, } from './components/rail-view-source.js';
|
|
48
|
+
export type { OkResult, RailAdapter } from './components/rail-view-source.js';
|
|
49
|
+
export type { CollectionViewCapabilities, CollectionViewSource, FieldAccess, } from './lib/collection-view/collection-view-source.js';
|
|
50
|
+
export { useOperationCache, useOperationQuery } from './lib/query/index.js';
|
|
51
|
+
export type { OperationCache, UseOperationQueryOptions } from './lib/query/index.js';
|
|
52
|
+
export { useStudioLocale } from './lib/locale/index.js';
|
|
53
|
+
export type { StudioLocale } from './lib/locale/index.js';
|
|
54
|
+
export { useSetBreadcrumb } from './components/breadcrumb-context.js';
|
|
55
|
+
export type { BreadcrumbItem } from './components/breadcrumb-context.js';
|
|
56
|
+
export { useNavIssues } from './components/nav-issues-registry.js';
|
|
57
|
+
export type { NavIssue } from './components/nav-issues-registry.js';
|
|
58
|
+
/** A pane in the document editor's inspector — `defineStudio({ documentPanes: [documentPane({ … })] })`. */
|
|
59
|
+
export { documentPane } from './components/inspector/document-panes.js';
|
|
60
|
+
export type { DocumentPane, DocumentPaneContext } from './components/inspector/document-panes.js';
|
|
61
|
+
/**
|
|
62
|
+
* The portable edit shell alone (AD-19), with its form-column appendix seam (EC-396): an addon
|
|
63
|
+
* that assembles its own source (`useRailViewSource`) renders one record's detail with
|
|
64
|
+
* read-only sections below the editable fields — the forms inbox shows a submission's answers,
|
|
65
|
+
* files and delivery log there.
|
|
66
|
+
*/
|
|
67
|
+
export { PortableDetailEditor } from './components/cms/detail-editor.js';
|
|
68
|
+
/** The one query key of a kind's records in a project — patch it after a write (`useOperationCache`). */
|
|
69
|
+
export { recordListKey } from './components/records/record-rail.js';
|
|
70
|
+
/** Resolve a `LocalizedString` (`'Text'` or `{ en, de, … }`) in the studio's UI language. */
|
|
71
|
+
export { useLabel } from './lib/i18n/index.js';
|
package/dist/addon.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@elytracms/studio/addon` — THE public addon API (EC-616, ruling EC-565 § 6b item 2).
|
|
3
|
+
*
|
|
4
|
+
* An addon (`@elytracms/forms`, `@elytracms/analytics`, or your own) is an optional
|
|
5
|
+
* package whose studio half contributes navigation items to a project's
|
|
6
|
+
* `defineStudio({ sidebar })` — a rail bound to a record kind, or a view with its own
|
|
7
|
+
* component — and whose backend half is a record kind in the generic record store
|
|
8
|
+
* (`defineRecordKind` / `adapter.records(kind)` in `@elytracms/core/persistence`, its
|
|
9
|
+
* Convex functions from `defineRecordFunctions` in `@elytracms/studio/convex/
|
|
10
|
+
* record-functions`). Everything an addon's studio code touches is exported HERE; the
|
|
11
|
+
* studio's internals (`lib/*`, `components/*`) are not part of the published package.
|
|
12
|
+
* `@elytracms/studio/ui` stays the primitive set (Button, Panel, Text, …).
|
|
13
|
+
*
|
|
14
|
+
* ## The chrome contract
|
|
15
|
+
*
|
|
16
|
+
* The SHELL draws the top bar, the breadcrumb (its section crumb is the view's `label`;
|
|
17
|
+
* deeper crumbs are contributed with {@link useSetBreadcrumb}), the rail with its issues
|
|
18
|
+
* foot (findings contributed with {@link useNavIssues}, or always-on through a view's
|
|
19
|
+
* `useIssues`), the banners and the theme. A VIEW owns the whole scrollable content area
|
|
20
|
+
* under it — including its own title header: the shell adds no frame, title or padding.
|
|
21
|
+
* A view reaches the studio through its {@link AppViewContext}: the project, its deep
|
|
22
|
+
* link and search, the operations client (every read and write goes through the one
|
|
23
|
+
* authorized chokepoint), the query hooks over the one cache, the content locale, and
|
|
24
|
+
* the signed-in user with their role.
|
|
25
|
+
*
|
|
26
|
+
* ## The two navigation items
|
|
27
|
+
*
|
|
28
|
+
* ```tsx
|
|
29
|
+
* import { nav } from '@elytracms/studio/addon'
|
|
30
|
+
* import { submissionRecordKind } from './kinds'
|
|
31
|
+
*
|
|
32
|
+
* // a rail bound to a record kind — the portable list/edit surfaces, no component to write
|
|
33
|
+
* nav.rail(submissionRecordKind, { label: 'Submissions' })
|
|
34
|
+
* // a custom component — the whole content area is yours
|
|
35
|
+
* nav.view({ id: 'forms-stats', label: 'Form stats', render: (ctx) => <Stats ctx={ctx} /> })
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
// --- Navigation items and the view contract --------------------------------------------
|
|
39
|
+
export { nav } from './components/app-views/default-modules.js';
|
|
40
|
+
// --- Rails: a record kind, or your own source -------------------------------------------
|
|
41
|
+
/** A record rail's pieces, for an addon composing its own view around one. */
|
|
42
|
+
export { RECORD_RAIL_CAPABILITIES, RecordRailModule, RecordRailProvider, useRecordCollectionViewSource, useRecordList, useRecordRail, } from './components/records/record-rail.js';
|
|
43
|
+
export { lensDocumentToRecordWrite, recordLensDef, recordToLensDocument } from './components/records/record-lens.js';
|
|
44
|
+
/** The portable list/edit surfaces over any source, and the scaffold that assembles one. */
|
|
45
|
+
export { CollectionViewSurface } from './components/collection-view/collection-view-surface.js';
|
|
46
|
+
export { assembleRailViewSource, metaBagProjection, normalizeOkResult, useRailViewSource, } from './components/rail-view-source.js';
|
|
47
|
+
// --- Hooks: the cache, the locale, the breadcrumb, the rail foot -------------------------
|
|
48
|
+
export { useOperationCache, useOperationQuery } from './lib/query/index.js';
|
|
49
|
+
export { useStudioLocale } from './lib/locale/index.js';
|
|
50
|
+
export { useSetBreadcrumb } from './components/breadcrumb-context.js';
|
|
51
|
+
export { useNavIssues } from './components/nav-issues-registry.js';
|
|
52
|
+
// --- The document editor: contributed inspector panes (EC-618) ---------------------------
|
|
53
|
+
/** A pane in the document editor's inspector — `defineStudio({ documentPanes: [documentPane({ … })] })`. */
|
|
54
|
+
export { documentPane } from './components/inspector/document-panes.js';
|
|
55
|
+
// --- EC-613 (the forms addon): an own source's edit shell, its list key, the UI language -----
|
|
56
|
+
/**
|
|
57
|
+
* The portable edit shell alone (AD-19), with its form-column appendix seam (EC-396): an addon
|
|
58
|
+
* that assembles its own source (`useRailViewSource`) renders one record's detail with
|
|
59
|
+
* read-only sections below the editable fields — the forms inbox shows a submission's answers,
|
|
60
|
+
* files and delivery log there.
|
|
61
|
+
*/
|
|
62
|
+
export { PortableDetailEditor } from './components/cms/detail-editor.js';
|
|
63
|
+
/** The one query key of a kind's records in a project — patch it after a write (`useOperationCache`). */
|
|
64
|
+
export { recordListKey } from './components/records/record-rail.js';
|
|
65
|
+
/** Resolve a `LocalizedString` (`'Text'` or `{ en, de, … }`) in the studio's UI language. */
|
|
66
|
+
export { useLabel } from './lib/i18n/index.js';
|
|
67
|
+
//# sourceMappingURL=addon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"addon.js","sourceRoot":"","sources":["../src/addon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,0FAA0F;AAE1F,OAAO,EAAE,GAAG,EAAE,MAAM,wCAAwC,CAAA;AAkB5D,2FAA2F;AAE3F,8EAA8E;AAC9E,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,kBAAkB,EAClB,6BAA6B,EAC7B,aAAa,EACb,aAAa,GACd,MAAM,kCAAkC,CAAA;AAEzC,OAAO,EAAE,yBAAyB,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAA;AAEjH,4FAA4F;AAC5F,OAAO,EAAE,qBAAqB,EAAE,MAAM,sDAAsD,CAAA;AAC5F,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,+BAA+B,CAAA;AAQtC,4FAA4F;AAE5F,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAElE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAE9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AAElE,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAG/D,4FAA4F;AAE5F,4GAA4G;AAC5G,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAA;AAGpE,gGAAgG;AAEhG;;;;;GAKG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAA;AACrE,yGAAyG;AACzG,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAA;AAChE,6FAA6F;AAC7F,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA","sourcesContent":["/**\n * `@elytracms/studio/addon` — THE public addon API (EC-616, ruling EC-565 § 6b item 2).\n *\n * An addon (`@elytracms/forms`, `@elytracms/analytics`, or your own) is an optional\n * package whose studio half contributes navigation items to a project's\n * `defineStudio({ sidebar })` — a rail bound to a record kind, or a view with its own\n * component — and whose backend half is a record kind in the generic record store\n * (`defineRecordKind` / `adapter.records(kind)` in `@elytracms/core/persistence`, its\n * Convex functions from `defineRecordFunctions` in `@elytracms/studio/convex/\n * record-functions`). Everything an addon's studio code touches is exported HERE; the\n * studio's internals (`lib/*`, `components/*`) are not part of the published package.\n * `@elytracms/studio/ui` stays the primitive set (Button, Panel, Text, …).\n *\n * ## The chrome contract\n *\n * The SHELL draws the top bar, the breadcrumb (its section crumb is the view's `label`;\n * deeper crumbs are contributed with {@link useSetBreadcrumb}), the rail with its issues\n * foot (findings contributed with {@link useNavIssues}, or always-on through a view's\n * `useIssues`), the banners and the theme. A VIEW owns the whole scrollable content area\n * under it — including its own title header: the shell adds no frame, title or padding.\n * A view reaches the studio through its {@link AppViewContext}: the project, its deep\n * link and search, the operations client (every read and write goes through the one\n * authorized chokepoint), the query hooks over the one cache, the content locale, and\n * the signed-in user with their role.\n *\n * ## The two navigation items\n *\n * ```tsx\n * import { nav } from '@elytracms/studio/addon'\n * import { submissionRecordKind } from './kinds'\n *\n * // a rail bound to a record kind — the portable list/edit surfaces, no component to write\n * nav.rail(submissionRecordKind, { label: 'Submissions' })\n * // a custom component — the whole content area is yours\n * nav.view({ id: 'forms-stats', label: 'Form stats', render: (ctx) => <Stats ctx={ctx} /> })\n * ```\n */\n\n// --- Navigation items and the view contract --------------------------------------------\n\nexport { nav } from './components/app-views/default-modules'\nexport type {\n CustomViewConfig,\n RailViewConfig,\n BuiltinViewConfig,\n} from './components/app-views/default-modules'\nexport type {\n AppViewContext,\n AppViewDeepLink,\n AppViewModule,\n AppViewQueryHooks,\n NavIssuesHook,\n NavPermission,\n NavPermissionContext,\n SidebarNode,\n SidebarViewNode,\n} from './components/app-views/module'\n\n// --- Rails: a record kind, or your own source -------------------------------------------\n\n/** A record rail's pieces, for an addon composing its own view around one. */\nexport {\n RECORD_RAIL_CAPABILITIES,\n RecordRailModule,\n RecordRailProvider,\n useRecordCollectionViewSource,\n useRecordList,\n useRecordRail,\n} from './components/records/record-rail'\nexport type { RecordRailModuleProps, RecordRailPaths, RecordRailStore } from './components/records/record-rail'\nexport { lensDocumentToRecordWrite, recordLensDef, recordToLensDocument } from './components/records/record-lens'\n\n/** The portable list/edit surfaces over any source, and the scaffold that assembles one. */\nexport { CollectionViewSurface } from './components/collection-view/collection-view-surface'\nexport {\n assembleRailViewSource,\n metaBagProjection,\n normalizeOkResult,\n useRailViewSource,\n} from './components/rail-view-source'\nexport type { OkResult, RailAdapter } from './components/rail-view-source'\nexport type {\n CollectionViewCapabilities,\n CollectionViewSource,\n FieldAccess,\n} from './lib/collection-view/collection-view-source'\n\n// --- Hooks: the cache, the locale, the breadcrumb, the rail foot -------------------------\n\nexport { useOperationCache, useOperationQuery } from './lib/query'\nexport type { OperationCache, UseOperationQueryOptions } from './lib/query'\nexport { useStudioLocale } from './lib/locale'\nexport type { StudioLocale } from './lib/locale'\nexport { useSetBreadcrumb } from './components/breadcrumb-context'\nexport type { BreadcrumbItem } from './components/breadcrumb-context'\nexport { useNavIssues } from './components/nav-issues-registry'\nexport type { NavIssue } from './components/nav-issues-registry'\n\n// --- The document editor: contributed inspector panes (EC-618) ---------------------------\n\n/** A pane in the document editor's inspector — `defineStudio({ documentPanes: [documentPane({ … })] })`. */\nexport { documentPane } from './components/inspector/document-panes'\nexport type { DocumentPane, DocumentPaneContext } from './components/inspector/document-panes'\n\n// --- EC-613 (the forms addon): an own source's edit shell, its list key, the UI language -----\n\n/**\n * The portable edit shell alone (AD-19), with its form-column appendix seam (EC-396): an addon\n * that assembles its own source (`useRailViewSource`) renders one record's detail with\n * read-only sections below the editable fields — the forms inbox shows a submission's answers,\n * files and delivery log there.\n */\nexport { PortableDetailEditor } from './components/cms/detail-editor'\n/** The one query key of a kind's records in a project — patch it after a write (`useOperationCache`). */\nexport { recordListKey } from './components/records/record-rail'\n/** Resolve a `LocalizedString` (`'Text'` or `{ en, de, … }`) in the studio's UI language. */\nexport { useLabel } from './lib/i18n'\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { UserCog } from 'lucide-react';
|
|
3
3
|
import { Heading, Stack, Text } from '@elytracms/studio/ui';
|
|
4
|
-
import { listStoreState, useOperationQuery } from '
|
|
5
|
-
import { translate } from '
|
|
4
|
+
import { listStoreState, useOperationQuery } from '../../lib/query/index.js';
|
|
5
|
+
import { translate } from '../../lib/i18n/index.js';
|
|
6
6
|
import { useAuth } from '../auth-context.js';
|
|
7
7
|
import { PortableDetailEditor } from '../cms/detail-editor.js';
|
|
8
8
|
import { CredentialPanel } from './credential-panel.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account-settings.js","sourceRoot":"","sources":["../../../src/components/account/account-settings.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"account-settings.js","sourceRoot":"","sources":["../../../src/components/account/account-settings.tsx"],"names":[],"mappings":"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","sourcesContent":["import { UserCog } from 'lucide-react'\nimport type { UserRecord } from '@elytracms/core/persistence'\nimport { Heading, Stack, Text } from '@elytracms/studio/ui'\nimport { listStoreState, useOperationQuery } from '../../lib/query'\nimport { translate } from '../../lib/i18n'\nimport { useAuth } from '../auth-context'\nimport { PortableDetailEditor } from '../cms/detail-editor'\nimport { CredentialPanel } from './credential-panel'\nimport { useSelfAccountViewSource } from './self-account-view-source'\n\n/**\n * The **account-settings** surface (EC-240 H-tail items 1–4). A member — admin or\n * not — opens their OWN record here (via the user menu → `users/<selfId>`). It is\n * self-permitted: the self record is read through `users.getSelf` (never the\n * admin-only `users.list`/`get`), so a non-admin reaches ONLY their own account.\n *\n * Reuses the portable edit shell (AD-19) for the identity form (name/avatar\n * editable → `updateProfile`; email/role read-only) and appends the credential\n * seam (change password). No bespoke form — the shell + the self source carry it.\n */\nexport function AccountSettings({ projectId }: { projectId: string }) {\n const auth = useAuth()\n const userId = auth.session?.user?.id ?? null\n\n const query = useOperationQuery<UserRecord | null>({\n queryKey: ['account', projectId, userId ?? '∅'],\n loader: async (operations) => {\n const result = await operations.users.getSelf({ projectId })\n if (!result.ok) throw new Error(result.error.message)\n return result.value ?? null\n },\n enabled: userId !== null,\n })\n const { status, errorMessage } = listStoreState(query)\n const self = query.data ?? null\n\n if (status === 'loading') {\n return <CenteredNote>{translate('account.loading')}</CenteredNote>\n }\n if (status === 'error') {\n return (\n <CenteredNote testId=\"account-error\">\n {errorMessage ?? translate('account.loadFailed')}\n </CenteredNote>\n )\n }\n if (!self) {\n // Authenticated but not a member (no role yet) — honest, not a raw auth error.\n return (\n <Stack gap=\"2\" align=\"center\" justify=\"center\" className=\"h-full p-8 text-center\">\n <UserCog className=\"size-6 text-muted-foreground\" />\n <Heading level={2} size=\"h3\">\n {translate('account.notMemberTitle')}\n </Heading>\n <Text size=\"sm\" tone=\"muted\" className=\"max-w-sm\">\n {translate('account.notMemberBody')}\n </Text>\n </Stack>\n )\n }\n\n return <LoadedAccount projectId={projectId} self={self} refresh={async () => void (await query.refetch())} />\n}\n\nfunction LoadedAccount({\n projectId,\n self,\n refresh,\n}: {\n projectId: string\n self: UserRecord\n refresh: () => Promise<void>\n}) {\n const source = useSelfAccountViewSource({ projectId, self, refresh })\n // EC-396: ONE editor surface. The identity form renders through the portable edit\n // shell (name/avatar editable), and the credential seam mounts through the shell's\n // form-column appendix — so the CredentialPanel sits IN the form column (aligned,\n // same width as the fieldset cards) and the shell owns the scroll + full height,\n // making the Issues sidebar span the whole surface. No parallel card wrapper.\n return (\n <PortableDetailEditor\n source={source}\n projectId={projectId}\n documentId={self.id}\n formAppendix={<CredentialPanel />}\n />\n )\n}\n\nfunction CenteredNote({ children, testId }: { children: React.ReactNode; testId?: string }) {\n return (\n <Stack className=\"h-full place-items-center p-8\" align=\"center\" justify=\"center\">\n <Text size=\"sm\" tone=\"muted\" {...(testId ? { 'data-testid': testId } : {})}>\n {children}\n </Text>\n </Stack>\n )\n}\n"]}
|
|
@@ -2,8 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { KeyRound, ShieldCheck } from 'lucide-react';
|
|
4
4
|
import { Button, Card, CardContent, Field, Heading, Input, Row, Stack, Text, toast, } from '@elytracms/studio/ui';
|
|
5
|
-
import { translate } from '
|
|
6
|
-
import { changePasswordErrorMessageKey } from '
|
|
5
|
+
import { translate } from '../../lib/i18n/index.js';
|
|
6
|
+
import { changePasswordErrorMessageKey } from '../../lib/auth-errors.js';
|
|
7
7
|
import { useAuth } from '../auth-context.js';
|
|
8
8
|
/**
|
|
9
9
|
* The credential seam (EC-240 H-tail item 3) — part of the account **property
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credential-panel.js","sourceRoot":"","sources":["../../../src/components/account/credential-panel.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEhC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AACpD,OAAO,EACL,MAAM,EACN,IAAI,EACJ,WAAW,EACX,KAAK,EACL,OAAO,EACP,KAAK,EACL,GAAG,EACH,KAAK,EACL,IAAI,EACJ,KAAK,GACN,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"credential-panel.js","sourceRoot":"","sources":["../../../src/components/account/credential-panel.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState } from 'react'\nimport type { FormEvent } from 'react'\nimport { KeyRound, ShieldCheck } from 'lucide-react'\nimport {\n Button,\n Card,\n CardContent,\n Field,\n Heading,\n Input,\n Row,\n Stack,\n Text,\n toast,\n} from '@elytracms/studio/ui'\nimport { translate } from '../../lib/i18n'\nimport { changePasswordErrorMessageKey } from '../../lib/auth-errors'\nimport { useAuth } from '../auth-context'\n\n/**\n * The credential seam (EC-240 H-tail item 3) — part of the account **property\n * surface**, never a modal. Two blocks:\n *\n * - **Sign-in method** (read-only): today every studio account is email + password.\n * OAuth \"connected accounts\" is a deferred extension.\n * - **Change password**: current + new + confirm, handed straight to\n * `AuthAdapter.changePassword` (provider-delegated). SEAM ONLY — the raw values\n * are never logged, stored, or inspected here; they leave in the adapter call.\n *\n * The current-password field is the gate around this sensitive action (no separate\n * confirm dialog needed).\n */\nexport function CredentialPanel() {\n const auth = useAuth()\n const [current, setCurrent] = useState('')\n const [next, setNext] = useState('')\n const [confirm, setConfirm] = useState('')\n const [phase, setPhase] = useState<'idle' | 'submitting'>('idle')\n const [error, setError] = useState<string | null>(null)\n\n async function handleSubmit(event: FormEvent<HTMLFormElement>) {\n event.preventDefault()\n setError(null)\n if (next !== confirm) {\n setError(translate('account.password.mismatch'))\n return\n }\n setPhase('submitting')\n // The raw values leave here ONLY into the provider adapter — never logged.\n const result = await auth.changePassword({ currentPassword: current, newPassword: next })\n setPhase('idle')\n if (result.ok) {\n setCurrent('')\n setNext('')\n setConfirm('')\n toast.success(translate('account.password.changed'))\n return\n }\n // EC-412: engine-classified failures (the EC-377 reasons) localize through\n // the message catalog; an unrecognized shape renders the adapter's raw\n // English message — honest, never a stale mapping (the EC-397 pattern).\n const errorKey = changePasswordErrorMessageKey(result)\n setError(errorKey ? translate(errorKey) : result.message)\n }\n\n const submitting = phase === 'submitting'\n\n return (\n <Card data-testid=\"credential-panel\">\n <CardContent className=\"pt-5\">\n <Stack gap=\"4\">\n <Stack gap=\"1\">\n <Row gap=\"2\" align=\"center\">\n <ShieldCheck className=\"size-4 text-muted-foreground\" />\n <Heading level={3} size=\"h4\">\n {translate('account.security.title')}\n </Heading>\n </Row>\n <Text size=\"sm\" tone=\"muted\">\n {translate('account.security.method')}\n </Text>\n </Stack>\n\n <form onSubmit={handleSubmit} noValidate>\n <Stack gap=\"3\">\n <Field\n label={translate('account.password.current')}\n htmlFor=\"account-current-password\"\n required\n >\n <Input\n id=\"account-current-password\"\n type=\"password\"\n autoComplete=\"current-password\"\n value={current}\n onChange={(e) => setCurrent(e.target.value)}\n disabled={submitting}\n />\n </Field>\n <Field\n label={translate('account.password.new')}\n htmlFor=\"account-new-password\"\n required\n >\n <Input\n id=\"account-new-password\"\n type=\"password\"\n autoComplete=\"new-password\"\n value={next}\n onChange={(e) => setNext(e.target.value)}\n disabled={submitting}\n />\n </Field>\n <Field\n label={translate('account.password.confirm')}\n htmlFor=\"account-confirm-password\"\n required\n error={error}\n >\n <Input\n id=\"account-confirm-password\"\n type=\"password\"\n autoComplete=\"new-password\"\n value={confirm}\n onChange={(e) => setConfirm(e.target.value)}\n disabled={submitting}\n />\n </Field>\n <Row>\n <Button\n type=\"submit\"\n variant=\"outline\"\n disabled={submitting || !current || !next || !confirm}\n >\n <KeyRound />\n {submitting\n ? translate('account.password.changing')\n : translate('account.password.change')}\n </Button>\n </Row>\n </Stack>\n </form>\n </Stack>\n </CardContent>\n </Card>\n )\n}\n"]}
|
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
import type { CollectionDef } from '@elytracms/core/cms-core';
|
|
2
|
+
import type { RolePolicy } from '@elytracms/core/persistence';
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* scope dictates:
|
|
7
|
-
*
|
|
8
|
-
* - **name / avatar are EDITABLE** (not `form.readOnly`) — the person edits their
|
|
9
|
-
* own identity; the source's `save` routes these to `AuthAdapter.updateProfile`
|
|
10
|
-
* (auth-owned), never the members rail.
|
|
11
|
-
* - **email is read-only** (email change is a separate, deferred seam).
|
|
12
|
-
* - **role is read-only** — you never change your own role (the server integrity
|
|
13
|
-
* floor also guards it).
|
|
14
|
-
*
|
|
15
|
-
* Avatar is a plain URL text field for now; the media-picker convention is a
|
|
16
|
-
* deferred polish item — this keeps the mechanism (name + avatar → updateProfile)
|
|
17
|
-
* honest and complete without a half-built picker.
|
|
4
|
+
* EC-605 — the account lens for a project's role policy: the read-only `role` field
|
|
5
|
+
* shows the member's role by its DECLARED label (a project's own role would otherwise
|
|
6
|
+
* render as a value missing from the select). Built once per policy object.
|
|
18
7
|
*/
|
|
8
|
+
export declare function selfAccountCollectionDefFor(policy: RolePolicy): CollectionDef;
|
|
9
|
+
/** The account lens under the DEFAULT role policy (a project declaring no `roles`). */
|
|
19
10
|
export declare const selfAccountCollectionDef: CollectionDef;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { collectionDefSchema } from '@elytracms/core/cms-core';
|
|
2
|
-
import { roleOptions } from '@elytracms/core/persistence';
|
|
3
|
-
import { msgLabel } from '
|
|
2
|
+
import { defaultRolePolicy, roleOptions } from '@elytracms/core/persistence';
|
|
3
|
+
import { msgLabel } from '../../lib/i18n/index.js';
|
|
4
4
|
import { userTitleFallback } from '../users/users-schema.js';
|
|
5
5
|
/**
|
|
6
6
|
* The **account-settings** field lens (EC-240 H-tail) — the schema the portable
|
|
@@ -19,37 +19,55 @@ import { userTitleFallback } from '../users/users-schema.js';
|
|
|
19
19
|
* deferred polish item — this keeps the mechanism (name + avatar → updateProfile)
|
|
20
20
|
* honest and complete without a half-built picker.
|
|
21
21
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
name: 'role',
|
|
49
|
-
type: 'select',
|
|
50
|
-
options: [...roleOptions()],
|
|
51
|
-
form: { label: msgLabel('account.field.role.label'), readOnly: true },
|
|
22
|
+
const accountDefs = new WeakMap();
|
|
23
|
+
/**
|
|
24
|
+
* EC-605 — the account lens for a project's role policy: the read-only `role` field
|
|
25
|
+
* shows the member's role by its DECLARED label (a project's own role would otherwise
|
|
26
|
+
* render as a value missing from the select). Built once per policy object.
|
|
27
|
+
*/
|
|
28
|
+
export function selfAccountCollectionDefFor(policy) {
|
|
29
|
+
let def = accountDefs.get(policy);
|
|
30
|
+
if (!def) {
|
|
31
|
+
def = buildSelfAccountCollectionDef(roleOptions(policy));
|
|
32
|
+
accountDefs.set(policy, def);
|
|
33
|
+
}
|
|
34
|
+
return def;
|
|
35
|
+
}
|
|
36
|
+
function buildSelfAccountCollectionDef(options) {
|
|
37
|
+
return collectionDefSchema.parse({
|
|
38
|
+
id: 'account',
|
|
39
|
+
kind: 'document',
|
|
40
|
+
// EC-396: name → email → id (shared with the users rail) so the account header,
|
|
41
|
+
// breadcrumb, and user menu never show the raw internal id when an email exists.
|
|
42
|
+
titleField: userTitleFallback,
|
|
43
|
+
form: {
|
|
44
|
+
label: msgLabel('account.rail.label'),
|
|
45
|
+
labelSingular: msgLabel('account.rail.labelSingular'),
|
|
52
46
|
},
|
|
53
|
-
|
|
54
|
-
}
|
|
47
|
+
fields: [
|
|
48
|
+
{ name: 'name', type: 'text', form: { label: msgLabel('account.field.name.label') } },
|
|
49
|
+
{
|
|
50
|
+
name: 'avatar',
|
|
51
|
+
type: 'text',
|
|
52
|
+
form: {
|
|
53
|
+
label: msgLabel('account.field.avatar.label'),
|
|
54
|
+
description: msgLabel('account.field.avatar.hint'),
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'email',
|
|
59
|
+
type: 'text',
|
|
60
|
+
form: { label: msgLabel('account.field.email.label'), readOnly: true },
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'role',
|
|
64
|
+
type: 'select',
|
|
65
|
+
options: [...options],
|
|
66
|
+
form: { label: msgLabel('account.field.role.label'), readOnly: true },
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/** The account lens under the DEFAULT role policy (a project declaring no `roles`). */
|
|
72
|
+
export const selfAccountCollectionDef = selfAccountCollectionDefFor(defaultRolePolicy);
|
|
55
73
|
//# sourceMappingURL=self-account-schema.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self-account-schema.js","sourceRoot":"","sources":["../../../src/components/account/self-account-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAE9D,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;
|
|
1
|
+
{"version":3,"file":"self-account-schema.js","sourceRoot":"","sources":["../../../src/components/account/self-account-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAE9D,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAE5E,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAEzD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,GAAG,IAAI,OAAO,EAA6B,CAAA;AAE5D;;;;GAIG;AACH,MAAM,UAAU,2BAA2B,CAAC,MAAkB;IAC5D,IAAI,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACjC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,GAAG,GAAG,6BAA6B,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAA;QACxD,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC9B,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,SAAS,6BAA6B,CAAC,OAA2C;IAChF,OAAO,mBAAmB,CAAC,KAAK,CAAC;QAC/B,EAAE,EAAE,SAAS;QACb,IAAI,EAAE,UAAU;QAChB,gFAAgF;QAChF,iFAAiF;QACjF,UAAU,EAAE,iBAAiB;QAC7B,IAAI,EAAE;YACJ,KAAK,EAAE,QAAQ,CAAC,oBAAoB,CAAC;YACrC,aAAa,EAAE,QAAQ,CAAC,4BAA4B,CAAC;SACtD;QACD,MAAM,EAAE;YACN,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,0BAA0B,CAAC,EAAE,EAAE;YACrF;gBACE,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE;oBACJ,KAAK,EAAE,QAAQ,CAAC,4BAA4B,CAAC;oBAC7C,WAAW,EAAE,QAAQ,CAAC,2BAA2B,CAAC;iBACnD;aACF;YACD;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,2BAA2B,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE;aACvE;YACD;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC;gBACrB,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,0BAA0B,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE;aACtE;SACF;KACF,CAAC,CAAA;AACJ,CAAC;AAED,uFAAuF;AACvF,MAAM,CAAC,MAAM,wBAAwB,GAAkB,2BAA2B,CAAC,iBAAiB,CAAC,CAAA","sourcesContent":["import { collectionDefSchema } from '@elytracms/core/cms-core'\nimport type { CollectionDef } from '@elytracms/core/cms-core'\nimport { defaultRolePolicy, roleOptions } from '@elytracms/core/persistence'\nimport type { RolePolicy } from '@elytracms/core/persistence'\nimport { msgLabel } from '../../lib/i18n'\nimport { userTitleFallback } from '../users/users-schema'\n\n/**\n * The **account-settings** field lens (EC-240 H-tail) — the schema the portable\n * edit shell renders when a member opens their OWN record (via the user menu). It\n * diverges from the admin `usersCollectionDef` in exactly the way the ratified\n * scope dictates:\n *\n * - **name / avatar are EDITABLE** (not `form.readOnly`) — the person edits their\n * own identity; the source's `save` routes these to `AuthAdapter.updateProfile`\n * (auth-owned), never the members rail.\n * - **email is read-only** (email change is a separate, deferred seam).\n * - **role is read-only** — you never change your own role (the server integrity\n * floor also guards it).\n *\n * Avatar is a plain URL text field for now; the media-picker convention is a\n * deferred polish item — this keeps the mechanism (name + avatar → updateProfile)\n * honest and complete without a half-built picker.\n */\nconst accountDefs = new WeakMap<RolePolicy, CollectionDef>()\n\n/**\n * EC-605 — the account lens for a project's role policy: the read-only `role` field\n * shows the member's role by its DECLARED label (a project's own role would otherwise\n * render as a value missing from the select). Built once per policy object.\n */\nexport function selfAccountCollectionDefFor(policy: RolePolicy): CollectionDef {\n let def = accountDefs.get(policy)\n if (!def) {\n def = buildSelfAccountCollectionDef(roleOptions(policy))\n accountDefs.set(policy, def)\n }\n return def\n}\n\nfunction buildSelfAccountCollectionDef(options: { value: string; label: string }[]): CollectionDef {\n return collectionDefSchema.parse({\n id: 'account',\n kind: 'document',\n // EC-396: name → email → id (shared with the users rail) so the account header,\n // breadcrumb, and user menu never show the raw internal id when an email exists.\n titleField: userTitleFallback,\n form: {\n label: msgLabel('account.rail.label'),\n labelSingular: msgLabel('account.rail.labelSingular'),\n },\n fields: [\n { name: 'name', type: 'text', form: { label: msgLabel('account.field.name.label') } },\n {\n name: 'avatar',\n type: 'text',\n form: {\n label: msgLabel('account.field.avatar.label'),\n description: msgLabel('account.field.avatar.hint'),\n },\n },\n {\n name: 'email',\n type: 'text',\n form: { label: msgLabel('account.field.email.label'), readOnly: true },\n },\n {\n name: 'role',\n type: 'select',\n options: [...options],\n form: { label: msgLabel('account.field.role.label'), readOnly: true },\n },\n ],\n })\n}\n\n/** The account lens under the DEFAULT role policy (a project declaring no `roles`). */\nexport const selfAccountCollectionDef: CollectionDef = selfAccountCollectionDefFor(defaultRolePolicy)\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CmsDocument } from '@elytracms/core/cms-core';
|
|
2
2
|
import type { UserRecord } from '@elytracms/core/persistence';
|
|
3
|
-
import type { CollectionViewCapabilities, CollectionViewSource } from '
|
|
3
|
+
import type { CollectionViewCapabilities, CollectionViewSource } from '../../lib/collection-view/collection-view-source.js';
|
|
4
4
|
/**
|
|
5
5
|
* The capability profile of the account surface (EC-240 H-tail): a single self
|
|
6
6
|
* record edited in place — no publish/versions/create/remove/import. The record
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
2
|
import { studioPath } from '@elytracms/studio/router';
|
|
3
|
-
import { translate } from '
|
|
4
|
-
import { updateProfileErrorMessageKey } from '
|
|
3
|
+
import { translate } from '../../lib/i18n/index.js';
|
|
4
|
+
import { updateProfileErrorMessageKey } from '../../lib/auth-errors.js';
|
|
5
5
|
import { useAuth } from '../auth-context.js';
|
|
6
|
-
import { selfAccountCollectionDef } from './self-account-schema.js';
|
|
6
|
+
import { selfAccountCollectionDef, selfAccountCollectionDefFor } from './self-account-schema.js';
|
|
7
|
+
import { projectRolePolicyFor } from '../../lib/operations/project-runtime-config.js';
|
|
7
8
|
import { normalizeOkResult, useRailViewSource } from '../rail-view-source.js';
|
|
8
9
|
import { parseLocaleConfig } from '@elytracms/core/cms-core';
|
|
9
10
|
/** The account surface is not localized — one implicit locale keeps the lens honest. */
|
|
@@ -98,7 +99,8 @@ export function useSelfAccountViewSource(input) {
|
|
|
98
99
|
}, []);
|
|
99
100
|
return useRailViewSource({
|
|
100
101
|
projectId,
|
|
101
|
-
|
|
102
|
+
// EC-605: the role is shown by THIS project's declared label (stable per policy).
|
|
103
|
+
schema: selfAccountCollectionDefFor(projectRolePolicyFor(projectId)),
|
|
102
104
|
capabilities: ACCOUNT_CAPABILITIES,
|
|
103
105
|
localeConfig: ACCOUNT_LOCALE_CONFIG,
|
|
104
106
|
documents,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self-account-view-source.js","sourceRoot":"","sources":["../../../src/components/account/self-account-view-source.ts"],"names":[],"mappings":"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","sourcesContent":["import { useCallback } from 'react'\nimport type { CmsDocument, CmsValidationIssue, DocumentRef, Locale, LocaleConfig } from '@elytracms/core/cms-core'\nimport type { UserRecord } from '@elytracms/core/persistence'\nimport { studioPath } from '@elytracms/studio/router'\nimport type {\n CollectionViewCapabilities,\n CollectionViewSource,\n} from '@elytracms/studio/lib/collection-view/collection-view-source'\nimport type { OperationError } from '@elytracms/core/operations'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { updateProfileErrorMessageKey } from '@elytracms/studio/lib/auth-errors'\nimport { useAuth } from '../auth-context'\nimport { selfAccountCollectionDef } from './self-account-schema'\nimport { normalizeOkResult, useRailViewSource } from '../rail-view-source'\nimport { parseLocaleConfig } from '@elytracms/core/cms-core'\n\n/** The account surface is not localized — one implicit locale keeps the lens honest. */\nconst ACCOUNT_LOCALE: Locale = 'en'\nconst ACCOUNT_LOCALE_CONFIG: LocaleConfig = parseLocaleConfig({ default: ACCOUNT_LOCALE, locales: [ACCOUNT_LOCALE] })\n\n/**\n * The capability profile of the account surface (EC-240 H-tail): a single self\n * record edited in place — no publish/versions/create/remove/import. The record\n * is the caller's own; there is nothing to delete or list.\n */\nexport const ACCOUNT_CAPABILITIES: CollectionViewCapabilities = {\n publish: false,\n versions: false,\n locales: false,\n inlineEdit: false,\n create: false,\n duplicate: false,\n remove: false,\n bulk: false,\n liveUrl: false,\n hierarchy: false,\n importExport: false,\n}\n\n/** Everything in `values` that is NOT an editable identity field is display-only. */\nconst EDITABLE_IDENTITY = new Set(['name', 'avatar'])\n\n/** Project the self record into the account lens's `values`. */\nexport function selfToDocument(record: UserRecord): CmsDocument {\n return {\n collection: selfAccountCollectionDef.id,\n id: record.id,\n values: {\n name: record.name ?? '',\n avatar: record.avatar ?? '',\n email: record.email,\n role: record.roles[0] ?? 'viewer',\n },\n }\n}\n\n/**\n * Compute the identity diff (name / avatar) an edited account document carries —\n * the exact seam handed to `AuthAdapter.updateProfile`. Pure so the split-write is\n * unit-testable: only the fields the person changed are sent (an empty diff is a\n * no-op the caller can short-circuit). Never carries `email`/`role` — those are\n * read-only on this surface and are not auth-adapter-writable here.\n */\nexport function accountIdentityDiff(\n doc: CmsDocument,\n previous: UserRecord,\n): { name?: string; avatar?: string } {\n const values = doc.values ?? {}\n const diff: { name?: string; avatar?: string } = {}\n const nextName = typeof values.name === 'string' ? values.name : ''\n const nextAvatar = typeof values.avatar === 'string' ? values.avatar : ''\n if (nextName !== (previous.name ?? '')) diff.name = nextName\n if (nextAvatar !== (previous.avatar ?? '')) diff.avatar = nextAvatar\n return diff\n}\n\n/**\n * Assemble a {@link CollectionViewSource} for the **account-settings** surface\n * (EC-240 H-tail). Reuses the portable edit shell over the caller's OWN record —\n * name/avatar editable, email/role read-only (per the schema). The `save` routes\n * the identity diff to `AuthAdapter.updateProfile` (auth-owned) — NOT the\n * members-rail `users.save` — then refreshes the loaded record. `EDITABLE_IDENTITY`\n * marks which fields the save may write; everything else is display-only.\n */\nexport function useSelfAccountViewSource(input: {\n projectId: string\n self: UserRecord\n refresh: () => Promise<void>\n}): CollectionViewSource {\n const { projectId, self, refresh } = input\n const auth = useAuth()\n\n const documents = useCallback(() => [selfToDocument(self)], [self])\n const get = useCallback(\n (ref: DocumentRef): CmsDocument | undefined =>\n ref.id === self.id ? selfToDocument(self) : undefined,\n [self],\n )\n const titleOf = useCallback(() => self.name || self.email || self.id, [self])\n\n const save = useCallback(\n async (doc: CmsDocument): Promise<{ ok: true } | { ok: false; message: string }> => {\n const diff = accountIdentityDiff(doc, self)\n // No identity change (e.g. a read-only-only edit) → nothing to write.\n if (diff.name === undefined && diff.avatar === undefined) return { ok: true }\n const result = await auth.updateProfile(diff)\n if (!result.ok) {\n // EC-416: engine-classified failures localize through the message\n // catalog; an unrecognized shape renders the adapter's raw English\n // message — honest, never a stale mapping (the EC-397/EC-412 pattern).\n const errorKey = updateProfileErrorMessageKey(result)\n return { ok: false, message: errorKey ? translate(errorKey) : result.message }\n }\n // Reflect the new identity in the loaded record (session already refreshed).\n await refresh()\n return { ok: true }\n },\n [auth, self, refresh],\n )\n\n const noRemove = useCallback(\n async (): Promise<{ ok: true }> => ({ ok: true }),\n [],\n )\n const noValidation = useCallback((): CmsValidationIssue[] => [], [])\n const createUnsupported = useCallback((): DocumentRef => {\n throw new Error('the account surface has no create')\n }, [])\n\n return useRailViewSource({\n projectId,\n schema: selfAccountCollectionDef,\n capabilities: ACCOUNT_CAPABILITIES,\n localeConfig: ACCOUNT_LOCALE_CONFIG,\n documents,\n get,\n titleOf,\n // Editable-identity fields drive writability; the rest are read-only per schema.\n isFieldReadOnly: (field) => !EDITABLE_IDENTITY.has(field.name) || (field.form?.readOnly ?? false),\n detailPath: (id: string) => studioPath.user(id),\n listPath: studioPath.users(),\n validate: noValidation,\n create: createUnsupported,\n save,\n remove: noRemove,\n normalizeSaveResult: normalizeOkResult,\n normalizeRemoveResult: (): OperationError | null => null,\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"self-account-view-source.js","sourceRoot":"","sources":["../../../src/components/account/self-account-view-source.ts"],"names":[],"mappings":"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","sourcesContent":["import { useCallback } from 'react'\nimport type { CmsDocument, CmsValidationIssue, DocumentRef, Locale, LocaleConfig } from '@elytracms/core/cms-core'\nimport type { UserRecord } from '@elytracms/core/persistence'\nimport { studioPath } from '@elytracms/studio/router'\nimport type {\n CollectionViewCapabilities,\n CollectionViewSource,\n} from '../../lib/collection-view/collection-view-source'\nimport type { OperationError } from '@elytracms/core/operations'\nimport { translate } from '../../lib/i18n'\nimport { updateProfileErrorMessageKey } from '../../lib/auth-errors'\nimport { useAuth } from '../auth-context'\nimport { selfAccountCollectionDef, selfAccountCollectionDefFor } from './self-account-schema'\nimport { projectRolePolicyFor } from '../../lib/operations/project-runtime-config'\nimport { normalizeOkResult, useRailViewSource } from '../rail-view-source'\nimport { parseLocaleConfig } from '@elytracms/core/cms-core'\n\n/** The account surface is not localized — one implicit locale keeps the lens honest. */\nconst ACCOUNT_LOCALE: Locale = 'en'\nconst ACCOUNT_LOCALE_CONFIG: LocaleConfig = parseLocaleConfig({ default: ACCOUNT_LOCALE, locales: [ACCOUNT_LOCALE] })\n\n/**\n * The capability profile of the account surface (EC-240 H-tail): a single self\n * record edited in place — no publish/versions/create/remove/import. The record\n * is the caller's own; there is nothing to delete or list.\n */\nexport const ACCOUNT_CAPABILITIES: CollectionViewCapabilities = {\n publish: false,\n versions: false,\n locales: false,\n inlineEdit: false,\n create: false,\n duplicate: false,\n remove: false,\n bulk: false,\n liveUrl: false,\n hierarchy: false,\n importExport: false,\n}\n\n/** Everything in `values` that is NOT an editable identity field is display-only. */\nconst EDITABLE_IDENTITY = new Set(['name', 'avatar'])\n\n/** Project the self record into the account lens's `values`. */\nexport function selfToDocument(record: UserRecord): CmsDocument {\n return {\n collection: selfAccountCollectionDef.id,\n id: record.id,\n values: {\n name: record.name ?? '',\n avatar: record.avatar ?? '',\n email: record.email,\n role: record.roles[0] ?? 'viewer',\n },\n }\n}\n\n/**\n * Compute the identity diff (name / avatar) an edited account document carries —\n * the exact seam handed to `AuthAdapter.updateProfile`. Pure so the split-write is\n * unit-testable: only the fields the person changed are sent (an empty diff is a\n * no-op the caller can short-circuit). Never carries `email`/`role` — those are\n * read-only on this surface and are not auth-adapter-writable here.\n */\nexport function accountIdentityDiff(\n doc: CmsDocument,\n previous: UserRecord,\n): { name?: string; avatar?: string } {\n const values = doc.values ?? {}\n const diff: { name?: string; avatar?: string } = {}\n const nextName = typeof values.name === 'string' ? values.name : ''\n const nextAvatar = typeof values.avatar === 'string' ? values.avatar : ''\n if (nextName !== (previous.name ?? '')) diff.name = nextName\n if (nextAvatar !== (previous.avatar ?? '')) diff.avatar = nextAvatar\n return diff\n}\n\n/**\n * Assemble a {@link CollectionViewSource} for the **account-settings** surface\n * (EC-240 H-tail). Reuses the portable edit shell over the caller's OWN record —\n * name/avatar editable, email/role read-only (per the schema). The `save` routes\n * the identity diff to `AuthAdapter.updateProfile` (auth-owned) — NOT the\n * members-rail `users.save` — then refreshes the loaded record. `EDITABLE_IDENTITY`\n * marks which fields the save may write; everything else is display-only.\n */\nexport function useSelfAccountViewSource(input: {\n projectId: string\n self: UserRecord\n refresh: () => Promise<void>\n}): CollectionViewSource {\n const { projectId, self, refresh } = input\n const auth = useAuth()\n\n const documents = useCallback(() => [selfToDocument(self)], [self])\n const get = useCallback(\n (ref: DocumentRef): CmsDocument | undefined =>\n ref.id === self.id ? selfToDocument(self) : undefined,\n [self],\n )\n const titleOf = useCallback(() => self.name || self.email || self.id, [self])\n\n const save = useCallback(\n async (doc: CmsDocument): Promise<{ ok: true } | { ok: false; message: string }> => {\n const diff = accountIdentityDiff(doc, self)\n // No identity change (e.g. a read-only-only edit) → nothing to write.\n if (diff.name === undefined && diff.avatar === undefined) return { ok: true }\n const result = await auth.updateProfile(diff)\n if (!result.ok) {\n // EC-416: engine-classified failures localize through the message\n // catalog; an unrecognized shape renders the adapter's raw English\n // message — honest, never a stale mapping (the EC-397/EC-412 pattern).\n const errorKey = updateProfileErrorMessageKey(result)\n return { ok: false, message: errorKey ? translate(errorKey) : result.message }\n }\n // Reflect the new identity in the loaded record (session already refreshed).\n await refresh()\n return { ok: true }\n },\n [auth, self, refresh],\n )\n\n const noRemove = useCallback(\n async (): Promise<{ ok: true }> => ({ ok: true }),\n [],\n )\n const noValidation = useCallback((): CmsValidationIssue[] => [], [])\n const createUnsupported = useCallback((): DocumentRef => {\n throw new Error('the account surface has no create')\n }, [])\n\n return useRailViewSource({\n projectId,\n // EC-605: the role is shown by THIS project's declared label (stable per policy).\n schema: selfAccountCollectionDefFor(projectRolePolicyFor(projectId)),\n capabilities: ACCOUNT_CAPABILITIES,\n localeConfig: ACCOUNT_LOCALE_CONFIG,\n documents,\n get,\n titleOf,\n // Editable-identity fields drive writability; the rest are read-only per schema.\n isFieldReadOnly: (field) => !EDITABLE_IDENTITY.has(field.name) || (field.form?.readOnly ?? false),\n detailPath: (id: string) => studioPath.user(id),\n listPath: studioPath.users(),\n validate: noValidation,\n create: createUnsupported,\n save,\n remove: noRemove,\n normalizeSaveResult: normalizeOkResult,\n normalizeRemoveResult: (): OperationError | null => null,\n })\n}\n"]}
|