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
|
@@ -15,12 +15,6 @@ export interface ReferenceOption {
|
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
17
|
* ReferenceResolver resolves content IDs to display values for reference fields.
|
|
18
|
-
*
|
|
19
|
-
* This class provides utilities for:
|
|
20
|
-
* - Resolving a single ID to its display value (e.g., title)
|
|
21
|
-
* - Loading all available options for a reference field
|
|
22
|
-
* - Filtering options by collection constraints
|
|
23
|
-
* - Searching options by display value
|
|
24
18
|
*/
|
|
25
19
|
export declare class ReferenceResolver {
|
|
26
20
|
private store;
|
|
@@ -29,9 +23,6 @@ export declare class ReferenceResolver {
|
|
|
29
23
|
/**
|
|
30
24
|
* Resolve a content ID to a display value.
|
|
31
25
|
* Returns null if the ID doesn't exist or points to a collection.
|
|
32
|
-
*
|
|
33
|
-
* @param id - The content ID to resolve
|
|
34
|
-
* @param displayField - The field to use for display value (default: 'title')
|
|
35
26
|
*/
|
|
36
27
|
resolve(id: string, displayField?: string): Promise<ResolvedReference | null>;
|
|
37
28
|
/**
|
|
@@ -40,10 +31,6 @@ export declare class ReferenceResolver {
|
|
|
40
31
|
* Scans collections (including subcollections) and/or filters by entry type.
|
|
41
32
|
* At least one of `collections` or `entryTypes` should be provided.
|
|
42
33
|
*
|
|
43
|
-
* @param collections - Collection paths to search, including subcollections (e.g., ['data-catalog'])
|
|
44
|
-
* @param displayField - Field to use for option labels (default: 'title')
|
|
45
|
-
* @param search - Optional search string to filter options
|
|
46
|
-
* @param entryTypes - Optional entry type names to filter by (e.g., ['partner'])
|
|
47
34
|
* @param canAccess - Optional permission predicate, called with each candidate's
|
|
48
35
|
* relative path before it is read. Returning false skips the entry entirely --
|
|
49
36
|
* no file I/O, no label, no option -- so a caller who can't read a path never
|
|
@@ -2,12 +2,6 @@ import nodePath from 'node:path';
|
|
|
2
2
|
import { extractSlugFromFilename, extractEntryTypeFromFilename } from './content-id-index.js';
|
|
3
3
|
/**
|
|
4
4
|
* ReferenceResolver resolves content IDs to display values for reference fields.
|
|
5
|
-
*
|
|
6
|
-
* This class provides utilities for:
|
|
7
|
-
* - Resolving a single ID to its display value (e.g., title)
|
|
8
|
-
* - Loading all available options for a reference field
|
|
9
|
-
* - Filtering options by collection constraints
|
|
10
|
-
* - Searching options by display value
|
|
11
5
|
*/
|
|
12
6
|
export class ReferenceResolver {
|
|
13
7
|
constructor(store, idIndex) {
|
|
@@ -17,9 +11,6 @@ export class ReferenceResolver {
|
|
|
17
11
|
/**
|
|
18
12
|
* Resolve a content ID to a display value.
|
|
19
13
|
* Returns null if the ID doesn't exist or points to a collection.
|
|
20
|
-
*
|
|
21
|
-
* @param id - The content ID to resolve
|
|
22
|
-
* @param displayField - The field to use for display value (default: 'title')
|
|
23
14
|
*/
|
|
24
15
|
async resolve(id, displayField = 'title') {
|
|
25
16
|
const location = this.idIndex.findById(id);
|
|
@@ -56,10 +47,6 @@ export class ReferenceResolver {
|
|
|
56
47
|
* Scans collections (including subcollections) and/or filters by entry type.
|
|
57
48
|
* At least one of `collections` or `entryTypes` should be provided.
|
|
58
49
|
*
|
|
59
|
-
* @param collections - Collection paths to search, including subcollections (e.g., ['data-catalog'])
|
|
60
|
-
* @param displayField - Field to use for option labels (default: 'title')
|
|
61
|
-
* @param search - Optional search string to filter options
|
|
62
|
-
* @param entryTypes - Optional entry type names to filter by (e.g., ['partner'])
|
|
63
50
|
* @param canAccess - Optional permission predicate, called with each candidate's
|
|
64
51
|
* relative path before it is read. Returning false skips the entry entirely --
|
|
65
52
|
* no file I/O, no label, no option -- so a caller who can't read a path never
|
|
@@ -69,18 +56,14 @@ export class ReferenceResolver {
|
|
|
69
56
|
const options = [];
|
|
70
57
|
let candidates;
|
|
71
58
|
if (collections && collections.length > 0) {
|
|
72
|
-
// Search within specified collection trees (including subcollections)
|
|
73
|
-
// getCollectionEntryPaths handles normalization (e.g., 'authors' → 'content/authors')
|
|
74
59
|
const results = await Promise.all(collections.map((col) => this.store.getCollectionEntryPaths(col)));
|
|
75
60
|
candidates = results.flat();
|
|
76
61
|
}
|
|
77
62
|
else {
|
|
78
|
-
// No collection scope — search all entries via index
|
|
79
63
|
candidates = this.idIndex
|
|
80
64
|
.getAllEntryLocations()
|
|
81
65
|
.filter((loc) => loc.type === 'entry' && !!loc.collection && !!loc.slug);
|
|
82
66
|
}
|
|
83
|
-
// Filter by entry type if specified
|
|
84
67
|
if (entryTypes && entryTypes.length > 0) {
|
|
85
68
|
candidates = candidates.filter((loc) => {
|
|
86
69
|
const entryType = extractEntryTypeFromFilename(nodePath.basename(loc.relativePath));
|
|
@@ -101,7 +84,6 @@ export class ReferenceResolver {
|
|
|
101
84
|
const normalizedSlug = extractSlugFromFilename(filename);
|
|
102
85
|
const doc = await this.store.read(location.collection, normalizedSlug);
|
|
103
86
|
const label = String(doc.data[displayField] || doc.data.title || normalizedSlug);
|
|
104
|
-
// Apply search filter if provided
|
|
105
87
|
if (search && !label.toLowerCase().includes(search.toLowerCase())) {
|
|
106
88
|
continue;
|
|
107
89
|
}
|
|
@@ -1,33 +1,31 @@
|
|
|
1
1
|
import type { AuthenticationResult } from './auth/types.js';
|
|
2
2
|
import type { CanopyUser } from './user.js';
|
|
3
3
|
import type { OperatingMode } from './operating-mode/index.js';
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Test-only: reset the once-per-process "no admins configured" warning latch.
|
|
6
|
+
* @internal No importer; deletion candidate in knip-no-importer-deletion-candidates.md.
|
|
7
|
+
*/
|
|
5
8
|
export declare function resetResolveCanopyUserWarningForTests(): void;
|
|
6
9
|
export interface ResolveCanopyUserDeps {
|
|
7
10
|
/**
|
|
8
|
-
* Resolves (and ensures) the settings workspace root. Internal groups are
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* content branch clone.
|
|
11
|
+
* Resolves (and ensures) the settings workspace root. Internal groups are the
|
|
12
|
+
* single source of truth for group-based privileges and MUST be loaded from
|
|
13
|
+
* here — the same root `createContentAccessChecker` (authorization/content.ts)
|
|
14
|
+
* uses for path permissions — never from a content branch clone.
|
|
13
15
|
*
|
|
14
|
-
*
|
|
15
|
-
* `createContentAccessChecker`'s fail-loud contract: a
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* degradation.
|
|
16
|
+
* MUST THROW if the settings workspace cannot be ensured, matching
|
|
17
|
+
* `createContentAccessChecker`'s fail-loud contract: a silent fallback to an
|
|
18
|
+
* empty group list reads as "no privileges", which is a silent authorization
|
|
19
|
+
* change rather than a safe degradation.
|
|
19
20
|
*/
|
|
20
21
|
getSettingsBranchRoot: () => Promise<string>;
|
|
21
22
|
mode: OperatingMode;
|
|
22
23
|
bootstrapAdminIds: Set<string>;
|
|
23
24
|
}
|
|
24
25
|
/**
|
|
25
|
-
* Resolve the CanopyUser for a request: load internal groups from the
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* Framework-agnostic: callers supply the already-computed `authResult` (from
|
|
30
|
-
* whatever auth-plugin invocation their transport uses) and a small deps
|
|
31
|
-
* bag drawn from `CanopyServices`.
|
|
26
|
+
* Resolve the CanopyUser for a request: load internal groups from the settings
|
|
27
|
+
* workspace and merge them, plus bootstrap admins, into an authentication result
|
|
28
|
+
* via `authResultToCanopyUser`. Framework-agnostic — callers supply the
|
|
29
|
+
* already-computed `authResult` and a small deps bag from `CanopyServices`.
|
|
32
30
|
*/
|
|
33
31
|
export declare function resolveCanopyUser(authResult: AuthenticationResult, deps: ResolveCanopyUserDeps): Promise<CanopyUser>;
|
|
@@ -1,29 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* pipeline.
|
|
2
|
+
* The shared "authenticate -> resolve internal groups -> merge into CanopyUser"
|
|
3
|
+
* pipeline: the single resolution point for `http/handler.ts` and
|
|
4
|
+
* `canopycms-next`'s `context-wrapper.ts`, so the two cannot diverge over where
|
|
5
|
+
* group-based privileges come from.
|
|
4
6
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* groups from the BASE BRANCH content clone's `groups.json`, which nothing
|
|
10
|
-
* in the product ever writes (writes go to the settings workspace via
|
|
11
|
-
* `mutateGroupsFile` - `api/groups.ts`), so group-based privileges never
|
|
12
|
-
* actually took effect. Consolidating the pipeline here means both callers
|
|
13
|
-
* read from the same place and cannot silently diverge again.
|
|
14
|
-
*
|
|
15
|
-
* canopyLogWarn, not console.warn: this module has no worker-specific logic,
|
|
16
|
-
* but nothing prevents it from becoming reachable from the worker's runtime
|
|
17
|
-
* import closure later, and the existing "no admins configured" warning is
|
|
18
|
-
* exactly the kind of operationally interesting line that must not be
|
|
19
|
-
* silently folded into an unrelated worker.log event (see utils/logger.ts).
|
|
7
|
+
* canopyLogWarn, not console.warn: nothing prevents this module from becoming
|
|
8
|
+
* reachable from the worker's runtime import closure, and the "no admins
|
|
9
|
+
* configured" warning must not be folded silently into an unrelated worker.log
|
|
10
|
+
* event (see utils/logger.ts).
|
|
20
11
|
*/
|
|
21
12
|
import { canopyLogWarn } from './utils/logger.js';
|
|
22
13
|
import { authResultToCanopyUser } from './user.js';
|
|
23
14
|
import { loadInternalGroups, RESERVED_GROUPS } from './authorization/index.js';
|
|
24
|
-
/** Module-level
|
|
15
|
+
/** Module-level: warn at most once per process. */
|
|
25
16
|
let warnedNoAdmins = false;
|
|
26
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Test-only: reset the once-per-process "no admins configured" warning latch.
|
|
19
|
+
* @internal No importer; deletion candidate in knip-no-importer-deletion-candidates.md.
|
|
20
|
+
*/
|
|
27
21
|
export function resetResolveCanopyUserWarningForTests() {
|
|
28
22
|
warnedNoAdmins = false;
|
|
29
23
|
}
|
|
@@ -38,13 +32,10 @@ function warnIfNoAdmins(internalGroups, bootstrapAdminIds) {
|
|
|
38
32
|
warnedNoAdmins = true;
|
|
39
33
|
}
|
|
40
34
|
/**
|
|
41
|
-
* Resolve the CanopyUser for a request: load internal groups from the
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* Framework-agnostic: callers supply the already-computed `authResult` (from
|
|
46
|
-
* whatever auth-plugin invocation their transport uses) and a small deps
|
|
47
|
-
* bag drawn from `CanopyServices`.
|
|
35
|
+
* Resolve the CanopyUser for a request: load internal groups from the settings
|
|
36
|
+
* workspace and merge them, plus bootstrap admins, into an authentication result
|
|
37
|
+
* via `authResultToCanopyUser`. Framework-agnostic — callers supply the
|
|
38
|
+
* already-computed `authResult` and a small deps bag from `CanopyServices`.
|
|
48
39
|
*/
|
|
49
40
|
export async function resolveCanopyUser(authResult, deps) {
|
|
50
41
|
const settingsRoot = await deps.getSettingsBranchRoot();
|
|
@@ -2,13 +2,9 @@
|
|
|
2
2
|
export declare function resourceGenerationPath(root: string, resource: string): string;
|
|
3
3
|
export interface BumpResourceGenerationOptions {
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* callers must not silently succeed while leaving stale readers unaware.
|
|
9
|
-
* Default false (hint flavor): log-warn and swallow, since the mutation
|
|
10
|
-
* itself is already durable and a lost bump only degrades to pre-marker
|
|
11
|
-
* staleness behavior plus whatever backstop the consumer has.
|
|
5
|
+
* Rethrow a failed bump instead of logging and swallowing it. Set it where a
|
|
6
|
+
* lost bump means indefinitely stale durable data with no bounding backstop
|
|
7
|
+
* (e.g. a registry's invalidate()). Default false.
|
|
12
8
|
*/
|
|
13
9
|
mustSucceed?: boolean;
|
|
14
10
|
}
|
|
@@ -17,16 +13,15 @@ export interface BumpResourceGenerationOptions {
|
|
|
17
13
|
* processes rebuild. Must be called AFTER the filesystem mutation.
|
|
18
14
|
*
|
|
19
15
|
* Returns the token written, or null if the write failed and `mustSucceed`
|
|
20
|
-
* was not set
|
|
16
|
+
* was not set.
|
|
21
17
|
*/
|
|
22
18
|
export declare function bumpResourceGeneration(root: string, resource: string, options?: BumpResourceGenerationOptions): Promise<string | null>;
|
|
23
19
|
/**
|
|
24
|
-
* Result of reading a generation marker. `ok: false` means the read failed
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* distinguishable from "we don't actually know the current token".
|
|
20
|
+
* Result of reading a generation marker. `ok: false` means the read failed for
|
|
21
|
+
* a reason OTHER than "marker doesn't exist yet"; callers force-regenerate
|
|
22
|
+
* rather than folding it into a token value, because a legitimate snapshot can
|
|
23
|
+
* embed `token: null` (a fresh clone regenerated before any bump) and that must
|
|
24
|
+
* stay distinguishable from "we don't know the current token".
|
|
30
25
|
*/
|
|
31
26
|
export type GenerationReadResult = {
|
|
32
27
|
ok: true;
|
|
@@ -35,19 +30,15 @@ export type GenerationReadResult = {
|
|
|
35
30
|
ok: false;
|
|
36
31
|
};
|
|
37
32
|
/**
|
|
38
|
-
* Read the current generation token for `resource` under `root`.
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* distinct from every real token. Any OTHER read error maps to `{ok: false}`
|
|
42
|
-
* (logged) so callers can force-regenerate instead of trusting a null they
|
|
43
|
-
* cannot actually attribute to "never bumped".
|
|
33
|
+
* Read the current generation token for `resource` under `root`. ENOENT maps to
|
|
34
|
+
* `{ok: true, token: null}`, the "never bumped" state; every other read error
|
|
35
|
+
* maps to `{ok: false}`.
|
|
44
36
|
*/
|
|
45
37
|
export declare function readResourceGeneration(root: string, resource: string): Promise<GenerationReadResult>;
|
|
46
38
|
/**
|
|
47
|
-
* True when a
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* safe default is to treat it as stale.
|
|
39
|
+
* True when a snapshot's captured token is still current: the read succeeded
|
|
40
|
+
* AND its token matches. A failed read (`ok: false`) is never current, even
|
|
41
|
+
* against a null snapshot token — an unreadable marker vouches for nothing, so
|
|
42
|
+
* the safe default is stale.
|
|
52
43
|
*/
|
|
53
44
|
export declare function isGenerationCurrent(snapshotToken: string | null, read: GenerationReadResult): boolean;
|
|
@@ -5,93 +5,34 @@ import { atomicWriteFile } from './utils/atomic-write.js';
|
|
|
5
5
|
import { getErrorMessage, isNodeError } from './utils/error.js';
|
|
6
6
|
import { createDebugLogger } from './utils/debug.js';
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* Cross-process generation marker for an on-disk resource cached under a
|
|
9
|
+
* branch-clone root: several warm Lambda containers and the EC2 worker share
|
|
10
|
+
* those clones on EFS with no shared memory and no cross-host file watching,
|
|
11
|
+
* so the filesystem coordinates. The marker for `resource` lives at
|
|
12
|
+
* {root}/.canopy-meta/{resource}.generation — dot-prefixed so content and
|
|
13
|
+
* index scans skip it, and excluded from git via .git/info/exclude.
|
|
10
14
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
15
|
+
* - Mutators bump AFTER mutating, with a fresh random token: a counter would
|
|
16
|
+
* need read-modify-write and lose concurrent bumps without a lock.
|
|
17
|
+
* - Regenerators capture the token BEFORE scanning and embed it in the
|
|
18
|
+
* snapshot; readers compare that token against the live marker and
|
|
19
|
+
* regenerate on mismatch. A regeneration racing an invalidation embeds the
|
|
20
|
+
* old token, so it self-describes as stale and heals on the next read.
|
|
21
|
+
* - Regeneration returns its own scan result and never loops until the tokens
|
|
22
|
+
* match, which would livelock under a bump storm.
|
|
23
|
+
* - `mustSucceed` bumps explicit invalidations, where a swallowed failure
|
|
24
|
+
* means indefinite staleness; bulk `finally`-block callers take the default
|
|
25
|
+
* log-and-swallow hint bump.
|
|
26
|
+
* - A marker read error other than ENOENT stays distinct from "never bumped":
|
|
27
|
+
* the consumer serves the fresh scan but skips persisting a snapshot whose
|
|
28
|
+
* token it cannot attribute to that scan.
|
|
20
29
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* Readers only need "did it change since I captured it", so inequality against
|
|
28
|
-
* the captured value suffices. A counter would need read-modify-write, which
|
|
29
|
-
* silently loses concurrent bumps without a lock (two bumpers read 5, both
|
|
30
|
-
* write 6 — a reader that recorded 6 after the first bump never learns of the
|
|
31
|
-
* second mutation). A unique token per bump has no lost-update problem, needs
|
|
32
|
-
* no lock, and avoids NFS mtime-granularity / cross-host clock-skew issues.
|
|
33
|
-
* Each bump is a single atomic temp-file + rename.
|
|
34
|
-
*
|
|
35
|
-
* ## Ordering protocol (correctness)
|
|
36
|
-
*
|
|
37
|
-
* - Bumpers write the marker strictly AFTER their filesystem mutations.
|
|
38
|
-
* - Readers capture the marker token strictly BEFORE scanning/rebuilding the
|
|
39
|
-
* resource, and record it only after the rebuild completes. A bump landing
|
|
40
|
-
* mid-rebuild therefore leaves the recorded token older than the file,
|
|
41
|
-
* forcing another rebuild on the next probe.
|
|
42
|
-
*
|
|
43
|
-
* ## Consistency guarantees and residual staleness windows (EFS/NFSv4)
|
|
44
|
-
*
|
|
45
|
-
* Guaranteed: any completed mutation that bumps the marker is observed by
|
|
46
|
-
* every consumer on that root at its next freshness probe. Residual windows
|
|
47
|
-
* (bounded in practice by per-request lifetimes and, where implemented, a
|
|
48
|
-
* suspicious-lookup backstop):
|
|
49
|
-
*
|
|
50
|
-
* - (A) NFS attribute caching (benign direction): another host may not see a
|
|
51
|
-
* new marker for up to the attribute-cache timeout (~3-60s on default EFS
|
|
52
|
-
* mounts; `noac` cannot be assumed). The reader acts on a stale token and
|
|
53
|
-
* keeps a stale snapshot until the cache expires.
|
|
54
|
-
* - (B) Probe throttle: however long the consumer debounces freshness checks.
|
|
55
|
-
* - (C) Self-adoption: after its own mutation a consumer adopts the token it
|
|
56
|
-
* wrote; if a concurrent foreign bump landed just before ours, we miss that
|
|
57
|
-
* one notification (window: from our last token observation to our rename).
|
|
58
|
-
* - (E) Fresh-token/stale-scan (malignant direction, cross-host only): NFS
|
|
59
|
-
* revalidates the marker file on open, but a rebuild's reads may be served
|
|
60
|
-
* from dentry/attribute caches — a rebuild can record a NEW token against
|
|
61
|
-
* PRE-mutation data, leaving that consumer confidently stale until the next
|
|
62
|
-
* bump. Structurally unfixable with a filesystem marker; bounded by
|
|
63
|
-
* per-request lifetimes and any backstop the consumer implements.
|
|
64
|
-
*
|
|
65
|
-
* ## Guarantee delta for DURABLE snapshot consumers (registry / schema-cache)
|
|
66
|
-
*
|
|
67
|
-
* The in-memory ContentIdIndex tolerates window (E) because a stale index is
|
|
68
|
-
* scoped to one process's memory: it self-heals on the next probe or process
|
|
69
|
-
* recycle, and a wrong-file write is independently guarded by ContentStore's
|
|
70
|
-
* existence check. Consumers that persist a durable snapshot ALONGSIDE this
|
|
71
|
-
* marker — a branch registry list, a resolved-schema cache file — do not get
|
|
72
|
-
* that same containment. If such a consumer's regeneration scan is served
|
|
73
|
-
* from stale NFS dentry/attribute caches, window (E) produces a snapshot that
|
|
74
|
-
* embeds a FRESH token over STALE data, and that snapshot is written to disk.
|
|
75
|
-
* Every other host that reads the marker sees the fresh token, concludes the
|
|
76
|
-
* durable snapshot is current, and serves the stale data too — this is now a
|
|
77
|
-
* durable, SHARED staleness visible to all hosts until the next bump, not a
|
|
78
|
-
* transient one-process condition. A random token cannot distinguish "fresh
|
|
79
|
-
* token over fresh data" from "fresh token over stale data" — the token only
|
|
80
|
-
* proves a bump happened, not that the bumping host's own scan observed it.
|
|
81
|
-
*
|
|
82
|
-
* Durable-snapshot consumers must therefore implement mitigations this module
|
|
83
|
-
* cannot provide on their behalf:
|
|
84
|
-
*
|
|
85
|
-
* - Eager regeneration on the mutating host, performed immediately after its
|
|
86
|
-
* own bump (in the same request/operation). That host's own scan is
|
|
87
|
-
* necessarily coherent with the mutation it just made (no NFS round trip
|
|
88
|
-
* was needed to observe its own writes), so regenerating there rather than
|
|
89
|
-
* waiting for a lazy pull on some other host avoids handing window (E) a
|
|
90
|
-
* chance to run at all for the common case.
|
|
91
|
-
* - A get-miss / suspicious-lookup backstop: if a consumer looks up something
|
|
92
|
-
* that "should" exist per the durable snapshot but is missing (or vice
|
|
93
|
-
* versa), that mismatch is a signal to force a fresh regeneration rather
|
|
94
|
-
* than trusting the token match, bounding how long a bad snapshot survives.
|
|
30
|
+
* A consumer that persists its snapshot (branch registry, schema cache) can
|
|
31
|
+
* durably record a fresh token over data its scan read from a stale NFS cache,
|
|
32
|
+
* which every other host then trusts. So the mutating host regenerates eagerly
|
|
33
|
+
* right after its own bump — that scan is coherent with its own mutation — and
|
|
34
|
+
* the registry adds a suspicious-miss backstop. Staleness windows (A/B/C/E) and
|
|
35
|
+
* the rolling-deploy transient: docs/concurrency.md, "Residual staleness windows".
|
|
95
36
|
*/
|
|
96
37
|
const log = createDebugLogger({ prefix: 'ResourceGeneration' });
|
|
97
38
|
const META_DIR = '.canopy-meta';
|
|
@@ -104,7 +45,7 @@ export function resourceGenerationPath(root, resource) {
|
|
|
104
45
|
* processes rebuild. Must be called AFTER the filesystem mutation.
|
|
105
46
|
*
|
|
106
47
|
* Returns the token written, or null if the write failed and `mustSucceed`
|
|
107
|
-
* was not set
|
|
48
|
+
* was not set.
|
|
108
49
|
*/
|
|
109
50
|
export async function bumpResourceGeneration(root, resource, options) {
|
|
110
51
|
const token = randomUUID();
|
|
@@ -122,12 +63,9 @@ export async function bumpResourceGeneration(root, resource, options) {
|
|
|
122
63
|
}
|
|
123
64
|
}
|
|
124
65
|
/**
|
|
125
|
-
* Read the current generation token for `resource` under `root`.
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
* distinct from every real token. Any OTHER read error maps to `{ok: false}`
|
|
129
|
-
* (logged) so callers can force-regenerate instead of trusting a null they
|
|
130
|
-
* cannot actually attribute to "never bumped".
|
|
66
|
+
* Read the current generation token for `resource` under `root`. ENOENT maps to
|
|
67
|
+
* `{ok: true, token: null}`, the "never bumped" state; every other read error
|
|
68
|
+
* maps to `{ok: false}`.
|
|
131
69
|
*/
|
|
132
70
|
export async function readResourceGeneration(root, resource) {
|
|
133
71
|
try {
|
|
@@ -144,11 +82,10 @@ export async function readResourceGeneration(root, resource) {
|
|
|
144
82
|
}
|
|
145
83
|
}
|
|
146
84
|
/**
|
|
147
|
-
* True when a
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
* safe default is to treat it as stale.
|
|
85
|
+
* True when a snapshot's captured token is still current: the read succeeded
|
|
86
|
+
* AND its token matches. A failed read (`ok: false`) is never current, even
|
|
87
|
+
* against a null snapshot token — an unreadable marker vouches for nothing, so
|
|
88
|
+
* the safe default is stale.
|
|
152
89
|
*/
|
|
153
90
|
export function isGenerationCurrent(snapshotToken, read) {
|
|
154
91
|
return read.ok && read.token === snapshotToken;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RootCollectionConfig } from '../config/index.js';
|
|
2
2
|
import type { ContentId } from '../paths/types.js';
|
|
3
3
|
import type { EntrySchemaRegistry } from './types.js';
|
|
4
|
-
|
|
4
|
+
type EntryTypeMeta = {
|
|
5
5
|
name: string;
|
|
6
6
|
format: 'md' | 'mdx' | 'json' | 'yaml';
|
|
7
7
|
schema: string;
|
|
@@ -23,11 +23,6 @@ export type RootCollectionMeta = {
|
|
|
23
23
|
/**
|
|
24
24
|
* Loads all .collection.json meta files from contentRoot, including root.
|
|
25
25
|
*
|
|
26
|
-
* This function orchestrates the complete discovery process:
|
|
27
|
-
* 1. Attempts to load the root .collection.json (contentRoot/.collection.json) - optional
|
|
28
|
-
* 2. Recursively scans all subdirectories for .collection.json files
|
|
29
|
-
* 3. Returns both root configuration and nested collections
|
|
30
|
-
*
|
|
31
26
|
* Meta File Structure:
|
|
32
27
|
* - Root: contentRoot/.collection.json (optional, defines root-level entry types)
|
|
33
28
|
* - Collections: contentRoot/[path]/.collection.json (defines collection in that directory)
|
|
@@ -49,11 +44,6 @@ export declare function loadCollectionMetaFiles(contentRoot: string): Promise<{
|
|
|
49
44
|
* This function takes the loaded meta files (which contain string references like "postSchema")
|
|
50
45
|
* and resolves them to actual EntrySchema arrays from the entry schema registry.
|
|
51
46
|
*
|
|
52
|
-
* Resolution Process:
|
|
53
|
-
* 1. Root entry types: Resolve "schema" string to entry schema registry lookup
|
|
54
|
-
* 2. Top-level collections: Resolve recursively, building nested tree structure
|
|
55
|
-
* 3. Nested collections: Automatically grouped under their parent collections
|
|
56
|
-
*
|
|
57
47
|
* @param metaFiles - Loaded meta files from loadCollectionMetaFiles()
|
|
58
48
|
* @param entrySchemaRegistry - Map of schema names to EntrySchema arrays
|
|
59
49
|
* @returns Fully resolved root collection config ready for use by CanopyCMS
|
|
@@ -66,7 +56,5 @@ export declare function resolveCollectionReferences(metaFiles: {
|
|
|
66
56
|
contentId?: ContentId;
|
|
67
57
|
}>;
|
|
68
58
|
}, entrySchemaRegistry: EntrySchemaRegistry): RootCollectionConfig;
|
|
69
|
-
/**
|
|
70
|
-
* Watch for changes to .collection.json files
|
|
71
|
-
*/
|
|
72
59
|
export declare function watchCollectionMetaFiles(contentRoot: string, onChange: () => void): () => void;
|
|
60
|
+
export {};
|