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/assets/types.d.ts
CHANGED
|
@@ -41,6 +41,12 @@ export interface PublicObject {
|
|
|
41
41
|
contentDisposition?: string;
|
|
42
42
|
cacheControl?: string;
|
|
43
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* What a create-only write did. Every key the store writes this way is content-addressed, so no
|
|
46
|
+
* correct writer ever replaces an object: `already-exists` means an object was already at the key
|
|
47
|
+
* and was left alone.
|
|
48
|
+
*/
|
|
49
|
+
export type CreateOnlyResult = 'created' | 'already-exists';
|
|
44
50
|
export interface AssetStore {
|
|
45
51
|
readonly capabilities: {
|
|
46
52
|
directUpload: boolean;
|
|
@@ -49,26 +55,47 @@ export interface AssetStore {
|
|
|
49
55
|
writeStaging(stagingKey: string, data: Uint8Array, contentType?: string): Promise<void>;
|
|
50
56
|
readStaging(stagingKey: string): Promise<Uint8Array | null>;
|
|
51
57
|
deleteStaging(stagingKey: string): Promise<void>;
|
|
58
|
+
/** Create-only; see `CreateOnlyResult`. */
|
|
52
59
|
putOriginal(input: {
|
|
53
60
|
hash32: string;
|
|
54
61
|
ext: string;
|
|
55
62
|
data: Uint8Array;
|
|
56
63
|
contentType: string;
|
|
57
|
-
}): Promise<
|
|
58
|
-
|
|
64
|
+
}): Promise<CreateOnlyResult>;
|
|
65
|
+
/**
|
|
66
|
+
* `ext` is where the original is expected (its meta's `ext`): that key is read first, and any
|
|
67
|
+
* `{hash32}.*` is looked for only on a miss. A hit needs no list permission; on S3 without
|
|
68
|
+
* `s3:ListBucket` a miss is a 403, which throws.
|
|
69
|
+
*/
|
|
70
|
+
readOriginal(hash32: string, ext?: string): Promise<{
|
|
59
71
|
data: Uint8Array;
|
|
60
72
|
ext: string;
|
|
61
73
|
contentType?: string;
|
|
62
74
|
} | null>;
|
|
75
|
+
/** Create-only; see `CreateOnlyResult`. */
|
|
63
76
|
putPublicObject(input: {
|
|
64
77
|
key: string;
|
|
65
78
|
data: Uint8Array;
|
|
66
79
|
contentType: string;
|
|
67
80
|
contentDisposition?: string;
|
|
68
81
|
cacheControl?: string;
|
|
69
|
-
|
|
82
|
+
/** Object tags; bucket lifecycle rules can filter on them. */
|
|
83
|
+
tags?: Readonly<Record<string, string>>;
|
|
84
|
+
}): Promise<CreateOnlyResult>;
|
|
85
|
+
/**
|
|
86
|
+
* Copy the public object at `sourceKey` to `destKey` inside the store, create-only like
|
|
87
|
+
* `putPublicObject`. The copy keeps the source's headers and carries no tags. `source-missing`
|
|
88
|
+
* when nothing is at `sourceKey`.
|
|
89
|
+
*/
|
|
90
|
+
copyPublicObject(sourceKey: string, destKey: string): Promise<CreateOnlyResult | 'source-missing'>;
|
|
70
91
|
readPublicObject(key: string): Promise<PublicObject | null>;
|
|
71
|
-
|
|
92
|
+
/** Whether a public object exists at `key`, without reading its body. */
|
|
93
|
+
hasPublicObject(key: string): Promise<boolean>;
|
|
94
|
+
/** Every public object key under `prefix`, in the store's own pages. S3 only. */
|
|
95
|
+
listPublicObjectKeys?(prefix: string): AsyncIterable<string>;
|
|
96
|
+
/** A short-lived URL a browser can GET `key` from directly, or `null` if absent. S3 only. */
|
|
97
|
+
presignPublicObjectRead?(key: string): Promise<string | null>;
|
|
98
|
+
putMetaIfAbsent(hash32: string, meta: AssetMeta): Promise<CreateOnlyResult>;
|
|
72
99
|
getMeta(hash32: string): Promise<AssetMeta | null>;
|
|
73
100
|
listMeta(input?: {
|
|
74
101
|
cursor?: string;
|
package/dist/auth/cache.d.ts
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Server-only: these use node:fs/promises and must NOT reach a client bundle.
|
|
3
3
|
* Import them as 'canopycms/auth/cache'.
|
|
4
4
|
*/
|
|
5
|
-
export { FileBasedAuthCache, writeAuthCacheSnapshot } from './file-based-auth-cache.js';
|
|
5
|
+
export { FileBasedAuthCache, writeAuthCacheSnapshot, writeAuthSnapshot, type AuthCacheSnapshot, } from './file-based-auth-cache.js';
|
|
6
6
|
export { CachingAuthPlugin } from './caching-auth-plugin.js';
|
package/dist/auth/cache.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Server-only: these use node:fs/promises and must NOT reach a client bundle.
|
|
3
3
|
* Import them as 'canopycms/auth/cache'.
|
|
4
4
|
*/
|
|
5
|
-
export { FileBasedAuthCache, writeAuthCacheSnapshot } from './file-based-auth-cache.js';
|
|
5
|
+
export { FileBasedAuthCache, writeAuthCacheSnapshot, writeAuthSnapshot, } from './file-based-auth-cache.js';
|
|
6
6
|
export { CachingAuthPlugin } from './caching-auth-plugin.js';
|
|
@@ -38,6 +38,8 @@ export declare class CachingAuthPlugin implements AuthPlugin {
|
|
|
38
38
|
authenticate(context: unknown): Promise<AuthenticationResult>;
|
|
39
39
|
searchUsers(query: string, limit?: number): Promise<UserSearchResult[]>;
|
|
40
40
|
getUserMetadata(userId: CanopyUserId): Promise<UserSearchResult | null>;
|
|
41
|
+
/** One cache read for the whole set, where `getUserMetadata` per id re-stats the files each time. */
|
|
42
|
+
getUsersMetadata(userIds: CanopyUserId[]): Promise<UserSearchResult[]>;
|
|
41
43
|
getGroupMetadata(groupId: CanopyGroupId): Promise<GroupMetadata | null>;
|
|
42
44
|
listGroups(limit?: number): Promise<GroupMetadata[]>;
|
|
43
45
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createDebugLogger } from '../utils/debug.js';
|
|
2
|
+
import { personName } from './person-name.js';
|
|
2
3
|
const log = createDebugLogger({ prefix: 'CachingAuthPlugin' });
|
|
3
4
|
/**
|
|
4
5
|
* Wraps a token verifier with cached metadata lookups, for environments where
|
|
@@ -45,7 +46,7 @@ export class CachingAuthPlugin {
|
|
|
45
46
|
success: true,
|
|
46
47
|
user: {
|
|
47
48
|
userId: identity.userId,
|
|
48
|
-
name:
|
|
49
|
+
name: personName(identity.userId, user?.name),
|
|
49
50
|
email: user?.email,
|
|
50
51
|
avatarUrl: user?.avatarUrl,
|
|
51
52
|
externalGroups,
|
|
@@ -62,7 +63,6 @@ export class CachingAuthPlugin {
|
|
|
62
63
|
success: true,
|
|
63
64
|
user: {
|
|
64
65
|
userId: identity.userId,
|
|
65
|
-
name: identity.userId,
|
|
66
66
|
externalGroups: [],
|
|
67
67
|
},
|
|
68
68
|
};
|
|
@@ -88,6 +88,16 @@ export class CachingAuthPlugin {
|
|
|
88
88
|
return null;
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
+
/** One cache read for the whole set, where `getUserMetadata` per id re-stats the files each time. */
|
|
92
|
+
async getUsersMetadata(userIds) {
|
|
93
|
+
try {
|
|
94
|
+
const wanted = new Set(userIds);
|
|
95
|
+
return (await this.cache.getAllUsers()).filter((u) => wanted.has(u.id));
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
91
101
|
async getGroupMetadata(groupId) {
|
|
92
102
|
try {
|
|
93
103
|
return await this.cache.getGroup(groupId);
|
|
@@ -32,3 +32,11 @@ export declare class FileBasedAuthCache implements AuthCacheProvider {
|
|
|
32
32
|
* recent snapshot directories are kept.
|
|
33
33
|
*/
|
|
34
34
|
export declare function writeAuthCacheSnapshot(cachePath: string, files: Record<string, unknown>): Promise<string>;
|
|
35
|
+
/** One auth provider's users, groups and memberships: what an auth-cache refresh writes. */
|
|
36
|
+
export interface AuthCacheSnapshot {
|
|
37
|
+
users: UserSearchResult[];
|
|
38
|
+
groups: GroupMetadata[];
|
|
39
|
+
memberships: Record<CanopyUserId, CanopyGroupId[]>;
|
|
40
|
+
}
|
|
41
|
+
/** Write `snapshot` as the three files FileBasedAuthCache reads (users.json, orgs.json, memberships.json). */
|
|
42
|
+
export declare function writeAuthSnapshot(cachePath: string, snapshot: AuthCacheSnapshot): Promise<string>;
|
|
@@ -168,14 +168,13 @@ export async function writeAuthCacheSnapshot(cachePath, files) {
|
|
|
168
168
|
await fs.rename(tmpPath, finalPath);
|
|
169
169
|
}
|
|
170
170
|
// The symlink target MUST be relative (the bare `snapshot-<ts>` basename),
|
|
171
|
-
// because writer and reader
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
// was given, so it is correct from both.
|
|
171
|
+
// because writer and reader are separate hosts (in prod, the EC2 worker and
|
|
172
|
+
// the CMS Lambda) that each mount EFS themselves, so nothing guarantees they
|
|
173
|
+
// reach this directory by the same path. An absolute target recorded by one
|
|
174
|
+
// can be a nonexistent path to the other, and `resolveActiveCacheDir`'s
|
|
175
|
+
// escape guard then falls back to the flat layout, where the worker never
|
|
176
|
+
// writes, leaving the reader a permanently empty cache. A relative target
|
|
177
|
+
// resolves against whichever cachePath the reader was given.
|
|
179
178
|
const currentLink = path.join(cachePath, 'current');
|
|
180
179
|
const tmpLink = path.join(cachePath, `current-${timestamp}`);
|
|
181
180
|
await fs.symlink(path.basename(snapshotDir), tmpLink);
|
|
@@ -183,6 +182,17 @@ export async function writeAuthCacheSnapshot(cachePath, files) {
|
|
|
183
182
|
await cleanupOldSnapshots(cachePath, 2);
|
|
184
183
|
return snapshotDir;
|
|
185
184
|
}
|
|
185
|
+
/** Write `snapshot` as the three files FileBasedAuthCache reads (users.json, orgs.json, memberships.json). */
|
|
186
|
+
export async function writeAuthSnapshot(cachePath, snapshot) {
|
|
187
|
+
const users = { users: snapshot.users };
|
|
188
|
+
const groups = { groups: snapshot.groups };
|
|
189
|
+
const memberships = { memberships: snapshot.memberships };
|
|
190
|
+
return writeAuthCacheSnapshot(cachePath, {
|
|
191
|
+
'users.json': users,
|
|
192
|
+
'orgs.json': groups,
|
|
193
|
+
'memberships.json': memberships,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
186
196
|
async function cleanupOldSnapshots(cachePath, keepCount) {
|
|
187
197
|
let entries;
|
|
188
198
|
try {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The name to show for a person, or undefined when there is none. An id is an internal name
|
|
3
|
+
* (docs/ux-guidelines.md, "People"), so a name equal to the id is no name.
|
|
4
|
+
*/
|
|
5
|
+
export declare function personName(id: string, name: string | undefined): string | undefined;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The name to show for a person, or undefined when there is none. An id is an internal name
|
|
3
|
+
* (docs/ux-guidelines.md, "People"), so a name equal to the id is no name.
|
|
4
|
+
*/
|
|
5
|
+
export function personName(id, name) {
|
|
6
|
+
const trimmed = name?.trim();
|
|
7
|
+
return trimmed && trimmed !== id ? trimmed : undefined;
|
|
8
|
+
}
|
package/dist/auth/plugin.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export interface AuthPlugin {
|
|
|
14
14
|
* groups; core applies bootstrap admins.
|
|
15
15
|
*
|
|
16
16
|
* CREDENTIAL failures (missing, invalid or expired token) RESOLVE to
|
|
17
|
-
* `{ success: false }` and map to
|
|
17
|
+
* `{ success: false }` and map to `unauthenticatedStatus` (default 401). CONFIGURATION errors (an absent
|
|
18
18
|
* CLERK_SECRET_KEY, say) may THROW instead: they are operator mistakes, and
|
|
19
19
|
* belong in a loud 500 rather than a quiet auth denial. A custom adapter
|
|
20
20
|
* calling this directly must be ready for that rejection.
|
|
@@ -23,6 +23,15 @@ export interface AuthPlugin {
|
|
|
23
23
|
/** For the permission-management UI. */
|
|
24
24
|
searchUsers(query: string, limit?: number): Promise<UserSearchResult[]>;
|
|
25
25
|
getUserMetadata(userId: CanopyUserId): Promise<UserSearchResult | null>;
|
|
26
|
+
/**
|
|
27
|
+
* Looks up many users in as few provider calls as possible, resolving to the users found, in
|
|
28
|
+
* any order; unknown ids are omitted. Core never passes more than 100 ids at once. Without
|
|
29
|
+
* it, core falls back to concurrent `getUserMetadata` calls, a few at a time.
|
|
30
|
+
*
|
|
31
|
+
* Reject on a provider failure rather than omitting ids: core caches an omitted id as unknown,
|
|
32
|
+
* as it does a `null` from the `getUserMetadata` fallback.
|
|
33
|
+
*/
|
|
34
|
+
getUsersMetadata?(userIds: CanopyUserId[]): Promise<UserSearchResult[]>;
|
|
26
35
|
getGroupMetadata(groupId: CanopyGroupId): Promise<GroupMetadata | null>;
|
|
27
36
|
/** For permission UI dropdowns. */
|
|
28
37
|
listGroups(limit?: number): Promise<GroupMetadata[]>;
|
package/dist/auth/types.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export interface UserSearchResult {
|
|
|
6
6
|
email: string;
|
|
7
7
|
avatarUrl?: string;
|
|
8
8
|
}
|
|
9
|
+
/** What a reader who is not privileged may learn about another user: never the email. */
|
|
10
|
+
export type UserProfile = Pick<UserSearchResult, 'id' | 'name' | 'avatarUrl'>;
|
|
9
11
|
/** Group metadata for the permission UI. */
|
|
10
12
|
export interface GroupMetadata {
|
|
11
13
|
id: CanopyGroupId;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AuthPlugin } from './plugin.js';
|
|
2
|
+
import type { UserProfile, UserSearchResult } from './types.js';
|
|
3
|
+
import type { CanopyUserId } from '../types.js';
|
|
4
|
+
/**
|
|
5
|
+
* How long a looked-up user, or the fact that an id is unknown, is served without asking again.
|
|
6
|
+
* @internal Exported for tests.
|
|
7
|
+
*/
|
|
8
|
+
export declare const USER_METADATA_TTL_MS: number;
|
|
9
|
+
/**
|
|
10
|
+
* Resolves each id to its user, or `null` when the provider does not know it. Unknown ids are
|
|
11
|
+
* cached like found ones, so a stale id in permissions.json costs a process one provider call
|
|
12
|
+
* per TTL. A rejection caches nothing; a `getUserMetadata` that answers `null` on failure is
|
|
13
|
+
* cached as unknown.
|
|
14
|
+
*/
|
|
15
|
+
export declare function lookupUsersMetadata(plugin: AuthPlugin, userIds: readonly CanopyUserId[]): Promise<Map<CanopyUserId, UserSearchResult | null>>;
|
|
16
|
+
/**
|
|
17
|
+
* The name and avatar of each id a response may show to any reader, never the email. Callers pass
|
|
18
|
+
* only ids the requester can already see. Non-string, empty, oversized, bot and anonymous ids are
|
|
19
|
+
* skipped: the editor labels bots and the anonymous user without a lookup. Unknown ids are absent.
|
|
20
|
+
*/
|
|
21
|
+
export declare function lookupUserProfiles(plugin: AuthPlugin, ids: Iterable<unknown>): Promise<UserProfile[]>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { LRUCache } from 'lru-cache';
|
|
2
|
+
import { CachingAuthPlugin } from './caching-auth-plugin.js';
|
|
3
|
+
import { MAX_USER_METADATA_BATCH } from '../api/users-constants.js';
|
|
4
|
+
import { isSystemUserId } from '../system-users.js';
|
|
5
|
+
import { ANONYMOUS_USER } from '../user.js';
|
|
6
|
+
import { personName } from './person-name.js';
|
|
7
|
+
/**
|
|
8
|
+
* How long a looked-up user, or the fact that an id is unknown, is served without asking again.
|
|
9
|
+
* @internal Exported for tests.
|
|
10
|
+
*/
|
|
11
|
+
export const USER_METADATA_TTL_MS = 5 * 60 * 1000;
|
|
12
|
+
const MAX_CACHED_USERS = 5000;
|
|
13
|
+
/** Concurrent `getUserMetadata` calls for a plugin without `getUsersMetadata`. */
|
|
14
|
+
const SINGLE_LOOKUP_CONCURRENCY = 8;
|
|
15
|
+
/**
|
|
16
|
+
* Per-process, in-memory, never persisted: each process keeps its own copy, so a changed name or
|
|
17
|
+
* avatar shows everywhere within one TTL. Keyed by plugin so two plugins never share answers.
|
|
18
|
+
*/
|
|
19
|
+
const caches = new WeakMap();
|
|
20
|
+
function cacheFor(plugin) {
|
|
21
|
+
let cache = caches.get(plugin);
|
|
22
|
+
if (!cache) {
|
|
23
|
+
cache = new LRUCache({ max: MAX_CACHED_USERS, ttl: USER_METADATA_TTL_MS });
|
|
24
|
+
caches.set(plugin, cache);
|
|
25
|
+
}
|
|
26
|
+
return cache;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Resolves each id to its user, or `null` when the provider does not know it. Unknown ids are
|
|
30
|
+
* cached like found ones, so a stale id in permissions.json costs a process one provider call
|
|
31
|
+
* per TTL. A rejection caches nothing; a `getUserMetadata` that answers `null` on failure is
|
|
32
|
+
* cached as unknown.
|
|
33
|
+
*/
|
|
34
|
+
export async function lookupUsersMetadata(plugin, userIds) {
|
|
35
|
+
const unique = [...new Set(userIds)];
|
|
36
|
+
// Answered from an in-memory copy of the worker-written file cache; a TTL on top would only
|
|
37
|
+
// delay the worker's refreshes. canopycms-next wraps every plugin with `verifyTokenOnly`.
|
|
38
|
+
if (plugin instanceof CachingAuthPlugin)
|
|
39
|
+
return fetchFromPlugin(plugin, unique);
|
|
40
|
+
const cache = cacheFor(plugin);
|
|
41
|
+
const result = new Map();
|
|
42
|
+
const missing = [];
|
|
43
|
+
for (const id of unique) {
|
|
44
|
+
const hit = cache.get(id);
|
|
45
|
+
if (hit)
|
|
46
|
+
result.set(id, hit.user);
|
|
47
|
+
else
|
|
48
|
+
missing.push(id);
|
|
49
|
+
}
|
|
50
|
+
if (missing.length === 0)
|
|
51
|
+
return result;
|
|
52
|
+
const fetched = await fetchFromPlugin(plugin, missing);
|
|
53
|
+
for (const [id, user] of fetched) {
|
|
54
|
+
cache.set(id, { user });
|
|
55
|
+
result.set(id, user);
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
/** Every lookup answers with the same name the editor shows: blank or id-equal names become ''. */
|
|
60
|
+
const withPersonName = (user) => user && { ...user, name: personName(user.id, user.name) ?? '' };
|
|
61
|
+
async function fetchFromPlugin(plugin, ids) {
|
|
62
|
+
const result = new Map(ids.map((id) => [id, null]));
|
|
63
|
+
const getUsersMetadata = plugin.getUsersMetadata?.bind(plugin);
|
|
64
|
+
if (getUsersMetadata) {
|
|
65
|
+
for (let i = 0; i < ids.length; i += MAX_USER_METADATA_BATCH) {
|
|
66
|
+
const users = await getUsersMetadata(ids.slice(i, i + MAX_USER_METADATA_BATCH));
|
|
67
|
+
// A provider answering for an id nobody asked about must not plant it in the cache.
|
|
68
|
+
for (const user of users)
|
|
69
|
+
if (result.has(user.id))
|
|
70
|
+
result.set(user.id, withPersonName(user));
|
|
71
|
+
}
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
let next = 0;
|
|
75
|
+
const worker = async () => {
|
|
76
|
+
while (next < ids.length) {
|
|
77
|
+
const id = ids[next++];
|
|
78
|
+
result.set(id, withPersonName(await plugin.getUserMetadata(id)));
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
await Promise.all(Array.from({ length: Math.min(SINGLE_LOOKUP_CONCURRENCY, ids.length) }, worker));
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
/** Matches the id bound `/users/batch` accepts; ids read from stored JSON are unvalidated. */
|
|
85
|
+
const MAX_USER_ID_LENGTH = 256;
|
|
86
|
+
/**
|
|
87
|
+
* The name and avatar of each id a response may show to any reader, never the email. Callers pass
|
|
88
|
+
* only ids the requester can already see. Non-string, empty, oversized, bot and anonymous ids are
|
|
89
|
+
* skipped: the editor labels bots and the anonymous user without a lookup. Unknown ids are absent.
|
|
90
|
+
*/
|
|
91
|
+
export async function lookupUserProfiles(plugin, ids) {
|
|
92
|
+
const wanted = new Set();
|
|
93
|
+
for (const id of ids) {
|
|
94
|
+
if (typeof id === 'string' &&
|
|
95
|
+
id.length > 0 &&
|
|
96
|
+
id.length <= MAX_USER_ID_LENGTH &&
|
|
97
|
+
id !== ANONYMOUS_USER.userId &&
|
|
98
|
+
!isSystemUserId(id)) {
|
|
99
|
+
wanted.add(id);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (wanted.size === 0)
|
|
103
|
+
return [];
|
|
104
|
+
const found = await lookupUsersMetadata(plugin, [...wanted]);
|
|
105
|
+
const profiles = [];
|
|
106
|
+
// Built field by field: a provider's user record carries an email, which a profile never does.
|
|
107
|
+
for (const [id, user] of found) {
|
|
108
|
+
// A record for some other id (a provider resolving an alias) names someone nobody asked about.
|
|
109
|
+
if (user === null || user.id !== id)
|
|
110
|
+
continue;
|
|
111
|
+
profiles.push(user.avatarUrl === undefined
|
|
112
|
+
? { id: user.id, name: user.name }
|
|
113
|
+
: { id: user.id, name: user.name, avatarUrl: user.avatarUrl });
|
|
114
|
+
}
|
|
115
|
+
return profiles;
|
|
116
|
+
}
|
|
@@ -50,7 +50,7 @@ export declare function createCheckBranchAccess(defaultAccess?: DefaultBranchAcc
|
|
|
50
50
|
export interface WorkflowActionOptions {
|
|
51
51
|
/**
|
|
52
52
|
* When true, disables the system-branch grant below. The protected base
|
|
53
|
-
* branch is auto-provisioned with `createdBy:
|
|
53
|
+
* branch is auto-provisioned with `createdBy: SYSTEM_USER_ID`, which
|
|
54
54
|
* would otherwise let anyone with general branch access submit/withdraw it
|
|
55
55
|
* -- pass `getBranchProtection(...).isProtected` here so only
|
|
56
56
|
* admins/reviewers/explicit-ACL users retain workflow rights on it.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { isAdmin, isReviewer } from './helpers.js';
|
|
1
|
+
import { isAdmin, isLockedOutOfBranch, isReviewer } from './helpers.js';
|
|
2
2
|
import { getBranchProtection } from './protected-branch.js';
|
|
3
|
+
import { SYSTEM_USER_ID } from '../system-users.js';
|
|
3
4
|
/**
|
|
4
5
|
* Check if user has access to a branch with explicit default behavior.
|
|
5
6
|
*
|
|
@@ -18,20 +19,18 @@ export function checkBranchAccessWithDefault(context, user, defaultAccess = 'den
|
|
|
18
19
|
return { allowed: true, reason: 'privileged' };
|
|
19
20
|
}
|
|
20
21
|
const access = context.branch.access;
|
|
21
|
-
|
|
22
|
-
const hasGroupConstraint = !!access.allowedGroups?.length;
|
|
23
|
-
const managerOrAdminAllowed = access.managerOrAdminAllowed ?? false;
|
|
24
|
-
if (!hasUserConstraint && !hasGroupConstraint && managerOrAdminAllowed) {
|
|
22
|
+
if (isLockedOutOfBranch(access, user.groups)) {
|
|
25
23
|
return { allowed: false, reason: 'denied_by_acl' };
|
|
26
24
|
}
|
|
25
|
+
const hasUserConstraint = !!access.allowedUsers?.length;
|
|
26
|
+
const hasGroupConstraint = !!access.allowedGroups?.length;
|
|
27
27
|
if (!hasUserConstraint && !hasGroupConstraint) {
|
|
28
|
-
// The branch creator owns their own un-ACL'd branch,
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
// an admin locks down a branch someone else created.
|
|
28
|
+
// The branch creator owns their own un-ACL'd branch, as listBranchesHandler,
|
|
29
|
+
// canDeleteBranch and canModifyBranchAccess also grant: without it, under
|
|
30
|
+
// 'deny' a creator could delete their branch and rewrite its ACL but not
|
|
31
|
+
// read a file on it. Scoped to the no-ACL case on purpose -- an EXPLICIT
|
|
32
|
+
// allowlist omitting the creator still denies them, which is how an admin
|
|
33
|
+
// locks down a branch someone else created.
|
|
35
34
|
if (context.branch.createdBy === user.userId) {
|
|
36
35
|
return { allowed: true, reason: 'creator' };
|
|
37
36
|
}
|
|
@@ -80,7 +79,7 @@ export function canPerformWorkflowAction(context, user, defaultAccess = 'deny',
|
|
|
80
79
|
return false;
|
|
81
80
|
}
|
|
82
81
|
const userIsCreator = context.branch.createdBy === user.userId;
|
|
83
|
-
const isSystemBranch = !options?.isProtectedBranch && context.branch.createdBy ===
|
|
82
|
+
const isSystemBranch = !options?.isProtectedBranch && context.branch.createdBy === SYSTEM_USER_ID;
|
|
84
83
|
return (userIsCreator ||
|
|
85
84
|
accessResult.reason === 'privileged' ||
|
|
86
85
|
accessResult.reason === 'allowed_by_acl' ||
|
|
@@ -15,21 +15,21 @@ export declare const GroupsFileSchema: z.ZodObject<{
|
|
|
15
15
|
members: z.ZodArray<z.ZodType<string, z.ZodTypeDef, string>, "many">;
|
|
16
16
|
}, "strip", z.ZodTypeAny, {
|
|
17
17
|
name: string;
|
|
18
|
-
members: string[];
|
|
19
18
|
id: string;
|
|
19
|
+
members: string[];
|
|
20
20
|
description?: string | undefined;
|
|
21
21
|
}, {
|
|
22
22
|
name: string;
|
|
23
|
-
members: string[];
|
|
24
23
|
id: string;
|
|
24
|
+
members: string[];
|
|
25
25
|
description?: string | undefined;
|
|
26
26
|
}>, "many">;
|
|
27
27
|
}, "strip", z.ZodTypeAny, {
|
|
28
28
|
updatedAt: string;
|
|
29
29
|
groups: {
|
|
30
30
|
name: string;
|
|
31
|
-
members: string[];
|
|
32
31
|
id: string;
|
|
32
|
+
members: string[];
|
|
33
33
|
description?: string | undefined;
|
|
34
34
|
}[];
|
|
35
35
|
updatedBy: string;
|
|
@@ -39,8 +39,8 @@ export declare const GroupsFileSchema: z.ZodObject<{
|
|
|
39
39
|
updatedAt: string;
|
|
40
40
|
groups: {
|
|
41
41
|
name: string;
|
|
42
|
-
members: string[];
|
|
43
42
|
id: string;
|
|
43
|
+
members: string[];
|
|
44
44
|
description?: string | undefined;
|
|
45
45
|
}[];
|
|
46
46
|
updatedBy: string;
|
|
@@ -29,3 +29,11 @@ export declare function isAdmin(groups: readonly string[] | undefined): boolean;
|
|
|
29
29
|
export declare function isReviewer(groups: readonly string[] | undefined): boolean;
|
|
30
30
|
/** For operations that need elevated rights but not full admin. */
|
|
31
31
|
export declare function isPrivileged(groups: readonly string[] | undefined): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Whether a branch's `managerOrAdminAllowed` lockdown shuts this user out. The lockdown is a
|
|
34
|
+
* ceiling over everything else that grants branch access -- the ACL, the creator, the default --
|
|
35
|
+
* so only Admins and Reviewers pass it. Dependency-free, so the editor's gating shares it.
|
|
36
|
+
*/
|
|
37
|
+
export declare function isLockedOutOfBranch(access: {
|
|
38
|
+
managerOrAdminAllowed?: boolean;
|
|
39
|
+
} | undefined, groups: readonly string[] | undefined): boolean;
|
|
@@ -38,3 +38,11 @@ export function isReviewer(groups) {
|
|
|
38
38
|
export function isPrivileged(groups) {
|
|
39
39
|
return isReviewer(groups);
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Whether a branch's `managerOrAdminAllowed` lockdown shuts this user out. The lockdown is a
|
|
43
|
+
* ceiling over everything else that grants branch access -- the ACL, the creator, the default --
|
|
44
|
+
* so only Admins and Reviewers pass it. Dependency-free, so the editor's gating shares it.
|
|
45
|
+
*/
|
|
46
|
+
export function isLockedOutOfBranch(access, groups) {
|
|
47
|
+
return (access?.managerOrAdminAllowed ?? false) && !isPrivileged(groups);
|
|
48
|
+
}
|
|
@@ -9,7 +9,7 @@ export { checkContentAccess, createCheckContentAccess, createContentAccessChecke
|
|
|
9
9
|
export { checkBranchAccessWithDefault, createCheckBranchAccess, canPerformWorkflowAction, } from './branch.js';
|
|
10
10
|
export { getBranchProtection, getBranchWriteProtection, type BranchProtection, type BranchWriteProtection, } from './protected-branch.js';
|
|
11
11
|
export { checkPathAccess, createCheckPathAccess, resolveDefaultPathAccess } from './path.js';
|
|
12
|
-
export { RESERVED_GROUPS, type ReservedGroupId, isReservedGroup, stripReservedGroups, isAdmin, isReviewer, isPrivileged, } from './helpers.js';
|
|
12
|
+
export { RESERVED_GROUPS, type ReservedGroupId, isReservedGroup, stripReservedGroups, isAdmin, isReviewer, isPrivileged, isLockedOutOfBranch, } from './helpers.js';
|
|
13
13
|
export { PermissionsFileSchema, createDefaultPermissionsFile, type PermissionsFile, loadPermissionsFile, loadPathPermissions, mutatePermissionsFile, ensurePermissionsFile, } from './permissions/index.js';
|
|
14
14
|
export { GroupsFileSchema, createDefaultGroupsFile, type GroupsFile, type InternalGroup, loadGroupsFile, loadInternalGroups, deriveInternalGroups, mutateGroupsFile, } from './groups/index.js';
|
|
15
15
|
export { mutateSettingsJsonFile, SettingsFileConflictError, SettingsVersionConflictError, type MutateSettingsFileOptions, } from './settings-file-store.js';
|
|
@@ -8,7 +8,7 @@ export { checkContentAccess, createCheckContentAccess, createContentAccessChecke
|
|
|
8
8
|
export { checkBranchAccessWithDefault, createCheckBranchAccess, canPerformWorkflowAction, } from './branch.js';
|
|
9
9
|
export { getBranchProtection, getBranchWriteProtection, } from './protected-branch.js';
|
|
10
10
|
export { checkPathAccess, createCheckPathAccess, resolveDefaultPathAccess } from './path.js';
|
|
11
|
-
export { RESERVED_GROUPS, isReservedGroup, stripReservedGroups, isAdmin, isReviewer, isPrivileged, } from './helpers.js';
|
|
11
|
+
export { RESERVED_GROUPS, isReservedGroup, stripReservedGroups, isAdmin, isReviewer, isPrivileged, isLockedOutOfBranch, } from './helpers.js';
|
|
12
12
|
export { PermissionsFileSchema, createDefaultPermissionsFile, loadPermissionsFile, loadPathPermissions, mutatePermissionsFile, ensurePermissionsFile, } from './permissions/index.js';
|
|
13
13
|
export { GroupsFileSchema, createDefaultGroupsFile, loadGroupsFile, loadInternalGroups, deriveInternalGroups, mutateGroupsFile, } from './groups/index.js';
|
|
14
14
|
export { mutateSettingsJsonFile, SettingsFileConflictError, SettingsVersionConflictError, } from './settings-file-store.js';
|
|
@@ -76,9 +76,10 @@ export declare function getBranchProtection(config: Pick<CanopyConfig, 'mode' |
|
|
|
76
76
|
* branches-list wire flag and the editor.
|
|
77
77
|
*
|
|
78
78
|
* `status` is REQUIRED and admits `undefined` because a missing status must
|
|
79
|
-
* FAIL CLOSED
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
79
|
+
* FAIL CLOSED. A branch.json without one never gets this far (its read
|
|
80
|
+
* boundary, branch-metadata-file.ts, rejects it as corrupt), but a status can
|
|
81
|
+
* still arrive unset from a context built anywhere else. Required, not
|
|
82
|
+
* optional, so "argument omitted" and "status unknown" stay distinguishable --
|
|
83
|
+
* the safe answer differs.
|
|
83
84
|
*/
|
|
84
85
|
export declare function getBranchWriteProtection(config: Pick<CanopyConfig, 'mode' | 'defaultBaseBranch'>, branchName: string, recordedBaseBranch: string | undefined, status: BranchStatus | undefined): BranchWriteProtection;
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
// api/guards.ts → here), and paths/branch.ts drags node:fs into the graph,
|
|
12
12
|
// which breaks adopters' production `next build`.
|
|
13
13
|
import { sanitizeBranchName } from '../paths/branch-name.js';
|
|
14
|
+
import { baseBranchOf } from '../utils/base-branch.js';
|
|
14
15
|
/**
|
|
15
16
|
* Whether `branchName` is the protected base branch for `config`.
|
|
16
17
|
*
|
|
@@ -32,7 +33,7 @@ import { sanitizeBranchName } from '../paths/branch-name.js';
|
|
|
32
33
|
*/
|
|
33
34
|
export function getBranchProtection(config, branchName, recordedBaseBranch) {
|
|
34
35
|
const sanitizedName = sanitizeBranchName(branchName);
|
|
35
|
-
const isProtected = sanitizedName === sanitizeBranchName(config
|
|
36
|
+
const isProtected = sanitizedName === sanitizeBranchName(baseBranchOf(config)) ||
|
|
36
37
|
(recordedBaseBranch !== undefined && sanitizedName === sanitizeBranchName(recordedBaseBranch));
|
|
37
38
|
return {
|
|
38
39
|
isProtected,
|
|
@@ -47,10 +48,11 @@ export function getBranchProtection(config, branchName, recordedBaseBranch) {
|
|
|
47
48
|
* branches-list wire flag and the editor.
|
|
48
49
|
*
|
|
49
50
|
* `status` is REQUIRED and admits `undefined` because a missing status must
|
|
50
|
-
* FAIL CLOSED
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
51
|
+
* FAIL CLOSED. A branch.json without one never gets this far (its read
|
|
52
|
+
* boundary, branch-metadata-file.ts, rejects it as corrupt), but a status can
|
|
53
|
+
* still arrive unset from a context built anywhere else. Required, not
|
|
54
|
+
* optional, so "argument omitted" and "status unknown" stay distinguishable --
|
|
55
|
+
* the safe answer differs.
|
|
54
56
|
*/
|
|
55
57
|
export function getBranchWriteProtection(config, branchName, recordedBaseBranch, status) {
|
|
56
58
|
const protection = getBranchProtection(config, branchName, recordedBaseBranch);
|