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
package/dist/api/entries.js
CHANGED
|
@@ -12,11 +12,7 @@ import { SchemaOps, SchemaStoreBusyError } from '../schema/schema-store.js';
|
|
|
12
12
|
import { listCollectionEntries as listCollectionEntriesShared, sortByOrder, } from '../content-listing.js';
|
|
13
13
|
// Re-export pagination constants from the dependency-free module so they remain
|
|
14
14
|
// part of the entries API surface without pulling server deps into client bundles.
|
|
15
|
-
export { MAX_ENTRIES_PER_PAGE, DEFAULT_ENTRIES_LIMIT } from './entries-constants.js';
|
|
16
15
|
const log = createDebugLogger({ prefix: 'EntriesAPI' });
|
|
17
|
-
// ============================================================================
|
|
18
|
-
// Zod Schemas for Validation
|
|
19
|
-
// ============================================================================
|
|
20
16
|
const listEntriesParamsSchema = z.object({
|
|
21
17
|
branch: branchNameSchema,
|
|
22
18
|
collection: logicalPathSchema.optional(),
|
|
@@ -54,14 +50,11 @@ const toCollectionItem = (entry, collection) => {
|
|
|
54
50
|
/**
|
|
55
51
|
* List entries in a single collection, mapped to API CollectionItem type.
|
|
56
52
|
*
|
|
57
|
-
* Deliberately does NOT resolve `reference` fields
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* request path, so every keystroke in the admin search box would pay a full ContentId index
|
|
63
|
-
* scan plus one read per distinct referenced entry. Revisit only if a column ever needs to
|
|
64
|
-
* display a reference's content.
|
|
53
|
+
* Deliberately does NOT resolve `reference` fields (unlike the `resolveReferences` option
|
|
54
|
+
* elsewhere on the same primitive): this runs BEFORE pagination (`slice` happens at the end) on
|
|
55
|
+
* a search request path, so resolving would cost a full ContentId scan plus one read per
|
|
56
|
+
* referenced entry on every keystroke. Revisit only if a column needs to display a reference's
|
|
57
|
+
* content.
|
|
65
58
|
*/
|
|
66
59
|
const listCollectionEntries = async (root, collection) => {
|
|
67
60
|
const entries = await listCollectionEntriesShared(root, collection);
|
|
@@ -179,12 +172,10 @@ const listEntriesHandler = async (gc, ctx, req, params) => {
|
|
|
179
172
|
},
|
|
180
173
|
};
|
|
181
174
|
};
|
|
182
|
-
// ============================================================================
|
|
183
|
-
// Route Definitions with defineEndpoint
|
|
184
|
-
// ============================================================================
|
|
185
175
|
/**
|
|
186
176
|
* List entries for a branch
|
|
187
177
|
* GET /:branch/entries
|
|
178
|
+
* @internal Exported for tests.
|
|
188
179
|
*/
|
|
189
180
|
export const listEntries = defineEndpoint({
|
|
190
181
|
namespace: 'entries',
|
|
@@ -215,14 +206,10 @@ const deleteEntryParamsSchema = z.object({
|
|
|
215
206
|
*/
|
|
216
207
|
const deleteEntryHandler = async (gc, ctx, req, params) => {
|
|
217
208
|
const { branchContext } = gc;
|
|
218
|
-
// Parse entryPath to get collection and slug
|
|
219
209
|
// Format: collectionPath/slug (e.g., "posts/hello-world" or "docs/api/getting-started")
|
|
220
210
|
// params.entryPath is already decoded exactly once, uniformly with every
|
|
221
|
-
// other route param, by http/router.ts's matchRoute (C5)
|
|
222
|
-
//
|
|
223
|
-
// with content.ts's (undecoded) catch-all and vulnerable to a malformed
|
|
224
|
-
// `%` escape throwing past this handler's try/catch. Still re-validate the
|
|
225
|
-
// final decoded value for traversal, same as before.
|
|
211
|
+
// other route param, by http/router.ts's matchRoute (C5). Still re-validate the
|
|
212
|
+
// final decoded value for traversal.
|
|
226
213
|
const entryPathResult = parseLogicalPath(params.entryPath);
|
|
227
214
|
if (!entryPathResult.ok) {
|
|
228
215
|
return {
|
|
@@ -250,8 +237,6 @@ const deleteEntryHandler = async (gc, ctx, req, params) => {
|
|
|
250
237
|
};
|
|
251
238
|
}
|
|
252
239
|
const flatSchema = branchContext.flatSchema;
|
|
253
|
-
// Check edit permission on the entry
|
|
254
|
-
// Build the physical path for permission check
|
|
255
240
|
const collection = flatSchema.find((item) => item.type === 'collection' && item.logicalPath === collectionPath);
|
|
256
241
|
if (!collection) {
|
|
257
242
|
return { ok: false, status: 404, error: 'Collection not found' };
|
|
@@ -280,16 +265,13 @@ const deleteEntryHandler = async (gc, ctx, req, params) => {
|
|
|
280
265
|
if (isNotFoundError(err)) {
|
|
281
266
|
return { ok: false, status: 404, error: 'Entry not found' };
|
|
282
267
|
}
|
|
283
|
-
// C2:
|
|
284
|
-
//
|
|
285
|
-
// server fault and must surface as a 500, not get mislabeled as
|
|
286
|
-
// "Invalid entry path".
|
|
268
|
+
// C2: same rule as content.ts's writeContentHandler catch (ContentStoreError -> 400,
|
|
269
|
+
// everything else -> 500).
|
|
287
270
|
if (err instanceof ContentStoreError) {
|
|
288
271
|
return { ok: false, status: 400, error: 'Invalid entry path' };
|
|
289
272
|
}
|
|
290
273
|
throw err;
|
|
291
274
|
}
|
|
292
|
-
// Check edit access using the real physical path
|
|
293
275
|
const editAccess = await ctx.services.checkContentAccess(branchContext, branchContext.branchRoot, physicalPath, req.user, 'edit');
|
|
294
276
|
if (!editAccess.allowed) {
|
|
295
277
|
return {
|
|
@@ -302,15 +284,11 @@ const deleteEntryHandler = async (gc, ctx, req, params) => {
|
|
|
302
284
|
try {
|
|
303
285
|
// Get the entry's content ID before deleting (for order update)
|
|
304
286
|
const contentId = await contentStore.getIdForEntry(collectionLogicalPath, entrySlug);
|
|
305
|
-
// Delete the entry
|
|
306
287
|
await contentStore.delete(collectionLogicalPath, entrySlug);
|
|
307
|
-
//
|
|
308
|
-
//
|
|
309
|
-
//
|
|
310
|
-
//
|
|
311
|
-
// bumps the schema generation marker. Without the bump, every host durably
|
|
312
|
-
// serves the stale cached order (still containing the deleted entry) until
|
|
313
|
-
// the next unrelated schema mutation — prod has no mtime backstop.
|
|
288
|
+
// Construct exactly like api/schema.ts's getSchemaOps (content root, registry, services,
|
|
289
|
+
// branch root) so updateOrder's write bumps the schema generation marker — without it, every
|
|
290
|
+
// host keeps serving the stale cached order (still containing the deleted entry) until the
|
|
291
|
+
// next unrelated schema mutation, since prod has no mtime backstop.
|
|
314
292
|
if (contentId && collection.type === 'collection' && collection.order) {
|
|
315
293
|
const contentRootName = ctx.services.config.contentRoot || 'content';
|
|
316
294
|
const schemaStore = new SchemaOps(path.join(branchContext.branchRoot, contentRootName), ctx.services.entrySchemaRegistry, ctx.services, branchContext.branchRoot);
|
|
@@ -320,13 +298,9 @@ const deleteEntryHandler = async (gc, ctx, req, params) => {
|
|
|
320
298
|
await schemaStore.updateOrder(collectionPath, newOrder);
|
|
321
299
|
}
|
|
322
300
|
catch (err) {
|
|
323
|
-
// C6: order cleanup is best-effort hygiene
|
|
324
|
-
//
|
|
325
|
-
//
|
|
326
|
-
// successful delete into an error response (the entry is gone; a
|
|
327
|
-
// client that sees an error and retries the delete would just get
|
|
328
|
-
// a confusing 404). Surface it as a warning on the success
|
|
329
|
-
// response instead (mirrors content.ts's write-path `validationWarnings`).
|
|
301
|
+
// C6: order cleanup is best-effort hygiene after the entry is already deleted, so no
|
|
302
|
+
// failure here may turn an otherwise-successful delete into an error (a retry would
|
|
303
|
+
// just 404). Surface it as a warning instead (mirrors content.ts's `validationWarnings`).
|
|
330
304
|
const reason = err instanceof SchemaStoreBusyError ? 'schema is busy' : getErrorMessage(err);
|
|
331
305
|
log.warn('delete-entry', 'Skipped order cleanup', {
|
|
332
306
|
collectionPath,
|
|
@@ -347,9 +321,8 @@ const deleteEntryHandler = async (gc, ctx, req, params) => {
|
|
|
347
321
|
if (isNotFoundError(err)) {
|
|
348
322
|
return { ok: false, status: 404, error: 'Entry not found' };
|
|
349
323
|
}
|
|
350
|
-
// [SYNC-C1] Contention with the worker's rebase (or another editor) is a
|
|
351
|
-
//
|
|
352
|
-
// variant's own "try again" message when that is what happened.
|
|
324
|
+
// [SYNC-C1] Contention with the worker's rebase (or another editor) is a retriable conflict,
|
|
325
|
+
// not a server fault — 409, with the syncing variant's own "try again" message.
|
|
353
326
|
if (err instanceof ContentConflictError) {
|
|
354
327
|
return {
|
|
355
328
|
ok: false,
|
|
@@ -366,11 +339,7 @@ const deleteEntryHandler = async (gc, ctx, req, params) => {
|
|
|
366
339
|
};
|
|
367
340
|
}
|
|
368
341
|
};
|
|
369
|
-
/**
|
|
370
|
-
* Delete an entry
|
|
371
|
-
* DELETE /:branch/entries/...entryPath
|
|
372
|
-
* Note: Uses catch-all to support paths with slashes (e.g., content/posts/hello-world)
|
|
373
|
-
*/
|
|
342
|
+
/** @internal Exported for tests. */
|
|
374
343
|
export const deleteEntry = defineEndpoint({
|
|
375
344
|
namespace: 'entries',
|
|
376
345
|
name: 'delete',
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { ApiContext } from './types.js';
|
|
2
2
|
import type { BranchContext, SyncStatus } from '../types.js';
|
|
3
3
|
/**
|
|
4
|
-
* Result of a GitHub sync operation.
|
|
5
4
|
* The caller uses this to update branch metadata.
|
|
6
5
|
*/
|
|
7
6
|
export interface GitHubSyncResult {
|
|
@@ -10,12 +9,11 @@ export interface GitHubSyncResult {
|
|
|
10
9
|
syncStatus?: SyncStatus;
|
|
11
10
|
}
|
|
12
11
|
/**
|
|
13
|
-
* Submit a branch: create or update a PR.
|
|
14
12
|
* Uses githubService directly if available, otherwise queues a task for the worker.
|
|
15
13
|
*/
|
|
16
14
|
export declare function syncSubmitPr(ctx: ApiContext, context: BranchContext): Promise<GitHubSyncResult>;
|
|
17
15
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
* Used by withdraw and request-changes. Uses githubService directly if
|
|
17
|
+
* available, otherwise queues a task.
|
|
20
18
|
*/
|
|
21
19
|
export declare function syncConvertToDraft(ctx: ApiContext, context: BranchContext): Promise<void>;
|
package/dist/api/github-sync.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { enqueueTask } from '../
|
|
2
|
-
import { getTaskQueueDir } from '../
|
|
1
|
+
import { enqueueTask } from '../task-queue/cms-task-queue.js';
|
|
2
|
+
import { getTaskQueueDir } from '../task-queue/task-queue-config.js';
|
|
3
3
|
import { clientOperatingStrategy } from '../operating-mode/index.js';
|
|
4
4
|
import { getErrorMessage } from '../utils/error.js';
|
|
5
5
|
import { sanitizeBranchName } from '../paths/branch-name.js';
|
|
6
6
|
/**
|
|
7
|
-
* Submit a branch: create or update a PR.
|
|
8
7
|
* Uses githubService directly if available, otherwise queues a task for the worker.
|
|
9
8
|
*/
|
|
10
9
|
export async function syncSubmitPr(ctx, context) {
|
|
@@ -118,8 +117,8 @@ export async function syncSubmitPr(ctx, context) {
|
|
|
118
117
|
});
|
|
119
118
|
}
|
|
120
119
|
/**
|
|
121
|
-
*
|
|
122
|
-
*
|
|
120
|
+
* Used by withdraw and request-changes. Uses githubService directly if
|
|
121
|
+
* available, otherwise queues a task.
|
|
123
122
|
*/
|
|
124
123
|
export async function syncConvertToDraft(ctx, context) {
|
|
125
124
|
if (!context.branch.pullRequestNumber)
|
|
@@ -147,9 +146,6 @@ export async function syncConvertToDraft(ctx, context) {
|
|
|
147
146
|
});
|
|
148
147
|
}
|
|
149
148
|
}
|
|
150
|
-
/**
|
|
151
|
-
* Enqueue a GitHub task for the EC2 worker.
|
|
152
|
-
*/
|
|
153
149
|
async function enqueueGitHubTask(ctx, context, task) {
|
|
154
150
|
const taskDir = getTaskQueueDir(ctx.services.config);
|
|
155
151
|
try {
|
package/dist/api/groups.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export type ExternalGroupsResponse = ApiResponse<{
|
|
|
16
16
|
/**
|
|
17
17
|
* Validate that an update to internal groups doesn't remove the last admin.
|
|
18
18
|
* Considers both internal Admins group members and bootstrap admins.
|
|
19
|
+
* @internal Exported for tests.
|
|
19
20
|
*/
|
|
20
21
|
export declare const validateAdminGroupUpdate: (newGroups: InternalGroup[], bootstrapAdminIds: Set<string>) => {
|
|
21
22
|
valid: boolean;
|
|
@@ -23,6 +24,7 @@ export declare const validateAdminGroupUpdate: (newGroups: InternalGroup[], boot
|
|
|
23
24
|
};
|
|
24
25
|
/**
|
|
25
26
|
* Validate that reserved groups are not deleted or renamed.
|
|
27
|
+
* @internal Exported for tests.
|
|
26
28
|
*/
|
|
27
29
|
export declare const validateReservedGroups: (newGroups: InternalGroup[]) => {
|
|
28
30
|
valid: boolean;
|
|
@@ -35,6 +37,7 @@ export interface UpdateInternalGroupsBody {
|
|
|
35
37
|
}
|
|
36
38
|
/**
|
|
37
39
|
* Search external groups (for group UI)
|
|
40
|
+
* @internal Exported for tests.
|
|
38
41
|
*/
|
|
39
42
|
export interface SearchExternalGroupsParams {
|
|
40
43
|
query: string;
|
package/dist/api/groups.js
CHANGED
|
@@ -4,9 +4,6 @@ import { defineEndpoint } from './route-builder.js';
|
|
|
4
4
|
import { getSettingsBranchContext, commitSettings } from './settings-helpers.js';
|
|
5
5
|
import { generateId } from '../id.js';
|
|
6
6
|
import { getErrorMessage, sanitizeErrorMessage } from '../utils/error.js';
|
|
7
|
-
// ============================================================================
|
|
8
|
-
// Zod Schemas for Validation
|
|
9
|
-
// ============================================================================
|
|
10
7
|
const internalGroupSchema = z.object({
|
|
11
8
|
id: z.string(),
|
|
12
9
|
name: z.string(),
|
|
@@ -37,15 +34,14 @@ class GroupsValidationError extends Error {
|
|
|
37
34
|
/**
|
|
38
35
|
* Validate that an update to internal groups doesn't remove the last admin.
|
|
39
36
|
* Considers both internal Admins group members and bootstrap admins.
|
|
37
|
+
* @internal Exported for tests.
|
|
40
38
|
*/
|
|
41
39
|
export const validateAdminGroupUpdate = (newGroups, bootstrapAdminIds) => {
|
|
42
|
-
// Find the Admins group in the new groups
|
|
43
40
|
const adminsGroup = newGroups.find((g) => g.id === RESERVED_GROUPS.ADMINS);
|
|
44
41
|
const adminMembersCount = adminsGroup?.members?.length ?? 0;
|
|
45
42
|
// Total admins = internal Admins group members + bootstrap admins (excluding overlap)
|
|
46
43
|
const internalAdmins = new Set(adminsGroup?.members ?? []);
|
|
47
44
|
let totalAdmins = adminMembersCount;
|
|
48
|
-
// Add bootstrap admins that aren't already in the internal group
|
|
49
45
|
for (const bootstrapId of bootstrapAdminIds) {
|
|
50
46
|
if (!internalAdmins.has(bootstrapId)) {
|
|
51
47
|
totalAdmins++;
|
|
@@ -61,12 +57,11 @@ export const validateAdminGroupUpdate = (newGroups, bootstrapAdminIds) => {
|
|
|
61
57
|
};
|
|
62
58
|
/**
|
|
63
59
|
* Validate that reserved groups are not deleted or renamed.
|
|
60
|
+
* @internal Exported for tests.
|
|
64
61
|
*/
|
|
65
62
|
export const validateReservedGroups = (newGroups) => {
|
|
66
|
-
// Check if any reserved group IDs have been altered
|
|
67
63
|
for (const group of newGroups) {
|
|
68
64
|
if (isReservedGroup(group.id)) {
|
|
69
|
-
// Reserved group exists - make sure the name matches the ID
|
|
70
65
|
if (group.name !== group.id) {
|
|
71
66
|
return {
|
|
72
67
|
valid: false,
|
|
@@ -122,11 +117,10 @@ const updateInternalGroupsHandler = async (_gc, ctx, req, body) => {
|
|
|
122
117
|
return { ok: false, status: result.status, error: result.error };
|
|
123
118
|
}
|
|
124
119
|
const { context, mode } = result;
|
|
125
|
-
// Load -> compare -> reconcile -> validate -> write all happen atomically
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
//
|
|
129
|
-
// TOCTOU window between the version/reconciliation checks and the write.
|
|
120
|
+
// Load -> compare -> reconcile -> validate -> write all happen atomically under the
|
|
121
|
+
// cross-host layered lock (see authorization/settings-file-store.ts), against the mutator's
|
|
122
|
+
// own freshly-reloaded file — no separate pre-read, so no TOCTOU window between the
|
|
123
|
+
// version/reconciliation checks and the write.
|
|
130
124
|
await mutateGroupsFile(context.branchRoot, mode, (currentFile, version) => {
|
|
131
125
|
if (body.expectedContentVersion !== undefined && body.expectedContentVersion !== version) {
|
|
132
126
|
throw new SettingsVersionConflictError('Groups were modified by another user. Please reload and try again.');
|
|
@@ -137,16 +131,13 @@ const updateInternalGroupsHandler = async (_gc, ctx, req, body) => {
|
|
|
137
131
|
const existingById = new Set(existingGroups.map((g) => g.id));
|
|
138
132
|
// Process groups: generate IDs for new groups, keep IDs for existing groups
|
|
139
133
|
const processedGroups = body.groups.map((group) => {
|
|
140
|
-
// Existing group with valid ID - keep ID
|
|
141
134
|
if (group.id && group.id.trim() !== '' && existingById.has(group.id)) {
|
|
142
135
|
return group;
|
|
143
136
|
}
|
|
144
|
-
// Check if this is a reserved group (by ID or name)
|
|
145
137
|
if (isReservedGroup(group.id) || isReservedGroup(group.name)) {
|
|
146
138
|
// Reserved groups: ID = name (e.g., "Admins", "Reviewers")
|
|
147
139
|
return { ...group, id: group.name };
|
|
148
140
|
}
|
|
149
|
-
// New regular group (empty ID or not in existing set) - generate ID
|
|
150
141
|
return { ...group, id: generateId() };
|
|
151
142
|
});
|
|
152
143
|
// Validate no duplicate IDs
|
|
@@ -182,9 +173,8 @@ const updateInternalGroupsHandler = async (_gc, ctx, req, body) => {
|
|
|
182
173
|
groups: processedGroups,
|
|
183
174
|
};
|
|
184
175
|
});
|
|
185
|
-
//
|
|
186
|
-
//
|
|
187
|
-
// that to the client instead of reporting a bare 200.
|
|
176
|
+
// A failed push is returned to the client as an error, never a bare 200 (see
|
|
177
|
+
// CommitSettingsResult in settings-helpers.ts).
|
|
188
178
|
const commitResult = await commitSettings(ctx, {
|
|
189
179
|
context,
|
|
190
180
|
branchRoot: context.branchRoot,
|
|
@@ -239,9 +229,6 @@ const searchExternalGroupsHandler = async (_gc, ctx, req, params) => {
|
|
|
239
229
|
};
|
|
240
230
|
}
|
|
241
231
|
};
|
|
242
|
-
// ============================================================================
|
|
243
|
-
// Route Definitions with defineEndpoint
|
|
244
|
-
// ============================================================================
|
|
245
232
|
/**
|
|
246
233
|
* Get internal groups
|
|
247
234
|
* GET /groups/internal
|
package/dist/api/guards.d.ts
CHANGED
|
@@ -1,26 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Declarative guard system for API endpoints
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* - Return an error response (404, 403, 500) to short-circuit
|
|
6
|
-
* - Produce a guard context (e.g., branch context with schema) for the handler
|
|
7
|
-
*
|
|
8
|
-
* Usage in defineEndpoint:
|
|
9
|
-
* ```ts
|
|
10
|
-
* defineEndpoint({
|
|
11
|
-
* guards: ['branchAccessWithSchema'] as const,
|
|
12
|
-
* handler: async (gc, ctx, req, params) => {
|
|
13
|
-
* // gc.branchContext is guaranteed non-null with flatSchema
|
|
14
|
-
* }
|
|
15
|
-
* })
|
|
16
|
-
* ```
|
|
2
|
+
* Declarative guard system for API endpoints: guards run before the handler and either return an
|
|
3
|
+
* error response (404/403/500) to short-circuit, or produce a guard context (e.g. branch context
|
|
4
|
+
* with schema) for the handler. See api/AGENTS.md for the full guard reference.
|
|
17
5
|
*/
|
|
18
6
|
import type { BranchContext, BranchContextWithSchema } from '../types.js';
|
|
19
7
|
import type { ApiContext, ApiRequest, ApiResponse } from './types.js';
|
|
20
8
|
/** All available guard identifiers */
|
|
21
9
|
export type GuardId = 'branch' | 'branchAccess' | 'schema' | 'branchAccessWithSchema' | 'admin' | 'reviewer' | 'privileged' | 'writableBranch' | 'submittableBranch';
|
|
22
10
|
/** Maps each guard ID to the context it contributes */
|
|
23
|
-
|
|
11
|
+
interface GuardContextMap {
|
|
24
12
|
branch: {
|
|
25
13
|
branchContext: BranchContext;
|
|
26
14
|
};
|
package/dist/api/guards.js
CHANGED
|
@@ -1,26 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Declarative guard system for API endpoints
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* - Return an error response (404, 403, 500) to short-circuit
|
|
6
|
-
* - Produce a guard context (e.g., branch context with schema) for the handler
|
|
7
|
-
*
|
|
8
|
-
* Usage in defineEndpoint:
|
|
9
|
-
* ```ts
|
|
10
|
-
* defineEndpoint({
|
|
11
|
-
* guards: ['branchAccessWithSchema'] as const,
|
|
12
|
-
* handler: async (gc, ctx, req, params) => {
|
|
13
|
-
* // gc.branchContext is guaranteed non-null with flatSchema
|
|
14
|
-
* }
|
|
15
|
-
* })
|
|
16
|
-
* ```
|
|
2
|
+
* Declarative guard system for API endpoints: guards run before the handler and either return an
|
|
3
|
+
* error response (404/403/500) to short-circuit, or produce a guard context (e.g. branch context
|
|
4
|
+
* with schema) for the handler. See api/AGENTS.md for the full guard reference.
|
|
17
5
|
*/
|
|
18
6
|
import { isAdmin, isReviewer, isPrivileged } from '../authorization/helpers.js';
|
|
19
7
|
import { getBranchProtection, getBranchWriteProtection } from '../authorization/protected-branch.js';
|
|
20
|
-
// ============================================================================
|
|
21
|
-
// Guard runner implementations
|
|
22
|
-
// ============================================================================
|
|
23
|
-
/** Extracts branch name from params, returning error response if missing */
|
|
24
8
|
function extractBranchName(params) {
|
|
25
9
|
const branch = params.branch;
|
|
26
10
|
if (typeof branch !== 'string' || !branch) {
|
|
@@ -193,9 +177,6 @@ const runPrivilegedGuard = async (_ctx, req) => {
|
|
|
193
177
|
}
|
|
194
178
|
return { ok: true, context: {} };
|
|
195
179
|
};
|
|
196
|
-
// ============================================================================
|
|
197
|
-
// Guard registry
|
|
198
|
-
// ============================================================================
|
|
199
180
|
const GUARD_RUNNERS = {
|
|
200
181
|
branch: runBranchGuard,
|
|
201
182
|
branchAccess: runBranchAccessGuard,
|
package/dist/api/index.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
export type { ApiResponse, ApiRequest, ApiContext } from './types.js';
|
|
2
2
|
export type { BranchResponse, BranchListResponse, BranchDeleteResponse, CreateBranchBody, UpdateBranchAccessBody, } from './branch.js';
|
|
3
3
|
export type { BranchMergeResponse } from './branch-merge.js';
|
|
4
|
-
export type { CommentsResponse, AddCommentResponse, ResolveCommentResponse
|
|
4
|
+
export type { CommentsResponse, AddCommentResponse, ResolveCommentResponse } from './comments.js';
|
|
5
5
|
export type { EntriesResponse, ListEntriesResponse, CollectionItem, ListEntriesParams, DeleteEntryResponse, } from './entries.js';
|
|
6
6
|
export type { PermissionsResponse, UpdatePermissionsBody, SearchUsersParams, GetUserMetadataResponse, GetUserMetadataParams, } from './permissions.js';
|
|
7
7
|
export type { UserInfoResponse } from './user.js';
|
|
8
|
-
export type { AssetRecord, AssetsListResponse, PresignAssetResponse, PresignAssetBody, FinalizeAssetResponse, FinalizeAssetBody, AssetDeleteResponse,
|
|
8
|
+
export type { AssetRecord, AssetsListResponse, PresignAssetResponse, PresignAssetBody, FinalizeAssetResponse, FinalizeAssetBody, AssetDeleteResponse, } from './assets.js';
|
|
9
9
|
export type { InternalGroupsResponse, ExternalGroupsResponse, UpdateInternalGroupsBody, SearchExternalGroupsParams, ExternalGroup, } from './groups.js';
|
|
10
10
|
export type { ReferenceOptionsResponse } from './reference-options.js';
|
|
11
11
|
export type { ResolveReferencesResponse } from './resolve-references.js';
|
|
12
|
-
export type {
|
|
12
|
+
export type { GetSchemaApiResponse, GetCollectionApiResponse, CreateCollectionApiResponse, UpdateCollectionApiResponse, DeleteCollectionApiResponse, AddEntryTypeApiResponse, UpdateEntryTypeApiResponse, RemoveEntryTypeApiResponse, UpdateOrderApiResponse, } from './schema.js';
|
|
13
13
|
export type { CreateCollectionInput, UpdateCollectionInput, CreateEntryTypeInput, UpdateEntryTypeInput, } from '../schema/schema-store-types.js';
|
|
14
14
|
export type { EntryTypeSummary } from './entries.js';
|
|
15
|
-
export type { AdminStatusResponse, AdminStatusData, AdminTasksResponse, AdminTasksData, ListAdminTasksParams, AdminRetryTaskResponse,
|
|
15
|
+
export type { AdminStatusResponse, AdminStatusData, AdminTasksResponse, AdminTasksData, ListAdminTasksParams, AdminRetryTaskResponse, AdminDeleteTaskResponse, DeleteTaskParams, WorkerLiveness, } from './admin.js';
|
|
16
16
|
export { USER_ROUTES } from './user.js';
|
|
17
17
|
export { CanopyApiClient, createApiClient } from './client.js';
|
|
18
18
|
export type { ApiClientOptions } from './client.js';
|
|
@@ -143,7 +143,9 @@ declare const getUserMetadataParamsSchema: z.ZodObject<{
|
|
|
143
143
|
userId: string;
|
|
144
144
|
}>;
|
|
145
145
|
export type UpdatePermissionsBody = z.infer<typeof updatePermissionsBodySchema>;
|
|
146
|
+
/** @internal No importer; deletion candidate in knip-no-importer-deletion-candidates.md. */
|
|
146
147
|
export type SearchUsersParams = z.infer<typeof searchUsersParamsSchema>;
|
|
148
|
+
/** @internal No importer; deletion candidate in knip-no-importer-deletion-candidates.md. */
|
|
147
149
|
export type GetUserMetadataParams = z.infer<typeof getUserMetadataParamsSchema>;
|
|
148
150
|
/**
|
|
149
151
|
* Exported routes for router registration
|
package/dist/api/permissions.js
CHANGED
|
@@ -5,9 +5,6 @@ import { MAX_ENTRIES_PER_PAGE } from './entries-constants.js';
|
|
|
5
5
|
import { defineEndpoint } from './route-builder.js';
|
|
6
6
|
import { getSettingsBranchContext, commitSettings } from './settings-helpers.js';
|
|
7
7
|
import { getErrorMessage, sanitizeErrorMessage } from '../utils/error.js';
|
|
8
|
-
// ============================================================================
|
|
9
|
-
// Zod Schemas for Validation
|
|
10
|
-
// ============================================================================
|
|
11
8
|
const permissionTargetSchema = z.object({
|
|
12
9
|
allowedUsers: z.array(z.string()).optional(),
|
|
13
10
|
allowedGroups: z.array(z.string()).optional(),
|
|
@@ -24,18 +21,14 @@ const updatePermissionsBodySchema = z.object({
|
|
|
24
21
|
});
|
|
25
22
|
const searchUsersParamsSchema = z.object({
|
|
26
23
|
q: z.string(),
|
|
27
|
-
// Coerced + range-checked (
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
// request an unbounded page from the auth provider.
|
|
24
|
+
// Coerced + range-checked, not z.string() + an unchecked parseInt() (which silently produced
|
|
25
|
+
// NaN for a non-numeric limit): capped like entries.ts's listEntriesParamsSchema so a caller
|
|
26
|
+
// can't request an unbounded page from the auth provider.
|
|
31
27
|
limit: z.coerce.number().int().min(1).max(MAX_ENTRIES_PER_PAGE).optional(),
|
|
32
28
|
});
|
|
33
29
|
const getUserMetadataParamsSchema = z.object({
|
|
34
30
|
userId: z.string(),
|
|
35
31
|
});
|
|
36
|
-
/**
|
|
37
|
-
* Get current permissions (admin only)
|
|
38
|
-
*/
|
|
39
32
|
const getPermissionsHandler = async (_gc, ctx, _req) => {
|
|
40
33
|
try {
|
|
41
34
|
const result = await getSettingsBranchContext(ctx);
|
|
@@ -58,9 +51,6 @@ const getPermissionsHandler = async (_gc, ctx, _req) => {
|
|
|
58
51
|
};
|
|
59
52
|
}
|
|
60
53
|
};
|
|
61
|
-
/**
|
|
62
|
-
* Update permissions (admin only)
|
|
63
|
-
*/
|
|
64
54
|
const updatePermissionsHandler = async (_gc, ctx, req, body) => {
|
|
65
55
|
if (!body?.permissions) {
|
|
66
56
|
return { ok: false, status: 400, error: 'permissions array required' };
|
|
@@ -85,9 +75,8 @@ const updatePermissionsHandler = async (_gc, ctx, req, body) => {
|
|
|
85
75
|
pathPermissions: body.permissions,
|
|
86
76
|
};
|
|
87
77
|
});
|
|
88
|
-
// Commit and push (mode-aware)
|
|
89
|
-
//
|
|
90
|
-
// that to the client instead of reporting a bare 200.
|
|
78
|
+
// Commit and push (mode-aware): a push failure means the change is saved to the branch
|
|
79
|
+
// working tree but NOT durably persisted — surface that to the client, not a bare 200.
|
|
91
80
|
const commitResult = await commitSettings(ctx, {
|
|
92
81
|
context,
|
|
93
82
|
branchRoot: context.branchRoot,
|
|
@@ -141,18 +130,13 @@ const searchUsersHandler = async (_gc, ctx, req, params) => {
|
|
|
141
130
|
}
|
|
142
131
|
};
|
|
143
132
|
/**
|
|
144
|
-
* List groups (for permission UI)
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
* the auth provider's groups and Canopy's own internal groups from groups.json
|
|
148
|
-
* (see PermissionGroupOption in auth/types.ts). Feeding this endpoint from the
|
|
149
|
-
* auth plugin alone made internally-created groups unreachable from the
|
|
150
|
-
* Permission Manager's picker -- they could only be granted a path permission
|
|
151
|
-
* by hand-editing permissions.json.
|
|
133
|
+
* List groups (for permission UI). Merges BOTH group universes — the auth provider's and
|
|
134
|
+
* Canopy's own internal groups from groups.json (see PermissionGroupOption in auth/types.ts) —
|
|
135
|
+
* since both are valid `allowedGroups` targets.
|
|
152
136
|
*
|
|
153
|
-
* Internal entries are name-only (no members, no memberCount): this endpoint is
|
|
154
|
-
*
|
|
155
|
-
*
|
|
137
|
+
* Internal entries are name-only (no members, no memberCount): this endpoint is `privileged`
|
|
138
|
+
* (admin or reviewer) whereas `groups.getInternal` is admin-only, so member identities and
|
|
139
|
+
* counts must not leak through here.
|
|
156
140
|
*/
|
|
157
141
|
const listGroupsHandler = async (_gc, ctx, _req) => {
|
|
158
142
|
const authPlugin = ctx.authPlugin;
|
|
@@ -168,13 +152,11 @@ const listGroupsHandler = async (_gc, ctx, _req) => {
|
|
|
168
152
|
const { context, mode } = result;
|
|
169
153
|
const file = await loadGroupsFile(context.branchRoot, mode);
|
|
170
154
|
const internalGroups = deriveInternalGroups(file?.groups ?? [], ctx.services.bootstrapAdminIds);
|
|
171
|
-
// Deduplicate by ID, internal first so it wins a collision
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
// (Reserved IDs can never arrive from the provider: stripReservedGroups in
|
|
177
|
-
// user.ts removes them before they reach `user.groups`.)
|
|
155
|
+
// Deduplicate by ID, internal first so it wins a collision: the two ID spaces aren't
|
|
156
|
+
// namespaced against each other, but `checkPathPermission` matches `allowedGroups` by ID
|
|
157
|
+
// string against one flattened `user.groups` list, so two same-ID groups ARE a single
|
|
158
|
+
// permission target — emitting both would misrepresent enforcement. (Reserved IDs never
|
|
159
|
+
// arrive from the provider: stripReservedGroups in user.ts removes them first.)
|
|
178
160
|
const byId = new Map();
|
|
179
161
|
for (const group of internalGroups) {
|
|
180
162
|
byId.set(group.id, {
|
|
@@ -187,9 +169,8 @@ const listGroupsHandler = async (_gc, ctx, _req) => {
|
|
|
187
169
|
for (const group of externalGroups) {
|
|
188
170
|
const collision = byId.get(group.id);
|
|
189
171
|
if (collision) {
|
|
190
|
-
// Keep the internal entry, but record that granting this ID ALSO
|
|
191
|
-
//
|
|
192
|
-
// so an admin isn't shown a name-and-members set narrower than the
|
|
172
|
+
// Keep the internal entry, but record that granting this ID ALSO reaches the provider
|
|
173
|
+
// group's membership, so the picker doesn't show an admin a narrower set than the
|
|
193
174
|
// grant's real reach.
|
|
194
175
|
collision.source = 'both';
|
|
195
176
|
continue;
|
|
@@ -228,9 +209,6 @@ const getUserMetadataHandler = async (_gc, ctx, req, params) => {
|
|
|
228
209
|
};
|
|
229
210
|
}
|
|
230
211
|
};
|
|
231
|
-
// ============================================================================
|
|
232
|
-
// Route Definitions with defineEndpoint
|
|
233
|
-
// ============================================================================
|
|
234
212
|
/**
|
|
235
213
|
* Get current permissions (admin only)
|
|
236
214
|
* GET /permissions
|
|
@@ -4,9 +4,6 @@ import { defineEndpoint } from './route-builder.js';
|
|
|
4
4
|
import { ReferenceResolver } from '../reference-resolver.js';
|
|
5
5
|
import { parseLogicalPath } from '../paths/index.js';
|
|
6
6
|
import { branchNameSchema } from './validators.js';
|
|
7
|
-
// ============================================================================
|
|
8
|
-
// Zod Schemas for Validation
|
|
9
|
-
// ============================================================================
|
|
10
7
|
const getReferenceOptionsParamsSchema = z.object({
|
|
11
8
|
branch: branchNameSchema,
|
|
12
9
|
});
|
|
@@ -68,11 +65,9 @@ const getReferenceOptionsHandler = async (gc, ctx, req, _params) => {
|
|
|
68
65
|
.map((t) => t.trim())
|
|
69
66
|
.filter(Boolean)
|
|
70
67
|
: undefined;
|
|
71
|
-
// Build the access checker once
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
// store.read() that loadReferenceOptions would otherwise do just to compute a
|
|
75
|
-
// label for an option the caller isn't allowed to see.
|
|
68
|
+
// Build the access checker once and pass it in as a filter *before* loading: a denied path is
|
|
69
|
+
// skipped outright, so it never triggers the store.read() that would otherwise compute a label
|
|
70
|
+
// for an option the caller isn't allowed to see.
|
|
76
71
|
const checkAccess = await ctx.services.createContentAccessChecker(branchContext, branchContext.branchRoot, req.user);
|
|
77
72
|
const resolver = new ReferenceResolver(store, idIndex);
|
|
78
73
|
const options = await resolver.loadReferenceOptions(collections, displayField, search, entryTypes, (relativePath) => checkAccess(relativePath, 'read').allowed);
|
|
@@ -82,9 +77,6 @@ const getReferenceOptionsHandler = async (gc, ctx, req, _params) => {
|
|
|
82
77
|
data: { options },
|
|
83
78
|
};
|
|
84
79
|
};
|
|
85
|
-
// ============================================================================
|
|
86
|
-
// Route Definitions
|
|
87
|
-
// ============================================================================
|
|
88
80
|
/**
|
|
89
81
|
* Get reference options for a field
|
|
90
82
|
* GET /:branch/reference-options
|