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,20 +1,18 @@
|
|
|
1
|
-
import type { Task } from '
|
|
1
|
+
import type { Task } from '../task-queue/cms-task-queue.js';
|
|
2
2
|
import type { WorkerContext } from './worker-context.js';
|
|
3
3
|
/**
|
|
4
|
-
* The task-queue cluster: everything reachable from
|
|
5
|
-
* the loop that drains tasks Lambda enqueued
|
|
4
|
+
* The task-queue cluster: everything reachable from
|
|
5
|
+
* `CmsWorker.processTaskQueue()`, the loop that drains tasks Lambda enqueued
|
|
6
|
+
* because it has no internet. It owns the GitHub-facing side of the worker --
|
|
7
|
+
* pushing branches, creating and updating PRs, recording the outcome on branch
|
|
8
|
+
* metadata -- plus the permanent-vs-transient classification that decides
|
|
9
|
+
* whether a failed task is retried or fails fast.
|
|
6
10
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* updating PRs, and recording the outcome on branch metadata -- plus the
|
|
10
|
-
* permanent-vs-transient failure classification that decides whether a failed
|
|
11
|
-
* task is retried or fails fast.
|
|
12
|
-
*
|
|
13
|
-
* Shares nothing with the git-sync cluster but the four resolved paths, the
|
|
14
|
-
* Octokit client and the history-rewrite marker (history-rewrite.ts). Note the
|
|
11
|
+
* It shares nothing with the git-sync cluster but the four resolved paths, the
|
|
12
|
+
* Octokit client and the history-rewrite marker (history-rewrite.ts), and the
|
|
15
13
|
* two loops run CONCURRENTLY: `scheduleLoop` drives this on `taskPollInterval`
|
|
16
|
-
* (default 5s) and syncGit on `gitSyncInterval` (default 5min)
|
|
17
|
-
* here that reads branch metadata written by the rebase loop
|
|
14
|
+
* (default 5s) and syncGit on `gitSyncInterval` (default 5min). So anything
|
|
15
|
+
* here that reads branch metadata written by the rebase loop MUST re-read it
|
|
18
16
|
* rather than trust a snapshot.
|
|
19
17
|
*/
|
|
20
18
|
export type TaskRunnerContext = Pick<WorkerContext, 'githubOwner' | 'githubRepo' | 'baseBranch' | 'sanitizedBaseBranch' | 'taskDir' | 'remoteGitPath' | 'contentBranchesPath' | 'taskTimeoutMs' | 'maxTasksPerCycle' | 'maxRetries' | 'log' | 'octokit' | 'buildGitHubUrl' | 'refreshGitHubCredential' | 'branchWorkspacePath' | 'executeTask' | 'pushBranchToGitHub' | 'isRunning' | 'ensureStatusReport'>;
|
|
@@ -29,72 +27,40 @@ export declare class PermanentTaskError extends Error {
|
|
|
29
27
|
* Classify a task failure as permanent (fail fast) or transient (retry).
|
|
30
28
|
*
|
|
31
29
|
* Transient — worth retrying with backoff:
|
|
32
|
-
* - network errors / anything without an HTTP status
|
|
33
|
-
* most push/fetch failures are connectivity or contention and the retry
|
|
34
|
-
* budget bounds the pathological cases
|
|
35
|
-
* - HTTP 408
|
|
36
|
-
* - HTTP 403
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* permanently and wedge the branch (`sync-failed`, no retry).
|
|
44
|
-
* - HTTP 5xx (server-side, usually recovers)
|
|
30
|
+
* - network errors / anything without an HTTP status, git failures included:
|
|
31
|
+
* most push/fetch failures are connectivity or contention, and the retry
|
|
32
|
+
* budget bounds the pathological cases;
|
|
33
|
+
* - HTTP 408 and 429;
|
|
34
|
+
* - HTTP 403 carrying a rate-limit signal (`isRateLimitSignal403`): GitHub
|
|
35
|
+
* returns 403, not 429, for both primary and secondary rate limits. The
|
|
36
|
+
* throttling plugin (github-service.ts's createCanopyOctokit) retries short
|
|
37
|
+
* waits, and this carve-out is the safety net for waits it gives up on and
|
|
38
|
+
* errors it never sees — without it a rate-limited
|
|
39
|
+
* push-and-create-or-update-pr task fails permanently and wedges the branch;
|
|
40
|
+
* - HTTP 5xx.
|
|
45
41
|
*
|
|
46
42
|
* Permanent — retrying the identical request cannot succeed:
|
|
47
|
-
* - PermanentTaskError (malformed payload, unknown action)
|
|
48
|
-
* - other HTTP 4xx (
|
|
49
|
-
* - plain HTTP 403 with no rate-limit signal: a real permission denial
|
|
43
|
+
* - PermanentTaskError (malformed payload, unknown action);
|
|
44
|
+
* - other HTTP 4xx (401/404/422): the request itself is bad;
|
|
45
|
+
* - plain HTTP 403 with no rate-limit signal: a real permission denial.
|
|
50
46
|
*/
|
|
51
47
|
export declare function isPermanentTaskFailure(err: unknown): boolean;
|
|
52
48
|
/**
|
|
53
|
-
* Staleness threshold for recoverOrphanedTasks, derived from the
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* (60s timeout vs 5min threshold); the 5-minute floor preserves the
|
|
60
|
-
* long-standing default for a replacement instance's boot window.
|
|
49
|
+
* Staleness threshold for recoverOrphanedTasks, derived from the configured
|
|
50
|
+
* task timeout rather than fixed. The safety argument for running recovery on
|
|
51
|
+
* every poll cycle is "no legitimately in-flight task can be this old, because
|
|
52
|
+
* executeTaskWithTimeout bounds every attempt by taskTimeoutMs" -- true only
|
|
53
|
+
* while this threshold scales with taskTimeoutMs. The 5-minute floor covers a
|
|
54
|
+
* replacement instance's boot window.
|
|
61
55
|
*/
|
|
62
56
|
export declare function orphanRecoveryMaxAgeMs(ctx: Pick<TaskRunnerContext, 'taskTimeoutMs'>): number;
|
|
63
57
|
/**
|
|
64
|
-
* Process queued tasks from Lambda.
|
|
65
|
-
* Polls .tasks/pending/ directory and executes each task.
|
|
66
|
-
* Processes up to maxTasksPerCycle tasks per invocation.
|
|
67
|
-
* Retries transient failures with exponential backoff.
|
|
58
|
+
* Process queued tasks from Lambda, up to maxTasksPerCycle per invocation.
|
|
68
59
|
*/
|
|
69
60
|
export declare function processTaskQueue(ctx: TaskRunnerContext): Promise<void>;
|
|
70
|
-
/**
|
|
71
|
-
* Execute a task bounded by taskTimeoutMs (DEP-H1). Two layers:
|
|
72
|
-
* - An AbortSignal cancels Octokit HTTP calls promptly.
|
|
73
|
-
* - A Promise.race rejects when the timeout fires, so work that cannot
|
|
74
|
-
* observe the signal (git subprocesses via simple-git) still fails the
|
|
75
|
-
* attempt and the worker moves on instead of stalling forever.
|
|
76
|
-
* That second layer also stops a hung `ctx.buildGitHubUrl()` in
|
|
77
|
-
* pushBranchToGitHub from stalling the worker: resolving the tokenized URL is
|
|
78
|
-
* async and does not observe the signal, so the attempt fails at taskTimeoutMs —
|
|
79
|
-
* but the resolution is not cancelled, and if it later settles the abandoned
|
|
80
|
-
* push continues. (On the App path the mint is separately bounded by
|
|
81
|
-
* gitTokenMintTimeoutMs. git-sync.ts's two resolutions run on the sync loop,
|
|
82
|
-
* not through here, and are not bounded by taskTimeoutMs.)
|
|
83
|
-
* pushBranchToGitHub additionally kills stalled git processes via
|
|
84
|
-
* simple-git's block timeout, so a hung push doesn't leak a process.
|
|
85
|
-
*/
|
|
86
|
-
export declare function executeTaskWithTimeout(ctx: TaskRunnerContext, task: Task): Promise<Record<string, unknown>>;
|
|
87
61
|
export declare function executeTask(ctx: TaskRunnerContext, task: Task, signal: AbortSignal): Promise<Record<string, unknown>>;
|
|
88
62
|
/**
|
|
89
63
|
* Update branch metadata after successful task completion.
|
|
90
|
-
* Writes PR URL/number and sets syncStatus to 'synced'.
|
|
91
64
|
*/
|
|
92
65
|
export declare function updateBranchMetadata(ctx: TaskRunnerContext, task: Task, result: Record<string, unknown>): Promise<void>;
|
|
93
|
-
/**
|
|
94
|
-
* Update branch metadata after permanent task failure.
|
|
95
|
-
* Sets syncStatus to 'sync-failed' and records `error` (already redacted
|
|
96
|
-
* by the caller, processTaskQueue -- see [REDACT] there) as
|
|
97
|
-
* syncFailureReason, so the editor can show WHY, not just that it failed.
|
|
98
|
-
*/
|
|
99
|
-
export declare function updateBranchMetadataOnFailure(ctx: TaskRunnerContext, task: Task, error: string): Promise<void>;
|
|
100
66
|
export declare function pushBranchToGitHub(ctx: TaskRunnerContext, branch: string): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import { simpleGit } from 'simple-git';
|
|
3
|
-
import { completeTask, dequeueTask, failTask, recoverOrphanedTasks, retryTask } from '
|
|
3
|
+
import { completeTask, dequeueTask, failTask, recoverOrphanedTasks, retryTask, } from '../task-queue/cms-task-queue.js';
|
|
4
4
|
import { createOrUpdatePullRequest } from '../github-service.js';
|
|
5
5
|
import { BranchMetadataFileManager, getBranchMetadataFileManager } from '../branch-metadata.js';
|
|
6
6
|
import { sanitizeBranchName } from '../paths/branch-name.js';
|
|
@@ -8,7 +8,7 @@ import { gitNetworkChildEnv } from '../git-manager.js';
|
|
|
8
8
|
import { getErrorMessage, redactCredentials } from '../utils/error.js';
|
|
9
9
|
import { isNonFastForwardRejection, isStaleLeaseRejection } from '../utils/git.js';
|
|
10
10
|
import { clearHistoryRewrittenMarker, readPublishedSha } from './history-rewrite.js';
|
|
11
|
-
import { writeWorkerStatus } from '
|
|
11
|
+
import { writeWorkerStatus } from '../task-queue/worker-status.js';
|
|
12
12
|
import { workerLog, workerLogError } from './log.js';
|
|
13
13
|
/**
|
|
14
14
|
* An error inherent to the task itself (malformed payload, unknown action):
|
|
@@ -21,24 +21,22 @@ export class PermanentTaskError extends Error {
|
|
|
21
21
|
* Classify a task failure as permanent (fail fast) or transient (retry).
|
|
22
22
|
*
|
|
23
23
|
* Transient — worth retrying with backoff:
|
|
24
|
-
* - network errors / anything without an HTTP status
|
|
25
|
-
* most push/fetch failures are connectivity or contention and the retry
|
|
26
|
-
* budget bounds the pathological cases
|
|
27
|
-
* - HTTP 408
|
|
28
|
-
* - HTTP 403
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* permanently and wedge the branch (`sync-failed`, no retry).
|
|
36
|
-
* - HTTP 5xx (server-side, usually recovers)
|
|
24
|
+
* - network errors / anything without an HTTP status, git failures included:
|
|
25
|
+
* most push/fetch failures are connectivity or contention, and the retry
|
|
26
|
+
* budget bounds the pathological cases;
|
|
27
|
+
* - HTTP 408 and 429;
|
|
28
|
+
* - HTTP 403 carrying a rate-limit signal (`isRateLimitSignal403`): GitHub
|
|
29
|
+
* returns 403, not 429, for both primary and secondary rate limits. The
|
|
30
|
+
* throttling plugin (github-service.ts's createCanopyOctokit) retries short
|
|
31
|
+
* waits, and this carve-out is the safety net for waits it gives up on and
|
|
32
|
+
* errors it never sees — without it a rate-limited
|
|
33
|
+
* push-and-create-or-update-pr task fails permanently and wedges the branch;
|
|
34
|
+
* - HTTP 5xx.
|
|
37
35
|
*
|
|
38
36
|
* Permanent — retrying the identical request cannot succeed:
|
|
39
|
-
* - PermanentTaskError (malformed payload, unknown action)
|
|
40
|
-
* - other HTTP 4xx (
|
|
41
|
-
* - plain HTTP 403 with no rate-limit signal: a real permission denial
|
|
37
|
+
* - PermanentTaskError (malformed payload, unknown action);
|
|
38
|
+
* - other HTTP 4xx (401/404/422): the request itself is bad;
|
|
39
|
+
* - plain HTTP 403 with no rate-limit signal: a real permission denial.
|
|
42
40
|
*/
|
|
43
41
|
export function isPermanentTaskFailure(err) {
|
|
44
42
|
if (err instanceof PermanentTaskError)
|
|
@@ -74,11 +72,10 @@ function getResponseHeaders(err) {
|
|
|
74
72
|
return headers;
|
|
75
73
|
}
|
|
76
74
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* containing "rate limit" (e.g. "You have exceeded a secondary rate limit").
|
|
75
|
+
* Whether a 403 is a GitHub rate-limit response rather than a plain permission
|
|
76
|
+
* denial. GitHub signals rate limiting on 403s three ways: the primary limit
|
|
77
|
+
* zeroes `x-ratelimit-remaining`, secondary limits often carry `retry-after`,
|
|
78
|
+
* and both produce a message containing "rate limit".
|
|
82
79
|
*/
|
|
83
80
|
function isRateLimitSignal403(err) {
|
|
84
81
|
const headers = getResponseHeaders(err);
|
|
@@ -110,49 +107,35 @@ function optionalString(payload, key, fallback) {
|
|
|
110
107
|
return typeof val === 'string' ? val : fallback;
|
|
111
108
|
}
|
|
112
109
|
/**
|
|
113
|
-
* Staleness threshold for recoverOrphanedTasks, derived from the
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* (60s timeout vs 5min threshold); the 5-minute floor preserves the
|
|
120
|
-
* long-standing default for a replacement instance's boot window.
|
|
110
|
+
* Staleness threshold for recoverOrphanedTasks, derived from the configured
|
|
111
|
+
* task timeout rather than fixed. The safety argument for running recovery on
|
|
112
|
+
* every poll cycle is "no legitimately in-flight task can be this old, because
|
|
113
|
+
* executeTaskWithTimeout bounds every attempt by taskTimeoutMs" -- true only
|
|
114
|
+
* while this threshold scales with taskTimeoutMs. The 5-minute floor covers a
|
|
115
|
+
* replacement instance's boot window.
|
|
121
116
|
*/
|
|
122
117
|
export function orphanRecoveryMaxAgeMs(ctx) {
|
|
123
118
|
return Math.max(5 * 60_000, ctx.taskTimeoutMs * 2);
|
|
124
119
|
}
|
|
125
120
|
/**
|
|
126
|
-
* Process queued tasks from Lambda.
|
|
127
|
-
* Polls .tasks/pending/ directory and executes each task.
|
|
128
|
-
* Processes up to maxTasksPerCycle tasks per invocation.
|
|
129
|
-
* Retries transient failures with exponential backoff.
|
|
121
|
+
* Process queued tasks from Lambda, up to maxTasksPerCycle per invocation.
|
|
130
122
|
*/
|
|
131
123
|
export async function processTaskQueue(ctx) {
|
|
132
124
|
if (!ctx.isRunning())
|
|
133
125
|
return;
|
|
134
126
|
// Recover tasks orphaned in processing/ on EVERY cycle, not only at boot
|
|
135
|
-
// (start()'s call
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
// efs-utils, mount EFS) takes roughly 2-4 minutes, well under
|
|
141
|
-
// recoverOrphanedTasks()'s 5-minute default staleness threshold - so
|
|
142
|
-
// THAT ONE boot-time call would see the just-orphaned file as "too
|
|
143
|
-
// fresh" and skip it, and nothing rescanned afterward: the task (and its
|
|
144
|
-
// branch's syncStatus) would be wedged forever. Re-checking every poll
|
|
145
|
-
// means the file's age eventually crosses the threshold and it gets
|
|
146
|
-
// recovered without operator intervention.
|
|
127
|
+
// (start()'s call). Instance replacement is routine -- CanopyCmsService's
|
|
128
|
+
// worker ASG rolls on every `cdk deploy` -- and a replacement's user-data
|
|
129
|
+
// takes roughly 2-4 minutes, well under the staleness threshold, so a
|
|
130
|
+
// boot-only call sees the just-orphaned file as "too fresh", skips it, and
|
|
131
|
+
// nothing rescans: the task and its branch's syncStatus wedge forever.
|
|
147
132
|
//
|
|
148
|
-
// Safe to run this often
|
|
149
|
-
// THIS process dequeues is completed, failed
|
|
150
|
-
// remove the processing/ file) within taskTimeoutMs
|
|
151
|
-
// threshold is derived from taskTimeoutMs (orphanRecoveryMaxAgeMs
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
-
// the worker's own still-in-flight task back to pending whenever an
|
|
155
|
-
// adopter configured taskTimeoutMs above ~5 minutes.
|
|
133
|
+
// Safe to run this often because executeTaskWithTimeout() guarantees every
|
|
134
|
+
// task THIS process dequeues is completed, failed or retried (all three
|
|
135
|
+
// remove the processing/ file) within taskTimeoutMs -- which is why the
|
|
136
|
+
// threshold is derived from taskTimeoutMs (orphanRecoveryMaxAgeMs) rather
|
|
137
|
+
// than fixed. A fixed 5 minutes would steal the worker's own in-flight task
|
|
138
|
+
// back to pending whenever an adopter configured a longer timeout.
|
|
156
139
|
const recovered = await recoverOrphanedTasks(ctx.taskDir, orphanRecoveryMaxAgeMs(ctx), ctx.log);
|
|
157
140
|
if (recovered > 0) {
|
|
158
141
|
workerLog(`Recovered ${recovered} orphaned task(s)`);
|
|
@@ -169,14 +152,13 @@ export async function processTaskQueue(ctx) {
|
|
|
169
152
|
catch (err) {
|
|
170
153
|
const message = getErrorMessage(err);
|
|
171
154
|
workerLogError(`Task ${task.id} (${task.action}) failed:`, message);
|
|
172
|
-
// [REDACT] task.error is persisted (pending/failed task JSON) and
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
//
|
|
155
|
+
// [REDACT] task.error is persisted (pending/failed task JSON) and served
|
|
156
|
+
// to the browser by the admin panel's Tasks tab -- a push failure's
|
|
157
|
+
// message can embed the bot token via buildGitHubUrl(). Console output
|
|
158
|
+
// above stays raw (journald/CloudWatch is trusted).
|
|
176
159
|
const persistedMessage = redactCredentials(message);
|
|
177
|
-
// DEP-L1: only transient failures
|
|
178
|
-
//
|
|
179
|
-
// just burn the retry budget on an identical doomed request.
|
|
160
|
+
// DEP-L1: only transient failures are worth retrying; a permanent one
|
|
161
|
+
// would burn the retry budget on an identical doomed request.
|
|
180
162
|
const permanent = isPermanentTaskFailure(err);
|
|
181
163
|
const retryCount = task.retryCount ?? 0;
|
|
182
164
|
const maxRetries = task.maxRetries ?? ctx.maxRetries;
|
|
@@ -191,26 +173,23 @@ export async function processTaskQueue(ctx) {
|
|
|
191
173
|
? ' Permanently failed (non-retryable error)'
|
|
192
174
|
: ` Permanently failed after ${maxRetries} retries`);
|
|
193
175
|
}
|
|
194
|
-
// The credential may have rotated
|
|
195
|
-
//
|
|
196
|
-
//
|
|
197
|
-
//
|
|
198
|
-
//
|
|
199
|
-
// another failure used the re-read within the floor (60s in core, five
|
|
200
|
-
// minutes for the AWS provider), in which case a publish that exhausts
|
|
201
|
-
// its retries first still fails.
|
|
176
|
+
// The credential may have rotated, and the next retry resolves
|
|
177
|
+
// buildGitHubUrl() afresh to pick a new token up. Without this a push
|
|
178
|
+
// meeting a revoked token spends its whole retry budget (5s/10s/20s
|
|
179
|
+
// backoff) waiting on the git-sync loop's refresh up to 5 minutes away,
|
|
180
|
+
// and fails permanently while the working token sits in the secret store.
|
|
202
181
|
//
|
|
203
|
-
// Ungated, and
|
|
182
|
+
// Ungated, and AFTER the outcome is recorded rather than before: the task
|
|
204
183
|
// is safely in pending/ or failed/ while a network read runs, and that
|
|
205
184
|
// read is bounded and never throws. See CmsWorker.refreshGitHubCredential.
|
|
206
185
|
await ctx.refreshGitHubCredential();
|
|
207
186
|
}
|
|
208
187
|
processed++;
|
|
209
188
|
}
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
//
|
|
213
|
-
//
|
|
189
|
+
// Only stamp/write when work actually happened this poll: otherwise every
|
|
190
|
+
// idle 5s poll would hit worker-status.json, an EFS write treadmill for no
|
|
191
|
+
// signal, since liveness is already covered by the lock heartbeat (see
|
|
192
|
+
// api/admin.ts's classifyWorkerLiveness).
|
|
214
193
|
if (processed > 0) {
|
|
215
194
|
const report = ctx.ensureStatusReport();
|
|
216
195
|
report.lastTaskCycleAt = new Date().toISOString();
|
|
@@ -219,21 +198,19 @@ export async function processTaskQueue(ctx) {
|
|
|
219
198
|
}
|
|
220
199
|
/**
|
|
221
200
|
* Execute a task bounded by taskTimeoutMs (DEP-H1). Two layers:
|
|
222
|
-
* -
|
|
223
|
-
* -
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
* pushBranchToGitHub additionally kills stalled git processes via
|
|
234
|
-
* simple-git's block timeout, so a hung push doesn't leak a process.
|
|
201
|
+
* - an AbortSignal cancels Octokit HTTP calls promptly;
|
|
202
|
+
* - a Promise.race rejects when the timeout fires, so work that cannot observe
|
|
203
|
+
* the signal (git subprocesses via simple-git, and a hung
|
|
204
|
+
* `ctx.buildGitHubUrl()` in pushBranchToGitHub) still fails the attempt and
|
|
205
|
+
* the worker moves on instead of stalling forever.
|
|
206
|
+
*
|
|
207
|
+
* A raced-out resolution is not CANCELLED: if it later settles, the abandoned
|
|
208
|
+
* push continues. On the App path the mint is separately bounded by
|
|
209
|
+
* gitTokenMintTimeoutMs, and git-sync.ts's two resolutions run on the sync loop
|
|
210
|
+
* and are not bounded by taskTimeoutMs at all. pushBranchToGitHub additionally
|
|
211
|
+
* kills stalled git processes via simple-git's block timeout.
|
|
235
212
|
*/
|
|
236
|
-
|
|
213
|
+
async function executeTaskWithTimeout(ctx, task) {
|
|
237
214
|
const controller = new AbortController();
|
|
238
215
|
const timer = setTimeout(() => controller.abort(), ctx.taskTimeoutMs);
|
|
239
216
|
try {
|
|
@@ -289,22 +266,19 @@ export async function executeTask(ctx, task, signal) {
|
|
|
289
266
|
return { prNumber };
|
|
290
267
|
}
|
|
291
268
|
case 'push-and-create-or-update-pr': {
|
|
292
|
-
// GIT-H1: idempotent create-or-update
|
|
293
|
-
//
|
|
294
|
-
//
|
|
295
|
-
//
|
|
296
|
-
//
|
|
297
|
-
//
|
|
298
|
-
//
|
|
299
|
-
// the draft->ready conversion live in one place.
|
|
269
|
+
// GIT-H1: idempotent create-or-update, so a retry after a crash (the task
|
|
270
|
+
// completed on GitHub but branch metadata never recorded the PR number)
|
|
271
|
+
// recovers the existing PR instead of hitting the 422 a blind
|
|
272
|
+
// `pulls.create` throws on a duplicate head+base. Delegates to the shared
|
|
273
|
+
// helper GitHubService's direct-API path also uses, so the
|
|
274
|
+
// list->tiebreak->update/create logic and the draft->ready conversion
|
|
275
|
+
// live in one place.
|
|
300
276
|
const branch = requireString(payload, 'branch');
|
|
301
277
|
const base = optionalString(payload, 'baseBranch', ctx.baseBranch);
|
|
302
278
|
// Defense-in-depth: refuse head===base even if the 'submittableBranch'
|
|
303
|
-
// API guard and the syncSubmitPr backstop were both
|
|
304
|
-
//
|
|
305
|
-
//
|
|
306
|
-
// the retry budget on an identical doomed request -- retrying can
|
|
307
|
-
// never make the branch not be the base branch.
|
|
279
|
+
// API guard and the syncSubmitPr backstop were both bypassed.
|
|
280
|
+
// PermanentTaskError, not a plain Error, so it fails immediately --
|
|
281
|
+
// retrying can never make the branch not be the base branch.
|
|
308
282
|
if (sanitizeBranchName(branch) === ctx.sanitizedBaseBranch) {
|
|
309
283
|
throw new PermanentTaskError(`Refusing to push-and-create-or-update-pr for "${branch}": it is the base branch -- submitting the base branch is never valid`);
|
|
310
284
|
}
|
|
@@ -370,7 +344,6 @@ export async function executeTask(ctx, task, signal) {
|
|
|
370
344
|
}
|
|
371
345
|
/**
|
|
372
346
|
* Update branch metadata after successful task completion.
|
|
373
|
-
* Writes PR URL/number and sets syncStatus to 'synced'.
|
|
374
347
|
*/
|
|
375
348
|
export async function updateBranchMetadata(ctx, task, result) {
|
|
376
349
|
const branch = typeof task.payload.branch === 'string' ? task.payload.branch : null;
|
|
@@ -388,22 +361,20 @@ export async function updateBranchMetadata(ctx, task, result) {
|
|
|
388
361
|
const updates = {
|
|
389
362
|
name: branch,
|
|
390
363
|
syncStatus: 'synced',
|
|
391
|
-
// save()'s merge only overwrites keys present in this update
|
|
392
|
-
//
|
|
393
|
-
//
|
|
394
|
-
// survive forever past this successful sync. Explicitly clear it,
|
|
395
|
-
// same pattern as rebaseFailure's PR-W2 M2 clearing elsewhere.
|
|
364
|
+
// save()'s merge only overwrites keys present in this update, so a prior
|
|
365
|
+
// syncFailureReason would survive this successful sync forever unless
|
|
366
|
+
// cleared explicitly (same pattern as rebaseFailure elsewhere).
|
|
396
367
|
syncFailureReason: undefined,
|
|
397
368
|
};
|
|
398
369
|
if (result.prUrl)
|
|
399
370
|
updates.pullRequestUrl = result.prUrl;
|
|
400
371
|
if (result.prNumber) {
|
|
401
372
|
updates.pullRequestNumber = result.prNumber;
|
|
402
|
-
// As soon as the PR exists the field
|
|
403
|
-
//
|
|
404
|
-
//
|
|
405
|
-
//
|
|
406
|
-
//
|
|
373
|
+
// As soon as the PR exists the field reads 'open', rather than staying
|
|
374
|
+
// absent until the next poll cycle observes it. Exception: the git-sync
|
|
375
|
+
// loop may have archived this branch (PR merged/closed) while the task
|
|
376
|
+
// was in flight, and a late completion must not downgrade that terminal
|
|
377
|
+
// state back to 'open'.
|
|
407
378
|
const current = await BranchMetadataFileManager.loadOnly(branchPath);
|
|
408
379
|
const terminal = current?.branch.status === 'archived' ||
|
|
409
380
|
current?.branch.pullRequestState === 'merged' ||
|
|
@@ -419,12 +390,11 @@ export async function updateBranchMetadata(ctx, task, result) {
|
|
|
419
390
|
}
|
|
420
391
|
}
|
|
421
392
|
/**
|
|
422
|
-
* Update branch metadata after permanent task failure.
|
|
423
|
-
*
|
|
424
|
-
*
|
|
425
|
-
* syncFailureReason, so the editor can show WHY, not just that it failed.
|
|
393
|
+
* Update branch metadata after permanent task failure. `error` is already
|
|
394
|
+
* redacted by the caller (see [REDACT] in processTaskQueue) and is recorded as
|
|
395
|
+
* syncFailureReason so the editor can show WHY, not just that it failed.
|
|
426
396
|
*/
|
|
427
|
-
|
|
397
|
+
async function updateBranchMetadataOnFailure(ctx, task, error) {
|
|
428
398
|
const branch = typeof task.payload.branch === 'string' ? task.payload.branch : null;
|
|
429
399
|
if (!branch)
|
|
430
400
|
return;
|
|
@@ -448,36 +418,33 @@ export async function updateBranchMetadataOnFailure(ctx, task, error) {
|
|
|
448
418
|
export async function pushBranchToGitHub(ctx, branch) {
|
|
449
419
|
const git = simpleGit({
|
|
450
420
|
baseDir: ctx.remoteGitPath,
|
|
451
|
-
// DEP-H1: kill the git process if it produces no output for
|
|
452
|
-
//
|
|
453
|
-
//
|
|
421
|
+
// DEP-H1: kill the git process if it produces no output for taskTimeoutMs
|
|
422
|
+
// (network stall, credential prompt) instead of letting it hang past the
|
|
423
|
+
// task timeout.
|
|
454
424
|
timeout: { block: ctx.taskTimeoutMs },
|
|
455
425
|
});
|
|
456
|
-
// Force stable (English) git output so isNonFastForwardRejection below
|
|
457
|
-
//
|
|
458
|
-
//
|
|
459
|
-
//
|
|
460
|
-
//
|
|
461
|
-
//
|
|
426
|
+
// Force stable (English) git output so isNonFastForwardRejection below can
|
|
427
|
+
// match it -- git's rejection text is gettext-translated, so a non-English
|
|
428
|
+
// host would silently turn that classifier into a no-op. gitNetworkChildEnv
|
|
429
|
+
// (NOT gitChildEnv) because this call talks to GitHub: it keeps ambient
|
|
430
|
+
// HTTPS_PROXY/GIT_SSL_*/GIT_SSH_COMMAND, which gitChildEnv's local-ops
|
|
431
|
+
// allowlist deliberately drops.
|
|
462
432
|
git.env(gitNetworkChildEnv());
|
|
463
|
-
// Resolve the tokenized URL ONCE, here
|
|
464
|
-
//
|
|
465
|
-
//
|
|
466
|
-
// -- resolution is async, and doing it per-push breaks two things:
|
|
433
|
+
// Resolve the tokenized URL ONCE, here: all three pushes below use this
|
|
434
|
+
// const and none calls ctx.buildGitHubUrl() again. A correctness
|
|
435
|
+
// requirement, not tidiness, since resolution is async:
|
|
467
436
|
//
|
|
468
|
-
// -
|
|
469
|
-
//
|
|
470
|
-
//
|
|
471
|
-
//
|
|
472
|
-
// PermanentTaskError
|
|
473
|
-
// carve-out exists to prevent.
|
|
437
|
+
// - the retry push sits INSIDE the stale-lease catch, and a resolution that
|
|
438
|
+
// threw there would replace the push error being classified, so neither
|
|
439
|
+
// isStaleLeaseRejection nor isNonFastForwardRejection would run and a
|
|
440
|
+
// genuinely diverged branch would be retried instead of raising
|
|
441
|
+
// PermanentTaskError;
|
|
474
442
|
// - readPublishedSha below captures remote.git's tip BEFORE the push, and
|
|
475
|
-
// that value decides whether the [SYNC-H1] marker
|
|
476
|
-
// An awaited resolution between the
|
|
477
|
-
//
|
|
443
|
+
// that value decides whether the [SYNC-H1] marker is cleared at the end.
|
|
444
|
+
// An awaited resolution in between widens the window in which the tip can
|
|
445
|
+
// move underneath that decision.
|
|
478
446
|
//
|
|
479
|
-
// It also means all three pushes provably carry the same credential
|
|
480
|
-
// than one per push with an expiry boundary somewhere in between.
|
|
447
|
+
// It also means all three pushes provably carry the same credential.
|
|
481
448
|
const githubUrl = await ctx.buildGitHubUrl();
|
|
482
449
|
// [SYNC-H1] If the rebase loop rewrote this branch's already-published
|
|
483
450
|
// history, GitHub still holds the commit it replaced, so an ordinary
|
|
@@ -507,23 +474,20 @@ export async function pushBranchToGitHub(ctx, branch) {
|
|
|
507
474
|
catch (err) {
|
|
508
475
|
const message = getErrorMessage(err);
|
|
509
476
|
// A refused lease means GitHub is not at the commit we rewrote, so the
|
|
510
|
-
// marker is stale --
|
|
511
|
-
//
|
|
512
|
-
//
|
|
513
|
-
//
|
|
514
|
-
//
|
|
515
|
-
// or the branch has since moved past it.
|
|
477
|
+
// marker is stale -- routine, not exceptional: tasks are re-run after a
|
|
478
|
+
// crash (recoverOrphanedTasks) and the marker survives any failure to
|
|
479
|
+
// clear it. The two benign shapes that reach here (GitHub already holds
|
|
480
|
+
// the rewritten history, or the branch moved past it) are ordinary
|
|
481
|
+
// fast-forwards a lease has no business blocking.
|
|
516
482
|
//
|
|
517
|
-
//
|
|
518
|
-
//
|
|
519
|
-
//
|
|
520
|
-
//
|
|
521
|
-
// the branch genuinely diverged.
|
|
483
|
+
// So retry PLAIN and let git adjudicate: a non-forced push succeeds if and
|
|
484
|
+
// only if it fast-forwards, so it can never destroy anything, with no
|
|
485
|
+
// ancestry check to get wrong and no extra round trip to read GitHub's
|
|
486
|
+
// tip. Only if THAT is also rejected has the branch genuinely diverged.
|
|
522
487
|
//
|
|
523
|
-
// (
|
|
524
|
-
//
|
|
525
|
-
//
|
|
526
|
-
// usually absorbed above and never even reaches this branch.)
|
|
488
|
+
// (git evaluates the lease only when it actually has an update to apply,
|
|
489
|
+
// so an up-to-date ref with a stale lease prints "Everything up-to-date",
|
|
490
|
+
// exits 0, and is absorbed above without reaching here.)
|
|
527
491
|
if (marker && isStaleLeaseRejection(message)) {
|
|
528
492
|
try {
|
|
529
493
|
await git.push(githubUrl, branch);
|
|
@@ -545,11 +509,11 @@ export async function pushBranchToGitHub(ctx, branch) {
|
|
|
545
509
|
return;
|
|
546
510
|
}
|
|
547
511
|
// An ordinary non-fast-forward rejection: GitHub has commits this
|
|
548
|
-
// deployment never published
|
|
549
|
-
// succeed (DEP-L1's git-failure-is-transient carve-out does NOT apply
|
|
550
|
-
//
|
|
551
|
-
//
|
|
552
|
-
//
|
|
512
|
+
// deployment never published, so retrying the identical push can never
|
|
513
|
+
// succeed (DEP-L1's git-failure-is-transient carve-out does NOT apply) and
|
|
514
|
+
// it fails fast instead of burning the retry budget. Deliberately does NOT
|
|
515
|
+
// advise renaming the branch: one reaching this point usually has an open
|
|
516
|
+
// PR, which renaming would orphan.
|
|
553
517
|
if (isNonFastForwardRejection(message)) {
|
|
554
518
|
throw new PermanentTaskError(`Push rejected for branch "${branch}": GitHub's tip is not what this deployment last ` +
|
|
555
519
|
`published, so the branch has diverged and needs reconciling. Something else moved it ` +
|