canopycms 0.0.63 → 0.0.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +153 -19
- package/dist/ai/generate.d.ts +4 -5
- package/dist/ai/generate.js +0 -1
- package/dist/ai/handler.d.ts +3 -4
- package/dist/ai/handler.js +0 -1
- package/dist/ai/index.d.ts +7 -8
- package/dist/ai/index.js +0 -1
- package/dist/ai/json-to-markdown.d.ts +1 -2
- package/dist/ai/json-to-markdown.js +11 -2
- package/dist/ai/resolve-branch.d.ts +1 -2
- package/dist/ai/resolve-branch.js +0 -1
- package/dist/ai/strip-mdx.d.ts +0 -1
- package/dist/ai/strip-mdx.js +0 -1
- package/dist/ai/to-plain-text.d.ts +4 -1
- package/dist/ai/to-plain-text.js +47 -1
- package/dist/ai/transform-components.d.ts +1 -2
- package/dist/ai/transform-components.js +0 -1
- package/dist/ai/types.d.ts +1 -2
- package/dist/ai/types.js +0 -1
- package/dist/api/admin-branch-health.d.ts +7 -8
- package/dist/api/admin-branch-health.js +0 -1
- package/dist/api/admin.d.ts +16 -17
- package/dist/api/admin.js +0 -1
- package/dist/api/assets.d.ts +8 -9
- package/dist/api/assets.js +0 -1
- package/dist/api/branch-merge.d.ts +3 -4
- package/dist/api/branch-merge.js +0 -1
- package/dist/api/branch-review.d.ts +5 -6
- package/dist/api/branch-review.js +0 -1
- package/dist/api/branch-status.d.ts +15 -16
- package/dist/api/branch-status.js +0 -1
- package/dist/api/branch-withdraw.d.ts +3 -4
- package/dist/api/branch-withdraw.js +0 -1
- package/dist/api/branch.d.ts +13 -14
- package/dist/api/branch.js +0 -1
- package/dist/api/client.d.ts +14 -15
- package/dist/api/client.js +0 -1
- package/dist/api/comments.d.ts +11 -12
- package/dist/api/comments.js +0 -1
- package/dist/api/content.d.ts +22 -24
- package/dist/api/content.js +132 -18
- package/dist/api/entries-constants.d.ts +0 -1
- package/dist/api/entries-constants.js +0 -1
- package/dist/api/entries.d.ts +12 -13
- package/dist/api/entries.js +12 -2
- package/dist/api/github-sync.d.ts +2 -3
- package/dist/api/github-sync.js +0 -1
- package/dist/api/groups.d.ts +6 -7
- package/dist/api/groups.js +0 -1
- package/dist/api/guards.d.ts +2 -3
- package/dist/api/guards.js +0 -1
- package/dist/api/index.d.ts +18 -19
- package/dist/api/index.js +0 -1
- package/dist/api/permissions.d.ts +10 -11
- package/dist/api/permissions.js +0 -1
- package/dist/api/reference-options.d.ts +3 -4
- package/dist/api/reference-options.js +0 -1
- package/dist/api/request-body-hash.d.ts +0 -1
- package/dist/api/request-body-hash.js +0 -1
- package/dist/api/resolve-references.d.ts +6 -7
- package/dist/api/resolve-references.js +24 -6
- package/dist/api/route-builder.d.ts +2 -3
- package/dist/api/route-builder.js +0 -1
- package/dist/api/schema.d.ts +43 -44
- package/dist/api/schema.js +0 -1
- package/dist/api/settings-helpers.d.ts +2 -3
- package/dist/api/settings-helpers.js +0 -1
- package/dist/api/types.d.ts +6 -7
- package/dist/api/types.js +0 -1
- package/dist/api/user.d.ts +2 -3
- package/dist/api/user.js +0 -1
- package/dist/api/validators.d.ts +3 -4
- package/dist/api/validators.js +0 -1
- package/dist/assets/asset-prefixes.d.ts +1 -2
- package/dist/assets/asset-prefixes.js +0 -1
- package/dist/assets/asset-src.d.ts +17 -5
- package/dist/assets/asset-src.js +15 -3
- package/dist/assets/asset-url.d.ts +28 -7
- package/dist/assets/asset-url.js +20 -15
- package/dist/assets/factory.d.ts +2 -3
- package/dist/assets/factory.js +0 -2
- package/dist/assets/finalize.d.ts +2 -3
- package/dist/assets/finalize.js +0 -1
- package/dist/assets/index.d.ts +12 -13
- package/dist/assets/index.js +0 -1
- package/dist/assets/keys.d.ts +1 -2
- package/dist/assets/keys.js +0 -1
- package/dist/assets/pipeline.d.ts +1 -2
- package/dist/assets/pipeline.js +0 -1
- package/dist/assets/store-local.d.ts +1 -2
- package/dist/assets/store-local.js +0 -1
- package/dist/assets/store-s3.d.ts +2 -4
- package/dist/assets/store-s3.js +0 -1
- package/dist/assets/svg-sanitizer.d.ts +0 -1
- package/dist/assets/svg-sanitizer.js +0 -1
- package/dist/assets/transform-directives.d.ts +0 -1
- package/dist/assets/transform-directives.js +0 -1
- package/dist/assets/transform.d.ts +1 -2
- package/dist/assets/transform.js +0 -1
- package/dist/assets/types.d.ts +0 -1
- package/dist/assets/types.js +0 -1
- package/dist/auth/cache.d.ts +2 -3
- package/dist/auth/cache.js +0 -1
- package/dist/auth/caching-auth-plugin.d.ts +3 -4
- package/dist/auth/caching-auth-plugin.js +0 -1
- package/dist/auth/context-helpers.d.ts +1 -2
- package/dist/auth/context-helpers.js +0 -1
- package/dist/auth/file-based-auth-cache.d.ts +3 -4
- package/dist/auth/file-based-auth-cache.js +0 -1
- package/dist/auth/index.d.ts +6 -7
- package/dist/auth/index.js +0 -1
- package/dist/auth/plugin.d.ts +3 -4
- package/dist/auth/plugin.js +0 -1
- package/dist/auth/types.d.ts +1 -2
- package/dist/auth/types.js +0 -1
- package/dist/authorization/branch.d.ts +4 -5
- package/dist/authorization/branch.js +0 -1
- package/dist/authorization/content.d.ts +6 -7
- package/dist/authorization/content.js +0 -1
- package/dist/authorization/groups/index.d.ts +2 -3
- package/dist/authorization/groups/index.js +0 -1
- package/dist/authorization/groups/loader.d.ts +3 -4
- package/dist/authorization/groups/loader.js +0 -1
- package/dist/authorization/groups/schema.d.ts +1 -2
- package/dist/authorization/groups/schema.js +0 -1
- package/dist/authorization/helpers.d.ts +0 -1
- package/dist/authorization/helpers.js +0 -1
- package/dist/authorization/index.d.ts +11 -12
- package/dist/authorization/index.js +0 -1
- package/dist/authorization/path.d.ts +4 -5
- package/dist/authorization/path.js +0 -1
- package/dist/authorization/permissions/index.d.ts +2 -3
- package/dist/authorization/permissions/index.js +0 -1
- package/dist/authorization/permissions/loader.d.ts +4 -5
- package/dist/authorization/permissions/loader.js +0 -1
- package/dist/authorization/permissions/schema.d.ts +2 -3
- package/dist/authorization/permissions/schema.js +0 -1
- package/dist/authorization/protected-branch.d.ts +2 -3
- package/dist/authorization/protected-branch.js +0 -1
- package/dist/authorization/settings-file-store.d.ts +1 -2
- package/dist/authorization/settings-file-store.js +0 -1
- package/dist/authorization/types.d.ts +6 -7
- package/dist/authorization/types.js +0 -1
- package/dist/authorization/validation.d.ts +1 -2
- package/dist/authorization/validation.js +0 -1
- package/dist/branch-health.d.ts +2 -3
- package/dist/branch-health.js +0 -1
- package/dist/branch-metadata.d.ts +2 -3
- package/dist/branch-metadata.js +0 -1
- package/dist/branch-registry.d.ts +1 -2
- package/dist/branch-registry.js +0 -1
- package/dist/branch-schema-cache.d.ts +4 -5
- package/dist/branch-schema-cache.js +0 -1
- package/dist/branch-workspace.d.ts +4 -5
- package/dist/branch-workspace.js +0 -1
- package/dist/build/generate-ai-content.d.ts +21 -5
- package/dist/build/generate-ai-content.js +98 -6
- package/dist/build/index.d.ts +2 -3
- package/dist/build/index.js +0 -1
- package/dist/build-canopy.d.ts +5 -6
- package/dist/build-canopy.js +0 -1
- package/dist/build-mode.d.ts +1 -2
- package/dist/build-mode.js +0 -1
- package/dist/cli/cli.d.ts +1 -2
- package/dist/cli/cli.js +1131 -486
- package/dist/cli/generate-ai-content.d.ts +0 -1
- package/dist/cli/generate-ai-content.js +1000 -360
- package/dist/cli/init.d.ts +1 -2
- package/dist/cli/init.js +12 -2
- package/dist/cli/migrate.d.ts +5 -3
- package/dist/cli/migrate.js +5 -3
- package/dist/cli/project-detect.d.ts +5 -2
- package/dist/cli/project-detect.js +5 -1
- package/dist/cli/project-root.d.ts +0 -1
- package/dist/cli/project-root.js +0 -1
- package/dist/cli/sync.d.ts +0 -1
- package/dist/cli/sync.js +0 -1
- package/dist/cli/template-files/deploy-cms.yml.template +8 -6
- package/dist/cli/templates.d.ts +0 -1
- package/dist/cli/templates.js +0 -1
- package/dist/client.d.ts +13 -14
- package/dist/client.js +0 -1
- package/dist/comment-store.d.ts +0 -1
- package/dist/comment-store.js +0 -1
- package/dist/config/flatten.d.ts +1 -2
- package/dist/config/flatten.js +0 -1
- package/dist/config/helpers.d.ts +3 -4
- package/dist/config/helpers.js +2 -2
- package/dist/config/index.d.ts +10 -11
- package/dist/config/index.js +0 -1
- package/dist/config/schemas/collection.d.ts +0 -1
- package/dist/config/schemas/collection.js +0 -1
- package/dist/config/schemas/config.d.ts +7 -4
- package/dist/config/schemas/config.js +12 -1
- package/dist/config/schemas/field.d.ts +3 -1
- package/dist/config/schemas/field.js +5 -1
- package/dist/config/schemas/media.d.ts +0 -1
- package/dist/config/schemas/media.js +0 -1
- package/dist/config/schemas/permissions.d.ts +0 -1
- package/dist/config/schemas/permissions.js +0 -1
- package/dist/config/types.d.ts +55 -9
- package/dist/config/types.js +0 -1
- package/dist/config/validation.d.ts +1 -2
- package/dist/config/validation.js +0 -1
- package/dist/config.d.ts +2 -3
- package/dist/config.js +0 -1
- package/dist/content-id-index.d.ts +1 -2
- package/dist/content-id-index.js +0 -1
- package/dist/content-index-generation.d.ts +0 -1
- package/dist/content-index-generation.js +0 -1
- package/dist/content-index-registry.d.ts +0 -1
- package/dist/content-index-registry.js +0 -1
- package/dist/content-listing.d.ts +75 -59
- package/dist/content-listing.js +76 -83
- package/dist/content-reader.d.ts +4 -5
- package/dist/content-reader.js +22 -3
- package/dist/content-store.d.ts +137 -6
- package/dist/content-store.js +294 -22
- package/dist/content-tree.d.ts +15 -5
- package/dist/content-tree.js +27 -8
- package/dist/context.d.ts +9 -6
- package/dist/context.js +0 -1
- package/dist/dev-content-watcher.d.ts +2 -3
- package/dist/dev-content-watcher.js +0 -1
- package/dist/editor/BranchManager.d.ts +4 -5
- package/dist/editor/BranchManager.js +0 -1
- package/dist/editor/CanopyEditor.d.ts +2 -3
- package/dist/editor/CanopyEditor.js +1 -2
- package/dist/editor/CanopyEditorPage.d.ts +2 -3
- package/dist/editor/CanopyEditorPage.js +0 -1
- package/dist/editor/CommentsPanel.d.ts +2 -3
- package/dist/editor/CommentsPanel.js +0 -1
- package/dist/editor/Editor.d.ts +13 -8
- package/dist/editor/Editor.js +4 -5
- package/dist/editor/EditorPanes.d.ts +0 -1
- package/dist/editor/EditorPanes.js +0 -1
- package/dist/editor/EntryNavigator.d.ts +1 -2
- package/dist/editor/EntryNavigator.js +0 -1
- package/dist/editor/FormRenderer.d.ts +2 -3
- package/dist/editor/FormRenderer.js +22 -3
- package/dist/editor/GroupManager.d.ts +2 -3
- package/dist/editor/GroupManager.js +0 -1
- package/dist/editor/PermissionManager.d.ts +2 -3
- package/dist/editor/PermissionManager.js +0 -1
- package/dist/editor/admin/SystemHealthPanel.d.ts +0 -1
- package/dist/editor/admin/SystemHealthPanel.js +0 -1
- package/dist/editor/admin/useSystemHealth.d.ts +2 -3
- package/dist/editor/admin/useSystemHealth.js +0 -1
- package/dist/editor/canopy-path.d.ts +0 -1
- package/dist/editor/canopy-path.js +0 -1
- package/dist/editor/client-reference-resolver.d.ts +13 -4
- package/dist/editor/client-reference-resolver.js +18 -8
- package/dist/editor/comments/BranchComments.d.ts +2 -3
- package/dist/editor/comments/BranchComments.js +0 -1
- package/dist/editor/comments/EntryComments.d.ts +1 -2
- package/dist/editor/comments/EntryComments.js +0 -1
- package/dist/editor/comments/FieldWrapper.d.ts +1 -2
- package/dist/editor/comments/FieldWrapper.js +0 -1
- package/dist/editor/comments/InlineCommentThread.d.ts +2 -3
- package/dist/editor/comments/InlineCommentThread.js +0 -1
- package/dist/editor/comments/ThreadCarousel.d.ts +2 -3
- package/dist/editor/comments/ThreadCarousel.js +0 -1
- package/dist/editor/components/ConfirmDeleteModal.d.ts +0 -1
- package/dist/editor/components/ConfirmDeleteModal.js +0 -1
- package/dist/editor/components/EditorFooter.d.ts +0 -1
- package/dist/editor/components/EditorFooter.js +0 -1
- package/dist/editor/components/EditorHeader.d.ts +4 -5
- package/dist/editor/components/EditorHeader.js +0 -1
- package/dist/editor/components/EditorSidebar.d.ts +1 -2
- package/dist/editor/components/EditorSidebar.js +0 -1
- package/dist/editor/components/EntryCreateModal.d.ts +0 -1
- package/dist/editor/components/EntryCreateModal.js +21 -10
- package/dist/editor/components/RenameEntryModal.d.ts +0 -1
- package/dist/editor/components/RenameEntryModal.js +0 -1
- package/dist/editor/components/UserBadge.d.ts +2 -3
- package/dist/editor/components/UserBadge.js +0 -1
- package/dist/editor/components/index.d.ts +3 -4
- package/dist/editor/components/index.js +0 -1
- package/dist/editor/context/ApiClientContext.d.ts +9 -3
- package/dist/editor/context/ApiClientContext.js +8 -4
- package/dist/editor/context/AssetContext.d.ts +26 -2
- package/dist/editor/context/AssetContext.js +23 -3
- package/dist/editor/context/EditorStateContext.d.ts +1 -2
- package/dist/editor/context/EditorStateContext.js +0 -1
- package/dist/editor/context/SWRProvider.d.ts +0 -1
- package/dist/editor/context/SWRProvider.js +0 -1
- package/dist/editor/context/index.d.ts +4 -5
- package/dist/editor/context/index.js +0 -1
- package/dist/editor/editor-config.d.ts +2 -3
- package/dist/editor/editor-config.js +0 -1
- package/dist/editor/editor-utils.d.ts +22 -10
- package/dist/editor/editor-utils.js +41 -10
- package/dist/editor/fields/BlockField.d.ts +1 -2
- package/dist/editor/fields/BlockField.js +0 -1
- package/dist/editor/fields/CodeField.d.ts +0 -1
- package/dist/editor/fields/CodeField.js +0 -1
- package/dist/editor/fields/DateTimeField.d.ts +0 -1
- package/dist/editor/fields/DateTimeField.js +0 -1
- package/dist/editor/fields/ImageField.d.ts +1 -2
- package/dist/editor/fields/ImageField.js +0 -1
- package/dist/editor/fields/InlineGroupField.d.ts +2 -3
- package/dist/editor/fields/InlineGroupField.js +0 -1
- package/dist/editor/fields/MarkdownField.d.ts +0 -1
- package/dist/editor/fields/MarkdownField.js +0 -1
- package/dist/editor/fields/MdxImageDialog.d.ts +0 -1
- package/dist/editor/fields/MdxImageDialog.js +0 -1
- package/dist/editor/fields/NumberField.d.ts +0 -1
- package/dist/editor/fields/NumberField.js +0 -1
- package/dist/editor/fields/NumberListField.d.ts +0 -1
- package/dist/editor/fields/NumberListField.js +0 -1
- package/dist/editor/fields/ObjectField.d.ts +11 -2
- package/dist/editor/fields/ObjectField.js +3 -4
- package/dist/editor/fields/ReferenceField.d.ts +0 -1
- package/dist/editor/fields/ReferenceField.js +8 -3
- package/dist/editor/fields/SelectField.d.ts +0 -1
- package/dist/editor/fields/SelectField.js +0 -1
- package/dist/editor/fields/StringListField.d.ts +0 -1
- package/dist/editor/fields/StringListField.js +0 -1
- package/dist/editor/fields/TextField.d.ts +0 -1
- package/dist/editor/fields/TextField.js +0 -1
- package/dist/editor/fields/ToggleField.d.ts +0 -1
- package/dist/editor/fields/ToggleField.js +0 -1
- package/dist/editor/fields/entry-link/EntryLinkContext.d.ts +1 -2
- package/dist/editor/fields/entry-link/EntryLinkContext.js +0 -1
- package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +0 -1
- package/dist/editor/fields/entry-link/InsertEntryLink.js +0 -1
- package/dist/editor/fields/entry-link/index.d.ts +2 -3
- package/dist/editor/fields/entry-link/index.js +0 -1
- package/dist/editor/group-manager/ExternalGroupsTab.d.ts +1 -2
- package/dist/editor/group-manager/ExternalGroupsTab.js +0 -1
- package/dist/editor/group-manager/GroupCard.d.ts +1 -2
- package/dist/editor/group-manager/GroupCard.js +0 -1
- package/dist/editor/group-manager/GroupForm.d.ts +1 -2
- package/dist/editor/group-manager/GroupForm.js +0 -1
- package/dist/editor/group-manager/InternalGroupsTab.d.ts +1 -2
- package/dist/editor/group-manager/InternalGroupsTab.js +0 -1
- package/dist/editor/group-manager/MemberList.d.ts +1 -2
- package/dist/editor/group-manager/MemberList.js +0 -1
- package/dist/editor/group-manager/hooks/useExternalGroupSearch.d.ts +1 -2
- package/dist/editor/group-manager/hooks/useExternalGroupSearch.js +0 -1
- package/dist/editor/group-manager/hooks/useGroupState.d.ts +1 -2
- package/dist/editor/group-manager/hooks/useGroupState.js +0 -1
- package/dist/editor/group-manager/hooks/useUserSearch.d.ts +1 -2
- package/dist/editor/group-manager/hooks/useUserSearch.js +0 -1
- package/dist/editor/group-manager/index.d.ts +5 -6
- package/dist/editor/group-manager/index.js +0 -1
- package/dist/editor/group-manager/types.d.ts +4 -5
- package/dist/editor/group-manager/types.js +0 -1
- package/dist/editor/hooks/index.d.ts +14 -15
- package/dist/editor/hooks/index.js +0 -1
- package/dist/editor/hooks/useBranchActions.d.ts +0 -1
- package/dist/editor/hooks/useBranchActions.js +0 -1
- package/dist/editor/hooks/useBranchManager.d.ts +4 -5
- package/dist/editor/hooks/useBranchManager.js +0 -1
- package/dist/editor/hooks/useBranchesData.d.ts +2 -3
- package/dist/editor/hooks/useBranchesData.js +0 -1
- package/dist/editor/hooks/useCommentSystem.d.ts +2 -3
- package/dist/editor/hooks/useCommentSystem.js +0 -1
- package/dist/editor/hooks/useCommentsData.d.ts +2 -3
- package/dist/editor/hooks/useCommentsData.js +0 -1
- package/dist/editor/hooks/useDraftManager.d.ts +3 -4
- package/dist/editor/hooks/useDraftManager.js +0 -1
- package/dist/editor/hooks/useEditorLayout.d.ts +1 -2
- package/dist/editor/hooks/useEditorLayout.js +0 -1
- package/dist/editor/hooks/useEntriesData.d.ts +3 -5
- package/dist/editor/hooks/useEntriesData.js +0 -3
- package/dist/editor/hooks/useEntryLinkResolution.d.ts +2 -3
- package/dist/editor/hooks/useEntryLinkResolution.js +0 -1
- package/dist/editor/hooks/useEntryManager.d.ts +5 -7
- package/dist/editor/hooks/useEntryManager.js +8 -3
- package/dist/editor/hooks/useGroupManager.d.ts +2 -3
- package/dist/editor/hooks/useGroupManager.js +0 -1
- package/dist/editor/hooks/usePermissionManager.d.ts +2 -3
- package/dist/editor/hooks/usePermissionManager.js +0 -1
- package/dist/editor/hooks/useReferenceResolution.d.ts +1 -2
- package/dist/editor/hooks/useReferenceResolution.js +8 -3
- package/dist/editor/hooks/useSchemaManager.d.ts +2 -3
- package/dist/editor/hooks/useSchemaManager.js +0 -1
- package/dist/editor/hooks/useUserContext.d.ts +1 -2
- package/dist/editor/hooks/useUserContext.js +8 -3
- package/dist/editor/hooks/useUserMetadata.d.ts +2 -3
- package/dist/editor/hooks/useUserMetadata.js +0 -1
- package/dist/editor/media/AssetCard.d.ts +1 -2
- package/dist/editor/media/AssetCard.js +0 -1
- package/dist/editor/media/CropStep.d.ts +1 -2
- package/dist/editor/media/CropStep.js +0 -1
- package/dist/editor/media/MediaLibrary.d.ts +1 -2
- package/dist/editor/media/MediaLibrary.js +0 -1
- package/dist/editor/media/MediaLibraryBody.d.ts +1 -2
- package/dist/editor/media/MediaLibraryBody.js +0 -1
- package/dist/editor/media/crop-math.d.ts +1 -2
- package/dist/editor/media/crop-math.js +0 -1
- package/dist/editor/media/upload-asset.d.ts +2 -3
- package/dist/editor/media/upload-asset.js +0 -1
- package/dist/editor/media/upload-constants.d.ts +0 -1
- package/dist/editor/media/upload-constants.js +0 -1
- package/dist/editor/media/useAssetUpload.d.ts +1 -2
- package/dist/editor/media/useAssetUpload.js +0 -1
- package/dist/editor/media/xhr-upload.d.ts +0 -1
- package/dist/editor/media/xhr-upload.js +0 -1
- package/dist/editor/permission-manager/GroupSelector.d.ts +1 -2
- package/dist/editor/permission-manager/GroupSelector.js +0 -1
- package/dist/editor/permission-manager/PermissionEditor.d.ts +1 -2
- package/dist/editor/permission-manager/PermissionEditor.js +0 -1
- package/dist/editor/permission-manager/PermissionLevelBadge.d.ts +1 -2
- package/dist/editor/permission-manager/PermissionLevelBadge.js +0 -1
- package/dist/editor/permission-manager/PermissionTree.d.ts +1 -2
- package/dist/editor/permission-manager/PermissionTree.js +0 -1
- package/dist/editor/permission-manager/UserSelector.d.ts +1 -2
- package/dist/editor/permission-manager/UserSelector.js +0 -1
- package/dist/editor/permission-manager/constants.d.ts +1 -2
- package/dist/editor/permission-manager/constants.js +0 -1
- package/dist/editor/permission-manager/hooks/useGroupsAndUsers.d.ts +1 -2
- package/dist/editor/permission-manager/hooks/useGroupsAndUsers.js +0 -1
- package/dist/editor/permission-manager/hooks/usePermissionTree.d.ts +2 -3
- package/dist/editor/permission-manager/hooks/usePermissionTree.js +0 -1
- package/dist/editor/permission-manager/index.d.ts +4 -5
- package/dist/editor/permission-manager/index.js +0 -1
- package/dist/editor/permission-manager/types.d.ts +3 -4
- package/dist/editor/permission-manager/types.js +0 -1
- package/dist/editor/permission-manager/utils.d.ts +2 -3
- package/dist/editor/permission-manager/utils.js +0 -1
- package/dist/editor/preview-bridge.d.ts +1 -2
- package/dist/editor/preview-bridge.js +0 -1
- package/dist/editor/relative-time.d.ts +0 -1
- package/dist/editor/relative-time.js +0 -1
- package/dist/editor/schema-editor/CollectionEditor.d.ts +4 -5
- package/dist/editor/schema-editor/CollectionEditor.js +0 -1
- package/dist/editor/schema-editor/EntryTypeEditor.d.ts +2 -3
- package/dist/editor/schema-editor/EntryTypeEditor.js +0 -1
- package/dist/editor/schema-editor/index.d.ts +2 -3
- package/dist/editor/schema-editor/index.js +0 -1
- package/dist/editor/theme.d.ts +0 -1
- package/dist/editor/theme.js +0 -1
- package/dist/editor/utils/env.d.ts +0 -1
- package/dist/editor/utils/env.js +0 -1
- package/dist/entry-link-resolver.d.ts +1 -2
- package/dist/entry-link-resolver.js +0 -1
- package/dist/entry-schema-registry.d.ts +3 -4
- package/dist/entry-schema-registry.js +6 -2
- package/dist/entry-schema.d.ts +114 -3
- package/dist/entry-schema.js +46 -1
- package/dist/git-manager.d.ts +1 -2
- package/dist/git-manager.js +0 -1
- package/dist/github-service.d.ts +1 -2
- package/dist/github-service.js +0 -1
- package/dist/http/handler.d.ts +6 -7
- package/dist/http/handler.js +0 -1
- package/dist/http/index.d.ts +6 -7
- package/dist/http/index.js +0 -1
- package/dist/http/router.d.ts +2 -3
- package/dist/http/router.js +0 -1
- package/dist/http/types.d.ts +0 -1
- package/dist/http/types.js +0 -1
- package/dist/id.d.ts +2 -3
- package/dist/id.js +0 -1
- package/dist/index.d.ts +17 -18
- package/dist/index.js +0 -1
- package/dist/operating-mode/client-safe-strategy.d.ts +1 -2
- package/dist/operating-mode/client-safe-strategy.js +0 -1
- package/dist/operating-mode/client-unsafe-strategy.d.ts +1 -2
- package/dist/operating-mode/client-unsafe-strategy.js +0 -1
- package/dist/operating-mode/client.d.ts +3 -4
- package/dist/operating-mode/client.js +0 -1
- package/dist/operating-mode/deployment-name-fixtures.d.ts +0 -1
- package/dist/operating-mode/deployment-name-fixtures.js +0 -1
- package/dist/operating-mode/deployment-name.d.ts +0 -1
- package/dist/operating-mode/deployment-name.js +0 -1
- package/dist/operating-mode/index.d.ts +5 -6
- package/dist/operating-mode/index.js +0 -1
- package/dist/operating-mode/mode-env.d.ts +1 -2
- package/dist/operating-mode/mode-env.js +0 -1
- package/dist/operating-mode/types.d.ts +2 -3
- package/dist/operating-mode/types.js +0 -1
- package/dist/paths/branch-name.d.ts +1 -2
- package/dist/paths/branch-name.js +0 -1
- package/dist/paths/branch.d.ts +3 -4
- package/dist/paths/branch.js +0 -1
- package/dist/paths/index.d.ts +8 -9
- package/dist/paths/index.js +0 -1
- package/dist/paths/normalize-server.d.ts +1 -2
- package/dist/paths/normalize-server.js +0 -1
- package/dist/paths/normalize.d.ts +1 -2
- package/dist/paths/normalize.js +0 -1
- package/dist/paths/resolve.d.ts +2 -3
- package/dist/paths/resolve.js +0 -1
- package/dist/paths/types.d.ts +0 -1
- package/dist/paths/types.js +0 -1
- package/dist/paths/validation.d.ts +1 -2
- package/dist/paths/validation.js +0 -1
- package/dist/reference-resolver.d.ts +3 -4
- package/dist/reference-resolver.js +0 -1
- package/dist/resolve-canopy-user.d.ts +3 -4
- package/dist/resolve-canopy-user.js +0 -1
- package/dist/resource-generation.d.ts +0 -1
- package/dist/resource-generation.js +0 -1
- package/dist/schema/index.d.ts +3 -4
- package/dist/schema/index.js +0 -1
- package/dist/schema/meta-loader.d.ts +3 -4
- package/dist/schema/meta-loader.js +3 -3
- package/dist/schema/resolver.d.ts +2 -3
- package/dist/schema/resolver.js +0 -1
- package/dist/schema/schema-store-types.d.ts +2 -3
- package/dist/schema/schema-store-types.js +0 -1
- package/dist/schema/schema-store.d.ts +6 -7
- package/dist/schema/schema-store.js +33 -1
- package/dist/schema/types.d.ts +1 -2
- package/dist/schema/types.js +0 -1
- package/dist/server.d.ts +54 -45
- package/dist/server.js +11 -3
- package/dist/services.d.ts +10 -11
- package/dist/services.js +0 -1
- package/dist/settings-workspace.d.ts +12 -15
- package/dist/settings-workspace.js +10 -13
- package/dist/static/index.d.ts +164 -6
- package/dist/static/index.js +242 -7
- package/dist/static/seo.d.ts +8 -30
- package/dist/static/seo.js +19 -46
- package/dist/sync-core.d.ts +0 -1
- package/dist/sync-core.js +0 -1
- package/dist/task-queue/index.d.ts +2 -3
- package/dist/task-queue/index.js +0 -1
- package/dist/task-queue/task-queue.d.ts +1 -2
- package/dist/task-queue/task-queue.js +0 -1
- package/dist/task-queue/types.d.ts +0 -1
- package/dist/task-queue/types.js +0 -1
- package/dist/types.d.ts +3 -4
- package/dist/types.js +0 -1
- package/dist/url-collision.d.ts +86 -0
- package/dist/url-collision.js +186 -0
- package/dist/url-path-resolver.d.ts +11 -2
- package/dist/url-path-resolver.js +37 -5
- package/dist/user.d.ts +3 -4
- package/dist/user.js +0 -1
- package/dist/utils/async-mutex.d.ts +0 -1
- package/dist/utils/async-mutex.js +0 -1
- package/dist/utils/atomic-write.d.ts +0 -1
- package/dist/utils/atomic-write.js +0 -1
- package/dist/utils/body-field.d.ts +12 -2
- package/dist/utils/body-field.js +17 -1
- package/dist/utils/content-serialize.d.ts +37 -0
- package/dist/utils/content-serialize.js +429 -0
- package/dist/utils/content-write-lock.d.ts +12 -16
- package/dist/utils/content-write-lock.js +38 -22
- package/dist/utils/debug.d.ts +0 -1
- package/dist/utils/debug.js +0 -1
- package/dist/utils/entry-url.d.ts +17 -1
- package/dist/utils/entry-url.js +21 -3
- package/dist/utils/error.d.ts +0 -1
- package/dist/utils/error.js +0 -1
- package/dist/utils/flatten-group-fields.d.ts +1 -2
- package/dist/utils/flatten-group-fields.js +0 -1
- package/dist/utils/format.d.ts +1 -2
- package/dist/utils/format.js +0 -1
- package/dist/utils/fs.d.ts +7 -1
- package/dist/utils/fs.js +16 -1
- package/dist/utils/git.d.ts +1 -2
- package/dist/utils/git.js +0 -1
- package/dist/utils/logger.d.ts +0 -1
- package/dist/utils/logger.js +0 -1
- package/dist/utils/occ-json-write.d.ts +0 -1
- package/dist/utils/occ-json-write.js +0 -1
- package/dist/utils/provisioning-lock.d.ts +17 -4
- package/dist/utils/provisioning-lock.js +94 -14
- package/dist/utils/sanitize-href.d.ts +2 -3
- package/dist/utils/sanitize-href.js +2 -3
- package/dist/utils/title-field.d.ts +1 -2
- package/dist/utils/title-field.js +0 -1
- package/dist/utils/typed-filename.d.ts +61 -0
- package/dist/utils/typed-filename.js +92 -0
- package/dist/utils/url-prefix.d.ts +121 -0
- package/dist/utils/url-prefix.js +158 -0
- package/dist/validation/block-structural-keys.d.ts +42 -0
- package/dist/validation/block-structural-keys.js +44 -0
- package/dist/validation/deletion-checker.d.ts +4 -5
- package/dist/validation/deletion-checker.js +0 -1
- package/dist/validation/entry-link-validator.d.ts +2 -3
- package/dist/validation/entry-link-validator.js +0 -1
- package/dist/validation/entry-type-reference-validator.d.ts +1 -2
- package/dist/validation/entry-type-reference-validator.js +0 -1
- package/dist/validation/entry-validator.d.ts +23 -2
- package/dist/validation/entry-validator.js +34 -2
- package/dist/validation/field-traversal.d.ts +28 -4
- package/dist/validation/field-traversal.js +24 -7
- package/dist/validation/reference-validator.d.ts +2 -3
- package/dist/validation/reference-validator.js +0 -1
- package/dist/worker/cms-worker.d.ts +9 -2
- package/dist/worker/cms-worker.js +59 -2
- package/dist/worker/log.d.ts +0 -1
- package/dist/worker/log.js +0 -1
- package/dist/worker/task-queue-config.d.ts +1 -2
- package/dist/worker/task-queue-config.js +0 -1
- package/dist/worker/task-queue.d.ts +3 -4
- package/dist/worker/task-queue.js +0 -1
- package/dist/worker/worker-status.d.ts +1 -2
- package/dist/worker/worker-status.js +0 -1
- package/package.json +2 -6
- package/dist/ai/generate.d.ts.map +0 -1
- package/dist/ai/generate.js.map +0 -1
- package/dist/ai/handler.d.ts.map +0 -1
- package/dist/ai/handler.js.map +0 -1
- package/dist/ai/index.d.ts.map +0 -1
- package/dist/ai/index.js.map +0 -1
- package/dist/ai/json-to-markdown.d.ts.map +0 -1
- package/dist/ai/json-to-markdown.js.map +0 -1
- package/dist/ai/resolve-branch.d.ts.map +0 -1
- package/dist/ai/resolve-branch.js.map +0 -1
- package/dist/ai/strip-mdx.d.ts.map +0 -1
- package/dist/ai/strip-mdx.js.map +0 -1
- package/dist/ai/to-plain-text.d.ts.map +0 -1
- package/dist/ai/to-plain-text.js.map +0 -1
- package/dist/ai/transform-components.d.ts.map +0 -1
- package/dist/ai/transform-components.js.map +0 -1
- package/dist/ai/types.d.ts.map +0 -1
- package/dist/ai/types.js.map +0 -1
- package/dist/api/__test__/mock-client.d.ts +0 -231
- package/dist/api/__test__/mock-client.d.ts.map +0 -1
- package/dist/api/__test__/mock-client.js +0 -388
- package/dist/api/__test__/mock-client.js.map +0 -1
- package/dist/api/admin-branch-health.d.ts.map +0 -1
- package/dist/api/admin-branch-health.js.map +0 -1
- package/dist/api/admin.d.ts.map +0 -1
- package/dist/api/admin.js.map +0 -1
- package/dist/api/assets.d.ts.map +0 -1
- package/dist/api/assets.js.map +0 -1
- package/dist/api/branch-merge.d.ts.map +0 -1
- package/dist/api/branch-merge.js.map +0 -1
- package/dist/api/branch-review.d.ts.map +0 -1
- package/dist/api/branch-review.js.map +0 -1
- package/dist/api/branch-status.d.ts.map +0 -1
- package/dist/api/branch-status.js.map +0 -1
- package/dist/api/branch-withdraw.d.ts.map +0 -1
- package/dist/api/branch-withdraw.js.map +0 -1
- package/dist/api/branch.d.ts.map +0 -1
- package/dist/api/branch.js.map +0 -1
- package/dist/api/client.d.ts.map +0 -1
- package/dist/api/client.js.map +0 -1
- package/dist/api/comments.d.ts.map +0 -1
- package/dist/api/comments.js.map +0 -1
- package/dist/api/content.d.ts.map +0 -1
- package/dist/api/content.js.map +0 -1
- package/dist/api/entries-constants.d.ts.map +0 -1
- package/dist/api/entries-constants.js.map +0 -1
- package/dist/api/entries.d.ts.map +0 -1
- package/dist/api/entries.js.map +0 -1
- package/dist/api/github-sync.d.ts.map +0 -1
- package/dist/api/github-sync.js.map +0 -1
- package/dist/api/groups.d.ts.map +0 -1
- package/dist/api/groups.js.map +0 -1
- package/dist/api/guards.d.ts.map +0 -1
- package/dist/api/guards.js.map +0 -1
- package/dist/api/index.d.ts.map +0 -1
- package/dist/api/index.js.map +0 -1
- package/dist/api/permissions.d.ts.map +0 -1
- package/dist/api/permissions.js.map +0 -1
- package/dist/api/reference-options.d.ts.map +0 -1
- package/dist/api/reference-options.js.map +0 -1
- package/dist/api/request-body-hash.d.ts.map +0 -1
- package/dist/api/request-body-hash.js.map +0 -1
- package/dist/api/resolve-references.d.ts.map +0 -1
- package/dist/api/resolve-references.js.map +0 -1
- package/dist/api/route-builder.d.ts.map +0 -1
- package/dist/api/route-builder.js.map +0 -1
- package/dist/api/schema.d.ts.map +0 -1
- package/dist/api/schema.js.map +0 -1
- package/dist/api/settings-helpers.d.ts.map +0 -1
- package/dist/api/settings-helpers.js.map +0 -1
- package/dist/api/types.d.ts.map +0 -1
- package/dist/api/types.js.map +0 -1
- package/dist/api/user.d.ts.map +0 -1
- package/dist/api/user.js.map +0 -1
- package/dist/api/validators.d.ts.map +0 -1
- package/dist/api/validators.js.map +0 -1
- package/dist/assets/asset-prefixes.d.ts.map +0 -1
- package/dist/assets/asset-prefixes.js.map +0 -1
- package/dist/assets/asset-src.d.ts.map +0 -1
- package/dist/assets/asset-src.js.map +0 -1
- package/dist/assets/asset-url.d.ts.map +0 -1
- package/dist/assets/asset-url.js.map +0 -1
- package/dist/assets/factory.d.ts.map +0 -1
- package/dist/assets/factory.js.map +0 -1
- package/dist/assets/finalize.d.ts.map +0 -1
- package/dist/assets/finalize.js.map +0 -1
- package/dist/assets/index.d.ts.map +0 -1
- package/dist/assets/index.js.map +0 -1
- package/dist/assets/keys.d.ts.map +0 -1
- package/dist/assets/keys.js.map +0 -1
- package/dist/assets/pipeline.d.ts.map +0 -1
- package/dist/assets/pipeline.js.map +0 -1
- package/dist/assets/store-local.d.ts.map +0 -1
- package/dist/assets/store-local.js.map +0 -1
- package/dist/assets/store-s3.d.ts.map +0 -1
- package/dist/assets/store-s3.js.map +0 -1
- package/dist/assets/svg-sanitizer.d.ts.map +0 -1
- package/dist/assets/svg-sanitizer.js.map +0 -1
- package/dist/assets/transform-directives.d.ts.map +0 -1
- package/dist/assets/transform-directives.js.map +0 -1
- package/dist/assets/transform.d.ts.map +0 -1
- package/dist/assets/transform.js.map +0 -1
- package/dist/assets/types.d.ts.map +0 -1
- package/dist/assets/types.js.map +0 -1
- package/dist/auth/cache.d.ts.map +0 -1
- package/dist/auth/cache.js.map +0 -1
- package/dist/auth/caching-auth-plugin.d.ts.map +0 -1
- package/dist/auth/caching-auth-plugin.js.map +0 -1
- package/dist/auth/context-helpers.d.ts.map +0 -1
- package/dist/auth/context-helpers.js.map +0 -1
- package/dist/auth/file-based-auth-cache.d.ts.map +0 -1
- package/dist/auth/file-based-auth-cache.js.map +0 -1
- package/dist/auth/index.d.ts.map +0 -1
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/plugin.d.ts.map +0 -1
- package/dist/auth/plugin.js.map +0 -1
- package/dist/auth/types.d.ts.map +0 -1
- package/dist/auth/types.js.map +0 -1
- package/dist/authorization/branch.d.ts.map +0 -1
- package/dist/authorization/branch.js.map +0 -1
- package/dist/authorization/content.d.ts.map +0 -1
- package/dist/authorization/content.js.map +0 -1
- package/dist/authorization/groups/index.d.ts.map +0 -1
- package/dist/authorization/groups/index.js.map +0 -1
- package/dist/authorization/groups/loader.d.ts.map +0 -1
- package/dist/authorization/groups/loader.js.map +0 -1
- package/dist/authorization/groups/schema.d.ts.map +0 -1
- package/dist/authorization/groups/schema.js.map +0 -1
- package/dist/authorization/helpers.d.ts.map +0 -1
- package/dist/authorization/helpers.js.map +0 -1
- package/dist/authorization/index.d.ts.map +0 -1
- package/dist/authorization/index.js.map +0 -1
- package/dist/authorization/path.d.ts.map +0 -1
- package/dist/authorization/path.js.map +0 -1
- package/dist/authorization/permissions/index.d.ts.map +0 -1
- package/dist/authorization/permissions/index.js.map +0 -1
- package/dist/authorization/permissions/loader.d.ts.map +0 -1
- package/dist/authorization/permissions/loader.js.map +0 -1
- package/dist/authorization/permissions/schema.d.ts.map +0 -1
- package/dist/authorization/permissions/schema.js.map +0 -1
- package/dist/authorization/protected-branch.d.ts.map +0 -1
- package/dist/authorization/protected-branch.js.map +0 -1
- package/dist/authorization/settings-file-store.d.ts.map +0 -1
- package/dist/authorization/settings-file-store.js.map +0 -1
- package/dist/authorization/test-utils.d.ts +0 -26
- package/dist/authorization/test-utils.d.ts.map +0 -1
- package/dist/authorization/test-utils.js +0 -23
- package/dist/authorization/test-utils.js.map +0 -1
- package/dist/authorization/types.d.ts.map +0 -1
- package/dist/authorization/types.js.map +0 -1
- package/dist/authorization/validation.d.ts.map +0 -1
- package/dist/authorization/validation.js.map +0 -1
- package/dist/branch-health.d.ts.map +0 -1
- package/dist/branch-health.js.map +0 -1
- package/dist/branch-metadata.d.ts.map +0 -1
- package/dist/branch-metadata.js.map +0 -1
- package/dist/branch-registry.d.ts.map +0 -1
- package/dist/branch-registry.js.map +0 -1
- package/dist/branch-schema-cache.d.ts.map +0 -1
- package/dist/branch-schema-cache.js.map +0 -1
- package/dist/branch-workspace.d.ts.map +0 -1
- package/dist/branch-workspace.js.map +0 -1
- package/dist/build/generate-ai-content.d.ts.map +0 -1
- package/dist/build/generate-ai-content.js.map +0 -1
- package/dist/build/index.d.ts.map +0 -1
- package/dist/build/index.js.map +0 -1
- package/dist/build-canopy.d.ts.map +0 -1
- package/dist/build-canopy.js.map +0 -1
- package/dist/build-mode.d.ts.map +0 -1
- package/dist/build-mode.js.map +0 -1
- package/dist/cli/cli.d.ts.map +0 -1
- package/dist/cli/cli.js.map +0 -1
- package/dist/cli/generate-ai-content.d.ts.map +0 -1
- package/dist/cli/generate-ai-content.js.map +0 -1
- package/dist/cli/init.d.ts.map +0 -1
- package/dist/cli/init.js.map +0 -1
- package/dist/cli/migrate.d.ts.map +0 -1
- package/dist/cli/migrate.js.map +0 -1
- package/dist/cli/project-detect.d.ts.map +0 -1
- package/dist/cli/project-detect.js.map +0 -1
- package/dist/cli/project-root.d.ts.map +0 -1
- package/dist/cli/project-root.js.map +0 -1
- package/dist/cli/sync.d.ts.map +0 -1
- package/dist/cli/sync.js.map +0 -1
- package/dist/cli/templates.d.ts.map +0 -1
- package/dist/cli/templates.js.map +0 -1
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js.map +0 -1
- package/dist/comment-store.d.ts.map +0 -1
- package/dist/comment-store.js.map +0 -1
- package/dist/config/flatten.d.ts.map +0 -1
- package/dist/config/flatten.js.map +0 -1
- package/dist/config/helpers.d.ts.map +0 -1
- package/dist/config/helpers.js.map +0 -1
- package/dist/config/index.d.ts.map +0 -1
- package/dist/config/index.js.map +0 -1
- package/dist/config/schemas/collection.d.ts.map +0 -1
- package/dist/config/schemas/collection.js.map +0 -1
- package/dist/config/schemas/config.d.ts.map +0 -1
- package/dist/config/schemas/config.js.map +0 -1
- package/dist/config/schemas/field.d.ts.map +0 -1
- package/dist/config/schemas/field.js.map +0 -1
- package/dist/config/schemas/media.d.ts.map +0 -1
- package/dist/config/schemas/media.js.map +0 -1
- package/dist/config/schemas/permissions.d.ts.map +0 -1
- package/dist/config/schemas/permissions.js.map +0 -1
- package/dist/config/types.d.ts.map +0 -1
- package/dist/config/types.js.map +0 -1
- package/dist/config/validation.d.ts.map +0 -1
- package/dist/config/validation.js.map +0 -1
- package/dist/config-test.d.ts +0 -20
- package/dist/config-test.d.ts.map +0 -1
- package/dist/config-test.js +0 -49
- package/dist/config-test.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/content-id-index.d.ts.map +0 -1
- package/dist/content-id-index.js.map +0 -1
- package/dist/content-index-generation.d.ts.map +0 -1
- package/dist/content-index-generation.js.map +0 -1
- package/dist/content-index-registry.d.ts.map +0 -1
- package/dist/content-index-registry.js.map +0 -1
- package/dist/content-listing.d.ts.map +0 -1
- package/dist/content-listing.js.map +0 -1
- package/dist/content-reader.d.ts.map +0 -1
- package/dist/content-reader.js.map +0 -1
- package/dist/content-store.d.ts.map +0 -1
- package/dist/content-store.js.map +0 -1
- package/dist/content-tree.d.ts.map +0 -1
- package/dist/content-tree.js.map +0 -1
- package/dist/context.d.ts.map +0 -1
- package/dist/context.js.map +0 -1
- package/dist/dev-content-watcher.d.ts.map +0 -1
- package/dist/dev-content-watcher.js.map +0 -1
- package/dist/editor/BranchManager.d.ts.map +0 -1
- package/dist/editor/BranchManager.js.map +0 -1
- package/dist/editor/CanopyEditor.d.ts.map +0 -1
- package/dist/editor/CanopyEditor.js.map +0 -1
- package/dist/editor/CanopyEditorPage.d.ts.map +0 -1
- package/dist/editor/CanopyEditorPage.js.map +0 -1
- package/dist/editor/CommentsPanel.d.ts.map +0 -1
- package/dist/editor/CommentsPanel.js.map +0 -1
- package/dist/editor/Editor.d.ts.map +0 -1
- package/dist/editor/Editor.js.map +0 -1
- package/dist/editor/EditorPanes.d.ts.map +0 -1
- package/dist/editor/EditorPanes.js.map +0 -1
- package/dist/editor/EntryNavigator.d.ts.map +0 -1
- package/dist/editor/EntryNavigator.js.map +0 -1
- package/dist/editor/FormRenderer.d.ts.map +0 -1
- package/dist/editor/FormRenderer.js.map +0 -1
- package/dist/editor/GroupManager.d.ts.map +0 -1
- package/dist/editor/GroupManager.js.map +0 -1
- package/dist/editor/PermissionManager.d.ts.map +0 -1
- package/dist/editor/PermissionManager.js.map +0 -1
- package/dist/editor/admin/SystemHealthPanel.d.ts.map +0 -1
- package/dist/editor/admin/SystemHealthPanel.js.map +0 -1
- package/dist/editor/admin/useSystemHealth.d.ts.map +0 -1
- package/dist/editor/admin/useSystemHealth.js.map +0 -1
- package/dist/editor/canopy-path.d.ts.map +0 -1
- package/dist/editor/canopy-path.js.map +0 -1
- package/dist/editor/client-reference-resolver.d.ts.map +0 -1
- package/dist/editor/client-reference-resolver.js.map +0 -1
- package/dist/editor/comments/BranchComments.d.ts.map +0 -1
- package/dist/editor/comments/BranchComments.js.map +0 -1
- package/dist/editor/comments/EntryComments.d.ts.map +0 -1
- package/dist/editor/comments/EntryComments.js.map +0 -1
- package/dist/editor/comments/FieldWrapper.d.ts.map +0 -1
- package/dist/editor/comments/FieldWrapper.js.map +0 -1
- package/dist/editor/comments/InlineCommentThread.d.ts.map +0 -1
- package/dist/editor/comments/InlineCommentThread.js.map +0 -1
- package/dist/editor/comments/ThreadCarousel.d.ts.map +0 -1
- package/dist/editor/comments/ThreadCarousel.js.map +0 -1
- package/dist/editor/components/ConfirmDeleteModal.d.ts.map +0 -1
- package/dist/editor/components/ConfirmDeleteModal.js.map +0 -1
- package/dist/editor/components/EditorFooter.d.ts.map +0 -1
- package/dist/editor/components/EditorFooter.js.map +0 -1
- package/dist/editor/components/EditorHeader.d.ts.map +0 -1
- package/dist/editor/components/EditorHeader.js.map +0 -1
- package/dist/editor/components/EditorSidebar.d.ts.map +0 -1
- package/dist/editor/components/EditorSidebar.js.map +0 -1
- package/dist/editor/components/EntryCreateModal.d.ts.map +0 -1
- package/dist/editor/components/EntryCreateModal.js.map +0 -1
- package/dist/editor/components/RenameEntryModal.d.ts.map +0 -1
- package/dist/editor/components/RenameEntryModal.js.map +0 -1
- package/dist/editor/components/UserBadge.d.ts.map +0 -1
- package/dist/editor/components/UserBadge.js.map +0 -1
- package/dist/editor/components/index.d.ts.map +0 -1
- package/dist/editor/components/index.js.map +0 -1
- package/dist/editor/context/ApiClientContext.d.ts.map +0 -1
- package/dist/editor/context/ApiClientContext.js.map +0 -1
- package/dist/editor/context/AssetContext.d.ts.map +0 -1
- package/dist/editor/context/AssetContext.js.map +0 -1
- package/dist/editor/context/EditorStateContext.d.ts.map +0 -1
- package/dist/editor/context/EditorStateContext.js.map +0 -1
- package/dist/editor/context/SWRProvider.d.ts.map +0 -1
- package/dist/editor/context/SWRProvider.js.map +0 -1
- package/dist/editor/context/index.d.ts.map +0 -1
- package/dist/editor/context/index.js.map +0 -1
- package/dist/editor/editor-config.d.ts.map +0 -1
- package/dist/editor/editor-config.js.map +0 -1
- package/dist/editor/editor-utils.d.ts.map +0 -1
- package/dist/editor/editor-utils.js.map +0 -1
- package/dist/editor/fields/BlockField.d.ts.map +0 -1
- package/dist/editor/fields/BlockField.js.map +0 -1
- package/dist/editor/fields/CodeField.d.ts.map +0 -1
- package/dist/editor/fields/CodeField.js.map +0 -1
- package/dist/editor/fields/DateTimeField.d.ts.map +0 -1
- package/dist/editor/fields/DateTimeField.js.map +0 -1
- package/dist/editor/fields/ImageField.d.ts.map +0 -1
- package/dist/editor/fields/ImageField.js.map +0 -1
- package/dist/editor/fields/InlineGroupField.d.ts.map +0 -1
- package/dist/editor/fields/InlineGroupField.js.map +0 -1
- package/dist/editor/fields/MarkdownField.d.ts.map +0 -1
- package/dist/editor/fields/MarkdownField.js.map +0 -1
- package/dist/editor/fields/MdxImageDialog.d.ts.map +0 -1
- package/dist/editor/fields/MdxImageDialog.js.map +0 -1
- package/dist/editor/fields/NumberField.d.ts.map +0 -1
- package/dist/editor/fields/NumberField.js.map +0 -1
- package/dist/editor/fields/NumberListField.d.ts.map +0 -1
- package/dist/editor/fields/NumberListField.js.map +0 -1
- package/dist/editor/fields/ObjectField.d.ts.map +0 -1
- package/dist/editor/fields/ObjectField.js.map +0 -1
- package/dist/editor/fields/ReferenceField.d.ts.map +0 -1
- package/dist/editor/fields/ReferenceField.js.map +0 -1
- package/dist/editor/fields/SelectField.d.ts.map +0 -1
- package/dist/editor/fields/SelectField.js.map +0 -1
- package/dist/editor/fields/StringListField.d.ts.map +0 -1
- package/dist/editor/fields/StringListField.js.map +0 -1
- package/dist/editor/fields/TextField.d.ts.map +0 -1
- package/dist/editor/fields/TextField.js.map +0 -1
- package/dist/editor/fields/ToggleField.d.ts.map +0 -1
- package/dist/editor/fields/ToggleField.js.map +0 -1
- package/dist/editor/fields/entry-link/EntryLinkContext.d.ts.map +0 -1
- package/dist/editor/fields/entry-link/EntryLinkContext.js.map +0 -1
- package/dist/editor/fields/entry-link/InsertEntryLink.d.ts.map +0 -1
- package/dist/editor/fields/entry-link/InsertEntryLink.js.map +0 -1
- package/dist/editor/fields/entry-link/index.d.ts.map +0 -1
- package/dist/editor/fields/entry-link/index.js.map +0 -1
- package/dist/editor/group-manager/ExternalGroupsTab.d.ts.map +0 -1
- package/dist/editor/group-manager/ExternalGroupsTab.js.map +0 -1
- package/dist/editor/group-manager/GroupCard.d.ts.map +0 -1
- package/dist/editor/group-manager/GroupCard.js.map +0 -1
- package/dist/editor/group-manager/GroupForm.d.ts.map +0 -1
- package/dist/editor/group-manager/GroupForm.js.map +0 -1
- package/dist/editor/group-manager/InternalGroupsTab.d.ts.map +0 -1
- package/dist/editor/group-manager/InternalGroupsTab.js.map +0 -1
- package/dist/editor/group-manager/MemberList.d.ts.map +0 -1
- package/dist/editor/group-manager/MemberList.js.map +0 -1
- package/dist/editor/group-manager/hooks/useExternalGroupSearch.d.ts.map +0 -1
- package/dist/editor/group-manager/hooks/useExternalGroupSearch.js.map +0 -1
- package/dist/editor/group-manager/hooks/useGroupState.d.ts.map +0 -1
- package/dist/editor/group-manager/hooks/useGroupState.js.map +0 -1
- package/dist/editor/group-manager/hooks/useUserSearch.d.ts.map +0 -1
- package/dist/editor/group-manager/hooks/useUserSearch.js.map +0 -1
- package/dist/editor/group-manager/index.d.ts.map +0 -1
- package/dist/editor/group-manager/index.js.map +0 -1
- package/dist/editor/group-manager/types.d.ts.map +0 -1
- package/dist/editor/group-manager/types.js.map +0 -1
- package/dist/editor/hooks/__test__/test-utils.d.ts +0 -164
- package/dist/editor/hooks/__test__/test-utils.d.ts.map +0 -1
- package/dist/editor/hooks/__test__/test-utils.js +0 -203
- package/dist/editor/hooks/__test__/test-utils.js.map +0 -1
- package/dist/editor/hooks/index.d.ts.map +0 -1
- package/dist/editor/hooks/index.js.map +0 -1
- package/dist/editor/hooks/useBranchActions.d.ts.map +0 -1
- package/dist/editor/hooks/useBranchActions.js.map +0 -1
- package/dist/editor/hooks/useBranchManager.d.ts.map +0 -1
- package/dist/editor/hooks/useBranchManager.js.map +0 -1
- package/dist/editor/hooks/useBranchesData.d.ts.map +0 -1
- package/dist/editor/hooks/useBranchesData.js.map +0 -1
- package/dist/editor/hooks/useCommentSystem.d.ts.map +0 -1
- package/dist/editor/hooks/useCommentSystem.js.map +0 -1
- package/dist/editor/hooks/useCommentsData.d.ts.map +0 -1
- package/dist/editor/hooks/useCommentsData.js.map +0 -1
- package/dist/editor/hooks/useDraftManager.d.ts.map +0 -1
- package/dist/editor/hooks/useDraftManager.js.map +0 -1
- package/dist/editor/hooks/useEditorLayout.d.ts.map +0 -1
- package/dist/editor/hooks/useEditorLayout.js.map +0 -1
- package/dist/editor/hooks/useEntriesData.d.ts.map +0 -1
- package/dist/editor/hooks/useEntriesData.js.map +0 -1
- package/dist/editor/hooks/useEntryLinkResolution.d.ts.map +0 -1
- package/dist/editor/hooks/useEntryLinkResolution.js.map +0 -1
- package/dist/editor/hooks/useEntryManager.d.ts.map +0 -1
- package/dist/editor/hooks/useEntryManager.js.map +0 -1
- package/dist/editor/hooks/useGroupManager.d.ts.map +0 -1
- package/dist/editor/hooks/useGroupManager.js.map +0 -1
- package/dist/editor/hooks/usePermissionManager.d.ts.map +0 -1
- package/dist/editor/hooks/usePermissionManager.js.map +0 -1
- package/dist/editor/hooks/useReferenceResolution.d.ts.map +0 -1
- package/dist/editor/hooks/useReferenceResolution.js.map +0 -1
- package/dist/editor/hooks/useSchemaManager.d.ts.map +0 -1
- package/dist/editor/hooks/useSchemaManager.js.map +0 -1
- package/dist/editor/hooks/useUserContext.d.ts.map +0 -1
- package/dist/editor/hooks/useUserContext.js.map +0 -1
- package/dist/editor/hooks/useUserMetadata.d.ts.map +0 -1
- package/dist/editor/hooks/useUserMetadata.js.map +0 -1
- package/dist/editor/media/AssetCard.d.ts.map +0 -1
- package/dist/editor/media/AssetCard.js.map +0 -1
- package/dist/editor/media/CropStep.d.ts.map +0 -1
- package/dist/editor/media/CropStep.js.map +0 -1
- package/dist/editor/media/MediaLibrary.d.ts.map +0 -1
- package/dist/editor/media/MediaLibrary.js.map +0 -1
- package/dist/editor/media/MediaLibraryBody.d.ts.map +0 -1
- package/dist/editor/media/MediaLibraryBody.js.map +0 -1
- package/dist/editor/media/crop-math.d.ts.map +0 -1
- package/dist/editor/media/crop-math.js.map +0 -1
- package/dist/editor/media/upload-asset.d.ts.map +0 -1
- package/dist/editor/media/upload-asset.js.map +0 -1
- package/dist/editor/media/upload-constants.d.ts.map +0 -1
- package/dist/editor/media/upload-constants.js.map +0 -1
- package/dist/editor/media/useAssetUpload.d.ts.map +0 -1
- package/dist/editor/media/useAssetUpload.js.map +0 -1
- package/dist/editor/media/xhr-upload.d.ts.map +0 -1
- package/dist/editor/media/xhr-upload.js.map +0 -1
- package/dist/editor/permission-manager/GroupSelector.d.ts.map +0 -1
- package/dist/editor/permission-manager/GroupSelector.js.map +0 -1
- package/dist/editor/permission-manager/PermissionEditor.d.ts.map +0 -1
- package/dist/editor/permission-manager/PermissionEditor.js.map +0 -1
- package/dist/editor/permission-manager/PermissionLevelBadge.d.ts.map +0 -1
- package/dist/editor/permission-manager/PermissionLevelBadge.js.map +0 -1
- package/dist/editor/permission-manager/PermissionTree.d.ts.map +0 -1
- package/dist/editor/permission-manager/PermissionTree.js.map +0 -1
- package/dist/editor/permission-manager/UserSelector.d.ts.map +0 -1
- package/dist/editor/permission-manager/UserSelector.js.map +0 -1
- package/dist/editor/permission-manager/constants.d.ts.map +0 -1
- package/dist/editor/permission-manager/constants.js.map +0 -1
- package/dist/editor/permission-manager/hooks/useGroupsAndUsers.d.ts.map +0 -1
- package/dist/editor/permission-manager/hooks/useGroupsAndUsers.js.map +0 -1
- package/dist/editor/permission-manager/hooks/usePermissionTree.d.ts.map +0 -1
- package/dist/editor/permission-manager/hooks/usePermissionTree.js.map +0 -1
- package/dist/editor/permission-manager/index.d.ts.map +0 -1
- package/dist/editor/permission-manager/index.js.map +0 -1
- package/dist/editor/permission-manager/types.d.ts.map +0 -1
- package/dist/editor/permission-manager/types.js.map +0 -1
- package/dist/editor/permission-manager/utils.d.ts.map +0 -1
- package/dist/editor/permission-manager/utils.js.map +0 -1
- package/dist/editor/preview-bridge.d.ts.map +0 -1
- package/dist/editor/preview-bridge.js.map +0 -1
- package/dist/editor/relative-time.d.ts.map +0 -1
- package/dist/editor/relative-time.js.map +0 -1
- package/dist/editor/schema-editor/CollectionEditor.d.ts.map +0 -1
- package/dist/editor/schema-editor/CollectionEditor.js.map +0 -1
- package/dist/editor/schema-editor/EntryTypeEditor.d.ts.map +0 -1
- package/dist/editor/schema-editor/EntryTypeEditor.js.map +0 -1
- package/dist/editor/schema-editor/index.d.ts.map +0 -1
- package/dist/editor/schema-editor/index.js.map +0 -1
- package/dist/editor/setup-test-dom.d.ts +0 -1
- package/dist/editor/setup-test-dom.d.ts.map +0 -1
- package/dist/editor/setup-test-dom.js +0 -12
- package/dist/editor/setup-test-dom.js.map +0 -1
- package/dist/editor/test-setup.d.ts +0 -6
- package/dist/editor/test-setup.d.ts.map +0 -1
- package/dist/editor/test-setup.js +0 -42
- package/dist/editor/test-setup.js.map +0 -1
- package/dist/editor/theme.d.ts.map +0 -1
- package/dist/editor/theme.js.map +0 -1
- package/dist/editor/utils/env.d.ts.map +0 -1
- package/dist/editor/utils/env.js.map +0 -1
- package/dist/entry-link-resolver.d.ts.map +0 -1
- package/dist/entry-link-resolver.js.map +0 -1
- package/dist/entry-schema-registry.d.ts.map +0 -1
- package/dist/entry-schema-registry.js.map +0 -1
- package/dist/entry-schema.d.ts.map +0 -1
- package/dist/entry-schema.js.map +0 -1
- package/dist/git-manager.d.ts.map +0 -1
- package/dist/git-manager.js.map +0 -1
- package/dist/github-service.d.ts.map +0 -1
- package/dist/github-service.js.map +0 -1
- package/dist/http/handler.d.ts.map +0 -1
- package/dist/http/handler.js.map +0 -1
- package/dist/http/index.d.ts.map +0 -1
- package/dist/http/index.js.map +0 -1
- package/dist/http/router.d.ts.map +0 -1
- package/dist/http/router.js.map +0 -1
- package/dist/http/types.d.ts.map +0 -1
- package/dist/http/types.js.map +0 -1
- package/dist/id.d.ts.map +0 -1
- package/dist/id.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/operating-mode/client-safe-strategy.d.ts.map +0 -1
- package/dist/operating-mode/client-safe-strategy.js.map +0 -1
- package/dist/operating-mode/client-unsafe-strategy.d.ts.map +0 -1
- package/dist/operating-mode/client-unsafe-strategy.js.map +0 -1
- package/dist/operating-mode/client.d.ts.map +0 -1
- package/dist/operating-mode/client.js.map +0 -1
- package/dist/operating-mode/deployment-name-fixtures.d.ts.map +0 -1
- package/dist/operating-mode/deployment-name-fixtures.js.map +0 -1
- package/dist/operating-mode/deployment-name.d.ts.map +0 -1
- package/dist/operating-mode/deployment-name.js.map +0 -1
- package/dist/operating-mode/index.d.ts.map +0 -1
- package/dist/operating-mode/index.js.map +0 -1
- package/dist/operating-mode/mode-env.d.ts.map +0 -1
- package/dist/operating-mode/mode-env.js.map +0 -1
- package/dist/operating-mode/types.d.ts.map +0 -1
- package/dist/operating-mode/types.js.map +0 -1
- package/dist/paths/branch-name.d.ts.map +0 -1
- package/dist/paths/branch-name.js.map +0 -1
- package/dist/paths/branch.d.ts.map +0 -1
- package/dist/paths/branch.js.map +0 -1
- package/dist/paths/index.d.ts.map +0 -1
- package/dist/paths/index.js.map +0 -1
- package/dist/paths/normalize-server.d.ts.map +0 -1
- package/dist/paths/normalize-server.js.map +0 -1
- package/dist/paths/normalize.d.ts.map +0 -1
- package/dist/paths/normalize.js.map +0 -1
- package/dist/paths/resolve.d.ts.map +0 -1
- package/dist/paths/resolve.js.map +0 -1
- package/dist/paths/test-utils.d.ts +0 -22
- package/dist/paths/test-utils.d.ts.map +0 -1
- package/dist/paths/test-utils.js +0 -21
- package/dist/paths/test-utils.js.map +0 -1
- package/dist/paths/types.d.ts.map +0 -1
- package/dist/paths/types.js.map +0 -1
- package/dist/paths/validation.d.ts.map +0 -1
- package/dist/paths/validation.js.map +0 -1
- package/dist/reference-resolver.d.ts.map +0 -1
- package/dist/reference-resolver.js.map +0 -1
- package/dist/resolve-canopy-user.d.ts.map +0 -1
- package/dist/resolve-canopy-user.js.map +0 -1
- package/dist/resource-generation.d.ts.map +0 -1
- package/dist/resource-generation.js.map +0 -1
- package/dist/schema/index.d.ts.map +0 -1
- package/dist/schema/index.js.map +0 -1
- package/dist/schema/meta-loader.d.ts.map +0 -1
- package/dist/schema/meta-loader.js.map +0 -1
- package/dist/schema/resolver.d.ts.map +0 -1
- package/dist/schema/resolver.js.map +0 -1
- package/dist/schema/schema-store-types.d.ts.map +0 -1
- package/dist/schema/schema-store-types.js.map +0 -1
- package/dist/schema/schema-store.d.ts.map +0 -1
- package/dist/schema/schema-store.js.map +0 -1
- package/dist/schema/types.d.ts.map +0 -1
- package/dist/schema/types.js.map +0 -1
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/services.d.ts.map +0 -1
- package/dist/services.js.map +0 -1
- package/dist/settings-workspace.d.ts.map +0 -1
- package/dist/settings-workspace.js.map +0 -1
- package/dist/static/index.d.ts.map +0 -1
- package/dist/static/index.js.map +0 -1
- package/dist/static/seo.d.ts.map +0 -1
- package/dist/static/seo.js.map +0 -1
- package/dist/sync-core.d.ts.map +0 -1
- package/dist/sync-core.js.map +0 -1
- package/dist/task-queue/index.d.ts.map +0 -1
- package/dist/task-queue/index.js.map +0 -1
- package/dist/task-queue/task-queue.d.ts.map +0 -1
- package/dist/task-queue/task-queue.js.map +0 -1
- package/dist/task-queue/types.d.ts.map +0 -1
- package/dist/task-queue/types.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/url-path-resolver.d.ts.map +0 -1
- package/dist/url-path-resolver.js.map +0 -1
- package/dist/user.d.ts.map +0 -1
- package/dist/user.js.map +0 -1
- package/dist/utils/async-mutex.d.ts.map +0 -1
- package/dist/utils/async-mutex.js.map +0 -1
- package/dist/utils/atomic-write.d.ts.map +0 -1
- package/dist/utils/atomic-write.js.map +0 -1
- package/dist/utils/body-field.d.ts.map +0 -1
- package/dist/utils/body-field.js.map +0 -1
- package/dist/utils/content-write-lock.d.ts.map +0 -1
- package/dist/utils/content-write-lock.js.map +0 -1
- package/dist/utils/debug.d.ts.map +0 -1
- package/dist/utils/debug.js.map +0 -1
- package/dist/utils/entry-url.d.ts.map +0 -1
- package/dist/utils/entry-url.js.map +0 -1
- package/dist/utils/error.d.ts.map +0 -1
- package/dist/utils/error.js.map +0 -1
- package/dist/utils/flatten-group-fields.d.ts.map +0 -1
- package/dist/utils/flatten-group-fields.js.map +0 -1
- package/dist/utils/format.d.ts.map +0 -1
- package/dist/utils/format.js.map +0 -1
- package/dist/utils/fs.d.ts.map +0 -1
- package/dist/utils/fs.js.map +0 -1
- package/dist/utils/git.d.ts.map +0 -1
- package/dist/utils/git.js.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/occ-json-write.d.ts.map +0 -1
- package/dist/utils/occ-json-write.js.map +0 -1
- package/dist/utils/provisioning-lock.d.ts.map +0 -1
- package/dist/utils/provisioning-lock.js.map +0 -1
- package/dist/utils/sanitize-href.d.ts.map +0 -1
- package/dist/utils/sanitize-href.js.map +0 -1
- package/dist/utils/title-field.d.ts.map +0 -1
- package/dist/utils/title-field.js.map +0 -1
- package/dist/validation/deletion-checker.d.ts.map +0 -1
- package/dist/validation/deletion-checker.js.map +0 -1
- package/dist/validation/entry-link-validator.d.ts.map +0 -1
- package/dist/validation/entry-link-validator.js.map +0 -1
- package/dist/validation/entry-type-reference-validator.d.ts.map +0 -1
- package/dist/validation/entry-type-reference-validator.js.map +0 -1
- package/dist/validation/entry-validator.d.ts.map +0 -1
- package/dist/validation/entry-validator.js.map +0 -1
- package/dist/validation/field-traversal.d.ts.map +0 -1
- package/dist/validation/field-traversal.js.map +0 -1
- package/dist/validation/reference-validator.d.ts.map +0 -1
- package/dist/validation/reference-validator.js.map +0 -1
- package/dist/worker/cms-worker.d.ts.map +0 -1
- package/dist/worker/cms-worker.js.map +0 -1
- package/dist/worker/log.d.ts.map +0 -1
- package/dist/worker/log.js.map +0 -1
- package/dist/worker/task-queue-config.d.ts.map +0 -1
- package/dist/worker/task-queue-config.js.map +0 -1
- package/dist/worker/task-queue.d.ts.map +0 -1
- package/dist/worker/task-queue.js.map +0 -1
- package/dist/worker/worker-status.d.ts.map +0 -1
- package/dist/worker/worker-status.js.map +0 -1
|
@@ -8,12 +8,27 @@ var __export = (target, all) => {
|
|
|
8
8
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
// dist/utils/logger.js
|
|
12
|
+
function canopyLogWarn(...args) {
|
|
13
|
+
active.warn(...args);
|
|
14
|
+
}
|
|
15
|
+
function canopyLogError(...args) {
|
|
16
|
+
active.error(...args);
|
|
17
|
+
}
|
|
18
|
+
var active;
|
|
19
|
+
var init_logger = __esm({
|
|
20
|
+
"dist/utils/logger.js"() {
|
|
21
|
+
"use strict";
|
|
22
|
+
active = console;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
11
26
|
// dist/paths/normalize.js
|
|
12
|
-
function normalizeFilesystemPath(
|
|
13
|
-
return
|
|
27
|
+
function normalizeFilesystemPath(path21) {
|
|
28
|
+
return path21.split(/[\\/]+/).filter(Boolean).join("/");
|
|
14
29
|
}
|
|
15
|
-
function hasTraversalSequence(
|
|
16
|
-
const normalized = normalizeFilesystemPath(
|
|
30
|
+
function hasTraversalSequence(path21) {
|
|
31
|
+
const normalized = normalizeFilesystemPath(path21);
|
|
17
32
|
return normalized.includes("..");
|
|
18
33
|
}
|
|
19
34
|
function createLogicalPath(...segments) {
|
|
@@ -23,14 +38,14 @@ function createLogicalPath(...segments) {
|
|
|
23
38
|
}
|
|
24
39
|
return normalized;
|
|
25
40
|
}
|
|
26
|
-
function trimSlashes(
|
|
41
|
+
function trimSlashes(path21) {
|
|
27
42
|
let start = 0;
|
|
28
|
-
let end =
|
|
29
|
-
while (start < end &&
|
|
43
|
+
let end = path21.length;
|
|
44
|
+
while (start < end && path21[start] === "/")
|
|
30
45
|
start++;
|
|
31
|
-
while (end > start &&
|
|
46
|
+
while (end > start && path21[end - 1] === "/")
|
|
32
47
|
end--;
|
|
33
|
-
return
|
|
48
|
+
return path21.slice(start, end);
|
|
34
49
|
}
|
|
35
50
|
var init_normalize = __esm({
|
|
36
51
|
"dist/paths/normalize.js"() {
|
|
@@ -38,21 +53,6 @@ var init_normalize = __esm({
|
|
|
38
53
|
}
|
|
39
54
|
});
|
|
40
55
|
|
|
41
|
-
// dist/utils/logger.js
|
|
42
|
-
function canopyLogWarn(...args) {
|
|
43
|
-
active.warn(...args);
|
|
44
|
-
}
|
|
45
|
-
function canopyLogError(...args) {
|
|
46
|
-
active.error(...args);
|
|
47
|
-
}
|
|
48
|
-
var active;
|
|
49
|
-
var init_logger = __esm({
|
|
50
|
-
"dist/utils/logger.js"() {
|
|
51
|
-
"use strict";
|
|
52
|
-
active = console;
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
|
|
56
56
|
// dist/paths/types.js
|
|
57
57
|
var ROOT_COLLECTION_ID;
|
|
58
58
|
var init_types = __esm({
|
|
@@ -239,7 +239,12 @@ var init_field = __esm({
|
|
|
239
239
|
collections: z2.array(z2.string().min(1)).min(1).optional(),
|
|
240
240
|
entryTypes: z2.array(z2.string().min(1)).min(1).optional(),
|
|
241
241
|
displayField: z2.string().min(1).optional(),
|
|
242
|
-
options: z2.array(referenceOptionSchema).optional()
|
|
242
|
+
options: z2.array(referenceOptionSchema).optional(),
|
|
243
|
+
// Must be listed here, not just on ReferenceFieldConfig: zod strips unknown keys by
|
|
244
|
+
// default, so a consumer that adopts this schema's parse output would silently delete a
|
|
245
|
+
// runtime-consumed flag and the feature would no-op with no error. (`resolvedSchema` is
|
|
246
|
+
// absent on purpose — it is type-inference-only and stripping it changes no behavior.)
|
|
247
|
+
includeBody: z2.boolean().optional()
|
|
243
248
|
});
|
|
244
249
|
fieldHolder = [z2.never()];
|
|
245
250
|
blockSchema = z2.object({
|
|
@@ -349,7 +354,7 @@ var init_media = __esm({
|
|
|
349
354
|
|
|
350
355
|
// dist/config/schemas/config.js
|
|
351
356
|
import { z as z5 } from "zod";
|
|
352
|
-
var defaultBranchAccessSchema, defaultPathAccessLevelSchema, defaultPathAccessLevelsSchema, defaultPathAccessSchema, defaultBaseBranchSchema, defaultRemoteNameSchema, defaultRemoteUrlSchema, gitBotAuthorNameSchema, gitBotAuthorEmailSchema, githubTokenEnvVarSchema, operatingModeSchema, deployedAsSchema, contentRootSchema, sourceRootSchema, deploymentNameSchema, devContentSyncSchema, devConfigSchema, editorConfigSchema, CanopyConfigSchema, DEFAULT_PROD_WORKSPACE;
|
|
357
|
+
var defaultBranchAccessSchema, defaultPathAccessLevelSchema, defaultPathAccessLevelsSchema, defaultPathAccessSchema, defaultBaseBranchSchema, defaultRemoteNameSchema, defaultRemoteUrlSchema, gitBotAuthorNameSchema, gitBotAuthorEmailSchema, githubTokenEnvVarSchema, operatingModeSchema, deployedAsSchema, contentRootSchema, sourceRootSchema, basePathSchema, deploymentNameSchema, devContentSyncSchema, devConfigSchema, editorConfigSchema, CanopyConfigSchema, DEFAULT_PROD_WORKSPACE;
|
|
353
358
|
var init_config = __esm({
|
|
354
359
|
"dist/config/schemas/config.js"() {
|
|
355
360
|
"use strict";
|
|
@@ -373,6 +378,9 @@ var init_config = __esm({
|
|
|
373
378
|
deployedAsSchema = z5.enum(["static", "server"]).default("server");
|
|
374
379
|
contentRootSchema = relativePathSchema.default("content");
|
|
375
380
|
sourceRootSchema = z5.string().min(1).optional();
|
|
381
|
+
basePathSchema = z5.string().transform((value) => value.trim()).refine((value) => value.length > 0, {
|
|
382
|
+
message: "basePath must not be empty or only whitespace"
|
|
383
|
+
}).optional();
|
|
376
384
|
deploymentNameSchema = z5.string().default("prod");
|
|
377
385
|
devContentSyncSchema = z5.enum(["off", "warn"]).default("warn");
|
|
378
386
|
devConfigSchema = z5.object({
|
|
@@ -435,6 +443,7 @@ var init_config = __esm({
|
|
|
435
443
|
deploymentName: deploymentNameSchema.optional(),
|
|
436
444
|
contentRoot: contentRootSchema.default("content"),
|
|
437
445
|
sourceRoot: sourceRootSchema.optional(),
|
|
446
|
+
basePath: basePathSchema,
|
|
438
447
|
editor: editorConfigSchema.optional(),
|
|
439
448
|
authPlugin: z5.custom().optional(),
|
|
440
449
|
entryLinkUrl: z5.custom().optional(),
|
|
@@ -672,7 +681,7 @@ var init_config2 = __esm({
|
|
|
672
681
|
});
|
|
673
682
|
|
|
674
683
|
// dist/operating-mode/client-unsafe-strategy.js
|
|
675
|
-
import
|
|
684
|
+
import path9 from "node:path";
|
|
676
685
|
function operatingStrategy(mode) {
|
|
677
686
|
const cached = strategyCache.get(mode);
|
|
678
687
|
if (cached)
|
|
@@ -710,32 +719,32 @@ var init_client_unsafe_strategy = __esm({
|
|
|
710
719
|
// - shouldCommit(), shouldPush()
|
|
711
720
|
// Add client-unsafe methods (use Node.js APIs)
|
|
712
721
|
getWorkspaceRoot(_sourceRoot) {
|
|
713
|
-
return
|
|
722
|
+
return path9.resolve(process.env.CANOPYCMS_WORKSPACE_ROOT ?? DEFAULT_PROD_WORKSPACE);
|
|
714
723
|
}
|
|
715
724
|
getContentRoot(contentRoot, sourceRoot) {
|
|
716
|
-
return
|
|
725
|
+
return path9.resolve(sourceRoot ?? process.cwd(), contentRoot);
|
|
717
726
|
}
|
|
718
727
|
getContentBranchesRoot(sourceRoot) {
|
|
719
|
-
return
|
|
728
|
+
return path9.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
|
|
720
729
|
}
|
|
721
730
|
getContentBranchRoot(branchName, sourceRoot) {
|
|
722
|
-
return
|
|
731
|
+
return path9.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
|
|
723
732
|
}
|
|
724
733
|
getGitExcludePattern() {
|
|
725
734
|
return ".canopy-meta/";
|
|
726
735
|
}
|
|
727
736
|
getPermissionsFilePath(root) {
|
|
728
|
-
return
|
|
737
|
+
return path9.join(root, this.getPermissionsFileName());
|
|
729
738
|
}
|
|
730
739
|
getGroupsFilePath(root) {
|
|
731
|
-
return
|
|
740
|
+
return path9.join(root, this.getGroupsFileName());
|
|
732
741
|
}
|
|
733
742
|
getRemoteUrlConfig() {
|
|
734
743
|
return {
|
|
735
744
|
shouldAutoInitLocal: false,
|
|
736
745
|
defaultRemotePath: "",
|
|
737
746
|
envVarName: "CANOPYCMS_REMOTE_URL",
|
|
738
|
-
autoDetectRemotePath:
|
|
747
|
+
autoDetectRemotePath: path9.join(this.getWorkspaceRoot(), "remote.git")
|
|
739
748
|
};
|
|
740
749
|
}
|
|
741
750
|
requiresExistingRepo() {
|
|
@@ -747,7 +756,7 @@ var init_client_unsafe_strategy = __esm({
|
|
|
747
756
|
return `canopycms-settings-${resolveDeploymentName(config, "prod")}`;
|
|
748
757
|
}
|
|
749
758
|
getSettingsRoot(sourceRoot) {
|
|
750
|
-
return
|
|
759
|
+
return path9.join(this.getWorkspaceRoot(sourceRoot), "settings");
|
|
751
760
|
}
|
|
752
761
|
usesSeparateSettingsBranch() {
|
|
753
762
|
return true;
|
|
@@ -764,25 +773,25 @@ var init_client_unsafe_strategy = __esm({
|
|
|
764
773
|
DevStrategy = class extends DevClientSafeStrategy {
|
|
765
774
|
// Inherits client-safe methods from DevClientSafeStrategy
|
|
766
775
|
getWorkspaceRoot(sourceRoot) {
|
|
767
|
-
return
|
|
776
|
+
return path9.resolve(sourceRoot ?? process.cwd(), ".canopy-dev");
|
|
768
777
|
}
|
|
769
778
|
getContentRoot(contentRoot, sourceRoot) {
|
|
770
|
-
return
|
|
779
|
+
return path9.resolve(sourceRoot ?? process.cwd(), contentRoot);
|
|
771
780
|
}
|
|
772
781
|
getContentBranchesRoot(sourceRoot) {
|
|
773
|
-
return
|
|
782
|
+
return path9.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
|
|
774
783
|
}
|
|
775
784
|
getContentBranchRoot(branchName, sourceRoot) {
|
|
776
|
-
return
|
|
785
|
+
return path9.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
|
|
777
786
|
}
|
|
778
787
|
getGitExcludePattern() {
|
|
779
788
|
return ".canopy-meta/";
|
|
780
789
|
}
|
|
781
790
|
getPermissionsFilePath(root) {
|
|
782
|
-
return
|
|
791
|
+
return path9.join(root, this.getPermissionsFileName());
|
|
783
792
|
}
|
|
784
793
|
getGroupsFilePath(root) {
|
|
785
|
-
return
|
|
794
|
+
return path9.join(root, this.getGroupsFileName());
|
|
786
795
|
}
|
|
787
796
|
getRemoteUrlConfig() {
|
|
788
797
|
return {
|
|
@@ -800,7 +809,7 @@ var init_client_unsafe_strategy = __esm({
|
|
|
800
809
|
return `canopycms-settings-${resolveDeploymentName(config, "local")}`;
|
|
801
810
|
}
|
|
802
811
|
getSettingsRoot(sourceRoot) {
|
|
803
|
-
return
|
|
812
|
+
return path9.join(this.getWorkspaceRoot(sourceRoot), "settings");
|
|
804
813
|
}
|
|
805
814
|
usesSeparateSettingsBranch() {
|
|
806
815
|
return true;
|
|
@@ -839,18 +848,38 @@ var init_operating_mode = __esm({
|
|
|
839
848
|
});
|
|
840
849
|
|
|
841
850
|
// dist/cli/generate-ai-content.js
|
|
842
|
-
import
|
|
851
|
+
import path20 from "node:path";
|
|
843
852
|
import { createJiti } from "jiti";
|
|
844
853
|
|
|
845
854
|
// dist/build/generate-ai-content.js
|
|
846
|
-
import
|
|
847
|
-
import
|
|
855
|
+
import fs17 from "node:fs/promises";
|
|
856
|
+
import path19 from "node:path";
|
|
857
|
+
|
|
858
|
+
// dist/utils/error.js
|
|
859
|
+
function getErrorMessage(err) {
|
|
860
|
+
if (err instanceof Error) {
|
|
861
|
+
return err.message;
|
|
862
|
+
}
|
|
863
|
+
if (typeof err === "string") {
|
|
864
|
+
return err;
|
|
865
|
+
}
|
|
866
|
+
return String(err);
|
|
867
|
+
}
|
|
868
|
+
function isNodeError(err) {
|
|
869
|
+
return err instanceof Error && "code" in err;
|
|
870
|
+
}
|
|
871
|
+
function isNotFoundError(err) {
|
|
872
|
+
return isNodeError(err) && err.code === "ENOENT";
|
|
873
|
+
}
|
|
874
|
+
function isFileExistsError(err) {
|
|
875
|
+
return isNodeError(err) && err.code === "EEXIST";
|
|
876
|
+
}
|
|
848
877
|
|
|
849
878
|
// dist/content-store.js
|
|
850
|
-
import
|
|
851
|
-
import
|
|
852
|
-
import
|
|
853
|
-
import { parse as yamlParse
|
|
879
|
+
import fs10 from "node:fs/promises";
|
|
880
|
+
import path11 from "node:path";
|
|
881
|
+
import matter2 from "gray-matter";
|
|
882
|
+
import { parse as yamlParse } from "yaml";
|
|
854
883
|
|
|
855
884
|
// dist/utils/atomic-write.js
|
|
856
885
|
import fs from "node:fs/promises";
|
|
@@ -869,6 +898,207 @@ async function atomicWriteFile(filePath, content) {
|
|
|
869
898
|
}
|
|
870
899
|
}
|
|
871
900
|
|
|
901
|
+
// dist/utils/content-serialize.js
|
|
902
|
+
import matter from "gray-matter";
|
|
903
|
+
import { isCollection, isMap, isNode, isScalar, isSeq, parseDocument, stringify as yamlStringify } from "yaml";
|
|
904
|
+
|
|
905
|
+
// dist/validation/block-structural-keys.js
|
|
906
|
+
var BLOCK_DISCRIMINATOR_KEYS = ["template", "_type"];
|
|
907
|
+
var BLOCK_STRUCTURAL_KEYS = new Set(BLOCK_DISCRIMINATOR_KEYS);
|
|
908
|
+
function isBlockStructuralKey(key) {
|
|
909
|
+
return BLOCK_STRUCTURAL_KEYS.has(key);
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
// dist/utils/content-serialize.js
|
|
913
|
+
function isPlainRecord(value) {
|
|
914
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
915
|
+
return false;
|
|
916
|
+
const proto = Object.getPrototypeOf(value);
|
|
917
|
+
return proto === Object.prototype || proto === null;
|
|
918
|
+
}
|
|
919
|
+
function recordKeyOf(keyNode) {
|
|
920
|
+
if (!isScalar(keyNode))
|
|
921
|
+
return void 0;
|
|
922
|
+
const { value } = keyNode;
|
|
923
|
+
if (value === null || value === void 0)
|
|
924
|
+
return void 0;
|
|
925
|
+
if (typeof value === "object")
|
|
926
|
+
return void 0;
|
|
927
|
+
return String(value);
|
|
928
|
+
}
|
|
929
|
+
function carryComments(from, to) {
|
|
930
|
+
if (!isNode(from) || !isNode(to))
|
|
931
|
+
return;
|
|
932
|
+
const source = from;
|
|
933
|
+
const target = to;
|
|
934
|
+
if (source.commentBefore !== void 0)
|
|
935
|
+
target.commentBefore = source.commentBefore;
|
|
936
|
+
if (source.comment !== void 0)
|
|
937
|
+
target.comment = source.comment;
|
|
938
|
+
if (source.spaceBefore !== void 0)
|
|
939
|
+
target.spaceBefore = source.spaceBefore;
|
|
940
|
+
}
|
|
941
|
+
function identityKey(value) {
|
|
942
|
+
try {
|
|
943
|
+
return JSON.stringify(value) ?? "undefined";
|
|
944
|
+
} catch {
|
|
945
|
+
return void 0;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
function nodePlainValue(node) {
|
|
949
|
+
if (!isNode(node))
|
|
950
|
+
return node;
|
|
951
|
+
try {
|
|
952
|
+
return node.toJSON();
|
|
953
|
+
} catch {
|
|
954
|
+
return void 0;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
function nodeIdentityKey(node) {
|
|
958
|
+
const plain = nodePlainValue(node);
|
|
959
|
+
return plain === void 0 && isNode(node) ? void 0 : identityKey(plain);
|
|
960
|
+
}
|
|
961
|
+
var EVIDENCE_MAX_DEPTH = 6;
|
|
962
|
+
function sharesFieldEvidence(existing, value, depth) {
|
|
963
|
+
for (const key of Object.keys(value)) {
|
|
964
|
+
if (isBlockStructuralKey(key))
|
|
965
|
+
continue;
|
|
966
|
+
if (!Object.prototype.hasOwnProperty.call(existing, key))
|
|
967
|
+
continue;
|
|
968
|
+
const before = existing[key];
|
|
969
|
+
const after = value[key];
|
|
970
|
+
if (depth < EVIDENCE_MAX_DEPTH && isPlainRecord(before) && isPlainRecord(after) && sharesFieldEvidence(before, after, depth + 1)) {
|
|
971
|
+
return true;
|
|
972
|
+
}
|
|
973
|
+
const beforeKey = identityKey(before);
|
|
974
|
+
if (beforeKey !== void 0 && beforeKey === identityKey(after))
|
|
975
|
+
return true;
|
|
976
|
+
}
|
|
977
|
+
return false;
|
|
978
|
+
}
|
|
979
|
+
function looksLikeSameItem(node, value) {
|
|
980
|
+
const existing = nodePlainValue(node);
|
|
981
|
+
if (!isPlainRecord(existing) || !isPlainRecord(value))
|
|
982
|
+
return true;
|
|
983
|
+
return sharesFieldEvidence(existing, value, 0);
|
|
984
|
+
}
|
|
985
|
+
function reconcileNode(doc, existing, value) {
|
|
986
|
+
if (isMap(existing) && isPlainRecord(value)) {
|
|
987
|
+
reconcileMap(doc, existing, value);
|
|
988
|
+
return existing;
|
|
989
|
+
}
|
|
990
|
+
if (isSeq(existing) && Array.isArray(value)) {
|
|
991
|
+
reconcileSeq(doc, existing, value);
|
|
992
|
+
return existing;
|
|
993
|
+
}
|
|
994
|
+
if (isScalar(existing) && Object.is(existing.value, value))
|
|
995
|
+
return existing;
|
|
996
|
+
const fresh = doc.createNode(value);
|
|
997
|
+
if (!isCollection(existing))
|
|
998
|
+
carryComments(existing, fresh);
|
|
999
|
+
return fresh;
|
|
1000
|
+
}
|
|
1001
|
+
function reconcileMap(doc, map, value) {
|
|
1002
|
+
const wanted = new Set(Object.keys(value).filter((key) => value[key] !== void 0));
|
|
1003
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1004
|
+
const retained = [];
|
|
1005
|
+
for (const pair of map.items) {
|
|
1006
|
+
const key = recordKeyOf(pair.key);
|
|
1007
|
+
if (key === void 0 || !wanted.has(key) || seen.has(key))
|
|
1008
|
+
continue;
|
|
1009
|
+
seen.add(key);
|
|
1010
|
+
pair.value = reconcileNode(doc, pair.value, value[key]);
|
|
1011
|
+
retained.push(pair);
|
|
1012
|
+
}
|
|
1013
|
+
map.items = retained;
|
|
1014
|
+
for (const key of Object.keys(value)) {
|
|
1015
|
+
if (seen.has(key) || !wanted.has(key))
|
|
1016
|
+
continue;
|
|
1017
|
+
map.set(doc.createNode(key), doc.createNode(value[key]));
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
function reconcileSeq(doc, seq, value) {
|
|
1021
|
+
const oldItems = seq.items;
|
|
1022
|
+
const byIdentity = /* @__PURE__ */ new Map();
|
|
1023
|
+
oldItems.forEach((node, index) => {
|
|
1024
|
+
const key = nodeIdentityKey(node);
|
|
1025
|
+
if (key === void 0)
|
|
1026
|
+
return;
|
|
1027
|
+
const bucket = byIdentity.get(key);
|
|
1028
|
+
if (bucket)
|
|
1029
|
+
bucket.push(index);
|
|
1030
|
+
else
|
|
1031
|
+
byIdentity.set(key, [index]);
|
|
1032
|
+
});
|
|
1033
|
+
const consumed = /* @__PURE__ */ new Set();
|
|
1034
|
+
const matches = value.map((item) => {
|
|
1035
|
+
const key = identityKey(item);
|
|
1036
|
+
if (key === void 0)
|
|
1037
|
+
return void 0;
|
|
1038
|
+
const bucket = byIdentity.get(key);
|
|
1039
|
+
while (bucket && bucket.length > 0) {
|
|
1040
|
+
const index = bucket.shift();
|
|
1041
|
+
if (index !== void 0 && !consumed.has(index)) {
|
|
1042
|
+
consumed.add(index);
|
|
1043
|
+
return index;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
return void 0;
|
|
1047
|
+
});
|
|
1048
|
+
seq.items = value.map((item, index) => {
|
|
1049
|
+
const matched = matches[index];
|
|
1050
|
+
if (matched !== void 0)
|
|
1051
|
+
return oldItems[matched];
|
|
1052
|
+
const candidate = index < oldItems.length && !consumed.has(index) ? oldItems[index] : void 0;
|
|
1053
|
+
const sameItem = candidate !== void 0 && looksLikeSameItem(candidate, item) ? candidate : void 0;
|
|
1054
|
+
return reconcileNode(doc, sameItem, item);
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
function applyDataToDocument(doc, data) {
|
|
1058
|
+
doc.contents = reconcileNode(doc, doc.contents, data);
|
|
1059
|
+
}
|
|
1060
|
+
function serializeYaml(data, existingRaw) {
|
|
1061
|
+
if (existingRaw === void 0)
|
|
1062
|
+
return yamlStringify(data);
|
|
1063
|
+
const doc = parseDocument(existingRaw);
|
|
1064
|
+
if (doc.errors.length > 0)
|
|
1065
|
+
return yamlStringify(data);
|
|
1066
|
+
applyDataToDocument(doc, data);
|
|
1067
|
+
return doc.toString();
|
|
1068
|
+
}
|
|
1069
|
+
function extractRawFrontmatter(raw) {
|
|
1070
|
+
let parsed;
|
|
1071
|
+
try {
|
|
1072
|
+
parsed = matter(raw, {});
|
|
1073
|
+
} catch {
|
|
1074
|
+
return void 0;
|
|
1075
|
+
}
|
|
1076
|
+
const frontmatter = parsed.matter;
|
|
1077
|
+
if (typeof frontmatter !== "string" || frontmatter.trim() === "")
|
|
1078
|
+
return void 0;
|
|
1079
|
+
return frontmatter;
|
|
1080
|
+
}
|
|
1081
|
+
function serializeFrontmatter(body, data, existingRaw) {
|
|
1082
|
+
if (existingRaw === void 0)
|
|
1083
|
+
return matter.stringify(body, data);
|
|
1084
|
+
const existingFrontmatter = extractRawFrontmatter(existingRaw);
|
|
1085
|
+
if (existingFrontmatter === void 0)
|
|
1086
|
+
return matter.stringify(body, data);
|
|
1087
|
+
const doc = parseDocument(existingFrontmatter);
|
|
1088
|
+
if (doc.errors.length > 0)
|
|
1089
|
+
return matter.stringify(body, data);
|
|
1090
|
+
applyDataToDocument(doc, data);
|
|
1091
|
+
const reconciled = doc.toString();
|
|
1092
|
+
return matter.stringify(body, data, {
|
|
1093
|
+
engines: {
|
|
1094
|
+
yaml: {
|
|
1095
|
+
parse: () => ({}),
|
|
1096
|
+
stringify: () => reconciled
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
|
|
872
1102
|
// dist/utils/async-mutex.js
|
|
873
1103
|
var locks = /* @__PURE__ */ new Map();
|
|
874
1104
|
async function withLock(key, fn) {
|
|
@@ -890,46 +1120,66 @@ async function withLock(key, fn) {
|
|
|
890
1120
|
|
|
891
1121
|
// dist/utils/content-write-lock.js
|
|
892
1122
|
import path3 from "node:path";
|
|
893
|
-
|
|
894
|
-
// dist/utils/error.js
|
|
895
|
-
function getErrorMessage(err) {
|
|
896
|
-
if (err instanceof Error) {
|
|
897
|
-
return err.message;
|
|
898
|
-
}
|
|
899
|
-
if (typeof err === "string") {
|
|
900
|
-
return err;
|
|
901
|
-
}
|
|
902
|
-
return String(err);
|
|
903
|
-
}
|
|
904
|
-
function isNodeError(err) {
|
|
905
|
-
return err instanceof Error && "code" in err;
|
|
906
|
-
}
|
|
907
|
-
function isNotFoundError(err) {
|
|
908
|
-
return isNodeError(err) && err.code === "ENOENT";
|
|
909
|
-
}
|
|
910
|
-
function isFileExistsError(err) {
|
|
911
|
-
return isNodeError(err) && err.code === "EEXIST";
|
|
912
|
-
}
|
|
1123
|
+
init_logger();
|
|
913
1124
|
|
|
914
1125
|
// dist/utils/provisioning-lock.js
|
|
915
1126
|
import fs2 from "node:fs/promises";
|
|
916
1127
|
import path2 from "node:path";
|
|
917
1128
|
import lockfile from "proper-lockfile";
|
|
918
|
-
|
|
1129
|
+
init_logger();
|
|
1130
|
+
function provisioningLockOptions(lockPath, retries, onCompromised) {
|
|
1131
|
+
return {
|
|
1132
|
+
lockfilePath: lockPath,
|
|
1133
|
+
realpath: false,
|
|
1134
|
+
retries,
|
|
1135
|
+
stale: 3e4,
|
|
1136
|
+
// proper-lockfile invokes this from inside its refresh timer, so ANY throw
|
|
1137
|
+
// escaping here is an uncaught exception that kills the process -- the very
|
|
1138
|
+
// failure the handler exists to prevent. Call sites are told not to throw
|
|
1139
|
+
// (see OnLockCompromised); this makes it structural rather than a
|
|
1140
|
+
// convention, and also covers the LOGGER throwing: under `CI=true`,
|
|
1141
|
+
// vitest's `onConsoleLog` turns any console write into a throw.
|
|
1142
|
+
onCompromised: (err) => {
|
|
1143
|
+
try {
|
|
1144
|
+
if (onCompromised) {
|
|
1145
|
+
onCompromised(err);
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1148
|
+
canopyLogWarn(`[canopy] Provisioning lock compromised mid-hold for ${lockPath}:`, getErrorMessage(err));
|
|
1149
|
+
} catch {
|
|
1150
|
+
try {
|
|
1151
|
+
process.stderr.write(`[canopy] lock compromised for ${lockPath}; its handler or logger threw
|
|
1152
|
+
`);
|
|
1153
|
+
} catch {
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
};
|
|
1158
|
+
}
|
|
1159
|
+
function releaseIgnoringAlreadyReleased(release, lockPath) {
|
|
1160
|
+
return async () => {
|
|
1161
|
+
try {
|
|
1162
|
+
await release();
|
|
1163
|
+
} catch (err) {
|
|
1164
|
+
if (isNodeError(err) && err.code === "ERELEASED") {
|
|
1165
|
+
canopyLogWarn(`[canopy] Lock at ${lockPath} was already released (compromised mid-hold, or released twice); nothing to release`);
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1168
|
+
throw err;
|
|
1169
|
+
}
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
async function acquireProvisioningLock(lockTargetDir2, lockName, onCompromised) {
|
|
919
1173
|
await fs2.mkdir(lockTargetDir2, { recursive: true });
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
stale: 3e4
|
|
924
|
-
});
|
|
1174
|
+
const lockPath = path2.join(lockTargetDir2, lockName);
|
|
1175
|
+
const release = await lockfile.lock(lockPath, provisioningLockOptions(lockPath, { retries: 600, factor: 1, minTimeout: 300, maxTimeout: 800, randomize: true }, onCompromised));
|
|
1176
|
+
return releaseIgnoringAlreadyReleased(release, lockPath);
|
|
925
1177
|
}
|
|
926
|
-
async function tryAcquireProvisioningLock(lockTargetDir2, lockName) {
|
|
1178
|
+
async function tryAcquireProvisioningLock(lockTargetDir2, lockName, onCompromised) {
|
|
927
1179
|
await fs2.mkdir(lockTargetDir2, { recursive: true });
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
stale: 3e4
|
|
932
|
-
});
|
|
1180
|
+
const lockPath = path2.join(lockTargetDir2, lockName);
|
|
1181
|
+
const release = await lockfile.lock(lockPath, provisioningLockOptions(lockPath, 0, onCompromised));
|
|
1182
|
+
return releaseIgnoringAlreadyReleased(release, lockPath);
|
|
933
1183
|
}
|
|
934
1184
|
|
|
935
1185
|
// dist/utils/content-write-lock.js
|
|
@@ -948,14 +1198,14 @@ function lockTargetDir(branchRoot) {
|
|
|
948
1198
|
var sleep = (ms) => new Promise((resolve2) => {
|
|
949
1199
|
setTimeout(resolve2, ms);
|
|
950
1200
|
});
|
|
951
|
-
function tryAcquireContentWriteLock(branchRoot) {
|
|
952
|
-
return tryAcquireProvisioningLock(lockTargetDir(branchRoot), CONTENT_WRITE_LOCK_NAME);
|
|
1201
|
+
function tryAcquireContentWriteLock(branchRoot, onCompromised) {
|
|
1202
|
+
return tryAcquireProvisioningLock(lockTargetDir(branchRoot), CONTENT_WRITE_LOCK_NAME, onCompromised);
|
|
953
1203
|
}
|
|
954
|
-
async function acquireContentWriteLock(branchRoot, waitMs = DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS) {
|
|
1204
|
+
async function acquireContentWriteLock(branchRoot, waitMs = DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS, onCompromised) {
|
|
955
1205
|
const startedAt = Date.now();
|
|
956
1206
|
for (let attempt = 0; ; attempt++) {
|
|
957
1207
|
try {
|
|
958
|
-
return await tryAcquireContentWriteLock(branchRoot);
|
|
1208
|
+
return await tryAcquireContentWriteLock(branchRoot, onCompromised);
|
|
959
1209
|
} catch (err) {
|
|
960
1210
|
if (!isNodeError(err) || err.code !== "ELOCKED")
|
|
961
1211
|
throw err;
|
|
@@ -968,12 +1218,21 @@ async function acquireContentWriteLock(branchRoot, waitMs = DEFAULT_CONTENT_WRIT
|
|
|
968
1218
|
}
|
|
969
1219
|
}
|
|
970
1220
|
async function withContentWriteLock(branchRoot, fn, waitMs = DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS) {
|
|
971
|
-
|
|
1221
|
+
let compromised = false;
|
|
1222
|
+
const release = await acquireContentWriteLock(branchRoot, waitMs, (err) => {
|
|
1223
|
+
compromised = true;
|
|
1224
|
+
canopyLogWarn(`[canopy] Content-write lock compromised mid-hold for ${branchRoot}:`, getErrorMessage(err));
|
|
1225
|
+
});
|
|
1226
|
+
let result;
|
|
972
1227
|
try {
|
|
973
|
-
|
|
1228
|
+
result = await fn();
|
|
974
1229
|
} finally {
|
|
975
1230
|
await release();
|
|
976
1231
|
}
|
|
1232
|
+
if (compromised) {
|
|
1233
|
+
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.");
|
|
1234
|
+
}
|
|
1235
|
+
return result;
|
|
977
1236
|
}
|
|
978
1237
|
|
|
979
1238
|
// dist/utils/flatten-group-fields.js
|
|
@@ -998,6 +1257,105 @@ function findBodyFieldName(fields) {
|
|
|
998
1257
|
return "body";
|
|
999
1258
|
}
|
|
1000
1259
|
|
|
1260
|
+
// dist/static/seo.js
|
|
1261
|
+
var DEFAULT_SEO_FIELD_NAMES = {
|
|
1262
|
+
title: "metaTitle",
|
|
1263
|
+
description: "metaDescription",
|
|
1264
|
+
ogImage: "ogImage",
|
|
1265
|
+
ogType: "ogType",
|
|
1266
|
+
canonical: "canonical",
|
|
1267
|
+
noindex: "noindex",
|
|
1268
|
+
twitterCard: "twitterCard"
|
|
1269
|
+
};
|
|
1270
|
+
|
|
1271
|
+
// dist/entry-schema.js
|
|
1272
|
+
function buildResolvedReference(data, meta, body) {
|
|
1273
|
+
const resolved = { ...data };
|
|
1274
|
+
if (body && body.value)
|
|
1275
|
+
resolved[body.fieldName] = body.value;
|
|
1276
|
+
resolved.id = meta.id;
|
|
1277
|
+
resolved.slug = meta.slug;
|
|
1278
|
+
resolved.collection = meta.collection;
|
|
1279
|
+
resolved.urlPath = meta.urlPath;
|
|
1280
|
+
return resolved;
|
|
1281
|
+
}
|
|
1282
|
+
var SEO_GROUP_FIELDS = [
|
|
1283
|
+
{
|
|
1284
|
+
name: DEFAULT_SEO_FIELD_NAMES.title,
|
|
1285
|
+
type: "string",
|
|
1286
|
+
label: "Meta Title",
|
|
1287
|
+
description: "Overrides the page title in search results and social cards.",
|
|
1288
|
+
required: false
|
|
1289
|
+
},
|
|
1290
|
+
{
|
|
1291
|
+
name: DEFAULT_SEO_FIELD_NAMES.description,
|
|
1292
|
+
type: "string",
|
|
1293
|
+
label: "Meta Description",
|
|
1294
|
+
description: "Summary shown under the title in search results.",
|
|
1295
|
+
required: false
|
|
1296
|
+
},
|
|
1297
|
+
{
|
|
1298
|
+
name: DEFAULT_SEO_FIELD_NAMES.ogImage,
|
|
1299
|
+
type: "string",
|
|
1300
|
+
label: "Social Image URL",
|
|
1301
|
+
description: "Image for social cards. Site-relative or absolute.",
|
|
1302
|
+
required: false
|
|
1303
|
+
},
|
|
1304
|
+
{
|
|
1305
|
+
name: DEFAULT_SEO_FIELD_NAMES.ogType,
|
|
1306
|
+
type: "select",
|
|
1307
|
+
label: "OpenGraph Type",
|
|
1308
|
+
options: ["website", "article", "profile"],
|
|
1309
|
+
required: false
|
|
1310
|
+
},
|
|
1311
|
+
{
|
|
1312
|
+
name: DEFAULT_SEO_FIELD_NAMES.canonical,
|
|
1313
|
+
type: "string",
|
|
1314
|
+
label: "Canonical URL",
|
|
1315
|
+
description: "Set only to point at a different canonical copy of this page.",
|
|
1316
|
+
required: false
|
|
1317
|
+
},
|
|
1318
|
+
{
|
|
1319
|
+
name: DEFAULT_SEO_FIELD_NAMES.noindex,
|
|
1320
|
+
type: "boolean",
|
|
1321
|
+
label: "Hide from search engines",
|
|
1322
|
+
description: "Marks the page noindex AND drops it from the sitemap.",
|
|
1323
|
+
required: false
|
|
1324
|
+
},
|
|
1325
|
+
{
|
|
1326
|
+
name: DEFAULT_SEO_FIELD_NAMES.twitterCard,
|
|
1327
|
+
type: "select",
|
|
1328
|
+
label: "Twitter Card",
|
|
1329
|
+
options: ["summary", "summary_large_image"],
|
|
1330
|
+
required: false
|
|
1331
|
+
}
|
|
1332
|
+
];
|
|
1333
|
+
|
|
1334
|
+
// dist/utils/entry-url.js
|
|
1335
|
+
init_normalize();
|
|
1336
|
+
function isIndexSlug(slug) {
|
|
1337
|
+
return slug?.toLowerCase() === "index";
|
|
1338
|
+
}
|
|
1339
|
+
function computeEntryUrl(collection, slug, contentRoot) {
|
|
1340
|
+
const root = trimSlashes(contentRoot);
|
|
1341
|
+
let stripped = collection;
|
|
1342
|
+
if (root && collection.startsWith(`${root}/`)) {
|
|
1343
|
+
stripped = collection.slice(root.length + 1);
|
|
1344
|
+
} else if (collection === root) {
|
|
1345
|
+
stripped = "";
|
|
1346
|
+
}
|
|
1347
|
+
const segments = stripped.split("/").filter(Boolean);
|
|
1348
|
+
if (slug && !isIndexSlug(slug)) {
|
|
1349
|
+
segments.push(slug);
|
|
1350
|
+
}
|
|
1351
|
+
const path21 = segments.length > 0 ? `/${segments.join("/")}` : "/";
|
|
1352
|
+
return path21.toLowerCase();
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
// dist/url-collision.js
|
|
1356
|
+
import fs4 from "node:fs/promises";
|
|
1357
|
+
import path5 from "node:path";
|
|
1358
|
+
|
|
1001
1359
|
// dist/content-id-index.js
|
|
1002
1360
|
import fs3 from "node:fs/promises";
|
|
1003
1361
|
import path4 from "node:path";
|
|
@@ -1013,6 +1371,37 @@ var PHYSICAL_SEGMENT_PATTERN = new RegExp(`\\.${BASE58_PATTERN}{12}(?:\\.[a-z]+)
|
|
|
1013
1371
|
function isValidContentId(id) {
|
|
1014
1372
|
return CONTENT_ID_PATTERN.test(id);
|
|
1015
1373
|
}
|
|
1374
|
+
function parseSlug(slug) {
|
|
1375
|
+
if (!slug) {
|
|
1376
|
+
return {
|
|
1377
|
+
ok: false,
|
|
1378
|
+
error: "Slug is required"
|
|
1379
|
+
};
|
|
1380
|
+
}
|
|
1381
|
+
if (slug.length > 64) {
|
|
1382
|
+
return { ok: false, error: "Slug too long (max 64 characters)" };
|
|
1383
|
+
}
|
|
1384
|
+
if (slug.includes("/") || slug.includes("\\")) {
|
|
1385
|
+
return {
|
|
1386
|
+
ok: false,
|
|
1387
|
+
error: "Slug cannot contain path separators"
|
|
1388
|
+
};
|
|
1389
|
+
}
|
|
1390
|
+
if (slug === "." || slug === "..") {
|
|
1391
|
+
return {
|
|
1392
|
+
ok: false,
|
|
1393
|
+
error: "Slug cannot be a traversal sequence"
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
const normalized = slug.toLowerCase();
|
|
1397
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(normalized)) {
|
|
1398
|
+
return {
|
|
1399
|
+
ok: false,
|
|
1400
|
+
error: "Slug must start with a letter or number and contain only lowercase letters, numbers, and hyphens"
|
|
1401
|
+
};
|
|
1402
|
+
}
|
|
1403
|
+
return { ok: true, slug: normalized };
|
|
1404
|
+
}
|
|
1016
1405
|
|
|
1017
1406
|
// dist/id.js
|
|
1018
1407
|
function generateId() {
|
|
@@ -1357,13 +1746,13 @@ function extractIdFromFilename(filename) {
|
|
|
1357
1746
|
return null;
|
|
1358
1747
|
}
|
|
1359
1748
|
async function resolveCollectionPath(root, logicalPath) {
|
|
1360
|
-
const
|
|
1361
|
-
const
|
|
1749
|
+
const fs18 = await import("node:fs/promises");
|
|
1750
|
+
const path21 = await import("node:path");
|
|
1362
1751
|
const segments = logicalPath.split("/").filter(Boolean);
|
|
1363
1752
|
let currentPath = root;
|
|
1364
1753
|
for (const segment of segments) {
|
|
1365
1754
|
try {
|
|
1366
|
-
const entries = await
|
|
1755
|
+
const entries = await fs18.readdir(currentPath, { withFileTypes: true });
|
|
1367
1756
|
const matchingDir = entries.find((entry) => {
|
|
1368
1757
|
if (!entry.isDirectory())
|
|
1369
1758
|
return false;
|
|
@@ -1371,7 +1760,7 @@ async function resolveCollectionPath(root, logicalPath) {
|
|
|
1371
1760
|
return logicalName === segment.toLowerCase();
|
|
1372
1761
|
});
|
|
1373
1762
|
if (matchingDir) {
|
|
1374
|
-
currentPath =
|
|
1763
|
+
currentPath = path21.join(currentPath, matchingDir.name);
|
|
1375
1764
|
} else {
|
|
1376
1765
|
return null;
|
|
1377
1766
|
}
|
|
@@ -1421,8 +1810,99 @@ function extractSlugFromFilename(filename, entryTypeName) {
|
|
|
1421
1810
|
return filename.toLowerCase();
|
|
1422
1811
|
}
|
|
1423
1812
|
|
|
1813
|
+
// dist/utils/typed-filename.js
|
|
1814
|
+
var parseTypedFilename = (filename, entryTypes) => {
|
|
1815
|
+
if (filename.startsWith("."))
|
|
1816
|
+
return null;
|
|
1817
|
+
const lastDot = filename.lastIndexOf(".");
|
|
1818
|
+
if (lastDot === -1)
|
|
1819
|
+
return null;
|
|
1820
|
+
const nameWithoutExt = filename.slice(0, lastDot);
|
|
1821
|
+
const parts = nameWithoutExt.split(".");
|
|
1822
|
+
if (parts.length < 3)
|
|
1823
|
+
return null;
|
|
1824
|
+
const potentialType = parts[0];
|
|
1825
|
+
if (entryTypes && !entryTypes.some((e) => e.name === potentialType)) {
|
|
1826
|
+
return null;
|
|
1827
|
+
}
|
|
1828
|
+
const id = parts[parts.length - 1];
|
|
1829
|
+
if (!isValidId(id))
|
|
1830
|
+
return null;
|
|
1831
|
+
const slug = parts.slice(1, -1).join(".").toLowerCase();
|
|
1832
|
+
return {
|
|
1833
|
+
type: potentialType,
|
|
1834
|
+
slug,
|
|
1835
|
+
id
|
|
1836
|
+
};
|
|
1837
|
+
};
|
|
1838
|
+
|
|
1839
|
+
// dist/url-collision.js
|
|
1840
|
+
var CONTENT_EXTENSIONS = [".md", ".mdx", ".json", ".yaml"];
|
|
1841
|
+
async function readDirSafe(dir) {
|
|
1842
|
+
try {
|
|
1843
|
+
return await fs4.readdir(dir, { withFileTypes: true });
|
|
1844
|
+
} catch (err) {
|
|
1845
|
+
if (isNotFoundError(err))
|
|
1846
|
+
return [];
|
|
1847
|
+
throw err;
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
async function findChildCollectionDir(dir, name) {
|
|
1851
|
+
const wanted = name.toLowerCase();
|
|
1852
|
+
for (const entry of await readDirSafe(dir)) {
|
|
1853
|
+
if (!entry.isDirectory())
|
|
1854
|
+
continue;
|
|
1855
|
+
if (extractSlugFromFilename(entry.name) === wanted)
|
|
1856
|
+
return path5.join(dir, entry.name);
|
|
1857
|
+
}
|
|
1858
|
+
return null;
|
|
1859
|
+
}
|
|
1860
|
+
function entrySlugOf(filename) {
|
|
1861
|
+
if (!CONTENT_EXTENSIONS.some((ext) => filename.endsWith(ext)))
|
|
1862
|
+
return null;
|
|
1863
|
+
return parseTypedFilename(filename)?.slug ?? null;
|
|
1864
|
+
}
|
|
1865
|
+
async function findIndexEntryIn(dir) {
|
|
1866
|
+
for (const entry of await readDirSafe(dir)) {
|
|
1867
|
+
if (entry.isDirectory())
|
|
1868
|
+
continue;
|
|
1869
|
+
if (isIndexSlug(entrySlugOf(entry.name) ?? void 0))
|
|
1870
|
+
return path5.join(dir, entry.name);
|
|
1871
|
+
}
|
|
1872
|
+
return null;
|
|
1873
|
+
}
|
|
1874
|
+
async function findEntryBySlugIn(dir, slug) {
|
|
1875
|
+
const wanted = slug.toLowerCase();
|
|
1876
|
+
for (const entry of await readDirSafe(dir)) {
|
|
1877
|
+
if (entry.isDirectory())
|
|
1878
|
+
continue;
|
|
1879
|
+
if (entrySlugOf(entry.name) === wanted)
|
|
1880
|
+
return path5.join(dir, entry.name);
|
|
1881
|
+
}
|
|
1882
|
+
return null;
|
|
1883
|
+
}
|
|
1884
|
+
async function findUrlPathClaimant(opts) {
|
|
1885
|
+
const { collectionDir, slug, contentRoot } = opts;
|
|
1886
|
+
if (isIndexSlug(slug)) {
|
|
1887
|
+
const resolvedRoot = path5.resolve(contentRoot);
|
|
1888
|
+
if (path5.resolve(collectionDir) === resolvedRoot)
|
|
1889
|
+
return null;
|
|
1890
|
+
const parentDir = path5.dirname(collectionDir);
|
|
1891
|
+
const ownName = extractSlugFromFilename(path5.basename(collectionDir));
|
|
1892
|
+
if (isIndexSlug(ownName))
|
|
1893
|
+
return null;
|
|
1894
|
+
const claimant = await findEntryBySlugIn(parentDir, ownName);
|
|
1895
|
+
return claimant ? { kind: "parent-entry", physicalPath: claimant, name: ownName } : null;
|
|
1896
|
+
}
|
|
1897
|
+
const childDir = await findChildCollectionDir(collectionDir, slug);
|
|
1898
|
+
if (!childDir)
|
|
1899
|
+
return null;
|
|
1900
|
+
const indexEntry = await findIndexEntryIn(childDir);
|
|
1901
|
+
return indexEntry ? { kind: "sibling-collection-index", physicalPath: indexEntry, name: slug } : null;
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1424
1904
|
// dist/content-index-registry.js
|
|
1425
|
-
import
|
|
1905
|
+
import path6 from "node:path";
|
|
1426
1906
|
var registry = /* @__PURE__ */ new Map();
|
|
1427
1907
|
var finalization = new FinalizationRegistry(({ rootKey, ref }) => {
|
|
1428
1908
|
const refs = registry.get(rootKey);
|
|
@@ -1433,7 +1913,7 @@ var finalization = new FinalizationRegistry(({ rootKey, ref }) => {
|
|
|
1433
1913
|
registry.delete(rootKey);
|
|
1434
1914
|
});
|
|
1435
1915
|
function registerContentIndexForInvalidation(root, target) {
|
|
1436
|
-
const rootKey =
|
|
1916
|
+
const rootKey = path6.resolve(root);
|
|
1437
1917
|
let refs = registry.get(rootKey);
|
|
1438
1918
|
if (!refs) {
|
|
1439
1919
|
refs = /* @__PURE__ */ new Set();
|
|
@@ -1444,8 +1924,8 @@ function registerContentIndexForInvalidation(root, target) {
|
|
|
1444
1924
|
finalization.register(target, { rootKey, ref });
|
|
1445
1925
|
}
|
|
1446
1926
|
function invalidateContentIndexesForRoot(root) {
|
|
1447
|
-
const rootKey =
|
|
1448
|
-
const prefix = rootKey +
|
|
1927
|
+
const rootKey = path6.resolve(root);
|
|
1928
|
+
const prefix = rootKey + path6.sep;
|
|
1449
1929
|
for (const [storeRoot, refs] of registry) {
|
|
1450
1930
|
if (storeRoot !== rootKey && !storeRoot.startsWith(prefix))
|
|
1451
1931
|
continue;
|
|
@@ -1463,8 +1943,8 @@ function invalidateContentIndexesForRoot(root) {
|
|
|
1463
1943
|
}
|
|
1464
1944
|
|
|
1465
1945
|
// dist/resource-generation.js
|
|
1466
|
-
import
|
|
1467
|
-
import
|
|
1946
|
+
import fs5 from "node:fs/promises";
|
|
1947
|
+
import path7 from "node:path";
|
|
1468
1948
|
import { randomUUID } from "node:crypto";
|
|
1469
1949
|
|
|
1470
1950
|
// dist/utils/debug.js
|
|
@@ -1573,7 +2053,7 @@ var testLogger = createDebugLogger({
|
|
|
1573
2053
|
var log = createDebugLogger({ prefix: "ResourceGeneration" });
|
|
1574
2054
|
var META_DIR2 = ".canopy-meta";
|
|
1575
2055
|
function resourceGenerationPath(root, resource) {
|
|
1576
|
-
return
|
|
2056
|
+
return path7.resolve(root, META_DIR2, `${resource}.generation`);
|
|
1577
2057
|
}
|
|
1578
2058
|
async function bumpResourceGeneration(root, resource, options) {
|
|
1579
2059
|
const token = randomUUID();
|
|
@@ -1591,7 +2071,7 @@ async function bumpResourceGeneration(root, resource, options) {
|
|
|
1591
2071
|
}
|
|
1592
2072
|
async function readResourceGeneration(root, resource) {
|
|
1593
2073
|
try {
|
|
1594
|
-
const token = await
|
|
2074
|
+
const token = await fs5.readFile(resourceGenerationPath(root, resource), "utf-8");
|
|
1595
2075
|
return { ok: true, token };
|
|
1596
2076
|
} catch (err) {
|
|
1597
2077
|
if (isNodeError(err) && err.code === "ENOENT")
|
|
@@ -1607,11 +2087,11 @@ function isGenerationCurrent(snapshotToken, read) {
|
|
|
1607
2087
|
}
|
|
1608
2088
|
|
|
1609
2089
|
// dist/branch-schema-cache.js
|
|
1610
|
-
import
|
|
1611
|
-
import
|
|
2090
|
+
import fs7 from "node:fs/promises";
|
|
2091
|
+
import path8 from "node:path";
|
|
1612
2092
|
|
|
1613
2093
|
// dist/schema/meta-loader.js
|
|
1614
|
-
import { promises as
|
|
2094
|
+
import { promises as fs6 } from "fs";
|
|
1615
2095
|
import { join } from "pathe";
|
|
1616
2096
|
import { z } from "zod";
|
|
1617
2097
|
import chokidar from "chokidar";
|
|
@@ -1648,7 +2128,7 @@ function stripEmbeddedIdFromName(name) {
|
|
|
1648
2128
|
async function scanForCollectionMeta(baseDir, relativePath = "") {
|
|
1649
2129
|
const collections = [];
|
|
1650
2130
|
try {
|
|
1651
|
-
const entries = await
|
|
2131
|
+
const entries = await fs6.readdir(baseDir, { withFileTypes: true });
|
|
1652
2132
|
for (const entry of entries) {
|
|
1653
2133
|
if (!entry.isDirectory())
|
|
1654
2134
|
continue;
|
|
@@ -1659,8 +2139,8 @@ async function scanForCollectionMeta(baseDir, relativePath = "") {
|
|
|
1659
2139
|
const absolutePath = join(baseDir, folderName);
|
|
1660
2140
|
const metaPath = join(absolutePath, ".collection.json");
|
|
1661
2141
|
try {
|
|
1662
|
-
await
|
|
1663
|
-
const content = await
|
|
2142
|
+
await fs6.access(metaPath);
|
|
2143
|
+
const content = await fs6.readFile(metaPath, "utf-8");
|
|
1664
2144
|
const parsed = JSON.parse(content);
|
|
1665
2145
|
const meta = collectionMetaSchema.parse(parsed);
|
|
1666
2146
|
collections.push({
|
|
@@ -1692,7 +2172,7 @@ async function loadCollectionMetaFiles(contentRoot) {
|
|
|
1692
2172
|
let root = null;
|
|
1693
2173
|
const rootMetaPath = join(contentRoot, ".collection.json");
|
|
1694
2174
|
try {
|
|
1695
|
-
await
|
|
2175
|
+
await fs6.access(rootMetaPath);
|
|
1696
2176
|
} catch (err) {
|
|
1697
2177
|
if (err.code === "ENOENT") {
|
|
1698
2178
|
} else {
|
|
@@ -1700,7 +2180,7 @@ async function loadCollectionMetaFiles(contentRoot) {
|
|
|
1700
2180
|
}
|
|
1701
2181
|
}
|
|
1702
2182
|
try {
|
|
1703
|
-
const content = await
|
|
2183
|
+
const content = await fs6.readFile(rootMetaPath, "utf-8");
|
|
1704
2184
|
const parsed = JSON.parse(content);
|
|
1705
2185
|
root = rootCollectionMetaSchema.parse(parsed);
|
|
1706
2186
|
} catch (err) {
|
|
@@ -1887,16 +2367,16 @@ var SCHEMA_GENERATION_RESOURCE = "schema";
|
|
|
1887
2367
|
async function isStaleByMtime(dir, cachedAt) {
|
|
1888
2368
|
let entries;
|
|
1889
2369
|
try {
|
|
1890
|
-
entries = await
|
|
2370
|
+
entries = await fs7.readdir(dir, { recursive: true, encoding: "utf-8" });
|
|
1891
2371
|
} catch {
|
|
1892
2372
|
return true;
|
|
1893
2373
|
}
|
|
1894
2374
|
for (const entry of entries) {
|
|
1895
2375
|
if (!entry.endsWith(".collection.json"))
|
|
1896
2376
|
continue;
|
|
1897
|
-
const full =
|
|
2377
|
+
const full = path8.join(dir, entry);
|
|
1898
2378
|
try {
|
|
1899
|
-
const stat = await
|
|
2379
|
+
const stat = await fs7.stat(full);
|
|
1900
2380
|
if (stat.mtimeMs > cachedAt.getTime())
|
|
1901
2381
|
return true;
|
|
1902
2382
|
} catch {
|
|
@@ -1920,7 +2400,7 @@ var BranchSchemaCache = class {
|
|
|
1920
2400
|
* the project root, regardless of which entrypoint produced the cwd branchRoot.
|
|
1921
2401
|
*/
|
|
1922
2402
|
skipDiskCache(branchRoot) {
|
|
1923
|
-
return isBuildMode() ||
|
|
2403
|
+
return isBuildMode() || path8.resolve(branchRoot) === path8.resolve(process.cwd());
|
|
1924
2404
|
}
|
|
1925
2405
|
/**
|
|
1926
2406
|
* Get schema for a branch (loads from cache or resolves fresh).
|
|
@@ -1946,14 +2426,14 @@ var BranchSchemaCache = class {
|
|
|
1946
2426
|
* Load schema from cache or resolve fresh if cache is missing or stale.
|
|
1947
2427
|
*/
|
|
1948
2428
|
async loadFromCacheOrResolve(branchRoot, entrySchemaRegistry, contentRootName) {
|
|
1949
|
-
const contentRoot =
|
|
2429
|
+
const contentRoot = path8.join(branchRoot, contentRootName);
|
|
1950
2430
|
const skipDiskCache = this.skipDiskCache(branchRoot);
|
|
1951
2431
|
if (!skipDiskCache) {
|
|
1952
|
-
const cacheDir =
|
|
1953
|
-
const cachePath =
|
|
2432
|
+
const cacheDir = path8.join(branchRoot, ".canopy-meta");
|
|
2433
|
+
const cachePath = path8.join(cacheDir, "schema-cache.json");
|
|
1954
2434
|
let cacheData = null;
|
|
1955
2435
|
try {
|
|
1956
|
-
const cacheContent = await
|
|
2436
|
+
const cacheContent = await fs7.readFile(cachePath, "utf-8");
|
|
1957
2437
|
cacheData = JSON.parse(cacheContent);
|
|
1958
2438
|
} catch {
|
|
1959
2439
|
cacheData = null;
|
|
@@ -1990,7 +2470,7 @@ var BranchSchemaCache = class {
|
|
|
1990
2470
|
*/
|
|
1991
2471
|
async resolveFreshAndPersist(branchRoot, entrySchemaRegistry, contentRootName, options) {
|
|
1992
2472
|
const { skipDiskCache } = options;
|
|
1993
|
-
const contentRoot =
|
|
2473
|
+
const contentRoot = path8.join(branchRoot, contentRootName);
|
|
1994
2474
|
const read = skipDiskCache ? null : await readResourceGeneration(branchRoot, SCHEMA_GENERATION_RESOURCE);
|
|
1995
2475
|
const result = await this.resolveFresh(contentRoot, entrySchemaRegistry);
|
|
1996
2476
|
if (!isValidSchema(result.schema)) {
|
|
@@ -2003,9 +2483,9 @@ var BranchSchemaCache = class {
|
|
|
2003
2483
|
}
|
|
2004
2484
|
const flatSchema = flattenSchema(result.schema, contentRootName);
|
|
2005
2485
|
if (!skipDiskCache) {
|
|
2006
|
-
const cacheDir =
|
|
2007
|
-
const cachePath =
|
|
2008
|
-
await
|
|
2486
|
+
const cacheDir = path8.join(branchRoot, ".canopy-meta");
|
|
2487
|
+
const cachePath = path8.join(cacheDir, "schema-cache.json");
|
|
2488
|
+
await fs7.unlink(path8.join(cacheDir, "schema-cache.stale")).catch(() => {
|
|
2009
2489
|
});
|
|
2010
2490
|
if (read && read.ok) {
|
|
2011
2491
|
const newCache = {
|
|
@@ -2015,13 +2495,13 @@ var BranchSchemaCache = class {
|
|
|
2015
2495
|
cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2016
2496
|
generation: read.token
|
|
2017
2497
|
};
|
|
2018
|
-
await
|
|
2019
|
-
const tmpPath =
|
|
2020
|
-
await
|
|
2498
|
+
await fs7.mkdir(cacheDir, { recursive: true });
|
|
2499
|
+
const tmpPath = path8.join(cacheDir, `schema-cache.tmp.${Date.now()}.${Math.random()}.json`);
|
|
2500
|
+
await fs7.writeFile(tmpPath, JSON.stringify(newCache, null, 2), "utf-8");
|
|
2021
2501
|
try {
|
|
2022
|
-
await
|
|
2502
|
+
await fs7.rename(tmpPath, cachePath);
|
|
2023
2503
|
} catch (err) {
|
|
2024
|
-
await
|
|
2504
|
+
await fs7.unlink(tmpPath).catch(() => {
|
|
2025
2505
|
});
|
|
2026
2506
|
throw err;
|
|
2027
2507
|
}
|
|
@@ -2093,10 +2573,10 @@ async function invalidateBranchContentCaches(root) {
|
|
|
2093
2573
|
}
|
|
2094
2574
|
|
|
2095
2575
|
// dist/utils/fs.js
|
|
2096
|
-
import
|
|
2576
|
+
import fs8 from "node:fs/promises";
|
|
2097
2577
|
async function filePathExists(filePath) {
|
|
2098
2578
|
try {
|
|
2099
|
-
await
|
|
2579
|
+
await fs8.stat(filePath);
|
|
2100
2580
|
return true;
|
|
2101
2581
|
} catch (err) {
|
|
2102
2582
|
if (isNotFoundError(err))
|
|
@@ -2104,6 +2584,15 @@ async function filePathExists(filePath) {
|
|
|
2104
2584
|
throw err;
|
|
2105
2585
|
}
|
|
2106
2586
|
}
|
|
2587
|
+
async function readFileIfExists(filePath) {
|
|
2588
|
+
try {
|
|
2589
|
+
return await fs8.readFile(filePath, "utf8");
|
|
2590
|
+
} catch (err) {
|
|
2591
|
+
if (isNotFoundError(err))
|
|
2592
|
+
return void 0;
|
|
2593
|
+
throw err;
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2107
2596
|
|
|
2108
2597
|
// dist/utils/format.js
|
|
2109
2598
|
var getFormatExtension = (format) => {
|
|
@@ -2142,8 +2631,8 @@ function validateAndNormalizePath(root, target) {
|
|
|
2142
2631
|
|
|
2143
2632
|
// dist/paths/branch.js
|
|
2144
2633
|
init_operating_mode();
|
|
2145
|
-
import
|
|
2146
|
-
import
|
|
2634
|
+
import fs9 from "node:fs/promises";
|
|
2635
|
+
import path10 from "node:path";
|
|
2147
2636
|
|
|
2148
2637
|
// dist/paths/branch-name.js
|
|
2149
2638
|
function sanitizeBranchName(branchName) {
|
|
@@ -2166,11 +2655,11 @@ function resolveBranchPath(options) {
|
|
|
2166
2655
|
const safeBranch = sanitizeBranchName(options.branchName);
|
|
2167
2656
|
const strategy = operatingStrategy(options.mode);
|
|
2168
2657
|
const baseRoot = resolveContentBranchesRoot(options.mode, options.basePathOverride);
|
|
2169
|
-
const normalizedBase =
|
|
2170
|
-
const baseWithSep = normalizedBase.endsWith(
|
|
2658
|
+
const normalizedBase = path10.resolve(baseRoot);
|
|
2659
|
+
const baseWithSep = normalizedBase.endsWith(path10.sep) ? normalizedBase : `${normalizedBase}${path10.sep}`;
|
|
2171
2660
|
const branchRoot = strategy.getContentBranchRoot(safeBranch, options.basePathOverride);
|
|
2172
2661
|
const withinBase = (target) => {
|
|
2173
|
-
const resolved =
|
|
2662
|
+
const resolved = path10.resolve(target);
|
|
2174
2663
|
return resolved === normalizedBase || resolved.startsWith(baseWithSep);
|
|
2175
2664
|
};
|
|
2176
2665
|
if (!withinBase(branchRoot)) {
|
|
@@ -2180,7 +2669,7 @@ function resolveBranchPath(options) {
|
|
|
2180
2669
|
}
|
|
2181
2670
|
async function ensureBranchRoot(options) {
|
|
2182
2671
|
const result = resolveBranchPath(options);
|
|
2183
|
-
await
|
|
2672
|
+
await fs9.mkdir(result.branchRoot, { recursive: true });
|
|
2184
2673
|
return result;
|
|
2185
2674
|
}
|
|
2186
2675
|
|
|
@@ -2226,6 +2715,13 @@ var DuplicateContentIdError = class extends ContentConflictError {
|
|
|
2226
2715
|
this.paths = sorted;
|
|
2227
2716
|
}
|
|
2228
2717
|
};
|
|
2718
|
+
var UrlPathConflictError = class extends ContentConflictError {
|
|
2719
|
+
constructor(message, conflictingPath) {
|
|
2720
|
+
super(message);
|
|
2721
|
+
this.name = "UrlPathConflictError";
|
|
2722
|
+
this.conflictingPath = conflictingPath;
|
|
2723
|
+
}
|
|
2724
|
+
};
|
|
2229
2725
|
function getDefaultEntryType(entries) {
|
|
2230
2726
|
if (!entries || entries.length === 0)
|
|
2231
2727
|
return void 0;
|
|
@@ -2242,6 +2738,7 @@ function validateSlug(slug) {
|
|
|
2242
2738
|
var DEFAULT_INDEX_FRESHNESS_INTERVAL_MS = 1e3;
|
|
2243
2739
|
var FORCED_REFRESH_MIN_INTERVAL_MS = 5e3;
|
|
2244
2740
|
var STALE_LOOKUP = Symbol("stale-index-lookup");
|
|
2741
|
+
var createReferenceResolveCache = () => /* @__PURE__ */ new Map();
|
|
2245
2742
|
var ContentStore = class {
|
|
2246
2743
|
constructor(root, flatSchema, options = {}) {
|
|
2247
2744
|
this.indexGeneration = 0;
|
|
@@ -2250,7 +2747,7 @@ var ContentStore = class {
|
|
|
2250
2747
|
this.lastDiskProbeMs = 0;
|
|
2251
2748
|
this.lastForcedRefreshMs = 0;
|
|
2252
2749
|
this.indexBuild = null;
|
|
2253
|
-
this.root =
|
|
2750
|
+
this.root = path11.resolve(root);
|
|
2254
2751
|
this.contentRootName = options.contentRootName || "content";
|
|
2255
2752
|
this.indexFreshnessIntervalMs = options.indexFreshnessIntervalMs ?? DEFAULT_INDEX_FRESHNESS_INTERVAL_MS;
|
|
2256
2753
|
this.contentWriteLockWaitMs = options.contentWriteLockWaitMs ?? DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS;
|
|
@@ -2398,7 +2895,7 @@ var ContentStore = class {
|
|
|
2398
2895
|
async findEntryPathsById(dir, id) {
|
|
2399
2896
|
let entries;
|
|
2400
2897
|
try {
|
|
2401
|
-
entries = await
|
|
2898
|
+
entries = await fs10.readdir(dir, { withFileTypes: true });
|
|
2402
2899
|
} catch (err) {
|
|
2403
2900
|
if (isNodeError(err) && err.code === "ENOENT")
|
|
2404
2901
|
return [];
|
|
@@ -2409,7 +2906,7 @@ var ContentStore = class {
|
|
|
2409
2906
|
if (entry.isDirectory())
|
|
2410
2907
|
continue;
|
|
2411
2908
|
if (extractIdFromFilename(entry.name) === id) {
|
|
2412
|
-
matches.push(
|
|
2909
|
+
matches.push(path11.relative(this.root, path11.join(dir, entry.name)));
|
|
2413
2910
|
}
|
|
2414
2911
|
}
|
|
2415
2912
|
return matches.sort();
|
|
@@ -2421,11 +2918,11 @@ var ContentStore = class {
|
|
|
2421
2918
|
getSchemaItems() {
|
|
2422
2919
|
return this.schemaIndex.values();
|
|
2423
2920
|
}
|
|
2424
|
-
assertSchemaItem(
|
|
2425
|
-
const normalized = normalizeFilesystemPath(
|
|
2921
|
+
assertSchemaItem(path21) {
|
|
2922
|
+
const normalized = normalizeFilesystemPath(path21);
|
|
2426
2923
|
const item = this.schemaIndex.get(normalized);
|
|
2427
2924
|
if (!item) {
|
|
2428
|
-
throw new ContentStoreError(`Unknown schema item: ${
|
|
2925
|
+
throw new ContentStoreError(`Unknown schema item: ${path21}`, "NO_SCHEMA_ITEM");
|
|
2429
2926
|
}
|
|
2430
2927
|
return item;
|
|
2431
2928
|
}
|
|
@@ -2492,6 +2989,26 @@ var ContentStore = class {
|
|
|
2492
2989
|
return this.createLockKey(schemaItem, slug);
|
|
2493
2990
|
return prePass.id ? this.idLockKey(prePass.id) : prePass.absolutePath;
|
|
2494
2991
|
}
|
|
2992
|
+
/**
|
|
2993
|
+
* Refuse a create/rename that would give a second entry a `urlPath` another entry already
|
|
2994
|
+
* holds. See url-collision.ts for the two shapes that count, and the legitimate
|
|
2995
|
+
* landing-page-beside-a-collection shape that deliberately does not.
|
|
2996
|
+
*
|
|
2997
|
+
* @param collectionDir Absolute physical directory the entry will live in.
|
|
2998
|
+
* @param slug The entry's slug, as it will be written.
|
|
2999
|
+
*/
|
|
3000
|
+
async assertUrlPathAvailable(collectionDir, slug) {
|
|
3001
|
+
const claimant = await findUrlPathClaimant({
|
|
3002
|
+
collectionDir,
|
|
3003
|
+
slug,
|
|
3004
|
+
contentRoot: path11.resolve(this.root, this.contentRootName)
|
|
3005
|
+
});
|
|
3006
|
+
if (!claimant)
|
|
3007
|
+
return;
|
|
3008
|
+
const relative2 = path11.relative(this.root, claimant.physicalPath);
|
|
3009
|
+
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.`;
|
|
3010
|
+
throw new UrlPathConflictError(message, claimant.physicalPath);
|
|
3011
|
+
}
|
|
2495
3012
|
/**
|
|
2496
3013
|
* Build absolute and relative paths with security validation.
|
|
2497
3014
|
* All entries use the unified filename pattern: {type}.{slug}.{id}.{ext}
|
|
@@ -2508,7 +3025,7 @@ var ContentStore = class {
|
|
|
2508
3025
|
* @param options.entryTypeName - For collections with multiple entry types, specify which one to use. Defaults to the default entry type.
|
|
2509
3026
|
*/
|
|
2510
3027
|
async buildPaths(schemaItem, slug, options = {}) {
|
|
2511
|
-
const rootWithSep = this.root.endsWith(
|
|
3028
|
+
const rootWithSep = this.root.endsWith(path11.sep) ? this.root : `${this.root}${path11.sep}`;
|
|
2512
3029
|
if (schemaItem.type === "entry-type") {
|
|
2513
3030
|
const parentPath = schemaItem.parentPath || "";
|
|
2514
3031
|
const parentCollection = this.schemaIndex.get(parentPath);
|
|
@@ -2541,7 +3058,7 @@ var ContentStore = class {
|
|
|
2541
3058
|
const entryTypeName = entryTypeConfig?.name || "entry";
|
|
2542
3059
|
let collectionRoot = await resolveCollectionPath(this.root, schemaItem.logicalPath);
|
|
2543
3060
|
if (!collectionRoot) {
|
|
2544
|
-
collectionRoot =
|
|
3061
|
+
collectionRoot = path11.resolve(this.root, schemaItem.logicalPath);
|
|
2545
3062
|
}
|
|
2546
3063
|
if (!collectionRoot.startsWith(rootWithSep)) {
|
|
2547
3064
|
throw new ContentStoreError("Path traversal detected", "VALIDATION");
|
|
@@ -2551,7 +3068,7 @@ var ContentStore = class {
|
|
|
2551
3068
|
let existingEntryType;
|
|
2552
3069
|
let foundExisting = false;
|
|
2553
3070
|
if (!id) {
|
|
2554
|
-
const entries = await
|
|
3071
|
+
const entries = await fs10.readdir(collectionRoot, { withFileTypes: true }).catch(() => []);
|
|
2555
3072
|
const existingFile = entries.find((entry) => {
|
|
2556
3073
|
if (entry.isDirectory())
|
|
2557
3074
|
return false;
|
|
@@ -2577,14 +3094,14 @@ var ContentStore = class {
|
|
|
2577
3094
|
}
|
|
2578
3095
|
filename = `${finalEntryTypeName}.${safeSlug}.${id}${ext}`;
|
|
2579
3096
|
}
|
|
2580
|
-
const resolved =
|
|
2581
|
-
const collectionRootWithSep = collectionRoot.endsWith(
|
|
3097
|
+
const resolved = path11.resolve(collectionRoot, filename);
|
|
3098
|
+
const collectionRootWithSep = collectionRoot.endsWith(path11.sep) ? collectionRoot : `${collectionRoot}${path11.sep}`;
|
|
2582
3099
|
if (!resolved.startsWith(collectionRootWithSep)) {
|
|
2583
3100
|
throw new ContentStoreError("Path traversal detected", "VALIDATION");
|
|
2584
3101
|
}
|
|
2585
3102
|
return {
|
|
2586
3103
|
absolutePath: resolved,
|
|
2587
|
-
relativePath:
|
|
3104
|
+
relativePath: path11.relative(this.root, resolved),
|
|
2588
3105
|
id,
|
|
2589
3106
|
entryTypeName: finalEntryTypeName,
|
|
2590
3107
|
existed
|
|
@@ -2620,8 +3137,8 @@ var ContentStore = class {
|
|
|
2620
3137
|
async read(collectionPath, slug = "", options = {}) {
|
|
2621
3138
|
const schemaItem = this.assertSchemaItem(collectionPath);
|
|
2622
3139
|
const { absolutePath, relativePath, entryTypeName: resolvedEntryTypeName } = await this.buildPaths(schemaItem, slug);
|
|
2623
|
-
const stat = await
|
|
2624
|
-
const raw = await
|
|
3140
|
+
const stat = await fs10.stat(absolutePath);
|
|
3141
|
+
const raw = await fs10.readFile(absolutePath, "utf8");
|
|
2625
3142
|
let doc;
|
|
2626
3143
|
let format;
|
|
2627
3144
|
let fields;
|
|
@@ -2660,7 +3177,7 @@ var ContentStore = class {
|
|
|
2660
3177
|
absolutePath
|
|
2661
3178
|
};
|
|
2662
3179
|
} else {
|
|
2663
|
-
const parsed =
|
|
3180
|
+
const parsed = matter2(raw);
|
|
2664
3181
|
doc = {
|
|
2665
3182
|
collection: schemaItem.logicalPath,
|
|
2666
3183
|
collectionName: schemaItem.name,
|
|
@@ -2723,7 +3240,7 @@ var ContentStore = class {
|
|
|
2723
3240
|
const indexedPath = guardIndex.findById(id)?.relativePath ?? null;
|
|
2724
3241
|
if (indexedPath && indexedPath !== relativePath) {
|
|
2725
3242
|
const quarantined = guardIndex.getDuplicateFor(id);
|
|
2726
|
-
const bothOnDisk = await filePathExists(absolutePath) && await filePathExists(
|
|
3243
|
+
const bothOnDisk = await filePathExists(absolutePath) && await filePathExists(path11.join(this.root, indexedPath));
|
|
2727
3244
|
if (quarantined || bothOnDisk) {
|
|
2728
3245
|
throw new DuplicateContentIdError(id, [
|
|
2729
3246
|
indexedPath,
|
|
@@ -2734,10 +3251,18 @@ var ContentStore = class {
|
|
|
2734
3251
|
}
|
|
2735
3252
|
}
|
|
2736
3253
|
}
|
|
2737
|
-
await
|
|
3254
|
+
if (!await filePathExists(absolutePath)) {
|
|
3255
|
+
const chosenSlug = extractSlugFromFilename(path11.basename(absolutePath));
|
|
3256
|
+
const routable = parseSlug(chosenSlug);
|
|
3257
|
+
if (!routable.ok) {
|
|
3258
|
+
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");
|
|
3259
|
+
}
|
|
3260
|
+
await this.assertUrlPathAvailable(path11.dirname(absolutePath), chosenSlug);
|
|
3261
|
+
}
|
|
3262
|
+
await fs10.mkdir(path11.dirname(absolutePath), { recursive: true });
|
|
2738
3263
|
if (input.expectedVersion !== void 0) {
|
|
2739
3264
|
try {
|
|
2740
|
-
const existing = await
|
|
3265
|
+
const existing = await fs10.stat(absolutePath);
|
|
2741
3266
|
if (input.expectedVersion === null) {
|
|
2742
3267
|
throw new ContentConflictError("An entry with this slug already exists");
|
|
2743
3268
|
}
|
|
@@ -2754,7 +3279,7 @@ var ContentStore = class {
|
|
|
2754
3279
|
}
|
|
2755
3280
|
}
|
|
2756
3281
|
if (existingId && !await filePathExists(absolutePath)) {
|
|
2757
|
-
const actualRelPaths = await this.findEntryPathsById(
|
|
3282
|
+
const actualRelPaths = await this.findEntryPathsById(path11.dirname(absolutePath), existingId);
|
|
2758
3283
|
if (actualRelPaths.length > 1) {
|
|
2759
3284
|
throw new DuplicateContentIdError(existingId, actualRelPaths);
|
|
2760
3285
|
}
|
|
@@ -2764,14 +3289,15 @@ var ContentStore = class {
|
|
|
2764
3289
|
throw new ContentConflictError();
|
|
2765
3290
|
}
|
|
2766
3291
|
}
|
|
3292
|
+
const existingRaw = input.format === "json" ? void 0 : await readFileIfExists(absolutePath);
|
|
2767
3293
|
let content;
|
|
2768
3294
|
if (input.format === "json") {
|
|
2769
3295
|
content = `${JSON.stringify(input.data ?? {}, null, 2)}
|
|
2770
3296
|
`;
|
|
2771
3297
|
} else if (input.format === "yaml") {
|
|
2772
|
-
content =
|
|
3298
|
+
content = serializeYaml(input.data ?? {}, existingRaw);
|
|
2773
3299
|
} else {
|
|
2774
|
-
content =
|
|
3300
|
+
content = serializeFrontmatter(input.body, input.data ?? {}, existingRaw);
|
|
2775
3301
|
}
|
|
2776
3302
|
await atomicWriteFile(absolutePath, content);
|
|
2777
3303
|
const liveIndex = this._idIndex;
|
|
@@ -2780,7 +3306,7 @@ var ContentStore = class {
|
|
|
2780
3306
|
const existing = liveIndex.findById(id);
|
|
2781
3307
|
if (existing) {
|
|
2782
3308
|
if (existing.relativePath !== relativePath) {
|
|
2783
|
-
staleOldAbsPath =
|
|
3309
|
+
staleOldAbsPath = path11.join(this.root, existing.relativePath);
|
|
2784
3310
|
liveIndex.updatePath(existing.id, relativePath);
|
|
2785
3311
|
}
|
|
2786
3312
|
} else {
|
|
@@ -2793,13 +3319,13 @@ var ContentStore = class {
|
|
|
2793
3319
|
}
|
|
2794
3320
|
}
|
|
2795
3321
|
if (staleOldAbsPath) {
|
|
2796
|
-
await
|
|
3322
|
+
await fs10.unlink(staleOldAbsPath).catch((err) => {
|
|
2797
3323
|
if (!isNodeError(err) || err.code !== "ENOENT")
|
|
2798
3324
|
throw err;
|
|
2799
3325
|
});
|
|
2800
3326
|
}
|
|
2801
3327
|
await this.recordOwnMutation(liveIndex);
|
|
2802
|
-
const afterStat = await
|
|
3328
|
+
const afterStat = await fs10.stat(absolutePath);
|
|
2803
3329
|
const base = {
|
|
2804
3330
|
collection: schemaItem.logicalPath,
|
|
2805
3331
|
collectionName: schemaItem.name,
|
|
@@ -2877,7 +3403,7 @@ var ContentStore = class {
|
|
|
2877
3403
|
const schemaItem = this.assertSchemaItem(collectionPath);
|
|
2878
3404
|
const { absolutePath } = await this.buildPaths(schemaItem, slug);
|
|
2879
3405
|
try {
|
|
2880
|
-
await
|
|
3406
|
+
await fs10.access(absolutePath);
|
|
2881
3407
|
return true;
|
|
2882
3408
|
} catch (err) {
|
|
2883
3409
|
if (isNodeError(err) && err.code === "ENOENT")
|
|
@@ -2916,7 +3442,7 @@ var ContentStore = class {
|
|
|
2916
3442
|
const collectionRoot = await resolveCollectionPath(this.root, collectionPath);
|
|
2917
3443
|
if (!collectionRoot)
|
|
2918
3444
|
return 0;
|
|
2919
|
-
const entries = await
|
|
3445
|
+
const entries = await fs10.readdir(collectionRoot, { withFileTypes: true }).catch(() => []);
|
|
2920
3446
|
return entries.filter((entry) => !entry.isDirectory() && extractEntryTypeFromFilename(entry.name) === entryTypeName).length;
|
|
2921
3447
|
}
|
|
2922
3448
|
/**
|
|
@@ -2940,7 +3466,7 @@ var ContentStore = class {
|
|
|
2940
3466
|
const collection = this.assertCollection(collectionPath);
|
|
2941
3467
|
const prePass = await this.buildPaths(collection, slug);
|
|
2942
3468
|
if (!prePass.existed) {
|
|
2943
|
-
await
|
|
3469
|
+
await fs10.unlink(prePass.absolutePath);
|
|
2944
3470
|
return;
|
|
2945
3471
|
}
|
|
2946
3472
|
let lockKey = this.entryLockKey(collection, slug, prePass);
|
|
@@ -2956,7 +3482,7 @@ var ContentStore = class {
|
|
|
2956
3482
|
return RETRY_KEY;
|
|
2957
3483
|
}
|
|
2958
3484
|
const { absolutePath, relativePath } = inLock;
|
|
2959
|
-
await
|
|
3485
|
+
await fs10.unlink(absolutePath);
|
|
2960
3486
|
const liveIndex = this._idIndex;
|
|
2961
3487
|
const id = liveIndex.findByPath(relativePath);
|
|
2962
3488
|
if (id) {
|
|
@@ -2992,6 +3518,10 @@ var ContentStore = class {
|
|
|
2992
3518
|
if (currentSlug === safeNewSlug) {
|
|
2993
3519
|
return { newPath: `${collectionPath}/${currentSlug}` };
|
|
2994
3520
|
}
|
|
3521
|
+
const routable = parseSlug(safeNewSlug);
|
|
3522
|
+
if (!routable.ok) {
|
|
3523
|
+
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");
|
|
3524
|
+
}
|
|
2995
3525
|
const prePass = await this.buildPaths(collection, currentSlug);
|
|
2996
3526
|
if (!prePass.existed) {
|
|
2997
3527
|
throw new ContentStoreError(`Entry not found: ${currentSlug}`, "NOT_FOUND");
|
|
@@ -3018,7 +3548,7 @@ var ContentStore = class {
|
|
|
3018
3548
|
}
|
|
3019
3549
|
destLockKey = currentDestKey;
|
|
3020
3550
|
const { absolutePath: currentPath, relativePath: currentRelPath } = inLock;
|
|
3021
|
-
const currentFilename =
|
|
3551
|
+
const currentFilename = path11.basename(currentPath);
|
|
3022
3552
|
const parts = currentFilename.split(".");
|
|
3023
3553
|
if (parts.length < 4) {
|
|
3024
3554
|
throw new ContentStoreError(`Invalid entry filename format: ${currentFilename}`, "VALIDATION");
|
|
@@ -3027,10 +3557,10 @@ var ContentStore = class {
|
|
|
3027
3557
|
const contentId = parts[parts.length - 2];
|
|
3028
3558
|
const ext = `.${parts[parts.length - 1]}`;
|
|
3029
3559
|
const newFilename = `${entryTypeName}.${safeNewSlug}.${contentId}${ext}`;
|
|
3030
|
-
const parentDir =
|
|
3031
|
-
const newPath =
|
|
3560
|
+
const parentDir = path11.dirname(currentPath);
|
|
3561
|
+
const newPath = path11.join(parentDir, newFilename);
|
|
3032
3562
|
try {
|
|
3033
|
-
const entries = await
|
|
3563
|
+
const entries = await fs10.readdir(parentDir, { withFileTypes: true });
|
|
3034
3564
|
for (const entry of entries) {
|
|
3035
3565
|
if (entry.isDirectory())
|
|
3036
3566
|
continue;
|
|
@@ -3043,16 +3573,17 @@ var ContentStore = class {
|
|
|
3043
3573
|
if (err instanceof ContentStoreError)
|
|
3044
3574
|
throw err;
|
|
3045
3575
|
}
|
|
3576
|
+
await this.assertUrlPathAvailable(parentDir, safeNewSlug);
|
|
3046
3577
|
try {
|
|
3047
|
-
await
|
|
3578
|
+
await fs10.link(currentPath, newPath);
|
|
3048
3579
|
} catch (err) {
|
|
3049
3580
|
if (isNodeError(err) && err.code === "EEXIST") {
|
|
3050
3581
|
throw new ContentStoreError(`Entry with slug "${safeNewSlug}" already exists in collection "${collectionPath}"`, "VALIDATION");
|
|
3051
3582
|
}
|
|
3052
3583
|
throw err;
|
|
3053
3584
|
}
|
|
3054
|
-
await
|
|
3055
|
-
const newRelativePath =
|
|
3585
|
+
await fs10.unlink(currentPath);
|
|
3586
|
+
const newRelativePath = path11.relative(this.root, newPath);
|
|
3056
3587
|
const liveIndex = this._idIndex;
|
|
3057
3588
|
const entryId = liveIndex.findByPath(currentRelPath);
|
|
3058
3589
|
if (entryId) {
|
|
@@ -3124,34 +3655,57 @@ var ContentStore = class {
|
|
|
3124
3655
|
}
|
|
3125
3656
|
return entries;
|
|
3126
3657
|
}
|
|
3658
|
+
/**
|
|
3659
|
+
* Resolve every `reference` field in `data` against `fields`, returning a copy.
|
|
3660
|
+
*
|
|
3661
|
+
* This is what `read()` applies automatically (unless `resolveReferences: false`), exposed
|
|
3662
|
+
* so BATCH surfaces can opt into the same resolution without duplicating the walk: the
|
|
3663
|
+
* listing primitives in content-listing.ts and content-tree.ts read entry files straight
|
|
3664
|
+
* off disk and never touch this store, so before this existed a `reference` field reached
|
|
3665
|
+
* `listEntries()`/`buildContentTree()` callers as a bare id string or `null`.
|
|
3666
|
+
*
|
|
3667
|
+
* Pass one {@link ReferenceResolveCache} across a whole batch so a target referenced by
|
|
3668
|
+
* many entries is read once rather than once per referencing entry. Omit `cache` and the
|
|
3669
|
+
* behavior is exactly what `read()` has always done, unmemoized.
|
|
3670
|
+
*
|
|
3671
|
+
* **Path ACLs are not consulted for the targets.** Resolution goes through this store's
|
|
3672
|
+
* own `read()`, below the per-entry permission check in content-reader.ts — so a resolved
|
|
3673
|
+
* target may be an entry the caller could not `read()` directly. That is pre-existing
|
|
3674
|
+
* `read()` behavior, matched here on purpose so one rule covers both; see the
|
|
3675
|
+
* `resolveReferences` option in content-listing.ts for the note adopters see.
|
|
3676
|
+
*/
|
|
3677
|
+
async resolveReferences(data, fields, cache) {
|
|
3678
|
+
return this.resolveReferencesInData(data, fields, cache);
|
|
3679
|
+
}
|
|
3127
3680
|
/**
|
|
3128
3681
|
* Recursively resolve reference fields in data.
|
|
3129
3682
|
* This traverses objects, arrays, and blocks to find and resolve all reference fields.
|
|
3130
3683
|
*/
|
|
3131
|
-
async resolveReferencesInData(data, fields) {
|
|
3684
|
+
async resolveReferencesInData(data, fields, cache) {
|
|
3132
3685
|
const resolved = { ...data };
|
|
3133
3686
|
const idIndex = await this.idIndex();
|
|
3134
3687
|
for (const field of fields) {
|
|
3135
3688
|
if (field.type === "group") {
|
|
3136
|
-
const groupResolved = await this.resolveReferencesInData(resolved, field.fields);
|
|
3689
|
+
const groupResolved = await this.resolveReferencesInData(resolved, field.fields, cache);
|
|
3137
3690
|
Object.assign(resolved, groupResolved);
|
|
3138
3691
|
continue;
|
|
3139
3692
|
}
|
|
3140
3693
|
const value = data[field.name];
|
|
3141
3694
|
if (field.type === "reference") {
|
|
3695
|
+
const includeBody = field.includeBody === true;
|
|
3142
3696
|
if (typeof value === "string" && value) {
|
|
3143
|
-
resolved[field.name] = await this.resolveSingleReference(value, idIndex);
|
|
3697
|
+
resolved[field.name] = await this.resolveSingleReference(value, idIndex, includeBody, cache);
|
|
3144
3698
|
} else if (field.list && Array.isArray(value)) {
|
|
3145
|
-
resolved[field.name] = await Promise.all(value.map((id) => typeof id === "string" ? this.resolveSingleReference(id, idIndex) : null));
|
|
3699
|
+
resolved[field.name] = await Promise.all(value.map((id) => typeof id === "string" ? this.resolveSingleReference(id, idIndex, includeBody, cache) : null));
|
|
3146
3700
|
}
|
|
3147
3701
|
} else if (field.type === "object" && value) {
|
|
3148
3702
|
const objectField = field;
|
|
3149
3703
|
if (!objectField.fields)
|
|
3150
3704
|
continue;
|
|
3151
3705
|
if (objectField.list && Array.isArray(value)) {
|
|
3152
|
-
resolved[field.name] = await Promise.all(value.map((item) => typeof item === "object" && item !== null ? this.resolveReferencesInData(item, objectField.fields) : item));
|
|
3706
|
+
resolved[field.name] = await Promise.all(value.map((item) => typeof item === "object" && item !== null ? this.resolveReferencesInData(item, objectField.fields, cache) : item));
|
|
3153
3707
|
} else if (typeof value === "object") {
|
|
3154
|
-
resolved[field.name] = await this.resolveReferencesInData(value, objectField.fields);
|
|
3708
|
+
resolved[field.name] = await this.resolveReferencesInData(value, objectField.fields, cache);
|
|
3155
3709
|
}
|
|
3156
3710
|
} else if (field.type === "block" && Array.isArray(value)) {
|
|
3157
3711
|
const blockField = field;
|
|
@@ -3164,7 +3718,7 @@ var ContentStore = class {
|
|
|
3164
3718
|
return block;
|
|
3165
3719
|
return {
|
|
3166
3720
|
...b,
|
|
3167
|
-
value: await this.resolveReferencesInData(b.value, template.fields)
|
|
3721
|
+
value: await this.resolveReferencesInData(b.value, template.fields, cache)
|
|
3168
3722
|
};
|
|
3169
3723
|
}));
|
|
3170
3724
|
}
|
|
@@ -3172,7 +3726,56 @@ var ContentStore = class {
|
|
|
3172
3726
|
return resolved;
|
|
3173
3727
|
}
|
|
3174
3728
|
/**
|
|
3175
|
-
* Resolve a single reference ID to full entry data
|
|
3729
|
+
* Resolve a single reference ID to full entry data, memoized when a batch cache is
|
|
3730
|
+
* supplied. Without a cache this is a straight pass-through to the uncached path, so
|
|
3731
|
+
* `read()` behaves exactly as it always has.
|
|
3732
|
+
*
|
|
3733
|
+
* Every occurrence gets its OWN deep copy, even on a cache hit. Without that, the memo
|
|
3734
|
+
* would hand one shared object to all 40 entries referencing the same block — a mutation
|
|
3735
|
+
* in one caller's `extract` (truncating a body for a search index, deleting a field) would
|
|
3736
|
+
* silently rewrite it for every sibling, and both `list: true` elements of `[id, id]` would
|
|
3737
|
+
* be the same instance. The copy is what keeps the cache a pure performance optimization
|
|
3738
|
+
* instead of a semantic change.
|
|
3739
|
+
*
|
|
3740
|
+
* Note the uncached path is NOT the clean baseline it looks like. For a json/yaml target it
|
|
3741
|
+
* genuinely reparses fresh per occurrence, but for md/mdx gray-matter serves `data` from a
|
|
3742
|
+
* process-global content-keyed cache, so `resolveSingleReferenceOnce`'s top-level spread
|
|
3743
|
+
* severs exactly one level and NESTED frontmatter objects alias across occurrences, calls and
|
|
3744
|
+
* requests. That is pre-existing `read()` behavior and out of scope here — deliberately, since
|
|
3745
|
+
* touching it would change `read()` — but it means the cached path is the safer of the two,
|
|
3746
|
+
* not a relaxation of a guarantee the uncached one provides. See
|
|
3747
|
+
* `.claude/future-tasks/graymatter-cache-shared-frontmatter.md`.
|
|
3748
|
+
*
|
|
3749
|
+
* What the copy costs, measured rather than assumed (2000 occurrences of one target, local
|
|
3750
|
+
* disk, so every read hits the page cache — the friendliest possible case for NOT caching):
|
|
3751
|
+
* a snippet-sized target is ~63x cheaper to clone than to re-read-and-parse, while a 265KB
|
|
3752
|
+
* JSON target is ~0.8x, i.e. cloning is marginally SLOWER than reparsing it. So the win is
|
|
3753
|
+
* large in the case this exists for and roughly a wash at the pathological end, never a
|
|
3754
|
+
* blow-up. Two things keep the bad end narrow: an md/mdx target resolves to its FRONTMATTER
|
|
3755
|
+
* only *unless the field sets `includeBody`* (`read()` puts the body on `doc.body`, which
|
|
3756
|
+
* `resolveSingleReferenceOnce` spreads in only for an embedding field), so by default body
|
|
3757
|
+
* size is irrelevant no matter how long the document and only a genuinely huge JSON/YAML
|
|
3758
|
+
* target reaches the wash. **`includeBody: true` is the case that CAN reach it on markdown**:
|
|
3759
|
+
* the body then sits inside the memoized object and is cloned once per referencing entry, so
|
|
3760
|
+
* a long document embedded by many pages pays that repeatedly — the reason `includeBody`
|
|
3761
|
+
* exists as an opt-in per field rather than as resolution's default. And in the deployment this
|
|
3762
|
+
* targets, content lives on EFS/NFS where the syscall the memo removes dominates parse and
|
|
3763
|
+
* clone alike, which the local-disk numbers above understate badly. Correctness is the
|
|
3764
|
+
* reason for the copy regardless; the numbers are here so nobody has to re-derive them
|
|
3765
|
+
* before touching this.
|
|
3766
|
+
*/
|
|
3767
|
+
resolveSingleReference(id, idIndex, includeBody, cache) {
|
|
3768
|
+
if (!cache)
|
|
3769
|
+
return this.resolveSingleReferenceUncached(id, idIndex, includeBody);
|
|
3770
|
+
const key = includeBody ? `${id}:body` : id;
|
|
3771
|
+
let pending = cache.get(key);
|
|
3772
|
+
if (!pending) {
|
|
3773
|
+
pending = this.resolveSingleReferenceUncached(id, idIndex, includeBody);
|
|
3774
|
+
cache.set(key, pending);
|
|
3775
|
+
}
|
|
3776
|
+
return pending.then((resolved) => resolved === null ? null : structuredClone(resolved));
|
|
3777
|
+
}
|
|
3778
|
+
/**
|
|
3176
3779
|
* Returns null if the reference is invalid or missing.
|
|
3177
3780
|
* Includes id, slug, and collection fields for debugging.
|
|
3178
3781
|
*
|
|
@@ -3186,16 +3789,21 @@ var ContentStore = class {
|
|
|
3186
3789
|
* idIndex() dedupes concurrent builds — so a sibling call that wins the
|
|
3187
3790
|
* throttle and rebuilds heals every other miss in the same batch, not just
|
|
3188
3791
|
* the first.
|
|
3792
|
+
*
|
|
3793
|
+
* A {@link ReferenceResolveCache} sits ABOVE this, never inside it, so every
|
|
3794
|
+
* distinct id still runs the full refresh-and-retry above. What a cache changes
|
|
3795
|
+
* is only that repeats of the SAME id in one batch share that one attempt's
|
|
3796
|
+
* outcome instead of each getting an independent throw of the dice.
|
|
3189
3797
|
*/
|
|
3190
|
-
async
|
|
3191
|
-
const first = await this.resolveSingleReferenceOnce(id, idIndex);
|
|
3798
|
+
async resolveSingleReferenceUncached(id, idIndex, includeBody) {
|
|
3799
|
+
const first = await this.resolveSingleReferenceOnce(id, idIndex, includeBody);
|
|
3192
3800
|
if (first !== STALE_LOOKUP)
|
|
3193
3801
|
return first;
|
|
3194
3802
|
await this.refreshIndexForSuspiciousLookup();
|
|
3195
|
-
const second = await this.resolveSingleReferenceOnce(id, await this.idIndex());
|
|
3803
|
+
const second = await this.resolveSingleReferenceOnce(id, await this.idIndex(), includeBody);
|
|
3196
3804
|
return second === STALE_LOOKUP ? null : second;
|
|
3197
3805
|
}
|
|
3198
|
-
async resolveSingleReferenceOnce(id, idIndex) {
|
|
3806
|
+
async resolveSingleReferenceOnce(id, idIndex, includeBody) {
|
|
3199
3807
|
try {
|
|
3200
3808
|
const location = idIndex.findById(id);
|
|
3201
3809
|
if (!location)
|
|
@@ -3206,12 +3814,13 @@ var ContentStore = class {
|
|
|
3206
3814
|
const doc = await this.read(location.collection, location.slug, {
|
|
3207
3815
|
resolveReferences: false
|
|
3208
3816
|
});
|
|
3209
|
-
|
|
3817
|
+
const bodyForEmbed = includeBody && "body" in doc ? { fieldName: doc.bodyFieldName, value: doc.body } : void 0;
|
|
3818
|
+
return buildResolvedReference(doc.data, {
|
|
3210
3819
|
id,
|
|
3211
3820
|
slug: location.slug,
|
|
3212
3821
|
collection: location.collection,
|
|
3213
|
-
|
|
3214
|
-
};
|
|
3822
|
+
urlPath: computeEntryUrl(location.collection, location.slug, this.contentRootName)
|
|
3823
|
+
}, bodyForEmbed);
|
|
3215
3824
|
} catch (error) {
|
|
3216
3825
|
if (isNodeError(error) && error.code === "ENOENT")
|
|
3217
3826
|
return STALE_LOOKUP;
|
|
@@ -3222,8 +3831,8 @@ var ContentStore = class {
|
|
|
3222
3831
|
};
|
|
3223
3832
|
|
|
3224
3833
|
// dist/ai/generate.js
|
|
3225
|
-
import
|
|
3226
|
-
import
|
|
3834
|
+
import path12 from "node:path";
|
|
3835
|
+
import fs11 from "node:fs/promises";
|
|
3227
3836
|
import { minimatch } from "minimatch";
|
|
3228
3837
|
|
|
3229
3838
|
// dist/ai/strip-mdx.js
|
|
@@ -3505,7 +4114,7 @@ function renderField(field, value, depth, entry, config) {
|
|
|
3505
4114
|
const heading = "#".repeat(Math.min(depth, 6));
|
|
3506
4115
|
const descriptionLine = "description" in field && field.description ? `
|
|
3507
4116
|
|
|
3508
|
-
|
|
4117
|
+
_${field.description}_` : "";
|
|
3509
4118
|
if ("list" in field && field.list && Array.isArray(value)) {
|
|
3510
4119
|
return renderListField(field, value, depth, label, heading, descriptionLine, entry, config);
|
|
3511
4120
|
}
|
|
@@ -3770,30 +4379,14 @@ function formatInlineValue(field, value) {
|
|
|
3770
4379
|
return String(value);
|
|
3771
4380
|
}
|
|
3772
4381
|
function yamlValue(value) {
|
|
4382
|
+
if (value === "")
|
|
4383
|
+
return '""';
|
|
3773
4384
|
if (/[:#{}[\],&*?|>!%@`]/.test(value) || value.includes("\n")) {
|
|
3774
4385
|
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
3775
4386
|
}
|
|
3776
4387
|
return value;
|
|
3777
4388
|
}
|
|
3778
4389
|
|
|
3779
|
-
// dist/utils/entry-url.js
|
|
3780
|
-
init_normalize();
|
|
3781
|
-
function computeEntryUrl(collection, slug, contentRoot) {
|
|
3782
|
-
const root = trimSlashes(contentRoot);
|
|
3783
|
-
let stripped = collection;
|
|
3784
|
-
if (root && collection.startsWith(`${root}/`)) {
|
|
3785
|
-
stripped = collection.slice(root.length + 1);
|
|
3786
|
-
} else if (collection === root) {
|
|
3787
|
-
stripped = "";
|
|
3788
|
-
}
|
|
3789
|
-
const segments = stripped.split("/").filter(Boolean);
|
|
3790
|
-
if (slug && slug !== "index") {
|
|
3791
|
-
segments.push(slug);
|
|
3792
|
-
}
|
|
3793
|
-
const path20 = segments.length > 0 ? `/${segments.join("/")}` : "/";
|
|
3794
|
-
return path20.toLowerCase();
|
|
3795
|
-
}
|
|
3796
|
-
|
|
3797
4390
|
// dist/entry-link-resolver.js
|
|
3798
4391
|
var log2 = createDebugLogger({ prefix: "EntryLinks" });
|
|
3799
4392
|
var BASE58_CHAR = "[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]";
|
|
@@ -3966,7 +4559,7 @@ async function processCollection(store, collection, flatSchema, contentRoot, con
|
|
|
3966
4559
|
const listed = await store.getCollectionEntryPaths(collection.logicalPath);
|
|
3967
4560
|
const directEntries = listed.filter((e) => e.collection === collection.logicalPath);
|
|
3968
4561
|
for (const listEntry of directEntries) {
|
|
3969
|
-
const entryTypeName = extractEntryTypeFromFilename(
|
|
4562
|
+
const entryTypeName = extractEntryTypeFromFilename(path12.basename(listEntry.relativePath));
|
|
3970
4563
|
if (!entryTypeName)
|
|
3971
4564
|
continue;
|
|
3972
4565
|
if (config?.exclude?.entryTypes?.includes(entryTypeName))
|
|
@@ -3984,7 +4577,7 @@ async function processCollection(store, collection, flatSchema, contentRoot, con
|
|
|
3984
4577
|
}
|
|
3985
4578
|
if (config?.exclude?.where?.(aiEntry))
|
|
3986
4579
|
continue;
|
|
3987
|
-
await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(
|
|
4580
|
+
await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(path12.basename(listEntry.relativePath)), config);
|
|
3988
4581
|
entries.push(aiEntry);
|
|
3989
4582
|
const entryFilePath = `${cleanPath}/${listEntry.slug}.md`;
|
|
3990
4583
|
const entryMarkdown = entryToMarkdown(aiEntry, config);
|
|
@@ -4035,7 +4628,7 @@ async function processRootEntries(store, rootCollection, contentRoot, config, id
|
|
|
4035
4628
|
const listed = await store.getCollectionEntryPaths(rootCollection.logicalPath);
|
|
4036
4629
|
const directEntries = listed.filter((e) => e.collection === rootCollection.logicalPath);
|
|
4037
4630
|
for (const listEntry of directEntries) {
|
|
4038
|
-
const entryTypeName = extractEntryTypeFromFilename(
|
|
4631
|
+
const entryTypeName = extractEntryTypeFromFilename(path12.basename(listEntry.relativePath));
|
|
4039
4632
|
if (!entryTypeName)
|
|
4040
4633
|
continue;
|
|
4041
4634
|
if (config?.exclude?.entryTypes?.includes(entryTypeName))
|
|
@@ -4053,7 +4646,7 @@ async function processRootEntries(store, rootCollection, contentRoot, config, id
|
|
|
4053
4646
|
}
|
|
4054
4647
|
if (config?.exclude?.where?.(aiEntry))
|
|
4055
4648
|
continue;
|
|
4056
|
-
await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(
|
|
4649
|
+
await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(path12.basename(listEntry.relativePath)), config);
|
|
4057
4650
|
entries.push(aiEntry);
|
|
4058
4651
|
const entryFilePath = `${listEntry.slug}.md`;
|
|
4059
4652
|
const entryMarkdown = entryToMarkdown(aiEntry, config);
|
|
@@ -4101,19 +4694,19 @@ function docToAIEntry(doc, slug, entryTypeName, entryTypeConfig, cleanCollection
|
|
|
4101
4694
|
};
|
|
4102
4695
|
}
|
|
4103
4696
|
function makeReadSibling(dir) {
|
|
4104
|
-
const resolvedDir =
|
|
4697
|
+
const resolvedDir = path12.resolve(dir);
|
|
4105
4698
|
return async (name) => {
|
|
4106
|
-
if (!name || name.includes("/") || name.includes("\\") ||
|
|
4699
|
+
if (!name || name.includes("/") || name.includes("\\") || path12.isAbsolute(name) || hasTraversalSequence(name)) {
|
|
4107
4700
|
return null;
|
|
4108
4701
|
}
|
|
4109
|
-
const abs =
|
|
4110
|
-
if (
|
|
4702
|
+
const abs = path12.resolve(resolvedDir, name);
|
|
4703
|
+
if (path12.dirname(abs) !== resolvedDir)
|
|
4111
4704
|
return null;
|
|
4112
4705
|
try {
|
|
4113
|
-
const stats = await
|
|
4706
|
+
const stats = await fs11.lstat(abs);
|
|
4114
4707
|
if (!stats.isFile())
|
|
4115
4708
|
return null;
|
|
4116
|
-
return await
|
|
4709
|
+
return await fs11.readFile(abs, "utf8");
|
|
4117
4710
|
} catch (err) {
|
|
4118
4711
|
if (isNodeError(err) && (err.code === "ENOENT" || err.code === "ENOTDIR"))
|
|
4119
4712
|
return null;
|
|
@@ -4127,7 +4720,7 @@ async function runEntryTransform(entry, absolutePath, contentId, config) {
|
|
|
4127
4720
|
return;
|
|
4128
4721
|
const ctx = {
|
|
4129
4722
|
contentId: contentId ?? "",
|
|
4130
|
-
readSibling: makeReadSibling(
|
|
4723
|
+
readSibling: makeReadSibling(path12.dirname(absolutePath))
|
|
4131
4724
|
};
|
|
4132
4725
|
try {
|
|
4133
4726
|
const appended = await transform(entry, ctx);
|
|
@@ -4164,15 +4757,15 @@ function matchesBundleFilter(entry, filter, contentRoot) {
|
|
|
4164
4757
|
}
|
|
4165
4758
|
|
|
4166
4759
|
// dist/branch-workspace.js
|
|
4167
|
-
import
|
|
4760
|
+
import path17 from "node:path";
|
|
4168
4761
|
|
|
4169
4762
|
// dist/branch-metadata.js
|
|
4170
|
-
import
|
|
4171
|
-
import
|
|
4763
|
+
import fs14 from "node:fs/promises";
|
|
4764
|
+
import path15 from "node:path";
|
|
4172
4765
|
|
|
4173
4766
|
// dist/branch-registry.js
|
|
4174
|
-
import
|
|
4175
|
-
import
|
|
4767
|
+
import fs12 from "node:fs/promises";
|
|
4768
|
+
import path13 from "node:path";
|
|
4176
4769
|
init_logger();
|
|
4177
4770
|
var log3 = createDebugLogger({ prefix: "BranchRegistry" });
|
|
4178
4771
|
var REGISTRY_FILE = "branches.json";
|
|
@@ -4185,10 +4778,10 @@ var BranchRegistry = class {
|
|
|
4185
4778
|
constructor(root) {
|
|
4186
4779
|
this.regenInFlight = null;
|
|
4187
4780
|
this.lastForcedRefreshMs = 0;
|
|
4188
|
-
this.root =
|
|
4189
|
-
this.registryPath =
|
|
4190
|
-
this.stalePath =
|
|
4191
|
-
this.tempPath =
|
|
4781
|
+
this.root = path13.resolve(root);
|
|
4782
|
+
this.registryPath = path13.join(this.root, REGISTRY_FILE);
|
|
4783
|
+
this.stalePath = path13.join(this.root, REGISTRY_STALE_FILE);
|
|
4784
|
+
this.tempPath = path13.join(this.root, REGISTRY_TEMP_FILE);
|
|
4192
4785
|
}
|
|
4193
4786
|
/**
|
|
4194
4787
|
* Returns all branches. Uses the cached snapshot if its embedded generation
|
|
@@ -4197,7 +4790,7 @@ var BranchRegistry = class {
|
|
|
4197
4790
|
async list() {
|
|
4198
4791
|
let parsed;
|
|
4199
4792
|
try {
|
|
4200
|
-
const raw = await
|
|
4793
|
+
const raw = await fs12.readFile(this.registryPath, "utf8");
|
|
4201
4794
|
parsed = JSON.parse(raw);
|
|
4202
4795
|
} catch (err) {
|
|
4203
4796
|
if (isNotFoundError(err)) {
|
|
@@ -4286,7 +4879,7 @@ var BranchRegistry = class {
|
|
|
4286
4879
|
async performRegenerate() {
|
|
4287
4880
|
const read = await readResourceGeneration(this.root, RESOURCE2);
|
|
4288
4881
|
const branches = await this.scanBranchDirectories();
|
|
4289
|
-
await
|
|
4882
|
+
await fs12.unlink(this.stalePath).catch(() => {
|
|
4290
4883
|
});
|
|
4291
4884
|
if (!read.ok) {
|
|
4292
4885
|
return branches;
|
|
@@ -4297,12 +4890,12 @@ var BranchRegistry = class {
|
|
|
4297
4890
|
generation: read.token
|
|
4298
4891
|
};
|
|
4299
4892
|
const uniqueTempPath = `${this.tempPath}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
4300
|
-
await
|
|
4301
|
-
await
|
|
4893
|
+
await fs12.mkdir(this.root, { recursive: true });
|
|
4894
|
+
await fs12.writeFile(uniqueTempPath, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
|
|
4302
4895
|
try {
|
|
4303
|
-
await
|
|
4896
|
+
await fs12.rename(uniqueTempPath, this.registryPath);
|
|
4304
4897
|
} catch (err) {
|
|
4305
|
-
await
|
|
4898
|
+
await fs12.unlink(uniqueTempPath).catch(() => {
|
|
4306
4899
|
});
|
|
4307
4900
|
throw err;
|
|
4308
4901
|
}
|
|
@@ -4316,12 +4909,12 @@ var BranchRegistry = class {
|
|
|
4316
4909
|
async scanBranchDirectories() {
|
|
4317
4910
|
const branches = [];
|
|
4318
4911
|
try {
|
|
4319
|
-
const entries = await
|
|
4912
|
+
const entries = await fs12.readdir(this.root, { withFileTypes: true });
|
|
4320
4913
|
for (const entry of entries) {
|
|
4321
4914
|
if (!entry.isDirectory() || entry.name.startsWith(".")) {
|
|
4322
4915
|
continue;
|
|
4323
4916
|
}
|
|
4324
|
-
const branchRoot =
|
|
4917
|
+
const branchRoot = path13.join(this.root, entry.name);
|
|
4325
4918
|
let meta;
|
|
4326
4919
|
try {
|
|
4327
4920
|
meta = await BranchMetadataFileManager.loadOnly(branchRoot);
|
|
@@ -4348,8 +4941,8 @@ var BranchRegistry = class {
|
|
|
4348
4941
|
};
|
|
4349
4942
|
|
|
4350
4943
|
// dist/utils/occ-json-write.js
|
|
4351
|
-
import
|
|
4352
|
-
import
|
|
4944
|
+
import fs13 from "node:fs/promises";
|
|
4945
|
+
import path14 from "node:path";
|
|
4353
4946
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
4354
4947
|
import lockfile2 from "proper-lockfile";
|
|
4355
4948
|
var log4 = createDebugLogger({ prefix: "OccJsonWrite" });
|
|
@@ -4365,29 +4958,29 @@ async function writeOccJsonFile(filePath, payload, options) {
|
|
|
4365
4958
|
const writeId = randomUUID2();
|
|
4366
4959
|
const data = { ...payload, version: newVersion, writeId };
|
|
4367
4960
|
const content = JSON.stringify(data, null, 2) + (trailingNewline ? "\n" : "");
|
|
4368
|
-
const dir =
|
|
4369
|
-
await
|
|
4961
|
+
const dir = path14.dirname(filePath);
|
|
4962
|
+
await fs13.mkdir(dir, { recursive: true });
|
|
4370
4963
|
const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
4371
|
-
await
|
|
4964
|
+
await fs13.writeFile(tempPath, content, "utf-8");
|
|
4372
4965
|
if (expectedVersion === null) {
|
|
4373
4966
|
try {
|
|
4374
|
-
await
|
|
4967
|
+
await fs13.link(tempPath, filePath);
|
|
4375
4968
|
} catch (err) {
|
|
4376
|
-
await
|
|
4969
|
+
await fs13.unlink(tempPath).catch(() => {
|
|
4377
4970
|
});
|
|
4378
4971
|
if (isFileExistsError(err)) {
|
|
4379
4972
|
throw new OccWriteConflictError();
|
|
4380
4973
|
}
|
|
4381
4974
|
throw err;
|
|
4382
4975
|
}
|
|
4383
|
-
await
|
|
4976
|
+
await fs13.unlink(tempPath).catch(() => {
|
|
4384
4977
|
});
|
|
4385
4978
|
return { version: newVersion, writeId };
|
|
4386
4979
|
}
|
|
4387
4980
|
try {
|
|
4388
4981
|
let currentVersion = null;
|
|
4389
4982
|
try {
|
|
4390
|
-
const current = JSON.parse(await
|
|
4983
|
+
const current = JSON.parse(await fs13.readFile(filePath, "utf-8"));
|
|
4391
4984
|
currentVersion = current.version ?? 0;
|
|
4392
4985
|
} catch {
|
|
4393
4986
|
currentVersion = null;
|
|
@@ -4395,16 +4988,16 @@ async function writeOccJsonFile(filePath, payload, options) {
|
|
|
4395
4988
|
if (currentVersion !== expectedVersion) {
|
|
4396
4989
|
throw new OccWriteConflictError();
|
|
4397
4990
|
}
|
|
4398
|
-
await
|
|
4991
|
+
await fs13.rename(tempPath, filePath);
|
|
4399
4992
|
if (settleMs > 0) {
|
|
4400
4993
|
await new Promise((resolve2) => setTimeout(resolve2, settleMs));
|
|
4401
4994
|
}
|
|
4402
|
-
const afterWrite = JSON.parse(await
|
|
4995
|
+
const afterWrite = JSON.parse(await fs13.readFile(filePath, "utf-8"));
|
|
4403
4996
|
if (afterWrite.writeId !== writeId) {
|
|
4404
4997
|
throw new OccWriteConflictError();
|
|
4405
4998
|
}
|
|
4406
4999
|
} catch (err) {
|
|
4407
|
-
await
|
|
5000
|
+
await fs13.unlink(tempPath).catch(() => {
|
|
4408
5001
|
});
|
|
4409
5002
|
throw err;
|
|
4410
5003
|
}
|
|
@@ -4430,8 +5023,8 @@ async function withOccRetry(operation, options) {
|
|
|
4430
5023
|
throw new Error("Unreachable");
|
|
4431
5024
|
}
|
|
4432
5025
|
async function withOccFileLock(filePath, fn) {
|
|
4433
|
-
const dir =
|
|
4434
|
-
await
|
|
5026
|
+
const dir = path14.dirname(filePath);
|
|
5027
|
+
await fs13.mkdir(dir, { recursive: true });
|
|
4435
5028
|
const MAX_ATTEMPTS = 14;
|
|
4436
5029
|
let release = null;
|
|
4437
5030
|
for (let attempt = 1; release === null; attempt++) {
|
|
@@ -4494,8 +5087,8 @@ var BranchMetadataCorruptError = class extends Error {
|
|
|
4494
5087
|
};
|
|
4495
5088
|
var BranchMetadataFileManager = class _BranchMetadataFileManager {
|
|
4496
5089
|
constructor(branchRoot, baseRoot, options) {
|
|
4497
|
-
this.branchRoot =
|
|
4498
|
-
this.filePath =
|
|
5090
|
+
this.branchRoot = path15.resolve(branchRoot);
|
|
5091
|
+
this.filePath = path15.join(this.branchRoot, BRANCH_META_DIR, BRANCH_META_FILE);
|
|
4499
5092
|
this.baseRoot = baseRoot;
|
|
4500
5093
|
this.settleMs = options?.settleMs;
|
|
4501
5094
|
}
|
|
@@ -4504,10 +5097,10 @@ var BranchMetadataFileManager = class _BranchMetadataFileManager {
|
|
|
4504
5097
|
* Use this for read-only access (e.g., in registry scanning or loadBranchContext).
|
|
4505
5098
|
*/
|
|
4506
5099
|
static async loadOnly(branchRoot) {
|
|
4507
|
-
const resolvedRoot =
|
|
4508
|
-
const filePath =
|
|
5100
|
+
const resolvedRoot = path15.resolve(branchRoot);
|
|
5101
|
+
const filePath = path15.join(resolvedRoot, BRANCH_META_DIR, BRANCH_META_FILE);
|
|
4509
5102
|
try {
|
|
4510
|
-
const raw = await
|
|
5103
|
+
const raw = await fs14.readFile(filePath, "utf8");
|
|
4511
5104
|
return JSON.parse(raw);
|
|
4512
5105
|
} catch (err) {
|
|
4513
5106
|
if (isNotFoundError(err)) {
|
|
@@ -4528,7 +5121,7 @@ var BranchMetadataFileManager = class _BranchMetadataFileManager {
|
|
|
4528
5121
|
}
|
|
4529
5122
|
async load() {
|
|
4530
5123
|
try {
|
|
4531
|
-
const raw = await
|
|
5124
|
+
const raw = await fs14.readFile(this.filePath, "utf8");
|
|
4532
5125
|
const parsed = JSON.parse(raw);
|
|
4533
5126
|
const version = parsed.version ?? 0;
|
|
4534
5127
|
return { meta: parsed, version };
|
|
@@ -4590,7 +5183,7 @@ var BranchMetadataFileManager = class _BranchMetadataFileManager {
|
|
|
4590
5183
|
*/
|
|
4591
5184
|
async save(incoming) {
|
|
4592
5185
|
try {
|
|
4593
|
-
await
|
|
5186
|
+
await fs14.stat(this.branchRoot);
|
|
4594
5187
|
} catch (err) {
|
|
4595
5188
|
if (isNotFoundError(err)) {
|
|
4596
5189
|
throw new BranchMetadataConflictError("Branch no longer exists");
|
|
@@ -4678,8 +5271,8 @@ var loadBranchContext = async (options) => {
|
|
|
4678
5271
|
init_operating_mode();
|
|
4679
5272
|
|
|
4680
5273
|
// dist/git-manager.js
|
|
4681
|
-
import
|
|
4682
|
-
import
|
|
5274
|
+
import fs15 from "node:fs/promises";
|
|
5275
|
+
import path16 from "node:path";
|
|
4683
5276
|
import { simpleGit as simpleGit2 } from "simple-git";
|
|
4684
5277
|
|
|
4685
5278
|
// dist/utils/git.js
|
|
@@ -4739,11 +5332,11 @@ function gitChildEnv(overrides) {
|
|
|
4739
5332
|
var remoteInitLocks = /* @__PURE__ */ new Map();
|
|
4740
5333
|
var GITHUB_TRACKING_REF_PREFIX = "refs/remotes/github/";
|
|
4741
5334
|
async function ensureGitExcludePattern(repoPath, pattern) {
|
|
4742
|
-
const excludePath =
|
|
4743
|
-
await
|
|
5335
|
+
const excludePath = path16.join(repoPath, ".git", "info", "exclude");
|
|
5336
|
+
await fs15.mkdir(path16.dirname(excludePath), { recursive: true });
|
|
4744
5337
|
let content = "";
|
|
4745
5338
|
try {
|
|
4746
|
-
content = await
|
|
5339
|
+
content = await fs15.readFile(excludePath, "utf-8");
|
|
4747
5340
|
} catch (err) {
|
|
4748
5341
|
if (!isNotFoundError(err))
|
|
4749
5342
|
throw err;
|
|
@@ -4755,7 +5348,7 @@ async function ensureGitExcludePattern(repoPath, pattern) {
|
|
|
4755
5348
|
}
|
|
4756
5349
|
const needsLeadingNewline = content.length > 0 && !content.endsWith("\n");
|
|
4757
5350
|
const newContent = content + (needsLeadingNewline ? "\n" : "") + pattern + "\n";
|
|
4758
|
-
await
|
|
5351
|
+
await fs15.writeFile(excludePath, newContent, "utf-8");
|
|
4759
5352
|
log5.debug("git", "Added pattern to .git/info/exclude", { pattern });
|
|
4760
5353
|
}
|
|
4761
5354
|
var GitConflictError = class extends Error {
|
|
@@ -4776,12 +5369,12 @@ var GitRemoteRefMissingError = class extends Error {
|
|
|
4776
5369
|
};
|
|
4777
5370
|
var GitManager = class _GitManager {
|
|
4778
5371
|
constructor(options, gitOptions) {
|
|
4779
|
-
this.repoPath =
|
|
5372
|
+
this.repoPath = path16.resolve(options.repoPath);
|
|
4780
5373
|
this.baseBranch = options.baseBranch ?? "main";
|
|
4781
5374
|
this.remote = options.remote ?? "origin";
|
|
4782
5375
|
this.skipIndexMarker = options.skipIndexMarker ?? false;
|
|
4783
5376
|
this.git = simpleGit2({ baseDir: this.repoPath, ...gitOptions });
|
|
4784
|
-
this.git.env(gitChildEnv({ GIT_CEILING_DIRECTORIES:
|
|
5377
|
+
this.git.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(this.repoPath) }));
|
|
4785
5378
|
}
|
|
4786
5379
|
static async cloneRepo(remoteUrl, targetPath, baseBranch = "main") {
|
|
4787
5380
|
log5.debug("git", "Cloning repository", {
|
|
@@ -4823,11 +5416,11 @@ var GitManager = class _GitManager {
|
|
|
4823
5416
|
remotePath: options.remotePath,
|
|
4824
5417
|
baseBranch: options.baseBranch
|
|
4825
5418
|
});
|
|
4826
|
-
const remoteParent =
|
|
5419
|
+
const remoteParent = path16.dirname(options.remotePath);
|
|
4827
5420
|
releaseLock = await acquireProvisioningLock(remoteParent, ".remote-init.lock");
|
|
4828
5421
|
let remoteExists = false;
|
|
4829
5422
|
try {
|
|
4830
|
-
const stat = await
|
|
5423
|
+
const stat = await fs15.stat(options.remotePath);
|
|
4831
5424
|
remoteExists = stat.isDirectory();
|
|
4832
5425
|
} catch (err) {
|
|
4833
5426
|
if (!isNotFoundError(err))
|
|
@@ -5079,7 +5672,7 @@ var GitManager = class _GitManager {
|
|
|
5079
5672
|
*/
|
|
5080
5673
|
static async validateGitRepoExists(repoPath) {
|
|
5081
5674
|
try {
|
|
5082
|
-
const stat = await
|
|
5675
|
+
const stat = await fs15.stat(path16.join(repoPath, ".git"));
|
|
5083
5676
|
if (!stat.isDirectory()) {
|
|
5084
5677
|
throw new Error(`Expected git repo at ${repoPath}`);
|
|
5085
5678
|
}
|
|
@@ -5157,7 +5750,7 @@ var GitManager = class _GitManager {
|
|
|
5157
5750
|
}
|
|
5158
5751
|
if (config.autoDetectRemotePath) {
|
|
5159
5752
|
try {
|
|
5160
|
-
const stat = await
|
|
5753
|
+
const stat = await fs15.stat(config.autoDetectRemotePath);
|
|
5161
5754
|
if (stat.isDirectory()) {
|
|
5162
5755
|
log5.debug("git", "Auto-detected local remote", {
|
|
5163
5756
|
path: config.autoDetectRemotePath
|
|
@@ -5170,8 +5763,8 @@ var GitManager = class _GitManager {
|
|
|
5170
5763
|
if (config.shouldAutoInitLocal) {
|
|
5171
5764
|
const gitRoot = await this.findGitRoot();
|
|
5172
5765
|
const sourceRoot = options.sourceRoot;
|
|
5173
|
-
const sourcePath = sourceRoot ?
|
|
5174
|
-
const localRemotePath =
|
|
5766
|
+
const sourcePath = sourceRoot ? path16.resolve(gitRoot, sourceRoot) : gitRoot;
|
|
5767
|
+
const localRemotePath = path16.join(sourcePath, config.defaultRemotePath);
|
|
5175
5768
|
await this.ensureLocalSimulatedRemote({
|
|
5176
5769
|
remotePath: localRemotePath,
|
|
5177
5770
|
sourcePath: gitRoot,
|
|
@@ -5199,7 +5792,7 @@ var GitManager = class _GitManager {
|
|
|
5199
5792
|
static async repoExistsAt(workspacePath) {
|
|
5200
5793
|
try {
|
|
5201
5794
|
const checkGit = simpleGit2({ baseDir: workspacePath });
|
|
5202
|
-
checkGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES:
|
|
5795
|
+
checkGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(workspacePath) }));
|
|
5203
5796
|
await checkGit.raw(["rev-parse", "--git-dir"]);
|
|
5204
5797
|
return true;
|
|
5205
5798
|
} catch {
|
|
@@ -5221,19 +5814,19 @@ var GitManager = class _GitManager {
|
|
|
5221
5814
|
const baseBranch = await resolveBaseBranch({
|
|
5222
5815
|
defaultBaseBranch: options.baseBranch,
|
|
5223
5816
|
mode: options.mode,
|
|
5224
|
-
detectFrom: options.sourceRoot ?
|
|
5817
|
+
detectFrom: options.sourceRoot ? path16.resolve(process.cwd(), options.sourceRoot) : process.cwd()
|
|
5225
5818
|
});
|
|
5226
5819
|
const remoteName = options.remoteName ?? "origin";
|
|
5227
5820
|
const repoExists = await _GitManager.repoExistsAt(options.workspacePath);
|
|
5228
5821
|
if (!repoExists) {
|
|
5229
|
-
const gitPath =
|
|
5822
|
+
const gitPath = path16.join(options.workspacePath, ".git");
|
|
5230
5823
|
try {
|
|
5231
|
-
const stat = await
|
|
5824
|
+
const stat = await fs15.stat(gitPath);
|
|
5232
5825
|
if (stat.isDirectory()) {
|
|
5233
5826
|
log5.debug("git", "Removing corrupt .git directory", {
|
|
5234
5827
|
workspacePath: options.workspacePath
|
|
5235
5828
|
});
|
|
5236
|
-
await
|
|
5829
|
+
await fs15.rm(gitPath, { recursive: true });
|
|
5237
5830
|
}
|
|
5238
5831
|
} catch (cleanupErr) {
|
|
5239
5832
|
if (!isNotFoundError(cleanupErr))
|
|
@@ -5260,7 +5853,7 @@ var GitManager = class _GitManager {
|
|
|
5260
5853
|
}
|
|
5261
5854
|
justCloned = true;
|
|
5262
5855
|
const freshGit = simpleGit2({ baseDir: options.workspacePath });
|
|
5263
|
-
freshGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES:
|
|
5856
|
+
freshGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(options.workspacePath) }));
|
|
5264
5857
|
await freshGit.addConfig("canopycms.managed", "true");
|
|
5265
5858
|
await freshGit.addConfig("user.name", options.gitBotAuthorName);
|
|
5266
5859
|
await freshGit.addConfig("user.email", options.gitBotAuthorEmail);
|
|
@@ -5611,9 +6204,9 @@ var GitManager = class _GitManager {
|
|
|
5611
6204
|
} catch {
|
|
5612
6205
|
}
|
|
5613
6206
|
for (const [filePath, content] of Object.entries(initialFiles)) {
|
|
5614
|
-
const absolutePath =
|
|
5615
|
-
await
|
|
5616
|
-
await
|
|
6207
|
+
const absolutePath = path16.join(this.repoPath, filePath);
|
|
6208
|
+
await fs15.mkdir(path16.dirname(absolutePath), { recursive: true });
|
|
6209
|
+
await fs15.writeFile(absolutePath, content, "utf-8");
|
|
5617
6210
|
await this.git.add(filePath);
|
|
5618
6211
|
}
|
|
5619
6212
|
await this.git.commit("Initialize settings branch", ["--allow-empty"]);
|
|
@@ -5642,7 +6235,7 @@ var BranchWorkspaceManager = class {
|
|
|
5642
6235
|
branchName: options.branchName,
|
|
5643
6236
|
mode: options.mode
|
|
5644
6237
|
});
|
|
5645
|
-
releaseLock = await acquireProvisioningLock(
|
|
6238
|
+
releaseLock = await acquireProvisioningLock(path17.dirname(options.branchRoot), `.${path17.basename(options.branchRoot)}.init.lock`);
|
|
5646
6239
|
await GitManager.initializeWorkspace({
|
|
5647
6240
|
workspacePath: options.branchRoot,
|
|
5648
6241
|
branchName: options.branchName,
|
|
@@ -5683,7 +6276,7 @@ var BranchWorkspaceManager = class {
|
|
|
5683
6276
|
const baseBranch = await resolveBaseBranch({
|
|
5684
6277
|
defaultBaseBranch: this.config.defaultBaseBranch,
|
|
5685
6278
|
mode,
|
|
5686
|
-
detectFrom: this.config.sourceRoot ?
|
|
6279
|
+
detectFrom: this.config.sourceRoot ? path17.resolve(process.cwd(), this.config.sourceRoot) : void 0
|
|
5687
6280
|
});
|
|
5688
6281
|
await this.ensureGitWorkspace({
|
|
5689
6282
|
branchRoot,
|
|
@@ -5767,9 +6360,9 @@ async function resolveBranchRoot(config) {
|
|
|
5767
6360
|
}
|
|
5768
6361
|
|
|
5769
6362
|
// dist/content-listing.js
|
|
5770
|
-
import
|
|
5771
|
-
import
|
|
5772
|
-
import
|
|
6363
|
+
import fs16 from "node:fs/promises";
|
|
6364
|
+
import path18 from "node:path";
|
|
6365
|
+
import matter3 from "gray-matter";
|
|
5773
6366
|
import { parse as yamlParse2 } from "yaml";
|
|
5774
6367
|
var log7 = createDebugLogger({ prefix: "ContentListing" });
|
|
5775
6368
|
var normalizePath = (root, target) => {
|
|
@@ -5781,15 +6374,15 @@ var normalizePath = (root, target) => {
|
|
|
5781
6374
|
};
|
|
5782
6375
|
var readEntryData = async (filePath, format, bodyFieldName = "body") => {
|
|
5783
6376
|
try {
|
|
5784
|
-
const raw = await
|
|
6377
|
+
const raw = await fs16.readFile(filePath, "utf8");
|
|
5785
6378
|
if (format === "json") {
|
|
5786
6379
|
return asRecord(JSON.parse(raw));
|
|
5787
6380
|
}
|
|
5788
6381
|
if (format === "yaml") {
|
|
5789
6382
|
return asRecord(yamlParse2(raw));
|
|
5790
6383
|
}
|
|
5791
|
-
const parsed =
|
|
5792
|
-
const data = parsed.data ?? {};
|
|
6384
|
+
const parsed = matter3(raw);
|
|
6385
|
+
const data = { ...parsed.data ?? {} };
|
|
5793
6386
|
if (parsed.content) {
|
|
5794
6387
|
data[bodyFieldName] = parsed.content;
|
|
5795
6388
|
}
|
|
@@ -5801,30 +6394,19 @@ var readEntryData = async (filePath, format, bodyFieldName = "body") => {
|
|
|
5801
6394
|
return {};
|
|
5802
6395
|
}
|
|
5803
6396
|
};
|
|
5804
|
-
var
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
if (parts.length < 3)
|
|
5813
|
-
return null;
|
|
5814
|
-
const potentialType = parts[0];
|
|
5815
|
-
if (entryTypes && !entryTypes.some((e) => e.name === potentialType)) {
|
|
5816
|
-
return null;
|
|
5817
|
-
}
|
|
5818
|
-
const id = parts[parts.length - 1];
|
|
5819
|
-
if (!isValidId(id))
|
|
5820
|
-
return null;
|
|
5821
|
-
const slug = parts.slice(1, -1).join(".").toLowerCase();
|
|
6397
|
+
var createReferenceResolver = (branchRoot, flatSchema, contentRootName) => ({
|
|
6398
|
+
store: new ContentStore(branchRoot, flatSchema, { contentRootName }),
|
|
6399
|
+
cache: createReferenceResolveCache()
|
|
6400
|
+
});
|
|
6401
|
+
var resolveCollectionItemReferences = async (items, collection, resolver) => Promise.all(items.map(async (item) => {
|
|
6402
|
+
const fields = collection.entries?.find((e) => e.name === item.entryType)?.schema;
|
|
6403
|
+
if (!fields)
|
|
6404
|
+
return item;
|
|
5822
6405
|
return {
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
id
|
|
6406
|
+
...item,
|
|
6407
|
+
data: await resolver.store.resolveReferences(item.data, fields, resolver.cache)
|
|
5826
6408
|
};
|
|
5827
|
-
};
|
|
6409
|
+
}));
|
|
5828
6410
|
async function listEntries(branchRoot, flatSchema, contentRootName, options, visibility) {
|
|
5829
6411
|
const rootPath = options?.rootPath ?? contentRootName;
|
|
5830
6412
|
const extract = options?.extract;
|
|
@@ -5833,10 +6415,12 @@ async function listEntries(branchRoot, flatSchema, contentRootName, options, vis
|
|
|
5833
6415
|
const collections = flatSchema.filter((item) => item.type === "collection" && item.entries !== void 0 && (item.logicalPath === rootPath || item.logicalPath.startsWith(`${rootPath}/`)));
|
|
5834
6416
|
const shouldInclude = visibility?.shouldInclude;
|
|
5835
6417
|
const skippedFiles = [];
|
|
6418
|
+
const resolver = options?.resolveReferences ? createReferenceResolver(branchRoot, flatSchema, contentRootName) : null;
|
|
5836
6419
|
const collectionResults = await Promise.all(collections.map(async (collection) => {
|
|
5837
6420
|
const entries = await listCollectionEntries(branchRoot, collection, (file) => skippedFiles.push(file));
|
|
5838
6421
|
const visible = shouldInclude ? entries.filter((e) => shouldInclude(e.physicalPath)) : entries;
|
|
5839
|
-
|
|
6422
|
+
const resolved = resolver ? await resolveCollectionItemReferences(visible, collection, resolver) : visible;
|
|
6423
|
+
return resolved.map((entry) => ({ entry, collection }));
|
|
5840
6424
|
}));
|
|
5841
6425
|
if (isBuildMode() && skippedFiles.length > 0) {
|
|
5842
6426
|
const lines = skippedFiles.map(({ filename, collectionPath }) => ` - ${collectionPath}/${filename}`);
|
|
@@ -5850,8 +6434,7 @@ Expected {type}.{slug}.{id}.{ext} with a known entry type (a name declared in th
|
|
|
5850
6434
|
for (const { entry, collection } of results) {
|
|
5851
6435
|
const pathWithoutRoot = entry.logicalPath.startsWith(contentPrefix) ? entry.logicalPath.slice(contentPrefix.length) : entry.logicalPath;
|
|
5852
6436
|
const pathSegments = pathWithoutRoot.split("/").filter(Boolean);
|
|
5853
|
-
const
|
|
5854
|
-
const urlPath = urlSegments.length > 0 ? `/${urlSegments.join("/")}`.toLowerCase() : "/";
|
|
6437
|
+
const urlPath = computeEntryUrl(entry.collectionPath, entry.slug, contentRootName);
|
|
5855
6438
|
const raw = entry.data;
|
|
5856
6439
|
const meta = {
|
|
5857
6440
|
entryPath: entry.logicalPath,
|
|
@@ -5913,7 +6496,7 @@ var listCollectionEntries = async (root, collection, onSkip) => {
|
|
|
5913
6496
|
normalizePath(root, collectionRoot);
|
|
5914
6497
|
let dirents;
|
|
5915
6498
|
try {
|
|
5916
|
-
dirents = await
|
|
6499
|
+
dirents = await fs16.readdir(collectionRoot, { withFileTypes: true });
|
|
5917
6500
|
} catch (err) {
|
|
5918
6501
|
if (isNotFoundError(err))
|
|
5919
6502
|
return [];
|
|
@@ -5921,7 +6504,7 @@ var listCollectionEntries = async (root, collection, onSkip) => {
|
|
|
5921
6504
|
}
|
|
5922
6505
|
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));
|
|
5923
6506
|
const entries = await Promise.all(files.map(async (file) => {
|
|
5924
|
-
const absolutePath =
|
|
6507
|
+
const absolutePath = path18.join(collectionRoot, file.name);
|
|
5925
6508
|
const relativePath = normalizePath(root, absolutePath);
|
|
5926
6509
|
const parsed = parseTypedFilename(file.name, entryTypes);
|
|
5927
6510
|
if (!parsed) {
|
|
@@ -5936,7 +6519,7 @@ var listCollectionEntries = async (root, collection, onSkip) => {
|
|
|
5936
6519
|
const format = entryType?.format || "json";
|
|
5937
6520
|
const bodyField = entryType?.schema ? findBodyFieldName(entryType.schema) : "body";
|
|
5938
6521
|
const [stats, data] = await Promise.all([
|
|
5939
|
-
|
|
6522
|
+
fs16.stat(absolutePath),
|
|
5940
6523
|
readEntryData(absolutePath, format, bodyField)
|
|
5941
6524
|
]);
|
|
5942
6525
|
const item = {
|
|
@@ -5974,7 +6557,7 @@ function isValidCropRect(x, y, w, h) {
|
|
|
5974
6557
|
}
|
|
5975
6558
|
|
|
5976
6559
|
// dist/validation/field-traversal.js
|
|
5977
|
-
function
|
|
6560
|
+
function isPlainRecord2(value) {
|
|
5978
6561
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5979
6562
|
}
|
|
5980
6563
|
function resolveBlockItem(blockField, item) {
|
|
@@ -5984,21 +6567,21 @@ function resolveBlockItem(blockField, item) {
|
|
|
5984
6567
|
const template = blockField.templates?.find((t) => t.name === templateName);
|
|
5985
6568
|
if (!template?.fields)
|
|
5986
6569
|
return void 0;
|
|
5987
|
-
const data =
|
|
6570
|
+
const data = isPlainRecord2(item.value) ? item.value : item;
|
|
5988
6571
|
return { fields: template.fields, data };
|
|
5989
6572
|
}
|
|
5990
6573
|
|
|
5991
6574
|
// dist/validation/entry-validator.js
|
|
5992
6575
|
var KNOWN_FIELD_TYPES = new Set(fieldTypes);
|
|
5993
6576
|
var STRING_FIELD_TYPES = /* @__PURE__ */ new Set(["string", "markdown", "mdx", "code"]);
|
|
5994
|
-
function
|
|
6577
|
+
function isPlainRecord3(value) {
|
|
5995
6578
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5996
6579
|
}
|
|
5997
6580
|
function isPositiveInt(value) {
|
|
5998
6581
|
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
5999
6582
|
}
|
|
6000
6583
|
function isValidImageCropValue(value) {
|
|
6001
|
-
if (!
|
|
6584
|
+
if (!isPlainRecord3(value))
|
|
6002
6585
|
return false;
|
|
6003
6586
|
const { x, y, w, h } = value;
|
|
6004
6587
|
if (typeof x !== "number" || typeof y !== "number" || typeof w !== "number" || typeof h !== "number") {
|
|
@@ -6006,79 +6589,79 @@ function isValidImageCropValue(value) {
|
|
|
6006
6589
|
}
|
|
6007
6590
|
return isValidCropRect(x, y, w, h);
|
|
6008
6591
|
}
|
|
6009
|
-
function validateImageValue(field, value,
|
|
6010
|
-
if (!
|
|
6011
|
-
return [{ fieldPath:
|
|
6592
|
+
function validateImageValue(field, value, path21) {
|
|
6593
|
+
if (!isPlainRecord3(value)) {
|
|
6594
|
+
return [{ fieldPath: path21, message: "Expected an image object with { src, alt }" }];
|
|
6012
6595
|
}
|
|
6013
6596
|
const errors = [];
|
|
6014
6597
|
if (typeof value.src !== "string" || value.src.trim() === "") {
|
|
6015
|
-
errors.push({ fieldPath: `${
|
|
6598
|
+
errors.push({ fieldPath: `${path21}.src`, message: "Image src is required" });
|
|
6016
6599
|
}
|
|
6017
6600
|
if (typeof value.alt !== "string") {
|
|
6018
|
-
errors.push({ fieldPath: `${
|
|
6601
|
+
errors.push({ fieldPath: `${path21}.alt`, message: "Image alt text is required" });
|
|
6019
6602
|
} else if (value.alt.trim() === "" && field.altOptional !== true) {
|
|
6020
|
-
errors.push({ fieldPath: `${
|
|
6603
|
+
errors.push({ fieldPath: `${path21}.alt`, message: "Image alt text is required" });
|
|
6021
6604
|
}
|
|
6022
6605
|
if (value.width !== void 0 && !isPositiveInt(value.width)) {
|
|
6023
|
-
errors.push({ fieldPath: `${
|
|
6606
|
+
errors.push({ fieldPath: `${path21}.width`, message: "Image width must be a positive integer" });
|
|
6024
6607
|
}
|
|
6025
6608
|
if (value.height !== void 0 && !isPositiveInt(value.height)) {
|
|
6026
6609
|
errors.push({
|
|
6027
|
-
fieldPath: `${
|
|
6610
|
+
fieldPath: `${path21}.height`,
|
|
6028
6611
|
message: "Image height must be a positive integer"
|
|
6029
6612
|
});
|
|
6030
6613
|
}
|
|
6031
6614
|
if (value.crop !== void 0 && !isValidImageCropValue(value.crop)) {
|
|
6032
|
-
errors.push({ fieldPath: `${
|
|
6615
|
+
errors.push({ fieldPath: `${path21}.crop`, message: "Invalid image crop rect" });
|
|
6033
6616
|
}
|
|
6034
6617
|
return errors;
|
|
6035
6618
|
}
|
|
6036
6619
|
function referenceValueId(value) {
|
|
6037
6620
|
if (typeof value === "string")
|
|
6038
6621
|
return value;
|
|
6039
|
-
if (
|
|
6622
|
+
if (isPlainRecord3(value) && typeof value.id === "string")
|
|
6040
6623
|
return value.id;
|
|
6041
6624
|
return void 0;
|
|
6042
6625
|
}
|
|
6043
6626
|
var selectOptionValues = (field) => (field.options ?? []).map((opt) => typeof opt === "string" ? opt : opt.value);
|
|
6044
|
-
function validateScalar(field, value,
|
|
6627
|
+
function validateScalar(field, value, path21) {
|
|
6045
6628
|
switch (field.type) {
|
|
6046
6629
|
case "number":
|
|
6047
6630
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
6048
|
-
return [{ fieldPath:
|
|
6631
|
+
return [{ fieldPath: path21, message: "Expected a number" }];
|
|
6049
6632
|
}
|
|
6050
6633
|
return [];
|
|
6051
6634
|
case "boolean":
|
|
6052
6635
|
if (typeof value !== "boolean") {
|
|
6053
|
-
return [{ fieldPath:
|
|
6636
|
+
return [{ fieldPath: path21, message: "Expected true or false" }];
|
|
6054
6637
|
}
|
|
6055
6638
|
return [];
|
|
6056
6639
|
case "datetime":
|
|
6057
6640
|
if (typeof value !== "string" || value !== "" && Number.isNaN(Date.parse(value))) {
|
|
6058
|
-
return [{ fieldPath:
|
|
6641
|
+
return [{ fieldPath: path21, message: "Expected a valid date/time string" }];
|
|
6059
6642
|
}
|
|
6060
6643
|
return [];
|
|
6061
6644
|
case "select": {
|
|
6062
6645
|
if (typeof value !== "string") {
|
|
6063
|
-
return [{ fieldPath:
|
|
6646
|
+
return [{ fieldPath: path21, message: "Expected a selection" }];
|
|
6064
6647
|
}
|
|
6065
6648
|
const options = selectOptionValues(field);
|
|
6066
6649
|
if (value !== "" && !options.includes(value)) {
|
|
6067
|
-
return [{ fieldPath:
|
|
6650
|
+
return [{ fieldPath: path21, message: `Must be one of: ${options.join(", ")}` }];
|
|
6068
6651
|
}
|
|
6069
6652
|
return [];
|
|
6070
6653
|
}
|
|
6071
6654
|
case "reference":
|
|
6072
6655
|
if (referenceValueId(value) === void 0) {
|
|
6073
|
-
return [{ fieldPath:
|
|
6656
|
+
return [{ fieldPath: path21, message: "Expected a reference id" }];
|
|
6074
6657
|
}
|
|
6075
6658
|
return [];
|
|
6076
6659
|
case "image":
|
|
6077
|
-
return validateImageValue(field, value,
|
|
6660
|
+
return validateImageValue(field, value, path21);
|
|
6078
6661
|
default:
|
|
6079
6662
|
if (STRING_FIELD_TYPES.has(field.type)) {
|
|
6080
6663
|
if (typeof value !== "string") {
|
|
6081
|
-
return [{ fieldPath:
|
|
6664
|
+
return [{ fieldPath: path21, message: "Expected text" }];
|
|
6082
6665
|
}
|
|
6083
6666
|
}
|
|
6084
6667
|
return [];
|
|
@@ -6101,12 +6684,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
|
|
|
6101
6684
|
errors.push(...validateEntryData(field.fields, data, pathPrefix));
|
|
6102
6685
|
continue;
|
|
6103
6686
|
}
|
|
6104
|
-
const
|
|
6687
|
+
const path21 = pathPrefix ? `${pathPrefix}.${field.name}` : field.name;
|
|
6105
6688
|
const value = data[field.name];
|
|
6106
6689
|
const isRequired = "required" in field && field.required === true;
|
|
6107
6690
|
if (isRequired && isEmptyForRequired(field, value)) {
|
|
6108
6691
|
const message = Array.isArray(value) ? "At least one item is required" : "This field is required";
|
|
6109
|
-
errors.push({ fieldPath:
|
|
6692
|
+
errors.push({ fieldPath: path21, message });
|
|
6110
6693
|
continue;
|
|
6111
6694
|
}
|
|
6112
6695
|
if (value === void 0 || value === null)
|
|
@@ -6114,12 +6697,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
|
|
|
6114
6697
|
if (field.type === "block") {
|
|
6115
6698
|
const blockField = field;
|
|
6116
6699
|
if (!Array.isArray(value)) {
|
|
6117
|
-
errors.push({ fieldPath:
|
|
6700
|
+
errors.push({ fieldPath: path21, message: "Expected a list of blocks" });
|
|
6118
6701
|
continue;
|
|
6119
6702
|
}
|
|
6120
6703
|
value.forEach((item, index) => {
|
|
6121
|
-
const itemPath = `${
|
|
6122
|
-
if (!
|
|
6704
|
+
const itemPath = `${path21}[${index}]`;
|
|
6705
|
+
if (!isPlainRecord3(item)) {
|
|
6123
6706
|
errors.push({ fieldPath: itemPath, message: "Expected a block object" });
|
|
6124
6707
|
return;
|
|
6125
6708
|
}
|
|
@@ -6140,12 +6723,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
|
|
|
6140
6723
|
const objectField = field;
|
|
6141
6724
|
if (objectField.list) {
|
|
6142
6725
|
if (!Array.isArray(value)) {
|
|
6143
|
-
errors.push({ fieldPath:
|
|
6726
|
+
errors.push({ fieldPath: path21, message: "Expected a list of items" });
|
|
6144
6727
|
continue;
|
|
6145
6728
|
}
|
|
6146
6729
|
value.forEach((item, index) => {
|
|
6147
|
-
const itemPath = `${
|
|
6148
|
-
if (!
|
|
6730
|
+
const itemPath = `${path21}[${index}]`;
|
|
6731
|
+
if (!isPlainRecord3(item)) {
|
|
6149
6732
|
errors.push({ fieldPath: itemPath, message: "Expected an object" });
|
|
6150
6733
|
return;
|
|
6151
6734
|
}
|
|
@@ -6153,28 +6736,28 @@ function validateEntryData(fields, data, pathPrefix = "") {
|
|
|
6153
6736
|
errors.push(...validateEntryData(objectField.fields, item, itemPath));
|
|
6154
6737
|
}
|
|
6155
6738
|
});
|
|
6156
|
-
} else if (!
|
|
6157
|
-
errors.push({ fieldPath:
|
|
6739
|
+
} else if (!isPlainRecord3(value)) {
|
|
6740
|
+
errors.push({ fieldPath: path21, message: "Expected an object" });
|
|
6158
6741
|
} else if (objectField.fields) {
|
|
6159
|
-
errors.push(...validateEntryData(objectField.fields, value,
|
|
6742
|
+
errors.push(...validateEntryData(objectField.fields, value, path21));
|
|
6160
6743
|
}
|
|
6161
6744
|
continue;
|
|
6162
6745
|
}
|
|
6163
6746
|
if ("list" in field && field.list) {
|
|
6164
6747
|
if (!Array.isArray(value)) {
|
|
6165
|
-
errors.push({ fieldPath:
|
|
6748
|
+
errors.push({ fieldPath: path21, message: "Expected a list of values" });
|
|
6166
6749
|
continue;
|
|
6167
6750
|
}
|
|
6168
6751
|
value.forEach((item, index) => {
|
|
6169
|
-
errors.push(...validateScalar(field, item, `${
|
|
6752
|
+
errors.push(...validateScalar(field, item, `${path21}[${index}]`));
|
|
6170
6753
|
});
|
|
6171
6754
|
continue;
|
|
6172
6755
|
}
|
|
6173
6756
|
if (Array.isArray(value) && KNOWN_FIELD_TYPES.has(field.type)) {
|
|
6174
|
-
errors.push({ fieldPath:
|
|
6757
|
+
errors.push({ fieldPath: path21, message: "Expected a single value, not a list" });
|
|
6175
6758
|
continue;
|
|
6176
6759
|
}
|
|
6177
|
-
errors.push(...validateScalar(field, value,
|
|
6760
|
+
errors.push(...validateScalar(field, value, path21));
|
|
6178
6761
|
}
|
|
6179
6762
|
return errors;
|
|
6180
6763
|
}
|
|
@@ -6222,6 +6805,38 @@ These are likely abandoned create-scaffolds (empty entries left behind when a cr
|
|
|
6222
6805
|
}
|
|
6223
6806
|
|
|
6224
6807
|
// dist/build/generate-ai-content.js
|
|
6808
|
+
var GENERATED_RECORD_FILENAME = ".canopy-generated.json";
|
|
6809
|
+
async function readGeneratedRecord(outputDir) {
|
|
6810
|
+
try {
|
|
6811
|
+
const raw = await fs17.readFile(path19.join(outputDir, GENERATED_RECORD_FILENAME), "utf-8");
|
|
6812
|
+
const parsed = JSON.parse(raw);
|
|
6813
|
+
if (typeof parsed !== "object" || parsed === null || !("files" in parsed))
|
|
6814
|
+
return [];
|
|
6815
|
+
const { files } = parsed;
|
|
6816
|
+
if (!Array.isArray(files))
|
|
6817
|
+
return [];
|
|
6818
|
+
return files.filter((entry) => typeof entry === "string");
|
|
6819
|
+
} catch {
|
|
6820
|
+
return [];
|
|
6821
|
+
}
|
|
6822
|
+
}
|
|
6823
|
+
async function writeGeneratedRecord(outputDir, files) {
|
|
6824
|
+
const record = { files: [...files].sort() };
|
|
6825
|
+
await fs17.mkdir(outputDir, { recursive: true });
|
|
6826
|
+
await fs17.writeFile(path19.join(outputDir, GENERATED_RECORD_FILENAME), `${JSON.stringify(record, null, 2)}
|
|
6827
|
+
`, "utf-8");
|
|
6828
|
+
}
|
|
6829
|
+
async function removeEmptyDirsUpward(startDir, stopAt) {
|
|
6830
|
+
let current = startDir;
|
|
6831
|
+
while (current.startsWith(stopAt) && current !== stopAt) {
|
|
6832
|
+
try {
|
|
6833
|
+
await fs17.rmdir(current);
|
|
6834
|
+
} catch {
|
|
6835
|
+
return;
|
|
6836
|
+
}
|
|
6837
|
+
current = path19.dirname(current);
|
|
6838
|
+
}
|
|
6839
|
+
}
|
|
6225
6840
|
async function generateAIContentFiles(options) {
|
|
6226
6841
|
const { config, entrySchemaRegistry, outputDir, aiConfig, _testFlatSchema } = options;
|
|
6227
6842
|
const contentRootName = config.contentRoot || "content";
|
|
@@ -6244,18 +6859,40 @@ async function generateAIContentFiles(options) {
|
|
|
6244
6859
|
config: aiConfig,
|
|
6245
6860
|
entryLinkUrl: config.entryLinkUrl
|
|
6246
6861
|
});
|
|
6247
|
-
const absoluteOutputDir =
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
const absolutePath = path18.resolve(path18.join(absoluteOutputDir, filePath));
|
|
6862
|
+
const absoluteOutputDir = path19.resolve(outputDir) + path19.sep;
|
|
6863
|
+
const resolveOutputPath = (filePath) => {
|
|
6864
|
+
const absolutePath = path19.resolve(path19.join(absoluteOutputDir, filePath));
|
|
6251
6865
|
if (!absolutePath.startsWith(absoluteOutputDir)) {
|
|
6252
6866
|
throw new Error(`Path traversal detected in AI content output: ${filePath}`);
|
|
6253
6867
|
}
|
|
6254
|
-
|
|
6255
|
-
|
|
6868
|
+
return absolutePath;
|
|
6869
|
+
};
|
|
6870
|
+
const previousFiles = await readGeneratedRecord(absoluteOutputDir);
|
|
6871
|
+
const currentFiles = [...result.files.keys()];
|
|
6872
|
+
await writeGeneratedRecord(absoluteOutputDir, [.../* @__PURE__ */ new Set([...previousFiles, ...currentFiles])]);
|
|
6873
|
+
let fileCount = 0;
|
|
6874
|
+
for (const [filePath, content] of result.files) {
|
|
6875
|
+
const absolutePath = resolveOutputPath(filePath);
|
|
6876
|
+
await fs17.mkdir(path19.dirname(absolutePath), { recursive: true });
|
|
6877
|
+
await fs17.writeFile(absolutePath, content, "utf-8");
|
|
6256
6878
|
fileCount++;
|
|
6257
6879
|
}
|
|
6258
|
-
|
|
6880
|
+
const currentSet = new Set(currentFiles);
|
|
6881
|
+
const stale = previousFiles.filter((filePath) => !currentSet.has(filePath));
|
|
6882
|
+
let removedCount = 0;
|
|
6883
|
+
for (const filePath of stale) {
|
|
6884
|
+
const absolutePath = resolveOutputPath(filePath);
|
|
6885
|
+
try {
|
|
6886
|
+
await fs17.unlink(absolutePath);
|
|
6887
|
+
removedCount++;
|
|
6888
|
+
} catch (err) {
|
|
6889
|
+
if (!isNodeError(err) || err.code !== "ENOENT")
|
|
6890
|
+
throw err;
|
|
6891
|
+
}
|
|
6892
|
+
await removeEmptyDirsUpward(path19.dirname(absolutePath), absoluteOutputDir);
|
|
6893
|
+
}
|
|
6894
|
+
await writeGeneratedRecord(absoluteOutputDir, currentFiles);
|
|
6895
|
+
return { fileCount, removedCount, outputDir: absoluteOutputDir };
|
|
6259
6896
|
}
|
|
6260
6897
|
|
|
6261
6898
|
// dist/cli/generate-ai-content.js
|
|
@@ -6263,7 +6900,7 @@ var jiti = createJiti(import.meta.url);
|
|
|
6263
6900
|
async function generateAIContentCLI(options) {
|
|
6264
6901
|
const { projectDir, outputDir = "public/ai", configPath, appDir = "app" } = options;
|
|
6265
6902
|
console.log("\nCanopyCMS generate-ai-content\n");
|
|
6266
|
-
const canopyConfigPath =
|
|
6903
|
+
const canopyConfigPath = path20.join(projectDir, "canopycms.config.ts");
|
|
6267
6904
|
let canopyConfigModule;
|
|
6268
6905
|
try {
|
|
6269
6906
|
canopyConfigModule = await jiti.import(canopyConfigPath);
|
|
@@ -6274,7 +6911,7 @@ async function generateAIContentCLI(options) {
|
|
|
6274
6911
|
}
|
|
6275
6912
|
const configExport = canopyConfigModule.default ?? canopyConfigModule.config ?? canopyConfigModule;
|
|
6276
6913
|
const serverConfig = typeof configExport === "object" && configExport !== null && "server" in configExport ? configExport.server : configExport;
|
|
6277
|
-
const schemasPath =
|
|
6914
|
+
const schemasPath = path20.join(projectDir, appDir, "schemas.ts");
|
|
6278
6915
|
let entrySchemaRegistry = {};
|
|
6279
6916
|
try {
|
|
6280
6917
|
const schemasModule = await jiti.import(schemasPath);
|
|
@@ -6285,7 +6922,7 @@ async function generateAIContentCLI(options) {
|
|
|
6285
6922
|
let aiConfig;
|
|
6286
6923
|
if (configPath) {
|
|
6287
6924
|
try {
|
|
6288
|
-
const aiConfigModule = await jiti.import(
|
|
6925
|
+
const aiConfigModule = await jiti.import(path20.resolve(configPath));
|
|
6289
6926
|
aiConfig = aiConfigModule.aiContentConfig ?? aiConfigModule.default ?? aiConfigModule.config;
|
|
6290
6927
|
} catch (err) {
|
|
6291
6928
|
console.error(`Could not load AI config from ${configPath}`);
|
|
@@ -6302,7 +6939,7 @@ async function generateAIContentCLI(options) {
|
|
|
6302
6939
|
console.error("Make sure canopycms.config.ts uses defineCanopyConfig().");
|
|
6303
6940
|
process.exit(1);
|
|
6304
6941
|
}
|
|
6305
|
-
const resolvedOutput =
|
|
6942
|
+
const resolvedOutput = path20.resolve(projectDir, outputDir);
|
|
6306
6943
|
console.log(` Output: ${resolvedOutput}`);
|
|
6307
6944
|
console.log(` Mode: ${serverConfig.mode ?? "dev"}`);
|
|
6308
6945
|
const result = await generateAIContentFiles({
|
|
@@ -6313,6 +6950,9 @@ async function generateAIContentCLI(options) {
|
|
|
6313
6950
|
});
|
|
6314
6951
|
console.log(`
|
|
6315
6952
|
Generated ${result.fileCount} files`);
|
|
6953
|
+
if (result.removedCount > 0) {
|
|
6954
|
+
console.log(` Removed ${result.removedCount} stale files from the previous run`);
|
|
6955
|
+
}
|
|
6316
6956
|
console.log(` Output: ${result.outputDir}
|
|
6317
6957
|
`);
|
|
6318
6958
|
}
|