canopycms 0.0.62 → 0.0.64
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 +153 -19
- package/dist/ai/generate.d.ts +4 -5
- package/dist/ai/generate.js +0 -1
- package/dist/ai/handler.d.ts +3 -4
- package/dist/ai/handler.js +0 -1
- package/dist/ai/index.d.ts +15 -7
- package/dist/ai/index.js +9 -1
- package/dist/ai/json-to-markdown.d.ts +1 -2
- package/dist/ai/json-to-markdown.js +11 -2
- package/dist/ai/resolve-branch.d.ts +1 -2
- package/dist/ai/resolve-branch.js +0 -1
- package/dist/ai/strip-mdx.d.ts +0 -1
- package/dist/ai/strip-mdx.js +0 -1
- package/dist/ai/to-plain-text.d.ts +60 -0
- package/dist/ai/to-plain-text.js +301 -0
- package/dist/ai/transform-components.d.ts +1 -2
- package/dist/ai/transform-components.js +70 -6
- package/dist/ai/types.d.ts +1 -2
- package/dist/ai/types.js +0 -1
- package/dist/api/admin-branch-health.d.ts +7 -8
- package/dist/api/admin-branch-health.js +0 -1
- package/dist/api/admin.d.ts +16 -17
- package/dist/api/admin.js +0 -1
- package/dist/api/assets.d.ts +8 -9
- package/dist/api/assets.js +0 -1
- package/dist/api/branch-merge.d.ts +3 -4
- package/dist/api/branch-merge.js +0 -1
- package/dist/api/branch-review.d.ts +5 -6
- package/dist/api/branch-review.js +0 -1
- package/dist/api/branch-status.d.ts +15 -16
- package/dist/api/branch-status.js +0 -1
- package/dist/api/branch-withdraw.d.ts +3 -4
- package/dist/api/branch-withdraw.js +0 -1
- package/dist/api/branch.d.ts +13 -14
- package/dist/api/branch.js +0 -1
- package/dist/api/client.d.ts +14 -15
- package/dist/api/client.js +0 -1
- package/dist/api/comments.d.ts +11 -12
- package/dist/api/comments.js +0 -1
- package/dist/api/content.d.ts +22 -24
- package/dist/api/content.js +132 -18
- package/dist/api/entries-constants.d.ts +0 -1
- package/dist/api/entries-constants.js +0 -1
- package/dist/api/entries.d.ts +12 -13
- package/dist/api/entries.js +12 -2
- package/dist/api/github-sync.d.ts +2 -3
- package/dist/api/github-sync.js +0 -1
- package/dist/api/groups.d.ts +6 -7
- package/dist/api/groups.js +0 -1
- package/dist/api/guards.d.ts +2 -3
- package/dist/api/guards.js +0 -1
- package/dist/api/index.d.ts +18 -19
- package/dist/api/index.js +0 -1
- package/dist/api/permissions.d.ts +10 -11
- package/dist/api/permissions.js +0 -1
- package/dist/api/reference-options.d.ts +3 -4
- package/dist/api/reference-options.js +0 -1
- package/dist/api/request-body-hash.d.ts +0 -1
- package/dist/api/request-body-hash.js +0 -1
- package/dist/api/resolve-references.d.ts +6 -7
- package/dist/api/resolve-references.js +24 -6
- package/dist/api/route-builder.d.ts +2 -3
- package/dist/api/route-builder.js +0 -1
- package/dist/api/schema.d.ts +43 -44
- package/dist/api/schema.js +0 -1
- package/dist/api/settings-helpers.d.ts +2 -3
- package/dist/api/settings-helpers.js +0 -1
- package/dist/api/types.d.ts +6 -7
- package/dist/api/types.js +0 -1
- package/dist/api/user.d.ts +2 -3
- package/dist/api/user.js +0 -1
- package/dist/api/validators.d.ts +3 -4
- package/dist/api/validators.js +0 -1
- package/dist/assets/asset-prefixes.d.ts +1 -2
- package/dist/assets/asset-prefixes.js +0 -1
- package/dist/assets/asset-src.d.ts +17 -5
- package/dist/assets/asset-src.js +15 -3
- package/dist/assets/asset-url.d.ts +28 -7
- package/dist/assets/asset-url.js +20 -15
- package/dist/assets/factory.d.ts +2 -3
- package/dist/assets/factory.js +0 -2
- package/dist/assets/finalize.d.ts +2 -3
- package/dist/assets/finalize.js +0 -1
- package/dist/assets/index.d.ts +12 -13
- package/dist/assets/index.js +0 -1
- package/dist/assets/keys.d.ts +1 -2
- package/dist/assets/keys.js +0 -1
- package/dist/assets/pipeline.d.ts +1 -2
- package/dist/assets/pipeline.js +0 -1
- package/dist/assets/store-local.d.ts +1 -2
- package/dist/assets/store-local.js +0 -1
- package/dist/assets/store-s3.d.ts +2 -4
- package/dist/assets/store-s3.js +0 -1
- package/dist/assets/svg-sanitizer.d.ts +0 -1
- package/dist/assets/svg-sanitizer.js +0 -1
- package/dist/assets/transform-directives.d.ts +0 -1
- package/dist/assets/transform-directives.js +0 -1
- package/dist/assets/transform.d.ts +1 -2
- package/dist/assets/transform.js +0 -1
- package/dist/assets/types.d.ts +0 -1
- package/dist/assets/types.js +0 -1
- package/dist/auth/cache.d.ts +2 -3
- package/dist/auth/cache.js +0 -1
- package/dist/auth/caching-auth-plugin.d.ts +3 -4
- package/dist/auth/caching-auth-plugin.js +0 -1
- package/dist/auth/context-helpers.d.ts +1 -2
- package/dist/auth/context-helpers.js +0 -1
- package/dist/auth/file-based-auth-cache.d.ts +3 -4
- package/dist/auth/file-based-auth-cache.js +0 -1
- package/dist/auth/index.d.ts +6 -7
- package/dist/auth/index.js +0 -1
- package/dist/auth/plugin.d.ts +3 -4
- package/dist/auth/plugin.js +0 -1
- package/dist/auth/types.d.ts +1 -2
- package/dist/auth/types.js +0 -1
- package/dist/authorization/branch.d.ts +58 -7
- package/dist/authorization/branch.js +55 -10
- package/dist/authorization/content.d.ts +6 -7
- package/dist/authorization/content.js +0 -1
- package/dist/authorization/groups/index.d.ts +2 -3
- package/dist/authorization/groups/index.js +0 -1
- package/dist/authorization/groups/loader.d.ts +3 -4
- package/dist/authorization/groups/loader.js +0 -1
- package/dist/authorization/groups/schema.d.ts +1 -2
- package/dist/authorization/groups/schema.js +0 -1
- package/dist/authorization/helpers.d.ts +0 -1
- package/dist/authorization/helpers.js +0 -1
- package/dist/authorization/index.d.ts +11 -12
- package/dist/authorization/index.js +0 -1
- package/dist/authorization/path.d.ts +4 -5
- package/dist/authorization/path.js +0 -1
- package/dist/authorization/permissions/index.d.ts +2 -3
- package/dist/authorization/permissions/index.js +0 -1
- package/dist/authorization/permissions/loader.d.ts +4 -5
- package/dist/authorization/permissions/loader.js +0 -1
- package/dist/authorization/permissions/schema.d.ts +2 -3
- package/dist/authorization/permissions/schema.js +0 -1
- package/dist/authorization/protected-branch.d.ts +2 -3
- package/dist/authorization/protected-branch.js +0 -1
- package/dist/authorization/settings-file-store.d.ts +1 -2
- package/dist/authorization/settings-file-store.js +0 -1
- package/dist/authorization/types.d.ts +7 -8
- package/dist/authorization/types.js +0 -1
- package/dist/authorization/validation.d.ts +1 -2
- package/dist/authorization/validation.js +0 -1
- package/dist/branch-health.d.ts +2 -3
- package/dist/branch-health.js +0 -1
- package/dist/branch-metadata.d.ts +2 -3
- package/dist/branch-metadata.js +0 -1
- package/dist/branch-registry.d.ts +1 -2
- package/dist/branch-registry.js +0 -1
- package/dist/branch-schema-cache.d.ts +4 -5
- package/dist/branch-schema-cache.js +0 -1
- package/dist/branch-workspace.d.ts +4 -5
- package/dist/branch-workspace.js +0 -1
- package/dist/build/generate-ai-content.d.ts +21 -5
- package/dist/build/generate-ai-content.js +98 -6
- package/dist/build/index.d.ts +2 -3
- package/dist/build/index.js +0 -1
- package/dist/build-canopy.d.ts +48 -0
- package/dist/build-canopy.js +50 -0
- package/dist/build-mode.d.ts +1 -2
- package/dist/build-mode.js +0 -1
- package/dist/cli/cli.d.ts +1 -2
- package/dist/cli/cli.js +1192 -495
- package/dist/cli/generate-ai-content.d.ts +0 -1
- package/dist/cli/generate-ai-content.js +1062 -370
- package/dist/cli/init.d.ts +1 -2
- package/dist/cli/init.js +12 -2
- package/dist/cli/migrate.d.ts +5 -3
- package/dist/cli/migrate.js +5 -3
- package/dist/cli/project-detect.d.ts +5 -2
- package/dist/cli/project-detect.js +5 -1
- package/dist/cli/project-root.d.ts +0 -1
- package/dist/cli/project-root.js +0 -1
- package/dist/cli/sync.d.ts +0 -1
- package/dist/cli/sync.js +0 -1
- package/dist/cli/template-files/canopycms.config.ts.template +18 -1
- package/dist/cli/template-files/deploy-cms.yml.template +8 -6
- package/dist/cli/templates.d.ts +0 -1
- package/dist/cli/templates.js +0 -1
- package/dist/client.d.ts +13 -14
- package/dist/client.js +0 -1
- package/dist/comment-store.d.ts +0 -1
- package/dist/comment-store.js +0 -1
- package/dist/config/flatten.d.ts +1 -2
- package/dist/config/flatten.js +0 -1
- package/dist/config/helpers.d.ts +3 -4
- package/dist/config/helpers.js +2 -2
- package/dist/config/index.d.ts +10 -11
- package/dist/config/index.js +0 -1
- package/dist/config/schemas/collection.d.ts +0 -1
- package/dist/config/schemas/collection.js +0 -1
- package/dist/config/schemas/config.d.ts +7 -4
- package/dist/config/schemas/config.js +12 -1
- package/dist/config/schemas/field.d.ts +3 -1
- package/dist/config/schemas/field.js +5 -1
- package/dist/config/schemas/media.d.ts +0 -1
- package/dist/config/schemas/media.js +0 -1
- package/dist/config/schemas/permissions.d.ts +0 -1
- package/dist/config/schemas/permissions.js +0 -1
- package/dist/config/types.d.ts +55 -9
- package/dist/config/types.js +0 -1
- package/dist/config/validation.d.ts +1 -2
- package/dist/config/validation.js +0 -1
- package/dist/config.d.ts +2 -3
- package/dist/config.js +0 -1
- package/dist/content-id-index.d.ts +1 -2
- package/dist/content-id-index.js +0 -1
- package/dist/content-index-generation.d.ts +0 -1
- package/dist/content-index-generation.js +0 -1
- package/dist/content-index-registry.d.ts +0 -1
- package/dist/content-index-registry.js +0 -1
- package/dist/content-listing.d.ts +137 -16
- package/dist/content-listing.js +175 -41
- package/dist/content-reader.d.ts +44 -8
- package/dist/content-reader.js +39 -7
- package/dist/content-store.d.ts +147 -7
- package/dist/content-store.js +294 -22
- package/dist/content-tree.d.ts +44 -5
- package/dist/content-tree.js +47 -11
- package/dist/context.d.ts +38 -15
- package/dist/context.js +55 -5
- package/dist/dev-content-watcher.d.ts +2 -3
- package/dist/dev-content-watcher.js +0 -1
- package/dist/editor/BranchManager.d.ts +4 -5
- package/dist/editor/BranchManager.js +0 -1
- package/dist/editor/CanopyEditor.d.ts +2 -3
- package/dist/editor/CanopyEditor.js +1 -2
- package/dist/editor/CanopyEditorPage.d.ts +2 -3
- package/dist/editor/CanopyEditorPage.js +0 -1
- package/dist/editor/CommentsPanel.d.ts +2 -3
- package/dist/editor/CommentsPanel.js +0 -1
- package/dist/editor/Editor.d.ts +13 -8
- package/dist/editor/Editor.js +4 -5
- package/dist/editor/EditorPanes.d.ts +0 -1
- package/dist/editor/EditorPanes.js +0 -1
- package/dist/editor/EntryNavigator.d.ts +1 -2
- package/dist/editor/EntryNavigator.js +0 -1
- package/dist/editor/FormRenderer.d.ts +2 -3
- package/dist/editor/FormRenderer.js +22 -3
- package/dist/editor/GroupManager.d.ts +2 -3
- package/dist/editor/GroupManager.js +0 -1
- package/dist/editor/PermissionManager.d.ts +2 -3
- package/dist/editor/PermissionManager.js +0 -1
- package/dist/editor/admin/SystemHealthPanel.d.ts +0 -1
- package/dist/editor/admin/SystemHealthPanel.js +0 -1
- package/dist/editor/admin/useSystemHealth.d.ts +2 -3
- package/dist/editor/admin/useSystemHealth.js +0 -1
- package/dist/editor/canopy-path.d.ts +0 -1
- package/dist/editor/canopy-path.js +0 -1
- package/dist/editor/client-reference-resolver.d.ts +13 -4
- package/dist/editor/client-reference-resolver.js +18 -8
- package/dist/editor/comments/BranchComments.d.ts +2 -3
- package/dist/editor/comments/BranchComments.js +0 -1
- package/dist/editor/comments/EntryComments.d.ts +1 -2
- package/dist/editor/comments/EntryComments.js +0 -1
- package/dist/editor/comments/FieldWrapper.d.ts +1 -2
- package/dist/editor/comments/FieldWrapper.js +0 -1
- package/dist/editor/comments/InlineCommentThread.d.ts +2 -3
- package/dist/editor/comments/InlineCommentThread.js +0 -1
- package/dist/editor/comments/ThreadCarousel.d.ts +2 -3
- package/dist/editor/comments/ThreadCarousel.js +0 -1
- package/dist/editor/components/ConfirmDeleteModal.d.ts +0 -1
- package/dist/editor/components/ConfirmDeleteModal.js +0 -1
- package/dist/editor/components/EditorFooter.d.ts +0 -1
- package/dist/editor/components/EditorFooter.js +0 -1
- package/dist/editor/components/EditorHeader.d.ts +4 -5
- package/dist/editor/components/EditorHeader.js +0 -1
- package/dist/editor/components/EditorSidebar.d.ts +1 -2
- package/dist/editor/components/EditorSidebar.js +0 -1
- package/dist/editor/components/EntryCreateModal.d.ts +0 -1
- package/dist/editor/components/EntryCreateModal.js +21 -10
- package/dist/editor/components/RenameEntryModal.d.ts +0 -1
- package/dist/editor/components/RenameEntryModal.js +0 -1
- package/dist/editor/components/UserBadge.d.ts +2 -3
- package/dist/editor/components/UserBadge.js +0 -1
- package/dist/editor/components/index.d.ts +3 -4
- package/dist/editor/components/index.js +0 -1
- package/dist/editor/context/ApiClientContext.d.ts +9 -3
- package/dist/editor/context/ApiClientContext.js +8 -4
- package/dist/editor/context/AssetContext.d.ts +26 -2
- package/dist/editor/context/AssetContext.js +23 -3
- package/dist/editor/context/EditorStateContext.d.ts +1 -2
- package/dist/editor/context/EditorStateContext.js +0 -1
- package/dist/editor/context/SWRProvider.d.ts +0 -1
- package/dist/editor/context/SWRProvider.js +0 -1
- package/dist/editor/context/index.d.ts +4 -5
- package/dist/editor/context/index.js +0 -1
- package/dist/editor/editor-config.d.ts +2 -3
- package/dist/editor/editor-config.js +0 -1
- package/dist/editor/editor-utils.d.ts +22 -10
- package/dist/editor/editor-utils.js +41 -10
- package/dist/editor/fields/BlockField.d.ts +1 -2
- package/dist/editor/fields/BlockField.js +0 -1
- package/dist/editor/fields/CodeField.d.ts +0 -1
- package/dist/editor/fields/CodeField.js +0 -1
- package/dist/editor/fields/DateTimeField.d.ts +0 -1
- package/dist/editor/fields/DateTimeField.js +0 -1
- package/dist/editor/fields/ImageField.d.ts +1 -2
- package/dist/editor/fields/ImageField.js +0 -1
- package/dist/editor/fields/InlineGroupField.d.ts +2 -3
- package/dist/editor/fields/InlineGroupField.js +0 -1
- package/dist/editor/fields/MarkdownField.d.ts +0 -1
- package/dist/editor/fields/MarkdownField.js +0 -1
- package/dist/editor/fields/MdxImageDialog.d.ts +0 -1
- package/dist/editor/fields/MdxImageDialog.js +0 -1
- package/dist/editor/fields/NumberField.d.ts +0 -1
- package/dist/editor/fields/NumberField.js +0 -1
- package/dist/editor/fields/NumberListField.d.ts +0 -1
- package/dist/editor/fields/NumberListField.js +0 -1
- package/dist/editor/fields/ObjectField.d.ts +11 -2
- package/dist/editor/fields/ObjectField.js +3 -4
- package/dist/editor/fields/ReferenceField.d.ts +0 -1
- package/dist/editor/fields/ReferenceField.js +8 -3
- package/dist/editor/fields/SelectField.d.ts +0 -1
- package/dist/editor/fields/SelectField.js +0 -1
- package/dist/editor/fields/StringListField.d.ts +0 -1
- package/dist/editor/fields/StringListField.js +0 -1
- 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.d.ts +1 -2
- package/dist/editor/fields/entry-link/EntryLinkContext.js +0 -1
- package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +0 -1
- package/dist/editor/fields/entry-link/InsertEntryLink.js +0 -1
- package/dist/editor/fields/entry-link/index.d.ts +2 -3
- package/dist/editor/fields/entry-link/index.js +0 -1
- package/dist/editor/group-manager/ExternalGroupsTab.d.ts +1 -2
- package/dist/editor/group-manager/ExternalGroupsTab.js +0 -1
- package/dist/editor/group-manager/GroupCard.d.ts +1 -2
- package/dist/editor/group-manager/GroupCard.js +0 -1
- package/dist/editor/group-manager/GroupForm.d.ts +1 -2
- package/dist/editor/group-manager/GroupForm.js +0 -1
- package/dist/editor/group-manager/InternalGroupsTab.d.ts +1 -2
- package/dist/editor/group-manager/InternalGroupsTab.js +0 -1
- package/dist/editor/group-manager/MemberList.d.ts +1 -2
- package/dist/editor/group-manager/MemberList.js +0 -1
- package/dist/editor/group-manager/hooks/useExternalGroupSearch.d.ts +1 -2
- package/dist/editor/group-manager/hooks/useExternalGroupSearch.js +0 -1
- package/dist/editor/group-manager/hooks/useGroupState.d.ts +1 -2
- package/dist/editor/group-manager/hooks/useGroupState.js +0 -1
- package/dist/editor/group-manager/hooks/useUserSearch.d.ts +1 -2
- package/dist/editor/group-manager/hooks/useUserSearch.js +0 -1
- package/dist/editor/group-manager/index.d.ts +5 -6
- package/dist/editor/group-manager/index.js +0 -1
- package/dist/editor/group-manager/types.d.ts +4 -5
- package/dist/editor/group-manager/types.js +0 -1
- package/dist/editor/hooks/index.d.ts +14 -15
- package/dist/editor/hooks/index.js +0 -1
- package/dist/editor/hooks/useBranchActions.d.ts +0 -1
- package/dist/editor/hooks/useBranchActions.js +0 -1
- package/dist/editor/hooks/useBranchManager.d.ts +4 -5
- package/dist/editor/hooks/useBranchManager.js +0 -1
- package/dist/editor/hooks/useBranchesData.d.ts +2 -3
- package/dist/editor/hooks/useBranchesData.js +0 -1
- package/dist/editor/hooks/useCommentSystem.d.ts +2 -3
- package/dist/editor/hooks/useCommentSystem.js +0 -1
- package/dist/editor/hooks/useCommentsData.d.ts +2 -3
- package/dist/editor/hooks/useCommentsData.js +0 -1
- package/dist/editor/hooks/useDraftManager.d.ts +3 -4
- package/dist/editor/hooks/useDraftManager.js +0 -1
- package/dist/editor/hooks/useEditorLayout.d.ts +1 -2
- package/dist/editor/hooks/useEditorLayout.js +0 -1
- package/dist/editor/hooks/useEntriesData.d.ts +3 -5
- package/dist/editor/hooks/useEntriesData.js +0 -3
- package/dist/editor/hooks/useEntryLinkResolution.d.ts +2 -3
- package/dist/editor/hooks/useEntryLinkResolution.js +0 -1
- package/dist/editor/hooks/useEntryManager.d.ts +5 -7
- package/dist/editor/hooks/useEntryManager.js +8 -3
- package/dist/editor/hooks/useGroupManager.d.ts +2 -3
- package/dist/editor/hooks/useGroupManager.js +0 -1
- package/dist/editor/hooks/usePermissionManager.d.ts +2 -3
- package/dist/editor/hooks/usePermissionManager.js +0 -1
- package/dist/editor/hooks/useReferenceResolution.d.ts +1 -2
- package/dist/editor/hooks/useReferenceResolution.js +8 -3
- package/dist/editor/hooks/useSchemaManager.d.ts +2 -3
- package/dist/editor/hooks/useSchemaManager.js +0 -1
- package/dist/editor/hooks/useUserContext.d.ts +1 -2
- package/dist/editor/hooks/useUserContext.js +8 -3
- package/dist/editor/hooks/useUserMetadata.d.ts +2 -3
- package/dist/editor/hooks/useUserMetadata.js +0 -1
- package/dist/editor/media/AssetCard.d.ts +1 -2
- package/dist/editor/media/AssetCard.js +0 -1
- package/dist/editor/media/CropStep.d.ts +1 -2
- package/dist/editor/media/CropStep.js +0 -1
- package/dist/editor/media/MediaLibrary.d.ts +1 -2
- package/dist/editor/media/MediaLibrary.js +0 -1
- package/dist/editor/media/MediaLibraryBody.d.ts +1 -2
- package/dist/editor/media/MediaLibraryBody.js +0 -1
- package/dist/editor/media/crop-math.d.ts +1 -2
- package/dist/editor/media/crop-math.js +0 -1
- package/dist/editor/media/upload-asset.d.ts +2 -3
- package/dist/editor/media/upload-asset.js +0 -1
- package/dist/editor/media/upload-constants.d.ts +0 -1
- package/dist/editor/media/upload-constants.js +0 -1
- package/dist/editor/media/useAssetUpload.d.ts +1 -2
- package/dist/editor/media/useAssetUpload.js +0 -1
- package/dist/editor/media/xhr-upload.d.ts +0 -1
- package/dist/editor/media/xhr-upload.js +0 -1
- package/dist/editor/permission-manager/GroupSelector.d.ts +1 -2
- package/dist/editor/permission-manager/GroupSelector.js +0 -1
- package/dist/editor/permission-manager/PermissionEditor.d.ts +1 -2
- package/dist/editor/permission-manager/PermissionEditor.js +0 -1
- package/dist/editor/permission-manager/PermissionLevelBadge.d.ts +1 -2
- package/dist/editor/permission-manager/PermissionLevelBadge.js +0 -1
- package/dist/editor/permission-manager/PermissionTree.d.ts +1 -2
- package/dist/editor/permission-manager/PermissionTree.js +0 -1
- package/dist/editor/permission-manager/UserSelector.d.ts +1 -2
- package/dist/editor/permission-manager/UserSelector.js +0 -1
- package/dist/editor/permission-manager/constants.d.ts +1 -2
- package/dist/editor/permission-manager/constants.js +0 -1
- package/dist/editor/permission-manager/hooks/useGroupsAndUsers.d.ts +1 -2
- package/dist/editor/permission-manager/hooks/useGroupsAndUsers.js +0 -1
- package/dist/editor/permission-manager/hooks/usePermissionTree.d.ts +2 -3
- package/dist/editor/permission-manager/hooks/usePermissionTree.js +0 -1
- package/dist/editor/permission-manager/index.d.ts +4 -5
- package/dist/editor/permission-manager/index.js +0 -1
- package/dist/editor/permission-manager/types.d.ts +3 -4
- package/dist/editor/permission-manager/types.js +0 -1
- package/dist/editor/permission-manager/utils.d.ts +2 -3
- package/dist/editor/permission-manager/utils.js +0 -1
- package/dist/editor/preview-bridge.d.ts +1 -2
- package/dist/editor/preview-bridge.js +0 -1
- package/dist/editor/relative-time.d.ts +0 -1
- package/dist/editor/relative-time.js +0 -1
- package/dist/editor/schema-editor/CollectionEditor.d.ts +4 -5
- package/dist/editor/schema-editor/CollectionEditor.js +0 -1
- package/dist/editor/schema-editor/EntryTypeEditor.d.ts +2 -3
- package/dist/editor/schema-editor/EntryTypeEditor.js +0 -1
- package/dist/editor/schema-editor/index.d.ts +2 -3
- package/dist/editor/schema-editor/index.js +0 -1
- package/dist/editor/theme.d.ts +0 -1
- package/dist/editor/theme.js +0 -1
- package/dist/editor/utils/env.d.ts +0 -1
- package/dist/editor/utils/env.js +0 -1
- package/dist/entry-link-resolver.d.ts +1 -2
- package/dist/entry-link-resolver.js +0 -1
- package/dist/entry-schema-registry.d.ts +3 -4
- package/dist/entry-schema-registry.js +6 -2
- package/dist/entry-schema.d.ts +342 -11
- package/dist/entry-schema.js +170 -1
- package/dist/git-manager.d.ts +1 -2
- package/dist/git-manager.js +0 -1
- package/dist/github-service.d.ts +1 -2
- package/dist/github-service.js +0 -1
- package/dist/http/handler.d.ts +6 -7
- package/dist/http/handler.js +0 -1
- package/dist/http/index.d.ts +6 -7
- package/dist/http/index.js +0 -1
- package/dist/http/router.d.ts +2 -3
- package/dist/http/router.js +0 -1
- package/dist/http/types.d.ts +0 -1
- package/dist/http/types.js +0 -1
- package/dist/id.d.ts +2 -3
- package/dist/id.js +0 -1
- package/dist/index.d.ts +17 -17
- package/dist/index.js +7 -1
- package/dist/operating-mode/client-safe-strategy.d.ts +1 -2
- package/dist/operating-mode/client-safe-strategy.js +0 -1
- package/dist/operating-mode/client-unsafe-strategy.d.ts +1 -2
- package/dist/operating-mode/client-unsafe-strategy.js +0 -1
- package/dist/operating-mode/client.d.ts +3 -4
- package/dist/operating-mode/client.js +0 -1
- package/dist/operating-mode/deployment-name-fixtures.d.ts +0 -1
- package/dist/operating-mode/deployment-name-fixtures.js +0 -1
- package/dist/operating-mode/deployment-name.d.ts +0 -1
- package/dist/operating-mode/deployment-name.js +0 -1
- package/dist/operating-mode/index.d.ts +5 -6
- package/dist/operating-mode/index.js +0 -1
- package/dist/operating-mode/mode-env.d.ts +1 -2
- package/dist/operating-mode/mode-env.js +0 -1
- package/dist/operating-mode/types.d.ts +2 -3
- package/dist/operating-mode/types.js +0 -1
- package/dist/paths/branch-name.d.ts +1 -2
- package/dist/paths/branch-name.js +0 -1
- package/dist/paths/branch.d.ts +3 -4
- package/dist/paths/branch.js +0 -1
- package/dist/paths/index.d.ts +8 -9
- package/dist/paths/index.js +0 -1
- package/dist/paths/normalize-server.d.ts +1 -2
- package/dist/paths/normalize-server.js +0 -1
- package/dist/paths/normalize.d.ts +1 -2
- package/dist/paths/normalize.js +0 -1
- package/dist/paths/resolve.d.ts +2 -3
- package/dist/paths/resolve.js +0 -1
- package/dist/paths/types.d.ts +0 -1
- package/dist/paths/types.js +0 -1
- package/dist/paths/validation.d.ts +1 -2
- package/dist/paths/validation.js +0 -1
- package/dist/reference-resolver.d.ts +3 -4
- package/dist/reference-resolver.js +0 -1
- package/dist/resolve-canopy-user.d.ts +3 -4
- package/dist/resolve-canopy-user.js +0 -1
- package/dist/resource-generation.d.ts +0 -1
- package/dist/resource-generation.js +0 -1
- package/dist/schema/index.d.ts +3 -4
- package/dist/schema/index.js +0 -1
- package/dist/schema/meta-loader.d.ts +3 -4
- package/dist/schema/meta-loader.js +3 -3
- package/dist/schema/resolver.d.ts +2 -3
- package/dist/schema/resolver.js +0 -1
- package/dist/schema/schema-store-types.d.ts +2 -3
- package/dist/schema/schema-store-types.js +0 -1
- package/dist/schema/schema-store.d.ts +6 -7
- package/dist/schema/schema-store.js +33 -1
- package/dist/schema/types.d.ts +1 -2
- package/dist/schema/types.js +0 -1
- package/dist/server.d.ts +97 -37
- package/dist/server.js +60 -3
- package/dist/services.d.ts +10 -12
- package/dist/services.js +2 -7
- package/dist/settings-workspace.d.ts +12 -15
- package/dist/settings-workspace.js +10 -13
- package/dist/static/index.d.ts +227 -9
- package/dist/static/index.js +302 -14
- package/dist/static/seo.d.ts +128 -0
- package/dist/static/seo.js +162 -0
- package/dist/sync-core.d.ts +0 -1
- package/dist/sync-core.js +0 -1
- package/dist/task-queue/index.d.ts +2 -3
- package/dist/task-queue/index.js +0 -1
- package/dist/task-queue/task-queue.d.ts +1 -2
- package/dist/task-queue/task-queue.js +0 -1
- package/dist/task-queue/types.d.ts +0 -1
- package/dist/task-queue/types.js +0 -1
- package/dist/types.d.ts +3 -4
- package/dist/types.js +0 -1
- package/dist/url-collision.d.ts +86 -0
- package/dist/url-collision.js +186 -0
- package/dist/url-path-resolver.d.ts +11 -2
- package/dist/url-path-resolver.js +37 -5
- package/dist/user.d.ts +3 -4
- package/dist/user.js +0 -1
- package/dist/utils/async-mutex.d.ts +0 -1
- package/dist/utils/async-mutex.js +0 -1
- package/dist/utils/atomic-write.d.ts +0 -1
- package/dist/utils/atomic-write.js +0 -1
- package/dist/utils/body-field.d.ts +12 -2
- package/dist/utils/body-field.js +17 -1
- package/dist/utils/content-serialize.d.ts +37 -0
- package/dist/utils/content-serialize.js +429 -0
- package/dist/utils/content-write-lock.d.ts +12 -16
- package/dist/utils/content-write-lock.js +38 -22
- package/dist/utils/debug.d.ts +0 -1
- package/dist/utils/debug.js +0 -1
- package/dist/utils/entry-url.d.ts +17 -1
- package/dist/utils/entry-url.js +21 -3
- package/dist/utils/error.d.ts +0 -1
- package/dist/utils/error.js +0 -1
- package/dist/utils/flatten-group-fields.d.ts +1 -2
- package/dist/utils/flatten-group-fields.js +0 -1
- package/dist/utils/format.d.ts +1 -2
- package/dist/utils/format.js +0 -1
- package/dist/utils/fs.d.ts +7 -1
- package/dist/utils/fs.js +16 -1
- package/dist/utils/git.d.ts +1 -2
- package/dist/utils/git.js +0 -1
- package/dist/utils/logger.d.ts +0 -1
- package/dist/utils/logger.js +0 -1
- package/dist/utils/occ-json-write.d.ts +0 -1
- package/dist/utils/occ-json-write.js +0 -1
- package/dist/utils/provisioning-lock.d.ts +17 -4
- package/dist/utils/provisioning-lock.js +94 -14
- package/dist/utils/sanitize-href.d.ts +46 -1
- package/dist/utils/sanitize-href.js +63 -3
- package/dist/utils/title-field.d.ts +1 -2
- package/dist/utils/title-field.js +0 -1
- package/dist/utils/typed-filename.d.ts +61 -0
- package/dist/utils/typed-filename.js +92 -0
- package/dist/utils/url-prefix.d.ts +121 -0
- package/dist/utils/url-prefix.js +158 -0
- package/dist/validation/block-structural-keys.d.ts +42 -0
- package/dist/validation/block-structural-keys.js +44 -0
- package/dist/validation/deletion-checker.d.ts +4 -5
- package/dist/validation/deletion-checker.js +0 -1
- package/dist/validation/entry-link-validator.d.ts +2 -3
- package/dist/validation/entry-link-validator.js +0 -1
- package/dist/validation/entry-type-reference-validator.d.ts +1 -2
- package/dist/validation/entry-type-reference-validator.js +0 -1
- package/dist/validation/entry-validator.d.ts +23 -2
- package/dist/validation/entry-validator.js +34 -2
- package/dist/validation/field-traversal.d.ts +28 -4
- package/dist/validation/field-traversal.js +24 -7
- package/dist/validation/reference-validator.d.ts +2 -3
- package/dist/validation/reference-validator.js +0 -1
- package/dist/worker/cms-worker.d.ts +9 -2
- package/dist/worker/cms-worker.js +59 -2
- package/dist/worker/log.d.ts +0 -1
- package/dist/worker/log.js +0 -1
- package/dist/worker/task-queue-config.d.ts +1 -2
- package/dist/worker/task-queue-config.js +0 -1
- package/dist/worker/task-queue.d.ts +3 -4
- package/dist/worker/task-queue.js +0 -1
- package/dist/worker/worker-status.d.ts +1 -2
- package/dist/worker/worker-status.js +0 -1
- package/package.json +2 -6
- package/dist/ai/generate.d.ts.map +0 -1
- package/dist/ai/generate.js.map +0 -1
- package/dist/ai/handler.d.ts.map +0 -1
- package/dist/ai/handler.js.map +0 -1
- package/dist/ai/index.d.ts.map +0 -1
- package/dist/ai/index.js.map +0 -1
- package/dist/ai/json-to-markdown.d.ts.map +0 -1
- package/dist/ai/json-to-markdown.js.map +0 -1
- package/dist/ai/resolve-branch.d.ts.map +0 -1
- package/dist/ai/resolve-branch.js.map +0 -1
- package/dist/ai/strip-mdx.d.ts.map +0 -1
- package/dist/ai/strip-mdx.js.map +0 -1
- package/dist/ai/transform-components.d.ts.map +0 -1
- package/dist/ai/transform-components.js.map +0 -1
- package/dist/ai/types.d.ts.map +0 -1
- package/dist/ai/types.js.map +0 -1
- package/dist/api/__test__/mock-client.d.ts +0 -231
- package/dist/api/__test__/mock-client.d.ts.map +0 -1
- package/dist/api/__test__/mock-client.js +0 -388
- package/dist/api/__test__/mock-client.js.map +0 -1
- package/dist/api/admin-branch-health.d.ts.map +0 -1
- package/dist/api/admin-branch-health.js.map +0 -1
- package/dist/api/admin.d.ts.map +0 -1
- package/dist/api/admin.js.map +0 -1
- package/dist/api/assets.d.ts.map +0 -1
- package/dist/api/assets.js.map +0 -1
- package/dist/api/branch-merge.d.ts.map +0 -1
- package/dist/api/branch-merge.js.map +0 -1
- package/dist/api/branch-review.d.ts.map +0 -1
- package/dist/api/branch-review.js.map +0 -1
- package/dist/api/branch-status.d.ts.map +0 -1
- package/dist/api/branch-status.js.map +0 -1
- package/dist/api/branch-withdraw.d.ts.map +0 -1
- package/dist/api/branch-withdraw.js.map +0 -1
- package/dist/api/branch.d.ts.map +0 -1
- package/dist/api/branch.js.map +0 -1
- package/dist/api/client.d.ts.map +0 -1
- package/dist/api/client.js.map +0 -1
- package/dist/api/comments.d.ts.map +0 -1
- package/dist/api/comments.js.map +0 -1
- package/dist/api/content.d.ts.map +0 -1
- package/dist/api/content.js.map +0 -1
- package/dist/api/entries-constants.d.ts.map +0 -1
- package/dist/api/entries-constants.js.map +0 -1
- package/dist/api/entries.d.ts.map +0 -1
- package/dist/api/entries.js.map +0 -1
- package/dist/api/github-sync.d.ts.map +0 -1
- package/dist/api/github-sync.js.map +0 -1
- package/dist/api/groups.d.ts.map +0 -1
- package/dist/api/groups.js.map +0 -1
- package/dist/api/guards.d.ts.map +0 -1
- package/dist/api/guards.js.map +0 -1
- package/dist/api/index.d.ts.map +0 -1
- package/dist/api/index.js.map +0 -1
- package/dist/api/permissions.d.ts.map +0 -1
- package/dist/api/permissions.js.map +0 -1
- package/dist/api/reference-options.d.ts.map +0 -1
- package/dist/api/reference-options.js.map +0 -1
- package/dist/api/request-body-hash.d.ts.map +0 -1
- package/dist/api/request-body-hash.js.map +0 -1
- package/dist/api/resolve-references.d.ts.map +0 -1
- package/dist/api/resolve-references.js.map +0 -1
- package/dist/api/route-builder.d.ts.map +0 -1
- package/dist/api/route-builder.js.map +0 -1
- package/dist/api/schema.d.ts.map +0 -1
- package/dist/api/schema.js.map +0 -1
- package/dist/api/settings-helpers.d.ts.map +0 -1
- package/dist/api/settings-helpers.js.map +0 -1
- package/dist/api/types.d.ts.map +0 -1
- package/dist/api/types.js.map +0 -1
- package/dist/api/user.d.ts.map +0 -1
- package/dist/api/user.js.map +0 -1
- package/dist/api/validators.d.ts.map +0 -1
- package/dist/api/validators.js.map +0 -1
- package/dist/assets/asset-prefixes.d.ts.map +0 -1
- package/dist/assets/asset-prefixes.js.map +0 -1
- package/dist/assets/asset-src.d.ts.map +0 -1
- package/dist/assets/asset-src.js.map +0 -1
- package/dist/assets/asset-url.d.ts.map +0 -1
- package/dist/assets/asset-url.js.map +0 -1
- package/dist/assets/factory.d.ts.map +0 -1
- package/dist/assets/factory.js.map +0 -1
- package/dist/assets/finalize.d.ts.map +0 -1
- package/dist/assets/finalize.js.map +0 -1
- package/dist/assets/index.d.ts.map +0 -1
- package/dist/assets/index.js.map +0 -1
- package/dist/assets/keys.d.ts.map +0 -1
- package/dist/assets/keys.js.map +0 -1
- package/dist/assets/pipeline.d.ts.map +0 -1
- package/dist/assets/pipeline.js.map +0 -1
- package/dist/assets/store-local.d.ts.map +0 -1
- package/dist/assets/store-local.js.map +0 -1
- package/dist/assets/store-s3.d.ts.map +0 -1
- package/dist/assets/store-s3.js.map +0 -1
- package/dist/assets/svg-sanitizer.d.ts.map +0 -1
- package/dist/assets/svg-sanitizer.js.map +0 -1
- package/dist/assets/transform-directives.d.ts.map +0 -1
- package/dist/assets/transform-directives.js.map +0 -1
- package/dist/assets/transform.d.ts.map +0 -1
- package/dist/assets/transform.js.map +0 -1
- package/dist/assets/types.d.ts.map +0 -1
- package/dist/assets/types.js.map +0 -1
- package/dist/auth/cache.d.ts.map +0 -1
- package/dist/auth/cache.js.map +0 -1
- package/dist/auth/caching-auth-plugin.d.ts.map +0 -1
- package/dist/auth/caching-auth-plugin.js.map +0 -1
- package/dist/auth/context-helpers.d.ts.map +0 -1
- package/dist/auth/context-helpers.js.map +0 -1
- package/dist/auth/file-based-auth-cache.d.ts.map +0 -1
- package/dist/auth/file-based-auth-cache.js.map +0 -1
- package/dist/auth/index.d.ts.map +0 -1
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/plugin.d.ts.map +0 -1
- package/dist/auth/plugin.js.map +0 -1
- package/dist/auth/types.d.ts.map +0 -1
- package/dist/auth/types.js.map +0 -1
- package/dist/authorization/branch.d.ts.map +0 -1
- package/dist/authorization/branch.js.map +0 -1
- package/dist/authorization/content.d.ts.map +0 -1
- package/dist/authorization/content.js.map +0 -1
- package/dist/authorization/groups/index.d.ts.map +0 -1
- package/dist/authorization/groups/index.js.map +0 -1
- package/dist/authorization/groups/loader.d.ts.map +0 -1
- package/dist/authorization/groups/loader.js.map +0 -1
- package/dist/authorization/groups/schema.d.ts.map +0 -1
- package/dist/authorization/groups/schema.js.map +0 -1
- package/dist/authorization/helpers.d.ts.map +0 -1
- package/dist/authorization/helpers.js.map +0 -1
- package/dist/authorization/index.d.ts.map +0 -1
- package/dist/authorization/index.js.map +0 -1
- package/dist/authorization/path.d.ts.map +0 -1
- package/dist/authorization/path.js.map +0 -1
- package/dist/authorization/permissions/index.d.ts.map +0 -1
- package/dist/authorization/permissions/index.js.map +0 -1
- package/dist/authorization/permissions/loader.d.ts.map +0 -1
- package/dist/authorization/permissions/loader.js.map +0 -1
- package/dist/authorization/permissions/schema.d.ts.map +0 -1
- package/dist/authorization/permissions/schema.js.map +0 -1
- package/dist/authorization/protected-branch.d.ts.map +0 -1
- package/dist/authorization/protected-branch.js.map +0 -1
- package/dist/authorization/settings-file-store.d.ts.map +0 -1
- package/dist/authorization/settings-file-store.js.map +0 -1
- package/dist/authorization/test-utils.d.ts +0 -26
- package/dist/authorization/test-utils.d.ts.map +0 -1
- package/dist/authorization/test-utils.js +0 -23
- package/dist/authorization/test-utils.js.map +0 -1
- package/dist/authorization/types.d.ts.map +0 -1
- package/dist/authorization/types.js.map +0 -1
- package/dist/authorization/validation.d.ts.map +0 -1
- package/dist/authorization/validation.js.map +0 -1
- package/dist/branch-health.d.ts.map +0 -1
- package/dist/branch-health.js.map +0 -1
- package/dist/branch-metadata.d.ts.map +0 -1
- package/dist/branch-metadata.js.map +0 -1
- package/dist/branch-registry.d.ts.map +0 -1
- package/dist/branch-registry.js.map +0 -1
- package/dist/branch-schema-cache.d.ts.map +0 -1
- package/dist/branch-schema-cache.js.map +0 -1
- package/dist/branch-workspace.d.ts.map +0 -1
- package/dist/branch-workspace.js.map +0 -1
- package/dist/build/generate-ai-content.d.ts.map +0 -1
- package/dist/build/generate-ai-content.js.map +0 -1
- package/dist/build/index.d.ts.map +0 -1
- package/dist/build/index.js.map +0 -1
- package/dist/build-mode.d.ts.map +0 -1
- package/dist/build-mode.js.map +0 -1
- package/dist/cli/cli.d.ts.map +0 -1
- package/dist/cli/cli.js.map +0 -1
- package/dist/cli/generate-ai-content.d.ts.map +0 -1
- package/dist/cli/generate-ai-content.js.map +0 -1
- package/dist/cli/init.d.ts.map +0 -1
- package/dist/cli/init.js.map +0 -1
- package/dist/cli/migrate.d.ts.map +0 -1
- package/dist/cli/migrate.js.map +0 -1
- package/dist/cli/project-detect.d.ts.map +0 -1
- package/dist/cli/project-detect.js.map +0 -1
- package/dist/cli/project-root.d.ts.map +0 -1
- package/dist/cli/project-root.js.map +0 -1
- package/dist/cli/sync.d.ts.map +0 -1
- package/dist/cli/sync.js.map +0 -1
- package/dist/cli/templates.d.ts.map +0 -1
- package/dist/cli/templates.js.map +0 -1
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js.map +0 -1
- package/dist/comment-store.d.ts.map +0 -1
- package/dist/comment-store.js.map +0 -1
- package/dist/config/flatten.d.ts.map +0 -1
- package/dist/config/flatten.js.map +0 -1
- package/dist/config/helpers.d.ts.map +0 -1
- package/dist/config/helpers.js.map +0 -1
- package/dist/config/index.d.ts.map +0 -1
- package/dist/config/index.js.map +0 -1
- package/dist/config/schemas/collection.d.ts.map +0 -1
- package/dist/config/schemas/collection.js.map +0 -1
- package/dist/config/schemas/config.d.ts.map +0 -1
- package/dist/config/schemas/config.js.map +0 -1
- package/dist/config/schemas/field.d.ts.map +0 -1
- package/dist/config/schemas/field.js.map +0 -1
- package/dist/config/schemas/media.d.ts.map +0 -1
- package/dist/config/schemas/media.js.map +0 -1
- package/dist/config/schemas/permissions.d.ts.map +0 -1
- package/dist/config/schemas/permissions.js.map +0 -1
- package/dist/config/types.d.ts.map +0 -1
- package/dist/config/types.js.map +0 -1
- package/dist/config/validation.d.ts.map +0 -1
- package/dist/config/validation.js.map +0 -1
- package/dist/config-test.d.ts +0 -20
- package/dist/config-test.d.ts.map +0 -1
- package/dist/config-test.js +0 -49
- package/dist/config-test.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/content-id-index.d.ts.map +0 -1
- package/dist/content-id-index.js.map +0 -1
- package/dist/content-index-generation.d.ts.map +0 -1
- package/dist/content-index-generation.js.map +0 -1
- package/dist/content-index-registry.d.ts.map +0 -1
- package/dist/content-index-registry.js.map +0 -1
- package/dist/content-listing.d.ts.map +0 -1
- package/dist/content-listing.js.map +0 -1
- package/dist/content-reader.d.ts.map +0 -1
- package/dist/content-reader.js.map +0 -1
- package/dist/content-store.d.ts.map +0 -1
- package/dist/content-store.js.map +0 -1
- package/dist/content-tree.d.ts.map +0 -1
- package/dist/content-tree.js.map +0 -1
- package/dist/context.d.ts.map +0 -1
- package/dist/context.js.map +0 -1
- package/dist/dev-content-watcher.d.ts.map +0 -1
- package/dist/dev-content-watcher.js.map +0 -1
- package/dist/editor/BranchManager.d.ts.map +0 -1
- package/dist/editor/BranchManager.js.map +0 -1
- package/dist/editor/CanopyEditor.d.ts.map +0 -1
- package/dist/editor/CanopyEditor.js.map +0 -1
- package/dist/editor/CanopyEditorPage.d.ts.map +0 -1
- package/dist/editor/CanopyEditorPage.js.map +0 -1
- package/dist/editor/CommentsPanel.d.ts.map +0 -1
- package/dist/editor/CommentsPanel.js.map +0 -1
- package/dist/editor/Editor.d.ts.map +0 -1
- package/dist/editor/Editor.js.map +0 -1
- package/dist/editor/EditorPanes.d.ts.map +0 -1
- package/dist/editor/EditorPanes.js.map +0 -1
- package/dist/editor/EntryNavigator.d.ts.map +0 -1
- package/dist/editor/EntryNavigator.js.map +0 -1
- package/dist/editor/FormRenderer.d.ts.map +0 -1
- package/dist/editor/FormRenderer.js.map +0 -1
- package/dist/editor/GroupManager.d.ts.map +0 -1
- package/dist/editor/GroupManager.js.map +0 -1
- package/dist/editor/PermissionManager.d.ts.map +0 -1
- package/dist/editor/PermissionManager.js.map +0 -1
- package/dist/editor/admin/SystemHealthPanel.d.ts.map +0 -1
- package/dist/editor/admin/SystemHealthPanel.js.map +0 -1
- package/dist/editor/admin/useSystemHealth.d.ts.map +0 -1
- package/dist/editor/admin/useSystemHealth.js.map +0 -1
- package/dist/editor/canopy-path.d.ts.map +0 -1
- package/dist/editor/canopy-path.js.map +0 -1
- package/dist/editor/client-reference-resolver.d.ts.map +0 -1
- package/dist/editor/client-reference-resolver.js.map +0 -1
- package/dist/editor/comments/BranchComments.d.ts.map +0 -1
- package/dist/editor/comments/BranchComments.js.map +0 -1
- package/dist/editor/comments/EntryComments.d.ts.map +0 -1
- package/dist/editor/comments/EntryComments.js.map +0 -1
- package/dist/editor/comments/FieldWrapper.d.ts.map +0 -1
- package/dist/editor/comments/FieldWrapper.js.map +0 -1
- package/dist/editor/comments/InlineCommentThread.d.ts.map +0 -1
- package/dist/editor/comments/InlineCommentThread.js.map +0 -1
- package/dist/editor/comments/ThreadCarousel.d.ts.map +0 -1
- package/dist/editor/comments/ThreadCarousel.js.map +0 -1
- package/dist/editor/components/ConfirmDeleteModal.d.ts.map +0 -1
- package/dist/editor/components/ConfirmDeleteModal.js.map +0 -1
- package/dist/editor/components/EditorFooter.d.ts.map +0 -1
- package/dist/editor/components/EditorFooter.js.map +0 -1
- package/dist/editor/components/EditorHeader.d.ts.map +0 -1
- package/dist/editor/components/EditorHeader.js.map +0 -1
- package/dist/editor/components/EditorSidebar.d.ts.map +0 -1
- package/dist/editor/components/EditorSidebar.js.map +0 -1
- package/dist/editor/components/EntryCreateModal.d.ts.map +0 -1
- package/dist/editor/components/EntryCreateModal.js.map +0 -1
- package/dist/editor/components/RenameEntryModal.d.ts.map +0 -1
- package/dist/editor/components/RenameEntryModal.js.map +0 -1
- package/dist/editor/components/UserBadge.d.ts.map +0 -1
- package/dist/editor/components/UserBadge.js.map +0 -1
- package/dist/editor/components/index.d.ts.map +0 -1
- package/dist/editor/components/index.js.map +0 -1
- package/dist/editor/context/ApiClientContext.d.ts.map +0 -1
- package/dist/editor/context/ApiClientContext.js.map +0 -1
- package/dist/editor/context/AssetContext.d.ts.map +0 -1
- package/dist/editor/context/AssetContext.js.map +0 -1
- package/dist/editor/context/EditorStateContext.d.ts.map +0 -1
- package/dist/editor/context/EditorStateContext.js.map +0 -1
- package/dist/editor/context/SWRProvider.d.ts.map +0 -1
- package/dist/editor/context/SWRProvider.js.map +0 -1
- package/dist/editor/context/index.d.ts.map +0 -1
- package/dist/editor/context/index.js.map +0 -1
- package/dist/editor/editor-config.d.ts.map +0 -1
- package/dist/editor/editor-config.js.map +0 -1
- package/dist/editor/editor-utils.d.ts.map +0 -1
- package/dist/editor/editor-utils.js.map +0 -1
- package/dist/editor/fields/BlockField.d.ts.map +0 -1
- package/dist/editor/fields/BlockField.js.map +0 -1
- package/dist/editor/fields/CodeField.d.ts.map +0 -1
- package/dist/editor/fields/CodeField.js.map +0 -1
- package/dist/editor/fields/DateTimeField.d.ts.map +0 -1
- package/dist/editor/fields/DateTimeField.js.map +0 -1
- package/dist/editor/fields/ImageField.d.ts.map +0 -1
- package/dist/editor/fields/ImageField.js.map +0 -1
- package/dist/editor/fields/InlineGroupField.d.ts.map +0 -1
- package/dist/editor/fields/InlineGroupField.js.map +0 -1
- package/dist/editor/fields/MarkdownField.d.ts.map +0 -1
- package/dist/editor/fields/MarkdownField.js.map +0 -1
- package/dist/editor/fields/MdxImageDialog.d.ts.map +0 -1
- package/dist/editor/fields/MdxImageDialog.js.map +0 -1
- package/dist/editor/fields/NumberField.d.ts.map +0 -1
- package/dist/editor/fields/NumberField.js.map +0 -1
- package/dist/editor/fields/NumberListField.d.ts.map +0 -1
- package/dist/editor/fields/NumberListField.js.map +0 -1
- package/dist/editor/fields/ObjectField.d.ts.map +0 -1
- package/dist/editor/fields/ObjectField.js.map +0 -1
- package/dist/editor/fields/ReferenceField.d.ts.map +0 -1
- package/dist/editor/fields/ReferenceField.js.map +0 -1
- package/dist/editor/fields/SelectField.d.ts.map +0 -1
- package/dist/editor/fields/SelectField.js.map +0 -1
- package/dist/editor/fields/StringListField.d.ts.map +0 -1
- package/dist/editor/fields/StringListField.js.map +0 -1
- package/dist/editor/fields/TextField.d.ts.map +0 -1
- package/dist/editor/fields/TextField.js.map +0 -1
- package/dist/editor/fields/ToggleField.d.ts.map +0 -1
- package/dist/editor/fields/ToggleField.js.map +0 -1
- package/dist/editor/fields/entry-link/EntryLinkContext.d.ts.map +0 -1
- package/dist/editor/fields/entry-link/EntryLinkContext.js.map +0 -1
- package/dist/editor/fields/entry-link/InsertEntryLink.d.ts.map +0 -1
- package/dist/editor/fields/entry-link/InsertEntryLink.js.map +0 -1
- package/dist/editor/fields/entry-link/index.d.ts.map +0 -1
- package/dist/editor/fields/entry-link/index.js.map +0 -1
- package/dist/editor/group-manager/ExternalGroupsTab.d.ts.map +0 -1
- package/dist/editor/group-manager/ExternalGroupsTab.js.map +0 -1
- package/dist/editor/group-manager/GroupCard.d.ts.map +0 -1
- package/dist/editor/group-manager/GroupCard.js.map +0 -1
- package/dist/editor/group-manager/GroupForm.d.ts.map +0 -1
- package/dist/editor/group-manager/GroupForm.js.map +0 -1
- package/dist/editor/group-manager/InternalGroupsTab.d.ts.map +0 -1
- package/dist/editor/group-manager/InternalGroupsTab.js.map +0 -1
- package/dist/editor/group-manager/MemberList.d.ts.map +0 -1
- package/dist/editor/group-manager/MemberList.js.map +0 -1
- package/dist/editor/group-manager/hooks/useExternalGroupSearch.d.ts.map +0 -1
- package/dist/editor/group-manager/hooks/useExternalGroupSearch.js.map +0 -1
- package/dist/editor/group-manager/hooks/useGroupState.d.ts.map +0 -1
- package/dist/editor/group-manager/hooks/useGroupState.js.map +0 -1
- package/dist/editor/group-manager/hooks/useUserSearch.d.ts.map +0 -1
- package/dist/editor/group-manager/hooks/useUserSearch.js.map +0 -1
- package/dist/editor/group-manager/index.d.ts.map +0 -1
- package/dist/editor/group-manager/index.js.map +0 -1
- package/dist/editor/group-manager/types.d.ts.map +0 -1
- package/dist/editor/group-manager/types.js.map +0 -1
- package/dist/editor/hooks/__test__/test-utils.d.ts +0 -164
- package/dist/editor/hooks/__test__/test-utils.d.ts.map +0 -1
- package/dist/editor/hooks/__test__/test-utils.js +0 -203
- package/dist/editor/hooks/__test__/test-utils.js.map +0 -1
- package/dist/editor/hooks/index.d.ts.map +0 -1
- package/dist/editor/hooks/index.js.map +0 -1
- package/dist/editor/hooks/useBranchActions.d.ts.map +0 -1
- package/dist/editor/hooks/useBranchActions.js.map +0 -1
- package/dist/editor/hooks/useBranchManager.d.ts.map +0 -1
- package/dist/editor/hooks/useBranchManager.js.map +0 -1
- package/dist/editor/hooks/useBranchesData.d.ts.map +0 -1
- package/dist/editor/hooks/useBranchesData.js.map +0 -1
- package/dist/editor/hooks/useCommentSystem.d.ts.map +0 -1
- package/dist/editor/hooks/useCommentSystem.js.map +0 -1
- package/dist/editor/hooks/useCommentsData.d.ts.map +0 -1
- package/dist/editor/hooks/useCommentsData.js.map +0 -1
- package/dist/editor/hooks/useDraftManager.d.ts.map +0 -1
- package/dist/editor/hooks/useDraftManager.js.map +0 -1
- package/dist/editor/hooks/useEditorLayout.d.ts.map +0 -1
- package/dist/editor/hooks/useEditorLayout.js.map +0 -1
- package/dist/editor/hooks/useEntriesData.d.ts.map +0 -1
- package/dist/editor/hooks/useEntriesData.js.map +0 -1
- package/dist/editor/hooks/useEntryLinkResolution.d.ts.map +0 -1
- package/dist/editor/hooks/useEntryLinkResolution.js.map +0 -1
- package/dist/editor/hooks/useEntryManager.d.ts.map +0 -1
- package/dist/editor/hooks/useEntryManager.js.map +0 -1
- package/dist/editor/hooks/useGroupManager.d.ts.map +0 -1
- package/dist/editor/hooks/useGroupManager.js.map +0 -1
- package/dist/editor/hooks/usePermissionManager.d.ts.map +0 -1
- package/dist/editor/hooks/usePermissionManager.js.map +0 -1
- package/dist/editor/hooks/useReferenceResolution.d.ts.map +0 -1
- package/dist/editor/hooks/useReferenceResolution.js.map +0 -1
- package/dist/editor/hooks/useSchemaManager.d.ts.map +0 -1
- package/dist/editor/hooks/useSchemaManager.js.map +0 -1
- package/dist/editor/hooks/useUserContext.d.ts.map +0 -1
- package/dist/editor/hooks/useUserContext.js.map +0 -1
- package/dist/editor/hooks/useUserMetadata.d.ts.map +0 -1
- package/dist/editor/hooks/useUserMetadata.js.map +0 -1
- package/dist/editor/media/AssetCard.d.ts.map +0 -1
- package/dist/editor/media/AssetCard.js.map +0 -1
- package/dist/editor/media/CropStep.d.ts.map +0 -1
- package/dist/editor/media/CropStep.js.map +0 -1
- package/dist/editor/media/MediaLibrary.d.ts.map +0 -1
- package/dist/editor/media/MediaLibrary.js.map +0 -1
- package/dist/editor/media/MediaLibraryBody.d.ts.map +0 -1
- package/dist/editor/media/MediaLibraryBody.js.map +0 -1
- package/dist/editor/media/crop-math.d.ts.map +0 -1
- package/dist/editor/media/crop-math.js.map +0 -1
- package/dist/editor/media/upload-asset.d.ts.map +0 -1
- package/dist/editor/media/upload-asset.js.map +0 -1
- package/dist/editor/media/upload-constants.d.ts.map +0 -1
- package/dist/editor/media/upload-constants.js.map +0 -1
- package/dist/editor/media/useAssetUpload.d.ts.map +0 -1
- package/dist/editor/media/useAssetUpload.js.map +0 -1
- package/dist/editor/media/xhr-upload.d.ts.map +0 -1
- package/dist/editor/media/xhr-upload.js.map +0 -1
- package/dist/editor/permission-manager/GroupSelector.d.ts.map +0 -1
- package/dist/editor/permission-manager/GroupSelector.js.map +0 -1
- package/dist/editor/permission-manager/PermissionEditor.d.ts.map +0 -1
- package/dist/editor/permission-manager/PermissionEditor.js.map +0 -1
- package/dist/editor/permission-manager/PermissionLevelBadge.d.ts.map +0 -1
- package/dist/editor/permission-manager/PermissionLevelBadge.js.map +0 -1
- package/dist/editor/permission-manager/PermissionTree.d.ts.map +0 -1
- package/dist/editor/permission-manager/PermissionTree.js.map +0 -1
- package/dist/editor/permission-manager/UserSelector.d.ts.map +0 -1
- package/dist/editor/permission-manager/UserSelector.js.map +0 -1
- package/dist/editor/permission-manager/constants.d.ts.map +0 -1
- package/dist/editor/permission-manager/constants.js.map +0 -1
- package/dist/editor/permission-manager/hooks/useGroupsAndUsers.d.ts.map +0 -1
- package/dist/editor/permission-manager/hooks/useGroupsAndUsers.js.map +0 -1
- package/dist/editor/permission-manager/hooks/usePermissionTree.d.ts.map +0 -1
- package/dist/editor/permission-manager/hooks/usePermissionTree.js.map +0 -1
- package/dist/editor/permission-manager/index.d.ts.map +0 -1
- package/dist/editor/permission-manager/index.js.map +0 -1
- package/dist/editor/permission-manager/types.d.ts.map +0 -1
- package/dist/editor/permission-manager/types.js.map +0 -1
- package/dist/editor/permission-manager/utils.d.ts.map +0 -1
- package/dist/editor/permission-manager/utils.js.map +0 -1
- package/dist/editor/preview-bridge.d.ts.map +0 -1
- package/dist/editor/preview-bridge.js.map +0 -1
- package/dist/editor/relative-time.d.ts.map +0 -1
- package/dist/editor/relative-time.js.map +0 -1
- package/dist/editor/schema-editor/CollectionEditor.d.ts.map +0 -1
- package/dist/editor/schema-editor/CollectionEditor.js.map +0 -1
- package/dist/editor/schema-editor/EntryTypeEditor.d.ts.map +0 -1
- package/dist/editor/schema-editor/EntryTypeEditor.js.map +0 -1
- package/dist/editor/schema-editor/index.d.ts.map +0 -1
- package/dist/editor/schema-editor/index.js.map +0 -1
- package/dist/editor/setup-test-dom.d.ts +0 -1
- package/dist/editor/setup-test-dom.d.ts.map +0 -1
- package/dist/editor/setup-test-dom.js +0 -12
- package/dist/editor/setup-test-dom.js.map +0 -1
- package/dist/editor/test-setup.d.ts +0 -6
- package/dist/editor/test-setup.d.ts.map +0 -1
- package/dist/editor/test-setup.js +0 -42
- package/dist/editor/test-setup.js.map +0 -1
- package/dist/editor/theme.d.ts.map +0 -1
- package/dist/editor/theme.js.map +0 -1
- package/dist/editor/utils/env.d.ts.map +0 -1
- package/dist/editor/utils/env.js.map +0 -1
- package/dist/entry-link-resolver.d.ts.map +0 -1
- package/dist/entry-link-resolver.js.map +0 -1
- package/dist/entry-schema-registry.d.ts.map +0 -1
- package/dist/entry-schema-registry.js.map +0 -1
- package/dist/entry-schema.d.ts.map +0 -1
- package/dist/entry-schema.js.map +0 -1
- package/dist/git-manager.d.ts.map +0 -1
- package/dist/git-manager.js.map +0 -1
- package/dist/github-service.d.ts.map +0 -1
- package/dist/github-service.js.map +0 -1
- package/dist/http/handler.d.ts.map +0 -1
- package/dist/http/handler.js.map +0 -1
- package/dist/http/index.d.ts.map +0 -1
- package/dist/http/index.js.map +0 -1
- package/dist/http/router.d.ts.map +0 -1
- package/dist/http/router.js.map +0 -1
- package/dist/http/types.d.ts.map +0 -1
- package/dist/http/types.js.map +0 -1
- package/dist/id.d.ts.map +0 -1
- package/dist/id.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/operating-mode/client-safe-strategy.d.ts.map +0 -1
- package/dist/operating-mode/client-safe-strategy.js.map +0 -1
- package/dist/operating-mode/client-unsafe-strategy.d.ts.map +0 -1
- package/dist/operating-mode/client-unsafe-strategy.js.map +0 -1
- package/dist/operating-mode/client.d.ts.map +0 -1
- package/dist/operating-mode/client.js.map +0 -1
- package/dist/operating-mode/deployment-name-fixtures.d.ts.map +0 -1
- package/dist/operating-mode/deployment-name-fixtures.js.map +0 -1
- package/dist/operating-mode/deployment-name.d.ts.map +0 -1
- package/dist/operating-mode/deployment-name.js.map +0 -1
- package/dist/operating-mode/index.d.ts.map +0 -1
- package/dist/operating-mode/index.js.map +0 -1
- package/dist/operating-mode/mode-env.d.ts.map +0 -1
- package/dist/operating-mode/mode-env.js.map +0 -1
- package/dist/operating-mode/types.d.ts.map +0 -1
- package/dist/operating-mode/types.js.map +0 -1
- package/dist/paths/branch-name.d.ts.map +0 -1
- package/dist/paths/branch-name.js.map +0 -1
- package/dist/paths/branch.d.ts.map +0 -1
- package/dist/paths/branch.js.map +0 -1
- package/dist/paths/index.d.ts.map +0 -1
- package/dist/paths/index.js.map +0 -1
- package/dist/paths/normalize-server.d.ts.map +0 -1
- package/dist/paths/normalize-server.js.map +0 -1
- package/dist/paths/normalize.d.ts.map +0 -1
- package/dist/paths/normalize.js.map +0 -1
- package/dist/paths/resolve.d.ts.map +0 -1
- package/dist/paths/resolve.js.map +0 -1
- package/dist/paths/test-utils.d.ts +0 -22
- package/dist/paths/test-utils.d.ts.map +0 -1
- package/dist/paths/test-utils.js +0 -21
- package/dist/paths/test-utils.js.map +0 -1
- package/dist/paths/types.d.ts.map +0 -1
- package/dist/paths/types.js.map +0 -1
- package/dist/paths/validation.d.ts.map +0 -1
- package/dist/paths/validation.js.map +0 -1
- package/dist/reference-resolver.d.ts.map +0 -1
- package/dist/reference-resolver.js.map +0 -1
- package/dist/resolve-canopy-user.d.ts.map +0 -1
- package/dist/resolve-canopy-user.js.map +0 -1
- package/dist/resource-generation.d.ts.map +0 -1
- package/dist/resource-generation.js.map +0 -1
- package/dist/schema/index.d.ts.map +0 -1
- package/dist/schema/index.js.map +0 -1
- package/dist/schema/meta-loader.d.ts.map +0 -1
- package/dist/schema/meta-loader.js.map +0 -1
- package/dist/schema/resolver.d.ts.map +0 -1
- package/dist/schema/resolver.js.map +0 -1
- package/dist/schema/schema-store-types.d.ts.map +0 -1
- package/dist/schema/schema-store-types.js.map +0 -1
- package/dist/schema/schema-store.d.ts.map +0 -1
- package/dist/schema/schema-store.js.map +0 -1
- package/dist/schema/types.d.ts.map +0 -1
- package/dist/schema/types.js.map +0 -1
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/services.d.ts.map +0 -1
- package/dist/services.js.map +0 -1
- package/dist/settings-workspace.d.ts.map +0 -1
- package/dist/settings-workspace.js.map +0 -1
- package/dist/static/index.d.ts.map +0 -1
- package/dist/static/index.js.map +0 -1
- package/dist/sync-core.d.ts.map +0 -1
- package/dist/sync-core.js.map +0 -1
- package/dist/task-queue/index.d.ts.map +0 -1
- package/dist/task-queue/index.js.map +0 -1
- package/dist/task-queue/task-queue.d.ts.map +0 -1
- package/dist/task-queue/task-queue.js.map +0 -1
- package/dist/task-queue/types.d.ts.map +0 -1
- package/dist/task-queue/types.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/url-path-resolver.d.ts.map +0 -1
- package/dist/url-path-resolver.js.map +0 -1
- package/dist/user.d.ts.map +0 -1
- package/dist/user.js.map +0 -1
- package/dist/utils/async-mutex.d.ts.map +0 -1
- package/dist/utils/async-mutex.js.map +0 -1
- package/dist/utils/atomic-write.d.ts.map +0 -1
- package/dist/utils/atomic-write.js.map +0 -1
- package/dist/utils/body-field.d.ts.map +0 -1
- package/dist/utils/body-field.js.map +0 -1
- package/dist/utils/content-write-lock.d.ts.map +0 -1
- package/dist/utils/content-write-lock.js.map +0 -1
- package/dist/utils/debug.d.ts.map +0 -1
- package/dist/utils/debug.js.map +0 -1
- package/dist/utils/entry-url.d.ts.map +0 -1
- package/dist/utils/entry-url.js.map +0 -1
- package/dist/utils/error.d.ts.map +0 -1
- package/dist/utils/error.js.map +0 -1
- package/dist/utils/flatten-group-fields.d.ts.map +0 -1
- package/dist/utils/flatten-group-fields.js.map +0 -1
- package/dist/utils/format.d.ts.map +0 -1
- package/dist/utils/format.js.map +0 -1
- package/dist/utils/fs.d.ts.map +0 -1
- package/dist/utils/fs.js.map +0 -1
- package/dist/utils/git.d.ts.map +0 -1
- package/dist/utils/git.js.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/occ-json-write.d.ts.map +0 -1
- package/dist/utils/occ-json-write.js.map +0 -1
- package/dist/utils/provisioning-lock.d.ts.map +0 -1
- package/dist/utils/provisioning-lock.js.map +0 -1
- package/dist/utils/sanitize-href.d.ts.map +0 -1
- package/dist/utils/sanitize-href.js.map +0 -1
- package/dist/utils/title-field.d.ts.map +0 -1
- package/dist/utils/title-field.js.map +0 -1
- package/dist/validation/deletion-checker.d.ts.map +0 -1
- package/dist/validation/deletion-checker.js.map +0 -1
- package/dist/validation/entry-link-validator.d.ts.map +0 -1
- package/dist/validation/entry-link-validator.js.map +0 -1
- package/dist/validation/entry-type-reference-validator.d.ts.map +0 -1
- package/dist/validation/entry-type-reference-validator.js.map +0 -1
- package/dist/validation/entry-validator.d.ts.map +0 -1
- package/dist/validation/entry-validator.js.map +0 -1
- package/dist/validation/field-traversal.d.ts.map +0 -1
- package/dist/validation/field-traversal.js.map +0 -1
- package/dist/validation/reference-validator.d.ts.map +0 -1
- package/dist/validation/reference-validator.js.map +0 -1
- package/dist/worker/cms-worker.d.ts.map +0 -1
- package/dist/worker/cms-worker.js.map +0 -1
- package/dist/worker/log.d.ts.map +0 -1
- package/dist/worker/log.js.map +0 -1
- package/dist/worker/task-queue-config.d.ts.map +0 -1
- package/dist/worker/task-queue-config.js.map +0 -1
- package/dist/worker/task-queue.d.ts.map +0 -1
- package/dist/worker/task-queue.js.map +0 -1
- package/dist/worker/worker-status.d.ts.map +0 -1
- package/dist/worker/worker-status.js.map +0 -1
package/dist/cli/cli.js
CHANGED
|
@@ -1047,7 +1047,7 @@ CanopyCMS worker run-once (mode: ${mode}, auth: ${authMode})
|
|
|
1047
1047
|
}
|
|
1048
1048
|
console.log("\nDone");
|
|
1049
1049
|
}
|
|
1050
|
-
var __defProp2, __getOwnPropNames2, __esm2, __export2, active, init_logger, primitiveFieldTypes, fieldTypes, init_types, fieldBaseSchema, selectOptionSchema, referenceOptionSchema, primitiveFieldSchema, ASPECT_RATIO_RE, imageFieldSchema, selectFieldSchema, referenceFieldSchema, fieldHolder, blockSchema, blockFieldSchema, objectFieldSchema, inlineGroupFieldSchema, customFieldSchema, knownFieldSchema, fieldSchema, init_field, relativePathSchema, entryTypeSchema, collectionSchema, init_collection, mediaSchema, init_media, defaultBranchAccessSchema, defaultPathAccessLevelSchema, defaultPathAccessLevelsSchema, defaultPathAccessSchema, defaultBaseBranchSchema, defaultRemoteNameSchema, defaultRemoteUrlSchema, gitBotAuthorNameSchema, gitBotAuthorEmailSchema, githubTokenEnvVarSchema, operatingModeSchema, deployedAsSchema, contentRootSchema, sourceRootSchema, deploymentNameSchema, devContentSyncSchema, devConfigSchema, editorConfigSchema, CanopyConfigSchema, DEFAULT_PROD_WORKSPACE, init_config, permissionTargetSchema, pathPermissionSchema, init_permissions, init_normalize, init_types2, init_flatten, init_mode_env, init_validation, init_helpers, init_config2, init_error2, init_fs2, templates_exports, __dirname, TEMPLATES_DIR, SCAFFOLD_STACK_NAME, init_templates, project_detect_exports, COMMANDS, MAX_WORKSPACE_DEPTH, CDK_DEPENDENCIES, init_project_detect, task_queue_config_exports, init_task_queue_config, LOG_LEVELS, DebugLogger, testLogger, init_debug, init_atomic_write, DEFAULT_MAX_RETRIES, nullLogger, init_task_queue, init_task_queue2, task_queue_exports, debugLogger, cmsTaskQueueLogger, init_task_queue3, ProdClientSafeStrategy, DevClientSafeStrategy, warned, VALID_DEPLOYMENT_NAME, isValidDeploymentName, ProdStrategy, DevStrategy, strategyCache;
|
|
1050
|
+
var __defProp2, __getOwnPropNames2, __esm2, __export2, active, init_logger, primitiveFieldTypes, fieldTypes, init_types, fieldBaseSchema, selectOptionSchema, referenceOptionSchema, primitiveFieldSchema, ASPECT_RATIO_RE, imageFieldSchema, selectFieldSchema, referenceFieldSchema, fieldHolder, blockSchema, blockFieldSchema, objectFieldSchema, inlineGroupFieldSchema, customFieldSchema, knownFieldSchema, fieldSchema, init_field, relativePathSchema, entryTypeSchema, collectionSchema, init_collection, mediaSchema, init_media, defaultBranchAccessSchema, defaultPathAccessLevelSchema, defaultPathAccessLevelsSchema, defaultPathAccessSchema, defaultBaseBranchSchema, defaultRemoteNameSchema, defaultRemoteUrlSchema, gitBotAuthorNameSchema, gitBotAuthorEmailSchema, githubTokenEnvVarSchema, operatingModeSchema, deployedAsSchema, contentRootSchema, sourceRootSchema, basePathSchema, deploymentNameSchema, devContentSyncSchema, devConfigSchema, editorConfigSchema, CanopyConfigSchema, DEFAULT_PROD_WORKSPACE, init_config, permissionTargetSchema, pathPermissionSchema, init_permissions, init_normalize, init_types2, init_flatten, init_mode_env, init_validation, init_helpers, init_config2, init_error2, init_fs2, templates_exports, __dirname, TEMPLATES_DIR, SCAFFOLD_STACK_NAME, init_templates, project_detect_exports, COMMANDS, MAX_WORKSPACE_DEPTH, CDK_DEPENDENCIES, init_project_detect, task_queue_config_exports, init_task_queue_config, LOG_LEVELS, DebugLogger, testLogger, init_debug, init_atomic_write, DEFAULT_MAX_RETRIES, nullLogger, init_task_queue, init_task_queue2, task_queue_exports, debugLogger, cmsTaskQueueLogger, init_task_queue3, ProdClientSafeStrategy, DevClientSafeStrategy, warned, VALID_DEPLOYMENT_NAME, isValidDeploymentName, ProdStrategy, DevStrategy, strategyCache;
|
|
1051
1051
|
var init_init = __esm({
|
|
1052
1052
|
"dist/cli/init.js"() {
|
|
1053
1053
|
"use strict";
|
|
@@ -1134,7 +1134,12 @@ var init_init = __esm({
|
|
|
1134
1134
|
collections: z.array(z.string().min(1)).min(1).optional(),
|
|
1135
1135
|
entryTypes: z.array(z.string().min(1)).min(1).optional(),
|
|
1136
1136
|
displayField: z.string().min(1).optional(),
|
|
1137
|
-
options: z.array(referenceOptionSchema).optional()
|
|
1137
|
+
options: z.array(referenceOptionSchema).optional(),
|
|
1138
|
+
// Must be listed here, not just on ReferenceFieldConfig: zod strips unknown keys by
|
|
1139
|
+
// default, so a consumer that adopts this schema's parse output would silently delete a
|
|
1140
|
+
// runtime-consumed flag and the feature would no-op with no error. (`resolvedSchema` is
|
|
1141
|
+
// absent on purpose — it is type-inference-only and stripping it changes no behavior.)
|
|
1142
|
+
includeBody: z.boolean().optional()
|
|
1138
1143
|
});
|
|
1139
1144
|
fieldHolder = [z.never()];
|
|
1140
1145
|
blockSchema = z.object({
|
|
@@ -1255,6 +1260,9 @@ var init_init = __esm({
|
|
|
1255
1260
|
deployedAsSchema = z4.enum(["static", "server"]).default("server");
|
|
1256
1261
|
contentRootSchema = relativePathSchema.default("content");
|
|
1257
1262
|
sourceRootSchema = z4.string().min(1).optional();
|
|
1263
|
+
basePathSchema = z4.string().transform((value) => value.trim()).refine((value) => value.length > 0, {
|
|
1264
|
+
message: "basePath must not be empty or only whitespace"
|
|
1265
|
+
}).optional();
|
|
1258
1266
|
deploymentNameSchema = z4.string().default("prod");
|
|
1259
1267
|
devContentSyncSchema = z4.enum(["off", "warn"]).default("warn");
|
|
1260
1268
|
devConfigSchema = z4.object({
|
|
@@ -1317,6 +1325,7 @@ var init_init = __esm({
|
|
|
1317
1325
|
deploymentName: deploymentNameSchema.optional(),
|
|
1318
1326
|
contentRoot: contentRootSchema.default("content"),
|
|
1319
1327
|
sourceRoot: sourceRootSchema.optional(),
|
|
1328
|
+
basePath: basePathSchema,
|
|
1320
1329
|
editor: editorConfigSchema.optional(),
|
|
1321
1330
|
authPlugin: z4.custom().optional(),
|
|
1322
1331
|
entryLinkUrl: z4.custom().optional(),
|
|
@@ -1480,6 +1489,7 @@ var init_init = __esm({
|
|
|
1480
1489
|
};
|
|
1481
1490
|
MAX_WORKSPACE_DEPTH = 8;
|
|
1482
1491
|
CDK_DEPENDENCIES = [
|
|
1492
|
+
"canopycms",
|
|
1483
1493
|
"canopycms-cdk",
|
|
1484
1494
|
"aws-cdk-lib",
|
|
1485
1495
|
"constructs",
|
|
@@ -1844,63 +1854,73 @@ import { isAbsolute as isAbsolute2 } from "pathe";
|
|
|
1844
1854
|
import { z as z42 } from "zod";
|
|
1845
1855
|
import { z as z52 } from "zod";
|
|
1846
1856
|
import { z as z6 } from "zod";
|
|
1847
|
-
import
|
|
1848
|
-
import
|
|
1857
|
+
import path9 from "node:path";
|
|
1858
|
+
import path20 from "node:path";
|
|
1849
1859
|
import { createJiti as createJiti2 } from "jiti";
|
|
1850
|
-
import
|
|
1851
|
-
import
|
|
1852
|
-
import
|
|
1860
|
+
import fs17 from "node:fs/promises";
|
|
1861
|
+
import path19 from "node:path";
|
|
1862
|
+
import fs10 from "node:fs/promises";
|
|
1863
|
+
import path11 from "node:path";
|
|
1864
|
+
import matter2 from "gray-matter";
|
|
1865
|
+
import { parse as yamlParse } from "yaml";
|
|
1866
|
+
import fs7 from "node:fs/promises";
|
|
1853
1867
|
import path10 from "node:path";
|
|
1854
1868
|
import matter from "gray-matter";
|
|
1855
|
-
import {
|
|
1856
|
-
import fs7 from "node:fs/promises";
|
|
1857
|
-
import path9 from "node:path";
|
|
1869
|
+
import { isCollection, isMap, isNode, isScalar, isSeq, parseDocument, stringify as yamlStringify } from "yaml";
|
|
1858
1870
|
import path32 from "node:path";
|
|
1859
1871
|
import fs23 from "node:fs/promises";
|
|
1860
1872
|
import path22 from "node:path";
|
|
1861
1873
|
import lockfile from "proper-lockfile";
|
|
1874
|
+
import fs42 from "node:fs/promises";
|
|
1875
|
+
import path52 from "node:path";
|
|
1862
1876
|
import fs32 from "node:fs/promises";
|
|
1863
1877
|
import path42 from "node:path";
|
|
1864
1878
|
import { generate } from "short-uuid";
|
|
1865
|
-
import path52 from "node:path";
|
|
1866
|
-
import fs42 from "node:fs/promises";
|
|
1867
1879
|
import path62 from "node:path";
|
|
1868
|
-
import
|
|
1869
|
-
import fs62 from "node:fs/promises";
|
|
1880
|
+
import fs52 from "node:fs/promises";
|
|
1870
1881
|
import path72 from "node:path";
|
|
1871
|
-
import {
|
|
1882
|
+
import { randomUUID } from "node:crypto";
|
|
1883
|
+
import fs72 from "node:fs/promises";
|
|
1884
|
+
import path82 from "node:path";
|
|
1885
|
+
import { promises as fs62 } from "fs";
|
|
1872
1886
|
import { join as join3 } from "pathe";
|
|
1873
1887
|
import { z as z7 } from "zod";
|
|
1874
1888
|
import chokidar from "chokidar";
|
|
1875
|
-
import fs72 from "node:fs/promises";
|
|
1876
|
-
import { sep, resolve, relative } from "node:path";
|
|
1877
1889
|
import fs8 from "node:fs/promises";
|
|
1878
|
-
import
|
|
1879
|
-
import
|
|
1880
|
-
import
|
|
1881
|
-
import { minimatch } from "minimatch";
|
|
1882
|
-
import path16 from "node:path";
|
|
1883
|
-
import fs13 from "node:fs/promises";
|
|
1884
|
-
import path14 from "node:path";
|
|
1885
|
-
import fs11 from "node:fs/promises";
|
|
1890
|
+
import { sep, resolve, relative } from "node:path";
|
|
1891
|
+
import fs9 from "node:fs/promises";
|
|
1892
|
+
import path102 from "node:path";
|
|
1886
1893
|
import path12 from "node:path";
|
|
1894
|
+
import fs11 from "node:fs/promises";
|
|
1895
|
+
import { minimatch } from "minimatch";
|
|
1896
|
+
import path17 from "node:path";
|
|
1897
|
+
import fs14 from "node:fs/promises";
|
|
1898
|
+
import path15 from "node:path";
|
|
1887
1899
|
import fs12 from "node:fs/promises";
|
|
1888
1900
|
import path13 from "node:path";
|
|
1901
|
+
import fs13 from "node:fs/promises";
|
|
1902
|
+
import path14 from "node:path";
|
|
1889
1903
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
1890
1904
|
import lockfile2 from "proper-lockfile";
|
|
1891
|
-
import
|
|
1892
|
-
import
|
|
1905
|
+
import fs15 from "node:fs/promises";
|
|
1906
|
+
import path16 from "node:path";
|
|
1893
1907
|
import { simpleGit as simpleGit2 } from "simple-git";
|
|
1894
1908
|
import { simpleGit as simpleGit3 } from "simple-git";
|
|
1895
|
-
import
|
|
1896
|
-
import
|
|
1897
|
-
import
|
|
1909
|
+
import fs16 from "node:fs/promises";
|
|
1910
|
+
import path18 from "node:path";
|
|
1911
|
+
import matter3 from "gray-matter";
|
|
1898
1912
|
import { parse as yamlParse2 } from "yaml";
|
|
1899
|
-
function
|
|
1900
|
-
|
|
1913
|
+
function canopyLogWarn2(...args) {
|
|
1914
|
+
active2.warn(...args);
|
|
1915
|
+
}
|
|
1916
|
+
function canopyLogError(...args) {
|
|
1917
|
+
active2.error(...args);
|
|
1918
|
+
}
|
|
1919
|
+
function normalizeFilesystemPath(path212) {
|
|
1920
|
+
return path212.split(/[\\/]+/).filter(Boolean).join("/");
|
|
1901
1921
|
}
|
|
1902
|
-
function hasTraversalSequence(
|
|
1903
|
-
const normalized = normalizeFilesystemPath(
|
|
1922
|
+
function hasTraversalSequence(path212) {
|
|
1923
|
+
const normalized = normalizeFilesystemPath(path212);
|
|
1904
1924
|
return normalized.includes("..");
|
|
1905
1925
|
}
|
|
1906
1926
|
function createLogicalPath(...segments) {
|
|
@@ -1910,20 +1930,14 @@ function createLogicalPath(...segments) {
|
|
|
1910
1930
|
}
|
|
1911
1931
|
return normalized;
|
|
1912
1932
|
}
|
|
1913
|
-
function trimSlashes(
|
|
1933
|
+
function trimSlashes(path212) {
|
|
1914
1934
|
let start = 0;
|
|
1915
|
-
let end =
|
|
1916
|
-
while (start < end &&
|
|
1935
|
+
let end = path212.length;
|
|
1936
|
+
while (start < end && path212[start] === "/")
|
|
1917
1937
|
start++;
|
|
1918
|
-
while (end > start &&
|
|
1938
|
+
while (end > start && path212[end - 1] === "/")
|
|
1919
1939
|
end--;
|
|
1920
|
-
return
|
|
1921
|
-
}
|
|
1922
|
-
function canopyLogWarn2(...args) {
|
|
1923
|
-
active2.warn(...args);
|
|
1924
|
-
}
|
|
1925
|
-
function canopyLogError(...args) {
|
|
1926
|
-
active2.error(...args);
|
|
1940
|
+
return path212.slice(start, end);
|
|
1927
1941
|
}
|
|
1928
1942
|
function readModeEnv() {
|
|
1929
1943
|
if (typeof process === "undefined" || typeof process.env === "undefined")
|
|
@@ -2007,8 +2021,26 @@ function operatingStrategy2(mode) {
|
|
|
2007
2021
|
function clearStrategyCache() {
|
|
2008
2022
|
strategyCache2.clear();
|
|
2009
2023
|
}
|
|
2024
|
+
function getErrorMessage3(err) {
|
|
2025
|
+
if (err instanceof Error) {
|
|
2026
|
+
return err.message;
|
|
2027
|
+
}
|
|
2028
|
+
if (typeof err === "string") {
|
|
2029
|
+
return err;
|
|
2030
|
+
}
|
|
2031
|
+
return String(err);
|
|
2032
|
+
}
|
|
2033
|
+
function isNodeError3(err) {
|
|
2034
|
+
return err instanceof Error && "code" in err;
|
|
2035
|
+
}
|
|
2036
|
+
function isNotFoundError3(err) {
|
|
2037
|
+
return isNodeError3(err) && err.code === "ENOENT";
|
|
2038
|
+
}
|
|
2039
|
+
function isFileExistsError2(err) {
|
|
2040
|
+
return isNodeError3(err) && err.code === "EEXIST";
|
|
2041
|
+
}
|
|
2010
2042
|
async function atomicWriteFile2(filePath, content) {
|
|
2011
|
-
const dir =
|
|
2043
|
+
const dir = path10.dirname(filePath);
|
|
2012
2044
|
await fs7.mkdir(dir, { recursive: true });
|
|
2013
2045
|
const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
2014
2046
|
await fs7.writeFile(tempPath, content, typeof content === "string" ? "utf-8" : void 0);
|
|
@@ -2020,6 +2052,196 @@ async function atomicWriteFile2(filePath, content) {
|
|
|
2020
2052
|
throw err;
|
|
2021
2053
|
}
|
|
2022
2054
|
}
|
|
2055
|
+
function isBlockStructuralKey(key) {
|
|
2056
|
+
return BLOCK_STRUCTURAL_KEYS.has(key);
|
|
2057
|
+
}
|
|
2058
|
+
function isPlainRecord(value) {
|
|
2059
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
2060
|
+
return false;
|
|
2061
|
+
const proto = Object.getPrototypeOf(value);
|
|
2062
|
+
return proto === Object.prototype || proto === null;
|
|
2063
|
+
}
|
|
2064
|
+
function recordKeyOf(keyNode) {
|
|
2065
|
+
if (!isScalar(keyNode))
|
|
2066
|
+
return void 0;
|
|
2067
|
+
const { value } = keyNode;
|
|
2068
|
+
if (value === null || value === void 0)
|
|
2069
|
+
return void 0;
|
|
2070
|
+
if (typeof value === "object")
|
|
2071
|
+
return void 0;
|
|
2072
|
+
return String(value);
|
|
2073
|
+
}
|
|
2074
|
+
function carryComments(from, to) {
|
|
2075
|
+
if (!isNode(from) || !isNode(to))
|
|
2076
|
+
return;
|
|
2077
|
+
const source = from;
|
|
2078
|
+
const target = to;
|
|
2079
|
+
if (source.commentBefore !== void 0)
|
|
2080
|
+
target.commentBefore = source.commentBefore;
|
|
2081
|
+
if (source.comment !== void 0)
|
|
2082
|
+
target.comment = source.comment;
|
|
2083
|
+
if (source.spaceBefore !== void 0)
|
|
2084
|
+
target.spaceBefore = source.spaceBefore;
|
|
2085
|
+
}
|
|
2086
|
+
function identityKey(value) {
|
|
2087
|
+
try {
|
|
2088
|
+
return JSON.stringify(value) ?? "undefined";
|
|
2089
|
+
} catch {
|
|
2090
|
+
return void 0;
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
function nodePlainValue(node) {
|
|
2094
|
+
if (!isNode(node))
|
|
2095
|
+
return node;
|
|
2096
|
+
try {
|
|
2097
|
+
return node.toJSON();
|
|
2098
|
+
} catch {
|
|
2099
|
+
return void 0;
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
function nodeIdentityKey(node) {
|
|
2103
|
+
const plain = nodePlainValue(node);
|
|
2104
|
+
return plain === void 0 && isNode(node) ? void 0 : identityKey(plain);
|
|
2105
|
+
}
|
|
2106
|
+
function sharesFieldEvidence(existing, value, depth) {
|
|
2107
|
+
for (const key of Object.keys(value)) {
|
|
2108
|
+
if (isBlockStructuralKey(key))
|
|
2109
|
+
continue;
|
|
2110
|
+
if (!Object.prototype.hasOwnProperty.call(existing, key))
|
|
2111
|
+
continue;
|
|
2112
|
+
const before = existing[key];
|
|
2113
|
+
const after = value[key];
|
|
2114
|
+
if (depth < EVIDENCE_MAX_DEPTH && isPlainRecord(before) && isPlainRecord(after) && sharesFieldEvidence(before, after, depth + 1)) {
|
|
2115
|
+
return true;
|
|
2116
|
+
}
|
|
2117
|
+
const beforeKey = identityKey(before);
|
|
2118
|
+
if (beforeKey !== void 0 && beforeKey === identityKey(after))
|
|
2119
|
+
return true;
|
|
2120
|
+
}
|
|
2121
|
+
return false;
|
|
2122
|
+
}
|
|
2123
|
+
function looksLikeSameItem(node, value) {
|
|
2124
|
+
const existing = nodePlainValue(node);
|
|
2125
|
+
if (!isPlainRecord(existing) || !isPlainRecord(value))
|
|
2126
|
+
return true;
|
|
2127
|
+
return sharesFieldEvidence(existing, value, 0);
|
|
2128
|
+
}
|
|
2129
|
+
function reconcileNode(doc, existing, value) {
|
|
2130
|
+
if (isMap(existing) && isPlainRecord(value)) {
|
|
2131
|
+
reconcileMap(doc, existing, value);
|
|
2132
|
+
return existing;
|
|
2133
|
+
}
|
|
2134
|
+
if (isSeq(existing) && Array.isArray(value)) {
|
|
2135
|
+
reconcileSeq(doc, existing, value);
|
|
2136
|
+
return existing;
|
|
2137
|
+
}
|
|
2138
|
+
if (isScalar(existing) && Object.is(existing.value, value))
|
|
2139
|
+
return existing;
|
|
2140
|
+
const fresh = doc.createNode(value);
|
|
2141
|
+
if (!isCollection(existing))
|
|
2142
|
+
carryComments(existing, fresh);
|
|
2143
|
+
return fresh;
|
|
2144
|
+
}
|
|
2145
|
+
function reconcileMap(doc, map, value) {
|
|
2146
|
+
const wanted = new Set(Object.keys(value).filter((key) => value[key] !== void 0));
|
|
2147
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2148
|
+
const retained = [];
|
|
2149
|
+
for (const pair of map.items) {
|
|
2150
|
+
const key = recordKeyOf(pair.key);
|
|
2151
|
+
if (key === void 0 || !wanted.has(key) || seen.has(key))
|
|
2152
|
+
continue;
|
|
2153
|
+
seen.add(key);
|
|
2154
|
+
pair.value = reconcileNode(doc, pair.value, value[key]);
|
|
2155
|
+
retained.push(pair);
|
|
2156
|
+
}
|
|
2157
|
+
map.items = retained;
|
|
2158
|
+
for (const key of Object.keys(value)) {
|
|
2159
|
+
if (seen.has(key) || !wanted.has(key))
|
|
2160
|
+
continue;
|
|
2161
|
+
map.set(doc.createNode(key), doc.createNode(value[key]));
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
function reconcileSeq(doc, seq, value) {
|
|
2165
|
+
const oldItems = seq.items;
|
|
2166
|
+
const byIdentity = /* @__PURE__ */ new Map();
|
|
2167
|
+
oldItems.forEach((node, index) => {
|
|
2168
|
+
const key = nodeIdentityKey(node);
|
|
2169
|
+
if (key === void 0)
|
|
2170
|
+
return;
|
|
2171
|
+
const bucket = byIdentity.get(key);
|
|
2172
|
+
if (bucket)
|
|
2173
|
+
bucket.push(index);
|
|
2174
|
+
else
|
|
2175
|
+
byIdentity.set(key, [index]);
|
|
2176
|
+
});
|
|
2177
|
+
const consumed = /* @__PURE__ */ new Set();
|
|
2178
|
+
const matches = value.map((item) => {
|
|
2179
|
+
const key = identityKey(item);
|
|
2180
|
+
if (key === void 0)
|
|
2181
|
+
return void 0;
|
|
2182
|
+
const bucket = byIdentity.get(key);
|
|
2183
|
+
while (bucket && bucket.length > 0) {
|
|
2184
|
+
const index = bucket.shift();
|
|
2185
|
+
if (index !== void 0 && !consumed.has(index)) {
|
|
2186
|
+
consumed.add(index);
|
|
2187
|
+
return index;
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
return void 0;
|
|
2191
|
+
});
|
|
2192
|
+
seq.items = value.map((item, index) => {
|
|
2193
|
+
const matched = matches[index];
|
|
2194
|
+
if (matched !== void 0)
|
|
2195
|
+
return oldItems[matched];
|
|
2196
|
+
const candidate = index < oldItems.length && !consumed.has(index) ? oldItems[index] : void 0;
|
|
2197
|
+
const sameItem = candidate !== void 0 && looksLikeSameItem(candidate, item) ? candidate : void 0;
|
|
2198
|
+
return reconcileNode(doc, sameItem, item);
|
|
2199
|
+
});
|
|
2200
|
+
}
|
|
2201
|
+
function applyDataToDocument(doc, data) {
|
|
2202
|
+
doc.contents = reconcileNode(doc, doc.contents, data);
|
|
2203
|
+
}
|
|
2204
|
+
function serializeYaml(data, existingRaw) {
|
|
2205
|
+
if (existingRaw === void 0)
|
|
2206
|
+
return yamlStringify(data);
|
|
2207
|
+
const doc = parseDocument(existingRaw);
|
|
2208
|
+
if (doc.errors.length > 0)
|
|
2209
|
+
return yamlStringify(data);
|
|
2210
|
+
applyDataToDocument(doc, data);
|
|
2211
|
+
return doc.toString();
|
|
2212
|
+
}
|
|
2213
|
+
function extractRawFrontmatter(raw) {
|
|
2214
|
+
let parsed;
|
|
2215
|
+
try {
|
|
2216
|
+
parsed = matter(raw, {});
|
|
2217
|
+
} catch {
|
|
2218
|
+
return void 0;
|
|
2219
|
+
}
|
|
2220
|
+
const frontmatter = parsed.matter;
|
|
2221
|
+
if (typeof frontmatter !== "string" || frontmatter.trim() === "")
|
|
2222
|
+
return void 0;
|
|
2223
|
+
return frontmatter;
|
|
2224
|
+
}
|
|
2225
|
+
function serializeFrontmatter(body, data, existingRaw) {
|
|
2226
|
+
if (existingRaw === void 0)
|
|
2227
|
+
return matter.stringify(body, data);
|
|
2228
|
+
const existingFrontmatter = extractRawFrontmatter(existingRaw);
|
|
2229
|
+
if (existingFrontmatter === void 0)
|
|
2230
|
+
return matter.stringify(body, data);
|
|
2231
|
+
const doc = parseDocument(existingFrontmatter);
|
|
2232
|
+
if (doc.errors.length > 0)
|
|
2233
|
+
return matter.stringify(body, data);
|
|
2234
|
+
applyDataToDocument(doc, data);
|
|
2235
|
+
const reconciled = doc.toString();
|
|
2236
|
+
return matter.stringify(body, data, {
|
|
2237
|
+
engines: {
|
|
2238
|
+
yaml: {
|
|
2239
|
+
parse: () => ({}),
|
|
2240
|
+
stringify: () => reconciled
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
});
|
|
2244
|
+
}
|
|
2023
2245
|
async function withLock(key, fn) {
|
|
2024
2246
|
const prev = locks.get(key) ?? Promise.resolve();
|
|
2025
2247
|
let resolve2;
|
|
@@ -2036,51 +2258,71 @@ async function withLock(key, fn) {
|
|
|
2036
2258
|
locks.delete(key);
|
|
2037
2259
|
}
|
|
2038
2260
|
}
|
|
2039
|
-
function
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2261
|
+
function provisioningLockOptions(lockPath, retries, onCompromised) {
|
|
2262
|
+
return {
|
|
2263
|
+
lockfilePath: lockPath,
|
|
2264
|
+
realpath: false,
|
|
2265
|
+
retries,
|
|
2266
|
+
stale: 3e4,
|
|
2267
|
+
// proper-lockfile invokes this from inside its refresh timer, so ANY throw
|
|
2268
|
+
// escaping here is an uncaught exception that kills the process -- the very
|
|
2269
|
+
// failure the handler exists to prevent. Call sites are told not to throw
|
|
2270
|
+
// (see OnLockCompromised); this makes it structural rather than a
|
|
2271
|
+
// convention, and also covers the LOGGER throwing: under `CI=true`,
|
|
2272
|
+
// vitest's `onConsoleLog` turns any console write into a throw.
|
|
2273
|
+
onCompromised: (err) => {
|
|
2274
|
+
try {
|
|
2275
|
+
if (onCompromised) {
|
|
2276
|
+
onCompromised(err);
|
|
2277
|
+
return;
|
|
2278
|
+
}
|
|
2279
|
+
canopyLogWarn2(`[canopy] Provisioning lock compromised mid-hold for ${lockPath}:`, getErrorMessage3(err));
|
|
2280
|
+
} catch {
|
|
2281
|
+
try {
|
|
2282
|
+
process.stderr.write(`[canopy] lock compromised for ${lockPath}; its handler or logger threw
|
|
2283
|
+
`);
|
|
2284
|
+
} catch {
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
};
|
|
2053
2289
|
}
|
|
2054
|
-
function
|
|
2055
|
-
return
|
|
2290
|
+
function releaseIgnoringAlreadyReleased(release, lockPath) {
|
|
2291
|
+
return async () => {
|
|
2292
|
+
try {
|
|
2293
|
+
await release();
|
|
2294
|
+
} catch (err) {
|
|
2295
|
+
if (isNodeError3(err) && err.code === "ERELEASED") {
|
|
2296
|
+
canopyLogWarn2(`[canopy] Lock at ${lockPath} was already released (compromised mid-hold, or released twice); nothing to release`);
|
|
2297
|
+
return;
|
|
2298
|
+
}
|
|
2299
|
+
throw err;
|
|
2300
|
+
}
|
|
2301
|
+
};
|
|
2056
2302
|
}
|
|
2057
|
-
async function acquireProvisioningLock(lockTargetDir2, lockName) {
|
|
2303
|
+
async function acquireProvisioningLock(lockTargetDir2, lockName, onCompromised) {
|
|
2058
2304
|
await fs23.mkdir(lockTargetDir2, { recursive: true });
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
stale: 3e4
|
|
2063
|
-
});
|
|
2305
|
+
const lockPath = path22.join(lockTargetDir2, lockName);
|
|
2306
|
+
const release = await lockfile.lock(lockPath, provisioningLockOptions(lockPath, { retries: 600, factor: 1, minTimeout: 300, maxTimeout: 800, randomize: true }, onCompromised));
|
|
2307
|
+
return releaseIgnoringAlreadyReleased(release, lockPath);
|
|
2064
2308
|
}
|
|
2065
|
-
async function tryAcquireProvisioningLock(lockTargetDir2, lockName) {
|
|
2309
|
+
async function tryAcquireProvisioningLock(lockTargetDir2, lockName, onCompromised) {
|
|
2066
2310
|
await fs23.mkdir(lockTargetDir2, { recursive: true });
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
stale: 3e4
|
|
2071
|
-
});
|
|
2311
|
+
const lockPath = path22.join(lockTargetDir2, lockName);
|
|
2312
|
+
const release = await lockfile.lock(lockPath, provisioningLockOptions(lockPath, 0, onCompromised));
|
|
2313
|
+
return releaseIgnoringAlreadyReleased(release, lockPath);
|
|
2072
2314
|
}
|
|
2073
2315
|
function lockTargetDir(branchRoot) {
|
|
2074
2316
|
return path32.join(path32.resolve(branchRoot), META_DIR);
|
|
2075
2317
|
}
|
|
2076
|
-
function tryAcquireContentWriteLock(branchRoot) {
|
|
2077
|
-
return tryAcquireProvisioningLock(lockTargetDir(branchRoot), CONTENT_WRITE_LOCK_NAME);
|
|
2318
|
+
function tryAcquireContentWriteLock(branchRoot, onCompromised) {
|
|
2319
|
+
return tryAcquireProvisioningLock(lockTargetDir(branchRoot), CONTENT_WRITE_LOCK_NAME, onCompromised);
|
|
2078
2320
|
}
|
|
2079
|
-
async function acquireContentWriteLock(branchRoot, waitMs = DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS) {
|
|
2321
|
+
async function acquireContentWriteLock(branchRoot, waitMs = DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS, onCompromised) {
|
|
2080
2322
|
const startedAt = Date.now();
|
|
2081
2323
|
for (let attempt = 0; ; attempt++) {
|
|
2082
2324
|
try {
|
|
2083
|
-
return await tryAcquireContentWriteLock(branchRoot);
|
|
2325
|
+
return await tryAcquireContentWriteLock(branchRoot, onCompromised);
|
|
2084
2326
|
} catch (err) {
|
|
2085
2327
|
if (!isNodeError3(err) || err.code !== "ELOCKED")
|
|
2086
2328
|
throw err;
|
|
@@ -2093,12 +2335,21 @@ async function acquireContentWriteLock(branchRoot, waitMs = DEFAULT_CONTENT_WRIT
|
|
|
2093
2335
|
}
|
|
2094
2336
|
}
|
|
2095
2337
|
async function withContentWriteLock(branchRoot, fn, waitMs = DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS) {
|
|
2096
|
-
|
|
2338
|
+
let compromised = false;
|
|
2339
|
+
const release = await acquireContentWriteLock(branchRoot, waitMs, (err) => {
|
|
2340
|
+
compromised = true;
|
|
2341
|
+
canopyLogWarn2(`[canopy] Content-write lock compromised mid-hold for ${branchRoot}:`, getErrorMessage3(err));
|
|
2342
|
+
});
|
|
2343
|
+
let result;
|
|
2097
2344
|
try {
|
|
2098
|
-
|
|
2345
|
+
result = await fn();
|
|
2099
2346
|
} finally {
|
|
2100
2347
|
await release();
|
|
2101
2348
|
}
|
|
2349
|
+
if (compromised) {
|
|
2350
|
+
throw new ContentWriteLockBusyError("This branch was being synced while your change was written, so the change may or may not have been recorded. Reload the entry to see the current state before saving again.");
|
|
2351
|
+
}
|
|
2352
|
+
return result;
|
|
2102
2353
|
}
|
|
2103
2354
|
function flattenGroupFields(fields) {
|
|
2104
2355
|
const result = [];
|
|
@@ -2118,9 +2369,68 @@ function findBodyFieldName(fields) {
|
|
|
2118
2369
|
}
|
|
2119
2370
|
return "body";
|
|
2120
2371
|
}
|
|
2372
|
+
function buildResolvedReference(data, meta, body) {
|
|
2373
|
+
const resolved = { ...data };
|
|
2374
|
+
if (body && body.value)
|
|
2375
|
+
resolved[body.fieldName] = body.value;
|
|
2376
|
+
resolved.id = meta.id;
|
|
2377
|
+
resolved.slug = meta.slug;
|
|
2378
|
+
resolved.collection = meta.collection;
|
|
2379
|
+
resolved.urlPath = meta.urlPath;
|
|
2380
|
+
return resolved;
|
|
2381
|
+
}
|
|
2382
|
+
function isIndexSlug(slug) {
|
|
2383
|
+
return slug?.toLowerCase() === "index";
|
|
2384
|
+
}
|
|
2385
|
+
function computeEntryUrl(collection, slug, contentRoot) {
|
|
2386
|
+
const root = trimSlashes(contentRoot);
|
|
2387
|
+
let stripped = collection;
|
|
2388
|
+
if (root && collection.startsWith(`${root}/`)) {
|
|
2389
|
+
stripped = collection.slice(root.length + 1);
|
|
2390
|
+
} else if (collection === root) {
|
|
2391
|
+
stripped = "";
|
|
2392
|
+
}
|
|
2393
|
+
const segments = stripped.split("/").filter(Boolean);
|
|
2394
|
+
if (slug && !isIndexSlug(slug)) {
|
|
2395
|
+
segments.push(slug);
|
|
2396
|
+
}
|
|
2397
|
+
const path212 = segments.length > 0 ? `/${segments.join("/")}` : "/";
|
|
2398
|
+
return path212.toLowerCase();
|
|
2399
|
+
}
|
|
2121
2400
|
function isValidContentId(id) {
|
|
2122
2401
|
return CONTENT_ID_PATTERN.test(id);
|
|
2123
2402
|
}
|
|
2403
|
+
function parseSlug(slug) {
|
|
2404
|
+
if (!slug) {
|
|
2405
|
+
return {
|
|
2406
|
+
ok: false,
|
|
2407
|
+
error: "Slug is required"
|
|
2408
|
+
};
|
|
2409
|
+
}
|
|
2410
|
+
if (slug.length > 64) {
|
|
2411
|
+
return { ok: false, error: "Slug too long (max 64 characters)" };
|
|
2412
|
+
}
|
|
2413
|
+
if (slug.includes("/") || slug.includes("\\")) {
|
|
2414
|
+
return {
|
|
2415
|
+
ok: false,
|
|
2416
|
+
error: "Slug cannot contain path separators"
|
|
2417
|
+
};
|
|
2418
|
+
}
|
|
2419
|
+
if (slug === "." || slug === "..") {
|
|
2420
|
+
return {
|
|
2421
|
+
ok: false,
|
|
2422
|
+
error: "Slug cannot be a traversal sequence"
|
|
2423
|
+
};
|
|
2424
|
+
}
|
|
2425
|
+
const normalized = slug.toLowerCase();
|
|
2426
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(normalized)) {
|
|
2427
|
+
return {
|
|
2428
|
+
ok: false,
|
|
2429
|
+
error: "Slug must start with a letter or number and contain only lowercase letters, numbers, and hyphens"
|
|
2430
|
+
};
|
|
2431
|
+
}
|
|
2432
|
+
return { ok: true, slug: normalized };
|
|
2433
|
+
}
|
|
2124
2434
|
function generateId() {
|
|
2125
2435
|
const full = generate();
|
|
2126
2436
|
return full.substring(0, 12);
|
|
@@ -2148,13 +2458,13 @@ function extractIdFromFilename(filename) {
|
|
|
2148
2458
|
return null;
|
|
2149
2459
|
}
|
|
2150
2460
|
async function resolveCollectionPath(root, logicalPath) {
|
|
2151
|
-
const
|
|
2152
|
-
const
|
|
2461
|
+
const fs182 = await import("node:fs/promises");
|
|
2462
|
+
const path212 = await import("node:path");
|
|
2153
2463
|
const segments = logicalPath.split("/").filter(Boolean);
|
|
2154
2464
|
let currentPath = root;
|
|
2155
2465
|
for (const segment of segments) {
|
|
2156
2466
|
try {
|
|
2157
|
-
const entries = await
|
|
2467
|
+
const entries = await fs182.readdir(currentPath, { withFileTypes: true });
|
|
2158
2468
|
const matchingDir = entries.find((entry) => {
|
|
2159
2469
|
if (!entry.isDirectory())
|
|
2160
2470
|
return false;
|
|
@@ -2162,7 +2472,7 @@ async function resolveCollectionPath(root, logicalPath) {
|
|
|
2162
2472
|
return logicalName === segment.toLowerCase();
|
|
2163
2473
|
});
|
|
2164
2474
|
if (matchingDir) {
|
|
2165
|
-
currentPath =
|
|
2475
|
+
currentPath = path212.join(currentPath, matchingDir.name);
|
|
2166
2476
|
} else {
|
|
2167
2477
|
return null;
|
|
2168
2478
|
}
|
|
@@ -2211,8 +2521,70 @@ function extractSlugFromFilename(filename, entryTypeName) {
|
|
|
2211
2521
|
}
|
|
2212
2522
|
return filename.toLowerCase();
|
|
2213
2523
|
}
|
|
2524
|
+
async function readDirSafe(dir) {
|
|
2525
|
+
try {
|
|
2526
|
+
return await fs42.readdir(dir, { withFileTypes: true });
|
|
2527
|
+
} catch (err) {
|
|
2528
|
+
if (isNotFoundError3(err))
|
|
2529
|
+
return [];
|
|
2530
|
+
throw err;
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
async function findChildCollectionDir(dir, name) {
|
|
2534
|
+
const wanted = name.toLowerCase();
|
|
2535
|
+
for (const entry of await readDirSafe(dir)) {
|
|
2536
|
+
if (!entry.isDirectory())
|
|
2537
|
+
continue;
|
|
2538
|
+
if (extractSlugFromFilename(entry.name) === wanted)
|
|
2539
|
+
return path52.join(dir, entry.name);
|
|
2540
|
+
}
|
|
2541
|
+
return null;
|
|
2542
|
+
}
|
|
2543
|
+
function entrySlugOf(filename) {
|
|
2544
|
+
if (!CONTENT_EXTENSIONS.some((ext) => filename.endsWith(ext)))
|
|
2545
|
+
return null;
|
|
2546
|
+
return parseTypedFilename(filename)?.slug ?? null;
|
|
2547
|
+
}
|
|
2548
|
+
async function findIndexEntryIn(dir) {
|
|
2549
|
+
for (const entry of await readDirSafe(dir)) {
|
|
2550
|
+
if (entry.isDirectory())
|
|
2551
|
+
continue;
|
|
2552
|
+
if (isIndexSlug(entrySlugOf(entry.name) ?? void 0))
|
|
2553
|
+
return path52.join(dir, entry.name);
|
|
2554
|
+
}
|
|
2555
|
+
return null;
|
|
2556
|
+
}
|
|
2557
|
+
async function findEntryBySlugIn(dir, slug) {
|
|
2558
|
+
const wanted = slug.toLowerCase();
|
|
2559
|
+
for (const entry of await readDirSafe(dir)) {
|
|
2560
|
+
if (entry.isDirectory())
|
|
2561
|
+
continue;
|
|
2562
|
+
if (entrySlugOf(entry.name) === wanted)
|
|
2563
|
+
return path52.join(dir, entry.name);
|
|
2564
|
+
}
|
|
2565
|
+
return null;
|
|
2566
|
+
}
|
|
2567
|
+
async function findUrlPathClaimant(opts) {
|
|
2568
|
+
const { collectionDir, slug, contentRoot } = opts;
|
|
2569
|
+
if (isIndexSlug(slug)) {
|
|
2570
|
+
const resolvedRoot = path52.resolve(contentRoot);
|
|
2571
|
+
if (path52.resolve(collectionDir) === resolvedRoot)
|
|
2572
|
+
return null;
|
|
2573
|
+
const parentDir = path52.dirname(collectionDir);
|
|
2574
|
+
const ownName = extractSlugFromFilename(path52.basename(collectionDir));
|
|
2575
|
+
if (isIndexSlug(ownName))
|
|
2576
|
+
return null;
|
|
2577
|
+
const claimant = await findEntryBySlugIn(parentDir, ownName);
|
|
2578
|
+
return claimant ? { kind: "parent-entry", physicalPath: claimant, name: ownName } : null;
|
|
2579
|
+
}
|
|
2580
|
+
const childDir = await findChildCollectionDir(collectionDir, slug);
|
|
2581
|
+
if (!childDir)
|
|
2582
|
+
return null;
|
|
2583
|
+
const indexEntry = await findIndexEntryIn(childDir);
|
|
2584
|
+
return indexEntry ? { kind: "sibling-collection-index", physicalPath: indexEntry, name: slug } : null;
|
|
2585
|
+
}
|
|
2214
2586
|
function registerContentIndexForInvalidation(root, target) {
|
|
2215
|
-
const rootKey =
|
|
2587
|
+
const rootKey = path62.resolve(root);
|
|
2216
2588
|
let refs = registry.get(rootKey);
|
|
2217
2589
|
if (!refs) {
|
|
2218
2590
|
refs = /* @__PURE__ */ new Set();
|
|
@@ -2223,8 +2595,8 @@ function registerContentIndexForInvalidation(root, target) {
|
|
|
2223
2595
|
finalization.register(target, { rootKey, ref });
|
|
2224
2596
|
}
|
|
2225
2597
|
function invalidateContentIndexesForRoot(root) {
|
|
2226
|
-
const rootKey =
|
|
2227
|
-
const prefix = rootKey +
|
|
2598
|
+
const rootKey = path62.resolve(root);
|
|
2599
|
+
const prefix = rootKey + path62.sep;
|
|
2228
2600
|
for (const [storeRoot, refs] of registry) {
|
|
2229
2601
|
if (storeRoot !== rootKey && !storeRoot.startsWith(prefix))
|
|
2230
2602
|
continue;
|
|
@@ -2244,7 +2616,7 @@ function createDebugLogger2(options) {
|
|
|
2244
2616
|
return new DebugLogger2(options);
|
|
2245
2617
|
}
|
|
2246
2618
|
function resourceGenerationPath(root, resource) {
|
|
2247
|
-
return
|
|
2619
|
+
return path72.resolve(root, META_DIR2, `${resource}.generation`);
|
|
2248
2620
|
}
|
|
2249
2621
|
async function bumpResourceGeneration(root, resource, options) {
|
|
2250
2622
|
const token = randomUUID();
|
|
@@ -2262,7 +2634,7 @@ async function bumpResourceGeneration(root, resource, options) {
|
|
|
2262
2634
|
}
|
|
2263
2635
|
async function readResourceGeneration(root, resource) {
|
|
2264
2636
|
try {
|
|
2265
|
-
const token = await
|
|
2637
|
+
const token = await fs52.readFile(resourceGenerationPath(root, resource), "utf-8");
|
|
2266
2638
|
return { ok: true, token };
|
|
2267
2639
|
} catch (err) {
|
|
2268
2640
|
if (isNodeError3(err) && err.code === "ENOENT")
|
|
@@ -2282,7 +2654,7 @@ function stripEmbeddedIdFromName(name) {
|
|
|
2282
2654
|
async function scanForCollectionMeta(baseDir, relativePath = "") {
|
|
2283
2655
|
const collections = [];
|
|
2284
2656
|
try {
|
|
2285
|
-
const entries = await
|
|
2657
|
+
const entries = await fs62.readdir(baseDir, { withFileTypes: true });
|
|
2286
2658
|
for (const entry of entries) {
|
|
2287
2659
|
if (!entry.isDirectory())
|
|
2288
2660
|
continue;
|
|
@@ -2293,8 +2665,8 @@ async function scanForCollectionMeta(baseDir, relativePath = "") {
|
|
|
2293
2665
|
const absolutePath = join3(baseDir, folderName);
|
|
2294
2666
|
const metaPath = join3(absolutePath, ".collection.json");
|
|
2295
2667
|
try {
|
|
2296
|
-
await
|
|
2297
|
-
const content = await
|
|
2668
|
+
await fs62.access(metaPath);
|
|
2669
|
+
const content = await fs62.readFile(metaPath, "utf-8");
|
|
2298
2670
|
const parsed = JSON.parse(content);
|
|
2299
2671
|
const meta = collectionMetaSchema.parse(parsed);
|
|
2300
2672
|
collections.push({
|
|
@@ -2326,7 +2698,7 @@ async function loadCollectionMetaFiles(contentRoot) {
|
|
|
2326
2698
|
let root = null;
|
|
2327
2699
|
const rootMetaPath = join3(contentRoot, ".collection.json");
|
|
2328
2700
|
try {
|
|
2329
|
-
await
|
|
2701
|
+
await fs62.access(rootMetaPath);
|
|
2330
2702
|
} catch (err) {
|
|
2331
2703
|
if (err.code === "ENOENT") {
|
|
2332
2704
|
} else {
|
|
@@ -2334,7 +2706,7 @@ async function loadCollectionMetaFiles(contentRoot) {
|
|
|
2334
2706
|
}
|
|
2335
2707
|
}
|
|
2336
2708
|
try {
|
|
2337
|
-
const content = await
|
|
2709
|
+
const content = await fs62.readFile(rootMetaPath, "utf-8");
|
|
2338
2710
|
const parsed = JSON.parse(content);
|
|
2339
2711
|
root = rootCollectionMetaSchema.parse(parsed);
|
|
2340
2712
|
} catch (err) {
|
|
@@ -2424,16 +2796,16 @@ function isValidSchema(schema) {
|
|
|
2424
2796
|
async function isStaleByMtime(dir, cachedAt) {
|
|
2425
2797
|
let entries;
|
|
2426
2798
|
try {
|
|
2427
|
-
entries = await
|
|
2799
|
+
entries = await fs72.readdir(dir, { recursive: true, encoding: "utf-8" });
|
|
2428
2800
|
} catch {
|
|
2429
2801
|
return true;
|
|
2430
2802
|
}
|
|
2431
2803
|
for (const entry of entries) {
|
|
2432
2804
|
if (!entry.endsWith(".collection.json"))
|
|
2433
2805
|
continue;
|
|
2434
|
-
const full =
|
|
2806
|
+
const full = path82.join(dir, entry);
|
|
2435
2807
|
try {
|
|
2436
|
-
const stat = await
|
|
2808
|
+
const stat = await fs72.stat(full);
|
|
2437
2809
|
if (stat.mtimeMs > cachedAt.getTime())
|
|
2438
2810
|
return true;
|
|
2439
2811
|
} catch {
|
|
@@ -2456,7 +2828,7 @@ async function invalidateBranchContentCaches(root) {
|
|
|
2456
2828
|
}
|
|
2457
2829
|
async function filePathExists3(filePath) {
|
|
2458
2830
|
try {
|
|
2459
|
-
await
|
|
2831
|
+
await fs8.stat(filePath);
|
|
2460
2832
|
return true;
|
|
2461
2833
|
} catch (err) {
|
|
2462
2834
|
if (isNotFoundError3(err))
|
|
@@ -2464,6 +2836,15 @@ async function filePathExists3(filePath) {
|
|
|
2464
2836
|
throw err;
|
|
2465
2837
|
}
|
|
2466
2838
|
}
|
|
2839
|
+
async function readFileIfExists(filePath) {
|
|
2840
|
+
try {
|
|
2841
|
+
return await fs8.readFile(filePath, "utf8");
|
|
2842
|
+
} catch (err) {
|
|
2843
|
+
if (isNotFoundError3(err))
|
|
2844
|
+
return void 0;
|
|
2845
|
+
throw err;
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2467
2848
|
function validateAndNormalizePath(root, target) {
|
|
2468
2849
|
const resolvedRoot = resolve(root);
|
|
2469
2850
|
const withSep = resolvedRoot.endsWith(sep) ? resolvedRoot : `${resolvedRoot}${sep}`;
|
|
@@ -2493,11 +2874,11 @@ function resolveBranchPath(options) {
|
|
|
2493
2874
|
const safeBranch = sanitizeBranchName(options.branchName);
|
|
2494
2875
|
const strategy = operatingStrategy2(options.mode);
|
|
2495
2876
|
const baseRoot = resolveContentBranchesRoot(options.mode, options.basePathOverride);
|
|
2496
|
-
const normalizedBase =
|
|
2497
|
-
const baseWithSep = normalizedBase.endsWith(
|
|
2877
|
+
const normalizedBase = path102.resolve(baseRoot);
|
|
2878
|
+
const baseWithSep = normalizedBase.endsWith(path102.sep) ? normalizedBase : `${normalizedBase}${path102.sep}`;
|
|
2498
2879
|
const branchRoot = strategy.getContentBranchRoot(safeBranch, options.basePathOverride);
|
|
2499
2880
|
const withinBase = (target) => {
|
|
2500
|
-
const resolved =
|
|
2881
|
+
const resolved = path102.resolve(target);
|
|
2501
2882
|
return resolved === normalizedBase || resolved.startsWith(baseWithSep);
|
|
2502
2883
|
};
|
|
2503
2884
|
if (!withinBase(branchRoot)) {
|
|
@@ -2507,7 +2888,7 @@ function resolveBranchPath(options) {
|
|
|
2507
2888
|
}
|
|
2508
2889
|
async function ensureBranchRoot(options) {
|
|
2509
2890
|
const result = resolveBranchPath(options);
|
|
2510
|
-
await
|
|
2891
|
+
await fs9.mkdir(result.branchRoot, { recursive: true });
|
|
2511
2892
|
return result;
|
|
2512
2893
|
}
|
|
2513
2894
|
async function withLocks(keys, fn) {
|
|
@@ -2590,14 +2971,44 @@ function parseComponentProps(attrString) {
|
|
|
2590
2971
|
}
|
|
2591
2972
|
return props;
|
|
2592
2973
|
}
|
|
2974
|
+
function isFenceCloseLine(line, marker) {
|
|
2975
|
+
return line.startsWith(marker) && /^\s*$/.test(line.slice(marker.length));
|
|
2976
|
+
}
|
|
2977
|
+
function maskFencedCodeBlocks(body, blocks) {
|
|
2978
|
+
const lines = body.split("\n");
|
|
2979
|
+
const lineCount = lines.length;
|
|
2980
|
+
const nextCloseLine = {
|
|
2981
|
+
"```": new Array(lineCount + 1).fill(-1),
|
|
2982
|
+
"~~~": new Array(lineCount + 1).fill(-1)
|
|
2983
|
+
};
|
|
2984
|
+
for (let i2 = lineCount - 1; i2 >= 0; i2--) {
|
|
2985
|
+
nextCloseLine["```"][i2] = isFenceCloseLine(lines[i2], "```") ? i2 : nextCloseLine["```"][i2 + 1];
|
|
2986
|
+
nextCloseLine["~~~"][i2] = isFenceCloseLine(lines[i2], "~~~") ? i2 : nextCloseLine["~~~"][i2 + 1];
|
|
2987
|
+
}
|
|
2988
|
+
const outLines = [];
|
|
2989
|
+
let i = 0;
|
|
2990
|
+
while (i < lineCount) {
|
|
2991
|
+
const line = lines[i];
|
|
2992
|
+
const marker = line.startsWith("```") ? "```" : line.startsWith("~~~") ? "~~~" : null;
|
|
2993
|
+
const searchFrom = i + 2;
|
|
2994
|
+
const closeIndex = marker && searchFrom < lineCount ? nextCloseLine[marker][searchFrom] : -1;
|
|
2995
|
+
if (!marker || closeIndex === -1) {
|
|
2996
|
+
outLines.push(line);
|
|
2997
|
+
i++;
|
|
2998
|
+
continue;
|
|
2999
|
+
}
|
|
3000
|
+
const block = lines.slice(i, closeIndex + 1).join("\n");
|
|
3001
|
+
const idx = blocks.length;
|
|
3002
|
+
blocks.push(block);
|
|
3003
|
+
outLines.push(`${BLOCK_PREFIX}${idx}${BLOCK_SUFFIX}`);
|
|
3004
|
+
i = closeIndex + 1;
|
|
3005
|
+
}
|
|
3006
|
+
return outLines.join("\n");
|
|
3007
|
+
}
|
|
2593
3008
|
function maskCodeBlocks(body) {
|
|
2594
3009
|
const blocks = [];
|
|
2595
3010
|
const inlines = [];
|
|
2596
|
-
let masked = body
|
|
2597
|
-
const idx = blocks.length;
|
|
2598
|
-
blocks.push(block);
|
|
2599
|
-
return `${BLOCK_PREFIX}${idx}${BLOCK_SUFFIX}`;
|
|
2600
|
-
});
|
|
3011
|
+
let masked = maskFencedCodeBlocks(body, blocks);
|
|
2601
3012
|
masked = masked.replace(/``[^`]+``|`[^`]+`/g, (span) => {
|
|
2602
3013
|
const idx = inlines.length;
|
|
2603
3014
|
inlines.push(span);
|
|
@@ -2765,7 +3176,7 @@ function renderField(field, value, depth, entry, config) {
|
|
|
2765
3176
|
const heading = "#".repeat(Math.min(depth, 6));
|
|
2766
3177
|
const descriptionLine = "description" in field && field.description ? `
|
|
2767
3178
|
|
|
2768
|
-
|
|
3179
|
+
_${field.description}_` : "";
|
|
2769
3180
|
if ("list" in field && field.list && Array.isArray(value)) {
|
|
2770
3181
|
return renderListField(field, value, depth, label, heading, descriptionLine, entry, config);
|
|
2771
3182
|
}
|
|
@@ -3021,26 +3432,13 @@ function formatInlineValue(field, value) {
|
|
|
3021
3432
|
return String(value);
|
|
3022
3433
|
}
|
|
3023
3434
|
function yamlValue(value) {
|
|
3435
|
+
if (value === "")
|
|
3436
|
+
return '""';
|
|
3024
3437
|
if (/[:#{}[\],&*?|>!%@`]/.test(value) || value.includes("\n")) {
|
|
3025
3438
|
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
3026
3439
|
}
|
|
3027
3440
|
return value;
|
|
3028
3441
|
}
|
|
3029
|
-
function computeEntryUrl(collection, slug, contentRoot) {
|
|
3030
|
-
const root = trimSlashes(contentRoot);
|
|
3031
|
-
let stripped = collection;
|
|
3032
|
-
if (root && collection.startsWith(`${root}/`)) {
|
|
3033
|
-
stripped = collection.slice(root.length + 1);
|
|
3034
|
-
} else if (collection === root) {
|
|
3035
|
-
stripped = "";
|
|
3036
|
-
}
|
|
3037
|
-
const segments = stripped.split("/").filter(Boolean);
|
|
3038
|
-
if (slug && slug !== "index") {
|
|
3039
|
-
segments.push(slug);
|
|
3040
|
-
}
|
|
3041
|
-
const path202 = segments.length > 0 ? `/${segments.join("/")}` : "/";
|
|
3042
|
-
return path202.toLowerCase();
|
|
3043
|
-
}
|
|
3044
3442
|
function resolveEntryUrl(location, contentRoot) {
|
|
3045
3443
|
return computeEntryUrl(location.collection ?? "", location.slug ?? "", contentRoot);
|
|
3046
3444
|
}
|
|
@@ -3207,7 +3605,7 @@ async function processCollection(store, collection, flatSchema, contentRoot, con
|
|
|
3207
3605
|
const listed = await store.getCollectionEntryPaths(collection.logicalPath);
|
|
3208
3606
|
const directEntries = listed.filter((e) => e.collection === collection.logicalPath);
|
|
3209
3607
|
for (const listEntry of directEntries) {
|
|
3210
|
-
const entryTypeName = extractEntryTypeFromFilename(
|
|
3608
|
+
const entryTypeName = extractEntryTypeFromFilename(path12.basename(listEntry.relativePath));
|
|
3211
3609
|
if (!entryTypeName)
|
|
3212
3610
|
continue;
|
|
3213
3611
|
if (config?.exclude?.entryTypes?.includes(entryTypeName))
|
|
@@ -3225,7 +3623,7 @@ async function processCollection(store, collection, flatSchema, contentRoot, con
|
|
|
3225
3623
|
}
|
|
3226
3624
|
if (config?.exclude?.where?.(aiEntry))
|
|
3227
3625
|
continue;
|
|
3228
|
-
await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(
|
|
3626
|
+
await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(path12.basename(listEntry.relativePath)), config);
|
|
3229
3627
|
entries.push(aiEntry);
|
|
3230
3628
|
const entryFilePath = `${cleanPath}/${listEntry.slug}.md`;
|
|
3231
3629
|
const entryMarkdown = entryToMarkdown(aiEntry, config);
|
|
@@ -3276,7 +3674,7 @@ async function processRootEntries(store, rootCollection, contentRoot, config, id
|
|
|
3276
3674
|
const listed = await store.getCollectionEntryPaths(rootCollection.logicalPath);
|
|
3277
3675
|
const directEntries = listed.filter((e) => e.collection === rootCollection.logicalPath);
|
|
3278
3676
|
for (const listEntry of directEntries) {
|
|
3279
|
-
const entryTypeName = extractEntryTypeFromFilename(
|
|
3677
|
+
const entryTypeName = extractEntryTypeFromFilename(path12.basename(listEntry.relativePath));
|
|
3280
3678
|
if (!entryTypeName)
|
|
3281
3679
|
continue;
|
|
3282
3680
|
if (config?.exclude?.entryTypes?.includes(entryTypeName))
|
|
@@ -3294,7 +3692,7 @@ async function processRootEntries(store, rootCollection, contentRoot, config, id
|
|
|
3294
3692
|
}
|
|
3295
3693
|
if (config?.exclude?.where?.(aiEntry))
|
|
3296
3694
|
continue;
|
|
3297
|
-
await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(
|
|
3695
|
+
await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(path12.basename(listEntry.relativePath)), config);
|
|
3298
3696
|
entries.push(aiEntry);
|
|
3299
3697
|
const entryFilePath = `${listEntry.slug}.md`;
|
|
3300
3698
|
const entryMarkdown = entryToMarkdown(aiEntry, config);
|
|
@@ -3342,19 +3740,19 @@ function docToAIEntry(doc, slug, entryTypeName, entryTypeConfig, cleanCollection
|
|
|
3342
3740
|
};
|
|
3343
3741
|
}
|
|
3344
3742
|
function makeReadSibling(dir) {
|
|
3345
|
-
const resolvedDir =
|
|
3743
|
+
const resolvedDir = path12.resolve(dir);
|
|
3346
3744
|
return async (name) => {
|
|
3347
|
-
if (!name || name.includes("/") || name.includes("\\") ||
|
|
3745
|
+
if (!name || name.includes("/") || name.includes("\\") || path12.isAbsolute(name) || hasTraversalSequence(name)) {
|
|
3348
3746
|
return null;
|
|
3349
3747
|
}
|
|
3350
|
-
const abs =
|
|
3351
|
-
if (
|
|
3748
|
+
const abs = path12.resolve(resolvedDir, name);
|
|
3749
|
+
if (path12.dirname(abs) !== resolvedDir)
|
|
3352
3750
|
return null;
|
|
3353
3751
|
try {
|
|
3354
|
-
const stats = await
|
|
3752
|
+
const stats = await fs11.lstat(abs);
|
|
3355
3753
|
if (!stats.isFile())
|
|
3356
3754
|
return null;
|
|
3357
|
-
return await
|
|
3755
|
+
return await fs11.readFile(abs, "utf8");
|
|
3358
3756
|
} catch (err) {
|
|
3359
3757
|
if (isNodeError3(err) && (err.code === "ENOENT" || err.code === "ENOTDIR"))
|
|
3360
3758
|
return null;
|
|
@@ -3368,7 +3766,7 @@ async function runEntryTransform(entry, absolutePath, contentId, config) {
|
|
|
3368
3766
|
return;
|
|
3369
3767
|
const ctx = {
|
|
3370
3768
|
contentId: contentId ?? "",
|
|
3371
|
-
readSibling: makeReadSibling(
|
|
3769
|
+
readSibling: makeReadSibling(path12.dirname(absolutePath))
|
|
3372
3770
|
};
|
|
3373
3771
|
try {
|
|
3374
3772
|
const appended = await transform(entry, ctx);
|
|
@@ -3409,29 +3807,29 @@ async function writeOccJsonFile(filePath, payload, options) {
|
|
|
3409
3807
|
const writeId = randomUUID2();
|
|
3410
3808
|
const data = { ...payload, version: newVersion, writeId };
|
|
3411
3809
|
const content = JSON.stringify(data, null, 2) + (trailingNewline ? "\n" : "");
|
|
3412
|
-
const dir =
|
|
3413
|
-
await
|
|
3810
|
+
const dir = path14.dirname(filePath);
|
|
3811
|
+
await fs13.mkdir(dir, { recursive: true });
|
|
3414
3812
|
const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
3415
|
-
await
|
|
3813
|
+
await fs13.writeFile(tempPath, content, "utf-8");
|
|
3416
3814
|
if (expectedVersion === null) {
|
|
3417
3815
|
try {
|
|
3418
|
-
await
|
|
3816
|
+
await fs13.link(tempPath, filePath);
|
|
3419
3817
|
} catch (err) {
|
|
3420
|
-
await
|
|
3818
|
+
await fs13.unlink(tempPath).catch(() => {
|
|
3421
3819
|
});
|
|
3422
3820
|
if (isFileExistsError2(err)) {
|
|
3423
3821
|
throw new OccWriteConflictError();
|
|
3424
3822
|
}
|
|
3425
3823
|
throw err;
|
|
3426
3824
|
}
|
|
3427
|
-
await
|
|
3825
|
+
await fs13.unlink(tempPath).catch(() => {
|
|
3428
3826
|
});
|
|
3429
3827
|
return { version: newVersion, writeId };
|
|
3430
3828
|
}
|
|
3431
3829
|
try {
|
|
3432
3830
|
let currentVersion = null;
|
|
3433
3831
|
try {
|
|
3434
|
-
const current = JSON.parse(await
|
|
3832
|
+
const current = JSON.parse(await fs13.readFile(filePath, "utf-8"));
|
|
3435
3833
|
currentVersion = current.version ?? 0;
|
|
3436
3834
|
} catch {
|
|
3437
3835
|
currentVersion = null;
|
|
@@ -3439,16 +3837,16 @@ async function writeOccJsonFile(filePath, payload, options) {
|
|
|
3439
3837
|
if (currentVersion !== expectedVersion) {
|
|
3440
3838
|
throw new OccWriteConflictError();
|
|
3441
3839
|
}
|
|
3442
|
-
await
|
|
3840
|
+
await fs13.rename(tempPath, filePath);
|
|
3443
3841
|
if (settleMs > 0) {
|
|
3444
3842
|
await new Promise((resolve2) => setTimeout(resolve2, settleMs));
|
|
3445
3843
|
}
|
|
3446
|
-
const afterWrite = JSON.parse(await
|
|
3844
|
+
const afterWrite = JSON.parse(await fs13.readFile(filePath, "utf-8"));
|
|
3447
3845
|
if (afterWrite.writeId !== writeId) {
|
|
3448
3846
|
throw new OccWriteConflictError();
|
|
3449
3847
|
}
|
|
3450
3848
|
} catch (err) {
|
|
3451
|
-
await
|
|
3849
|
+
await fs13.unlink(tempPath).catch(() => {
|
|
3452
3850
|
});
|
|
3453
3851
|
throw err;
|
|
3454
3852
|
}
|
|
@@ -3474,8 +3872,8 @@ async function withOccRetry(operation, options) {
|
|
|
3474
3872
|
throw new Error("Unreachable");
|
|
3475
3873
|
}
|
|
3476
3874
|
async function withOccFileLock(filePath, fn) {
|
|
3477
|
-
const dir =
|
|
3478
|
-
await
|
|
3875
|
+
const dir = path14.dirname(filePath);
|
|
3876
|
+
await fs13.mkdir(dir, { recursive: true });
|
|
3479
3877
|
const MAX_ATTEMPTS = 14;
|
|
3480
3878
|
let release = null;
|
|
3481
3879
|
for (let attempt = 1; release === null; attempt++) {
|
|
@@ -3559,11 +3957,11 @@ function gitChildEnv(overrides) {
|
|
|
3559
3957
|
return { ...env, ...FORCE_C_LOCALE, ...overrides };
|
|
3560
3958
|
}
|
|
3561
3959
|
async function ensureGitExcludePattern(repoPath, pattern) {
|
|
3562
|
-
const excludePath =
|
|
3563
|
-
await
|
|
3960
|
+
const excludePath = path16.join(repoPath, ".git", "info", "exclude");
|
|
3961
|
+
await fs15.mkdir(path16.dirname(excludePath), { recursive: true });
|
|
3564
3962
|
let content = "";
|
|
3565
3963
|
try {
|
|
3566
|
-
content = await
|
|
3964
|
+
content = await fs15.readFile(excludePath, "utf-8");
|
|
3567
3965
|
} catch (err) {
|
|
3568
3966
|
if (!isNotFoundError3(err))
|
|
3569
3967
|
throw err;
|
|
@@ -3575,7 +3973,7 @@ async function ensureGitExcludePattern(repoPath, pattern) {
|
|
|
3575
3973
|
}
|
|
3576
3974
|
const needsLeadingNewline = content.length > 0 && !content.endsWith("\n");
|
|
3577
3975
|
const newContent = content + (needsLeadingNewline ? "\n" : "") + pattern + "\n";
|
|
3578
|
-
await
|
|
3976
|
+
await fs15.writeFile(excludePath, newContent, "utf-8");
|
|
3579
3977
|
log5.debug("git", "Added pattern to .git/info/exclude", { pattern });
|
|
3580
3978
|
}
|
|
3581
3979
|
async function loadOrCreateBranchContext(options) {
|
|
@@ -3631,24 +4029,34 @@ async function resolveBranchRoot(config) {
|
|
|
3631
4029
|
});
|
|
3632
4030
|
return context.branchRoot;
|
|
3633
4031
|
}
|
|
3634
|
-
async function listEntries(branchRoot, flatSchema, contentRootName, options) {
|
|
4032
|
+
async function listEntries(branchRoot, flatSchema, contentRootName, options, visibility) {
|
|
3635
4033
|
const rootPath = options?.rootPath ?? contentRootName;
|
|
3636
4034
|
const extract = options?.extract;
|
|
3637
4035
|
const filter = options?.filter;
|
|
3638
4036
|
const customSort = options?.sort;
|
|
3639
4037
|
const collections = flatSchema.filter((item) => item.type === "collection" && item.entries !== void 0 && (item.logicalPath === rootPath || item.logicalPath.startsWith(`${rootPath}/`)));
|
|
4038
|
+
const shouldInclude = visibility?.shouldInclude;
|
|
4039
|
+
const skippedFiles = [];
|
|
4040
|
+
const resolver = options?.resolveReferences ? createReferenceResolver(branchRoot, flatSchema, contentRootName) : null;
|
|
3640
4041
|
const collectionResults = await Promise.all(collections.map(async (collection) => {
|
|
3641
|
-
const entries = await listCollectionEntries(branchRoot, collection);
|
|
3642
|
-
|
|
4042
|
+
const entries = await listCollectionEntries(branchRoot, collection, (file) => skippedFiles.push(file));
|
|
4043
|
+
const visible = shouldInclude ? entries.filter((e) => shouldInclude(e.physicalPath)) : entries;
|
|
4044
|
+
const resolved = resolver ? await resolveCollectionItemReferences(visible, collection, resolver) : visible;
|
|
4045
|
+
return resolved.map((entry) => ({ entry, collection }));
|
|
3643
4046
|
}));
|
|
4047
|
+
if (isBuildMode() && skippedFiles.length > 0) {
|
|
4048
|
+
const lines = skippedFiles.map(({ filename, collectionPath }) => ` - ${collectionPath}/${filename}`);
|
|
4049
|
+
throw new Error(`CanopyCMS static build: found ${skippedFiles.length} file(s) that look like malformed content entries inside a content collection:
|
|
4050
|
+
${lines.join("\n")}
|
|
4051
|
+
Expected {type}.{slug}.{id}.{ext} with a known entry type (a name declared in that collection's entries config) and a valid 12-char Base58 ID. This usually means a schema rename without a matching file rename, an entry type declared in one collection but not another, or a stray file placed directly in a collection directory. If this is meant to be a colocated sibling artifact (e.g. an entry's contentId-prefixed data file read via an entryTransforms readSibling call), keep its name to three or fewer dot-separated segments (id.suffix.ext) so it is never mistaken for an entry attempt. Otherwise rename or move the file, or fix the schema, then rebuild.`);
|
|
4052
|
+
}
|
|
3644
4053
|
const contentPrefix = contentRootName ? `${contentRootName}/` : "";
|
|
3645
4054
|
const items = [];
|
|
3646
4055
|
for (const results of collectionResults) {
|
|
3647
4056
|
for (const { entry, collection } of results) {
|
|
3648
4057
|
const pathWithoutRoot = entry.logicalPath.startsWith(contentPrefix) ? entry.logicalPath.slice(contentPrefix.length) : entry.logicalPath;
|
|
3649
4058
|
const pathSegments = pathWithoutRoot.split("/").filter(Boolean);
|
|
3650
|
-
const
|
|
3651
|
-
const urlPath = urlSegments.length > 0 ? `/${urlSegments.join("/")}`.toLowerCase() : "/";
|
|
4059
|
+
const urlPath = computeEntryUrl(entry.collectionPath, entry.slug, contentRootName);
|
|
3652
4060
|
const raw = entry.data;
|
|
3653
4061
|
const meta = {
|
|
3654
4062
|
entryPath: entry.logicalPath,
|
|
@@ -3667,7 +4075,8 @@ async function listEntries(branchRoot, flatSchema, contentRootName, options) {
|
|
|
3667
4075
|
entryType: entry.entryType,
|
|
3668
4076
|
format: entry.format,
|
|
3669
4077
|
data,
|
|
3670
|
-
schema: collection.entries?.find((e) => e.name === entry.entryType)?.schema
|
|
4078
|
+
schema: collection.entries?.find((e) => e.name === entry.entryType)?.schema,
|
|
4079
|
+
updatedAt: entry.updatedAt
|
|
3671
4080
|
};
|
|
3672
4081
|
if (filter && !filter(item))
|
|
3673
4082
|
continue;
|
|
@@ -3692,7 +4101,7 @@ function isValidCropRect(x, y, w, h) {
|
|
|
3692
4101
|
return false;
|
|
3693
4102
|
return true;
|
|
3694
4103
|
}
|
|
3695
|
-
function
|
|
4104
|
+
function isPlainRecord2(value) {
|
|
3696
4105
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3697
4106
|
}
|
|
3698
4107
|
function resolveBlockItem(blockField, item) {
|
|
@@ -3702,17 +4111,17 @@ function resolveBlockItem(blockField, item) {
|
|
|
3702
4111
|
const template = blockField.templates?.find((t) => t.name === templateName);
|
|
3703
4112
|
if (!template?.fields)
|
|
3704
4113
|
return void 0;
|
|
3705
|
-
const data =
|
|
4114
|
+
const data = isPlainRecord2(item.value) ? item.value : item;
|
|
3706
4115
|
return { fields: template.fields, data };
|
|
3707
4116
|
}
|
|
3708
|
-
function
|
|
4117
|
+
function isPlainRecord3(value) {
|
|
3709
4118
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3710
4119
|
}
|
|
3711
4120
|
function isPositiveInt(value) {
|
|
3712
4121
|
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
3713
4122
|
}
|
|
3714
4123
|
function isValidImageCropValue(value) {
|
|
3715
|
-
if (!
|
|
4124
|
+
if (!isPlainRecord3(value))
|
|
3716
4125
|
return false;
|
|
3717
4126
|
const { x, y, w, h } = value;
|
|
3718
4127
|
if (typeof x !== "number" || typeof y !== "number" || typeof w !== "number" || typeof h !== "number") {
|
|
@@ -3720,78 +4129,78 @@ function isValidImageCropValue(value) {
|
|
|
3720
4129
|
}
|
|
3721
4130
|
return isValidCropRect(x, y, w, h);
|
|
3722
4131
|
}
|
|
3723
|
-
function validateImageValue(field, value,
|
|
3724
|
-
if (!
|
|
3725
|
-
return [{ fieldPath:
|
|
4132
|
+
function validateImageValue(field, value, path212) {
|
|
4133
|
+
if (!isPlainRecord3(value)) {
|
|
4134
|
+
return [{ fieldPath: path212, message: "Expected an image object with { src, alt }" }];
|
|
3726
4135
|
}
|
|
3727
4136
|
const errors = [];
|
|
3728
4137
|
if (typeof value.src !== "string" || value.src.trim() === "") {
|
|
3729
|
-
errors.push({ fieldPath: `${
|
|
4138
|
+
errors.push({ fieldPath: `${path212}.src`, message: "Image src is required" });
|
|
3730
4139
|
}
|
|
3731
4140
|
if (typeof value.alt !== "string") {
|
|
3732
|
-
errors.push({ fieldPath: `${
|
|
4141
|
+
errors.push({ fieldPath: `${path212}.alt`, message: "Image alt text is required" });
|
|
3733
4142
|
} else if (value.alt.trim() === "" && field.altOptional !== true) {
|
|
3734
|
-
errors.push({ fieldPath: `${
|
|
4143
|
+
errors.push({ fieldPath: `${path212}.alt`, message: "Image alt text is required" });
|
|
3735
4144
|
}
|
|
3736
4145
|
if (value.width !== void 0 && !isPositiveInt(value.width)) {
|
|
3737
|
-
errors.push({ fieldPath: `${
|
|
4146
|
+
errors.push({ fieldPath: `${path212}.width`, message: "Image width must be a positive integer" });
|
|
3738
4147
|
}
|
|
3739
4148
|
if (value.height !== void 0 && !isPositiveInt(value.height)) {
|
|
3740
4149
|
errors.push({
|
|
3741
|
-
fieldPath: `${
|
|
4150
|
+
fieldPath: `${path212}.height`,
|
|
3742
4151
|
message: "Image height must be a positive integer"
|
|
3743
4152
|
});
|
|
3744
4153
|
}
|
|
3745
4154
|
if (value.crop !== void 0 && !isValidImageCropValue(value.crop)) {
|
|
3746
|
-
errors.push({ fieldPath: `${
|
|
4155
|
+
errors.push({ fieldPath: `${path212}.crop`, message: "Invalid image crop rect" });
|
|
3747
4156
|
}
|
|
3748
4157
|
return errors;
|
|
3749
4158
|
}
|
|
3750
4159
|
function referenceValueId(value) {
|
|
3751
4160
|
if (typeof value === "string")
|
|
3752
4161
|
return value;
|
|
3753
|
-
if (
|
|
4162
|
+
if (isPlainRecord3(value) && typeof value.id === "string")
|
|
3754
4163
|
return value.id;
|
|
3755
4164
|
return void 0;
|
|
3756
4165
|
}
|
|
3757
|
-
function validateScalar(field, value,
|
|
4166
|
+
function validateScalar(field, value, path212) {
|
|
3758
4167
|
switch (field.type) {
|
|
3759
4168
|
case "number":
|
|
3760
4169
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
3761
|
-
return [{ fieldPath:
|
|
4170
|
+
return [{ fieldPath: path212, message: "Expected a number" }];
|
|
3762
4171
|
}
|
|
3763
4172
|
return [];
|
|
3764
4173
|
case "boolean":
|
|
3765
4174
|
if (typeof value !== "boolean") {
|
|
3766
|
-
return [{ fieldPath:
|
|
4175
|
+
return [{ fieldPath: path212, message: "Expected true or false" }];
|
|
3767
4176
|
}
|
|
3768
4177
|
return [];
|
|
3769
4178
|
case "datetime":
|
|
3770
4179
|
if (typeof value !== "string" || value !== "" && Number.isNaN(Date.parse(value))) {
|
|
3771
|
-
return [{ fieldPath:
|
|
4180
|
+
return [{ fieldPath: path212, message: "Expected a valid date/time string" }];
|
|
3772
4181
|
}
|
|
3773
4182
|
return [];
|
|
3774
4183
|
case "select": {
|
|
3775
4184
|
if (typeof value !== "string") {
|
|
3776
|
-
return [{ fieldPath:
|
|
4185
|
+
return [{ fieldPath: path212, message: "Expected a selection" }];
|
|
3777
4186
|
}
|
|
3778
4187
|
const options = selectOptionValues(field);
|
|
3779
4188
|
if (value !== "" && !options.includes(value)) {
|
|
3780
|
-
return [{ fieldPath:
|
|
4189
|
+
return [{ fieldPath: path212, message: `Must be one of: ${options.join(", ")}` }];
|
|
3781
4190
|
}
|
|
3782
4191
|
return [];
|
|
3783
4192
|
}
|
|
3784
4193
|
case "reference":
|
|
3785
4194
|
if (referenceValueId(value) === void 0) {
|
|
3786
|
-
return [{ fieldPath:
|
|
4195
|
+
return [{ fieldPath: path212, message: "Expected a reference id" }];
|
|
3787
4196
|
}
|
|
3788
4197
|
return [];
|
|
3789
4198
|
case "image":
|
|
3790
|
-
return validateImageValue(field, value,
|
|
4199
|
+
return validateImageValue(field, value, path212);
|
|
3791
4200
|
default:
|
|
3792
4201
|
if (STRING_FIELD_TYPES.has(field.type)) {
|
|
3793
4202
|
if (typeof value !== "string") {
|
|
3794
|
-
return [{ fieldPath:
|
|
4203
|
+
return [{ fieldPath: path212, message: "Expected text" }];
|
|
3795
4204
|
}
|
|
3796
4205
|
}
|
|
3797
4206
|
return [];
|
|
@@ -3814,12 +4223,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
|
|
|
3814
4223
|
errors.push(...validateEntryData(field.fields, data, pathPrefix));
|
|
3815
4224
|
continue;
|
|
3816
4225
|
}
|
|
3817
|
-
const
|
|
4226
|
+
const path212 = pathPrefix ? `${pathPrefix}.${field.name}` : field.name;
|
|
3818
4227
|
const value = data[field.name];
|
|
3819
4228
|
const isRequired = "required" in field && field.required === true;
|
|
3820
4229
|
if (isRequired && isEmptyForRequired(field, value)) {
|
|
3821
4230
|
const message = Array.isArray(value) ? "At least one item is required" : "This field is required";
|
|
3822
|
-
errors.push({ fieldPath:
|
|
4231
|
+
errors.push({ fieldPath: path212, message });
|
|
3823
4232
|
continue;
|
|
3824
4233
|
}
|
|
3825
4234
|
if (value === void 0 || value === null)
|
|
@@ -3827,12 +4236,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
|
|
|
3827
4236
|
if (field.type === "block") {
|
|
3828
4237
|
const blockField = field;
|
|
3829
4238
|
if (!Array.isArray(value)) {
|
|
3830
|
-
errors.push({ fieldPath:
|
|
4239
|
+
errors.push({ fieldPath: path212, message: "Expected a list of blocks" });
|
|
3831
4240
|
continue;
|
|
3832
4241
|
}
|
|
3833
4242
|
value.forEach((item, index) => {
|
|
3834
|
-
const itemPath = `${
|
|
3835
|
-
if (!
|
|
4243
|
+
const itemPath = `${path212}[${index}]`;
|
|
4244
|
+
if (!isPlainRecord3(item)) {
|
|
3836
4245
|
errors.push({ fieldPath: itemPath, message: "Expected a block object" });
|
|
3837
4246
|
return;
|
|
3838
4247
|
}
|
|
@@ -3853,12 +4262,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
|
|
|
3853
4262
|
const objectField = field;
|
|
3854
4263
|
if (objectField.list) {
|
|
3855
4264
|
if (!Array.isArray(value)) {
|
|
3856
|
-
errors.push({ fieldPath:
|
|
4265
|
+
errors.push({ fieldPath: path212, message: "Expected a list of items" });
|
|
3857
4266
|
continue;
|
|
3858
4267
|
}
|
|
3859
4268
|
value.forEach((item, index) => {
|
|
3860
|
-
const itemPath = `${
|
|
3861
|
-
if (!
|
|
4269
|
+
const itemPath = `${path212}[${index}]`;
|
|
4270
|
+
if (!isPlainRecord3(item)) {
|
|
3862
4271
|
errors.push({ fieldPath: itemPath, message: "Expected an object" });
|
|
3863
4272
|
return;
|
|
3864
4273
|
}
|
|
@@ -3866,28 +4275,28 @@ function validateEntryData(fields, data, pathPrefix = "") {
|
|
|
3866
4275
|
errors.push(...validateEntryData(objectField.fields, item, itemPath));
|
|
3867
4276
|
}
|
|
3868
4277
|
});
|
|
3869
|
-
} else if (!
|
|
3870
|
-
errors.push({ fieldPath:
|
|
4278
|
+
} else if (!isPlainRecord3(value)) {
|
|
4279
|
+
errors.push({ fieldPath: path212, message: "Expected an object" });
|
|
3871
4280
|
} else if (objectField.fields) {
|
|
3872
|
-
errors.push(...validateEntryData(objectField.fields, value,
|
|
4281
|
+
errors.push(...validateEntryData(objectField.fields, value, path212));
|
|
3873
4282
|
}
|
|
3874
4283
|
continue;
|
|
3875
4284
|
}
|
|
3876
4285
|
if ("list" in field && field.list) {
|
|
3877
4286
|
if (!Array.isArray(value)) {
|
|
3878
|
-
errors.push({ fieldPath:
|
|
4287
|
+
errors.push({ fieldPath: path212, message: "Expected a list of values" });
|
|
3879
4288
|
continue;
|
|
3880
4289
|
}
|
|
3881
4290
|
value.forEach((item, index) => {
|
|
3882
|
-
errors.push(...validateScalar(field, item, `${
|
|
4291
|
+
errors.push(...validateScalar(field, item, `${path212}[${index}]`));
|
|
3883
4292
|
});
|
|
3884
4293
|
continue;
|
|
3885
4294
|
}
|
|
3886
4295
|
if (Array.isArray(value) && KNOWN_FIELD_TYPES.has(field.type)) {
|
|
3887
|
-
errors.push({ fieldPath:
|
|
4296
|
+
errors.push({ fieldPath: path212, message: "Expected a single value, not a list" });
|
|
3888
4297
|
continue;
|
|
3889
4298
|
}
|
|
3890
|
-
errors.push(...validateScalar(field, value,
|
|
4299
|
+
errors.push(...validateScalar(field, value, path212));
|
|
3891
4300
|
}
|
|
3892
4301
|
return errors;
|
|
3893
4302
|
}
|
|
@@ -3931,6 +4340,37 @@ function assertBuildEntriesValid(items, phaseLabel) {
|
|
|
3931
4340
|
${lines.join("\n")}
|
|
3932
4341
|
These are likely abandoned create-scaffolds (empty entries left behind when a create was started but never finished). Finish editing the entry (fill in its required fields) or delete the abandoned draft, then rebuild.`);
|
|
3933
4342
|
}
|
|
4343
|
+
async function readGeneratedRecord(outputDir) {
|
|
4344
|
+
try {
|
|
4345
|
+
const raw = await fs17.readFile(path19.join(outputDir, GENERATED_RECORD_FILENAME), "utf-8");
|
|
4346
|
+
const parsed = JSON.parse(raw);
|
|
4347
|
+
if (typeof parsed !== "object" || parsed === null || !("files" in parsed))
|
|
4348
|
+
return [];
|
|
4349
|
+
const { files } = parsed;
|
|
4350
|
+
if (!Array.isArray(files))
|
|
4351
|
+
return [];
|
|
4352
|
+
return files.filter((entry) => typeof entry === "string");
|
|
4353
|
+
} catch {
|
|
4354
|
+
return [];
|
|
4355
|
+
}
|
|
4356
|
+
}
|
|
4357
|
+
async function writeGeneratedRecord(outputDir, files) {
|
|
4358
|
+
const record = { files: [...files].sort() };
|
|
4359
|
+
await fs17.mkdir(outputDir, { recursive: true });
|
|
4360
|
+
await fs17.writeFile(path19.join(outputDir, GENERATED_RECORD_FILENAME), `${JSON.stringify(record, null, 2)}
|
|
4361
|
+
`, "utf-8");
|
|
4362
|
+
}
|
|
4363
|
+
async function removeEmptyDirsUpward(startDir, stopAt) {
|
|
4364
|
+
let current = startDir;
|
|
4365
|
+
while (current.startsWith(stopAt) && current !== stopAt) {
|
|
4366
|
+
try {
|
|
4367
|
+
await fs17.rmdir(current);
|
|
4368
|
+
} catch {
|
|
4369
|
+
return;
|
|
4370
|
+
}
|
|
4371
|
+
current = path19.dirname(current);
|
|
4372
|
+
}
|
|
4373
|
+
}
|
|
3934
4374
|
async function generateAIContentFiles(options) {
|
|
3935
4375
|
const { config, entrySchemaRegistry, outputDir, aiConfig: aiConfig2, _testFlatSchema } = options;
|
|
3936
4376
|
const contentRootName = config.contentRoot || "content";
|
|
@@ -3953,23 +4393,45 @@ async function generateAIContentFiles(options) {
|
|
|
3953
4393
|
config: aiConfig2,
|
|
3954
4394
|
entryLinkUrl: config.entryLinkUrl
|
|
3955
4395
|
});
|
|
3956
|
-
const absoluteOutputDir =
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
const absolutePath = path18.resolve(path18.join(absoluteOutputDir, filePath));
|
|
4396
|
+
const absoluteOutputDir = path19.resolve(outputDir) + path19.sep;
|
|
4397
|
+
const resolveOutputPath = (filePath) => {
|
|
4398
|
+
const absolutePath = path19.resolve(path19.join(absoluteOutputDir, filePath));
|
|
3960
4399
|
if (!absolutePath.startsWith(absoluteOutputDir)) {
|
|
3961
4400
|
throw new Error(`Path traversal detected in AI content output: ${filePath}`);
|
|
3962
4401
|
}
|
|
3963
|
-
|
|
3964
|
-
|
|
4402
|
+
return absolutePath;
|
|
4403
|
+
};
|
|
4404
|
+
const previousFiles = await readGeneratedRecord(absoluteOutputDir);
|
|
4405
|
+
const currentFiles = [...result.files.keys()];
|
|
4406
|
+
await writeGeneratedRecord(absoluteOutputDir, [.../* @__PURE__ */ new Set([...previousFiles, ...currentFiles])]);
|
|
4407
|
+
let fileCount = 0;
|
|
4408
|
+
for (const [filePath, content] of result.files) {
|
|
4409
|
+
const absolutePath = resolveOutputPath(filePath);
|
|
4410
|
+
await fs17.mkdir(path19.dirname(absolutePath), { recursive: true });
|
|
4411
|
+
await fs17.writeFile(absolutePath, content, "utf-8");
|
|
3965
4412
|
fileCount++;
|
|
3966
4413
|
}
|
|
3967
|
-
|
|
4414
|
+
const currentSet = new Set(currentFiles);
|
|
4415
|
+
const stale = previousFiles.filter((filePath) => !currentSet.has(filePath));
|
|
4416
|
+
let removedCount = 0;
|
|
4417
|
+
for (const filePath of stale) {
|
|
4418
|
+
const absolutePath = resolveOutputPath(filePath);
|
|
4419
|
+
try {
|
|
4420
|
+
await fs17.unlink(absolutePath);
|
|
4421
|
+
removedCount++;
|
|
4422
|
+
} catch (err) {
|
|
4423
|
+
if (!isNodeError3(err) || err.code !== "ENOENT")
|
|
4424
|
+
throw err;
|
|
4425
|
+
}
|
|
4426
|
+
await removeEmptyDirsUpward(path19.dirname(absolutePath), absoluteOutputDir);
|
|
4427
|
+
}
|
|
4428
|
+
await writeGeneratedRecord(absoluteOutputDir, currentFiles);
|
|
4429
|
+
return { fileCount, removedCount, outputDir: absoluteOutputDir };
|
|
3968
4430
|
}
|
|
3969
4431
|
async function generateAIContentCLI(options) {
|
|
3970
4432
|
const { projectDir, outputDir = "public/ai", configPath, appDir = "app" } = options;
|
|
3971
4433
|
console.log("\nCanopyCMS generate-ai-content\n");
|
|
3972
|
-
const canopyConfigPath =
|
|
4434
|
+
const canopyConfigPath = path20.join(projectDir, "canopycms.config.ts");
|
|
3973
4435
|
let canopyConfigModule;
|
|
3974
4436
|
try {
|
|
3975
4437
|
canopyConfigModule = await jiti.import(canopyConfigPath);
|
|
@@ -3980,7 +4442,7 @@ async function generateAIContentCLI(options) {
|
|
|
3980
4442
|
}
|
|
3981
4443
|
const configExport = canopyConfigModule.default ?? canopyConfigModule.config ?? canopyConfigModule;
|
|
3982
4444
|
const serverConfig = typeof configExport === "object" && configExport !== null && "server" in configExport ? configExport.server : configExport;
|
|
3983
|
-
const schemasPath =
|
|
4445
|
+
const schemasPath = path20.join(projectDir, appDir, "schemas.ts");
|
|
3984
4446
|
let entrySchemaRegistry = {};
|
|
3985
4447
|
try {
|
|
3986
4448
|
const schemasModule = await jiti.import(schemasPath);
|
|
@@ -3991,7 +4453,7 @@ async function generateAIContentCLI(options) {
|
|
|
3991
4453
|
let aiConfig2;
|
|
3992
4454
|
if (configPath) {
|
|
3993
4455
|
try {
|
|
3994
|
-
const aiConfigModule = await jiti.import(
|
|
4456
|
+
const aiConfigModule = await jiti.import(path20.resolve(configPath));
|
|
3995
4457
|
aiConfig2 = aiConfigModule.aiContentConfig ?? aiConfigModule.default ?? aiConfigModule.config;
|
|
3996
4458
|
} catch (err) {
|
|
3997
4459
|
console.error(`Could not load AI config from ${configPath}`);
|
|
@@ -4008,7 +4470,7 @@ async function generateAIContentCLI(options) {
|
|
|
4008
4470
|
console.error("Make sure canopycms.config.ts uses defineCanopyConfig().");
|
|
4009
4471
|
process.exit(1);
|
|
4010
4472
|
}
|
|
4011
|
-
const resolvedOutput =
|
|
4473
|
+
const resolvedOutput = path20.resolve(projectDir, outputDir);
|
|
4012
4474
|
console.log(` Output: ${resolvedOutput}`);
|
|
4013
4475
|
console.log(` Mode: ${serverConfig.mode ?? "dev"}`);
|
|
4014
4476
|
const result = await generateAIContentFiles({
|
|
@@ -4019,10 +4481,13 @@ async function generateAIContentCLI(options) {
|
|
|
4019
4481
|
});
|
|
4020
4482
|
console.log(`
|
|
4021
4483
|
Generated ${result.fileCount} files`);
|
|
4484
|
+
if (result.removedCount > 0) {
|
|
4485
|
+
console.log(` Removed ${result.removedCount} stale files from the previous run`);
|
|
4486
|
+
}
|
|
4022
4487
|
console.log(` Output: ${result.outputDir}
|
|
4023
4488
|
`);
|
|
4024
4489
|
}
|
|
4025
|
-
var __defProp3, __getOwnPropNames3, __esm3, __export3,
|
|
4490
|
+
var __defProp3, __getOwnPropNames3, __esm3, __export3, active2, init_logger2, init_normalize2, ROOT_COLLECTION_ID, init_types3, normalizePathValue, flattenSchema, init_flatten2, primitiveFieldTypes2, fieldTypes2, init_types22, fieldBaseSchema2, selectOptionSchema2, referenceOptionSchema2, primitiveFieldSchema2, ASPECT_RATIO_RE2, imageFieldSchema2, selectFieldSchema2, referenceFieldSchema2, fieldHolder2, blockSchema2, blockFieldSchema2, objectFieldSchema2, inlineGroupFieldSchema2, customFieldSchema2, knownFieldSchema2, fieldSchema2, init_field2, relativePathSchema2, entryTypeSchema2, collectionSchema2, init_collection2, mediaSchema2, init_media2, defaultBranchAccessSchema2, defaultPathAccessLevelSchema2, defaultPathAccessLevelsSchema2, defaultPathAccessSchema2, defaultBaseBranchSchema2, defaultRemoteNameSchema2, defaultRemoteUrlSchema2, gitBotAuthorNameSchema2, gitBotAuthorEmailSchema2, githubTokenEnvVarSchema2, operatingModeSchema2, deployedAsSchema2, contentRootSchema2, sourceRootSchema2, basePathSchema2, deploymentNameSchema2, devContentSyncSchema2, devConfigSchema2, editorConfigSchema2, CanopyConfigSchema2, DEFAULT_PROD_WORKSPACE2, init_config3, SERVER_MODE_ENV_VAR, BROWSER_MODE_ENV_VAR, warned2, init_mode_env2, forEachReferenceField, init_validation2, ProdClientSafeStrategy2, DevClientSafeStrategy2, clientStrategyCache, init_client_safe_strategy, warned22, VALID_DEPLOYMENT_NAME2, isValidDeploymentName2, init_deployment_name, permissionTargetSchema2, pathPermissionSchema2, init_permissions2, init_helpers2, init_config22, ProdStrategy2, DevStrategy2, strategyCache2, init_client_unsafe_strategy, operating_mode_exports, init_operating_mode, BLOCK_DISCRIMINATOR_KEYS, BLOCK_STRUCTURAL_KEYS, EVIDENCE_MAX_DEPTH, locks, META_DIR, CONTENT_WRITE_LOCK_NAME, DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS, ContentWriteLockBusyError, sleep, DEFAULT_SEO_FIELD_NAMES, SEO_GROUP_FIELDS, BASE58_PATTERN, CONTENT_ID_PATTERN, PHYSICAL_SEGMENT_PATTERN, isValidId, EMPTY_LOGICAL_PATH, ContentIdIndex, parseTypedFilename, CONTENT_EXTENSIONS, registry, finalization, LOG_LEVELS2, DebugLogger2, testLogger2, log2, META_DIR2, entryTypeMetaSchema, collectionMetaSchema, rootCollectionMetaSchema, editDistance, closestName, forEachEntryType, collectEntryTypeNames, validateReferenceEntryTypes, isDeployedStatic, isBuildMode, STATIC_DEPLOY_USER, SCHEMA_CACHE_VERSION, MTIME_CHECK_DEBOUNCE_MS, SCHEMA_GENERATION_RESOURCE, BranchSchemaCache, RESOURCE, getFormatExtension, isDataOnlyFormat, asRecord, BranchPathError, resolveContentBranchesRoot, ContentStoreError, ContentConflictError, BranchSyncingError, DuplicateContentIdError, UrlPathConflictError, DEFAULT_INDEX_FRESHNESS_INTERVAL_MS, FORCED_REFRESH_MIN_INTERVAL_MS, STALE_LOOKUP, createReferenceResolveCache, ContentStore, ATTR_CONTENT, BLOCK_PREFIX, BLOCK_SUFFIX, BLOCK_RESTORE_RE, INLINE_PREFIX, INLINE_SUFFIX, INLINE_RESTORE_RE, FLAT_CELL_TYPES, log22, BASE58_CHAR, ENTRY_LINK_PATTERN, log3, REGISTRY_FILE, REGISTRY_STALE_FILE, REGISTRY_TEMP_FILE, REGISTRY_VERSION, RESOURCE2, GET_MISS_REFRESH_MIN_INTERVAL_MS, BranchRegistry, log4, OccWriteConflictError, BRANCH_META_DIR, BRANCH_META_FILE, CURRENT_SCHEMA_VERSION, BranchMetadataConflictError, BranchMetadataCorruptError, BranchMetadataFileManager, getBranchMetadataFileManager, loadBranchContext, NETWORK_SCHEME_PATTERN, TRANSPORT_HELPER_PATTERN, LEADING_OPTION_PATTERN, WINDOWS_DRIVE_PATTERN, COLON_BEFORE_SLASH_PATTERN, MISSING_REMOTE_REF_REASONS, log5, GIT_ENV_PASSTHROUGH, FORCE_C_LOCALE, remoteInitLocks, GITHUB_TRACKING_REF_PREFIX, GitConflictError, GitRemoteRefMissingError, GitManager, log6, workspaceInitLocks, BranchWorkspaceManager, log7, normalizePath, readEntryData, createReferenceResolver, resolveCollectionItemReferences, looksLikeMalformedEntry, listCollectionEntries, MAX_INPUT_PIXELS, KNOWN_FIELD_TYPES, STRING_FIELD_TYPES, selectOptionValues, GENERATED_RECORD_FILENAME, jiti;
|
|
4026
4491
|
var init_generate_ai_content = __esm({
|
|
4027
4492
|
"dist/cli/generate-ai-content.js"() {
|
|
4028
4493
|
"use strict";
|
|
@@ -4035,17 +4500,17 @@ var init_generate_ai_content = __esm({
|
|
|
4035
4500
|
for (var name in all)
|
|
4036
4501
|
__defProp3(target, name, { get: all[name], enumerable: true });
|
|
4037
4502
|
};
|
|
4038
|
-
init_normalize2 = __esm3({
|
|
4039
|
-
"dist/paths/normalize.js"() {
|
|
4040
|
-
"use strict";
|
|
4041
|
-
}
|
|
4042
|
-
});
|
|
4043
4503
|
init_logger2 = __esm3({
|
|
4044
4504
|
"dist/utils/logger.js"() {
|
|
4045
4505
|
"use strict";
|
|
4046
4506
|
active2 = console;
|
|
4047
4507
|
}
|
|
4048
4508
|
});
|
|
4509
|
+
init_normalize2 = __esm3({
|
|
4510
|
+
"dist/paths/normalize.js"() {
|
|
4511
|
+
"use strict";
|
|
4512
|
+
}
|
|
4513
|
+
});
|
|
4049
4514
|
init_types3 = __esm3({
|
|
4050
4515
|
"dist/paths/types.js"() {
|
|
4051
4516
|
"use strict";
|
|
@@ -4219,7 +4684,12 @@ var init_generate_ai_content = __esm({
|
|
|
4219
4684
|
collections: z22.array(z22.string().min(1)).min(1).optional(),
|
|
4220
4685
|
entryTypes: z22.array(z22.string().min(1)).min(1).optional(),
|
|
4221
4686
|
displayField: z22.string().min(1).optional(),
|
|
4222
|
-
options: z22.array(referenceOptionSchema2).optional()
|
|
4687
|
+
options: z22.array(referenceOptionSchema2).optional(),
|
|
4688
|
+
// Must be listed here, not just on ReferenceFieldConfig: zod strips unknown keys by
|
|
4689
|
+
// default, so a consumer that adopts this schema's parse output would silently delete a
|
|
4690
|
+
// runtime-consumed flag and the feature would no-op with no error. (`resolvedSchema` is
|
|
4691
|
+
// absent on purpose — it is type-inference-only and stripping it changes no behavior.)
|
|
4692
|
+
includeBody: z22.boolean().optional()
|
|
4223
4693
|
});
|
|
4224
4694
|
fieldHolder2 = [z22.never()];
|
|
4225
4695
|
blockSchema2 = z22.object({
|
|
@@ -4340,6 +4810,9 @@ var init_generate_ai_content = __esm({
|
|
|
4340
4810
|
deployedAsSchema2 = z52.enum(["static", "server"]).default("server");
|
|
4341
4811
|
contentRootSchema2 = relativePathSchema2.default("content");
|
|
4342
4812
|
sourceRootSchema2 = z52.string().min(1).optional();
|
|
4813
|
+
basePathSchema2 = z52.string().transform((value) => value.trim()).refine((value) => value.length > 0, {
|
|
4814
|
+
message: "basePath must not be empty or only whitespace"
|
|
4815
|
+
}).optional();
|
|
4343
4816
|
deploymentNameSchema2 = z52.string().default("prod");
|
|
4344
4817
|
devContentSyncSchema2 = z52.enum(["off", "warn"]).default("warn");
|
|
4345
4818
|
devConfigSchema2 = z52.object({
|
|
@@ -4402,6 +4875,7 @@ var init_generate_ai_content = __esm({
|
|
|
4402
4875
|
deploymentName: deploymentNameSchema2.optional(),
|
|
4403
4876
|
contentRoot: contentRootSchema2.default("content"),
|
|
4404
4877
|
sourceRoot: sourceRootSchema2.optional(),
|
|
4878
|
+
basePath: basePathSchema2,
|
|
4405
4879
|
editor: editorConfigSchema2.optional(),
|
|
4406
4880
|
authPlugin: z52.custom().optional(),
|
|
4407
4881
|
entryLinkUrl: z52.custom().optional(),
|
|
@@ -4571,32 +5045,32 @@ var init_generate_ai_content = __esm({
|
|
|
4571
5045
|
// - shouldCommit(), shouldPush()
|
|
4572
5046
|
// Add client-unsafe methods (use Node.js APIs)
|
|
4573
5047
|
getWorkspaceRoot(_sourceRoot) {
|
|
4574
|
-
return
|
|
5048
|
+
return path9.resolve(process.env.CANOPYCMS_WORKSPACE_ROOT ?? DEFAULT_PROD_WORKSPACE2);
|
|
4575
5049
|
}
|
|
4576
5050
|
getContentRoot(contentRoot, sourceRoot) {
|
|
4577
|
-
return
|
|
5051
|
+
return path9.resolve(sourceRoot ?? process.cwd(), contentRoot);
|
|
4578
5052
|
}
|
|
4579
5053
|
getContentBranchesRoot(sourceRoot) {
|
|
4580
|
-
return
|
|
5054
|
+
return path9.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
|
|
4581
5055
|
}
|
|
4582
5056
|
getContentBranchRoot(branchName, sourceRoot) {
|
|
4583
|
-
return
|
|
5057
|
+
return path9.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
|
|
4584
5058
|
}
|
|
4585
5059
|
getGitExcludePattern() {
|
|
4586
5060
|
return ".canopy-meta/";
|
|
4587
5061
|
}
|
|
4588
5062
|
getPermissionsFilePath(root) {
|
|
4589
|
-
return
|
|
5063
|
+
return path9.join(root, this.getPermissionsFileName());
|
|
4590
5064
|
}
|
|
4591
5065
|
getGroupsFilePath(root) {
|
|
4592
|
-
return
|
|
5066
|
+
return path9.join(root, this.getGroupsFileName());
|
|
4593
5067
|
}
|
|
4594
5068
|
getRemoteUrlConfig() {
|
|
4595
5069
|
return {
|
|
4596
5070
|
shouldAutoInitLocal: false,
|
|
4597
5071
|
defaultRemotePath: "",
|
|
4598
5072
|
envVarName: "CANOPYCMS_REMOTE_URL",
|
|
4599
|
-
autoDetectRemotePath:
|
|
5073
|
+
autoDetectRemotePath: path9.join(this.getWorkspaceRoot(), "remote.git")
|
|
4600
5074
|
};
|
|
4601
5075
|
}
|
|
4602
5076
|
requiresExistingRepo() {
|
|
@@ -4608,7 +5082,7 @@ var init_generate_ai_content = __esm({
|
|
|
4608
5082
|
return `canopycms-settings-${resolveDeploymentName2(config, "prod")}`;
|
|
4609
5083
|
}
|
|
4610
5084
|
getSettingsRoot(sourceRoot) {
|
|
4611
|
-
return
|
|
5085
|
+
return path9.join(this.getWorkspaceRoot(sourceRoot), "settings");
|
|
4612
5086
|
}
|
|
4613
5087
|
usesSeparateSettingsBranch() {
|
|
4614
5088
|
return true;
|
|
@@ -4625,25 +5099,25 @@ var init_generate_ai_content = __esm({
|
|
|
4625
5099
|
DevStrategy2 = class extends DevClientSafeStrategy2 {
|
|
4626
5100
|
// Inherits client-safe methods from DevClientSafeStrategy
|
|
4627
5101
|
getWorkspaceRoot(sourceRoot) {
|
|
4628
|
-
return
|
|
5102
|
+
return path9.resolve(sourceRoot ?? process.cwd(), ".canopy-dev");
|
|
4629
5103
|
}
|
|
4630
5104
|
getContentRoot(contentRoot, sourceRoot) {
|
|
4631
|
-
return
|
|
5105
|
+
return path9.resolve(sourceRoot ?? process.cwd(), contentRoot);
|
|
4632
5106
|
}
|
|
4633
5107
|
getContentBranchesRoot(sourceRoot) {
|
|
4634
|
-
return
|
|
5108
|
+
return path9.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
|
|
4635
5109
|
}
|
|
4636
5110
|
getContentBranchRoot(branchName, sourceRoot) {
|
|
4637
|
-
return
|
|
5111
|
+
return path9.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
|
|
4638
5112
|
}
|
|
4639
5113
|
getGitExcludePattern() {
|
|
4640
5114
|
return ".canopy-meta/";
|
|
4641
5115
|
}
|
|
4642
5116
|
getPermissionsFilePath(root) {
|
|
4643
|
-
return
|
|
5117
|
+
return path9.join(root, this.getPermissionsFileName());
|
|
4644
5118
|
}
|
|
4645
5119
|
getGroupsFilePath(root) {
|
|
4646
|
-
return
|
|
5120
|
+
return path9.join(root, this.getGroupsFileName());
|
|
4647
5121
|
}
|
|
4648
5122
|
getRemoteUrlConfig() {
|
|
4649
5123
|
return {
|
|
@@ -4661,7 +5135,7 @@ var init_generate_ai_content = __esm({
|
|
|
4661
5135
|
return `canopycms-settings-${resolveDeploymentName2(config, "local")}`;
|
|
4662
5136
|
}
|
|
4663
5137
|
getSettingsRoot(sourceRoot) {
|
|
4664
|
-
return
|
|
5138
|
+
return path9.join(this.getWorkspaceRoot(sourceRoot), "settings");
|
|
4665
5139
|
}
|
|
4666
5140
|
usesSeparateSettingsBranch() {
|
|
4667
5141
|
return true;
|
|
@@ -4696,7 +5170,12 @@ var init_generate_ai_content = __esm({
|
|
|
4696
5170
|
init_mode_env2();
|
|
4697
5171
|
}
|
|
4698
5172
|
});
|
|
5173
|
+
BLOCK_DISCRIMINATOR_KEYS = ["template", "_type"];
|
|
5174
|
+
BLOCK_STRUCTURAL_KEYS = new Set(BLOCK_DISCRIMINATOR_KEYS);
|
|
5175
|
+
EVIDENCE_MAX_DEPTH = 6;
|
|
4699
5176
|
locks = /* @__PURE__ */ new Map();
|
|
5177
|
+
init_logger2();
|
|
5178
|
+
init_logger2();
|
|
4700
5179
|
META_DIR = ".canopy-meta";
|
|
4701
5180
|
CONTENT_WRITE_LOCK_NAME = "content-write.lock";
|
|
4702
5181
|
DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS = 2e3;
|
|
@@ -4709,6 +5188,67 @@ var init_generate_ai_content = __esm({
|
|
|
4709
5188
|
sleep = (ms) => new Promise((resolve2) => {
|
|
4710
5189
|
setTimeout(resolve2, ms);
|
|
4711
5190
|
});
|
|
5191
|
+
DEFAULT_SEO_FIELD_NAMES = {
|
|
5192
|
+
title: "metaTitle",
|
|
5193
|
+
description: "metaDescription",
|
|
5194
|
+
ogImage: "ogImage",
|
|
5195
|
+
ogType: "ogType",
|
|
5196
|
+
canonical: "canonical",
|
|
5197
|
+
noindex: "noindex",
|
|
5198
|
+
twitterCard: "twitterCard"
|
|
5199
|
+
};
|
|
5200
|
+
SEO_GROUP_FIELDS = [
|
|
5201
|
+
{
|
|
5202
|
+
name: DEFAULT_SEO_FIELD_NAMES.title,
|
|
5203
|
+
type: "string",
|
|
5204
|
+
label: "Meta Title",
|
|
5205
|
+
description: "Overrides the page title in search results and social cards.",
|
|
5206
|
+
required: false
|
|
5207
|
+
},
|
|
5208
|
+
{
|
|
5209
|
+
name: DEFAULT_SEO_FIELD_NAMES.description,
|
|
5210
|
+
type: "string",
|
|
5211
|
+
label: "Meta Description",
|
|
5212
|
+
description: "Summary shown under the title in search results.",
|
|
5213
|
+
required: false
|
|
5214
|
+
},
|
|
5215
|
+
{
|
|
5216
|
+
name: DEFAULT_SEO_FIELD_NAMES.ogImage,
|
|
5217
|
+
type: "string",
|
|
5218
|
+
label: "Social Image URL",
|
|
5219
|
+
description: "Image for social cards. Site-relative or absolute.",
|
|
5220
|
+
required: false
|
|
5221
|
+
},
|
|
5222
|
+
{
|
|
5223
|
+
name: DEFAULT_SEO_FIELD_NAMES.ogType,
|
|
5224
|
+
type: "select",
|
|
5225
|
+
label: "OpenGraph Type",
|
|
5226
|
+
options: ["website", "article", "profile"],
|
|
5227
|
+
required: false
|
|
5228
|
+
},
|
|
5229
|
+
{
|
|
5230
|
+
name: DEFAULT_SEO_FIELD_NAMES.canonical,
|
|
5231
|
+
type: "string",
|
|
5232
|
+
label: "Canonical URL",
|
|
5233
|
+
description: "Set only to point at a different canonical copy of this page.",
|
|
5234
|
+
required: false
|
|
5235
|
+
},
|
|
5236
|
+
{
|
|
5237
|
+
name: DEFAULT_SEO_FIELD_NAMES.noindex,
|
|
5238
|
+
type: "boolean",
|
|
5239
|
+
label: "Hide from search engines",
|
|
5240
|
+
description: "Marks the page noindex AND drops it from the sitemap.",
|
|
5241
|
+
required: false
|
|
5242
|
+
},
|
|
5243
|
+
{
|
|
5244
|
+
name: DEFAULT_SEO_FIELD_NAMES.twitterCard,
|
|
5245
|
+
type: "select",
|
|
5246
|
+
label: "Twitter Card",
|
|
5247
|
+
options: ["summary", "summary_large_image"],
|
|
5248
|
+
required: false
|
|
5249
|
+
}
|
|
5250
|
+
];
|
|
5251
|
+
init_normalize2();
|
|
4712
5252
|
init_normalize2();
|
|
4713
5253
|
BASE58_PATTERN = "[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]";
|
|
4714
5254
|
CONTENT_ID_PATTERN = new RegExp(`^${BASE58_PATTERN}{12}$`);
|
|
@@ -5026,6 +5566,31 @@ var init_generate_ai_content = __esm({
|
|
|
5026
5566
|
this.pathToId.set(newRelativePath, id);
|
|
5027
5567
|
}
|
|
5028
5568
|
};
|
|
5569
|
+
parseTypedFilename = (filename, entryTypes) => {
|
|
5570
|
+
if (filename.startsWith("."))
|
|
5571
|
+
return null;
|
|
5572
|
+
const lastDot = filename.lastIndexOf(".");
|
|
5573
|
+
if (lastDot === -1)
|
|
5574
|
+
return null;
|
|
5575
|
+
const nameWithoutExt = filename.slice(0, lastDot);
|
|
5576
|
+
const parts = nameWithoutExt.split(".");
|
|
5577
|
+
if (parts.length < 3)
|
|
5578
|
+
return null;
|
|
5579
|
+
const potentialType = parts[0];
|
|
5580
|
+
if (entryTypes && !entryTypes.some((e) => e.name === potentialType)) {
|
|
5581
|
+
return null;
|
|
5582
|
+
}
|
|
5583
|
+
const id = parts[parts.length - 1];
|
|
5584
|
+
if (!isValidId(id))
|
|
5585
|
+
return null;
|
|
5586
|
+
const slug = parts.slice(1, -1).join(".").toLowerCase();
|
|
5587
|
+
return {
|
|
5588
|
+
type: potentialType,
|
|
5589
|
+
slug,
|
|
5590
|
+
id
|
|
5591
|
+
};
|
|
5592
|
+
};
|
|
5593
|
+
CONTENT_EXTENSIONS = [".md", ".mdx", ".json", ".yaml"];
|
|
5029
5594
|
registry = /* @__PURE__ */ new Map();
|
|
5030
5595
|
finalization = new FinalizationRegistry(({ rootKey, ref }) => {
|
|
5031
5596
|
const refs = registry.get(rootKey);
|
|
@@ -5263,7 +5828,7 @@ var init_generate_ai_content = __esm({
|
|
|
5263
5828
|
* the project root, regardless of which entrypoint produced the cwd branchRoot.
|
|
5264
5829
|
*/
|
|
5265
5830
|
skipDiskCache(branchRoot) {
|
|
5266
|
-
return isBuildMode() ||
|
|
5831
|
+
return isBuildMode() || path82.resolve(branchRoot) === path82.resolve(process.cwd());
|
|
5267
5832
|
}
|
|
5268
5833
|
/**
|
|
5269
5834
|
* Get schema for a branch (loads from cache or resolves fresh).
|
|
@@ -5289,14 +5854,14 @@ var init_generate_ai_content = __esm({
|
|
|
5289
5854
|
* Load schema from cache or resolve fresh if cache is missing or stale.
|
|
5290
5855
|
*/
|
|
5291
5856
|
async loadFromCacheOrResolve(branchRoot, entrySchemaRegistry, contentRootName) {
|
|
5292
|
-
const contentRoot =
|
|
5857
|
+
const contentRoot = path82.join(branchRoot, contentRootName);
|
|
5293
5858
|
const skipDiskCache = this.skipDiskCache(branchRoot);
|
|
5294
5859
|
if (!skipDiskCache) {
|
|
5295
|
-
const cacheDir =
|
|
5296
|
-
const cachePath =
|
|
5860
|
+
const cacheDir = path82.join(branchRoot, ".canopy-meta");
|
|
5861
|
+
const cachePath = path82.join(cacheDir, "schema-cache.json");
|
|
5297
5862
|
let cacheData = null;
|
|
5298
5863
|
try {
|
|
5299
|
-
const cacheContent = await
|
|
5864
|
+
const cacheContent = await fs72.readFile(cachePath, "utf-8");
|
|
5300
5865
|
cacheData = JSON.parse(cacheContent);
|
|
5301
5866
|
} catch {
|
|
5302
5867
|
cacheData = null;
|
|
@@ -5333,7 +5898,7 @@ var init_generate_ai_content = __esm({
|
|
|
5333
5898
|
*/
|
|
5334
5899
|
async resolveFreshAndPersist(branchRoot, entrySchemaRegistry, contentRootName, options) {
|
|
5335
5900
|
const { skipDiskCache } = options;
|
|
5336
|
-
const contentRoot =
|
|
5901
|
+
const contentRoot = path82.join(branchRoot, contentRootName);
|
|
5337
5902
|
const read = skipDiskCache ? null : await readResourceGeneration(branchRoot, SCHEMA_GENERATION_RESOURCE);
|
|
5338
5903
|
const result = await this.resolveFresh(contentRoot, entrySchemaRegistry);
|
|
5339
5904
|
if (!isValidSchema(result.schema)) {
|
|
@@ -5346,9 +5911,9 @@ var init_generate_ai_content = __esm({
|
|
|
5346
5911
|
}
|
|
5347
5912
|
const flatSchema = flattenSchema(result.schema, contentRootName);
|
|
5348
5913
|
if (!skipDiskCache) {
|
|
5349
|
-
const cacheDir =
|
|
5350
|
-
const cachePath =
|
|
5351
|
-
await
|
|
5914
|
+
const cacheDir = path82.join(branchRoot, ".canopy-meta");
|
|
5915
|
+
const cachePath = path82.join(cacheDir, "schema-cache.json");
|
|
5916
|
+
await fs72.unlink(path82.join(cacheDir, "schema-cache.stale")).catch(() => {
|
|
5352
5917
|
});
|
|
5353
5918
|
if (read && read.ok) {
|
|
5354
5919
|
const newCache = {
|
|
@@ -5358,13 +5923,13 @@ var init_generate_ai_content = __esm({
|
|
|
5358
5923
|
cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5359
5924
|
generation: read.token
|
|
5360
5925
|
};
|
|
5361
|
-
await
|
|
5362
|
-
const tmpPath =
|
|
5363
|
-
await
|
|
5926
|
+
await fs72.mkdir(cacheDir, { recursive: true });
|
|
5927
|
+
const tmpPath = path82.join(cacheDir, `schema-cache.tmp.${Date.now()}.${Math.random()}.json`);
|
|
5928
|
+
await fs72.writeFile(tmpPath, JSON.stringify(newCache, null, 2), "utf-8");
|
|
5364
5929
|
try {
|
|
5365
|
-
await
|
|
5930
|
+
await fs72.rename(tmpPath, cachePath);
|
|
5366
5931
|
} catch (err) {
|
|
5367
|
-
await
|
|
5932
|
+
await fs72.unlink(tmpPath).catch(() => {
|
|
5368
5933
|
});
|
|
5369
5934
|
throw err;
|
|
5370
5935
|
}
|
|
@@ -5474,9 +6039,17 @@ var init_generate_ai_content = __esm({
|
|
|
5474
6039
|
this.paths = sorted;
|
|
5475
6040
|
}
|
|
5476
6041
|
};
|
|
6042
|
+
UrlPathConflictError = class extends ContentConflictError {
|
|
6043
|
+
constructor(message, conflictingPath) {
|
|
6044
|
+
super(message);
|
|
6045
|
+
this.name = "UrlPathConflictError";
|
|
6046
|
+
this.conflictingPath = conflictingPath;
|
|
6047
|
+
}
|
|
6048
|
+
};
|
|
5477
6049
|
DEFAULT_INDEX_FRESHNESS_INTERVAL_MS = 1e3;
|
|
5478
6050
|
FORCED_REFRESH_MIN_INTERVAL_MS = 5e3;
|
|
5479
6051
|
STALE_LOOKUP = Symbol("stale-index-lookup");
|
|
6052
|
+
createReferenceResolveCache = () => /* @__PURE__ */ new Map();
|
|
5480
6053
|
ContentStore = class {
|
|
5481
6054
|
constructor(root, flatSchema, options = {}) {
|
|
5482
6055
|
this.indexGeneration = 0;
|
|
@@ -5485,7 +6058,7 @@ var init_generate_ai_content = __esm({
|
|
|
5485
6058
|
this.lastDiskProbeMs = 0;
|
|
5486
6059
|
this.lastForcedRefreshMs = 0;
|
|
5487
6060
|
this.indexBuild = null;
|
|
5488
|
-
this.root =
|
|
6061
|
+
this.root = path11.resolve(root);
|
|
5489
6062
|
this.contentRootName = options.contentRootName || "content";
|
|
5490
6063
|
this.indexFreshnessIntervalMs = options.indexFreshnessIntervalMs ?? DEFAULT_INDEX_FRESHNESS_INTERVAL_MS;
|
|
5491
6064
|
this.contentWriteLockWaitMs = options.contentWriteLockWaitMs ?? DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS;
|
|
@@ -5633,7 +6206,7 @@ var init_generate_ai_content = __esm({
|
|
|
5633
6206
|
async findEntryPathsById(dir, id) {
|
|
5634
6207
|
let entries;
|
|
5635
6208
|
try {
|
|
5636
|
-
entries = await
|
|
6209
|
+
entries = await fs10.readdir(dir, { withFileTypes: true });
|
|
5637
6210
|
} catch (err) {
|
|
5638
6211
|
if (isNodeError3(err) && err.code === "ENOENT")
|
|
5639
6212
|
return [];
|
|
@@ -5644,7 +6217,7 @@ var init_generate_ai_content = __esm({
|
|
|
5644
6217
|
if (entry.isDirectory())
|
|
5645
6218
|
continue;
|
|
5646
6219
|
if (extractIdFromFilename(entry.name) === id) {
|
|
5647
|
-
matches.push(
|
|
6220
|
+
matches.push(path11.relative(this.root, path11.join(dir, entry.name)));
|
|
5648
6221
|
}
|
|
5649
6222
|
}
|
|
5650
6223
|
return matches.sort();
|
|
@@ -5656,11 +6229,11 @@ var init_generate_ai_content = __esm({
|
|
|
5656
6229
|
getSchemaItems() {
|
|
5657
6230
|
return this.schemaIndex.values();
|
|
5658
6231
|
}
|
|
5659
|
-
assertSchemaItem(
|
|
5660
|
-
const normalized = normalizeFilesystemPath(
|
|
6232
|
+
assertSchemaItem(path212) {
|
|
6233
|
+
const normalized = normalizeFilesystemPath(path212);
|
|
5661
6234
|
const item = this.schemaIndex.get(normalized);
|
|
5662
6235
|
if (!item) {
|
|
5663
|
-
throw new ContentStoreError(`Unknown schema item: ${
|
|
6236
|
+
throw new ContentStoreError(`Unknown schema item: ${path212}`, "NO_SCHEMA_ITEM");
|
|
5664
6237
|
}
|
|
5665
6238
|
return item;
|
|
5666
6239
|
}
|
|
@@ -5727,6 +6300,26 @@ var init_generate_ai_content = __esm({
|
|
|
5727
6300
|
return this.createLockKey(schemaItem, slug);
|
|
5728
6301
|
return prePass.id ? this.idLockKey(prePass.id) : prePass.absolutePath;
|
|
5729
6302
|
}
|
|
6303
|
+
/**
|
|
6304
|
+
* Refuse a create/rename that would give a second entry a `urlPath` another entry already
|
|
6305
|
+
* holds. See url-collision.ts for the two shapes that count, and the legitimate
|
|
6306
|
+
* landing-page-beside-a-collection shape that deliberately does not.
|
|
6307
|
+
*
|
|
6308
|
+
* @param collectionDir Absolute physical directory the entry will live in.
|
|
6309
|
+
* @param slug The entry's slug, as it will be written.
|
|
6310
|
+
*/
|
|
6311
|
+
async assertUrlPathAvailable(collectionDir, slug) {
|
|
6312
|
+
const claimant = await findUrlPathClaimant({
|
|
6313
|
+
collectionDir,
|
|
6314
|
+
slug,
|
|
6315
|
+
contentRoot: path11.resolve(this.root, this.contentRootName)
|
|
6316
|
+
});
|
|
6317
|
+
if (!claimant)
|
|
6318
|
+
return;
|
|
6319
|
+
const relative2 = path11.relative(this.root, claimant.physicalPath);
|
|
6320
|
+
const message = claimant.kind === "sibling-collection-index" ? `An entry with slug "${slug}" would share a URL with the index entry of the "${claimant.name}" collection beside it ("${relative2}"), and only one of them could be served there. Rename this entry, or remove that collection's index entry.` : `An index entry here would share a URL with the "${claimant.name}" entry in the parent collection ("${relative2}"), and only one of them could be served there. Rename that entry, or give this collection's landing page a different slug.`;
|
|
6321
|
+
throw new UrlPathConflictError(message, claimant.physicalPath);
|
|
6322
|
+
}
|
|
5730
6323
|
/**
|
|
5731
6324
|
* Build absolute and relative paths with security validation.
|
|
5732
6325
|
* All entries use the unified filename pattern: {type}.{slug}.{id}.{ext}
|
|
@@ -5743,7 +6336,7 @@ var init_generate_ai_content = __esm({
|
|
|
5743
6336
|
* @param options.entryTypeName - For collections with multiple entry types, specify which one to use. Defaults to the default entry type.
|
|
5744
6337
|
*/
|
|
5745
6338
|
async buildPaths(schemaItem, slug, options = {}) {
|
|
5746
|
-
const rootWithSep = this.root.endsWith(
|
|
6339
|
+
const rootWithSep = this.root.endsWith(path11.sep) ? this.root : `${this.root}${path11.sep}`;
|
|
5747
6340
|
if (schemaItem.type === "entry-type") {
|
|
5748
6341
|
const parentPath = schemaItem.parentPath || "";
|
|
5749
6342
|
const parentCollection = this.schemaIndex.get(parentPath);
|
|
@@ -5776,7 +6369,7 @@ var init_generate_ai_content = __esm({
|
|
|
5776
6369
|
const entryTypeName = entryTypeConfig?.name || "entry";
|
|
5777
6370
|
let collectionRoot = await resolveCollectionPath(this.root, schemaItem.logicalPath);
|
|
5778
6371
|
if (!collectionRoot) {
|
|
5779
|
-
collectionRoot =
|
|
6372
|
+
collectionRoot = path11.resolve(this.root, schemaItem.logicalPath);
|
|
5780
6373
|
}
|
|
5781
6374
|
if (!collectionRoot.startsWith(rootWithSep)) {
|
|
5782
6375
|
throw new ContentStoreError("Path traversal detected", "VALIDATION");
|
|
@@ -5786,7 +6379,7 @@ var init_generate_ai_content = __esm({
|
|
|
5786
6379
|
let existingEntryType;
|
|
5787
6380
|
let foundExisting = false;
|
|
5788
6381
|
if (!id) {
|
|
5789
|
-
const entries = await
|
|
6382
|
+
const entries = await fs10.readdir(collectionRoot, { withFileTypes: true }).catch(() => []);
|
|
5790
6383
|
const existingFile = entries.find((entry) => {
|
|
5791
6384
|
if (entry.isDirectory())
|
|
5792
6385
|
return false;
|
|
@@ -5812,14 +6405,14 @@ var init_generate_ai_content = __esm({
|
|
|
5812
6405
|
}
|
|
5813
6406
|
filename = `${finalEntryTypeName}.${safeSlug}.${id}${ext}`;
|
|
5814
6407
|
}
|
|
5815
|
-
const resolved =
|
|
5816
|
-
const collectionRootWithSep = collectionRoot.endsWith(
|
|
6408
|
+
const resolved = path11.resolve(collectionRoot, filename);
|
|
6409
|
+
const collectionRootWithSep = collectionRoot.endsWith(path11.sep) ? collectionRoot : `${collectionRoot}${path11.sep}`;
|
|
5817
6410
|
if (!resolved.startsWith(collectionRootWithSep)) {
|
|
5818
6411
|
throw new ContentStoreError("Path traversal detected", "VALIDATION");
|
|
5819
6412
|
}
|
|
5820
6413
|
return {
|
|
5821
6414
|
absolutePath: resolved,
|
|
5822
|
-
relativePath:
|
|
6415
|
+
relativePath: path11.relative(this.root, resolved),
|
|
5823
6416
|
id,
|
|
5824
6417
|
entryTypeName: finalEntryTypeName,
|
|
5825
6418
|
existed
|
|
@@ -5855,8 +6448,8 @@ var init_generate_ai_content = __esm({
|
|
|
5855
6448
|
async read(collectionPath, slug = "", options = {}) {
|
|
5856
6449
|
const schemaItem = this.assertSchemaItem(collectionPath);
|
|
5857
6450
|
const { absolutePath, relativePath, entryTypeName: resolvedEntryTypeName } = await this.buildPaths(schemaItem, slug);
|
|
5858
|
-
const stat = await
|
|
5859
|
-
const raw = await
|
|
6451
|
+
const stat = await fs10.stat(absolutePath);
|
|
6452
|
+
const raw = await fs10.readFile(absolutePath, "utf8");
|
|
5860
6453
|
let doc;
|
|
5861
6454
|
let format;
|
|
5862
6455
|
let fields;
|
|
@@ -5895,7 +6488,7 @@ var init_generate_ai_content = __esm({
|
|
|
5895
6488
|
absolutePath
|
|
5896
6489
|
};
|
|
5897
6490
|
} else {
|
|
5898
|
-
const parsed =
|
|
6491
|
+
const parsed = matter2(raw);
|
|
5899
6492
|
doc = {
|
|
5900
6493
|
collection: schemaItem.logicalPath,
|
|
5901
6494
|
collectionName: schemaItem.name,
|
|
@@ -5958,7 +6551,7 @@ var init_generate_ai_content = __esm({
|
|
|
5958
6551
|
const indexedPath = guardIndex.findById(id)?.relativePath ?? null;
|
|
5959
6552
|
if (indexedPath && indexedPath !== relativePath) {
|
|
5960
6553
|
const quarantined = guardIndex.getDuplicateFor(id);
|
|
5961
|
-
const bothOnDisk = await filePathExists3(absolutePath) && await filePathExists3(
|
|
6554
|
+
const bothOnDisk = await filePathExists3(absolutePath) && await filePathExists3(path11.join(this.root, indexedPath));
|
|
5962
6555
|
if (quarantined || bothOnDisk) {
|
|
5963
6556
|
throw new DuplicateContentIdError(id, [
|
|
5964
6557
|
indexedPath,
|
|
@@ -5969,10 +6562,18 @@ var init_generate_ai_content = __esm({
|
|
|
5969
6562
|
}
|
|
5970
6563
|
}
|
|
5971
6564
|
}
|
|
5972
|
-
await
|
|
6565
|
+
if (!await filePathExists3(absolutePath)) {
|
|
6566
|
+
const chosenSlug = extractSlugFromFilename(path11.basename(absolutePath));
|
|
6567
|
+
const routable = parseSlug(chosenSlug);
|
|
6568
|
+
if (!routable.ok) {
|
|
6569
|
+
throw new ContentStoreError(`Cannot create entry "${chosenSlug}": ${routable.error}. An entry whose slug is not addressable as a URL segment would build and then 404 on every visit.`, "VALIDATION");
|
|
6570
|
+
}
|
|
6571
|
+
await this.assertUrlPathAvailable(path11.dirname(absolutePath), chosenSlug);
|
|
6572
|
+
}
|
|
6573
|
+
await fs10.mkdir(path11.dirname(absolutePath), { recursive: true });
|
|
5973
6574
|
if (input.expectedVersion !== void 0) {
|
|
5974
6575
|
try {
|
|
5975
|
-
const existing = await
|
|
6576
|
+
const existing = await fs10.stat(absolutePath);
|
|
5976
6577
|
if (input.expectedVersion === null) {
|
|
5977
6578
|
throw new ContentConflictError("An entry with this slug already exists");
|
|
5978
6579
|
}
|
|
@@ -5989,7 +6590,7 @@ var init_generate_ai_content = __esm({
|
|
|
5989
6590
|
}
|
|
5990
6591
|
}
|
|
5991
6592
|
if (existingId && !await filePathExists3(absolutePath)) {
|
|
5992
|
-
const actualRelPaths = await this.findEntryPathsById(
|
|
6593
|
+
const actualRelPaths = await this.findEntryPathsById(path11.dirname(absolutePath), existingId);
|
|
5993
6594
|
if (actualRelPaths.length > 1) {
|
|
5994
6595
|
throw new DuplicateContentIdError(existingId, actualRelPaths);
|
|
5995
6596
|
}
|
|
@@ -5999,14 +6600,15 @@ var init_generate_ai_content = __esm({
|
|
|
5999
6600
|
throw new ContentConflictError();
|
|
6000
6601
|
}
|
|
6001
6602
|
}
|
|
6603
|
+
const existingRaw = input.format === "json" ? void 0 : await readFileIfExists(absolutePath);
|
|
6002
6604
|
let content;
|
|
6003
6605
|
if (input.format === "json") {
|
|
6004
6606
|
content = `${JSON.stringify(input.data ?? {}, null, 2)}
|
|
6005
6607
|
`;
|
|
6006
6608
|
} else if (input.format === "yaml") {
|
|
6007
|
-
content =
|
|
6609
|
+
content = serializeYaml(input.data ?? {}, existingRaw);
|
|
6008
6610
|
} else {
|
|
6009
|
-
content =
|
|
6611
|
+
content = serializeFrontmatter(input.body, input.data ?? {}, existingRaw);
|
|
6010
6612
|
}
|
|
6011
6613
|
await atomicWriteFile2(absolutePath, content);
|
|
6012
6614
|
const liveIndex = this._idIndex;
|
|
@@ -6015,7 +6617,7 @@ var init_generate_ai_content = __esm({
|
|
|
6015
6617
|
const existing = liveIndex.findById(id);
|
|
6016
6618
|
if (existing) {
|
|
6017
6619
|
if (existing.relativePath !== relativePath) {
|
|
6018
|
-
staleOldAbsPath =
|
|
6620
|
+
staleOldAbsPath = path11.join(this.root, existing.relativePath);
|
|
6019
6621
|
liveIndex.updatePath(existing.id, relativePath);
|
|
6020
6622
|
}
|
|
6021
6623
|
} else {
|
|
@@ -6028,13 +6630,13 @@ var init_generate_ai_content = __esm({
|
|
|
6028
6630
|
}
|
|
6029
6631
|
}
|
|
6030
6632
|
if (staleOldAbsPath) {
|
|
6031
|
-
await
|
|
6633
|
+
await fs10.unlink(staleOldAbsPath).catch((err) => {
|
|
6032
6634
|
if (!isNodeError3(err) || err.code !== "ENOENT")
|
|
6033
6635
|
throw err;
|
|
6034
6636
|
});
|
|
6035
6637
|
}
|
|
6036
6638
|
await this.recordOwnMutation(liveIndex);
|
|
6037
|
-
const afterStat = await
|
|
6639
|
+
const afterStat = await fs10.stat(absolutePath);
|
|
6038
6640
|
const base = {
|
|
6039
6641
|
collection: schemaItem.logicalPath,
|
|
6040
6642
|
collectionName: schemaItem.name,
|
|
@@ -6112,7 +6714,7 @@ var init_generate_ai_content = __esm({
|
|
|
6112
6714
|
const schemaItem = this.assertSchemaItem(collectionPath);
|
|
6113
6715
|
const { absolutePath } = await this.buildPaths(schemaItem, slug);
|
|
6114
6716
|
try {
|
|
6115
|
-
await
|
|
6717
|
+
await fs10.access(absolutePath);
|
|
6116
6718
|
return true;
|
|
6117
6719
|
} catch (err) {
|
|
6118
6720
|
if (isNodeError3(err) && err.code === "ENOENT")
|
|
@@ -6151,7 +6753,7 @@ var init_generate_ai_content = __esm({
|
|
|
6151
6753
|
const collectionRoot = await resolveCollectionPath(this.root, collectionPath);
|
|
6152
6754
|
if (!collectionRoot)
|
|
6153
6755
|
return 0;
|
|
6154
|
-
const entries = await
|
|
6756
|
+
const entries = await fs10.readdir(collectionRoot, { withFileTypes: true }).catch(() => []);
|
|
6155
6757
|
return entries.filter((entry) => !entry.isDirectory() && extractEntryTypeFromFilename(entry.name) === entryTypeName).length;
|
|
6156
6758
|
}
|
|
6157
6759
|
/**
|
|
@@ -6175,7 +6777,7 @@ var init_generate_ai_content = __esm({
|
|
|
6175
6777
|
const collection = this.assertCollection(collectionPath);
|
|
6176
6778
|
const prePass = await this.buildPaths(collection, slug);
|
|
6177
6779
|
if (!prePass.existed) {
|
|
6178
|
-
await
|
|
6780
|
+
await fs10.unlink(prePass.absolutePath);
|
|
6179
6781
|
return;
|
|
6180
6782
|
}
|
|
6181
6783
|
let lockKey = this.entryLockKey(collection, slug, prePass);
|
|
@@ -6191,7 +6793,7 @@ var init_generate_ai_content = __esm({
|
|
|
6191
6793
|
return RETRY_KEY;
|
|
6192
6794
|
}
|
|
6193
6795
|
const { absolutePath, relativePath } = inLock;
|
|
6194
|
-
await
|
|
6796
|
+
await fs10.unlink(absolutePath);
|
|
6195
6797
|
const liveIndex = this._idIndex;
|
|
6196
6798
|
const id = liveIndex.findByPath(relativePath);
|
|
6197
6799
|
if (id) {
|
|
@@ -6227,6 +6829,10 @@ var init_generate_ai_content = __esm({
|
|
|
6227
6829
|
if (currentSlug === safeNewSlug) {
|
|
6228
6830
|
return { newPath: `${collectionPath}/${currentSlug}` };
|
|
6229
6831
|
}
|
|
6832
|
+
const routable = parseSlug(safeNewSlug);
|
|
6833
|
+
if (!routable.ok) {
|
|
6834
|
+
throw new ContentStoreError(`Cannot rename to "${safeNewSlug}": ${routable.error}. An entry whose slug is not addressable as a URL segment would build and then 404 on every visit.`, "VALIDATION");
|
|
6835
|
+
}
|
|
6230
6836
|
const prePass = await this.buildPaths(collection, currentSlug);
|
|
6231
6837
|
if (!prePass.existed) {
|
|
6232
6838
|
throw new ContentStoreError(`Entry not found: ${currentSlug}`, "NOT_FOUND");
|
|
@@ -6253,7 +6859,7 @@ var init_generate_ai_content = __esm({
|
|
|
6253
6859
|
}
|
|
6254
6860
|
destLockKey = currentDestKey;
|
|
6255
6861
|
const { absolutePath: currentPath, relativePath: currentRelPath } = inLock;
|
|
6256
|
-
const currentFilename =
|
|
6862
|
+
const currentFilename = path11.basename(currentPath);
|
|
6257
6863
|
const parts = currentFilename.split(".");
|
|
6258
6864
|
if (parts.length < 4) {
|
|
6259
6865
|
throw new ContentStoreError(`Invalid entry filename format: ${currentFilename}`, "VALIDATION");
|
|
@@ -6262,10 +6868,10 @@ var init_generate_ai_content = __esm({
|
|
|
6262
6868
|
const contentId = parts[parts.length - 2];
|
|
6263
6869
|
const ext = `.${parts[parts.length - 1]}`;
|
|
6264
6870
|
const newFilename = `${entryTypeName}.${safeNewSlug}.${contentId}${ext}`;
|
|
6265
|
-
const parentDir =
|
|
6266
|
-
const newPath =
|
|
6871
|
+
const parentDir = path11.dirname(currentPath);
|
|
6872
|
+
const newPath = path11.join(parentDir, newFilename);
|
|
6267
6873
|
try {
|
|
6268
|
-
const entries = await
|
|
6874
|
+
const entries = await fs10.readdir(parentDir, { withFileTypes: true });
|
|
6269
6875
|
for (const entry of entries) {
|
|
6270
6876
|
if (entry.isDirectory())
|
|
6271
6877
|
continue;
|
|
@@ -6278,16 +6884,17 @@ var init_generate_ai_content = __esm({
|
|
|
6278
6884
|
if (err instanceof ContentStoreError)
|
|
6279
6885
|
throw err;
|
|
6280
6886
|
}
|
|
6887
|
+
await this.assertUrlPathAvailable(parentDir, safeNewSlug);
|
|
6281
6888
|
try {
|
|
6282
|
-
await
|
|
6889
|
+
await fs10.link(currentPath, newPath);
|
|
6283
6890
|
} catch (err) {
|
|
6284
6891
|
if (isNodeError3(err) && err.code === "EEXIST") {
|
|
6285
6892
|
throw new ContentStoreError(`Entry with slug "${safeNewSlug}" already exists in collection "${collectionPath}"`, "VALIDATION");
|
|
6286
6893
|
}
|
|
6287
6894
|
throw err;
|
|
6288
6895
|
}
|
|
6289
|
-
await
|
|
6290
|
-
const newRelativePath =
|
|
6896
|
+
await fs10.unlink(currentPath);
|
|
6897
|
+
const newRelativePath = path11.relative(this.root, newPath);
|
|
6291
6898
|
const liveIndex = this._idIndex;
|
|
6292
6899
|
const entryId = liveIndex.findByPath(currentRelPath);
|
|
6293
6900
|
if (entryId) {
|
|
@@ -6359,34 +6966,57 @@ var init_generate_ai_content = __esm({
|
|
|
6359
6966
|
}
|
|
6360
6967
|
return entries;
|
|
6361
6968
|
}
|
|
6969
|
+
/**
|
|
6970
|
+
* Resolve every `reference` field in `data` against `fields`, returning a copy.
|
|
6971
|
+
*
|
|
6972
|
+
* This is what `read()` applies automatically (unless `resolveReferences: false`), exposed
|
|
6973
|
+
* so BATCH surfaces can opt into the same resolution without duplicating the walk: the
|
|
6974
|
+
* listing primitives in content-listing.ts and content-tree.ts read entry files straight
|
|
6975
|
+
* off disk and never touch this store, so before this existed a `reference` field reached
|
|
6976
|
+
* `listEntries()`/`buildContentTree()` callers as a bare id string or `null`.
|
|
6977
|
+
*
|
|
6978
|
+
* Pass one {@link ReferenceResolveCache} across a whole batch so a target referenced by
|
|
6979
|
+
* many entries is read once rather than once per referencing entry. Omit `cache` and the
|
|
6980
|
+
* behavior is exactly what `read()` has always done, unmemoized.
|
|
6981
|
+
*
|
|
6982
|
+
* **Path ACLs are not consulted for the targets.** Resolution goes through this store's
|
|
6983
|
+
* own `read()`, below the per-entry permission check in content-reader.ts — so a resolved
|
|
6984
|
+
* target may be an entry the caller could not `read()` directly. That is pre-existing
|
|
6985
|
+
* `read()` behavior, matched here on purpose so one rule covers both; see the
|
|
6986
|
+
* `resolveReferences` option in content-listing.ts for the note adopters see.
|
|
6987
|
+
*/
|
|
6988
|
+
async resolveReferences(data, fields, cache) {
|
|
6989
|
+
return this.resolveReferencesInData(data, fields, cache);
|
|
6990
|
+
}
|
|
6362
6991
|
/**
|
|
6363
6992
|
* Recursively resolve reference fields in data.
|
|
6364
6993
|
* This traverses objects, arrays, and blocks to find and resolve all reference fields.
|
|
6365
6994
|
*/
|
|
6366
|
-
async resolveReferencesInData(data, fields) {
|
|
6995
|
+
async resolveReferencesInData(data, fields, cache) {
|
|
6367
6996
|
const resolved = { ...data };
|
|
6368
6997
|
const idIndex = await this.idIndex();
|
|
6369
6998
|
for (const field of fields) {
|
|
6370
6999
|
if (field.type === "group") {
|
|
6371
|
-
const groupResolved = await this.resolveReferencesInData(resolved, field.fields);
|
|
7000
|
+
const groupResolved = await this.resolveReferencesInData(resolved, field.fields, cache);
|
|
6372
7001
|
Object.assign(resolved, groupResolved);
|
|
6373
7002
|
continue;
|
|
6374
7003
|
}
|
|
6375
7004
|
const value = data[field.name];
|
|
6376
7005
|
if (field.type === "reference") {
|
|
7006
|
+
const includeBody = field.includeBody === true;
|
|
6377
7007
|
if (typeof value === "string" && value) {
|
|
6378
|
-
resolved[field.name] = await this.resolveSingleReference(value, idIndex);
|
|
7008
|
+
resolved[field.name] = await this.resolveSingleReference(value, idIndex, includeBody, cache);
|
|
6379
7009
|
} else if (field.list && Array.isArray(value)) {
|
|
6380
|
-
resolved[field.name] = await Promise.all(value.map((id) => typeof id === "string" ? this.resolveSingleReference(id, idIndex) : null));
|
|
7010
|
+
resolved[field.name] = await Promise.all(value.map((id) => typeof id === "string" ? this.resolveSingleReference(id, idIndex, includeBody, cache) : null));
|
|
6381
7011
|
}
|
|
6382
7012
|
} else if (field.type === "object" && value) {
|
|
6383
7013
|
const objectField = field;
|
|
6384
7014
|
if (!objectField.fields)
|
|
6385
7015
|
continue;
|
|
6386
7016
|
if (objectField.list && Array.isArray(value)) {
|
|
6387
|
-
resolved[field.name] = await Promise.all(value.map((item) => typeof item === "object" && item !== null ? this.resolveReferencesInData(item, objectField.fields) : item));
|
|
7017
|
+
resolved[field.name] = await Promise.all(value.map((item) => typeof item === "object" && item !== null ? this.resolveReferencesInData(item, objectField.fields, cache) : item));
|
|
6388
7018
|
} else if (typeof value === "object") {
|
|
6389
|
-
resolved[field.name] = await this.resolveReferencesInData(value, objectField.fields);
|
|
7019
|
+
resolved[field.name] = await this.resolveReferencesInData(value, objectField.fields, cache);
|
|
6390
7020
|
}
|
|
6391
7021
|
} else if (field.type === "block" && Array.isArray(value)) {
|
|
6392
7022
|
const blockField = field;
|
|
@@ -6399,7 +7029,7 @@ var init_generate_ai_content = __esm({
|
|
|
6399
7029
|
return block;
|
|
6400
7030
|
return {
|
|
6401
7031
|
...b,
|
|
6402
|
-
value: await this.resolveReferencesInData(b.value, template.fields)
|
|
7032
|
+
value: await this.resolveReferencesInData(b.value, template.fields, cache)
|
|
6403
7033
|
};
|
|
6404
7034
|
}));
|
|
6405
7035
|
}
|
|
@@ -6407,7 +7037,56 @@ var init_generate_ai_content = __esm({
|
|
|
6407
7037
|
return resolved;
|
|
6408
7038
|
}
|
|
6409
7039
|
/**
|
|
6410
|
-
* Resolve a single reference ID to full entry data
|
|
7040
|
+
* Resolve a single reference ID to full entry data, memoized when a batch cache is
|
|
7041
|
+
* supplied. Without a cache this is a straight pass-through to the uncached path, so
|
|
7042
|
+
* `read()` behaves exactly as it always has.
|
|
7043
|
+
*
|
|
7044
|
+
* Every occurrence gets its OWN deep copy, even on a cache hit. Without that, the memo
|
|
7045
|
+
* would hand one shared object to all 40 entries referencing the same block — a mutation
|
|
7046
|
+
* in one caller's `extract` (truncating a body for a search index, deleting a field) would
|
|
7047
|
+
* silently rewrite it for every sibling, and both `list: true` elements of `[id, id]` would
|
|
7048
|
+
* be the same instance. The copy is what keeps the cache a pure performance optimization
|
|
7049
|
+
* instead of a semantic change.
|
|
7050
|
+
*
|
|
7051
|
+
* Note the uncached path is NOT the clean baseline it looks like. For a json/yaml target it
|
|
7052
|
+
* genuinely reparses fresh per occurrence, but for md/mdx gray-matter serves `data` from a
|
|
7053
|
+
* process-global content-keyed cache, so `resolveSingleReferenceOnce`'s top-level spread
|
|
7054
|
+
* severs exactly one level and NESTED frontmatter objects alias across occurrences, calls and
|
|
7055
|
+
* requests. That is pre-existing `read()` behavior and out of scope here — deliberately, since
|
|
7056
|
+
* touching it would change `read()` — but it means the cached path is the safer of the two,
|
|
7057
|
+
* not a relaxation of a guarantee the uncached one provides. See
|
|
7058
|
+
* `.claude/future-tasks/graymatter-cache-shared-frontmatter.md`.
|
|
7059
|
+
*
|
|
7060
|
+
* What the copy costs, measured rather than assumed (2000 occurrences of one target, local
|
|
7061
|
+
* disk, so every read hits the page cache — the friendliest possible case for NOT caching):
|
|
7062
|
+
* a snippet-sized target is ~63x cheaper to clone than to re-read-and-parse, while a 265KB
|
|
7063
|
+
* JSON target is ~0.8x, i.e. cloning is marginally SLOWER than reparsing it. So the win is
|
|
7064
|
+
* large in the case this exists for and roughly a wash at the pathological end, never a
|
|
7065
|
+
* blow-up. Two things keep the bad end narrow: an md/mdx target resolves to its FRONTMATTER
|
|
7066
|
+
* only *unless the field sets `includeBody`* (`read()` puts the body on `doc.body`, which
|
|
7067
|
+
* `resolveSingleReferenceOnce` spreads in only for an embedding field), so by default body
|
|
7068
|
+
* size is irrelevant no matter how long the document and only a genuinely huge JSON/YAML
|
|
7069
|
+
* target reaches the wash. **`includeBody: true` is the case that CAN reach it on markdown**:
|
|
7070
|
+
* the body then sits inside the memoized object and is cloned once per referencing entry, so
|
|
7071
|
+
* a long document embedded by many pages pays that repeatedly — the reason `includeBody`
|
|
7072
|
+
* exists as an opt-in per field rather than as resolution's default. And in the deployment this
|
|
7073
|
+
* targets, content lives on EFS/NFS where the syscall the memo removes dominates parse and
|
|
7074
|
+
* clone alike, which the local-disk numbers above understate badly. Correctness is the
|
|
7075
|
+
* reason for the copy regardless; the numbers are here so nobody has to re-derive them
|
|
7076
|
+
* before touching this.
|
|
7077
|
+
*/
|
|
7078
|
+
resolveSingleReference(id, idIndex, includeBody, cache) {
|
|
7079
|
+
if (!cache)
|
|
7080
|
+
return this.resolveSingleReferenceUncached(id, idIndex, includeBody);
|
|
7081
|
+
const key = includeBody ? `${id}:body` : id;
|
|
7082
|
+
let pending = cache.get(key);
|
|
7083
|
+
if (!pending) {
|
|
7084
|
+
pending = this.resolveSingleReferenceUncached(id, idIndex, includeBody);
|
|
7085
|
+
cache.set(key, pending);
|
|
7086
|
+
}
|
|
7087
|
+
return pending.then((resolved) => resolved === null ? null : structuredClone(resolved));
|
|
7088
|
+
}
|
|
7089
|
+
/**
|
|
6411
7090
|
* Returns null if the reference is invalid or missing.
|
|
6412
7091
|
* Includes id, slug, and collection fields for debugging.
|
|
6413
7092
|
*
|
|
@@ -6421,16 +7100,21 @@ var init_generate_ai_content = __esm({
|
|
|
6421
7100
|
* idIndex() dedupes concurrent builds — so a sibling call that wins the
|
|
6422
7101
|
* throttle and rebuilds heals every other miss in the same batch, not just
|
|
6423
7102
|
* the first.
|
|
7103
|
+
*
|
|
7104
|
+
* A {@link ReferenceResolveCache} sits ABOVE this, never inside it, so every
|
|
7105
|
+
* distinct id still runs the full refresh-and-retry above. What a cache changes
|
|
7106
|
+
* is only that repeats of the SAME id in one batch share that one attempt's
|
|
7107
|
+
* outcome instead of each getting an independent throw of the dice.
|
|
6424
7108
|
*/
|
|
6425
|
-
async
|
|
6426
|
-
const first = await this.resolveSingleReferenceOnce(id, idIndex);
|
|
7109
|
+
async resolveSingleReferenceUncached(id, idIndex, includeBody) {
|
|
7110
|
+
const first = await this.resolveSingleReferenceOnce(id, idIndex, includeBody);
|
|
6427
7111
|
if (first !== STALE_LOOKUP)
|
|
6428
7112
|
return first;
|
|
6429
7113
|
await this.refreshIndexForSuspiciousLookup();
|
|
6430
|
-
const second = await this.resolveSingleReferenceOnce(id, await this.idIndex());
|
|
7114
|
+
const second = await this.resolveSingleReferenceOnce(id, await this.idIndex(), includeBody);
|
|
6431
7115
|
return second === STALE_LOOKUP ? null : second;
|
|
6432
7116
|
}
|
|
6433
|
-
async resolveSingleReferenceOnce(id, idIndex) {
|
|
7117
|
+
async resolveSingleReferenceOnce(id, idIndex, includeBody) {
|
|
6434
7118
|
try {
|
|
6435
7119
|
const location = idIndex.findById(id);
|
|
6436
7120
|
if (!location)
|
|
@@ -6441,12 +7125,13 @@ var init_generate_ai_content = __esm({
|
|
|
6441
7125
|
const doc = await this.read(location.collection, location.slug, {
|
|
6442
7126
|
resolveReferences: false
|
|
6443
7127
|
});
|
|
6444
|
-
|
|
7128
|
+
const bodyForEmbed = includeBody && "body" in doc ? { fieldName: doc.bodyFieldName, value: doc.body } : void 0;
|
|
7129
|
+
return buildResolvedReference(doc.data, {
|
|
6445
7130
|
id,
|
|
6446
7131
|
slug: location.slug,
|
|
6447
7132
|
collection: location.collection,
|
|
6448
|
-
|
|
6449
|
-
};
|
|
7133
|
+
urlPath: computeEntryUrl(location.collection, location.slug, this.contentRootName)
|
|
7134
|
+
}, bodyForEmbed);
|
|
6450
7135
|
} catch (error) {
|
|
6451
7136
|
if (isNodeError3(error) && error.code === "ENOENT")
|
|
6452
7137
|
return STALE_LOOKUP;
|
|
@@ -6471,7 +7156,6 @@ var init_generate_ai_content = __esm({
|
|
|
6471
7156
|
"reference",
|
|
6472
7157
|
"image"
|
|
6473
7158
|
]);
|
|
6474
|
-
init_normalize2();
|
|
6475
7159
|
log22 = createDebugLogger2({ prefix: "EntryLinks" });
|
|
6476
7160
|
BASE58_CHAR = "[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]";
|
|
6477
7161
|
ENTRY_LINK_PATTERN = new RegExp(`entry:(${BASE58_CHAR}{12})(#[^\\s)>"']*)?`, "g");
|
|
@@ -6487,10 +7171,10 @@ var init_generate_ai_content = __esm({
|
|
|
6487
7171
|
constructor(root) {
|
|
6488
7172
|
this.regenInFlight = null;
|
|
6489
7173
|
this.lastForcedRefreshMs = 0;
|
|
6490
|
-
this.root =
|
|
6491
|
-
this.registryPath =
|
|
6492
|
-
this.stalePath =
|
|
6493
|
-
this.tempPath =
|
|
7174
|
+
this.root = path13.resolve(root);
|
|
7175
|
+
this.registryPath = path13.join(this.root, REGISTRY_FILE);
|
|
7176
|
+
this.stalePath = path13.join(this.root, REGISTRY_STALE_FILE);
|
|
7177
|
+
this.tempPath = path13.join(this.root, REGISTRY_TEMP_FILE);
|
|
6494
7178
|
}
|
|
6495
7179
|
/**
|
|
6496
7180
|
* Returns all branches. Uses the cached snapshot if its embedded generation
|
|
@@ -6499,7 +7183,7 @@ var init_generate_ai_content = __esm({
|
|
|
6499
7183
|
async list() {
|
|
6500
7184
|
let parsed;
|
|
6501
7185
|
try {
|
|
6502
|
-
const raw = await
|
|
7186
|
+
const raw = await fs12.readFile(this.registryPath, "utf8");
|
|
6503
7187
|
parsed = JSON.parse(raw);
|
|
6504
7188
|
} catch (err) {
|
|
6505
7189
|
if (isNotFoundError3(err)) {
|
|
@@ -6588,7 +7272,7 @@ var init_generate_ai_content = __esm({
|
|
|
6588
7272
|
async performRegenerate() {
|
|
6589
7273
|
const read = await readResourceGeneration(this.root, RESOURCE2);
|
|
6590
7274
|
const branches = await this.scanBranchDirectories();
|
|
6591
|
-
await
|
|
7275
|
+
await fs12.unlink(this.stalePath).catch(() => {
|
|
6592
7276
|
});
|
|
6593
7277
|
if (!read.ok) {
|
|
6594
7278
|
return branches;
|
|
@@ -6599,12 +7283,12 @@ var init_generate_ai_content = __esm({
|
|
|
6599
7283
|
generation: read.token
|
|
6600
7284
|
};
|
|
6601
7285
|
const uniqueTempPath = `${this.tempPath}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
6602
|
-
await
|
|
6603
|
-
await
|
|
7286
|
+
await fs12.mkdir(this.root, { recursive: true });
|
|
7287
|
+
await fs12.writeFile(uniqueTempPath, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
|
|
6604
7288
|
try {
|
|
6605
|
-
await
|
|
7289
|
+
await fs12.rename(uniqueTempPath, this.registryPath);
|
|
6606
7290
|
} catch (err) {
|
|
6607
|
-
await
|
|
7291
|
+
await fs12.unlink(uniqueTempPath).catch(() => {
|
|
6608
7292
|
});
|
|
6609
7293
|
throw err;
|
|
6610
7294
|
}
|
|
@@ -6618,12 +7302,12 @@ var init_generate_ai_content = __esm({
|
|
|
6618
7302
|
async scanBranchDirectories() {
|
|
6619
7303
|
const branches = [];
|
|
6620
7304
|
try {
|
|
6621
|
-
const entries = await
|
|
7305
|
+
const entries = await fs12.readdir(this.root, { withFileTypes: true });
|
|
6622
7306
|
for (const entry of entries) {
|
|
6623
7307
|
if (!entry.isDirectory() || entry.name.startsWith(".")) {
|
|
6624
7308
|
continue;
|
|
6625
7309
|
}
|
|
6626
|
-
const branchRoot =
|
|
7310
|
+
const branchRoot = path13.join(this.root, entry.name);
|
|
6627
7311
|
let meta;
|
|
6628
7312
|
try {
|
|
6629
7313
|
meta = await BranchMetadataFileManager.loadOnly(branchRoot);
|
|
@@ -6674,8 +7358,8 @@ var init_generate_ai_content = __esm({
|
|
|
6674
7358
|
};
|
|
6675
7359
|
BranchMetadataFileManager = class _BranchMetadataFileManager {
|
|
6676
7360
|
constructor(branchRoot, baseRoot, options) {
|
|
6677
|
-
this.branchRoot =
|
|
6678
|
-
this.filePath =
|
|
7361
|
+
this.branchRoot = path15.resolve(branchRoot);
|
|
7362
|
+
this.filePath = path15.join(this.branchRoot, BRANCH_META_DIR, BRANCH_META_FILE);
|
|
6679
7363
|
this.baseRoot = baseRoot;
|
|
6680
7364
|
this.settleMs = options?.settleMs;
|
|
6681
7365
|
}
|
|
@@ -6684,10 +7368,10 @@ var init_generate_ai_content = __esm({
|
|
|
6684
7368
|
* Use this for read-only access (e.g., in registry scanning or loadBranchContext).
|
|
6685
7369
|
*/
|
|
6686
7370
|
static async loadOnly(branchRoot) {
|
|
6687
|
-
const resolvedRoot =
|
|
6688
|
-
const filePath =
|
|
7371
|
+
const resolvedRoot = path15.resolve(branchRoot);
|
|
7372
|
+
const filePath = path15.join(resolvedRoot, BRANCH_META_DIR, BRANCH_META_FILE);
|
|
6689
7373
|
try {
|
|
6690
|
-
const raw = await
|
|
7374
|
+
const raw = await fs14.readFile(filePath, "utf8");
|
|
6691
7375
|
return JSON.parse(raw);
|
|
6692
7376
|
} catch (err) {
|
|
6693
7377
|
if (isNotFoundError3(err)) {
|
|
@@ -6708,7 +7392,7 @@ var init_generate_ai_content = __esm({
|
|
|
6708
7392
|
}
|
|
6709
7393
|
async load() {
|
|
6710
7394
|
try {
|
|
6711
|
-
const raw = await
|
|
7395
|
+
const raw = await fs14.readFile(this.filePath, "utf8");
|
|
6712
7396
|
const parsed = JSON.parse(raw);
|
|
6713
7397
|
const version = parsed.version ?? 0;
|
|
6714
7398
|
return { meta: parsed, version };
|
|
@@ -6770,7 +7454,7 @@ var init_generate_ai_content = __esm({
|
|
|
6770
7454
|
*/
|
|
6771
7455
|
async save(incoming) {
|
|
6772
7456
|
try {
|
|
6773
|
-
await
|
|
7457
|
+
await fs14.stat(this.branchRoot);
|
|
6774
7458
|
} catch (err) {
|
|
6775
7459
|
if (isNotFoundError3(err)) {
|
|
6776
7460
|
throw new BranchMetadataConflictError("Branch no longer exists");
|
|
@@ -6883,12 +7567,12 @@ var init_generate_ai_content = __esm({
|
|
|
6883
7567
|
};
|
|
6884
7568
|
GitManager = class _GitManager {
|
|
6885
7569
|
constructor(options, gitOptions) {
|
|
6886
|
-
this.repoPath =
|
|
7570
|
+
this.repoPath = path16.resolve(options.repoPath);
|
|
6887
7571
|
this.baseBranch = options.baseBranch ?? "main";
|
|
6888
7572
|
this.remote = options.remote ?? "origin";
|
|
6889
7573
|
this.skipIndexMarker = options.skipIndexMarker ?? false;
|
|
6890
7574
|
this.git = simpleGit2({ baseDir: this.repoPath, ...gitOptions });
|
|
6891
|
-
this.git.env(gitChildEnv({ GIT_CEILING_DIRECTORIES:
|
|
7575
|
+
this.git.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(this.repoPath) }));
|
|
6892
7576
|
}
|
|
6893
7577
|
static async cloneRepo(remoteUrl, targetPath, baseBranch = "main") {
|
|
6894
7578
|
log5.debug("git", "Cloning repository", {
|
|
@@ -6930,11 +7614,11 @@ var init_generate_ai_content = __esm({
|
|
|
6930
7614
|
remotePath: options.remotePath,
|
|
6931
7615
|
baseBranch: options.baseBranch
|
|
6932
7616
|
});
|
|
6933
|
-
const remoteParent =
|
|
7617
|
+
const remoteParent = path16.dirname(options.remotePath);
|
|
6934
7618
|
releaseLock = await acquireProvisioningLock(remoteParent, ".remote-init.lock");
|
|
6935
7619
|
let remoteExists = false;
|
|
6936
7620
|
try {
|
|
6937
|
-
const stat = await
|
|
7621
|
+
const stat = await fs15.stat(options.remotePath);
|
|
6938
7622
|
remoteExists = stat.isDirectory();
|
|
6939
7623
|
} catch (err) {
|
|
6940
7624
|
if (!isNotFoundError3(err))
|
|
@@ -7186,7 +7870,7 @@ var init_generate_ai_content = __esm({
|
|
|
7186
7870
|
*/
|
|
7187
7871
|
static async validateGitRepoExists(repoPath) {
|
|
7188
7872
|
try {
|
|
7189
|
-
const stat = await
|
|
7873
|
+
const stat = await fs15.stat(path16.join(repoPath, ".git"));
|
|
7190
7874
|
if (!stat.isDirectory()) {
|
|
7191
7875
|
throw new Error(`Expected git repo at ${repoPath}`);
|
|
7192
7876
|
}
|
|
@@ -7264,7 +7948,7 @@ var init_generate_ai_content = __esm({
|
|
|
7264
7948
|
}
|
|
7265
7949
|
if (config.autoDetectRemotePath) {
|
|
7266
7950
|
try {
|
|
7267
|
-
const stat = await
|
|
7951
|
+
const stat = await fs15.stat(config.autoDetectRemotePath);
|
|
7268
7952
|
if (stat.isDirectory()) {
|
|
7269
7953
|
log5.debug("git", "Auto-detected local remote", {
|
|
7270
7954
|
path: config.autoDetectRemotePath
|
|
@@ -7277,8 +7961,8 @@ var init_generate_ai_content = __esm({
|
|
|
7277
7961
|
if (config.shouldAutoInitLocal) {
|
|
7278
7962
|
const gitRoot = await this.findGitRoot();
|
|
7279
7963
|
const sourceRoot = options.sourceRoot;
|
|
7280
|
-
const sourcePath = sourceRoot ?
|
|
7281
|
-
const localRemotePath =
|
|
7964
|
+
const sourcePath = sourceRoot ? path16.resolve(gitRoot, sourceRoot) : gitRoot;
|
|
7965
|
+
const localRemotePath = path16.join(sourcePath, config.defaultRemotePath);
|
|
7282
7966
|
await this.ensureLocalSimulatedRemote({
|
|
7283
7967
|
remotePath: localRemotePath,
|
|
7284
7968
|
sourcePath: gitRoot,
|
|
@@ -7306,7 +7990,7 @@ var init_generate_ai_content = __esm({
|
|
|
7306
7990
|
static async repoExistsAt(workspacePath) {
|
|
7307
7991
|
try {
|
|
7308
7992
|
const checkGit = simpleGit2({ baseDir: workspacePath });
|
|
7309
|
-
checkGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES:
|
|
7993
|
+
checkGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(workspacePath) }));
|
|
7310
7994
|
await checkGit.raw(["rev-parse", "--git-dir"]);
|
|
7311
7995
|
return true;
|
|
7312
7996
|
} catch {
|
|
@@ -7328,19 +8012,19 @@ var init_generate_ai_content = __esm({
|
|
|
7328
8012
|
const baseBranch = await resolveBaseBranch({
|
|
7329
8013
|
defaultBaseBranch: options.baseBranch,
|
|
7330
8014
|
mode: options.mode,
|
|
7331
|
-
detectFrom: options.sourceRoot ?
|
|
8015
|
+
detectFrom: options.sourceRoot ? path16.resolve(process.cwd(), options.sourceRoot) : process.cwd()
|
|
7332
8016
|
});
|
|
7333
8017
|
const remoteName = options.remoteName ?? "origin";
|
|
7334
8018
|
const repoExists = await _GitManager.repoExistsAt(options.workspacePath);
|
|
7335
8019
|
if (!repoExists) {
|
|
7336
|
-
const gitPath =
|
|
8020
|
+
const gitPath = path16.join(options.workspacePath, ".git");
|
|
7337
8021
|
try {
|
|
7338
|
-
const stat = await
|
|
8022
|
+
const stat = await fs15.stat(gitPath);
|
|
7339
8023
|
if (stat.isDirectory()) {
|
|
7340
8024
|
log5.debug("git", "Removing corrupt .git directory", {
|
|
7341
8025
|
workspacePath: options.workspacePath
|
|
7342
8026
|
});
|
|
7343
|
-
await
|
|
8027
|
+
await fs15.rm(gitPath, { recursive: true });
|
|
7344
8028
|
}
|
|
7345
8029
|
} catch (cleanupErr) {
|
|
7346
8030
|
if (!isNotFoundError3(cleanupErr))
|
|
@@ -7367,7 +8051,7 @@ var init_generate_ai_content = __esm({
|
|
|
7367
8051
|
}
|
|
7368
8052
|
justCloned = true;
|
|
7369
8053
|
const freshGit = simpleGit2({ baseDir: options.workspacePath });
|
|
7370
|
-
freshGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES:
|
|
8054
|
+
freshGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(options.workspacePath) }));
|
|
7371
8055
|
await freshGit.addConfig("canopycms.managed", "true");
|
|
7372
8056
|
await freshGit.addConfig("user.name", options.gitBotAuthorName);
|
|
7373
8057
|
await freshGit.addConfig("user.email", options.gitBotAuthorEmail);
|
|
@@ -7718,9 +8402,9 @@ var init_generate_ai_content = __esm({
|
|
|
7718
8402
|
} catch {
|
|
7719
8403
|
}
|
|
7720
8404
|
for (const [filePath, content] of Object.entries(initialFiles)) {
|
|
7721
|
-
const absolutePath =
|
|
7722
|
-
await
|
|
7723
|
-
await
|
|
8405
|
+
const absolutePath = path16.join(this.repoPath, filePath);
|
|
8406
|
+
await fs15.mkdir(path16.dirname(absolutePath), { recursive: true });
|
|
8407
|
+
await fs15.writeFile(absolutePath, content, "utf-8");
|
|
7724
8408
|
await this.git.add(filePath);
|
|
7725
8409
|
}
|
|
7726
8410
|
await this.git.commit("Initialize settings branch", ["--allow-empty"]);
|
|
@@ -7747,7 +8431,7 @@ var init_generate_ai_content = __esm({
|
|
|
7747
8431
|
branchName: options.branchName,
|
|
7748
8432
|
mode: options.mode
|
|
7749
8433
|
});
|
|
7750
|
-
releaseLock = await acquireProvisioningLock(
|
|
8434
|
+
releaseLock = await acquireProvisioningLock(path17.dirname(options.branchRoot), `.${path17.basename(options.branchRoot)}.init.lock`);
|
|
7751
8435
|
await GitManager.initializeWorkspace({
|
|
7752
8436
|
workspacePath: options.branchRoot,
|
|
7753
8437
|
branchName: options.branchName,
|
|
@@ -7788,7 +8472,7 @@ var init_generate_ai_content = __esm({
|
|
|
7788
8472
|
const baseBranch = await resolveBaseBranch({
|
|
7789
8473
|
defaultBaseBranch: this.config.defaultBaseBranch,
|
|
7790
8474
|
mode,
|
|
7791
|
-
detectFrom: this.config.sourceRoot ?
|
|
8475
|
+
detectFrom: this.config.sourceRoot ? path17.resolve(process.cwd(), this.config.sourceRoot) : void 0
|
|
7792
8476
|
});
|
|
7793
8477
|
await this.ensureGitWorkspace({
|
|
7794
8478
|
branchRoot,
|
|
@@ -7825,15 +8509,15 @@ var init_generate_ai_content = __esm({
|
|
|
7825
8509
|
};
|
|
7826
8510
|
readEntryData = async (filePath, format, bodyFieldName = "body") => {
|
|
7827
8511
|
try {
|
|
7828
|
-
const raw = await
|
|
8512
|
+
const raw = await fs16.readFile(filePath, "utf8");
|
|
7829
8513
|
if (format === "json") {
|
|
7830
8514
|
return asRecord(JSON.parse(raw));
|
|
7831
8515
|
}
|
|
7832
8516
|
if (format === "yaml") {
|
|
7833
8517
|
return asRecord(yamlParse2(raw));
|
|
7834
8518
|
}
|
|
7835
|
-
const parsed =
|
|
7836
|
-
const data = parsed.data ?? {};
|
|
8519
|
+
const parsed = matter3(raw);
|
|
8520
|
+
const data = { ...parsed.data ?? {} };
|
|
7837
8521
|
if (parsed.content) {
|
|
7838
8522
|
data[bodyFieldName] = parsed.content;
|
|
7839
8523
|
}
|
|
@@ -7845,30 +8529,28 @@ var init_generate_ai_content = __esm({
|
|
|
7845
8529
|
return {};
|
|
7846
8530
|
}
|
|
7847
8531
|
};
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
const
|
|
7854
|
-
if (
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
7860
|
-
|
|
7861
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
|
|
7868
|
-
}
|
|
7869
|
-
return null;
|
|
8532
|
+
createReferenceResolver = (branchRoot, flatSchema, contentRootName) => ({
|
|
8533
|
+
store: new ContentStore(branchRoot, flatSchema, { contentRootName }),
|
|
8534
|
+
cache: createReferenceResolveCache()
|
|
8535
|
+
});
|
|
8536
|
+
resolveCollectionItemReferences = async (items, collection, resolver) => Promise.all(items.map(async (item) => {
|
|
8537
|
+
const fields = collection.entries?.find((e) => e.name === item.entryType)?.schema;
|
|
8538
|
+
if (!fields)
|
|
8539
|
+
return item;
|
|
8540
|
+
return {
|
|
8541
|
+
...item,
|
|
8542
|
+
data: await resolver.store.resolveReferences(item.data, fields, resolver.cache)
|
|
8543
|
+
};
|
|
8544
|
+
}));
|
|
8545
|
+
looksLikeMalformedEntry = (filename, entryTypes) => {
|
|
8546
|
+
if (filename.startsWith(".") || filename.startsWith("_"))
|
|
8547
|
+
return false;
|
|
8548
|
+
const segments = filename.split(".");
|
|
8549
|
+
if (segments.length >= 4)
|
|
8550
|
+
return true;
|
|
8551
|
+
return segments.length === 3 && entryTypes.some((e) => e.name === segments[0]);
|
|
7870
8552
|
};
|
|
7871
|
-
listCollectionEntries = async (root, collection) => {
|
|
8553
|
+
listCollectionEntries = async (root, collection, onSkip) => {
|
|
7872
8554
|
if (collection.type !== "collection" || !collection.entries) {
|
|
7873
8555
|
return [];
|
|
7874
8556
|
}
|
|
@@ -7888,7 +8570,7 @@ var init_generate_ai_content = __esm({
|
|
|
7888
8570
|
normalizePath(root, collectionRoot);
|
|
7889
8571
|
let dirents;
|
|
7890
8572
|
try {
|
|
7891
|
-
dirents = await
|
|
8573
|
+
dirents = await fs16.readdir(collectionRoot, { withFileTypes: true });
|
|
7892
8574
|
} catch (err) {
|
|
7893
8575
|
if (isNotFoundError3(err))
|
|
7894
8576
|
return [];
|
|
@@ -7896,11 +8578,14 @@ var init_generate_ai_content = __esm({
|
|
|
7896
8578
|
}
|
|
7897
8579
|
const files = dirents.filter((d) => d.isFile() && validExts.some((ext) => d.name.endsWith(ext)) && d.name !== ".collection.json").sort((a, b) => a.name.localeCompare(b.name));
|
|
7898
8580
|
const entries = await Promise.all(files.map(async (file) => {
|
|
7899
|
-
const absolutePath =
|
|
8581
|
+
const absolutePath = path18.join(collectionRoot, file.name);
|
|
7900
8582
|
const relativePath = normalizePath(root, absolutePath);
|
|
7901
8583
|
const parsed = parseTypedFilename(file.name, entryTypes);
|
|
7902
8584
|
if (!parsed) {
|
|
7903
8585
|
log7.warn("listCollectionEntries", `Skipping file with unrecognized filename format: ${file.name} (expected {type}.{slug}.{id}.{ext} with a known entry type and valid 12-char Base58 ID)`);
|
|
8586
|
+
if (looksLikeMalformedEntry(file.name, entryTypes)) {
|
|
8587
|
+
onSkip?.({ filename: file.name, collectionPath: collection.logicalPath });
|
|
8588
|
+
}
|
|
7904
8589
|
return null;
|
|
7905
8590
|
}
|
|
7906
8591
|
const { type: entryTypeName, slug, id: contentId } = parsed;
|
|
@@ -7908,7 +8593,7 @@ var init_generate_ai_content = __esm({
|
|
|
7908
8593
|
const format = entryType?.format || "json";
|
|
7909
8594
|
const bodyField = entryType?.schema ? findBodyFieldName(entryType.schema) : "body";
|
|
7910
8595
|
const [stats, data] = await Promise.all([
|
|
7911
|
-
|
|
8596
|
+
fs16.stat(absolutePath),
|
|
7912
8597
|
readEntryData(absolutePath, format, bodyField)
|
|
7913
8598
|
]);
|
|
7914
8599
|
const item = {
|
|
@@ -7932,22 +8617,23 @@ var init_generate_ai_content = __esm({
|
|
|
7932
8617
|
KNOWN_FIELD_TYPES = new Set(fieldTypes2);
|
|
7933
8618
|
STRING_FIELD_TYPES = /* @__PURE__ */ new Set(["string", "markdown", "mdx", "code"]);
|
|
7934
8619
|
selectOptionValues = (field) => (field.options ?? []).map((opt) => typeof opt === "string" ? opt : opt.value);
|
|
8620
|
+
GENERATED_RECORD_FILENAME = ".canopy-generated.json";
|
|
7935
8621
|
jiti = createJiti2(import.meta.url);
|
|
7936
8622
|
}
|
|
7937
8623
|
});
|
|
7938
8624
|
|
|
7939
8625
|
// dist/utils/atomic-write.js
|
|
7940
|
-
import
|
|
7941
|
-
import
|
|
8626
|
+
import fs18 from "node:fs/promises";
|
|
8627
|
+
import path21 from "node:path";
|
|
7942
8628
|
async function atomicWriteFile3(filePath, content) {
|
|
7943
|
-
const dir =
|
|
7944
|
-
await
|
|
8629
|
+
const dir = path21.dirname(filePath);
|
|
8630
|
+
await fs18.mkdir(dir, { recursive: true });
|
|
7945
8631
|
const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
7946
|
-
await
|
|
8632
|
+
await fs18.writeFile(tempPath, content, typeof content === "string" ? "utf-8" : void 0);
|
|
7947
8633
|
try {
|
|
7948
|
-
await
|
|
8634
|
+
await fs18.rename(tempPath, filePath);
|
|
7949
8635
|
} catch (err) {
|
|
7950
|
-
await
|
|
8636
|
+
await fs18.unlink(tempPath).catch(() => {
|
|
7951
8637
|
});
|
|
7952
8638
|
throw err;
|
|
7953
8639
|
}
|
|
@@ -8067,11 +8753,11 @@ var init_debug2 = __esm({
|
|
|
8067
8753
|
});
|
|
8068
8754
|
|
|
8069
8755
|
// dist/resource-generation.js
|
|
8070
|
-
import
|
|
8071
|
-
import
|
|
8756
|
+
import fs19 from "node:fs/promises";
|
|
8757
|
+
import path23 from "node:path";
|
|
8072
8758
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
8073
8759
|
function resourceGenerationPath2(root, resource) {
|
|
8074
|
-
return
|
|
8760
|
+
return path23.resolve(root, META_DIR3, `${resource}.generation`);
|
|
8075
8761
|
}
|
|
8076
8762
|
async function bumpResourceGeneration2(root, resource, options) {
|
|
8077
8763
|
const token = randomUUID3();
|
|
@@ -8089,7 +8775,7 @@ async function bumpResourceGeneration2(root, resource, options) {
|
|
|
8089
8775
|
}
|
|
8090
8776
|
async function readResourceGeneration2(root, resource) {
|
|
8091
8777
|
try {
|
|
8092
|
-
const token = await
|
|
8778
|
+
const token = await fs19.readFile(resourceGenerationPath2(root, resource), "utf-8");
|
|
8093
8779
|
return { ok: true, token };
|
|
8094
8780
|
} catch (err) {
|
|
8095
8781
|
if (isNodeError(err) && err.code === "ENOENT")
|
|
@@ -8116,10 +8802,10 @@ var init_resource_generation = __esm({
|
|
|
8116
8802
|
});
|
|
8117
8803
|
|
|
8118
8804
|
// dist/content-index-registry.js
|
|
8119
|
-
import
|
|
8805
|
+
import path24 from "node:path";
|
|
8120
8806
|
function invalidateContentIndexesForRoot2(root) {
|
|
8121
|
-
const rootKey =
|
|
8122
|
-
const prefix = rootKey +
|
|
8807
|
+
const rootKey = path24.resolve(root);
|
|
8808
|
+
const prefix = rootKey + path24.sep;
|
|
8123
8809
|
for (const [storeRoot, refs] of registry2) {
|
|
8124
8810
|
if (storeRoot !== rootKey && !storeRoot.startsWith(prefix))
|
|
8125
8811
|
continue;
|
|
@@ -8177,7 +8863,7 @@ var init_normalize3 = __esm({
|
|
|
8177
8863
|
function isValidContentId2(id) {
|
|
8178
8864
|
return CONTENT_ID_PATTERN2.test(id);
|
|
8179
8865
|
}
|
|
8180
|
-
function
|
|
8866
|
+
function parseSlug2(slug) {
|
|
8181
8867
|
if (!slug) {
|
|
8182
8868
|
return {
|
|
8183
8869
|
ok: false,
|
|
@@ -8287,7 +8973,7 @@ var init_content_id_index = __esm({
|
|
|
8287
8973
|
});
|
|
8288
8974
|
|
|
8289
8975
|
// dist/schema/meta-loader.js
|
|
8290
|
-
import { promises as
|
|
8976
|
+
import { promises as fs20 } from "fs";
|
|
8291
8977
|
import { join as join4 } from "pathe";
|
|
8292
8978
|
import { z as z8 } from "zod";
|
|
8293
8979
|
import chokidar2 from "chokidar";
|
|
@@ -8297,7 +8983,7 @@ function stripEmbeddedIdFromName2(name) {
|
|
|
8297
8983
|
async function scanForCollectionMeta2(baseDir, relativePath = "") {
|
|
8298
8984
|
const collections = [];
|
|
8299
8985
|
try {
|
|
8300
|
-
const entries = await
|
|
8986
|
+
const entries = await fs20.readdir(baseDir, { withFileTypes: true });
|
|
8301
8987
|
for (const entry of entries) {
|
|
8302
8988
|
if (!entry.isDirectory())
|
|
8303
8989
|
continue;
|
|
@@ -8308,8 +8994,8 @@ async function scanForCollectionMeta2(baseDir, relativePath = "") {
|
|
|
8308
8994
|
const absolutePath = join4(baseDir, folderName);
|
|
8309
8995
|
const metaPath = join4(absolutePath, ".collection.json");
|
|
8310
8996
|
try {
|
|
8311
|
-
await
|
|
8312
|
-
const content = await
|
|
8997
|
+
await fs20.access(metaPath);
|
|
8998
|
+
const content = await fs20.readFile(metaPath, "utf-8");
|
|
8313
8999
|
const parsed = JSON.parse(content);
|
|
8314
9000
|
const meta = collectionMetaSchema2.parse(parsed);
|
|
8315
9001
|
collections.push({
|
|
@@ -8341,7 +9027,7 @@ async function loadCollectionMetaFiles2(contentRoot) {
|
|
|
8341
9027
|
let root = null;
|
|
8342
9028
|
const rootMetaPath = join4(contentRoot, ".collection.json");
|
|
8343
9029
|
try {
|
|
8344
|
-
await
|
|
9030
|
+
await fs20.access(rootMetaPath);
|
|
8345
9031
|
} catch (err) {
|
|
8346
9032
|
if (err.code === "ENOENT") {
|
|
8347
9033
|
} else {
|
|
@@ -8349,7 +9035,7 @@ async function loadCollectionMetaFiles2(contentRoot) {
|
|
|
8349
9035
|
}
|
|
8350
9036
|
}
|
|
8351
9037
|
try {
|
|
8352
|
-
const content = await
|
|
9038
|
+
const content = await fs20.readFile(rootMetaPath, "utf-8");
|
|
8353
9039
|
const parsed = JSON.parse(content);
|
|
8354
9040
|
root = rootCollectionMetaSchema2.parse(parsed);
|
|
8355
9041
|
} catch (err) {
|
|
@@ -8496,7 +9182,12 @@ var init_field3 = __esm({
|
|
|
8496
9182
|
collections: z9.array(z9.string().min(1)).min(1).optional(),
|
|
8497
9183
|
entryTypes: z9.array(z9.string().min(1)).min(1).optional(),
|
|
8498
9184
|
displayField: z9.string().min(1).optional(),
|
|
8499
|
-
options: z9.array(referenceOptionSchema3).optional()
|
|
9185
|
+
options: z9.array(referenceOptionSchema3).optional(),
|
|
9186
|
+
// Must be listed here, not just on ReferenceFieldConfig: zod strips unknown keys by
|
|
9187
|
+
// default, so a consumer that adopts this schema's parse output would silently delete a
|
|
9188
|
+
// runtime-consumed flag and the feature would no-op with no error. (`resolvedSchema` is
|
|
9189
|
+
// absent on purpose — it is type-inference-only and stripping it changes no behavior.)
|
|
9190
|
+
includeBody: z9.boolean().optional()
|
|
8500
9191
|
});
|
|
8501
9192
|
fieldHolder3 = [z9.never()];
|
|
8502
9193
|
blockSchema3 = z9.object({
|
|
@@ -8606,7 +9297,7 @@ var init_media3 = __esm({
|
|
|
8606
9297
|
|
|
8607
9298
|
// dist/config/schemas/config.js
|
|
8608
9299
|
import { z as z12 } from "zod";
|
|
8609
|
-
var defaultBranchAccessSchema3, defaultPathAccessLevelSchema3, defaultPathAccessLevelsSchema3, defaultPathAccessSchema3, defaultBaseBranchSchema3, defaultRemoteNameSchema3, defaultRemoteUrlSchema3, gitBotAuthorNameSchema3, gitBotAuthorEmailSchema3, githubTokenEnvVarSchema3, operatingModeSchema3, deployedAsSchema3, contentRootSchema3, sourceRootSchema3, deploymentNameSchema3, devContentSyncSchema3, devConfigSchema3, editorConfigSchema3, CanopyConfigSchema3, DEFAULT_PROD_WORKSPACE3;
|
|
9300
|
+
var defaultBranchAccessSchema3, defaultPathAccessLevelSchema3, defaultPathAccessLevelsSchema3, defaultPathAccessSchema3, defaultBaseBranchSchema3, defaultRemoteNameSchema3, defaultRemoteUrlSchema3, gitBotAuthorNameSchema3, gitBotAuthorEmailSchema3, githubTokenEnvVarSchema3, operatingModeSchema3, deployedAsSchema3, contentRootSchema3, sourceRootSchema3, basePathSchema3, deploymentNameSchema3, devContentSyncSchema3, devConfigSchema3, editorConfigSchema3, CanopyConfigSchema3, DEFAULT_PROD_WORKSPACE3;
|
|
8610
9301
|
var init_config4 = __esm({
|
|
8611
9302
|
"dist/config/schemas/config.js"() {
|
|
8612
9303
|
"use strict";
|
|
@@ -8630,6 +9321,9 @@ var init_config4 = __esm({
|
|
|
8630
9321
|
deployedAsSchema3 = z12.enum(["static", "server"]).default("server");
|
|
8631
9322
|
contentRootSchema3 = relativePathSchema3.default("content");
|
|
8632
9323
|
sourceRootSchema3 = z12.string().min(1).optional();
|
|
9324
|
+
basePathSchema3 = z12.string().transform((value) => value.trim()).refine((value) => value.length > 0, {
|
|
9325
|
+
message: "basePath must not be empty or only whitespace"
|
|
9326
|
+
}).optional();
|
|
8633
9327
|
deploymentNameSchema3 = z12.string().default("prod");
|
|
8634
9328
|
devContentSyncSchema3 = z12.enum(["off", "warn"]).default("warn");
|
|
8635
9329
|
devConfigSchema3 = z12.object({
|
|
@@ -8692,6 +9386,7 @@ var init_config4 = __esm({
|
|
|
8692
9386
|
deploymentName: deploymentNameSchema3.optional(),
|
|
8693
9387
|
contentRoot: contentRootSchema3.default("content"),
|
|
8694
9388
|
sourceRoot: sourceRootSchema3.optional(),
|
|
9389
|
+
basePath: basePathSchema3,
|
|
8695
9390
|
editor: editorConfigSchema3.optional(),
|
|
8696
9391
|
authPlugin: z12.custom().optional(),
|
|
8697
9392
|
entryLinkUrl: z12.custom().optional(),
|
|
@@ -8778,13 +9473,13 @@ var init_content_index_generation = __esm({
|
|
|
8778
9473
|
});
|
|
8779
9474
|
|
|
8780
9475
|
// dist/sync-core.js
|
|
8781
|
-
import
|
|
8782
|
-
import
|
|
9476
|
+
import fs21 from "node:fs/promises";
|
|
9477
|
+
import path25 from "node:path";
|
|
8783
9478
|
import { simpleGit as simpleGit4 } from "simple-git";
|
|
8784
9479
|
function assertWithinDir(resolved, parent, label) {
|
|
8785
|
-
const normalizedResolved =
|
|
8786
|
-
const normalizedParent =
|
|
8787
|
-
if (!normalizedResolved.startsWith(normalizedParent +
|
|
9480
|
+
const normalizedResolved = path25.resolve(resolved);
|
|
9481
|
+
const normalizedParent = path25.resolve(parent);
|
|
9482
|
+
if (!normalizedResolved.startsWith(normalizedParent + path25.sep) && normalizedResolved !== normalizedParent) {
|
|
8788
9483
|
throw new Error(`${label} escapes the expected directory: ${resolved}`);
|
|
8789
9484
|
}
|
|
8790
9485
|
}
|
|
@@ -8792,19 +9487,19 @@ async function safeReplaceDir(oldDir, newDir) {
|
|
|
8792
9487
|
const backupDir = `${oldDir}.sync-backup-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
8793
9488
|
const oldExists = await filePathExists(oldDir);
|
|
8794
9489
|
if (oldExists) {
|
|
8795
|
-
await
|
|
9490
|
+
await fs21.rename(oldDir, backupDir);
|
|
8796
9491
|
}
|
|
8797
9492
|
try {
|
|
8798
|
-
await
|
|
9493
|
+
await fs21.rename(newDir, oldDir);
|
|
8799
9494
|
} catch (err) {
|
|
8800
9495
|
if (oldExists) {
|
|
8801
|
-
await
|
|
9496
|
+
await fs21.rename(backupDir, oldDir).catch(() => {
|
|
8802
9497
|
});
|
|
8803
9498
|
}
|
|
8804
9499
|
throw err;
|
|
8805
9500
|
}
|
|
8806
9501
|
if (oldExists) {
|
|
8807
|
-
await
|
|
9502
|
+
await fs21.rm(backupDir, { recursive: true, force: true }).catch(() => {
|
|
8808
9503
|
});
|
|
8809
9504
|
}
|
|
8810
9505
|
}
|
|
@@ -8812,7 +9507,7 @@ async function listFilesRecursive(dir, prefix = "") {
|
|
|
8812
9507
|
const results = [];
|
|
8813
9508
|
let entries;
|
|
8814
9509
|
try {
|
|
8815
|
-
entries = await
|
|
9510
|
+
entries = await fs21.readdir(dir, { withFileTypes: true });
|
|
8816
9511
|
} catch {
|
|
8817
9512
|
return results;
|
|
8818
9513
|
}
|
|
@@ -8823,7 +9518,7 @@ async function listFilesRecursive(dir, prefix = "") {
|
|
|
8823
9518
|
continue;
|
|
8824
9519
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
8825
9520
|
if (entry.isDirectory()) {
|
|
8826
|
-
results.push(...await listFilesRecursive(
|
|
9521
|
+
results.push(...await listFilesRecursive(path25.join(dir, entry.name), rel));
|
|
8827
9522
|
} else {
|
|
8828
9523
|
results.push(rel);
|
|
8829
9524
|
}
|
|
@@ -8831,19 +9526,19 @@ async function listFilesRecursive(dir, prefix = "") {
|
|
|
8831
9526
|
return results;
|
|
8832
9527
|
}
|
|
8833
9528
|
async function copyDir(src, dest) {
|
|
8834
|
-
await
|
|
8835
|
-
const entries = await
|
|
9529
|
+
await fs21.mkdir(dest, { recursive: true });
|
|
9530
|
+
const entries = await fs21.readdir(src, { withFileTypes: true });
|
|
8836
9531
|
for (const entry of entries) {
|
|
8837
9532
|
if (entry.name === ".git")
|
|
8838
9533
|
continue;
|
|
8839
9534
|
if (entry.isSymbolicLink())
|
|
8840
9535
|
continue;
|
|
8841
|
-
const srcPath =
|
|
8842
|
-
const destPath =
|
|
9536
|
+
const srcPath = path25.join(src, entry.name);
|
|
9537
|
+
const destPath = path25.join(dest, entry.name);
|
|
8843
9538
|
if (entry.isDirectory()) {
|
|
8844
9539
|
await copyDir(srcPath, destPath);
|
|
8845
9540
|
} else {
|
|
8846
|
-
await
|
|
9541
|
+
await fs21.copyFile(srcPath, destPath);
|
|
8847
9542
|
}
|
|
8848
9543
|
}
|
|
8849
9544
|
}
|
|
@@ -8852,14 +9547,14 @@ async function pushContentToWorkspace(options) {
|
|
|
8852
9547
|
if (!await filePathExists(srcContentDir)) {
|
|
8853
9548
|
return { fileCount: 0 };
|
|
8854
9549
|
}
|
|
8855
|
-
const wsContentDir =
|
|
9550
|
+
const wsContentDir = path25.join(branchPath, contentRoot);
|
|
8856
9551
|
assertWithinDir(wsContentDir, branchPath, "content-root");
|
|
8857
9552
|
const tmpDir = `${wsContentDir}.sync-tmp-${Date.now()}`;
|
|
8858
9553
|
try {
|
|
8859
9554
|
await copyDir(srcContentDir, tmpDir);
|
|
8860
9555
|
await safeReplaceDir(wsContentDir, tmpDir);
|
|
8861
9556
|
} catch (err) {
|
|
8862
|
-
await
|
|
9557
|
+
await fs21.rm(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
8863
9558
|
});
|
|
8864
9559
|
throw err;
|
|
8865
9560
|
}
|
|
@@ -8903,19 +9598,21 @@ import lockfile3 from "proper-lockfile";
|
|
|
8903
9598
|
var init_provisioning_lock = __esm({
|
|
8904
9599
|
"dist/utils/provisioning-lock.js"() {
|
|
8905
9600
|
"use strict";
|
|
9601
|
+
init_error();
|
|
9602
|
+
init_logger3();
|
|
8906
9603
|
}
|
|
8907
9604
|
});
|
|
8908
9605
|
|
|
8909
9606
|
// dist/git-manager.js
|
|
8910
|
-
import
|
|
8911
|
-
import
|
|
9607
|
+
import fs24 from "node:fs/promises";
|
|
9608
|
+
import path26 from "node:path";
|
|
8912
9609
|
import { simpleGit as simpleGit6 } from "simple-git";
|
|
8913
9610
|
async function ensureGitExcludePattern2(repoPath, pattern) {
|
|
8914
|
-
const excludePath =
|
|
8915
|
-
await
|
|
9611
|
+
const excludePath = path26.join(repoPath, ".git", "info", "exclude");
|
|
9612
|
+
await fs24.mkdir(path26.dirname(excludePath), { recursive: true });
|
|
8916
9613
|
let content = "";
|
|
8917
9614
|
try {
|
|
8918
|
-
content = await
|
|
9615
|
+
content = await fs24.readFile(excludePath, "utf-8");
|
|
8919
9616
|
} catch (err) {
|
|
8920
9617
|
if (!isNotFoundError(err))
|
|
8921
9618
|
throw err;
|
|
@@ -8927,7 +9624,7 @@ async function ensureGitExcludePattern2(repoPath, pattern) {
|
|
|
8927
9624
|
}
|
|
8928
9625
|
const needsLeadingNewline = content.length > 0 && !content.endsWith("\n");
|
|
8929
9626
|
const newContent = content + (needsLeadingNewline ? "\n" : "") + pattern + "\n";
|
|
8930
|
-
await
|
|
9627
|
+
await fs24.writeFile(excludePath, newContent, "utf-8");
|
|
8931
9628
|
log9.debug("git", "Added pattern to .git/info/exclude", { pattern });
|
|
8932
9629
|
}
|
|
8933
9630
|
var log9;
|
|
@@ -9084,7 +9781,7 @@ var init_config5 = __esm({
|
|
|
9084
9781
|
});
|
|
9085
9782
|
|
|
9086
9783
|
// dist/operating-mode/client-unsafe-strategy.js
|
|
9087
|
-
import
|
|
9784
|
+
import path27 from "node:path";
|
|
9088
9785
|
function operatingStrategy3(mode) {
|
|
9089
9786
|
const cached = strategyCache3.get(mode);
|
|
9090
9787
|
if (cached)
|
|
@@ -9119,32 +9816,32 @@ var init_client_unsafe_strategy2 = __esm({
|
|
|
9119
9816
|
// - shouldCommit(), shouldPush()
|
|
9120
9817
|
// Add client-unsafe methods (use Node.js APIs)
|
|
9121
9818
|
getWorkspaceRoot(_sourceRoot) {
|
|
9122
|
-
return
|
|
9819
|
+
return path27.resolve(process.env.CANOPYCMS_WORKSPACE_ROOT ?? DEFAULT_PROD_WORKSPACE3);
|
|
9123
9820
|
}
|
|
9124
9821
|
getContentRoot(contentRoot, sourceRoot) {
|
|
9125
|
-
return
|
|
9822
|
+
return path27.resolve(sourceRoot ?? process.cwd(), contentRoot);
|
|
9126
9823
|
}
|
|
9127
9824
|
getContentBranchesRoot(sourceRoot) {
|
|
9128
|
-
return
|
|
9825
|
+
return path27.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
|
|
9129
9826
|
}
|
|
9130
9827
|
getContentBranchRoot(branchName, sourceRoot) {
|
|
9131
|
-
return
|
|
9828
|
+
return path27.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
|
|
9132
9829
|
}
|
|
9133
9830
|
getGitExcludePattern() {
|
|
9134
9831
|
return ".canopy-meta/";
|
|
9135
9832
|
}
|
|
9136
9833
|
getPermissionsFilePath(root) {
|
|
9137
|
-
return
|
|
9834
|
+
return path27.join(root, this.getPermissionsFileName());
|
|
9138
9835
|
}
|
|
9139
9836
|
getGroupsFilePath(root) {
|
|
9140
|
-
return
|
|
9837
|
+
return path27.join(root, this.getGroupsFileName());
|
|
9141
9838
|
}
|
|
9142
9839
|
getRemoteUrlConfig() {
|
|
9143
9840
|
return {
|
|
9144
9841
|
shouldAutoInitLocal: false,
|
|
9145
9842
|
defaultRemotePath: "",
|
|
9146
9843
|
envVarName: "CANOPYCMS_REMOTE_URL",
|
|
9147
|
-
autoDetectRemotePath:
|
|
9844
|
+
autoDetectRemotePath: path27.join(this.getWorkspaceRoot(), "remote.git")
|
|
9148
9845
|
};
|
|
9149
9846
|
}
|
|
9150
9847
|
requiresExistingRepo() {
|
|
@@ -9156,7 +9853,7 @@ var init_client_unsafe_strategy2 = __esm({
|
|
|
9156
9853
|
return `canopycms-settings-${resolveDeploymentName3(config, "prod")}`;
|
|
9157
9854
|
}
|
|
9158
9855
|
getSettingsRoot(sourceRoot) {
|
|
9159
|
-
return
|
|
9856
|
+
return path27.join(this.getWorkspaceRoot(sourceRoot), "settings");
|
|
9160
9857
|
}
|
|
9161
9858
|
usesSeparateSettingsBranch() {
|
|
9162
9859
|
return true;
|
|
@@ -9173,25 +9870,25 @@ var init_client_unsafe_strategy2 = __esm({
|
|
|
9173
9870
|
DevStrategy3 = class extends DevClientSafeStrategy3 {
|
|
9174
9871
|
// Inherits client-safe methods from DevClientSafeStrategy
|
|
9175
9872
|
getWorkspaceRoot(sourceRoot) {
|
|
9176
|
-
return
|
|
9873
|
+
return path27.resolve(sourceRoot ?? process.cwd(), ".canopy-dev");
|
|
9177
9874
|
}
|
|
9178
9875
|
getContentRoot(contentRoot, sourceRoot) {
|
|
9179
|
-
return
|
|
9876
|
+
return path27.resolve(sourceRoot ?? process.cwd(), contentRoot);
|
|
9180
9877
|
}
|
|
9181
9878
|
getContentBranchesRoot(sourceRoot) {
|
|
9182
|
-
return
|
|
9879
|
+
return path27.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
|
|
9183
9880
|
}
|
|
9184
9881
|
getContentBranchRoot(branchName, sourceRoot) {
|
|
9185
|
-
return
|
|
9882
|
+
return path27.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
|
|
9186
9883
|
}
|
|
9187
9884
|
getGitExcludePattern() {
|
|
9188
9885
|
return ".canopy-meta/";
|
|
9189
9886
|
}
|
|
9190
9887
|
getPermissionsFilePath(root) {
|
|
9191
|
-
return
|
|
9888
|
+
return path27.join(root, this.getPermissionsFileName());
|
|
9192
9889
|
}
|
|
9193
9890
|
getGroupsFilePath(root) {
|
|
9194
|
-
return
|
|
9891
|
+
return path27.join(root, this.getGroupsFileName());
|
|
9195
9892
|
}
|
|
9196
9893
|
getRemoteUrlConfig() {
|
|
9197
9894
|
return {
|
|
@@ -9209,7 +9906,7 @@ var init_client_unsafe_strategy2 = __esm({
|
|
|
9209
9906
|
return `canopycms-settings-${resolveDeploymentName3(config, "local")}`;
|
|
9210
9907
|
}
|
|
9211
9908
|
getSettingsRoot(sourceRoot) {
|
|
9212
|
-
return
|
|
9909
|
+
return path27.join(this.getWorkspaceRoot(sourceRoot), "settings");
|
|
9213
9910
|
}
|
|
9214
9911
|
usesSeparateSettingsBranch() {
|
|
9215
9912
|
return true;
|
|
@@ -9241,8 +9938,8 @@ __export(sync_exports, {
|
|
|
9241
9938
|
SyncError: () => SyncError,
|
|
9242
9939
|
sync: () => sync
|
|
9243
9940
|
});
|
|
9244
|
-
import
|
|
9245
|
-
import
|
|
9941
|
+
import fs25 from "node:fs/promises";
|
|
9942
|
+
import path28 from "node:path";
|
|
9246
9943
|
import { simpleGit as simpleGit7 } from "simple-git";
|
|
9247
9944
|
import * as p2 from "@clack/prompts";
|
|
9248
9945
|
async function detectCurrentBranch(projectDir) {
|
|
@@ -9255,7 +9952,7 @@ async function detectCurrentBranch(projectDir) {
|
|
|
9255
9952
|
async function selectBranch(options, branchesDir) {
|
|
9256
9953
|
let branches = [];
|
|
9257
9954
|
if (await filePathExists(branchesDir)) {
|
|
9258
|
-
const entries = await
|
|
9955
|
+
const entries = await fs25.readdir(branchesDir, { withFileTypes: true });
|
|
9259
9956
|
branches = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name);
|
|
9260
9957
|
}
|
|
9261
9958
|
let branchName = options.branch;
|
|
@@ -9283,11 +9980,11 @@ async function selectBranch(options, branchesDir) {
|
|
|
9283
9980
|
branchName = result;
|
|
9284
9981
|
}
|
|
9285
9982
|
}
|
|
9286
|
-
const branchPath =
|
|
9983
|
+
const branchPath = path28.join(branchesDir, branchName);
|
|
9287
9984
|
assertWithinDir(branchPath, branchesDir, "--branch");
|
|
9288
9985
|
if (!branches.includes(branchName)) {
|
|
9289
9986
|
if (options.autoCreate) {
|
|
9290
|
-
await
|
|
9987
|
+
await fs25.mkdir(branchPath, { recursive: true });
|
|
9291
9988
|
const wsGit = simpleGit7({ baseDir: branchPath });
|
|
9292
9989
|
await wsGit.init();
|
|
9293
9990
|
await wsGit.checkoutLocalBranch(branchName);
|
|
@@ -9304,8 +10001,8 @@ async function selectBranch(options, branchesDir) {
|
|
|
9304
10001
|
async function syncPush(options) {
|
|
9305
10002
|
const { projectDir } = options;
|
|
9306
10003
|
const contentRoot = options.contentRoot || "content";
|
|
9307
|
-
const branchesDir =
|
|
9308
|
-
const srcContentDir =
|
|
10004
|
+
const branchesDir = path28.join(projectDir, ".canopy-dev", "content-branches");
|
|
10005
|
+
const srcContentDir = path28.join(projectDir, contentRoot);
|
|
9309
10006
|
assertWithinDir(srcContentDir, projectDir, "--content-root");
|
|
9310
10007
|
if (!await filePathExists(srcContentDir)) {
|
|
9311
10008
|
throw new SyncError(`Content directory not found: ${contentRoot}/ (expected at ${srcContentDir})`);
|
|
@@ -9313,7 +10010,7 @@ async function syncPush(options) {
|
|
|
9313
10010
|
const branchName = await selectBranch({ ...options, projectDir, autoCreate: true }, branchesDir);
|
|
9314
10011
|
if (!branchName)
|
|
9315
10012
|
return { fileCount: 0 };
|
|
9316
|
-
const branchPath =
|
|
10013
|
+
const branchPath = path28.join(branchesDir, branchName);
|
|
9317
10014
|
assertWithinDir(branchPath, branchesDir, "--branch");
|
|
9318
10015
|
const wsGit = simpleGit7({ baseDir: branchPath });
|
|
9319
10016
|
const status = await wsGit.status();
|
|
@@ -9371,19 +10068,19 @@ async function syncPush(options) {
|
|
|
9371
10068
|
async function syncPull(options) {
|
|
9372
10069
|
const { projectDir } = options;
|
|
9373
10070
|
const contentRoot = options.contentRoot || "content";
|
|
9374
|
-
const branchesDir =
|
|
10071
|
+
const branchesDir = path28.join(projectDir, ".canopy-dev", "content-branches");
|
|
9375
10072
|
const branchName = await selectBranch({ ...options, projectDir }, branchesDir);
|
|
9376
10073
|
if (!branchName)
|
|
9377
10074
|
return { fileCount: 0 };
|
|
9378
|
-
const branchPath =
|
|
10075
|
+
const branchPath = path28.join(branchesDir, branchName);
|
|
9379
10076
|
assertWithinDir(branchPath, branchesDir, "--branch");
|
|
9380
|
-
const branchContentDir =
|
|
10077
|
+
const branchContentDir = path28.join(branchPath, contentRoot);
|
|
9381
10078
|
assertWithinDir(branchContentDir, branchPath, "--content-root");
|
|
9382
10079
|
if (!await filePathExists(branchContentDir)) {
|
|
9383
10080
|
throw new SyncError(`Content directory not found in branch workspace: ${branchName}/${contentRoot}`);
|
|
9384
10081
|
}
|
|
9385
10082
|
p2.log.step(`Pulling content from branch: ${branchName}`);
|
|
9386
|
-
const destContentDir =
|
|
10083
|
+
const destContentDir = path28.join(projectDir, contentRoot);
|
|
9387
10084
|
assertWithinDir(destContentDir, projectDir, "--content-root");
|
|
9388
10085
|
const sourceGit = simpleGit7({ baseDir: projectDir });
|
|
9389
10086
|
const status = await sourceGit.status();
|
|
@@ -9435,7 +10132,7 @@ async function syncPull(options) {
|
|
|
9435
10132
|
await copyDir(branchContentDir, tmpDestDir);
|
|
9436
10133
|
await safeReplaceDir(destContentDir, tmpDestDir);
|
|
9437
10134
|
} catch (err) {
|
|
9438
|
-
await
|
|
10135
|
+
await fs25.rm(tmpDestDir, { recursive: true, force: true }).catch(() => {
|
|
9439
10136
|
});
|
|
9440
10137
|
throw err;
|
|
9441
10138
|
}
|
|
@@ -9459,8 +10156,8 @@ async function syncPull(options) {
|
|
|
9459
10156
|
async function syncBoth(options) {
|
|
9460
10157
|
const { projectDir } = options;
|
|
9461
10158
|
const contentRoot = options.contentRoot || "content";
|
|
9462
|
-
const branchesDir =
|
|
9463
|
-
const srcContentDir =
|
|
10159
|
+
const branchesDir = path28.join(projectDir, ".canopy-dev", "content-branches");
|
|
10160
|
+
const srcContentDir = path28.join(projectDir, contentRoot);
|
|
9464
10161
|
assertWithinDir(srcContentDir, projectDir, "--content-root");
|
|
9465
10162
|
if (!await filePathExists(srcContentDir)) {
|
|
9466
10163
|
throw new SyncError(`Content directory not found: ${contentRoot}/ (expected at ${srcContentDir})`);
|
|
@@ -9468,7 +10165,7 @@ async function syncBoth(options) {
|
|
|
9468
10165
|
const branchName = await selectBranch({ ...options, projectDir, autoCreate: true }, branchesDir);
|
|
9469
10166
|
if (!branchName)
|
|
9470
10167
|
return { pushed: 0, pulled: 0 };
|
|
9471
|
-
const branchPath =
|
|
10168
|
+
const branchPath = path28.join(branchesDir, branchName);
|
|
9472
10169
|
assertWithinDir(branchPath, branchesDir, "--branch");
|
|
9473
10170
|
const wsGit = simpleGit7({ baseDir: branchPath });
|
|
9474
10171
|
const status = await wsGit.status();
|
|
@@ -9503,14 +10200,14 @@ async function syncBoth(options) {
|
|
|
9503
10200
|
try {
|
|
9504
10201
|
const incomingBranch = `sync-incoming-${Date.now()}`;
|
|
9505
10202
|
await wsGit.raw(["checkout", "-b", incomingBranch, baseRef]);
|
|
9506
|
-
const wsContentDir =
|
|
10203
|
+
const wsContentDir = path28.join(branchPath, contentRoot);
|
|
9507
10204
|
assertWithinDir(wsContentDir, branchPath, "--content-root");
|
|
9508
10205
|
const tmpDir = `${wsContentDir}.sync-tmp-${Date.now()}`;
|
|
9509
10206
|
try {
|
|
9510
10207
|
await copyDir(srcContentDir, tmpDir);
|
|
9511
10208
|
await safeReplaceDir(wsContentDir, tmpDir);
|
|
9512
10209
|
} catch (err) {
|
|
9513
|
-
await
|
|
10210
|
+
await fs25.rm(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
9514
10211
|
});
|
|
9515
10212
|
await wsGit.checkout(currentBranch);
|
|
9516
10213
|
await wsGit.raw(["branch", "-D", incomingBranch]).catch(() => {
|
|
@@ -9567,11 +10264,11 @@ async function syncBoth(options) {
|
|
|
9567
10264
|
}
|
|
9568
10265
|
async function syncAbort(options) {
|
|
9569
10266
|
const { projectDir } = options;
|
|
9570
|
-
const branchesDir =
|
|
10267
|
+
const branchesDir = path28.join(projectDir, ".canopy-dev", "content-branches");
|
|
9571
10268
|
const branchName = await selectBranch({ ...options, projectDir }, branchesDir);
|
|
9572
10269
|
if (!branchName)
|
|
9573
10270
|
return;
|
|
9574
|
-
const branchPath =
|
|
10271
|
+
const branchPath = path28.join(branchesDir, branchName);
|
|
9575
10272
|
assertWithinDir(branchPath, branchesDir, "--branch");
|
|
9576
10273
|
const wsGit = simpleGit7({ baseDir: branchPath });
|
|
9577
10274
|
const status = await wsGit.status();
|
|
@@ -9699,8 +10396,8 @@ var init_async_mutex = __esm({
|
|
|
9699
10396
|
});
|
|
9700
10397
|
|
|
9701
10398
|
// dist/utils/occ-json-write.js
|
|
9702
|
-
import
|
|
9703
|
-
import
|
|
10399
|
+
import fs26 from "node:fs/promises";
|
|
10400
|
+
import path29 from "node:path";
|
|
9704
10401
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
9705
10402
|
import lockfile4 from "proper-lockfile";
|
|
9706
10403
|
async function writeOccJsonFile2(filePath, payload, options) {
|
|
@@ -9709,29 +10406,29 @@ async function writeOccJsonFile2(filePath, payload, options) {
|
|
|
9709
10406
|
const writeId = randomUUID4();
|
|
9710
10407
|
const data = { ...payload, version: newVersion, writeId };
|
|
9711
10408
|
const content = JSON.stringify(data, null, 2) + (trailingNewline ? "\n" : "");
|
|
9712
|
-
const dir =
|
|
9713
|
-
await
|
|
10409
|
+
const dir = path29.dirname(filePath);
|
|
10410
|
+
await fs26.mkdir(dir, { recursive: true });
|
|
9714
10411
|
const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
9715
|
-
await
|
|
10412
|
+
await fs26.writeFile(tempPath, content, "utf-8");
|
|
9716
10413
|
if (expectedVersion === null) {
|
|
9717
10414
|
try {
|
|
9718
|
-
await
|
|
10415
|
+
await fs26.link(tempPath, filePath);
|
|
9719
10416
|
} catch (err) {
|
|
9720
|
-
await
|
|
10417
|
+
await fs26.unlink(tempPath).catch(() => {
|
|
9721
10418
|
});
|
|
9722
10419
|
if (isFileExistsError(err)) {
|
|
9723
10420
|
throw new OccWriteConflictError2();
|
|
9724
10421
|
}
|
|
9725
10422
|
throw err;
|
|
9726
10423
|
}
|
|
9727
|
-
await
|
|
10424
|
+
await fs26.unlink(tempPath).catch(() => {
|
|
9728
10425
|
});
|
|
9729
10426
|
return { version: newVersion, writeId };
|
|
9730
10427
|
}
|
|
9731
10428
|
try {
|
|
9732
10429
|
let currentVersion = null;
|
|
9733
10430
|
try {
|
|
9734
|
-
const current = JSON.parse(await
|
|
10431
|
+
const current = JSON.parse(await fs26.readFile(filePath, "utf-8"));
|
|
9735
10432
|
currentVersion = current.version ?? 0;
|
|
9736
10433
|
} catch {
|
|
9737
10434
|
currentVersion = null;
|
|
@@ -9739,16 +10436,16 @@ async function writeOccJsonFile2(filePath, payload, options) {
|
|
|
9739
10436
|
if (currentVersion !== expectedVersion) {
|
|
9740
10437
|
throw new OccWriteConflictError2();
|
|
9741
10438
|
}
|
|
9742
|
-
await
|
|
10439
|
+
await fs26.rename(tempPath, filePath);
|
|
9743
10440
|
if (settleMs > 0) {
|
|
9744
10441
|
await new Promise((resolve2) => setTimeout(resolve2, settleMs));
|
|
9745
10442
|
}
|
|
9746
|
-
const afterWrite = JSON.parse(await
|
|
10443
|
+
const afterWrite = JSON.parse(await fs26.readFile(filePath, "utf-8"));
|
|
9747
10444
|
if (afterWrite.writeId !== writeId) {
|
|
9748
10445
|
throw new OccWriteConflictError2();
|
|
9749
10446
|
}
|
|
9750
10447
|
} catch (err) {
|
|
9751
|
-
await
|
|
10448
|
+
await fs26.unlink(tempPath).catch(() => {
|
|
9752
10449
|
});
|
|
9753
10450
|
throw err;
|
|
9754
10451
|
}
|
|
@@ -9774,8 +10471,8 @@ async function withOccRetry2(operation, options) {
|
|
|
9774
10471
|
throw new Error("Unreachable");
|
|
9775
10472
|
}
|
|
9776
10473
|
async function withOccFileLock2(filePath, fn) {
|
|
9777
|
-
const dir =
|
|
9778
|
-
await
|
|
10474
|
+
const dir = path29.dirname(filePath);
|
|
10475
|
+
await fs26.mkdir(dir, { recursive: true });
|
|
9779
10476
|
const MAX_ATTEMPTS = 14;
|
|
9780
10477
|
let release = null;
|
|
9781
10478
|
for (let attempt = 1; release === null; attempt++) {
|
|
@@ -9834,8 +10531,8 @@ var init_occ_json_write = __esm({
|
|
|
9834
10531
|
});
|
|
9835
10532
|
|
|
9836
10533
|
// dist/branch-registry.js
|
|
9837
|
-
import
|
|
9838
|
-
import
|
|
10534
|
+
import fs27 from "node:fs/promises";
|
|
10535
|
+
import path30 from "node:path";
|
|
9839
10536
|
var log12, REGISTRY_FILE2, REGISTRY_STALE_FILE2, REGISTRY_TEMP_FILE2, REGISTRY_VERSION2, RESOURCE4, GET_MISS_REFRESH_MIN_INTERVAL_MS2, BranchRegistry2;
|
|
9840
10537
|
var init_branch_registry = __esm({
|
|
9841
10538
|
"dist/branch-registry.js"() {
|
|
@@ -9856,10 +10553,10 @@ var init_branch_registry = __esm({
|
|
|
9856
10553
|
constructor(root) {
|
|
9857
10554
|
this.regenInFlight = null;
|
|
9858
10555
|
this.lastForcedRefreshMs = 0;
|
|
9859
|
-
this.root =
|
|
9860
|
-
this.registryPath =
|
|
9861
|
-
this.stalePath =
|
|
9862
|
-
this.tempPath =
|
|
10556
|
+
this.root = path30.resolve(root);
|
|
10557
|
+
this.registryPath = path30.join(this.root, REGISTRY_FILE2);
|
|
10558
|
+
this.stalePath = path30.join(this.root, REGISTRY_STALE_FILE2);
|
|
10559
|
+
this.tempPath = path30.join(this.root, REGISTRY_TEMP_FILE2);
|
|
9863
10560
|
}
|
|
9864
10561
|
/**
|
|
9865
10562
|
* Returns all branches. Uses the cached snapshot if its embedded generation
|
|
@@ -9868,7 +10565,7 @@ var init_branch_registry = __esm({
|
|
|
9868
10565
|
async list() {
|
|
9869
10566
|
let parsed;
|
|
9870
10567
|
try {
|
|
9871
|
-
const raw = await
|
|
10568
|
+
const raw = await fs27.readFile(this.registryPath, "utf8");
|
|
9872
10569
|
parsed = JSON.parse(raw);
|
|
9873
10570
|
} catch (err) {
|
|
9874
10571
|
if (isNotFoundError(err)) {
|
|
@@ -9957,7 +10654,7 @@ var init_branch_registry = __esm({
|
|
|
9957
10654
|
async performRegenerate() {
|
|
9958
10655
|
const read = await readResourceGeneration2(this.root, RESOURCE4);
|
|
9959
10656
|
const branches = await this.scanBranchDirectories();
|
|
9960
|
-
await
|
|
10657
|
+
await fs27.unlink(this.stalePath).catch(() => {
|
|
9961
10658
|
});
|
|
9962
10659
|
if (!read.ok) {
|
|
9963
10660
|
return branches;
|
|
@@ -9968,12 +10665,12 @@ var init_branch_registry = __esm({
|
|
|
9968
10665
|
generation: read.token
|
|
9969
10666
|
};
|
|
9970
10667
|
const uniqueTempPath = `${this.tempPath}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
9971
|
-
await
|
|
9972
|
-
await
|
|
10668
|
+
await fs27.mkdir(this.root, { recursive: true });
|
|
10669
|
+
await fs27.writeFile(uniqueTempPath, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
|
|
9973
10670
|
try {
|
|
9974
|
-
await
|
|
10671
|
+
await fs27.rename(uniqueTempPath, this.registryPath);
|
|
9975
10672
|
} catch (err) {
|
|
9976
|
-
await
|
|
10673
|
+
await fs27.unlink(uniqueTempPath).catch(() => {
|
|
9977
10674
|
});
|
|
9978
10675
|
throw err;
|
|
9979
10676
|
}
|
|
@@ -9987,12 +10684,12 @@ var init_branch_registry = __esm({
|
|
|
9987
10684
|
async scanBranchDirectories() {
|
|
9988
10685
|
const branches = [];
|
|
9989
10686
|
try {
|
|
9990
|
-
const entries = await
|
|
10687
|
+
const entries = await fs27.readdir(this.root, { withFileTypes: true });
|
|
9991
10688
|
for (const entry of entries) {
|
|
9992
10689
|
if (!entry.isDirectory() || entry.name.startsWith(".")) {
|
|
9993
10690
|
continue;
|
|
9994
10691
|
}
|
|
9995
|
-
const branchRoot =
|
|
10692
|
+
const branchRoot = path30.join(this.root, entry.name);
|
|
9996
10693
|
let meta;
|
|
9997
10694
|
try {
|
|
9998
10695
|
meta = await BranchMetadataFileManager2.loadOnly(branchRoot);
|
|
@@ -10021,8 +10718,8 @@ var init_branch_registry = __esm({
|
|
|
10021
10718
|
});
|
|
10022
10719
|
|
|
10023
10720
|
// dist/branch-metadata.js
|
|
10024
|
-
import
|
|
10025
|
-
import
|
|
10721
|
+
import fs28 from "node:fs/promises";
|
|
10722
|
+
import path31 from "node:path";
|
|
10026
10723
|
var BRANCH_META_DIR2, BRANCH_META_FILE2, CURRENT_SCHEMA_VERSION2, BranchMetadataConflictError2, BranchMetadataCorruptError2, BranchMetadataFileManager2;
|
|
10027
10724
|
var init_branch_metadata = __esm({
|
|
10028
10725
|
"dist/branch-metadata.js"() {
|
|
@@ -10051,8 +10748,8 @@ var init_branch_metadata = __esm({
|
|
|
10051
10748
|
};
|
|
10052
10749
|
BranchMetadataFileManager2 = class _BranchMetadataFileManager2 {
|
|
10053
10750
|
constructor(branchRoot, baseRoot, options) {
|
|
10054
|
-
this.branchRoot =
|
|
10055
|
-
this.filePath =
|
|
10751
|
+
this.branchRoot = path31.resolve(branchRoot);
|
|
10752
|
+
this.filePath = path31.join(this.branchRoot, BRANCH_META_DIR2, BRANCH_META_FILE2);
|
|
10056
10753
|
this.baseRoot = baseRoot;
|
|
10057
10754
|
this.settleMs = options?.settleMs;
|
|
10058
10755
|
}
|
|
@@ -10061,10 +10758,10 @@ var init_branch_metadata = __esm({
|
|
|
10061
10758
|
* Use this for read-only access (e.g., in registry scanning or loadBranchContext).
|
|
10062
10759
|
*/
|
|
10063
10760
|
static async loadOnly(branchRoot) {
|
|
10064
|
-
const resolvedRoot =
|
|
10065
|
-
const filePath =
|
|
10761
|
+
const resolvedRoot = path31.resolve(branchRoot);
|
|
10762
|
+
const filePath = path31.join(resolvedRoot, BRANCH_META_DIR2, BRANCH_META_FILE2);
|
|
10066
10763
|
try {
|
|
10067
|
-
const raw = await
|
|
10764
|
+
const raw = await fs28.readFile(filePath, "utf8");
|
|
10068
10765
|
return JSON.parse(raw);
|
|
10069
10766
|
} catch (err) {
|
|
10070
10767
|
if (isNotFoundError(err)) {
|
|
@@ -10085,7 +10782,7 @@ var init_branch_metadata = __esm({
|
|
|
10085
10782
|
}
|
|
10086
10783
|
async load() {
|
|
10087
10784
|
try {
|
|
10088
|
-
const raw = await
|
|
10785
|
+
const raw = await fs28.readFile(this.filePath, "utf8");
|
|
10089
10786
|
const parsed = JSON.parse(raw);
|
|
10090
10787
|
const version = parsed.version ?? 0;
|
|
10091
10788
|
return { meta: parsed, version };
|
|
@@ -10147,7 +10844,7 @@ var init_branch_metadata = __esm({
|
|
|
10147
10844
|
*/
|
|
10148
10845
|
async save(incoming) {
|
|
10149
10846
|
try {
|
|
10150
|
-
await
|
|
10847
|
+
await fs28.stat(this.branchRoot);
|
|
10151
10848
|
} catch (err) {
|
|
10152
10849
|
if (isNotFoundError(err)) {
|
|
10153
10850
|
throw new BranchMetadataConflictError2("Branch no longer exists");
|
|
@@ -10222,8 +10919,8 @@ __export(migrate_exports, {
|
|
|
10222
10919
|
migrate: () => migrate,
|
|
10223
10920
|
slugifyName: () => slugifyName
|
|
10224
10921
|
});
|
|
10225
|
-
import
|
|
10226
|
-
import
|
|
10922
|
+
import fs29 from "node:fs/promises";
|
|
10923
|
+
import path33 from "node:path";
|
|
10227
10924
|
import * as p3 from "@clack/prompts";
|
|
10228
10925
|
function slugifyName(name) {
|
|
10229
10926
|
const slug = name.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -10231,7 +10928,7 @@ function slugifyName(name) {
|
|
|
10231
10928
|
}
|
|
10232
10929
|
function toValidSlug(name) {
|
|
10233
10930
|
const slug = slugifyName(name);
|
|
10234
|
-
const parsed =
|
|
10931
|
+
const parsed = parseSlug2(slug);
|
|
10235
10932
|
if (!parsed.ok) {
|
|
10236
10933
|
throw new MigrateError(`Cannot derive a valid slug from "${name}" (got "${slug}"): ${parsed.error}`);
|
|
10237
10934
|
}
|
|
@@ -10248,7 +10945,7 @@ function stripDirIdSuffix(dirName) {
|
|
|
10248
10945
|
return dirName;
|
|
10249
10946
|
}
|
|
10250
10947
|
async function planDirectory(dirPath, isRoot, ctx) {
|
|
10251
|
-
const entries = await
|
|
10948
|
+
const entries = await fs29.readdir(dirPath, { withFileTypes: true });
|
|
10252
10949
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
10253
10950
|
const ops = [];
|
|
10254
10951
|
let hasOwnFiles = false;
|
|
@@ -10257,7 +10954,7 @@ async function planDirectory(dirPath, isRoot, ctx) {
|
|
|
10257
10954
|
if (entry.name.startsWith("."))
|
|
10258
10955
|
continue;
|
|
10259
10956
|
if (entry.isDirectory()) {
|
|
10260
|
-
const subPath =
|
|
10957
|
+
const subPath = path33.join(dirPath, entry.name);
|
|
10261
10958
|
const sub = await planDirectory(subPath, false, ctx);
|
|
10262
10959
|
if (!sub.hasContent)
|
|
10263
10960
|
continue;
|
|
@@ -10265,10 +10962,10 @@ async function planDirectory(dirPath, isRoot, ctx) {
|
|
|
10265
10962
|
ops.push(...sub.ops);
|
|
10266
10963
|
if (!extractIdFromFilename2(entry.name)) {
|
|
10267
10964
|
const newName = `${toValidSlug(entry.name)}.${generateId2()}`;
|
|
10268
|
-
ops.push({ kind: "rename", from: subPath, to:
|
|
10965
|
+
ops.push({ kind: "rename", from: subPath, to: path33.join(dirPath, newName) });
|
|
10269
10966
|
}
|
|
10270
10967
|
} else if (entry.isFile()) {
|
|
10271
|
-
const ext =
|
|
10968
|
+
const ext = path33.extname(entry.name).slice(1);
|
|
10272
10969
|
const matchesFormat = ext === ctx.format || ctx.format === "yaml" && ext === "yml";
|
|
10273
10970
|
if (!matchesFormat)
|
|
10274
10971
|
continue;
|
|
@@ -10279,17 +10976,17 @@ async function planDirectory(dirPath, isRoot, ctx) {
|
|
|
10279
10976
|
const newName = `${ctx.entryType}.${toValidSlug(base)}.${generateId2()}.${ext}`;
|
|
10280
10977
|
ops.push({
|
|
10281
10978
|
kind: "rename",
|
|
10282
|
-
from:
|
|
10283
|
-
to:
|
|
10979
|
+
from: path33.join(dirPath, entry.name),
|
|
10980
|
+
to: path33.join(dirPath, newName)
|
|
10284
10981
|
});
|
|
10285
10982
|
}
|
|
10286
10983
|
}
|
|
10287
10984
|
}
|
|
10288
10985
|
const needsMeta = isRoot ? hasOwnFiles : hasContent;
|
|
10289
|
-
const metaPath =
|
|
10986
|
+
const metaPath = path33.join(dirPath, ".collection.json");
|
|
10290
10987
|
if (needsMeta && !await filePathExists(metaPath)) {
|
|
10291
10988
|
const entryTypeMeta = { name: ctx.entryType, format: ctx.format, schema: ctx.schema };
|
|
10292
|
-
const meta = isRoot ? { entries: [entryTypeMeta] } : { name: toValidSlug(stripDirIdSuffix(
|
|
10989
|
+
const meta = isRoot ? { entries: [entryTypeMeta] } : { name: toValidSlug(stripDirIdSuffix(path33.basename(dirPath))), entries: [entryTypeMeta] };
|
|
10293
10990
|
ops.push({ kind: "write", filePath: metaPath, content: JSON.stringify(meta, null, 2) + "\n" });
|
|
10294
10991
|
}
|
|
10295
10992
|
return { ops, hasContent };
|
|
@@ -10298,7 +10995,7 @@ async function migrate(options) {
|
|
|
10298
10995
|
const { projectDir } = options;
|
|
10299
10996
|
const contentRoot = options.contentRoot || "content";
|
|
10300
10997
|
p3.intro("CanopyCMS migrate");
|
|
10301
|
-
const contentDir =
|
|
10998
|
+
const contentDir = path33.join(projectDir, contentRoot);
|
|
10302
10999
|
if (!await filePathExists(contentDir)) {
|
|
10303
11000
|
throw new MigrateError(`Content directory not found: ${contentRoot}/ (expected at ${contentDir})`);
|
|
10304
11001
|
}
|
|
@@ -10375,14 +11072,14 @@ async function migrate(options) {
|
|
|
10375
11072
|
const applyOps = async () => {
|
|
10376
11073
|
for (const op of ops) {
|
|
10377
11074
|
if (op.kind === "rename") {
|
|
10378
|
-
await
|
|
11075
|
+
await fs29.rename(op.from, op.to);
|
|
10379
11076
|
} else {
|
|
10380
|
-
await
|
|
11077
|
+
await fs29.writeFile(op.filePath, op.content, "utf-8");
|
|
10381
11078
|
}
|
|
10382
11079
|
}
|
|
10383
11080
|
};
|
|
10384
11081
|
if (isBranchClone) {
|
|
10385
|
-
const lockPath =
|
|
11082
|
+
const lockPath = path33.join(projectDir, ".canopy-meta", "schema");
|
|
10386
11083
|
try {
|
|
10387
11084
|
await withLock2(lockPath, () => withOccFileLock2(lockPath, applyOps));
|
|
10388
11085
|
} catch (err) {
|
|
@@ -10430,7 +11127,7 @@ var init_migrate = __esm({
|
|
|
10430
11127
|
this.name = "MigrateError";
|
|
10431
11128
|
}
|
|
10432
11129
|
};
|
|
10433
|
-
describeOp = (op, baseDir) => op.kind === "rename" ? `rename ${
|
|
11130
|
+
describeOp = (op, baseDir) => op.kind === "rename" ? `rename ${path33.relative(baseDir, op.from)} \u2192 ${path33.basename(op.to)}` : `create ${path33.relative(baseDir, op.filePath)}`;
|
|
10434
11131
|
}
|
|
10435
11132
|
});
|
|
10436
11133
|
|