canopycms 0.0.67-int.90 → 0.0.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -3
- package/dist/ai/generate.js +1 -27
- package/dist/ai/handler.d.ts +0 -4
- package/dist/ai/handler.js +0 -11
- package/dist/ai/index.d.ts +1 -8
- package/dist/ai/index.js +1 -8
- package/dist/ai/json-to-markdown.js +15 -58
- package/dist/ai/resolve-branch.d.ts +2 -7
- package/dist/ai/resolve-branch.js +2 -8
- package/dist/ai/strip-mdx.d.ts +5 -13
- package/dist/ai/strip-mdx.js +5 -17
- package/dist/ai/to-plain-text.d.ts +10 -28
- package/dist/ai/to-plain-text.js +10 -28
- package/dist/ai/transform-components.d.ts +2 -4
- package/dist/ai/transform-components.js +8 -19
- package/dist/ai/types.d.ts +5 -10
- package/dist/api/admin-branch-health.d.ts +4 -12
- package/dist/api/admin-branch-health.js +26 -66
- package/dist/api/admin.d.ts +4 -12
- package/dist/api/admin.js +10 -26
- package/dist/api/assets.d.ts +0 -25
- package/dist/api/assets.js +50 -91
- package/dist/api/branch-merge.d.ts +1 -1
- package/dist/api/branch-merge.js +0 -2
- package/dist/api/branch-review.d.ts +0 -8
- package/dist/api/branch-review.js +0 -13
- package/dist/api/branch-status.d.ts +0 -3
- package/dist/api/branch-status.js +8 -33
- package/dist/api/branch-withdraw.d.ts +0 -1
- package/dist/api/branch-withdraw.js +6 -9
- package/dist/api/branch.d.ts +7 -12
- package/dist/api/branch.js +7 -44
- package/dist/api/client.d.ts +71 -224
- package/dist/api/client.js +82 -233
- package/dist/api/comments.d.ts +2 -4
- package/dist/api/comments.js +0 -17
- package/dist/api/content.d.ts +0 -6
- package/dist/api/content.js +66 -142
- package/dist/api/entries-constants.d.ts +5 -9
- package/dist/api/entries-constants.js +5 -9
- package/dist/api/entries.d.ts +8 -13
- package/dist/api/entries.js +20 -51
- package/dist/api/github-sync.d.ts +2 -4
- package/dist/api/github-sync.js +4 -8
- package/dist/api/groups.d.ts +3 -0
- package/dist/api/groups.js +8 -21
- package/dist/api/guards.d.ts +4 -16
- package/dist/api/guards.js +3 -22
- package/dist/api/index.d.ts +4 -4
- package/dist/api/permissions.d.ts +2 -0
- package/dist/api/permissions.js +18 -40
- package/dist/api/reference-options.d.ts +0 -1
- package/dist/api/reference-options.js +3 -11
- package/dist/api/request-body-hash.d.ts +12 -23
- package/dist/api/request-body-hash.js +12 -23
- package/dist/api/resolve-references.d.ts +0 -1
- package/dist/api/resolve-references.js +13 -28
- package/dist/api/route-builder.d.ts +3 -7
- package/dist/api/route-builder.js +1 -1
- package/dist/api/routes.d.ts +12 -0
- package/dist/api/routes.js +47 -0
- package/dist/api/schema.d.ts +23 -33
- package/dist/api/schema.js +20 -74
- package/dist/api/settings-helpers.js +4 -5
- package/dist/api/types.d.ts +0 -5
- package/dist/api/user.js +0 -5
- package/dist/api/validators.d.ts +14 -52
- package/dist/api/validators.js +14 -52
- package/dist/assets/asset-prefixes.d.ts +4 -8
- package/dist/assets/asset-prefixes.js +4 -8
- package/dist/assets/asset-src.d.ts +5 -22
- package/dist/assets/asset-src.js +5 -21
- package/dist/assets/factory.d.ts +1 -2
- package/dist/assets/factory.js +1 -2
- package/dist/assets/finalize.d.ts +3 -1
- package/dist/assets/finalize.js +3 -1
- package/dist/assets/index.d.ts +3 -3
- package/dist/assets/index.js +1 -1
- package/dist/assets/keys.d.ts +5 -3
- package/dist/assets/keys.js +6 -3
- package/dist/assets/pipeline.d.ts +3 -2
- package/dist/assets/pipeline.js +22 -56
- package/dist/assets/sharp-loader.d.ts +2 -10
- package/dist/assets/sharp-loader.js +2 -10
- package/dist/assets/store-local.d.ts +1 -2
- package/dist/assets/store-local.js +1 -2
- package/dist/assets/store-s3.d.ts +3 -4
- package/dist/assets/svg-sanitizer.d.ts +6 -14
- package/dist/assets/svg-sanitizer.js +6 -14
- package/dist/assets/transform-directives.d.ts +3 -4
- package/dist/assets/transform-directives.js +1 -1
- package/dist/assets/transform.d.ts +19 -30
- package/dist/assets/transform.js +18 -31
- package/dist/auth/cache.d.ts +2 -3
- package/dist/auth/cache.js +2 -3
- package/dist/auth/caching-auth-plugin.d.ts +11 -22
- package/dist/auth/caching-auth-plugin.js +12 -14
- package/dist/auth/context-helpers.d.ts +6 -20
- package/dist/auth/context-helpers.js +5 -17
- package/dist/auth/file-based-auth-cache.d.ts +10 -21
- package/dist/auth/file-based-auth-cache.js +23 -51
- package/dist/auth/plugin.d.ts +29 -61
- package/dist/auth/plugin.js +9 -13
- package/dist/auth/types.d.ts +11 -20
- package/dist/authorization/branch.d.ts +30 -49
- package/dist/authorization/branch.js +16 -42
- package/dist/authorization/content.d.ts +11 -40
- package/dist/authorization/content.js +13 -45
- package/dist/authorization/groups/index.d.ts +0 -3
- package/dist/authorization/groups/index.js +0 -3
- package/dist/authorization/groups/loader.d.ts +14 -28
- package/dist/authorization/groups/loader.js +14 -38
- package/dist/authorization/groups/schema.d.ts +0 -6
- package/dist/authorization/groups/schema.js +4 -7
- package/dist/authorization/helpers.d.ts +9 -28
- package/dist/authorization/helpers.js +9 -28
- package/dist/authorization/index.d.ts +3 -25
- package/dist/authorization/index.js +3 -35
- package/dist/authorization/path.d.ts +6 -13
- package/dist/authorization/path.js +8 -25
- package/dist/authorization/permissions/index.d.ts +0 -3
- package/dist/authorization/permissions/index.js +0 -3
- package/dist/authorization/permissions/loader.d.ts +14 -27
- package/dist/authorization/permissions/loader.js +14 -32
- package/dist/authorization/permissions/schema.d.ts +1 -6
- package/dist/authorization/permissions/schema.js +6 -13
- package/dist/authorization/protected-branch.d.ts +36 -65
- package/dist/authorization/protected-branch.js +29 -41
- package/dist/authorization/settings-file-store.d.ts +38 -81
- package/dist/authorization/settings-file-store.js +38 -79
- package/dist/authorization/types.d.ts +4 -26
- package/dist/authorization/types.js +0 -6
- package/dist/authorization/validation.d.ts +1 -23
- package/dist/authorization/validation.js +1 -24
- package/dist/branch-health.d.ts +39 -67
- package/dist/branch-health.js +27 -43
- package/dist/branch-metadata-file.d.ts +16 -32
- package/dist/branch-metadata-file.js +13 -26
- package/dist/branch-metadata.d.ts +49 -80
- package/dist/branch-metadata.js +57 -87
- package/dist/branch-registry.d.ts +26 -64
- package/dist/branch-registry.js +44 -93
- package/dist/branch-schema-cache.d.ts +34 -124
- package/dist/branch-schema-cache.js +49 -155
- package/dist/branch-workspace.d.ts +4 -4
- package/dist/branch-workspace.js +15 -19
- package/dist/build/generate-ai-content.d.ts +1 -0
- package/dist/build/generate-ai-content.js +12 -25
- package/dist/build-canopy.d.ts +17 -27
- package/dist/build-canopy.js +16 -23
- package/dist/build-mode.d.ts +25 -27
- package/dist/build-mode.js +25 -29
- package/dist/cli/cli.d.ts +15 -26
- package/dist/cli/cli.js +601 -978
- package/dist/cli/generate-ai-content.js +351 -628
- package/dist/cli/github-app-manifest.d.ts +84 -0
- package/dist/cli/github-app-manifest.js +161 -0
- package/dist/cli/init-github-app.d.ts +110 -444
- package/dist/cli/init-github-app.js +236 -773
- package/dist/cli/init.js +39 -80
- package/dist/cli/migrate.d.ts +13 -10
- package/dist/cli/migrate.js +22 -30
- package/dist/cli/project-detect.d.ts +17 -31
- package/dist/cli/project-detect.js +31 -42
- package/dist/cli/project-root.d.ts +4 -11
- package/dist/cli/project-root.js +4 -11
- package/dist/cli/prompt.d.ts +10 -0
- package/dist/cli/prompt.js +67 -0
- package/dist/cli/sync.d.ts +0 -8
- package/dist/cli/sync.js +8 -28
- package/dist/cli/template-files/middleware.ts.template +15 -29
- package/dist/cli/templates.d.ts +2 -12
- package/dist/cli/templates.js +4 -4
- package/dist/client.d.ts +1 -1
- package/dist/comment-store.d.ts +32 -53
- package/dist/comment-store.js +32 -52
- package/dist/config/flatten.d.ts +0 -3
- package/dist/config/flatten.js +2 -12
- package/dist/config/helpers.js +2 -2
- package/dist/config/index.d.ts +2 -2
- package/dist/config/index.js +1 -4
- package/dist/config/schemas/collection.d.ts +0 -8
- package/dist/config/schemas/collection.js +0 -10
- package/dist/config/schemas/config.d.ts +6 -78
- package/dist/config/schemas/config.js +38 -54
- package/dist/config/schemas/field.d.ts +2 -242
- package/dist/config/schemas/field.js +9 -20
- package/dist/config/schemas/media.js +1 -1
- package/dist/config/schemas/permissions.js +0 -2
- package/dist/config/schemas/url.d.ts +5 -6
- package/dist/config/schemas/url.js +5 -6
- package/dist/config/types.d.ts +45 -33
- package/dist/config/types.js +0 -1
- package/dist/config.d.ts +1 -8
- package/dist/config.js +1 -9
- package/dist/content-id-index.d.ts +76 -188
- package/dist/content-id-index.js +79 -230
- package/dist/content-index-generation.d.ts +27 -48
- package/dist/content-index-generation.js +35 -84
- package/dist/content-index-registry.d.ts +15 -24
- package/dist/content-index-registry.js +5 -9
- package/dist/content-listing.d.ts +64 -107
- package/dist/content-listing.js +68 -118
- package/dist/content-reader.d.ts +20 -29
- package/dist/content-reader.js +10 -18
- package/dist/content-store.d.ts +210 -336
- package/dist/content-store.js +413 -657
- package/dist/content-tree.d.ts +44 -86
- package/dist/content-tree.js +26 -54
- package/dist/context.d.ts +67 -94
- package/dist/context.js +53 -72
- package/dist/dev-content-watcher.d.ts +18 -18
- package/dist/dev-content-watcher.js +41 -44
- package/dist/editor/BranchManager.d.ts +3 -6
- package/dist/editor/BranchManager.js +24 -44
- package/dist/editor/CanopyEditor.js +5 -2
- package/dist/editor/CommentsPanel.js +0 -2
- package/dist/editor/Editor.js +19 -76
- package/dist/editor/EditorAuthGate.d.ts +27 -0
- package/dist/editor/EditorAuthGate.js +140 -0
- package/dist/editor/EntryNavigator.js +0 -20
- package/dist/editor/FormRenderer.d.ts +1 -2
- package/dist/editor/FormRenderer.js +8 -23
- package/dist/editor/admin/SystemHealthPanel.js +20 -37
- package/dist/editor/admin/useSystemHealth.d.ts +2 -3
- package/dist/editor/admin/useSystemHealth.js +10 -12
- package/dist/editor/client-reference-resolver.d.ts +2 -5
- package/dist/editor/client-reference-resolver.js +2 -19
- package/dist/editor/comments/BranchComments.js +0 -4
- package/dist/editor/comments/EntryComments.js +0 -4
- package/dist/editor/comments/FieldWrapper.js +0 -4
- package/dist/editor/comments/InlineCommentThread.js +0 -2
- package/dist/editor/comments/ThreadCarousel.d.ts +0 -58
- package/dist/editor/comments/ThreadCarousel.js +0 -12
- package/dist/editor/components/EditorFooter.d.ts +0 -8
- package/dist/editor/components/EditorFooter.js +0 -5
- package/dist/editor/components/EditorHeader.d.ts +0 -31
- package/dist/editor/components/EditorHeader.js +21 -71
- package/dist/editor/components/EditorSidebar.d.ts +0 -19
- package/dist/editor/components/EditorSidebar.js +0 -16
- package/dist/editor/components/EntryCreateModal.d.ts +4 -4
- package/dist/editor/components/EntryCreateModal.js +7 -22
- package/dist/editor/components/RenameEntryModal.js +0 -4
- package/dist/editor/components/UserBadge.js +0 -10
- package/dist/editor/components/index.js +0 -2
- package/dist/editor/context/ApiClientContext.d.ts +8 -7
- package/dist/editor/context/ApiClientContext.js +39 -11
- package/dist/editor/context/AssetContext.d.ts +7 -17
- package/dist/editor/context/AssetContext.js +7 -17
- package/dist/editor/context/EditorIdentityContext.d.ts +13 -0
- package/dist/editor/context/EditorIdentityContext.js +7 -0
- package/dist/editor/context/EditorStateContext.d.ts +10 -41
- package/dist/editor/context/EditorStateContext.js +7 -23
- package/dist/editor/context/SWRProvider.d.ts +3 -6
- package/dist/editor/context/index.d.ts +1 -20
- package/dist/editor/context/index.js +1 -20
- package/dist/editor/editor-utils.d.ts +8 -47
- package/dist/editor/editor-utils.js +19 -72
- package/dist/editor/fields/BlockField.d.ts +2 -2
- package/dist/editor/fields/BlockField.js +1 -2
- package/dist/editor/fields/CodeField.d.ts +0 -1
- package/dist/editor/fields/CodeField.js +0 -1
- package/dist/editor/fields/DateTimeField.d.ts +15 -22
- package/dist/editor/fields/DateTimeField.js +17 -26
- package/dist/editor/fields/ImageField.d.ts +2 -2
- package/dist/editor/fields/ImageField.js +8 -14
- package/dist/editor/fields/InlineGroupField.d.ts +0 -1
- package/dist/editor/fields/InlineGroupField.js +0 -1
- package/dist/editor/fields/MarkdownField.d.ts +0 -1
- package/dist/editor/fields/MarkdownField.js +6 -11
- package/dist/editor/fields/MdxImageDialog.d.ts +1 -1
- package/dist/editor/fields/MdxImageDialog.js +0 -1
- package/dist/editor/fields/NumberField.d.ts +9 -19
- package/dist/editor/fields/NumberField.js +11 -22
- package/dist/editor/fields/NumberListField.d.ts +7 -10
- package/dist/editor/fields/NumberListField.js +7 -10
- package/dist/editor/fields/ObjectField.d.ts +5 -8
- package/dist/editor/fields/ObjectField.js +0 -1
- package/dist/editor/fields/ReferenceField.d.ts +1 -1
- package/dist/editor/fields/ReferenceField.js +11 -16
- package/dist/editor/fields/SelectField.d.ts +2 -2
- package/dist/editor/fields/SelectField.js +0 -1
- package/dist/editor/fields/StringListField.d.ts +0 -4
- package/dist/editor/fields/StringListField.js +4 -9
- package/dist/editor/fields/TextField.d.ts +0 -1
- package/dist/editor/fields/TextField.js +0 -1
- package/dist/editor/fields/ToggleField.d.ts +0 -1
- package/dist/editor/fields/ToggleField.js +0 -1
- package/dist/editor/fields/entry-link/EntryLinkContext.js +2 -4
- package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +0 -3
- package/dist/editor/fields/entry-link/InsertEntryLink.js +0 -4
- package/dist/editor/group-manager/ExternalGroupsTab.d.ts +0 -3
- package/dist/editor/group-manager/ExternalGroupsTab.js +0 -1
- package/dist/editor/group-manager/GroupCard.d.ts +0 -3
- package/dist/editor/group-manager/GroupForm.d.ts +0 -3
- package/dist/editor/group-manager/InternalGroupsTab.d.ts +0 -3
- package/dist/editor/group-manager/InternalGroupsTab.js +0 -2
- package/dist/editor/group-manager/MemberList.d.ts +0 -3
- package/dist/editor/group-manager/hooks/useExternalGroupSearch.d.ts +0 -3
- package/dist/editor/group-manager/hooks/useExternalGroupSearch.js +0 -3
- package/dist/editor/group-manager/hooks/useGroupState.d.ts +0 -3
- package/dist/editor/group-manager/hooks/useGroupState.js +0 -5
- package/dist/editor/group-manager/hooks/useUserSearch.d.ts +0 -3
- package/dist/editor/group-manager/hooks/useUserSearch.js +0 -3
- package/dist/editor/group-manager/index.d.ts +0 -6
- package/dist/editor/group-manager/index.js +0 -10
- package/dist/editor/group-manager/types.d.ts +2 -5
- package/dist/editor/group-manager/types.js +0 -3
- package/dist/editor/hooks/index.d.ts +6 -11
- package/dist/editor/hooks/index.js +6 -12
- package/dist/editor/hooks/useBranchActions.d.ts +0 -14
- package/dist/editor/hooks/useBranchActions.js +0 -22
- package/dist/editor/hooks/useBranchManager.d.ts +2 -48
- package/dist/editor/hooks/useBranchManager.js +4 -64
- package/dist/editor/hooks/useBranchesData.d.ts +7 -6
- package/dist/editor/hooks/useBranchesData.js +7 -6
- package/dist/editor/hooks/useCommentSystem.d.ts +0 -49
- package/dist/editor/hooks/useCommentSystem.js +1 -36
- package/dist/editor/hooks/useDraftManager.d.ts +2 -35
- package/dist/editor/hooks/useDraftManager.js +23 -64
- package/dist/editor/hooks/useEditorLayout.d.ts +0 -20
- package/dist/editor/hooks/useEditorLayout.js +0 -23
- package/dist/editor/hooks/useEntriesData.d.ts +1 -0
- package/dist/editor/hooks/useEntriesData.js +2 -3
- package/dist/editor/hooks/useEntryLinkResolution.d.ts +2 -2
- package/dist/editor/hooks/useEntryLinkResolution.js +2 -2
- package/dist/editor/hooks/useEntryManager.d.ts +2 -27
- package/dist/editor/hooks/useEntryManager.js +29 -78
- package/dist/editor/hooks/useGroupManager.d.ts +0 -21
- package/dist/editor/hooks/useGroupManager.js +0 -21
- package/dist/editor/hooks/usePermissionManager.d.ts +0 -20
- package/dist/editor/hooks/usePermissionManager.js +0 -20
- package/dist/editor/hooks/useReferenceResolution.d.ts +2 -33
- package/dist/editor/hooks/useReferenceResolution.js +1 -48
- package/dist/editor/hooks/useSchemaManager.d.ts +8 -27
- package/dist/editor/hooks/useSchemaManager.js +0 -19
- package/dist/editor/hooks/useUserContext.d.ts +2 -9
- package/dist/editor/hooks/useUserContext.js +10 -10
- package/dist/editor/hooks/useUserMetadata.d.ts +0 -2
- package/dist/editor/hooks/useUserMetadata.js +0 -3
- package/dist/editor/media/AssetCard.d.ts +0 -1
- package/dist/editor/media/AssetCard.js +1 -2
- package/dist/editor/media/CropStep.d.ts +0 -1
- package/dist/editor/media/CropStep.js +0 -1
- package/dist/editor/media/MediaLibrary.d.ts +1 -2
- package/dist/editor/media/MediaLibrary.js +1 -2
- package/dist/editor/media/MediaLibraryBody.d.ts +0 -1
- package/dist/editor/media/MediaLibraryBody.js +0 -1
- package/dist/editor/media/crop-math.d.ts +1 -1
- package/dist/editor/media/crop-math.js +1 -1
- package/dist/editor/permission-manager/GroupSelector.d.ts +0 -3
- package/dist/editor/permission-manager/PermissionEditor.d.ts +0 -4
- package/dist/editor/permission-manager/PermissionEditor.js +0 -1
- package/dist/editor/permission-manager/PermissionLevelBadge.d.ts +0 -7
- package/dist/editor/permission-manager/PermissionLevelBadge.js +0 -4
- package/dist/editor/permission-manager/PermissionTree.d.ts +0 -4
- package/dist/editor/permission-manager/UserSelector.d.ts +0 -3
- package/dist/editor/permission-manager/constants.d.ts +0 -3
- package/dist/editor/permission-manager/hooks/useGroupsAndUsers.d.ts +0 -3
- package/dist/editor/permission-manager/hooks/useGroupsAndUsers.js +0 -10
- package/dist/editor/permission-manager/hooks/usePermissionTree.d.ts +0 -14
- package/dist/editor/permission-manager/hooks/usePermissionTree.js +0 -11
- package/dist/editor/permission-manager/index.d.ts +0 -7
- package/dist/editor/permission-manager/index.js +0 -16
- package/dist/editor/permission-manager/types.d.ts +2 -12
- package/dist/editor/permission-manager/types.js +0 -3
- package/dist/editor/permission-manager/utils.d.ts +0 -28
- package/dist/editor/permission-manager/utils.js +9 -23
- package/dist/editor/preview-bridge.d.ts +5 -1
- package/dist/editor/preview-bridge.js +4 -4
- package/dist/editor/schema-editor/CollectionEditor.d.ts +0 -5
- package/dist/editor/schema-editor/CollectionEditor.js +9 -31
- package/dist/editor/schema-editor/EntryTypeEditor.d.ts +0 -6
- package/dist/editor/schema-editor/EntryTypeEditor.js +3 -24
- package/dist/editor/schema-editor/index.d.ts +0 -7
- package/dist/editor/schema-editor/index.js +0 -7
- package/dist/editor/utils/env.d.ts +3 -18
- package/dist/editor/utils/env.js +6 -25
- package/dist/entry-link-resolver.d.ts +13 -35
- package/dist/entry-link-resolver.js +20 -53
- package/dist/entry-schema-registry.d.ts +20 -60
- package/dist/entry-schema-registry.js +20 -69
- package/dist/entry-schema.d.ts +118 -223
- package/dist/entry-schema.js +46 -91
- package/dist/git-manager.d.ts +101 -200
- package/dist/git-manager.js +211 -384
- package/dist/github-service.d.ts +34 -75
- package/dist/github-service.js +37 -91
- package/dist/http/handler.d.ts +6 -37
- package/dist/http/handler.js +65 -120
- package/dist/http/router.d.ts +15 -32
- package/dist/http/router.js +34 -99
- package/dist/http/types.d.ts +15 -40
- package/dist/http/types.js +3 -7
- package/dist/id.d.ts +4 -10
- package/dist/id.js +4 -10
- package/dist/index.js +6 -9
- package/dist/operating-mode/client-safe-strategy.d.ts +7 -14
- package/dist/operating-mode/client-safe-strategy.js +8 -28
- package/dist/operating-mode/client-unsafe-strategy.d.ts +6 -16
- package/dist/operating-mode/client-unsafe-strategy.js +9 -34
- package/dist/operating-mode/client.d.ts +3 -10
- package/dist/operating-mode/client.js +3 -8
- package/dist/operating-mode/deployment-name-fixtures.d.ts +14 -18
- package/dist/operating-mode/deployment-name-fixtures.js +14 -18
- package/dist/operating-mode/deployment-name.d.ts +19 -29
- package/dist/operating-mode/deployment-name.js +29 -47
- package/dist/operating-mode/index.d.ts +4 -25
- package/dist/operating-mode/index.js +9 -31
- package/dist/operating-mode/mode-env.d.ts +32 -54
- package/dist/operating-mode/mode-env.js +36 -58
- package/dist/operating-mode/types.d.ts +24 -72
- package/dist/operating-mode/types.js +1 -7
- package/dist/paths/branch-name.d.ts +30 -40
- package/dist/paths/branch-name.js +30 -40
- package/dist/paths/branch.d.ts +4 -18
- package/dist/paths/branch.js +6 -22
- package/dist/paths/index.d.ts +2 -13
- package/dist/paths/index.js +3 -23
- package/dist/paths/normalize-server.d.ts +3 -15
- package/dist/paths/normalize-server.js +3 -15
- package/dist/paths/normalize.d.ts +13 -33
- package/dist/paths/normalize.js +13 -33
- package/dist/paths/resolve.d.ts +4 -17
- package/dist/paths/resolve.js +4 -22
- package/dist/paths/types.d.ts +12 -34
- package/dist/paths/types.js +5 -7
- package/dist/paths/validation.d.ts +22 -119
- package/dist/paths/validation.js +30 -148
- package/dist/reference-resolver.d.ts +0 -13
- package/dist/reference-resolver.js +0 -18
- package/dist/resolve-canopy-user.d.ts +16 -18
- package/dist/resolve-canopy-user.js +17 -26
- package/dist/resource-generation.d.ts +16 -25
- package/dist/resource-generation.js +34 -97
- package/dist/schema/meta-loader.d.ts +2 -14
- package/dist/schema/meta-loader.js +15 -64
- package/dist/schema/resolver.d.ts +1 -4
- package/dist/schema/resolver.js +1 -6
- package/dist/schema/schema-store-types.d.ts +0 -12
- package/dist/schema/schema-store.d.ts +61 -138
- package/dist/schema/schema-store.js +85 -282
- package/dist/schema/types.d.ts +0 -4
- package/dist/server.d.ts +62 -93
- package/dist/server.js +63 -94
- package/dist/services.d.ts +23 -47
- package/dist/services.js +55 -98
- package/dist/settings-workspace.d.ts +17 -30
- package/dist/settings-workspace.js +51 -81
- package/dist/static/index.d.ts +26 -52
- package/dist/static/index.js +33 -67
- package/dist/{worker/task-queue.d.ts → task-queue/cms-task-queue.d.ts} +7 -9
- package/dist/task-queue/cms-task-queue.js +13 -0
- package/dist/task-queue/task-queue-config.d.ts +3 -0
- package/dist/{worker → task-queue}/task-queue-config.js +1 -6
- package/dist/task-queue/task-queue.d.ts +16 -22
- package/dist/task-queue/task-queue.js +20 -44
- package/dist/task-queue/types.d.ts +0 -1
- package/dist/task-queue/worker-status.d.ts +35 -0
- package/dist/task-queue/worker-status.js +40 -0
- package/dist/types.d.ts +40 -51
- package/dist/url-collision.d.ts +26 -40
- package/dist/url-collision.js +47 -63
- package/dist/url-exclusivity-fixtures.d.ts +15 -20
- package/dist/url-exclusivity-fixtures.js +14 -19
- package/dist/url-path-resolver.d.ts +8 -16
- package/dist/url-path-resolver.js +19 -29
- package/dist/user.d.ts +8 -21
- package/dist/user.js +10 -19
- package/dist/utils/async-mutex.js +4 -6
- package/dist/utils/atomic-write.d.ts +2 -11
- package/dist/utils/atomic-write.js +2 -11
- package/dist/utils/body-field.d.ts +8 -15
- package/dist/utils/body-field.js +8 -15
- package/dist/utils/content-serialize.d.ts +18 -24
- package/dist/utils/content-serialize.js +109 -160
- package/dist/utils/content-write-lock.d.ts +51 -106
- package/dist/utils/content-write-lock.js +66 -111
- package/dist/utils/debug.d.ts +7 -23
- package/dist/utils/debug.js +7 -23
- package/dist/utils/entry-url.d.ts +11 -23
- package/dist/utils/entry-url.js +11 -26
- package/dist/utils/error.d.ts +25 -90
- package/dist/utils/error.js +60 -147
- package/dist/utils/flatten-group-fields.d.ts +5 -7
- package/dist/utils/flatten-group-fields.js +5 -7
- package/dist/utils/format.d.ts +1 -5
- package/dist/utils/format.js +1 -5
- package/dist/utils/fs.d.ts +3 -4
- package/dist/utils/fs.js +3 -4
- package/dist/utils/git.d.ts +52 -83
- package/dist/utils/git.js +79 -125
- package/dist/utils/logger.d.ts +35 -50
- package/dist/utils/logger.js +35 -52
- package/dist/utils/provisioning-lock.d.ts +23 -35
- package/dist/utils/provisioning-lock.js +49 -69
- package/dist/utils/sanitize-href.d.ts +5 -10
- package/dist/utils/sanitize-href.js +8 -18
- package/dist/utils/title-field.d.ts +17 -20
- package/dist/utils/title-field.js +18 -27
- package/dist/utils/typed-filename.d.ts +20 -48
- package/dist/utils/typed-filename.js +25 -61
- package/dist/utils/url-prefix.d.ts +3 -3
- package/dist/utils/url-prefix.js +3 -3
- package/dist/validation/block-structural-keys.d.ts +16 -31
- package/dist/validation/block-structural-keys.js +19 -29
- package/dist/validation/deletion-checker.d.ts +0 -34
- package/dist/validation/deletion-checker.js +1 -43
- package/dist/validation/entry-link-validator.d.ts +6 -13
- package/dist/validation/entry-link-validator.js +4 -13
- package/dist/validation/entry-type-reference-validator.d.ts +13 -18
- package/dist/validation/entry-type-reference-validator.js +13 -18
- package/dist/validation/entry-validator.d.ts +13 -25
- package/dist/validation/entry-validator.js +15 -32
- package/dist/validation/field-traversal.d.ts +3 -30
- package/dist/validation/field-traversal.js +1 -32
- package/dist/validation/reference-validator.d.ts +5 -24
- package/dist/validation/reference-validator.js +5 -30
- package/dist/worker/cms-worker.d.ts +172 -232
- package/dist/worker/cms-worker.js +241 -333
- package/dist/worker/git-sync.d.ts +32 -133
- package/dist/worker/git-sync.js +129 -191
- package/dist/worker/github-auth.d.ts +13 -19
- package/dist/worker/github-auth.js +13 -19
- package/dist/worker/history-rewrite.d.ts +53 -66
- package/dist/worker/history-rewrite.js +54 -60
- package/dist/worker/log.d.ts +24 -41
- package/dist/worker/log.js +25 -42
- package/dist/worker/rebase.d.ts +20 -110
- package/dist/worker/rebase.js +279 -354
- package/dist/worker/task-runner.d.ts +32 -66
- package/dist/worker/task-runner.js +126 -162
- package/dist/worker/worker-context.d.ts +41 -81
- package/package.json +4 -4
- package/dist/cli/template-files/middleware-clerk.ts.template +0 -37
- package/dist/worker/task-queue-config.d.ts +0 -8
- package/dist/worker/task-queue.js +0 -19
- package/dist/worker/worker-status.d.ts +0 -47
- package/dist/worker/worker-status.js +0 -52
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import type { AuthPlugin } from './plugin.js';
|
|
2
2
|
import type { UserSearchResult, GroupMetadata, AuthenticationResult } from './types.js';
|
|
3
3
|
import type { CanopyUserId, CanopyGroupId } from '../types.js';
|
|
4
|
-
/**
|
|
5
|
-
* Generic cache provider interface for auth metadata.
|
|
6
|
-
* Any auth system can implement its own cache backend
|
|
7
|
-
* (file-based, Redis, in-memory, etc.)
|
|
8
|
-
*/
|
|
4
|
+
/** Auth-metadata cache backend: file-based, Redis, in-memory, whatever. */
|
|
9
5
|
export interface AuthCacheProvider {
|
|
10
6
|
getUser(userId: CanopyUserId): Promise<UserSearchResult | null>;
|
|
11
7
|
getGroup(groupId: CanopyGroupId): Promise<GroupMetadata | null>;
|
|
@@ -13,28 +9,21 @@ export interface AuthCacheProvider {
|
|
|
13
9
|
getAllGroups(): Promise<GroupMetadata[]>;
|
|
14
10
|
getUserExternalGroups(userId: CanopyUserId): Promise<CanopyGroupId[]>;
|
|
15
11
|
}
|
|
16
|
-
/**
|
|
17
|
-
* Token verifier function type.
|
|
18
|
-
* Given a request context, extracts and verifies the auth token,
|
|
19
|
-
* returning the user ID on success.
|
|
20
|
-
*/
|
|
12
|
+
/** Extracts and verifies the request's auth token, yielding its user ID. */
|
|
21
13
|
export type TokenVerifier = (context: unknown) => Promise<{
|
|
22
14
|
userId: CanopyUserId;
|
|
23
15
|
} | null>;
|
|
24
16
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* (e.g., by an EC2 worker).
|
|
31
|
-
*
|
|
32
|
-
* In dev mode, an optional `lazyRefresher` can be provided to auto-populate
|
|
33
|
-
* the cache on first request, eliminating the need to run `worker run-once` manually.
|
|
17
|
+
* Wraps a token verifier with cached metadata lookups, for environments where
|
|
18
|
+
* the auth provider's API is unreachable (a Lambda with no internet): JWT
|
|
19
|
+
* verification happens locally, and user/group metadata comes from a cache
|
|
20
|
+
* populated externally by the EC2 worker. In dev an optional `lazyRefresher`
|
|
21
|
+
* populates that cache on first request instead of `worker run-once`.
|
|
34
22
|
*
|
|
35
|
-
*
|
|
36
|
-
* `options`
|
|
37
|
-
* createNextCanopyContext asserts the INNER plugin
|
|
23
|
+
* The wrapper only FORWARDS the inner plugin's `verifiesCredentials`
|
|
24
|
+
* affirmation, via the `options` param. It cannot launder an insecure plugin,
|
|
25
|
+
* because createNextCanopyContext asserts the INNER plugin before wrapping
|
|
26
|
+
* (context-wrapper.ts).
|
|
38
27
|
*/
|
|
39
28
|
export declare class CachingAuthPlugin implements AuthPlugin {
|
|
40
29
|
private readonly verifyToken;
|
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
import { createDebugLogger } from '../utils/debug.js';
|
|
2
2
|
const log = createDebugLogger({ prefix: 'CachingAuthPlugin' });
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Wraps a token verifier with cached metadata lookups, for environments where
|
|
5
|
+
* the auth provider's API is unreachable (a Lambda with no internet): JWT
|
|
6
|
+
* verification happens locally, and user/group metadata comes from a cache
|
|
7
|
+
* populated externally by the EC2 worker. In dev an optional `lazyRefresher`
|
|
8
|
+
* populates that cache on first request instead of `worker run-once`.
|
|
5
9
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* (
|
|
10
|
-
*
|
|
11
|
-
* In dev mode, an optional `lazyRefresher` can be provided to auto-populate
|
|
12
|
-
* the cache on first request, eliminating the need to run `worker run-once` manually.
|
|
13
|
-
*
|
|
14
|
-
* This wrapper only forwards the inner plugin's `verifiesCredentials` affirmation via the
|
|
15
|
-
* `options` constructor param — it cannot launder an insecure plugin, because
|
|
16
|
-
* createNextCanopyContext asserts the INNER plugin (before wrapping) in context-wrapper.ts.
|
|
10
|
+
* The wrapper only FORWARDS the inner plugin's `verifiesCredentials`
|
|
11
|
+
* affirmation, via the `options` param. It cannot launder an insecure plugin,
|
|
12
|
+
* because createNextCanopyContext asserts the INNER plugin before wrapping
|
|
13
|
+
* (context-wrapper.ts).
|
|
17
14
|
*/
|
|
18
15
|
export class CachingAuthPlugin {
|
|
19
16
|
constructor(verifyToken, cache, lazyRefresher, options) {
|
|
@@ -26,7 +23,7 @@ export class CachingAuthPlugin {
|
|
|
26
23
|
async ensureCachePopulated() {
|
|
27
24
|
if (!this.lazyRefresher)
|
|
28
25
|
return;
|
|
29
|
-
//
|
|
26
|
+
// A shared promise, so concurrent callers coalesce into one refresh.
|
|
30
27
|
this.refreshPromise ??= this.lazyRefresher()
|
|
31
28
|
.then(() => log.debug('auth', 'Lazy cache refresh completed'))
|
|
32
29
|
.catch((err) => {
|
|
@@ -56,7 +53,8 @@ export class CachingAuthPlugin {
|
|
|
56
53
|
};
|
|
57
54
|
}
|
|
58
55
|
catch {
|
|
59
|
-
//
|
|
56
|
+
// A cache failure must not reject an already-verified token: degrade to
|
|
57
|
+
// the bare identity, with no external groups.
|
|
60
58
|
log.debug('auth', 'Cache lookup failed, returning minimal user', {
|
|
61
59
|
userId: identity.userId,
|
|
62
60
|
});
|
|
@@ -1,30 +1,16 @@
|
|
|
1
1
|
import type { CanopyRequest } from '../http/types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Headers-like interface for auth context.
|
|
4
|
-
* Framework-agnostic - matches Web Headers, Next.js Headers, and any similar interface.
|
|
5
|
-
*/
|
|
2
|
+
/** The shape Web Headers, Next.js Headers and anything similar share. */
|
|
6
3
|
export interface HeadersLike {
|
|
7
4
|
get(name: string): string | null;
|
|
8
5
|
}
|
|
9
|
-
/**
|
|
10
|
-
* Type guard to check if context is a CanopyRequest.
|
|
11
|
-
* CanopyRequest has both 'header' method and 'method' property.
|
|
12
|
-
*/
|
|
6
|
+
/** A CanopyRequest is recognized by its `header` method plus `method`. */
|
|
13
7
|
export declare function isCanopyRequest(context: unknown): context is CanopyRequest;
|
|
14
|
-
/**
|
|
15
|
-
* Type guard to check if context is a headers-like object.
|
|
16
|
-
* Headers have a 'get' method for retrieving header values.
|
|
17
|
-
*/
|
|
8
|
+
/** Headers-like objects are recognized by their `get` method. */
|
|
18
9
|
export declare function isHeadersLike(context: unknown): context is HeadersLike;
|
|
19
10
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* @returns HeadersLike object or null if context type is unsupported
|
|
11
|
+
* Headers from either auth context shape -- a CanopyRequest (API routes) or a
|
|
12
|
+
* headers-like object (server components) -- or null for anything else.
|
|
24
13
|
*/
|
|
25
14
|
export declare function extractHeaders(context: unknown): HeadersLike | null;
|
|
26
|
-
/**
|
|
27
|
-
* Validate auth context and throw helpful error if unsupported.
|
|
28
|
-
* Use this in auth plugins to provide clear error messages.
|
|
29
|
-
*/
|
|
15
|
+
/** Use this in auth plugins: same as extractHeaders, but throws on null. */
|
|
30
16
|
export declare function validateAuthContext(context: unknown): HeadersLike;
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type guard to check if context is a CanopyRequest.
|
|
3
|
-
* CanopyRequest has both 'header' method and 'method' property.
|
|
4
|
-
*/
|
|
1
|
+
/** A CanopyRequest is recognized by its `header` method plus `method`. */
|
|
5
2
|
export function isCanopyRequest(context) {
|
|
6
3
|
return (typeof context === 'object' &&
|
|
7
4
|
context !== null &&
|
|
@@ -9,10 +6,7 @@ export function isCanopyRequest(context) {
|
|
|
9
6
|
'method' in context &&
|
|
10
7
|
typeof context.header === 'function');
|
|
11
8
|
}
|
|
12
|
-
/**
|
|
13
|
-
* Type guard to check if context is a headers-like object.
|
|
14
|
-
* Headers have a 'get' method for retrieving header values.
|
|
15
|
-
*/
|
|
9
|
+
/** Headers-like objects are recognized by their `get` method. */
|
|
16
10
|
export function isHeadersLike(context) {
|
|
17
11
|
return (typeof context === 'object' &&
|
|
18
12
|
context !== null &&
|
|
@@ -20,14 +14,11 @@ export function isHeadersLike(context) {
|
|
|
20
14
|
typeof context.get === 'function');
|
|
21
15
|
}
|
|
22
16
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* @returns HeadersLike object or null if context type is unsupported
|
|
17
|
+
* Headers from either auth context shape -- a CanopyRequest (API routes) or a
|
|
18
|
+
* headers-like object (server components) -- or null for anything else.
|
|
27
19
|
*/
|
|
28
20
|
export function extractHeaders(context) {
|
|
29
21
|
if (isCanopyRequest(context)) {
|
|
30
|
-
// Wrap CanopyRequest.header() as HeadersLike.get()
|
|
31
22
|
return {
|
|
32
23
|
get: (name) => context.header(name),
|
|
33
24
|
};
|
|
@@ -37,10 +28,7 @@ export function extractHeaders(context) {
|
|
|
37
28
|
}
|
|
38
29
|
return null;
|
|
39
30
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Validate auth context and throw helpful error if unsupported.
|
|
42
|
-
* Use this in auth plugins to provide clear error messages.
|
|
43
|
-
*/
|
|
31
|
+
/** Use this in auth plugins: same as extractHeaders, but throws on null. */
|
|
44
32
|
export function validateAuthContext(context) {
|
|
45
33
|
const headers = extractHeaders(context);
|
|
46
34
|
if (!headers) {
|
|
@@ -2,20 +2,12 @@ import type { AuthCacheProvider } from './caching-auth-plugin.js';
|
|
|
2
2
|
import type { UserSearchResult, GroupMetadata } from './types.js';
|
|
3
3
|
import type { CanopyUserId, CanopyGroupId } from '../types.js';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* (e.g., by an EC2 worker running refreshClerkCache).
|
|
5
|
+
* Reads a directory populated externally (the EC2 worker's refreshClerkCache)
|
|
6
|
+
* and holds the result in memory, re-reading whenever a file's mtime changes.
|
|
8
7
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* Expects:
|
|
14
|
-
* - users.json — { users: UserSearchResult[] }
|
|
15
|
-
* - orgs.json — { groups: GroupMetadata[] }
|
|
16
|
-
* - memberships.json — { memberships: { [userId]: groupId[] } }
|
|
17
|
-
*
|
|
18
|
-
* Caches in memory and re-reads when file mtime changes.
|
|
8
|
+
* Expects users.json `{ users }`, orgs.json `{ groups }` and memberships.json
|
|
9
|
+
* `{ memberships: { [userId]: groupId[] } }`, in whichever directory
|
|
10
|
+
* `resolveActiveCacheDir` picks.
|
|
19
11
|
*/
|
|
20
12
|
export declare class FileBasedAuthCache implements AuthCacheProvider {
|
|
21
13
|
private readonly cachePath;
|
|
@@ -33,13 +25,10 @@ export declare class FileBasedAuthCache implements AuthCacheProvider {
|
|
|
33
25
|
private emptyCache;
|
|
34
26
|
}
|
|
35
27
|
/**
|
|
36
|
-
* Write
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* This ensures readers (FileBasedAuthCache) always see a consistent set of files:
|
|
43
|
-
* either the old snapshot or the new one, never a mix.
|
|
28
|
+
* Write the cache files into a fresh snapshot directory, then swap the `current`
|
|
29
|
+
* symlink over to it, so a reader always sees one consistent set of files --
|
|
30
|
+
* the old snapshot or the new one, never a mix. Individual files go down by
|
|
31
|
+
* temp-file + rename (utils/atomic-write.ts owns that mechanism). The 2 most
|
|
32
|
+
* recent snapshot directories are kept.
|
|
44
33
|
*/
|
|
45
34
|
export declare function writeAuthCacheSnapshot(cachePath: string, files: Record<string, unknown>): Promise<string>;
|
|
@@ -3,22 +3,16 @@ import path from 'node:path';
|
|
|
3
3
|
import { createDebugLogger } from '../utils/debug.js';
|
|
4
4
|
const log = createDebugLogger({ prefix: 'FileBasedAuthCache' });
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* 1. Snapshot layout (preferred): {cachePath}/current → {cachePath}/snapshot-{ts}/
|
|
10
|
-
* The `current` symlink points to the active snapshot directory.
|
|
11
|
-
* 2. Flat layout (legacy/simple): files directly in {cachePath}/
|
|
12
|
-
*
|
|
13
|
-
* Returns the directory path where users.json, orgs.json, memberships.json live.
|
|
6
|
+
* The directory holding users.json, orgs.json and memberships.json: the target
|
|
7
|
+
* of the `{cachePath}/current` symlink under the preferred snapshot layout, or
|
|
8
|
+
* `{cachePath}` itself under the flat one.
|
|
14
9
|
*/
|
|
15
10
|
async function resolveActiveCacheDir(cachePath) {
|
|
16
11
|
const currentLink = path.join(cachePath, 'current');
|
|
17
12
|
try {
|
|
18
13
|
const target = await fs.readlink(currentLink);
|
|
19
|
-
// Symlink target may be relative or absolute
|
|
20
14
|
const resolved = path.isAbsolute(target) ? target : path.resolve(cachePath, target);
|
|
21
|
-
// SECURITY:
|
|
15
|
+
// SECURITY: the symlink target must stay inside the cache directory.
|
|
22
16
|
const normalizedCache = path.resolve(cachePath);
|
|
23
17
|
const normalizedTarget = path.resolve(resolved);
|
|
24
18
|
if (!normalizedTarget.startsWith(normalizedCache + path.sep) &&
|
|
@@ -37,20 +31,12 @@ async function resolveActiveCacheDir(cachePath) {
|
|
|
37
31
|
}
|
|
38
32
|
}
|
|
39
33
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* (e.g., by an EC2 worker running refreshClerkCache).
|
|
43
|
-
*
|
|
44
|
-
* Supports two directory layouts:
|
|
45
|
-
* - Snapshot layout: {cachePath}/current/ symlink → snapshot-{ts}/ directory
|
|
46
|
-
* - Flat layout: files directly in {cachePath}/
|
|
34
|
+
* Reads a directory populated externally (the EC2 worker's refreshClerkCache)
|
|
35
|
+
* and holds the result in memory, re-reading whenever a file's mtime changes.
|
|
47
36
|
*
|
|
48
|
-
* Expects
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* - memberships.json — { memberships: { [userId]: groupId[] } }
|
|
52
|
-
*
|
|
53
|
-
* Caches in memory and re-reads when file mtime changes.
|
|
37
|
+
* Expects users.json `{ users }`, orgs.json `{ groups }` and memberships.json
|
|
38
|
+
* `{ memberships: { [userId]: groupId[] } }`, in whichever directory
|
|
39
|
+
* `resolveActiveCacheDir` picks.
|
|
54
40
|
*/
|
|
55
41
|
export class FileBasedAuthCache {
|
|
56
42
|
constructor(cachePath) {
|
|
@@ -83,7 +69,6 @@ export class FileBasedAuthCache {
|
|
|
83
69
|
const usersPath = path.join(activeDir, 'users.json');
|
|
84
70
|
const orgsPath = path.join(activeDir, 'orgs.json');
|
|
85
71
|
const membershipsPath = path.join(activeDir, 'memberships.json');
|
|
86
|
-
// Check max mtime across all three files for cache freshness
|
|
87
72
|
let maxMtime = 0;
|
|
88
73
|
for (const filePath of [usersPath, orgsPath, membershipsPath]) {
|
|
89
74
|
try {
|
|
@@ -95,17 +80,14 @@ export class FileBasedAuthCache {
|
|
|
95
80
|
}
|
|
96
81
|
}
|
|
97
82
|
if (maxMtime === 0) {
|
|
98
|
-
// No cache files exist — return empty cache
|
|
99
83
|
if (!this.cache) {
|
|
100
84
|
this.cache = this.emptyCache();
|
|
101
85
|
}
|
|
102
86
|
return this.cache;
|
|
103
87
|
}
|
|
104
|
-
// If max mtime hasn't changed and we have a cache, return it
|
|
105
88
|
if (this.cache && maxMtime === this.lastMtime) {
|
|
106
89
|
return this.cache;
|
|
107
90
|
}
|
|
108
|
-
// Load fresh data
|
|
109
91
|
this.cache = await this.loadFromDisk(activeDir);
|
|
110
92
|
this.lastMtime = maxMtime;
|
|
111
93
|
return this.cache;
|
|
@@ -168,45 +150,36 @@ export class FileBasedAuthCache {
|
|
|
168
150
|
}
|
|
169
151
|
}
|
|
170
152
|
/**
|
|
171
|
-
* Write
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
* This ensures readers (FileBasedAuthCache) always see a consistent set of files:
|
|
178
|
-
* either the old snapshot or the new one, never a mix.
|
|
153
|
+
* Write the cache files into a fresh snapshot directory, then swap the `current`
|
|
154
|
+
* symlink over to it, so a reader always sees one consistent set of files --
|
|
155
|
+
* the old snapshot or the new one, never a mix. Individual files go down by
|
|
156
|
+
* temp-file + rename (utils/atomic-write.ts owns that mechanism). The 2 most
|
|
157
|
+
* recent snapshot directories are kept.
|
|
179
158
|
*/
|
|
180
159
|
export async function writeAuthCacheSnapshot(cachePath, files) {
|
|
181
160
|
await fs.mkdir(cachePath, { recursive: true });
|
|
182
161
|
const timestamp = Date.now();
|
|
183
162
|
const snapshotDir = path.join(cachePath, `snapshot-${timestamp}`);
|
|
184
163
|
await fs.mkdir(snapshotDir, { recursive: true });
|
|
185
|
-
// Write all files to the snapshot directory
|
|
186
164
|
for (const [fileName, data] of Object.entries(files)) {
|
|
187
165
|
const tmpPath = path.join(snapshotDir, `${fileName}.tmp`);
|
|
188
166
|
const finalPath = path.join(snapshotDir, fileName);
|
|
189
167
|
await fs.writeFile(tmpPath, JSON.stringify(data, null, 2), 'utf-8');
|
|
190
168
|
await fs.rename(tmpPath, finalPath);
|
|
191
169
|
}
|
|
192
|
-
//
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
//
|
|
196
|
-
//
|
|
197
|
-
//
|
|
198
|
-
//
|
|
199
|
-
//
|
|
200
|
-
//
|
|
201
|
-
// `resolveActiveCacheDir`'s escape guard then correctly rejects it and falls
|
|
202
|
-
// back to the flat layout, where the worker never writes, leaving the Lambda
|
|
203
|
-
// with a permanently empty cache. A relative target resolves against
|
|
204
|
-
// whichever cachePath the reader was given, so it is correct from both.
|
|
170
|
+
// The symlink target MUST be relative (the bare `snapshot-<ts>` basename),
|
|
171
|
+
// because writer and reader do not share a mount namespace: in prod the EC2
|
|
172
|
+
// worker writes through /mnt/efs/workspace/.cache while the CMS Lambda mounts
|
|
173
|
+
// the /workspace access point and reads the SAME directory as /mnt/efs/.cache.
|
|
174
|
+
// An absolute target recorded by one is a nonexistent path to the other, and
|
|
175
|
+
// `resolveActiveCacheDir`'s escape guard then falls back to the flat layout,
|
|
176
|
+
// where the worker never writes — leaving the Lambda a permanently empty
|
|
177
|
+
// cache. A relative target resolves against whichever cachePath the reader
|
|
178
|
+
// was given, so it is correct from both.
|
|
205
179
|
const currentLink = path.join(cachePath, 'current');
|
|
206
180
|
const tmpLink = path.join(cachePath, `current-${timestamp}`);
|
|
207
181
|
await fs.symlink(path.basename(snapshotDir), tmpLink);
|
|
208
182
|
await fs.rename(tmpLink, currentLink);
|
|
209
|
-
// Clean up old snapshots (keep the 2 most recent)
|
|
210
183
|
await cleanupOldSnapshots(cachePath, 2);
|
|
211
184
|
return snapshotDir;
|
|
212
185
|
}
|
|
@@ -222,7 +195,6 @@ async function cleanupOldSnapshots(cachePath, keepCount) {
|
|
|
222
195
|
.filter((e) => e.startsWith('snapshot-'))
|
|
223
196
|
.sort()
|
|
224
197
|
.reverse();
|
|
225
|
-
// Skip the most recent `keepCount` snapshots
|
|
226
198
|
for (const snapshot of snapshots.slice(keepCount)) {
|
|
227
199
|
try {
|
|
228
200
|
await fs.rm(path.join(cachePath, snapshot), {
|
package/dist/auth/plugin.d.ts
CHANGED
|
@@ -1,98 +1,66 @@
|
|
|
1
1
|
import type { UserSearchResult, GroupMetadata, AuthenticationResult } from './types.js';
|
|
2
2
|
import type { CanopyUserId, CanopyGroupId } from '../types.js';
|
|
3
3
|
import type { OperatingMode } from '../operating-mode/types.js';
|
|
4
|
-
/**
|
|
5
|
-
* Abstract auth provider interface.
|
|
6
|
-
* Implement this to integrate different auth systems (Clerk, Auth0, NextAuth, etc.)
|
|
7
|
-
*/
|
|
4
|
+
/** Implement this to integrate an auth system (Clerk, Auth0, NextAuth, ...). */
|
|
8
5
|
export interface AuthPlugin {
|
|
9
6
|
/**
|
|
10
|
-
* Affirmative allowlist marker:
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* whenever the operating mode is 'prod' — absence fails closed, so a
|
|
14
|
-
* third-party plugin that forgets the marker is rejected, not accepted.
|
|
7
|
+
* Affirmative allowlist marker: true ONLY on plugins that cryptographically
|
|
8
|
+
* verify credentials. In 'prod', assertAuthPluginAllowedForMode() rejects any
|
|
9
|
+
* plugin without it, so a plugin that forgets the marker fails closed.
|
|
15
10
|
*/
|
|
16
11
|
readonly verifiesCredentials?: boolean;
|
|
17
12
|
/**
|
|
18
|
-
* Authenticate
|
|
19
|
-
*
|
|
13
|
+
* Authenticate from a request context, returning identity without final
|
|
14
|
+
* groups; core applies bootstrap admins.
|
|
20
15
|
*
|
|
21
|
-
*
|
|
22
|
-
* `{ success: false }`
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* (custom adapters) should be prepared for a rejection on misconfiguration.
|
|
27
|
-
*
|
|
28
|
-
* @param context - Framework-specific context (CanopyRequest, headers, etc.)
|
|
29
|
-
* @returns AuthenticationResult with user identity or error
|
|
16
|
+
* CREDENTIAL failures (missing, invalid or expired token) RESOLVE to
|
|
17
|
+
* `{ success: false }` and map to a 401. CONFIGURATION errors (an absent
|
|
18
|
+
* CLERK_SECRET_KEY, say) may THROW instead: they are operator mistakes, and
|
|
19
|
+
* belong in a loud 500 rather than a quiet auth denial. A custom adapter
|
|
20
|
+
* calling this directly must be ready for that rejection.
|
|
30
21
|
*/
|
|
31
22
|
authenticate(context: unknown): Promise<AuthenticationResult>;
|
|
32
|
-
/**
|
|
33
|
-
* Search for users (for permission management UI)
|
|
34
|
-
* @param query - Search string (email, name, etc.)
|
|
35
|
-
* @param limit - Max results (default 10)
|
|
36
|
-
*/
|
|
23
|
+
/** For the permission-management UI. */
|
|
37
24
|
searchUsers(query: string, limit?: number): Promise<UserSearchResult[]>;
|
|
38
|
-
/**
|
|
39
|
-
* Get detailed user metadata by ID
|
|
40
|
-
*/
|
|
41
25
|
getUserMetadata(userId: CanopyUserId): Promise<UserSearchResult | null>;
|
|
42
|
-
/**
|
|
43
|
-
* Get group/organization metadata by ID
|
|
44
|
-
*/
|
|
45
26
|
getGroupMetadata(groupId: CanopyGroupId): Promise<GroupMetadata | null>;
|
|
46
|
-
/**
|
|
47
|
-
* List all groups (for permission UI dropdowns)
|
|
48
|
-
*/
|
|
27
|
+
/** For permission UI dropdowns. */
|
|
49
28
|
listGroups(limit?: number): Promise<GroupMetadata[]>;
|
|
50
|
-
/**
|
|
51
|
-
* Search for external groups/organizations (for group management UI)
|
|
52
|
-
* Optional - only needed if auth provider supports external groups
|
|
53
|
-
* @param query - Search string (name, ID, etc.)
|
|
54
|
-
*/
|
|
29
|
+
/** For the group-management UI; only providers with groups need it. */
|
|
55
30
|
searchExternalGroups?(query: string): Promise<Array<{
|
|
56
31
|
id: CanopyGroupId;
|
|
57
32
|
name: string;
|
|
58
33
|
}>>;
|
|
59
34
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
35
|
+
* Token-only verification: no metadata lookup, no network. When present,
|
|
36
|
+
* createNextCanopyContext wraps this plugin with CachingAuthPlugin in both
|
|
37
|
+
* modes, over a cache the worker daemon populates.
|
|
63
38
|
*/
|
|
64
39
|
verifyTokenOnly?(context: unknown): Promise<{
|
|
65
40
|
userId: CanopyUserId;
|
|
66
41
|
} | null>;
|
|
67
42
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
43
|
+
* Builds the refresher the worker daemon and CLI run-once use to populate the
|
|
44
|
+
* file-based auth cache. Undefined when this plugin cannot refresh (no
|
|
45
|
+
* credentials, say).
|
|
71
46
|
*/
|
|
72
47
|
createCacheRefresher?(cachePath: string): (() => Promise<{
|
|
73
48
|
userCount: number;
|
|
74
49
|
groupCount: number;
|
|
75
50
|
}>) | undefined;
|
|
76
51
|
}
|
|
77
|
-
/**
|
|
78
|
-
* Factory function type for creating auth plugins
|
|
79
|
-
*/
|
|
80
52
|
export type AuthPluginFactory<TConfig = unknown> = (config: TConfig) => AuthPlugin;
|
|
81
53
|
/**
|
|
82
|
-
* Fail closed:
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* mode 'prod' would let any caller impersonate any user — including admins —
|
|
90
|
-
* by sending a header like `X-Test-User: admin`. Call this wherever an
|
|
91
|
-
* adopter-provided auth plugin meets the operating mode (framework wrappers,
|
|
92
|
-
* request handlers) BEFORE the plugin is wrapped or used.
|
|
54
|
+
* Fail closed in prod: an ALLOWLIST, so a plugin passes only by setting
|
|
55
|
+
* `verifiesCredentials: true`. DevAuthPlugin, and any plugin that forgets the
|
|
56
|
+
* marker, trusts request headers without cryptographic verification, so
|
|
57
|
+
* accepting one in 'prod' would let any caller impersonate any user, admins
|
|
58
|
+
* included, with a header like `X-Test-User: admin`. Absence of
|
|
59
|
+
* `verifyTokenOnly` is NOT a substitute for the marker — the dev plugin
|
|
60
|
+
* implements that too.
|
|
93
61
|
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
62
|
+
* Call this wherever an adopter-provided plugin meets the operating mode
|
|
63
|
+
* (framework wrappers, request handlers) BEFORE the plugin is wrapped or used.
|
|
96
64
|
*
|
|
97
65
|
* @throws Error when mode is 'prod' and the plugin does not set `verifiesCredentials: true`
|
|
98
66
|
*/
|
package/dist/auth/plugin.js
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Fail closed:
|
|
3
|
-
*
|
|
2
|
+
* Fail closed in prod: an ALLOWLIST, so a plugin passes only by setting
|
|
3
|
+
* `verifiesCredentials: true`. DevAuthPlugin, and any plugin that forgets the
|
|
4
|
+
* marker, trusts request headers without cryptographic verification, so
|
|
5
|
+
* accepting one in 'prod' would let any caller impersonate any user, admins
|
|
6
|
+
* included, with a header like `X-Test-User: admin`. Absence of
|
|
7
|
+
* `verifyTokenOnly` is NOT a substitute for the marker — the dev plugin
|
|
8
|
+
* implements that too.
|
|
4
9
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* any third-party plugin that forgets to set the marker) trusts request
|
|
8
|
-
* headers/cookies without cryptographic verification, so accepting it with
|
|
9
|
-
* mode 'prod' would let any caller impersonate any user — including admins —
|
|
10
|
-
* by sending a header like `X-Test-User: admin`. Call this wherever an
|
|
11
|
-
* adopter-provided auth plugin meets the operating mode (framework wrappers,
|
|
12
|
-
* request handlers) BEFORE the plugin is wrapped or used.
|
|
13
|
-
*
|
|
14
|
-
* Note: checking for the absence of verifyTokenOnly is NOT a substitute for
|
|
15
|
-
* this marker — the dev plugin implements verifyTokenOnly too.
|
|
10
|
+
* Call this wherever an adopter-provided plugin meets the operating mode
|
|
11
|
+
* (framework wrappers, request handlers) BEFORE the plugin is wrapped or used.
|
|
16
12
|
*
|
|
17
13
|
* @throws Error when mode is 'prod' and the plugin does not set `verifiesCredentials: true`
|
|
18
14
|
*/
|
package/dist/auth/types.d.ts
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import type { CanopyUserId, CanopyGroupId } from '../types.js';
|
|
2
|
-
/**
|
|
3
|
-
* User search result for permission UI
|
|
4
|
-
*/
|
|
2
|
+
/** A user offered as a permission target. */
|
|
5
3
|
export interface UserSearchResult {
|
|
6
4
|
id: CanopyUserId;
|
|
7
5
|
name: string;
|
|
8
6
|
email: string;
|
|
9
7
|
avatarUrl?: string;
|
|
10
8
|
}
|
|
11
|
-
/**
|
|
12
|
-
* Group metadata for permission UI
|
|
13
|
-
*/
|
|
9
|
+
/** Group metadata for the permission UI. */
|
|
14
10
|
export interface GroupMetadata {
|
|
15
11
|
id: CanopyGroupId;
|
|
16
12
|
name: string;
|
|
@@ -22,12 +18,11 @@ export interface GroupMetadata {
|
|
|
22
18
|
* ('external'), Canopy's own groups.json ('internal'), or BOTH -- the same ID
|
|
23
19
|
* exists in each universe.
|
|
24
20
|
*
|
|
25
|
-
* 'both'
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* its blast radius to the admin making the grant.
|
|
21
|
+
* 'both' changes what a grant does. The two ID spaces are not namespaced against
|
|
22
|
+
* each other and `checkPathPermission` matches one flattened `user.groups` list
|
|
23
|
+
* by ID, so granting a colliding ID reaches the internal group's members AND
|
|
24
|
+
* every provider user carrying that ID externally. Labeling such an option
|
|
25
|
+
* merely 'internal' would understate that blast radius to the granting admin.
|
|
31
26
|
*/
|
|
32
27
|
export type GroupSource = 'internal' | 'external' | 'both';
|
|
33
28
|
/**
|
|
@@ -35,21 +30,17 @@ export type GroupSource = 'internal' | 'external' | 'both';
|
|
|
35
30
|
*
|
|
36
31
|
* Both universes are valid `allowedGroups` values -- `authResultToCanopyUser`
|
|
37
32
|
* (user.ts) flattens external and internal groups into one `user.groups` list
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* other, hence `source` to disambiguate them in the UI.
|
|
33
|
+
* that `checkPathPermission` matches by ID -- so the picker offers both, with
|
|
34
|
+
* `source` disambiguating the two un-namespaced ID spaces in the UI.
|
|
41
35
|
*
|
|
42
36
|
* Internal options deliberately carry no `memberCount`: member identities and
|
|
43
37
|
* counts stay behind the admin-only `groups.getInternal`, while this endpoint
|
|
44
|
-
*
|
|
38
|
+
* only needs the `privileged` guard (authorization/helpers.ts's `isPrivileged`).
|
|
45
39
|
*/
|
|
46
40
|
export interface PermissionGroupOption extends GroupMetadata {
|
|
47
41
|
source: GroupSource;
|
|
48
42
|
}
|
|
49
|
-
/**
|
|
50
|
-
* Authentication result from auth plugins.
|
|
51
|
-
* Returns user identity (without final groups) on success.
|
|
52
|
-
*/
|
|
43
|
+
/** An auth plugin's verdict: on success, user identity without final groups. */
|
|
53
44
|
export interface AuthenticationResult {
|
|
54
45
|
success: boolean;
|
|
55
46
|
user?: {
|