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
package/dist/static/seo.js
CHANGED
|
@@ -92,12 +92,12 @@ export function extractSeoFields(entryData, opts = {}) {
|
|
|
92
92
|
* THE `noindex` predicate. Every surface that suppresses an entry must route through this one
|
|
93
93
|
* function rather than re-deriving the flag:
|
|
94
94
|
*
|
|
95
|
-
* - the page's own `robots: { index: false }` (canopycms-next's `entryToMetadata`),
|
|
96
|
-
* - exclusion from the sitemap (canopycms-next's `generateContentSitemap`)
|
|
95
|
+
* - the page's own `robots: { index: false }` (canopycms-next's `entryToMetadata`),
|
|
96
|
+
* - exclusion from the sitemap (canopycms-next's `generateContentSitemap`), and
|
|
97
|
+
* - exclusion from AI content (`ai/generate.ts`, unless `exclude.noindex: false`).
|
|
97
98
|
*
|
|
98
|
-
* Those
|
|
99
|
-
*
|
|
100
|
-
* from the other, and nothing warned.
|
|
99
|
+
* Those surfaces shipping from one predicate is the point. Derived separately, a `noindex` entry
|
|
100
|
+
* stays advertised in one surface while correctly absent from another, and nothing warns.
|
|
101
101
|
*
|
|
102
102
|
* NOT applied to enumeration: `noindex` means "don't advertise this", not "don't build this".
|
|
103
103
|
* `collectRoutableEntries` and `generateStaticParams` must still emit the entry, so its URL
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { UserSearchResult } from './auth/types.js';
|
|
1
2
|
import type { CanopyUser } from './user.js';
|
|
2
3
|
/**
|
|
3
4
|
* Who submitted (and edited) a branch, recorded in the submit commit's trailers
|
|
@@ -38,6 +39,13 @@ export declare function sanitizeUserId(raw: string | undefined): string | undefi
|
|
|
38
39
|
export declare function sanitizeEmail(raw: string | undefined): string | undefined;
|
|
39
40
|
/** The submitter as a SubmissionEditor, or undefined for an anonymous user. */
|
|
40
41
|
export declare function submissionEditorFromUser(user: CanopyUser): SubmissionEditor | undefined;
|
|
42
|
+
/** Looks a user up by id, as `AuthPlugin.getUserMetadata` does. */
|
|
43
|
+
export type EditorLookup = (userId: string) => Promise<UserSearchResult | null>;
|
|
44
|
+
/**
|
|
45
|
+
* Recorded editor ids as SubmissionEditors, with the email and usable name (see personName) the
|
|
46
|
+
* auth provider gives now. A user the lookup cannot find, or a lookup that throws, keeps just the id.
|
|
47
|
+
*/
|
|
48
|
+
export declare function describeEditors(userIds: readonly string[], lookup: EditorLookup | undefined): Promise<SubmissionEditor[]>;
|
|
41
49
|
export interface CommitTrailerOptions {
|
|
42
50
|
/** One `Edited-by: Name (id)` per editor. */
|
|
43
51
|
editedBy: boolean;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { personName } from './auth/person-name.js';
|
|
2
|
+
import { getErrorMessage } from './utils/error.js';
|
|
1
3
|
import { canopyLogWarn } from './utils/logger.js';
|
|
2
4
|
const MAX_NAME_LENGTH = 80;
|
|
3
5
|
const MAX_ID_LENGTH = 128;
|
|
@@ -87,6 +89,26 @@ export function submissionEditorFromUser(user) {
|
|
|
87
89
|
return undefined;
|
|
88
90
|
return { userId: user.userId, name: user.name, email: user.email };
|
|
89
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Recorded editor ids as SubmissionEditors, with the email and usable name (see personName) the
|
|
94
|
+
* auth provider gives now. A user the lookup cannot find, or a lookup that throws, keeps just the id.
|
|
95
|
+
*/
|
|
96
|
+
export async function describeEditors(userIds, lookup) {
|
|
97
|
+
return Promise.all(userIds.map(async (userId) => {
|
|
98
|
+
if (!lookup)
|
|
99
|
+
return { userId };
|
|
100
|
+
try {
|
|
101
|
+
const found = await lookup(userId);
|
|
102
|
+
return found
|
|
103
|
+
? { userId, name: personName(userId, found.name), email: found.email }
|
|
104
|
+
: { userId };
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
canopyLogWarn('CanopyCMS: Could not look up an editor; crediting them by id:', getErrorMessage(err));
|
|
108
|
+
return { userId };
|
|
109
|
+
}
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
90
112
|
function cleanEditors(editors) {
|
|
91
113
|
const seen = new Set();
|
|
92
114
|
const result = [];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The user ids CanopyCMS itself acts as, never a person. Dependency-free, so the editor bundle can
|
|
3
|
+
* import it.
|
|
4
|
+
*/
|
|
5
|
+
/** Owner of a branch CanopyCMS provisions itself (http/handler.ts); see authorization/branch.ts. */
|
|
6
|
+
export declare const SYSTEM_USER_ID = "canopycms-system";
|
|
7
|
+
/** Owner recorded by a content read outside any request (content-reader.ts). */
|
|
8
|
+
export declare const CONTENT_READER_USER_ID = "canopycms-content-reader";
|
|
9
|
+
/** Owner recorded for the active branch a server context provisions (context.ts). */
|
|
10
|
+
export declare const CONTEXT_USER_ID = "canopycms-context";
|
|
11
|
+
/** True for a user id CanopyCMS acts as; the editor shows these as "CanopyCMS bot". */
|
|
12
|
+
export declare const isSystemUserId: (userId: string) => boolean;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The user ids CanopyCMS itself acts as, never a person. Dependency-free, so the editor bundle can
|
|
3
|
+
* import it.
|
|
4
|
+
*/
|
|
5
|
+
/** Owner of a branch CanopyCMS provisions itself (http/handler.ts); see authorization/branch.ts. */
|
|
6
|
+
export const SYSTEM_USER_ID = 'canopycms-system';
|
|
7
|
+
/** Owner recorded by a content read outside any request (content-reader.ts). */
|
|
8
|
+
export const CONTENT_READER_USER_ID = 'canopycms-content-reader';
|
|
9
|
+
/** Owner recorded for the active branch a server context provisions (context.ts). */
|
|
10
|
+
export const CONTEXT_USER_ID = 'canopycms-context';
|
|
11
|
+
/** True for a user id CanopyCMS acts as; the editor shows these as "CanopyCMS bot". */
|
|
12
|
+
export const isSystemUserId = (userId) => userId === SYSTEM_USER_ID || userId === CONTENT_READER_USER_ID || userId === CONTEXT_USER_ID;
|
|
@@ -11,5 +11,5 @@ export type WorkerTask = Task & {
|
|
|
11
11
|
action: TaskAction;
|
|
12
12
|
};
|
|
13
13
|
export declare const cmsTaskQueueLogger: TaskQueueLogger;
|
|
14
|
-
export { enqueueTask, dequeueTask, completeTask, failTask, retryTask, requeueFailedTask, recoverOrphanedTasks, cleanupOldTasks, getTask, listTasks, getQueueStats, listCorruptTaskFiles, } from './task-queue.js';
|
|
14
|
+
export { enqueueTask, dequeueTask, completeTask, failTask, retryTask, releaseTask, requeueFailedTask, recoverOrphanedTasks, cleanupOldTasks, getTask, listTasks, getQueueStats, listCorruptTaskFiles, } from './task-queue.js';
|
|
15
15
|
export type { Task, TaskStatus, QueueStats, TaskQueueLogger, CorruptTaskFile } from './types.js';
|
|
@@ -10,4 +10,4 @@ export const cmsTaskQueueLogger = {
|
|
|
10
10
|
debugLogger.debug('task', message, data);
|
|
11
11
|
},
|
|
12
12
|
};
|
|
13
|
-
export { enqueueTask, dequeueTask, completeTask, failTask, retryTask, requeueFailedTask, recoverOrphanedTasks, cleanupOldTasks, getTask, listTasks, getQueueStats, listCorruptTaskFiles, } from './task-queue.js';
|
|
13
|
+
export { enqueueTask, dequeueTask, completeTask, failTask, retryTask, releaseTask, requeueFailedTask, recoverOrphanedTasks, cleanupOldTasks, getTask, listTasks, getQueueStats, listCorruptTaskFiles, } from './task-queue.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export type { Task, TaskStatus, QueueStats, TaskQueueLogger, CorruptTaskFile } from './types.js';
|
|
2
|
-
export { enqueueTask, dequeueTask, completeTask, failTask, retryTask, requeueFailedTask, recoverOrphanedTasks, cleanupOldTasks, getTask, listTasks, getQueueStats, listCorruptTaskFiles, } from './task-queue.js';
|
|
2
|
+
export { enqueueTask, dequeueTask, completeTask, failTask, retryTask, releaseTask, requeueFailedTask, recoverOrphanedTasks, cleanupOldTasks, getTask, listTasks, getQueueStats, listCorruptTaskFiles, } from './task-queue.js';
|
package/dist/task-queue/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { enqueueTask, dequeueTask, completeTask, failTask, retryTask, requeueFailedTask, recoverOrphanedTasks, cleanupOldTasks, getTask, listTasks, getQueueStats, listCorruptTaskFiles, } from './task-queue.js';
|
|
1
|
+
export { enqueueTask, dequeueTask, completeTask, failTask, retryTask, releaseTask, requeueFailedTask, recoverOrphanedTasks, cleanupOldTasks, getTask, listTasks, getQueueStats, listCorruptTaskFiles, } from './task-queue.js';
|
|
@@ -49,6 +49,12 @@ export declare function failTask(taskDir: string, taskId: string, error: string,
|
|
|
49
49
|
* and a retryAfter timestamp. Backoff: 5s → 10s → 20s → 40s → 60s cap.
|
|
50
50
|
*/
|
|
51
51
|
export declare function retryTask(taskDir: string, taskId: string, error: string, logger?: TaskQueueLogger): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Hand an in-flight task back to pending/ unchanged, with no retry spent and no
|
|
54
|
+
* backoff, for a consumer abandoning it while shutting down. Safe only for an
|
|
55
|
+
* idempotent action: the abandoned attempt may have done part of its work.
|
|
56
|
+
*/
|
|
57
|
+
export declare function releaseTask(taskDir: string, taskId: string, logger?: TaskQueueLogger): Promise<void>;
|
|
52
58
|
/**
|
|
53
59
|
* Requeue a permanently-failed task: reads failed/{taskId}.json and creates a
|
|
54
60
|
* brand-new pending task with a fresh `id`, never the original — `dequeueTask`
|
|
@@ -214,6 +214,35 @@ export async function retryTask(taskDir, taskId, error, logger = nullLogger) {
|
|
|
214
214
|
await fs.unlink(processingPath).catch(() => { });
|
|
215
215
|
logger.debug('Retrying task', { id: taskId, retryCount, backoffMs });
|
|
216
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* Hand an in-flight task back to pending/ unchanged, with no retry spent and no
|
|
219
|
+
* backoff, for a consumer abandoning it while shutting down. Safe only for an
|
|
220
|
+
* idempotent action: the abandoned attempt may have done part of its work.
|
|
221
|
+
*/
|
|
222
|
+
export async function releaseTask(taskDir, taskId, logger = nullLogger) {
|
|
223
|
+
const processingPath = path.join(taskDir, 'processing', `${taskId}.json`);
|
|
224
|
+
const pendingPath = path.join(taskDir, 'pending', `${taskId}.json`);
|
|
225
|
+
let task;
|
|
226
|
+
try {
|
|
227
|
+
const content = await fs.readFile(processingPath, 'utf-8');
|
|
228
|
+
const parsed = parseTaskJson(content);
|
|
229
|
+
if (!parsed) {
|
|
230
|
+
logger.debug('Corrupt task file in processing, removing', { id: taskId });
|
|
231
|
+
await fs.unlink(processingPath).catch(() => { });
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
task = parsed;
|
|
235
|
+
}
|
|
236
|
+
catch (err) {
|
|
237
|
+
if (isNotFoundError(err))
|
|
238
|
+
return;
|
|
239
|
+
throw err;
|
|
240
|
+
}
|
|
241
|
+
task.status = 'pending';
|
|
242
|
+
await atomicWriteFile(pendingPath, JSON.stringify(task, null, 2));
|
|
243
|
+
await fs.unlink(processingPath).catch(() => { });
|
|
244
|
+
logger.debug('Released task', { id: taskId });
|
|
245
|
+
}
|
|
217
246
|
/**
|
|
218
247
|
* Requeue a permanently-failed task: reads failed/{taskId}.json and creates a
|
|
219
248
|
* brand-new pending task with a fresh `id`, never the original — `dequeueTask`
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* (utils/atomic-write.ts), never a read-modify-write, so whichever write lands
|
|
12
12
|
* last is one writer's complete, self-consistent snapshot. That covers the one
|
|
13
13
|
* window where two holders overlap -- after a lock compromise the old holder's
|
|
14
|
-
* `stop()`
|
|
14
|
+
* `stop()` aborts its in-flight work while a new holder may already be
|
|
15
15
|
* running against the same workspace.
|
|
16
16
|
*
|
|
17
17
|
* Readers are stale-tolerant by design: this is a liveness signal, not
|
|
@@ -21,6 +21,40 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import type { WorkerStatusReport } from '../types.js';
|
|
23
23
|
export declare const WORKER_STATUS_FILE = "worker-status.json";
|
|
24
|
+
/**
|
|
25
|
+
* What a new worker carries from the previous status file into its first snapshot:
|
|
26
|
+
* `lastFatalError`, so a crash loop keeps its alert, and how the last worker that ran stopped.
|
|
27
|
+
* A `lastShutdown` written by an earlier worker than the file's own means the last one stopped
|
|
28
|
+
* without draining, unless the file's own worker recorded its failed start: it never ran, so the
|
|
29
|
+
* carried record holds. Tolerant like every reader: a missing or unreadable file yields neither.
|
|
30
|
+
*/
|
|
31
|
+
export declare function readCarriedOverStatus(taskDir: string): Promise<Pick<WorkerStatusReport, 'lastFatalError' | 'lastShutdown'>>;
|
|
32
|
+
/**
|
|
33
|
+
* `startedAt` of the worker that wrote the status file, or `undefined` when there is no file or
|
|
34
|
+
* it names no worker. Throws on any other read error: a caller deciding whether the file is its
|
|
35
|
+
* own must not take an unreadable one for an absent one.
|
|
36
|
+
*/
|
|
37
|
+
export declare function readWorkerStatusStartedAt(taskDir: string): Promise<string | undefined>;
|
|
38
|
+
/** A startup failure the worker recorded; see {@link readWorkerStartupFailure}. */
|
|
39
|
+
export interface WorkerStartupFailure {
|
|
40
|
+
/** Already redacted by the worker. */
|
|
41
|
+
message: string;
|
|
42
|
+
at: string;
|
|
43
|
+
/**
|
|
44
|
+
* The attempt that wrote the file is the one that failed. False while a newer worker carries
|
|
45
|
+
* an older failure forward and is starting again.
|
|
46
|
+
*/
|
|
47
|
+
current: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The startup failure in `{taskDir}/worker-status.json`, for a request that found no remote to
|
|
51
|
+
* clone. A failure is current when the worker that recorded it is the one the snapshot
|
|
52
|
+
* describes: a worker that starts again writes its own `startedAt` and carries the previous
|
|
53
|
+
* failure forward, so a retry in progress (a first clone can take minutes) is not reported as a
|
|
54
|
+
* dead worker. Compared by identity, not by clock, since the two workers can run on different
|
|
55
|
+
* hosts. Tolerant like every reader: a missing or unreadable file yields none.
|
|
56
|
+
*/
|
|
57
|
+
export declare function readWorkerStartupFailure(taskDir: string): Promise<WorkerStartupFailure | undefined>;
|
|
24
58
|
/**
|
|
25
59
|
* Write the worker's status report to `{taskDir}/worker-status.json`.
|
|
26
60
|
*
|
|
@@ -32,12 +66,4 @@ export declare const WORKER_STATUS_FILE = "worker-status.json";
|
|
|
32
66
|
* `processTaskQueue`, `start()`); any that don't fall back on scheduleLoop's
|
|
33
67
|
* per-cycle catch, which logs and continues.
|
|
34
68
|
*/
|
|
35
|
-
/**
|
|
36
|
-
* The `lastFatalError` in the current status file, or undefined when the file is
|
|
37
|
-
* missing, unreadable or has none. Tolerant for the same reason readers are.
|
|
38
|
-
* Its one caller carries the value into a full snapshot right after taking the
|
|
39
|
-
* worker lock; a write racing in between only keeps or drops one crash alert
|
|
40
|
-
* until the next write.
|
|
41
|
-
*/
|
|
42
|
-
export declare function readLastFatalError(taskDir: string): Promise<WorkerStatusReport['lastFatalError']>;
|
|
43
69
|
export declare function writeWorkerStatus(taskDir: string, report: WorkerStatusReport): Promise<void>;
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* (utils/atomic-write.ts), never a read-modify-write, so whichever write lands
|
|
12
12
|
* last is one writer's complete, self-consistent snapshot. That covers the one
|
|
13
13
|
* window where two holders overlap -- after a lock compromise the old holder's
|
|
14
|
-
* `stop()`
|
|
14
|
+
* `stop()` aborts its in-flight work while a new holder may already be
|
|
15
15
|
* running against the same workspace.
|
|
16
16
|
*
|
|
17
17
|
* Readers are stale-tolerant by design: this is a liveness signal, not
|
|
@@ -22,7 +22,90 @@
|
|
|
22
22
|
import fs from 'node:fs/promises';
|
|
23
23
|
import path from 'node:path';
|
|
24
24
|
import { atomicWriteFile } from '../utils/atomic-write.js';
|
|
25
|
+
import { isNotFoundError } from '../utils/error.js';
|
|
25
26
|
export const WORKER_STATUS_FILE = 'worker-status.json';
|
|
27
|
+
/**
|
|
28
|
+
* What a new worker carries from the previous status file into its first snapshot:
|
|
29
|
+
* `lastFatalError`, so a crash loop keeps its alert, and how the last worker that ran stopped.
|
|
30
|
+
* A `lastShutdown` written by an earlier worker than the file's own means the last one stopped
|
|
31
|
+
* without draining, unless the file's own worker recorded its failed start: it never ran, so the
|
|
32
|
+
* carried record holds. Tolerant like every reader: a missing or unreadable file yields neither.
|
|
33
|
+
*/
|
|
34
|
+
export async function readCarriedOverStatus(taskDir) {
|
|
35
|
+
let previous;
|
|
36
|
+
try {
|
|
37
|
+
const content = await fs.readFile(path.join(taskDir, WORKER_STATUS_FILE), 'utf-8');
|
|
38
|
+
previous = JSON.parse(content);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
const { lastFatalError, startedAt, updatedAt } = previous;
|
|
44
|
+
let { lastShutdown } = previous;
|
|
45
|
+
const failedStart = lastFatalError?.phase === 'startup' && lastFatalError.workerStartedAt === startedAt;
|
|
46
|
+
if (startedAt && updatedAt && !failedStart && lastShutdown?.workerStartedAt !== startedAt) {
|
|
47
|
+
lastShutdown = {
|
|
48
|
+
reason: 'stopped without draining',
|
|
49
|
+
at: updatedAt,
|
|
50
|
+
workerStartedAt: startedAt,
|
|
51
|
+
outcome: 'not-drained',
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return { lastFatalError, lastShutdown };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* `startedAt` of the worker that wrote the status file, or `undefined` when there is no file or
|
|
58
|
+
* it names no worker. Throws on any other read error: a caller deciding whether the file is its
|
|
59
|
+
* own must not take an unreadable one for an absent one.
|
|
60
|
+
*/
|
|
61
|
+
export async function readWorkerStatusStartedAt(taskDir) {
|
|
62
|
+
let content;
|
|
63
|
+
try {
|
|
64
|
+
content = await fs.readFile(path.join(taskDir, WORKER_STATUS_FILE), 'utf-8');
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
if (isNotFoundError(err))
|
|
68
|
+
return undefined;
|
|
69
|
+
throw err;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const report = JSON.parse(content);
|
|
73
|
+
return typeof report.startedAt === 'string' ? report.startedAt : undefined;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The startup failure in `{taskDir}/worker-status.json`, for a request that found no remote to
|
|
81
|
+
* clone. A failure is current when the worker that recorded it is the one the snapshot
|
|
82
|
+
* describes: a worker that starts again writes its own `startedAt` and carries the previous
|
|
83
|
+
* failure forward, so a retry in progress (a first clone can take minutes) is not reported as a
|
|
84
|
+
* dead worker. Compared by identity, not by clock, since the two workers can run on different
|
|
85
|
+
* hosts. Tolerant like every reader: a missing or unreadable file yields none.
|
|
86
|
+
*/
|
|
87
|
+
export async function readWorkerStartupFailure(taskDir) {
|
|
88
|
+
let report;
|
|
89
|
+
try {
|
|
90
|
+
report = JSON.parse(await fs.readFile(path.join(taskDir, WORKER_STATUS_FILE), 'utf-8'));
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
const fatal = report.lastFatalError;
|
|
96
|
+
if (fatal?.phase !== 'startup' || typeof fatal.message !== 'string')
|
|
97
|
+
return undefined;
|
|
98
|
+
let current;
|
|
99
|
+
if (fatal.workerStartedAt !== undefined) {
|
|
100
|
+
current = fatal.workerStartedAt === report.startedAt;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
// A file from a worker that does not link the two: compare clocks instead.
|
|
104
|
+
const startedAt = report.startedAt ? Date.parse(report.startedAt) : NaN;
|
|
105
|
+
current = Number.isNaN(startedAt) || !(Date.parse(fatal.at) < startedAt);
|
|
106
|
+
}
|
|
107
|
+
return { message: fatal.message, at: fatal.at, current };
|
|
108
|
+
}
|
|
26
109
|
/**
|
|
27
110
|
* Write the worker's status report to `{taskDir}/worker-status.json`.
|
|
28
111
|
*
|
|
@@ -34,22 +117,6 @@ export const WORKER_STATUS_FILE = 'worker-status.json';
|
|
|
34
117
|
* `processTaskQueue`, `start()`); any that don't fall back on scheduleLoop's
|
|
35
118
|
* per-cycle catch, which logs and continues.
|
|
36
119
|
*/
|
|
37
|
-
/**
|
|
38
|
-
* The `lastFatalError` in the current status file, or undefined when the file is
|
|
39
|
-
* missing, unreadable or has none. Tolerant for the same reason readers are.
|
|
40
|
-
* Its one caller carries the value into a full snapshot right after taking the
|
|
41
|
-
* worker lock; a write racing in between only keeps or drops one crash alert
|
|
42
|
-
* until the next write.
|
|
43
|
-
*/
|
|
44
|
-
export async function readLastFatalError(taskDir) {
|
|
45
|
-
try {
|
|
46
|
-
const content = await fs.readFile(path.join(taskDir, WORKER_STATUS_FILE), 'utf-8');
|
|
47
|
-
return JSON.parse(content).lastFatalError;
|
|
48
|
-
}
|
|
49
|
-
catch {
|
|
50
|
-
return undefined;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
120
|
export async function writeWorkerStatus(taskDir, report) {
|
|
54
121
|
const filePath = path.join(taskDir, WORKER_STATUS_FILE);
|
|
55
122
|
const stamped = { ...report, updatedAt: new Date().toISOString() };
|
package/dist/types.d.ts
CHANGED
|
@@ -33,11 +33,23 @@ export interface BranchMetadata {
|
|
|
33
33
|
baseBranch?: string;
|
|
34
34
|
pullRequestUrl?: string;
|
|
35
35
|
pullRequestNumber?: number;
|
|
36
|
+
/**
|
|
37
|
+
* ISO timestamp of the branch's latest submit. A queued PR task carries it, so the worker's
|
|
38
|
+
* failure handling acts only on the submit that queued it.
|
|
39
|
+
*/
|
|
40
|
+
submittedAt?: string;
|
|
41
|
+
/**
|
|
42
|
+
* ISO timestamp of the CMS's latest push of this branch to GitHub: a worker push GitHub
|
|
43
|
+
* accepted, or a direct-path submit. Branch delete takes it as
|
|
44
|
+
* proof that a same-named GitHub branch is this branch's, since a submit whose PR GitHub refused
|
|
45
|
+
* leaves no PR number. Absent on branches the CMS never pushed there.
|
|
46
|
+
*/
|
|
47
|
+
pushedToGitHubAt?: string;
|
|
36
48
|
/** Sync status for async GitHub operations (used when Lambda has no internet) */
|
|
37
49
|
syncStatus?: SyncStatus;
|
|
38
|
-
/** Whether this branch
|
|
50
|
+
/** Whether any rebase of this branch kept its version of an entry base also changed */
|
|
39
51
|
conflictStatus?: ConflictStatus;
|
|
40
|
-
/** ContentIds of entries where
|
|
52
|
+
/** ContentIds of the entries where a rebase kept the branch's version; cleared when it merges */
|
|
41
53
|
conflictFiles?: ContentId[];
|
|
42
54
|
/**
|
|
43
55
|
* Lifecycle state of the branch's PR as last observed by the worker's merge-poll
|
|
@@ -78,14 +90,21 @@ export interface BranchMetadata {
|
|
|
78
90
|
*/
|
|
79
91
|
historyRewrittenFrom?: string;
|
|
80
92
|
/**
|
|
81
|
-
* Short, sanitized reason the
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* survives a later successful push.
|
|
93
|
+
* Short, sanitized reason the last GitHub sync failed, set alongside
|
|
94
|
+
* `syncStatus: 'sync-failed'` by the worker's updateBranchMetadataOnFailure or a
|
|
95
|
+
* direct-path submit -- e.g. a non-fast-forward push rejection naming the branch.
|
|
96
|
+
* Shown on the branch's row in the editor. Reset to undefined by the next submit
|
|
97
|
+
* and the next successful sync task, so a stale reason never outlives it.
|
|
87
98
|
*/
|
|
88
99
|
syncFailureReason?: string;
|
|
100
|
+
/**
|
|
101
|
+
* Every user whose successful change to the branch's working tree is recorded, in first-save
|
|
102
|
+
* order (recordBranchEditor in branch-metadata.ts). Never reset, because each submit rebuilds
|
|
103
|
+
* the whole PR body and credits them all. User ids only: names are looked up at submit.
|
|
104
|
+
*/
|
|
105
|
+
editors?: CanopyUserId[];
|
|
106
|
+
/** The `editors` who saved since the last submit commit; the next one's trailers name them. */
|
|
107
|
+
uncommittedEditors?: CanopyUserId[];
|
|
89
108
|
}
|
|
90
109
|
export interface BranchPaths {
|
|
91
110
|
/** Root where all branches live (e.g., /mnt/efs/site, ~/.canopycms/branches) */
|
|
@@ -127,6 +146,29 @@ export interface BuildIdentity {
|
|
|
127
146
|
/** Adopter source revision the deployed image was built from (CANOPY_SOURCE_SHA); absent when unset. */
|
|
128
147
|
sourceRevision?: string;
|
|
129
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* The worker holding the base branch at its current tip because the incoming tip references
|
|
151
|
+
* entry schemas the serving editor does not define (worker/schema-gate.ts).
|
|
152
|
+
*/
|
|
153
|
+
export interface BaseSchemaHold {
|
|
154
|
+
/** The earliest of `firstSeen`. */
|
|
155
|
+
since: string;
|
|
156
|
+
/** When each missing schema was first seen missing; the earliest bounds the hold. */
|
|
157
|
+
firstSeen: Record<string, string>;
|
|
158
|
+
/** GitHub's base tip the worker is not advancing to. */
|
|
159
|
+
incomingSha: string;
|
|
160
|
+
/** Schema names the incoming tip references and the serving editor's registry lacks. */
|
|
161
|
+
missingSchemas: string[];
|
|
162
|
+
/** `.collection.json` files referencing them, repo-relative, at most 10. */
|
|
163
|
+
files: string[];
|
|
164
|
+
/** How many files reference them, `files` being the first 10. */
|
|
165
|
+
fileCount: number;
|
|
166
|
+
/** The build that recorded the registry the gate checked against. */
|
|
167
|
+
editorBuild: BuildIdentity;
|
|
168
|
+
editorRecordedAt: string;
|
|
169
|
+
/** Set on the cycle the hold outlived its bound and the worker advanced anyway. */
|
|
170
|
+
expired?: true;
|
|
171
|
+
}
|
|
130
172
|
/**
|
|
131
173
|
* Wire shape of the worker's self-reported status file (worker-status.json, under
|
|
132
174
|
* the task queue dir), written by the CmsWorker daemon. Read-only here: GET
|
|
@@ -164,7 +206,8 @@ export interface WorkerStatusReport {
|
|
|
164
206
|
baseRefresh?: BaseRefreshReport;
|
|
165
207
|
/**
|
|
166
208
|
* Outcome of reconciling remote.git's `refs/heads/*` against GitHub's fetched
|
|
167
|
-
* tips,
|
|
209
|
+
* tips, never moving a head the worker finds editor work in (worker/git-sync.ts's
|
|
210
|
+
* `reconcileTrackedBranches`, worker/stale-mirror.ts).
|
|
168
211
|
* Optional: a status file written by a worker without that reconcile has no
|
|
169
212
|
* such key, and readers must tolerate its absence rather than assume every
|
|
170
213
|
* status file has it.
|
|
@@ -180,11 +223,49 @@ export interface WorkerStatusReport {
|
|
|
180
223
|
* queued -- expected and self-resolving, unlike `diverged`.
|
|
181
224
|
*/
|
|
182
225
|
rewritten?: string[];
|
|
226
|
+
/**
|
|
227
|
+
* Optional for the same reason. Heads that diverged while holding no editor
|
|
228
|
+
* work, moved to GitHub's tip, and heads of branches GitHub no longer has,
|
|
229
|
+
* deleted (worker/stale-mirror.ts).
|
|
230
|
+
*/
|
|
231
|
+
repointed?: string[];
|
|
232
|
+
pruned?: string[];
|
|
183
233
|
};
|
|
184
234
|
};
|
|
185
235
|
lastFatalError?: {
|
|
186
236
|
message: string;
|
|
187
237
|
at: string;
|
|
188
238
|
phase: 'startup' | 'run';
|
|
239
|
+
/**
|
|
240
|
+
* `startedAt` of the worker that recorded it. Equal to the snapshot's own `startedAt` until a
|
|
241
|
+
* newer worker carries the failure forward. Optional: older workers do not write it.
|
|
242
|
+
*/
|
|
243
|
+
workerStartedAt?: string;
|
|
189
244
|
};
|
|
245
|
+
/**
|
|
246
|
+
* Present while the schema gate holds the base branch, and on the cycle a hold expires. Carried
|
|
247
|
+
* into a restarted worker's first snapshot, so the bound survives restarts.
|
|
248
|
+
*/
|
|
249
|
+
baseHold?: BaseSchemaHold;
|
|
250
|
+
/**
|
|
251
|
+
* How the last worker that ran stopped, carried into each new worker's snapshot
|
|
252
|
+
* (task-queue/worker-status.ts's `readCarriedOverStatus`). A worker that fails at startup
|
|
253
|
+
* leaves it alone and records the failure as `lastFatalError`.
|
|
254
|
+
*/
|
|
255
|
+
lastShutdown?: WorkerShutdownRecord;
|
|
256
|
+
}
|
|
257
|
+
export interface WorkerShutdownRecord {
|
|
258
|
+
/** Why the worker stopped, as its entrypoint described it (e.g. 'SIGTERM'). */
|
|
259
|
+
reason: string;
|
|
260
|
+
at: string;
|
|
261
|
+
/** The stopped worker's `startedAt`, which ties the record to that worker. */
|
|
262
|
+
workerStartedAt: string;
|
|
263
|
+
/**
|
|
264
|
+
* `deadline`: in-flight work was still running at the drain deadline, and
|
|
265
|
+
* `abandoned` names it. `not-drained`: the worker stopped without recording
|
|
266
|
+
* a shutdown (a crash or a forced kill); `at` is its last status write.
|
|
267
|
+
*/
|
|
268
|
+
outcome: 'drained' | 'deadline' | 'not-drained';
|
|
269
|
+
drainMs?: number;
|
|
270
|
+
abandoned?: string[];
|
|
190
271
|
}
|
package/dist/url-collision.js
CHANGED
|
@@ -18,7 +18,7 @@ import { parseTypedFilename } from './utils/typed-filename.js';
|
|
|
18
18
|
* `doc.index.{id}.json` inside an md-only collection claims no URL yet still blocks a sibling
|
|
19
19
|
* write. Closing it means threading each collection's configured formats into a deliberately
|
|
20
20
|
* schema-free module; tracked in
|
|
21
|
-
*
|
|
21
|
+
* safeinsights/canopycms#878.
|
|
22
22
|
*
|
|
23
23
|
* A literal rather than derived: deriving it needs the `ContentFormat` union this module has no
|
|
24
24
|
* reason to import. `url-collision.test.ts` carries the drift tripwire — a compile-time
|
|
@@ -65,7 +65,7 @@ async function findChildCollectionDir(dir, name) {
|
|
|
65
65
|
*
|
|
66
66
|
* The claimant set is nonetheless a strict superset of the listing's in three ways, all
|
|
67
67
|
* over-blocking and all needing the same fix — the schema this module deliberately does not have
|
|
68
|
-
* — so they are one task (
|
|
68
|
+
* — so they are one task (safeinsights/canopycms#878):
|
|
69
69
|
*
|
|
70
70
|
* 1. extension — see `CONTENT_EXTENSIONS` above;
|
|
71
71
|
* 2. entry TYPE — parsing is structural (no `entryTypes` list), so a file whose type is not in
|
|
@@ -155,7 +155,7 @@ export async function findUrlPathClaimant(opts) {
|
|
|
155
155
|
// KNOWN DEPENDENCY: this resolves ONE child collection by name, and the index direction above
|
|
156
156
|
// likewise looks only for a parent ENTRY. Neither considers a second collection sharing the same
|
|
157
157
|
// name, because nothing stops one being created -- `createCollectionInner` does not check
|
|
158
|
-
// sibling names (tracked in
|
|
158
|
+
// sibling names (tracked in safeinsights/canopycms#624). With two `guides.{id}`
|
|
159
159
|
// directories side by side, an index entry can be written into each: both writes pass this
|
|
160
160
|
// guard, two entries claim one URL, and only the build guard catches it. Fixing sibling-name
|
|
161
161
|
// uniqueness closes this without changing anything here, so that task is a prerequisite for
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* Scope of the invariant it checks: entries written in the `{type}.{slug}.{id}.{ext}` grammar
|
|
16
16
|
* with a type their collection declares -- exactly the set `listEntries` can see. A legacy
|
|
17
17
|
* untyped file (`overview.json`) is invisible to enumeration and is deliberately NOT probed here;
|
|
18
|
-
* see
|
|
18
|
+
* see safeinsights/canopycms#728.
|
|
19
19
|
*/
|
|
20
20
|
import { type RootCollectionConfig } from './config/index.js';
|
|
21
21
|
import type { ListEntriesItem } from './content-listing.js';
|
|
@@ -54,6 +54,13 @@ export interface UrlExclusivityReport {
|
|
|
54
54
|
expectedEntryId?: string;
|
|
55
55
|
actualEntryId?: string;
|
|
56
56
|
}>;
|
|
57
|
+
/** Published URLs whose read reports a `meta.slug` or `meta.urlPath` other than the listing's. */
|
|
58
|
+
misreported: Array<{
|
|
59
|
+
urlPath: string;
|
|
60
|
+
slug: string;
|
|
61
|
+
readSlug: string;
|
|
62
|
+
readUrlPath: string;
|
|
63
|
+
}>;
|
|
57
64
|
/** Every adjacent URL probed, sorted. */
|
|
58
65
|
probes: string[];
|
|
59
66
|
/** Probes that resolved despite not being published -- the phantom URLs. Must be empty. */
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* Scope of the invariant it checks: entries written in the `{type}.{slug}.{id}.{ext}` grammar
|
|
16
16
|
* with a type their collection declares -- exactly the set `listEntries` can see. A legacy
|
|
17
17
|
* untyped file (`overview.json`) is invisible to enumeration and is deliberately NOT probed here;
|
|
18
|
-
* see
|
|
18
|
+
* see safeinsights/canopycms#728.
|
|
19
19
|
*/
|
|
20
20
|
import { flattenSchema } from './config/index.js';
|
|
21
21
|
import { findDuplicateUrlPaths } from './static/index.js';
|
|
@@ -80,12 +80,21 @@ export const collectUrlExclusivityReport = async (ctx, schema, contentRoot = 'co
|
|
|
80
80
|
const items = await ctx.listEntries();
|
|
81
81
|
const unresolved = [];
|
|
82
82
|
const mismatched = [];
|
|
83
|
+
const misreported = [];
|
|
83
84
|
for (const item of items) {
|
|
84
85
|
const result = await ctx.readByUrlPath(item.urlPath);
|
|
85
86
|
if (!result) {
|
|
86
87
|
unresolved.push(item.urlPath);
|
|
87
88
|
continue;
|
|
88
89
|
}
|
|
90
|
+
if (result.meta.slug !== item.slug || result.meta.urlPath !== item.urlPath) {
|
|
91
|
+
misreported.push({
|
|
92
|
+
urlPath: item.urlPath,
|
|
93
|
+
slug: item.slug,
|
|
94
|
+
readSlug: result.meta.slug,
|
|
95
|
+
readUrlPath: result.meta.urlPath,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
89
98
|
if (result.meta.entryId !== item.entryId) {
|
|
90
99
|
mismatched.push({
|
|
91
100
|
urlPath: item.urlPath,
|
|
@@ -108,6 +117,7 @@ export const collectUrlExclusivityReport = async (ctx, schema, contentRoot = 'co
|
|
|
108
117
|
duplicates: findDuplicateUrlPaths(items),
|
|
109
118
|
unresolved: unresolved.sort(),
|
|
110
119
|
mismatched,
|
|
120
|
+
misreported,
|
|
111
121
|
probes: [...probes].sort(),
|
|
112
122
|
phantoms: phantoms.sort(),
|
|
113
123
|
};
|
package/dist/user.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Import from client-safe subpaths to avoid pulling in server-only loader code
|
|
2
2
|
import { RESERVED_GROUPS, stripReservedGroups } from './authorization/helpers.js';
|
|
3
|
+
import { personName } from './auth/person-name.js';
|
|
3
4
|
/** Pass this constant explicitly wherever anonymous access is intended. */
|
|
4
5
|
export const ANONYMOUS_USER = Object.freeze({
|
|
5
6
|
type: 'anonymous',
|
|
@@ -37,7 +38,7 @@ export function authResultToCanopyUser(authResult, bootstrapAdminIds, internalGr
|
|
|
37
38
|
type: 'authenticated',
|
|
38
39
|
userId: authResult.user.userId,
|
|
39
40
|
email: authResult.user.email,
|
|
40
|
-
name: authResult.user.name,
|
|
41
|
+
name: personName(authResult.user.userId, authResult.user.name),
|
|
41
42
|
avatarUrl: authResult.user.avatarUrl,
|
|
42
43
|
groups,
|
|
43
44
|
};
|
|
@@ -8,8 +8,9 @@ export async function atomicWriteFile(filePath, content) {
|
|
|
8
8
|
const dir = path.dirname(filePath);
|
|
9
9
|
await fs.mkdir(dir, { recursive: true });
|
|
10
10
|
const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
11
|
-
|
|
11
|
+
// A temp file a failed write leaves behind would sit in the working tree for a commit to pick up.
|
|
12
12
|
try {
|
|
13
|
+
await fs.writeFile(tempPath, content, typeof content === 'string' ? 'utf-8' : undefined);
|
|
13
14
|
await fs.rename(tempPath, filePath);
|
|
14
15
|
}
|
|
15
16
|
catch (err) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CanopyConfig } from '../config/index.js';
|
|
2
|
+
/** The base branch is unknown, and prod never assumes one. */
|
|
3
|
+
export declare class BaseBranchUnresolvedError extends Error {
|
|
4
|
+
constructor(detail: string);
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* `config`'s resolved base branch. Prod resolves an unset one from the remote's HEAD
|
|
8
|
+
* (createCanopyServices, then resolvePendingBaseBranch per request), so an unset value in prod
|
|
9
|
+
* means that has not happened yet, or the path skipped it, and it throws rather than guessing
|
|
10
|
+
* 'main'. In the other modes a config that never went through
|
|
11
|
+
* services keeps the 'main' default; services itself resolves dev's from git HEAD.
|
|
12
|
+
*/
|
|
13
|
+
export declare function baseBranchOf(config: Pick<CanopyConfig, 'mode' | 'defaultBaseBranch'>): string;
|