canopycms 0.0.68-int.98 → 0.1.0
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/CHANGELOG.md +2131 -0
- package/README.md +47 -63
- package/dist/ai/generate.d.ts +5 -0
- package/dist/ai/generate.js +244 -115
- package/dist/ai/index.d.ts +1 -1
- package/dist/ai/json-to-markdown.d.ts +21 -1
- package/dist/ai/json-to-markdown.js +120 -57
- package/dist/ai/references.d.ts +72 -0
- package/dist/ai/references.js +223 -0
- package/dist/ai/resolve-branch.js +9 -2
- package/dist/ai/to-plain-text.d.ts +17 -8
- package/dist/ai/to-plain-text.js +18 -15
- package/dist/ai/types.d.ts +84 -3
- package/dist/api/admin-branch-health.d.ts +24 -1
- package/dist/api/admin-branch-health.js +52 -20
- package/dist/api/admin.d.ts +23 -5
- package/dist/api/admin.js +36 -1
- package/dist/api/assets.js +88 -78
- package/dist/api/branch-create-window.d.ts +12 -0
- package/dist/api/branch-create-window.js +13 -0
- package/dist/api/branch-merge.d.ts +1 -1
- package/dist/api/branch-merge.js +1 -1
- package/dist/api/branch-review.d.ts +3 -3
- package/dist/api/branch-review.js +16 -7
- package/dist/api/branch-status.d.ts +16 -6
- package/dist/api/branch-status.js +57 -12
- package/dist/api/branch-withdraw.d.ts +2 -2
- package/dist/api/branch-withdraw.js +8 -3
- package/dist/api/branch.d.ts +25 -12
- package/dist/api/branch.js +164 -103
- package/dist/api/client.d.ts +78 -58
- package/dist/api/client.js +150 -117
- package/dist/api/comments.d.ts +12 -3
- package/dist/api/comments.js +118 -9
- package/dist/api/content.d.ts +9 -9
- package/dist/api/content.js +131 -22
- package/dist/api/entries-constants.d.ts +14 -3
- package/dist/api/entries-constants.js +14 -3
- package/dist/api/entries.d.ts +40 -2
- package/dist/api/entries.js +102 -6
- package/dist/api/github-sync.d.ts +19 -0
- package/dist/api/github-sync.js +50 -3
- package/dist/api/groups.d.ts +4 -4
- package/dist/api/groups.js +2 -1
- package/dist/api/guards.js +23 -3
- package/dist/api/index.d.ts +3 -1
- package/dist/api/index.js +1 -0
- package/dist/api/permissions.d.ts +21 -2
- package/dist/api/permissions.js +50 -3
- package/dist/api/request-deadline.d.ts +59 -0
- package/dist/api/request-deadline.js +73 -0
- package/dist/api/resolve-references.js +8 -7
- package/dist/api/route-builder.d.ts +14 -0
- package/dist/api/route-builder.js +14 -1
- package/dist/api/schema.d.ts +11 -9
- package/dist/api/schema.js +2 -0
- package/dist/api/settings-helpers.d.ts +5 -1
- package/dist/api/settings-helpers.js +10 -2
- package/dist/api/types.d.ts +18 -0
- package/dist/api/users-constants.d.ts +6 -0
- package/dist/api/users-constants.js +6 -0
- package/dist/assets/asset-url.d.ts +28 -16
- package/dist/assets/asset-url.js +51 -25
- package/dist/assets/finalize.js +3 -0
- package/dist/assets/index.d.ts +1 -1
- package/dist/assets/materialize.d.ts +153 -0
- package/dist/assets/materialize.js +402 -0
- package/dist/assets/store-local.d.ts +19 -5
- package/dist/assets/store-local.js +69 -10
- package/dist/assets/store-s3.d.ts +38 -7
- package/dist/assets/store-s3.js +128 -22
- package/dist/assets/transform-directives.d.ts +52 -13
- package/dist/assets/transform-directives.js +87 -27
- package/dist/assets/transform.d.ts +3 -3
- package/dist/assets/transform.js +13 -8
- package/dist/assets/types.d.ts +31 -4
- package/dist/auth/cache.d.ts +1 -1
- package/dist/auth/cache.js +1 -1
- package/dist/auth/caching-auth-plugin.d.ts +2 -0
- package/dist/auth/caching-auth-plugin.js +12 -2
- package/dist/auth/file-based-auth-cache.d.ts +8 -0
- package/dist/auth/file-based-auth-cache.js +18 -8
- package/dist/auth/person-name.d.ts +5 -0
- package/dist/auth/person-name.js +8 -0
- package/dist/auth/plugin.d.ts +10 -1
- package/dist/auth/types.d.ts +2 -0
- package/dist/auth/user-metadata-lookup.d.ts +21 -0
- package/dist/auth/user-metadata-lookup.js +116 -0
- package/dist/authorization/branch.d.ts +1 -1
- package/dist/authorization/branch.js +12 -13
- package/dist/authorization/groups/schema.d.ts +4 -4
- package/dist/authorization/helpers.d.ts +8 -0
- package/dist/authorization/helpers.js +8 -0
- package/dist/authorization/index.d.ts +1 -1
- package/dist/authorization/index.js +1 -1
- package/dist/authorization/protected-branch.d.ts +5 -4
- package/dist/authorization/protected-branch.js +7 -5
- package/dist/branch-health.d.ts +35 -8
- package/dist/branch-health.js +54 -18
- package/dist/branch-metadata-error.d.ts +27 -0
- package/dist/branch-metadata-error.js +23 -0
- package/dist/branch-metadata-file.d.ts +205 -24
- package/dist/branch-metadata-file.js +126 -25
- package/dist/branch-metadata.d.ts +45 -6
- package/dist/branch-metadata.js +142 -50
- package/dist/branch-provisioning.d.ts +167 -0
- package/dist/branch-provisioning.js +501 -0
- package/dist/branch-registry.d.ts +8 -0
- package/dist/branch-registry.js +61 -9
- package/dist/branch-schema-cache.d.ts +29 -12
- package/dist/branch-schema-cache.js +64 -21
- package/dist/branch-sparse.d.ts +23 -0
- package/dist/branch-sparse.js +118 -0
- package/dist/branch-workspace.d.ts +42 -3
- package/dist/branch-workspace.js +239 -100
- package/dist/build/asset-refs.d.ts +94 -0
- package/dist/build/asset-refs.js +267 -0
- package/dist/build/generate-ai-content.js +5 -0
- package/dist/build/inline-flight.d.ts +37 -0
- package/dist/build/inline-flight.js +142 -0
- package/dist/cli/asset-refs.d.ts +52 -0
- package/dist/cli/asset-refs.js +194 -0
- package/dist/cli/cli.d.ts +15 -1
- package/dist/cli/cli.js +8543 -3193
- package/dist/cli/configured-asset-store.d.ts +12 -0
- package/dist/cli/configured-asset-store.js +46 -0
- package/dist/cli/generate-ai-content.js +4244 -1072
- package/dist/cli/init.js +217 -126
- package/dist/cli/project-detect.d.ts +2 -0
- package/dist/cli/project-detect.js +2 -0
- package/dist/cli/template-files/Dockerfile.cms.template +13 -5
- package/dist/cli/template-files/cms-stack.ts.template +16 -13
- package/dist/client.d.ts +1 -2
- package/dist/client.js +1 -2
- package/dist/comment-store.d.ts +25 -0
- package/dist/comment-store.js +43 -8
- package/dist/config/flatten.js +2 -0
- package/dist/config/helpers.js +2 -2
- package/dist/config/index.d.ts +1 -1
- package/dist/config/schemas/config.d.ts +12 -29
- package/dist/config/schemas/config.js +9 -12
- package/dist/config/schemas/field.d.ts +3 -0
- package/dist/config/schemas/field.js +58 -4
- package/dist/config/schemas/media.d.ts +4 -13
- package/dist/config/schemas/media.js +5 -8
- package/dist/config/schemas/url.d.ts +2 -20
- package/dist/config/schemas/url.js +2 -25
- package/dist/config/types.d.ts +116 -22
- package/dist/config/types.js +3 -9
- package/dist/config/validation.d.ts +25 -4
- package/dist/config/validation.js +116 -3
- package/dist/content-id-index.js +2 -2
- package/dist/content-index-generation.d.ts +1 -1
- package/dist/content-index-generation.js +1 -1
- package/dist/content-listing.d.ts +10 -1
- package/dist/content-listing.js +22 -5
- package/dist/content-reader.d.ts +9 -0
- package/dist/content-reader.js +16 -11
- package/dist/content-store.d.ts +75 -12
- package/dist/content-store.js +249 -86
- package/dist/content-tree.js +2 -2
- package/dist/context.js +5 -2
- package/dist/dangling-reference-log.d.ts +17 -0
- package/dist/dangling-reference-log.js +29 -0
- package/dist/dev-content-watcher.d.ts +1 -1
- package/dist/dev-content-watcher.js +1 -1
- package/dist/editor/BranchManager.d.ts +23 -7
- package/dist/editor/BranchManager.js +119 -54
- package/dist/editor/CanopyEditor.d.ts +1 -1
- package/dist/editor/CanopyEditor.js +1 -2
- package/dist/editor/CommentsPanel.d.ts +14 -0
- package/dist/editor/CommentsPanel.js +68 -43
- package/dist/editor/Editor.d.ts +11 -5
- package/dist/editor/Editor.js +891 -218
- package/dist/editor/EditorAuthGate.d.ts +7 -1
- package/dist/editor/EditorAuthGate.js +41 -9
- package/dist/editor/EntryNavigator.d.ts +22 -0
- package/dist/editor/EntryNavigator.js +353 -105
- package/dist/editor/FormHeader.d.ts +25 -0
- package/dist/editor/FormHeader.js +82 -0
- package/dist/editor/FormRenderer.d.ts +27 -3
- package/dist/editor/FormRenderer.js +171 -76
- package/dist/editor/PreviewFrame.d.ts +40 -0
- package/dist/editor/PreviewFrame.js +215 -0
- package/dist/editor/PreviewPane.d.ts +47 -0
- package/dist/editor/PreviewPane.js +147 -0
- package/dist/editor/PreviewToolbarTools.d.ts +22 -0
- package/dist/editor/PreviewToolbarTools.js +73 -0
- package/dist/editor/admin/SystemHealthPanel.d.ts +2 -1
- package/dist/editor/admin/SystemHealthPanel.js +163 -33
- package/dist/editor/admin/useSystemHealth.d.ts +18 -0
- package/dist/editor/admin/useSystemHealth.js +70 -1
- package/dist/editor/branch-status.d.ts +17 -0
- package/dist/editor/branch-status.js +29 -0
- package/dist/editor/canopy-path.d.ts +9 -6
- package/dist/editor/canopy-path.js +8 -11
- package/dist/editor/client-reference-resolver.d.ts +43 -16
- package/dist/editor/client-reference-resolver.js +155 -64
- package/dist/editor/comments/BranchComments.d.ts +1 -1
- package/dist/editor/comments/BranchComments.js +2 -2
- package/dist/editor/comments/CloseRefusedNotice.d.ts +4 -0
- package/dist/editor/comments/CloseRefusedNotice.js +7 -0
- package/dist/editor/comments/CommentThreadsPopover.d.ts +47 -0
- package/dist/editor/comments/CommentThreadsPopover.js +274 -0
- package/dist/editor/comments/CommentWriteAlert.d.ts +11 -0
- package/dist/editor/comments/CommentWriteAlert.js +13 -0
- package/dist/editor/comments/EntryComments.d.ts +10 -4
- package/dist/editor/comments/EntryComments.js +14 -17
- package/dist/editor/comments/FieldWrapper.d.ts +18 -4
- package/dist/editor/comments/FieldWrapper.js +62 -28
- package/dist/editor/comments/InlineCommentThread.d.ts +9 -2
- package/dist/editor/comments/InlineCommentThread.js +11 -47
- package/dist/editor/comments/ThreadCarousel.d.ts +1 -1
- package/dist/editor/comments/ThreadCarousel.js +18 -21
- package/dist/editor/comments/ThreadReplyControls.d.ts +28 -0
- package/dist/editor/comments/ThreadReplyControls.js +92 -0
- package/dist/editor/comments/field-comment-context.d.ts +14 -0
- package/dist/editor/comments/field-comment-context.js +14 -0
- package/dist/editor/comments/form-comments.d.ts +48 -0
- package/dist/editor/comments/form-comments.js +178 -0
- package/dist/editor/comments/item-anchor-copy.d.ts +6 -0
- package/dist/editor/comments/item-anchor-copy.js +6 -0
- package/dist/editor/comments/move-focus-if-unmoved.d.ts +6 -0
- package/dist/editor/comments/move-focus-if-unmoved.js +11 -0
- package/dist/editor/comments/popover-placement.d.ts +18 -0
- package/dist/editor/comments/popover-placement.js +58 -0
- package/dist/editor/comments/use-tracked-writes.d.ts +16 -0
- package/dist/editor/comments/use-tracked-writes.js +53 -0
- package/dist/editor/components/BranchAccessList.d.ts +15 -0
- package/dist/editor/components/BranchAccessList.js +52 -0
- package/dist/editor/components/BranchLockBanner.d.ts +22 -0
- package/dist/editor/components/BranchLockBanner.js +39 -0
- package/dist/editor/components/BranchPill.d.ts +32 -0
- package/dist/editor/components/BranchPill.js +33 -0
- package/dist/editor/components/BranchesDrawer.d.ts +11 -0
- package/dist/editor/components/BranchesDrawer.js +5 -0
- package/dist/editor/components/ConfirmDeleteModal.d.ts +6 -1
- package/dist/editor/components/ConfirmDeleteModal.js +3 -2
- package/dist/editor/components/DestructiveMenuItem.d.ts +7 -0
- package/dist/editor/components/DestructiveMenuItem.js +8 -0
- package/dist/editor/components/EditorCrashScreen.d.ts +17 -0
- package/dist/editor/components/EditorCrashScreen.js +22 -0
- package/dist/editor/components/EditorErrorBoundary.d.ts +38 -0
- package/dist/editor/components/EditorErrorBoundary.js +40 -0
- package/dist/editor/components/EditorHeader.d.ts +56 -106
- package/dist/editor/components/EditorHeader.js +130 -131
- package/dist/editor/components/EditorRail.d.ts +49 -0
- package/dist/editor/components/EditorRail.js +65 -0
- package/dist/editor/components/EntryBreadcrumb.d.ts +33 -0
- package/dist/editor/components/EntryBreadcrumb.js +56 -0
- package/dist/editor/components/EntryCreateModal.d.ts +12 -7
- package/dist/editor/components/EntryCreateModal.js +51 -57
- package/dist/editor/components/NoEditPermissionNotice.d.ts +6 -5
- package/dist/editor/components/NoEditPermissionNotice.js +5 -4
- package/dist/editor/components/QuickOpenPalette.d.ts +22 -0
- package/dist/editor/components/QuickOpenPalette.js +66 -0
- package/dist/editor/components/ReadOnlyDraftNotice.d.ts +11 -0
- package/dist/editor/components/ReadOnlyDraftNotice.js +12 -0
- package/dist/editor/components/ReasonedMenuItem.d.ts +15 -0
- package/dist/editor/components/ReasonedMenuItem.js +15 -0
- package/dist/editor/components/ReferencedByList.d.ts +11 -0
- package/dist/editor/components/ReferencedByList.js +28 -0
- package/dist/editor/components/RelativeTime.d.ts +10 -0
- package/dist/editor/components/RelativeTime.js +10 -0
- package/dist/editor/components/RenameEntryModal.d.ts +9 -1
- package/dist/editor/components/RenameEntryModal.js +19 -31
- package/dist/editor/components/RetryToastMessage.d.ts +9 -0
- package/dist/editor/components/RetryToastMessage.js +6 -0
- package/dist/editor/components/SaveAllResult.d.ts +25 -0
- package/dist/editor/components/SaveAllResult.js +86 -0
- package/dist/editor/components/SaveSplitButton.d.ts +30 -0
- package/dist/editor/components/SaveSplitButton.js +108 -0
- package/dist/editor/components/StagedChangesDrawer.d.ts +39 -0
- package/dist/editor/components/StagedChangesDrawer.js +92 -0
- package/dist/editor/components/UnavailableEntryNotice.d.ts +6 -0
- package/dist/editor/components/UnavailableEntryNotice.js +9 -0
- package/dist/editor/components/UnavailableTypeMessage.d.ts +6 -0
- package/dist/editor/components/UnavailableTypeMessage.js +9 -0
- package/dist/editor/components/UndoToastMessage.d.ts +18 -0
- package/dist/editor/components/UndoToastMessage.js +10 -0
- package/dist/editor/components/UserBadge.d.ts +2 -5
- package/dist/editor/components/UserBadge.js +62 -33
- package/dist/editor/components/ValidationSummary.d.ts +14 -0
- package/dist/editor/components/ValidationSummary.js +24 -0
- package/dist/editor/components/index.d.ts +2 -2
- package/dist/editor/components/index.js +2 -2
- package/dist/editor/context/ApiClientContext.d.ts +8 -2
- package/dist/editor/context/ApiClientContext.js +19 -8
- package/dist/editor/context/AssetContext.d.ts +13 -35
- package/dist/editor/context/AssetContext.js +12 -31
- package/dist/editor/context/EditorStateContext.d.ts +4 -4
- package/dist/editor/context/EditorStateContext.js +4 -4
- package/dist/editor/context/SWRProvider.d.ts +3 -3
- package/dist/editor/context/SiteMdxAllowContext.d.ts +4 -0
- package/dist/editor/context/SiteMdxAllowContext.js +7 -0
- package/dist/editor/context/index.d.ts +2 -1
- package/dist/editor/context/index.js +2 -1
- package/dist/editor/contrast.d.ts +19 -0
- package/dist/editor/contrast.js +41 -0
- package/dist/editor/copy.d.ts +18 -0
- package/dist/editor/copy.js +18 -0
- package/dist/editor/editor-config.js +16 -0
- package/dist/editor/editor-utils.d.ts +34 -8
- package/dist/editor/editor-utils.js +42 -20
- package/dist/editor/entry-search.d.ts +20 -0
- package/dist/editor/entry-search.js +34 -0
- package/dist/editor/field-breadcrumb.d.ts +12 -0
- package/dist/editor/field-breadcrumb.js +85 -0
- package/dist/editor/field-props.d.ts +86 -0
- package/dist/editor/field-props.js +27 -0
- package/dist/editor/field-target.d.ts +30 -0
- package/dist/editor/field-target.js +77 -0
- package/dist/editor/fields/BlockField.d.ts +12 -0
- package/dist/editor/fields/BlockField.js +89 -73
- package/dist/editor/fields/CodeField.d.ts +2 -0
- package/dist/editor/fields/CodeField.js +6 -2
- package/dist/editor/fields/DateTimeField.d.ts +4 -29
- package/dist/editor/fields/DateTimeField.js +79 -41
- package/dist/editor/fields/ExpandAllButton.d.ts +6 -0
- package/dist/editor/fields/ExpandAllButton.js +4 -0
- package/dist/editor/fields/FieldCrashFallback.d.ts +17 -0
- package/dist/editor/fields/FieldCrashFallback.js +30 -0
- package/dist/editor/fields/FieldLabel.d.ts +37 -0
- package/dist/editor/fields/FieldLabel.js +19 -0
- package/dist/editor/fields/ImageField.d.ts +4 -0
- package/dist/editor/fields/ImageField.js +29 -14
- package/dist/editor/fields/InlineGroupField.js +4 -3
- package/dist/editor/fields/ItemList.d.ts +42 -0
- package/dist/editor/fields/ItemList.js +130 -0
- package/dist/editor/fields/MarkdownField.d.ts +32 -0
- package/dist/editor/fields/MarkdownField.js +223 -46
- package/dist/editor/fields/MdxImageDialog.js +1 -1
- package/dist/editor/fields/NumberField.d.ts +2 -0
- package/dist/editor/fields/NumberField.js +8 -5
- package/dist/editor/fields/NumberListField.d.ts +2 -0
- package/dist/editor/fields/NumberListField.js +19 -16
- package/dist/editor/fields/ObjectField.d.ts +2 -7
- package/dist/editor/fields/ObjectField.js +15 -5
- package/dist/editor/fields/ObjectListField.d.ts +29 -0
- package/dist/editor/fields/ObjectListField.js +57 -0
- package/dist/editor/fields/ReferenceField.d.ts +2 -0
- package/dist/editor/fields/ReferenceField.js +34 -9
- package/dist/editor/fields/SelectField.d.ts +2 -0
- package/dist/editor/fields/SelectField.js +11 -2
- package/dist/editor/fields/StringListField.d.ts +4 -1
- package/dist/editor/fields/StringListField.js +22 -8
- package/dist/editor/fields/TextField.d.ts +2 -0
- package/dist/editor/fields/TextField.js +6 -2
- package/dist/editor/fields/ToggleField.d.ts +2 -0
- package/dist/editor/fields/ToggleField.js +8 -3
- package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +1 -1
- package/dist/editor/fields/entry-link/InsertEntryLink.js +1 -1
- package/dist/editor/fields/form-expansion.d.ts +9 -0
- package/dist/editor/fields/form-expansion.js +2 -0
- package/dist/editor/fields/item-expansion.d.ts +15 -0
- package/dist/editor/fields/item-expansion.js +60 -0
- package/dist/editor/fields/list-item-keys.d.ts +8 -0
- package/dist/editor/fields/list-item-keys.js +50 -0
- package/dist/editor/fields/list-item-title.d.ts +20 -0
- package/dist/editor/fields/list-item-title.js +85 -0
- package/dist/editor/fields/markdown-export-options.d.ts +2 -0
- package/dist/editor/fields/markdown-export-options.js +8 -0
- package/dist/editor/fields/markdown-fidelity-visitors.d.ts +11 -0
- package/dist/editor/fields/markdown-fidelity-visitors.js +160 -0
- package/dist/editor/fields/mdx-jsx-support.d.ts +5 -1
- package/dist/editor/fields/mdx-jsx-support.js +157 -69
- package/dist/editor/fields/rich-text-failures.d.ts +5 -0
- package/dist/editor/fields/rich-text-failures.js +26 -0
- package/dist/editor/fields/toolbar-wrap.d.ts +7 -0
- package/dist/editor/fields/toolbar-wrap.js +35 -0
- package/dist/editor/form-outline.d.ts +13 -0
- package/dist/editor/form-outline.js +70 -0
- package/dist/editor/group-manager/GroupCard.d.ts +4 -1
- package/dist/editor/group-manager/GroupCard.js +12 -3
- package/dist/editor/group-manager/GroupForm.js +1 -1
- package/dist/editor/group-manager/InternalGroupsTab.d.ts +2 -1
- package/dist/editor/group-manager/InternalGroupsTab.js +4 -4
- package/dist/editor/group-manager/MemberList.d.ts +2 -1
- package/dist/editor/group-manager/MemberList.js +15 -4
- package/dist/editor/group-manager/hooks/useGroupState.d.ts +5 -0
- package/dist/editor/group-manager/hooks/useGroupState.js +30 -7
- package/dist/editor/group-manager/index.js +34 -5
- package/dist/editor/group-manager/types.d.ts +5 -2
- package/dist/editor/hooks/create-branch-request.d.ts +20 -0
- package/dist/editor/hooks/create-branch-request.js +54 -0
- package/dist/editor/hooks/save-all.d.ts +68 -0
- package/dist/editor/hooks/save-all.js +61 -0
- package/dist/editor/hooks/useBranchActions.d.ts +11 -1
- package/dist/editor/hooks/useBranchActions.js +42 -19
- package/dist/editor/hooks/useBranchManager.d.ts +21 -0
- package/dist/editor/hooks/useBranchManager.js +321 -125
- package/dist/editor/hooks/useBranchesData.d.ts +8 -4
- package/dist/editor/hooks/useBranchesData.js +9 -5
- package/dist/editor/hooks/useCommentSystem.d.ts +14 -2
- package/dist/editor/hooks/useCommentSystem.js +79 -55
- package/dist/editor/hooks/useCommentsData.d.ts +11 -7
- package/dist/editor/hooks/useCommentsData.js +20 -19
- package/dist/editor/hooks/useDraftManager.d.ts +77 -3
- package/dist/editor/hooks/useDraftManager.js +887 -94
- package/dist/editor/hooks/useEditorLayout.d.ts +53 -7
- package/dist/editor/hooks/useEditorLayout.js +98 -20
- package/dist/editor/hooks/useEntriesData.d.ts +2 -1
- package/dist/editor/hooks/useEntriesData.js +18 -4
- package/dist/editor/hooks/useEntryManager.d.ts +41 -2
- package/dist/editor/hooks/useEntryManager.js +227 -41
- package/dist/editor/hooks/useGroupManager.js +13 -16
- package/dist/editor/hooks/usePermissionManager.js +14 -6
- package/dist/editor/hooks/usePreviewMarks.d.ts +21 -0
- package/dist/editor/hooks/usePreviewMarks.js +33 -0
- package/dist/editor/hooks/useReferenceResolution.d.ts +10 -3
- package/dist/editor/hooks/useReferenceResolution.js +34 -177
- package/dist/editor/hooks/useSchemaManager.d.ts +25 -6
- package/dist/editor/hooks/useSchemaManager.js +97 -39
- package/dist/editor/hooks/useUserMetadata.d.ts +14 -4
- package/dist/editor/hooks/useUserMetadata.js +76 -47
- package/dist/editor/hooks/user-metadata-batcher.d.ts +8 -0
- package/dist/editor/hooks/user-metadata-batcher.js +33 -0
- package/dist/editor/media/AssetCard.d.ts +6 -7
- package/dist/editor/media/AssetCard.js +24 -31
- package/dist/editor/media/AssetListRow.d.ts +16 -0
- package/dist/editor/media/AssetListRow.js +41 -0
- package/dist/editor/media/CropStep.js +6 -1
- package/dist/editor/media/MediaLibrary.d.ts +4 -3
- package/dist/editor/media/MediaLibrary.js +11 -4
- package/dist/editor/media/MediaLibraryBody.d.ts +3 -3
- package/dist/editor/media/MediaLibraryBody.js +195 -80
- package/dist/editor/media/MediaLibrarySkeleton.d.ts +6 -0
- package/dist/editor/media/MediaLibrarySkeleton.js +14 -0
- package/dist/editor/media/crop-math.d.ts +3 -4
- package/dist/editor/media/crop-math.js +11 -22
- package/dist/editor/media/editor-image-src.d.ts +8 -0
- package/dist/editor/media/editor-image-src.js +10 -0
- package/dist/editor/media/format-bytes.d.ts +2 -0
- package/dist/editor/media/format-bytes.js +23 -0
- package/dist/editor/media/media-library-prefs.d.ts +23 -0
- package/dist/editor/media/media-library-prefs.js +49 -0
- package/dist/editor/media/media-library-view.d.ts +34 -0
- package/dist/editor/media/media-library-view.js +40 -0
- package/dist/editor/media/useAssetLibrary.d.ts +30 -0
- package/dist/editor/media/useAssetLibrary.js +126 -0
- package/dist/editor/media/useStableAssetOrder.d.ts +11 -0
- package/dist/editor/media/useStableAssetOrder.js +37 -0
- package/dist/editor/media/useThumbnailFailure.d.ts +6 -0
- package/dist/editor/media/useThumbnailFailure.js +16 -0
- package/dist/editor/permission-manager/GroupSelector.js +2 -2
- package/dist/editor/permission-manager/PermissionEditor.d.ts +1 -1
- package/dist/editor/permission-manager/PermissionEditor.js +15 -4
- package/dist/editor/permission-manager/PermissionLevelBadge.js +1 -1
- package/dist/editor/permission-manager/PermissionTree.d.ts +1 -1
- package/dist/editor/permission-manager/UserSelector.d.ts +1 -1
- package/dist/editor/permission-manager/UserSelector.js +3 -3
- package/dist/editor/permission-manager/index.js +12 -3
- package/dist/editor/permission-manager/types.d.ts +5 -2
- package/dist/editor/platform.d.ts +3 -0
- package/dist/editor/platform.js +9 -0
- package/dist/editor/preview-asset-base.d.ts +9 -0
- package/dist/editor/preview-asset-base.js +17 -0
- package/dist/editor/preview-bridge.d.ts +51 -27
- package/dist/editor/preview-bridge.js +103 -144
- package/dist/editor/preview-marks.d.ts +15 -0
- package/dist/editor/preview-marks.js +74 -0
- package/dist/editor/preview-path.d.ts +12 -0
- package/dist/editor/preview-path.js +45 -1
- package/dist/editor/preview-scale.d.ts +27 -0
- package/dist/editor/preview-scale.js +34 -0
- package/dist/editor/raw-asset-base.d.ts +5 -0
- package/dist/editor/raw-asset-base.js +14 -0
- package/dist/editor/relative-time.d.ts +4 -4
- package/dist/editor/relative-time.js +16 -8
- package/dist/editor/schema-editor/CollectionEditor.d.ts +20 -3
- package/dist/editor/schema-editor/CollectionEditor.js +361 -62
- package/dist/editor/schema-editor/EntryTypeEditor.d.ts +5 -1
- package/dist/editor/schema-editor/EntryTypeEditor.js +11 -6
- package/dist/editor/schema-editor/collection-draft.d.ts +22 -0
- package/dist/editor/schema-editor/collection-draft.js +40 -0
- package/dist/editor/schema-editor/index.d.ts +1 -1
- package/dist/editor/schema-label.d.ts +10 -0
- package/dist/editor/schema-label.js +17 -0
- package/dist/editor/settings-conflict.d.ts +5 -0
- package/dist/editor/settings-conflict.js +8 -0
- package/dist/editor/shell/ActivityRail.d.ts +37 -0
- package/dist/editor/shell/ActivityRail.js +91 -0
- package/dist/editor/shell/EditorShell.d.ts +17 -0
- package/dist/editor/shell/EditorShell.js +31 -0
- package/dist/editor/shell/PaneLayout.d.ts +28 -0
- package/dist/editor/shell/PaneLayout.js +116 -0
- package/dist/editor/shell/SidePanelHost.d.ts +35 -0
- package/dist/editor/shell/SidePanelHost.js +184 -0
- package/dist/editor/shell/TopBar.d.ts +12 -0
- package/dist/editor/shell/TopBar.js +14 -0
- package/dist/editor/shell/host-chrome.d.ts +16 -0
- package/dist/editor/shell/host-chrome.js +69 -0
- package/dist/editor/slug.d.ts +16 -0
- package/dist/editor/slug.js +43 -0
- package/dist/editor/theme.d.ts +2 -1
- package/dist/editor/theme.js +314 -13
- package/dist/editor/unanswered.d.ts +17 -0
- package/dist/editor/unanswered.js +26 -0
- package/dist/editor/unavailable-entry-type.d.ts +20 -0
- package/dist/editor/unavailable-entry-type.js +28 -0
- package/dist/editor/undo-removal.d.ts +57 -0
- package/dist/editor/undo-removal.js +163 -0
- package/dist/editor/user-display.d.ts +4 -0
- package/dist/editor/user-display.js +5 -0
- package/dist/editor/utils/confirm-modal.d.ts +8 -0
- package/dist/editor/utils/confirm-modal.js +12 -0
- package/dist/editor/utils/editor-errors.d.ts +19 -0
- package/dist/editor/utils/editor-errors.js +32 -0
- package/dist/editor/utils/focus-return.d.ts +56 -0
- package/dist/editor/utils/focus-return.js +106 -0
- package/dist/entry-link-resolver.d.ts +11 -1
- package/dist/entry-link-resolver.js +65 -5
- package/dist/entry-schema-registry.d.ts +3 -3
- package/dist/entry-schema-registry.js +7 -4
- package/dist/entry-schema.d.ts +49 -3
- package/dist/entry-schema.js +18 -0
- package/dist/git-manager.d.ts +172 -10
- package/dist/git-manager.js +449 -107
- package/dist/github-service.d.ts +39 -2
- package/dist/github-service.js +101 -7
- package/dist/http/handler.js +74 -9
- package/dist/http/types.d.ts +2 -0
- package/dist/http/worker-not-ready.d.ts +9 -4
- package/dist/http/worker-not-ready.js +59 -6
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/item-keys.d.ts +46 -0
- package/dist/item-keys.js +235 -0
- package/dist/operating-mode/editor-mode-check.d.ts +15 -0
- package/dist/operating-mode/editor-mode-check.js +24 -0
- package/dist/operating-mode/mode-env.d.ts +13 -14
- package/dist/operating-mode/mode-env.js +13 -14
- package/dist/operating-mode/types.d.ts +2 -2
- package/dist/paths/branch.d.ts +0 -1
- package/dist/paths/branch.js +1 -8
- package/dist/paths/index.d.ts +1 -1
- package/dist/paths/index.js +1 -1
- package/dist/paths/validation.js +0 -2
- package/dist/preview.d.ts +8 -0
- package/dist/preview.js +7 -0
- package/dist/reference-resolver.js +1 -0
- package/dist/resolve-canopy-user.d.ts +1 -1
- package/dist/resolve-canopy-user.js +1 -1
- package/dist/schema/meta-loader.d.ts +18 -8
- package/dist/schema/meta-loader.js +42 -9
- package/dist/schema/registry-fingerprint.d.ts +14 -0
- package/dist/schema/registry-fingerprint.js +63 -0
- package/dist/schema/resolver.d.ts +7 -4
- package/dist/schema/resolver.js +7 -6
- package/dist/schema/schema-store.d.ts +7 -10
- package/dist/schema/schema-store.js +13 -11
- package/dist/schema/schema-unavailable-error.d.ts +11 -0
- package/dist/schema/schema-unavailable-error.js +15 -0
- package/dist/schema/types.d.ts +22 -0
- package/dist/schema-registry-record.d.ts +35 -0
- package/dist/schema-registry-record.js +134 -0
- package/dist/server.d.ts +79 -9
- package/dist/server.js +62 -8
- package/dist/services.d.ts +33 -5
- package/dist/services.js +155 -37
- package/dist/settings-workspace.d.ts +23 -3
- package/dist/settings-workspace.js +159 -45
- package/dist/stamp-on-publish.d.ts +36 -0
- package/dist/stamp-on-publish.js +71 -0
- package/dist/static/index.d.ts +58 -5
- package/dist/static/index.js +133 -3
- package/dist/static/seo.d.ts +5 -5
- package/dist/static/seo.js +5 -5
- package/dist/submission-attribution.d.ts +8 -0
- package/dist/submission-attribution.js +22 -0
- package/dist/system-users.d.ts +12 -0
- package/dist/system-users.js +12 -0
- package/dist/task-queue/cms-task-queue.d.ts +1 -1
- package/dist/task-queue/cms-task-queue.js +1 -1
- package/dist/task-queue/index.d.ts +1 -1
- package/dist/task-queue/index.js +1 -1
- package/dist/task-queue/task-queue.d.ts +6 -0
- package/dist/task-queue/task-queue.js +29 -0
- package/dist/task-queue/worker-status.d.ts +35 -9
- package/dist/task-queue/worker-status.js +84 -17
- package/dist/types.d.ts +90 -9
- package/dist/url-collision.js +3 -3
- package/dist/url-exclusivity-fixtures.d.ts +8 -1
- package/dist/url-exclusivity-fixtures.js +11 -1
- package/dist/user.js +2 -1
- package/dist/utils/atomic-write.js +2 -1
- package/dist/utils/base-branch.d.ts +13 -0
- package/dist/utils/base-branch.js +23 -0
- package/dist/utils/content-serialize.d.ts +15 -7
- package/dist/utils/content-serialize.js +353 -51
- package/dist/utils/content-write-lock.d.ts +6 -1
- package/dist/utils/content-write-lock.js +21 -6
- package/dist/utils/debug.d.ts +1 -1
- package/dist/utils/debug.js +5 -3
- package/dist/utils/error.js +13 -2
- package/dist/utils/escape-text.d.ts +7 -0
- package/dist/utils/escape-text.js +27 -0
- package/dist/utils/fs.d.ts +12 -4
- package/dist/utils/fs.js +18 -5
- package/dist/utils/git.d.ts +21 -1
- package/dist/utils/git.js +63 -8
- package/dist/utils/json-source-splice.d.ts +14 -0
- package/dist/utils/json-source-splice.js +120 -0
- package/dist/utils/markdown-body-splice.d.ts +39 -0
- package/dist/utils/markdown-body-splice.js +421 -0
- package/dist/utils/occ-json-write.js +18 -12
- package/dist/utils/provision-log.d.ts +25 -0
- package/dist/utils/provision-log.js +49 -0
- package/dist/utils/provisioning-lock.d.ts +32 -1
- package/dist/utils/provisioning-lock.js +78 -32
- package/dist/utils/sanitize-href.d.ts +9 -23
- package/dist/utils/sanitize-href.js +14 -28
- package/dist/utils/title-field.d.ts +10 -0
- package/dist/utils/title-field.js +47 -0
- package/dist/utils/yaml-source-splice.d.ts +58 -0
- package/dist/utils/yaml-source-splice.js +515 -0
- package/dist/validation/block-structural-keys.d.ts +1 -1
- package/dist/validation/block-structural-keys.js +1 -1
- package/dist/validation/deletion-checker.d.ts +21 -29
- package/dist/validation/deletion-checker.js +41 -117
- package/dist/validation/entry-validator.d.ts +6 -10
- package/dist/validation/entry-validator.js +19 -26
- package/dist/validation/field-traversal.d.ts +22 -0
- package/dist/validation/field-traversal.js +39 -8
- package/dist/validation/markdown-safety.d.ts +68 -0
- package/dist/validation/markdown-safety.js +596 -0
- package/dist/validation/mdx-allowlist.d.ts +55 -0
- package/dist/validation/mdx-allowlist.js +183 -0
- package/dist/validation/reference-validator.d.ts +2 -0
- package/dist/validation/reference-validator.js +3 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker/branch-policy.d.ts +124 -0
- package/dist/worker/branch-policy.js +243 -0
- package/dist/worker/bundle-header.d.ts +117 -0
- package/dist/worker/bundle-header.js +253 -0
- package/dist/worker/cms-worker.d.ts +236 -142
- package/dist/worker/cms-worker.js +772 -285
- package/dist/worker/gateway-egress.d.ts +43 -0
- package/dist/worker/gateway-egress.js +209 -0
- package/dist/worker/gateway-instance.d.ts +42 -0
- package/dist/worker/gateway-instance.js +129 -0
- package/dist/worker/git-process.d.ts +81 -0
- package/dist/worker/git-process.js +234 -0
- package/dist/worker/git-sync.d.ts +34 -17
- package/dist/worker/git-sync.js +394 -131
- package/dist/worker/github-auth.d.ts +9 -9
- package/dist/worker/github-auth.js +13 -15
- package/dist/worker/github-gateway-http.d.ts +62 -0
- package/dist/worker/github-gateway-http.js +977 -0
- package/dist/worker/github-gateway-wire.d.ts +590 -0
- package/dist/worker/github-gateway-wire.js +488 -0
- package/dist/worker/github-gateway.d.ts +238 -0
- package/dist/worker/github-gateway.js +726 -0
- package/dist/worker/github-mirror-upkeep.d.ts +75 -0
- package/dist/worker/github-mirror-upkeep.js +266 -0
- package/dist/worker/github-mirror.d.ts +364 -0
- package/dist/worker/github-mirror.js +1030 -0
- package/dist/worker/github-transfer.d.ts +56 -0
- package/dist/worker/github-transfer.js +444 -0
- package/dist/worker/history-rewrite.d.ts +4 -5
- package/dist/worker/history-rewrite.js +12 -17
- package/dist/worker/provisioned-workspace.d.ts +5 -5
- package/dist/worker/provisioned-workspace.js +5 -5
- package/dist/worker/rebase.d.ts +1 -1
- package/dist/worker/rebase.js +58 -54
- package/dist/worker/remote-git-maintenance.d.ts +3 -0
- package/dist/worker/remote-git-maintenance.js +12 -0
- package/dist/worker/schema-gate.d.ts +49 -0
- package/dist/worker/schema-gate.js +226 -0
- package/dist/worker/self-checks.d.ts +107 -0
- package/dist/worker/self-checks.js +358 -0
- package/dist/worker/shared-repo-git.d.ts +96 -0
- package/dist/worker/shared-repo-git.js +459 -0
- package/dist/worker/sparse-cone.d.ts +20 -0
- package/dist/worker/sparse-cone.js +136 -0
- package/dist/worker/stale-mirror.d.ts +82 -0
- package/dist/worker/stale-mirror.js +130 -0
- package/dist/worker/task-runner.d.ts +5 -3
- package/dist/worker/task-runner.js +287 -186
- package/dist/worker/worker-context.d.ts +36 -37
- package/package.json +35 -7
- package/dist/editor/EditorPanes.d.ts +0 -10
- package/dist/editor/EditorPanes.js +0 -98
- package/dist/editor/components/EditorFooter.d.ts +0 -11
- package/dist/editor/components/EditorFooter.js +0 -9
- package/dist/editor/components/EditorSidebar.d.ts +0 -67
- package/dist/editor/components/EditorSidebar.js +0 -22
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { isPlainRecord, resolveBlockItem } from './validation/field-traversal.js';
|
|
2
|
+
import { formatCanopyPath, parseCanopyPath } from './editor/canopy-path.js';
|
|
3
|
+
/**
|
|
4
|
+
* The key each object-list item and block carries in content, naming that item among its list's
|
|
5
|
+
* items for as long as it exists: a move or an edit keeps it, a copy gets a new one. Field comment
|
|
6
|
+
* threads name the items on their path by it (`CommentThread.itemKeys`). Beside `template` on a
|
|
7
|
+
* block, never inside its `value`; a schema may not define a field of this name.
|
|
8
|
+
*
|
|
9
|
+
* Dependency-free: the editor and the server both use this module.
|
|
10
|
+
*/
|
|
11
|
+
export const ITEM_KEY = '_key';
|
|
12
|
+
const ITEM_KEY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
|
|
13
|
+
/** A usable item key: 1-64 letters, digits, `_` or `-`, starting with a letter or digit. */
|
|
14
|
+
export const isItemKey = (value) => typeof value === 'string' && ITEM_KEY_PATTERN.test(value);
|
|
15
|
+
const BASE58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
16
|
+
/** A new random item key: 12 Base58 characters. */
|
|
17
|
+
export function mintItemKey() {
|
|
18
|
+
return Array.from(crypto.getRandomValues(new Uint8Array(12)), (b) => BASE58[b % 58]).join('');
|
|
19
|
+
}
|
|
20
|
+
/** cyrb53: a fast, well-mixed 53-bit string hash. Not cryptographic, and needn't be. */
|
|
21
|
+
function hash53(text) {
|
|
22
|
+
let h1 = 0xdeadbeef;
|
|
23
|
+
let h2 = 0x41c6ce57;
|
|
24
|
+
for (let i = 0; i < text.length; i++) {
|
|
25
|
+
const c = text.charCodeAt(i);
|
|
26
|
+
h1 = Math.imul(h1 ^ c, 2654435761);
|
|
27
|
+
h2 = Math.imul(h2 ^ c, 1597334677);
|
|
28
|
+
}
|
|
29
|
+
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
|
30
|
+
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
|
31
|
+
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
|
32
|
+
}
|
|
33
|
+
/** `h` and the Base58 hash of an item as it was read, before any key was added inside it. */
|
|
34
|
+
function contentKey(item) {
|
|
35
|
+
let n = hash53(JSON.stringify(item));
|
|
36
|
+
let out = '';
|
|
37
|
+
do {
|
|
38
|
+
out = BASE58[n % 58] + out;
|
|
39
|
+
n = Math.floor(n / 58);
|
|
40
|
+
} while (n > 0);
|
|
41
|
+
return `h${out}`;
|
|
42
|
+
}
|
|
43
|
+
const isListField = (field) => field.type === 'block' || (field.type === 'object' && !!field.list);
|
|
44
|
+
/**
|
|
45
|
+
* `data` with every object-list item and block keyed, each unique in its list, nested lists
|
|
46
|
+
* included; the same object when nothing needed a key. A usable key is kept unless `fill` is
|
|
47
|
+
* `fresh`.
|
|
48
|
+
*/
|
|
49
|
+
export function withItemKeys(fields, data, fill) {
|
|
50
|
+
let out = data;
|
|
51
|
+
for (const field of fields) {
|
|
52
|
+
if (field.type === 'group') {
|
|
53
|
+
out = withItemKeys(field.fields, out, fill);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const value = out[field.name];
|
|
57
|
+
let next = value;
|
|
58
|
+
if (isListField(field)) {
|
|
59
|
+
if (Array.isArray(value))
|
|
60
|
+
next = keyList(field, value, fill);
|
|
61
|
+
}
|
|
62
|
+
else if (field.type === 'object' && isPlainRecord(value)) {
|
|
63
|
+
next = withItemKeys(field.fields ?? [], value, fill);
|
|
64
|
+
}
|
|
65
|
+
if (next !== value)
|
|
66
|
+
out = { ...out, [field.name]: next };
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
/** `item`, a copy about to join `field`'s list, with fresh keys for it and every item inside it. */
|
|
71
|
+
export function withFreshItemKeys(field, item) {
|
|
72
|
+
return keyList(field, [item], 'fresh')[0];
|
|
73
|
+
}
|
|
74
|
+
function keyList(field, items, fill) {
|
|
75
|
+
const held = new Set();
|
|
76
|
+
if (fill !== 'fresh') {
|
|
77
|
+
for (const item of items) {
|
|
78
|
+
if (isPlainRecord(item) && isItemKey(item[ITEM_KEY]))
|
|
79
|
+
held.add(item[ITEM_KEY]);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const kept = new Set();
|
|
83
|
+
let changed = false;
|
|
84
|
+
const out = items.map((item) => {
|
|
85
|
+
if (!isPlainRecord(item))
|
|
86
|
+
return item;
|
|
87
|
+
let next = keyInside(field, item, fill);
|
|
88
|
+
const own = item[ITEM_KEY];
|
|
89
|
+
if (fill !== 'fresh' && isItemKey(own) && !kept.has(own)) {
|
|
90
|
+
kept.add(own);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const key = fill === 'content' ? unheld(contentKey(item), held) : mintItemKey();
|
|
94
|
+
held.add(key);
|
|
95
|
+
kept.add(key);
|
|
96
|
+
next = { ...next, [ITEM_KEY]: key };
|
|
97
|
+
}
|
|
98
|
+
if (next !== item)
|
|
99
|
+
changed = true;
|
|
100
|
+
return next;
|
|
101
|
+
});
|
|
102
|
+
return changed ? out : items;
|
|
103
|
+
}
|
|
104
|
+
/** `key`, or with a suffix when another item of the list already holds it (identical items). */
|
|
105
|
+
function unheld(key, held) {
|
|
106
|
+
let out = key;
|
|
107
|
+
for (let n = 2; held.has(out); n++)
|
|
108
|
+
out = `${key}-${n}`;
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
/** The item with the lists inside it keyed. */
|
|
112
|
+
function keyInside(field, item, fill) {
|
|
113
|
+
if (field.type !== 'block') {
|
|
114
|
+
return withItemKeys(field.fields ?? [], item, fill);
|
|
115
|
+
}
|
|
116
|
+
const resolved = resolveBlockItem(field, item);
|
|
117
|
+
if (!resolved)
|
|
118
|
+
return item;
|
|
119
|
+
const data = withItemKeys(resolved.fields, resolved.data, fill);
|
|
120
|
+
if (data === resolved.data)
|
|
121
|
+
return item;
|
|
122
|
+
return resolved.data === item ? data : { ...item, value: data };
|
|
123
|
+
}
|
|
124
|
+
const findField = (fields, name) => {
|
|
125
|
+
for (const field of fields) {
|
|
126
|
+
if (field.type === 'group') {
|
|
127
|
+
const inGroup = findField(field.fields, name);
|
|
128
|
+
if (inGroup)
|
|
129
|
+
return inGroup;
|
|
130
|
+
}
|
|
131
|
+
else if (field.name === name) {
|
|
132
|
+
return field;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return undefined;
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* Walks `canopyPath` through `value` by schema, calling `atIndex` with each list index on the path
|
|
139
|
+
* and that list's items; it returns the index to continue with, or undefined to stop. Returns the
|
|
140
|
+
* path walked, or undefined when the walk stopped or the value has no such path.
|
|
141
|
+
*/
|
|
142
|
+
function walkPath(fields, value, canopyPath, atIndex) {
|
|
143
|
+
const segments = parseCanopyPath(canopyPath);
|
|
144
|
+
const out = [];
|
|
145
|
+
let scope = fields;
|
|
146
|
+
let record = value;
|
|
147
|
+
let depth = 0;
|
|
148
|
+
for (let i = 0; i < segments.length; i++) {
|
|
149
|
+
const name = segments[i];
|
|
150
|
+
if (typeof name !== 'string')
|
|
151
|
+
return undefined;
|
|
152
|
+
const field = findField(scope, name);
|
|
153
|
+
out.push(name);
|
|
154
|
+
if (!field || i === segments.length - 1) {
|
|
155
|
+
if (!field)
|
|
156
|
+
return undefined;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const node = record?.[name];
|
|
160
|
+
if (isListField(field)) {
|
|
161
|
+
const index = segments[i + 1];
|
|
162
|
+
if (typeof index !== 'number' || !Array.isArray(node))
|
|
163
|
+
return undefined;
|
|
164
|
+
const at = atIndex(index, node, depth);
|
|
165
|
+
if (at === undefined)
|
|
166
|
+
return undefined;
|
|
167
|
+
depth += 1;
|
|
168
|
+
out.push(at);
|
|
169
|
+
i += 1;
|
|
170
|
+
const item = node[at];
|
|
171
|
+
if (!isPlainRecord(item))
|
|
172
|
+
return undefined;
|
|
173
|
+
if (field.type === 'block') {
|
|
174
|
+
const resolved = resolveBlockItem(field, item);
|
|
175
|
+
if (!resolved)
|
|
176
|
+
return undefined;
|
|
177
|
+
scope = resolved.fields;
|
|
178
|
+
record = resolved.data;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
scope = field.fields ?? [];
|
|
182
|
+
record = item;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else if (field.type === 'object') {
|
|
186
|
+
scope = field.fields ?? [];
|
|
187
|
+
record = isPlainRecord(node) ? node : undefined;
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return out;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* The keys of the list items on `canopyPath` in `value`, outermost first: what a new field thread
|
|
197
|
+
* stores to name them. Undefined when an item on the path has no usable key or the path isn't
|
|
198
|
+
* there.
|
|
199
|
+
*/
|
|
200
|
+
export function itemKeysOnPath(fields, value, canopyPath) {
|
|
201
|
+
const keys = [];
|
|
202
|
+
const walked = walkPath(fields, value, canopyPath, (index, items) => {
|
|
203
|
+
const item = items[index];
|
|
204
|
+
const key = isPlainRecord(item) ? item[ITEM_KEY] : undefined;
|
|
205
|
+
if (!isItemKey(key))
|
|
206
|
+
return undefined;
|
|
207
|
+
keys.push(key);
|
|
208
|
+
return index;
|
|
209
|
+
});
|
|
210
|
+
return walked ? keys : undefined;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Where a field thread made at `canopyPath` on the items named by `itemKeys` is in `value` now:
|
|
214
|
+
* its path with each index replaced by that item's current one, or `null` when one of the items
|
|
215
|
+
* is gone. A path with no keys (one through no list) is returned as it is.
|
|
216
|
+
*/
|
|
217
|
+
export function resolveThreadPath(fields, value, canopyPath, itemKeys) {
|
|
218
|
+
if (!itemKeys || itemKeys.length === 0)
|
|
219
|
+
return canopyPath;
|
|
220
|
+
let missing = false;
|
|
221
|
+
const walked = walkPath(fields, value, canopyPath, (_index, items, depth) => {
|
|
222
|
+
const key = itemKeys[depth];
|
|
223
|
+
const at = items.findIndex((item) => isPlainRecord(item) && item[ITEM_KEY] === key);
|
|
224
|
+
if (key === undefined || at === -1) {
|
|
225
|
+
missing = true;
|
|
226
|
+
return undefined;
|
|
227
|
+
}
|
|
228
|
+
return at;
|
|
229
|
+
});
|
|
230
|
+
// A walk that can't reach an item, its enclosing object cleared or its block's template gone,
|
|
231
|
+
// has lost it just as surely as a removal.
|
|
232
|
+
if (missing || !walked)
|
|
233
|
+
return null;
|
|
234
|
+
return formatCanopyPath(walked);
|
|
235
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The run-time check that the editor bundle and its server agree on `mode` (see mode-env.ts).
|
|
3
|
+
* Without it, a dev bundle against a prod server fails only as a sign-in that never succeeds. The
|
|
4
|
+
* generated client sends its mode in `EDITOR_MODE_HEADER`, and the request handler refuses a
|
|
5
|
+
* mismatch with `EDITOR_MODE_MISMATCH_STATUS` before auth, naming only the editor's value (with
|
|
6
|
+
* two modes, that still tells the editor the server's). A request without the header is not
|
|
7
|
+
* checked; only the editor's client sends it. Dependency-free: it reaches the browser bundle.
|
|
8
|
+
*/
|
|
9
|
+
import type { OperatingMode } from './types.js';
|
|
10
|
+
export declare const EDITOR_MODE_HEADER = "x-canopy-editor-mode";
|
|
11
|
+
/** Not 409, which the editor reads as a save conflict to reload past. */
|
|
12
|
+
export declare const EDITOR_MODE_MISMATCH_STATUS = 412;
|
|
13
|
+
/** The header's value, or undefined for an absent or unrecognized one, which is not checked. */
|
|
14
|
+
export declare function parseEditorModeHeader(value: string | null): OperatingMode | undefined;
|
|
15
|
+
export declare function editorModeMismatchMessage(editorMode: OperatingMode): string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The run-time check that the editor bundle and its server agree on `mode` (see mode-env.ts).
|
|
3
|
+
* Without it, a dev bundle against a prod server fails only as a sign-in that never succeeds. The
|
|
4
|
+
* generated client sends its mode in `EDITOR_MODE_HEADER`, and the request handler refuses a
|
|
5
|
+
* mismatch with `EDITOR_MODE_MISMATCH_STATUS` before auth, naming only the editor's value (with
|
|
6
|
+
* two modes, that still tells the editor the server's). A request without the header is not
|
|
7
|
+
* checked; only the editor's client sends it. Dependency-free: it reaches the browser bundle.
|
|
8
|
+
*/
|
|
9
|
+
export const EDITOR_MODE_HEADER = 'x-canopy-editor-mode';
|
|
10
|
+
/** Not 409, which the editor reads as a save conflict to reload past. */
|
|
11
|
+
export const EDITOR_MODE_MISMATCH_STATUS = 412;
|
|
12
|
+
function otherOperatingMode(mode) {
|
|
13
|
+
return mode === 'prod' ? 'dev' : 'prod';
|
|
14
|
+
}
|
|
15
|
+
/** The header's value, or undefined for an absent or unrecognized one, which is not checked. */
|
|
16
|
+
export function parseEditorModeHeader(value) {
|
|
17
|
+
return value === 'prod' || value === 'dev' ? value : undefined;
|
|
18
|
+
}
|
|
19
|
+
export function editorModeMismatchMessage(editorMode) {
|
|
20
|
+
const serverMode = otherOperatingMode(editorMode);
|
|
21
|
+
return (`This editor was built for "${editorMode}" mode, but the CMS server runs in "${serverMode}" ` +
|
|
22
|
+
`mode, so signing in cannot work. Whoever deploys this site needs to rebuild the editor with ` +
|
|
23
|
+
`NEXT_PUBLIC_CANOPY_MODE=${serverMode} set at build time. Reloading this page will not help.`);
|
|
24
|
+
}
|
|
@@ -8,24 +8,23 @@
|
|
|
8
8
|
* - `next dev` and `next build` are both `dev`. Build-time reads come from
|
|
9
9
|
* the working tree in either mode (`readsFromCheckout` in build-mode.ts),
|
|
10
10
|
* while prod would hold the image builder to checks it has no reason to
|
|
11
|
-
* meet:
|
|
12
|
-
*
|
|
13
|
-
* (`assertAuthPluginAllowedForMode`). See Dockerfile.cms.template.
|
|
11
|
+
* meet: the prod strategy's `validateConfig` (`gitBotAuthorName`, `gitBotAuthorEmail`)
|
|
12
|
+
* and `assertAuthPluginAllowedForMode`. See Dockerfile.cms.template.
|
|
14
13
|
* - The Lambda is `prod`: dev resolves the workspace to `<cwd>/.canopy-dev`,
|
|
15
|
-
* and Lambda's filesystem is read-only outside /tmp
|
|
16
|
-
* fails with EROFS.
|
|
14
|
+
* and Lambda's filesystem is read-only outside /tmp (EROFS).
|
|
17
15
|
*
|
|
18
16
|
* Two variable names, on purpose. Server code reads `CANOPY_MODE`, stamped on
|
|
19
|
-
* the Lambda by `CanopyCmsService` and
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
17
|
+
* the Lambda by `CanopyCmsService` and NOT set during `next build`. The editor
|
|
18
|
+
* page imports the config directly, so the browser's `mode` is inlined at
|
|
19
|
+
* build, and Next inlines only `NEXT_PUBLIC_*`. Both names MUST appear as
|
|
20
|
+
* literal `process.env.X` member expressions here or the bundler cannot
|
|
21
|
+
* substitute them. The two MUST agree at run time: editor-mode-check.ts refuses
|
|
22
|
+
* editor requests where they do not. A prerendered `/edit` resolves the
|
|
23
|
+
* build's mode on the server, which is harmless: NextCanopyEditorPage's
|
|
24
|
+
* `<Suspense>` makes that prerender bail out to client rendering.
|
|
25
25
|
*
|
|
26
|
-
* An unrecognized value throws rather than falling back:
|
|
27
|
-
*
|
|
28
|
-
* running header-trusting dev auth semantics.
|
|
26
|
+
* An unrecognized value throws rather than falling back: a typo
|
|
27
|
+
* (`CANOPY_MODE=production`) would otherwise deploy dev auth semantics silently.
|
|
29
28
|
*/
|
|
30
29
|
import type { OperatingMode } from './types.js';
|
|
31
30
|
/**
|
|
@@ -8,24 +8,23 @@
|
|
|
8
8
|
* - `next dev` and `next build` are both `dev`. Build-time reads come from
|
|
9
9
|
* the working tree in either mode (`readsFromCheckout` in build-mode.ts),
|
|
10
10
|
* while prod would hold the image builder to checks it has no reason to
|
|
11
|
-
* meet:
|
|
12
|
-
*
|
|
13
|
-
* (`assertAuthPluginAllowedForMode`). See Dockerfile.cms.template.
|
|
11
|
+
* meet: the prod strategy's `validateConfig` (`gitBotAuthorName`, `gitBotAuthorEmail`)
|
|
12
|
+
* and `assertAuthPluginAllowedForMode`. See Dockerfile.cms.template.
|
|
14
13
|
* - The Lambda is `prod`: dev resolves the workspace to `<cwd>/.canopy-dev`,
|
|
15
|
-
* and Lambda's filesystem is read-only outside /tmp
|
|
16
|
-
* fails with EROFS.
|
|
14
|
+
* and Lambda's filesystem is read-only outside /tmp (EROFS).
|
|
17
15
|
*
|
|
18
16
|
* Two variable names, on purpose. Server code reads `CANOPY_MODE`, stamped on
|
|
19
|
-
* the Lambda by `CanopyCmsService` and
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
17
|
+
* the Lambda by `CanopyCmsService` and NOT set during `next build`. The editor
|
|
18
|
+
* page imports the config directly, so the browser's `mode` is inlined at
|
|
19
|
+
* build, and Next inlines only `NEXT_PUBLIC_*`. Both names MUST appear as
|
|
20
|
+
* literal `process.env.X` member expressions here or the bundler cannot
|
|
21
|
+
* substitute them. The two MUST agree at run time: editor-mode-check.ts refuses
|
|
22
|
+
* editor requests where they do not. A prerendered `/edit` resolves the
|
|
23
|
+
* build's mode on the server, which is harmless: NextCanopyEditorPage's
|
|
24
|
+
* `<Suspense>` makes that prerender bail out to client rendering.
|
|
25
25
|
*
|
|
26
|
-
* An unrecognized value throws rather than falling back:
|
|
27
|
-
*
|
|
28
|
-
* running header-trusting dev auth semantics.
|
|
26
|
+
* An unrecognized value throws rather than falling back: a typo
|
|
27
|
+
* (`CANOPY_MODE=production`) would otherwise deploy dev auth semantics silently.
|
|
29
28
|
*/
|
|
30
29
|
import { canopyLogWarn } from '../utils/logger.js';
|
|
31
30
|
const SERVER_MODE_ENV_VAR = 'CANOPY_MODE';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { OperatingMode as OM } from './index.js';
|
|
3
3
|
import type { CanopyConfig } from '../config/index.js';
|
|
4
4
|
export type OperatingMode = OM;
|
|
5
|
-
/** @internal No importer; deletion candidate in
|
|
5
|
+
/** @internal No importer; deletion candidate in safeinsights/canopycms#725. */
|
|
6
6
|
export interface ResolveRemoteUrlOptions {
|
|
7
7
|
mode: OperatingMode;
|
|
8
8
|
remoteUrl?: string;
|
|
@@ -47,7 +47,7 @@ export interface ClientSafeStrategy {
|
|
|
47
47
|
export interface ClientUnsafeStrategy extends ClientSafeStrategy {
|
|
48
48
|
/**
|
|
49
49
|
* The mode's workspace root; content-branches, settings and .cache all live
|
|
50
|
-
* under it. prod: CANOPYCMS_WORKSPACE_ROOT ?? /mnt/efs
|
|
50
|
+
* under it. prod: CANOPYCMS_WORKSPACE_ROOT ?? /mnt/efs.
|
|
51
51
|
* dev: {sourceRoot ?? cwd}/.canopy-dev.
|
|
52
52
|
*/
|
|
53
53
|
getWorkspaceRoot(sourceRoot?: string): string;
|
package/dist/paths/branch.d.ts
CHANGED
|
@@ -24,6 +24,5 @@ import { sanitizeBranchName } from './branch-name.js';
|
|
|
24
24
|
export { sanitizeBranchName };
|
|
25
25
|
/** Resolve a branch name to workspace paths, rejecting traversal and settings-branch names. */
|
|
26
26
|
export declare function resolveBranchPath(options: BranchPathOptions): BranchPathResult;
|
|
27
|
-
export declare function ensureBranchRoot(options: BranchPathOptions): Promise<BranchPathResult>;
|
|
28
27
|
export declare function getDefaultBranchBase(mode: OperatingMode, override?: string): string;
|
|
29
28
|
export declare function resolveBranchPaths(branchContext: BranchContext, mode: OperatingMode, basePathOverride?: string): BranchPathResult;
|
package/dist/paths/branch.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/** Branch path resolution utilities. */
|
|
2
|
-
import fs from 'node:fs/promises';
|
|
3
2
|
import path from 'node:path';
|
|
4
3
|
import { operatingStrategy } from '../operating-mode/index.js';
|
|
5
4
|
import { isNodeError } from '../utils/error.js';
|
|
@@ -15,8 +14,7 @@ export function namesNoWorkspace(err) {
|
|
|
15
14
|
return true;
|
|
16
15
|
return isNodeError(err) && (err.code === 'ENAMETOOLONG' || err.code === 'ENOTDIR');
|
|
17
16
|
}
|
|
18
|
-
// Lives in ./branch-name (dependency-free); re-exported
|
|
19
|
-
// importers, who may safely reach this module's node:fs imports.
|
|
17
|
+
// Lives in ./branch-name (dependency-free); re-exported for server-side importers.
|
|
20
18
|
import { sanitizeBranchName, isSettingsBranchName } from './branch-name.js';
|
|
21
19
|
/** @internal Exported for tests. */
|
|
22
20
|
export { sanitizeBranchName };
|
|
@@ -48,11 +46,6 @@ export function resolveBranchPath(options) {
|
|
|
48
46
|
}
|
|
49
47
|
return { branchRoot, baseRoot: normalizedBase, branchName: safeBranch };
|
|
50
48
|
}
|
|
51
|
-
export async function ensureBranchRoot(options) {
|
|
52
|
-
const result = resolveBranchPath(options);
|
|
53
|
-
await fs.mkdir(result.branchRoot, { recursive: true });
|
|
54
|
-
return result;
|
|
55
|
-
}
|
|
56
49
|
export function getDefaultBranchBase(mode, override) {
|
|
57
50
|
return resolveContentBranchesRoot(mode, override);
|
|
58
51
|
}
|
package/dist/paths/index.d.ts
CHANGED
|
@@ -7,5 +7,5 @@ export { normalizeFilesystemPath, normalizeCollectionPath, hasTraversalSequence,
|
|
|
7
7
|
export { validateAndNormalizePath } from './normalize-server.js';
|
|
8
8
|
export { validateContentPath, isValidCollectionPath, sanitizeForPath, hasEmbeddedContentId, looksLikePhysicalPath, looksLikeLogicalPath, parseLogicalPath, parsePhysicalPath, isValidContentId, parseContentId, parseBranchName, parseSlug, } from './validation.js';
|
|
9
9
|
export { resolveLogicalPath } from './resolve.js';
|
|
10
|
-
export { resolveBranchPath,
|
|
10
|
+
export { resolveBranchPath, getDefaultBranchBase, resolveBranchPaths, BranchPathError, namesNoWorkspace, type BranchPathOptions, type BranchPathResult, } from './branch.js';
|
|
11
11
|
export { sanitizeBranchName, RESERVED_SETTINGS_BRANCH_PREFIX, RESERVED_ROUTE_BRANCH_NAMES, isSettingsBranchName, } from './branch-name.js';
|
package/dist/paths/index.js
CHANGED
|
@@ -8,5 +8,5 @@ export { normalizeFilesystemPath, normalizeCollectionPath, hasTraversalSequence,
|
|
|
8
8
|
export { validateAndNormalizePath } from './normalize-server.js';
|
|
9
9
|
export { validateContentPath, isValidCollectionPath, sanitizeForPath, hasEmbeddedContentId, looksLikePhysicalPath, looksLikeLogicalPath, parseLogicalPath, parsePhysicalPath, isValidContentId, parseContentId, parseBranchName, parseSlug, } from './validation.js';
|
|
10
10
|
export { resolveLogicalPath } from './resolve.js';
|
|
11
|
-
export { resolveBranchPath,
|
|
11
|
+
export { resolveBranchPath, getDefaultBranchBase, resolveBranchPaths, BranchPathError, namesNoWorkspace, } from './branch.js';
|
|
12
12
|
export { sanitizeBranchName, RESERVED_SETTINGS_BRANCH_PREFIX, RESERVED_ROUTE_BRANCH_NAMES, isSettingsBranchName, } from './branch-name.js';
|
package/dist/paths/validation.js
CHANGED
|
@@ -186,7 +186,6 @@ export function parseSlug(slug) {
|
|
|
186
186
|
error: 'Slug is required',
|
|
187
187
|
};
|
|
188
188
|
}
|
|
189
|
-
// Check length (filesystem path safety)
|
|
190
189
|
if (slug.length > 64) {
|
|
191
190
|
return { ok: false, error: 'Slug too long (max 64 characters)' };
|
|
192
191
|
}
|
|
@@ -202,7 +201,6 @@ export function parseSlug(slug) {
|
|
|
202
201
|
error: 'Slug cannot be a traversal sequence',
|
|
203
202
|
};
|
|
204
203
|
}
|
|
205
|
-
// Normalize to lowercase for case-insensitive matching
|
|
206
204
|
const normalized = slug.toLowerCase();
|
|
207
205
|
if (!/^[a-z0-9][a-z0-9-]*$/.test(normalized)) {
|
|
208
206
|
return {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a host page needs from the preview bridge. Everything reachable from here stays free of
|
|
3
|
+
* CSS, `@mantine/*` and editor UI (`pnpm lint:bundle`): a page that imports it renders in the
|
|
4
|
+
* adopter's own styles inside the editor's preview, and ships no editor code to the public.
|
|
5
|
+
*/
|
|
6
|
+
export { CANOPY_PREVIEW_ERROR, CANOPY_PREVIEW_FOCUS, CANOPY_PREVIEW_HIGHLIGHT, CANOPY_PREVIEW_MESSAGE, CANOPY_PREVIEW_READY, isTrustedEditorMessage, resolveMessageOrigin, useCanopyPreview, usePreviewAssetBaseGate, usePreviewData, usePreviewFocusEmitter, usePreviewHighlight, } from './editor/preview-bridge.js';
|
|
7
|
+
export type { DraftUpdateMessage, HighlightMessage, PreviewErrorMessage, PreviewFocusMessage, PreviewLoadingState, } from './editor/preview-bridge.js';
|
|
8
|
+
export type { CanopyPathSegment } from './editor/canopy-path.js';
|
package/dist/preview.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
/**
|
|
3
|
+
* What a host page needs from the preview bridge. Everything reachable from here stays free of
|
|
4
|
+
* CSS, `@mantine/*` and editor UI (`pnpm lint:bundle`): a page that imports it renders in the
|
|
5
|
+
* adopter's own styles inside the editor's preview, and ships no editor code to the public.
|
|
6
|
+
*/
|
|
7
|
+
export { CANOPY_PREVIEW_ERROR, CANOPY_PREVIEW_FOCUS, CANOPY_PREVIEW_HIGHLIGHT, CANOPY_PREVIEW_MESSAGE, CANOPY_PREVIEW_READY, isTrustedEditorMessage, resolveMessageOrigin, useCanopyPreview, usePreviewAssetBaseGate, usePreviewData, usePreviewFocusEmitter, usePreviewHighlight, } from './editor/preview-bridge.js';
|
|
@@ -54,6 +54,7 @@ export class ReferenceResolver {
|
|
|
54
54
|
// Only the label is read, so the candidate's own references stay unresolved.
|
|
55
55
|
const doc = await this.store.read(location.collection, normalizedSlug, {
|
|
56
56
|
resolveReferences: false,
|
|
57
|
+
allowUnavailableEntryType: true,
|
|
57
58
|
});
|
|
58
59
|
const label = String(doc.data[displayField] || doc.data.title || normalizedSlug);
|
|
59
60
|
if (search && !label.toLowerCase().includes(search.toLowerCase())) {
|
|
@@ -3,7 +3,7 @@ import type { CanopyUser } from './user.js';
|
|
|
3
3
|
import type { OperatingMode } from './operating-mode/index.js';
|
|
4
4
|
/**
|
|
5
5
|
* Test-only: reset the once-per-process "no admins configured" warning latch.
|
|
6
|
-
* @internal No importer; deletion candidate in
|
|
6
|
+
* @internal No importer; deletion candidate in safeinsights/canopycms#725.
|
|
7
7
|
*/
|
|
8
8
|
export declare function resetResolveCanopyUserWarningForTests(): void;
|
|
9
9
|
export interface ResolveCanopyUserDeps {
|
|
@@ -17,7 +17,7 @@ import { timeRequestPhase } from './utils/request-timing.js';
|
|
|
17
17
|
let warnedNoAdmins = false;
|
|
18
18
|
/**
|
|
19
19
|
* Test-only: reset the once-per-process "no admins configured" warning latch.
|
|
20
|
-
* @internal No importer; deletion candidate in
|
|
20
|
+
* @internal No importer; deletion candidate in safeinsights/canopycms#725.
|
|
21
21
|
*/
|
|
22
22
|
export function resetResolveCanopyUserWarningForTests() {
|
|
23
23
|
warnedNoAdmins = false;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { RootCollectionConfig } from '../config/index.js';
|
|
2
2
|
import type { ContentId } from '../paths/types.js';
|
|
3
|
-
import type { EntrySchemaRegistry } from './types.js';
|
|
3
|
+
import type { EntrySchemaRegistry, SchemaIssue, UnknownSchemaPolicy } from './types.js';
|
|
4
4
|
type EntryTypeMeta = {
|
|
5
5
|
name: string;
|
|
6
6
|
format: 'md' | 'mdx' | 'json' | 'yaml';
|
|
@@ -38,6 +38,13 @@ export declare function loadCollectionMetaFiles(contentRoot: string): Promise<{
|
|
|
38
38
|
contentId?: ContentId;
|
|
39
39
|
}>;
|
|
40
40
|
}>;
|
|
41
|
+
type LoadedMetaFiles = {
|
|
42
|
+
root: RootCollectionMeta | null;
|
|
43
|
+
collections: Array<CollectionMeta & {
|
|
44
|
+
path: string;
|
|
45
|
+
contentId?: ContentId;
|
|
46
|
+
}>;
|
|
47
|
+
};
|
|
41
48
|
/**
|
|
42
49
|
* Resolve schema references for root collection and all collections.
|
|
43
50
|
*
|
|
@@ -49,12 +56,15 @@ export declare function loadCollectionMetaFiles(contentRoot: string): Promise<{
|
|
|
49
56
|
* @returns Fully resolved root collection config ready for use by CanopyCMS
|
|
50
57
|
* @throws Error if any schema reference doesn't exist in registry (with helpful suggestions)
|
|
51
58
|
*/
|
|
52
|
-
export declare function resolveCollectionReferences(metaFiles:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
export declare function resolveCollectionReferences(metaFiles: LoadedMetaFiles, entrySchemaRegistry: EntrySchemaRegistry): RootCollectionConfig;
|
|
60
|
+
/**
|
|
61
|
+
* {@link resolveCollectionReferences} under an explicit {@link UnknownSchemaPolicy}: 'degrade'
|
|
62
|
+
* marks an entry type naming an unregistered schema `unavailable` and reports it in `issues`
|
|
63
|
+
* instead of throwing, so the rest of the schema still resolves.
|
|
64
|
+
*/
|
|
65
|
+
export declare function resolveCollectionMetaFiles(metaFiles: LoadedMetaFiles, entrySchemaRegistry: EntrySchemaRegistry, policy: UnknownSchemaPolicy): {
|
|
66
|
+
schema: RootCollectionConfig;
|
|
67
|
+
issues: SchemaIssue[];
|
|
68
|
+
};
|
|
59
69
|
export declare function watchCollectionMetaFiles(contentRoot: string, onChange: () => void): () => void;
|
|
60
70
|
export {};
|
|
@@ -154,12 +154,36 @@ export async function loadCollectionMetaFiles(contentRoot) {
|
|
|
154
154
|
const collections = await scanForCollectionMeta(contentRoot);
|
|
155
155
|
return { root, collections };
|
|
156
156
|
}
|
|
157
|
-
function resolveEntryTypes(entryTypes, entrySchemaRegistry, contextName) {
|
|
157
|
+
function resolveEntryTypes(entryTypes, entrySchemaRegistry, contextName, location, resolution) {
|
|
158
158
|
return entryTypes.map((entryType) => {
|
|
159
159
|
const resolvedSchema = entrySchemaRegistry[entryType.schema];
|
|
160
160
|
if (!resolvedSchema) {
|
|
161
|
-
|
|
162
|
-
|
|
161
|
+
const message = `Schema reference "${entryType.schema}" in entry type "${entryType.name}" (${contextName}) not found in registry.`;
|
|
162
|
+
if (resolution.policy === 'throw') {
|
|
163
|
+
throw new Error(`${message} Available schemas: ${Object.keys(entrySchemaRegistry).join(', ')}`);
|
|
164
|
+
}
|
|
165
|
+
resolution.issues.push({
|
|
166
|
+
kind: 'unknown-schema',
|
|
167
|
+
collectionPath: location.collectionPath,
|
|
168
|
+
entryType: entryType.name,
|
|
169
|
+
schemaRef: entryType.schema,
|
|
170
|
+
metaFile: location.metaFile,
|
|
171
|
+
message,
|
|
172
|
+
});
|
|
173
|
+
return {
|
|
174
|
+
name: entryType.name,
|
|
175
|
+
label: entryType.label,
|
|
176
|
+
format: entryType.format,
|
|
177
|
+
schema: [],
|
|
178
|
+
schemaRef: entryType.schema,
|
|
179
|
+
default: entryType.default,
|
|
180
|
+
maxItems: entryType.maxItems,
|
|
181
|
+
unavailable: {
|
|
182
|
+
reason: 'unknown-schema',
|
|
183
|
+
schemaRef: entryType.schema,
|
|
184
|
+
metaFile: location.metaFile,
|
|
185
|
+
},
|
|
186
|
+
};
|
|
163
187
|
}
|
|
164
188
|
// Note: "body" field name validation for md/mdx formats is handled by the
|
|
165
189
|
// entry schema registry (isBody constraints). Not checked here because
|
|
@@ -175,9 +199,9 @@ function resolveEntryTypes(entryTypes, entrySchemaRegistry, contextName) {
|
|
|
175
199
|
};
|
|
176
200
|
});
|
|
177
201
|
}
|
|
178
|
-
function resolveCollectionMeta(meta, entrySchemaRegistry, allCollections) {
|
|
202
|
+
function resolveCollectionMeta(meta, entrySchemaRegistry, allCollections, resolution) {
|
|
179
203
|
const entries = meta.entries && meta.entries.length > 0
|
|
180
|
-
? resolveEntryTypes(meta.entries, entrySchemaRegistry, `collection "${meta.name}"`)
|
|
204
|
+
? resolveEntryTypes(meta.entries, entrySchemaRegistry, `collection "${meta.name}"`, { collectionPath: meta.path, metaFile: `${meta.path}/.collection.json` }, resolution)
|
|
181
205
|
: undefined;
|
|
182
206
|
// Find nested collections (subfolders with .collection.json)
|
|
183
207
|
const nestedCollections = allCollections.filter((col) => {
|
|
@@ -185,7 +209,7 @@ function resolveCollectionMeta(meta, entrySchemaRegistry, allCollections) {
|
|
|
185
209
|
col.path.split('/').length === meta.path.split('/').length + 1);
|
|
186
210
|
});
|
|
187
211
|
const collections = nestedCollections.length > 0
|
|
188
|
-
? nestedCollections.map((nestedMeta) => resolveCollectionMeta(nestedMeta, entrySchemaRegistry, allCollections))
|
|
212
|
+
? nestedCollections.map((nestedMeta) => resolveCollectionMeta(nestedMeta, entrySchemaRegistry, allCollections, resolution))
|
|
189
213
|
: undefined;
|
|
190
214
|
return {
|
|
191
215
|
name: meta.name,
|
|
@@ -209,13 +233,22 @@ function resolveCollectionMeta(meta, entrySchemaRegistry, allCollections) {
|
|
|
209
233
|
* @throws Error if any schema reference doesn't exist in registry (with helpful suggestions)
|
|
210
234
|
*/
|
|
211
235
|
export function resolveCollectionReferences(metaFiles, entrySchemaRegistry) {
|
|
236
|
+
return resolveCollectionMetaFiles(metaFiles, entrySchemaRegistry, 'throw').schema;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* {@link resolveCollectionReferences} under an explicit {@link UnknownSchemaPolicy}: 'degrade'
|
|
240
|
+
* marks an entry type naming an unregistered schema `unavailable` and reports it in `issues`
|
|
241
|
+
* instead of throwing, so the rest of the schema still resolves.
|
|
242
|
+
*/
|
|
243
|
+
export function resolveCollectionMetaFiles(metaFiles, entrySchemaRegistry, policy) {
|
|
244
|
+
const resolution = { policy, issues: [] };
|
|
212
245
|
// Build result object dynamically to avoid readonly conflicts
|
|
213
246
|
const result = {};
|
|
214
247
|
if (metaFiles.root?.label) {
|
|
215
248
|
result.label = metaFiles.root.label;
|
|
216
249
|
}
|
|
217
250
|
if (metaFiles.root?.entries && metaFiles.root.entries.length > 0) {
|
|
218
|
-
result.entries = resolveEntryTypes(metaFiles.root.entries, entrySchemaRegistry, 'root collection');
|
|
251
|
+
result.entries = resolveEntryTypes(metaFiles.root.entries, entrySchemaRegistry, 'root collection', { collectionPath: '', metaFile: '.collection.json' }, resolution);
|
|
219
252
|
}
|
|
220
253
|
if (metaFiles.root?.order) {
|
|
221
254
|
result.order = metaFiles.root.order;
|
|
@@ -223,9 +256,9 @@ export function resolveCollectionReferences(metaFiles, entrySchemaRegistry) {
|
|
|
223
256
|
// Resolve top-level collections (no slashes in path)
|
|
224
257
|
const topLevelCollections = metaFiles.collections.filter((meta) => !meta.path.includes('/'));
|
|
225
258
|
if (topLevelCollections.length > 0) {
|
|
226
|
-
result.collections = topLevelCollections.map((meta) => resolveCollectionMeta(meta, entrySchemaRegistry, metaFiles.collections));
|
|
259
|
+
result.collections = topLevelCollections.map((meta) => resolveCollectionMeta(meta, entrySchemaRegistry, metaFiles.collections, resolution));
|
|
227
260
|
}
|
|
228
|
-
return result;
|
|
261
|
+
return { schema: result, issues: resolution.issues };
|
|
229
262
|
}
|
|
230
263
|
export function watchCollectionMetaFiles(contentRoot, onChange) {
|
|
231
264
|
const watcher = chokidar.watch(`${contentRoot}/**/.collection.json`, {
|