@elytracms/studio 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/convex/assets.ts +107 -0
- package/convex/auth.config.ts +15 -0
- package/convex/auth.ts +50 -0
- package/convex/cliTokens.ts +63 -0
- package/convex/cms.ts +174 -0
- package/convex/content.ts +316 -0
- package/convex/delivery.ts +266 -0
- package/convex/functions.ts +35 -0
- package/convex/graphs.ts +51 -0
- package/convex/guard.ts +67 -0
- package/convex/http.ts +30 -0
- package/convex/members.ts +83 -0
- package/convex/publishing.ts +102 -0
- package/convex/references.ts +168 -0
- package/convex/schema.ts +173 -0
- package/convex/sync.ts +322 -0
- package/convex/tsconfig.json +12 -0
- package/convex/users.ts +23 -0
- package/convex/webhooks.ts +85 -0
- package/dist/components/assets/asset-library.d.ts +14 -0
- package/dist/components/assets/asset-library.js +191 -0
- package/dist/components/assets/asset-library.js.map +1 -0
- package/dist/components/assets/asset-metadata.d.ts +34 -0
- package/dist/components/assets/asset-metadata.js +40 -0
- package/dist/components/assets/asset-metadata.js.map +1 -0
- package/dist/components/assets/asset-search.d.ts +7 -0
- package/dist/components/assets/asset-search.js +12 -0
- package/dist/components/assets/asset-search.js.map +1 -0
- package/dist/components/assets/asset-selection.d.ts +17 -0
- package/dist/components/assets/asset-selection.js +33 -0
- package/dist/components/assets/asset-selection.js.map +1 -0
- package/dist/components/assets/assets-store.d.ts +51 -0
- package/dist/components/assets/assets-store.js +153 -0
- package/dist/components/assets/assets-store.js.map +1 -0
- package/dist/components/auth-context.d.ts +38 -0
- package/dist/components/auth-context.js +88 -0
- package/dist/components/auth-context.js.map +1 -0
- package/dist/components/backend-gate.d.ts +19 -0
- package/dist/components/backend-gate.js +63 -0
- package/dist/components/backend-gate.js.map +1 -0
- package/dist/components/breadcrumb-context.d.ts +39 -0
- package/dist/components/breadcrumb-context.js +38 -0
- package/dist/components/breadcrumb-context.js.map +1 -0
- package/dist/components/builder/blocks-model.d.ts +80 -0
- package/dist/components/builder/blocks-model.js +181 -0
- package/dist/components/builder/blocks-model.js.map +1 -0
- package/dist/components/builder/blocks-panel.d.ts +44 -0
- package/dist/components/builder/blocks-panel.js +147 -0
- package/dist/components/builder/blocks-panel.js.map +1 -0
- package/dist/components/builder/builder-store.d.ts +69 -0
- package/dist/components/builder/builder-store.js +294 -0
- package/dist/components/builder/builder-store.js.map +1 -0
- package/dist/components/builder/canvas-stylesheet.d.ts +4 -0
- package/dist/components/builder/canvas-stylesheet.js +24 -0
- package/dist/components/builder/canvas-stylesheet.js.map +1 -0
- package/dist/components/builder/canvas.d.ts +8 -0
- package/dist/components/builder/canvas.js +723 -0
- package/dist/components/builder/canvas.js.map +1 -0
- package/dist/components/builder/clipboard-actions.d.ts +93 -0
- package/dist/components/builder/clipboard-actions.js +246 -0
- package/dist/components/builder/clipboard-actions.js.map +1 -0
- package/dist/components/builder/composition-field-editor.d.ts +11 -0
- package/dist/components/builder/composition-field-editor.js +150 -0
- package/dist/components/builder/composition-field-editor.js.map +1 -0
- package/dist/components/builder/composition-scope.d.ts +16 -0
- package/dist/components/builder/composition-scope.js +7 -0
- package/dist/components/builder/composition-scope.js.map +1 -0
- package/dist/components/builder/drag-session.d.ts +41 -0
- package/dist/components/builder/drag-session.js +51 -0
- package/dist/components/builder/drag-session.js.map +1 -0
- package/dist/components/builder/fixture-thumbnail.d.ts +18 -0
- package/dist/components/builder/fixture-thumbnail.js +97 -0
- package/dist/components/builder/fixture-thumbnail.js.map +1 -0
- package/dist/components/builder/inline-edit.d.ts +142 -0
- package/dist/components/builder/inline-edit.js +136 -0
- package/dist/components/builder/inline-edit.js.map +1 -0
- package/dist/components/builder/insert-context.d.ts +14 -0
- package/dist/components/builder/insert-context.js +65 -0
- package/dist/components/builder/insert-context.js.map +1 -0
- package/dist/components/builder/insert-menu.d.ts +9 -0
- package/dist/components/builder/insert-menu.js +9 -0
- package/dist/components/builder/insert-menu.js.map +1 -0
- package/dist/components/builder/layout-inspector.d.ts +14 -0
- package/dist/components/builder/layout-inspector.js +84 -0
- package/dist/components/builder/layout-inspector.js.map +1 -0
- package/dist/components/builder/node-factory.d.ts +17 -0
- package/dist/components/builder/node-factory.js +90 -0
- package/dist/components/builder/node-factory.js.map +1 -0
- package/dist/components/builder/page-tree.d.ts +3 -0
- package/dist/components/builder/page-tree.js +207 -0
- package/dist/components/builder/page-tree.js.map +1 -0
- package/dist/components/builder/property-inspector.d.ts +1 -0
- package/dist/components/builder/property-inspector.js +233 -0
- package/dist/components/builder/property-inspector.js.map +1 -0
- package/dist/components/builder/rich-text-toolbar.d.ts +4 -0
- package/dist/components/builder/rich-text-toolbar.js +104 -0
- package/dist/components/builder/rich-text-toolbar.js.map +1 -0
- package/dist/components/builder/spacing-handles.d.ts +22 -0
- package/dist/components/builder/spacing-handles.js +213 -0
- package/dist/components/builder/spacing-handles.js.map +1 -0
- package/dist/components/cms/asset-picker.d.ts +12 -0
- package/dist/components/cms/asset-picker.js +60 -0
- package/dist/components/cms/asset-picker.js.map +1 -0
- package/dist/components/cms/bulk-actions.d.ts +60 -0
- package/dist/components/cms/bulk-actions.js +95 -0
- package/dist/components/cms/bulk-actions.js.map +1 -0
- package/dist/components/cms/bulk-bar.d.ts +23 -0
- package/dist/components/cms/bulk-bar.js +26 -0
- package/dist/components/cms/bulk-bar.js.map +1 -0
- package/dist/components/cms/cell-edit.d.ts +91 -0
- package/dist/components/cms/cell-edit.js +144 -0
- package/dist/components/cms/cell-edit.js.map +1 -0
- package/dist/components/cms/cell.d.ts +29 -0
- package/dist/components/cms/cell.js +127 -0
- package/dist/components/cms/cell.js.map +1 -0
- package/dist/components/cms/cms-index.d.ts +8 -0
- package/dist/components/cms/cms-index.js +23 -0
- package/dist/components/cms/cms-index.js.map +1 -0
- package/dist/components/cms/cms-store.d.ts +188 -0
- package/dist/components/cms/cms-store.js +702 -0
- package/dist/components/cms/cms-store.js.map +1 -0
- package/dist/components/cms/collection-table.d.ts +6 -0
- package/dist/components/cms/collection-table.js +250 -0
- package/dist/components/cms/collection-table.js.map +1 -0
- package/dist/components/cms/collections-sidebar.d.ts +9 -0
- package/dist/components/cms/collections-sidebar.js +25 -0
- package/dist/components/cms/collections-sidebar.js.map +1 -0
- package/dist/components/cms/detail-editor.d.ts +7 -0
- package/dist/components/cms/detail-editor.js +386 -0
- package/dist/components/cms/detail-editor.js.map +1 -0
- package/dist/components/cms/doc-state.d.ts +13 -0
- package/dist/components/cms/doc-state.js +18 -0
- package/dist/components/cms/doc-state.js.map +1 -0
- package/dist/components/cms/document-editor-context.d.ts +48 -0
- package/dist/components/cms/document-editor-context.js +23 -0
- package/dist/components/cms/document-editor-context.js.map +1 -0
- package/dist/components/cms/editable-cell.d.ts +22 -0
- package/dist/components/cms/editable-cell.js +176 -0
- package/dist/components/cms/editable-cell.js.map +1 -0
- package/dist/components/cms/field-control.d.ts +8 -0
- package/dist/components/cms/field-control.js +149 -0
- package/dist/components/cms/field-control.js.map +1 -0
- package/dist/components/cms/filter-builder.d.ts +12 -0
- package/dist/components/cms/filter-builder.js +84 -0
- package/dist/components/cms/filter-builder.js.map +1 -0
- package/dist/components/cms/import-export.d.ts +6 -0
- package/dist/components/cms/import-export.js +33 -0
- package/dist/components/cms/import-export.js.map +1 -0
- package/dist/components/cms/new-page-dialog.d.ts +22 -0
- package/dist/components/cms/new-page-dialog.js +42 -0
- package/dist/components/cms/new-page-dialog.js.map +1 -0
- package/dist/components/cms/reference-confirm.d.ts +25 -0
- package/dist/components/cms/reference-confirm.js +124 -0
- package/dist/components/cms/reference-confirm.js.map +1 -0
- package/dist/components/cms/relation-picker.d.ts +16 -0
- package/dist/components/cms/relation-picker.js +47 -0
- package/dist/components/cms/relation-picker.js.map +1 -0
- package/dist/components/cms/use-cell-edit.d.ts +33 -0
- package/dist/components/cms/use-cell-edit.js +125 -0
- package/dist/components/cms/use-cell-edit.js.map +1 -0
- package/dist/components/cms/versions-model.d.ts +15 -0
- package/dist/components/cms/versions-model.js +23 -0
- package/dist/components/cms/versions-model.js.map +1 -0
- package/dist/components/cms/versions-pane.d.ts +14 -0
- package/dist/components/cms/versions-pane.js +86 -0
- package/dist/components/cms/versions-pane.js.map +1 -0
- package/dist/components/cms/view-bar.d.ts +11 -0
- package/dist/components/cms/view-bar.js +80 -0
- package/dist/components/cms/view-bar.js.map +1 -0
- package/dist/components/collab/collab-context.d.ts +34 -0
- package/dist/components/collab/collab-context.js +52 -0
- package/dist/components/collab/collab-context.js.map +1 -0
- package/dist/components/collab/collab-seed.d.ts +27 -0
- package/dist/components/collab/collab-seed.js +42 -0
- package/dist/components/collab/collab-seed.js.map +1 -0
- package/dist/components/components/component-detail.d.ts +9 -0
- package/dist/components/components/component-detail.js +30 -0
- package/dist/components/components/component-detail.js.map +1 -0
- package/dist/components/components/component-status.d.ts +10 -0
- package/dist/components/components/component-status.js +30 -0
- package/dist/components/components/component-status.js.map +1 -0
- package/dist/components/components/components-index.d.ts +8 -0
- package/dist/components/components/components-index.js +42 -0
- package/dist/components/components/components-index.js.map +1 -0
- package/dist/components/components/field-inspector.d.ts +9 -0
- package/dist/components/components/field-inspector.js +38 -0
- package/dist/components/components/field-inspector.js.map +1 -0
- package/dist/components/components/fixture-runner.d.ts +10 -0
- package/dist/components/components/fixture-runner.js +24 -0
- package/dist/components/components/fixture-runner.js.map +1 -0
- package/dist/components/components/registry-browser.d.ts +4 -0
- package/dist/components/components/registry-browser.js +64 -0
- package/dist/components/components/registry-browser.js.map +1 -0
- package/dist/components/current-user-menu.d.ts +13 -0
- package/dist/components/current-user-menu.js +31 -0
- package/dist/components/current-user-menu.js.map +1 -0
- package/dist/components/dev-login-badge.d.ts +9 -0
- package/dist/components/dev-login-badge.js +18 -0
- package/dist/components/dev-login-badge.js.map +1 -0
- package/dist/components/extensions/extensions-view.d.ts +7 -0
- package/dist/components/extensions/extensions-view.js +126 -0
- package/dist/components/extensions/extensions-view.js.map +1 -0
- package/dist/components/guards.d.ts +27 -0
- package/dist/components/guards.js +46 -0
- package/dist/components/guards.js.map +1 -0
- package/dist/components/inspector/inspector-sidebar.d.ts +26 -0
- package/dist/components/inspector/inspector-sidebar.js +17 -0
- package/dist/components/inspector/inspector-sidebar.js.map +1 -0
- package/dist/components/operation-error.d.ts +17 -0
- package/dist/components/operation-error.js +54 -0
- package/dist/components/operation-error.js.map +1 -0
- package/dist/components/playground-badge.d.ts +10 -0
- package/dist/components/playground-badge.js +19 -0
- package/dist/components/playground-badge.js.map +1 -0
- package/dist/components/project-list.d.ts +15 -0
- package/dist/components/project-list.js +52 -0
- package/dist/components/project-list.js.map +1 -0
- package/dist/components/project-session.d.ts +46 -0
- package/dist/components/project-session.js +107 -0
- package/dist/components/project-session.js.map +1 -0
- package/dist/components/project-switcher.d.ts +11 -0
- package/dist/components/project-switcher.js +44 -0
- package/dist/components/project-switcher.js.map +1 -0
- package/dist/components/references/builder-deep-link.d.ts +12 -0
- package/dist/components/references/builder-deep-link.js +53 -0
- package/dist/components/references/builder-deep-link.js.map +1 -0
- package/dist/components/references/references-panel.d.ts +17 -0
- package/dist/components/references/references-panel.js +66 -0
- package/dist/components/references/references-panel.js.map +1 -0
- package/dist/components/routes/redirect-chain.d.ts +9 -0
- package/dist/components/routes/redirect-chain.js +16 -0
- package/dist/components/routes/redirect-chain.js.map +1 -0
- package/dist/components/routes/redirect-manager.d.ts +13 -0
- package/dist/components/routes/redirect-manager.js +24 -0
- package/dist/components/routes/redirect-manager.js.map +1 -0
- package/dist/components/routes/route-list.d.ts +35 -0
- package/dist/components/routes/route-list.js +69 -0
- package/dist/components/routes/route-list.js.map +1 -0
- package/dist/components/routes/routes-shell.d.ts +14 -0
- package/dist/components/routes/routes-shell.js +68 -0
- package/dist/components/routes/routes-shell.js.map +1 -0
- package/dist/components/section-nav.d.ts +17 -0
- package/dist/components/section-nav.js +33 -0
- package/dist/components/section-nav.js.map +1 -0
- package/dist/components/section-state.d.ts +24 -0
- package/dist/components/section-state.js +78 -0
- package/dist/components/section-state.js.map +1 -0
- package/dist/components/section-surface.d.ts +31 -0
- package/dist/components/section-surface.js +46 -0
- package/dist/components/section-surface.js.map +1 -0
- package/dist/components/sections.d.ts +38 -0
- package/dist/components/sections.js +72 -0
- package/dist/components/sections.js.map +1 -0
- package/dist/components/settings-form.d.ts +10 -0
- package/dist/components/settings-form.js +17 -0
- package/dist/components/settings-form.js.map +1 -0
- package/dist/components/studio-context.d.ts +22 -0
- package/dist/components/studio-context.js +48 -0
- package/dist/components/studio-context.js.map +1 -0
- package/dist/components/studio-project-screen.d.ts +19 -0
- package/dist/components/studio-project-screen.js +195 -0
- package/dist/components/studio-project-screen.js.map +1 -0
- package/dist/components/studio-shell.d.ts +18 -0
- package/dist/components/studio-shell.js +64 -0
- package/dist/components/studio-shell.js.map +1 -0
- package/dist/components/theme-context.d.ts +17 -0
- package/dist/components/theme-context.js +26 -0
- package/dist/components/theme-context.js.map +1 -0
- package/dist/components/workspace-gate.d.ts +12 -0
- package/dist/components/workspace-gate.js +27 -0
- package/dist/components/workspace-gate.js.map +1 -0
- package/dist/components/workspace-projects.d.ts +13 -0
- package/dist/components/workspace-projects.js +18 -0
- package/dist/components/workspace-projects.js.map +1 -0
- package/dist/lib/assets/delete-asset.d.ts +34 -0
- package/dist/lib/assets/delete-asset.js +34 -0
- package/dist/lib/assets/delete-asset.js.map +1 -0
- package/dist/lib/assets/image-dimensions.d.ts +18 -0
- package/dist/lib/assets/image-dimensions.js +26 -0
- package/dist/lib/assets/image-dimensions.js.map +1 -0
- package/dist/lib/assets/index.d.ts +9 -0
- package/dist/lib/assets/index.js +10 -0
- package/dist/lib/assets/index.js.map +1 -0
- package/dist/lib/assets/upload-state.d.ts +53 -0
- package/dist/lib/assets/upload-state.js +59 -0
- package/dist/lib/assets/upload-state.js.map +1 -0
- package/dist/lib/assets/upload.d.ts +56 -0
- package/dist/lib/assets/upload.js +125 -0
- package/dist/lib/assets/upload.js.map +1 -0
- package/dist/lib/auth/auth-adapter.d.ts +57 -0
- package/dist/lib/auth/auth-adapter.js +13 -0
- package/dist/lib/auth/auth-adapter.js.map +1 -0
- package/dist/lib/auth/convex-auth-adapter.d.ts +39 -0
- package/dist/lib/auth/convex-auth-adapter.js +171 -0
- package/dist/lib/auth/convex-auth-adapter.js.map +1 -0
- package/dist/lib/auth/dev-auto-login-adapter.d.ts +25 -0
- package/dist/lib/auth/dev-auto-login-adapter.js +40 -0
- package/dist/lib/auth/dev-auto-login-adapter.js.map +1 -0
- package/dist/lib/auth/index.d.ts +28 -0
- package/dist/lib/auth/index.js +61 -0
- package/dist/lib/auth/index.js.map +1 -0
- package/dist/lib/auth/local-auth-adapter.d.ts +57 -0
- package/dist/lib/auth/local-auth-adapter.js +78 -0
- package/dist/lib/auth/local-auth-adapter.js.map +1 -0
- package/dist/lib/auth/route-guard.d.ts +33 -0
- package/dist/lib/auth/route-guard.js +51 -0
- package/dist/lib/auth/route-guard.js.map +1 -0
- package/dist/lib/auth-errors.d.ts +42 -0
- package/dist/lib/auth-errors.js +74 -0
- package/dist/lib/auth-errors.js.map +1 -0
- package/dist/lib/bindings/section-bindings.d.ts +24 -0
- package/dist/lib/bindings/section-bindings.js +9 -0
- package/dist/lib/bindings/section-bindings.js.map +1 -0
- package/dist/lib/clipboard/index.d.ts +7 -0
- package/dist/lib/clipboard/index.js +8 -0
- package/dist/lib/clipboard/index.js.map +1 -0
- package/dist/lib/clipboard/os-clipboard.d.ts +46 -0
- package/dist/lib/clipboard/os-clipboard.js +105 -0
- package/dist/lib/clipboard/os-clipboard.js.map +1 -0
- package/dist/lib/clipboard/paste-issues.d.ts +34 -0
- package/dist/lib/clipboard/paste-issues.js +67 -0
- package/dist/lib/clipboard/paste-issues.js.map +1 -0
- package/dist/lib/clipboard/paste-target.d.ts +20 -0
- package/dist/lib/clipboard/paste-target.js +28 -0
- package/dist/lib/clipboard/paste-target.js.map +1 -0
- package/dist/lib/cms/published-documents.d.ts +30 -0
- package/dist/lib/cms/published-documents.js +75 -0
- package/dist/lib/cms/published-documents.js.map +1 -0
- package/dist/lib/cms-views/index.d.ts +9 -0
- package/dist/lib/cms-views/index.js +10 -0
- package/dist/lib/cms-views/index.js.map +1 -0
- package/dist/lib/cms-views/selection.d.ts +29 -0
- package/dist/lib/cms-views/selection.js +46 -0
- package/dist/lib/cms-views/selection.js.map +1 -0
- package/dist/lib/cms-views/view-model.d.ts +192 -0
- package/dist/lib/cms-views/view-model.js +353 -0
- package/dist/lib/cms-views/view-model.js.map +1 -0
- package/dist/lib/cms-views/views-store.d.ts +70 -0
- package/dist/lib/cms-views/views-store.js +129 -0
- package/dist/lib/cms-views/views-store.js.map +1 -0
- package/dist/lib/data/collection-content.d.ts +105 -0
- package/dist/lib/data/collection-content.js +196 -0
- package/dist/lib/data/collection-content.js.map +1 -0
- package/dist/lib/data/data-store.d.ts +97 -0
- package/dist/lib/data/data-store.js +205 -0
- package/dist/lib/data/data-store.js.map +1 -0
- package/dist/lib/data/index.d.ts +4 -0
- package/dist/lib/data/index.js +8 -0
- package/dist/lib/data/index.js.map +1 -0
- package/dist/lib/data/providers.d.ts +143 -0
- package/dist/lib/data/providers.js +255 -0
- package/dist/lib/data/providers.js.map +1 -0
- package/dist/lib/data/sample-capture.d.ts +30 -0
- package/dist/lib/data/sample-capture.js +70 -0
- package/dist/lib/data/sample-capture.js.map +1 -0
- package/dist/lib/data/sources-store.d.ts +42 -0
- package/dist/lib/data/sources-store.js +120 -0
- package/dist/lib/data/sources-store.js.map +1 -0
- package/dist/lib/dnd/drop-rules.d.ts +219 -0
- package/dist/lib/dnd/drop-rules.js +257 -0
- package/dist/lib/dnd/drop-rules.js.map +1 -0
- package/dist/lib/dnd/gap-drag.d.ts +66 -0
- package/dist/lib/dnd/gap-drag.js +95 -0
- package/dist/lib/dnd/gap-drag.js.map +1 -0
- package/dist/lib/locale/binding-fallback.d.ts +28 -0
- package/dist/lib/locale/binding-fallback.js +66 -0
- package/dist/lib/locale/binding-fallback.js.map +1 -0
- package/dist/lib/locale/fallback.d.ts +43 -0
- package/dist/lib/locale/fallback.js +52 -0
- package/dist/lib/locale/fallback.js.map +1 -0
- package/dist/lib/locale/index.d.ts +6 -0
- package/dist/lib/locale/index.js +7 -0
- package/dist/lib/locale/index.js.map +1 -0
- package/dist/lib/locale/locale-store.d.ts +40 -0
- package/dist/lib/locale/locale-store.js +61 -0
- package/dist/lib/locale/locale-store.js.map +1 -0
- package/dist/lib/locale/locale-switcher.d.ts +10 -0
- package/dist/lib/locale/locale-switcher.js +24 -0
- package/dist/lib/locale/locale-switcher.js.map +1 -0
- package/dist/lib/locale/route-variant.d.ts +14 -0
- package/dist/lib/locale/route-variant.js +11 -0
- package/dist/lib/locale/route-variant.js.map +1 -0
- package/dist/lib/locale/use-studio-locale.d.ts +10 -0
- package/dist/lib/locale/use-studio-locale.js +8 -0
- package/dist/lib/locale/use-studio-locale.js.map +1 -0
- package/dist/lib/operations/asset-repository.d.ts +15 -0
- package/dist/lib/operations/asset-repository.js +56 -0
- package/dist/lib/operations/asset-repository.js.map +1 -0
- package/dist/lib/operations/cms-persistence.d.ts +35 -0
- package/dist/lib/operations/cms-persistence.js +75 -0
- package/dist/lib/operations/cms-persistence.js.map +1 -0
- package/dist/lib/operations/graph-commands.d.ts +140 -0
- package/dist/lib/operations/graph-commands.js +86 -0
- package/dist/lib/operations/graph-commands.js.map +1 -0
- package/dist/lib/operations/graph-persistence.d.ts +27 -0
- package/dist/lib/operations/graph-persistence.js +35 -0
- package/dist/lib/operations/graph-persistence.js.map +1 -0
- package/dist/lib/operations/index.d.ts +13 -0
- package/dist/lib/operations/index.js +14 -0
- package/dist/lib/operations/index.js.map +1 -0
- package/dist/lib/operations/operations-package.d.ts +6 -0
- package/dist/lib/operations/operations-package.js +7 -0
- package/dist/lib/operations/operations-package.js.map +1 -0
- package/dist/lib/operations/persist-queue.d.ts +16 -0
- package/dist/lib/operations/persist-queue.js +18 -0
- package/dist/lib/operations/persist-queue.js.map +1 -0
- package/dist/lib/operations/session-hydration.d.ts +84 -0
- package/dist/lib/operations/session-hydration.js +112 -0
- package/dist/lib/operations/session-hydration.js.map +1 -0
- package/dist/lib/operations/studio-operations.d.ts +59 -0
- package/dist/lib/operations/studio-operations.js +92 -0
- package/dist/lib/operations/studio-operations.js.map +1 -0
- package/dist/lib/persistence/backend-mode.d.ts +69 -0
- package/dist/lib/persistence/backend-mode.js +120 -0
- package/dist/lib/persistence/backend-mode.js.map +1 -0
- package/dist/lib/persistence/convex-adapter.d.ts +34 -0
- package/dist/lib/persistence/convex-adapter.js +681 -0
- package/dist/lib/persistence/convex-adapter.js.map +1 -0
- package/dist/lib/persistence/convex-blob-storage.d.ts +57 -0
- package/dist/lib/persistence/convex-blob-storage.js +97 -0
- package/dist/lib/persistence/convex-blob-storage.js.map +1 -0
- package/dist/lib/persistence/convex-client.d.ts +19 -0
- package/dist/lib/persistence/convex-client.js +40 -0
- package/dist/lib/persistence/convex-client.js.map +1 -0
- package/dist/lib/persistence/index.d.ts +30 -0
- package/dist/lib/persistence/index.js +60 -0
- package/dist/lib/persistence/index.js.map +1 -0
- package/dist/lib/persona/labels.d.ts +23 -0
- package/dist/lib/persona/labels.js +122 -0
- package/dist/lib/persona/labels.js.map +1 -0
- package/dist/lib/rail.d.ts +11 -0
- package/dist/lib/rail.js +26 -0
- package/dist/lib/rail.js.map +1 -0
- package/dist/lib/references/impact.d.ts +64 -0
- package/dist/lib/references/impact.js +62 -0
- package/dist/lib/references/impact.js.map +1 -0
- package/dist/lib/references/index.d.ts +7 -0
- package/dist/lib/references/index.js +8 -0
- package/dist/lib/references/index.js.map +1 -0
- package/dist/lib/references/reference-model.d.ts +125 -0
- package/dist/lib/references/reference-model.js +242 -0
- package/dist/lib/references/reference-model.js.map +1 -0
- package/dist/lib/references/references-store.d.ts +65 -0
- package/dist/lib/references/references-store.js +221 -0
- package/dist/lib/references/references-store.js.map +1 -0
- package/dist/lib/registry/index.d.ts +65 -0
- package/dist/lib/registry/index.js +114 -0
- package/dist/lib/registry/index.js.map +1 -0
- package/dist/lib/registry/preview.d.ts +15 -0
- package/dist/lib/registry/preview.js +110 -0
- package/dist/lib/registry/preview.js.map +1 -0
- package/dist/lib/registry/project-components.d.ts +16 -0
- package/dist/lib/registry/project-components.js +152 -0
- package/dist/lib/registry/project-components.js.map +1 -0
- package/dist/lib/routing/index.d.ts +10 -0
- package/dist/lib/routing/index.js +11 -0
- package/dist/lib/routing/index.js.map +1 -0
- package/dist/lib/routing/routing-analysis.d.ts +26 -0
- package/dist/lib/routing/routing-analysis.js +37 -0
- package/dist/lib/routing/routing-analysis.js.map +1 -0
- package/dist/lib/routing/routing-store.d.ts +50 -0
- package/dist/lib/routing/routing-store.js +72 -0
- package/dist/lib/routing/routing-store.js.map +1 -0
- package/dist/lib/starters/kit-session.d.ts +5 -0
- package/dist/lib/starters/kit-session.js +17 -0
- package/dist/lib/starters/kit-session.js.map +1 -0
- package/dist/lib/theme.d.ts +21 -0
- package/dist/lib/theme.js +32 -0
- package/dist/lib/theme.js.map +1 -0
- package/dist/lib/utils.d.ts +11 -0
- package/dist/lib/utils.js +28 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/webhooks/config.d.ts +15 -0
- package/dist/lib/webhooks/config.js +64 -0
- package/dist/lib/webhooks/config.js.map +1 -0
- package/dist/lib/webhooks/dispatcher.d.ts +67 -0
- package/dist/lib/webhooks/dispatcher.js +61 -0
- package/dist/lib/webhooks/dispatcher.js.map +1 -0
- package/dist/lib/webhooks/index.d.ts +11 -0
- package/dist/lib/webhooks/index.js +10 -0
- package/dist/lib/webhooks/index.js.map +1 -0
- package/dist/lib/webhooks/signing.d.ts +15 -0
- package/dist/lib/webhooks/signing.js +24 -0
- package/dist/lib/webhooks/signing.js.map +1 -0
- package/dist/lib/webhooks/tags.d.ts +25 -0
- package/dist/lib/webhooks/tags.js +173 -0
- package/dist/lib/webhooks/tags.js.map +1 -0
- package/dist/lib/working-graph.d.ts +82 -0
- package/dist/lib/working-graph.js +113 -0
- package/dist/lib/working-graph.js.map +1 -0
- package/dist/lib/workspace/index.d.ts +109 -0
- package/dist/lib/workspace/index.js +206 -0
- package/dist/lib/workspace/index.js.map +1 -0
- package/dist/lib/workspace/switcher-source.d.ts +39 -0
- package/dist/lib/workspace/switcher-source.js +23 -0
- package/dist/lib/workspace/switcher-source.js.map +1 -0
- package/dist/lib/workspace/workspace-source.d.ts +47 -0
- package/dist/lib/workspace/workspace-source.js +67 -0
- package/dist/lib/workspace/workspace-source.js.map +1 -0
- package/dist/router/index.d.ts +32 -0
- package/dist/router/index.js +32 -0
- package/dist/router/index.js.map +1 -0
- package/dist/router/match.d.ts +75 -0
- package/dist/router/match.js +87 -0
- package/dist/router/match.js.map +1 -0
- package/dist/router/search.d.ts +22 -0
- package/dist/router/search.js +16 -0
- package/dist/router/search.js.map +1 -0
- package/dist/ui/avatar.d.ts +17 -0
- package/dist/ui/avatar.js +38 -0
- package/dist/ui/avatar.js.map +1 -0
- package/dist/ui/badge.d.ts +9 -0
- package/dist/ui/badge.js +23 -0
- package/dist/ui/badge.js.map +1 -0
- package/dist/ui/button.d.ts +11 -0
- package/dist/ui/button.js +30 -0
- package/dist/ui/button.js.map +1 -0
- package/dist/ui/card.d.ts +11 -0
- package/dist/ui/card.js +23 -0
- package/dist/ui/card.js.map +1 -0
- package/dist/ui/dialog.d.ts +12 -0
- package/dist/ui/dialog.js +27 -0
- package/dist/ui/dialog.js.map +1 -0
- package/dist/ui/dropdown-menu.d.ts +15 -0
- package/dist/ui/dropdown-menu.js +24 -0
- package/dist/ui/dropdown-menu.js.map +1 -0
- package/dist/ui/field.d.ts +15 -0
- package/dist/ui/field.js +14 -0
- package/dist/ui/field.js.map +1 -0
- package/dist/ui/index.d.ts +14 -0
- package/dist/ui/index.js +15 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/input.d.ts +3 -0
- package/dist/ui/input.js +7 -0
- package/dist/ui/input.js.map +1 -0
- package/dist/ui/inspector.d.ts +18 -0
- package/dist/ui/inspector.js +14 -0
- package/dist/ui/inspector.js.map +1 -0
- package/dist/ui/layout.d.ts +45 -0
- package/dist/ui/layout.js +48 -0
- package/dist/ui/layout.js.map +1 -0
- package/dist/ui/panel.d.ts +12 -0
- package/dist/ui/panel.js +20 -0
- package/dist/ui/panel.js.map +1 -0
- package/dist/ui/separator.d.ts +6 -0
- package/dist/ui/separator.js +7 -0
- package/dist/ui/separator.js.map +1 -0
- package/dist/ui/toolbar.d.ts +9 -0
- package/dist/ui/toolbar.js +16 -0
- package/dist/ui/toolbar.js.map +1 -0
- package/dist/ui/typography.d.ts +50 -0
- package/dist/ui/typography.js +43 -0
- package/dist/ui/typography.js.map +1 -0
- package/package.json +149 -0
- package/src/styles/studio.css +101 -0
- package/src/styles/tokens.css +63 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { OperationEvent, OperationEventBus } from '@elytracms/operations';
|
|
2
|
+
/**
|
|
3
|
+
* Revalidation webhook dispatcher (EC-146): subscribes to the EC-139
|
|
4
|
+
* operations event bus and POSTs a signed `{projectId, event, tags,
|
|
5
|
+
* timestamp}` payload to every configured host revalidate endpoint whenever a
|
|
6
|
+
* publish-shaped command succeeds (document upsert/delete/setState, graph
|
|
7
|
+
* publish/unpublish). The host's `createRevalidateRoute` (`@elytracms/next`)
|
|
8
|
+
* verifies the HMAC and maps the tags onto `revalidateTag`.
|
|
9
|
+
*
|
|
10
|
+
* This runs **wherever the operations client runs** — in the v1 studio that
|
|
11
|
+
* is the browser, so deliveries are cross-origin `fetch` calls. CORS
|
|
12
|
+
* implications (documented honestly):
|
|
13
|
+
*
|
|
14
|
+
* - the custom signature header always triggers a preflight, so the host
|
|
15
|
+
* endpoint must answer `OPTIONS` and allow the studio origin —
|
|
16
|
+
* `createRevalidateRoute({ allowOrigin })` does both;
|
|
17
|
+
* - the shared secret necessarily ships in the studio bundle in this mode.
|
|
18
|
+
* Acceptable for v1 (the secret only gates cache invalidation, never
|
|
19
|
+
* content access); the server-side Convex action variant
|
|
20
|
+
* (`apps/builder/convex/webhooks.ts`) keeps the secret out of the browser
|
|
21
|
+
* for Convex-backed deployments.
|
|
22
|
+
*
|
|
23
|
+
* Deliveries are fire-and-forget on a serial queue (same pattern as the
|
|
24
|
+
* EC-155 reference index): a slow or unreachable host never blocks the
|
|
25
|
+
* command pipeline, failures surface through `onError` only, and tests await
|
|
26
|
+
* `flush()` for determinism.
|
|
27
|
+
*/
|
|
28
|
+
export interface WebhookEndpoint {
|
|
29
|
+
/** Absolute URL of the host's revalidate route, e.g. `https://site/api/revalidate`. */
|
|
30
|
+
url: string;
|
|
31
|
+
/** Shared HMAC secret for this endpoint. */
|
|
32
|
+
secret: string;
|
|
33
|
+
}
|
|
34
|
+
export interface WebhookDispatcherOptions {
|
|
35
|
+
endpoints: readonly WebhookEndpoint[];
|
|
36
|
+
/**
|
|
37
|
+
* All locales the project serves. Document events sweep the collection
|
|
38
|
+
* membership tag once per locale (`collection:<name>:<locale>`).
|
|
39
|
+
*/
|
|
40
|
+
locales: readonly string[];
|
|
41
|
+
/** Injectable transport (tests); defaults to global `fetch`. */
|
|
42
|
+
fetchFn?: typeof fetch;
|
|
43
|
+
/** Injectable clock (tests); payload `timestamp` is `now().toISOString()`. */
|
|
44
|
+
now?: () => Date;
|
|
45
|
+
/** Delivery failures land here (never thrown into the command pipeline). */
|
|
46
|
+
onError?: (error: unknown, context: {
|
|
47
|
+
url: string;
|
|
48
|
+
event: OperationEvent;
|
|
49
|
+
}) => void;
|
|
50
|
+
}
|
|
51
|
+
export interface WebhookDispatcherAttachment {
|
|
52
|
+
detach(): void;
|
|
53
|
+
/** Await all queued deliveries (tests / shutdown). */
|
|
54
|
+
flush(): Promise<void>;
|
|
55
|
+
}
|
|
56
|
+
/** The signed payload shape (mirror of `revalidatePayloadSchema` in @elytracms/next). */
|
|
57
|
+
export interface RevalidateWebhookPayload {
|
|
58
|
+
projectId: string;
|
|
59
|
+
event: string;
|
|
60
|
+
tags: string[];
|
|
61
|
+
timestamp: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Attach the dispatcher to an event bus; returns a detach/flush handle.
|
|
65
|
+
* With no endpoints configured this still subscribes but never queues work.
|
|
66
|
+
*/
|
|
67
|
+
export declare function attachRevalidationWebhooks(events: OperationEventBus, options: WebhookDispatcherOptions): WebhookDispatcherAttachment;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { WEBHOOK_SIGNATURE_HEADER, signWebhookBody } from './signing';
|
|
2
|
+
import { webhookTagsForEvent } from './tags';
|
|
3
|
+
async function deliver(endpoint, tagSet, timestamp, fetchFn) {
|
|
4
|
+
const payload = {
|
|
5
|
+
projectId: tagSet.projectId,
|
|
6
|
+
event: tagSet.event,
|
|
7
|
+
tags: tagSet.tags,
|
|
8
|
+
timestamp,
|
|
9
|
+
};
|
|
10
|
+
// Sign the exact string that goes on the wire.
|
|
11
|
+
const rawBody = JSON.stringify(payload);
|
|
12
|
+
const signature = await signWebhookBody(rawBody, endpoint.secret);
|
|
13
|
+
const response = await fetchFn(endpoint.url, {
|
|
14
|
+
method: 'POST',
|
|
15
|
+
headers: {
|
|
16
|
+
'content-type': 'application/json',
|
|
17
|
+
[WEBHOOK_SIGNATURE_HEADER]: signature,
|
|
18
|
+
},
|
|
19
|
+
body: rawBody,
|
|
20
|
+
});
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw new Error(`Revalidation webhook to ${endpoint.url} answered ${response.status}.`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Attach the dispatcher to an event bus; returns a detach/flush handle.
|
|
27
|
+
* With no endpoints configured this still subscribes but never queues work.
|
|
28
|
+
*/
|
|
29
|
+
export function attachRevalidationWebhooks(events, options) {
|
|
30
|
+
const fetchFn = options.fetchFn ?? fetch;
|
|
31
|
+
const now = options.now ?? (() => new Date());
|
|
32
|
+
let pending = Promise.resolve();
|
|
33
|
+
const listener = (event) => {
|
|
34
|
+
if (options.endpoints.length === 0)
|
|
35
|
+
return;
|
|
36
|
+
const tagSet = webhookTagsForEvent(event, { locales: options.locales });
|
|
37
|
+
if (!tagSet)
|
|
38
|
+
return;
|
|
39
|
+
const timestamp = now().toISOString();
|
|
40
|
+
for (const endpoint of options.endpoints) {
|
|
41
|
+
pending = pending
|
|
42
|
+
.then(() => deliver(endpoint, tagSet, timestamp, fetchFn))
|
|
43
|
+
.catch((error) => {
|
|
44
|
+
options.onError?.(error, { url: endpoint.url, event });
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const unsubscribe = events.subscribe(listener);
|
|
49
|
+
return {
|
|
50
|
+
detach: unsubscribe,
|
|
51
|
+
flush: async () => {
|
|
52
|
+
// Drain until no new deliveries were queued while awaiting.
|
|
53
|
+
let current;
|
|
54
|
+
do {
|
|
55
|
+
current = pending;
|
|
56
|
+
await current;
|
|
57
|
+
} while (current !== pending);
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=dispatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatcher.js","sourceRoot":"","sources":["../../../src/lib/webhooks/dispatcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAA;AAkE5C,KAAK,UAAU,OAAO,CACpB,QAAyB,EACzB,MAAqB,EACrB,SAAiB,EACjB,OAAqB;IAErB,MAAM,OAAO,GAA6B;QACxC,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,SAAS;KACV,CAAA;IACD,+CAA+C;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IACvC,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;IACjE,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE;QAC3C,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,CAAC,wBAAwB,CAAC,EAAE,SAAS;SACtC;QACD,IAAI,EAAE,OAAO;KACd,CAAC,CAAA;IACF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,CAAC,GAAG,aAAa,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAA;IACzF,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,0BAA0B,CACxC,MAAyB,EACzB,OAAiC;IAEjC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK,CAAA;IACxC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAA;IAE7C,IAAI,OAAO,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAA;IAE9C,MAAM,QAAQ,GAAG,CAAC,KAAqB,EAAQ,EAAE;QAC/C,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QAC1C,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;QACvE,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,WAAW,EAAE,CAAA;QACrC,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACzC,OAAO,GAAG,OAAO;iBACd,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;iBACzD,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBACxB,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,CAAA;YACxD,CAAC,CAAC,CAAA;QACN,CAAC;IACH,CAAC,CAAA;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;IAC9C,OAAO;QACL,MAAM,EAAE,WAAW;QACnB,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,4DAA4D;YAC5D,IAAI,OAAsB,CAAA;YAC1B,GAAG,CAAC;gBACF,OAAO,GAAG,OAAO,CAAA;gBACjB,MAAM,OAAO,CAAA;YACf,CAAC,QAAQ,OAAO,KAAK,OAAO,EAAC;QAC/B,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EC-146 instant publish, emitter side: operations-event-driven webhook
|
|
3
|
+
* dispatch to host revalidate endpoints. See `dispatcher.ts` for the
|
|
4
|
+
* delivery/CORS model and `tags.ts` for the tag computation.
|
|
5
|
+
*/
|
|
6
|
+
export { attachRevalidationWebhooks } from './dispatcher';
|
|
7
|
+
export type { RevalidateWebhookPayload, WebhookDispatcherAttachment, WebhookDispatcherOptions, WebhookEndpoint, } from './dispatcher';
|
|
8
|
+
export { attachConfiguredRevalidationWebhooks } from './config';
|
|
9
|
+
export { WEBHOOK_SIGNATURE_HEADER, signWebhookBody } from './signing';
|
|
10
|
+
export { collectionWebhookTag, docWebhookTag, projectSweepWebhookTag, webhookTagsForEvent, } from './tags';
|
|
11
|
+
export type { WebhookTagSet } from './tags';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EC-146 instant publish, emitter side: operations-event-driven webhook
|
|
3
|
+
* dispatch to host revalidate endpoints. See `dispatcher.ts` for the
|
|
4
|
+
* delivery/CORS model and `tags.ts` for the tag computation.
|
|
5
|
+
*/
|
|
6
|
+
export { attachRevalidationWebhooks } from './dispatcher';
|
|
7
|
+
export { attachConfiguredRevalidationWebhooks } from './config';
|
|
8
|
+
export { WEBHOOK_SIGNATURE_HEADER, signWebhookBody } from './signing';
|
|
9
|
+
export { collectionWebhookTag, docWebhookTag, projectSweepWebhookTag, webhookTagsForEvent, } from './tags';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/webhooks/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAA;AAOzD,OAAO,EAAE,oCAAoC,EAAE,MAAM,UAAU,CAAA;AAC/D,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AACrE,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,QAAQ,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HMAC-SHA256 webhook signing (EC-146), emitter side.
|
|
3
|
+
*
|
|
4
|
+
* Uses the Web Crypto API (`crypto.subtle`) so the same code runs in the
|
|
5
|
+
* browser (the v1 studio dispatcher), in Node tests, and in Convex actions.
|
|
6
|
+
* The receiving end (`@elytracms/next` `evaluateRevalidateRequest`) verifies
|
|
7
|
+
* the same scheme with `node:crypto` and a timing-safe compare.
|
|
8
|
+
*
|
|
9
|
+
* The signature is computed over the **exact raw body string** that is sent
|
|
10
|
+
* — never re-serialize between signing and sending.
|
|
11
|
+
*/
|
|
12
|
+
/** Header carrying the signature (mirror of `REVALIDATE_SIGNATURE_HEADER`). */
|
|
13
|
+
export declare const WEBHOOK_SIGNATURE_HEADER = "x-elytra-signature";
|
|
14
|
+
/** Sign a raw webhook body: `sha256=<hex hmac>`. */
|
|
15
|
+
export declare function signWebhookBody(rawBody: string, secret: string): Promise<string>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HMAC-SHA256 webhook signing (EC-146), emitter side.
|
|
3
|
+
*
|
|
4
|
+
* Uses the Web Crypto API (`crypto.subtle`) so the same code runs in the
|
|
5
|
+
* browser (the v1 studio dispatcher), in Node tests, and in Convex actions.
|
|
6
|
+
* The receiving end (`@elytracms/next` `evaluateRevalidateRequest`) verifies
|
|
7
|
+
* the same scheme with `node:crypto` and a timing-safe compare.
|
|
8
|
+
*
|
|
9
|
+
* The signature is computed over the **exact raw body string** that is sent
|
|
10
|
+
* — never re-serialize between signing and sending.
|
|
11
|
+
*/
|
|
12
|
+
/** Header carrying the signature (mirror of `REVALIDATE_SIGNATURE_HEADER`). */
|
|
13
|
+
export const WEBHOOK_SIGNATURE_HEADER = 'x-elytra-signature';
|
|
14
|
+
function toHex(buffer) {
|
|
15
|
+
return [...new Uint8Array(buffer)].map((byte) => byte.toString(16).padStart(2, '0')).join('');
|
|
16
|
+
}
|
|
17
|
+
/** Sign a raw webhook body: `sha256=<hex hmac>`. */
|
|
18
|
+
export async function signWebhookBody(rawBody, secret) {
|
|
19
|
+
const encoder = new TextEncoder();
|
|
20
|
+
const key = await crypto.subtle.importKey('raw', encoder.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
|
|
21
|
+
const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(rawBody));
|
|
22
|
+
return `sha256=${toHex(signature)}`;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=signing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signing.js","sourceRoot":"","sources":["../../../src/lib/webhooks/signing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,+EAA+E;AAC/E,MAAM,CAAC,MAAM,wBAAwB,GAAG,oBAAoB,CAAA;AAE5D,SAAS,KAAK,CAAC,MAAmB;IAChC,OAAO,CAAC,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAC/F,CAAC;AAED,oDAAoD;AACpD,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAe,EAAE,MAAc;IACnE,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAA;IACjC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CACvC,KAAK,EACL,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EACtB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EACjC,KAAK,EACL,CAAC,MAAM,CAAC,CACT,CAAA;IACD,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAA;IAChF,OAAO,UAAU,KAAK,CAAC,SAAS,CAAC,EAAE,CAAA;AACrC,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { OperationEvent } from '@elytracms/operations';
|
|
2
|
+
/** `p:<projectId>:doc:<collection>:<id>` — mirror of `docCacheTag`. */
|
|
3
|
+
export declare function docWebhookTag(projectId: string, collection: string, id: string): string;
|
|
4
|
+
/** `p:<projectId>:collection:<name>:<locale>` — mirror of `collectionCacheTag`. */
|
|
5
|
+
export declare function collectionWebhookTag(projectId: string, collection: string, locale: string): string;
|
|
6
|
+
/** `p:<projectId>:asset:<id>` — mirror of `assetCacheTag` (EC-227). */
|
|
7
|
+
export declare function assetWebhookTag(projectId: string, assetId: string): string;
|
|
8
|
+
/** `p:<projectId>:project` — mirror of `projectSweepTag`. */
|
|
9
|
+
export declare function projectSweepWebhookTag(projectId: string): string;
|
|
10
|
+
/** One computed webhook emission: which project, why, and which tags. */
|
|
11
|
+
export interface WebhookTagSet {
|
|
12
|
+
projectId: string;
|
|
13
|
+
/** The operation name, carried verbatim as the webhook `event`. */
|
|
14
|
+
event: string;
|
|
15
|
+
/** Sorted, deduplicated, fully scoped Next tag strings. */
|
|
16
|
+
tags: string[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Compute the webhook tag set for one lifecycle event, or `null` when the
|
|
20
|
+
* event is not a successful publish-shaped command (queries, failures, and
|
|
21
|
+
* unrelated domains never fire webhooks).
|
|
22
|
+
*/
|
|
23
|
+
export declare function webhookTagsForEvent(event: Pick<OperationEvent, 'operation' | 'kind' | 'status' | 'inputSummary'>, options: {
|
|
24
|
+
locales: readonly string[];
|
|
25
|
+
}): WebhookTagSet | null;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure tag computation for the EC-146 revalidation webhooks: map a succeeded
|
|
3
|
+
* publish-shaped operation event onto the Next cache tags it invalidates.
|
|
4
|
+
*
|
|
5
|
+
* ## Tag format (mirror of `packages/next/src/cache.ts`)
|
|
6
|
+
*
|
|
7
|
+
* The canonical tag format lives in `@elytracms/next` (`src/cache.ts`). The
|
|
8
|
+
* builder cannot depend on that package — it would drag the `next` peer
|
|
9
|
+
* dependency into the studio bundle — so the three formatters are mirrored
|
|
10
|
+
* here. Both sides pin the exact literal strings in their tests
|
|
11
|
+
* (`tags.test.ts` here, `cache.test.ts` there) to keep them in lock-step.
|
|
12
|
+
*
|
|
13
|
+
* Every emitted tag is scoped `p:<projectId>:…` — the dispatcher always knows
|
|
14
|
+
* the project id, and the scope keeps multi-project hosts from
|
|
15
|
+
* cross-invalidating. Hosts must configure the same id as `cache.scope`.
|
|
16
|
+
*
|
|
17
|
+
* ## Which events produce which tags
|
|
18
|
+
*
|
|
19
|
+
* - **Document publish/unpublish/delete/save** (`documents.publish`,
|
|
20
|
+
* `documents.unpublish`, `documents.pinVersion`, `documents.upsert`,
|
|
21
|
+
* `documents.delete`): the document's own
|
|
22
|
+
* `doc:<collection>:<id>` tag — dropping its detail page *and every cached
|
|
23
|
+
* list that actually contained it* (fetch-time tagging) — plus the coarse
|
|
24
|
+
* `collection:<name>:<locale>` membership tag for **all** configured
|
|
25
|
+
* locales, sweeping cached lists whose membership may have changed
|
|
26
|
+
* (new/removed/newly-matching documents).
|
|
27
|
+
* - **Graph publish/unpublish** (`publishing.*`): the whole-project sweep tag
|
|
28
|
+
* `project` — a layout, route, or binding change can affect any page, so
|
|
29
|
+
* the honest v1 fallback (a superset of the per-route + per-collection
|
|
30
|
+
* sweep) is to drop every cached entry of the project. Unrelated projects
|
|
31
|
+
* stay cached.
|
|
32
|
+
* - **Asset edit** (`assets.upsert` of an existing asset, `assets.remove`,
|
|
33
|
+
* EC-227): the `asset:<id>` tag, dropping exactly the pages that *baked* that
|
|
34
|
+
* asset's delivery shape (alt/dimensions/url). An `assets.upsert` CREATE (no
|
|
35
|
+
* id in the summary — minted server-side) fires nothing: a brand-new asset is
|
|
36
|
+
* in no cached page yet.
|
|
37
|
+
* - **Fallback**: when a `documents` (or `assets.remove`) event's input summary
|
|
38
|
+
* was truncated past the identity (EC-139 caps summaries at 160 chars; only
|
|
39
|
+
* very large upserts hit this), the project sweep tag is emitted — coarse,
|
|
40
|
+
* always correct, mirroring the EC-155 reference-index fallback.
|
|
41
|
+
*/
|
|
42
|
+
function scoped(projectId, tag) {
|
|
43
|
+
return `p:${projectId}:${tag}`;
|
|
44
|
+
}
|
|
45
|
+
/** `p:<projectId>:doc:<collection>:<id>` — mirror of `docCacheTag`. */
|
|
46
|
+
export function docWebhookTag(projectId, collection, id) {
|
|
47
|
+
return scoped(projectId, `doc:${collection}:${id}`);
|
|
48
|
+
}
|
|
49
|
+
/** `p:<projectId>:collection:<name>:<locale>` — mirror of `collectionCacheTag`. */
|
|
50
|
+
export function collectionWebhookTag(projectId, collection, locale) {
|
|
51
|
+
return scoped(projectId, `collection:${collection}:${locale}`);
|
|
52
|
+
}
|
|
53
|
+
/** `p:<projectId>:asset:<id>` — mirror of `assetCacheTag` (EC-227). */
|
|
54
|
+
export function assetWebhookTag(projectId, assetId) {
|
|
55
|
+
return scoped(projectId, `asset:${assetId}`);
|
|
56
|
+
}
|
|
57
|
+
/** `p:<projectId>:project` — mirror of `projectSweepTag`. */
|
|
58
|
+
export function projectSweepWebhookTag(projectId) {
|
|
59
|
+
return scoped(projectId, 'project');
|
|
60
|
+
}
|
|
61
|
+
/** The operations whose success must reach the host's revalidate endpoint. */
|
|
62
|
+
const DOCUMENT_OPERATIONS = new Set([
|
|
63
|
+
'documents.upsert',
|
|
64
|
+
'documents.delete',
|
|
65
|
+
// EC-224: publish/unpublish/pinVersion move the version pointer; their
|
|
66
|
+
// `{ projectId, ref }` input drives the same doc + per-locale collection tag
|
|
67
|
+
// set (the flat `documents.setState` op is gone).
|
|
68
|
+
'documents.publish',
|
|
69
|
+
'documents.unpublish',
|
|
70
|
+
'documents.pinVersion',
|
|
71
|
+
]);
|
|
72
|
+
const PUBLISHING_OPERATIONS = new Set(['publishing.publish', 'publishing.unpublish']);
|
|
73
|
+
/**
|
|
74
|
+
* Asset-record mutations (EC-227): editing an asset (alt/dimensions/re-upload)
|
|
75
|
+
* must drop the published pages that *baked* its delivery shape, which carry the
|
|
76
|
+
* `asset:<id>` tag. `assets.remove` always carries `assetId`; `assets.upsert`
|
|
77
|
+
* carries `asset.id` only on an EDIT (a CREATE mints the id server-side).
|
|
78
|
+
*/
|
|
79
|
+
const ASSET_OPERATIONS = new Set(['assets.upsert', 'assets.remove']);
|
|
80
|
+
/** Tolerant parse of an EC-139 input summary (may be truncated past 160 chars). */
|
|
81
|
+
function parseSummary(summary) {
|
|
82
|
+
try {
|
|
83
|
+
const parsed = JSON.parse(summary);
|
|
84
|
+
return typeof parsed === 'object' && parsed !== null
|
|
85
|
+
? parsed
|
|
86
|
+
: undefined;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/** Extract the projectId even from a truncated summary (it serializes first). */
|
|
93
|
+
function projectIdOfSummary(summary) {
|
|
94
|
+
const match = /"projectId":"([^"]+)"/.exec(summary);
|
|
95
|
+
return match?.[1];
|
|
96
|
+
}
|
|
97
|
+
function documentRefOf(value) {
|
|
98
|
+
if (typeof value !== 'object' || value === null)
|
|
99
|
+
return undefined;
|
|
100
|
+
const candidate = value;
|
|
101
|
+
return typeof candidate.collection === 'string' &&
|
|
102
|
+
candidate.collection.length > 0 &&
|
|
103
|
+
typeof candidate.id === 'string' &&
|
|
104
|
+
candidate.id.length > 0
|
|
105
|
+
? { collection: candidate.collection, id: candidate.id }
|
|
106
|
+
: undefined;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Compute the webhook tag set for one lifecycle event, or `null` when the
|
|
110
|
+
* event is not a successful publish-shaped command (queries, failures, and
|
|
111
|
+
* unrelated domains never fire webhooks).
|
|
112
|
+
*/
|
|
113
|
+
export function webhookTagsForEvent(event, options) {
|
|
114
|
+
if (event.status !== 'succeeded' || event.kind !== 'command')
|
|
115
|
+
return null;
|
|
116
|
+
const isDocument = DOCUMENT_OPERATIONS.has(event.operation);
|
|
117
|
+
const isPublishing = PUBLISHING_OPERATIONS.has(event.operation);
|
|
118
|
+
const isAsset = ASSET_OPERATIONS.has(event.operation);
|
|
119
|
+
if (!isDocument && !isPublishing && !isAsset)
|
|
120
|
+
return null;
|
|
121
|
+
const projectId = projectIdOfSummary(event.inputSummary);
|
|
122
|
+
if (projectId === undefined)
|
|
123
|
+
return null;
|
|
124
|
+
if (isPublishing) {
|
|
125
|
+
return {
|
|
126
|
+
projectId,
|
|
127
|
+
event: event.operation,
|
|
128
|
+
tags: [projectSweepWebhookTag(projectId)],
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
if (isAsset)
|
|
132
|
+
return assetTagsForEvent(projectId, event);
|
|
133
|
+
const parsed = parseSummary(event.inputSummary);
|
|
134
|
+
const ref = documentRefOf(parsed?.['ref']) ?? documentRefOf(parsed?.['document']);
|
|
135
|
+
if (!ref) {
|
|
136
|
+
// Truncated summary (large upsert payload): honest coarse fallback.
|
|
137
|
+
return { projectId, event: event.operation, tags: [projectSweepWebhookTag(projectId)] };
|
|
138
|
+
}
|
|
139
|
+
const tags = new Set([docWebhookTag(projectId, ref.collection, ref.id)]);
|
|
140
|
+
for (const locale of options.locales) {
|
|
141
|
+
tags.add(collectionWebhookTag(projectId, ref.collection, locale));
|
|
142
|
+
}
|
|
143
|
+
// EC-207: routes/redirects are config-owned (a code deploy, which rebuilds the
|
|
144
|
+
// host) — they are no longer DB documents, so there is no route-document event
|
|
145
|
+
// to sweep the project for. Graph publishes still emit the project sweep above.
|
|
146
|
+
return { projectId, event: event.operation, tags: [...tags].sort() };
|
|
147
|
+
}
|
|
148
|
+
/** A non-empty string, else `undefined` (the asset id out of a summary). */
|
|
149
|
+
function stringOf(value) {
|
|
150
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Tags for an asset mutation (EC-227). The edit cases — `assets.remove` (carries
|
|
154
|
+
* `assetId`) and `assets.upsert` of an existing asset (carries `asset.id`) —
|
|
155
|
+
* emit exactly `asset:<id>`, dropping the pages that baked that asset. An
|
|
156
|
+
* `assets.upsert` with **no** id is a CREATE: the id is minted server-side and a
|
|
157
|
+
* brand-new asset cannot be baked into any existing page, so it invalidates
|
|
158
|
+
* nothing (`null`, no webhook). A `remove` missing its id means a truncated
|
|
159
|
+
* summary — sweep the project (coarse, always correct — the document fallback).
|
|
160
|
+
*/
|
|
161
|
+
function assetTagsForEvent(projectId, event) {
|
|
162
|
+
const parsed = parseSummary(event.inputSummary);
|
|
163
|
+
const assetId = event.operation === 'assets.remove'
|
|
164
|
+
? stringOf(parsed?.['assetId'])
|
|
165
|
+
: stringOf(parsed?.['asset']?.id);
|
|
166
|
+
if (assetId) {
|
|
167
|
+
return { projectId, event: event.operation, tags: [assetWebhookTag(projectId, assetId)] };
|
|
168
|
+
}
|
|
169
|
+
return event.operation === 'assets.remove'
|
|
170
|
+
? { projectId, event: event.operation, tags: [projectSweepWebhookTag(projectId)] }
|
|
171
|
+
: null;
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=tags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tags.js","sourceRoot":"","sources":["../../../src/lib/webhooks/tags.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { ComponentNode, Layout, ProjectGraph } from '@elytracms/project-graph';
|
|
2
|
+
/**
|
|
3
|
+
* Builder-local WORKING GRAPH (EC-187).
|
|
4
|
+
*
|
|
5
|
+
* The canonical {@link ProjectGraph} is now LAYOUTS-ONLY — a page is a document
|
|
6
|
+
* in the `page` collection (its `body` is a composition field value). But the
|
|
7
|
+
* legacy `/builder` editor and the composition-field editor are *node-tree*
|
|
8
|
+
* editors: they edit a single root-bearing surface with undo/redo, selection,
|
|
9
|
+
* and the same structural edit ops. So the builder store keeps its own
|
|
10
|
+
* root-bearing working type, decoupled from the page-less canonical schema.
|
|
11
|
+
*
|
|
12
|
+
* A `WorkingGraph` is a `ProjectGraph` (layouts + metadata) PLUS a `pages`
|
|
13
|
+
* array of {@link WorkingPage} — exactly the shape the reducer/history/edit ops
|
|
14
|
+
* have always operated on. It NEVER persists in this shape: page-body edits lift
|
|
15
|
+
* into a CMS document (the composition-field editor), and layout edits persist
|
|
16
|
+
* through the canonical layouts-only `graph.save`. {@link toProjectGraph} drops
|
|
17
|
+
* the pages to produce the canonical graph when one is needed.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Per-page SEO block (EC-171, legacy `/builder` chrome). The canonical
|
|
21
|
+
* `PageSeo` shape lived in `@elytracms/project-graph` and was deleted with the
|
|
22
|
+
* page node (EC-187); page SEO now lives on the `page` collection document's
|
|
23
|
+
* flat `seo*` fields. The legacy page-SEO panel keeps editing this local block
|
|
24
|
+
* so it stays compiling/tested until `/builder` is retired.
|
|
25
|
+
*/
|
|
26
|
+
export interface WorkingPageSeo {
|
|
27
|
+
title?: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
ogTitle?: string;
|
|
30
|
+
ogImage?: string;
|
|
31
|
+
noindex?: boolean;
|
|
32
|
+
}
|
|
33
|
+
/** A page in the builder's working state — a root-bearing editable surface. */
|
|
34
|
+
export interface WorkingPage {
|
|
35
|
+
id: string;
|
|
36
|
+
name: string;
|
|
37
|
+
/** Optional shared layout wrapper id (canvas preview only). */
|
|
38
|
+
layoutId?: string;
|
|
39
|
+
/** Root node of the page's component tree (the edited surface). */
|
|
40
|
+
root: ComponentNode;
|
|
41
|
+
/** Legacy per-page SEO block (EC-171). */
|
|
42
|
+
seo?: WorkingPageSeo;
|
|
43
|
+
}
|
|
44
|
+
/** The builder's internal working graph: the canonical layouts-only graph + editable pages. */
|
|
45
|
+
export interface WorkingGraph {
|
|
46
|
+
id: string;
|
|
47
|
+
schemaVersion: number;
|
|
48
|
+
metadata?: {
|
|
49
|
+
name?: string;
|
|
50
|
+
};
|
|
51
|
+
settingsRef?: string;
|
|
52
|
+
layouts: Layout[];
|
|
53
|
+
pages: WorkingPage[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Lift a (layouts-only) canonical {@link ProjectGraph} into a {@link WorkingGraph}
|
|
57
|
+
* with a single editable page, so the legacy builder canvas has a root to edit.
|
|
58
|
+
* The page root is an empty Stack the editor fills; the page selects the first
|
|
59
|
+
* layout for canvas preview (if any).
|
|
60
|
+
*/
|
|
61
|
+
export declare function toWorkingGraph(graph: ProjectGraph): WorkingGraph;
|
|
62
|
+
/** Drop the editable pages to produce the canonical (layouts-only) {@link ProjectGraph}. */
|
|
63
|
+
export declare function toProjectGraph(graph: WorkingGraph): ProjectGraph;
|
|
64
|
+
/** Build a working graph that wraps one composition value in a single editable page. */
|
|
65
|
+
export declare function workingGraphFromPage(page: WorkingPage, layouts?: Layout[]): WorkingGraph;
|
|
66
|
+
/**
|
|
67
|
+
* Normalize every editable surface of a working graph — each page root AND
|
|
68
|
+
* each layout root — via `normalizeContainers`. Mirrors the OLD
|
|
69
|
+
* `normalizeProjectGraph` (which normalized pages too, before EC-187 made the
|
|
70
|
+
* canonical graph layouts-only). Identity-preserving: returns the same graph
|
|
71
|
+
* reference when nothing changed so undo histories can detect no-ops by
|
|
72
|
+
* reference.
|
|
73
|
+
*/
|
|
74
|
+
export declare function normalizeWorkingGraph(graph: WorkingGraph): WorkingGraph;
|
|
75
|
+
/** Strip empty fields; an all-empty block becomes `undefined` (clear the block). */
|
|
76
|
+
export declare function cleanWorkingPageSeo(seo: WorkingPageSeo): WorkingPageSeo | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Apply a (cleaned) SEO block to a page in the working graph. Identity on
|
|
79
|
+
* no-ops — callers dispatch only when this returns a new graph. An `undefined`
|
|
80
|
+
* block removes `seo` from the page entity entirely.
|
|
81
|
+
*/
|
|
82
|
+
export declare function setWorkingPageSeo(graph: WorkingGraph, pageId: string, seo: WorkingPageSeo | undefined): WorkingGraph;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { normalizeContainers, PROJECT_GRAPH_SCHEMA_VERSION } from '@elytracms/project-graph';
|
|
2
|
+
const SYNTH_PAGE_ID = 'page.working';
|
|
3
|
+
/**
|
|
4
|
+
* Lift a (layouts-only) canonical {@link ProjectGraph} into a {@link WorkingGraph}
|
|
5
|
+
* with a single editable page, so the legacy builder canvas has a root to edit.
|
|
6
|
+
* The page root is an empty Stack the editor fills; the page selects the first
|
|
7
|
+
* layout for canvas preview (if any).
|
|
8
|
+
*/
|
|
9
|
+
export function toWorkingGraph(graph) {
|
|
10
|
+
return {
|
|
11
|
+
...graph,
|
|
12
|
+
pages: [
|
|
13
|
+
{
|
|
14
|
+
id: SYNTH_PAGE_ID,
|
|
15
|
+
name: graph.metadata?.name ?? 'Page',
|
|
16
|
+
...(graph.layouts[0] ? { layoutId: graph.layouts[0].id } : {}),
|
|
17
|
+
root: { id: 'working.root', componentId: 'base.primitives.Stack', slots: { children: [] } },
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/** Drop the editable pages to produce the canonical (layouts-only) {@link ProjectGraph}. */
|
|
23
|
+
export function toProjectGraph(graph) {
|
|
24
|
+
const { pages: _pages, ...canonical } = graph;
|
|
25
|
+
return canonical;
|
|
26
|
+
}
|
|
27
|
+
/** Build a working graph that wraps one composition value in a single editable page. */
|
|
28
|
+
export function workingGraphFromPage(page, layouts = []) {
|
|
29
|
+
return {
|
|
30
|
+
id: 'working',
|
|
31
|
+
schemaVersion: PROJECT_GRAPH_SCHEMA_VERSION,
|
|
32
|
+
layouts,
|
|
33
|
+
pages: [page],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Normalize every editable surface of a working graph — each page root AND
|
|
38
|
+
* each layout root — via `normalizeContainers`. Mirrors the OLD
|
|
39
|
+
* `normalizeProjectGraph` (which normalized pages too, before EC-187 made the
|
|
40
|
+
* canonical graph layouts-only). Identity-preserving: returns the same graph
|
|
41
|
+
* reference when nothing changed so undo histories can detect no-ops by
|
|
42
|
+
* reference.
|
|
43
|
+
*/
|
|
44
|
+
export function normalizeWorkingGraph(graph) {
|
|
45
|
+
let changed = false;
|
|
46
|
+
const pages = graph.pages.map((page) => {
|
|
47
|
+
const root = normalizeContainers(page.root);
|
|
48
|
+
if (root !== page.root)
|
|
49
|
+
changed = true;
|
|
50
|
+
return root === page.root ? page : { ...page, root };
|
|
51
|
+
});
|
|
52
|
+
const layouts = graph.layouts.map((layout) => {
|
|
53
|
+
const root = normalizeContainers(layout.root);
|
|
54
|
+
if (root !== layout.root)
|
|
55
|
+
changed = true;
|
|
56
|
+
return root === layout.root ? layout : { ...layout, root };
|
|
57
|
+
});
|
|
58
|
+
return changed ? { ...graph, pages, layouts } : graph;
|
|
59
|
+
}
|
|
60
|
+
// ---- Legacy page SEO (EC-171) ----------------------------------------------
|
|
61
|
+
//
|
|
62
|
+
// The canonical `setPageSeo`/`cleanPageSeo`/`PageSeo` were deleted with the
|
|
63
|
+
// page node (EC-187). These local helpers mirror the old behavior over the
|
|
64
|
+
// working graph's per-page `seo` block so the legacy SEO panel keeps working.
|
|
65
|
+
/** Strip empty fields; an all-empty block becomes `undefined` (clear the block). */
|
|
66
|
+
export function cleanWorkingPageSeo(seo) {
|
|
67
|
+
const trimmed = (value) => {
|
|
68
|
+
const next = value?.trim();
|
|
69
|
+
return next ? next : undefined;
|
|
70
|
+
};
|
|
71
|
+
const next = {};
|
|
72
|
+
const title = trimmed(seo.title);
|
|
73
|
+
const description = trimmed(seo.description);
|
|
74
|
+
const ogTitle = trimmed(seo.ogTitle);
|
|
75
|
+
const ogImage = trimmed(seo.ogImage);
|
|
76
|
+
if (title !== undefined)
|
|
77
|
+
next.title = title;
|
|
78
|
+
if (description !== undefined)
|
|
79
|
+
next.description = description;
|
|
80
|
+
if (ogTitle !== undefined)
|
|
81
|
+
next.ogTitle = ogTitle;
|
|
82
|
+
if (ogImage !== undefined)
|
|
83
|
+
next.ogImage = ogImage;
|
|
84
|
+
if (seo.noindex)
|
|
85
|
+
next.noindex = true;
|
|
86
|
+
return Object.keys(next).length > 0 ? next : undefined;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Apply a (cleaned) SEO block to a page in the working graph. Identity on
|
|
90
|
+
* no-ops — callers dispatch only when this returns a new graph. An `undefined`
|
|
91
|
+
* block removes `seo` from the page entity entirely.
|
|
92
|
+
*/
|
|
93
|
+
export function setWorkingPageSeo(graph, pageId, seo) {
|
|
94
|
+
const page = graph.pages.find((p) => p.id === pageId);
|
|
95
|
+
if (!page)
|
|
96
|
+
return graph;
|
|
97
|
+
const sameBlock = JSON.stringify(page.seo ?? null) === JSON.stringify(seo ?? null);
|
|
98
|
+
if (sameBlock)
|
|
99
|
+
return graph;
|
|
100
|
+
return {
|
|
101
|
+
...graph,
|
|
102
|
+
pages: graph.pages.map((p) => {
|
|
103
|
+
if (p.id !== pageId)
|
|
104
|
+
return p;
|
|
105
|
+
if (seo === undefined) {
|
|
106
|
+
const { seo: _drop, ...rest } = p;
|
|
107
|
+
return rest;
|
|
108
|
+
}
|
|
109
|
+
return { ...p, seo };
|
|
110
|
+
}),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=working-graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"working-graph.js","sourceRoot":"","sources":["../../src/lib/working-graph.ts"],"names":[],"mappings":"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"}
|