canopycms 0.0.63 → 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 +7 -8
- package/dist/ai/index.js +0 -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 +4 -1
- package/dist/ai/to-plain-text.js +47 -1
- package/dist/ai/transform-components.d.ts +1 -2
- package/dist/ai/transform-components.js +0 -1
- 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 +4 -5
- package/dist/authorization/branch.js +0 -1
- 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 +6 -7
- 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 +5 -6
- package/dist/build-canopy.js +0 -1
- 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 +1131 -486
- package/dist/cli/generate-ai-content.d.ts +0 -1
- package/dist/cli/generate-ai-content.js +1000 -360
- 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/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 +75 -59
- package/dist/content-listing.js +76 -83
- package/dist/content-reader.d.ts +4 -5
- package/dist/content-reader.js +22 -3
- package/dist/content-store.d.ts +137 -6
- package/dist/content-store.js +294 -22
- package/dist/content-tree.d.ts +15 -5
- package/dist/content-tree.js +27 -8
- package/dist/context.d.ts +9 -6
- package/dist/context.js +0 -1
- 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 +114 -3
- package/dist/entry-schema.js +46 -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 -18
- package/dist/index.js +0 -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 +54 -45
- package/dist/server.js +11 -3
- package/dist/services.d.ts +10 -11
- package/dist/services.js +0 -1
- package/dist/settings-workspace.d.ts +12 -15
- package/dist/settings-workspace.js +10 -13
- package/dist/static/index.d.ts +164 -6
- package/dist/static/index.js +242 -7
- package/dist/static/seo.d.ts +8 -30
- package/dist/static/seo.js +19 -46
- 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 +2 -3
- package/dist/utils/sanitize-href.js +2 -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/to-plain-text.d.ts.map +0 -1
- package/dist/ai/to-plain-text.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-canopy.d.ts.map +0 -1
- package/dist/build-canopy.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/static/seo.d.ts.map +0 -1
- package/dist/static/seo.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);
|
|
1901
1918
|
}
|
|
1902
|
-
function
|
|
1903
|
-
|
|
1919
|
+
function normalizeFilesystemPath(path212) {
|
|
1920
|
+
return path212.split(/[\\/]+/).filter(Boolean).join("/");
|
|
1921
|
+
}
|
|
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) {
|
|
@@ -2795,7 +3176,7 @@ function renderField(field, value, depth, entry, config) {
|
|
|
2795
3176
|
const heading = "#".repeat(Math.min(depth, 6));
|
|
2796
3177
|
const descriptionLine = "description" in field && field.description ? `
|
|
2797
3178
|
|
|
2798
|
-
|
|
3179
|
+
_${field.description}_` : "";
|
|
2799
3180
|
if ("list" in field && field.list && Array.isArray(value)) {
|
|
2800
3181
|
return renderListField(field, value, depth, label, heading, descriptionLine, entry, config);
|
|
2801
3182
|
}
|
|
@@ -3051,26 +3432,13 @@ function formatInlineValue(field, value) {
|
|
|
3051
3432
|
return String(value);
|
|
3052
3433
|
}
|
|
3053
3434
|
function yamlValue(value) {
|
|
3435
|
+
if (value === "")
|
|
3436
|
+
return '""';
|
|
3054
3437
|
if (/[:#{}[\],&*?|>!%@`]/.test(value) || value.includes("\n")) {
|
|
3055
3438
|
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
3056
3439
|
}
|
|
3057
3440
|
return value;
|
|
3058
3441
|
}
|
|
3059
|
-
function computeEntryUrl(collection, slug, contentRoot) {
|
|
3060
|
-
const root = trimSlashes(contentRoot);
|
|
3061
|
-
let stripped = collection;
|
|
3062
|
-
if (root && collection.startsWith(`${root}/`)) {
|
|
3063
|
-
stripped = collection.slice(root.length + 1);
|
|
3064
|
-
} else if (collection === root) {
|
|
3065
|
-
stripped = "";
|
|
3066
|
-
}
|
|
3067
|
-
const segments = stripped.split("/").filter(Boolean);
|
|
3068
|
-
if (slug && slug !== "index") {
|
|
3069
|
-
segments.push(slug);
|
|
3070
|
-
}
|
|
3071
|
-
const path202 = segments.length > 0 ? `/${segments.join("/")}` : "/";
|
|
3072
|
-
return path202.toLowerCase();
|
|
3073
|
-
}
|
|
3074
3442
|
function resolveEntryUrl(location, contentRoot) {
|
|
3075
3443
|
return computeEntryUrl(location.collection ?? "", location.slug ?? "", contentRoot);
|
|
3076
3444
|
}
|
|
@@ -3237,7 +3605,7 @@ async function processCollection(store, collection, flatSchema, contentRoot, con
|
|
|
3237
3605
|
const listed = await store.getCollectionEntryPaths(collection.logicalPath);
|
|
3238
3606
|
const directEntries = listed.filter((e) => e.collection === collection.logicalPath);
|
|
3239
3607
|
for (const listEntry of directEntries) {
|
|
3240
|
-
const entryTypeName = extractEntryTypeFromFilename(
|
|
3608
|
+
const entryTypeName = extractEntryTypeFromFilename(path12.basename(listEntry.relativePath));
|
|
3241
3609
|
if (!entryTypeName)
|
|
3242
3610
|
continue;
|
|
3243
3611
|
if (config?.exclude?.entryTypes?.includes(entryTypeName))
|
|
@@ -3255,7 +3623,7 @@ async function processCollection(store, collection, flatSchema, contentRoot, con
|
|
|
3255
3623
|
}
|
|
3256
3624
|
if (config?.exclude?.where?.(aiEntry))
|
|
3257
3625
|
continue;
|
|
3258
|
-
await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(
|
|
3626
|
+
await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(path12.basename(listEntry.relativePath)), config);
|
|
3259
3627
|
entries.push(aiEntry);
|
|
3260
3628
|
const entryFilePath = `${cleanPath}/${listEntry.slug}.md`;
|
|
3261
3629
|
const entryMarkdown = entryToMarkdown(aiEntry, config);
|
|
@@ -3306,7 +3674,7 @@ async function processRootEntries(store, rootCollection, contentRoot, config, id
|
|
|
3306
3674
|
const listed = await store.getCollectionEntryPaths(rootCollection.logicalPath);
|
|
3307
3675
|
const directEntries = listed.filter((e) => e.collection === rootCollection.logicalPath);
|
|
3308
3676
|
for (const listEntry of directEntries) {
|
|
3309
|
-
const entryTypeName = extractEntryTypeFromFilename(
|
|
3677
|
+
const entryTypeName = extractEntryTypeFromFilename(path12.basename(listEntry.relativePath));
|
|
3310
3678
|
if (!entryTypeName)
|
|
3311
3679
|
continue;
|
|
3312
3680
|
if (config?.exclude?.entryTypes?.includes(entryTypeName))
|
|
@@ -3324,7 +3692,7 @@ async function processRootEntries(store, rootCollection, contentRoot, config, id
|
|
|
3324
3692
|
}
|
|
3325
3693
|
if (config?.exclude?.where?.(aiEntry))
|
|
3326
3694
|
continue;
|
|
3327
|
-
await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(
|
|
3695
|
+
await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(path12.basename(listEntry.relativePath)), config);
|
|
3328
3696
|
entries.push(aiEntry);
|
|
3329
3697
|
const entryFilePath = `${listEntry.slug}.md`;
|
|
3330
3698
|
const entryMarkdown = entryToMarkdown(aiEntry, config);
|
|
@@ -3372,19 +3740,19 @@ function docToAIEntry(doc, slug, entryTypeName, entryTypeConfig, cleanCollection
|
|
|
3372
3740
|
};
|
|
3373
3741
|
}
|
|
3374
3742
|
function makeReadSibling(dir) {
|
|
3375
|
-
const resolvedDir =
|
|
3743
|
+
const resolvedDir = path12.resolve(dir);
|
|
3376
3744
|
return async (name) => {
|
|
3377
|
-
if (!name || name.includes("/") || name.includes("\\") ||
|
|
3745
|
+
if (!name || name.includes("/") || name.includes("\\") || path12.isAbsolute(name) || hasTraversalSequence(name)) {
|
|
3378
3746
|
return null;
|
|
3379
3747
|
}
|
|
3380
|
-
const abs =
|
|
3381
|
-
if (
|
|
3748
|
+
const abs = path12.resolve(resolvedDir, name);
|
|
3749
|
+
if (path12.dirname(abs) !== resolvedDir)
|
|
3382
3750
|
return null;
|
|
3383
3751
|
try {
|
|
3384
|
-
const stats = await
|
|
3752
|
+
const stats = await fs11.lstat(abs);
|
|
3385
3753
|
if (!stats.isFile())
|
|
3386
3754
|
return null;
|
|
3387
|
-
return await
|
|
3755
|
+
return await fs11.readFile(abs, "utf8");
|
|
3388
3756
|
} catch (err) {
|
|
3389
3757
|
if (isNodeError3(err) && (err.code === "ENOENT" || err.code === "ENOTDIR"))
|
|
3390
3758
|
return null;
|
|
@@ -3398,7 +3766,7 @@ async function runEntryTransform(entry, absolutePath, contentId, config) {
|
|
|
3398
3766
|
return;
|
|
3399
3767
|
const ctx = {
|
|
3400
3768
|
contentId: contentId ?? "",
|
|
3401
|
-
readSibling: makeReadSibling(
|
|
3769
|
+
readSibling: makeReadSibling(path12.dirname(absolutePath))
|
|
3402
3770
|
};
|
|
3403
3771
|
try {
|
|
3404
3772
|
const appended = await transform(entry, ctx);
|
|
@@ -3439,29 +3807,29 @@ async function writeOccJsonFile(filePath, payload, options) {
|
|
|
3439
3807
|
const writeId = randomUUID2();
|
|
3440
3808
|
const data = { ...payload, version: newVersion, writeId };
|
|
3441
3809
|
const content = JSON.stringify(data, null, 2) + (trailingNewline ? "\n" : "");
|
|
3442
|
-
const dir =
|
|
3443
|
-
await
|
|
3810
|
+
const dir = path14.dirname(filePath);
|
|
3811
|
+
await fs13.mkdir(dir, { recursive: true });
|
|
3444
3812
|
const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
3445
|
-
await
|
|
3813
|
+
await fs13.writeFile(tempPath, content, "utf-8");
|
|
3446
3814
|
if (expectedVersion === null) {
|
|
3447
3815
|
try {
|
|
3448
|
-
await
|
|
3816
|
+
await fs13.link(tempPath, filePath);
|
|
3449
3817
|
} catch (err) {
|
|
3450
|
-
await
|
|
3818
|
+
await fs13.unlink(tempPath).catch(() => {
|
|
3451
3819
|
});
|
|
3452
3820
|
if (isFileExistsError2(err)) {
|
|
3453
3821
|
throw new OccWriteConflictError();
|
|
3454
3822
|
}
|
|
3455
3823
|
throw err;
|
|
3456
3824
|
}
|
|
3457
|
-
await
|
|
3825
|
+
await fs13.unlink(tempPath).catch(() => {
|
|
3458
3826
|
});
|
|
3459
3827
|
return { version: newVersion, writeId };
|
|
3460
3828
|
}
|
|
3461
3829
|
try {
|
|
3462
3830
|
let currentVersion = null;
|
|
3463
3831
|
try {
|
|
3464
|
-
const current = JSON.parse(await
|
|
3832
|
+
const current = JSON.parse(await fs13.readFile(filePath, "utf-8"));
|
|
3465
3833
|
currentVersion = current.version ?? 0;
|
|
3466
3834
|
} catch {
|
|
3467
3835
|
currentVersion = null;
|
|
@@ -3469,16 +3837,16 @@ async function writeOccJsonFile(filePath, payload, options) {
|
|
|
3469
3837
|
if (currentVersion !== expectedVersion) {
|
|
3470
3838
|
throw new OccWriteConflictError();
|
|
3471
3839
|
}
|
|
3472
|
-
await
|
|
3840
|
+
await fs13.rename(tempPath, filePath);
|
|
3473
3841
|
if (settleMs > 0) {
|
|
3474
3842
|
await new Promise((resolve2) => setTimeout(resolve2, settleMs));
|
|
3475
3843
|
}
|
|
3476
|
-
const afterWrite = JSON.parse(await
|
|
3844
|
+
const afterWrite = JSON.parse(await fs13.readFile(filePath, "utf-8"));
|
|
3477
3845
|
if (afterWrite.writeId !== writeId) {
|
|
3478
3846
|
throw new OccWriteConflictError();
|
|
3479
3847
|
}
|
|
3480
3848
|
} catch (err) {
|
|
3481
|
-
await
|
|
3849
|
+
await fs13.unlink(tempPath).catch(() => {
|
|
3482
3850
|
});
|
|
3483
3851
|
throw err;
|
|
3484
3852
|
}
|
|
@@ -3504,8 +3872,8 @@ async function withOccRetry(operation, options) {
|
|
|
3504
3872
|
throw new Error("Unreachable");
|
|
3505
3873
|
}
|
|
3506
3874
|
async function withOccFileLock(filePath, fn) {
|
|
3507
|
-
const dir =
|
|
3508
|
-
await
|
|
3875
|
+
const dir = path14.dirname(filePath);
|
|
3876
|
+
await fs13.mkdir(dir, { recursive: true });
|
|
3509
3877
|
const MAX_ATTEMPTS = 14;
|
|
3510
3878
|
let release = null;
|
|
3511
3879
|
for (let attempt = 1; release === null; attempt++) {
|
|
@@ -3589,11 +3957,11 @@ function gitChildEnv(overrides) {
|
|
|
3589
3957
|
return { ...env, ...FORCE_C_LOCALE, ...overrides };
|
|
3590
3958
|
}
|
|
3591
3959
|
async function ensureGitExcludePattern(repoPath, pattern) {
|
|
3592
|
-
const excludePath =
|
|
3593
|
-
await
|
|
3960
|
+
const excludePath = path16.join(repoPath, ".git", "info", "exclude");
|
|
3961
|
+
await fs15.mkdir(path16.dirname(excludePath), { recursive: true });
|
|
3594
3962
|
let content = "";
|
|
3595
3963
|
try {
|
|
3596
|
-
content = await
|
|
3964
|
+
content = await fs15.readFile(excludePath, "utf-8");
|
|
3597
3965
|
} catch (err) {
|
|
3598
3966
|
if (!isNotFoundError3(err))
|
|
3599
3967
|
throw err;
|
|
@@ -3605,7 +3973,7 @@ async function ensureGitExcludePattern(repoPath, pattern) {
|
|
|
3605
3973
|
}
|
|
3606
3974
|
const needsLeadingNewline = content.length > 0 && !content.endsWith("\n");
|
|
3607
3975
|
const newContent = content + (needsLeadingNewline ? "\n" : "") + pattern + "\n";
|
|
3608
|
-
await
|
|
3976
|
+
await fs15.writeFile(excludePath, newContent, "utf-8");
|
|
3609
3977
|
log5.debug("git", "Added pattern to .git/info/exclude", { pattern });
|
|
3610
3978
|
}
|
|
3611
3979
|
async function loadOrCreateBranchContext(options) {
|
|
@@ -3669,10 +4037,12 @@ async function listEntries(branchRoot, flatSchema, contentRootName, options, vis
|
|
|
3669
4037
|
const collections = flatSchema.filter((item) => item.type === "collection" && item.entries !== void 0 && (item.logicalPath === rootPath || item.logicalPath.startsWith(`${rootPath}/`)));
|
|
3670
4038
|
const shouldInclude = visibility?.shouldInclude;
|
|
3671
4039
|
const skippedFiles = [];
|
|
4040
|
+
const resolver = options?.resolveReferences ? createReferenceResolver(branchRoot, flatSchema, contentRootName) : null;
|
|
3672
4041
|
const collectionResults = await Promise.all(collections.map(async (collection) => {
|
|
3673
4042
|
const entries = await listCollectionEntries(branchRoot, collection, (file) => skippedFiles.push(file));
|
|
3674
4043
|
const visible = shouldInclude ? entries.filter((e) => shouldInclude(e.physicalPath)) : entries;
|
|
3675
|
-
|
|
4044
|
+
const resolved = resolver ? await resolveCollectionItemReferences(visible, collection, resolver) : visible;
|
|
4045
|
+
return resolved.map((entry) => ({ entry, collection }));
|
|
3676
4046
|
}));
|
|
3677
4047
|
if (isBuildMode() && skippedFiles.length > 0) {
|
|
3678
4048
|
const lines = skippedFiles.map(({ filename, collectionPath }) => ` - ${collectionPath}/${filename}`);
|
|
@@ -3686,8 +4056,7 @@ Expected {type}.{slug}.{id}.{ext} with a known entry type (a name declared in th
|
|
|
3686
4056
|
for (const { entry, collection } of results) {
|
|
3687
4057
|
const pathWithoutRoot = entry.logicalPath.startsWith(contentPrefix) ? entry.logicalPath.slice(contentPrefix.length) : entry.logicalPath;
|
|
3688
4058
|
const pathSegments = pathWithoutRoot.split("/").filter(Boolean);
|
|
3689
|
-
const
|
|
3690
|
-
const urlPath = urlSegments.length > 0 ? `/${urlSegments.join("/")}`.toLowerCase() : "/";
|
|
4059
|
+
const urlPath = computeEntryUrl(entry.collectionPath, entry.slug, contentRootName);
|
|
3691
4060
|
const raw = entry.data;
|
|
3692
4061
|
const meta = {
|
|
3693
4062
|
entryPath: entry.logicalPath,
|
|
@@ -3732,7 +4101,7 @@ function isValidCropRect(x, y, w, h) {
|
|
|
3732
4101
|
return false;
|
|
3733
4102
|
return true;
|
|
3734
4103
|
}
|
|
3735
|
-
function
|
|
4104
|
+
function isPlainRecord2(value) {
|
|
3736
4105
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3737
4106
|
}
|
|
3738
4107
|
function resolveBlockItem(blockField, item) {
|
|
@@ -3742,17 +4111,17 @@ function resolveBlockItem(blockField, item) {
|
|
|
3742
4111
|
const template = blockField.templates?.find((t) => t.name === templateName);
|
|
3743
4112
|
if (!template?.fields)
|
|
3744
4113
|
return void 0;
|
|
3745
|
-
const data =
|
|
4114
|
+
const data = isPlainRecord2(item.value) ? item.value : item;
|
|
3746
4115
|
return { fields: template.fields, data };
|
|
3747
4116
|
}
|
|
3748
|
-
function
|
|
4117
|
+
function isPlainRecord3(value) {
|
|
3749
4118
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3750
4119
|
}
|
|
3751
4120
|
function isPositiveInt(value) {
|
|
3752
4121
|
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
3753
4122
|
}
|
|
3754
4123
|
function isValidImageCropValue(value) {
|
|
3755
|
-
if (!
|
|
4124
|
+
if (!isPlainRecord3(value))
|
|
3756
4125
|
return false;
|
|
3757
4126
|
const { x, y, w, h } = value;
|
|
3758
4127
|
if (typeof x !== "number" || typeof y !== "number" || typeof w !== "number" || typeof h !== "number") {
|
|
@@ -3760,78 +4129,78 @@ function isValidImageCropValue(value) {
|
|
|
3760
4129
|
}
|
|
3761
4130
|
return isValidCropRect(x, y, w, h);
|
|
3762
4131
|
}
|
|
3763
|
-
function validateImageValue(field, value,
|
|
3764
|
-
if (!
|
|
3765
|
-
return [{ fieldPath:
|
|
4132
|
+
function validateImageValue(field, value, path212) {
|
|
4133
|
+
if (!isPlainRecord3(value)) {
|
|
4134
|
+
return [{ fieldPath: path212, message: "Expected an image object with { src, alt }" }];
|
|
3766
4135
|
}
|
|
3767
4136
|
const errors = [];
|
|
3768
4137
|
if (typeof value.src !== "string" || value.src.trim() === "") {
|
|
3769
|
-
errors.push({ fieldPath: `${
|
|
4138
|
+
errors.push({ fieldPath: `${path212}.src`, message: "Image src is required" });
|
|
3770
4139
|
}
|
|
3771
4140
|
if (typeof value.alt !== "string") {
|
|
3772
|
-
errors.push({ fieldPath: `${
|
|
4141
|
+
errors.push({ fieldPath: `${path212}.alt`, message: "Image alt text is required" });
|
|
3773
4142
|
} else if (value.alt.trim() === "" && field.altOptional !== true) {
|
|
3774
|
-
errors.push({ fieldPath: `${
|
|
4143
|
+
errors.push({ fieldPath: `${path212}.alt`, message: "Image alt text is required" });
|
|
3775
4144
|
}
|
|
3776
4145
|
if (value.width !== void 0 && !isPositiveInt(value.width)) {
|
|
3777
|
-
errors.push({ fieldPath: `${
|
|
4146
|
+
errors.push({ fieldPath: `${path212}.width`, message: "Image width must be a positive integer" });
|
|
3778
4147
|
}
|
|
3779
4148
|
if (value.height !== void 0 && !isPositiveInt(value.height)) {
|
|
3780
4149
|
errors.push({
|
|
3781
|
-
fieldPath: `${
|
|
4150
|
+
fieldPath: `${path212}.height`,
|
|
3782
4151
|
message: "Image height must be a positive integer"
|
|
3783
4152
|
});
|
|
3784
4153
|
}
|
|
3785
4154
|
if (value.crop !== void 0 && !isValidImageCropValue(value.crop)) {
|
|
3786
|
-
errors.push({ fieldPath: `${
|
|
4155
|
+
errors.push({ fieldPath: `${path212}.crop`, message: "Invalid image crop rect" });
|
|
3787
4156
|
}
|
|
3788
4157
|
return errors;
|
|
3789
4158
|
}
|
|
3790
4159
|
function referenceValueId(value) {
|
|
3791
4160
|
if (typeof value === "string")
|
|
3792
4161
|
return value;
|
|
3793
|
-
if (
|
|
4162
|
+
if (isPlainRecord3(value) && typeof value.id === "string")
|
|
3794
4163
|
return value.id;
|
|
3795
4164
|
return void 0;
|
|
3796
4165
|
}
|
|
3797
|
-
function validateScalar(field, value,
|
|
4166
|
+
function validateScalar(field, value, path212) {
|
|
3798
4167
|
switch (field.type) {
|
|
3799
4168
|
case "number":
|
|
3800
4169
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
3801
|
-
return [{ fieldPath:
|
|
4170
|
+
return [{ fieldPath: path212, message: "Expected a number" }];
|
|
3802
4171
|
}
|
|
3803
4172
|
return [];
|
|
3804
4173
|
case "boolean":
|
|
3805
4174
|
if (typeof value !== "boolean") {
|
|
3806
|
-
return [{ fieldPath:
|
|
4175
|
+
return [{ fieldPath: path212, message: "Expected true or false" }];
|
|
3807
4176
|
}
|
|
3808
4177
|
return [];
|
|
3809
4178
|
case "datetime":
|
|
3810
4179
|
if (typeof value !== "string" || value !== "" && Number.isNaN(Date.parse(value))) {
|
|
3811
|
-
return [{ fieldPath:
|
|
4180
|
+
return [{ fieldPath: path212, message: "Expected a valid date/time string" }];
|
|
3812
4181
|
}
|
|
3813
4182
|
return [];
|
|
3814
4183
|
case "select": {
|
|
3815
4184
|
if (typeof value !== "string") {
|
|
3816
|
-
return [{ fieldPath:
|
|
4185
|
+
return [{ fieldPath: path212, message: "Expected a selection" }];
|
|
3817
4186
|
}
|
|
3818
4187
|
const options = selectOptionValues(field);
|
|
3819
4188
|
if (value !== "" && !options.includes(value)) {
|
|
3820
|
-
return [{ fieldPath:
|
|
4189
|
+
return [{ fieldPath: path212, message: `Must be one of: ${options.join(", ")}` }];
|
|
3821
4190
|
}
|
|
3822
4191
|
return [];
|
|
3823
4192
|
}
|
|
3824
4193
|
case "reference":
|
|
3825
4194
|
if (referenceValueId(value) === void 0) {
|
|
3826
|
-
return [{ fieldPath:
|
|
4195
|
+
return [{ fieldPath: path212, message: "Expected a reference id" }];
|
|
3827
4196
|
}
|
|
3828
4197
|
return [];
|
|
3829
4198
|
case "image":
|
|
3830
|
-
return validateImageValue(field, value,
|
|
4199
|
+
return validateImageValue(field, value, path212);
|
|
3831
4200
|
default:
|
|
3832
4201
|
if (STRING_FIELD_TYPES.has(field.type)) {
|
|
3833
4202
|
if (typeof value !== "string") {
|
|
3834
|
-
return [{ fieldPath:
|
|
4203
|
+
return [{ fieldPath: path212, message: "Expected text" }];
|
|
3835
4204
|
}
|
|
3836
4205
|
}
|
|
3837
4206
|
return [];
|
|
@@ -3854,12 +4223,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
|
|
|
3854
4223
|
errors.push(...validateEntryData(field.fields, data, pathPrefix));
|
|
3855
4224
|
continue;
|
|
3856
4225
|
}
|
|
3857
|
-
const
|
|
4226
|
+
const path212 = pathPrefix ? `${pathPrefix}.${field.name}` : field.name;
|
|
3858
4227
|
const value = data[field.name];
|
|
3859
4228
|
const isRequired = "required" in field && field.required === true;
|
|
3860
4229
|
if (isRequired && isEmptyForRequired(field, value)) {
|
|
3861
4230
|
const message = Array.isArray(value) ? "At least one item is required" : "This field is required";
|
|
3862
|
-
errors.push({ fieldPath:
|
|
4231
|
+
errors.push({ fieldPath: path212, message });
|
|
3863
4232
|
continue;
|
|
3864
4233
|
}
|
|
3865
4234
|
if (value === void 0 || value === null)
|
|
@@ -3867,12 +4236,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
|
|
|
3867
4236
|
if (field.type === "block") {
|
|
3868
4237
|
const blockField = field;
|
|
3869
4238
|
if (!Array.isArray(value)) {
|
|
3870
|
-
errors.push({ fieldPath:
|
|
4239
|
+
errors.push({ fieldPath: path212, message: "Expected a list of blocks" });
|
|
3871
4240
|
continue;
|
|
3872
4241
|
}
|
|
3873
4242
|
value.forEach((item, index) => {
|
|
3874
|
-
const itemPath = `${
|
|
3875
|
-
if (!
|
|
4243
|
+
const itemPath = `${path212}[${index}]`;
|
|
4244
|
+
if (!isPlainRecord3(item)) {
|
|
3876
4245
|
errors.push({ fieldPath: itemPath, message: "Expected a block object" });
|
|
3877
4246
|
return;
|
|
3878
4247
|
}
|
|
@@ -3893,12 +4262,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
|
|
|
3893
4262
|
const objectField = field;
|
|
3894
4263
|
if (objectField.list) {
|
|
3895
4264
|
if (!Array.isArray(value)) {
|
|
3896
|
-
errors.push({ fieldPath:
|
|
4265
|
+
errors.push({ fieldPath: path212, message: "Expected a list of items" });
|
|
3897
4266
|
continue;
|
|
3898
4267
|
}
|
|
3899
4268
|
value.forEach((item, index) => {
|
|
3900
|
-
const itemPath = `${
|
|
3901
|
-
if (!
|
|
4269
|
+
const itemPath = `${path212}[${index}]`;
|
|
4270
|
+
if (!isPlainRecord3(item)) {
|
|
3902
4271
|
errors.push({ fieldPath: itemPath, message: "Expected an object" });
|
|
3903
4272
|
return;
|
|
3904
4273
|
}
|
|
@@ -3906,28 +4275,28 @@ function validateEntryData(fields, data, pathPrefix = "") {
|
|
|
3906
4275
|
errors.push(...validateEntryData(objectField.fields, item, itemPath));
|
|
3907
4276
|
}
|
|
3908
4277
|
});
|
|
3909
|
-
} else if (!
|
|
3910
|
-
errors.push({ fieldPath:
|
|
4278
|
+
} else if (!isPlainRecord3(value)) {
|
|
4279
|
+
errors.push({ fieldPath: path212, message: "Expected an object" });
|
|
3911
4280
|
} else if (objectField.fields) {
|
|
3912
|
-
errors.push(...validateEntryData(objectField.fields, value,
|
|
4281
|
+
errors.push(...validateEntryData(objectField.fields, value, path212));
|
|
3913
4282
|
}
|
|
3914
4283
|
continue;
|
|
3915
4284
|
}
|
|
3916
4285
|
if ("list" in field && field.list) {
|
|
3917
4286
|
if (!Array.isArray(value)) {
|
|
3918
|
-
errors.push({ fieldPath:
|
|
4287
|
+
errors.push({ fieldPath: path212, message: "Expected a list of values" });
|
|
3919
4288
|
continue;
|
|
3920
4289
|
}
|
|
3921
4290
|
value.forEach((item, index) => {
|
|
3922
|
-
errors.push(...validateScalar(field, item, `${
|
|
4291
|
+
errors.push(...validateScalar(field, item, `${path212}[${index}]`));
|
|
3923
4292
|
});
|
|
3924
4293
|
continue;
|
|
3925
4294
|
}
|
|
3926
4295
|
if (Array.isArray(value) && KNOWN_FIELD_TYPES.has(field.type)) {
|
|
3927
|
-
errors.push({ fieldPath:
|
|
4296
|
+
errors.push({ fieldPath: path212, message: "Expected a single value, not a list" });
|
|
3928
4297
|
continue;
|
|
3929
4298
|
}
|
|
3930
|
-
errors.push(...validateScalar(field, value,
|
|
4299
|
+
errors.push(...validateScalar(field, value, path212));
|
|
3931
4300
|
}
|
|
3932
4301
|
return errors;
|
|
3933
4302
|
}
|
|
@@ -3971,6 +4340,37 @@ function assertBuildEntriesValid(items, phaseLabel) {
|
|
|
3971
4340
|
${lines.join("\n")}
|
|
3972
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.`);
|
|
3973
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
|
+
}
|
|
3974
4374
|
async function generateAIContentFiles(options) {
|
|
3975
4375
|
const { config, entrySchemaRegistry, outputDir, aiConfig: aiConfig2, _testFlatSchema } = options;
|
|
3976
4376
|
const contentRootName = config.contentRoot || "content";
|
|
@@ -3993,23 +4393,45 @@ async function generateAIContentFiles(options) {
|
|
|
3993
4393
|
config: aiConfig2,
|
|
3994
4394
|
entryLinkUrl: config.entryLinkUrl
|
|
3995
4395
|
});
|
|
3996
|
-
const absoluteOutputDir =
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
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));
|
|
4000
4399
|
if (!absolutePath.startsWith(absoluteOutputDir)) {
|
|
4001
4400
|
throw new Error(`Path traversal detected in AI content output: ${filePath}`);
|
|
4002
4401
|
}
|
|
4003
|
-
|
|
4004
|
-
|
|
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");
|
|
4005
4412
|
fileCount++;
|
|
4006
4413
|
}
|
|
4007
|
-
|
|
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 };
|
|
4008
4430
|
}
|
|
4009
4431
|
async function generateAIContentCLI(options) {
|
|
4010
4432
|
const { projectDir, outputDir = "public/ai", configPath, appDir = "app" } = options;
|
|
4011
4433
|
console.log("\nCanopyCMS generate-ai-content\n");
|
|
4012
|
-
const canopyConfigPath =
|
|
4434
|
+
const canopyConfigPath = path20.join(projectDir, "canopycms.config.ts");
|
|
4013
4435
|
let canopyConfigModule;
|
|
4014
4436
|
try {
|
|
4015
4437
|
canopyConfigModule = await jiti.import(canopyConfigPath);
|
|
@@ -4020,7 +4442,7 @@ async function generateAIContentCLI(options) {
|
|
|
4020
4442
|
}
|
|
4021
4443
|
const configExport = canopyConfigModule.default ?? canopyConfigModule.config ?? canopyConfigModule;
|
|
4022
4444
|
const serverConfig = typeof configExport === "object" && configExport !== null && "server" in configExport ? configExport.server : configExport;
|
|
4023
|
-
const schemasPath =
|
|
4445
|
+
const schemasPath = path20.join(projectDir, appDir, "schemas.ts");
|
|
4024
4446
|
let entrySchemaRegistry = {};
|
|
4025
4447
|
try {
|
|
4026
4448
|
const schemasModule = await jiti.import(schemasPath);
|
|
@@ -4031,7 +4453,7 @@ async function generateAIContentCLI(options) {
|
|
|
4031
4453
|
let aiConfig2;
|
|
4032
4454
|
if (configPath) {
|
|
4033
4455
|
try {
|
|
4034
|
-
const aiConfigModule = await jiti.import(
|
|
4456
|
+
const aiConfigModule = await jiti.import(path20.resolve(configPath));
|
|
4035
4457
|
aiConfig2 = aiConfigModule.aiContentConfig ?? aiConfigModule.default ?? aiConfigModule.config;
|
|
4036
4458
|
} catch (err) {
|
|
4037
4459
|
console.error(`Could not load AI config from ${configPath}`);
|
|
@@ -4048,7 +4470,7 @@ async function generateAIContentCLI(options) {
|
|
|
4048
4470
|
console.error("Make sure canopycms.config.ts uses defineCanopyConfig().");
|
|
4049
4471
|
process.exit(1);
|
|
4050
4472
|
}
|
|
4051
|
-
const resolvedOutput =
|
|
4473
|
+
const resolvedOutput = path20.resolve(projectDir, outputDir);
|
|
4052
4474
|
console.log(` Output: ${resolvedOutput}`);
|
|
4053
4475
|
console.log(` Mode: ${serverConfig.mode ?? "dev"}`);
|
|
4054
4476
|
const result = await generateAIContentFiles({
|
|
@@ -4059,10 +4481,13 @@ async function generateAIContentCLI(options) {
|
|
|
4059
4481
|
});
|
|
4060
4482
|
console.log(`
|
|
4061
4483
|
Generated ${result.fileCount} files`);
|
|
4484
|
+
if (result.removedCount > 0) {
|
|
4485
|
+
console.log(` Removed ${result.removedCount} stale files from the previous run`);
|
|
4486
|
+
}
|
|
4062
4487
|
console.log(` Output: ${result.outputDir}
|
|
4063
4488
|
`);
|
|
4064
4489
|
}
|
|
4065
|
-
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;
|
|
4066
4491
|
var init_generate_ai_content = __esm({
|
|
4067
4492
|
"dist/cli/generate-ai-content.js"() {
|
|
4068
4493
|
"use strict";
|
|
@@ -4075,17 +4500,17 @@ var init_generate_ai_content = __esm({
|
|
|
4075
4500
|
for (var name in all)
|
|
4076
4501
|
__defProp3(target, name, { get: all[name], enumerable: true });
|
|
4077
4502
|
};
|
|
4078
|
-
init_normalize2 = __esm3({
|
|
4079
|
-
"dist/paths/normalize.js"() {
|
|
4080
|
-
"use strict";
|
|
4081
|
-
}
|
|
4082
|
-
});
|
|
4083
4503
|
init_logger2 = __esm3({
|
|
4084
4504
|
"dist/utils/logger.js"() {
|
|
4085
4505
|
"use strict";
|
|
4086
4506
|
active2 = console;
|
|
4087
4507
|
}
|
|
4088
4508
|
});
|
|
4509
|
+
init_normalize2 = __esm3({
|
|
4510
|
+
"dist/paths/normalize.js"() {
|
|
4511
|
+
"use strict";
|
|
4512
|
+
}
|
|
4513
|
+
});
|
|
4089
4514
|
init_types3 = __esm3({
|
|
4090
4515
|
"dist/paths/types.js"() {
|
|
4091
4516
|
"use strict";
|
|
@@ -4259,7 +4684,12 @@ var init_generate_ai_content = __esm({
|
|
|
4259
4684
|
collections: z22.array(z22.string().min(1)).min(1).optional(),
|
|
4260
4685
|
entryTypes: z22.array(z22.string().min(1)).min(1).optional(),
|
|
4261
4686
|
displayField: z22.string().min(1).optional(),
|
|
4262
|
-
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()
|
|
4263
4693
|
});
|
|
4264
4694
|
fieldHolder2 = [z22.never()];
|
|
4265
4695
|
blockSchema2 = z22.object({
|
|
@@ -4380,6 +4810,9 @@ var init_generate_ai_content = __esm({
|
|
|
4380
4810
|
deployedAsSchema2 = z52.enum(["static", "server"]).default("server");
|
|
4381
4811
|
contentRootSchema2 = relativePathSchema2.default("content");
|
|
4382
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();
|
|
4383
4816
|
deploymentNameSchema2 = z52.string().default("prod");
|
|
4384
4817
|
devContentSyncSchema2 = z52.enum(["off", "warn"]).default("warn");
|
|
4385
4818
|
devConfigSchema2 = z52.object({
|
|
@@ -4442,6 +4875,7 @@ var init_generate_ai_content = __esm({
|
|
|
4442
4875
|
deploymentName: deploymentNameSchema2.optional(),
|
|
4443
4876
|
contentRoot: contentRootSchema2.default("content"),
|
|
4444
4877
|
sourceRoot: sourceRootSchema2.optional(),
|
|
4878
|
+
basePath: basePathSchema2,
|
|
4445
4879
|
editor: editorConfigSchema2.optional(),
|
|
4446
4880
|
authPlugin: z52.custom().optional(),
|
|
4447
4881
|
entryLinkUrl: z52.custom().optional(),
|
|
@@ -4611,32 +5045,32 @@ var init_generate_ai_content = __esm({
|
|
|
4611
5045
|
// - shouldCommit(), shouldPush()
|
|
4612
5046
|
// Add client-unsafe methods (use Node.js APIs)
|
|
4613
5047
|
getWorkspaceRoot(_sourceRoot) {
|
|
4614
|
-
return
|
|
5048
|
+
return path9.resolve(process.env.CANOPYCMS_WORKSPACE_ROOT ?? DEFAULT_PROD_WORKSPACE2);
|
|
4615
5049
|
}
|
|
4616
5050
|
getContentRoot(contentRoot, sourceRoot) {
|
|
4617
|
-
return
|
|
5051
|
+
return path9.resolve(sourceRoot ?? process.cwd(), contentRoot);
|
|
4618
5052
|
}
|
|
4619
5053
|
getContentBranchesRoot(sourceRoot) {
|
|
4620
|
-
return
|
|
5054
|
+
return path9.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
|
|
4621
5055
|
}
|
|
4622
5056
|
getContentBranchRoot(branchName, sourceRoot) {
|
|
4623
|
-
return
|
|
5057
|
+
return path9.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
|
|
4624
5058
|
}
|
|
4625
5059
|
getGitExcludePattern() {
|
|
4626
5060
|
return ".canopy-meta/";
|
|
4627
5061
|
}
|
|
4628
5062
|
getPermissionsFilePath(root) {
|
|
4629
|
-
return
|
|
5063
|
+
return path9.join(root, this.getPermissionsFileName());
|
|
4630
5064
|
}
|
|
4631
5065
|
getGroupsFilePath(root) {
|
|
4632
|
-
return
|
|
5066
|
+
return path9.join(root, this.getGroupsFileName());
|
|
4633
5067
|
}
|
|
4634
5068
|
getRemoteUrlConfig() {
|
|
4635
5069
|
return {
|
|
4636
5070
|
shouldAutoInitLocal: false,
|
|
4637
5071
|
defaultRemotePath: "",
|
|
4638
5072
|
envVarName: "CANOPYCMS_REMOTE_URL",
|
|
4639
|
-
autoDetectRemotePath:
|
|
5073
|
+
autoDetectRemotePath: path9.join(this.getWorkspaceRoot(), "remote.git")
|
|
4640
5074
|
};
|
|
4641
5075
|
}
|
|
4642
5076
|
requiresExistingRepo() {
|
|
@@ -4648,7 +5082,7 @@ var init_generate_ai_content = __esm({
|
|
|
4648
5082
|
return `canopycms-settings-${resolveDeploymentName2(config, "prod")}`;
|
|
4649
5083
|
}
|
|
4650
5084
|
getSettingsRoot(sourceRoot) {
|
|
4651
|
-
return
|
|
5085
|
+
return path9.join(this.getWorkspaceRoot(sourceRoot), "settings");
|
|
4652
5086
|
}
|
|
4653
5087
|
usesSeparateSettingsBranch() {
|
|
4654
5088
|
return true;
|
|
@@ -4665,25 +5099,25 @@ var init_generate_ai_content = __esm({
|
|
|
4665
5099
|
DevStrategy2 = class extends DevClientSafeStrategy2 {
|
|
4666
5100
|
// Inherits client-safe methods from DevClientSafeStrategy
|
|
4667
5101
|
getWorkspaceRoot(sourceRoot) {
|
|
4668
|
-
return
|
|
5102
|
+
return path9.resolve(sourceRoot ?? process.cwd(), ".canopy-dev");
|
|
4669
5103
|
}
|
|
4670
5104
|
getContentRoot(contentRoot, sourceRoot) {
|
|
4671
|
-
return
|
|
5105
|
+
return path9.resolve(sourceRoot ?? process.cwd(), contentRoot);
|
|
4672
5106
|
}
|
|
4673
5107
|
getContentBranchesRoot(sourceRoot) {
|
|
4674
|
-
return
|
|
5108
|
+
return path9.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
|
|
4675
5109
|
}
|
|
4676
5110
|
getContentBranchRoot(branchName, sourceRoot) {
|
|
4677
|
-
return
|
|
5111
|
+
return path9.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
|
|
4678
5112
|
}
|
|
4679
5113
|
getGitExcludePattern() {
|
|
4680
5114
|
return ".canopy-meta/";
|
|
4681
5115
|
}
|
|
4682
5116
|
getPermissionsFilePath(root) {
|
|
4683
|
-
return
|
|
5117
|
+
return path9.join(root, this.getPermissionsFileName());
|
|
4684
5118
|
}
|
|
4685
5119
|
getGroupsFilePath(root) {
|
|
4686
|
-
return
|
|
5120
|
+
return path9.join(root, this.getGroupsFileName());
|
|
4687
5121
|
}
|
|
4688
5122
|
getRemoteUrlConfig() {
|
|
4689
5123
|
return {
|
|
@@ -4701,7 +5135,7 @@ var init_generate_ai_content = __esm({
|
|
|
4701
5135
|
return `canopycms-settings-${resolveDeploymentName2(config, "local")}`;
|
|
4702
5136
|
}
|
|
4703
5137
|
getSettingsRoot(sourceRoot) {
|
|
4704
|
-
return
|
|
5138
|
+
return path9.join(this.getWorkspaceRoot(sourceRoot), "settings");
|
|
4705
5139
|
}
|
|
4706
5140
|
usesSeparateSettingsBranch() {
|
|
4707
5141
|
return true;
|
|
@@ -4736,7 +5170,12 @@ var init_generate_ai_content = __esm({
|
|
|
4736
5170
|
init_mode_env2();
|
|
4737
5171
|
}
|
|
4738
5172
|
});
|
|
5173
|
+
BLOCK_DISCRIMINATOR_KEYS = ["template", "_type"];
|
|
5174
|
+
BLOCK_STRUCTURAL_KEYS = new Set(BLOCK_DISCRIMINATOR_KEYS);
|
|
5175
|
+
EVIDENCE_MAX_DEPTH = 6;
|
|
4739
5176
|
locks = /* @__PURE__ */ new Map();
|
|
5177
|
+
init_logger2();
|
|
5178
|
+
init_logger2();
|
|
4740
5179
|
META_DIR = ".canopy-meta";
|
|
4741
5180
|
CONTENT_WRITE_LOCK_NAME = "content-write.lock";
|
|
4742
5181
|
DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS = 2e3;
|
|
@@ -4749,6 +5188,67 @@ var init_generate_ai_content = __esm({
|
|
|
4749
5188
|
sleep = (ms) => new Promise((resolve2) => {
|
|
4750
5189
|
setTimeout(resolve2, ms);
|
|
4751
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();
|
|
4752
5252
|
init_normalize2();
|
|
4753
5253
|
BASE58_PATTERN = "[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]";
|
|
4754
5254
|
CONTENT_ID_PATTERN = new RegExp(`^${BASE58_PATTERN}{12}$`);
|
|
@@ -5066,6 +5566,31 @@ var init_generate_ai_content = __esm({
|
|
|
5066
5566
|
this.pathToId.set(newRelativePath, id);
|
|
5067
5567
|
}
|
|
5068
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"];
|
|
5069
5594
|
registry = /* @__PURE__ */ new Map();
|
|
5070
5595
|
finalization = new FinalizationRegistry(({ rootKey, ref }) => {
|
|
5071
5596
|
const refs = registry.get(rootKey);
|
|
@@ -5303,7 +5828,7 @@ var init_generate_ai_content = __esm({
|
|
|
5303
5828
|
* the project root, regardless of which entrypoint produced the cwd branchRoot.
|
|
5304
5829
|
*/
|
|
5305
5830
|
skipDiskCache(branchRoot) {
|
|
5306
|
-
return isBuildMode() ||
|
|
5831
|
+
return isBuildMode() || path82.resolve(branchRoot) === path82.resolve(process.cwd());
|
|
5307
5832
|
}
|
|
5308
5833
|
/**
|
|
5309
5834
|
* Get schema for a branch (loads from cache or resolves fresh).
|
|
@@ -5329,14 +5854,14 @@ var init_generate_ai_content = __esm({
|
|
|
5329
5854
|
* Load schema from cache or resolve fresh if cache is missing or stale.
|
|
5330
5855
|
*/
|
|
5331
5856
|
async loadFromCacheOrResolve(branchRoot, entrySchemaRegistry, contentRootName) {
|
|
5332
|
-
const contentRoot =
|
|
5857
|
+
const contentRoot = path82.join(branchRoot, contentRootName);
|
|
5333
5858
|
const skipDiskCache = this.skipDiskCache(branchRoot);
|
|
5334
5859
|
if (!skipDiskCache) {
|
|
5335
|
-
const cacheDir =
|
|
5336
|
-
const cachePath =
|
|
5860
|
+
const cacheDir = path82.join(branchRoot, ".canopy-meta");
|
|
5861
|
+
const cachePath = path82.join(cacheDir, "schema-cache.json");
|
|
5337
5862
|
let cacheData = null;
|
|
5338
5863
|
try {
|
|
5339
|
-
const cacheContent = await
|
|
5864
|
+
const cacheContent = await fs72.readFile(cachePath, "utf-8");
|
|
5340
5865
|
cacheData = JSON.parse(cacheContent);
|
|
5341
5866
|
} catch {
|
|
5342
5867
|
cacheData = null;
|
|
@@ -5373,7 +5898,7 @@ var init_generate_ai_content = __esm({
|
|
|
5373
5898
|
*/
|
|
5374
5899
|
async resolveFreshAndPersist(branchRoot, entrySchemaRegistry, contentRootName, options) {
|
|
5375
5900
|
const { skipDiskCache } = options;
|
|
5376
|
-
const contentRoot =
|
|
5901
|
+
const contentRoot = path82.join(branchRoot, contentRootName);
|
|
5377
5902
|
const read = skipDiskCache ? null : await readResourceGeneration(branchRoot, SCHEMA_GENERATION_RESOURCE);
|
|
5378
5903
|
const result = await this.resolveFresh(contentRoot, entrySchemaRegistry);
|
|
5379
5904
|
if (!isValidSchema(result.schema)) {
|
|
@@ -5386,9 +5911,9 @@ var init_generate_ai_content = __esm({
|
|
|
5386
5911
|
}
|
|
5387
5912
|
const flatSchema = flattenSchema(result.schema, contentRootName);
|
|
5388
5913
|
if (!skipDiskCache) {
|
|
5389
|
-
const cacheDir =
|
|
5390
|
-
const cachePath =
|
|
5391
|
-
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(() => {
|
|
5392
5917
|
});
|
|
5393
5918
|
if (read && read.ok) {
|
|
5394
5919
|
const newCache = {
|
|
@@ -5398,13 +5923,13 @@ var init_generate_ai_content = __esm({
|
|
|
5398
5923
|
cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5399
5924
|
generation: read.token
|
|
5400
5925
|
};
|
|
5401
|
-
await
|
|
5402
|
-
const tmpPath =
|
|
5403
|
-
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");
|
|
5404
5929
|
try {
|
|
5405
|
-
await
|
|
5930
|
+
await fs72.rename(tmpPath, cachePath);
|
|
5406
5931
|
} catch (err) {
|
|
5407
|
-
await
|
|
5932
|
+
await fs72.unlink(tmpPath).catch(() => {
|
|
5408
5933
|
});
|
|
5409
5934
|
throw err;
|
|
5410
5935
|
}
|
|
@@ -5514,9 +6039,17 @@ var init_generate_ai_content = __esm({
|
|
|
5514
6039
|
this.paths = sorted;
|
|
5515
6040
|
}
|
|
5516
6041
|
};
|
|
6042
|
+
UrlPathConflictError = class extends ContentConflictError {
|
|
6043
|
+
constructor(message, conflictingPath) {
|
|
6044
|
+
super(message);
|
|
6045
|
+
this.name = "UrlPathConflictError";
|
|
6046
|
+
this.conflictingPath = conflictingPath;
|
|
6047
|
+
}
|
|
6048
|
+
};
|
|
5517
6049
|
DEFAULT_INDEX_FRESHNESS_INTERVAL_MS = 1e3;
|
|
5518
6050
|
FORCED_REFRESH_MIN_INTERVAL_MS = 5e3;
|
|
5519
6051
|
STALE_LOOKUP = Symbol("stale-index-lookup");
|
|
6052
|
+
createReferenceResolveCache = () => /* @__PURE__ */ new Map();
|
|
5520
6053
|
ContentStore = class {
|
|
5521
6054
|
constructor(root, flatSchema, options = {}) {
|
|
5522
6055
|
this.indexGeneration = 0;
|
|
@@ -5525,7 +6058,7 @@ var init_generate_ai_content = __esm({
|
|
|
5525
6058
|
this.lastDiskProbeMs = 0;
|
|
5526
6059
|
this.lastForcedRefreshMs = 0;
|
|
5527
6060
|
this.indexBuild = null;
|
|
5528
|
-
this.root =
|
|
6061
|
+
this.root = path11.resolve(root);
|
|
5529
6062
|
this.contentRootName = options.contentRootName || "content";
|
|
5530
6063
|
this.indexFreshnessIntervalMs = options.indexFreshnessIntervalMs ?? DEFAULT_INDEX_FRESHNESS_INTERVAL_MS;
|
|
5531
6064
|
this.contentWriteLockWaitMs = options.contentWriteLockWaitMs ?? DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS;
|
|
@@ -5673,7 +6206,7 @@ var init_generate_ai_content = __esm({
|
|
|
5673
6206
|
async findEntryPathsById(dir, id) {
|
|
5674
6207
|
let entries;
|
|
5675
6208
|
try {
|
|
5676
|
-
entries = await
|
|
6209
|
+
entries = await fs10.readdir(dir, { withFileTypes: true });
|
|
5677
6210
|
} catch (err) {
|
|
5678
6211
|
if (isNodeError3(err) && err.code === "ENOENT")
|
|
5679
6212
|
return [];
|
|
@@ -5684,7 +6217,7 @@ var init_generate_ai_content = __esm({
|
|
|
5684
6217
|
if (entry.isDirectory())
|
|
5685
6218
|
continue;
|
|
5686
6219
|
if (extractIdFromFilename(entry.name) === id) {
|
|
5687
|
-
matches.push(
|
|
6220
|
+
matches.push(path11.relative(this.root, path11.join(dir, entry.name)));
|
|
5688
6221
|
}
|
|
5689
6222
|
}
|
|
5690
6223
|
return matches.sort();
|
|
@@ -5696,11 +6229,11 @@ var init_generate_ai_content = __esm({
|
|
|
5696
6229
|
getSchemaItems() {
|
|
5697
6230
|
return this.schemaIndex.values();
|
|
5698
6231
|
}
|
|
5699
|
-
assertSchemaItem(
|
|
5700
|
-
const normalized = normalizeFilesystemPath(
|
|
6232
|
+
assertSchemaItem(path212) {
|
|
6233
|
+
const normalized = normalizeFilesystemPath(path212);
|
|
5701
6234
|
const item = this.schemaIndex.get(normalized);
|
|
5702
6235
|
if (!item) {
|
|
5703
|
-
throw new ContentStoreError(`Unknown schema item: ${
|
|
6236
|
+
throw new ContentStoreError(`Unknown schema item: ${path212}`, "NO_SCHEMA_ITEM");
|
|
5704
6237
|
}
|
|
5705
6238
|
return item;
|
|
5706
6239
|
}
|
|
@@ -5767,6 +6300,26 @@ var init_generate_ai_content = __esm({
|
|
|
5767
6300
|
return this.createLockKey(schemaItem, slug);
|
|
5768
6301
|
return prePass.id ? this.idLockKey(prePass.id) : prePass.absolutePath;
|
|
5769
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
|
+
}
|
|
5770
6323
|
/**
|
|
5771
6324
|
* Build absolute and relative paths with security validation.
|
|
5772
6325
|
* All entries use the unified filename pattern: {type}.{slug}.{id}.{ext}
|
|
@@ -5783,7 +6336,7 @@ var init_generate_ai_content = __esm({
|
|
|
5783
6336
|
* @param options.entryTypeName - For collections with multiple entry types, specify which one to use. Defaults to the default entry type.
|
|
5784
6337
|
*/
|
|
5785
6338
|
async buildPaths(schemaItem, slug, options = {}) {
|
|
5786
|
-
const rootWithSep = this.root.endsWith(
|
|
6339
|
+
const rootWithSep = this.root.endsWith(path11.sep) ? this.root : `${this.root}${path11.sep}`;
|
|
5787
6340
|
if (schemaItem.type === "entry-type") {
|
|
5788
6341
|
const parentPath = schemaItem.parentPath || "";
|
|
5789
6342
|
const parentCollection = this.schemaIndex.get(parentPath);
|
|
@@ -5816,7 +6369,7 @@ var init_generate_ai_content = __esm({
|
|
|
5816
6369
|
const entryTypeName = entryTypeConfig?.name || "entry";
|
|
5817
6370
|
let collectionRoot = await resolveCollectionPath(this.root, schemaItem.logicalPath);
|
|
5818
6371
|
if (!collectionRoot) {
|
|
5819
|
-
collectionRoot =
|
|
6372
|
+
collectionRoot = path11.resolve(this.root, schemaItem.logicalPath);
|
|
5820
6373
|
}
|
|
5821
6374
|
if (!collectionRoot.startsWith(rootWithSep)) {
|
|
5822
6375
|
throw new ContentStoreError("Path traversal detected", "VALIDATION");
|
|
@@ -5826,7 +6379,7 @@ var init_generate_ai_content = __esm({
|
|
|
5826
6379
|
let existingEntryType;
|
|
5827
6380
|
let foundExisting = false;
|
|
5828
6381
|
if (!id) {
|
|
5829
|
-
const entries = await
|
|
6382
|
+
const entries = await fs10.readdir(collectionRoot, { withFileTypes: true }).catch(() => []);
|
|
5830
6383
|
const existingFile = entries.find((entry) => {
|
|
5831
6384
|
if (entry.isDirectory())
|
|
5832
6385
|
return false;
|
|
@@ -5852,14 +6405,14 @@ var init_generate_ai_content = __esm({
|
|
|
5852
6405
|
}
|
|
5853
6406
|
filename = `${finalEntryTypeName}.${safeSlug}.${id}${ext}`;
|
|
5854
6407
|
}
|
|
5855
|
-
const resolved =
|
|
5856
|
-
const collectionRootWithSep = collectionRoot.endsWith(
|
|
6408
|
+
const resolved = path11.resolve(collectionRoot, filename);
|
|
6409
|
+
const collectionRootWithSep = collectionRoot.endsWith(path11.sep) ? collectionRoot : `${collectionRoot}${path11.sep}`;
|
|
5857
6410
|
if (!resolved.startsWith(collectionRootWithSep)) {
|
|
5858
6411
|
throw new ContentStoreError("Path traversal detected", "VALIDATION");
|
|
5859
6412
|
}
|
|
5860
6413
|
return {
|
|
5861
6414
|
absolutePath: resolved,
|
|
5862
|
-
relativePath:
|
|
6415
|
+
relativePath: path11.relative(this.root, resolved),
|
|
5863
6416
|
id,
|
|
5864
6417
|
entryTypeName: finalEntryTypeName,
|
|
5865
6418
|
existed
|
|
@@ -5895,8 +6448,8 @@ var init_generate_ai_content = __esm({
|
|
|
5895
6448
|
async read(collectionPath, slug = "", options = {}) {
|
|
5896
6449
|
const schemaItem = this.assertSchemaItem(collectionPath);
|
|
5897
6450
|
const { absolutePath, relativePath, entryTypeName: resolvedEntryTypeName } = await this.buildPaths(schemaItem, slug);
|
|
5898
|
-
const stat = await
|
|
5899
|
-
const raw = await
|
|
6451
|
+
const stat = await fs10.stat(absolutePath);
|
|
6452
|
+
const raw = await fs10.readFile(absolutePath, "utf8");
|
|
5900
6453
|
let doc;
|
|
5901
6454
|
let format;
|
|
5902
6455
|
let fields;
|
|
@@ -5935,7 +6488,7 @@ var init_generate_ai_content = __esm({
|
|
|
5935
6488
|
absolutePath
|
|
5936
6489
|
};
|
|
5937
6490
|
} else {
|
|
5938
|
-
const parsed =
|
|
6491
|
+
const parsed = matter2(raw);
|
|
5939
6492
|
doc = {
|
|
5940
6493
|
collection: schemaItem.logicalPath,
|
|
5941
6494
|
collectionName: schemaItem.name,
|
|
@@ -5998,7 +6551,7 @@ var init_generate_ai_content = __esm({
|
|
|
5998
6551
|
const indexedPath = guardIndex.findById(id)?.relativePath ?? null;
|
|
5999
6552
|
if (indexedPath && indexedPath !== relativePath) {
|
|
6000
6553
|
const quarantined = guardIndex.getDuplicateFor(id);
|
|
6001
|
-
const bothOnDisk = await filePathExists3(absolutePath) && await filePathExists3(
|
|
6554
|
+
const bothOnDisk = await filePathExists3(absolutePath) && await filePathExists3(path11.join(this.root, indexedPath));
|
|
6002
6555
|
if (quarantined || bothOnDisk) {
|
|
6003
6556
|
throw new DuplicateContentIdError(id, [
|
|
6004
6557
|
indexedPath,
|
|
@@ -6009,10 +6562,18 @@ var init_generate_ai_content = __esm({
|
|
|
6009
6562
|
}
|
|
6010
6563
|
}
|
|
6011
6564
|
}
|
|
6012
|
-
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 });
|
|
6013
6574
|
if (input.expectedVersion !== void 0) {
|
|
6014
6575
|
try {
|
|
6015
|
-
const existing = await
|
|
6576
|
+
const existing = await fs10.stat(absolutePath);
|
|
6016
6577
|
if (input.expectedVersion === null) {
|
|
6017
6578
|
throw new ContentConflictError("An entry with this slug already exists");
|
|
6018
6579
|
}
|
|
@@ -6029,7 +6590,7 @@ var init_generate_ai_content = __esm({
|
|
|
6029
6590
|
}
|
|
6030
6591
|
}
|
|
6031
6592
|
if (existingId && !await filePathExists3(absolutePath)) {
|
|
6032
|
-
const actualRelPaths = await this.findEntryPathsById(
|
|
6593
|
+
const actualRelPaths = await this.findEntryPathsById(path11.dirname(absolutePath), existingId);
|
|
6033
6594
|
if (actualRelPaths.length > 1) {
|
|
6034
6595
|
throw new DuplicateContentIdError(existingId, actualRelPaths);
|
|
6035
6596
|
}
|
|
@@ -6039,14 +6600,15 @@ var init_generate_ai_content = __esm({
|
|
|
6039
6600
|
throw new ContentConflictError();
|
|
6040
6601
|
}
|
|
6041
6602
|
}
|
|
6603
|
+
const existingRaw = input.format === "json" ? void 0 : await readFileIfExists(absolutePath);
|
|
6042
6604
|
let content;
|
|
6043
6605
|
if (input.format === "json") {
|
|
6044
6606
|
content = `${JSON.stringify(input.data ?? {}, null, 2)}
|
|
6045
6607
|
`;
|
|
6046
6608
|
} else if (input.format === "yaml") {
|
|
6047
|
-
content =
|
|
6609
|
+
content = serializeYaml(input.data ?? {}, existingRaw);
|
|
6048
6610
|
} else {
|
|
6049
|
-
content =
|
|
6611
|
+
content = serializeFrontmatter(input.body, input.data ?? {}, existingRaw);
|
|
6050
6612
|
}
|
|
6051
6613
|
await atomicWriteFile2(absolutePath, content);
|
|
6052
6614
|
const liveIndex = this._idIndex;
|
|
@@ -6055,7 +6617,7 @@ var init_generate_ai_content = __esm({
|
|
|
6055
6617
|
const existing = liveIndex.findById(id);
|
|
6056
6618
|
if (existing) {
|
|
6057
6619
|
if (existing.relativePath !== relativePath) {
|
|
6058
|
-
staleOldAbsPath =
|
|
6620
|
+
staleOldAbsPath = path11.join(this.root, existing.relativePath);
|
|
6059
6621
|
liveIndex.updatePath(existing.id, relativePath);
|
|
6060
6622
|
}
|
|
6061
6623
|
} else {
|
|
@@ -6068,13 +6630,13 @@ var init_generate_ai_content = __esm({
|
|
|
6068
6630
|
}
|
|
6069
6631
|
}
|
|
6070
6632
|
if (staleOldAbsPath) {
|
|
6071
|
-
await
|
|
6633
|
+
await fs10.unlink(staleOldAbsPath).catch((err) => {
|
|
6072
6634
|
if (!isNodeError3(err) || err.code !== "ENOENT")
|
|
6073
6635
|
throw err;
|
|
6074
6636
|
});
|
|
6075
6637
|
}
|
|
6076
6638
|
await this.recordOwnMutation(liveIndex);
|
|
6077
|
-
const afterStat = await
|
|
6639
|
+
const afterStat = await fs10.stat(absolutePath);
|
|
6078
6640
|
const base = {
|
|
6079
6641
|
collection: schemaItem.logicalPath,
|
|
6080
6642
|
collectionName: schemaItem.name,
|
|
@@ -6152,7 +6714,7 @@ var init_generate_ai_content = __esm({
|
|
|
6152
6714
|
const schemaItem = this.assertSchemaItem(collectionPath);
|
|
6153
6715
|
const { absolutePath } = await this.buildPaths(schemaItem, slug);
|
|
6154
6716
|
try {
|
|
6155
|
-
await
|
|
6717
|
+
await fs10.access(absolutePath);
|
|
6156
6718
|
return true;
|
|
6157
6719
|
} catch (err) {
|
|
6158
6720
|
if (isNodeError3(err) && err.code === "ENOENT")
|
|
@@ -6191,7 +6753,7 @@ var init_generate_ai_content = __esm({
|
|
|
6191
6753
|
const collectionRoot = await resolveCollectionPath(this.root, collectionPath);
|
|
6192
6754
|
if (!collectionRoot)
|
|
6193
6755
|
return 0;
|
|
6194
|
-
const entries = await
|
|
6756
|
+
const entries = await fs10.readdir(collectionRoot, { withFileTypes: true }).catch(() => []);
|
|
6195
6757
|
return entries.filter((entry) => !entry.isDirectory() && extractEntryTypeFromFilename(entry.name) === entryTypeName).length;
|
|
6196
6758
|
}
|
|
6197
6759
|
/**
|
|
@@ -6215,7 +6777,7 @@ var init_generate_ai_content = __esm({
|
|
|
6215
6777
|
const collection = this.assertCollection(collectionPath);
|
|
6216
6778
|
const prePass = await this.buildPaths(collection, slug);
|
|
6217
6779
|
if (!prePass.existed) {
|
|
6218
|
-
await
|
|
6780
|
+
await fs10.unlink(prePass.absolutePath);
|
|
6219
6781
|
return;
|
|
6220
6782
|
}
|
|
6221
6783
|
let lockKey = this.entryLockKey(collection, slug, prePass);
|
|
@@ -6231,7 +6793,7 @@ var init_generate_ai_content = __esm({
|
|
|
6231
6793
|
return RETRY_KEY;
|
|
6232
6794
|
}
|
|
6233
6795
|
const { absolutePath, relativePath } = inLock;
|
|
6234
|
-
await
|
|
6796
|
+
await fs10.unlink(absolutePath);
|
|
6235
6797
|
const liveIndex = this._idIndex;
|
|
6236
6798
|
const id = liveIndex.findByPath(relativePath);
|
|
6237
6799
|
if (id) {
|
|
@@ -6267,6 +6829,10 @@ var init_generate_ai_content = __esm({
|
|
|
6267
6829
|
if (currentSlug === safeNewSlug) {
|
|
6268
6830
|
return { newPath: `${collectionPath}/${currentSlug}` };
|
|
6269
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
|
+
}
|
|
6270
6836
|
const prePass = await this.buildPaths(collection, currentSlug);
|
|
6271
6837
|
if (!prePass.existed) {
|
|
6272
6838
|
throw new ContentStoreError(`Entry not found: ${currentSlug}`, "NOT_FOUND");
|
|
@@ -6293,7 +6859,7 @@ var init_generate_ai_content = __esm({
|
|
|
6293
6859
|
}
|
|
6294
6860
|
destLockKey = currentDestKey;
|
|
6295
6861
|
const { absolutePath: currentPath, relativePath: currentRelPath } = inLock;
|
|
6296
|
-
const currentFilename =
|
|
6862
|
+
const currentFilename = path11.basename(currentPath);
|
|
6297
6863
|
const parts = currentFilename.split(".");
|
|
6298
6864
|
if (parts.length < 4) {
|
|
6299
6865
|
throw new ContentStoreError(`Invalid entry filename format: ${currentFilename}`, "VALIDATION");
|
|
@@ -6302,10 +6868,10 @@ var init_generate_ai_content = __esm({
|
|
|
6302
6868
|
const contentId = parts[parts.length - 2];
|
|
6303
6869
|
const ext = `.${parts[parts.length - 1]}`;
|
|
6304
6870
|
const newFilename = `${entryTypeName}.${safeNewSlug}.${contentId}${ext}`;
|
|
6305
|
-
const parentDir =
|
|
6306
|
-
const newPath =
|
|
6871
|
+
const parentDir = path11.dirname(currentPath);
|
|
6872
|
+
const newPath = path11.join(parentDir, newFilename);
|
|
6307
6873
|
try {
|
|
6308
|
-
const entries = await
|
|
6874
|
+
const entries = await fs10.readdir(parentDir, { withFileTypes: true });
|
|
6309
6875
|
for (const entry of entries) {
|
|
6310
6876
|
if (entry.isDirectory())
|
|
6311
6877
|
continue;
|
|
@@ -6318,16 +6884,17 @@ var init_generate_ai_content = __esm({
|
|
|
6318
6884
|
if (err instanceof ContentStoreError)
|
|
6319
6885
|
throw err;
|
|
6320
6886
|
}
|
|
6887
|
+
await this.assertUrlPathAvailable(parentDir, safeNewSlug);
|
|
6321
6888
|
try {
|
|
6322
|
-
await
|
|
6889
|
+
await fs10.link(currentPath, newPath);
|
|
6323
6890
|
} catch (err) {
|
|
6324
6891
|
if (isNodeError3(err) && err.code === "EEXIST") {
|
|
6325
6892
|
throw new ContentStoreError(`Entry with slug "${safeNewSlug}" already exists in collection "${collectionPath}"`, "VALIDATION");
|
|
6326
6893
|
}
|
|
6327
6894
|
throw err;
|
|
6328
6895
|
}
|
|
6329
|
-
await
|
|
6330
|
-
const newRelativePath =
|
|
6896
|
+
await fs10.unlink(currentPath);
|
|
6897
|
+
const newRelativePath = path11.relative(this.root, newPath);
|
|
6331
6898
|
const liveIndex = this._idIndex;
|
|
6332
6899
|
const entryId = liveIndex.findByPath(currentRelPath);
|
|
6333
6900
|
if (entryId) {
|
|
@@ -6399,34 +6966,57 @@ var init_generate_ai_content = __esm({
|
|
|
6399
6966
|
}
|
|
6400
6967
|
return entries;
|
|
6401
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
|
+
}
|
|
6402
6991
|
/**
|
|
6403
6992
|
* Recursively resolve reference fields in data.
|
|
6404
6993
|
* This traverses objects, arrays, and blocks to find and resolve all reference fields.
|
|
6405
6994
|
*/
|
|
6406
|
-
async resolveReferencesInData(data, fields) {
|
|
6995
|
+
async resolveReferencesInData(data, fields, cache) {
|
|
6407
6996
|
const resolved = { ...data };
|
|
6408
6997
|
const idIndex = await this.idIndex();
|
|
6409
6998
|
for (const field of fields) {
|
|
6410
6999
|
if (field.type === "group") {
|
|
6411
|
-
const groupResolved = await this.resolveReferencesInData(resolved, field.fields);
|
|
7000
|
+
const groupResolved = await this.resolveReferencesInData(resolved, field.fields, cache);
|
|
6412
7001
|
Object.assign(resolved, groupResolved);
|
|
6413
7002
|
continue;
|
|
6414
7003
|
}
|
|
6415
7004
|
const value = data[field.name];
|
|
6416
7005
|
if (field.type === "reference") {
|
|
7006
|
+
const includeBody = field.includeBody === true;
|
|
6417
7007
|
if (typeof value === "string" && value) {
|
|
6418
|
-
resolved[field.name] = await this.resolveSingleReference(value, idIndex);
|
|
7008
|
+
resolved[field.name] = await this.resolveSingleReference(value, idIndex, includeBody, cache);
|
|
6419
7009
|
} else if (field.list && Array.isArray(value)) {
|
|
6420
|
-
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));
|
|
6421
7011
|
}
|
|
6422
7012
|
} else if (field.type === "object" && value) {
|
|
6423
7013
|
const objectField = field;
|
|
6424
7014
|
if (!objectField.fields)
|
|
6425
7015
|
continue;
|
|
6426
7016
|
if (objectField.list && Array.isArray(value)) {
|
|
6427
|
-
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));
|
|
6428
7018
|
} else if (typeof value === "object") {
|
|
6429
|
-
resolved[field.name] = await this.resolveReferencesInData(value, objectField.fields);
|
|
7019
|
+
resolved[field.name] = await this.resolveReferencesInData(value, objectField.fields, cache);
|
|
6430
7020
|
}
|
|
6431
7021
|
} else if (field.type === "block" && Array.isArray(value)) {
|
|
6432
7022
|
const blockField = field;
|
|
@@ -6439,7 +7029,7 @@ var init_generate_ai_content = __esm({
|
|
|
6439
7029
|
return block;
|
|
6440
7030
|
return {
|
|
6441
7031
|
...b,
|
|
6442
|
-
value: await this.resolveReferencesInData(b.value, template.fields)
|
|
7032
|
+
value: await this.resolveReferencesInData(b.value, template.fields, cache)
|
|
6443
7033
|
};
|
|
6444
7034
|
}));
|
|
6445
7035
|
}
|
|
@@ -6447,7 +7037,56 @@ var init_generate_ai_content = __esm({
|
|
|
6447
7037
|
return resolved;
|
|
6448
7038
|
}
|
|
6449
7039
|
/**
|
|
6450
|
-
* 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
|
+
/**
|
|
6451
7090
|
* Returns null if the reference is invalid or missing.
|
|
6452
7091
|
* Includes id, slug, and collection fields for debugging.
|
|
6453
7092
|
*
|
|
@@ -6461,16 +7100,21 @@ var init_generate_ai_content = __esm({
|
|
|
6461
7100
|
* idIndex() dedupes concurrent builds — so a sibling call that wins the
|
|
6462
7101
|
* throttle and rebuilds heals every other miss in the same batch, not just
|
|
6463
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.
|
|
6464
7108
|
*/
|
|
6465
|
-
async
|
|
6466
|
-
const first = await this.resolveSingleReferenceOnce(id, idIndex);
|
|
7109
|
+
async resolveSingleReferenceUncached(id, idIndex, includeBody) {
|
|
7110
|
+
const first = await this.resolveSingleReferenceOnce(id, idIndex, includeBody);
|
|
6467
7111
|
if (first !== STALE_LOOKUP)
|
|
6468
7112
|
return first;
|
|
6469
7113
|
await this.refreshIndexForSuspiciousLookup();
|
|
6470
|
-
const second = await this.resolveSingleReferenceOnce(id, await this.idIndex());
|
|
7114
|
+
const second = await this.resolveSingleReferenceOnce(id, await this.idIndex(), includeBody);
|
|
6471
7115
|
return second === STALE_LOOKUP ? null : second;
|
|
6472
7116
|
}
|
|
6473
|
-
async resolveSingleReferenceOnce(id, idIndex) {
|
|
7117
|
+
async resolveSingleReferenceOnce(id, idIndex, includeBody) {
|
|
6474
7118
|
try {
|
|
6475
7119
|
const location = idIndex.findById(id);
|
|
6476
7120
|
if (!location)
|
|
@@ -6481,12 +7125,13 @@ var init_generate_ai_content = __esm({
|
|
|
6481
7125
|
const doc = await this.read(location.collection, location.slug, {
|
|
6482
7126
|
resolveReferences: false
|
|
6483
7127
|
});
|
|
6484
|
-
|
|
7128
|
+
const bodyForEmbed = includeBody && "body" in doc ? { fieldName: doc.bodyFieldName, value: doc.body } : void 0;
|
|
7129
|
+
return buildResolvedReference(doc.data, {
|
|
6485
7130
|
id,
|
|
6486
7131
|
slug: location.slug,
|
|
6487
7132
|
collection: location.collection,
|
|
6488
|
-
|
|
6489
|
-
};
|
|
7133
|
+
urlPath: computeEntryUrl(location.collection, location.slug, this.contentRootName)
|
|
7134
|
+
}, bodyForEmbed);
|
|
6490
7135
|
} catch (error) {
|
|
6491
7136
|
if (isNodeError3(error) && error.code === "ENOENT")
|
|
6492
7137
|
return STALE_LOOKUP;
|
|
@@ -6511,7 +7156,6 @@ var init_generate_ai_content = __esm({
|
|
|
6511
7156
|
"reference",
|
|
6512
7157
|
"image"
|
|
6513
7158
|
]);
|
|
6514
|
-
init_normalize2();
|
|
6515
7159
|
log22 = createDebugLogger2({ prefix: "EntryLinks" });
|
|
6516
7160
|
BASE58_CHAR = "[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]";
|
|
6517
7161
|
ENTRY_LINK_PATTERN = new RegExp(`entry:(${BASE58_CHAR}{12})(#[^\\s)>"']*)?`, "g");
|
|
@@ -6527,10 +7171,10 @@ var init_generate_ai_content = __esm({
|
|
|
6527
7171
|
constructor(root) {
|
|
6528
7172
|
this.regenInFlight = null;
|
|
6529
7173
|
this.lastForcedRefreshMs = 0;
|
|
6530
|
-
this.root =
|
|
6531
|
-
this.registryPath =
|
|
6532
|
-
this.stalePath =
|
|
6533
|
-
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);
|
|
6534
7178
|
}
|
|
6535
7179
|
/**
|
|
6536
7180
|
* Returns all branches. Uses the cached snapshot if its embedded generation
|
|
@@ -6539,7 +7183,7 @@ var init_generate_ai_content = __esm({
|
|
|
6539
7183
|
async list() {
|
|
6540
7184
|
let parsed;
|
|
6541
7185
|
try {
|
|
6542
|
-
const raw = await
|
|
7186
|
+
const raw = await fs12.readFile(this.registryPath, "utf8");
|
|
6543
7187
|
parsed = JSON.parse(raw);
|
|
6544
7188
|
} catch (err) {
|
|
6545
7189
|
if (isNotFoundError3(err)) {
|
|
@@ -6628,7 +7272,7 @@ var init_generate_ai_content = __esm({
|
|
|
6628
7272
|
async performRegenerate() {
|
|
6629
7273
|
const read = await readResourceGeneration(this.root, RESOURCE2);
|
|
6630
7274
|
const branches = await this.scanBranchDirectories();
|
|
6631
|
-
await
|
|
7275
|
+
await fs12.unlink(this.stalePath).catch(() => {
|
|
6632
7276
|
});
|
|
6633
7277
|
if (!read.ok) {
|
|
6634
7278
|
return branches;
|
|
@@ -6639,12 +7283,12 @@ var init_generate_ai_content = __esm({
|
|
|
6639
7283
|
generation: read.token
|
|
6640
7284
|
};
|
|
6641
7285
|
const uniqueTempPath = `${this.tempPath}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
6642
|
-
await
|
|
6643
|
-
await
|
|
7286
|
+
await fs12.mkdir(this.root, { recursive: true });
|
|
7287
|
+
await fs12.writeFile(uniqueTempPath, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
|
|
6644
7288
|
try {
|
|
6645
|
-
await
|
|
7289
|
+
await fs12.rename(uniqueTempPath, this.registryPath);
|
|
6646
7290
|
} catch (err) {
|
|
6647
|
-
await
|
|
7291
|
+
await fs12.unlink(uniqueTempPath).catch(() => {
|
|
6648
7292
|
});
|
|
6649
7293
|
throw err;
|
|
6650
7294
|
}
|
|
@@ -6658,12 +7302,12 @@ var init_generate_ai_content = __esm({
|
|
|
6658
7302
|
async scanBranchDirectories() {
|
|
6659
7303
|
const branches = [];
|
|
6660
7304
|
try {
|
|
6661
|
-
const entries = await
|
|
7305
|
+
const entries = await fs12.readdir(this.root, { withFileTypes: true });
|
|
6662
7306
|
for (const entry of entries) {
|
|
6663
7307
|
if (!entry.isDirectory() || entry.name.startsWith(".")) {
|
|
6664
7308
|
continue;
|
|
6665
7309
|
}
|
|
6666
|
-
const branchRoot =
|
|
7310
|
+
const branchRoot = path13.join(this.root, entry.name);
|
|
6667
7311
|
let meta;
|
|
6668
7312
|
try {
|
|
6669
7313
|
meta = await BranchMetadataFileManager.loadOnly(branchRoot);
|
|
@@ -6714,8 +7358,8 @@ var init_generate_ai_content = __esm({
|
|
|
6714
7358
|
};
|
|
6715
7359
|
BranchMetadataFileManager = class _BranchMetadataFileManager {
|
|
6716
7360
|
constructor(branchRoot, baseRoot, options) {
|
|
6717
|
-
this.branchRoot =
|
|
6718
|
-
this.filePath =
|
|
7361
|
+
this.branchRoot = path15.resolve(branchRoot);
|
|
7362
|
+
this.filePath = path15.join(this.branchRoot, BRANCH_META_DIR, BRANCH_META_FILE);
|
|
6719
7363
|
this.baseRoot = baseRoot;
|
|
6720
7364
|
this.settleMs = options?.settleMs;
|
|
6721
7365
|
}
|
|
@@ -6724,10 +7368,10 @@ var init_generate_ai_content = __esm({
|
|
|
6724
7368
|
* Use this for read-only access (e.g., in registry scanning or loadBranchContext).
|
|
6725
7369
|
*/
|
|
6726
7370
|
static async loadOnly(branchRoot) {
|
|
6727
|
-
const resolvedRoot =
|
|
6728
|
-
const filePath =
|
|
7371
|
+
const resolvedRoot = path15.resolve(branchRoot);
|
|
7372
|
+
const filePath = path15.join(resolvedRoot, BRANCH_META_DIR, BRANCH_META_FILE);
|
|
6729
7373
|
try {
|
|
6730
|
-
const raw = await
|
|
7374
|
+
const raw = await fs14.readFile(filePath, "utf8");
|
|
6731
7375
|
return JSON.parse(raw);
|
|
6732
7376
|
} catch (err) {
|
|
6733
7377
|
if (isNotFoundError3(err)) {
|
|
@@ -6748,7 +7392,7 @@ var init_generate_ai_content = __esm({
|
|
|
6748
7392
|
}
|
|
6749
7393
|
async load() {
|
|
6750
7394
|
try {
|
|
6751
|
-
const raw = await
|
|
7395
|
+
const raw = await fs14.readFile(this.filePath, "utf8");
|
|
6752
7396
|
const parsed = JSON.parse(raw);
|
|
6753
7397
|
const version = parsed.version ?? 0;
|
|
6754
7398
|
return { meta: parsed, version };
|
|
@@ -6810,7 +7454,7 @@ var init_generate_ai_content = __esm({
|
|
|
6810
7454
|
*/
|
|
6811
7455
|
async save(incoming) {
|
|
6812
7456
|
try {
|
|
6813
|
-
await
|
|
7457
|
+
await fs14.stat(this.branchRoot);
|
|
6814
7458
|
} catch (err) {
|
|
6815
7459
|
if (isNotFoundError3(err)) {
|
|
6816
7460
|
throw new BranchMetadataConflictError("Branch no longer exists");
|
|
@@ -6923,12 +7567,12 @@ var init_generate_ai_content = __esm({
|
|
|
6923
7567
|
};
|
|
6924
7568
|
GitManager = class _GitManager {
|
|
6925
7569
|
constructor(options, gitOptions) {
|
|
6926
|
-
this.repoPath =
|
|
7570
|
+
this.repoPath = path16.resolve(options.repoPath);
|
|
6927
7571
|
this.baseBranch = options.baseBranch ?? "main";
|
|
6928
7572
|
this.remote = options.remote ?? "origin";
|
|
6929
7573
|
this.skipIndexMarker = options.skipIndexMarker ?? false;
|
|
6930
7574
|
this.git = simpleGit2({ baseDir: this.repoPath, ...gitOptions });
|
|
6931
|
-
this.git.env(gitChildEnv({ GIT_CEILING_DIRECTORIES:
|
|
7575
|
+
this.git.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(this.repoPath) }));
|
|
6932
7576
|
}
|
|
6933
7577
|
static async cloneRepo(remoteUrl, targetPath, baseBranch = "main") {
|
|
6934
7578
|
log5.debug("git", "Cloning repository", {
|
|
@@ -6970,11 +7614,11 @@ var init_generate_ai_content = __esm({
|
|
|
6970
7614
|
remotePath: options.remotePath,
|
|
6971
7615
|
baseBranch: options.baseBranch
|
|
6972
7616
|
});
|
|
6973
|
-
const remoteParent =
|
|
7617
|
+
const remoteParent = path16.dirname(options.remotePath);
|
|
6974
7618
|
releaseLock = await acquireProvisioningLock(remoteParent, ".remote-init.lock");
|
|
6975
7619
|
let remoteExists = false;
|
|
6976
7620
|
try {
|
|
6977
|
-
const stat = await
|
|
7621
|
+
const stat = await fs15.stat(options.remotePath);
|
|
6978
7622
|
remoteExists = stat.isDirectory();
|
|
6979
7623
|
} catch (err) {
|
|
6980
7624
|
if (!isNotFoundError3(err))
|
|
@@ -7226,7 +7870,7 @@ var init_generate_ai_content = __esm({
|
|
|
7226
7870
|
*/
|
|
7227
7871
|
static async validateGitRepoExists(repoPath) {
|
|
7228
7872
|
try {
|
|
7229
|
-
const stat = await
|
|
7873
|
+
const stat = await fs15.stat(path16.join(repoPath, ".git"));
|
|
7230
7874
|
if (!stat.isDirectory()) {
|
|
7231
7875
|
throw new Error(`Expected git repo at ${repoPath}`);
|
|
7232
7876
|
}
|
|
@@ -7304,7 +7948,7 @@ var init_generate_ai_content = __esm({
|
|
|
7304
7948
|
}
|
|
7305
7949
|
if (config.autoDetectRemotePath) {
|
|
7306
7950
|
try {
|
|
7307
|
-
const stat = await
|
|
7951
|
+
const stat = await fs15.stat(config.autoDetectRemotePath);
|
|
7308
7952
|
if (stat.isDirectory()) {
|
|
7309
7953
|
log5.debug("git", "Auto-detected local remote", {
|
|
7310
7954
|
path: config.autoDetectRemotePath
|
|
@@ -7317,8 +7961,8 @@ var init_generate_ai_content = __esm({
|
|
|
7317
7961
|
if (config.shouldAutoInitLocal) {
|
|
7318
7962
|
const gitRoot = await this.findGitRoot();
|
|
7319
7963
|
const sourceRoot = options.sourceRoot;
|
|
7320
|
-
const sourcePath = sourceRoot ?
|
|
7321
|
-
const localRemotePath =
|
|
7964
|
+
const sourcePath = sourceRoot ? path16.resolve(gitRoot, sourceRoot) : gitRoot;
|
|
7965
|
+
const localRemotePath = path16.join(sourcePath, config.defaultRemotePath);
|
|
7322
7966
|
await this.ensureLocalSimulatedRemote({
|
|
7323
7967
|
remotePath: localRemotePath,
|
|
7324
7968
|
sourcePath: gitRoot,
|
|
@@ -7346,7 +7990,7 @@ var init_generate_ai_content = __esm({
|
|
|
7346
7990
|
static async repoExistsAt(workspacePath) {
|
|
7347
7991
|
try {
|
|
7348
7992
|
const checkGit = simpleGit2({ baseDir: workspacePath });
|
|
7349
|
-
checkGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES:
|
|
7993
|
+
checkGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(workspacePath) }));
|
|
7350
7994
|
await checkGit.raw(["rev-parse", "--git-dir"]);
|
|
7351
7995
|
return true;
|
|
7352
7996
|
} catch {
|
|
@@ -7368,19 +8012,19 @@ var init_generate_ai_content = __esm({
|
|
|
7368
8012
|
const baseBranch = await resolveBaseBranch({
|
|
7369
8013
|
defaultBaseBranch: options.baseBranch,
|
|
7370
8014
|
mode: options.mode,
|
|
7371
|
-
detectFrom: options.sourceRoot ?
|
|
8015
|
+
detectFrom: options.sourceRoot ? path16.resolve(process.cwd(), options.sourceRoot) : process.cwd()
|
|
7372
8016
|
});
|
|
7373
8017
|
const remoteName = options.remoteName ?? "origin";
|
|
7374
8018
|
const repoExists = await _GitManager.repoExistsAt(options.workspacePath);
|
|
7375
8019
|
if (!repoExists) {
|
|
7376
|
-
const gitPath =
|
|
8020
|
+
const gitPath = path16.join(options.workspacePath, ".git");
|
|
7377
8021
|
try {
|
|
7378
|
-
const stat = await
|
|
8022
|
+
const stat = await fs15.stat(gitPath);
|
|
7379
8023
|
if (stat.isDirectory()) {
|
|
7380
8024
|
log5.debug("git", "Removing corrupt .git directory", {
|
|
7381
8025
|
workspacePath: options.workspacePath
|
|
7382
8026
|
});
|
|
7383
|
-
await
|
|
8027
|
+
await fs15.rm(gitPath, { recursive: true });
|
|
7384
8028
|
}
|
|
7385
8029
|
} catch (cleanupErr) {
|
|
7386
8030
|
if (!isNotFoundError3(cleanupErr))
|
|
@@ -7407,7 +8051,7 @@ var init_generate_ai_content = __esm({
|
|
|
7407
8051
|
}
|
|
7408
8052
|
justCloned = true;
|
|
7409
8053
|
const freshGit = simpleGit2({ baseDir: options.workspacePath });
|
|
7410
|
-
freshGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES:
|
|
8054
|
+
freshGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(options.workspacePath) }));
|
|
7411
8055
|
await freshGit.addConfig("canopycms.managed", "true");
|
|
7412
8056
|
await freshGit.addConfig("user.name", options.gitBotAuthorName);
|
|
7413
8057
|
await freshGit.addConfig("user.email", options.gitBotAuthorEmail);
|
|
@@ -7758,9 +8402,9 @@ var init_generate_ai_content = __esm({
|
|
|
7758
8402
|
} catch {
|
|
7759
8403
|
}
|
|
7760
8404
|
for (const [filePath, content] of Object.entries(initialFiles)) {
|
|
7761
|
-
const absolutePath =
|
|
7762
|
-
await
|
|
7763
|
-
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");
|
|
7764
8408
|
await this.git.add(filePath);
|
|
7765
8409
|
}
|
|
7766
8410
|
await this.git.commit("Initialize settings branch", ["--allow-empty"]);
|
|
@@ -7787,7 +8431,7 @@ var init_generate_ai_content = __esm({
|
|
|
7787
8431
|
branchName: options.branchName,
|
|
7788
8432
|
mode: options.mode
|
|
7789
8433
|
});
|
|
7790
|
-
releaseLock = await acquireProvisioningLock(
|
|
8434
|
+
releaseLock = await acquireProvisioningLock(path17.dirname(options.branchRoot), `.${path17.basename(options.branchRoot)}.init.lock`);
|
|
7791
8435
|
await GitManager.initializeWorkspace({
|
|
7792
8436
|
workspacePath: options.branchRoot,
|
|
7793
8437
|
branchName: options.branchName,
|
|
@@ -7828,7 +8472,7 @@ var init_generate_ai_content = __esm({
|
|
|
7828
8472
|
const baseBranch = await resolveBaseBranch({
|
|
7829
8473
|
defaultBaseBranch: this.config.defaultBaseBranch,
|
|
7830
8474
|
mode,
|
|
7831
|
-
detectFrom: this.config.sourceRoot ?
|
|
8475
|
+
detectFrom: this.config.sourceRoot ? path17.resolve(process.cwd(), this.config.sourceRoot) : void 0
|
|
7832
8476
|
});
|
|
7833
8477
|
await this.ensureGitWorkspace({
|
|
7834
8478
|
branchRoot,
|
|
@@ -7865,15 +8509,15 @@ var init_generate_ai_content = __esm({
|
|
|
7865
8509
|
};
|
|
7866
8510
|
readEntryData = async (filePath, format, bodyFieldName = "body") => {
|
|
7867
8511
|
try {
|
|
7868
|
-
const raw = await
|
|
8512
|
+
const raw = await fs16.readFile(filePath, "utf8");
|
|
7869
8513
|
if (format === "json") {
|
|
7870
8514
|
return asRecord(JSON.parse(raw));
|
|
7871
8515
|
}
|
|
7872
8516
|
if (format === "yaml") {
|
|
7873
8517
|
return asRecord(yamlParse2(raw));
|
|
7874
8518
|
}
|
|
7875
|
-
const parsed =
|
|
7876
|
-
const data = parsed.data ?? {};
|
|
8519
|
+
const parsed = matter3(raw);
|
|
8520
|
+
const data = { ...parsed.data ?? {} };
|
|
7877
8521
|
if (parsed.content) {
|
|
7878
8522
|
data[bodyFieldName] = parsed.content;
|
|
7879
8523
|
}
|
|
@@ -7885,30 +8529,19 @@ var init_generate_ai_content = __esm({
|
|
|
7885
8529
|
return {};
|
|
7886
8530
|
}
|
|
7887
8531
|
};
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
|
|
7892
|
-
|
|
7893
|
-
|
|
7894
|
-
|
|
7895
|
-
|
|
7896
|
-
if (parts.length < 3)
|
|
7897
|
-
return null;
|
|
7898
|
-
const potentialType = parts[0];
|
|
7899
|
-
if (entryTypes && !entryTypes.some((e) => e.name === potentialType)) {
|
|
7900
|
-
return null;
|
|
7901
|
-
}
|
|
7902
|
-
const id = parts[parts.length - 1];
|
|
7903
|
-
if (!isValidId(id))
|
|
7904
|
-
return null;
|
|
7905
|
-
const slug = parts.slice(1, -1).join(".").toLowerCase();
|
|
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;
|
|
7906
8540
|
return {
|
|
7907
|
-
|
|
7908
|
-
|
|
7909
|
-
id
|
|
8541
|
+
...item,
|
|
8542
|
+
data: await resolver.store.resolveReferences(item.data, fields, resolver.cache)
|
|
7910
8543
|
};
|
|
7911
|
-
};
|
|
8544
|
+
}));
|
|
7912
8545
|
looksLikeMalformedEntry = (filename, entryTypes) => {
|
|
7913
8546
|
if (filename.startsWith(".") || filename.startsWith("_"))
|
|
7914
8547
|
return false;
|
|
@@ -7937,7 +8570,7 @@ var init_generate_ai_content = __esm({
|
|
|
7937
8570
|
normalizePath(root, collectionRoot);
|
|
7938
8571
|
let dirents;
|
|
7939
8572
|
try {
|
|
7940
|
-
dirents = await
|
|
8573
|
+
dirents = await fs16.readdir(collectionRoot, { withFileTypes: true });
|
|
7941
8574
|
} catch (err) {
|
|
7942
8575
|
if (isNotFoundError3(err))
|
|
7943
8576
|
return [];
|
|
@@ -7945,7 +8578,7 @@ var init_generate_ai_content = __esm({
|
|
|
7945
8578
|
}
|
|
7946
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));
|
|
7947
8580
|
const entries = await Promise.all(files.map(async (file) => {
|
|
7948
|
-
const absolutePath =
|
|
8581
|
+
const absolutePath = path18.join(collectionRoot, file.name);
|
|
7949
8582
|
const relativePath = normalizePath(root, absolutePath);
|
|
7950
8583
|
const parsed = parseTypedFilename(file.name, entryTypes);
|
|
7951
8584
|
if (!parsed) {
|
|
@@ -7960,7 +8593,7 @@ var init_generate_ai_content = __esm({
|
|
|
7960
8593
|
const format = entryType?.format || "json";
|
|
7961
8594
|
const bodyField = entryType?.schema ? findBodyFieldName(entryType.schema) : "body";
|
|
7962
8595
|
const [stats, data] = await Promise.all([
|
|
7963
|
-
|
|
8596
|
+
fs16.stat(absolutePath),
|
|
7964
8597
|
readEntryData(absolutePath, format, bodyField)
|
|
7965
8598
|
]);
|
|
7966
8599
|
const item = {
|
|
@@ -7984,22 +8617,23 @@ var init_generate_ai_content = __esm({
|
|
|
7984
8617
|
KNOWN_FIELD_TYPES = new Set(fieldTypes2);
|
|
7985
8618
|
STRING_FIELD_TYPES = /* @__PURE__ */ new Set(["string", "markdown", "mdx", "code"]);
|
|
7986
8619
|
selectOptionValues = (field) => (field.options ?? []).map((opt) => typeof opt === "string" ? opt : opt.value);
|
|
8620
|
+
GENERATED_RECORD_FILENAME = ".canopy-generated.json";
|
|
7987
8621
|
jiti = createJiti2(import.meta.url);
|
|
7988
8622
|
}
|
|
7989
8623
|
});
|
|
7990
8624
|
|
|
7991
8625
|
// dist/utils/atomic-write.js
|
|
7992
|
-
import
|
|
7993
|
-
import
|
|
8626
|
+
import fs18 from "node:fs/promises";
|
|
8627
|
+
import path21 from "node:path";
|
|
7994
8628
|
async function atomicWriteFile3(filePath, content) {
|
|
7995
|
-
const dir =
|
|
7996
|
-
await
|
|
8629
|
+
const dir = path21.dirname(filePath);
|
|
8630
|
+
await fs18.mkdir(dir, { recursive: true });
|
|
7997
8631
|
const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
7998
|
-
await
|
|
8632
|
+
await fs18.writeFile(tempPath, content, typeof content === "string" ? "utf-8" : void 0);
|
|
7999
8633
|
try {
|
|
8000
|
-
await
|
|
8634
|
+
await fs18.rename(tempPath, filePath);
|
|
8001
8635
|
} catch (err) {
|
|
8002
|
-
await
|
|
8636
|
+
await fs18.unlink(tempPath).catch(() => {
|
|
8003
8637
|
});
|
|
8004
8638
|
throw err;
|
|
8005
8639
|
}
|
|
@@ -8119,11 +8753,11 @@ var init_debug2 = __esm({
|
|
|
8119
8753
|
});
|
|
8120
8754
|
|
|
8121
8755
|
// dist/resource-generation.js
|
|
8122
|
-
import
|
|
8123
|
-
import
|
|
8756
|
+
import fs19 from "node:fs/promises";
|
|
8757
|
+
import path23 from "node:path";
|
|
8124
8758
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
8125
8759
|
function resourceGenerationPath2(root, resource) {
|
|
8126
|
-
return
|
|
8760
|
+
return path23.resolve(root, META_DIR3, `${resource}.generation`);
|
|
8127
8761
|
}
|
|
8128
8762
|
async function bumpResourceGeneration2(root, resource, options) {
|
|
8129
8763
|
const token = randomUUID3();
|
|
@@ -8141,7 +8775,7 @@ async function bumpResourceGeneration2(root, resource, options) {
|
|
|
8141
8775
|
}
|
|
8142
8776
|
async function readResourceGeneration2(root, resource) {
|
|
8143
8777
|
try {
|
|
8144
|
-
const token = await
|
|
8778
|
+
const token = await fs19.readFile(resourceGenerationPath2(root, resource), "utf-8");
|
|
8145
8779
|
return { ok: true, token };
|
|
8146
8780
|
} catch (err) {
|
|
8147
8781
|
if (isNodeError(err) && err.code === "ENOENT")
|
|
@@ -8168,10 +8802,10 @@ var init_resource_generation = __esm({
|
|
|
8168
8802
|
});
|
|
8169
8803
|
|
|
8170
8804
|
// dist/content-index-registry.js
|
|
8171
|
-
import
|
|
8805
|
+
import path24 from "node:path";
|
|
8172
8806
|
function invalidateContentIndexesForRoot2(root) {
|
|
8173
|
-
const rootKey =
|
|
8174
|
-
const prefix = rootKey +
|
|
8807
|
+
const rootKey = path24.resolve(root);
|
|
8808
|
+
const prefix = rootKey + path24.sep;
|
|
8175
8809
|
for (const [storeRoot, refs] of registry2) {
|
|
8176
8810
|
if (storeRoot !== rootKey && !storeRoot.startsWith(prefix))
|
|
8177
8811
|
continue;
|
|
@@ -8229,7 +8863,7 @@ var init_normalize3 = __esm({
|
|
|
8229
8863
|
function isValidContentId2(id) {
|
|
8230
8864
|
return CONTENT_ID_PATTERN2.test(id);
|
|
8231
8865
|
}
|
|
8232
|
-
function
|
|
8866
|
+
function parseSlug2(slug) {
|
|
8233
8867
|
if (!slug) {
|
|
8234
8868
|
return {
|
|
8235
8869
|
ok: false,
|
|
@@ -8339,7 +8973,7 @@ var init_content_id_index = __esm({
|
|
|
8339
8973
|
});
|
|
8340
8974
|
|
|
8341
8975
|
// dist/schema/meta-loader.js
|
|
8342
|
-
import { promises as
|
|
8976
|
+
import { promises as fs20 } from "fs";
|
|
8343
8977
|
import { join as join4 } from "pathe";
|
|
8344
8978
|
import { z as z8 } from "zod";
|
|
8345
8979
|
import chokidar2 from "chokidar";
|
|
@@ -8349,7 +8983,7 @@ function stripEmbeddedIdFromName2(name) {
|
|
|
8349
8983
|
async function scanForCollectionMeta2(baseDir, relativePath = "") {
|
|
8350
8984
|
const collections = [];
|
|
8351
8985
|
try {
|
|
8352
|
-
const entries = await
|
|
8986
|
+
const entries = await fs20.readdir(baseDir, { withFileTypes: true });
|
|
8353
8987
|
for (const entry of entries) {
|
|
8354
8988
|
if (!entry.isDirectory())
|
|
8355
8989
|
continue;
|
|
@@ -8360,8 +8994,8 @@ async function scanForCollectionMeta2(baseDir, relativePath = "") {
|
|
|
8360
8994
|
const absolutePath = join4(baseDir, folderName);
|
|
8361
8995
|
const metaPath = join4(absolutePath, ".collection.json");
|
|
8362
8996
|
try {
|
|
8363
|
-
await
|
|
8364
|
-
const content = await
|
|
8997
|
+
await fs20.access(metaPath);
|
|
8998
|
+
const content = await fs20.readFile(metaPath, "utf-8");
|
|
8365
8999
|
const parsed = JSON.parse(content);
|
|
8366
9000
|
const meta = collectionMetaSchema2.parse(parsed);
|
|
8367
9001
|
collections.push({
|
|
@@ -8393,7 +9027,7 @@ async function loadCollectionMetaFiles2(contentRoot) {
|
|
|
8393
9027
|
let root = null;
|
|
8394
9028
|
const rootMetaPath = join4(contentRoot, ".collection.json");
|
|
8395
9029
|
try {
|
|
8396
|
-
await
|
|
9030
|
+
await fs20.access(rootMetaPath);
|
|
8397
9031
|
} catch (err) {
|
|
8398
9032
|
if (err.code === "ENOENT") {
|
|
8399
9033
|
} else {
|
|
@@ -8401,7 +9035,7 @@ async function loadCollectionMetaFiles2(contentRoot) {
|
|
|
8401
9035
|
}
|
|
8402
9036
|
}
|
|
8403
9037
|
try {
|
|
8404
|
-
const content = await
|
|
9038
|
+
const content = await fs20.readFile(rootMetaPath, "utf-8");
|
|
8405
9039
|
const parsed = JSON.parse(content);
|
|
8406
9040
|
root = rootCollectionMetaSchema2.parse(parsed);
|
|
8407
9041
|
} catch (err) {
|
|
@@ -8548,7 +9182,12 @@ var init_field3 = __esm({
|
|
|
8548
9182
|
collections: z9.array(z9.string().min(1)).min(1).optional(),
|
|
8549
9183
|
entryTypes: z9.array(z9.string().min(1)).min(1).optional(),
|
|
8550
9184
|
displayField: z9.string().min(1).optional(),
|
|
8551
|
-
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()
|
|
8552
9191
|
});
|
|
8553
9192
|
fieldHolder3 = [z9.never()];
|
|
8554
9193
|
blockSchema3 = z9.object({
|
|
@@ -8658,7 +9297,7 @@ var init_media3 = __esm({
|
|
|
8658
9297
|
|
|
8659
9298
|
// dist/config/schemas/config.js
|
|
8660
9299
|
import { z as z12 } from "zod";
|
|
8661
|
-
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;
|
|
8662
9301
|
var init_config4 = __esm({
|
|
8663
9302
|
"dist/config/schemas/config.js"() {
|
|
8664
9303
|
"use strict";
|
|
@@ -8682,6 +9321,9 @@ var init_config4 = __esm({
|
|
|
8682
9321
|
deployedAsSchema3 = z12.enum(["static", "server"]).default("server");
|
|
8683
9322
|
contentRootSchema3 = relativePathSchema3.default("content");
|
|
8684
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();
|
|
8685
9327
|
deploymentNameSchema3 = z12.string().default("prod");
|
|
8686
9328
|
devContentSyncSchema3 = z12.enum(["off", "warn"]).default("warn");
|
|
8687
9329
|
devConfigSchema3 = z12.object({
|
|
@@ -8744,6 +9386,7 @@ var init_config4 = __esm({
|
|
|
8744
9386
|
deploymentName: deploymentNameSchema3.optional(),
|
|
8745
9387
|
contentRoot: contentRootSchema3.default("content"),
|
|
8746
9388
|
sourceRoot: sourceRootSchema3.optional(),
|
|
9389
|
+
basePath: basePathSchema3,
|
|
8747
9390
|
editor: editorConfigSchema3.optional(),
|
|
8748
9391
|
authPlugin: z12.custom().optional(),
|
|
8749
9392
|
entryLinkUrl: z12.custom().optional(),
|
|
@@ -8830,13 +9473,13 @@ var init_content_index_generation = __esm({
|
|
|
8830
9473
|
});
|
|
8831
9474
|
|
|
8832
9475
|
// dist/sync-core.js
|
|
8833
|
-
import
|
|
8834
|
-
import
|
|
9476
|
+
import fs21 from "node:fs/promises";
|
|
9477
|
+
import path25 from "node:path";
|
|
8835
9478
|
import { simpleGit as simpleGit4 } from "simple-git";
|
|
8836
9479
|
function assertWithinDir(resolved, parent, label) {
|
|
8837
|
-
const normalizedResolved =
|
|
8838
|
-
const normalizedParent =
|
|
8839
|
-
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) {
|
|
8840
9483
|
throw new Error(`${label} escapes the expected directory: ${resolved}`);
|
|
8841
9484
|
}
|
|
8842
9485
|
}
|
|
@@ -8844,19 +9487,19 @@ async function safeReplaceDir(oldDir, newDir) {
|
|
|
8844
9487
|
const backupDir = `${oldDir}.sync-backup-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
8845
9488
|
const oldExists = await filePathExists(oldDir);
|
|
8846
9489
|
if (oldExists) {
|
|
8847
|
-
await
|
|
9490
|
+
await fs21.rename(oldDir, backupDir);
|
|
8848
9491
|
}
|
|
8849
9492
|
try {
|
|
8850
|
-
await
|
|
9493
|
+
await fs21.rename(newDir, oldDir);
|
|
8851
9494
|
} catch (err) {
|
|
8852
9495
|
if (oldExists) {
|
|
8853
|
-
await
|
|
9496
|
+
await fs21.rename(backupDir, oldDir).catch(() => {
|
|
8854
9497
|
});
|
|
8855
9498
|
}
|
|
8856
9499
|
throw err;
|
|
8857
9500
|
}
|
|
8858
9501
|
if (oldExists) {
|
|
8859
|
-
await
|
|
9502
|
+
await fs21.rm(backupDir, { recursive: true, force: true }).catch(() => {
|
|
8860
9503
|
});
|
|
8861
9504
|
}
|
|
8862
9505
|
}
|
|
@@ -8864,7 +9507,7 @@ async function listFilesRecursive(dir, prefix = "") {
|
|
|
8864
9507
|
const results = [];
|
|
8865
9508
|
let entries;
|
|
8866
9509
|
try {
|
|
8867
|
-
entries = await
|
|
9510
|
+
entries = await fs21.readdir(dir, { withFileTypes: true });
|
|
8868
9511
|
} catch {
|
|
8869
9512
|
return results;
|
|
8870
9513
|
}
|
|
@@ -8875,7 +9518,7 @@ async function listFilesRecursive(dir, prefix = "") {
|
|
|
8875
9518
|
continue;
|
|
8876
9519
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
8877
9520
|
if (entry.isDirectory()) {
|
|
8878
|
-
results.push(...await listFilesRecursive(
|
|
9521
|
+
results.push(...await listFilesRecursive(path25.join(dir, entry.name), rel));
|
|
8879
9522
|
} else {
|
|
8880
9523
|
results.push(rel);
|
|
8881
9524
|
}
|
|
@@ -8883,19 +9526,19 @@ async function listFilesRecursive(dir, prefix = "") {
|
|
|
8883
9526
|
return results;
|
|
8884
9527
|
}
|
|
8885
9528
|
async function copyDir(src, dest) {
|
|
8886
|
-
await
|
|
8887
|
-
const entries = await
|
|
9529
|
+
await fs21.mkdir(dest, { recursive: true });
|
|
9530
|
+
const entries = await fs21.readdir(src, { withFileTypes: true });
|
|
8888
9531
|
for (const entry of entries) {
|
|
8889
9532
|
if (entry.name === ".git")
|
|
8890
9533
|
continue;
|
|
8891
9534
|
if (entry.isSymbolicLink())
|
|
8892
9535
|
continue;
|
|
8893
|
-
const srcPath =
|
|
8894
|
-
const destPath =
|
|
9536
|
+
const srcPath = path25.join(src, entry.name);
|
|
9537
|
+
const destPath = path25.join(dest, entry.name);
|
|
8895
9538
|
if (entry.isDirectory()) {
|
|
8896
9539
|
await copyDir(srcPath, destPath);
|
|
8897
9540
|
} else {
|
|
8898
|
-
await
|
|
9541
|
+
await fs21.copyFile(srcPath, destPath);
|
|
8899
9542
|
}
|
|
8900
9543
|
}
|
|
8901
9544
|
}
|
|
@@ -8904,14 +9547,14 @@ async function pushContentToWorkspace(options) {
|
|
|
8904
9547
|
if (!await filePathExists(srcContentDir)) {
|
|
8905
9548
|
return { fileCount: 0 };
|
|
8906
9549
|
}
|
|
8907
|
-
const wsContentDir =
|
|
9550
|
+
const wsContentDir = path25.join(branchPath, contentRoot);
|
|
8908
9551
|
assertWithinDir(wsContentDir, branchPath, "content-root");
|
|
8909
9552
|
const tmpDir = `${wsContentDir}.sync-tmp-${Date.now()}`;
|
|
8910
9553
|
try {
|
|
8911
9554
|
await copyDir(srcContentDir, tmpDir);
|
|
8912
9555
|
await safeReplaceDir(wsContentDir, tmpDir);
|
|
8913
9556
|
} catch (err) {
|
|
8914
|
-
await
|
|
9557
|
+
await fs21.rm(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
8915
9558
|
});
|
|
8916
9559
|
throw err;
|
|
8917
9560
|
}
|
|
@@ -8955,19 +9598,21 @@ import lockfile3 from "proper-lockfile";
|
|
|
8955
9598
|
var init_provisioning_lock = __esm({
|
|
8956
9599
|
"dist/utils/provisioning-lock.js"() {
|
|
8957
9600
|
"use strict";
|
|
9601
|
+
init_error();
|
|
9602
|
+
init_logger3();
|
|
8958
9603
|
}
|
|
8959
9604
|
});
|
|
8960
9605
|
|
|
8961
9606
|
// dist/git-manager.js
|
|
8962
|
-
import
|
|
8963
|
-
import
|
|
9607
|
+
import fs24 from "node:fs/promises";
|
|
9608
|
+
import path26 from "node:path";
|
|
8964
9609
|
import { simpleGit as simpleGit6 } from "simple-git";
|
|
8965
9610
|
async function ensureGitExcludePattern2(repoPath, pattern) {
|
|
8966
|
-
const excludePath =
|
|
8967
|
-
await
|
|
9611
|
+
const excludePath = path26.join(repoPath, ".git", "info", "exclude");
|
|
9612
|
+
await fs24.mkdir(path26.dirname(excludePath), { recursive: true });
|
|
8968
9613
|
let content = "";
|
|
8969
9614
|
try {
|
|
8970
|
-
content = await
|
|
9615
|
+
content = await fs24.readFile(excludePath, "utf-8");
|
|
8971
9616
|
} catch (err) {
|
|
8972
9617
|
if (!isNotFoundError(err))
|
|
8973
9618
|
throw err;
|
|
@@ -8979,7 +9624,7 @@ async function ensureGitExcludePattern2(repoPath, pattern) {
|
|
|
8979
9624
|
}
|
|
8980
9625
|
const needsLeadingNewline = content.length > 0 && !content.endsWith("\n");
|
|
8981
9626
|
const newContent = content + (needsLeadingNewline ? "\n" : "") + pattern + "\n";
|
|
8982
|
-
await
|
|
9627
|
+
await fs24.writeFile(excludePath, newContent, "utf-8");
|
|
8983
9628
|
log9.debug("git", "Added pattern to .git/info/exclude", { pattern });
|
|
8984
9629
|
}
|
|
8985
9630
|
var log9;
|
|
@@ -9136,7 +9781,7 @@ var init_config5 = __esm({
|
|
|
9136
9781
|
});
|
|
9137
9782
|
|
|
9138
9783
|
// dist/operating-mode/client-unsafe-strategy.js
|
|
9139
|
-
import
|
|
9784
|
+
import path27 from "node:path";
|
|
9140
9785
|
function operatingStrategy3(mode) {
|
|
9141
9786
|
const cached = strategyCache3.get(mode);
|
|
9142
9787
|
if (cached)
|
|
@@ -9171,32 +9816,32 @@ var init_client_unsafe_strategy2 = __esm({
|
|
|
9171
9816
|
// - shouldCommit(), shouldPush()
|
|
9172
9817
|
// Add client-unsafe methods (use Node.js APIs)
|
|
9173
9818
|
getWorkspaceRoot(_sourceRoot) {
|
|
9174
|
-
return
|
|
9819
|
+
return path27.resolve(process.env.CANOPYCMS_WORKSPACE_ROOT ?? DEFAULT_PROD_WORKSPACE3);
|
|
9175
9820
|
}
|
|
9176
9821
|
getContentRoot(contentRoot, sourceRoot) {
|
|
9177
|
-
return
|
|
9822
|
+
return path27.resolve(sourceRoot ?? process.cwd(), contentRoot);
|
|
9178
9823
|
}
|
|
9179
9824
|
getContentBranchesRoot(sourceRoot) {
|
|
9180
|
-
return
|
|
9825
|
+
return path27.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
|
|
9181
9826
|
}
|
|
9182
9827
|
getContentBranchRoot(branchName, sourceRoot) {
|
|
9183
|
-
return
|
|
9828
|
+
return path27.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
|
|
9184
9829
|
}
|
|
9185
9830
|
getGitExcludePattern() {
|
|
9186
9831
|
return ".canopy-meta/";
|
|
9187
9832
|
}
|
|
9188
9833
|
getPermissionsFilePath(root) {
|
|
9189
|
-
return
|
|
9834
|
+
return path27.join(root, this.getPermissionsFileName());
|
|
9190
9835
|
}
|
|
9191
9836
|
getGroupsFilePath(root) {
|
|
9192
|
-
return
|
|
9837
|
+
return path27.join(root, this.getGroupsFileName());
|
|
9193
9838
|
}
|
|
9194
9839
|
getRemoteUrlConfig() {
|
|
9195
9840
|
return {
|
|
9196
9841
|
shouldAutoInitLocal: false,
|
|
9197
9842
|
defaultRemotePath: "",
|
|
9198
9843
|
envVarName: "CANOPYCMS_REMOTE_URL",
|
|
9199
|
-
autoDetectRemotePath:
|
|
9844
|
+
autoDetectRemotePath: path27.join(this.getWorkspaceRoot(), "remote.git")
|
|
9200
9845
|
};
|
|
9201
9846
|
}
|
|
9202
9847
|
requiresExistingRepo() {
|
|
@@ -9208,7 +9853,7 @@ var init_client_unsafe_strategy2 = __esm({
|
|
|
9208
9853
|
return `canopycms-settings-${resolveDeploymentName3(config, "prod")}`;
|
|
9209
9854
|
}
|
|
9210
9855
|
getSettingsRoot(sourceRoot) {
|
|
9211
|
-
return
|
|
9856
|
+
return path27.join(this.getWorkspaceRoot(sourceRoot), "settings");
|
|
9212
9857
|
}
|
|
9213
9858
|
usesSeparateSettingsBranch() {
|
|
9214
9859
|
return true;
|
|
@@ -9225,25 +9870,25 @@ var init_client_unsafe_strategy2 = __esm({
|
|
|
9225
9870
|
DevStrategy3 = class extends DevClientSafeStrategy3 {
|
|
9226
9871
|
// Inherits client-safe methods from DevClientSafeStrategy
|
|
9227
9872
|
getWorkspaceRoot(sourceRoot) {
|
|
9228
|
-
return
|
|
9873
|
+
return path27.resolve(sourceRoot ?? process.cwd(), ".canopy-dev");
|
|
9229
9874
|
}
|
|
9230
9875
|
getContentRoot(contentRoot, sourceRoot) {
|
|
9231
|
-
return
|
|
9876
|
+
return path27.resolve(sourceRoot ?? process.cwd(), contentRoot);
|
|
9232
9877
|
}
|
|
9233
9878
|
getContentBranchesRoot(sourceRoot) {
|
|
9234
|
-
return
|
|
9879
|
+
return path27.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
|
|
9235
9880
|
}
|
|
9236
9881
|
getContentBranchRoot(branchName, sourceRoot) {
|
|
9237
|
-
return
|
|
9882
|
+
return path27.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
|
|
9238
9883
|
}
|
|
9239
9884
|
getGitExcludePattern() {
|
|
9240
9885
|
return ".canopy-meta/";
|
|
9241
9886
|
}
|
|
9242
9887
|
getPermissionsFilePath(root) {
|
|
9243
|
-
return
|
|
9888
|
+
return path27.join(root, this.getPermissionsFileName());
|
|
9244
9889
|
}
|
|
9245
9890
|
getGroupsFilePath(root) {
|
|
9246
|
-
return
|
|
9891
|
+
return path27.join(root, this.getGroupsFileName());
|
|
9247
9892
|
}
|
|
9248
9893
|
getRemoteUrlConfig() {
|
|
9249
9894
|
return {
|
|
@@ -9261,7 +9906,7 @@ var init_client_unsafe_strategy2 = __esm({
|
|
|
9261
9906
|
return `canopycms-settings-${resolveDeploymentName3(config, "local")}`;
|
|
9262
9907
|
}
|
|
9263
9908
|
getSettingsRoot(sourceRoot) {
|
|
9264
|
-
return
|
|
9909
|
+
return path27.join(this.getWorkspaceRoot(sourceRoot), "settings");
|
|
9265
9910
|
}
|
|
9266
9911
|
usesSeparateSettingsBranch() {
|
|
9267
9912
|
return true;
|
|
@@ -9293,8 +9938,8 @@ __export(sync_exports, {
|
|
|
9293
9938
|
SyncError: () => SyncError,
|
|
9294
9939
|
sync: () => sync
|
|
9295
9940
|
});
|
|
9296
|
-
import
|
|
9297
|
-
import
|
|
9941
|
+
import fs25 from "node:fs/promises";
|
|
9942
|
+
import path28 from "node:path";
|
|
9298
9943
|
import { simpleGit as simpleGit7 } from "simple-git";
|
|
9299
9944
|
import * as p2 from "@clack/prompts";
|
|
9300
9945
|
async function detectCurrentBranch(projectDir) {
|
|
@@ -9307,7 +9952,7 @@ async function detectCurrentBranch(projectDir) {
|
|
|
9307
9952
|
async function selectBranch(options, branchesDir) {
|
|
9308
9953
|
let branches = [];
|
|
9309
9954
|
if (await filePathExists(branchesDir)) {
|
|
9310
|
-
const entries = await
|
|
9955
|
+
const entries = await fs25.readdir(branchesDir, { withFileTypes: true });
|
|
9311
9956
|
branches = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name);
|
|
9312
9957
|
}
|
|
9313
9958
|
let branchName = options.branch;
|
|
@@ -9335,11 +9980,11 @@ async function selectBranch(options, branchesDir) {
|
|
|
9335
9980
|
branchName = result;
|
|
9336
9981
|
}
|
|
9337
9982
|
}
|
|
9338
|
-
const branchPath =
|
|
9983
|
+
const branchPath = path28.join(branchesDir, branchName);
|
|
9339
9984
|
assertWithinDir(branchPath, branchesDir, "--branch");
|
|
9340
9985
|
if (!branches.includes(branchName)) {
|
|
9341
9986
|
if (options.autoCreate) {
|
|
9342
|
-
await
|
|
9987
|
+
await fs25.mkdir(branchPath, { recursive: true });
|
|
9343
9988
|
const wsGit = simpleGit7({ baseDir: branchPath });
|
|
9344
9989
|
await wsGit.init();
|
|
9345
9990
|
await wsGit.checkoutLocalBranch(branchName);
|
|
@@ -9356,8 +10001,8 @@ async function selectBranch(options, branchesDir) {
|
|
|
9356
10001
|
async function syncPush(options) {
|
|
9357
10002
|
const { projectDir } = options;
|
|
9358
10003
|
const contentRoot = options.contentRoot || "content";
|
|
9359
|
-
const branchesDir =
|
|
9360
|
-
const srcContentDir =
|
|
10004
|
+
const branchesDir = path28.join(projectDir, ".canopy-dev", "content-branches");
|
|
10005
|
+
const srcContentDir = path28.join(projectDir, contentRoot);
|
|
9361
10006
|
assertWithinDir(srcContentDir, projectDir, "--content-root");
|
|
9362
10007
|
if (!await filePathExists(srcContentDir)) {
|
|
9363
10008
|
throw new SyncError(`Content directory not found: ${contentRoot}/ (expected at ${srcContentDir})`);
|
|
@@ -9365,7 +10010,7 @@ async function syncPush(options) {
|
|
|
9365
10010
|
const branchName = await selectBranch({ ...options, projectDir, autoCreate: true }, branchesDir);
|
|
9366
10011
|
if (!branchName)
|
|
9367
10012
|
return { fileCount: 0 };
|
|
9368
|
-
const branchPath =
|
|
10013
|
+
const branchPath = path28.join(branchesDir, branchName);
|
|
9369
10014
|
assertWithinDir(branchPath, branchesDir, "--branch");
|
|
9370
10015
|
const wsGit = simpleGit7({ baseDir: branchPath });
|
|
9371
10016
|
const status = await wsGit.status();
|
|
@@ -9423,19 +10068,19 @@ async function syncPush(options) {
|
|
|
9423
10068
|
async function syncPull(options) {
|
|
9424
10069
|
const { projectDir } = options;
|
|
9425
10070
|
const contentRoot = options.contentRoot || "content";
|
|
9426
|
-
const branchesDir =
|
|
10071
|
+
const branchesDir = path28.join(projectDir, ".canopy-dev", "content-branches");
|
|
9427
10072
|
const branchName = await selectBranch({ ...options, projectDir }, branchesDir);
|
|
9428
10073
|
if (!branchName)
|
|
9429
10074
|
return { fileCount: 0 };
|
|
9430
|
-
const branchPath =
|
|
10075
|
+
const branchPath = path28.join(branchesDir, branchName);
|
|
9431
10076
|
assertWithinDir(branchPath, branchesDir, "--branch");
|
|
9432
|
-
const branchContentDir =
|
|
10077
|
+
const branchContentDir = path28.join(branchPath, contentRoot);
|
|
9433
10078
|
assertWithinDir(branchContentDir, branchPath, "--content-root");
|
|
9434
10079
|
if (!await filePathExists(branchContentDir)) {
|
|
9435
10080
|
throw new SyncError(`Content directory not found in branch workspace: ${branchName}/${contentRoot}`);
|
|
9436
10081
|
}
|
|
9437
10082
|
p2.log.step(`Pulling content from branch: ${branchName}`);
|
|
9438
|
-
const destContentDir =
|
|
10083
|
+
const destContentDir = path28.join(projectDir, contentRoot);
|
|
9439
10084
|
assertWithinDir(destContentDir, projectDir, "--content-root");
|
|
9440
10085
|
const sourceGit = simpleGit7({ baseDir: projectDir });
|
|
9441
10086
|
const status = await sourceGit.status();
|
|
@@ -9487,7 +10132,7 @@ async function syncPull(options) {
|
|
|
9487
10132
|
await copyDir(branchContentDir, tmpDestDir);
|
|
9488
10133
|
await safeReplaceDir(destContentDir, tmpDestDir);
|
|
9489
10134
|
} catch (err) {
|
|
9490
|
-
await
|
|
10135
|
+
await fs25.rm(tmpDestDir, { recursive: true, force: true }).catch(() => {
|
|
9491
10136
|
});
|
|
9492
10137
|
throw err;
|
|
9493
10138
|
}
|
|
@@ -9511,8 +10156,8 @@ async function syncPull(options) {
|
|
|
9511
10156
|
async function syncBoth(options) {
|
|
9512
10157
|
const { projectDir } = options;
|
|
9513
10158
|
const contentRoot = options.contentRoot || "content";
|
|
9514
|
-
const branchesDir =
|
|
9515
|
-
const srcContentDir =
|
|
10159
|
+
const branchesDir = path28.join(projectDir, ".canopy-dev", "content-branches");
|
|
10160
|
+
const srcContentDir = path28.join(projectDir, contentRoot);
|
|
9516
10161
|
assertWithinDir(srcContentDir, projectDir, "--content-root");
|
|
9517
10162
|
if (!await filePathExists(srcContentDir)) {
|
|
9518
10163
|
throw new SyncError(`Content directory not found: ${contentRoot}/ (expected at ${srcContentDir})`);
|
|
@@ -9520,7 +10165,7 @@ async function syncBoth(options) {
|
|
|
9520
10165
|
const branchName = await selectBranch({ ...options, projectDir, autoCreate: true }, branchesDir);
|
|
9521
10166
|
if (!branchName)
|
|
9522
10167
|
return { pushed: 0, pulled: 0 };
|
|
9523
|
-
const branchPath =
|
|
10168
|
+
const branchPath = path28.join(branchesDir, branchName);
|
|
9524
10169
|
assertWithinDir(branchPath, branchesDir, "--branch");
|
|
9525
10170
|
const wsGit = simpleGit7({ baseDir: branchPath });
|
|
9526
10171
|
const status = await wsGit.status();
|
|
@@ -9555,14 +10200,14 @@ async function syncBoth(options) {
|
|
|
9555
10200
|
try {
|
|
9556
10201
|
const incomingBranch = `sync-incoming-${Date.now()}`;
|
|
9557
10202
|
await wsGit.raw(["checkout", "-b", incomingBranch, baseRef]);
|
|
9558
|
-
const wsContentDir =
|
|
10203
|
+
const wsContentDir = path28.join(branchPath, contentRoot);
|
|
9559
10204
|
assertWithinDir(wsContentDir, branchPath, "--content-root");
|
|
9560
10205
|
const tmpDir = `${wsContentDir}.sync-tmp-${Date.now()}`;
|
|
9561
10206
|
try {
|
|
9562
10207
|
await copyDir(srcContentDir, tmpDir);
|
|
9563
10208
|
await safeReplaceDir(wsContentDir, tmpDir);
|
|
9564
10209
|
} catch (err) {
|
|
9565
|
-
await
|
|
10210
|
+
await fs25.rm(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
9566
10211
|
});
|
|
9567
10212
|
await wsGit.checkout(currentBranch);
|
|
9568
10213
|
await wsGit.raw(["branch", "-D", incomingBranch]).catch(() => {
|
|
@@ -9619,11 +10264,11 @@ async function syncBoth(options) {
|
|
|
9619
10264
|
}
|
|
9620
10265
|
async function syncAbort(options) {
|
|
9621
10266
|
const { projectDir } = options;
|
|
9622
|
-
const branchesDir =
|
|
10267
|
+
const branchesDir = path28.join(projectDir, ".canopy-dev", "content-branches");
|
|
9623
10268
|
const branchName = await selectBranch({ ...options, projectDir }, branchesDir);
|
|
9624
10269
|
if (!branchName)
|
|
9625
10270
|
return;
|
|
9626
|
-
const branchPath =
|
|
10271
|
+
const branchPath = path28.join(branchesDir, branchName);
|
|
9627
10272
|
assertWithinDir(branchPath, branchesDir, "--branch");
|
|
9628
10273
|
const wsGit = simpleGit7({ baseDir: branchPath });
|
|
9629
10274
|
const status = await wsGit.status();
|
|
@@ -9751,8 +10396,8 @@ var init_async_mutex = __esm({
|
|
|
9751
10396
|
});
|
|
9752
10397
|
|
|
9753
10398
|
// dist/utils/occ-json-write.js
|
|
9754
|
-
import
|
|
9755
|
-
import
|
|
10399
|
+
import fs26 from "node:fs/promises";
|
|
10400
|
+
import path29 from "node:path";
|
|
9756
10401
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
9757
10402
|
import lockfile4 from "proper-lockfile";
|
|
9758
10403
|
async function writeOccJsonFile2(filePath, payload, options) {
|
|
@@ -9761,29 +10406,29 @@ async function writeOccJsonFile2(filePath, payload, options) {
|
|
|
9761
10406
|
const writeId = randomUUID4();
|
|
9762
10407
|
const data = { ...payload, version: newVersion, writeId };
|
|
9763
10408
|
const content = JSON.stringify(data, null, 2) + (trailingNewline ? "\n" : "");
|
|
9764
|
-
const dir =
|
|
9765
|
-
await
|
|
10409
|
+
const dir = path29.dirname(filePath);
|
|
10410
|
+
await fs26.mkdir(dir, { recursive: true });
|
|
9766
10411
|
const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
9767
|
-
await
|
|
10412
|
+
await fs26.writeFile(tempPath, content, "utf-8");
|
|
9768
10413
|
if (expectedVersion === null) {
|
|
9769
10414
|
try {
|
|
9770
|
-
await
|
|
10415
|
+
await fs26.link(tempPath, filePath);
|
|
9771
10416
|
} catch (err) {
|
|
9772
|
-
await
|
|
10417
|
+
await fs26.unlink(tempPath).catch(() => {
|
|
9773
10418
|
});
|
|
9774
10419
|
if (isFileExistsError(err)) {
|
|
9775
10420
|
throw new OccWriteConflictError2();
|
|
9776
10421
|
}
|
|
9777
10422
|
throw err;
|
|
9778
10423
|
}
|
|
9779
|
-
await
|
|
10424
|
+
await fs26.unlink(tempPath).catch(() => {
|
|
9780
10425
|
});
|
|
9781
10426
|
return { version: newVersion, writeId };
|
|
9782
10427
|
}
|
|
9783
10428
|
try {
|
|
9784
10429
|
let currentVersion = null;
|
|
9785
10430
|
try {
|
|
9786
|
-
const current = JSON.parse(await
|
|
10431
|
+
const current = JSON.parse(await fs26.readFile(filePath, "utf-8"));
|
|
9787
10432
|
currentVersion = current.version ?? 0;
|
|
9788
10433
|
} catch {
|
|
9789
10434
|
currentVersion = null;
|
|
@@ -9791,16 +10436,16 @@ async function writeOccJsonFile2(filePath, payload, options) {
|
|
|
9791
10436
|
if (currentVersion !== expectedVersion) {
|
|
9792
10437
|
throw new OccWriteConflictError2();
|
|
9793
10438
|
}
|
|
9794
|
-
await
|
|
10439
|
+
await fs26.rename(tempPath, filePath);
|
|
9795
10440
|
if (settleMs > 0) {
|
|
9796
10441
|
await new Promise((resolve2) => setTimeout(resolve2, settleMs));
|
|
9797
10442
|
}
|
|
9798
|
-
const afterWrite = JSON.parse(await
|
|
10443
|
+
const afterWrite = JSON.parse(await fs26.readFile(filePath, "utf-8"));
|
|
9799
10444
|
if (afterWrite.writeId !== writeId) {
|
|
9800
10445
|
throw new OccWriteConflictError2();
|
|
9801
10446
|
}
|
|
9802
10447
|
} catch (err) {
|
|
9803
|
-
await
|
|
10448
|
+
await fs26.unlink(tempPath).catch(() => {
|
|
9804
10449
|
});
|
|
9805
10450
|
throw err;
|
|
9806
10451
|
}
|
|
@@ -9826,8 +10471,8 @@ async function withOccRetry2(operation, options) {
|
|
|
9826
10471
|
throw new Error("Unreachable");
|
|
9827
10472
|
}
|
|
9828
10473
|
async function withOccFileLock2(filePath, fn) {
|
|
9829
|
-
const dir =
|
|
9830
|
-
await
|
|
10474
|
+
const dir = path29.dirname(filePath);
|
|
10475
|
+
await fs26.mkdir(dir, { recursive: true });
|
|
9831
10476
|
const MAX_ATTEMPTS = 14;
|
|
9832
10477
|
let release = null;
|
|
9833
10478
|
for (let attempt = 1; release === null; attempt++) {
|
|
@@ -9886,8 +10531,8 @@ var init_occ_json_write = __esm({
|
|
|
9886
10531
|
});
|
|
9887
10532
|
|
|
9888
10533
|
// dist/branch-registry.js
|
|
9889
|
-
import
|
|
9890
|
-
import
|
|
10534
|
+
import fs27 from "node:fs/promises";
|
|
10535
|
+
import path30 from "node:path";
|
|
9891
10536
|
var log12, REGISTRY_FILE2, REGISTRY_STALE_FILE2, REGISTRY_TEMP_FILE2, REGISTRY_VERSION2, RESOURCE4, GET_MISS_REFRESH_MIN_INTERVAL_MS2, BranchRegistry2;
|
|
9892
10537
|
var init_branch_registry = __esm({
|
|
9893
10538
|
"dist/branch-registry.js"() {
|
|
@@ -9908,10 +10553,10 @@ var init_branch_registry = __esm({
|
|
|
9908
10553
|
constructor(root) {
|
|
9909
10554
|
this.regenInFlight = null;
|
|
9910
10555
|
this.lastForcedRefreshMs = 0;
|
|
9911
|
-
this.root =
|
|
9912
|
-
this.registryPath =
|
|
9913
|
-
this.stalePath =
|
|
9914
|
-
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);
|
|
9915
10560
|
}
|
|
9916
10561
|
/**
|
|
9917
10562
|
* Returns all branches. Uses the cached snapshot if its embedded generation
|
|
@@ -9920,7 +10565,7 @@ var init_branch_registry = __esm({
|
|
|
9920
10565
|
async list() {
|
|
9921
10566
|
let parsed;
|
|
9922
10567
|
try {
|
|
9923
|
-
const raw = await
|
|
10568
|
+
const raw = await fs27.readFile(this.registryPath, "utf8");
|
|
9924
10569
|
parsed = JSON.parse(raw);
|
|
9925
10570
|
} catch (err) {
|
|
9926
10571
|
if (isNotFoundError(err)) {
|
|
@@ -10009,7 +10654,7 @@ var init_branch_registry = __esm({
|
|
|
10009
10654
|
async performRegenerate() {
|
|
10010
10655
|
const read = await readResourceGeneration2(this.root, RESOURCE4);
|
|
10011
10656
|
const branches = await this.scanBranchDirectories();
|
|
10012
|
-
await
|
|
10657
|
+
await fs27.unlink(this.stalePath).catch(() => {
|
|
10013
10658
|
});
|
|
10014
10659
|
if (!read.ok) {
|
|
10015
10660
|
return branches;
|
|
@@ -10020,12 +10665,12 @@ var init_branch_registry = __esm({
|
|
|
10020
10665
|
generation: read.token
|
|
10021
10666
|
};
|
|
10022
10667
|
const uniqueTempPath = `${this.tempPath}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
10023
|
-
await
|
|
10024
|
-
await
|
|
10668
|
+
await fs27.mkdir(this.root, { recursive: true });
|
|
10669
|
+
await fs27.writeFile(uniqueTempPath, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
|
|
10025
10670
|
try {
|
|
10026
|
-
await
|
|
10671
|
+
await fs27.rename(uniqueTempPath, this.registryPath);
|
|
10027
10672
|
} catch (err) {
|
|
10028
|
-
await
|
|
10673
|
+
await fs27.unlink(uniqueTempPath).catch(() => {
|
|
10029
10674
|
});
|
|
10030
10675
|
throw err;
|
|
10031
10676
|
}
|
|
@@ -10039,12 +10684,12 @@ var init_branch_registry = __esm({
|
|
|
10039
10684
|
async scanBranchDirectories() {
|
|
10040
10685
|
const branches = [];
|
|
10041
10686
|
try {
|
|
10042
|
-
const entries = await
|
|
10687
|
+
const entries = await fs27.readdir(this.root, { withFileTypes: true });
|
|
10043
10688
|
for (const entry of entries) {
|
|
10044
10689
|
if (!entry.isDirectory() || entry.name.startsWith(".")) {
|
|
10045
10690
|
continue;
|
|
10046
10691
|
}
|
|
10047
|
-
const branchRoot =
|
|
10692
|
+
const branchRoot = path30.join(this.root, entry.name);
|
|
10048
10693
|
let meta;
|
|
10049
10694
|
try {
|
|
10050
10695
|
meta = await BranchMetadataFileManager2.loadOnly(branchRoot);
|
|
@@ -10073,8 +10718,8 @@ var init_branch_registry = __esm({
|
|
|
10073
10718
|
});
|
|
10074
10719
|
|
|
10075
10720
|
// dist/branch-metadata.js
|
|
10076
|
-
import
|
|
10077
|
-
import
|
|
10721
|
+
import fs28 from "node:fs/promises";
|
|
10722
|
+
import path31 from "node:path";
|
|
10078
10723
|
var BRANCH_META_DIR2, BRANCH_META_FILE2, CURRENT_SCHEMA_VERSION2, BranchMetadataConflictError2, BranchMetadataCorruptError2, BranchMetadataFileManager2;
|
|
10079
10724
|
var init_branch_metadata = __esm({
|
|
10080
10725
|
"dist/branch-metadata.js"() {
|
|
@@ -10103,8 +10748,8 @@ var init_branch_metadata = __esm({
|
|
|
10103
10748
|
};
|
|
10104
10749
|
BranchMetadataFileManager2 = class _BranchMetadataFileManager2 {
|
|
10105
10750
|
constructor(branchRoot, baseRoot, options) {
|
|
10106
|
-
this.branchRoot =
|
|
10107
|
-
this.filePath =
|
|
10751
|
+
this.branchRoot = path31.resolve(branchRoot);
|
|
10752
|
+
this.filePath = path31.join(this.branchRoot, BRANCH_META_DIR2, BRANCH_META_FILE2);
|
|
10108
10753
|
this.baseRoot = baseRoot;
|
|
10109
10754
|
this.settleMs = options?.settleMs;
|
|
10110
10755
|
}
|
|
@@ -10113,10 +10758,10 @@ var init_branch_metadata = __esm({
|
|
|
10113
10758
|
* Use this for read-only access (e.g., in registry scanning or loadBranchContext).
|
|
10114
10759
|
*/
|
|
10115
10760
|
static async loadOnly(branchRoot) {
|
|
10116
|
-
const resolvedRoot =
|
|
10117
|
-
const filePath =
|
|
10761
|
+
const resolvedRoot = path31.resolve(branchRoot);
|
|
10762
|
+
const filePath = path31.join(resolvedRoot, BRANCH_META_DIR2, BRANCH_META_FILE2);
|
|
10118
10763
|
try {
|
|
10119
|
-
const raw = await
|
|
10764
|
+
const raw = await fs28.readFile(filePath, "utf8");
|
|
10120
10765
|
return JSON.parse(raw);
|
|
10121
10766
|
} catch (err) {
|
|
10122
10767
|
if (isNotFoundError(err)) {
|
|
@@ -10137,7 +10782,7 @@ var init_branch_metadata = __esm({
|
|
|
10137
10782
|
}
|
|
10138
10783
|
async load() {
|
|
10139
10784
|
try {
|
|
10140
|
-
const raw = await
|
|
10785
|
+
const raw = await fs28.readFile(this.filePath, "utf8");
|
|
10141
10786
|
const parsed = JSON.parse(raw);
|
|
10142
10787
|
const version = parsed.version ?? 0;
|
|
10143
10788
|
return { meta: parsed, version };
|
|
@@ -10199,7 +10844,7 @@ var init_branch_metadata = __esm({
|
|
|
10199
10844
|
*/
|
|
10200
10845
|
async save(incoming) {
|
|
10201
10846
|
try {
|
|
10202
|
-
await
|
|
10847
|
+
await fs28.stat(this.branchRoot);
|
|
10203
10848
|
} catch (err) {
|
|
10204
10849
|
if (isNotFoundError(err)) {
|
|
10205
10850
|
throw new BranchMetadataConflictError2("Branch no longer exists");
|
|
@@ -10274,8 +10919,8 @@ __export(migrate_exports, {
|
|
|
10274
10919
|
migrate: () => migrate,
|
|
10275
10920
|
slugifyName: () => slugifyName
|
|
10276
10921
|
});
|
|
10277
|
-
import
|
|
10278
|
-
import
|
|
10922
|
+
import fs29 from "node:fs/promises";
|
|
10923
|
+
import path33 from "node:path";
|
|
10279
10924
|
import * as p3 from "@clack/prompts";
|
|
10280
10925
|
function slugifyName(name) {
|
|
10281
10926
|
const slug = name.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -10283,7 +10928,7 @@ function slugifyName(name) {
|
|
|
10283
10928
|
}
|
|
10284
10929
|
function toValidSlug(name) {
|
|
10285
10930
|
const slug = slugifyName(name);
|
|
10286
|
-
const parsed =
|
|
10931
|
+
const parsed = parseSlug2(slug);
|
|
10287
10932
|
if (!parsed.ok) {
|
|
10288
10933
|
throw new MigrateError(`Cannot derive a valid slug from "${name}" (got "${slug}"): ${parsed.error}`);
|
|
10289
10934
|
}
|
|
@@ -10300,7 +10945,7 @@ function stripDirIdSuffix(dirName) {
|
|
|
10300
10945
|
return dirName;
|
|
10301
10946
|
}
|
|
10302
10947
|
async function planDirectory(dirPath, isRoot, ctx) {
|
|
10303
|
-
const entries = await
|
|
10948
|
+
const entries = await fs29.readdir(dirPath, { withFileTypes: true });
|
|
10304
10949
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
10305
10950
|
const ops = [];
|
|
10306
10951
|
let hasOwnFiles = false;
|
|
@@ -10309,7 +10954,7 @@ async function planDirectory(dirPath, isRoot, ctx) {
|
|
|
10309
10954
|
if (entry.name.startsWith("."))
|
|
10310
10955
|
continue;
|
|
10311
10956
|
if (entry.isDirectory()) {
|
|
10312
|
-
const subPath =
|
|
10957
|
+
const subPath = path33.join(dirPath, entry.name);
|
|
10313
10958
|
const sub = await planDirectory(subPath, false, ctx);
|
|
10314
10959
|
if (!sub.hasContent)
|
|
10315
10960
|
continue;
|
|
@@ -10317,10 +10962,10 @@ async function planDirectory(dirPath, isRoot, ctx) {
|
|
|
10317
10962
|
ops.push(...sub.ops);
|
|
10318
10963
|
if (!extractIdFromFilename2(entry.name)) {
|
|
10319
10964
|
const newName = `${toValidSlug(entry.name)}.${generateId2()}`;
|
|
10320
|
-
ops.push({ kind: "rename", from: subPath, to:
|
|
10965
|
+
ops.push({ kind: "rename", from: subPath, to: path33.join(dirPath, newName) });
|
|
10321
10966
|
}
|
|
10322
10967
|
} else if (entry.isFile()) {
|
|
10323
|
-
const ext =
|
|
10968
|
+
const ext = path33.extname(entry.name).slice(1);
|
|
10324
10969
|
const matchesFormat = ext === ctx.format || ctx.format === "yaml" && ext === "yml";
|
|
10325
10970
|
if (!matchesFormat)
|
|
10326
10971
|
continue;
|
|
@@ -10331,17 +10976,17 @@ async function planDirectory(dirPath, isRoot, ctx) {
|
|
|
10331
10976
|
const newName = `${ctx.entryType}.${toValidSlug(base)}.${generateId2()}.${ext}`;
|
|
10332
10977
|
ops.push({
|
|
10333
10978
|
kind: "rename",
|
|
10334
|
-
from:
|
|
10335
|
-
to:
|
|
10979
|
+
from: path33.join(dirPath, entry.name),
|
|
10980
|
+
to: path33.join(dirPath, newName)
|
|
10336
10981
|
});
|
|
10337
10982
|
}
|
|
10338
10983
|
}
|
|
10339
10984
|
}
|
|
10340
10985
|
const needsMeta = isRoot ? hasOwnFiles : hasContent;
|
|
10341
|
-
const metaPath =
|
|
10986
|
+
const metaPath = path33.join(dirPath, ".collection.json");
|
|
10342
10987
|
if (needsMeta && !await filePathExists(metaPath)) {
|
|
10343
10988
|
const entryTypeMeta = { name: ctx.entryType, format: ctx.format, schema: ctx.schema };
|
|
10344
|
-
const meta = isRoot ? { entries: [entryTypeMeta] } : { name: toValidSlug(stripDirIdSuffix(
|
|
10989
|
+
const meta = isRoot ? { entries: [entryTypeMeta] } : { name: toValidSlug(stripDirIdSuffix(path33.basename(dirPath))), entries: [entryTypeMeta] };
|
|
10345
10990
|
ops.push({ kind: "write", filePath: metaPath, content: JSON.stringify(meta, null, 2) + "\n" });
|
|
10346
10991
|
}
|
|
10347
10992
|
return { ops, hasContent };
|
|
@@ -10350,7 +10995,7 @@ async function migrate(options) {
|
|
|
10350
10995
|
const { projectDir } = options;
|
|
10351
10996
|
const contentRoot = options.contentRoot || "content";
|
|
10352
10997
|
p3.intro("CanopyCMS migrate");
|
|
10353
|
-
const contentDir =
|
|
10998
|
+
const contentDir = path33.join(projectDir, contentRoot);
|
|
10354
10999
|
if (!await filePathExists(contentDir)) {
|
|
10355
11000
|
throw new MigrateError(`Content directory not found: ${contentRoot}/ (expected at ${contentDir})`);
|
|
10356
11001
|
}
|
|
@@ -10427,14 +11072,14 @@ async function migrate(options) {
|
|
|
10427
11072
|
const applyOps = async () => {
|
|
10428
11073
|
for (const op of ops) {
|
|
10429
11074
|
if (op.kind === "rename") {
|
|
10430
|
-
await
|
|
11075
|
+
await fs29.rename(op.from, op.to);
|
|
10431
11076
|
} else {
|
|
10432
|
-
await
|
|
11077
|
+
await fs29.writeFile(op.filePath, op.content, "utf-8");
|
|
10433
11078
|
}
|
|
10434
11079
|
}
|
|
10435
11080
|
};
|
|
10436
11081
|
if (isBranchClone) {
|
|
10437
|
-
const lockPath =
|
|
11082
|
+
const lockPath = path33.join(projectDir, ".canopy-meta", "schema");
|
|
10438
11083
|
try {
|
|
10439
11084
|
await withLock2(lockPath, () => withOccFileLock2(lockPath, applyOps));
|
|
10440
11085
|
} catch (err) {
|
|
@@ -10482,7 +11127,7 @@ var init_migrate = __esm({
|
|
|
10482
11127
|
this.name = "MigrateError";
|
|
10483
11128
|
}
|
|
10484
11129
|
};
|
|
10485
|
-
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)}`;
|
|
10486
11131
|
}
|
|
10487
11132
|
});
|
|
10488
11133
|
|