canopycms 0.0.63 → 0.0.65
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 +9 -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 +14 -3
- 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 +22 -3
- package/dist/branch-health.js +6 -2
- 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 +18 -2
- package/dist/cli/cli.js +1172 -490
- 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 +43 -6
- 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/Dockerfile.cms.template +8 -2
- package/dist/cli/template-files/cms-stack.ts.template +33 -6
- package/dist/cli/template-files/deploy-cms.yml.template +29 -14
- 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 +12 -3
- package/dist/dev-content-watcher.js +120 -30
- 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 +10 -2
- 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 +18 -2
- package/dist/utils/git.js +61 -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 +31 -2
- package/dist/worker/cms-worker.js +321 -13
- 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 +3 -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
|
@@ -592,7 +592,7 @@ async function recoverOrphanedTasks(taskDir, maxAgeMs = 5 * 6e4, logger = nullLo
|
|
|
592
592
|
async function cleanupOldTasks(taskDir, maxAgeMs = 30 * 24 * 60 * 6e4, logger = nullLogger) {
|
|
593
593
|
const now = Date.now();
|
|
594
594
|
let cleaned = 0;
|
|
595
|
-
for (const subdir of ["completed", "failed"]) {
|
|
595
|
+
for (const subdir of ["completed", "failed", "corrupt"]) {
|
|
596
596
|
const dir = path6.join(taskDir, subdir);
|
|
597
597
|
let files;
|
|
598
598
|
try {
|
|
@@ -810,6 +810,13 @@ function configImportPath(appDir, subdirs) {
|
|
|
810
810
|
const totalDepth = appDepth + subdirs;
|
|
811
811
|
return "../".repeat(totalDepth) + "canopycms.config";
|
|
812
812
|
}
|
|
813
|
+
async function firstExistingPath(projectDir, candidates) {
|
|
814
|
+
for (const candidate of candidates) {
|
|
815
|
+
if (await filePathExists2(path7.join(projectDir, candidate)))
|
|
816
|
+
return candidate;
|
|
817
|
+
}
|
|
818
|
+
return null;
|
|
819
|
+
}
|
|
813
820
|
async function init(options) {
|
|
814
821
|
const { projectDir, mode, appDir, ai, force, nonInteractive } = options;
|
|
815
822
|
const writeOpts = { force, nonInteractive };
|
|
@@ -864,15 +871,35 @@ async function init(options) {
|
|
|
864
871
|
await writeFile(path7.join(projectDir, appDir, "ai/config.ts"), await aiConfig2(), writeOpts);
|
|
865
872
|
await writeFile(path7.join(projectDir, appDir, `ai/[...path]/${serverRouteExt}`), await aiRoute2({ configImport: configImportPath(appDir, 2) }), writeOpts);
|
|
866
873
|
}
|
|
867
|
-
|
|
868
|
-
|
|
874
|
+
const existingJsConfig = await firstExistingPath(projectDir, [
|
|
875
|
+
"next.config.js",
|
|
876
|
+
"next.config.mjs"
|
|
877
|
+
]);
|
|
878
|
+
if (existingJsConfig) {
|
|
879
|
+
p.note([
|
|
880
|
+
`Found ${existingJsConfig}, which Next loads in preference to next.config.ts.`,
|
|
881
|
+
"Left it untouched rather than writing a second config Next would ignore.",
|
|
882
|
+
"",
|
|
883
|
+
"Wrap your existing config by hand:",
|
|
884
|
+
"",
|
|
885
|
+
" import { withCanopy } from 'canopycms-next/config'",
|
|
886
|
+
" export default withCanopy(yourConfig)"
|
|
887
|
+
].join("\n"), "Manual step");
|
|
888
|
+
} else {
|
|
889
|
+
await writeFile(path7.join(projectDir, "next.config.ts"), await nextConfig2({ staticBuild }), writeOpts);
|
|
890
|
+
}
|
|
891
|
+
await writeFile(path7.join(projectDir, path7.dirname(appDir), "middleware.ts"), await middleware2({ authProvider }), writeOpts);
|
|
869
892
|
const gitignorePath = path7.join(projectDir, ".gitignore");
|
|
893
|
+
const CANOPY_GITIGNORE_BLOCK = "# CanopyCMS\n.canopy-dev/\n";
|
|
870
894
|
if (await filePathExists2(gitignorePath)) {
|
|
871
895
|
const content = await fs6.readFile(gitignorePath, "utf-8");
|
|
872
896
|
if (!content.includes(".canopy-dev")) {
|
|
873
|
-
await fs6.appendFile(gitignorePath,
|
|
897
|
+
await fs6.appendFile(gitignorePath, `
|
|
898
|
+
${CANOPY_GITIGNORE_BLOCK}`);
|
|
874
899
|
p.log.success("updated: .gitignore");
|
|
875
900
|
}
|
|
901
|
+
} else {
|
|
902
|
+
await writeFile(gitignorePath, CANOPY_GITIGNORE_BLOCK, writeOpts);
|
|
876
903
|
}
|
|
877
904
|
const packages = authProvider === "clerk" ? "canopycms canopycms-next canopycms-auth-clerk canopycms-auth-dev" : "canopycms canopycms-next canopycms-auth-dev";
|
|
878
905
|
p.note([
|
|
@@ -1047,7 +1074,7 @@ CanopyCMS worker run-once (mode: ${mode}, auth: ${authMode})
|
|
|
1047
1074
|
}
|
|
1048
1075
|
console.log("\nDone");
|
|
1049
1076
|
}
|
|
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;
|
|
1077
|
+
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
1078
|
var init_init = __esm({
|
|
1052
1079
|
"dist/cli/init.js"() {
|
|
1053
1080
|
"use strict";
|
|
@@ -1134,7 +1161,12 @@ var init_init = __esm({
|
|
|
1134
1161
|
collections: z.array(z.string().min(1)).min(1).optional(),
|
|
1135
1162
|
entryTypes: z.array(z.string().min(1)).min(1).optional(),
|
|
1136
1163
|
displayField: z.string().min(1).optional(),
|
|
1137
|
-
options: z.array(referenceOptionSchema).optional()
|
|
1164
|
+
options: z.array(referenceOptionSchema).optional(),
|
|
1165
|
+
// Must be listed here, not just on ReferenceFieldConfig: zod strips unknown keys by
|
|
1166
|
+
// default, so a consumer that adopts this schema's parse output would silently delete a
|
|
1167
|
+
// runtime-consumed flag and the feature would no-op with no error. (`resolvedSchema` is
|
|
1168
|
+
// absent on purpose — it is type-inference-only and stripping it changes no behavior.)
|
|
1169
|
+
includeBody: z.boolean().optional()
|
|
1138
1170
|
});
|
|
1139
1171
|
fieldHolder = [z.never()];
|
|
1140
1172
|
blockSchema = z.object({
|
|
@@ -1255,6 +1287,9 @@ var init_init = __esm({
|
|
|
1255
1287
|
deployedAsSchema = z4.enum(["static", "server"]).default("server");
|
|
1256
1288
|
contentRootSchema = relativePathSchema.default("content");
|
|
1257
1289
|
sourceRootSchema = z4.string().min(1).optional();
|
|
1290
|
+
basePathSchema = z4.string().transform((value) => value.trim()).refine((value) => value.length > 0, {
|
|
1291
|
+
message: "basePath must not be empty or only whitespace"
|
|
1292
|
+
}).optional();
|
|
1258
1293
|
deploymentNameSchema = z4.string().default("prod");
|
|
1259
1294
|
devContentSyncSchema = z4.enum(["off", "warn"]).default("warn");
|
|
1260
1295
|
devConfigSchema = z4.object({
|
|
@@ -1317,6 +1352,7 @@ var init_init = __esm({
|
|
|
1317
1352
|
deploymentName: deploymentNameSchema.optional(),
|
|
1318
1353
|
contentRoot: contentRootSchema.default("content"),
|
|
1319
1354
|
sourceRoot: sourceRootSchema.optional(),
|
|
1355
|
+
basePath: basePathSchema,
|
|
1320
1356
|
editor: editorConfigSchema.optional(),
|
|
1321
1357
|
authPlugin: z4.custom().optional(),
|
|
1322
1358
|
entryLinkUrl: z4.custom().optional(),
|
|
@@ -1480,6 +1516,7 @@ var init_init = __esm({
|
|
|
1480
1516
|
};
|
|
1481
1517
|
MAX_WORKSPACE_DEPTH = 8;
|
|
1482
1518
|
CDK_DEPENDENCIES = [
|
|
1519
|
+
"canopycms",
|
|
1483
1520
|
"canopycms-cdk",
|
|
1484
1521
|
"aws-cdk-lib",
|
|
1485
1522
|
"constructs",
|
|
@@ -1844,63 +1881,73 @@ import { isAbsolute as isAbsolute2 } from "pathe";
|
|
|
1844
1881
|
import { z as z42 } from "zod";
|
|
1845
1882
|
import { z as z52 } from "zod";
|
|
1846
1883
|
import { z as z6 } from "zod";
|
|
1847
|
-
import
|
|
1848
|
-
import
|
|
1884
|
+
import path9 from "node:path";
|
|
1885
|
+
import path20 from "node:path";
|
|
1849
1886
|
import { createJiti as createJiti2 } from "jiti";
|
|
1850
|
-
import
|
|
1851
|
-
import
|
|
1852
|
-
import
|
|
1887
|
+
import fs17 from "node:fs/promises";
|
|
1888
|
+
import path19 from "node:path";
|
|
1889
|
+
import fs10 from "node:fs/promises";
|
|
1890
|
+
import path11 from "node:path";
|
|
1891
|
+
import matter2 from "gray-matter";
|
|
1892
|
+
import { parse as yamlParse } from "yaml";
|
|
1893
|
+
import fs7 from "node:fs/promises";
|
|
1853
1894
|
import path10 from "node:path";
|
|
1854
1895
|
import matter from "gray-matter";
|
|
1855
|
-
import {
|
|
1856
|
-
import fs7 from "node:fs/promises";
|
|
1857
|
-
import path9 from "node:path";
|
|
1896
|
+
import { isCollection, isMap, isNode, isScalar, isSeq, parseDocument, stringify as yamlStringify } from "yaml";
|
|
1858
1897
|
import path32 from "node:path";
|
|
1859
1898
|
import fs23 from "node:fs/promises";
|
|
1860
1899
|
import path22 from "node:path";
|
|
1861
1900
|
import lockfile from "proper-lockfile";
|
|
1901
|
+
import fs42 from "node:fs/promises";
|
|
1902
|
+
import path52 from "node:path";
|
|
1862
1903
|
import fs32 from "node:fs/promises";
|
|
1863
1904
|
import path42 from "node:path";
|
|
1864
1905
|
import { generate } from "short-uuid";
|
|
1865
|
-
import path52 from "node:path";
|
|
1866
|
-
import fs42 from "node:fs/promises";
|
|
1867
1906
|
import path62 from "node:path";
|
|
1868
|
-
import
|
|
1869
|
-
import fs62 from "node:fs/promises";
|
|
1907
|
+
import fs52 from "node:fs/promises";
|
|
1870
1908
|
import path72 from "node:path";
|
|
1871
|
-
import {
|
|
1909
|
+
import { randomUUID } from "node:crypto";
|
|
1910
|
+
import fs72 from "node:fs/promises";
|
|
1911
|
+
import path82 from "node:path";
|
|
1912
|
+
import { promises as fs62 } from "fs";
|
|
1872
1913
|
import { join as join3 } from "pathe";
|
|
1873
1914
|
import { z as z7 } from "zod";
|
|
1874
1915
|
import chokidar from "chokidar";
|
|
1875
|
-
import fs72 from "node:fs/promises";
|
|
1876
|
-
import { sep, resolve, relative } from "node:path";
|
|
1877
1916
|
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";
|
|
1917
|
+
import { sep, resolve, relative } from "node:path";
|
|
1918
|
+
import fs9 from "node:fs/promises";
|
|
1919
|
+
import path102 from "node:path";
|
|
1886
1920
|
import path12 from "node:path";
|
|
1921
|
+
import fs11 from "node:fs/promises";
|
|
1922
|
+
import { minimatch } from "minimatch";
|
|
1923
|
+
import path17 from "node:path";
|
|
1924
|
+
import fs14 from "node:fs/promises";
|
|
1925
|
+
import path15 from "node:path";
|
|
1887
1926
|
import fs12 from "node:fs/promises";
|
|
1888
1927
|
import path13 from "node:path";
|
|
1928
|
+
import fs13 from "node:fs/promises";
|
|
1929
|
+
import path14 from "node:path";
|
|
1889
1930
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
1890
1931
|
import lockfile2 from "proper-lockfile";
|
|
1891
|
-
import
|
|
1892
|
-
import
|
|
1932
|
+
import fs15 from "node:fs/promises";
|
|
1933
|
+
import path16 from "node:path";
|
|
1893
1934
|
import { simpleGit as simpleGit2 } from "simple-git";
|
|
1894
1935
|
import { simpleGit as simpleGit3 } from "simple-git";
|
|
1895
|
-
import
|
|
1896
|
-
import
|
|
1897
|
-
import
|
|
1936
|
+
import fs16 from "node:fs/promises";
|
|
1937
|
+
import path18 from "node:path";
|
|
1938
|
+
import matter3 from "gray-matter";
|
|
1898
1939
|
import { parse as yamlParse2 } from "yaml";
|
|
1899
|
-
function
|
|
1900
|
-
|
|
1940
|
+
function canopyLogWarn2(...args) {
|
|
1941
|
+
active2.warn(...args);
|
|
1942
|
+
}
|
|
1943
|
+
function canopyLogError(...args) {
|
|
1944
|
+
active2.error(...args);
|
|
1901
1945
|
}
|
|
1902
|
-
function
|
|
1903
|
-
|
|
1946
|
+
function normalizeFilesystemPath(path212) {
|
|
1947
|
+
return path212.split(/[\\/]+/).filter(Boolean).join("/");
|
|
1948
|
+
}
|
|
1949
|
+
function hasTraversalSequence(path212) {
|
|
1950
|
+
const normalized = normalizeFilesystemPath(path212);
|
|
1904
1951
|
return normalized.includes("..");
|
|
1905
1952
|
}
|
|
1906
1953
|
function createLogicalPath(...segments) {
|
|
@@ -1910,20 +1957,14 @@ function createLogicalPath(...segments) {
|
|
|
1910
1957
|
}
|
|
1911
1958
|
return normalized;
|
|
1912
1959
|
}
|
|
1913
|
-
function trimSlashes(
|
|
1960
|
+
function trimSlashes(path212) {
|
|
1914
1961
|
let start = 0;
|
|
1915
|
-
let end =
|
|
1916
|
-
while (start < end &&
|
|
1962
|
+
let end = path212.length;
|
|
1963
|
+
while (start < end && path212[start] === "/")
|
|
1917
1964
|
start++;
|
|
1918
|
-
while (end > start &&
|
|
1965
|
+
while (end > start && path212[end - 1] === "/")
|
|
1919
1966
|
end--;
|
|
1920
|
-
return
|
|
1921
|
-
}
|
|
1922
|
-
function canopyLogWarn2(...args) {
|
|
1923
|
-
active2.warn(...args);
|
|
1924
|
-
}
|
|
1925
|
-
function canopyLogError(...args) {
|
|
1926
|
-
active2.error(...args);
|
|
1967
|
+
return path212.slice(start, end);
|
|
1927
1968
|
}
|
|
1928
1969
|
function readModeEnv() {
|
|
1929
1970
|
if (typeof process === "undefined" || typeof process.env === "undefined")
|
|
@@ -2007,8 +2048,26 @@ function operatingStrategy2(mode) {
|
|
|
2007
2048
|
function clearStrategyCache() {
|
|
2008
2049
|
strategyCache2.clear();
|
|
2009
2050
|
}
|
|
2051
|
+
function getErrorMessage3(err) {
|
|
2052
|
+
if (err instanceof Error) {
|
|
2053
|
+
return err.message;
|
|
2054
|
+
}
|
|
2055
|
+
if (typeof err === "string") {
|
|
2056
|
+
return err;
|
|
2057
|
+
}
|
|
2058
|
+
return String(err);
|
|
2059
|
+
}
|
|
2060
|
+
function isNodeError3(err) {
|
|
2061
|
+
return err instanceof Error && "code" in err;
|
|
2062
|
+
}
|
|
2063
|
+
function isNotFoundError3(err) {
|
|
2064
|
+
return isNodeError3(err) && err.code === "ENOENT";
|
|
2065
|
+
}
|
|
2066
|
+
function isFileExistsError2(err) {
|
|
2067
|
+
return isNodeError3(err) && err.code === "EEXIST";
|
|
2068
|
+
}
|
|
2010
2069
|
async function atomicWriteFile2(filePath, content) {
|
|
2011
|
-
const dir =
|
|
2070
|
+
const dir = path10.dirname(filePath);
|
|
2012
2071
|
await fs7.mkdir(dir, { recursive: true });
|
|
2013
2072
|
const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
2014
2073
|
await fs7.writeFile(tempPath, content, typeof content === "string" ? "utf-8" : void 0);
|
|
@@ -2020,6 +2079,196 @@ async function atomicWriteFile2(filePath, content) {
|
|
|
2020
2079
|
throw err;
|
|
2021
2080
|
}
|
|
2022
2081
|
}
|
|
2082
|
+
function isBlockStructuralKey(key) {
|
|
2083
|
+
return BLOCK_STRUCTURAL_KEYS.has(key);
|
|
2084
|
+
}
|
|
2085
|
+
function isPlainRecord(value) {
|
|
2086
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
2087
|
+
return false;
|
|
2088
|
+
const proto = Object.getPrototypeOf(value);
|
|
2089
|
+
return proto === Object.prototype || proto === null;
|
|
2090
|
+
}
|
|
2091
|
+
function recordKeyOf(keyNode) {
|
|
2092
|
+
if (!isScalar(keyNode))
|
|
2093
|
+
return void 0;
|
|
2094
|
+
const { value } = keyNode;
|
|
2095
|
+
if (value === null || value === void 0)
|
|
2096
|
+
return void 0;
|
|
2097
|
+
if (typeof value === "object")
|
|
2098
|
+
return void 0;
|
|
2099
|
+
return String(value);
|
|
2100
|
+
}
|
|
2101
|
+
function carryComments(from, to) {
|
|
2102
|
+
if (!isNode(from) || !isNode(to))
|
|
2103
|
+
return;
|
|
2104
|
+
const source = from;
|
|
2105
|
+
const target = to;
|
|
2106
|
+
if (source.commentBefore !== void 0)
|
|
2107
|
+
target.commentBefore = source.commentBefore;
|
|
2108
|
+
if (source.comment !== void 0)
|
|
2109
|
+
target.comment = source.comment;
|
|
2110
|
+
if (source.spaceBefore !== void 0)
|
|
2111
|
+
target.spaceBefore = source.spaceBefore;
|
|
2112
|
+
}
|
|
2113
|
+
function identityKey(value) {
|
|
2114
|
+
try {
|
|
2115
|
+
return JSON.stringify(value) ?? "undefined";
|
|
2116
|
+
} catch {
|
|
2117
|
+
return void 0;
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
function nodePlainValue(node) {
|
|
2121
|
+
if (!isNode(node))
|
|
2122
|
+
return node;
|
|
2123
|
+
try {
|
|
2124
|
+
return node.toJSON();
|
|
2125
|
+
} catch {
|
|
2126
|
+
return void 0;
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
function nodeIdentityKey(node) {
|
|
2130
|
+
const plain = nodePlainValue(node);
|
|
2131
|
+
return plain === void 0 && isNode(node) ? void 0 : identityKey(plain);
|
|
2132
|
+
}
|
|
2133
|
+
function sharesFieldEvidence(existing, value, depth) {
|
|
2134
|
+
for (const key of Object.keys(value)) {
|
|
2135
|
+
if (isBlockStructuralKey(key))
|
|
2136
|
+
continue;
|
|
2137
|
+
if (!Object.prototype.hasOwnProperty.call(existing, key))
|
|
2138
|
+
continue;
|
|
2139
|
+
const before = existing[key];
|
|
2140
|
+
const after = value[key];
|
|
2141
|
+
if (depth < EVIDENCE_MAX_DEPTH && isPlainRecord(before) && isPlainRecord(after) && sharesFieldEvidence(before, after, depth + 1)) {
|
|
2142
|
+
return true;
|
|
2143
|
+
}
|
|
2144
|
+
const beforeKey = identityKey(before);
|
|
2145
|
+
if (beforeKey !== void 0 && beforeKey === identityKey(after))
|
|
2146
|
+
return true;
|
|
2147
|
+
}
|
|
2148
|
+
return false;
|
|
2149
|
+
}
|
|
2150
|
+
function looksLikeSameItem(node, value) {
|
|
2151
|
+
const existing = nodePlainValue(node);
|
|
2152
|
+
if (!isPlainRecord(existing) || !isPlainRecord(value))
|
|
2153
|
+
return true;
|
|
2154
|
+
return sharesFieldEvidence(existing, value, 0);
|
|
2155
|
+
}
|
|
2156
|
+
function reconcileNode(doc, existing, value) {
|
|
2157
|
+
if (isMap(existing) && isPlainRecord(value)) {
|
|
2158
|
+
reconcileMap(doc, existing, value);
|
|
2159
|
+
return existing;
|
|
2160
|
+
}
|
|
2161
|
+
if (isSeq(existing) && Array.isArray(value)) {
|
|
2162
|
+
reconcileSeq(doc, existing, value);
|
|
2163
|
+
return existing;
|
|
2164
|
+
}
|
|
2165
|
+
if (isScalar(existing) && Object.is(existing.value, value))
|
|
2166
|
+
return existing;
|
|
2167
|
+
const fresh = doc.createNode(value);
|
|
2168
|
+
if (!isCollection(existing))
|
|
2169
|
+
carryComments(existing, fresh);
|
|
2170
|
+
return fresh;
|
|
2171
|
+
}
|
|
2172
|
+
function reconcileMap(doc, map, value) {
|
|
2173
|
+
const wanted = new Set(Object.keys(value).filter((key) => value[key] !== void 0));
|
|
2174
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2175
|
+
const retained = [];
|
|
2176
|
+
for (const pair of map.items) {
|
|
2177
|
+
const key = recordKeyOf(pair.key);
|
|
2178
|
+
if (key === void 0 || !wanted.has(key) || seen.has(key))
|
|
2179
|
+
continue;
|
|
2180
|
+
seen.add(key);
|
|
2181
|
+
pair.value = reconcileNode(doc, pair.value, value[key]);
|
|
2182
|
+
retained.push(pair);
|
|
2183
|
+
}
|
|
2184
|
+
map.items = retained;
|
|
2185
|
+
for (const key of Object.keys(value)) {
|
|
2186
|
+
if (seen.has(key) || !wanted.has(key))
|
|
2187
|
+
continue;
|
|
2188
|
+
map.set(doc.createNode(key), doc.createNode(value[key]));
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
function reconcileSeq(doc, seq, value) {
|
|
2192
|
+
const oldItems = seq.items;
|
|
2193
|
+
const byIdentity = /* @__PURE__ */ new Map();
|
|
2194
|
+
oldItems.forEach((node, index) => {
|
|
2195
|
+
const key = nodeIdentityKey(node);
|
|
2196
|
+
if (key === void 0)
|
|
2197
|
+
return;
|
|
2198
|
+
const bucket = byIdentity.get(key);
|
|
2199
|
+
if (bucket)
|
|
2200
|
+
bucket.push(index);
|
|
2201
|
+
else
|
|
2202
|
+
byIdentity.set(key, [index]);
|
|
2203
|
+
});
|
|
2204
|
+
const consumed = /* @__PURE__ */ new Set();
|
|
2205
|
+
const matches = value.map((item) => {
|
|
2206
|
+
const key = identityKey(item);
|
|
2207
|
+
if (key === void 0)
|
|
2208
|
+
return void 0;
|
|
2209
|
+
const bucket = byIdentity.get(key);
|
|
2210
|
+
while (bucket && bucket.length > 0) {
|
|
2211
|
+
const index = bucket.shift();
|
|
2212
|
+
if (index !== void 0 && !consumed.has(index)) {
|
|
2213
|
+
consumed.add(index);
|
|
2214
|
+
return index;
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
return void 0;
|
|
2218
|
+
});
|
|
2219
|
+
seq.items = value.map((item, index) => {
|
|
2220
|
+
const matched = matches[index];
|
|
2221
|
+
if (matched !== void 0)
|
|
2222
|
+
return oldItems[matched];
|
|
2223
|
+
const candidate = index < oldItems.length && !consumed.has(index) ? oldItems[index] : void 0;
|
|
2224
|
+
const sameItem = candidate !== void 0 && looksLikeSameItem(candidate, item) ? candidate : void 0;
|
|
2225
|
+
return reconcileNode(doc, sameItem, item);
|
|
2226
|
+
});
|
|
2227
|
+
}
|
|
2228
|
+
function applyDataToDocument(doc, data) {
|
|
2229
|
+
doc.contents = reconcileNode(doc, doc.contents, data);
|
|
2230
|
+
}
|
|
2231
|
+
function serializeYaml(data, existingRaw) {
|
|
2232
|
+
if (existingRaw === void 0)
|
|
2233
|
+
return yamlStringify(data);
|
|
2234
|
+
const doc = parseDocument(existingRaw);
|
|
2235
|
+
if (doc.errors.length > 0)
|
|
2236
|
+
return yamlStringify(data);
|
|
2237
|
+
applyDataToDocument(doc, data);
|
|
2238
|
+
return doc.toString();
|
|
2239
|
+
}
|
|
2240
|
+
function extractRawFrontmatter(raw) {
|
|
2241
|
+
let parsed;
|
|
2242
|
+
try {
|
|
2243
|
+
parsed = matter(raw, {});
|
|
2244
|
+
} catch {
|
|
2245
|
+
return void 0;
|
|
2246
|
+
}
|
|
2247
|
+
const frontmatter = parsed.matter;
|
|
2248
|
+
if (typeof frontmatter !== "string" || frontmatter.trim() === "")
|
|
2249
|
+
return void 0;
|
|
2250
|
+
return frontmatter;
|
|
2251
|
+
}
|
|
2252
|
+
function serializeFrontmatter(body, data, existingRaw) {
|
|
2253
|
+
if (existingRaw === void 0)
|
|
2254
|
+
return matter.stringify(body, data);
|
|
2255
|
+
const existingFrontmatter = extractRawFrontmatter(existingRaw);
|
|
2256
|
+
if (existingFrontmatter === void 0)
|
|
2257
|
+
return matter.stringify(body, data);
|
|
2258
|
+
const doc = parseDocument(existingFrontmatter);
|
|
2259
|
+
if (doc.errors.length > 0)
|
|
2260
|
+
return matter.stringify(body, data);
|
|
2261
|
+
applyDataToDocument(doc, data);
|
|
2262
|
+
const reconciled = doc.toString();
|
|
2263
|
+
return matter.stringify(body, data, {
|
|
2264
|
+
engines: {
|
|
2265
|
+
yaml: {
|
|
2266
|
+
parse: () => ({}),
|
|
2267
|
+
stringify: () => reconciled
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
});
|
|
2271
|
+
}
|
|
2023
2272
|
async function withLock(key, fn) {
|
|
2024
2273
|
const prev = locks.get(key) ?? Promise.resolve();
|
|
2025
2274
|
let resolve2;
|
|
@@ -2036,51 +2285,71 @@ async function withLock(key, fn) {
|
|
|
2036
2285
|
locks.delete(key);
|
|
2037
2286
|
}
|
|
2038
2287
|
}
|
|
2039
|
-
function
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2288
|
+
function provisioningLockOptions(lockPath, retries, onCompromised) {
|
|
2289
|
+
return {
|
|
2290
|
+
lockfilePath: lockPath,
|
|
2291
|
+
realpath: false,
|
|
2292
|
+
retries,
|
|
2293
|
+
stale: 3e4,
|
|
2294
|
+
// proper-lockfile invokes this from inside its refresh timer, so ANY throw
|
|
2295
|
+
// escaping here is an uncaught exception that kills the process -- the very
|
|
2296
|
+
// failure the handler exists to prevent. Call sites are told not to throw
|
|
2297
|
+
// (see OnLockCompromised); this makes it structural rather than a
|
|
2298
|
+
// convention, and also covers the LOGGER throwing: under `CI=true`,
|
|
2299
|
+
// vitest's `onConsoleLog` turns any console write into a throw.
|
|
2300
|
+
onCompromised: (err) => {
|
|
2301
|
+
try {
|
|
2302
|
+
if (onCompromised) {
|
|
2303
|
+
onCompromised(err);
|
|
2304
|
+
return;
|
|
2305
|
+
}
|
|
2306
|
+
canopyLogWarn2(`[canopy] Provisioning lock compromised mid-hold for ${lockPath}:`, getErrorMessage3(err));
|
|
2307
|
+
} catch {
|
|
2308
|
+
try {
|
|
2309
|
+
process.stderr.write(`[canopy] lock compromised for ${lockPath}; its handler or logger threw
|
|
2310
|
+
`);
|
|
2311
|
+
} catch {
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
};
|
|
2053
2316
|
}
|
|
2054
|
-
function
|
|
2055
|
-
return
|
|
2317
|
+
function releaseIgnoringAlreadyReleased(release, lockPath) {
|
|
2318
|
+
return async () => {
|
|
2319
|
+
try {
|
|
2320
|
+
await release();
|
|
2321
|
+
} catch (err) {
|
|
2322
|
+
if (isNodeError3(err) && err.code === "ERELEASED") {
|
|
2323
|
+
canopyLogWarn2(`[canopy] Lock at ${lockPath} was already released (compromised mid-hold, or released twice); nothing to release`);
|
|
2324
|
+
return;
|
|
2325
|
+
}
|
|
2326
|
+
throw err;
|
|
2327
|
+
}
|
|
2328
|
+
};
|
|
2056
2329
|
}
|
|
2057
|
-
async function acquireProvisioningLock(lockTargetDir2, lockName) {
|
|
2330
|
+
async function acquireProvisioningLock(lockTargetDir2, lockName, onCompromised) {
|
|
2058
2331
|
await fs23.mkdir(lockTargetDir2, { recursive: true });
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
stale: 3e4
|
|
2063
|
-
});
|
|
2332
|
+
const lockPath = path22.join(lockTargetDir2, lockName);
|
|
2333
|
+
const release = await lockfile.lock(lockPath, provisioningLockOptions(lockPath, { retries: 600, factor: 1, minTimeout: 300, maxTimeout: 800, randomize: true }, onCompromised));
|
|
2334
|
+
return releaseIgnoringAlreadyReleased(release, lockPath);
|
|
2064
2335
|
}
|
|
2065
|
-
async function tryAcquireProvisioningLock(lockTargetDir2, lockName) {
|
|
2336
|
+
async function tryAcquireProvisioningLock(lockTargetDir2, lockName, onCompromised) {
|
|
2066
2337
|
await fs23.mkdir(lockTargetDir2, { recursive: true });
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
stale: 3e4
|
|
2071
|
-
});
|
|
2338
|
+
const lockPath = path22.join(lockTargetDir2, lockName);
|
|
2339
|
+
const release = await lockfile.lock(lockPath, provisioningLockOptions(lockPath, 0, onCompromised));
|
|
2340
|
+
return releaseIgnoringAlreadyReleased(release, lockPath);
|
|
2072
2341
|
}
|
|
2073
2342
|
function lockTargetDir(branchRoot) {
|
|
2074
2343
|
return path32.join(path32.resolve(branchRoot), META_DIR);
|
|
2075
2344
|
}
|
|
2076
|
-
function tryAcquireContentWriteLock(branchRoot) {
|
|
2077
|
-
return tryAcquireProvisioningLock(lockTargetDir(branchRoot), CONTENT_WRITE_LOCK_NAME);
|
|
2345
|
+
function tryAcquireContentWriteLock(branchRoot, onCompromised) {
|
|
2346
|
+
return tryAcquireProvisioningLock(lockTargetDir(branchRoot), CONTENT_WRITE_LOCK_NAME, onCompromised);
|
|
2078
2347
|
}
|
|
2079
|
-
async function acquireContentWriteLock(branchRoot, waitMs = DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS) {
|
|
2348
|
+
async function acquireContentWriteLock(branchRoot, waitMs = DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS, onCompromised) {
|
|
2080
2349
|
const startedAt = Date.now();
|
|
2081
2350
|
for (let attempt = 0; ; attempt++) {
|
|
2082
2351
|
try {
|
|
2083
|
-
return await tryAcquireContentWriteLock(branchRoot);
|
|
2352
|
+
return await tryAcquireContentWriteLock(branchRoot, onCompromised);
|
|
2084
2353
|
} catch (err) {
|
|
2085
2354
|
if (!isNodeError3(err) || err.code !== "ELOCKED")
|
|
2086
2355
|
throw err;
|
|
@@ -2093,12 +2362,21 @@ async function acquireContentWriteLock(branchRoot, waitMs = DEFAULT_CONTENT_WRIT
|
|
|
2093
2362
|
}
|
|
2094
2363
|
}
|
|
2095
2364
|
async function withContentWriteLock(branchRoot, fn, waitMs = DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS) {
|
|
2096
|
-
|
|
2365
|
+
let compromised = false;
|
|
2366
|
+
const release = await acquireContentWriteLock(branchRoot, waitMs, (err) => {
|
|
2367
|
+
compromised = true;
|
|
2368
|
+
canopyLogWarn2(`[canopy] Content-write lock compromised mid-hold for ${branchRoot}:`, getErrorMessage3(err));
|
|
2369
|
+
});
|
|
2370
|
+
let result;
|
|
2097
2371
|
try {
|
|
2098
|
-
|
|
2372
|
+
result = await fn();
|
|
2099
2373
|
} finally {
|
|
2100
2374
|
await release();
|
|
2101
2375
|
}
|
|
2376
|
+
if (compromised) {
|
|
2377
|
+
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.");
|
|
2378
|
+
}
|
|
2379
|
+
return result;
|
|
2102
2380
|
}
|
|
2103
2381
|
function flattenGroupFields(fields) {
|
|
2104
2382
|
const result = [];
|
|
@@ -2118,9 +2396,68 @@ function findBodyFieldName(fields) {
|
|
|
2118
2396
|
}
|
|
2119
2397
|
return "body";
|
|
2120
2398
|
}
|
|
2399
|
+
function buildResolvedReference(data, meta, body) {
|
|
2400
|
+
const resolved = { ...data };
|
|
2401
|
+
if (body && body.value)
|
|
2402
|
+
resolved[body.fieldName] = body.value;
|
|
2403
|
+
resolved.id = meta.id;
|
|
2404
|
+
resolved.slug = meta.slug;
|
|
2405
|
+
resolved.collection = meta.collection;
|
|
2406
|
+
resolved.urlPath = meta.urlPath;
|
|
2407
|
+
return resolved;
|
|
2408
|
+
}
|
|
2409
|
+
function isIndexSlug(slug) {
|
|
2410
|
+
return slug?.toLowerCase() === "index";
|
|
2411
|
+
}
|
|
2412
|
+
function computeEntryUrl(collection, slug, contentRoot) {
|
|
2413
|
+
const root = trimSlashes(contentRoot);
|
|
2414
|
+
let stripped = collection;
|
|
2415
|
+
if (root && collection.startsWith(`${root}/`)) {
|
|
2416
|
+
stripped = collection.slice(root.length + 1);
|
|
2417
|
+
} else if (collection === root) {
|
|
2418
|
+
stripped = "";
|
|
2419
|
+
}
|
|
2420
|
+
const segments = stripped.split("/").filter(Boolean);
|
|
2421
|
+
if (slug && !isIndexSlug(slug)) {
|
|
2422
|
+
segments.push(slug);
|
|
2423
|
+
}
|
|
2424
|
+
const path212 = segments.length > 0 ? `/${segments.join("/")}` : "/";
|
|
2425
|
+
return path212.toLowerCase();
|
|
2426
|
+
}
|
|
2121
2427
|
function isValidContentId(id) {
|
|
2122
2428
|
return CONTENT_ID_PATTERN.test(id);
|
|
2123
2429
|
}
|
|
2430
|
+
function parseSlug(slug) {
|
|
2431
|
+
if (!slug) {
|
|
2432
|
+
return {
|
|
2433
|
+
ok: false,
|
|
2434
|
+
error: "Slug is required"
|
|
2435
|
+
};
|
|
2436
|
+
}
|
|
2437
|
+
if (slug.length > 64) {
|
|
2438
|
+
return { ok: false, error: "Slug too long (max 64 characters)" };
|
|
2439
|
+
}
|
|
2440
|
+
if (slug.includes("/") || slug.includes("\\")) {
|
|
2441
|
+
return {
|
|
2442
|
+
ok: false,
|
|
2443
|
+
error: "Slug cannot contain path separators"
|
|
2444
|
+
};
|
|
2445
|
+
}
|
|
2446
|
+
if (slug === "." || slug === "..") {
|
|
2447
|
+
return {
|
|
2448
|
+
ok: false,
|
|
2449
|
+
error: "Slug cannot be a traversal sequence"
|
|
2450
|
+
};
|
|
2451
|
+
}
|
|
2452
|
+
const normalized = slug.toLowerCase();
|
|
2453
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(normalized)) {
|
|
2454
|
+
return {
|
|
2455
|
+
ok: false,
|
|
2456
|
+
error: "Slug must start with a letter or number and contain only lowercase letters, numbers, and hyphens"
|
|
2457
|
+
};
|
|
2458
|
+
}
|
|
2459
|
+
return { ok: true, slug: normalized };
|
|
2460
|
+
}
|
|
2124
2461
|
function generateId() {
|
|
2125
2462
|
const full = generate();
|
|
2126
2463
|
return full.substring(0, 12);
|
|
@@ -2148,13 +2485,13 @@ function extractIdFromFilename(filename) {
|
|
|
2148
2485
|
return null;
|
|
2149
2486
|
}
|
|
2150
2487
|
async function resolveCollectionPath(root, logicalPath) {
|
|
2151
|
-
const
|
|
2152
|
-
const
|
|
2488
|
+
const fs182 = await import("node:fs/promises");
|
|
2489
|
+
const path212 = await import("node:path");
|
|
2153
2490
|
const segments = logicalPath.split("/").filter(Boolean);
|
|
2154
2491
|
let currentPath = root;
|
|
2155
2492
|
for (const segment of segments) {
|
|
2156
2493
|
try {
|
|
2157
|
-
const entries = await
|
|
2494
|
+
const entries = await fs182.readdir(currentPath, { withFileTypes: true });
|
|
2158
2495
|
const matchingDir = entries.find((entry) => {
|
|
2159
2496
|
if (!entry.isDirectory())
|
|
2160
2497
|
return false;
|
|
@@ -2162,7 +2499,7 @@ async function resolveCollectionPath(root, logicalPath) {
|
|
|
2162
2499
|
return logicalName === segment.toLowerCase();
|
|
2163
2500
|
});
|
|
2164
2501
|
if (matchingDir) {
|
|
2165
|
-
currentPath =
|
|
2502
|
+
currentPath = path212.join(currentPath, matchingDir.name);
|
|
2166
2503
|
} else {
|
|
2167
2504
|
return null;
|
|
2168
2505
|
}
|
|
@@ -2211,8 +2548,70 @@ function extractSlugFromFilename(filename, entryTypeName) {
|
|
|
2211
2548
|
}
|
|
2212
2549
|
return filename.toLowerCase();
|
|
2213
2550
|
}
|
|
2551
|
+
async function readDirSafe(dir) {
|
|
2552
|
+
try {
|
|
2553
|
+
return await fs42.readdir(dir, { withFileTypes: true });
|
|
2554
|
+
} catch (err) {
|
|
2555
|
+
if (isNotFoundError3(err))
|
|
2556
|
+
return [];
|
|
2557
|
+
throw err;
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
async function findChildCollectionDir(dir, name) {
|
|
2561
|
+
const wanted = name.toLowerCase();
|
|
2562
|
+
for (const entry of await readDirSafe(dir)) {
|
|
2563
|
+
if (!entry.isDirectory())
|
|
2564
|
+
continue;
|
|
2565
|
+
if (extractSlugFromFilename(entry.name) === wanted)
|
|
2566
|
+
return path52.join(dir, entry.name);
|
|
2567
|
+
}
|
|
2568
|
+
return null;
|
|
2569
|
+
}
|
|
2570
|
+
function entrySlugOf(filename) {
|
|
2571
|
+
if (!CONTENT_EXTENSIONS.some((ext) => filename.endsWith(ext)))
|
|
2572
|
+
return null;
|
|
2573
|
+
return parseTypedFilename(filename)?.slug ?? null;
|
|
2574
|
+
}
|
|
2575
|
+
async function findIndexEntryIn(dir) {
|
|
2576
|
+
for (const entry of await readDirSafe(dir)) {
|
|
2577
|
+
if (entry.isDirectory())
|
|
2578
|
+
continue;
|
|
2579
|
+
if (isIndexSlug(entrySlugOf(entry.name) ?? void 0))
|
|
2580
|
+
return path52.join(dir, entry.name);
|
|
2581
|
+
}
|
|
2582
|
+
return null;
|
|
2583
|
+
}
|
|
2584
|
+
async function findEntryBySlugIn(dir, slug) {
|
|
2585
|
+
const wanted = slug.toLowerCase();
|
|
2586
|
+
for (const entry of await readDirSafe(dir)) {
|
|
2587
|
+
if (entry.isDirectory())
|
|
2588
|
+
continue;
|
|
2589
|
+
if (entrySlugOf(entry.name) === wanted)
|
|
2590
|
+
return path52.join(dir, entry.name);
|
|
2591
|
+
}
|
|
2592
|
+
return null;
|
|
2593
|
+
}
|
|
2594
|
+
async function findUrlPathClaimant(opts) {
|
|
2595
|
+
const { collectionDir, slug, contentRoot } = opts;
|
|
2596
|
+
if (isIndexSlug(slug)) {
|
|
2597
|
+
const resolvedRoot = path52.resolve(contentRoot);
|
|
2598
|
+
if (path52.resolve(collectionDir) === resolvedRoot)
|
|
2599
|
+
return null;
|
|
2600
|
+
const parentDir = path52.dirname(collectionDir);
|
|
2601
|
+
const ownName = extractSlugFromFilename(path52.basename(collectionDir));
|
|
2602
|
+
if (isIndexSlug(ownName))
|
|
2603
|
+
return null;
|
|
2604
|
+
const claimant = await findEntryBySlugIn(parentDir, ownName);
|
|
2605
|
+
return claimant ? { kind: "parent-entry", physicalPath: claimant, name: ownName } : null;
|
|
2606
|
+
}
|
|
2607
|
+
const childDir = await findChildCollectionDir(collectionDir, slug);
|
|
2608
|
+
if (!childDir)
|
|
2609
|
+
return null;
|
|
2610
|
+
const indexEntry = await findIndexEntryIn(childDir);
|
|
2611
|
+
return indexEntry ? { kind: "sibling-collection-index", physicalPath: indexEntry, name: slug } : null;
|
|
2612
|
+
}
|
|
2214
2613
|
function registerContentIndexForInvalidation(root, target) {
|
|
2215
|
-
const rootKey =
|
|
2614
|
+
const rootKey = path62.resolve(root);
|
|
2216
2615
|
let refs = registry.get(rootKey);
|
|
2217
2616
|
if (!refs) {
|
|
2218
2617
|
refs = /* @__PURE__ */ new Set();
|
|
@@ -2223,8 +2622,8 @@ function registerContentIndexForInvalidation(root, target) {
|
|
|
2223
2622
|
finalization.register(target, { rootKey, ref });
|
|
2224
2623
|
}
|
|
2225
2624
|
function invalidateContentIndexesForRoot(root) {
|
|
2226
|
-
const rootKey =
|
|
2227
|
-
const prefix = rootKey +
|
|
2625
|
+
const rootKey = path62.resolve(root);
|
|
2626
|
+
const prefix = rootKey + path62.sep;
|
|
2228
2627
|
for (const [storeRoot, refs] of registry) {
|
|
2229
2628
|
if (storeRoot !== rootKey && !storeRoot.startsWith(prefix))
|
|
2230
2629
|
continue;
|
|
@@ -2244,7 +2643,7 @@ function createDebugLogger2(options) {
|
|
|
2244
2643
|
return new DebugLogger2(options);
|
|
2245
2644
|
}
|
|
2246
2645
|
function resourceGenerationPath(root, resource) {
|
|
2247
|
-
return
|
|
2646
|
+
return path72.resolve(root, META_DIR2, `${resource}.generation`);
|
|
2248
2647
|
}
|
|
2249
2648
|
async function bumpResourceGeneration(root, resource, options) {
|
|
2250
2649
|
const token = randomUUID();
|
|
@@ -2262,7 +2661,7 @@ async function bumpResourceGeneration(root, resource, options) {
|
|
|
2262
2661
|
}
|
|
2263
2662
|
async function readResourceGeneration(root, resource) {
|
|
2264
2663
|
try {
|
|
2265
|
-
const token = await
|
|
2664
|
+
const token = await fs52.readFile(resourceGenerationPath(root, resource), "utf-8");
|
|
2266
2665
|
return { ok: true, token };
|
|
2267
2666
|
} catch (err) {
|
|
2268
2667
|
if (isNodeError3(err) && err.code === "ENOENT")
|
|
@@ -2282,7 +2681,7 @@ function stripEmbeddedIdFromName(name) {
|
|
|
2282
2681
|
async function scanForCollectionMeta(baseDir, relativePath = "") {
|
|
2283
2682
|
const collections = [];
|
|
2284
2683
|
try {
|
|
2285
|
-
const entries = await
|
|
2684
|
+
const entries = await fs62.readdir(baseDir, { withFileTypes: true });
|
|
2286
2685
|
for (const entry of entries) {
|
|
2287
2686
|
if (!entry.isDirectory())
|
|
2288
2687
|
continue;
|
|
@@ -2293,8 +2692,8 @@ async function scanForCollectionMeta(baseDir, relativePath = "") {
|
|
|
2293
2692
|
const absolutePath = join3(baseDir, folderName);
|
|
2294
2693
|
const metaPath = join3(absolutePath, ".collection.json");
|
|
2295
2694
|
try {
|
|
2296
|
-
await
|
|
2297
|
-
const content = await
|
|
2695
|
+
await fs62.access(metaPath);
|
|
2696
|
+
const content = await fs62.readFile(metaPath, "utf-8");
|
|
2298
2697
|
const parsed = JSON.parse(content);
|
|
2299
2698
|
const meta = collectionMetaSchema.parse(parsed);
|
|
2300
2699
|
collections.push({
|
|
@@ -2326,7 +2725,7 @@ async function loadCollectionMetaFiles(contentRoot) {
|
|
|
2326
2725
|
let root = null;
|
|
2327
2726
|
const rootMetaPath = join3(contentRoot, ".collection.json");
|
|
2328
2727
|
try {
|
|
2329
|
-
await
|
|
2728
|
+
await fs62.access(rootMetaPath);
|
|
2330
2729
|
} catch (err) {
|
|
2331
2730
|
if (err.code === "ENOENT") {
|
|
2332
2731
|
} else {
|
|
@@ -2334,7 +2733,7 @@ async function loadCollectionMetaFiles(contentRoot) {
|
|
|
2334
2733
|
}
|
|
2335
2734
|
}
|
|
2336
2735
|
try {
|
|
2337
|
-
const content = await
|
|
2736
|
+
const content = await fs62.readFile(rootMetaPath, "utf-8");
|
|
2338
2737
|
const parsed = JSON.parse(content);
|
|
2339
2738
|
root = rootCollectionMetaSchema.parse(parsed);
|
|
2340
2739
|
} catch (err) {
|
|
@@ -2424,16 +2823,16 @@ function isValidSchema(schema) {
|
|
|
2424
2823
|
async function isStaleByMtime(dir, cachedAt) {
|
|
2425
2824
|
let entries;
|
|
2426
2825
|
try {
|
|
2427
|
-
entries = await
|
|
2826
|
+
entries = await fs72.readdir(dir, { recursive: true, encoding: "utf-8" });
|
|
2428
2827
|
} catch {
|
|
2429
2828
|
return true;
|
|
2430
2829
|
}
|
|
2431
2830
|
for (const entry of entries) {
|
|
2432
2831
|
if (!entry.endsWith(".collection.json"))
|
|
2433
2832
|
continue;
|
|
2434
|
-
const full =
|
|
2833
|
+
const full = path82.join(dir, entry);
|
|
2435
2834
|
try {
|
|
2436
|
-
const stat = await
|
|
2835
|
+
const stat = await fs72.stat(full);
|
|
2437
2836
|
if (stat.mtimeMs > cachedAt.getTime())
|
|
2438
2837
|
return true;
|
|
2439
2838
|
} catch {
|
|
@@ -2456,7 +2855,7 @@ async function invalidateBranchContentCaches(root) {
|
|
|
2456
2855
|
}
|
|
2457
2856
|
async function filePathExists3(filePath) {
|
|
2458
2857
|
try {
|
|
2459
|
-
await
|
|
2858
|
+
await fs8.stat(filePath);
|
|
2460
2859
|
return true;
|
|
2461
2860
|
} catch (err) {
|
|
2462
2861
|
if (isNotFoundError3(err))
|
|
@@ -2464,6 +2863,15 @@ async function filePathExists3(filePath) {
|
|
|
2464
2863
|
throw err;
|
|
2465
2864
|
}
|
|
2466
2865
|
}
|
|
2866
|
+
async function readFileIfExists(filePath) {
|
|
2867
|
+
try {
|
|
2868
|
+
return await fs8.readFile(filePath, "utf8");
|
|
2869
|
+
} catch (err) {
|
|
2870
|
+
if (isNotFoundError3(err))
|
|
2871
|
+
return void 0;
|
|
2872
|
+
throw err;
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2467
2875
|
function validateAndNormalizePath(root, target) {
|
|
2468
2876
|
const resolvedRoot = resolve(root);
|
|
2469
2877
|
const withSep = resolvedRoot.endsWith(sep) ? resolvedRoot : `${resolvedRoot}${sep}`;
|
|
@@ -2493,11 +2901,11 @@ function resolveBranchPath(options) {
|
|
|
2493
2901
|
const safeBranch = sanitizeBranchName(options.branchName);
|
|
2494
2902
|
const strategy = operatingStrategy2(options.mode);
|
|
2495
2903
|
const baseRoot = resolveContentBranchesRoot(options.mode, options.basePathOverride);
|
|
2496
|
-
const normalizedBase =
|
|
2497
|
-
const baseWithSep = normalizedBase.endsWith(
|
|
2904
|
+
const normalizedBase = path102.resolve(baseRoot);
|
|
2905
|
+
const baseWithSep = normalizedBase.endsWith(path102.sep) ? normalizedBase : `${normalizedBase}${path102.sep}`;
|
|
2498
2906
|
const branchRoot = strategy.getContentBranchRoot(safeBranch, options.basePathOverride);
|
|
2499
2907
|
const withinBase = (target) => {
|
|
2500
|
-
const resolved =
|
|
2908
|
+
const resolved = path102.resolve(target);
|
|
2501
2909
|
return resolved === normalizedBase || resolved.startsWith(baseWithSep);
|
|
2502
2910
|
};
|
|
2503
2911
|
if (!withinBase(branchRoot)) {
|
|
@@ -2507,7 +2915,7 @@ function resolveBranchPath(options) {
|
|
|
2507
2915
|
}
|
|
2508
2916
|
async function ensureBranchRoot(options) {
|
|
2509
2917
|
const result = resolveBranchPath(options);
|
|
2510
|
-
await
|
|
2918
|
+
await fs9.mkdir(result.branchRoot, { recursive: true });
|
|
2511
2919
|
return result;
|
|
2512
2920
|
}
|
|
2513
2921
|
async function withLocks(keys, fn) {
|
|
@@ -2795,7 +3203,7 @@ function renderField(field, value, depth, entry, config) {
|
|
|
2795
3203
|
const heading = "#".repeat(Math.min(depth, 6));
|
|
2796
3204
|
const descriptionLine = "description" in field && field.description ? `
|
|
2797
3205
|
|
|
2798
|
-
|
|
3206
|
+
_${field.description}_` : "";
|
|
2799
3207
|
if ("list" in field && field.list && Array.isArray(value)) {
|
|
2800
3208
|
return renderListField(field, value, depth, label, heading, descriptionLine, entry, config);
|
|
2801
3209
|
}
|
|
@@ -3051,26 +3459,13 @@ function formatInlineValue(field, value) {
|
|
|
3051
3459
|
return String(value);
|
|
3052
3460
|
}
|
|
3053
3461
|
function yamlValue(value) {
|
|
3462
|
+
if (value === "")
|
|
3463
|
+
return '""';
|
|
3054
3464
|
if (/[:#{}[\],&*?|>!%@`]/.test(value) || value.includes("\n")) {
|
|
3055
3465
|
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
3056
3466
|
}
|
|
3057
3467
|
return value;
|
|
3058
3468
|
}
|
|
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
3469
|
function resolveEntryUrl(location, contentRoot) {
|
|
3075
3470
|
return computeEntryUrl(location.collection ?? "", location.slug ?? "", contentRoot);
|
|
3076
3471
|
}
|
|
@@ -3237,7 +3632,7 @@ async function processCollection(store, collection, flatSchema, contentRoot, con
|
|
|
3237
3632
|
const listed = await store.getCollectionEntryPaths(collection.logicalPath);
|
|
3238
3633
|
const directEntries = listed.filter((e) => e.collection === collection.logicalPath);
|
|
3239
3634
|
for (const listEntry of directEntries) {
|
|
3240
|
-
const entryTypeName = extractEntryTypeFromFilename(
|
|
3635
|
+
const entryTypeName = extractEntryTypeFromFilename(path12.basename(listEntry.relativePath));
|
|
3241
3636
|
if (!entryTypeName)
|
|
3242
3637
|
continue;
|
|
3243
3638
|
if (config?.exclude?.entryTypes?.includes(entryTypeName))
|
|
@@ -3255,7 +3650,7 @@ async function processCollection(store, collection, flatSchema, contentRoot, con
|
|
|
3255
3650
|
}
|
|
3256
3651
|
if (config?.exclude?.where?.(aiEntry))
|
|
3257
3652
|
continue;
|
|
3258
|
-
await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(
|
|
3653
|
+
await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(path12.basename(listEntry.relativePath)), config);
|
|
3259
3654
|
entries.push(aiEntry);
|
|
3260
3655
|
const entryFilePath = `${cleanPath}/${listEntry.slug}.md`;
|
|
3261
3656
|
const entryMarkdown = entryToMarkdown(aiEntry, config);
|
|
@@ -3306,7 +3701,7 @@ async function processRootEntries(store, rootCollection, contentRoot, config, id
|
|
|
3306
3701
|
const listed = await store.getCollectionEntryPaths(rootCollection.logicalPath);
|
|
3307
3702
|
const directEntries = listed.filter((e) => e.collection === rootCollection.logicalPath);
|
|
3308
3703
|
for (const listEntry of directEntries) {
|
|
3309
|
-
const entryTypeName = extractEntryTypeFromFilename(
|
|
3704
|
+
const entryTypeName = extractEntryTypeFromFilename(path12.basename(listEntry.relativePath));
|
|
3310
3705
|
if (!entryTypeName)
|
|
3311
3706
|
continue;
|
|
3312
3707
|
if (config?.exclude?.entryTypes?.includes(entryTypeName))
|
|
@@ -3324,7 +3719,7 @@ async function processRootEntries(store, rootCollection, contentRoot, config, id
|
|
|
3324
3719
|
}
|
|
3325
3720
|
if (config?.exclude?.where?.(aiEntry))
|
|
3326
3721
|
continue;
|
|
3327
|
-
await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(
|
|
3722
|
+
await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(path12.basename(listEntry.relativePath)), config);
|
|
3328
3723
|
entries.push(aiEntry);
|
|
3329
3724
|
const entryFilePath = `${listEntry.slug}.md`;
|
|
3330
3725
|
const entryMarkdown = entryToMarkdown(aiEntry, config);
|
|
@@ -3372,19 +3767,19 @@ function docToAIEntry(doc, slug, entryTypeName, entryTypeConfig, cleanCollection
|
|
|
3372
3767
|
};
|
|
3373
3768
|
}
|
|
3374
3769
|
function makeReadSibling(dir) {
|
|
3375
|
-
const resolvedDir =
|
|
3770
|
+
const resolvedDir = path12.resolve(dir);
|
|
3376
3771
|
return async (name) => {
|
|
3377
|
-
if (!name || name.includes("/") || name.includes("\\") ||
|
|
3772
|
+
if (!name || name.includes("/") || name.includes("\\") || path12.isAbsolute(name) || hasTraversalSequence(name)) {
|
|
3378
3773
|
return null;
|
|
3379
3774
|
}
|
|
3380
|
-
const abs =
|
|
3381
|
-
if (
|
|
3775
|
+
const abs = path12.resolve(resolvedDir, name);
|
|
3776
|
+
if (path12.dirname(abs) !== resolvedDir)
|
|
3382
3777
|
return null;
|
|
3383
3778
|
try {
|
|
3384
|
-
const stats = await
|
|
3779
|
+
const stats = await fs11.lstat(abs);
|
|
3385
3780
|
if (!stats.isFile())
|
|
3386
3781
|
return null;
|
|
3387
|
-
return await
|
|
3782
|
+
return await fs11.readFile(abs, "utf8");
|
|
3388
3783
|
} catch (err) {
|
|
3389
3784
|
if (isNodeError3(err) && (err.code === "ENOENT" || err.code === "ENOTDIR"))
|
|
3390
3785
|
return null;
|
|
@@ -3398,7 +3793,7 @@ async function runEntryTransform(entry, absolutePath, contentId, config) {
|
|
|
3398
3793
|
return;
|
|
3399
3794
|
const ctx = {
|
|
3400
3795
|
contentId: contentId ?? "",
|
|
3401
|
-
readSibling: makeReadSibling(
|
|
3796
|
+
readSibling: makeReadSibling(path12.dirname(absolutePath))
|
|
3402
3797
|
};
|
|
3403
3798
|
try {
|
|
3404
3799
|
const appended = await transform(entry, ctx);
|
|
@@ -3439,29 +3834,29 @@ async function writeOccJsonFile(filePath, payload, options) {
|
|
|
3439
3834
|
const writeId = randomUUID2();
|
|
3440
3835
|
const data = { ...payload, version: newVersion, writeId };
|
|
3441
3836
|
const content = JSON.stringify(data, null, 2) + (trailingNewline ? "\n" : "");
|
|
3442
|
-
const dir =
|
|
3443
|
-
await
|
|
3837
|
+
const dir = path14.dirname(filePath);
|
|
3838
|
+
await fs13.mkdir(dir, { recursive: true });
|
|
3444
3839
|
const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
3445
|
-
await
|
|
3840
|
+
await fs13.writeFile(tempPath, content, "utf-8");
|
|
3446
3841
|
if (expectedVersion === null) {
|
|
3447
3842
|
try {
|
|
3448
|
-
await
|
|
3843
|
+
await fs13.link(tempPath, filePath);
|
|
3449
3844
|
} catch (err) {
|
|
3450
|
-
await
|
|
3845
|
+
await fs13.unlink(tempPath).catch(() => {
|
|
3451
3846
|
});
|
|
3452
3847
|
if (isFileExistsError2(err)) {
|
|
3453
3848
|
throw new OccWriteConflictError();
|
|
3454
3849
|
}
|
|
3455
3850
|
throw err;
|
|
3456
3851
|
}
|
|
3457
|
-
await
|
|
3852
|
+
await fs13.unlink(tempPath).catch(() => {
|
|
3458
3853
|
});
|
|
3459
3854
|
return { version: newVersion, writeId };
|
|
3460
3855
|
}
|
|
3461
3856
|
try {
|
|
3462
3857
|
let currentVersion = null;
|
|
3463
3858
|
try {
|
|
3464
|
-
const current = JSON.parse(await
|
|
3859
|
+
const current = JSON.parse(await fs13.readFile(filePath, "utf-8"));
|
|
3465
3860
|
currentVersion = current.version ?? 0;
|
|
3466
3861
|
} catch {
|
|
3467
3862
|
currentVersion = null;
|
|
@@ -3469,16 +3864,16 @@ async function writeOccJsonFile(filePath, payload, options) {
|
|
|
3469
3864
|
if (currentVersion !== expectedVersion) {
|
|
3470
3865
|
throw new OccWriteConflictError();
|
|
3471
3866
|
}
|
|
3472
|
-
await
|
|
3867
|
+
await fs13.rename(tempPath, filePath);
|
|
3473
3868
|
if (settleMs > 0) {
|
|
3474
3869
|
await new Promise((resolve2) => setTimeout(resolve2, settleMs));
|
|
3475
3870
|
}
|
|
3476
|
-
const afterWrite = JSON.parse(await
|
|
3871
|
+
const afterWrite = JSON.parse(await fs13.readFile(filePath, "utf-8"));
|
|
3477
3872
|
if (afterWrite.writeId !== writeId) {
|
|
3478
3873
|
throw new OccWriteConflictError();
|
|
3479
3874
|
}
|
|
3480
3875
|
} catch (err) {
|
|
3481
|
-
await
|
|
3876
|
+
await fs13.unlink(tempPath).catch(() => {
|
|
3482
3877
|
});
|
|
3483
3878
|
throw err;
|
|
3484
3879
|
}
|
|
@@ -3504,8 +3899,8 @@ async function withOccRetry(operation, options) {
|
|
|
3504
3899
|
throw new Error("Unreachable");
|
|
3505
3900
|
}
|
|
3506
3901
|
async function withOccFileLock(filePath, fn) {
|
|
3507
|
-
const dir =
|
|
3508
|
-
await
|
|
3902
|
+
const dir = path14.dirname(filePath);
|
|
3903
|
+
await fs13.mkdir(dir, { recursive: true });
|
|
3509
3904
|
const MAX_ATTEMPTS = 14;
|
|
3510
3905
|
let release = null;
|
|
3511
3906
|
for (let attempt = 1; release === null; attempt++) {
|
|
@@ -3589,11 +3984,11 @@ function gitChildEnv(overrides) {
|
|
|
3589
3984
|
return { ...env, ...FORCE_C_LOCALE, ...overrides };
|
|
3590
3985
|
}
|
|
3591
3986
|
async function ensureGitExcludePattern(repoPath, pattern) {
|
|
3592
|
-
const excludePath =
|
|
3593
|
-
await
|
|
3987
|
+
const excludePath = path16.join(repoPath, ".git", "info", "exclude");
|
|
3988
|
+
await fs15.mkdir(path16.dirname(excludePath), { recursive: true });
|
|
3594
3989
|
let content = "";
|
|
3595
3990
|
try {
|
|
3596
|
-
content = await
|
|
3991
|
+
content = await fs15.readFile(excludePath, "utf-8");
|
|
3597
3992
|
} catch (err) {
|
|
3598
3993
|
if (!isNotFoundError3(err))
|
|
3599
3994
|
throw err;
|
|
@@ -3605,7 +4000,7 @@ async function ensureGitExcludePattern(repoPath, pattern) {
|
|
|
3605
4000
|
}
|
|
3606
4001
|
const needsLeadingNewline = content.length > 0 && !content.endsWith("\n");
|
|
3607
4002
|
const newContent = content + (needsLeadingNewline ? "\n" : "") + pattern + "\n";
|
|
3608
|
-
await
|
|
4003
|
+
await fs15.writeFile(excludePath, newContent, "utf-8");
|
|
3609
4004
|
log5.debug("git", "Added pattern to .git/info/exclude", { pattern });
|
|
3610
4005
|
}
|
|
3611
4006
|
async function loadOrCreateBranchContext(options) {
|
|
@@ -3669,10 +4064,12 @@ async function listEntries(branchRoot, flatSchema, contentRootName, options, vis
|
|
|
3669
4064
|
const collections = flatSchema.filter((item) => item.type === "collection" && item.entries !== void 0 && (item.logicalPath === rootPath || item.logicalPath.startsWith(`${rootPath}/`)));
|
|
3670
4065
|
const shouldInclude = visibility?.shouldInclude;
|
|
3671
4066
|
const skippedFiles = [];
|
|
4067
|
+
const resolver = options?.resolveReferences ? createReferenceResolver(branchRoot, flatSchema, contentRootName) : null;
|
|
3672
4068
|
const collectionResults = await Promise.all(collections.map(async (collection) => {
|
|
3673
4069
|
const entries = await listCollectionEntries(branchRoot, collection, (file) => skippedFiles.push(file));
|
|
3674
4070
|
const visible = shouldInclude ? entries.filter((e) => shouldInclude(e.physicalPath)) : entries;
|
|
3675
|
-
|
|
4071
|
+
const resolved = resolver ? await resolveCollectionItemReferences(visible, collection, resolver) : visible;
|
|
4072
|
+
return resolved.map((entry) => ({ entry, collection }));
|
|
3676
4073
|
}));
|
|
3677
4074
|
if (isBuildMode() && skippedFiles.length > 0) {
|
|
3678
4075
|
const lines = skippedFiles.map(({ filename, collectionPath }) => ` - ${collectionPath}/${filename}`);
|
|
@@ -3686,8 +4083,7 @@ Expected {type}.{slug}.{id}.{ext} with a known entry type (a name declared in th
|
|
|
3686
4083
|
for (const { entry, collection } of results) {
|
|
3687
4084
|
const pathWithoutRoot = entry.logicalPath.startsWith(contentPrefix) ? entry.logicalPath.slice(contentPrefix.length) : entry.logicalPath;
|
|
3688
4085
|
const pathSegments = pathWithoutRoot.split("/").filter(Boolean);
|
|
3689
|
-
const
|
|
3690
|
-
const urlPath = urlSegments.length > 0 ? `/${urlSegments.join("/")}`.toLowerCase() : "/";
|
|
4086
|
+
const urlPath = computeEntryUrl(entry.collectionPath, entry.slug, contentRootName);
|
|
3691
4087
|
const raw = entry.data;
|
|
3692
4088
|
const meta = {
|
|
3693
4089
|
entryPath: entry.logicalPath,
|
|
@@ -3732,7 +4128,7 @@ function isValidCropRect(x, y, w, h) {
|
|
|
3732
4128
|
return false;
|
|
3733
4129
|
return true;
|
|
3734
4130
|
}
|
|
3735
|
-
function
|
|
4131
|
+
function isPlainRecord2(value) {
|
|
3736
4132
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3737
4133
|
}
|
|
3738
4134
|
function resolveBlockItem(blockField, item) {
|
|
@@ -3742,17 +4138,17 @@ function resolveBlockItem(blockField, item) {
|
|
|
3742
4138
|
const template = blockField.templates?.find((t) => t.name === templateName);
|
|
3743
4139
|
if (!template?.fields)
|
|
3744
4140
|
return void 0;
|
|
3745
|
-
const data =
|
|
4141
|
+
const data = isPlainRecord2(item.value) ? item.value : item;
|
|
3746
4142
|
return { fields: template.fields, data };
|
|
3747
4143
|
}
|
|
3748
|
-
function
|
|
4144
|
+
function isPlainRecord3(value) {
|
|
3749
4145
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3750
4146
|
}
|
|
3751
4147
|
function isPositiveInt(value) {
|
|
3752
4148
|
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
3753
4149
|
}
|
|
3754
4150
|
function isValidImageCropValue(value) {
|
|
3755
|
-
if (!
|
|
4151
|
+
if (!isPlainRecord3(value))
|
|
3756
4152
|
return false;
|
|
3757
4153
|
const { x, y, w, h } = value;
|
|
3758
4154
|
if (typeof x !== "number" || typeof y !== "number" || typeof w !== "number" || typeof h !== "number") {
|
|
@@ -3760,78 +4156,78 @@ function isValidImageCropValue(value) {
|
|
|
3760
4156
|
}
|
|
3761
4157
|
return isValidCropRect(x, y, w, h);
|
|
3762
4158
|
}
|
|
3763
|
-
function validateImageValue(field, value,
|
|
3764
|
-
if (!
|
|
3765
|
-
return [{ fieldPath:
|
|
4159
|
+
function validateImageValue(field, value, path212) {
|
|
4160
|
+
if (!isPlainRecord3(value)) {
|
|
4161
|
+
return [{ fieldPath: path212, message: "Expected an image object with { src, alt }" }];
|
|
3766
4162
|
}
|
|
3767
4163
|
const errors = [];
|
|
3768
4164
|
if (typeof value.src !== "string" || value.src.trim() === "") {
|
|
3769
|
-
errors.push({ fieldPath: `${
|
|
4165
|
+
errors.push({ fieldPath: `${path212}.src`, message: "Image src is required" });
|
|
3770
4166
|
}
|
|
3771
4167
|
if (typeof value.alt !== "string") {
|
|
3772
|
-
errors.push({ fieldPath: `${
|
|
4168
|
+
errors.push({ fieldPath: `${path212}.alt`, message: "Image alt text is required" });
|
|
3773
4169
|
} else if (value.alt.trim() === "" && field.altOptional !== true) {
|
|
3774
|
-
errors.push({ fieldPath: `${
|
|
4170
|
+
errors.push({ fieldPath: `${path212}.alt`, message: "Image alt text is required" });
|
|
3775
4171
|
}
|
|
3776
4172
|
if (value.width !== void 0 && !isPositiveInt(value.width)) {
|
|
3777
|
-
errors.push({ fieldPath: `${
|
|
4173
|
+
errors.push({ fieldPath: `${path212}.width`, message: "Image width must be a positive integer" });
|
|
3778
4174
|
}
|
|
3779
4175
|
if (value.height !== void 0 && !isPositiveInt(value.height)) {
|
|
3780
4176
|
errors.push({
|
|
3781
|
-
fieldPath: `${
|
|
4177
|
+
fieldPath: `${path212}.height`,
|
|
3782
4178
|
message: "Image height must be a positive integer"
|
|
3783
4179
|
});
|
|
3784
4180
|
}
|
|
3785
4181
|
if (value.crop !== void 0 && !isValidImageCropValue(value.crop)) {
|
|
3786
|
-
errors.push({ fieldPath: `${
|
|
4182
|
+
errors.push({ fieldPath: `${path212}.crop`, message: "Invalid image crop rect" });
|
|
3787
4183
|
}
|
|
3788
4184
|
return errors;
|
|
3789
4185
|
}
|
|
3790
4186
|
function referenceValueId(value) {
|
|
3791
4187
|
if (typeof value === "string")
|
|
3792
4188
|
return value;
|
|
3793
|
-
if (
|
|
4189
|
+
if (isPlainRecord3(value) && typeof value.id === "string")
|
|
3794
4190
|
return value.id;
|
|
3795
4191
|
return void 0;
|
|
3796
4192
|
}
|
|
3797
|
-
function validateScalar(field, value,
|
|
4193
|
+
function validateScalar(field, value, path212) {
|
|
3798
4194
|
switch (field.type) {
|
|
3799
4195
|
case "number":
|
|
3800
4196
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
3801
|
-
return [{ fieldPath:
|
|
4197
|
+
return [{ fieldPath: path212, message: "Expected a number" }];
|
|
3802
4198
|
}
|
|
3803
4199
|
return [];
|
|
3804
4200
|
case "boolean":
|
|
3805
4201
|
if (typeof value !== "boolean") {
|
|
3806
|
-
return [{ fieldPath:
|
|
4202
|
+
return [{ fieldPath: path212, message: "Expected true or false" }];
|
|
3807
4203
|
}
|
|
3808
4204
|
return [];
|
|
3809
4205
|
case "datetime":
|
|
3810
4206
|
if (typeof value !== "string" || value !== "" && Number.isNaN(Date.parse(value))) {
|
|
3811
|
-
return [{ fieldPath:
|
|
4207
|
+
return [{ fieldPath: path212, message: "Expected a valid date/time string" }];
|
|
3812
4208
|
}
|
|
3813
4209
|
return [];
|
|
3814
4210
|
case "select": {
|
|
3815
4211
|
if (typeof value !== "string") {
|
|
3816
|
-
return [{ fieldPath:
|
|
4212
|
+
return [{ fieldPath: path212, message: "Expected a selection" }];
|
|
3817
4213
|
}
|
|
3818
4214
|
const options = selectOptionValues(field);
|
|
3819
4215
|
if (value !== "" && !options.includes(value)) {
|
|
3820
|
-
return [{ fieldPath:
|
|
4216
|
+
return [{ fieldPath: path212, message: `Must be one of: ${options.join(", ")}` }];
|
|
3821
4217
|
}
|
|
3822
4218
|
return [];
|
|
3823
4219
|
}
|
|
3824
4220
|
case "reference":
|
|
3825
4221
|
if (referenceValueId(value) === void 0) {
|
|
3826
|
-
return [{ fieldPath:
|
|
4222
|
+
return [{ fieldPath: path212, message: "Expected a reference id" }];
|
|
3827
4223
|
}
|
|
3828
4224
|
return [];
|
|
3829
4225
|
case "image":
|
|
3830
|
-
return validateImageValue(field, value,
|
|
4226
|
+
return validateImageValue(field, value, path212);
|
|
3831
4227
|
default:
|
|
3832
4228
|
if (STRING_FIELD_TYPES.has(field.type)) {
|
|
3833
4229
|
if (typeof value !== "string") {
|
|
3834
|
-
return [{ fieldPath:
|
|
4230
|
+
return [{ fieldPath: path212, message: "Expected text" }];
|
|
3835
4231
|
}
|
|
3836
4232
|
}
|
|
3837
4233
|
return [];
|
|
@@ -3854,12 +4250,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
|
|
|
3854
4250
|
errors.push(...validateEntryData(field.fields, data, pathPrefix));
|
|
3855
4251
|
continue;
|
|
3856
4252
|
}
|
|
3857
|
-
const
|
|
4253
|
+
const path212 = pathPrefix ? `${pathPrefix}.${field.name}` : field.name;
|
|
3858
4254
|
const value = data[field.name];
|
|
3859
4255
|
const isRequired = "required" in field && field.required === true;
|
|
3860
4256
|
if (isRequired && isEmptyForRequired(field, value)) {
|
|
3861
4257
|
const message = Array.isArray(value) ? "At least one item is required" : "This field is required";
|
|
3862
|
-
errors.push({ fieldPath:
|
|
4258
|
+
errors.push({ fieldPath: path212, message });
|
|
3863
4259
|
continue;
|
|
3864
4260
|
}
|
|
3865
4261
|
if (value === void 0 || value === null)
|
|
@@ -3867,12 +4263,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
|
|
|
3867
4263
|
if (field.type === "block") {
|
|
3868
4264
|
const blockField = field;
|
|
3869
4265
|
if (!Array.isArray(value)) {
|
|
3870
|
-
errors.push({ fieldPath:
|
|
4266
|
+
errors.push({ fieldPath: path212, message: "Expected a list of blocks" });
|
|
3871
4267
|
continue;
|
|
3872
4268
|
}
|
|
3873
4269
|
value.forEach((item, index) => {
|
|
3874
|
-
const itemPath = `${
|
|
3875
|
-
if (!
|
|
4270
|
+
const itemPath = `${path212}[${index}]`;
|
|
4271
|
+
if (!isPlainRecord3(item)) {
|
|
3876
4272
|
errors.push({ fieldPath: itemPath, message: "Expected a block object" });
|
|
3877
4273
|
return;
|
|
3878
4274
|
}
|
|
@@ -3893,12 +4289,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
|
|
|
3893
4289
|
const objectField = field;
|
|
3894
4290
|
if (objectField.list) {
|
|
3895
4291
|
if (!Array.isArray(value)) {
|
|
3896
|
-
errors.push({ fieldPath:
|
|
4292
|
+
errors.push({ fieldPath: path212, message: "Expected a list of items" });
|
|
3897
4293
|
continue;
|
|
3898
4294
|
}
|
|
3899
4295
|
value.forEach((item, index) => {
|
|
3900
|
-
const itemPath = `${
|
|
3901
|
-
if (!
|
|
4296
|
+
const itemPath = `${path212}[${index}]`;
|
|
4297
|
+
if (!isPlainRecord3(item)) {
|
|
3902
4298
|
errors.push({ fieldPath: itemPath, message: "Expected an object" });
|
|
3903
4299
|
return;
|
|
3904
4300
|
}
|
|
@@ -3906,28 +4302,28 @@ function validateEntryData(fields, data, pathPrefix = "") {
|
|
|
3906
4302
|
errors.push(...validateEntryData(objectField.fields, item, itemPath));
|
|
3907
4303
|
}
|
|
3908
4304
|
});
|
|
3909
|
-
} else if (!
|
|
3910
|
-
errors.push({ fieldPath:
|
|
4305
|
+
} else if (!isPlainRecord3(value)) {
|
|
4306
|
+
errors.push({ fieldPath: path212, message: "Expected an object" });
|
|
3911
4307
|
} else if (objectField.fields) {
|
|
3912
|
-
errors.push(...validateEntryData(objectField.fields, value,
|
|
4308
|
+
errors.push(...validateEntryData(objectField.fields, value, path212));
|
|
3913
4309
|
}
|
|
3914
4310
|
continue;
|
|
3915
4311
|
}
|
|
3916
4312
|
if ("list" in field && field.list) {
|
|
3917
4313
|
if (!Array.isArray(value)) {
|
|
3918
|
-
errors.push({ fieldPath:
|
|
4314
|
+
errors.push({ fieldPath: path212, message: "Expected a list of values" });
|
|
3919
4315
|
continue;
|
|
3920
4316
|
}
|
|
3921
4317
|
value.forEach((item, index) => {
|
|
3922
|
-
errors.push(...validateScalar(field, item, `${
|
|
4318
|
+
errors.push(...validateScalar(field, item, `${path212}[${index}]`));
|
|
3923
4319
|
});
|
|
3924
4320
|
continue;
|
|
3925
4321
|
}
|
|
3926
4322
|
if (Array.isArray(value) && KNOWN_FIELD_TYPES.has(field.type)) {
|
|
3927
|
-
errors.push({ fieldPath:
|
|
4323
|
+
errors.push({ fieldPath: path212, message: "Expected a single value, not a list" });
|
|
3928
4324
|
continue;
|
|
3929
4325
|
}
|
|
3930
|
-
errors.push(...validateScalar(field, value,
|
|
4326
|
+
errors.push(...validateScalar(field, value, path212));
|
|
3931
4327
|
}
|
|
3932
4328
|
return errors;
|
|
3933
4329
|
}
|
|
@@ -3971,6 +4367,37 @@ function assertBuildEntriesValid(items, phaseLabel) {
|
|
|
3971
4367
|
${lines.join("\n")}
|
|
3972
4368
|
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
4369
|
}
|
|
4370
|
+
async function readGeneratedRecord(outputDir) {
|
|
4371
|
+
try {
|
|
4372
|
+
const raw = await fs17.readFile(path19.join(outputDir, GENERATED_RECORD_FILENAME), "utf-8");
|
|
4373
|
+
const parsed = JSON.parse(raw);
|
|
4374
|
+
if (typeof parsed !== "object" || parsed === null || !("files" in parsed))
|
|
4375
|
+
return [];
|
|
4376
|
+
const { files } = parsed;
|
|
4377
|
+
if (!Array.isArray(files))
|
|
4378
|
+
return [];
|
|
4379
|
+
return files.filter((entry) => typeof entry === "string");
|
|
4380
|
+
} catch {
|
|
4381
|
+
return [];
|
|
4382
|
+
}
|
|
4383
|
+
}
|
|
4384
|
+
async function writeGeneratedRecord(outputDir, files) {
|
|
4385
|
+
const record = { files: [...files].sort() };
|
|
4386
|
+
await fs17.mkdir(outputDir, { recursive: true });
|
|
4387
|
+
await fs17.writeFile(path19.join(outputDir, GENERATED_RECORD_FILENAME), `${JSON.stringify(record, null, 2)}
|
|
4388
|
+
`, "utf-8");
|
|
4389
|
+
}
|
|
4390
|
+
async function removeEmptyDirsUpward(startDir, stopAt) {
|
|
4391
|
+
let current = startDir;
|
|
4392
|
+
while (current.startsWith(stopAt) && current !== stopAt) {
|
|
4393
|
+
try {
|
|
4394
|
+
await fs17.rmdir(current);
|
|
4395
|
+
} catch {
|
|
4396
|
+
return;
|
|
4397
|
+
}
|
|
4398
|
+
current = path19.dirname(current);
|
|
4399
|
+
}
|
|
4400
|
+
}
|
|
3974
4401
|
async function generateAIContentFiles(options) {
|
|
3975
4402
|
const { config, entrySchemaRegistry, outputDir, aiConfig: aiConfig2, _testFlatSchema } = options;
|
|
3976
4403
|
const contentRootName = config.contentRoot || "content";
|
|
@@ -3993,23 +4420,45 @@ async function generateAIContentFiles(options) {
|
|
|
3993
4420
|
config: aiConfig2,
|
|
3994
4421
|
entryLinkUrl: config.entryLinkUrl
|
|
3995
4422
|
});
|
|
3996
|
-
const absoluteOutputDir =
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
const absolutePath = path18.resolve(path18.join(absoluteOutputDir, filePath));
|
|
4423
|
+
const absoluteOutputDir = path19.resolve(outputDir) + path19.sep;
|
|
4424
|
+
const resolveOutputPath = (filePath) => {
|
|
4425
|
+
const absolutePath = path19.resolve(path19.join(absoluteOutputDir, filePath));
|
|
4000
4426
|
if (!absolutePath.startsWith(absoluteOutputDir)) {
|
|
4001
4427
|
throw new Error(`Path traversal detected in AI content output: ${filePath}`);
|
|
4002
4428
|
}
|
|
4003
|
-
|
|
4004
|
-
|
|
4429
|
+
return absolutePath;
|
|
4430
|
+
};
|
|
4431
|
+
const previousFiles = await readGeneratedRecord(absoluteOutputDir);
|
|
4432
|
+
const currentFiles = [...result.files.keys()];
|
|
4433
|
+
await writeGeneratedRecord(absoluteOutputDir, [.../* @__PURE__ */ new Set([...previousFiles, ...currentFiles])]);
|
|
4434
|
+
let fileCount = 0;
|
|
4435
|
+
for (const [filePath, content] of result.files) {
|
|
4436
|
+
const absolutePath = resolveOutputPath(filePath);
|
|
4437
|
+
await fs17.mkdir(path19.dirname(absolutePath), { recursive: true });
|
|
4438
|
+
await fs17.writeFile(absolutePath, content, "utf-8");
|
|
4005
4439
|
fileCount++;
|
|
4006
4440
|
}
|
|
4007
|
-
|
|
4441
|
+
const currentSet = new Set(currentFiles);
|
|
4442
|
+
const stale = previousFiles.filter((filePath) => !currentSet.has(filePath));
|
|
4443
|
+
let removedCount = 0;
|
|
4444
|
+
for (const filePath of stale) {
|
|
4445
|
+
const absolutePath = resolveOutputPath(filePath);
|
|
4446
|
+
try {
|
|
4447
|
+
await fs17.unlink(absolutePath);
|
|
4448
|
+
removedCount++;
|
|
4449
|
+
} catch (err) {
|
|
4450
|
+
if (!isNodeError3(err) || err.code !== "ENOENT")
|
|
4451
|
+
throw err;
|
|
4452
|
+
}
|
|
4453
|
+
await removeEmptyDirsUpward(path19.dirname(absolutePath), absoluteOutputDir);
|
|
4454
|
+
}
|
|
4455
|
+
await writeGeneratedRecord(absoluteOutputDir, currentFiles);
|
|
4456
|
+
return { fileCount, removedCount, outputDir: absoluteOutputDir };
|
|
4008
4457
|
}
|
|
4009
4458
|
async function generateAIContentCLI(options) {
|
|
4010
4459
|
const { projectDir, outputDir = "public/ai", configPath, appDir = "app" } = options;
|
|
4011
4460
|
console.log("\nCanopyCMS generate-ai-content\n");
|
|
4012
|
-
const canopyConfigPath =
|
|
4461
|
+
const canopyConfigPath = path20.join(projectDir, "canopycms.config.ts");
|
|
4013
4462
|
let canopyConfigModule;
|
|
4014
4463
|
try {
|
|
4015
4464
|
canopyConfigModule = await jiti.import(canopyConfigPath);
|
|
@@ -4020,7 +4469,7 @@ async function generateAIContentCLI(options) {
|
|
|
4020
4469
|
}
|
|
4021
4470
|
const configExport = canopyConfigModule.default ?? canopyConfigModule.config ?? canopyConfigModule;
|
|
4022
4471
|
const serverConfig = typeof configExport === "object" && configExport !== null && "server" in configExport ? configExport.server : configExport;
|
|
4023
|
-
const schemasPath =
|
|
4472
|
+
const schemasPath = path20.join(projectDir, appDir, "schemas.ts");
|
|
4024
4473
|
let entrySchemaRegistry = {};
|
|
4025
4474
|
try {
|
|
4026
4475
|
const schemasModule = await jiti.import(schemasPath);
|
|
@@ -4031,7 +4480,7 @@ async function generateAIContentCLI(options) {
|
|
|
4031
4480
|
let aiConfig2;
|
|
4032
4481
|
if (configPath) {
|
|
4033
4482
|
try {
|
|
4034
|
-
const aiConfigModule = await jiti.import(
|
|
4483
|
+
const aiConfigModule = await jiti.import(path20.resolve(configPath));
|
|
4035
4484
|
aiConfig2 = aiConfigModule.aiContentConfig ?? aiConfigModule.default ?? aiConfigModule.config;
|
|
4036
4485
|
} catch (err) {
|
|
4037
4486
|
console.error(`Could not load AI config from ${configPath}`);
|
|
@@ -4048,7 +4497,7 @@ async function generateAIContentCLI(options) {
|
|
|
4048
4497
|
console.error("Make sure canopycms.config.ts uses defineCanopyConfig().");
|
|
4049
4498
|
process.exit(1);
|
|
4050
4499
|
}
|
|
4051
|
-
const resolvedOutput =
|
|
4500
|
+
const resolvedOutput = path20.resolve(projectDir, outputDir);
|
|
4052
4501
|
console.log(` Output: ${resolvedOutput}`);
|
|
4053
4502
|
console.log(` Mode: ${serverConfig.mode ?? "dev"}`);
|
|
4054
4503
|
const result = await generateAIContentFiles({
|
|
@@ -4059,10 +4508,13 @@ async function generateAIContentCLI(options) {
|
|
|
4059
4508
|
});
|
|
4060
4509
|
console.log(`
|
|
4061
4510
|
Generated ${result.fileCount} files`);
|
|
4511
|
+
if (result.removedCount > 0) {
|
|
4512
|
+
console.log(` Removed ${result.removedCount} stale files from the previous run`);
|
|
4513
|
+
}
|
|
4062
4514
|
console.log(` Output: ${result.outputDir}
|
|
4063
4515
|
`);
|
|
4064
4516
|
}
|
|
4065
|
-
var __defProp3, __getOwnPropNames3, __esm3, __export3,
|
|
4517
|
+
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
4518
|
var init_generate_ai_content = __esm({
|
|
4067
4519
|
"dist/cli/generate-ai-content.js"() {
|
|
4068
4520
|
"use strict";
|
|
@@ -4075,17 +4527,17 @@ var init_generate_ai_content = __esm({
|
|
|
4075
4527
|
for (var name in all)
|
|
4076
4528
|
__defProp3(target, name, { get: all[name], enumerable: true });
|
|
4077
4529
|
};
|
|
4078
|
-
init_normalize2 = __esm3({
|
|
4079
|
-
"dist/paths/normalize.js"() {
|
|
4080
|
-
"use strict";
|
|
4081
|
-
}
|
|
4082
|
-
});
|
|
4083
4530
|
init_logger2 = __esm3({
|
|
4084
4531
|
"dist/utils/logger.js"() {
|
|
4085
4532
|
"use strict";
|
|
4086
4533
|
active2 = console;
|
|
4087
4534
|
}
|
|
4088
4535
|
});
|
|
4536
|
+
init_normalize2 = __esm3({
|
|
4537
|
+
"dist/paths/normalize.js"() {
|
|
4538
|
+
"use strict";
|
|
4539
|
+
}
|
|
4540
|
+
});
|
|
4089
4541
|
init_types3 = __esm3({
|
|
4090
4542
|
"dist/paths/types.js"() {
|
|
4091
4543
|
"use strict";
|
|
@@ -4259,7 +4711,12 @@ var init_generate_ai_content = __esm({
|
|
|
4259
4711
|
collections: z22.array(z22.string().min(1)).min(1).optional(),
|
|
4260
4712
|
entryTypes: z22.array(z22.string().min(1)).min(1).optional(),
|
|
4261
4713
|
displayField: z22.string().min(1).optional(),
|
|
4262
|
-
options: z22.array(referenceOptionSchema2).optional()
|
|
4714
|
+
options: z22.array(referenceOptionSchema2).optional(),
|
|
4715
|
+
// Must be listed here, not just on ReferenceFieldConfig: zod strips unknown keys by
|
|
4716
|
+
// default, so a consumer that adopts this schema's parse output would silently delete a
|
|
4717
|
+
// runtime-consumed flag and the feature would no-op with no error. (`resolvedSchema` is
|
|
4718
|
+
// absent on purpose — it is type-inference-only and stripping it changes no behavior.)
|
|
4719
|
+
includeBody: z22.boolean().optional()
|
|
4263
4720
|
});
|
|
4264
4721
|
fieldHolder2 = [z22.never()];
|
|
4265
4722
|
blockSchema2 = z22.object({
|
|
@@ -4380,6 +4837,9 @@ var init_generate_ai_content = __esm({
|
|
|
4380
4837
|
deployedAsSchema2 = z52.enum(["static", "server"]).default("server");
|
|
4381
4838
|
contentRootSchema2 = relativePathSchema2.default("content");
|
|
4382
4839
|
sourceRootSchema2 = z52.string().min(1).optional();
|
|
4840
|
+
basePathSchema2 = z52.string().transform((value) => value.trim()).refine((value) => value.length > 0, {
|
|
4841
|
+
message: "basePath must not be empty or only whitespace"
|
|
4842
|
+
}).optional();
|
|
4383
4843
|
deploymentNameSchema2 = z52.string().default("prod");
|
|
4384
4844
|
devContentSyncSchema2 = z52.enum(["off", "warn"]).default("warn");
|
|
4385
4845
|
devConfigSchema2 = z52.object({
|
|
@@ -4442,6 +4902,7 @@ var init_generate_ai_content = __esm({
|
|
|
4442
4902
|
deploymentName: deploymentNameSchema2.optional(),
|
|
4443
4903
|
contentRoot: contentRootSchema2.default("content"),
|
|
4444
4904
|
sourceRoot: sourceRootSchema2.optional(),
|
|
4905
|
+
basePath: basePathSchema2,
|
|
4445
4906
|
editor: editorConfigSchema2.optional(),
|
|
4446
4907
|
authPlugin: z52.custom().optional(),
|
|
4447
4908
|
entryLinkUrl: z52.custom().optional(),
|
|
@@ -4611,32 +5072,32 @@ var init_generate_ai_content = __esm({
|
|
|
4611
5072
|
// - shouldCommit(), shouldPush()
|
|
4612
5073
|
// Add client-unsafe methods (use Node.js APIs)
|
|
4613
5074
|
getWorkspaceRoot(_sourceRoot) {
|
|
4614
|
-
return
|
|
5075
|
+
return path9.resolve(process.env.CANOPYCMS_WORKSPACE_ROOT ?? DEFAULT_PROD_WORKSPACE2);
|
|
4615
5076
|
}
|
|
4616
5077
|
getContentRoot(contentRoot, sourceRoot) {
|
|
4617
|
-
return
|
|
5078
|
+
return path9.resolve(sourceRoot ?? process.cwd(), contentRoot);
|
|
4618
5079
|
}
|
|
4619
5080
|
getContentBranchesRoot(sourceRoot) {
|
|
4620
|
-
return
|
|
5081
|
+
return path9.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
|
|
4621
5082
|
}
|
|
4622
5083
|
getContentBranchRoot(branchName, sourceRoot) {
|
|
4623
|
-
return
|
|
5084
|
+
return path9.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
|
|
4624
5085
|
}
|
|
4625
5086
|
getGitExcludePattern() {
|
|
4626
5087
|
return ".canopy-meta/";
|
|
4627
5088
|
}
|
|
4628
5089
|
getPermissionsFilePath(root) {
|
|
4629
|
-
return
|
|
5090
|
+
return path9.join(root, this.getPermissionsFileName());
|
|
4630
5091
|
}
|
|
4631
5092
|
getGroupsFilePath(root) {
|
|
4632
|
-
return
|
|
5093
|
+
return path9.join(root, this.getGroupsFileName());
|
|
4633
5094
|
}
|
|
4634
5095
|
getRemoteUrlConfig() {
|
|
4635
5096
|
return {
|
|
4636
5097
|
shouldAutoInitLocal: false,
|
|
4637
5098
|
defaultRemotePath: "",
|
|
4638
5099
|
envVarName: "CANOPYCMS_REMOTE_URL",
|
|
4639
|
-
autoDetectRemotePath:
|
|
5100
|
+
autoDetectRemotePath: path9.join(this.getWorkspaceRoot(), "remote.git")
|
|
4640
5101
|
};
|
|
4641
5102
|
}
|
|
4642
5103
|
requiresExistingRepo() {
|
|
@@ -4648,7 +5109,7 @@ var init_generate_ai_content = __esm({
|
|
|
4648
5109
|
return `canopycms-settings-${resolveDeploymentName2(config, "prod")}`;
|
|
4649
5110
|
}
|
|
4650
5111
|
getSettingsRoot(sourceRoot) {
|
|
4651
|
-
return
|
|
5112
|
+
return path9.join(this.getWorkspaceRoot(sourceRoot), "settings");
|
|
4652
5113
|
}
|
|
4653
5114
|
usesSeparateSettingsBranch() {
|
|
4654
5115
|
return true;
|
|
@@ -4665,25 +5126,25 @@ var init_generate_ai_content = __esm({
|
|
|
4665
5126
|
DevStrategy2 = class extends DevClientSafeStrategy2 {
|
|
4666
5127
|
// Inherits client-safe methods from DevClientSafeStrategy
|
|
4667
5128
|
getWorkspaceRoot(sourceRoot) {
|
|
4668
|
-
return
|
|
5129
|
+
return path9.resolve(sourceRoot ?? process.cwd(), ".canopy-dev");
|
|
4669
5130
|
}
|
|
4670
5131
|
getContentRoot(contentRoot, sourceRoot) {
|
|
4671
|
-
return
|
|
5132
|
+
return path9.resolve(sourceRoot ?? process.cwd(), contentRoot);
|
|
4672
5133
|
}
|
|
4673
5134
|
getContentBranchesRoot(sourceRoot) {
|
|
4674
|
-
return
|
|
5135
|
+
return path9.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
|
|
4675
5136
|
}
|
|
4676
5137
|
getContentBranchRoot(branchName, sourceRoot) {
|
|
4677
|
-
return
|
|
5138
|
+
return path9.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
|
|
4678
5139
|
}
|
|
4679
5140
|
getGitExcludePattern() {
|
|
4680
5141
|
return ".canopy-meta/";
|
|
4681
5142
|
}
|
|
4682
5143
|
getPermissionsFilePath(root) {
|
|
4683
|
-
return
|
|
5144
|
+
return path9.join(root, this.getPermissionsFileName());
|
|
4684
5145
|
}
|
|
4685
5146
|
getGroupsFilePath(root) {
|
|
4686
|
-
return
|
|
5147
|
+
return path9.join(root, this.getGroupsFileName());
|
|
4687
5148
|
}
|
|
4688
5149
|
getRemoteUrlConfig() {
|
|
4689
5150
|
return {
|
|
@@ -4701,7 +5162,7 @@ var init_generate_ai_content = __esm({
|
|
|
4701
5162
|
return `canopycms-settings-${resolveDeploymentName2(config, "local")}`;
|
|
4702
5163
|
}
|
|
4703
5164
|
getSettingsRoot(sourceRoot) {
|
|
4704
|
-
return
|
|
5165
|
+
return path9.join(this.getWorkspaceRoot(sourceRoot), "settings");
|
|
4705
5166
|
}
|
|
4706
5167
|
usesSeparateSettingsBranch() {
|
|
4707
5168
|
return true;
|
|
@@ -4736,7 +5197,12 @@ var init_generate_ai_content = __esm({
|
|
|
4736
5197
|
init_mode_env2();
|
|
4737
5198
|
}
|
|
4738
5199
|
});
|
|
5200
|
+
BLOCK_DISCRIMINATOR_KEYS = ["template", "_type"];
|
|
5201
|
+
BLOCK_STRUCTURAL_KEYS = new Set(BLOCK_DISCRIMINATOR_KEYS);
|
|
5202
|
+
EVIDENCE_MAX_DEPTH = 6;
|
|
4739
5203
|
locks = /* @__PURE__ */ new Map();
|
|
5204
|
+
init_logger2();
|
|
5205
|
+
init_logger2();
|
|
4740
5206
|
META_DIR = ".canopy-meta";
|
|
4741
5207
|
CONTENT_WRITE_LOCK_NAME = "content-write.lock";
|
|
4742
5208
|
DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS = 2e3;
|
|
@@ -4749,6 +5215,67 @@ var init_generate_ai_content = __esm({
|
|
|
4749
5215
|
sleep = (ms) => new Promise((resolve2) => {
|
|
4750
5216
|
setTimeout(resolve2, ms);
|
|
4751
5217
|
});
|
|
5218
|
+
DEFAULT_SEO_FIELD_NAMES = {
|
|
5219
|
+
title: "metaTitle",
|
|
5220
|
+
description: "metaDescription",
|
|
5221
|
+
ogImage: "ogImage",
|
|
5222
|
+
ogType: "ogType",
|
|
5223
|
+
canonical: "canonical",
|
|
5224
|
+
noindex: "noindex",
|
|
5225
|
+
twitterCard: "twitterCard"
|
|
5226
|
+
};
|
|
5227
|
+
SEO_GROUP_FIELDS = [
|
|
5228
|
+
{
|
|
5229
|
+
name: DEFAULT_SEO_FIELD_NAMES.title,
|
|
5230
|
+
type: "string",
|
|
5231
|
+
label: "Meta Title",
|
|
5232
|
+
description: "Overrides the page title in search results and social cards.",
|
|
5233
|
+
required: false
|
|
5234
|
+
},
|
|
5235
|
+
{
|
|
5236
|
+
name: DEFAULT_SEO_FIELD_NAMES.description,
|
|
5237
|
+
type: "string",
|
|
5238
|
+
label: "Meta Description",
|
|
5239
|
+
description: "Summary shown under the title in search results.",
|
|
5240
|
+
required: false
|
|
5241
|
+
},
|
|
5242
|
+
{
|
|
5243
|
+
name: DEFAULT_SEO_FIELD_NAMES.ogImage,
|
|
5244
|
+
type: "string",
|
|
5245
|
+
label: "Social Image URL",
|
|
5246
|
+
description: "Image for social cards. Site-relative or absolute.",
|
|
5247
|
+
required: false
|
|
5248
|
+
},
|
|
5249
|
+
{
|
|
5250
|
+
name: DEFAULT_SEO_FIELD_NAMES.ogType,
|
|
5251
|
+
type: "select",
|
|
5252
|
+
label: "OpenGraph Type",
|
|
5253
|
+
options: ["website", "article", "profile"],
|
|
5254
|
+
required: false
|
|
5255
|
+
},
|
|
5256
|
+
{
|
|
5257
|
+
name: DEFAULT_SEO_FIELD_NAMES.canonical,
|
|
5258
|
+
type: "string",
|
|
5259
|
+
label: "Canonical URL",
|
|
5260
|
+
description: "Set only to point at a different canonical copy of this page.",
|
|
5261
|
+
required: false
|
|
5262
|
+
},
|
|
5263
|
+
{
|
|
5264
|
+
name: DEFAULT_SEO_FIELD_NAMES.noindex,
|
|
5265
|
+
type: "boolean",
|
|
5266
|
+
label: "Hide from search engines",
|
|
5267
|
+
description: "Marks the page noindex AND drops it from the sitemap.",
|
|
5268
|
+
required: false
|
|
5269
|
+
},
|
|
5270
|
+
{
|
|
5271
|
+
name: DEFAULT_SEO_FIELD_NAMES.twitterCard,
|
|
5272
|
+
type: "select",
|
|
5273
|
+
label: "Twitter Card",
|
|
5274
|
+
options: ["summary", "summary_large_image"],
|
|
5275
|
+
required: false
|
|
5276
|
+
}
|
|
5277
|
+
];
|
|
5278
|
+
init_normalize2();
|
|
4752
5279
|
init_normalize2();
|
|
4753
5280
|
BASE58_PATTERN = "[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]";
|
|
4754
5281
|
CONTENT_ID_PATTERN = new RegExp(`^${BASE58_PATTERN}{12}$`);
|
|
@@ -5066,6 +5593,31 @@ var init_generate_ai_content = __esm({
|
|
|
5066
5593
|
this.pathToId.set(newRelativePath, id);
|
|
5067
5594
|
}
|
|
5068
5595
|
};
|
|
5596
|
+
parseTypedFilename = (filename, entryTypes) => {
|
|
5597
|
+
if (filename.startsWith("."))
|
|
5598
|
+
return null;
|
|
5599
|
+
const lastDot = filename.lastIndexOf(".");
|
|
5600
|
+
if (lastDot === -1)
|
|
5601
|
+
return null;
|
|
5602
|
+
const nameWithoutExt = filename.slice(0, lastDot);
|
|
5603
|
+
const parts = nameWithoutExt.split(".");
|
|
5604
|
+
if (parts.length < 3)
|
|
5605
|
+
return null;
|
|
5606
|
+
const potentialType = parts[0];
|
|
5607
|
+
if (entryTypes && !entryTypes.some((e) => e.name === potentialType)) {
|
|
5608
|
+
return null;
|
|
5609
|
+
}
|
|
5610
|
+
const id = parts[parts.length - 1];
|
|
5611
|
+
if (!isValidId(id))
|
|
5612
|
+
return null;
|
|
5613
|
+
const slug = parts.slice(1, -1).join(".").toLowerCase();
|
|
5614
|
+
return {
|
|
5615
|
+
type: potentialType,
|
|
5616
|
+
slug,
|
|
5617
|
+
id
|
|
5618
|
+
};
|
|
5619
|
+
};
|
|
5620
|
+
CONTENT_EXTENSIONS = [".md", ".mdx", ".json", ".yaml"];
|
|
5069
5621
|
registry = /* @__PURE__ */ new Map();
|
|
5070
5622
|
finalization = new FinalizationRegistry(({ rootKey, ref }) => {
|
|
5071
5623
|
const refs = registry.get(rootKey);
|
|
@@ -5303,7 +5855,7 @@ var init_generate_ai_content = __esm({
|
|
|
5303
5855
|
* the project root, regardless of which entrypoint produced the cwd branchRoot.
|
|
5304
5856
|
*/
|
|
5305
5857
|
skipDiskCache(branchRoot) {
|
|
5306
|
-
return isBuildMode() ||
|
|
5858
|
+
return isBuildMode() || path82.resolve(branchRoot) === path82.resolve(process.cwd());
|
|
5307
5859
|
}
|
|
5308
5860
|
/**
|
|
5309
5861
|
* Get schema for a branch (loads from cache or resolves fresh).
|
|
@@ -5329,14 +5881,14 @@ var init_generate_ai_content = __esm({
|
|
|
5329
5881
|
* Load schema from cache or resolve fresh if cache is missing or stale.
|
|
5330
5882
|
*/
|
|
5331
5883
|
async loadFromCacheOrResolve(branchRoot, entrySchemaRegistry, contentRootName) {
|
|
5332
|
-
const contentRoot =
|
|
5884
|
+
const contentRoot = path82.join(branchRoot, contentRootName);
|
|
5333
5885
|
const skipDiskCache = this.skipDiskCache(branchRoot);
|
|
5334
5886
|
if (!skipDiskCache) {
|
|
5335
|
-
const cacheDir =
|
|
5336
|
-
const cachePath =
|
|
5887
|
+
const cacheDir = path82.join(branchRoot, ".canopy-meta");
|
|
5888
|
+
const cachePath = path82.join(cacheDir, "schema-cache.json");
|
|
5337
5889
|
let cacheData = null;
|
|
5338
5890
|
try {
|
|
5339
|
-
const cacheContent = await
|
|
5891
|
+
const cacheContent = await fs72.readFile(cachePath, "utf-8");
|
|
5340
5892
|
cacheData = JSON.parse(cacheContent);
|
|
5341
5893
|
} catch {
|
|
5342
5894
|
cacheData = null;
|
|
@@ -5373,7 +5925,7 @@ var init_generate_ai_content = __esm({
|
|
|
5373
5925
|
*/
|
|
5374
5926
|
async resolveFreshAndPersist(branchRoot, entrySchemaRegistry, contentRootName, options) {
|
|
5375
5927
|
const { skipDiskCache } = options;
|
|
5376
|
-
const contentRoot =
|
|
5928
|
+
const contentRoot = path82.join(branchRoot, contentRootName);
|
|
5377
5929
|
const read = skipDiskCache ? null : await readResourceGeneration(branchRoot, SCHEMA_GENERATION_RESOURCE);
|
|
5378
5930
|
const result = await this.resolveFresh(contentRoot, entrySchemaRegistry);
|
|
5379
5931
|
if (!isValidSchema(result.schema)) {
|
|
@@ -5386,9 +5938,9 @@ var init_generate_ai_content = __esm({
|
|
|
5386
5938
|
}
|
|
5387
5939
|
const flatSchema = flattenSchema(result.schema, contentRootName);
|
|
5388
5940
|
if (!skipDiskCache) {
|
|
5389
|
-
const cacheDir =
|
|
5390
|
-
const cachePath =
|
|
5391
|
-
await
|
|
5941
|
+
const cacheDir = path82.join(branchRoot, ".canopy-meta");
|
|
5942
|
+
const cachePath = path82.join(cacheDir, "schema-cache.json");
|
|
5943
|
+
await fs72.unlink(path82.join(cacheDir, "schema-cache.stale")).catch(() => {
|
|
5392
5944
|
});
|
|
5393
5945
|
if (read && read.ok) {
|
|
5394
5946
|
const newCache = {
|
|
@@ -5398,13 +5950,13 @@ var init_generate_ai_content = __esm({
|
|
|
5398
5950
|
cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5399
5951
|
generation: read.token
|
|
5400
5952
|
};
|
|
5401
|
-
await
|
|
5402
|
-
const tmpPath =
|
|
5403
|
-
await
|
|
5953
|
+
await fs72.mkdir(cacheDir, { recursive: true });
|
|
5954
|
+
const tmpPath = path82.join(cacheDir, `schema-cache.tmp.${Date.now()}.${Math.random()}.json`);
|
|
5955
|
+
await fs72.writeFile(tmpPath, JSON.stringify(newCache, null, 2), "utf-8");
|
|
5404
5956
|
try {
|
|
5405
|
-
await
|
|
5957
|
+
await fs72.rename(tmpPath, cachePath);
|
|
5406
5958
|
} catch (err) {
|
|
5407
|
-
await
|
|
5959
|
+
await fs72.unlink(tmpPath).catch(() => {
|
|
5408
5960
|
});
|
|
5409
5961
|
throw err;
|
|
5410
5962
|
}
|
|
@@ -5514,9 +6066,17 @@ var init_generate_ai_content = __esm({
|
|
|
5514
6066
|
this.paths = sorted;
|
|
5515
6067
|
}
|
|
5516
6068
|
};
|
|
6069
|
+
UrlPathConflictError = class extends ContentConflictError {
|
|
6070
|
+
constructor(message, conflictingPath) {
|
|
6071
|
+
super(message);
|
|
6072
|
+
this.name = "UrlPathConflictError";
|
|
6073
|
+
this.conflictingPath = conflictingPath;
|
|
6074
|
+
}
|
|
6075
|
+
};
|
|
5517
6076
|
DEFAULT_INDEX_FRESHNESS_INTERVAL_MS = 1e3;
|
|
5518
6077
|
FORCED_REFRESH_MIN_INTERVAL_MS = 5e3;
|
|
5519
6078
|
STALE_LOOKUP = Symbol("stale-index-lookup");
|
|
6079
|
+
createReferenceResolveCache = () => /* @__PURE__ */ new Map();
|
|
5520
6080
|
ContentStore = class {
|
|
5521
6081
|
constructor(root, flatSchema, options = {}) {
|
|
5522
6082
|
this.indexGeneration = 0;
|
|
@@ -5525,7 +6085,7 @@ var init_generate_ai_content = __esm({
|
|
|
5525
6085
|
this.lastDiskProbeMs = 0;
|
|
5526
6086
|
this.lastForcedRefreshMs = 0;
|
|
5527
6087
|
this.indexBuild = null;
|
|
5528
|
-
this.root =
|
|
6088
|
+
this.root = path11.resolve(root);
|
|
5529
6089
|
this.contentRootName = options.contentRootName || "content";
|
|
5530
6090
|
this.indexFreshnessIntervalMs = options.indexFreshnessIntervalMs ?? DEFAULT_INDEX_FRESHNESS_INTERVAL_MS;
|
|
5531
6091
|
this.contentWriteLockWaitMs = options.contentWriteLockWaitMs ?? DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS;
|
|
@@ -5673,7 +6233,7 @@ var init_generate_ai_content = __esm({
|
|
|
5673
6233
|
async findEntryPathsById(dir, id) {
|
|
5674
6234
|
let entries;
|
|
5675
6235
|
try {
|
|
5676
|
-
entries = await
|
|
6236
|
+
entries = await fs10.readdir(dir, { withFileTypes: true });
|
|
5677
6237
|
} catch (err) {
|
|
5678
6238
|
if (isNodeError3(err) && err.code === "ENOENT")
|
|
5679
6239
|
return [];
|
|
@@ -5684,7 +6244,7 @@ var init_generate_ai_content = __esm({
|
|
|
5684
6244
|
if (entry.isDirectory())
|
|
5685
6245
|
continue;
|
|
5686
6246
|
if (extractIdFromFilename(entry.name) === id) {
|
|
5687
|
-
matches.push(
|
|
6247
|
+
matches.push(path11.relative(this.root, path11.join(dir, entry.name)));
|
|
5688
6248
|
}
|
|
5689
6249
|
}
|
|
5690
6250
|
return matches.sort();
|
|
@@ -5696,11 +6256,11 @@ var init_generate_ai_content = __esm({
|
|
|
5696
6256
|
getSchemaItems() {
|
|
5697
6257
|
return this.schemaIndex.values();
|
|
5698
6258
|
}
|
|
5699
|
-
assertSchemaItem(
|
|
5700
|
-
const normalized = normalizeFilesystemPath(
|
|
6259
|
+
assertSchemaItem(path212) {
|
|
6260
|
+
const normalized = normalizeFilesystemPath(path212);
|
|
5701
6261
|
const item = this.schemaIndex.get(normalized);
|
|
5702
6262
|
if (!item) {
|
|
5703
|
-
throw new ContentStoreError(`Unknown schema item: ${
|
|
6263
|
+
throw new ContentStoreError(`Unknown schema item: ${path212}`, "NO_SCHEMA_ITEM");
|
|
5704
6264
|
}
|
|
5705
6265
|
return item;
|
|
5706
6266
|
}
|
|
@@ -5767,6 +6327,26 @@ var init_generate_ai_content = __esm({
|
|
|
5767
6327
|
return this.createLockKey(schemaItem, slug);
|
|
5768
6328
|
return prePass.id ? this.idLockKey(prePass.id) : prePass.absolutePath;
|
|
5769
6329
|
}
|
|
6330
|
+
/**
|
|
6331
|
+
* Refuse a create/rename that would give a second entry a `urlPath` another entry already
|
|
6332
|
+
* holds. See url-collision.ts for the two shapes that count, and the legitimate
|
|
6333
|
+
* landing-page-beside-a-collection shape that deliberately does not.
|
|
6334
|
+
*
|
|
6335
|
+
* @param collectionDir Absolute physical directory the entry will live in.
|
|
6336
|
+
* @param slug The entry's slug, as it will be written.
|
|
6337
|
+
*/
|
|
6338
|
+
async assertUrlPathAvailable(collectionDir, slug) {
|
|
6339
|
+
const claimant = await findUrlPathClaimant({
|
|
6340
|
+
collectionDir,
|
|
6341
|
+
slug,
|
|
6342
|
+
contentRoot: path11.resolve(this.root, this.contentRootName)
|
|
6343
|
+
});
|
|
6344
|
+
if (!claimant)
|
|
6345
|
+
return;
|
|
6346
|
+
const relative2 = path11.relative(this.root, claimant.physicalPath);
|
|
6347
|
+
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.`;
|
|
6348
|
+
throw new UrlPathConflictError(message, claimant.physicalPath);
|
|
6349
|
+
}
|
|
5770
6350
|
/**
|
|
5771
6351
|
* Build absolute and relative paths with security validation.
|
|
5772
6352
|
* All entries use the unified filename pattern: {type}.{slug}.{id}.{ext}
|
|
@@ -5783,7 +6363,7 @@ var init_generate_ai_content = __esm({
|
|
|
5783
6363
|
* @param options.entryTypeName - For collections with multiple entry types, specify which one to use. Defaults to the default entry type.
|
|
5784
6364
|
*/
|
|
5785
6365
|
async buildPaths(schemaItem, slug, options = {}) {
|
|
5786
|
-
const rootWithSep = this.root.endsWith(
|
|
6366
|
+
const rootWithSep = this.root.endsWith(path11.sep) ? this.root : `${this.root}${path11.sep}`;
|
|
5787
6367
|
if (schemaItem.type === "entry-type") {
|
|
5788
6368
|
const parentPath = schemaItem.parentPath || "";
|
|
5789
6369
|
const parentCollection = this.schemaIndex.get(parentPath);
|
|
@@ -5816,7 +6396,7 @@ var init_generate_ai_content = __esm({
|
|
|
5816
6396
|
const entryTypeName = entryTypeConfig?.name || "entry";
|
|
5817
6397
|
let collectionRoot = await resolveCollectionPath(this.root, schemaItem.logicalPath);
|
|
5818
6398
|
if (!collectionRoot) {
|
|
5819
|
-
collectionRoot =
|
|
6399
|
+
collectionRoot = path11.resolve(this.root, schemaItem.logicalPath);
|
|
5820
6400
|
}
|
|
5821
6401
|
if (!collectionRoot.startsWith(rootWithSep)) {
|
|
5822
6402
|
throw new ContentStoreError("Path traversal detected", "VALIDATION");
|
|
@@ -5826,7 +6406,7 @@ var init_generate_ai_content = __esm({
|
|
|
5826
6406
|
let existingEntryType;
|
|
5827
6407
|
let foundExisting = false;
|
|
5828
6408
|
if (!id) {
|
|
5829
|
-
const entries = await
|
|
6409
|
+
const entries = await fs10.readdir(collectionRoot, { withFileTypes: true }).catch(() => []);
|
|
5830
6410
|
const existingFile = entries.find((entry) => {
|
|
5831
6411
|
if (entry.isDirectory())
|
|
5832
6412
|
return false;
|
|
@@ -5852,14 +6432,14 @@ var init_generate_ai_content = __esm({
|
|
|
5852
6432
|
}
|
|
5853
6433
|
filename = `${finalEntryTypeName}.${safeSlug}.${id}${ext}`;
|
|
5854
6434
|
}
|
|
5855
|
-
const resolved =
|
|
5856
|
-
const collectionRootWithSep = collectionRoot.endsWith(
|
|
6435
|
+
const resolved = path11.resolve(collectionRoot, filename);
|
|
6436
|
+
const collectionRootWithSep = collectionRoot.endsWith(path11.sep) ? collectionRoot : `${collectionRoot}${path11.sep}`;
|
|
5857
6437
|
if (!resolved.startsWith(collectionRootWithSep)) {
|
|
5858
6438
|
throw new ContentStoreError("Path traversal detected", "VALIDATION");
|
|
5859
6439
|
}
|
|
5860
6440
|
return {
|
|
5861
6441
|
absolutePath: resolved,
|
|
5862
|
-
relativePath:
|
|
6442
|
+
relativePath: path11.relative(this.root, resolved),
|
|
5863
6443
|
id,
|
|
5864
6444
|
entryTypeName: finalEntryTypeName,
|
|
5865
6445
|
existed
|
|
@@ -5895,8 +6475,8 @@ var init_generate_ai_content = __esm({
|
|
|
5895
6475
|
async read(collectionPath, slug = "", options = {}) {
|
|
5896
6476
|
const schemaItem = this.assertSchemaItem(collectionPath);
|
|
5897
6477
|
const { absolutePath, relativePath, entryTypeName: resolvedEntryTypeName } = await this.buildPaths(schemaItem, slug);
|
|
5898
|
-
const stat = await
|
|
5899
|
-
const raw = await
|
|
6478
|
+
const stat = await fs10.stat(absolutePath);
|
|
6479
|
+
const raw = await fs10.readFile(absolutePath, "utf8");
|
|
5900
6480
|
let doc;
|
|
5901
6481
|
let format;
|
|
5902
6482
|
let fields;
|
|
@@ -5935,7 +6515,7 @@ var init_generate_ai_content = __esm({
|
|
|
5935
6515
|
absolutePath
|
|
5936
6516
|
};
|
|
5937
6517
|
} else {
|
|
5938
|
-
const parsed =
|
|
6518
|
+
const parsed = matter2(raw);
|
|
5939
6519
|
doc = {
|
|
5940
6520
|
collection: schemaItem.logicalPath,
|
|
5941
6521
|
collectionName: schemaItem.name,
|
|
@@ -5998,7 +6578,7 @@ var init_generate_ai_content = __esm({
|
|
|
5998
6578
|
const indexedPath = guardIndex.findById(id)?.relativePath ?? null;
|
|
5999
6579
|
if (indexedPath && indexedPath !== relativePath) {
|
|
6000
6580
|
const quarantined = guardIndex.getDuplicateFor(id);
|
|
6001
|
-
const bothOnDisk = await filePathExists3(absolutePath) && await filePathExists3(
|
|
6581
|
+
const bothOnDisk = await filePathExists3(absolutePath) && await filePathExists3(path11.join(this.root, indexedPath));
|
|
6002
6582
|
if (quarantined || bothOnDisk) {
|
|
6003
6583
|
throw new DuplicateContentIdError(id, [
|
|
6004
6584
|
indexedPath,
|
|
@@ -6009,10 +6589,18 @@ var init_generate_ai_content = __esm({
|
|
|
6009
6589
|
}
|
|
6010
6590
|
}
|
|
6011
6591
|
}
|
|
6012
|
-
await
|
|
6592
|
+
if (!await filePathExists3(absolutePath)) {
|
|
6593
|
+
const chosenSlug = extractSlugFromFilename(path11.basename(absolutePath));
|
|
6594
|
+
const routable = parseSlug(chosenSlug);
|
|
6595
|
+
if (!routable.ok) {
|
|
6596
|
+
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");
|
|
6597
|
+
}
|
|
6598
|
+
await this.assertUrlPathAvailable(path11.dirname(absolutePath), chosenSlug);
|
|
6599
|
+
}
|
|
6600
|
+
await fs10.mkdir(path11.dirname(absolutePath), { recursive: true });
|
|
6013
6601
|
if (input.expectedVersion !== void 0) {
|
|
6014
6602
|
try {
|
|
6015
|
-
const existing = await
|
|
6603
|
+
const existing = await fs10.stat(absolutePath);
|
|
6016
6604
|
if (input.expectedVersion === null) {
|
|
6017
6605
|
throw new ContentConflictError("An entry with this slug already exists");
|
|
6018
6606
|
}
|
|
@@ -6029,7 +6617,7 @@ var init_generate_ai_content = __esm({
|
|
|
6029
6617
|
}
|
|
6030
6618
|
}
|
|
6031
6619
|
if (existingId && !await filePathExists3(absolutePath)) {
|
|
6032
|
-
const actualRelPaths = await this.findEntryPathsById(
|
|
6620
|
+
const actualRelPaths = await this.findEntryPathsById(path11.dirname(absolutePath), existingId);
|
|
6033
6621
|
if (actualRelPaths.length > 1) {
|
|
6034
6622
|
throw new DuplicateContentIdError(existingId, actualRelPaths);
|
|
6035
6623
|
}
|
|
@@ -6039,14 +6627,15 @@ var init_generate_ai_content = __esm({
|
|
|
6039
6627
|
throw new ContentConflictError();
|
|
6040
6628
|
}
|
|
6041
6629
|
}
|
|
6630
|
+
const existingRaw = input.format === "json" ? void 0 : await readFileIfExists(absolutePath);
|
|
6042
6631
|
let content;
|
|
6043
6632
|
if (input.format === "json") {
|
|
6044
6633
|
content = `${JSON.stringify(input.data ?? {}, null, 2)}
|
|
6045
6634
|
`;
|
|
6046
6635
|
} else if (input.format === "yaml") {
|
|
6047
|
-
content =
|
|
6636
|
+
content = serializeYaml(input.data ?? {}, existingRaw);
|
|
6048
6637
|
} else {
|
|
6049
|
-
content =
|
|
6638
|
+
content = serializeFrontmatter(input.body, input.data ?? {}, existingRaw);
|
|
6050
6639
|
}
|
|
6051
6640
|
await atomicWriteFile2(absolutePath, content);
|
|
6052
6641
|
const liveIndex = this._idIndex;
|
|
@@ -6055,7 +6644,7 @@ var init_generate_ai_content = __esm({
|
|
|
6055
6644
|
const existing = liveIndex.findById(id);
|
|
6056
6645
|
if (existing) {
|
|
6057
6646
|
if (existing.relativePath !== relativePath) {
|
|
6058
|
-
staleOldAbsPath =
|
|
6647
|
+
staleOldAbsPath = path11.join(this.root, existing.relativePath);
|
|
6059
6648
|
liveIndex.updatePath(existing.id, relativePath);
|
|
6060
6649
|
}
|
|
6061
6650
|
} else {
|
|
@@ -6068,13 +6657,13 @@ var init_generate_ai_content = __esm({
|
|
|
6068
6657
|
}
|
|
6069
6658
|
}
|
|
6070
6659
|
if (staleOldAbsPath) {
|
|
6071
|
-
await
|
|
6660
|
+
await fs10.unlink(staleOldAbsPath).catch((err) => {
|
|
6072
6661
|
if (!isNodeError3(err) || err.code !== "ENOENT")
|
|
6073
6662
|
throw err;
|
|
6074
6663
|
});
|
|
6075
6664
|
}
|
|
6076
6665
|
await this.recordOwnMutation(liveIndex);
|
|
6077
|
-
const afterStat = await
|
|
6666
|
+
const afterStat = await fs10.stat(absolutePath);
|
|
6078
6667
|
const base = {
|
|
6079
6668
|
collection: schemaItem.logicalPath,
|
|
6080
6669
|
collectionName: schemaItem.name,
|
|
@@ -6152,7 +6741,7 @@ var init_generate_ai_content = __esm({
|
|
|
6152
6741
|
const schemaItem = this.assertSchemaItem(collectionPath);
|
|
6153
6742
|
const { absolutePath } = await this.buildPaths(schemaItem, slug);
|
|
6154
6743
|
try {
|
|
6155
|
-
await
|
|
6744
|
+
await fs10.access(absolutePath);
|
|
6156
6745
|
return true;
|
|
6157
6746
|
} catch (err) {
|
|
6158
6747
|
if (isNodeError3(err) && err.code === "ENOENT")
|
|
@@ -6191,7 +6780,7 @@ var init_generate_ai_content = __esm({
|
|
|
6191
6780
|
const collectionRoot = await resolveCollectionPath(this.root, collectionPath);
|
|
6192
6781
|
if (!collectionRoot)
|
|
6193
6782
|
return 0;
|
|
6194
|
-
const entries = await
|
|
6783
|
+
const entries = await fs10.readdir(collectionRoot, { withFileTypes: true }).catch(() => []);
|
|
6195
6784
|
return entries.filter((entry) => !entry.isDirectory() && extractEntryTypeFromFilename(entry.name) === entryTypeName).length;
|
|
6196
6785
|
}
|
|
6197
6786
|
/**
|
|
@@ -6215,7 +6804,7 @@ var init_generate_ai_content = __esm({
|
|
|
6215
6804
|
const collection = this.assertCollection(collectionPath);
|
|
6216
6805
|
const prePass = await this.buildPaths(collection, slug);
|
|
6217
6806
|
if (!prePass.existed) {
|
|
6218
|
-
await
|
|
6807
|
+
await fs10.unlink(prePass.absolutePath);
|
|
6219
6808
|
return;
|
|
6220
6809
|
}
|
|
6221
6810
|
let lockKey = this.entryLockKey(collection, slug, prePass);
|
|
@@ -6231,7 +6820,7 @@ var init_generate_ai_content = __esm({
|
|
|
6231
6820
|
return RETRY_KEY;
|
|
6232
6821
|
}
|
|
6233
6822
|
const { absolutePath, relativePath } = inLock;
|
|
6234
|
-
await
|
|
6823
|
+
await fs10.unlink(absolutePath);
|
|
6235
6824
|
const liveIndex = this._idIndex;
|
|
6236
6825
|
const id = liveIndex.findByPath(relativePath);
|
|
6237
6826
|
if (id) {
|
|
@@ -6267,6 +6856,10 @@ var init_generate_ai_content = __esm({
|
|
|
6267
6856
|
if (currentSlug === safeNewSlug) {
|
|
6268
6857
|
return { newPath: `${collectionPath}/${currentSlug}` };
|
|
6269
6858
|
}
|
|
6859
|
+
const routable = parseSlug(safeNewSlug);
|
|
6860
|
+
if (!routable.ok) {
|
|
6861
|
+
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");
|
|
6862
|
+
}
|
|
6270
6863
|
const prePass = await this.buildPaths(collection, currentSlug);
|
|
6271
6864
|
if (!prePass.existed) {
|
|
6272
6865
|
throw new ContentStoreError(`Entry not found: ${currentSlug}`, "NOT_FOUND");
|
|
@@ -6293,7 +6886,7 @@ var init_generate_ai_content = __esm({
|
|
|
6293
6886
|
}
|
|
6294
6887
|
destLockKey = currentDestKey;
|
|
6295
6888
|
const { absolutePath: currentPath, relativePath: currentRelPath } = inLock;
|
|
6296
|
-
const currentFilename =
|
|
6889
|
+
const currentFilename = path11.basename(currentPath);
|
|
6297
6890
|
const parts = currentFilename.split(".");
|
|
6298
6891
|
if (parts.length < 4) {
|
|
6299
6892
|
throw new ContentStoreError(`Invalid entry filename format: ${currentFilename}`, "VALIDATION");
|
|
@@ -6302,10 +6895,10 @@ var init_generate_ai_content = __esm({
|
|
|
6302
6895
|
const contentId = parts[parts.length - 2];
|
|
6303
6896
|
const ext = `.${parts[parts.length - 1]}`;
|
|
6304
6897
|
const newFilename = `${entryTypeName}.${safeNewSlug}.${contentId}${ext}`;
|
|
6305
|
-
const parentDir =
|
|
6306
|
-
const newPath =
|
|
6898
|
+
const parentDir = path11.dirname(currentPath);
|
|
6899
|
+
const newPath = path11.join(parentDir, newFilename);
|
|
6307
6900
|
try {
|
|
6308
|
-
const entries = await
|
|
6901
|
+
const entries = await fs10.readdir(parentDir, { withFileTypes: true });
|
|
6309
6902
|
for (const entry of entries) {
|
|
6310
6903
|
if (entry.isDirectory())
|
|
6311
6904
|
continue;
|
|
@@ -6318,16 +6911,17 @@ var init_generate_ai_content = __esm({
|
|
|
6318
6911
|
if (err instanceof ContentStoreError)
|
|
6319
6912
|
throw err;
|
|
6320
6913
|
}
|
|
6914
|
+
await this.assertUrlPathAvailable(parentDir, safeNewSlug);
|
|
6321
6915
|
try {
|
|
6322
|
-
await
|
|
6916
|
+
await fs10.link(currentPath, newPath);
|
|
6323
6917
|
} catch (err) {
|
|
6324
6918
|
if (isNodeError3(err) && err.code === "EEXIST") {
|
|
6325
6919
|
throw new ContentStoreError(`Entry with slug "${safeNewSlug}" already exists in collection "${collectionPath}"`, "VALIDATION");
|
|
6326
6920
|
}
|
|
6327
6921
|
throw err;
|
|
6328
6922
|
}
|
|
6329
|
-
await
|
|
6330
|
-
const newRelativePath =
|
|
6923
|
+
await fs10.unlink(currentPath);
|
|
6924
|
+
const newRelativePath = path11.relative(this.root, newPath);
|
|
6331
6925
|
const liveIndex = this._idIndex;
|
|
6332
6926
|
const entryId = liveIndex.findByPath(currentRelPath);
|
|
6333
6927
|
if (entryId) {
|
|
@@ -6399,34 +6993,57 @@ var init_generate_ai_content = __esm({
|
|
|
6399
6993
|
}
|
|
6400
6994
|
return entries;
|
|
6401
6995
|
}
|
|
6996
|
+
/**
|
|
6997
|
+
* Resolve every `reference` field in `data` against `fields`, returning a copy.
|
|
6998
|
+
*
|
|
6999
|
+
* This is what `read()` applies automatically (unless `resolveReferences: false`), exposed
|
|
7000
|
+
* so BATCH surfaces can opt into the same resolution without duplicating the walk: the
|
|
7001
|
+
* listing primitives in content-listing.ts and content-tree.ts read entry files straight
|
|
7002
|
+
* off disk and never touch this store, so before this existed a `reference` field reached
|
|
7003
|
+
* `listEntries()`/`buildContentTree()` callers as a bare id string or `null`.
|
|
7004
|
+
*
|
|
7005
|
+
* Pass one {@link ReferenceResolveCache} across a whole batch so a target referenced by
|
|
7006
|
+
* many entries is read once rather than once per referencing entry. Omit `cache` and the
|
|
7007
|
+
* behavior is exactly what `read()` has always done, unmemoized.
|
|
7008
|
+
*
|
|
7009
|
+
* **Path ACLs are not consulted for the targets.** Resolution goes through this store's
|
|
7010
|
+
* own `read()`, below the per-entry permission check in content-reader.ts — so a resolved
|
|
7011
|
+
* target may be an entry the caller could not `read()` directly. That is pre-existing
|
|
7012
|
+
* `read()` behavior, matched here on purpose so one rule covers both; see the
|
|
7013
|
+
* `resolveReferences` option in content-listing.ts for the note adopters see.
|
|
7014
|
+
*/
|
|
7015
|
+
async resolveReferences(data, fields, cache) {
|
|
7016
|
+
return this.resolveReferencesInData(data, fields, cache);
|
|
7017
|
+
}
|
|
6402
7018
|
/**
|
|
6403
7019
|
* Recursively resolve reference fields in data.
|
|
6404
7020
|
* This traverses objects, arrays, and blocks to find and resolve all reference fields.
|
|
6405
7021
|
*/
|
|
6406
|
-
async resolveReferencesInData(data, fields) {
|
|
7022
|
+
async resolveReferencesInData(data, fields, cache) {
|
|
6407
7023
|
const resolved = { ...data };
|
|
6408
7024
|
const idIndex = await this.idIndex();
|
|
6409
7025
|
for (const field of fields) {
|
|
6410
7026
|
if (field.type === "group") {
|
|
6411
|
-
const groupResolved = await this.resolveReferencesInData(resolved, field.fields);
|
|
7027
|
+
const groupResolved = await this.resolveReferencesInData(resolved, field.fields, cache);
|
|
6412
7028
|
Object.assign(resolved, groupResolved);
|
|
6413
7029
|
continue;
|
|
6414
7030
|
}
|
|
6415
7031
|
const value = data[field.name];
|
|
6416
7032
|
if (field.type === "reference") {
|
|
7033
|
+
const includeBody = field.includeBody === true;
|
|
6417
7034
|
if (typeof value === "string" && value) {
|
|
6418
|
-
resolved[field.name] = await this.resolveSingleReference(value, idIndex);
|
|
7035
|
+
resolved[field.name] = await this.resolveSingleReference(value, idIndex, includeBody, cache);
|
|
6419
7036
|
} 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));
|
|
7037
|
+
resolved[field.name] = await Promise.all(value.map((id) => typeof id === "string" ? this.resolveSingleReference(id, idIndex, includeBody, cache) : null));
|
|
6421
7038
|
}
|
|
6422
7039
|
} else if (field.type === "object" && value) {
|
|
6423
7040
|
const objectField = field;
|
|
6424
7041
|
if (!objectField.fields)
|
|
6425
7042
|
continue;
|
|
6426
7043
|
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));
|
|
7044
|
+
resolved[field.name] = await Promise.all(value.map((item) => typeof item === "object" && item !== null ? this.resolveReferencesInData(item, objectField.fields, cache) : item));
|
|
6428
7045
|
} else if (typeof value === "object") {
|
|
6429
|
-
resolved[field.name] = await this.resolveReferencesInData(value, objectField.fields);
|
|
7046
|
+
resolved[field.name] = await this.resolveReferencesInData(value, objectField.fields, cache);
|
|
6430
7047
|
}
|
|
6431
7048
|
} else if (field.type === "block" && Array.isArray(value)) {
|
|
6432
7049
|
const blockField = field;
|
|
@@ -6439,7 +7056,7 @@ var init_generate_ai_content = __esm({
|
|
|
6439
7056
|
return block;
|
|
6440
7057
|
return {
|
|
6441
7058
|
...b,
|
|
6442
|
-
value: await this.resolveReferencesInData(b.value, template.fields)
|
|
7059
|
+
value: await this.resolveReferencesInData(b.value, template.fields, cache)
|
|
6443
7060
|
};
|
|
6444
7061
|
}));
|
|
6445
7062
|
}
|
|
@@ -6447,7 +7064,56 @@ var init_generate_ai_content = __esm({
|
|
|
6447
7064
|
return resolved;
|
|
6448
7065
|
}
|
|
6449
7066
|
/**
|
|
6450
|
-
* Resolve a single reference ID to full entry data
|
|
7067
|
+
* Resolve a single reference ID to full entry data, memoized when a batch cache is
|
|
7068
|
+
* supplied. Without a cache this is a straight pass-through to the uncached path, so
|
|
7069
|
+
* `read()` behaves exactly as it always has.
|
|
7070
|
+
*
|
|
7071
|
+
* Every occurrence gets its OWN deep copy, even on a cache hit. Without that, the memo
|
|
7072
|
+
* would hand one shared object to all 40 entries referencing the same block — a mutation
|
|
7073
|
+
* in one caller's `extract` (truncating a body for a search index, deleting a field) would
|
|
7074
|
+
* silently rewrite it for every sibling, and both `list: true` elements of `[id, id]` would
|
|
7075
|
+
* be the same instance. The copy is what keeps the cache a pure performance optimization
|
|
7076
|
+
* instead of a semantic change.
|
|
7077
|
+
*
|
|
7078
|
+
* Note the uncached path is NOT the clean baseline it looks like. For a json/yaml target it
|
|
7079
|
+
* genuinely reparses fresh per occurrence, but for md/mdx gray-matter serves `data` from a
|
|
7080
|
+
* process-global content-keyed cache, so `resolveSingleReferenceOnce`'s top-level spread
|
|
7081
|
+
* severs exactly one level and NESTED frontmatter objects alias across occurrences, calls and
|
|
7082
|
+
* requests. That is pre-existing `read()` behavior and out of scope here — deliberately, since
|
|
7083
|
+
* touching it would change `read()` — but it means the cached path is the safer of the two,
|
|
7084
|
+
* not a relaxation of a guarantee the uncached one provides. See
|
|
7085
|
+
* `.claude/future-tasks/graymatter-cache-shared-frontmatter.md`.
|
|
7086
|
+
*
|
|
7087
|
+
* What the copy costs, measured rather than assumed (2000 occurrences of one target, local
|
|
7088
|
+
* disk, so every read hits the page cache — the friendliest possible case for NOT caching):
|
|
7089
|
+
* a snippet-sized target is ~63x cheaper to clone than to re-read-and-parse, while a 265KB
|
|
7090
|
+
* JSON target is ~0.8x, i.e. cloning is marginally SLOWER than reparsing it. So the win is
|
|
7091
|
+
* large in the case this exists for and roughly a wash at the pathological end, never a
|
|
7092
|
+
* blow-up. Two things keep the bad end narrow: an md/mdx target resolves to its FRONTMATTER
|
|
7093
|
+
* only *unless the field sets `includeBody`* (`read()` puts the body on `doc.body`, which
|
|
7094
|
+
* `resolveSingleReferenceOnce` spreads in only for an embedding field), so by default body
|
|
7095
|
+
* size is irrelevant no matter how long the document and only a genuinely huge JSON/YAML
|
|
7096
|
+
* target reaches the wash. **`includeBody: true` is the case that CAN reach it on markdown**:
|
|
7097
|
+
* the body then sits inside the memoized object and is cloned once per referencing entry, so
|
|
7098
|
+
* a long document embedded by many pages pays that repeatedly — the reason `includeBody`
|
|
7099
|
+
* exists as an opt-in per field rather than as resolution's default. And in the deployment this
|
|
7100
|
+
* targets, content lives on EFS/NFS where the syscall the memo removes dominates parse and
|
|
7101
|
+
* clone alike, which the local-disk numbers above understate badly. Correctness is the
|
|
7102
|
+
* reason for the copy regardless; the numbers are here so nobody has to re-derive them
|
|
7103
|
+
* before touching this.
|
|
7104
|
+
*/
|
|
7105
|
+
resolveSingleReference(id, idIndex, includeBody, cache) {
|
|
7106
|
+
if (!cache)
|
|
7107
|
+
return this.resolveSingleReferenceUncached(id, idIndex, includeBody);
|
|
7108
|
+
const key = includeBody ? `${id}:body` : id;
|
|
7109
|
+
let pending = cache.get(key);
|
|
7110
|
+
if (!pending) {
|
|
7111
|
+
pending = this.resolveSingleReferenceUncached(id, idIndex, includeBody);
|
|
7112
|
+
cache.set(key, pending);
|
|
7113
|
+
}
|
|
7114
|
+
return pending.then((resolved) => resolved === null ? null : structuredClone(resolved));
|
|
7115
|
+
}
|
|
7116
|
+
/**
|
|
6451
7117
|
* Returns null if the reference is invalid or missing.
|
|
6452
7118
|
* Includes id, slug, and collection fields for debugging.
|
|
6453
7119
|
*
|
|
@@ -6461,16 +7127,21 @@ var init_generate_ai_content = __esm({
|
|
|
6461
7127
|
* idIndex() dedupes concurrent builds — so a sibling call that wins the
|
|
6462
7128
|
* throttle and rebuilds heals every other miss in the same batch, not just
|
|
6463
7129
|
* the first.
|
|
7130
|
+
*
|
|
7131
|
+
* A {@link ReferenceResolveCache} sits ABOVE this, never inside it, so every
|
|
7132
|
+
* distinct id still runs the full refresh-and-retry above. What a cache changes
|
|
7133
|
+
* is only that repeats of the SAME id in one batch share that one attempt's
|
|
7134
|
+
* outcome instead of each getting an independent throw of the dice.
|
|
6464
7135
|
*/
|
|
6465
|
-
async
|
|
6466
|
-
const first = await this.resolveSingleReferenceOnce(id, idIndex);
|
|
7136
|
+
async resolveSingleReferenceUncached(id, idIndex, includeBody) {
|
|
7137
|
+
const first = await this.resolveSingleReferenceOnce(id, idIndex, includeBody);
|
|
6467
7138
|
if (first !== STALE_LOOKUP)
|
|
6468
7139
|
return first;
|
|
6469
7140
|
await this.refreshIndexForSuspiciousLookup();
|
|
6470
|
-
const second = await this.resolveSingleReferenceOnce(id, await this.idIndex());
|
|
7141
|
+
const second = await this.resolveSingleReferenceOnce(id, await this.idIndex(), includeBody);
|
|
6471
7142
|
return second === STALE_LOOKUP ? null : second;
|
|
6472
7143
|
}
|
|
6473
|
-
async resolveSingleReferenceOnce(id, idIndex) {
|
|
7144
|
+
async resolveSingleReferenceOnce(id, idIndex, includeBody) {
|
|
6474
7145
|
try {
|
|
6475
7146
|
const location = idIndex.findById(id);
|
|
6476
7147
|
if (!location)
|
|
@@ -6481,12 +7152,13 @@ var init_generate_ai_content = __esm({
|
|
|
6481
7152
|
const doc = await this.read(location.collection, location.slug, {
|
|
6482
7153
|
resolveReferences: false
|
|
6483
7154
|
});
|
|
6484
|
-
|
|
7155
|
+
const bodyForEmbed = includeBody && "body" in doc ? { fieldName: doc.bodyFieldName, value: doc.body } : void 0;
|
|
7156
|
+
return buildResolvedReference(doc.data, {
|
|
6485
7157
|
id,
|
|
6486
7158
|
slug: location.slug,
|
|
6487
7159
|
collection: location.collection,
|
|
6488
|
-
|
|
6489
|
-
};
|
|
7160
|
+
urlPath: computeEntryUrl(location.collection, location.slug, this.contentRootName)
|
|
7161
|
+
}, bodyForEmbed);
|
|
6490
7162
|
} catch (error) {
|
|
6491
7163
|
if (isNodeError3(error) && error.code === "ENOENT")
|
|
6492
7164
|
return STALE_LOOKUP;
|
|
@@ -6511,7 +7183,6 @@ var init_generate_ai_content = __esm({
|
|
|
6511
7183
|
"reference",
|
|
6512
7184
|
"image"
|
|
6513
7185
|
]);
|
|
6514
|
-
init_normalize2();
|
|
6515
7186
|
log22 = createDebugLogger2({ prefix: "EntryLinks" });
|
|
6516
7187
|
BASE58_CHAR = "[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]";
|
|
6517
7188
|
ENTRY_LINK_PATTERN = new RegExp(`entry:(${BASE58_CHAR}{12})(#[^\\s)>"']*)?`, "g");
|
|
@@ -6527,10 +7198,10 @@ var init_generate_ai_content = __esm({
|
|
|
6527
7198
|
constructor(root) {
|
|
6528
7199
|
this.regenInFlight = null;
|
|
6529
7200
|
this.lastForcedRefreshMs = 0;
|
|
6530
|
-
this.root =
|
|
6531
|
-
this.registryPath =
|
|
6532
|
-
this.stalePath =
|
|
6533
|
-
this.tempPath =
|
|
7201
|
+
this.root = path13.resolve(root);
|
|
7202
|
+
this.registryPath = path13.join(this.root, REGISTRY_FILE);
|
|
7203
|
+
this.stalePath = path13.join(this.root, REGISTRY_STALE_FILE);
|
|
7204
|
+
this.tempPath = path13.join(this.root, REGISTRY_TEMP_FILE);
|
|
6534
7205
|
}
|
|
6535
7206
|
/**
|
|
6536
7207
|
* Returns all branches. Uses the cached snapshot if its embedded generation
|
|
@@ -6539,7 +7210,7 @@ var init_generate_ai_content = __esm({
|
|
|
6539
7210
|
async list() {
|
|
6540
7211
|
let parsed;
|
|
6541
7212
|
try {
|
|
6542
|
-
const raw = await
|
|
7213
|
+
const raw = await fs12.readFile(this.registryPath, "utf8");
|
|
6543
7214
|
parsed = JSON.parse(raw);
|
|
6544
7215
|
} catch (err) {
|
|
6545
7216
|
if (isNotFoundError3(err)) {
|
|
@@ -6628,7 +7299,7 @@ var init_generate_ai_content = __esm({
|
|
|
6628
7299
|
async performRegenerate() {
|
|
6629
7300
|
const read = await readResourceGeneration(this.root, RESOURCE2);
|
|
6630
7301
|
const branches = await this.scanBranchDirectories();
|
|
6631
|
-
await
|
|
7302
|
+
await fs12.unlink(this.stalePath).catch(() => {
|
|
6632
7303
|
});
|
|
6633
7304
|
if (!read.ok) {
|
|
6634
7305
|
return branches;
|
|
@@ -6639,12 +7310,12 @@ var init_generate_ai_content = __esm({
|
|
|
6639
7310
|
generation: read.token
|
|
6640
7311
|
};
|
|
6641
7312
|
const uniqueTempPath = `${this.tempPath}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
6642
|
-
await
|
|
6643
|
-
await
|
|
7313
|
+
await fs12.mkdir(this.root, { recursive: true });
|
|
7314
|
+
await fs12.writeFile(uniqueTempPath, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
|
|
6644
7315
|
try {
|
|
6645
|
-
await
|
|
7316
|
+
await fs12.rename(uniqueTempPath, this.registryPath);
|
|
6646
7317
|
} catch (err) {
|
|
6647
|
-
await
|
|
7318
|
+
await fs12.unlink(uniqueTempPath).catch(() => {
|
|
6648
7319
|
});
|
|
6649
7320
|
throw err;
|
|
6650
7321
|
}
|
|
@@ -6658,12 +7329,12 @@ var init_generate_ai_content = __esm({
|
|
|
6658
7329
|
async scanBranchDirectories() {
|
|
6659
7330
|
const branches = [];
|
|
6660
7331
|
try {
|
|
6661
|
-
const entries = await
|
|
7332
|
+
const entries = await fs12.readdir(this.root, { withFileTypes: true });
|
|
6662
7333
|
for (const entry of entries) {
|
|
6663
7334
|
if (!entry.isDirectory() || entry.name.startsWith(".")) {
|
|
6664
7335
|
continue;
|
|
6665
7336
|
}
|
|
6666
|
-
const branchRoot =
|
|
7337
|
+
const branchRoot = path13.join(this.root, entry.name);
|
|
6667
7338
|
let meta;
|
|
6668
7339
|
try {
|
|
6669
7340
|
meta = await BranchMetadataFileManager.loadOnly(branchRoot);
|
|
@@ -6714,8 +7385,8 @@ var init_generate_ai_content = __esm({
|
|
|
6714
7385
|
};
|
|
6715
7386
|
BranchMetadataFileManager = class _BranchMetadataFileManager {
|
|
6716
7387
|
constructor(branchRoot, baseRoot, options) {
|
|
6717
|
-
this.branchRoot =
|
|
6718
|
-
this.filePath =
|
|
7388
|
+
this.branchRoot = path15.resolve(branchRoot);
|
|
7389
|
+
this.filePath = path15.join(this.branchRoot, BRANCH_META_DIR, BRANCH_META_FILE);
|
|
6719
7390
|
this.baseRoot = baseRoot;
|
|
6720
7391
|
this.settleMs = options?.settleMs;
|
|
6721
7392
|
}
|
|
@@ -6724,10 +7395,10 @@ var init_generate_ai_content = __esm({
|
|
|
6724
7395
|
* Use this for read-only access (e.g., in registry scanning or loadBranchContext).
|
|
6725
7396
|
*/
|
|
6726
7397
|
static async loadOnly(branchRoot) {
|
|
6727
|
-
const resolvedRoot =
|
|
6728
|
-
const filePath =
|
|
7398
|
+
const resolvedRoot = path15.resolve(branchRoot);
|
|
7399
|
+
const filePath = path15.join(resolvedRoot, BRANCH_META_DIR, BRANCH_META_FILE);
|
|
6729
7400
|
try {
|
|
6730
|
-
const raw = await
|
|
7401
|
+
const raw = await fs14.readFile(filePath, "utf8");
|
|
6731
7402
|
return JSON.parse(raw);
|
|
6732
7403
|
} catch (err) {
|
|
6733
7404
|
if (isNotFoundError3(err)) {
|
|
@@ -6748,7 +7419,7 @@ var init_generate_ai_content = __esm({
|
|
|
6748
7419
|
}
|
|
6749
7420
|
async load() {
|
|
6750
7421
|
try {
|
|
6751
|
-
const raw = await
|
|
7422
|
+
const raw = await fs14.readFile(this.filePath, "utf8");
|
|
6752
7423
|
const parsed = JSON.parse(raw);
|
|
6753
7424
|
const version = parsed.version ?? 0;
|
|
6754
7425
|
return { meta: parsed, version };
|
|
@@ -6810,7 +7481,7 @@ var init_generate_ai_content = __esm({
|
|
|
6810
7481
|
*/
|
|
6811
7482
|
async save(incoming) {
|
|
6812
7483
|
try {
|
|
6813
|
-
await
|
|
7484
|
+
await fs14.stat(this.branchRoot);
|
|
6814
7485
|
} catch (err) {
|
|
6815
7486
|
if (isNotFoundError3(err)) {
|
|
6816
7487
|
throw new BranchMetadataConflictError("Branch no longer exists");
|
|
@@ -6923,12 +7594,12 @@ var init_generate_ai_content = __esm({
|
|
|
6923
7594
|
};
|
|
6924
7595
|
GitManager = class _GitManager {
|
|
6925
7596
|
constructor(options, gitOptions) {
|
|
6926
|
-
this.repoPath =
|
|
7597
|
+
this.repoPath = path16.resolve(options.repoPath);
|
|
6927
7598
|
this.baseBranch = options.baseBranch ?? "main";
|
|
6928
7599
|
this.remote = options.remote ?? "origin";
|
|
6929
7600
|
this.skipIndexMarker = options.skipIndexMarker ?? false;
|
|
6930
7601
|
this.git = simpleGit2({ baseDir: this.repoPath, ...gitOptions });
|
|
6931
|
-
this.git.env(gitChildEnv({ GIT_CEILING_DIRECTORIES:
|
|
7602
|
+
this.git.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(this.repoPath) }));
|
|
6932
7603
|
}
|
|
6933
7604
|
static async cloneRepo(remoteUrl, targetPath, baseBranch = "main") {
|
|
6934
7605
|
log5.debug("git", "Cloning repository", {
|
|
@@ -6970,11 +7641,11 @@ var init_generate_ai_content = __esm({
|
|
|
6970
7641
|
remotePath: options.remotePath,
|
|
6971
7642
|
baseBranch: options.baseBranch
|
|
6972
7643
|
});
|
|
6973
|
-
const remoteParent =
|
|
7644
|
+
const remoteParent = path16.dirname(options.remotePath);
|
|
6974
7645
|
releaseLock = await acquireProvisioningLock(remoteParent, ".remote-init.lock");
|
|
6975
7646
|
let remoteExists = false;
|
|
6976
7647
|
try {
|
|
6977
|
-
const stat = await
|
|
7648
|
+
const stat = await fs15.stat(options.remotePath);
|
|
6978
7649
|
remoteExists = stat.isDirectory();
|
|
6979
7650
|
} catch (err) {
|
|
6980
7651
|
if (!isNotFoundError3(err))
|
|
@@ -7226,7 +7897,7 @@ var init_generate_ai_content = __esm({
|
|
|
7226
7897
|
*/
|
|
7227
7898
|
static async validateGitRepoExists(repoPath) {
|
|
7228
7899
|
try {
|
|
7229
|
-
const stat = await
|
|
7900
|
+
const stat = await fs15.stat(path16.join(repoPath, ".git"));
|
|
7230
7901
|
if (!stat.isDirectory()) {
|
|
7231
7902
|
throw new Error(`Expected git repo at ${repoPath}`);
|
|
7232
7903
|
}
|
|
@@ -7304,7 +7975,7 @@ var init_generate_ai_content = __esm({
|
|
|
7304
7975
|
}
|
|
7305
7976
|
if (config.autoDetectRemotePath) {
|
|
7306
7977
|
try {
|
|
7307
|
-
const stat = await
|
|
7978
|
+
const stat = await fs15.stat(config.autoDetectRemotePath);
|
|
7308
7979
|
if (stat.isDirectory()) {
|
|
7309
7980
|
log5.debug("git", "Auto-detected local remote", {
|
|
7310
7981
|
path: config.autoDetectRemotePath
|
|
@@ -7317,8 +7988,8 @@ var init_generate_ai_content = __esm({
|
|
|
7317
7988
|
if (config.shouldAutoInitLocal) {
|
|
7318
7989
|
const gitRoot = await this.findGitRoot();
|
|
7319
7990
|
const sourceRoot = options.sourceRoot;
|
|
7320
|
-
const sourcePath = sourceRoot ?
|
|
7321
|
-
const localRemotePath =
|
|
7991
|
+
const sourcePath = sourceRoot ? path16.resolve(gitRoot, sourceRoot) : gitRoot;
|
|
7992
|
+
const localRemotePath = path16.join(sourcePath, config.defaultRemotePath);
|
|
7322
7993
|
await this.ensureLocalSimulatedRemote({
|
|
7323
7994
|
remotePath: localRemotePath,
|
|
7324
7995
|
sourcePath: gitRoot,
|
|
@@ -7346,7 +8017,7 @@ var init_generate_ai_content = __esm({
|
|
|
7346
8017
|
static async repoExistsAt(workspacePath) {
|
|
7347
8018
|
try {
|
|
7348
8019
|
const checkGit = simpleGit2({ baseDir: workspacePath });
|
|
7349
|
-
checkGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES:
|
|
8020
|
+
checkGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(workspacePath) }));
|
|
7350
8021
|
await checkGit.raw(["rev-parse", "--git-dir"]);
|
|
7351
8022
|
return true;
|
|
7352
8023
|
} catch {
|
|
@@ -7368,19 +8039,19 @@ var init_generate_ai_content = __esm({
|
|
|
7368
8039
|
const baseBranch = await resolveBaseBranch({
|
|
7369
8040
|
defaultBaseBranch: options.baseBranch,
|
|
7370
8041
|
mode: options.mode,
|
|
7371
|
-
detectFrom: options.sourceRoot ?
|
|
8042
|
+
detectFrom: options.sourceRoot ? path16.resolve(process.cwd(), options.sourceRoot) : process.cwd()
|
|
7372
8043
|
});
|
|
7373
8044
|
const remoteName = options.remoteName ?? "origin";
|
|
7374
8045
|
const repoExists = await _GitManager.repoExistsAt(options.workspacePath);
|
|
7375
8046
|
if (!repoExists) {
|
|
7376
|
-
const gitPath =
|
|
8047
|
+
const gitPath = path16.join(options.workspacePath, ".git");
|
|
7377
8048
|
try {
|
|
7378
|
-
const stat = await
|
|
8049
|
+
const stat = await fs15.stat(gitPath);
|
|
7379
8050
|
if (stat.isDirectory()) {
|
|
7380
8051
|
log5.debug("git", "Removing corrupt .git directory", {
|
|
7381
8052
|
workspacePath: options.workspacePath
|
|
7382
8053
|
});
|
|
7383
|
-
await
|
|
8054
|
+
await fs15.rm(gitPath, { recursive: true });
|
|
7384
8055
|
}
|
|
7385
8056
|
} catch (cleanupErr) {
|
|
7386
8057
|
if (!isNotFoundError3(cleanupErr))
|
|
@@ -7407,7 +8078,7 @@ var init_generate_ai_content = __esm({
|
|
|
7407
8078
|
}
|
|
7408
8079
|
justCloned = true;
|
|
7409
8080
|
const freshGit = simpleGit2({ baseDir: options.workspacePath });
|
|
7410
|
-
freshGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES:
|
|
8081
|
+
freshGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(options.workspacePath) }));
|
|
7411
8082
|
await freshGit.addConfig("canopycms.managed", "true");
|
|
7412
8083
|
await freshGit.addConfig("user.name", options.gitBotAuthorName);
|
|
7413
8084
|
await freshGit.addConfig("user.email", options.gitBotAuthorEmail);
|
|
@@ -7758,9 +8429,9 @@ var init_generate_ai_content = __esm({
|
|
|
7758
8429
|
} catch {
|
|
7759
8430
|
}
|
|
7760
8431
|
for (const [filePath, content] of Object.entries(initialFiles)) {
|
|
7761
|
-
const absolutePath =
|
|
7762
|
-
await
|
|
7763
|
-
await
|
|
8432
|
+
const absolutePath = path16.join(this.repoPath, filePath);
|
|
8433
|
+
await fs15.mkdir(path16.dirname(absolutePath), { recursive: true });
|
|
8434
|
+
await fs15.writeFile(absolutePath, content, "utf-8");
|
|
7764
8435
|
await this.git.add(filePath);
|
|
7765
8436
|
}
|
|
7766
8437
|
await this.git.commit("Initialize settings branch", ["--allow-empty"]);
|
|
@@ -7787,7 +8458,7 @@ var init_generate_ai_content = __esm({
|
|
|
7787
8458
|
branchName: options.branchName,
|
|
7788
8459
|
mode: options.mode
|
|
7789
8460
|
});
|
|
7790
|
-
releaseLock = await acquireProvisioningLock(
|
|
8461
|
+
releaseLock = await acquireProvisioningLock(path17.dirname(options.branchRoot), `.${path17.basename(options.branchRoot)}.init.lock`);
|
|
7791
8462
|
await GitManager.initializeWorkspace({
|
|
7792
8463
|
workspacePath: options.branchRoot,
|
|
7793
8464
|
branchName: options.branchName,
|
|
@@ -7828,7 +8499,7 @@ var init_generate_ai_content = __esm({
|
|
|
7828
8499
|
const baseBranch = await resolveBaseBranch({
|
|
7829
8500
|
defaultBaseBranch: this.config.defaultBaseBranch,
|
|
7830
8501
|
mode,
|
|
7831
|
-
detectFrom: this.config.sourceRoot ?
|
|
8502
|
+
detectFrom: this.config.sourceRoot ? path17.resolve(process.cwd(), this.config.sourceRoot) : void 0
|
|
7832
8503
|
});
|
|
7833
8504
|
await this.ensureGitWorkspace({
|
|
7834
8505
|
branchRoot,
|
|
@@ -7865,15 +8536,15 @@ var init_generate_ai_content = __esm({
|
|
|
7865
8536
|
};
|
|
7866
8537
|
readEntryData = async (filePath, format, bodyFieldName = "body") => {
|
|
7867
8538
|
try {
|
|
7868
|
-
const raw = await
|
|
8539
|
+
const raw = await fs16.readFile(filePath, "utf8");
|
|
7869
8540
|
if (format === "json") {
|
|
7870
8541
|
return asRecord(JSON.parse(raw));
|
|
7871
8542
|
}
|
|
7872
8543
|
if (format === "yaml") {
|
|
7873
8544
|
return asRecord(yamlParse2(raw));
|
|
7874
8545
|
}
|
|
7875
|
-
const parsed =
|
|
7876
|
-
const data = parsed.data ?? {};
|
|
8546
|
+
const parsed = matter3(raw);
|
|
8547
|
+
const data = { ...parsed.data ?? {} };
|
|
7877
8548
|
if (parsed.content) {
|
|
7878
8549
|
data[bodyFieldName] = parsed.content;
|
|
7879
8550
|
}
|
|
@@ -7885,30 +8556,19 @@ var init_generate_ai_content = __esm({
|
|
|
7885
8556
|
return {};
|
|
7886
8557
|
}
|
|
7887
8558
|
};
|
|
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();
|
|
8559
|
+
createReferenceResolver = (branchRoot, flatSchema, contentRootName) => ({
|
|
8560
|
+
store: new ContentStore(branchRoot, flatSchema, { contentRootName }),
|
|
8561
|
+
cache: createReferenceResolveCache()
|
|
8562
|
+
});
|
|
8563
|
+
resolveCollectionItemReferences = async (items, collection, resolver) => Promise.all(items.map(async (item) => {
|
|
8564
|
+
const fields = collection.entries?.find((e) => e.name === item.entryType)?.schema;
|
|
8565
|
+
if (!fields)
|
|
8566
|
+
return item;
|
|
7906
8567
|
return {
|
|
7907
|
-
|
|
7908
|
-
|
|
7909
|
-
id
|
|
8568
|
+
...item,
|
|
8569
|
+
data: await resolver.store.resolveReferences(item.data, fields, resolver.cache)
|
|
7910
8570
|
};
|
|
7911
|
-
};
|
|
8571
|
+
}));
|
|
7912
8572
|
looksLikeMalformedEntry = (filename, entryTypes) => {
|
|
7913
8573
|
if (filename.startsWith(".") || filename.startsWith("_"))
|
|
7914
8574
|
return false;
|
|
@@ -7937,7 +8597,7 @@ var init_generate_ai_content = __esm({
|
|
|
7937
8597
|
normalizePath(root, collectionRoot);
|
|
7938
8598
|
let dirents;
|
|
7939
8599
|
try {
|
|
7940
|
-
dirents = await
|
|
8600
|
+
dirents = await fs16.readdir(collectionRoot, { withFileTypes: true });
|
|
7941
8601
|
} catch (err) {
|
|
7942
8602
|
if (isNotFoundError3(err))
|
|
7943
8603
|
return [];
|
|
@@ -7945,7 +8605,7 @@ var init_generate_ai_content = __esm({
|
|
|
7945
8605
|
}
|
|
7946
8606
|
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
8607
|
const entries = await Promise.all(files.map(async (file) => {
|
|
7948
|
-
const absolutePath =
|
|
8608
|
+
const absolutePath = path18.join(collectionRoot, file.name);
|
|
7949
8609
|
const relativePath = normalizePath(root, absolutePath);
|
|
7950
8610
|
const parsed = parseTypedFilename(file.name, entryTypes);
|
|
7951
8611
|
if (!parsed) {
|
|
@@ -7960,7 +8620,7 @@ var init_generate_ai_content = __esm({
|
|
|
7960
8620
|
const format = entryType?.format || "json";
|
|
7961
8621
|
const bodyField = entryType?.schema ? findBodyFieldName(entryType.schema) : "body";
|
|
7962
8622
|
const [stats, data] = await Promise.all([
|
|
7963
|
-
|
|
8623
|
+
fs16.stat(absolutePath),
|
|
7964
8624
|
readEntryData(absolutePath, format, bodyField)
|
|
7965
8625
|
]);
|
|
7966
8626
|
const item = {
|
|
@@ -7984,22 +8644,23 @@ var init_generate_ai_content = __esm({
|
|
|
7984
8644
|
KNOWN_FIELD_TYPES = new Set(fieldTypes2);
|
|
7985
8645
|
STRING_FIELD_TYPES = /* @__PURE__ */ new Set(["string", "markdown", "mdx", "code"]);
|
|
7986
8646
|
selectOptionValues = (field) => (field.options ?? []).map((opt) => typeof opt === "string" ? opt : opt.value);
|
|
8647
|
+
GENERATED_RECORD_FILENAME = ".canopy-generated.json";
|
|
7987
8648
|
jiti = createJiti2(import.meta.url);
|
|
7988
8649
|
}
|
|
7989
8650
|
});
|
|
7990
8651
|
|
|
7991
8652
|
// dist/utils/atomic-write.js
|
|
7992
|
-
import
|
|
7993
|
-
import
|
|
8653
|
+
import fs18 from "node:fs/promises";
|
|
8654
|
+
import path21 from "node:path";
|
|
7994
8655
|
async function atomicWriteFile3(filePath, content) {
|
|
7995
|
-
const dir =
|
|
7996
|
-
await
|
|
8656
|
+
const dir = path21.dirname(filePath);
|
|
8657
|
+
await fs18.mkdir(dir, { recursive: true });
|
|
7997
8658
|
const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
7998
|
-
await
|
|
8659
|
+
await fs18.writeFile(tempPath, content, typeof content === "string" ? "utf-8" : void 0);
|
|
7999
8660
|
try {
|
|
8000
|
-
await
|
|
8661
|
+
await fs18.rename(tempPath, filePath);
|
|
8001
8662
|
} catch (err) {
|
|
8002
|
-
await
|
|
8663
|
+
await fs18.unlink(tempPath).catch(() => {
|
|
8003
8664
|
});
|
|
8004
8665
|
throw err;
|
|
8005
8666
|
}
|
|
@@ -8119,11 +8780,11 @@ var init_debug2 = __esm({
|
|
|
8119
8780
|
});
|
|
8120
8781
|
|
|
8121
8782
|
// dist/resource-generation.js
|
|
8122
|
-
import
|
|
8123
|
-
import
|
|
8783
|
+
import fs19 from "node:fs/promises";
|
|
8784
|
+
import path23 from "node:path";
|
|
8124
8785
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
8125
8786
|
function resourceGenerationPath2(root, resource) {
|
|
8126
|
-
return
|
|
8787
|
+
return path23.resolve(root, META_DIR3, `${resource}.generation`);
|
|
8127
8788
|
}
|
|
8128
8789
|
async function bumpResourceGeneration2(root, resource, options) {
|
|
8129
8790
|
const token = randomUUID3();
|
|
@@ -8141,7 +8802,7 @@ async function bumpResourceGeneration2(root, resource, options) {
|
|
|
8141
8802
|
}
|
|
8142
8803
|
async function readResourceGeneration2(root, resource) {
|
|
8143
8804
|
try {
|
|
8144
|
-
const token = await
|
|
8805
|
+
const token = await fs19.readFile(resourceGenerationPath2(root, resource), "utf-8");
|
|
8145
8806
|
return { ok: true, token };
|
|
8146
8807
|
} catch (err) {
|
|
8147
8808
|
if (isNodeError(err) && err.code === "ENOENT")
|
|
@@ -8168,10 +8829,10 @@ var init_resource_generation = __esm({
|
|
|
8168
8829
|
});
|
|
8169
8830
|
|
|
8170
8831
|
// dist/content-index-registry.js
|
|
8171
|
-
import
|
|
8832
|
+
import path24 from "node:path";
|
|
8172
8833
|
function invalidateContentIndexesForRoot2(root) {
|
|
8173
|
-
const rootKey =
|
|
8174
|
-
const prefix = rootKey +
|
|
8834
|
+
const rootKey = path24.resolve(root);
|
|
8835
|
+
const prefix = rootKey + path24.sep;
|
|
8175
8836
|
for (const [storeRoot, refs] of registry2) {
|
|
8176
8837
|
if (storeRoot !== rootKey && !storeRoot.startsWith(prefix))
|
|
8177
8838
|
continue;
|
|
@@ -8229,7 +8890,7 @@ var init_normalize3 = __esm({
|
|
|
8229
8890
|
function isValidContentId2(id) {
|
|
8230
8891
|
return CONTENT_ID_PATTERN2.test(id);
|
|
8231
8892
|
}
|
|
8232
|
-
function
|
|
8893
|
+
function parseSlug2(slug) {
|
|
8233
8894
|
if (!slug) {
|
|
8234
8895
|
return {
|
|
8235
8896
|
ok: false,
|
|
@@ -8339,7 +9000,7 @@ var init_content_id_index = __esm({
|
|
|
8339
9000
|
});
|
|
8340
9001
|
|
|
8341
9002
|
// dist/schema/meta-loader.js
|
|
8342
|
-
import { promises as
|
|
9003
|
+
import { promises as fs20 } from "fs";
|
|
8343
9004
|
import { join as join4 } from "pathe";
|
|
8344
9005
|
import { z as z8 } from "zod";
|
|
8345
9006
|
import chokidar2 from "chokidar";
|
|
@@ -8349,7 +9010,7 @@ function stripEmbeddedIdFromName2(name) {
|
|
|
8349
9010
|
async function scanForCollectionMeta2(baseDir, relativePath = "") {
|
|
8350
9011
|
const collections = [];
|
|
8351
9012
|
try {
|
|
8352
|
-
const entries = await
|
|
9013
|
+
const entries = await fs20.readdir(baseDir, { withFileTypes: true });
|
|
8353
9014
|
for (const entry of entries) {
|
|
8354
9015
|
if (!entry.isDirectory())
|
|
8355
9016
|
continue;
|
|
@@ -8360,8 +9021,8 @@ async function scanForCollectionMeta2(baseDir, relativePath = "") {
|
|
|
8360
9021
|
const absolutePath = join4(baseDir, folderName);
|
|
8361
9022
|
const metaPath = join4(absolutePath, ".collection.json");
|
|
8362
9023
|
try {
|
|
8363
|
-
await
|
|
8364
|
-
const content = await
|
|
9024
|
+
await fs20.access(metaPath);
|
|
9025
|
+
const content = await fs20.readFile(metaPath, "utf-8");
|
|
8365
9026
|
const parsed = JSON.parse(content);
|
|
8366
9027
|
const meta = collectionMetaSchema2.parse(parsed);
|
|
8367
9028
|
collections.push({
|
|
@@ -8393,7 +9054,7 @@ async function loadCollectionMetaFiles2(contentRoot) {
|
|
|
8393
9054
|
let root = null;
|
|
8394
9055
|
const rootMetaPath = join4(contentRoot, ".collection.json");
|
|
8395
9056
|
try {
|
|
8396
|
-
await
|
|
9057
|
+
await fs20.access(rootMetaPath);
|
|
8397
9058
|
} catch (err) {
|
|
8398
9059
|
if (err.code === "ENOENT") {
|
|
8399
9060
|
} else {
|
|
@@ -8401,7 +9062,7 @@ async function loadCollectionMetaFiles2(contentRoot) {
|
|
|
8401
9062
|
}
|
|
8402
9063
|
}
|
|
8403
9064
|
try {
|
|
8404
|
-
const content = await
|
|
9065
|
+
const content = await fs20.readFile(rootMetaPath, "utf-8");
|
|
8405
9066
|
const parsed = JSON.parse(content);
|
|
8406
9067
|
root = rootCollectionMetaSchema2.parse(parsed);
|
|
8407
9068
|
} catch (err) {
|
|
@@ -8548,7 +9209,12 @@ var init_field3 = __esm({
|
|
|
8548
9209
|
collections: z9.array(z9.string().min(1)).min(1).optional(),
|
|
8549
9210
|
entryTypes: z9.array(z9.string().min(1)).min(1).optional(),
|
|
8550
9211
|
displayField: z9.string().min(1).optional(),
|
|
8551
|
-
options: z9.array(referenceOptionSchema3).optional()
|
|
9212
|
+
options: z9.array(referenceOptionSchema3).optional(),
|
|
9213
|
+
// Must be listed here, not just on ReferenceFieldConfig: zod strips unknown keys by
|
|
9214
|
+
// default, so a consumer that adopts this schema's parse output would silently delete a
|
|
9215
|
+
// runtime-consumed flag and the feature would no-op with no error. (`resolvedSchema` is
|
|
9216
|
+
// absent on purpose — it is type-inference-only and stripping it changes no behavior.)
|
|
9217
|
+
includeBody: z9.boolean().optional()
|
|
8552
9218
|
});
|
|
8553
9219
|
fieldHolder3 = [z9.never()];
|
|
8554
9220
|
blockSchema3 = z9.object({
|
|
@@ -8658,7 +9324,7 @@ var init_media3 = __esm({
|
|
|
8658
9324
|
|
|
8659
9325
|
// dist/config/schemas/config.js
|
|
8660
9326
|
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;
|
|
9327
|
+
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
9328
|
var init_config4 = __esm({
|
|
8663
9329
|
"dist/config/schemas/config.js"() {
|
|
8664
9330
|
"use strict";
|
|
@@ -8682,6 +9348,9 @@ var init_config4 = __esm({
|
|
|
8682
9348
|
deployedAsSchema3 = z12.enum(["static", "server"]).default("server");
|
|
8683
9349
|
contentRootSchema3 = relativePathSchema3.default("content");
|
|
8684
9350
|
sourceRootSchema3 = z12.string().min(1).optional();
|
|
9351
|
+
basePathSchema3 = z12.string().transform((value) => value.trim()).refine((value) => value.length > 0, {
|
|
9352
|
+
message: "basePath must not be empty or only whitespace"
|
|
9353
|
+
}).optional();
|
|
8685
9354
|
deploymentNameSchema3 = z12.string().default("prod");
|
|
8686
9355
|
devContentSyncSchema3 = z12.enum(["off", "warn"]).default("warn");
|
|
8687
9356
|
devConfigSchema3 = z12.object({
|
|
@@ -8744,6 +9413,7 @@ var init_config4 = __esm({
|
|
|
8744
9413
|
deploymentName: deploymentNameSchema3.optional(),
|
|
8745
9414
|
contentRoot: contentRootSchema3.default("content"),
|
|
8746
9415
|
sourceRoot: sourceRootSchema3.optional(),
|
|
9416
|
+
basePath: basePathSchema3,
|
|
8747
9417
|
editor: editorConfigSchema3.optional(),
|
|
8748
9418
|
authPlugin: z12.custom().optional(),
|
|
8749
9419
|
entryLinkUrl: z12.custom().optional(),
|
|
@@ -8830,13 +9500,13 @@ var init_content_index_generation = __esm({
|
|
|
8830
9500
|
});
|
|
8831
9501
|
|
|
8832
9502
|
// dist/sync-core.js
|
|
8833
|
-
import
|
|
8834
|
-
import
|
|
9503
|
+
import fs21 from "node:fs/promises";
|
|
9504
|
+
import path25 from "node:path";
|
|
8835
9505
|
import { simpleGit as simpleGit4 } from "simple-git";
|
|
8836
9506
|
function assertWithinDir(resolved, parent, label) {
|
|
8837
|
-
const normalizedResolved =
|
|
8838
|
-
const normalizedParent =
|
|
8839
|
-
if (!normalizedResolved.startsWith(normalizedParent +
|
|
9507
|
+
const normalizedResolved = path25.resolve(resolved);
|
|
9508
|
+
const normalizedParent = path25.resolve(parent);
|
|
9509
|
+
if (!normalizedResolved.startsWith(normalizedParent + path25.sep) && normalizedResolved !== normalizedParent) {
|
|
8840
9510
|
throw new Error(`${label} escapes the expected directory: ${resolved}`);
|
|
8841
9511
|
}
|
|
8842
9512
|
}
|
|
@@ -8844,19 +9514,19 @@ async function safeReplaceDir(oldDir, newDir) {
|
|
|
8844
9514
|
const backupDir = `${oldDir}.sync-backup-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
8845
9515
|
const oldExists = await filePathExists(oldDir);
|
|
8846
9516
|
if (oldExists) {
|
|
8847
|
-
await
|
|
9517
|
+
await fs21.rename(oldDir, backupDir);
|
|
8848
9518
|
}
|
|
8849
9519
|
try {
|
|
8850
|
-
await
|
|
9520
|
+
await fs21.rename(newDir, oldDir);
|
|
8851
9521
|
} catch (err) {
|
|
8852
9522
|
if (oldExists) {
|
|
8853
|
-
await
|
|
9523
|
+
await fs21.rename(backupDir, oldDir).catch(() => {
|
|
8854
9524
|
});
|
|
8855
9525
|
}
|
|
8856
9526
|
throw err;
|
|
8857
9527
|
}
|
|
8858
9528
|
if (oldExists) {
|
|
8859
|
-
await
|
|
9529
|
+
await fs21.rm(backupDir, { recursive: true, force: true }).catch(() => {
|
|
8860
9530
|
});
|
|
8861
9531
|
}
|
|
8862
9532
|
}
|
|
@@ -8864,7 +9534,7 @@ async function listFilesRecursive(dir, prefix = "") {
|
|
|
8864
9534
|
const results = [];
|
|
8865
9535
|
let entries;
|
|
8866
9536
|
try {
|
|
8867
|
-
entries = await
|
|
9537
|
+
entries = await fs21.readdir(dir, { withFileTypes: true });
|
|
8868
9538
|
} catch {
|
|
8869
9539
|
return results;
|
|
8870
9540
|
}
|
|
@@ -8875,7 +9545,7 @@ async function listFilesRecursive(dir, prefix = "") {
|
|
|
8875
9545
|
continue;
|
|
8876
9546
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
8877
9547
|
if (entry.isDirectory()) {
|
|
8878
|
-
results.push(...await listFilesRecursive(
|
|
9548
|
+
results.push(...await listFilesRecursive(path25.join(dir, entry.name), rel));
|
|
8879
9549
|
} else {
|
|
8880
9550
|
results.push(rel);
|
|
8881
9551
|
}
|
|
@@ -8883,19 +9553,19 @@ async function listFilesRecursive(dir, prefix = "") {
|
|
|
8883
9553
|
return results;
|
|
8884
9554
|
}
|
|
8885
9555
|
async function copyDir(src, dest) {
|
|
8886
|
-
await
|
|
8887
|
-
const entries = await
|
|
9556
|
+
await fs21.mkdir(dest, { recursive: true });
|
|
9557
|
+
const entries = await fs21.readdir(src, { withFileTypes: true });
|
|
8888
9558
|
for (const entry of entries) {
|
|
8889
9559
|
if (entry.name === ".git")
|
|
8890
9560
|
continue;
|
|
8891
9561
|
if (entry.isSymbolicLink())
|
|
8892
9562
|
continue;
|
|
8893
|
-
const srcPath =
|
|
8894
|
-
const destPath =
|
|
9563
|
+
const srcPath = path25.join(src, entry.name);
|
|
9564
|
+
const destPath = path25.join(dest, entry.name);
|
|
8895
9565
|
if (entry.isDirectory()) {
|
|
8896
9566
|
await copyDir(srcPath, destPath);
|
|
8897
9567
|
} else {
|
|
8898
|
-
await
|
|
9568
|
+
await fs21.copyFile(srcPath, destPath);
|
|
8899
9569
|
}
|
|
8900
9570
|
}
|
|
8901
9571
|
}
|
|
@@ -8904,14 +9574,14 @@ async function pushContentToWorkspace(options) {
|
|
|
8904
9574
|
if (!await filePathExists(srcContentDir)) {
|
|
8905
9575
|
return { fileCount: 0 };
|
|
8906
9576
|
}
|
|
8907
|
-
const wsContentDir =
|
|
9577
|
+
const wsContentDir = path25.join(branchPath, contentRoot);
|
|
8908
9578
|
assertWithinDir(wsContentDir, branchPath, "content-root");
|
|
8909
9579
|
const tmpDir = `${wsContentDir}.sync-tmp-${Date.now()}`;
|
|
8910
9580
|
try {
|
|
8911
9581
|
await copyDir(srcContentDir, tmpDir);
|
|
8912
9582
|
await safeReplaceDir(wsContentDir, tmpDir);
|
|
8913
9583
|
} catch (err) {
|
|
8914
|
-
await
|
|
9584
|
+
await fs21.rm(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
8915
9585
|
});
|
|
8916
9586
|
throw err;
|
|
8917
9587
|
}
|
|
@@ -8955,19 +9625,21 @@ import lockfile3 from "proper-lockfile";
|
|
|
8955
9625
|
var init_provisioning_lock = __esm({
|
|
8956
9626
|
"dist/utils/provisioning-lock.js"() {
|
|
8957
9627
|
"use strict";
|
|
9628
|
+
init_error();
|
|
9629
|
+
init_logger3();
|
|
8958
9630
|
}
|
|
8959
9631
|
});
|
|
8960
9632
|
|
|
8961
9633
|
// dist/git-manager.js
|
|
8962
|
-
import
|
|
8963
|
-
import
|
|
9634
|
+
import fs24 from "node:fs/promises";
|
|
9635
|
+
import path26 from "node:path";
|
|
8964
9636
|
import { simpleGit as simpleGit6 } from "simple-git";
|
|
8965
9637
|
async function ensureGitExcludePattern2(repoPath, pattern) {
|
|
8966
|
-
const excludePath =
|
|
8967
|
-
await
|
|
9638
|
+
const excludePath = path26.join(repoPath, ".git", "info", "exclude");
|
|
9639
|
+
await fs24.mkdir(path26.dirname(excludePath), { recursive: true });
|
|
8968
9640
|
let content = "";
|
|
8969
9641
|
try {
|
|
8970
|
-
content = await
|
|
9642
|
+
content = await fs24.readFile(excludePath, "utf-8");
|
|
8971
9643
|
} catch (err) {
|
|
8972
9644
|
if (!isNotFoundError(err))
|
|
8973
9645
|
throw err;
|
|
@@ -8979,7 +9651,7 @@ async function ensureGitExcludePattern2(repoPath, pattern) {
|
|
|
8979
9651
|
}
|
|
8980
9652
|
const needsLeadingNewline = content.length > 0 && !content.endsWith("\n");
|
|
8981
9653
|
const newContent = content + (needsLeadingNewline ? "\n" : "") + pattern + "\n";
|
|
8982
|
-
await
|
|
9654
|
+
await fs24.writeFile(excludePath, newContent, "utf-8");
|
|
8983
9655
|
log9.debug("git", "Added pattern to .git/info/exclude", { pattern });
|
|
8984
9656
|
}
|
|
8985
9657
|
var log9;
|
|
@@ -9136,7 +9808,7 @@ var init_config5 = __esm({
|
|
|
9136
9808
|
});
|
|
9137
9809
|
|
|
9138
9810
|
// dist/operating-mode/client-unsafe-strategy.js
|
|
9139
|
-
import
|
|
9811
|
+
import path27 from "node:path";
|
|
9140
9812
|
function operatingStrategy3(mode) {
|
|
9141
9813
|
const cached = strategyCache3.get(mode);
|
|
9142
9814
|
if (cached)
|
|
@@ -9171,32 +9843,32 @@ var init_client_unsafe_strategy2 = __esm({
|
|
|
9171
9843
|
// - shouldCommit(), shouldPush()
|
|
9172
9844
|
// Add client-unsafe methods (use Node.js APIs)
|
|
9173
9845
|
getWorkspaceRoot(_sourceRoot) {
|
|
9174
|
-
return
|
|
9846
|
+
return path27.resolve(process.env.CANOPYCMS_WORKSPACE_ROOT ?? DEFAULT_PROD_WORKSPACE3);
|
|
9175
9847
|
}
|
|
9176
9848
|
getContentRoot(contentRoot, sourceRoot) {
|
|
9177
|
-
return
|
|
9849
|
+
return path27.resolve(sourceRoot ?? process.cwd(), contentRoot);
|
|
9178
9850
|
}
|
|
9179
9851
|
getContentBranchesRoot(sourceRoot) {
|
|
9180
|
-
return
|
|
9852
|
+
return path27.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
|
|
9181
9853
|
}
|
|
9182
9854
|
getContentBranchRoot(branchName, sourceRoot) {
|
|
9183
|
-
return
|
|
9855
|
+
return path27.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
|
|
9184
9856
|
}
|
|
9185
9857
|
getGitExcludePattern() {
|
|
9186
9858
|
return ".canopy-meta/";
|
|
9187
9859
|
}
|
|
9188
9860
|
getPermissionsFilePath(root) {
|
|
9189
|
-
return
|
|
9861
|
+
return path27.join(root, this.getPermissionsFileName());
|
|
9190
9862
|
}
|
|
9191
9863
|
getGroupsFilePath(root) {
|
|
9192
|
-
return
|
|
9864
|
+
return path27.join(root, this.getGroupsFileName());
|
|
9193
9865
|
}
|
|
9194
9866
|
getRemoteUrlConfig() {
|
|
9195
9867
|
return {
|
|
9196
9868
|
shouldAutoInitLocal: false,
|
|
9197
9869
|
defaultRemotePath: "",
|
|
9198
9870
|
envVarName: "CANOPYCMS_REMOTE_URL",
|
|
9199
|
-
autoDetectRemotePath:
|
|
9871
|
+
autoDetectRemotePath: path27.join(this.getWorkspaceRoot(), "remote.git")
|
|
9200
9872
|
};
|
|
9201
9873
|
}
|
|
9202
9874
|
requiresExistingRepo() {
|
|
@@ -9208,7 +9880,7 @@ var init_client_unsafe_strategy2 = __esm({
|
|
|
9208
9880
|
return `canopycms-settings-${resolveDeploymentName3(config, "prod")}`;
|
|
9209
9881
|
}
|
|
9210
9882
|
getSettingsRoot(sourceRoot) {
|
|
9211
|
-
return
|
|
9883
|
+
return path27.join(this.getWorkspaceRoot(sourceRoot), "settings");
|
|
9212
9884
|
}
|
|
9213
9885
|
usesSeparateSettingsBranch() {
|
|
9214
9886
|
return true;
|
|
@@ -9225,25 +9897,25 @@ var init_client_unsafe_strategy2 = __esm({
|
|
|
9225
9897
|
DevStrategy3 = class extends DevClientSafeStrategy3 {
|
|
9226
9898
|
// Inherits client-safe methods from DevClientSafeStrategy
|
|
9227
9899
|
getWorkspaceRoot(sourceRoot) {
|
|
9228
|
-
return
|
|
9900
|
+
return path27.resolve(sourceRoot ?? process.cwd(), ".canopy-dev");
|
|
9229
9901
|
}
|
|
9230
9902
|
getContentRoot(contentRoot, sourceRoot) {
|
|
9231
|
-
return
|
|
9903
|
+
return path27.resolve(sourceRoot ?? process.cwd(), contentRoot);
|
|
9232
9904
|
}
|
|
9233
9905
|
getContentBranchesRoot(sourceRoot) {
|
|
9234
|
-
return
|
|
9906
|
+
return path27.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
|
|
9235
9907
|
}
|
|
9236
9908
|
getContentBranchRoot(branchName, sourceRoot) {
|
|
9237
|
-
return
|
|
9909
|
+
return path27.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
|
|
9238
9910
|
}
|
|
9239
9911
|
getGitExcludePattern() {
|
|
9240
9912
|
return ".canopy-meta/";
|
|
9241
9913
|
}
|
|
9242
9914
|
getPermissionsFilePath(root) {
|
|
9243
|
-
return
|
|
9915
|
+
return path27.join(root, this.getPermissionsFileName());
|
|
9244
9916
|
}
|
|
9245
9917
|
getGroupsFilePath(root) {
|
|
9246
|
-
return
|
|
9918
|
+
return path27.join(root, this.getGroupsFileName());
|
|
9247
9919
|
}
|
|
9248
9920
|
getRemoteUrlConfig() {
|
|
9249
9921
|
return {
|
|
@@ -9261,7 +9933,7 @@ var init_client_unsafe_strategy2 = __esm({
|
|
|
9261
9933
|
return `canopycms-settings-${resolveDeploymentName3(config, "local")}`;
|
|
9262
9934
|
}
|
|
9263
9935
|
getSettingsRoot(sourceRoot) {
|
|
9264
|
-
return
|
|
9936
|
+
return path27.join(this.getWorkspaceRoot(sourceRoot), "settings");
|
|
9265
9937
|
}
|
|
9266
9938
|
usesSeparateSettingsBranch() {
|
|
9267
9939
|
return true;
|
|
@@ -9293,8 +9965,8 @@ __export(sync_exports, {
|
|
|
9293
9965
|
SyncError: () => SyncError,
|
|
9294
9966
|
sync: () => sync
|
|
9295
9967
|
});
|
|
9296
|
-
import
|
|
9297
|
-
import
|
|
9968
|
+
import fs25 from "node:fs/promises";
|
|
9969
|
+
import path28 from "node:path";
|
|
9298
9970
|
import { simpleGit as simpleGit7 } from "simple-git";
|
|
9299
9971
|
import * as p2 from "@clack/prompts";
|
|
9300
9972
|
async function detectCurrentBranch(projectDir) {
|
|
@@ -9307,7 +9979,7 @@ async function detectCurrentBranch(projectDir) {
|
|
|
9307
9979
|
async function selectBranch(options, branchesDir) {
|
|
9308
9980
|
let branches = [];
|
|
9309
9981
|
if (await filePathExists(branchesDir)) {
|
|
9310
|
-
const entries = await
|
|
9982
|
+
const entries = await fs25.readdir(branchesDir, { withFileTypes: true });
|
|
9311
9983
|
branches = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name);
|
|
9312
9984
|
}
|
|
9313
9985
|
let branchName = options.branch;
|
|
@@ -9335,11 +10007,11 @@ async function selectBranch(options, branchesDir) {
|
|
|
9335
10007
|
branchName = result;
|
|
9336
10008
|
}
|
|
9337
10009
|
}
|
|
9338
|
-
const branchPath =
|
|
10010
|
+
const branchPath = path28.join(branchesDir, branchName);
|
|
9339
10011
|
assertWithinDir(branchPath, branchesDir, "--branch");
|
|
9340
10012
|
if (!branches.includes(branchName)) {
|
|
9341
10013
|
if (options.autoCreate) {
|
|
9342
|
-
await
|
|
10014
|
+
await fs25.mkdir(branchPath, { recursive: true });
|
|
9343
10015
|
const wsGit = simpleGit7({ baseDir: branchPath });
|
|
9344
10016
|
await wsGit.init();
|
|
9345
10017
|
await wsGit.checkoutLocalBranch(branchName);
|
|
@@ -9356,8 +10028,8 @@ async function selectBranch(options, branchesDir) {
|
|
|
9356
10028
|
async function syncPush(options) {
|
|
9357
10029
|
const { projectDir } = options;
|
|
9358
10030
|
const contentRoot = options.contentRoot || "content";
|
|
9359
|
-
const branchesDir =
|
|
9360
|
-
const srcContentDir =
|
|
10031
|
+
const branchesDir = path28.join(projectDir, ".canopy-dev", "content-branches");
|
|
10032
|
+
const srcContentDir = path28.join(projectDir, contentRoot);
|
|
9361
10033
|
assertWithinDir(srcContentDir, projectDir, "--content-root");
|
|
9362
10034
|
if (!await filePathExists(srcContentDir)) {
|
|
9363
10035
|
throw new SyncError(`Content directory not found: ${contentRoot}/ (expected at ${srcContentDir})`);
|
|
@@ -9365,7 +10037,7 @@ async function syncPush(options) {
|
|
|
9365
10037
|
const branchName = await selectBranch({ ...options, projectDir, autoCreate: true }, branchesDir);
|
|
9366
10038
|
if (!branchName)
|
|
9367
10039
|
return { fileCount: 0 };
|
|
9368
|
-
const branchPath =
|
|
10040
|
+
const branchPath = path28.join(branchesDir, branchName);
|
|
9369
10041
|
assertWithinDir(branchPath, branchesDir, "--branch");
|
|
9370
10042
|
const wsGit = simpleGit7({ baseDir: branchPath });
|
|
9371
10043
|
const status = await wsGit.status();
|
|
@@ -9423,19 +10095,19 @@ async function syncPush(options) {
|
|
|
9423
10095
|
async function syncPull(options) {
|
|
9424
10096
|
const { projectDir } = options;
|
|
9425
10097
|
const contentRoot = options.contentRoot || "content";
|
|
9426
|
-
const branchesDir =
|
|
10098
|
+
const branchesDir = path28.join(projectDir, ".canopy-dev", "content-branches");
|
|
9427
10099
|
const branchName = await selectBranch({ ...options, projectDir }, branchesDir);
|
|
9428
10100
|
if (!branchName)
|
|
9429
10101
|
return { fileCount: 0 };
|
|
9430
|
-
const branchPath =
|
|
10102
|
+
const branchPath = path28.join(branchesDir, branchName);
|
|
9431
10103
|
assertWithinDir(branchPath, branchesDir, "--branch");
|
|
9432
|
-
const branchContentDir =
|
|
10104
|
+
const branchContentDir = path28.join(branchPath, contentRoot);
|
|
9433
10105
|
assertWithinDir(branchContentDir, branchPath, "--content-root");
|
|
9434
10106
|
if (!await filePathExists(branchContentDir)) {
|
|
9435
10107
|
throw new SyncError(`Content directory not found in branch workspace: ${branchName}/${contentRoot}`);
|
|
9436
10108
|
}
|
|
9437
10109
|
p2.log.step(`Pulling content from branch: ${branchName}`);
|
|
9438
|
-
const destContentDir =
|
|
10110
|
+
const destContentDir = path28.join(projectDir, contentRoot);
|
|
9439
10111
|
assertWithinDir(destContentDir, projectDir, "--content-root");
|
|
9440
10112
|
const sourceGit = simpleGit7({ baseDir: projectDir });
|
|
9441
10113
|
const status = await sourceGit.status();
|
|
@@ -9487,7 +10159,7 @@ async function syncPull(options) {
|
|
|
9487
10159
|
await copyDir(branchContentDir, tmpDestDir);
|
|
9488
10160
|
await safeReplaceDir(destContentDir, tmpDestDir);
|
|
9489
10161
|
} catch (err) {
|
|
9490
|
-
await
|
|
10162
|
+
await fs25.rm(tmpDestDir, { recursive: true, force: true }).catch(() => {
|
|
9491
10163
|
});
|
|
9492
10164
|
throw err;
|
|
9493
10165
|
}
|
|
@@ -9511,8 +10183,8 @@ async function syncPull(options) {
|
|
|
9511
10183
|
async function syncBoth(options) {
|
|
9512
10184
|
const { projectDir } = options;
|
|
9513
10185
|
const contentRoot = options.contentRoot || "content";
|
|
9514
|
-
const branchesDir =
|
|
9515
|
-
const srcContentDir =
|
|
10186
|
+
const branchesDir = path28.join(projectDir, ".canopy-dev", "content-branches");
|
|
10187
|
+
const srcContentDir = path28.join(projectDir, contentRoot);
|
|
9516
10188
|
assertWithinDir(srcContentDir, projectDir, "--content-root");
|
|
9517
10189
|
if (!await filePathExists(srcContentDir)) {
|
|
9518
10190
|
throw new SyncError(`Content directory not found: ${contentRoot}/ (expected at ${srcContentDir})`);
|
|
@@ -9520,7 +10192,7 @@ async function syncBoth(options) {
|
|
|
9520
10192
|
const branchName = await selectBranch({ ...options, projectDir, autoCreate: true }, branchesDir);
|
|
9521
10193
|
if (!branchName)
|
|
9522
10194
|
return { pushed: 0, pulled: 0 };
|
|
9523
|
-
const branchPath =
|
|
10195
|
+
const branchPath = path28.join(branchesDir, branchName);
|
|
9524
10196
|
assertWithinDir(branchPath, branchesDir, "--branch");
|
|
9525
10197
|
const wsGit = simpleGit7({ baseDir: branchPath });
|
|
9526
10198
|
const status = await wsGit.status();
|
|
@@ -9555,14 +10227,14 @@ async function syncBoth(options) {
|
|
|
9555
10227
|
try {
|
|
9556
10228
|
const incomingBranch = `sync-incoming-${Date.now()}`;
|
|
9557
10229
|
await wsGit.raw(["checkout", "-b", incomingBranch, baseRef]);
|
|
9558
|
-
const wsContentDir =
|
|
10230
|
+
const wsContentDir = path28.join(branchPath, contentRoot);
|
|
9559
10231
|
assertWithinDir(wsContentDir, branchPath, "--content-root");
|
|
9560
10232
|
const tmpDir = `${wsContentDir}.sync-tmp-${Date.now()}`;
|
|
9561
10233
|
try {
|
|
9562
10234
|
await copyDir(srcContentDir, tmpDir);
|
|
9563
10235
|
await safeReplaceDir(wsContentDir, tmpDir);
|
|
9564
10236
|
} catch (err) {
|
|
9565
|
-
await
|
|
10237
|
+
await fs25.rm(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
9566
10238
|
});
|
|
9567
10239
|
await wsGit.checkout(currentBranch);
|
|
9568
10240
|
await wsGit.raw(["branch", "-D", incomingBranch]).catch(() => {
|
|
@@ -9619,11 +10291,11 @@ async function syncBoth(options) {
|
|
|
9619
10291
|
}
|
|
9620
10292
|
async function syncAbort(options) {
|
|
9621
10293
|
const { projectDir } = options;
|
|
9622
|
-
const branchesDir =
|
|
10294
|
+
const branchesDir = path28.join(projectDir, ".canopy-dev", "content-branches");
|
|
9623
10295
|
const branchName = await selectBranch({ ...options, projectDir }, branchesDir);
|
|
9624
10296
|
if (!branchName)
|
|
9625
10297
|
return;
|
|
9626
|
-
const branchPath =
|
|
10298
|
+
const branchPath = path28.join(branchesDir, branchName);
|
|
9627
10299
|
assertWithinDir(branchPath, branchesDir, "--branch");
|
|
9628
10300
|
const wsGit = simpleGit7({ baseDir: branchPath });
|
|
9629
10301
|
const status = await wsGit.status();
|
|
@@ -9751,8 +10423,8 @@ var init_async_mutex = __esm({
|
|
|
9751
10423
|
});
|
|
9752
10424
|
|
|
9753
10425
|
// dist/utils/occ-json-write.js
|
|
9754
|
-
import
|
|
9755
|
-
import
|
|
10426
|
+
import fs26 from "node:fs/promises";
|
|
10427
|
+
import path29 from "node:path";
|
|
9756
10428
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
9757
10429
|
import lockfile4 from "proper-lockfile";
|
|
9758
10430
|
async function writeOccJsonFile2(filePath, payload, options) {
|
|
@@ -9761,29 +10433,29 @@ async function writeOccJsonFile2(filePath, payload, options) {
|
|
|
9761
10433
|
const writeId = randomUUID4();
|
|
9762
10434
|
const data = { ...payload, version: newVersion, writeId };
|
|
9763
10435
|
const content = JSON.stringify(data, null, 2) + (trailingNewline ? "\n" : "");
|
|
9764
|
-
const dir =
|
|
9765
|
-
await
|
|
10436
|
+
const dir = path29.dirname(filePath);
|
|
10437
|
+
await fs26.mkdir(dir, { recursive: true });
|
|
9766
10438
|
const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
9767
|
-
await
|
|
10439
|
+
await fs26.writeFile(tempPath, content, "utf-8");
|
|
9768
10440
|
if (expectedVersion === null) {
|
|
9769
10441
|
try {
|
|
9770
|
-
await
|
|
10442
|
+
await fs26.link(tempPath, filePath);
|
|
9771
10443
|
} catch (err) {
|
|
9772
|
-
await
|
|
10444
|
+
await fs26.unlink(tempPath).catch(() => {
|
|
9773
10445
|
});
|
|
9774
10446
|
if (isFileExistsError(err)) {
|
|
9775
10447
|
throw new OccWriteConflictError2();
|
|
9776
10448
|
}
|
|
9777
10449
|
throw err;
|
|
9778
10450
|
}
|
|
9779
|
-
await
|
|
10451
|
+
await fs26.unlink(tempPath).catch(() => {
|
|
9780
10452
|
});
|
|
9781
10453
|
return { version: newVersion, writeId };
|
|
9782
10454
|
}
|
|
9783
10455
|
try {
|
|
9784
10456
|
let currentVersion = null;
|
|
9785
10457
|
try {
|
|
9786
|
-
const current = JSON.parse(await
|
|
10458
|
+
const current = JSON.parse(await fs26.readFile(filePath, "utf-8"));
|
|
9787
10459
|
currentVersion = current.version ?? 0;
|
|
9788
10460
|
} catch {
|
|
9789
10461
|
currentVersion = null;
|
|
@@ -9791,16 +10463,16 @@ async function writeOccJsonFile2(filePath, payload, options) {
|
|
|
9791
10463
|
if (currentVersion !== expectedVersion) {
|
|
9792
10464
|
throw new OccWriteConflictError2();
|
|
9793
10465
|
}
|
|
9794
|
-
await
|
|
10466
|
+
await fs26.rename(tempPath, filePath);
|
|
9795
10467
|
if (settleMs > 0) {
|
|
9796
10468
|
await new Promise((resolve2) => setTimeout(resolve2, settleMs));
|
|
9797
10469
|
}
|
|
9798
|
-
const afterWrite = JSON.parse(await
|
|
10470
|
+
const afterWrite = JSON.parse(await fs26.readFile(filePath, "utf-8"));
|
|
9799
10471
|
if (afterWrite.writeId !== writeId) {
|
|
9800
10472
|
throw new OccWriteConflictError2();
|
|
9801
10473
|
}
|
|
9802
10474
|
} catch (err) {
|
|
9803
|
-
await
|
|
10475
|
+
await fs26.unlink(tempPath).catch(() => {
|
|
9804
10476
|
});
|
|
9805
10477
|
throw err;
|
|
9806
10478
|
}
|
|
@@ -9826,8 +10498,8 @@ async function withOccRetry2(operation, options) {
|
|
|
9826
10498
|
throw new Error("Unreachable");
|
|
9827
10499
|
}
|
|
9828
10500
|
async function withOccFileLock2(filePath, fn) {
|
|
9829
|
-
const dir =
|
|
9830
|
-
await
|
|
10501
|
+
const dir = path29.dirname(filePath);
|
|
10502
|
+
await fs26.mkdir(dir, { recursive: true });
|
|
9831
10503
|
const MAX_ATTEMPTS = 14;
|
|
9832
10504
|
let release = null;
|
|
9833
10505
|
for (let attempt = 1; release === null; attempt++) {
|
|
@@ -9886,8 +10558,8 @@ var init_occ_json_write = __esm({
|
|
|
9886
10558
|
});
|
|
9887
10559
|
|
|
9888
10560
|
// dist/branch-registry.js
|
|
9889
|
-
import
|
|
9890
|
-
import
|
|
10561
|
+
import fs27 from "node:fs/promises";
|
|
10562
|
+
import path30 from "node:path";
|
|
9891
10563
|
var log12, REGISTRY_FILE2, REGISTRY_STALE_FILE2, REGISTRY_TEMP_FILE2, REGISTRY_VERSION2, RESOURCE4, GET_MISS_REFRESH_MIN_INTERVAL_MS2, BranchRegistry2;
|
|
9892
10564
|
var init_branch_registry = __esm({
|
|
9893
10565
|
"dist/branch-registry.js"() {
|
|
@@ -9908,10 +10580,10 @@ var init_branch_registry = __esm({
|
|
|
9908
10580
|
constructor(root) {
|
|
9909
10581
|
this.regenInFlight = null;
|
|
9910
10582
|
this.lastForcedRefreshMs = 0;
|
|
9911
|
-
this.root =
|
|
9912
|
-
this.registryPath =
|
|
9913
|
-
this.stalePath =
|
|
9914
|
-
this.tempPath =
|
|
10583
|
+
this.root = path30.resolve(root);
|
|
10584
|
+
this.registryPath = path30.join(this.root, REGISTRY_FILE2);
|
|
10585
|
+
this.stalePath = path30.join(this.root, REGISTRY_STALE_FILE2);
|
|
10586
|
+
this.tempPath = path30.join(this.root, REGISTRY_TEMP_FILE2);
|
|
9915
10587
|
}
|
|
9916
10588
|
/**
|
|
9917
10589
|
* Returns all branches. Uses the cached snapshot if its embedded generation
|
|
@@ -9920,7 +10592,7 @@ var init_branch_registry = __esm({
|
|
|
9920
10592
|
async list() {
|
|
9921
10593
|
let parsed;
|
|
9922
10594
|
try {
|
|
9923
|
-
const raw = await
|
|
10595
|
+
const raw = await fs27.readFile(this.registryPath, "utf8");
|
|
9924
10596
|
parsed = JSON.parse(raw);
|
|
9925
10597
|
} catch (err) {
|
|
9926
10598
|
if (isNotFoundError(err)) {
|
|
@@ -10009,7 +10681,7 @@ var init_branch_registry = __esm({
|
|
|
10009
10681
|
async performRegenerate() {
|
|
10010
10682
|
const read = await readResourceGeneration2(this.root, RESOURCE4);
|
|
10011
10683
|
const branches = await this.scanBranchDirectories();
|
|
10012
|
-
await
|
|
10684
|
+
await fs27.unlink(this.stalePath).catch(() => {
|
|
10013
10685
|
});
|
|
10014
10686
|
if (!read.ok) {
|
|
10015
10687
|
return branches;
|
|
@@ -10020,12 +10692,12 @@ var init_branch_registry = __esm({
|
|
|
10020
10692
|
generation: read.token
|
|
10021
10693
|
};
|
|
10022
10694
|
const uniqueTempPath = `${this.tempPath}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
10023
|
-
await
|
|
10024
|
-
await
|
|
10695
|
+
await fs27.mkdir(this.root, { recursive: true });
|
|
10696
|
+
await fs27.writeFile(uniqueTempPath, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
|
|
10025
10697
|
try {
|
|
10026
|
-
await
|
|
10698
|
+
await fs27.rename(uniqueTempPath, this.registryPath);
|
|
10027
10699
|
} catch (err) {
|
|
10028
|
-
await
|
|
10700
|
+
await fs27.unlink(uniqueTempPath).catch(() => {
|
|
10029
10701
|
});
|
|
10030
10702
|
throw err;
|
|
10031
10703
|
}
|
|
@@ -10039,12 +10711,12 @@ var init_branch_registry = __esm({
|
|
|
10039
10711
|
async scanBranchDirectories() {
|
|
10040
10712
|
const branches = [];
|
|
10041
10713
|
try {
|
|
10042
|
-
const entries = await
|
|
10714
|
+
const entries = await fs27.readdir(this.root, { withFileTypes: true });
|
|
10043
10715
|
for (const entry of entries) {
|
|
10044
10716
|
if (!entry.isDirectory() || entry.name.startsWith(".")) {
|
|
10045
10717
|
continue;
|
|
10046
10718
|
}
|
|
10047
|
-
const branchRoot =
|
|
10719
|
+
const branchRoot = path30.join(this.root, entry.name);
|
|
10048
10720
|
let meta;
|
|
10049
10721
|
try {
|
|
10050
10722
|
meta = await BranchMetadataFileManager2.loadOnly(branchRoot);
|
|
@@ -10073,8 +10745,8 @@ var init_branch_registry = __esm({
|
|
|
10073
10745
|
});
|
|
10074
10746
|
|
|
10075
10747
|
// dist/branch-metadata.js
|
|
10076
|
-
import
|
|
10077
|
-
import
|
|
10748
|
+
import fs28 from "node:fs/promises";
|
|
10749
|
+
import path31 from "node:path";
|
|
10078
10750
|
var BRANCH_META_DIR2, BRANCH_META_FILE2, CURRENT_SCHEMA_VERSION2, BranchMetadataConflictError2, BranchMetadataCorruptError2, BranchMetadataFileManager2;
|
|
10079
10751
|
var init_branch_metadata = __esm({
|
|
10080
10752
|
"dist/branch-metadata.js"() {
|
|
@@ -10103,8 +10775,8 @@ var init_branch_metadata = __esm({
|
|
|
10103
10775
|
};
|
|
10104
10776
|
BranchMetadataFileManager2 = class _BranchMetadataFileManager2 {
|
|
10105
10777
|
constructor(branchRoot, baseRoot, options) {
|
|
10106
|
-
this.branchRoot =
|
|
10107
|
-
this.filePath =
|
|
10778
|
+
this.branchRoot = path31.resolve(branchRoot);
|
|
10779
|
+
this.filePath = path31.join(this.branchRoot, BRANCH_META_DIR2, BRANCH_META_FILE2);
|
|
10108
10780
|
this.baseRoot = baseRoot;
|
|
10109
10781
|
this.settleMs = options?.settleMs;
|
|
10110
10782
|
}
|
|
@@ -10113,10 +10785,10 @@ var init_branch_metadata = __esm({
|
|
|
10113
10785
|
* Use this for read-only access (e.g., in registry scanning or loadBranchContext).
|
|
10114
10786
|
*/
|
|
10115
10787
|
static async loadOnly(branchRoot) {
|
|
10116
|
-
const resolvedRoot =
|
|
10117
|
-
const filePath =
|
|
10788
|
+
const resolvedRoot = path31.resolve(branchRoot);
|
|
10789
|
+
const filePath = path31.join(resolvedRoot, BRANCH_META_DIR2, BRANCH_META_FILE2);
|
|
10118
10790
|
try {
|
|
10119
|
-
const raw = await
|
|
10791
|
+
const raw = await fs28.readFile(filePath, "utf8");
|
|
10120
10792
|
return JSON.parse(raw);
|
|
10121
10793
|
} catch (err) {
|
|
10122
10794
|
if (isNotFoundError(err)) {
|
|
@@ -10137,7 +10809,7 @@ var init_branch_metadata = __esm({
|
|
|
10137
10809
|
}
|
|
10138
10810
|
async load() {
|
|
10139
10811
|
try {
|
|
10140
|
-
const raw = await
|
|
10812
|
+
const raw = await fs28.readFile(this.filePath, "utf8");
|
|
10141
10813
|
const parsed = JSON.parse(raw);
|
|
10142
10814
|
const version = parsed.version ?? 0;
|
|
10143
10815
|
return { meta: parsed, version };
|
|
@@ -10199,7 +10871,7 @@ var init_branch_metadata = __esm({
|
|
|
10199
10871
|
*/
|
|
10200
10872
|
async save(incoming) {
|
|
10201
10873
|
try {
|
|
10202
|
-
await
|
|
10874
|
+
await fs28.stat(this.branchRoot);
|
|
10203
10875
|
} catch (err) {
|
|
10204
10876
|
if (isNotFoundError(err)) {
|
|
10205
10877
|
throw new BranchMetadataConflictError2("Branch no longer exists");
|
|
@@ -10274,8 +10946,8 @@ __export(migrate_exports, {
|
|
|
10274
10946
|
migrate: () => migrate,
|
|
10275
10947
|
slugifyName: () => slugifyName
|
|
10276
10948
|
});
|
|
10277
|
-
import
|
|
10278
|
-
import
|
|
10949
|
+
import fs29 from "node:fs/promises";
|
|
10950
|
+
import path33 from "node:path";
|
|
10279
10951
|
import * as p3 from "@clack/prompts";
|
|
10280
10952
|
function slugifyName(name) {
|
|
10281
10953
|
const slug = name.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -10283,7 +10955,7 @@ function slugifyName(name) {
|
|
|
10283
10955
|
}
|
|
10284
10956
|
function toValidSlug(name) {
|
|
10285
10957
|
const slug = slugifyName(name);
|
|
10286
|
-
const parsed =
|
|
10958
|
+
const parsed = parseSlug2(slug);
|
|
10287
10959
|
if (!parsed.ok) {
|
|
10288
10960
|
throw new MigrateError(`Cannot derive a valid slug from "${name}" (got "${slug}"): ${parsed.error}`);
|
|
10289
10961
|
}
|
|
@@ -10300,7 +10972,7 @@ function stripDirIdSuffix(dirName) {
|
|
|
10300
10972
|
return dirName;
|
|
10301
10973
|
}
|
|
10302
10974
|
async function planDirectory(dirPath, isRoot, ctx) {
|
|
10303
|
-
const entries = await
|
|
10975
|
+
const entries = await fs29.readdir(dirPath, { withFileTypes: true });
|
|
10304
10976
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
10305
10977
|
const ops = [];
|
|
10306
10978
|
let hasOwnFiles = false;
|
|
@@ -10309,7 +10981,7 @@ async function planDirectory(dirPath, isRoot, ctx) {
|
|
|
10309
10981
|
if (entry.name.startsWith("."))
|
|
10310
10982
|
continue;
|
|
10311
10983
|
if (entry.isDirectory()) {
|
|
10312
|
-
const subPath =
|
|
10984
|
+
const subPath = path33.join(dirPath, entry.name);
|
|
10313
10985
|
const sub = await planDirectory(subPath, false, ctx);
|
|
10314
10986
|
if (!sub.hasContent)
|
|
10315
10987
|
continue;
|
|
@@ -10317,10 +10989,10 @@ async function planDirectory(dirPath, isRoot, ctx) {
|
|
|
10317
10989
|
ops.push(...sub.ops);
|
|
10318
10990
|
if (!extractIdFromFilename2(entry.name)) {
|
|
10319
10991
|
const newName = `${toValidSlug(entry.name)}.${generateId2()}`;
|
|
10320
|
-
ops.push({ kind: "rename", from: subPath, to:
|
|
10992
|
+
ops.push({ kind: "rename", from: subPath, to: path33.join(dirPath, newName) });
|
|
10321
10993
|
}
|
|
10322
10994
|
} else if (entry.isFile()) {
|
|
10323
|
-
const ext =
|
|
10995
|
+
const ext = path33.extname(entry.name).slice(1);
|
|
10324
10996
|
const matchesFormat = ext === ctx.format || ctx.format === "yaml" && ext === "yml";
|
|
10325
10997
|
if (!matchesFormat)
|
|
10326
10998
|
continue;
|
|
@@ -10331,17 +11003,17 @@ async function planDirectory(dirPath, isRoot, ctx) {
|
|
|
10331
11003
|
const newName = `${ctx.entryType}.${toValidSlug(base)}.${generateId2()}.${ext}`;
|
|
10332
11004
|
ops.push({
|
|
10333
11005
|
kind: "rename",
|
|
10334
|
-
from:
|
|
10335
|
-
to:
|
|
11006
|
+
from: path33.join(dirPath, entry.name),
|
|
11007
|
+
to: path33.join(dirPath, newName)
|
|
10336
11008
|
});
|
|
10337
11009
|
}
|
|
10338
11010
|
}
|
|
10339
11011
|
}
|
|
10340
11012
|
const needsMeta = isRoot ? hasOwnFiles : hasContent;
|
|
10341
|
-
const metaPath =
|
|
11013
|
+
const metaPath = path33.join(dirPath, ".collection.json");
|
|
10342
11014
|
if (needsMeta && !await filePathExists(metaPath)) {
|
|
10343
11015
|
const entryTypeMeta = { name: ctx.entryType, format: ctx.format, schema: ctx.schema };
|
|
10344
|
-
const meta = isRoot ? { entries: [entryTypeMeta] } : { name: toValidSlug(stripDirIdSuffix(
|
|
11016
|
+
const meta = isRoot ? { entries: [entryTypeMeta] } : { name: toValidSlug(stripDirIdSuffix(path33.basename(dirPath))), entries: [entryTypeMeta] };
|
|
10345
11017
|
ops.push({ kind: "write", filePath: metaPath, content: JSON.stringify(meta, null, 2) + "\n" });
|
|
10346
11018
|
}
|
|
10347
11019
|
return { ops, hasContent };
|
|
@@ -10350,7 +11022,7 @@ async function migrate(options) {
|
|
|
10350
11022
|
const { projectDir } = options;
|
|
10351
11023
|
const contentRoot = options.contentRoot || "content";
|
|
10352
11024
|
p3.intro("CanopyCMS migrate");
|
|
10353
|
-
const contentDir =
|
|
11025
|
+
const contentDir = path33.join(projectDir, contentRoot);
|
|
10354
11026
|
if (!await filePathExists(contentDir)) {
|
|
10355
11027
|
throw new MigrateError(`Content directory not found: ${contentRoot}/ (expected at ${contentDir})`);
|
|
10356
11028
|
}
|
|
@@ -10427,14 +11099,14 @@ async function migrate(options) {
|
|
|
10427
11099
|
const applyOps = async () => {
|
|
10428
11100
|
for (const op of ops) {
|
|
10429
11101
|
if (op.kind === "rename") {
|
|
10430
|
-
await
|
|
11102
|
+
await fs29.rename(op.from, op.to);
|
|
10431
11103
|
} else {
|
|
10432
|
-
await
|
|
11104
|
+
await fs29.writeFile(op.filePath, op.content, "utf-8");
|
|
10433
11105
|
}
|
|
10434
11106
|
}
|
|
10435
11107
|
};
|
|
10436
11108
|
if (isBranchClone) {
|
|
10437
|
-
const lockPath =
|
|
11109
|
+
const lockPath = path33.join(projectDir, ".canopy-meta", "schema");
|
|
10438
11110
|
try {
|
|
10439
11111
|
await withLock2(lockPath, () => withOccFileLock2(lockPath, applyOps));
|
|
10440
11112
|
} catch (err) {
|
|
@@ -10482,7 +11154,7 @@ var init_migrate = __esm({
|
|
|
10482
11154
|
this.name = "MigrateError";
|
|
10483
11155
|
}
|
|
10484
11156
|
};
|
|
10485
|
-
describeOp = (op, baseDir) => op.kind === "rename" ? `rename ${
|
|
11157
|
+
describeOp = (op, baseDir) => op.kind === "rename" ? `rename ${path33.relative(baseDir, op.from)} \u2192 ${path33.basename(op.to)}` : `create ${path33.relative(baseDir, op.filePath)}`;
|
|
10486
11158
|
}
|
|
10487
11159
|
});
|
|
10488
11160
|
|
|
@@ -10551,6 +11223,10 @@ async function requireProjectRoot(command) {
|
|
|
10551
11223
|
}
|
|
10552
11224
|
return root;
|
|
10553
11225
|
}
|
|
11226
|
+
var KNOWN_AUTH_MODES = ["clerk", "dev"];
|
|
11227
|
+
function isKnownAuthMode(value) {
|
|
11228
|
+
return KNOWN_AUTH_MODES.includes(value);
|
|
11229
|
+
}
|
|
10554
11230
|
function resolveSyncSubcommand(sub) {
|
|
10555
11231
|
if (sub && SYNC_SUBCOMMANDS.includes(sub))
|
|
10556
11232
|
return sub;
|
|
@@ -10642,6 +11318,10 @@ async function main() {
|
|
|
10642
11318
|
process.exit(1);
|
|
10643
11319
|
}
|
|
10644
11320
|
const authMode = process.env.CANOPY_AUTH_MODE || "dev";
|
|
11321
|
+
if (!isKnownAuthMode(authMode)) {
|
|
11322
|
+
console.error(`Unknown CANOPY_AUTH_MODE "${authMode}" \u2014 expected one of: ${KNOWN_AUTH_MODES.join(", ")}. No auth plugin was loaded, so the auth cache will NOT be refreshed.`);
|
|
11323
|
+
process.exitCode = 1;
|
|
11324
|
+
}
|
|
10645
11325
|
let authPlugin;
|
|
10646
11326
|
try {
|
|
10647
11327
|
if (authMode === "clerk") {
|
|
@@ -10753,6 +11433,8 @@ if (isDirectRun) {
|
|
|
10753
11433
|
});
|
|
10754
11434
|
}
|
|
10755
11435
|
export {
|
|
11436
|
+
KNOWN_AUTH_MODES,
|
|
11437
|
+
isKnownAuthMode,
|
|
10756
11438
|
parseArgs,
|
|
10757
11439
|
parseAuthFlag,
|
|
10758
11440
|
parseDualBuildFlag,
|