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,183 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `canopycms init-github-app <create|verify>` — registers the GitHub App the
|
|
3
|
-
* worker authenticates as, and reads its grant back.
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* `
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* into a warning by design (`github-service.ts`), leaving the PR stuck as a
|
|
26
|
-
* draft. Both surface hours after setup. `verify` moves that discovery to setup
|
|
27
|
-
* time, which is the only cheap place to find it.
|
|
28
|
-
*
|
|
29
|
-
* ONE APP PER SITE. NOT ONE APP PER ORGANISATION.
|
|
30
|
-
*
|
|
31
|
-
* Worth stating at length because the obvious economy is to register one App and
|
|
32
|
-
* install it on every repository that needs it, and for a READ-ONLY App whose key
|
|
33
|
-
* never leaves GitHub that is right. It is wrong here, and the reason is
|
|
34
|
-
* structural rather than a matter of taste:
|
|
35
|
-
*
|
|
36
|
-
* **A GitHub App's private key is App-level. Installation scoping is not a
|
|
37
|
-
* boundary GitHub enforces against whoever holds the key — it is a choice the
|
|
38
|
-
* key-holder makes at mint time.** Anyone with the key can sign a JWT, call
|
|
39
|
-
* `GET /app/installations` to enumerate every installation, and mint an access
|
|
40
|
-
* token for any of them.
|
|
41
|
-
*
|
|
42
|
-
* Our key does not stay in one place: each site's worker reads it at runtime,
|
|
43
|
-
* from that site's own secret store, on that site's own host. So one shared App
|
|
44
|
-
* with `contents: write` would mean that reading the marketing site's secret
|
|
45
|
-
* store hands you write access to the documentation site's repository. One App
|
|
46
|
-
* per site, one installation each, one key each — blast radius contained to the
|
|
47
|
-
* site that leaked.
|
|
48
|
-
*
|
|
49
|
-
* The cost is real and is not pretended away: N sites means N Apps, N keys and N
|
|
50
|
-
* things to rotate. That is affordable only because creating one is cheap, which
|
|
51
|
-
* is most of why this command exists.
|
|
52
|
-
*
|
|
53
|
-
* WHAT THE MANIFEST FLOW BUYS, WHICH IS MORE THAN IT LOOKS
|
|
54
|
-
*
|
|
55
|
-
* `redirect_url` is the point of it. GitHub redirects there with a one-hour code,
|
|
56
|
-
* and `POST /app-manifests/{code}/conversions` exchanges that code for the App's
|
|
57
|
-
* id, client id and **the private key itself**. So `create` runs a one-shot
|
|
58
|
-
* loopback server, captures the key in memory, and hands it straight to a
|
|
59
|
-
* destination the operator named. Sent to a command's stdin — the recommended
|
|
60
|
-
* route — **the key never touches disk**, and nobody has to find a downloaded
|
|
61
|
-
* `.pem`. `--key-out` deliberately does write it to a file, for an operator with
|
|
62
|
-
* no such command; that is the trade, not an oversight.
|
|
63
|
-
*
|
|
64
|
-
* MEASURED (2026-09-05, in a sibling project) and it contradicts the
|
|
65
|
-
* documentation: GitHub's REST docs list `redirect_url` as OPTIONAL, and the
|
|
66
|
-
* organisation App-creation form refuses a manifest without it — "Invalid GitHub
|
|
67
|
-
* App configuration ... Error 'redirect_url' wasn't supplied."
|
|
68
|
-
*
|
|
69
|
-
* THIS FILE TALKS TO GITHUB WITH `fetch`, NOT OCTOKIT, DELIBERATELY
|
|
70
|
-
*
|
|
71
|
-
* Two reasons. An App JWT requires `Authorization: Bearer <jwt>`, and a client
|
|
72
|
-
* that sends `token <value>` is answered with `401 A JSON web token could not be
|
|
73
|
-
* decoded` — measured in the sibling project, where it presented as "no
|
|
74
|
-
* installation found" and sent the operator to check a page that was correct.
|
|
75
|
-
* And Octokit here would add `octokit.apps.*` call sites to this package, which
|
|
76
|
-
* the guard in `github-app-permission-drift.test.ts` would then have to carve an
|
|
77
|
-
* exception for — an exception being exactly how a guard goes blind.
|
|
78
|
-
*
|
|
79
|
-
* The JWT is hand-rolled over `node:crypto` for a third reason that is not
|
|
80
|
-
* optional: `.dependency-cruiser.mjs`'s `core-no-github-app-auth` rule scopes to
|
|
81
|
-
* every package's own `src/`, so importing `@octokit/auth-app` here is a lint
|
|
82
|
-
* error, same as anywhere else in this package.
|
|
83
|
-
*
|
|
84
|
-
* THE KEY'S DESTINATION IS NOT THIS TOOL'S BUSINESS
|
|
85
|
-
*
|
|
86
|
-
* `create` takes either a command to pipe the PEM into (`-- <cmd>`) or a file to
|
|
87
|
-
* write (`--key-out`), and asks for a file path if that first one fails. It
|
|
88
|
-
* knows nothing about AWS, or any other secret store: an adopter may not deploy
|
|
89
|
-
* to AWS at all, and a setup tool that hardcodes one cloud is a setup tool for
|
|
90
|
-
* one adopter. `docs/deploying-to-aws.md` carries the worked invocation.
|
|
2
|
+
* `canopycms init-github-app <create|verify>` — registers the GitHub App the
|
|
3
|
+
* CMS worker authenticates as, and reads its grant back. A PAT's scope is
|
|
4
|
+
* unauditable — checkboxes somebody ticked, nowhere recorded.
|
|
5
|
+
* `CANOPY_APP_PERMISSIONS` in github-app-manifest.ts is the machine-checkable statement of what
|
|
6
|
+
* this App needs instead, checked against the call sites that force each
|
|
7
|
+
* entry (see the constant) and what an installation holds (see `verify`). A
|
|
8
|
+
* missing permission fails silently — a GraphQL denial answers HTTP 200 with
|
|
9
|
+
* no numeric status — so `verify` exists to catch that at setup time.
|
|
10
|
+
* One App per site, never shared across an organisation: a GitHub App's
|
|
11
|
+
* private key is App-level — GitHub does not enforce per-installation
|
|
12
|
+
* scoping against the key-holder — so anyone holding it can mint a token for
|
|
13
|
+
* every installation. Each site's worker reads its own key from its own
|
|
14
|
+
* secret store, so sharing one App would let one leaked store reach every
|
|
15
|
+
* other site's repository.
|
|
16
|
+
* `create` runs a one-shot loopback server, exchanges GitHub's redirect code
|
|
17
|
+
* for the App's credentials including the private key, then hands it to the
|
|
18
|
+
* destination the operator named — over a command's stdin so it never
|
|
19
|
+
* touches disk, or to a file with `--key-out`. That destination is not this
|
|
20
|
+
* tool's business: it knows nothing about AWS or any other secret store.
|
|
21
|
+
* This file talks to GitHub with `fetch`, not Octokit: an App JWT needs
|
|
22
|
+
* `Authorization: Bearer <jwt>` (sent as `token <value>` it gets a misleading
|
|
23
|
+
* 401), and `.dependency-cruiser.mjs` forbids importing `@octokit/auth-app`
|
|
24
|
+
* from this package's `src/` anyway.
|
|
91
25
|
*/
|
|
92
26
|
import type { ChildProcess } from 'node:child_process';
|
|
93
27
|
import { createServer } from 'node:http';
|
|
94
|
-
/** Permission levels GitHub uses for App repository permissions, weakest first. */
|
|
95
|
-
export declare const PERMISSION_LEVELS: readonly ["read", "write", "admin"];
|
|
96
|
-
export type PermissionLevel = (typeof PERMISSION_LEVELS)[number];
|
|
97
|
-
export type PermissionSet = Readonly<Record<string, PermissionLevel>>;
|
|
98
28
|
/**
|
|
99
|
-
* The
|
|
100
|
-
*
|
|
101
|
-
* Every entry names the call site that forces it, because a permission whose
|
|
102
|
-
* justification lives only in a commit message cannot be re-checked. Enumerated
|
|
103
|
-
* from the only two modules in this package that issue GitHub calls —
|
|
104
|
-
* `github-service.ts` and `worker/{task-runner,rebase}.ts` — plus every git
|
|
105
|
-
* operation that reaches github.com. `canopycms-cdk` makes no REST calls at all.
|
|
106
|
-
*
|
|
107
|
-
* - `contents: write`
|
|
108
|
-
* - git over HTTPS: the first-boot bare clone (`worker/cms-worker.ts`), the
|
|
109
|
-
* per-cycle fetch of all branches (`worker/git-sync.ts`), and the branch
|
|
110
|
-
* pushes including `--force-with-lease` (`worker/task-runner.ts`).
|
|
111
|
-
* - `octokit.git.deleteRef` (`github-service.ts`, `worker/task-runner.ts`).
|
|
112
|
-
* GitHub's permissions reference puts `DELETE /repos/{o}/{r}/git/refs/{ref}`
|
|
113
|
-
* under Contents/write — NOT `administration`, which is the plausible wrong
|
|
114
|
-
* guess. It is also dead code today: nothing enqueues `delete-remote-branch`
|
|
115
|
-
* and `GitHubService.deleteBranch`'s only call site is commented out, so it
|
|
116
|
-
* forces nothing that pushing does not already force. Declared anyway
|
|
117
|
-
* because the handler is live the moment a producer appears.
|
|
118
|
-
*
|
|
119
|
-
* - `pull_requests: write`
|
|
120
|
-
* - `pulls.create` and `pulls.update` (`github-service.ts`,
|
|
121
|
-
* `worker/task-runner.ts`). GitHub's reference: Create and Update a pull
|
|
122
|
-
* request are Pull requests/write. `pulls.list` and `pulls.get` are
|
|
123
|
-
* Pull requests/read, subsumed by this.
|
|
124
|
-
* - the GraphQL mutations `markPullRequestReadyForReview` and
|
|
125
|
-
* `convertPullRequestToDraft`. **This is the one entry with no
|
|
126
|
-
* documentation line behind it** — GitHub's permissions reference
|
|
127
|
-
* enumerates REST endpoints only — so it is derived by analogy with the
|
|
128
|
-
* REST PR mutations. A live run is the oracle, and until one has happened
|
|
129
|
-
* this comment is the honest state of it.
|
|
130
|
-
*
|
|
131
|
-
* - `metadata: read` — implied: GitHub grants it alongside any repository
|
|
132
|
-
* permission. Declared explicitly so this object states the whole surface
|
|
133
|
-
* rather than the part that is not automatic.
|
|
134
|
-
*
|
|
135
|
-
* Nothing else. No `issues` (there are no `issues.*` calls — nothing sets labels
|
|
136
|
-
* or assignees, which is the usual reason a PR bot needs it), no `administration`,
|
|
137
|
-
* no `actions`, and no organisation permissions. No `workflows`: nothing in the
|
|
138
|
-
* worker edits `.github/workflows/`, but GitHub may still refuse to push rebased
|
|
139
|
-
* history that carries a base-branch change to it — see
|
|
140
|
-
* .claude/future-tasks/worker-push-refused-when-base-changes-workflows.md, an
|
|
141
|
-
* open P1.
|
|
29
|
+
* The repository an App is being registered for.
|
|
30
|
+
* @internal Exported for tests.
|
|
142
31
|
*/
|
|
143
|
-
export declare const CANOPY_APP_PERMISSIONS: PermissionSet;
|
|
144
|
-
/**
|
|
145
|
-
* GitHub's limit on an App's display name.
|
|
146
|
-
*
|
|
147
|
-
* MEASURED 2026-09-06 in a sibling project, by having a 39-character name
|
|
148
|
-
* refused while a 33-character one was accepted; the documentation states no
|
|
149
|
-
* limit at all. So the true bound is somewhere in 33..38 and 34 is the safe
|
|
150
|
-
* direction: a wrongly-refused name costs the operator one `--name` flag, while a
|
|
151
|
-
* wrongly-accepted one costs a browser round trip to find out. Re-measure when a
|
|
152
|
-
* real App is created from this file.
|
|
153
|
-
*/
|
|
154
|
-
export declare const APP_NAME_MAX_LENGTH = 34;
|
|
155
|
-
/**
|
|
156
|
-
* How much of a description the account's App LIST renders before truncating —
|
|
157
|
-
* mid-word, with an ellipsis.
|
|
158
|
-
*
|
|
159
|
-
* MEASURED 2026-09-06 in the same project: a description opening "Read-only,
|
|
160
|
-
* organisation-wide. Lets th…" was cut at 37 characters. The list appears to
|
|
161
|
-
* truncate by CHARACTER rather than by line, so a newline does not rescue a long
|
|
162
|
-
* opening sentence. Hence the shape of `appDescription`: a standalone summary
|
|
163
|
-
* inside this budget, a blank line, then the detail only the App's own page
|
|
164
|
-
* shows.
|
|
165
|
-
*/
|
|
166
|
-
export declare const APP_SUMMARY_MAX_LENGTH = 37;
|
|
167
|
-
/** How long `create` waits for the browser round trip before giving up. */
|
|
168
|
-
export declare const CALLBACK_TIMEOUT_MS: number;
|
|
169
|
-
/** The repository an App is being registered for. */
|
|
170
32
|
export type AppTarget = {
|
|
171
33
|
owner: string;
|
|
172
34
|
repo: string;
|
|
173
35
|
/** Organisation accounts and user accounts post the manifest to different URLs. */
|
|
174
36
|
isOrganization: boolean;
|
|
175
37
|
};
|
|
176
|
-
/**
|
|
177
|
-
|
|
178
|
-
* the operator BEFORE the App exists — see `requireDestination`.
|
|
179
|
-
*/
|
|
180
|
-
export type KeyDestination = {
|
|
38
|
+
/** Where `create` should send the captured private key, chosen by the operator BEFORE the App exists. */
|
|
39
|
+
type KeyDestination = {
|
|
181
40
|
kind: 'command';
|
|
182
41
|
argv: string[];
|
|
183
42
|
} | {
|
|
@@ -185,246 +44,85 @@ export type KeyDestination = {
|
|
|
185
44
|
filePath: string;
|
|
186
45
|
};
|
|
187
46
|
/**
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
* an App named after the organisation would suggest it is shared, which is the
|
|
192
|
-
* arrangement this file exists to avoid.
|
|
193
|
-
*
|
|
194
|
-
* GitHub App names are unique across the WHOLE of GitHub, not merely within an
|
|
195
|
-
* account, so a short generic name is plausibly already taken by somebody else.
|
|
196
|
-
* `create` pre-checks what it can and `--name` overrides; see
|
|
197
|
-
* `checkNameAvailable`.
|
|
198
|
-
*/
|
|
199
|
-
export declare function appName(repo: string): string;
|
|
200
|
-
/**
|
|
201
|
-
* GitHub's slug derivation, as far as this needs it: lowercase, and runs of
|
|
202
|
-
* anything that is not alphanumeric collapse to single hyphens.
|
|
203
|
-
*
|
|
204
|
-
* Pinned by a test. If GitHub ever derives differently the name pre-check goes
|
|
205
|
-
* blind rather than loud, so this is not something to assume.
|
|
206
|
-
*/
|
|
207
|
-
export declare function appSlug(name: string): string;
|
|
208
|
-
/**
|
|
209
|
-
* A short summary that survives the App list's truncation, then the detail.
|
|
210
|
-
*
|
|
211
|
-
* Two audiences, two parts. Deliberately generic in both: this text is stored ON
|
|
212
|
-
* GITHUB rather than here, so anything in it that can go stale goes stale
|
|
213
|
-
* silently, with nothing in this repository able to detect or fix it. It
|
|
214
|
-
* therefore says only what stays true of the App itself — what it does, that it
|
|
215
|
-
* is installed on one repository, and that it is registered per site.
|
|
216
|
-
*/
|
|
217
|
-
export declare function appDescription(): string;
|
|
218
|
-
/**
|
|
219
|
-
* Where the manifest form posts, which differs by account type.
|
|
220
|
-
*
|
|
221
|
-
* A solo adopter who owns the content repository personally needs the user-level
|
|
222
|
-
* URL; posting an organisation manifest to it (or the reverse) fails at the form.
|
|
47
|
+
* Where the manifest form posts: user-owned and organisation repositories use
|
|
48
|
+
* different URLs, and posting the wrong one fails at the form.
|
|
49
|
+
* @internal Exported for tests.
|
|
223
50
|
*/
|
|
224
51
|
export declare function manifestPostUrl(target: AppTarget, state: string): string;
|
|
225
52
|
/**
|
|
226
|
-
* The App as GitHub's manifest flow takes it.
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
* it. `default_events` is empty and the webhook is inactive: nothing is ever
|
|
231
|
-
* delivered to this App — it is only ever assumed outward by the worker.
|
|
53
|
+
* The App as GitHub's manifest flow takes it. `default_permissions` is the
|
|
54
|
+
* entire security surface, defined in `CANOPY_APP_PERMISSIONS`. The webhook is
|
|
55
|
+
* declared but inactive: nothing is ever delivered to this App.
|
|
56
|
+
* @internal Exported for tests.
|
|
232
57
|
*/
|
|
233
58
|
export declare function appManifest(target: AppTarget, redirectUrl: string, name?: string): Record<string, unknown>;
|
|
234
59
|
/**
|
|
235
|
-
* The auto-submitting form that carries the manifest to GitHub
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
* adopter-supplied owner and repository names, and this string is written to a
|
|
240
|
-
* file that a browser then executes.
|
|
60
|
+
* The auto-submitting form that carries the manifest to GitHub — a manifest
|
|
61
|
+
* can only be delivered as a browser form POST. Both interpolations are
|
|
62
|
+
* escaped: this embeds adopter-supplied names into a file a browser executes.
|
|
63
|
+
* @internal Exported for tests.
|
|
241
64
|
*/
|
|
242
65
|
export declare function creationForm(target: string, manifest: Record<string, unknown>): string;
|
|
243
66
|
/**
|
|
244
|
-
* A short-lived App JWT, signed RS256 with `node:crypto`.
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
* ten-minute maximum for no benefit.
|
|
67
|
+
* A short-lived App JWT, signed RS256 with `node:crypto`. `iat` is backdated
|
|
68
|
+
* 60s because GitHub rejects a JWT whose `iat` is in its own future, and a
|
|
69
|
+
* second of clock skew is ordinary; `exp` leaves headroom rather than sitting
|
|
70
|
+
* on GitHub's stated ten-minute maximum for no benefit.
|
|
71
|
+
* @internal Exported for tests.
|
|
250
72
|
*/
|
|
251
73
|
export declare function appJwt(issuer: string, privateKey: string, now?: number): string;
|
|
252
|
-
|
|
253
|
-
ok: boolean;
|
|
254
|
-
status: number;
|
|
255
|
-
body: T | null;
|
|
256
|
-
/**
|
|
257
|
-
* On a FAILURE: GitHub's own `message`, a redacted prefix of the response text,
|
|
258
|
-
* or — when `status` is 0, meaning the request or the body read never completed
|
|
259
|
-
* — the redacted client-side error, since there is no response to quote. Empty
|
|
260
|
-
* string on success: a success body here is App credentials, and a prefix of one
|
|
261
|
-
* is not worth handing to a caller that might print it.
|
|
262
|
-
*/
|
|
263
|
-
message: string;
|
|
264
|
-
};
|
|
265
|
-
/**
|
|
266
|
-
* One call to api.github.com.
|
|
267
|
-
*
|
|
268
|
-
* Returns the status and body rather than collapsing failure to `null`, because
|
|
269
|
-
* the two failures a caller has to tell apart here — "this credential cannot
|
|
270
|
-
* authenticate" and "this App is not installed on that repository" — send an
|
|
271
|
-
* operator to entirely different pages. Collapsing them is measured to have sent
|
|
272
|
-
* a real run's operator to check a page that was correct.
|
|
273
|
-
*/
|
|
274
|
-
export declare function githubRequest<T>(apiPath: string, init?: {
|
|
275
|
-
method?: string;
|
|
276
|
-
body?: unknown;
|
|
277
|
-
token?: string;
|
|
278
|
-
jwt?: string;
|
|
279
|
-
}): Promise<GitHubResponse<T>>;
|
|
280
|
-
/** The parts of GitHub's installation object this tool reads back. */
|
|
281
|
-
export type InstallationSummary = {
|
|
282
|
-
id: number;
|
|
283
|
-
permissions?: Record<string, string>;
|
|
284
|
-
repository_selection?: string;
|
|
285
|
-
suspended_at?: string | null;
|
|
286
|
-
app_slug?: string;
|
|
287
|
-
};
|
|
288
|
-
export type ReadbackFinding = {
|
|
289
|
-
severity: 'error' | 'warn';
|
|
290
|
-
message: string;
|
|
291
|
-
};
|
|
292
|
-
/**
|
|
293
|
-
* Compare what an installation actually holds against what this package needs.
|
|
294
|
-
*
|
|
295
|
-
* Pure, so the whole judgement is testable without a live App — which matters,
|
|
296
|
-
* because everything around it can only ever be exercised by hand.
|
|
297
|
-
*
|
|
298
|
-
* Reports in BOTH directions. A credential does not usually fail by being
|
|
299
|
-
* unusable; that gets noticed immediately. It fails by being one permission too
|
|
300
|
-
* wide, which works perfectly and is never noticed. So an extra permission, or
|
|
301
|
-
* an installation scoped to every repository in the account, is an error here
|
|
302
|
-
* and not a shrug.
|
|
303
|
-
*/
|
|
304
|
-
export declare function readbackVerdict(installation: InstallationSummary, desired?: PermissionSet): ReadbackFinding[];
|
|
305
|
-
export type HandOffResult = {
|
|
74
|
+
type HandOffResult = {
|
|
306
75
|
stored: boolean;
|
|
307
76
|
detail: string;
|
|
308
77
|
};
|
|
309
78
|
/**
|
|
310
|
-
* Injectable so `handOffKey` is testable without spawning anything real.
|
|
311
|
-
*
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
*
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
*
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
*
|
|
329
|
-
*
|
|
330
|
-
*
|
|
331
|
-
*
|
|
332
|
-
*
|
|
333
|
-
*
|
|
334
|
-
* WHAT `stored: true` DOES AND DOES NOT MEAN. Everywhere but Windows it means
|
|
335
|
-
* three things: the command exited 0, the `cat` feeding it exited 0, and nothing
|
|
336
|
-
* went wrong writing to it. `cat` exiting 0 means every byte of the key went into
|
|
337
|
-
* the pipe. It still does NOT prove the command READ them, and cannot: a pipe
|
|
338
|
-
* write lands in the kernel's buffer, and a key this size fits in one write, so a
|
|
339
|
-
* command that exits without reading races `cat`'s write and can lose or win.
|
|
340
|
-
* MEASURED on macOS with a real 1.7KB key, 100 runs each through this function,
|
|
341
|
-
* with the same result before the bridge and after it: `true`, `head -c 10`,
|
|
342
|
-
* `sh -c 'exec 0<&-; exit 0'` and `sh -c 'head -c 5 >/dev/null; exit 0'` were
|
|
343
|
-
* each reported stored 100 times of 100. What IS caught, whatever the timing,
|
|
344
|
-
* is a command that leaves more unread than a pipe buffer holds: ~100KB into
|
|
345
|
-
* `true` was reported not stored 20 times of 20, by `cat` exiting 141 — the
|
|
346
|
-
* same case the direct spawn caught as a write EPIPE.
|
|
347
|
-
*
|
|
348
|
-
* So the command's EXIT CODE is still the contract, and the operator is still
|
|
349
|
-
* responsible for naming a command that fails loudly. That is stated here rather
|
|
350
|
-
* than papered over, because the tempting fix — waiting for the stream to flush
|
|
351
|
-
* — measures the kernel buffer rather than the command, and would look like a
|
|
352
|
-
* check while being one.
|
|
79
|
+
* Injectable so `handOffKey` is testable without spawning anything real. Everywhere but Windows
|
|
80
|
+
* the child carries the bridge's status channel at `stdio[3]`, without which nothing is stored.
|
|
81
|
+
*/
|
|
82
|
+
type SpawnFn = (command: string, args: string[]) => ChildProcess;
|
|
83
|
+
/**
|
|
84
|
+
* Send the captured private key to the destination the operator named. For a
|
|
85
|
+
* command, the PEM goes over **stdin**, never argv — an argument is visible
|
|
86
|
+
* in `ps` and lands in shell history (see `KEY_INPUT_BRIDGE` for how `sh`
|
|
87
|
+
* runs it without parsing that argv itself). Stdout/stderr are INHERITED,
|
|
88
|
+
* not captured: `aws secretsmanager create-secret` prints the ARN the
|
|
89
|
+
* operator needs, which this function must not swallow. The `'error'`
|
|
90
|
+
* listener on `child.stdin` is not optional: a child that exits or closes
|
|
91
|
+
* stdin early can fail the write with EPIPE, an unhandled stream error that
|
|
92
|
+
* would take the process — and the key — down with it.
|
|
93
|
+
* Everywhere but Windows, `stored: true` means the command exited 0, `cat`
|
|
94
|
+
* exited 0, and nothing went wrong writing — every byte reached the pipe. It
|
|
95
|
+
* does NOT prove the command read them: a write lands in the kernel buffer,
|
|
96
|
+
* and a key this size fits in one write, so a command that exits without
|
|
97
|
+
* reading races `cat`'s write and can win or lose silently. What IS caught is
|
|
98
|
+
* a command leaving more unread than the buffer holds, which fails loudly as
|
|
99
|
+
* `cat` exiting on SIGPIPE — so the exit code is still the contract, and
|
|
100
|
+
* naming a command that fails loudly is the operator's job.
|
|
101
|
+
* @internal Exported for tests.
|
|
353
102
|
*/
|
|
354
103
|
export declare function handOffKey(pem: string, destination: KeyDestination, spawnFn?: SpawnFn): Promise<HandOffResult>;
|
|
355
|
-
|
|
104
|
+
type CallbackServer = {
|
|
356
105
|
port: number;
|
|
357
106
|
code: Promise<string>;
|
|
358
107
|
close: () => void;
|
|
359
108
|
};
|
|
360
109
|
/**
|
|
361
|
-
* One request, then closed
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
* the
|
|
366
|
-
*
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
* the CSRF guard the manifest flow provides, but rejecting the promise on a
|
|
370
|
-
* mismatch ends the run on the first stray loopback request — a browser
|
|
371
|
-
* prefetch, an extension, a retried tab — possibly seconds before GitHub's real
|
|
372
|
-
* redirect arrives, and AFTER the App has been created. Aborting there leaves an
|
|
373
|
-
* App nobody holds a key for, over a request that was never GitHub's.
|
|
110
|
+
* One request, then closed by the handler itself, bound to loopback only —
|
|
111
|
+
* the standard CLI pattern (`gh auth login` does the same) so the key
|
|
112
|
+
* arrives over the redirect, not a downloads folder. A rejected request is
|
|
113
|
+
* answered and ignored, never fatal: the `state` check
|
|
114
|
+
* is the CSRF guard the manifest flow provides, but rejecting the promise on
|
|
115
|
+
* a mismatch would end the run on a stray loopback request, possibly before
|
|
116
|
+
* GitHub's real redirect, leaving an App nobody holds a key for.
|
|
117
|
+
* @internal Exported for tests.
|
|
374
118
|
*/
|
|
375
119
|
export declare function startCallbackServer(state: string, timeoutMs?: number, createServerFn?: typeof createServer): Promise<CallbackServer>;
|
|
376
|
-
type CreatedApp = {
|
|
377
|
-
id: number;
|
|
378
|
-
slug: string;
|
|
379
|
-
clientId: string;
|
|
380
|
-
pem: string;
|
|
381
|
-
};
|
|
382
|
-
/**
|
|
383
|
-
* The exchange. Unauthenticated by design: the one-hour code IS the credential.
|
|
384
|
-
*
|
|
385
|
-
* Only the four fields this tool needs are lifted out. The response also carries
|
|
386
|
-
* `client_secret` and `webhook_secret`, which this App never uses — so the body
|
|
387
|
-
* is never logged, never returned whole, and never reaches an error message.
|
|
388
|
-
* Failures collapse to `null` and nothing from the response is surfaced, for
|
|
389
|
-
* the same reason: the code itself is exchangeable for the private key for a
|
|
390
|
-
* full hour. That also drops the HTTP status, which the caller does not report
|
|
391
|
-
* (.claude/future-tasks/init-github-app-review-round-1-lows.md, item 2).
|
|
392
|
-
*/
|
|
393
|
-
export declare function convertManifest(code: string): Promise<CreatedApp | null>;
|
|
394
|
-
/**
|
|
395
|
-
* Whether the account is an organisation, which decides where the manifest posts.
|
|
396
|
-
*
|
|
397
|
-
* Unauthenticated, so it needs no credential at a point in the flow where we have
|
|
398
|
-
* none. `null` means "could not tell" and the caller says so rather than
|
|
399
|
-
* guessing — guessing wrong sends the operator to a form that refuses the
|
|
400
|
-
* manifest with no useful explanation.
|
|
401
|
-
*/
|
|
402
|
-
export declare function detectAccountType(owner: string): Promise<boolean | null>;
|
|
403
|
-
/**
|
|
404
|
-
* Best-effort check that the App name is not already taken.
|
|
405
|
-
*
|
|
406
|
-
* `true` = available as far as we can tell, `false` = definitely taken, `null` =
|
|
407
|
-
* could not check. The three are kept apart deliberately: a PRIVATE App with
|
|
408
|
-
* this slug also answers 404, so a 404 is not proof of availability, and
|
|
409
|
-
* reporting "could not check" as "checked, it is free" is how a guard goes
|
|
410
|
-
* blind. This exists because name collisions can otherwise only be discovered by
|
|
411
|
-
* the creation form — with the CLI already sitting on a loopback server waiting
|
|
412
|
-
* for a redirect that will never arrive.
|
|
413
|
-
*/
|
|
414
|
-
export declare function checkNameAvailable(slug: string): Promise<boolean | null>;
|
|
415
|
-
/** Wait for the operator to continue. Returns at once if stdin has ended. */
|
|
416
|
-
export declare function pressEnter(prompt: string): Promise<void>;
|
|
417
|
-
/** Read one line from the operator. `null` when stdin ended instead. */
|
|
418
|
-
export declare function askLine(prompt: string): Promise<string | null>;
|
|
419
|
-
/** Reset between tests. Not used by the command itself. */
|
|
420
|
-
export declare function resetStdinStateForTesting(): void;
|
|
421
120
|
/**
|
|
422
|
-
* What to do with one answer to the retry prompt: write
|
|
423
|
-
*
|
|
424
|
-
* `
|
|
425
|
-
*
|
|
426
|
-
*
|
|
427
|
-
* wrong with what they typed instead of silently asking again.
|
|
121
|
+
* What to do with one answer to the retry prompt: write to a file, ask again,
|
|
122
|
+
* or stop. No command here — see `parseKeyRetryAnswer`. `reprompt` carries
|
|
123
|
+
* WHY, so `handOffWithRetry` can tell the operator what was wrong instead of
|
|
124
|
+
* silently asking again.
|
|
125
|
+
* @internal Exported for tests.
|
|
428
126
|
*/
|
|
429
127
|
export type KeyRetryChoice = {
|
|
430
128
|
kind: 'give-up';
|
|
@@ -436,72 +134,40 @@ export type KeyRetryChoice = {
|
|
|
436
134
|
filePath: string;
|
|
437
135
|
};
|
|
438
136
|
/**
|
|
439
|
-
* Route one line of operator input at the retry prompt,
|
|
440
|
-
* PATH and nothing else
|
|
441
|
-
*
|
|
442
|
-
*
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
*
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
*
|
|
451
|
-
*
|
|
452
|
-
*
|
|
453
|
-
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
*
|
|
457
|
-
*
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
* wait for GitHub's redirect — or while the FIRST destination's command was
|
|
461
|
-
* running — sits in the terminal's line buffer. When that first hand-off
|
|
462
|
-
* then fails, `askLine` reads the buffered blank line immediately, before
|
|
463
|
-
* the operator has even seen this prompt. Treating that as "give up"
|
|
464
|
-
* discarded the only copy of the key without anyone actually answering.
|
|
465
|
-
* Re-prompting instead costs nothing when the blank line really was
|
|
466
|
-
* intentional, because the very next prompt still offers "give up" as
|
|
467
|
-
* something the operator has to type.
|
|
468
|
-
* - The words "give up", case-insensitively and with whitespace normalised, is
|
|
469
|
-
* the one deliberate way to give up once stdin is live.
|
|
470
|
-
* - Any whitespace inside the answer, or a leading `|`, is re-prompted with
|
|
471
|
-
* "commands are not accepted here" and the write-run-delete route. Every
|
|
472
|
-
* command-shaped answer above was spelled with whitespace, and nothing about
|
|
473
|
-
* a typed line tells a command apart from a path that contains spaces — so
|
|
474
|
-
* the cost, stated in the reason, is that such a path cannot be entered here.
|
|
475
|
-
* - A leading `~` is re-prompted: nothing here expands it, so `~/key.pem`
|
|
476
|
-
* would name a directory literally called `~` under the working directory.
|
|
477
|
-
* - A single token with NO `/` or `\` — `pbcopy`, `wl-copy`, any script on
|
|
478
|
-
* PATH — is re-prompted, suggesting `./<token>`. A "one word is a path" rule
|
|
479
|
-
* once let `writeFile('pbcopy', pem, { flag: 'wx' })` succeed in
|
|
480
|
-
* `process.cwd()` — normally the git repository root — leaving a
|
|
481
|
-
* `contents: write` private key sitting untracked on disk, while the
|
|
482
|
-
* operator read "written to pbcopy (mode 0600)" and believed it had gone
|
|
483
|
-
* into the command they meant.
|
|
484
|
-
* - Anything else is a path, which `handOffKey` creates with mode 0600 and
|
|
137
|
+
* Route one line of operator input at the retry prompt, accepting a FILE
|
|
138
|
+
* PATH and nothing else (exported and pure, so every rule is table-tested
|
|
139
|
+
* directly). The first destination can be a command because the operator's
|
|
140
|
+
* shell parses `-- <command…>` into argv; a typed line has no such parser,
|
|
141
|
+
* and splitting on whitespace sends the key somewhere unintended (a stray
|
|
142
|
+
* `|`, `>`, `;`, `&&` or quote becomes a literal argv word). Accepting only a
|
|
143
|
+
* path closes that class — a command means write, run, then delete. Rules,
|
|
144
|
+
* in order:
|
|
145
|
+
* - `null` (stdin has already ended — see prompt.ts) gives up.
|
|
146
|
+
* - A blank or whitespace-only line MUST NOT give up — a stray Enter pressed
|
|
147
|
+
* earlier sits buffered and is read back before the operator has seen this
|
|
148
|
+
* prompt — but the words "give up", case-insensitively and
|
|
149
|
+
* whitespace-normalised, deliberately do once stdin is live.
|
|
150
|
+
* - Whitespace inside the answer, or a leading `|`, is re-prompted: nothing
|
|
151
|
+
* tells a command apart from a path containing spaces, so such paths
|
|
152
|
+
* aren't accepted either.
|
|
153
|
+
* - A leading `~` is re-prompted (unexpanded, `~/key.pem` would name a
|
|
154
|
+
* directory literally called `~`), as is a single token with no `/` or `\`
|
|
155
|
+
* (`pbcopy`, any PATH script): as a bare word it would write the key into
|
|
156
|
+
* the current directory while the operator believes it reached the command.
|
|
157
|
+
* - Anything else is a path: `handOffKey` creates it with mode 0600 and
|
|
485
158
|
* refuses to write if something already exists there.
|
|
159
|
+
* @internal Exported for tests.
|
|
486
160
|
*/
|
|
487
161
|
export declare function parseKeyRetryAnswer(answer: string | null): KeyRetryChoice;
|
|
488
162
|
/**
|
|
489
163
|
* Hand the key over, and keep asking while the operator still has a chance.
|
|
490
|
-
*
|
|
491
|
-
*
|
|
492
|
-
* a
|
|
493
|
-
*
|
|
494
|
-
*
|
|
495
|
-
*
|
|
496
|
-
*
|
|
497
|
-
*
|
|
498
|
-
* So a failure asks for a file path instead, while the key is still in memory —
|
|
499
|
-
* a path only, never a command, for the reasons on `parseKeyRetryAnswer`.
|
|
500
|
-
* `create` already requires a TTY, so there is someone there to answer. Only a
|
|
501
|
-
* closed stdin (nobody left to answer) or the operator typing "give up" ends the
|
|
502
|
-
* loop without a destination — a blank line re-prompts instead, since that is
|
|
503
|
-
* exactly what a stray Enter pressed before this prompt existed leaves buffered.
|
|
504
|
-
* See `parseKeyRetryAnswer` for the exact rules.
|
|
164
|
+
* The pre-flight can only refuse a MISSING destination — a bad path or a
|
|
165
|
+
* command not on PATH fails only here, and exiting on that would destroy the
|
|
166
|
+
* only copy of a private key for an App that already exists, over a typo. So
|
|
167
|
+
* a failure asks for a file path instead, while the key is still in memory —
|
|
168
|
+
* a path only, never a command, per `parseKeyRetryAnswer`'s rules. Only a
|
|
169
|
+
* closed stdin or "give up" ends the loop without a destination.
|
|
170
|
+
* @internal Exported for tests.
|
|
505
171
|
*/
|
|
506
172
|
export declare function handOffWithRetry(pem: string, destination: KeyDestination): Promise<boolean>;
|
|
507
173
|
export type InitGitHubAppOptions = {
|