canopycms 0.0.67-int.90 → 0.0.67
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/README.md +30 -3
- package/dist/ai/generate.js +1 -27
- package/dist/ai/handler.d.ts +0 -4
- package/dist/ai/handler.js +0 -11
- package/dist/ai/index.d.ts +1 -8
- package/dist/ai/index.js +1 -8
- package/dist/ai/json-to-markdown.js +15 -58
- package/dist/ai/resolve-branch.d.ts +2 -7
- package/dist/ai/resolve-branch.js +2 -8
- package/dist/ai/strip-mdx.d.ts +5 -13
- package/dist/ai/strip-mdx.js +5 -17
- package/dist/ai/to-plain-text.d.ts +10 -28
- package/dist/ai/to-plain-text.js +10 -28
- package/dist/ai/transform-components.d.ts +2 -4
- package/dist/ai/transform-components.js +8 -19
- package/dist/ai/types.d.ts +5 -10
- package/dist/api/admin-branch-health.d.ts +4 -12
- package/dist/api/admin-branch-health.js +26 -66
- package/dist/api/admin.d.ts +4 -12
- package/dist/api/admin.js +10 -26
- package/dist/api/assets.d.ts +0 -25
- package/dist/api/assets.js +50 -91
- package/dist/api/branch-merge.d.ts +1 -1
- package/dist/api/branch-merge.js +0 -2
- package/dist/api/branch-review.d.ts +0 -8
- package/dist/api/branch-review.js +0 -13
- package/dist/api/branch-status.d.ts +0 -3
- package/dist/api/branch-status.js +8 -33
- package/dist/api/branch-withdraw.d.ts +0 -1
- package/dist/api/branch-withdraw.js +6 -9
- package/dist/api/branch.d.ts +7 -12
- package/dist/api/branch.js +7 -44
- package/dist/api/client.d.ts +71 -224
- package/dist/api/client.js +82 -233
- package/dist/api/comments.d.ts +2 -4
- package/dist/api/comments.js +0 -17
- package/dist/api/content.d.ts +0 -6
- package/dist/api/content.js +66 -142
- package/dist/api/entries-constants.d.ts +5 -9
- package/dist/api/entries-constants.js +5 -9
- package/dist/api/entries.d.ts +8 -13
- package/dist/api/entries.js +20 -51
- package/dist/api/github-sync.d.ts +2 -4
- package/dist/api/github-sync.js +4 -8
- package/dist/api/groups.d.ts +3 -0
- package/dist/api/groups.js +8 -21
- package/dist/api/guards.d.ts +4 -16
- package/dist/api/guards.js +3 -22
- package/dist/api/index.d.ts +4 -4
- package/dist/api/permissions.d.ts +2 -0
- package/dist/api/permissions.js +18 -40
- package/dist/api/reference-options.d.ts +0 -1
- package/dist/api/reference-options.js +3 -11
- package/dist/api/request-body-hash.d.ts +12 -23
- package/dist/api/request-body-hash.js +12 -23
- package/dist/api/resolve-references.d.ts +0 -1
- package/dist/api/resolve-references.js +13 -28
- package/dist/api/route-builder.d.ts +3 -7
- package/dist/api/route-builder.js +1 -1
- package/dist/api/routes.d.ts +12 -0
- package/dist/api/routes.js +47 -0
- package/dist/api/schema.d.ts +23 -33
- package/dist/api/schema.js +20 -74
- package/dist/api/settings-helpers.js +4 -5
- package/dist/api/types.d.ts +0 -5
- package/dist/api/user.js +0 -5
- package/dist/api/validators.d.ts +14 -52
- package/dist/api/validators.js +14 -52
- package/dist/assets/asset-prefixes.d.ts +4 -8
- package/dist/assets/asset-prefixes.js +4 -8
- package/dist/assets/asset-src.d.ts +5 -22
- package/dist/assets/asset-src.js +5 -21
- package/dist/assets/factory.d.ts +1 -2
- package/dist/assets/factory.js +1 -2
- package/dist/assets/finalize.d.ts +3 -1
- package/dist/assets/finalize.js +3 -1
- package/dist/assets/index.d.ts +3 -3
- package/dist/assets/index.js +1 -1
- package/dist/assets/keys.d.ts +5 -3
- package/dist/assets/keys.js +6 -3
- package/dist/assets/pipeline.d.ts +3 -2
- package/dist/assets/pipeline.js +22 -56
- package/dist/assets/sharp-loader.d.ts +2 -10
- package/dist/assets/sharp-loader.js +2 -10
- package/dist/assets/store-local.d.ts +1 -2
- package/dist/assets/store-local.js +1 -2
- package/dist/assets/store-s3.d.ts +3 -4
- package/dist/assets/svg-sanitizer.d.ts +6 -14
- package/dist/assets/svg-sanitizer.js +6 -14
- package/dist/assets/transform-directives.d.ts +3 -4
- package/dist/assets/transform-directives.js +1 -1
- package/dist/assets/transform.d.ts +19 -30
- package/dist/assets/transform.js +18 -31
- package/dist/auth/cache.d.ts +2 -3
- package/dist/auth/cache.js +2 -3
- package/dist/auth/caching-auth-plugin.d.ts +11 -22
- package/dist/auth/caching-auth-plugin.js +12 -14
- package/dist/auth/context-helpers.d.ts +6 -20
- package/dist/auth/context-helpers.js +5 -17
- package/dist/auth/file-based-auth-cache.d.ts +10 -21
- package/dist/auth/file-based-auth-cache.js +23 -51
- package/dist/auth/plugin.d.ts +29 -61
- package/dist/auth/plugin.js +9 -13
- package/dist/auth/types.d.ts +11 -20
- package/dist/authorization/branch.d.ts +30 -49
- package/dist/authorization/branch.js +16 -42
- package/dist/authorization/content.d.ts +11 -40
- package/dist/authorization/content.js +13 -45
- package/dist/authorization/groups/index.d.ts +0 -3
- package/dist/authorization/groups/index.js +0 -3
- package/dist/authorization/groups/loader.d.ts +14 -28
- package/dist/authorization/groups/loader.js +14 -38
- package/dist/authorization/groups/schema.d.ts +0 -6
- package/dist/authorization/groups/schema.js +4 -7
- package/dist/authorization/helpers.d.ts +9 -28
- package/dist/authorization/helpers.js +9 -28
- package/dist/authorization/index.d.ts +3 -25
- package/dist/authorization/index.js +3 -35
- package/dist/authorization/path.d.ts +6 -13
- package/dist/authorization/path.js +8 -25
- package/dist/authorization/permissions/index.d.ts +0 -3
- package/dist/authorization/permissions/index.js +0 -3
- package/dist/authorization/permissions/loader.d.ts +14 -27
- package/dist/authorization/permissions/loader.js +14 -32
- package/dist/authorization/permissions/schema.d.ts +1 -6
- package/dist/authorization/permissions/schema.js +6 -13
- package/dist/authorization/protected-branch.d.ts +36 -65
- package/dist/authorization/protected-branch.js +29 -41
- package/dist/authorization/settings-file-store.d.ts +38 -81
- package/dist/authorization/settings-file-store.js +38 -79
- package/dist/authorization/types.d.ts +4 -26
- package/dist/authorization/types.js +0 -6
- package/dist/authorization/validation.d.ts +1 -23
- package/dist/authorization/validation.js +1 -24
- package/dist/branch-health.d.ts +39 -67
- package/dist/branch-health.js +27 -43
- package/dist/branch-metadata-file.d.ts +16 -32
- package/dist/branch-metadata-file.js +13 -26
- package/dist/branch-metadata.d.ts +49 -80
- package/dist/branch-metadata.js +57 -87
- package/dist/branch-registry.d.ts +26 -64
- package/dist/branch-registry.js +44 -93
- package/dist/branch-schema-cache.d.ts +34 -124
- package/dist/branch-schema-cache.js +49 -155
- package/dist/branch-workspace.d.ts +4 -4
- package/dist/branch-workspace.js +15 -19
- package/dist/build/generate-ai-content.d.ts +1 -0
- package/dist/build/generate-ai-content.js +12 -25
- package/dist/build-canopy.d.ts +17 -27
- package/dist/build-canopy.js +16 -23
- package/dist/build-mode.d.ts +25 -27
- package/dist/build-mode.js +25 -29
- package/dist/cli/cli.d.ts +15 -26
- package/dist/cli/cli.js +601 -978
- package/dist/cli/generate-ai-content.js +351 -628
- package/dist/cli/github-app-manifest.d.ts +84 -0
- package/dist/cli/github-app-manifest.js +161 -0
- package/dist/cli/init-github-app.d.ts +110 -444
- package/dist/cli/init-github-app.js +236 -773
- package/dist/cli/init.js +39 -80
- package/dist/cli/migrate.d.ts +13 -10
- package/dist/cli/migrate.js +22 -30
- package/dist/cli/project-detect.d.ts +17 -31
- package/dist/cli/project-detect.js +31 -42
- package/dist/cli/project-root.d.ts +4 -11
- package/dist/cli/project-root.js +4 -11
- package/dist/cli/prompt.d.ts +10 -0
- package/dist/cli/prompt.js +67 -0
- package/dist/cli/sync.d.ts +0 -8
- package/dist/cli/sync.js +8 -28
- package/dist/cli/template-files/middleware.ts.template +15 -29
- package/dist/cli/templates.d.ts +2 -12
- package/dist/cli/templates.js +4 -4
- package/dist/client.d.ts +1 -1
- package/dist/comment-store.d.ts +32 -53
- package/dist/comment-store.js +32 -52
- package/dist/config/flatten.d.ts +0 -3
- package/dist/config/flatten.js +2 -12
- package/dist/config/helpers.js +2 -2
- package/dist/config/index.d.ts +2 -2
- package/dist/config/index.js +1 -4
- package/dist/config/schemas/collection.d.ts +0 -8
- package/dist/config/schemas/collection.js +0 -10
- package/dist/config/schemas/config.d.ts +6 -78
- package/dist/config/schemas/config.js +38 -54
- package/dist/config/schemas/field.d.ts +2 -242
- package/dist/config/schemas/field.js +9 -20
- package/dist/config/schemas/media.js +1 -1
- package/dist/config/schemas/permissions.js +0 -2
- package/dist/config/schemas/url.d.ts +5 -6
- package/dist/config/schemas/url.js +5 -6
- package/dist/config/types.d.ts +45 -33
- package/dist/config/types.js +0 -1
- package/dist/config.d.ts +1 -8
- package/dist/config.js +1 -9
- package/dist/content-id-index.d.ts +76 -188
- package/dist/content-id-index.js +79 -230
- package/dist/content-index-generation.d.ts +27 -48
- package/dist/content-index-generation.js +35 -84
- package/dist/content-index-registry.d.ts +15 -24
- package/dist/content-index-registry.js +5 -9
- package/dist/content-listing.d.ts +64 -107
- package/dist/content-listing.js +68 -118
- package/dist/content-reader.d.ts +20 -29
- package/dist/content-reader.js +10 -18
- package/dist/content-store.d.ts +210 -336
- package/dist/content-store.js +413 -657
- package/dist/content-tree.d.ts +44 -86
- package/dist/content-tree.js +26 -54
- package/dist/context.d.ts +67 -94
- package/dist/context.js +53 -72
- package/dist/dev-content-watcher.d.ts +18 -18
- package/dist/dev-content-watcher.js +41 -44
- package/dist/editor/BranchManager.d.ts +3 -6
- package/dist/editor/BranchManager.js +24 -44
- package/dist/editor/CanopyEditor.js +5 -2
- package/dist/editor/CommentsPanel.js +0 -2
- package/dist/editor/Editor.js +19 -76
- package/dist/editor/EditorAuthGate.d.ts +27 -0
- package/dist/editor/EditorAuthGate.js +140 -0
- package/dist/editor/EntryNavigator.js +0 -20
- package/dist/editor/FormRenderer.d.ts +1 -2
- package/dist/editor/FormRenderer.js +8 -23
- package/dist/editor/admin/SystemHealthPanel.js +20 -37
- package/dist/editor/admin/useSystemHealth.d.ts +2 -3
- package/dist/editor/admin/useSystemHealth.js +10 -12
- package/dist/editor/client-reference-resolver.d.ts +2 -5
- package/dist/editor/client-reference-resolver.js +2 -19
- package/dist/editor/comments/BranchComments.js +0 -4
- package/dist/editor/comments/EntryComments.js +0 -4
- package/dist/editor/comments/FieldWrapper.js +0 -4
- package/dist/editor/comments/InlineCommentThread.js +0 -2
- package/dist/editor/comments/ThreadCarousel.d.ts +0 -58
- package/dist/editor/comments/ThreadCarousel.js +0 -12
- package/dist/editor/components/EditorFooter.d.ts +0 -8
- package/dist/editor/components/EditorFooter.js +0 -5
- package/dist/editor/components/EditorHeader.d.ts +0 -31
- package/dist/editor/components/EditorHeader.js +21 -71
- package/dist/editor/components/EditorSidebar.d.ts +0 -19
- package/dist/editor/components/EditorSidebar.js +0 -16
- package/dist/editor/components/EntryCreateModal.d.ts +4 -4
- package/dist/editor/components/EntryCreateModal.js +7 -22
- package/dist/editor/components/RenameEntryModal.js +0 -4
- package/dist/editor/components/UserBadge.js +0 -10
- package/dist/editor/components/index.js +0 -2
- package/dist/editor/context/ApiClientContext.d.ts +8 -7
- package/dist/editor/context/ApiClientContext.js +39 -11
- package/dist/editor/context/AssetContext.d.ts +7 -17
- package/dist/editor/context/AssetContext.js +7 -17
- package/dist/editor/context/EditorIdentityContext.d.ts +13 -0
- package/dist/editor/context/EditorIdentityContext.js +7 -0
- package/dist/editor/context/EditorStateContext.d.ts +10 -41
- package/dist/editor/context/EditorStateContext.js +7 -23
- package/dist/editor/context/SWRProvider.d.ts +3 -6
- package/dist/editor/context/index.d.ts +1 -20
- package/dist/editor/context/index.js +1 -20
- package/dist/editor/editor-utils.d.ts +8 -47
- package/dist/editor/editor-utils.js +19 -72
- package/dist/editor/fields/BlockField.d.ts +2 -2
- package/dist/editor/fields/BlockField.js +1 -2
- package/dist/editor/fields/CodeField.d.ts +0 -1
- package/dist/editor/fields/CodeField.js +0 -1
- package/dist/editor/fields/DateTimeField.d.ts +15 -22
- package/dist/editor/fields/DateTimeField.js +17 -26
- package/dist/editor/fields/ImageField.d.ts +2 -2
- package/dist/editor/fields/ImageField.js +8 -14
- package/dist/editor/fields/InlineGroupField.d.ts +0 -1
- package/dist/editor/fields/InlineGroupField.js +0 -1
- package/dist/editor/fields/MarkdownField.d.ts +0 -1
- package/dist/editor/fields/MarkdownField.js +6 -11
- package/dist/editor/fields/MdxImageDialog.d.ts +1 -1
- package/dist/editor/fields/MdxImageDialog.js +0 -1
- package/dist/editor/fields/NumberField.d.ts +9 -19
- package/dist/editor/fields/NumberField.js +11 -22
- package/dist/editor/fields/NumberListField.d.ts +7 -10
- package/dist/editor/fields/NumberListField.js +7 -10
- package/dist/editor/fields/ObjectField.d.ts +5 -8
- package/dist/editor/fields/ObjectField.js +0 -1
- package/dist/editor/fields/ReferenceField.d.ts +1 -1
- package/dist/editor/fields/ReferenceField.js +11 -16
- package/dist/editor/fields/SelectField.d.ts +2 -2
- package/dist/editor/fields/SelectField.js +0 -1
- package/dist/editor/fields/StringListField.d.ts +0 -4
- package/dist/editor/fields/StringListField.js +4 -9
- package/dist/editor/fields/TextField.d.ts +0 -1
- package/dist/editor/fields/TextField.js +0 -1
- package/dist/editor/fields/ToggleField.d.ts +0 -1
- package/dist/editor/fields/ToggleField.js +0 -1
- package/dist/editor/fields/entry-link/EntryLinkContext.js +2 -4
- package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +0 -3
- package/dist/editor/fields/entry-link/InsertEntryLink.js +0 -4
- package/dist/editor/group-manager/ExternalGroupsTab.d.ts +0 -3
- package/dist/editor/group-manager/ExternalGroupsTab.js +0 -1
- package/dist/editor/group-manager/GroupCard.d.ts +0 -3
- package/dist/editor/group-manager/GroupForm.d.ts +0 -3
- package/dist/editor/group-manager/InternalGroupsTab.d.ts +0 -3
- package/dist/editor/group-manager/InternalGroupsTab.js +0 -2
- package/dist/editor/group-manager/MemberList.d.ts +0 -3
- package/dist/editor/group-manager/hooks/useExternalGroupSearch.d.ts +0 -3
- package/dist/editor/group-manager/hooks/useExternalGroupSearch.js +0 -3
- package/dist/editor/group-manager/hooks/useGroupState.d.ts +0 -3
- package/dist/editor/group-manager/hooks/useGroupState.js +0 -5
- package/dist/editor/group-manager/hooks/useUserSearch.d.ts +0 -3
- package/dist/editor/group-manager/hooks/useUserSearch.js +0 -3
- package/dist/editor/group-manager/index.d.ts +0 -6
- package/dist/editor/group-manager/index.js +0 -10
- package/dist/editor/group-manager/types.d.ts +2 -5
- package/dist/editor/group-manager/types.js +0 -3
- package/dist/editor/hooks/index.d.ts +6 -11
- package/dist/editor/hooks/index.js +6 -12
- package/dist/editor/hooks/useBranchActions.d.ts +0 -14
- package/dist/editor/hooks/useBranchActions.js +0 -22
- package/dist/editor/hooks/useBranchManager.d.ts +2 -48
- package/dist/editor/hooks/useBranchManager.js +4 -64
- package/dist/editor/hooks/useBranchesData.d.ts +7 -6
- package/dist/editor/hooks/useBranchesData.js +7 -6
- package/dist/editor/hooks/useCommentSystem.d.ts +0 -49
- package/dist/editor/hooks/useCommentSystem.js +1 -36
- package/dist/editor/hooks/useDraftManager.d.ts +2 -35
- package/dist/editor/hooks/useDraftManager.js +23 -64
- package/dist/editor/hooks/useEditorLayout.d.ts +0 -20
- package/dist/editor/hooks/useEditorLayout.js +0 -23
- package/dist/editor/hooks/useEntriesData.d.ts +1 -0
- package/dist/editor/hooks/useEntriesData.js +2 -3
- package/dist/editor/hooks/useEntryLinkResolution.d.ts +2 -2
- package/dist/editor/hooks/useEntryLinkResolution.js +2 -2
- package/dist/editor/hooks/useEntryManager.d.ts +2 -27
- package/dist/editor/hooks/useEntryManager.js +29 -78
- package/dist/editor/hooks/useGroupManager.d.ts +0 -21
- package/dist/editor/hooks/useGroupManager.js +0 -21
- package/dist/editor/hooks/usePermissionManager.d.ts +0 -20
- package/dist/editor/hooks/usePermissionManager.js +0 -20
- package/dist/editor/hooks/useReferenceResolution.d.ts +2 -33
- package/dist/editor/hooks/useReferenceResolution.js +1 -48
- package/dist/editor/hooks/useSchemaManager.d.ts +8 -27
- package/dist/editor/hooks/useSchemaManager.js +0 -19
- package/dist/editor/hooks/useUserContext.d.ts +2 -9
- package/dist/editor/hooks/useUserContext.js +10 -10
- package/dist/editor/hooks/useUserMetadata.d.ts +0 -2
- package/dist/editor/hooks/useUserMetadata.js +0 -3
- package/dist/editor/media/AssetCard.d.ts +0 -1
- package/dist/editor/media/AssetCard.js +1 -2
- package/dist/editor/media/CropStep.d.ts +0 -1
- package/dist/editor/media/CropStep.js +0 -1
- package/dist/editor/media/MediaLibrary.d.ts +1 -2
- package/dist/editor/media/MediaLibrary.js +1 -2
- package/dist/editor/media/MediaLibraryBody.d.ts +0 -1
- package/dist/editor/media/MediaLibraryBody.js +0 -1
- package/dist/editor/media/crop-math.d.ts +1 -1
- package/dist/editor/media/crop-math.js +1 -1
- package/dist/editor/permission-manager/GroupSelector.d.ts +0 -3
- package/dist/editor/permission-manager/PermissionEditor.d.ts +0 -4
- package/dist/editor/permission-manager/PermissionEditor.js +0 -1
- package/dist/editor/permission-manager/PermissionLevelBadge.d.ts +0 -7
- package/dist/editor/permission-manager/PermissionLevelBadge.js +0 -4
- package/dist/editor/permission-manager/PermissionTree.d.ts +0 -4
- package/dist/editor/permission-manager/UserSelector.d.ts +0 -3
- package/dist/editor/permission-manager/constants.d.ts +0 -3
- package/dist/editor/permission-manager/hooks/useGroupsAndUsers.d.ts +0 -3
- package/dist/editor/permission-manager/hooks/useGroupsAndUsers.js +0 -10
- package/dist/editor/permission-manager/hooks/usePermissionTree.d.ts +0 -14
- package/dist/editor/permission-manager/hooks/usePermissionTree.js +0 -11
- package/dist/editor/permission-manager/index.d.ts +0 -7
- package/dist/editor/permission-manager/index.js +0 -16
- package/dist/editor/permission-manager/types.d.ts +2 -12
- package/dist/editor/permission-manager/types.js +0 -3
- package/dist/editor/permission-manager/utils.d.ts +0 -28
- package/dist/editor/permission-manager/utils.js +9 -23
- package/dist/editor/preview-bridge.d.ts +5 -1
- package/dist/editor/preview-bridge.js +4 -4
- package/dist/editor/schema-editor/CollectionEditor.d.ts +0 -5
- package/dist/editor/schema-editor/CollectionEditor.js +9 -31
- package/dist/editor/schema-editor/EntryTypeEditor.d.ts +0 -6
- package/dist/editor/schema-editor/EntryTypeEditor.js +3 -24
- package/dist/editor/schema-editor/index.d.ts +0 -7
- package/dist/editor/schema-editor/index.js +0 -7
- package/dist/editor/utils/env.d.ts +3 -18
- package/dist/editor/utils/env.js +6 -25
- package/dist/entry-link-resolver.d.ts +13 -35
- package/dist/entry-link-resolver.js +20 -53
- package/dist/entry-schema-registry.d.ts +20 -60
- package/dist/entry-schema-registry.js +20 -69
- package/dist/entry-schema.d.ts +118 -223
- package/dist/entry-schema.js +46 -91
- package/dist/git-manager.d.ts +101 -200
- package/dist/git-manager.js +211 -384
- package/dist/github-service.d.ts +34 -75
- package/dist/github-service.js +37 -91
- package/dist/http/handler.d.ts +6 -37
- package/dist/http/handler.js +65 -120
- package/dist/http/router.d.ts +15 -32
- package/dist/http/router.js +34 -99
- package/dist/http/types.d.ts +15 -40
- package/dist/http/types.js +3 -7
- package/dist/id.d.ts +4 -10
- package/dist/id.js +4 -10
- package/dist/index.js +6 -9
- package/dist/operating-mode/client-safe-strategy.d.ts +7 -14
- package/dist/operating-mode/client-safe-strategy.js +8 -28
- package/dist/operating-mode/client-unsafe-strategy.d.ts +6 -16
- package/dist/operating-mode/client-unsafe-strategy.js +9 -34
- package/dist/operating-mode/client.d.ts +3 -10
- package/dist/operating-mode/client.js +3 -8
- package/dist/operating-mode/deployment-name-fixtures.d.ts +14 -18
- package/dist/operating-mode/deployment-name-fixtures.js +14 -18
- package/dist/operating-mode/deployment-name.d.ts +19 -29
- package/dist/operating-mode/deployment-name.js +29 -47
- package/dist/operating-mode/index.d.ts +4 -25
- package/dist/operating-mode/index.js +9 -31
- package/dist/operating-mode/mode-env.d.ts +32 -54
- package/dist/operating-mode/mode-env.js +36 -58
- package/dist/operating-mode/types.d.ts +24 -72
- package/dist/operating-mode/types.js +1 -7
- package/dist/paths/branch-name.d.ts +30 -40
- package/dist/paths/branch-name.js +30 -40
- package/dist/paths/branch.d.ts +4 -18
- package/dist/paths/branch.js +6 -22
- package/dist/paths/index.d.ts +2 -13
- package/dist/paths/index.js +3 -23
- package/dist/paths/normalize-server.d.ts +3 -15
- package/dist/paths/normalize-server.js +3 -15
- package/dist/paths/normalize.d.ts +13 -33
- package/dist/paths/normalize.js +13 -33
- package/dist/paths/resolve.d.ts +4 -17
- package/dist/paths/resolve.js +4 -22
- package/dist/paths/types.d.ts +12 -34
- package/dist/paths/types.js +5 -7
- package/dist/paths/validation.d.ts +22 -119
- package/dist/paths/validation.js +30 -148
- package/dist/reference-resolver.d.ts +0 -13
- package/dist/reference-resolver.js +0 -18
- package/dist/resolve-canopy-user.d.ts +16 -18
- package/dist/resolve-canopy-user.js +17 -26
- package/dist/resource-generation.d.ts +16 -25
- package/dist/resource-generation.js +34 -97
- package/dist/schema/meta-loader.d.ts +2 -14
- package/dist/schema/meta-loader.js +15 -64
- package/dist/schema/resolver.d.ts +1 -4
- package/dist/schema/resolver.js +1 -6
- package/dist/schema/schema-store-types.d.ts +0 -12
- package/dist/schema/schema-store.d.ts +61 -138
- package/dist/schema/schema-store.js +85 -282
- package/dist/schema/types.d.ts +0 -4
- package/dist/server.d.ts +62 -93
- package/dist/server.js +63 -94
- package/dist/services.d.ts +23 -47
- package/dist/services.js +55 -98
- package/dist/settings-workspace.d.ts +17 -30
- package/dist/settings-workspace.js +51 -81
- package/dist/static/index.d.ts +26 -52
- package/dist/static/index.js +33 -67
- package/dist/{worker/task-queue.d.ts → task-queue/cms-task-queue.d.ts} +7 -9
- package/dist/task-queue/cms-task-queue.js +13 -0
- package/dist/task-queue/task-queue-config.d.ts +3 -0
- package/dist/{worker → task-queue}/task-queue-config.js +1 -6
- package/dist/task-queue/task-queue.d.ts +16 -22
- package/dist/task-queue/task-queue.js +20 -44
- package/dist/task-queue/types.d.ts +0 -1
- package/dist/task-queue/worker-status.d.ts +35 -0
- package/dist/task-queue/worker-status.js +40 -0
- package/dist/types.d.ts +40 -51
- package/dist/url-collision.d.ts +26 -40
- package/dist/url-collision.js +47 -63
- package/dist/url-exclusivity-fixtures.d.ts +15 -20
- package/dist/url-exclusivity-fixtures.js +14 -19
- package/dist/url-path-resolver.d.ts +8 -16
- package/dist/url-path-resolver.js +19 -29
- package/dist/user.d.ts +8 -21
- package/dist/user.js +10 -19
- package/dist/utils/async-mutex.js +4 -6
- package/dist/utils/atomic-write.d.ts +2 -11
- package/dist/utils/atomic-write.js +2 -11
- package/dist/utils/body-field.d.ts +8 -15
- package/dist/utils/body-field.js +8 -15
- package/dist/utils/content-serialize.d.ts +18 -24
- package/dist/utils/content-serialize.js +109 -160
- package/dist/utils/content-write-lock.d.ts +51 -106
- package/dist/utils/content-write-lock.js +66 -111
- package/dist/utils/debug.d.ts +7 -23
- package/dist/utils/debug.js +7 -23
- package/dist/utils/entry-url.d.ts +11 -23
- package/dist/utils/entry-url.js +11 -26
- package/dist/utils/error.d.ts +25 -90
- package/dist/utils/error.js +60 -147
- package/dist/utils/flatten-group-fields.d.ts +5 -7
- package/dist/utils/flatten-group-fields.js +5 -7
- package/dist/utils/format.d.ts +1 -5
- package/dist/utils/format.js +1 -5
- package/dist/utils/fs.d.ts +3 -4
- package/dist/utils/fs.js +3 -4
- package/dist/utils/git.d.ts +52 -83
- package/dist/utils/git.js +79 -125
- package/dist/utils/logger.d.ts +35 -50
- package/dist/utils/logger.js +35 -52
- package/dist/utils/provisioning-lock.d.ts +23 -35
- package/dist/utils/provisioning-lock.js +49 -69
- package/dist/utils/sanitize-href.d.ts +5 -10
- package/dist/utils/sanitize-href.js +8 -18
- package/dist/utils/title-field.d.ts +17 -20
- package/dist/utils/title-field.js +18 -27
- package/dist/utils/typed-filename.d.ts +20 -48
- package/dist/utils/typed-filename.js +25 -61
- package/dist/utils/url-prefix.d.ts +3 -3
- package/dist/utils/url-prefix.js +3 -3
- package/dist/validation/block-structural-keys.d.ts +16 -31
- package/dist/validation/block-structural-keys.js +19 -29
- package/dist/validation/deletion-checker.d.ts +0 -34
- package/dist/validation/deletion-checker.js +1 -43
- package/dist/validation/entry-link-validator.d.ts +6 -13
- package/dist/validation/entry-link-validator.js +4 -13
- package/dist/validation/entry-type-reference-validator.d.ts +13 -18
- package/dist/validation/entry-type-reference-validator.js +13 -18
- package/dist/validation/entry-validator.d.ts +13 -25
- package/dist/validation/entry-validator.js +15 -32
- package/dist/validation/field-traversal.d.ts +3 -30
- package/dist/validation/field-traversal.js +1 -32
- package/dist/validation/reference-validator.d.ts +5 -24
- package/dist/validation/reference-validator.js +5 -30
- package/dist/worker/cms-worker.d.ts +172 -232
- package/dist/worker/cms-worker.js +241 -333
- package/dist/worker/git-sync.d.ts +32 -133
- package/dist/worker/git-sync.js +129 -191
- package/dist/worker/github-auth.d.ts +13 -19
- package/dist/worker/github-auth.js +13 -19
- package/dist/worker/history-rewrite.d.ts +53 -66
- package/dist/worker/history-rewrite.js +54 -60
- package/dist/worker/log.d.ts +24 -41
- package/dist/worker/log.js +25 -42
- package/dist/worker/rebase.d.ts +20 -110
- package/dist/worker/rebase.js +279 -354
- package/dist/worker/task-runner.d.ts +32 -66
- package/dist/worker/task-runner.js +126 -162
- package/dist/worker/worker-context.d.ts +41 -81
- package/package.json +4 -4
- package/dist/cli/template-files/middleware-clerk.ts.template +0 -37
- package/dist/worker/task-queue-config.d.ts +0 -8
- package/dist/worker/task-queue.js +0 -19
- package/dist/worker/worker-status.d.ts +0 -47
- package/dist/worker/worker-status.js +0 -52
|
@@ -1,37 +1,28 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Branch-level authorization
|
|
3
|
-
*
|
|
4
|
-
* Handles checking if a user can access a branch based on ACLs.
|
|
5
|
-
*/
|
|
6
1
|
import type { BranchContext } from '../types.js';
|
|
7
2
|
import type { CanopyConfig, DefaultBranchAccess } from '../config/index.js';
|
|
8
3
|
import type { CanopyUser } from '../user.js';
|
|
9
4
|
import type { BranchAccessResult } from './types.js';
|
|
10
5
|
/** Options narrowing {@link checkBranchAccessWithDefault} to a specific branch's nature. */
|
|
11
|
-
|
|
6
|
+
interface BranchAccessOptions {
|
|
12
7
|
/**
|
|
13
8
|
* Whether this is the protected base branch -- pass
|
|
14
|
-
* `getBranchProtection(...).isProtected`. When true
|
|
15
|
-
* layer wherever no explicit ACL decided the question,
|
|
16
|
-
*
|
|
17
|
-
* (see the
|
|
9
|
+
* `getBranchProtection(...).isProtected`. When true the branch passes this
|
|
10
|
+
* layer wherever no explicit ACL decided the question, leaving the PATH layer
|
|
11
|
+
* to decide what is readable; explicit ACL verdicts still win in both
|
|
12
|
+
* directions (see the fallback site below).
|
|
18
13
|
*
|
|
19
|
-
*
|
|
20
|
-
* (`updateBranchAccessHandler` rejects one
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* same flag, prod writes stay blocked by `getBranchWriteProtection().readOnly`,
|
|
30
|
-
* and the editor API 401s anonymous callers before authorization runs. What it
|
|
31
|
-
* buys is that a public-read `deployedAs: 'server'` site can run 'deny' with
|
|
14
|
+
* The grant is load-bearing: the base branch takes no ACL
|
|
15
|
+
* (`updateBranchAccessHandler` rejects one, since an entry there would feed
|
|
16
|
+
* `allowed_by_acl` and confer Withdraw rights) and its `createdBy` is
|
|
17
|
+
* `canopycms-system`, so nobody is its creator -- without this it is
|
|
18
|
+
* unreachable under `defaultBranchAccess: 'deny'` with no way to configure
|
|
19
|
+
* around it. It widens nothing dangerous: {@link canPerformWorkflowAction}
|
|
20
|
+
* disables its system-branch grant on the same flag, prod writes stay blocked
|
|
21
|
+
* by `getBranchWriteProtection().readOnly`, and the editor API 401s anonymous
|
|
22
|
+
* callers before authorization runs. What it buys: a public-read
|
|
23
|
+
* `deployedAs: 'server'` site can run 'deny' with
|
|
32
24
|
* `defaultPathAccess: { read: 'allow' }` and still keep un-ACL'd work branches
|
|
33
|
-
* private
|
|
34
|
-
* which opened every work branch too.
|
|
25
|
+
* private.
|
|
35
26
|
*/
|
|
36
27
|
isProtectedBranch?: boolean;
|
|
37
28
|
}
|
|
@@ -46,14 +37,13 @@ export interface BranchAccessOptions {
|
|
|
46
37
|
* 4. With no ACL: the branch creator, then `defaultAccess`, and only where that
|
|
47
38
|
* would deny, the protected base branch grant
|
|
48
39
|
* (see {@link BranchAccessOptions.isProtectedBranch})
|
|
40
|
+
* @internal Exported for tests.
|
|
49
41
|
*/
|
|
50
42
|
export declare function checkBranchAccessWithDefault(context: BranchContext, user: CanopyUser, defaultAccess?: DefaultBranchAccess, options?: BranchAccessOptions): BranchAccessResult;
|
|
51
43
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* it routes through `getBranchProtection`, the single source of truth for that
|
|
56
|
-
* question, rather than repeating the base-branch test here.
|
|
44
|
+
* Bind a default access level. `config` is needed only to resolve the
|
|
45
|
+
* protected-base-branch question, which routes through `getBranchProtection`,
|
|
46
|
+
* its single source of truth, rather than repeating the comparison here.
|
|
57
47
|
*/
|
|
58
48
|
export declare function createCheckBranchAccess(defaultAccess?: DefaultBranchAccess, config?: Pick<CanopyConfig, 'mode' | 'defaultBaseBranch'>): (context: BranchContext, user: CanopyUser) => BranchAccessResult;
|
|
59
49
|
/** Options tightening {@link canPerformWorkflowAction} beyond the default hybrid model. */
|
|
@@ -65,29 +55,20 @@ export interface WorkflowActionOptions {
|
|
|
65
55
|
* -- pass `getBranchProtection(...).isProtected` here so only
|
|
66
56
|
* admins/reviewers/explicit-ACL users retain workflow rights on it.
|
|
67
57
|
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* by no one. The access layer says yes, then `isSystemBranch` below is false,
|
|
73
|
-
* so a non-creator/non-ACL/non-privileged user still gets `false` here.
|
|
58
|
+
* The same flag GRANTS access in {@link checkBranchAccessWithDefault} (see
|
|
59
|
+
* {@link BranchAccessOptions.isProtectedBranch}); pulling in opposite
|
|
60
|
+
* directions is the intended base-branch posture -- readable by anyone the
|
|
61
|
+
* path layer permits, submittable by no one.
|
|
74
62
|
*/
|
|
75
63
|
isProtectedBranch?: boolean;
|
|
76
64
|
}
|
|
77
65
|
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* This implements a hybrid permission model:
|
|
82
|
-
* - Branch creators can always submit/withdraw their branches
|
|
83
|
-
* - Users explicitly listed in branch ACLs can also submit/withdraw
|
|
84
|
-
* - For system branches (createdBy: 'canopycms-system'), anyone with general access can submit/withdraw
|
|
85
|
-
* - Admins and Reviewers always have access (via checkBranchAccess)
|
|
86
|
-
* - Unless `options.isProtectedBranch` is set, in which case the system-branch
|
|
87
|
-
* grant above is disabled (see {@link WorkflowActionOptions})
|
|
66
|
+
* Whether a user may submit/withdraw a branch: creator, OR ACL access, OR a
|
|
67
|
+
* system branch plus general access.
|
|
88
68
|
*
|
|
89
|
-
* The creator grant is enforced twice
|
|
90
|
-
*
|
|
91
|
-
* `defaultBranchAccess: 'deny'
|
|
69
|
+
* The creator grant is enforced twice: `checkBranchAccessWithDefault` admits
|
|
70
|
+
* the creator, so the gate below cannot swallow them under
|
|
71
|
+
* `defaultBranchAccess: 'deny'`, and `userIsCreator` decides the result.
|
|
92
72
|
*/
|
|
93
73
|
export declare function canPerformWorkflowAction(context: BranchContext, user: CanopyUser, defaultAccess?: DefaultBranchAccess, options?: WorkflowActionOptions): boolean;
|
|
74
|
+
export {};
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Branch-level authorization
|
|
3
|
-
*
|
|
4
|
-
* Handles checking if a user can access a branch based on ACLs.
|
|
5
|
-
*/
|
|
6
1
|
import { isAdmin, isReviewer } from './helpers.js';
|
|
7
2
|
import { getBranchProtection } from './protected-branch.js';
|
|
8
3
|
/**
|
|
@@ -16,9 +11,9 @@ import { getBranchProtection } from './protected-branch.js';
|
|
|
16
11
|
* 4. With no ACL: the branch creator, then `defaultAccess`, and only where that
|
|
17
12
|
* would deny, the protected base branch grant
|
|
18
13
|
* (see {@link BranchAccessOptions.isProtectedBranch})
|
|
14
|
+
* @internal Exported for tests.
|
|
19
15
|
*/
|
|
20
16
|
export function checkBranchAccessWithDefault(context, user, defaultAccess = 'deny', options) {
|
|
21
|
-
// Admins and Reviewers have full branch access
|
|
22
17
|
if (isAdmin(user.groups) || isReviewer(user.groups)) {
|
|
23
18
|
return { allowed: true, reason: 'privileged' };
|
|
24
19
|
}
|
|
@@ -30,16 +25,13 @@ export function checkBranchAccessWithDefault(context, user, defaultAccess = 'den
|
|
|
30
25
|
return { allowed: false, reason: 'denied_by_acl' };
|
|
31
26
|
}
|
|
32
27
|
if (!hasUserConstraint && !hasGroupConstraint) {
|
|
33
|
-
// The branch creator owns their own un-ACL'd branch
|
|
34
|
-
// places
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
// its ACL but not read a
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
// the creator still denies them, because that is how an admin locks down a
|
|
41
|
-
// branch someone else created. Granting creator ahead of the ACL would make
|
|
42
|
-
// that lockdown silently ineffective.
|
|
28
|
+
// The branch creator owns their own un-ACL'd branch, matching the three
|
|
29
|
+
// places that already grant on creator-ownership independently of branch
|
|
30
|
+
// access (listBranchesHandler, canDeleteBranch, canModifyBranchAccess):
|
|
31
|
+
// without it, under 'deny' a creator could delete their branch and rewrite
|
|
32
|
+
// its ACL but not read a file on it. Scoped to the no-ACL case on purpose --
|
|
33
|
+
// an EXPLICIT allowlist omitting the creator still denies them, which is how
|
|
34
|
+
// an admin locks down a branch someone else created.
|
|
43
35
|
if (context.branch.createdBy === user.userId) {
|
|
44
36
|
return { allowed: true, reason: 'creator' };
|
|
45
37
|
}
|
|
@@ -61,11 +53,9 @@ export function checkBranchAccessWithDefault(context, user, defaultAccess = 'den
|
|
|
61
53
|
return { allowed, reason: allowed ? 'allowed_by_acl' : 'denied_by_acl' };
|
|
62
54
|
}
|
|
63
55
|
/**
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* it routes through `getBranchProtection`, the single source of truth for that
|
|
68
|
-
* question, rather than repeating the base-branch test here.
|
|
56
|
+
* Bind a default access level. `config` is needed only to resolve the
|
|
57
|
+
* protected-base-branch question, which routes through `getBranchProtection`,
|
|
58
|
+
* its single source of truth, rather than repeating the comparison here.
|
|
69
59
|
*/
|
|
70
60
|
export function createCheckBranchAccess(defaultAccess = 'deny', config) {
|
|
71
61
|
return (context, user) => checkBranchAccessWithDefault(context, user, defaultAccess, {
|
|
@@ -75,38 +65,22 @@ export function createCheckBranchAccess(defaultAccess = 'deny', config) {
|
|
|
75
65
|
});
|
|
76
66
|
}
|
|
77
67
|
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* This implements a hybrid permission model:
|
|
82
|
-
* - Branch creators can always submit/withdraw their branches
|
|
83
|
-
* - Users explicitly listed in branch ACLs can also submit/withdraw
|
|
84
|
-
* - For system branches (createdBy: 'canopycms-system'), anyone with general access can submit/withdraw
|
|
85
|
-
* - Admins and Reviewers always have access (via checkBranchAccess)
|
|
86
|
-
* - Unless `options.isProtectedBranch` is set, in which case the system-branch
|
|
87
|
-
* grant above is disabled (see {@link WorkflowActionOptions})
|
|
68
|
+
* Whether a user may submit/withdraw a branch: creator, OR ACL access, OR a
|
|
69
|
+
* system branch plus general access.
|
|
88
70
|
*
|
|
89
|
-
* The creator grant is enforced twice
|
|
90
|
-
*
|
|
91
|
-
* `defaultBranchAccess: 'deny'
|
|
71
|
+
* The creator grant is enforced twice: `checkBranchAccessWithDefault` admits
|
|
72
|
+
* the creator, so the gate below cannot swallow them under
|
|
73
|
+
* `defaultBranchAccess: 'deny'`, and `userIsCreator` decides the result.
|
|
92
74
|
*/
|
|
93
75
|
export function canPerformWorkflowAction(context, user, defaultAccess = 'deny', options) {
|
|
94
|
-
// Check if user has general branch access (handles admins, reviewers, creator, ACLs)
|
|
95
76
|
const accessResult = checkBranchAccessWithDefault(context, user, defaultAccess, {
|
|
96
77
|
isProtectedBranch: options?.isProtectedBranch,
|
|
97
78
|
});
|
|
98
|
-
// If user doesn't have basic branch access, deny immediately
|
|
99
79
|
if (!accessResult.allowed) {
|
|
100
80
|
return false;
|
|
101
81
|
}
|
|
102
|
-
// Check if user is the branch creator
|
|
103
82
|
const userIsCreator = context.branch.createdBy === user.userId;
|
|
104
|
-
// Check if this is a system-created branch (grant disabled on protected branches)
|
|
105
83
|
const isSystemBranch = !options?.isProtectedBranch && context.branch.createdBy === 'canopycms-system';
|
|
106
|
-
// Allow if:
|
|
107
|
-
// 1. User is the creator, OR
|
|
108
|
-
// 2. User has ACL access (reason: 'privileged' or 'allowed_by_acl'), OR
|
|
109
|
-
// 3. System branch with general access
|
|
110
84
|
return (userIsCreator ||
|
|
111
85
|
accessResult.reason === 'privileged' ||
|
|
112
86
|
accessResult.reason === 'allowed_by_acl' ||
|
|
@@ -1,18 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* This is the main entry point for authorization checks. It combines
|
|
5
|
-
* branch-level and path-level access checks into a single API.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* ```ts
|
|
9
|
-
* import { checkContentAccess } from './authorization.js'
|
|
10
|
-
*
|
|
11
|
-
* const result = await checkContentAccess(deps, context, branchRoot, 'content/posts/my-post.mdx', user, 'edit')
|
|
12
|
-
* if (result.allowed) {
|
|
13
|
-
* // User can edit the file
|
|
14
|
-
* }
|
|
15
|
-
* ```
|
|
2
|
+
* Main entry point for authorization checks: combines branch-level and
|
|
3
|
+
* path-level access into a single API.
|
|
16
4
|
*/
|
|
17
5
|
import type { BranchContext } from '../types.js';
|
|
18
6
|
import type { PermissionLevel } from '../config/index.js';
|
|
@@ -25,35 +13,18 @@ import type { PhysicalPath } from '../paths/types.js';
|
|
|
25
13
|
*/
|
|
26
14
|
export type ContentAccessChecker = (relativePath: PhysicalPath, level: PermissionLevel) => ContentAccessResult;
|
|
27
15
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* and
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* settings branch, re-ensuring the settings workspace) for every entry. This is
|
|
36
|
-
* the batch primitive used by listing endpoints that check many paths per request.
|
|
37
|
-
*
|
|
38
|
-
* @param deps - Dependencies including branch access checker and path permissions loader
|
|
39
|
-
* @param context - Branch context containing branch metadata
|
|
40
|
-
* @param branchRoot - Root directory of the branch
|
|
41
|
-
* @param user - User to check access for
|
|
16
|
+
* Resolve the request-constant work once -- branch access, the
|
|
17
|
+
* settings/permissions root and the path-permission rules, all identical for a
|
|
18
|
+
* fixed `(context, branchRoot, user)` -- and return a synchronous per-path
|
|
19
|
+
* checker. Hoisting it avoids re-reading the permissions file (and, in modes
|
|
20
|
+
* with a separate settings branch, re-ensuring the settings workspace) for
|
|
21
|
+
* every entry. This is the batch primitive for listing endpoints that check
|
|
22
|
+
* many paths per request.
|
|
42
23
|
*/
|
|
43
24
|
export declare function createContentAccessChecker(deps: ContentAccessDeps, context: BranchContext, branchRoot: string, user: CanopyUser): Promise<ContentAccessChecker>;
|
|
44
25
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* @param deps - Dependencies including branch access checker and path permissions loader
|
|
49
|
-
* @param context - Branch context containing branch metadata
|
|
50
|
-
* @param branchRoot - Root directory of the branch
|
|
51
|
-
* @param relativePath - Physical path relative to branch root (with embedded IDs)
|
|
52
|
-
* @param user - User to check access for
|
|
53
|
-
* @param level - Permission level to check ('read', 'edit', or 'review')
|
|
26
|
+
* Single-path check; loads the path permissions from the branch root per call.
|
|
27
|
+
* @internal Exported for tests.
|
|
54
28
|
*/
|
|
55
29
|
export declare function checkContentAccess(deps: ContentAccessDeps, context: BranchContext, branchRoot: string, relativePath: PhysicalPath, user: CanopyUser, level: PermissionLevel): Promise<ContentAccessResult>;
|
|
56
|
-
/**
|
|
57
|
-
* Create a content access checker with bound dependencies.
|
|
58
|
-
*/
|
|
59
30
|
export declare function createCheckContentAccess(deps: ContentAccessDeps): (context: BranchContext, branchRoot: string, relativePath: PhysicalPath, user: CanopyUser, level: PermissionLevel) => Promise<ContentAccessResult>;
|
|
@@ -1,42 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* This is the main entry point for authorization checks. It combines
|
|
5
|
-
* branch-level and path-level access checks into a single API.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* ```ts
|
|
9
|
-
* import { checkContentAccess } from './authorization.js'
|
|
10
|
-
*
|
|
11
|
-
* const result = await checkContentAccess(deps, context, branchRoot, 'content/posts/my-post.mdx', user, 'edit')
|
|
12
|
-
* if (result.allowed) {
|
|
13
|
-
* // User can edit the file
|
|
14
|
-
* }
|
|
15
|
-
* ```
|
|
2
|
+
* Main entry point for authorization checks: combines branch-level and
|
|
3
|
+
* path-level access into a single API.
|
|
16
4
|
*/
|
|
17
5
|
import { operatingStrategy } from '../operating-mode/index.js';
|
|
18
6
|
import { createCheckPathAccess } from './path.js';
|
|
19
7
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* and
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* settings branch, re-ensuring the settings workspace) for every entry. This is
|
|
28
|
-
* the batch primitive used by listing endpoints that check many paths per request.
|
|
29
|
-
*
|
|
30
|
-
* @param deps - Dependencies including branch access checker and path permissions loader
|
|
31
|
-
* @param context - Branch context containing branch metadata
|
|
32
|
-
* @param branchRoot - Root directory of the branch
|
|
33
|
-
* @param user - User to check access for
|
|
8
|
+
* Resolve the request-constant work once -- branch access, the
|
|
9
|
+
* settings/permissions root and the path-permission rules, all identical for a
|
|
10
|
+
* fixed `(context, branchRoot, user)` -- and return a synchronous per-path
|
|
11
|
+
* checker. Hoisting it avoids re-reading the permissions file (and, in modes
|
|
12
|
+
* with a separate settings branch, re-ensuring the settings workspace) for
|
|
13
|
+
* every entry. This is the batch primitive for listing endpoints that check
|
|
14
|
+
* many paths per request.
|
|
34
15
|
*/
|
|
35
16
|
export async function createContentAccessChecker(deps, context, branchRoot, user) {
|
|
36
17
|
const branch = deps.checkBranchAccess(context, user);
|
|
37
|
-
// Load permissions from appropriate location based on operating mode
|
|
38
|
-
// Modes with separate settings branch: load from settings branch
|
|
39
|
-
// Other modes: load from the current branch
|
|
40
18
|
let permissionsRoot = branchRoot;
|
|
41
19
|
const mode = deps.mode;
|
|
42
20
|
const strategy = operatingStrategy(mode);
|
|
@@ -44,8 +22,8 @@ export async function createContentAccessChecker(deps, context, branchRoot, user
|
|
|
44
22
|
if (!deps.getSettingsBranchRoot) {
|
|
45
23
|
throw new Error('getSettingsBranchRoot is required for modes that use separate settings branch');
|
|
46
24
|
}
|
|
47
|
-
// getSettingsBranchRoot must throw if it cannot load the settings branch
|
|
48
|
-
//
|
|
25
|
+
// getSettingsBranchRoot must throw if it cannot load the settings branch:
|
|
26
|
+
// falling back would read permissions from the branch being edited.
|
|
49
27
|
permissionsRoot = await deps.getSettingsBranchRoot();
|
|
50
28
|
}
|
|
51
29
|
const rules = await deps.loadPathPermissions(permissionsRoot, deps.mode);
|
|
@@ -64,23 +42,13 @@ export async function createContentAccessChecker(deps, context, branchRoot, user
|
|
|
64
42
|
};
|
|
65
43
|
}
|
|
66
44
|
/**
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* @param deps - Dependencies including branch access checker and path permissions loader
|
|
71
|
-
* @param context - Branch context containing branch metadata
|
|
72
|
-
* @param branchRoot - Root directory of the branch
|
|
73
|
-
* @param relativePath - Physical path relative to branch root (with embedded IDs)
|
|
74
|
-
* @param user - User to check access for
|
|
75
|
-
* @param level - Permission level to check ('read', 'edit', or 'review')
|
|
45
|
+
* Single-path check; loads the path permissions from the branch root per call.
|
|
46
|
+
* @internal Exported for tests.
|
|
76
47
|
*/
|
|
77
48
|
export async function checkContentAccess(deps, context, branchRoot, relativePath, user, level) {
|
|
78
49
|
const check = await createContentAccessChecker(deps, context, branchRoot, user);
|
|
79
50
|
return check(relativePath, level);
|
|
80
51
|
}
|
|
81
|
-
/**
|
|
82
|
-
* Create a content access checker with bound dependencies.
|
|
83
|
-
*/
|
|
84
52
|
export function createCheckContentAccess(deps) {
|
|
85
53
|
return (context, branchRoot, relativePath, user, level) => checkContentAccess(deps, context, branchRoot, relativePath, user, level);
|
|
86
54
|
}
|
|
@@ -1,42 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* Handles loading internal groups from the filesystem and mutating
|
|
5
|
-
* groups.json under the cross-host layered lock in
|
|
6
|
-
* authorization/settings-file-store.ts.
|
|
2
|
+
* Loads internal groups, and mutates groups.json under the cross-host layered
|
|
3
|
+
* lock in authorization/settings-file-store.ts.
|
|
7
4
|
*/
|
|
8
5
|
import { type InternalGroup, type GroupsFile } from './schema.js';
|
|
9
6
|
import type { OperatingMode } from '../../operating-mode/index.js';
|
|
10
7
|
import type { OccWriteResult } from '../../utils/occ-json-write.js';
|
|
11
|
-
/**
|
|
12
|
-
* Load full groups file (for version checking)
|
|
13
|
-
* Returns null if file doesn't exist.
|
|
14
|
-
*/
|
|
8
|
+
/** Returns null when the file doesn't exist. */
|
|
15
9
|
export declare function loadGroupsFile(branchRoot: string, mode: OperatingMode): Promise<GroupsFile | null>;
|
|
16
10
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* attempt) can reconcile against it without a second read.
|
|
11
|
+
* The effective internal groups for a raw on-disk groups array: the reserved
|
|
12
|
+
* Admins/Reviewers groups always exist (synthesized when absent) and bootstrap
|
|
13
|
+
* admin IDs merge into Admins. Pure — no disk I/O — so a caller holding a
|
|
14
|
+
* freshly loaded file (e.g. a settings-file mutator, which reloads on every
|
|
15
|
+
* retry attempt) can reconcile against it without a second read.
|
|
23
16
|
*/
|
|
24
17
|
export declare function deriveInternalGroups(fileGroups: InternalGroup[], bootstrapAdminIds?: Set<string>): InternalGroup[];
|
|
25
|
-
/**
|
|
26
|
-
* Load internal groups from .canopycms/groups.json (or .local.json in dev mode)
|
|
27
|
-
* Ensures Admins and Reviewers groups always exist, adding them dynamically if not present.
|
|
28
|
-
* If Admins group exists in file, merges with bootstrap admin IDs.
|
|
29
|
-
*/
|
|
18
|
+
/** Loads .canopycms/groups.json (groups.local.json in dev mode). */
|
|
30
19
|
export declare function loadInternalGroups(branchRoot: string, mode: OperatingMode, bootstrapAdminIds?: Set<string>): Promise<InternalGroup[]>;
|
|
31
20
|
/**
|
|
32
|
-
* Mutate groups.json (
|
|
33
|
-
* lock + OCC-retry stack (see authorization/settings-file-store.ts).
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* payload
|
|
37
|
-
* validated against {@link GroupsFileSchema} before being written,
|
|
38
|
-
* preserving the previous validate-before-write behavior of the old
|
|
39
|
-
* `saveInternalGroups`.
|
|
21
|
+
* Mutate groups.json (groups.local.json in dev mode) under the full cross-host
|
|
22
|
+
* lock + OCC-retry stack (see authorization/settings-file-store.ts). `mutate`
|
|
23
|
+
* receives the current parsed file (`null` if absent) and the version to write
|
|
24
|
+
* under, and returns the next raw payload or `null` for a deliberate no-op.
|
|
25
|
+
* The payload is validated against {@link GroupsFileSchema} before writing.
|
|
40
26
|
*/
|
|
41
27
|
export declare function mutateGroupsFile(branchRoot: string, mode: OperatingMode, mutate: (current: GroupsFile | null, version: number) => Record<string, unknown> | null, options?: {
|
|
42
28
|
settleMs?: number;
|
|
@@ -1,25 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* Handles loading internal groups from the filesystem and mutating
|
|
5
|
-
* groups.json under the cross-host layered lock in
|
|
6
|
-
* authorization/settings-file-store.ts.
|
|
2
|
+
* Loads internal groups, and mutates groups.json under the cross-host layered
|
|
3
|
+
* lock in authorization/settings-file-store.ts.
|
|
7
4
|
*/
|
|
8
5
|
import { promises as fs } from 'node:fs';
|
|
9
6
|
import { GroupsFileSchema } from './schema.js';
|
|
10
7
|
import { operatingStrategy } from '../../operating-mode/index.js';
|
|
11
8
|
import { RESERVED_GROUPS } from '../helpers.js';
|
|
12
9
|
import { mutateSettingsJsonFile } from '../settings-file-store.js';
|
|
13
|
-
/**
|
|
14
|
-
* Get the appropriate groups file path based on mode
|
|
15
|
-
*/
|
|
16
10
|
function getGroupsFilePath(branchRoot, mode) {
|
|
17
11
|
return operatingStrategy(mode).getGroupsFilePath(branchRoot);
|
|
18
12
|
}
|
|
19
|
-
/**
|
|
20
|
-
* Load full groups file (for version checking)
|
|
21
|
-
* Returns null if file doesn't exist.
|
|
22
|
-
*/
|
|
13
|
+
/** Returns null when the file doesn't exist. */
|
|
23
14
|
export async function loadGroupsFile(branchRoot, mode) {
|
|
24
15
|
const groupsPath = getGroupsFilePath(branchRoot, mode);
|
|
25
16
|
try {
|
|
@@ -29,7 +20,6 @@ export async function loadGroupsFile(branchRoot, mode) {
|
|
|
29
20
|
return validated;
|
|
30
21
|
}
|
|
31
22
|
catch (error) {
|
|
32
|
-
// File doesn't exist
|
|
33
23
|
if (error.code === 'ENOENT') {
|
|
34
24
|
return null;
|
|
35
25
|
}
|
|
@@ -37,20 +27,16 @@ export async function loadGroupsFile(branchRoot, mode) {
|
|
|
37
27
|
}
|
|
38
28
|
}
|
|
39
29
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* attempt) can reconcile against it without a second read.
|
|
30
|
+
* The effective internal groups for a raw on-disk groups array: the reserved
|
|
31
|
+
* Admins/Reviewers groups always exist (synthesized when absent) and bootstrap
|
|
32
|
+
* admin IDs merge into Admins. Pure — no disk I/O — so a caller holding a
|
|
33
|
+
* freshly loaded file (e.g. a settings-file mutator, which reloads on every
|
|
34
|
+
* retry attempt) can reconcile against it without a second read.
|
|
46
35
|
*/
|
|
47
36
|
export function deriveInternalGroups(fileGroups, bootstrapAdminIds = new Set()) {
|
|
48
|
-
// Find existing Admins and Reviewers groups
|
|
49
37
|
let adminsGroup = fileGroups.find((g) => g.id === RESERVED_GROUPS.ADMINS);
|
|
50
38
|
let reviewersGroup = fileGroups.find((g) => g.id === RESERVED_GROUPS.REVIEWERS);
|
|
51
|
-
// Ensure Admins group exists and includes bootstrap admins
|
|
52
39
|
if (adminsGroup) {
|
|
53
|
-
// Merge bootstrap admin IDs with existing members
|
|
54
40
|
const allAdmins = new Set([...adminsGroup.members, ...bootstrapAdminIds]);
|
|
55
41
|
adminsGroup = {
|
|
56
42
|
...adminsGroup,
|
|
@@ -58,7 +44,6 @@ export function deriveInternalGroups(fileGroups, bootstrapAdminIds = new Set())
|
|
|
58
44
|
};
|
|
59
45
|
}
|
|
60
46
|
else {
|
|
61
|
-
// Create Admins group with bootstrap admins
|
|
62
47
|
adminsGroup = {
|
|
63
48
|
id: RESERVED_GROUPS.ADMINS,
|
|
64
49
|
name: RESERVED_GROUPS.ADMINS,
|
|
@@ -66,7 +51,6 @@ export function deriveInternalGroups(fileGroups, bootstrapAdminIds = new Set())
|
|
|
66
51
|
members: Array.from(bootstrapAdminIds),
|
|
67
52
|
};
|
|
68
53
|
}
|
|
69
|
-
// Ensure Reviewers group exists
|
|
70
54
|
if (!reviewersGroup) {
|
|
71
55
|
reviewersGroup = {
|
|
72
56
|
id: RESERVED_GROUPS.REVIEWERS,
|
|
@@ -75,28 +59,20 @@ export function deriveInternalGroups(fileGroups, bootstrapAdminIds = new Set())
|
|
|
75
59
|
members: [],
|
|
76
60
|
};
|
|
77
61
|
}
|
|
78
|
-
// Return all groups: reserved groups first, then other groups
|
|
79
62
|
const otherGroups = fileGroups.filter((g) => g.id !== RESERVED_GROUPS.ADMINS && g.id !== RESERVED_GROUPS.REVIEWERS);
|
|
80
63
|
return [adminsGroup, reviewersGroup, ...otherGroups];
|
|
81
64
|
}
|
|
82
|
-
/**
|
|
83
|
-
* Load internal groups from .canopycms/groups.json (or .local.json in dev mode)
|
|
84
|
-
* Ensures Admins and Reviewers groups always exist, adding them dynamically if not present.
|
|
85
|
-
* If Admins group exists in file, merges with bootstrap admin IDs.
|
|
86
|
-
*/
|
|
65
|
+
/** Loads .canopycms/groups.json (groups.local.json in dev mode). */
|
|
87
66
|
export async function loadInternalGroups(branchRoot, mode, bootstrapAdminIds = new Set()) {
|
|
88
67
|
const file = await loadGroupsFile(branchRoot, mode);
|
|
89
68
|
return deriveInternalGroups(file?.groups ?? [], bootstrapAdminIds);
|
|
90
69
|
}
|
|
91
70
|
/**
|
|
92
|
-
* Mutate groups.json (
|
|
93
|
-
* lock + OCC-retry stack (see authorization/settings-file-store.ts).
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* payload
|
|
97
|
-
* validated against {@link GroupsFileSchema} before being written,
|
|
98
|
-
* preserving the previous validate-before-write behavior of the old
|
|
99
|
-
* `saveInternalGroups`.
|
|
71
|
+
* Mutate groups.json (groups.local.json in dev mode) under the full cross-host
|
|
72
|
+
* lock + OCC-retry stack (see authorization/settings-file-store.ts). `mutate`
|
|
73
|
+
* receives the current parsed file (`null` if absent) and the version to write
|
|
74
|
+
* under, and returns the next raw payload or `null` for a deliberate no-op.
|
|
75
|
+
* The payload is validated against {@link GroupsFileSchema} before writing.
|
|
100
76
|
*/
|
|
101
77
|
export async function mutateGroupsFile(branchRoot, mode, mutate, options) {
|
|
102
78
|
const groupsPath = getGroupsFilePath(branchRoot, mode);
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Schema for groups.json file
|
|
3
|
-
*/
|
|
4
1
|
import { z } from 'zod';
|
|
5
2
|
import type { CanopyUserId, CanopyGroupId } from '../../types.js';
|
|
6
3
|
/**
|
|
@@ -51,9 +48,6 @@ export declare const GroupsFileSchema: z.ZodObject<{
|
|
|
51
48
|
writeId?: string | undefined;
|
|
52
49
|
}>;
|
|
53
50
|
export type GroupsFile = z.infer<typeof GroupsFileSchema>;
|
|
54
|
-
/**
|
|
55
|
-
* Internal group representation
|
|
56
|
-
*/
|
|
57
51
|
export interface InternalGroup {
|
|
58
52
|
id: CanopyGroupId;
|
|
59
53
|
name: string;
|
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Schema for groups.json file
|
|
3
|
-
*/
|
|
4
1
|
import { z } from 'zod';
|
|
5
2
|
/**
|
|
6
3
|
* Schema for .canopycms/groups.json
|
|
7
4
|
*/
|
|
8
5
|
export const GroupsFileSchema = z.object({
|
|
9
|
-
// Managed by writeOccJsonFile (see authorization/settings-file-store.ts)
|
|
10
|
-
// the single OCC counter for this file. Optional so a hand-written file
|
|
11
|
-
//
|
|
12
|
-
//
|
|
6
|
+
// Managed by writeOccJsonFile (see authorization/settings-file-store.ts):
|
|
7
|
+
// the single OCC counter for this file. Optional so a hand-written file with
|
|
8
|
+
// no version field parses as version 0; a stray `contentVersion` key is
|
|
9
|
+
// silently stripped by this non-strict zod parse.
|
|
13
10
|
version: z.number().int().nonnegative().optional(),
|
|
14
11
|
writeId: z.string().optional(),
|
|
15
12
|
updatedAt: z.string().datetime(),
|