@elytracms/studio 0.0.51 → 0.0.53
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/auth.ts +135 -62
- package/convex/invites.ts +77 -0
- package/dist/components/account/account-settings.js +4 -4
- package/dist/components/account/credential-panel.js +1 -1
- package/dist/components/account/self-account-view-source.js +3 -3
- package/dist/components/ai/ai-chat-panel-lazy.js +1 -1
- package/dist/components/ai/ai-chat-panel.js +4 -4
- package/dist/components/ai/ai-cms-panel.js +1 -1
- package/dist/components/ai/proposal-card.js +4 -4
- package/dist/components/ai/translate-document-action.js +1 -1
- package/dist/components/ai/translate-document-dialog.d.ts +1 -1
- package/dist/components/app-views/default-modules.d.ts +3 -3
- package/dist/components/app-views/default-modules.js +20 -20
- package/dist/components/app-views/sidebar.d.ts +1 -1
- package/dist/components/app-views/sidebar.js +2 -2
- package/dist/components/app-views/studio-config.d.ts +1 -1
- package/dist/components/assets/asset-detail.js +9 -9
- package/dist/components/assets/asset-grid.js +7 -7
- package/dist/components/assets/asset-thumb.d.ts +1 -1
- package/dist/components/assets/asset-thumb.js +2 -2
- package/dist/components/assets/assets-collection-view-source.js +3 -3
- package/dist/components/assets/assets-module.js +8 -8
- package/dist/components/assets/assets-store.d.ts +1 -1
- package/dist/components/assets/assets-store.js +1 -1
- package/dist/components/builder/blocks-model.js +1 -1
- package/dist/components/builder/blocks-panel.d.ts +1 -1
- package/dist/components/builder/blocks-panel.js +6 -6
- package/dist/components/builder/canvas.js +11 -11
- package/dist/components/builder/clipboard-actions.js +2 -2
- package/dist/components/builder/composition-field-editor-lazy.d.ts +1 -1
- package/dist/components/builder/composition-field-editor-lazy.js +1 -1
- package/dist/components/builder/composition-field-editor.d.ts +1 -1
- package/dist/components/builder/composition-field-editor.js +9 -9
- package/dist/components/builder/insert-context.d.ts +2 -2
- package/dist/components/builder/insert-context.js +2 -2
- package/dist/components/builder/insert-menu.d.ts +2 -2
- package/dist/components/builder/insert-menu.js +1 -1
- package/dist/components/builder/layout-inspector.js +1 -1
- package/dist/components/builder/page-tree.js +5 -5
- package/dist/components/builder/property-inspector.js +3 -3
- package/dist/components/builder/reuse-context.d.ts +1 -1
- package/dist/components/builder/reuse-context.js +3 -3
- package/dist/components/builder/spacing-handles.js +2 -2
- package/dist/components/cms/asset-picker.js +4 -4
- package/dist/components/cms/bulk-actions.js +1 -1
- package/dist/components/cms/bulk-bar.d.ts +1 -1
- package/dist/components/cms/bulk-bar.js +3 -3
- package/dist/components/cms/cell-edit.js +1 -1
- package/dist/components/cms/cell.js +2 -2
- package/dist/components/cms/cms-index.js +1 -1
- package/dist/components/cms/cms-store.d.ts +2 -2
- package/dist/components/cms/cms-store.js +6 -6
- package/dist/components/cms/collection-table.js +17 -17
- package/dist/components/cms/detail-editor.js +31 -31
- package/dist/components/cms/document-diff-view.js +4 -4
- package/dist/components/cms/editable-cell.d.ts +1 -1
- package/dist/components/cms/editable-cell.js +6 -6
- package/dist/components/cms/field-control.js +15 -15
- package/dist/components/cms/field-renderer.d.ts +2 -2
- package/dist/components/cms/filter-builder.js +3 -3
- package/dist/components/cms/import-export.js +1 -1
- package/dist/components/cms/issues-pane.js +1 -1
- package/dist/components/cms/prop-fields.js +3 -3
- package/dist/components/cms/reference-confirm.js +1 -1
- package/dist/components/cms/relation-picker.js +1 -1
- package/dist/components/cms/rich-text/block-commands.d.ts +1 -1
- package/dist/components/cms/rich-text/component-embed.js +2 -2
- package/dist/components/cms/rich-text/editor.js +8 -8
- package/dist/components/cms/rich-text/embed-inspector.d.ts +1 -1
- package/dist/components/cms/rich-text/embed-inspector.js +2 -2
- package/dist/components/cms/rich-text/embed-picker.js +1 -1
- package/dist/components/cms/rich-text/embed-props.js +1 -1
- package/dist/components/cms/rich-text/extensions.d.ts +1 -1
- package/dist/components/cms/rich-text/extensions.js +4 -4
- package/dist/components/cms/rich-text/index.d.ts +1 -1
- package/dist/components/cms/rich-text/index.js +1 -1
- package/dist/components/cms/rich-text/insert.d.ts +1 -1
- package/dist/components/cms/rich-text/lazy.d.ts +1 -1
- package/dist/components/cms/rich-text/lazy.js +1 -1
- package/dist/components/cms/rich-text/slash-command.js +1 -1
- package/dist/components/cms/rich-text/toolbar.d.ts +1 -1
- package/dist/components/cms/rich-text/toolbar.js +4 -4
- package/dist/components/cms/use-cell-edit.d.ts +1 -1
- package/dist/components/cms/use-cell-edit.js +2 -2
- package/dist/components/cms/use-compare-selection.d.ts +1 -1
- package/dist/components/cms/use-discard-controller.d.ts +1 -1
- package/dist/components/cms/use-discard-controller.js +2 -2
- package/dist/components/cms/use-document-versions.d.ts +1 -1
- package/dist/components/cms/use-document-versions.js +1 -1
- package/dist/components/cms/use-embed-inspector-host.d.ts +1 -1
- package/dist/components/cms/use-published-perspective.d.ts +2 -2
- package/dist/components/cms/use-published-perspective.js +2 -2
- package/dist/components/cms/use-restore-version.js +1 -1
- package/dist/components/cms/version-compare-lazy.js +1 -1
- package/dist/components/cms/version-compare.js +6 -6
- package/dist/components/cms/versions-model.d.ts +1 -1
- package/dist/components/cms/versions-pane.js +5 -5
- package/dist/components/cms/view-bar.js +2 -2
- package/dist/components/collab/collab-context.js +1 -1
- package/dist/components/collection-view/cms-collection-view-source.js +2 -2
- package/dist/components/components/component-preview.js +3 -3
- package/dist/components/components/components-index.js +2 -2
- package/dist/components/components/registry-browser.js +2 -2
- package/dist/components/components/transfer-dialog.js +5 -5
- package/dist/components/components/transfer.js +4 -4
- package/dist/components/current-user-menu.js +2 -2
- package/dist/components/delivery-health-banner.js +2 -2
- package/dist/components/operation-error.js +1 -1
- package/dist/components/project-list.js +5 -5
- package/dist/components/project-session.js +1 -1
- package/dist/components/project-switcher.js +3 -3
- package/dist/components/rail-store-status.js +1 -1
- package/dist/components/redirects/redirects-collection-view-source.js +3 -3
- package/dist/components/redirects/redirects-module.js +6 -6
- package/dist/components/section-nav.js +3 -3
- package/dist/components/section-surface.js +1 -1
- package/dist/components/studio-project-screen.js +7 -7
- package/dist/components/studio-shell.js +9 -9
- package/dist/components/use-hydration-phase.js +1 -1
- package/dist/components/users/users-collection-view-source.js +4 -4
- package/dist/components/users/users-module.js +9 -9
- package/dist/components/workspace-projects.js +1 -1
- package/dist/customization.d.ts +9 -9
- package/dist/customization.js +5 -5
- package/dist/lib/ai/anthropic-provider.d.ts +1 -1
- package/dist/lib/ai/apply-content.d.ts +1 -1
- package/dist/lib/ai/apply-content.js +3 -3
- package/dist/lib/ai/chat-state.d.ts +2 -2
- package/dist/lib/ai/config.d.ts +1 -1
- package/dist/lib/ai/create-flow.d.ts +2 -2
- package/dist/lib/ai/create-flow.js +3 -3
- package/dist/lib/ai/fake-provider.d.ts +1 -1
- package/dist/lib/ai/index.d.ts +15 -15
- package/dist/lib/ai/index.js +15 -15
- package/dist/lib/ai/knowledge.d.ts +1 -1
- package/dist/lib/ai/provenance.d.ts +1 -1
- package/dist/lib/ai/route-provider.d.ts +1 -1
- package/dist/lib/ai/route.d.ts +1 -1
- package/dist/lib/ai/shape.d.ts +1 -1
- package/dist/lib/ai/translate-document.d.ts +1 -1
- package/dist/lib/ai/translate-document.js +3 -3
- package/dist/lib/ai-panel.js +1 -1
- package/dist/lib/assets/index.d.ts +4 -4
- package/dist/lib/assets/index.js +4 -4
- package/dist/lib/assets/upload.d.ts +2 -2
- package/dist/lib/assets/upload.js +2 -2
- package/dist/lib/auth/convex-auth-adapter.d.ts +53 -2
- package/dist/lib/auth/convex-auth-adapter.js +149 -68
- package/dist/lib/auth/convex-auth-adapter.js.map +1 -1
- package/dist/lib/auth/dev-auto-login-adapter.d.ts +1 -1
- package/dist/lib/auth/index.d.ts +9 -9
- package/dist/lib/auth/index.js +10 -10
- package/dist/lib/auth/local-auth-adapter.d.ts +1 -1
- package/dist/lib/auth/route-guard.d.ts +1 -1
- package/dist/lib/auth-errors.d.ts +1 -1
- package/dist/lib/clipboard/index.d.ts +3 -3
- package/dist/lib/clipboard/index.js +3 -3
- package/dist/lib/cms/published-documents.d.ts +1 -1
- package/dist/lib/cms-views/index.d.ts +2 -2
- package/dist/lib/cms-views/index.js +2 -2
- package/dist/lib/collection-view/collection-view-source.d.ts +4 -4
- package/dist/lib/data/collection-content.js +1 -1
- package/dist/lib/data/data-store.js +6 -6
- package/dist/lib/data/index.d.ts +4 -4
- package/dist/lib/data/index.js +4 -4
- package/dist/lib/data/sample-capture.js +4 -4
- package/dist/lib/data/sources-store.d.ts +1 -1
- package/dist/lib/diff-view-preference.js +1 -1
- package/dist/lib/dnd/gap-drag.d.ts +1 -1
- package/dist/lib/i18n/i18n.d.ts +1 -1
- package/dist/lib/i18n/i18n.js +1 -1
- package/dist/lib/i18n/index.d.ts +4 -4
- package/dist/lib/i18n/index.js +3 -3
- package/dist/lib/i18n/messages.en.d.ts +1 -1
- package/dist/lib/i18n/messages.en.js +1 -1
- package/dist/lib/locale/binding-fallback.d.ts +1 -1
- package/dist/lib/locale/binding-fallback.js +2 -2
- package/dist/lib/locale/index.d.ts +6 -6
- package/dist/lib/locale/index.js +6 -6
- package/dist/lib/locale/locale-switcher.js +3 -3
- package/dist/lib/locale/use-studio-locale.js +1 -1
- package/dist/lib/operations/asset-repository.d.ts +1 -1
- package/dist/lib/operations/cms-persistence.d.ts +1 -1
- package/dist/lib/operations/cms-persistence.js +1 -1
- package/dist/lib/operations/index.d.ts +6 -6
- package/dist/lib/operations/index.js +6 -6
- package/dist/lib/operations/session-hydration.d.ts +1 -1
- package/dist/lib/operations/session-hydration.js +1 -1
- package/dist/lib/operations/studio-operations.d.ts +1 -1
- package/dist/lib/operations/studio-operations.js +3 -3
- package/dist/lib/persistence/convex-adapter.js +2 -2
- package/dist/lib/persistence/convex-blob-storage.d.ts +1 -1
- package/dist/lib/persistence/convex-blob-storage.js +1 -1
- package/dist/lib/persistence/deployment-readiness.d.ts +2 -2
- package/dist/lib/persistence/index.d.ts +6 -6
- package/dist/lib/persistence/index.js +7 -7
- package/dist/lib/persona/labels.js +1 -1
- package/dist/lib/query/index.d.ts +2 -2
- package/dist/lib/query/index.js +1 -1
- package/dist/lib/rail.js +1 -1
- package/dist/lib/references/impact.d.ts +1 -1
- package/dist/lib/references/impact.js +1 -1
- package/dist/lib/references/index.d.ts +3 -3
- package/dist/lib/references/index.js +3 -3
- package/dist/lib/references/references-store.d.ts +2 -2
- package/dist/lib/references/references-store.js +3 -3
- package/dist/lib/registry/index.js +2 -2
- package/dist/lib/theme.js +1 -1
- package/dist/lib/webhooks/config.d.ts +1 -1
- package/dist/lib/webhooks/config.js +2 -2
- package/dist/lib/webhooks/dispatcher.js +2 -2
- package/dist/lib/webhooks/index.d.ts +6 -6
- package/dist/lib/webhooks/index.js +4 -4
- package/dist/lib/workspace/index.d.ts +7 -7
- package/dist/lib/workspace/index.js +3 -3
- package/dist/lib/workspace/switcher-source.d.ts +1 -1
- package/dist/router/index.d.ts +1 -1
- package/dist/router/index.js +1 -1
- package/dist/ui/avatar.js +1 -1
- package/dist/ui/badge.js +1 -1
- package/dist/ui/button.js +1 -1
- package/dist/ui/card.js +1 -1
- package/dist/ui/collapsible-section.js +2 -2
- package/dist/ui/dialog.js +1 -1
- package/dist/ui/dropdown-menu.js +1 -1
- package/dist/ui/field.js +1 -1
- package/dist/ui/index.d.ts +19 -19
- package/dist/ui/index.js +19 -19
- package/dist/ui/input.js +1 -1
- package/dist/ui/inspector.js +1 -1
- package/dist/ui/layout.js +1 -1
- package/dist/ui/panel.js +2 -2
- package/dist/ui/popover.js +1 -1
- package/dist/ui/row-item.js +2 -2
- package/dist/ui/segmented-control.js +1 -1
- package/dist/ui/separator.js +1 -1
- package/dist/ui/toolbar.js +2 -2
- package/dist/ui/typography.js +1 -1
- package/package.json +3 -3
- package/dist/components/assets/asset-library.d.ts +0 -14
- package/dist/components/assets/asset-library.js +0 -202
- package/dist/components/assets/asset-library.js.map +0 -1
- package/dist/components/backend-gate.d.ts +0 -19
- package/dist/components/backend-gate.js +0 -64
- package/dist/components/backend-gate.js.map +0 -1
- package/dist/components/builder/composition-scope.d.ts +0 -16
- package/dist/components/builder/composition-scope.js +0 -7
- package/dist/components/builder/composition-scope.js.map +0 -1
- package/dist/components/cms/alias-selector.d.ts +0 -20
- package/dist/components/cms/alias-selector.js +0 -34
- package/dist/components/cms/alias-selector.js.map +0 -1
- package/dist/components/cms/collections-sidebar.d.ts +0 -18
- package/dist/components/cms/collections-sidebar.js +0 -36
- package/dist/components/cms/collections-sidebar.js.map +0 -1
- package/dist/components/cms/new-page-dialog.d.ts +0 -22
- package/dist/components/cms/new-page-dialog.js +0 -42
- package/dist/components/cms/new-page-dialog.js.map +0 -1
- package/dist/components/cms/rich-text/embed-control.d.ts +0 -17
- package/dist/components/cms/rich-text/embed-control.js +0 -62
- package/dist/components/cms/rich-text/embed-control.js.map +0 -1
- package/dist/components/cms/rich-text/image-control.d.ts +0 -16
- package/dist/components/cms/rich-text/image-control.js +0 -36
- package/dist/components/cms/rich-text/image-control.js.map +0 -1
- package/dist/components/components/fixture-runner.d.ts +0 -10
- package/dist/components/components/fixture-runner.js +0 -27
- package/dist/components/components/fixture-runner.js.map +0 -1
- package/dist/components/references/builder-deep-link.d.ts +0 -12
- package/dist/components/references/builder-deep-link.js +0 -53
- package/dist/components/references/builder-deep-link.js.map +0 -1
- package/dist/components/routes/redirect-chain.d.ts +0 -9
- package/dist/components/routes/redirect-chain.js +0 -16
- package/dist/components/routes/redirect-chain.js.map +0 -1
- package/dist/components/routes/redirect-manager.d.ts +0 -13
- package/dist/components/routes/redirect-manager.js +0 -24
- package/dist/components/routes/redirect-manager.js.map +0 -1
- package/dist/components/routes/route-list.d.ts +0 -35
- package/dist/components/routes/route-list.js +0 -69
- package/dist/components/routes/route-list.js.map +0 -1
- package/dist/components/routes/routes-shell.d.ts +0 -14
- package/dist/components/routes/routes-shell.js +0 -68
- package/dist/components/routes/routes-shell.js.map +0 -1
- package/dist/components/sections.d.ts +0 -37
- package/dist/components/sections.js +0 -62
- package/dist/components/sections.js.map +0 -1
- package/dist/components/users/user-search.d.ts +0 -8
- package/dist/components/users/user-search.js +0 -13
- package/dist/components/users/user-search.js.map +0 -1
- package/dist/components/workspace-gate.d.ts +0 -12
- package/dist/components/workspace-gate.js +0 -28
- package/dist/components/workspace-gate.js.map +0 -1
- package/dist/lib/cms-views/views-store.d.ts +0 -70
- package/dist/lib/cms-views/views-store.js +0 -129
- package/dist/lib/cms-views/views-store.js.map +0 -1
- package/dist/lib/operations/graph-commands.d.ts +0 -136
- package/dist/lib/operations/graph-commands.js +0 -85
- package/dist/lib/operations/graph-commands.js.map +0 -1
- package/dist/lib/operations/graph-persistence.d.ts +0 -27
- package/dist/lib/operations/graph-persistence.js +0 -35
- package/dist/lib/operations/graph-persistence.js.map +0 -1
- package/dist/lib/routing/index.d.ts +0 -10
- package/dist/lib/routing/index.js +0 -11
- package/dist/lib/routing/index.js.map +0 -1
- package/dist/lib/routing/routing-analysis.d.ts +0 -26
- package/dist/lib/routing/routing-analysis.js +0 -37
- package/dist/lib/routing/routing-analysis.js.map +0 -1
- package/dist/lib/routing/routing-store.d.ts +0 -50
- package/dist/lib/routing/routing-store.js +0 -72
- package/dist/lib/routing/routing-store.js.map +0 -1
- package/dist/lib/working-graph.d.ts +0 -82
- package/dist/lib/working-graph.js +0 -113
- package/dist/lib/working-graph.js.map +0 -1
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Index the router's `route-conflict` issues by route id, attributing each
|
|
3
|
-
* conflict to BOTH routes in the pair so each affected row can render it
|
|
4
|
-
* inline with a deep link to its counterpart.
|
|
5
|
-
*/
|
|
6
|
-
export function conflictsByRoute(issues) {
|
|
7
|
-
const map = new Map();
|
|
8
|
-
const add = (routeId, conflict) => {
|
|
9
|
-
const list = map.get(routeId) ?? [];
|
|
10
|
-
list.push(conflict);
|
|
11
|
-
map.set(routeId, list);
|
|
12
|
-
};
|
|
13
|
-
for (const issue of issues) {
|
|
14
|
-
if (issue.code !== 'route-conflict')
|
|
15
|
-
continue;
|
|
16
|
-
// The engine attaches the issue at path ['routes', <routeId>] and names
|
|
17
|
-
// the partner in meta.conflictsWith.
|
|
18
|
-
const routeId = typeof issue.path[1] === 'string' ? issue.path[1] : undefined;
|
|
19
|
-
const other = typeof issue.meta?.conflictsWith === 'string' ? issue.meta.conflictsWith : undefined;
|
|
20
|
-
if (routeId)
|
|
21
|
-
add(routeId, { issue, otherRouteId: other ?? '' });
|
|
22
|
-
if (other && routeId)
|
|
23
|
-
add(other, { issue, otherRouteId: routeId });
|
|
24
|
-
}
|
|
25
|
-
return map;
|
|
26
|
-
}
|
|
27
|
-
/** 301/302 label for a redirect record. */
|
|
28
|
-
export function statusCodeOf(redirect) {
|
|
29
|
-
return redirect.permanent ? '301' : '302';
|
|
30
|
-
}
|
|
31
|
-
export function patternSegments(pattern) {
|
|
32
|
-
return pattern
|
|
33
|
-
.split('/')
|
|
34
|
-
.filter((segment) => segment.length > 0)
|
|
35
|
-
.map((segment) => segment.startsWith(':') ? { text: segment, param: true } : { text: segment, param: false });
|
|
36
|
-
}
|
|
37
|
-
//# sourceMappingURL=routing-analysis.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"routing-analysis.js","sourceRoot":"","sources":["../../../src/lib/routing/routing-analysis.ts"],"names":[],"mappings":"AAeA;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAqC;IAErC,MAAM,GAAG,GAAG,IAAI,GAAG,EAA2B,CAAA;IAC9C,MAAM,GAAG,GAAG,CAAC,OAAe,EAAE,QAAuB,EAAE,EAAE;QACvD,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;QACnC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACnB,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IACxB,CAAC,CAAA;IACD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB;YAAE,SAAQ;QAC7C,wEAAwE;QACxE,qCAAqC;QACrC,MAAM,OAAO,GAAG,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAC7E,MAAM,KAAK,GACT,OAAO,KAAK,CAAC,IAAI,EAAE,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAA;QACtF,IAAI,OAAO;YAAE,GAAG,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,IAAI,EAAE,EAAE,CAAC,CAAA;QAC/D,IAAI,KAAK,IAAI,OAAO;YAAE,GAAG,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,CAAA;IACpE,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,YAAY,CAAC,QAA2C;IACtE,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAA;AAC3C,CAAC;AAQD,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,OAAO,OAAO;SACX,KAAK,CAAC,GAAG,CAAC;SACV,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;SACvC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CACf,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAC3F,CAAA;AACL,CAAC","sourcesContent":["import type { CmsValidationIssue, RedirectRecord } from '@elytracms/core/cms-core'\n\n/**\n * Engine-derived view models for the Routes section (EC-170). Everything here\n * is a thin projection over the existing `@elytracms/core/cms-core` router — the UI\n * never reimplements pattern matching, conflict detection, or loop detection.\n */\n\nexport interface RouteConflict {\n /** The structured `route-conflict` issue from `createRouter`. */\n issue: CmsValidationIssue\n /** The id of the *other* route in the conflicting pair. */\n otherRouteId: string\n}\n\n/**\n * Index the router's `route-conflict` issues by route id, attributing each\n * conflict to BOTH routes in the pair so each affected row can render it\n * inline with a deep link to its counterpart.\n */\nexport function conflictsByRoute(\n issues: readonly CmsValidationIssue[],\n): Map<string, RouteConflict[]> {\n const map = new Map<string, RouteConflict[]>()\n const add = (routeId: string, conflict: RouteConflict) => {\n const list = map.get(routeId) ?? []\n list.push(conflict)\n map.set(routeId, list)\n }\n for (const issue of issues) {\n if (issue.code !== 'route-conflict') continue\n // The engine attaches the issue at path ['routes', <routeId>] and names\n // the partner in meta.conflictsWith.\n const routeId = typeof issue.path[1] === 'string' ? issue.path[1] : undefined\n const other =\n typeof issue.meta?.conflictsWith === 'string' ? issue.meta.conflictsWith : undefined\n if (routeId) add(routeId, { issue, otherRouteId: other ?? '' })\n if (other && routeId) add(other, { issue, otherRouteId: routeId })\n }\n return map\n}\n\n/** 301/302 label for a redirect record. */\nexport function statusCodeOf(redirect: Pick<RedirectRecord, 'permanent'>): '301' | '302' {\n return redirect.permanent ? '301' : '302'\n}\n\n/** Split a route pattern into segments, flagging `:param` segments. */\nexport interface PatternSegmentView {\n text: string\n param: boolean\n}\n\nexport function patternSegments(pattern: string): PatternSegmentView[] {\n return pattern\n .split('/')\n .filter((segment) => segment.length > 0)\n .map((segment) =>\n segment.startsWith(':') ? { text: segment, param: true } : { text: segment, param: false },\n )\n}\n"]}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import type { RouteRecord } from '@elytracms/core/cms-core';
|
|
2
|
-
/**
|
|
3
|
-
* Pure template-route helpers for the Routes domain (EC-166, reshaped by
|
|
4
|
-
* EC-187; route persistence retired by EC-207).
|
|
5
|
-
*
|
|
6
|
-
* Routes & redirects are config-sourced (EC-207 "routes as code"): they are
|
|
7
|
-
* authored in `elytra.config.ts`, materialized by `composeProject`, and read
|
|
8
|
-
* through `resolveDeploymentRoutes`/`resolveDeploymentRedirects` — never written
|
|
9
|
-
* to or read from the backend. The former `routes`/`redirects` system
|
|
10
|
-
* collections are retired. What survives here are pure functions over the
|
|
11
|
-
* canonical `RouteRecord` schema, useful for authoring/inspecting template
|
|
12
|
-
* routes in config.
|
|
13
|
-
*
|
|
14
|
-
* A template page is one page definition serving *every* document of a
|
|
15
|
-
* collection through a dynamic pattern. It is expressed entirely in the
|
|
16
|
-
* canonical route-record schema: the parameterized `document` ref
|
|
17
|
-
* (`{ collection, id: ':slug' }`) names the collection plus the URL param
|
|
18
|
-
* carrying the document's slug/id — `@elytracms/core/content`'s `resolvePage`
|
|
19
|
-
* substitutes the matched value at request time. After EC-187 there is no
|
|
20
|
-
* `templateId`; a template route is identified purely by its parameterized
|
|
21
|
-
* `document` ref (a `:param` id over a collection). One template route per
|
|
22
|
-
* collection. No new record shape, no parallel store.
|
|
23
|
-
*/
|
|
24
|
-
/** Deterministic record id: one template route per collection (EC-187). */
|
|
25
|
-
export declare function templateRouteId(collectionId: string): string;
|
|
26
|
-
export interface TemplateRouteInit {
|
|
27
|
-
collectionId: string;
|
|
28
|
-
/** Dynamic pattern, e.g. `/blog/:slug`. Must capture {@link param}. */
|
|
29
|
-
pattern: string;
|
|
30
|
-
/** The URL param carrying the document slug or id. Defaults to `slug`. */
|
|
31
|
-
param?: string;
|
|
32
|
-
locale?: string;
|
|
33
|
-
}
|
|
34
|
-
/** What a template route binds, read back from a stored record. */
|
|
35
|
-
export interface TemplateRouteBinding {
|
|
36
|
-
collectionId: string;
|
|
37
|
-
param: string;
|
|
38
|
-
}
|
|
39
|
-
/** Build the canonical route record of a template page. */
|
|
40
|
-
export declare function buildTemplateRoute(init: TemplateRouteInit): RouteRecord;
|
|
41
|
-
/** The collection + param a route record templates over, if it is one. */
|
|
42
|
-
export declare function templateBindingOf(route: RouteRecord): TemplateRouteBinding | undefined;
|
|
43
|
-
/** The template route serving a collection, if registered (EC-187). */
|
|
44
|
-
export declare function templateRouteFor(routes: readonly RouteRecord[], collectionId: string): RouteRecord | undefined;
|
|
45
|
-
/**
|
|
46
|
-
* Plain-language validation of a template pattern: it must be a real dynamic
|
|
47
|
-
* pattern that captures the document param exactly once. Returns `undefined`
|
|
48
|
-
* when the pattern is usable.
|
|
49
|
-
*/
|
|
50
|
-
export declare function templatePatternError(pattern: string, param?: string): string | undefined;
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { routeRecordSchema } from '@elytracms/core/cms-core';
|
|
2
|
-
/**
|
|
3
|
-
* Pure template-route helpers for the Routes domain (EC-166, reshaped by
|
|
4
|
-
* EC-187; route persistence retired by EC-207).
|
|
5
|
-
*
|
|
6
|
-
* Routes & redirects are config-sourced (EC-207 "routes as code"): they are
|
|
7
|
-
* authored in `elytra.config.ts`, materialized by `composeProject`, and read
|
|
8
|
-
* through `resolveDeploymentRoutes`/`resolveDeploymentRedirects` — never written
|
|
9
|
-
* to or read from the backend. The former `routes`/`redirects` system
|
|
10
|
-
* collections are retired. What survives here are pure functions over the
|
|
11
|
-
* canonical `RouteRecord` schema, useful for authoring/inspecting template
|
|
12
|
-
* routes in config.
|
|
13
|
-
*
|
|
14
|
-
* A template page is one page definition serving *every* document of a
|
|
15
|
-
* collection through a dynamic pattern. It is expressed entirely in the
|
|
16
|
-
* canonical route-record schema: the parameterized `document` ref
|
|
17
|
-
* (`{ collection, id: ':slug' }`) names the collection plus the URL param
|
|
18
|
-
* carrying the document's slug/id — `@elytracms/core/content`'s `resolvePage`
|
|
19
|
-
* substitutes the matched value at request time. After EC-187 there is no
|
|
20
|
-
* `templateId`; a template route is identified purely by its parameterized
|
|
21
|
-
* `document` ref (a `:param` id over a collection). One template route per
|
|
22
|
-
* collection. No new record shape, no parallel store.
|
|
23
|
-
*/
|
|
24
|
-
/** Deterministic record id: one template route per collection (EC-187). */
|
|
25
|
-
export function templateRouteId(collectionId) {
|
|
26
|
-
return `route-template-${collectionId}`;
|
|
27
|
-
}
|
|
28
|
-
/** Build the canonical route record of a template page. */
|
|
29
|
-
export function buildTemplateRoute(init) {
|
|
30
|
-
const param = init.param ?? 'slug';
|
|
31
|
-
return routeRecordSchema.parse({
|
|
32
|
-
id: templateRouteId(init.collectionId),
|
|
33
|
-
pattern: init.pattern,
|
|
34
|
-
document: { collection: init.collectionId, id: `:${param}` },
|
|
35
|
-
...(init.locale !== undefined ? { locale: init.locale } : {}),
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
/** The collection + param a route record templates over, if it is one. */
|
|
39
|
-
export function templateBindingOf(route) {
|
|
40
|
-
if (route.document === undefined)
|
|
41
|
-
return undefined;
|
|
42
|
-
if (!route.document.id.startsWith(':'))
|
|
43
|
-
return undefined;
|
|
44
|
-
return { collectionId: route.document.collection, param: route.document.id.slice(1) };
|
|
45
|
-
}
|
|
46
|
-
/** The template route serving a collection, if registered (EC-187). */
|
|
47
|
-
export function templateRouteFor(routes, collectionId) {
|
|
48
|
-
return routes.find((route) => templateBindingOf(route)?.collectionId === collectionId);
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Plain-language validation of a template pattern: it must be a real dynamic
|
|
52
|
-
* pattern that captures the document param exactly once. Returns `undefined`
|
|
53
|
-
* when the pattern is usable.
|
|
54
|
-
*/
|
|
55
|
-
export function templatePatternError(pattern, param = 'slug') {
|
|
56
|
-
if (!pattern.startsWith('/'))
|
|
57
|
-
return 'The address must start with “/”.';
|
|
58
|
-
const segments = pattern.split('/').filter((segment) => segment.length > 0);
|
|
59
|
-
if (segments.length === 0)
|
|
60
|
-
return `The address needs at least one part, e.g. “/posts/:${param}”.`;
|
|
61
|
-
if (segments.some((segment) => segment === ':'))
|
|
62
|
-
return 'A “:” part needs a name after it.';
|
|
63
|
-
const params = segments.filter((segment) => segment.startsWith(':'));
|
|
64
|
-
if (params.length === 0) {
|
|
65
|
-
return `The address needs a “:${param}” part — that's where each entry's own address goes.`;
|
|
66
|
-
}
|
|
67
|
-
if (params.length > 1 || params[0] !== `:${param}`) {
|
|
68
|
-
return `Use exactly one “:${param}” part so every entry gets its own address.`;
|
|
69
|
-
}
|
|
70
|
-
return undefined;
|
|
71
|
-
}
|
|
72
|
-
//# sourceMappingURL=routing-store.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"routing-store.js","sourceRoot":"","sources":["../../../src/lib/routing/routing-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAG5D;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,2EAA2E;AAC3E,MAAM,UAAU,eAAe,CAAC,YAAoB;IAClD,OAAO,kBAAkB,YAAY,EAAE,CAAA;AACzC,CAAC;AAiBD,2DAA2D;AAC3D,MAAM,UAAU,kBAAkB,CAAC,IAAuB;IACxD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,MAAM,CAAA;IAClC,OAAO,iBAAiB,CAAC,KAAK,CAAC;QAC7B,EAAE,EAAE,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC;QACtC,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,QAAQ,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,YAAY,EAAE,EAAE,EAAE,IAAI,KAAK,EAAE,EAAE;QAC5D,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9D,CAAC,CAAA;AACJ,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,iBAAiB,CAAC,KAAkB;IAClD,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IAClD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAA;IACxD,OAAO,EAAE,YAAY,EAAE,KAAK,CAAC,QAAQ,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;AACvF,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,gBAAgB,CAC9B,MAA8B,EAC9B,YAAoB;IAEpB,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,YAAY,KAAK,YAAY,CAAC,CAAA;AACxF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAe,EAAE,KAAK,GAAG,MAAM;IAClE,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,kCAAkC,CAAA;IACvE,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC3E,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,sDAAsD,KAAK,IAAI,CAAA;IACjG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,GAAG,CAAC;QAAE,OAAO,mCAAmC,CAAA;IAC3F,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAA;IACpE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,yBAAyB,KAAK,sDAAsD,CAAA;IAC7F,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,KAAK,EAAE,EAAE,CAAC;QACnD,OAAO,qBAAqB,KAAK,6CAA6C,CAAA;IAChF,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC","sourcesContent":["import { routeRecordSchema } from '@elytracms/core/cms-core'\nimport type { RouteRecord } from '@elytracms/core/cms-core'\n\n/**\n * Pure template-route helpers for the Routes domain (EC-166, reshaped by\n * EC-187; route persistence retired by EC-207).\n *\n * Routes & redirects are config-sourced (EC-207 \"routes as code\"): they are\n * authored in `elytra.config.ts`, materialized by `composeProject`, and read\n * through `resolveDeploymentRoutes`/`resolveDeploymentRedirects` — never written\n * to or read from the backend. The former `routes`/`redirects` system\n * collections are retired. What survives here are pure functions over the\n * canonical `RouteRecord` schema, useful for authoring/inspecting template\n * routes in config.\n *\n * A template page is one page definition serving *every* document of a\n * collection through a dynamic pattern. It is expressed entirely in the\n * canonical route-record schema: the parameterized `document` ref\n * (`{ collection, id: ':slug' }`) names the collection plus the URL param\n * carrying the document's slug/id — `@elytracms/core/content`'s `resolvePage`\n * substitutes the matched value at request time. After EC-187 there is no\n * `templateId`; a template route is identified purely by its parameterized\n * `document` ref (a `:param` id over a collection). One template route per\n * collection. No new record shape, no parallel store.\n */\n\n/** Deterministic record id: one template route per collection (EC-187). */\nexport function templateRouteId(collectionId: string): string {\n return `route-template-${collectionId}`\n}\n\nexport interface TemplateRouteInit {\n collectionId: string\n /** Dynamic pattern, e.g. `/blog/:slug`. Must capture {@link param}. */\n pattern: string\n /** The URL param carrying the document slug or id. Defaults to `slug`. */\n param?: string\n locale?: string\n}\n\n/** What a template route binds, read back from a stored record. */\nexport interface TemplateRouteBinding {\n collectionId: string\n param: string\n}\n\n/** Build the canonical route record of a template page. */\nexport function buildTemplateRoute(init: TemplateRouteInit): RouteRecord {\n const param = init.param ?? 'slug'\n return routeRecordSchema.parse({\n id: templateRouteId(init.collectionId),\n pattern: init.pattern,\n document: { collection: init.collectionId, id: `:${param}` },\n ...(init.locale !== undefined ? { locale: init.locale } : {}),\n })\n}\n\n/** The collection + param a route record templates over, if it is one. */\nexport function templateBindingOf(route: RouteRecord): TemplateRouteBinding | undefined {\n if (route.document === undefined) return undefined\n if (!route.document.id.startsWith(':')) return undefined\n return { collectionId: route.document.collection, param: route.document.id.slice(1) }\n}\n\n/** The template route serving a collection, if registered (EC-187). */\nexport function templateRouteFor(\n routes: readonly RouteRecord[],\n collectionId: string,\n): RouteRecord | undefined {\n return routes.find((route) => templateBindingOf(route)?.collectionId === collectionId)\n}\n\n/**\n * Plain-language validation of a template pattern: it must be a real dynamic\n * pattern that captures the document param exactly once. Returns `undefined`\n * when the pattern is usable.\n */\nexport function templatePatternError(pattern: string, param = 'slug'): string | undefined {\n if (!pattern.startsWith('/')) return 'The address must start with “/”.'\n const segments = pattern.split('/').filter((segment) => segment.length > 0)\n if (segments.length === 0) return `The address needs at least one part, e.g. “/posts/:${param}”.`\n if (segments.some((segment) => segment === ':')) return 'A “:” part needs a name after it.'\n const params = segments.filter((segment) => segment.startsWith(':'))\n if (params.length === 0) {\n return `The address needs a “:${param}” part — that's where each entry's own address goes.`\n }\n if (params.length > 1 || params[0] !== `:${param}`) {\n return `Use exactly one “:${param}” part so every entry gets its own address.`\n }\n return undefined\n}\n"]}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import type { ComponentNode, Layout, ProjectGraph } from '@elytracms/core/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/core/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;
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { normalizeContainers, PROJECT_GRAPH_SCHEMA_VERSION } from '@elytracms/core/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
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"working-graph.js","sourceRoot":"","sources":["../../src/lib/working-graph.ts"],"names":[],"mappings":"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","sourcesContent":["import { normalizeContainers, PROJECT_GRAPH_SCHEMA_VERSION } from '@elytracms/core/project-graph'\nimport type { ComponentNode, Layout, ProjectGraph } from '@elytracms/core/project-graph'\n\n/**\n * Builder-local WORKING GRAPH (EC-187).\n *\n * The canonical {@link ProjectGraph} is now LAYOUTS-ONLY — a page is a document\n * in the `page` collection (its `body` is a composition field value). But the\n * legacy `/builder` editor and the composition-field editor are *node-tree*\n * editors: they edit a single root-bearing surface with undo/redo, selection,\n * and the same structural edit ops. So the builder store keeps its own\n * root-bearing working type, decoupled from the page-less canonical schema.\n *\n * A `WorkingGraph` is a `ProjectGraph` (layouts + metadata) PLUS a `pages`\n * array of {@link WorkingPage} — exactly the shape the reducer/history/edit ops\n * have always operated on. It NEVER persists in this shape: page-body edits lift\n * into a CMS document (the composition-field editor), and layout edits persist\n * through the canonical layouts-only `graph.save`. {@link toProjectGraph} drops\n * the pages to produce the canonical graph when one is needed.\n */\n\n/**\n * Per-page SEO block (EC-171, legacy `/builder` chrome). The canonical\n * `PageSeo` shape lived in `@elytracms/core/project-graph` and was deleted with the\n * page node (EC-187); page SEO now lives on the `page` collection document's\n * flat `seo*` fields. The legacy page-SEO panel keeps editing this local block\n * so it stays compiling/tested until `/builder` is retired.\n */\nexport interface WorkingPageSeo {\n title?: string\n description?: string\n ogTitle?: string\n ogImage?: string\n noindex?: boolean\n}\n\n/** A page in the builder's working state — a root-bearing editable surface. */\nexport interface WorkingPage {\n id: string\n name: string\n /** Optional shared layout wrapper id (canvas preview only). */\n layoutId?: string\n /** Root node of the page's component tree (the edited surface). */\n root: ComponentNode\n /** Legacy per-page SEO block (EC-171). */\n seo?: WorkingPageSeo\n}\n\n/** The builder's internal working graph: the canonical layouts-only graph + editable pages. */\nexport interface WorkingGraph {\n id: string\n schemaVersion: number\n metadata?: { name?: string }\n settingsRef?: string\n layouts: Layout[]\n pages: WorkingPage[]\n}\n\nconst SYNTH_PAGE_ID = 'page.working'\n\n/**\n * Lift a (layouts-only) canonical {@link ProjectGraph} into a {@link WorkingGraph}\n * with a single editable page, so the legacy builder canvas has a root to edit.\n * The page root is an empty Stack the editor fills; the page selects the first\n * layout for canvas preview (if any).\n */\nexport function toWorkingGraph(graph: ProjectGraph): WorkingGraph {\n return {\n ...graph,\n pages: [\n {\n id: SYNTH_PAGE_ID,\n name: graph.metadata?.name ?? 'Page',\n ...(graph.layouts[0] ? { layoutId: graph.layouts[0].id } : {}),\n root: { id: 'working.root', componentId: 'base.primitives.Stack', slots: { children: [] } },\n },\n ],\n }\n}\n\n/** Drop the editable pages to produce the canonical (layouts-only) {@link ProjectGraph}. */\nexport function toProjectGraph(graph: WorkingGraph): ProjectGraph {\n const { pages: _pages, ...canonical } = graph\n return canonical\n}\n\n/** Build a working graph that wraps one composition value in a single editable page. */\nexport function workingGraphFromPage(page: WorkingPage, layouts: Layout[] = []): WorkingGraph {\n return {\n id: 'working',\n schemaVersion: PROJECT_GRAPH_SCHEMA_VERSION,\n layouts,\n pages: [page],\n }\n}\n\n/**\n * Normalize every editable surface of a working graph — each page root AND\n * each layout root — via `normalizeContainers`. Mirrors the OLD\n * `normalizeProjectGraph` (which normalized pages too, before EC-187 made the\n * canonical graph layouts-only). Identity-preserving: returns the same graph\n * reference when nothing changed so undo histories can detect no-ops by\n * reference.\n */\nexport function normalizeWorkingGraph(graph: WorkingGraph): WorkingGraph {\n let changed = false\n const pages = graph.pages.map((page) => {\n const root = normalizeContainers(page.root)\n if (root !== page.root) changed = true\n return root === page.root ? page : { ...page, root }\n })\n const layouts = graph.layouts.map((layout) => {\n const root = normalizeContainers(layout.root)\n if (root !== layout.root) changed = true\n return root === layout.root ? layout : { ...layout, root }\n })\n return changed ? { ...graph, pages, layouts } : graph\n}\n\n// ---- Legacy page SEO (EC-171) ----------------------------------------------\n//\n// The canonical `setPageSeo`/`cleanPageSeo`/`PageSeo` were deleted with the\n// page node (EC-187). These local helpers mirror the old behavior over the\n// working graph's per-page `seo` block so the legacy SEO panel keeps working.\n\n/** Strip empty fields; an all-empty block becomes `undefined` (clear the block). */\nexport function cleanWorkingPageSeo(seo: WorkingPageSeo): WorkingPageSeo | undefined {\n const trimmed = (value: string | undefined): string | undefined => {\n const next = value?.trim()\n return next ? next : undefined\n }\n const next: WorkingPageSeo = {}\n const title = trimmed(seo.title)\n const description = trimmed(seo.description)\n const ogTitle = trimmed(seo.ogTitle)\n const ogImage = trimmed(seo.ogImage)\n if (title !== undefined) next.title = title\n if (description !== undefined) next.description = description\n if (ogTitle !== undefined) next.ogTitle = ogTitle\n if (ogImage !== undefined) next.ogImage = ogImage\n if (seo.noindex) next.noindex = true\n return Object.keys(next).length > 0 ? next : undefined\n}\n\n/**\n * Apply a (cleaned) SEO block to a page in the working graph. Identity on\n * no-ops — callers dispatch only when this returns a new graph. An `undefined`\n * block removes `seo` from the page entity entirely.\n */\nexport function setWorkingPageSeo(\n graph: WorkingGraph,\n pageId: string,\n seo: WorkingPageSeo | undefined,\n): WorkingGraph {\n const page = graph.pages.find((p) => p.id === pageId)\n if (!page) return graph\n const sameBlock = JSON.stringify(page.seo ?? null) === JSON.stringify(seo ?? null)\n if (sameBlock) return graph\n return {\n ...graph,\n pages: graph.pages.map((p) => {\n if (p.id !== pageId) return p\n if (seo === undefined) {\n const { seo: _drop, ...rest } = p\n return rest\n }\n return { ...p, seo }\n }),\n }\n}\n"]}
|