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
|
@@ -12,16 +12,11 @@ const MTIME_CHECK_DEBOUNCE_MS = 1000;
|
|
|
12
12
|
/** resource-generation.ts resource key for the schema cache's marker. */
|
|
13
13
|
export const SCHEMA_GENERATION_RESOURCE = 'schema';
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
16
|
-
* modified more recently than cachedAt. Returns true if stale.
|
|
15
|
+
* True when a .collection.json under `dir` is newer than `cachedAt`.
|
|
17
16
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* This is a dev-only convenience for out-of-band hand edits made directly to
|
|
22
|
-
* .collection.json files outside the CMS (which don't go through SchemaOps
|
|
23
|
-
* and therefore never bump the generation marker below). It is not needed for
|
|
24
|
-
* prod correctness: every mutation path that matters in prod bumps the marker.
|
|
17
|
+
* Dev-only, and dev-only on purpose: it catches hand edits made outside the
|
|
18
|
+
* CMS, which bypass SchemaOps and so never bump the marker. Every prod mutation
|
|
19
|
+
* path does bump it, so the marker alone is sufficient there.
|
|
25
20
|
*/
|
|
26
21
|
async function isStaleByMtime(dir, cachedAt) {
|
|
27
22
|
let entries;
|
|
@@ -48,75 +43,18 @@ async function isStaleByMtime(dir, cachedAt) {
|
|
|
48
43
|
return false;
|
|
49
44
|
}
|
|
50
45
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* ## Cross-process freshness (resource-generation.ts marker protocol)
|
|
55
|
-
*
|
|
56
|
-
* Several warm Lambda containers plus the EC2 worker can share one
|
|
57
|
-
* branch-clone root over EFS, each with its own copy of
|
|
58
|
-
* `schema-cache.json`. There is no shared memory and no cross-host file
|
|
59
|
-
* watching, so freshness is coordinated via the generic on-disk generation
|
|
60
|
-
* marker in resource-generation.ts: every cached snapshot embeds the marker
|
|
61
|
-
* token it was resolved against, and every read cheaply re-checks the live
|
|
62
|
-
* marker before trusting the cache. See that module's doc comment for the
|
|
63
|
-
* full protocol and residual staleness windows (A/B/C/E).
|
|
64
|
-
*
|
|
65
|
-
* BranchSchemaCache is the "durable snapshot consumer" case called out there:
|
|
66
|
-
* a resolve whose scan is served from stale NFS dentry/attribute caches can
|
|
67
|
-
* record a FRESH token over STALE data (window E), and because the result is
|
|
68
|
-
* written to `schema-cache.json`, that staleness becomes durable and shared
|
|
69
|
-
* with every other host that reads the marker - not just one process's
|
|
70
|
-
* memory. `loadFromCacheOrResolve` mitigates this the same way
|
|
71
|
-
* BranchRegistry does:
|
|
46
|
+
* Per-branch schema cache: a file at {branchRoot}/.canopy-meta/schema-cache.json
|
|
47
|
+
* with no in-memory layer, so it stays coherent across Lambda invocations.
|
|
72
48
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* from a correctly-attributed one to every future reader. The fresh result
|
|
83
|
-
* is still served to this caller; it just isn't written durably.
|
|
84
|
-
* - invalidate() bumps the marker with `mustSucceed: true`: an explicit
|
|
85
|
-
* invalidation (e.g. after a schema mutation) must not silently fail and
|
|
86
|
-
* leave every reader confidently stale with no bounding backstop.
|
|
87
|
-
* invalidate() itself does NOT eager-regenerate - it isn't given the
|
|
88
|
-
* entrySchemaRegistry/contentRootName that resolveSchema needs. The
|
|
89
|
-
* eager re-resolve (window-E mitigation, mirroring BranchRegistry's
|
|
90
|
-
* eager regen) lives one level up in SchemaOps.invalidateSchemaCache()
|
|
91
|
-
* (schema/schema-store.ts), which has those arguments and calls
|
|
92
|
-
* {@link resolveAndPersist} (NOT getSchema()) right after invalidating -
|
|
93
|
-
* so every SchemaOps mutation re-resolves on the mutating host via a scan
|
|
94
|
-
* that is GUARANTEED to run, not merely likely to run. getSchema() would
|
|
95
|
-
* be the wrong call here: its cache-read fast path can short-circuit
|
|
96
|
-
* through a snapshot a DIFFERENT concurrent host just wrote (see
|
|
97
|
-
* resolveAndPersist()'s doc comment for the exact race), silently
|
|
98
|
-
* skipping the one scan this eager re-resolve exists to guarantee. (The
|
|
99
|
-
* editor's follow-up schema GET is a separate Lambda invocation with no
|
|
100
|
-
* container affinity, so it could not serve this purpose either.)
|
|
101
|
-
* Callers of invalidate() that bypass SchemaOps (api/schema.ts's explicit
|
|
102
|
-
* invalidate endpoint; the bulk-mutation bump in
|
|
103
|
-
* invalidateBranchContentCaches) accept the lazy next-read regen.
|
|
104
|
-
*
|
|
105
|
-
* This is also why prod needs no mtime walk: the dev-only mtime check below
|
|
106
|
-
* exists solely to catch hand edits to .collection.json made outside the CMS
|
|
107
|
-
* (which bypass SchemaOps and therefore never bump the marker). Every
|
|
108
|
-
* mutation path that matters in prod - SchemaOps writes, git working-tree
|
|
109
|
-
* rewrites (checkout/merge/rebase/sync/migrate) - bumps the marker via
|
|
110
|
-
* SchemaOps.invalidateSchemaCache() or the combined
|
|
111
|
-
* invalidateBranchContentCaches() helper in content-index-generation.ts, so
|
|
112
|
-
* the marker alone is a sufficient prod backstop.
|
|
113
|
-
*
|
|
114
|
-
* Caching Strategy:
|
|
115
|
-
* - File-based cache at {branchRoot}/.canopy-meta/schema-cache.json (no
|
|
116
|
-
* in-memory layer - intentional: matches prod behavior and keeps cache
|
|
117
|
-
* coherent across Lambda invocations)
|
|
118
|
-
* - Invalidation: invalidate() bumps the cross-process generation marker;
|
|
119
|
-
* every reader sharing this branchRoot re-resolves at its next access.
|
|
49
|
+
* Freshness follows the generation-marker protocol owned by
|
|
50
|
+
* resource-generation.ts, and this is one of that protocol's durable-snapshot
|
|
51
|
+
* consumers. Its eager re-resolve lives one level up, in
|
|
52
|
+
* `SchemaOps.invalidateSchemaCache()` (schema/schema-store.ts), because that is
|
|
53
|
+
* where the entrySchemaRegistry/contentRootName arguments {@link invalidate}
|
|
54
|
+
* lacks are available; it calls {@link resolveAndPersist}, never getSchema().
|
|
55
|
+
* Callers that bypass SchemaOps (api/schema.ts's invalidate endpoint, and the
|
|
56
|
+
* bulk git-op bump in invalidateBranchContentCaches) accept the lazy
|
|
57
|
+
* next-read regen instead.
|
|
120
58
|
*/
|
|
121
59
|
export class BranchSchemaCache {
|
|
122
60
|
constructor(mode = 'prod') {
|
|
@@ -127,42 +65,28 @@ export class BranchSchemaCache {
|
|
|
127
65
|
/**
|
|
128
66
|
* Whether to skip the on-disk cache for this branchRoot.
|
|
129
67
|
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* the project root, regardless of which entrypoint produced the cwd branchRoot.
|
|
68
|
+
* Never write `.canopy-meta/` at the project root, whichever entrypoint
|
|
69
|
+
* produced the cwd branchRoot. branchRoot equals process.cwd() only in the
|
|
70
|
+
* synthetic contexts static deployments and build phases use; a real branch
|
|
71
|
+
* root is always nested under the workspace.
|
|
135
72
|
*/
|
|
136
73
|
skipDiskCache(branchRoot) {
|
|
137
74
|
return isBuildMode() || path.resolve(branchRoot) === path.resolve(process.cwd());
|
|
138
75
|
}
|
|
139
|
-
/**
|
|
140
|
-
* Get schema for a branch (loads from cache or resolves fresh).
|
|
141
|
-
*
|
|
142
|
-
* @param branchRoot - Root directory of the branch (e.g., .canopy-dev/content-branches/main)
|
|
143
|
-
* @param entrySchemaRegistry - Map of schema names to field definitions
|
|
144
|
-
* @param contentRootName - Name of content directory (e.g., "content") from config
|
|
145
|
-
* @returns Resolved schema tree and flattened schema
|
|
146
|
-
*/
|
|
76
|
+
/** Get schema for a branch, from the cache when fresh, else resolved fresh. */
|
|
147
77
|
async getSchema(branchRoot, entrySchemaRegistry, contentRootName = 'content') {
|
|
148
78
|
return this.loadFromCacheOrResolve(branchRoot, entrySchemaRegistry, contentRootName);
|
|
149
79
|
}
|
|
150
80
|
/**
|
|
151
|
-
* Resolve the schema from disk.
|
|
152
|
-
*
|
|
153
|
-
* override with a deferred/blocking implementation to simulate cross-process
|
|
81
|
+
* Resolve the schema from disk. Protected rather than a direct resolveSchema
|
|
82
|
+
* call so tests can subclass and block it to simulate cross-process
|
|
154
83
|
* interleavings — mirrors BranchRegistry's scanBranchDirectories() hook.
|
|
155
84
|
*/
|
|
156
85
|
async resolveFresh(contentRoot, entrySchemaRegistry) {
|
|
157
86
|
return resolveSchema(contentRoot, entrySchemaRegistry);
|
|
158
87
|
}
|
|
159
|
-
/**
|
|
160
|
-
* Load schema from cache or resolve fresh if cache is missing or stale.
|
|
161
|
-
*/
|
|
162
88
|
async loadFromCacheOrResolve(branchRoot, entrySchemaRegistry, contentRootName) {
|
|
163
89
|
const contentRoot = path.join(branchRoot, contentRootName);
|
|
164
|
-
// In static/build mode, branchRoot is process.cwd() (the project root).
|
|
165
|
-
// Skip disk cache to avoid creating .canopy-meta/ at the project root.
|
|
166
90
|
const skipDiskCache = this.skipDiskCache(branchRoot);
|
|
167
91
|
if (!skipDiskCache) {
|
|
168
92
|
const cacheDir = path.join(branchRoot, '.canopy-meta');
|
|
@@ -176,16 +100,13 @@ export class BranchSchemaCache {
|
|
|
176
100
|
// Cache doesn't exist or can't be read
|
|
177
101
|
cacheData = null;
|
|
178
102
|
}
|
|
179
|
-
// Strict version check: a
|
|
180
|
-
//
|
|
181
|
-
//
|
|
182
|
-
// rather than a real token or explicit `null`, breaking the freshness
|
|
183
|
-
// comparison below.
|
|
103
|
+
// Strict version check, not truthiness: a snapshot from an older version
|
|
104
|
+
// left on EFS by a rolling deploy has no `generation` field, and an
|
|
105
|
+
// `undefined` token breaks the freshness comparison below.
|
|
184
106
|
if (cacheData && cacheData.version === SCHEMA_CACHE_VERSION) {
|
|
185
107
|
const read = await readResourceGeneration(branchRoot, SCHEMA_GENERATION_RESOURCE);
|
|
186
108
|
if (isGenerationCurrent(cacheData.generation, read)) {
|
|
187
|
-
//
|
|
188
|
-
// Debounce: skip the walk if we checked this contentRoot within the last second.
|
|
109
|
+
// Dev also walks mtimes, debounced, to catch edits made outside the CMS.
|
|
189
110
|
const now = Date.now();
|
|
190
111
|
const lastCheck = this.lastMtimeCheck.get(contentRoot) ?? 0;
|
|
191
112
|
if (this.devMode &&
|
|
@@ -209,8 +130,6 @@ export class BranchSchemaCache {
|
|
|
209
130
|
cacheData = null;
|
|
210
131
|
}
|
|
211
132
|
}
|
|
212
|
-
// Cache miss, stale, or build mode - resolve fresh (and persist, subject
|
|
213
|
-
// to the same skip-persist rule) via the shared resolve half.
|
|
214
133
|
return this.resolveFreshAndPersist(branchRoot, entrySchemaRegistry, contentRootName, {
|
|
215
134
|
skipDiskCache,
|
|
216
135
|
});
|
|
@@ -224,10 +143,9 @@ export class BranchSchemaCache {
|
|
|
224
143
|
async resolveFreshAndPersist(branchRoot, entrySchemaRegistry, contentRootName, options) {
|
|
225
144
|
const { skipDiskCache } = options;
|
|
226
145
|
const contentRoot = path.join(branchRoot, contentRootName);
|
|
227
|
-
// Capture the marker strictly BEFORE resolving
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
// token over pre-mutation data.
|
|
146
|
+
// Capture the marker strictly BEFORE resolving, so a bump landing
|
|
147
|
+
// mid-resolve differs from the token persisted below and forces a
|
|
148
|
+
// re-resolve on the next read.
|
|
231
149
|
const read = skipDiskCache
|
|
232
150
|
? null
|
|
233
151
|
: await readResourceGeneration(branchRoot, SCHEMA_GENERATION_RESOURCE);
|
|
@@ -250,9 +168,8 @@ export class BranchSchemaCache {
|
|
|
250
168
|
if (!skipDiskCache) {
|
|
251
169
|
const cacheDir = path.join(branchRoot, '.canopy-meta');
|
|
252
170
|
const cachePath = path.join(cacheDir, 'schema-cache.json');
|
|
253
|
-
// Opportunistic cleanup of the
|
|
254
|
-
//
|
|
255
|
-
// may find one left over from before the deploy). Not load-bearing.
|
|
171
|
+
// Opportunistic cleanup of the retired .stale marker file, which a
|
|
172
|
+
// mid-flight deploy can leave behind. Not load-bearing.
|
|
256
173
|
await fs.unlink(path.join(cacheDir, 'schema-cache.stale')).catch(() => { });
|
|
257
174
|
if (read && read.ok) {
|
|
258
175
|
const newCache = {
|
|
@@ -262,10 +179,8 @@ export class BranchSchemaCache {
|
|
|
262
179
|
cachedAt: new Date().toISOString(),
|
|
263
180
|
generation: read.token,
|
|
264
181
|
};
|
|
265
|
-
//
|
|
266
|
-
//
|
|
267
|
-
// codebase, e.g. utils/atomic-write.ts) so a transient rename error
|
|
268
|
-
// doesn't leak a stray `.tmp` file into `.canopy-meta/` forever.
|
|
182
|
+
// Temp file then rename, with the temp file unlinked on a failed
|
|
183
|
+
// rename so a transient error leaves no stray `.tmp` in `.canopy-meta/`.
|
|
269
184
|
await fs.mkdir(cacheDir, { recursive: true });
|
|
270
185
|
const tmpPath = path.join(cacheDir, `schema-cache.tmp.${Date.now()}.${Math.random()}.json`);
|
|
271
186
|
await fs.writeFile(tmpPath, JSON.stringify(newCache, null, 2), 'utf-8');
|
|
@@ -277,34 +192,21 @@ export class BranchSchemaCache {
|
|
|
277
192
|
throw err;
|
|
278
193
|
}
|
|
279
194
|
}
|
|
280
|
-
// else: the marker
|
|
281
|
-
//
|
|
282
|
-
//
|
|
283
|
-
//
|
|
284
|
-
// reader. Serve the fresh result without persisting it; the next read
|
|
285
|
-
// retries the marker read and, on success, resolves and persists
|
|
286
|
-
// normally.
|
|
195
|
+
// else: the marker read failed for a reason other than "never bumped",
|
|
196
|
+
// so no token can be attributed to this resolve, and a snapshot stamped
|
|
197
|
+
// with an unattributable one would look correctly attributed to every
|
|
198
|
+
// future reader. Serve the fresh result without persisting it.
|
|
287
199
|
}
|
|
288
200
|
return { schema: result.schema, flatSchema };
|
|
289
201
|
}
|
|
290
202
|
/**
|
|
291
|
-
* Resolve
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
* `getSchema()` call right after `invalidate()` is NOT that guarantee --
|
|
299
|
-
* `getSchema()`'s cache-read fast path (`loadFromCacheOrResolve`) can still
|
|
300
|
-
* return a snapshot written by a DIFFERENT, concurrent host: if that
|
|
301
|
-
* foreign host's own eager re-resolve raced this one and embedded the
|
|
302
|
-
* (now-current) marker token over ITS OWN stale-NFS-cache scan (the
|
|
303
|
-
* window-E case this class's doc comment describes), this host's
|
|
304
|
-
* `getSchema()` would happily accept that foreign snapshot as "current"
|
|
305
|
-
* and skip the one scan this call was specifically trying to guarantee.
|
|
306
|
-
* `resolveAndPersist()` never reads the cache file at all, so it cannot be
|
|
307
|
-
* short-circuited that way.
|
|
203
|
+
* Resolve fresh from disk and persist, SKIPPING the cache read entirely.
|
|
204
|
+
* That is what makes it, and not {@link getSchema}, the right call for the
|
|
205
|
+
* eager re-resolve in `SchemaOps.invalidateSchemaCache()` (its sole intended
|
|
206
|
+
* caller): an eager re-resolve exists to guarantee ONE scan coherent with the
|
|
207
|
+
* mutation this host just made, and getSchema()'s cache-read fast path can
|
|
208
|
+
* instead return a snapshot a concurrent host wrote — possibly one embedding
|
|
209
|
+
* the now-current token over ITS own stale-NFS scan — skipping that scan.
|
|
308
210
|
*/
|
|
309
211
|
async resolveAndPersist(branchRoot, entrySchemaRegistry, contentRootName = 'content') {
|
|
310
212
|
const skipDiskCache = this.skipDiskCache(branchRoot);
|
|
@@ -313,20 +215,12 @@ export class BranchSchemaCache {
|
|
|
313
215
|
});
|
|
314
216
|
}
|
|
315
217
|
/**
|
|
316
|
-
* Invalidate
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
*
|
|
320
|
-
* The bump must succeed: a swallowed failure here would leave the schema
|
|
321
|
-
* cache stale indefinitely with no bounding backstop (unlike
|
|
322
|
-
* BranchRegistry, there is no get-miss backstop for a resolved schema).
|
|
323
|
-
*
|
|
324
|
-
* No eager regeneration here (unlike BranchRegistry.invalidate()): this
|
|
325
|
-
* method isn't given the entrySchemaRegistry/contentRootName resolveSchema
|
|
326
|
-
* needs. See the class doc comment for why the mutating request's own
|
|
327
|
-
* follow-up schema read closes the same window-E gap instead.
|
|
218
|
+
* Invalidate a branch's cache by bumping the marker; every process sharing
|
|
219
|
+
* this branchRoot re-resolves at its next read. The bump must succeed —
|
|
220
|
+
* swallowing that failure leaves the schema cache stale indefinitely, and
|
|
221
|
+
* unlike BranchRegistry there is no get-miss backstop for a resolved schema.
|
|
328
222
|
*
|
|
329
|
-
*
|
|
223
|
+
* No eager re-resolve here; it lives in SchemaOps (see the class doc).
|
|
330
224
|
*/
|
|
331
225
|
async invalidate(branchRoot) {
|
|
332
226
|
if (this.skipDiskCache(branchRoot))
|
|
@@ -23,12 +23,12 @@ export declare class BranchWorkspaceManager {
|
|
|
23
23
|
}
|
|
24
24
|
export { loadBranchContext } from './branch-metadata.js';
|
|
25
25
|
/**
|
|
26
|
-
* Load an existing branch context,
|
|
26
|
+
* Load an existing branch context, provisioning the workspace if there is none.
|
|
27
27
|
*
|
|
28
28
|
* When content is read from the checkout (`readsFromCheckout`: a static
|
|
29
|
-
* deployment, or any build) this skips every git and branch-workspace
|
|
30
|
-
*
|
|
31
|
-
*
|
|
29
|
+
* deployment, or any build) this skips every git and branch-workspace operation
|
|
30
|
+
* and returns a synthetic context rooted at the current working directory,
|
|
31
|
+
* where `branchName` is echoed back but selects nothing.
|
|
32
32
|
*/
|
|
33
33
|
export declare function loadOrCreateBranchContext(options: {
|
|
34
34
|
config: CanopyConfig;
|
package/dist/branch-workspace.js
CHANGED
|
@@ -20,23 +20,21 @@ export class BranchWorkspaceManager {
|
|
|
20
20
|
}
|
|
21
21
|
async ensureGitWorkspace(options) {
|
|
22
22
|
return log.timed('workspace', 'ensureGitWorkspace', async () => {
|
|
23
|
-
//
|
|
23
|
+
// One initialization per branch workspace per process.
|
|
24
24
|
const existingLock = workspaceInitLocks.get(options.branchRoot);
|
|
25
25
|
if (existingLock) {
|
|
26
26
|
await existingLock;
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
|
-
// Create new lock promise
|
|
30
29
|
const lockPromise = (async () => {
|
|
31
|
-
// The in-memory lock above only serializes
|
|
32
|
-
// processes can provision the same
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
// loadOrCreateBranchContext returns the checkout before provisioning.)
|
|
30
|
+
// The in-memory lock above only serializes one process, and separate
|
|
31
|
+
// processes can provision the same workspace at once (several Lambda
|
|
32
|
+
// containers on one EFS root; the dev server beside a content-reading
|
|
33
|
+
// script), which without a cross-process lock means both cloning into
|
|
34
|
+
// it: "destination path already exists". initializeWorkspace is
|
|
35
|
+
// idempotent, so the waiter finds the workspace already cloned. A
|
|
36
|
+
// build's content reads never get here — loadOrCreateBranchContext
|
|
37
|
+
// returns the checkout before provisioning.
|
|
40
38
|
let releaseLock;
|
|
41
39
|
try {
|
|
42
40
|
log.debug('workspace', 'Ensuring git workspace', {
|
|
@@ -44,7 +42,6 @@ export class BranchWorkspaceManager {
|
|
|
44
42
|
mode: options.mode,
|
|
45
43
|
});
|
|
46
44
|
releaseLock = await acquireProvisioningLock(path.dirname(options.branchRoot), `.${path.basename(options.branchRoot)}.init.lock`);
|
|
47
|
-
// Delegate git initialization to GitManager
|
|
48
45
|
await GitManager.initializeWorkspace({
|
|
49
46
|
workspacePath: options.branchRoot,
|
|
50
47
|
branchName: options.branchName,
|
|
@@ -74,9 +71,7 @@ export class BranchWorkspaceManager {
|
|
|
74
71
|
workspaceInitLocks.delete(options.branchRoot);
|
|
75
72
|
}
|
|
76
73
|
})();
|
|
77
|
-
// Store the lock promise
|
|
78
74
|
workspaceInitLocks.set(options.branchRoot, lockPromise);
|
|
79
|
-
// Wait for initialization to complete
|
|
80
75
|
await lockPromise;
|
|
81
76
|
});
|
|
82
77
|
}
|
|
@@ -103,7 +98,8 @@ export class BranchWorkspaceManager {
|
|
|
103
98
|
baseBranch,
|
|
104
99
|
remoteUrl,
|
|
105
100
|
});
|
|
106
|
-
// save()
|
|
101
|
+
// save() covers creation and update, keeping existing values and
|
|
102
|
+
// invalidating the registry.
|
|
107
103
|
const metadata = getBranchMetadataFileManager(branchRoot, baseRoot);
|
|
108
104
|
const meta = await metadata.save({
|
|
109
105
|
branch: {
|
|
@@ -124,12 +120,12 @@ export class BranchWorkspaceManager {
|
|
|
124
120
|
}
|
|
125
121
|
export { loadBranchContext } from './branch-metadata.js';
|
|
126
122
|
/**
|
|
127
|
-
* Load an existing branch context,
|
|
123
|
+
* Load an existing branch context, provisioning the workspace if there is none.
|
|
128
124
|
*
|
|
129
125
|
* When content is read from the checkout (`readsFromCheckout`: a static
|
|
130
|
-
* deployment, or any build) this skips every git and branch-workspace
|
|
131
|
-
*
|
|
132
|
-
*
|
|
126
|
+
* deployment, or any build) this skips every git and branch-workspace operation
|
|
127
|
+
* and returns a synthetic context rooted at the current working directory,
|
|
128
|
+
* where `branchName` is echoed back but selects nothing.
|
|
133
129
|
*/
|
|
134
130
|
export async function loadOrCreateBranchContext(options) {
|
|
135
131
|
// Static deployments and builds read content directly from the checkout — no git ops
|
|
@@ -16,6 +16,7 @@ import type { AIContentConfig } from '../ai/types.js';
|
|
|
16
16
|
* consumers. Overloading it with a build-time file list would change a contract adopters read.
|
|
17
17
|
*
|
|
18
18
|
* Dot-prefixed so it sorts out of the way and reads as machine bookkeeping rather than content.
|
|
19
|
+
* @internal Exported for tests.
|
|
19
20
|
*/
|
|
20
21
|
export declare const GENERATED_RECORD_FILENAME = ".canopy-generated.json";
|
|
21
22
|
export interface GenerateAIContentFilesOptions {
|
|
@@ -22,6 +22,7 @@ import { assertBuildEntriesValid } from '../static/index.js';
|
|
|
22
22
|
* consumers. Overloading it with a build-time file list would change a contract adopters read.
|
|
23
23
|
*
|
|
24
24
|
* Dot-prefixed so it sorts out of the way and reads as machine bookkeeping rather than content.
|
|
25
|
+
* @internal Exported for tests.
|
|
25
26
|
*/
|
|
26
27
|
export const GENERATED_RECORD_FILENAME = '.canopy-generated.json';
|
|
27
28
|
/** Read the previous run's record. A missing, unreadable or malformed record means "know nothing". */
|
|
@@ -102,30 +103,20 @@ function unpinnedConsequence(buildId) {
|
|
|
102
103
|
/**
|
|
103
104
|
* Resolve the manifest's build stamp from the environment.
|
|
104
105
|
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* response's timestamp.
|
|
106
|
+
* Lives at the BUILD boundary, not inside `generateAIContent`: the same generator also serves
|
|
107
|
+
* the runtime route, where a live clock is correct and a `SOURCE_DATE_EPOCH` exported in a
|
|
108
|
+
* server environment must not freeze a response's timestamp.
|
|
109
109
|
*
|
|
110
|
-
* `SOURCE_DATE_EPOCH` is the Reproducible Builds convention (decimal seconds since the epoch)
|
|
111
|
-
*
|
|
112
|
-
*
|
|
110
|
+
* `SOURCE_DATE_EPOCH` is the Reproducible Builds convention (decimal seconds since the epoch).
|
|
111
|
+
* `CANOPY_BUILD_ID` is validated against the same rule as `SAFE_BUILD_ID` above, since the
|
|
112
|
+
* manifest's `buildId` and Next's build id must name the SAME artifact.
|
|
113
113
|
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* manifest's `buildId` and the framework's build id name the SAME artifact, so a value one reader
|
|
117
|
-
* would reject is not useful to the other. The cost is that a non-Next adopter cannot use, say, an
|
|
118
|
-
* ISO timestamp as a build id — revisit this rule, in both copies, when a second framework lands.
|
|
114
|
+
* Both variables warn and are ignored when set but unusable, rather than failing the build —
|
|
115
|
+
* same stance as `readGeneratedRecord` above; "unset" is a deliberate opt-out and warns nothing.
|
|
119
116
|
*
|
|
120
|
-
*
|
|
121
|
-
* `
|
|
122
|
-
*
|
|
123
|
-
* "unset" is a deliberate opt-out and says nothing.
|
|
124
|
-
*
|
|
125
|
-
* Note what ignoring a bad `SOURCE_DATE_EPOCH` means when a build id IS set: `generatedAt` stays
|
|
126
|
-
* undefined, so `generated` is omitted rather than falling back to a live clock. A bad value must
|
|
127
|
-
* not resurrect a field the adopter's configuration says is meaningless — which is also why that
|
|
128
|
-
* case warns rather than failing silently, since the field simply disappears.
|
|
117
|
+
* When `SOURCE_DATE_EPOCH` is bad and a build id IS set, `generatedAt` stays undefined so
|
|
118
|
+
* `generated` is omitted rather than falling back to a live clock — a bad value must not
|
|
119
|
+
* resurrect a field the adopter's configuration says is meaningless.
|
|
129
120
|
*/
|
|
130
121
|
function resolveBuildStamp() {
|
|
131
122
|
// Trimmed and shape-checked with the same rule `withCanopy` applies, so that when an adopter
|
|
@@ -182,9 +173,7 @@ function resolveBuildStamp() {
|
|
|
182
173
|
export async function generateAIContentFiles(options) {
|
|
183
174
|
const { config, entrySchemaRegistry, outputDir, aiConfig, _testFlatSchema } = options;
|
|
184
175
|
const contentRootName = config.contentRoot || 'content';
|
|
185
|
-
// Resolve branch root
|
|
186
176
|
const branchRoot = await resolveBranchRoot(config);
|
|
187
|
-
// Load schema
|
|
188
177
|
let flatSchema;
|
|
189
178
|
if (_testFlatSchema) {
|
|
190
179
|
flatSchema = _testFlatSchema;
|
|
@@ -199,7 +188,6 @@ export async function generateAIContentFiles(options) {
|
|
|
199
188
|
// command, not something `next dev` runs incidentally.
|
|
200
189
|
const entriesForValidation = await listEntries(branchRoot, flatSchema, contentRootName);
|
|
201
190
|
assertBuildEntriesValid(entriesForValidation, 'AI content generation');
|
|
202
|
-
// Create store and generate
|
|
203
191
|
const store = new ContentStore(branchRoot, flatSchema, { contentRootName });
|
|
204
192
|
const result = await generateAIContent({
|
|
205
193
|
store,
|
|
@@ -209,7 +197,6 @@ export async function generateAIContentFiles(options) {
|
|
|
209
197
|
entryLinkUrl: config.entryLinkUrl,
|
|
210
198
|
...resolveBuildStamp(),
|
|
211
199
|
});
|
|
212
|
-
// Write files to disk
|
|
213
200
|
const absoluteOutputDir = path.resolve(outputDir) + path.sep;
|
|
214
201
|
/** Resolve an output-relative path, refusing anything that escapes the output directory. */
|
|
215
202
|
const resolveOutputPath = (filePath) => {
|
package/dist/build-canopy.d.ts
CHANGED
|
@@ -2,41 +2,31 @@ import type { CanopyConfig } from './config/index.js';
|
|
|
2
2
|
import type { EntrySchemaRegistry } from './schema/types.js';
|
|
3
3
|
import { type CanopyBuildContext } from './context.js';
|
|
4
4
|
export interface CreateBuildCanopyOptions {
|
|
5
|
-
/**
|
|
6
|
-
* Entry schema registry for resolving `.collection.json` references.
|
|
7
|
-
* Same shape as `createCanopyServices`'s option of the same name.
|
|
8
|
-
*/
|
|
5
|
+
/** Entry schema registry for `.collection.json` references; `createCanopyServices`'s shape. */
|
|
9
6
|
entrySchemaRegistry?: EntrySchemaRegistry;
|
|
10
7
|
}
|
|
11
8
|
/**
|
|
12
|
-
* One-call factory for a **build/admin** Canopy context
|
|
13
|
-
*
|
|
14
|
-
*
|
|
9
|
+
* One-call factory for a **build/admin** Canopy context, for standalone scripts
|
|
10
|
+
* that run entirely outside a Next.js request or build phase (index builders,
|
|
11
|
+
* content audits, codegen, ad hoc reports).
|
|
15
12
|
*
|
|
16
|
-
* **
|
|
17
|
-
* synthetic admin user
|
|
18
|
-
*
|
|
19
|
-
* request
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* enforce branch/path permissions per user. This factory mirrors the same
|
|
24
|
-
* `createCanopyServices` + `createCanopyContext` + `STATIC_DEPLOY_USER` boot
|
|
25
|
-
* sequence that `createNextCanopyContext`'s own `getCanopyForBuild()` uses
|
|
26
|
-
* internally, minus the Next.js pieces (no `next/headers`, no React
|
|
27
|
-
* `cache()`, no request-time misuse guard — there is no request phase for
|
|
28
|
-
* it to guard against) — so it works in a plain script run with `tsx`/`node`.
|
|
13
|
+
* **Bypasses ALL branch and path ACLs: it reads the filesystem directly as the
|
|
14
|
+
* synthetic admin user `STATIC_DEPLOY_USER`.** That is safe only because there
|
|
15
|
+
* is no request, and so no per-request auth to enforce. Never reach for it from
|
|
16
|
+
* request-handling code (an API route, a server component rendering for a
|
|
17
|
+
* specific visitor); there, use `createNextCanopyContext(...)`'s `getCanopy()`
|
|
18
|
+
* or its phase-selecting `read`/`readByUrlPath`, which enforce branch and path
|
|
19
|
+
* permissions per user.
|
|
29
20
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* (
|
|
34
|
-
*
|
|
35
|
-
*
|
|
21
|
+
* Mirrors the `createCanopyServices` + `createCanopyContext` +
|
|
22
|
+
* `STATIC_DEPLOY_USER` boot sequence of `createNextCanopyContext`'s own
|
|
23
|
+
* `getCanopyForBuild()`, minus the Next.js pieces (no `next/headers`, no React
|
|
24
|
+
* `cache()`, no request-time misuse guard — there is no request phase to guard
|
|
25
|
+
* against), so it runs in a plain `tsx`/`node` script and can be stubbed from a
|
|
26
|
+
* test the way a top-level-`await` boot block cannot.
|
|
36
27
|
*
|
|
37
28
|
* @example
|
|
38
29
|
* ```ts
|
|
39
|
-
* // scripts/build-search-index.ts
|
|
40
30
|
* import { createBuildCanopy } from 'canopycms/server'
|
|
41
31
|
* import config from '../canopycms.config.js'
|
|
42
32
|
* import { entrySchemaRegistry } from '../src/schemas.js'
|
package/dist/build-canopy.js
CHANGED
|
@@ -2,34 +2,27 @@ import { createCanopyServices } from './services.js';
|
|
|
2
2
|
import { createCanopyContext } from './context.js';
|
|
3
3
|
import { STATIC_DEPLOY_USER } from './build-mode.js';
|
|
4
4
|
/**
|
|
5
|
-
* One-call factory for a **build/admin** Canopy context
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* One-call factory for a **build/admin** Canopy context, for standalone scripts
|
|
6
|
+
* that run entirely outside a Next.js request or build phase (index builders,
|
|
7
|
+
* content audits, codegen, ad hoc reports).
|
|
8
8
|
*
|
|
9
|
-
* **
|
|
10
|
-
* synthetic admin user
|
|
11
|
-
*
|
|
12
|
-
* request
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* enforce branch/path permissions per user. This factory mirrors the same
|
|
17
|
-
* `createCanopyServices` + `createCanopyContext` + `STATIC_DEPLOY_USER` boot
|
|
18
|
-
* sequence that `createNextCanopyContext`'s own `getCanopyForBuild()` uses
|
|
19
|
-
* internally, minus the Next.js pieces (no `next/headers`, no React
|
|
20
|
-
* `cache()`, no request-time misuse guard — there is no request phase for
|
|
21
|
-
* it to guard against) — so it works in a plain script run with `tsx`/`node`.
|
|
9
|
+
* **Bypasses ALL branch and path ACLs: it reads the filesystem directly as the
|
|
10
|
+
* synthetic admin user `STATIC_DEPLOY_USER`.** That is safe only because there
|
|
11
|
+
* is no request, and so no per-request auth to enforce. Never reach for it from
|
|
12
|
+
* request-handling code (an API route, a server component rendering for a
|
|
13
|
+
* specific visitor); there, use `createNextCanopyContext(...)`'s `getCanopy()`
|
|
14
|
+
* or its phase-selecting `read`/`readByUrlPath`, which enforce branch and path
|
|
15
|
+
* permissions per user.
|
|
22
16
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* (
|
|
27
|
-
*
|
|
28
|
-
*
|
|
17
|
+
* Mirrors the `createCanopyServices` + `createCanopyContext` +
|
|
18
|
+
* `STATIC_DEPLOY_USER` boot sequence of `createNextCanopyContext`'s own
|
|
19
|
+
* `getCanopyForBuild()`, minus the Next.js pieces (no `next/headers`, no React
|
|
20
|
+
* `cache()`, no request-time misuse guard — there is no request phase to guard
|
|
21
|
+
* against), so it runs in a plain `tsx`/`node` script and can be stubbed from a
|
|
22
|
+
* test the way a top-level-`await` boot block cannot.
|
|
29
23
|
*
|
|
30
24
|
* @example
|
|
31
25
|
* ```ts
|
|
32
|
-
* // scripts/build-search-index.ts
|
|
33
26
|
* import { createBuildCanopy } from 'canopycms/server'
|
|
34
27
|
* import config from '../canopycms.config.js'
|
|
35
28
|
* import { entrySchemaRegistry } from '../src/schemas.js'
|