canopycms 0.0.68-int.98 → 0.1.0
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/CHANGELOG.md +2131 -0
- package/README.md +47 -63
- package/dist/ai/generate.d.ts +5 -0
- package/dist/ai/generate.js +244 -115
- package/dist/ai/index.d.ts +1 -1
- package/dist/ai/json-to-markdown.d.ts +21 -1
- package/dist/ai/json-to-markdown.js +120 -57
- package/dist/ai/references.d.ts +72 -0
- package/dist/ai/references.js +223 -0
- package/dist/ai/resolve-branch.js +9 -2
- package/dist/ai/to-plain-text.d.ts +17 -8
- package/dist/ai/to-plain-text.js +18 -15
- package/dist/ai/types.d.ts +84 -3
- package/dist/api/admin-branch-health.d.ts +24 -1
- package/dist/api/admin-branch-health.js +52 -20
- package/dist/api/admin.d.ts +23 -5
- package/dist/api/admin.js +36 -1
- package/dist/api/assets.js +88 -78
- package/dist/api/branch-create-window.d.ts +12 -0
- package/dist/api/branch-create-window.js +13 -0
- package/dist/api/branch-merge.d.ts +1 -1
- package/dist/api/branch-merge.js +1 -1
- package/dist/api/branch-review.d.ts +3 -3
- package/dist/api/branch-review.js +16 -7
- package/dist/api/branch-status.d.ts +16 -6
- package/dist/api/branch-status.js +57 -12
- package/dist/api/branch-withdraw.d.ts +2 -2
- package/dist/api/branch-withdraw.js +8 -3
- package/dist/api/branch.d.ts +25 -12
- package/dist/api/branch.js +164 -103
- package/dist/api/client.d.ts +78 -58
- package/dist/api/client.js +150 -117
- package/dist/api/comments.d.ts +12 -3
- package/dist/api/comments.js +118 -9
- package/dist/api/content.d.ts +9 -9
- package/dist/api/content.js +131 -22
- package/dist/api/entries-constants.d.ts +14 -3
- package/dist/api/entries-constants.js +14 -3
- package/dist/api/entries.d.ts +40 -2
- package/dist/api/entries.js +102 -6
- package/dist/api/github-sync.d.ts +19 -0
- package/dist/api/github-sync.js +50 -3
- package/dist/api/groups.d.ts +4 -4
- package/dist/api/groups.js +2 -1
- package/dist/api/guards.js +23 -3
- package/dist/api/index.d.ts +3 -1
- package/dist/api/index.js +1 -0
- package/dist/api/permissions.d.ts +21 -2
- package/dist/api/permissions.js +50 -3
- package/dist/api/request-deadline.d.ts +59 -0
- package/dist/api/request-deadline.js +73 -0
- package/dist/api/resolve-references.js +8 -7
- package/dist/api/route-builder.d.ts +14 -0
- package/dist/api/route-builder.js +14 -1
- package/dist/api/schema.d.ts +11 -9
- package/dist/api/schema.js +2 -0
- package/dist/api/settings-helpers.d.ts +5 -1
- package/dist/api/settings-helpers.js +10 -2
- package/dist/api/types.d.ts +18 -0
- package/dist/api/users-constants.d.ts +6 -0
- package/dist/api/users-constants.js +6 -0
- package/dist/assets/asset-url.d.ts +28 -16
- package/dist/assets/asset-url.js +51 -25
- package/dist/assets/finalize.js +3 -0
- package/dist/assets/index.d.ts +1 -1
- package/dist/assets/materialize.d.ts +153 -0
- package/dist/assets/materialize.js +402 -0
- package/dist/assets/store-local.d.ts +19 -5
- package/dist/assets/store-local.js +69 -10
- package/dist/assets/store-s3.d.ts +38 -7
- package/dist/assets/store-s3.js +128 -22
- package/dist/assets/transform-directives.d.ts +52 -13
- package/dist/assets/transform-directives.js +87 -27
- package/dist/assets/transform.d.ts +3 -3
- package/dist/assets/transform.js +13 -8
- package/dist/assets/types.d.ts +31 -4
- package/dist/auth/cache.d.ts +1 -1
- package/dist/auth/cache.js +1 -1
- package/dist/auth/caching-auth-plugin.d.ts +2 -0
- package/dist/auth/caching-auth-plugin.js +12 -2
- package/dist/auth/file-based-auth-cache.d.ts +8 -0
- package/dist/auth/file-based-auth-cache.js +18 -8
- package/dist/auth/person-name.d.ts +5 -0
- package/dist/auth/person-name.js +8 -0
- package/dist/auth/plugin.d.ts +10 -1
- package/dist/auth/types.d.ts +2 -0
- package/dist/auth/user-metadata-lookup.d.ts +21 -0
- package/dist/auth/user-metadata-lookup.js +116 -0
- package/dist/authorization/branch.d.ts +1 -1
- package/dist/authorization/branch.js +12 -13
- package/dist/authorization/groups/schema.d.ts +4 -4
- package/dist/authorization/helpers.d.ts +8 -0
- package/dist/authorization/helpers.js +8 -0
- package/dist/authorization/index.d.ts +1 -1
- package/dist/authorization/index.js +1 -1
- package/dist/authorization/protected-branch.d.ts +5 -4
- package/dist/authorization/protected-branch.js +7 -5
- package/dist/branch-health.d.ts +35 -8
- package/dist/branch-health.js +54 -18
- package/dist/branch-metadata-error.d.ts +27 -0
- package/dist/branch-metadata-error.js +23 -0
- package/dist/branch-metadata-file.d.ts +205 -24
- package/dist/branch-metadata-file.js +126 -25
- package/dist/branch-metadata.d.ts +45 -6
- package/dist/branch-metadata.js +142 -50
- package/dist/branch-provisioning.d.ts +167 -0
- package/dist/branch-provisioning.js +501 -0
- package/dist/branch-registry.d.ts +8 -0
- package/dist/branch-registry.js +61 -9
- package/dist/branch-schema-cache.d.ts +29 -12
- package/dist/branch-schema-cache.js +64 -21
- package/dist/branch-sparse.d.ts +23 -0
- package/dist/branch-sparse.js +118 -0
- package/dist/branch-workspace.d.ts +42 -3
- package/dist/branch-workspace.js +239 -100
- package/dist/build/asset-refs.d.ts +94 -0
- package/dist/build/asset-refs.js +267 -0
- package/dist/build/generate-ai-content.js +5 -0
- package/dist/build/inline-flight.d.ts +37 -0
- package/dist/build/inline-flight.js +142 -0
- package/dist/cli/asset-refs.d.ts +52 -0
- package/dist/cli/asset-refs.js +194 -0
- package/dist/cli/cli.d.ts +15 -1
- package/dist/cli/cli.js +8543 -3193
- package/dist/cli/configured-asset-store.d.ts +12 -0
- package/dist/cli/configured-asset-store.js +46 -0
- package/dist/cli/generate-ai-content.js +4244 -1072
- package/dist/cli/init.js +217 -126
- package/dist/cli/project-detect.d.ts +2 -0
- package/dist/cli/project-detect.js +2 -0
- package/dist/cli/template-files/Dockerfile.cms.template +13 -5
- package/dist/cli/template-files/cms-stack.ts.template +16 -13
- package/dist/client.d.ts +1 -2
- package/dist/client.js +1 -2
- package/dist/comment-store.d.ts +25 -0
- package/dist/comment-store.js +43 -8
- package/dist/config/flatten.js +2 -0
- package/dist/config/helpers.js +2 -2
- package/dist/config/index.d.ts +1 -1
- package/dist/config/schemas/config.d.ts +12 -29
- package/dist/config/schemas/config.js +9 -12
- package/dist/config/schemas/field.d.ts +3 -0
- package/dist/config/schemas/field.js +58 -4
- package/dist/config/schemas/media.d.ts +4 -13
- package/dist/config/schemas/media.js +5 -8
- package/dist/config/schemas/url.d.ts +2 -20
- package/dist/config/schemas/url.js +2 -25
- package/dist/config/types.d.ts +116 -22
- package/dist/config/types.js +3 -9
- package/dist/config/validation.d.ts +25 -4
- package/dist/config/validation.js +116 -3
- package/dist/content-id-index.js +2 -2
- package/dist/content-index-generation.d.ts +1 -1
- package/dist/content-index-generation.js +1 -1
- package/dist/content-listing.d.ts +10 -1
- package/dist/content-listing.js +22 -5
- package/dist/content-reader.d.ts +9 -0
- package/dist/content-reader.js +16 -11
- package/dist/content-store.d.ts +75 -12
- package/dist/content-store.js +249 -86
- package/dist/content-tree.js +2 -2
- package/dist/context.js +5 -2
- package/dist/dangling-reference-log.d.ts +17 -0
- package/dist/dangling-reference-log.js +29 -0
- package/dist/dev-content-watcher.d.ts +1 -1
- package/dist/dev-content-watcher.js +1 -1
- package/dist/editor/BranchManager.d.ts +23 -7
- package/dist/editor/BranchManager.js +119 -54
- package/dist/editor/CanopyEditor.d.ts +1 -1
- package/dist/editor/CanopyEditor.js +1 -2
- package/dist/editor/CommentsPanel.d.ts +14 -0
- package/dist/editor/CommentsPanel.js +68 -43
- package/dist/editor/Editor.d.ts +11 -5
- package/dist/editor/Editor.js +891 -218
- package/dist/editor/EditorAuthGate.d.ts +7 -1
- package/dist/editor/EditorAuthGate.js +41 -9
- package/dist/editor/EntryNavigator.d.ts +22 -0
- package/dist/editor/EntryNavigator.js +353 -105
- package/dist/editor/FormHeader.d.ts +25 -0
- package/dist/editor/FormHeader.js +82 -0
- package/dist/editor/FormRenderer.d.ts +27 -3
- package/dist/editor/FormRenderer.js +171 -76
- package/dist/editor/PreviewFrame.d.ts +40 -0
- package/dist/editor/PreviewFrame.js +215 -0
- package/dist/editor/PreviewPane.d.ts +47 -0
- package/dist/editor/PreviewPane.js +147 -0
- package/dist/editor/PreviewToolbarTools.d.ts +22 -0
- package/dist/editor/PreviewToolbarTools.js +73 -0
- package/dist/editor/admin/SystemHealthPanel.d.ts +2 -1
- package/dist/editor/admin/SystemHealthPanel.js +163 -33
- package/dist/editor/admin/useSystemHealth.d.ts +18 -0
- package/dist/editor/admin/useSystemHealth.js +70 -1
- package/dist/editor/branch-status.d.ts +17 -0
- package/dist/editor/branch-status.js +29 -0
- package/dist/editor/canopy-path.d.ts +9 -6
- package/dist/editor/canopy-path.js +8 -11
- package/dist/editor/client-reference-resolver.d.ts +43 -16
- package/dist/editor/client-reference-resolver.js +155 -64
- package/dist/editor/comments/BranchComments.d.ts +1 -1
- package/dist/editor/comments/BranchComments.js +2 -2
- package/dist/editor/comments/CloseRefusedNotice.d.ts +4 -0
- package/dist/editor/comments/CloseRefusedNotice.js +7 -0
- package/dist/editor/comments/CommentThreadsPopover.d.ts +47 -0
- package/dist/editor/comments/CommentThreadsPopover.js +274 -0
- package/dist/editor/comments/CommentWriteAlert.d.ts +11 -0
- package/dist/editor/comments/CommentWriteAlert.js +13 -0
- package/dist/editor/comments/EntryComments.d.ts +10 -4
- package/dist/editor/comments/EntryComments.js +14 -17
- package/dist/editor/comments/FieldWrapper.d.ts +18 -4
- package/dist/editor/comments/FieldWrapper.js +62 -28
- package/dist/editor/comments/InlineCommentThread.d.ts +9 -2
- package/dist/editor/comments/InlineCommentThread.js +11 -47
- package/dist/editor/comments/ThreadCarousel.d.ts +1 -1
- package/dist/editor/comments/ThreadCarousel.js +18 -21
- package/dist/editor/comments/ThreadReplyControls.d.ts +28 -0
- package/dist/editor/comments/ThreadReplyControls.js +92 -0
- package/dist/editor/comments/field-comment-context.d.ts +14 -0
- package/dist/editor/comments/field-comment-context.js +14 -0
- package/dist/editor/comments/form-comments.d.ts +48 -0
- package/dist/editor/comments/form-comments.js +178 -0
- package/dist/editor/comments/item-anchor-copy.d.ts +6 -0
- package/dist/editor/comments/item-anchor-copy.js +6 -0
- package/dist/editor/comments/move-focus-if-unmoved.d.ts +6 -0
- package/dist/editor/comments/move-focus-if-unmoved.js +11 -0
- package/dist/editor/comments/popover-placement.d.ts +18 -0
- package/dist/editor/comments/popover-placement.js +58 -0
- package/dist/editor/comments/use-tracked-writes.d.ts +16 -0
- package/dist/editor/comments/use-tracked-writes.js +53 -0
- package/dist/editor/components/BranchAccessList.d.ts +15 -0
- package/dist/editor/components/BranchAccessList.js +52 -0
- package/dist/editor/components/BranchLockBanner.d.ts +22 -0
- package/dist/editor/components/BranchLockBanner.js +39 -0
- package/dist/editor/components/BranchPill.d.ts +32 -0
- package/dist/editor/components/BranchPill.js +33 -0
- package/dist/editor/components/BranchesDrawer.d.ts +11 -0
- package/dist/editor/components/BranchesDrawer.js +5 -0
- package/dist/editor/components/ConfirmDeleteModal.d.ts +6 -1
- package/dist/editor/components/ConfirmDeleteModal.js +3 -2
- package/dist/editor/components/DestructiveMenuItem.d.ts +7 -0
- package/dist/editor/components/DestructiveMenuItem.js +8 -0
- package/dist/editor/components/EditorCrashScreen.d.ts +17 -0
- package/dist/editor/components/EditorCrashScreen.js +22 -0
- package/dist/editor/components/EditorErrorBoundary.d.ts +38 -0
- package/dist/editor/components/EditorErrorBoundary.js +40 -0
- package/dist/editor/components/EditorHeader.d.ts +56 -106
- package/dist/editor/components/EditorHeader.js +130 -131
- package/dist/editor/components/EditorRail.d.ts +49 -0
- package/dist/editor/components/EditorRail.js +65 -0
- package/dist/editor/components/EntryBreadcrumb.d.ts +33 -0
- package/dist/editor/components/EntryBreadcrumb.js +56 -0
- package/dist/editor/components/EntryCreateModal.d.ts +12 -7
- package/dist/editor/components/EntryCreateModal.js +51 -57
- package/dist/editor/components/NoEditPermissionNotice.d.ts +6 -5
- package/dist/editor/components/NoEditPermissionNotice.js +5 -4
- package/dist/editor/components/QuickOpenPalette.d.ts +22 -0
- package/dist/editor/components/QuickOpenPalette.js +66 -0
- package/dist/editor/components/ReadOnlyDraftNotice.d.ts +11 -0
- package/dist/editor/components/ReadOnlyDraftNotice.js +12 -0
- package/dist/editor/components/ReasonedMenuItem.d.ts +15 -0
- package/dist/editor/components/ReasonedMenuItem.js +15 -0
- package/dist/editor/components/ReferencedByList.d.ts +11 -0
- package/dist/editor/components/ReferencedByList.js +28 -0
- package/dist/editor/components/RelativeTime.d.ts +10 -0
- package/dist/editor/components/RelativeTime.js +10 -0
- package/dist/editor/components/RenameEntryModal.d.ts +9 -1
- package/dist/editor/components/RenameEntryModal.js +19 -31
- package/dist/editor/components/RetryToastMessage.d.ts +9 -0
- package/dist/editor/components/RetryToastMessage.js +6 -0
- package/dist/editor/components/SaveAllResult.d.ts +25 -0
- package/dist/editor/components/SaveAllResult.js +86 -0
- package/dist/editor/components/SaveSplitButton.d.ts +30 -0
- package/dist/editor/components/SaveSplitButton.js +108 -0
- package/dist/editor/components/StagedChangesDrawer.d.ts +39 -0
- package/dist/editor/components/StagedChangesDrawer.js +92 -0
- package/dist/editor/components/UnavailableEntryNotice.d.ts +6 -0
- package/dist/editor/components/UnavailableEntryNotice.js +9 -0
- package/dist/editor/components/UnavailableTypeMessage.d.ts +6 -0
- package/dist/editor/components/UnavailableTypeMessage.js +9 -0
- package/dist/editor/components/UndoToastMessage.d.ts +18 -0
- package/dist/editor/components/UndoToastMessage.js +10 -0
- package/dist/editor/components/UserBadge.d.ts +2 -5
- package/dist/editor/components/UserBadge.js +62 -33
- package/dist/editor/components/ValidationSummary.d.ts +14 -0
- package/dist/editor/components/ValidationSummary.js +24 -0
- package/dist/editor/components/index.d.ts +2 -2
- package/dist/editor/components/index.js +2 -2
- package/dist/editor/context/ApiClientContext.d.ts +8 -2
- package/dist/editor/context/ApiClientContext.js +19 -8
- package/dist/editor/context/AssetContext.d.ts +13 -35
- package/dist/editor/context/AssetContext.js +12 -31
- package/dist/editor/context/EditorStateContext.d.ts +4 -4
- package/dist/editor/context/EditorStateContext.js +4 -4
- package/dist/editor/context/SWRProvider.d.ts +3 -3
- package/dist/editor/context/SiteMdxAllowContext.d.ts +4 -0
- package/dist/editor/context/SiteMdxAllowContext.js +7 -0
- package/dist/editor/context/index.d.ts +2 -1
- package/dist/editor/context/index.js +2 -1
- package/dist/editor/contrast.d.ts +19 -0
- package/dist/editor/contrast.js +41 -0
- package/dist/editor/copy.d.ts +18 -0
- package/dist/editor/copy.js +18 -0
- package/dist/editor/editor-config.js +16 -0
- package/dist/editor/editor-utils.d.ts +34 -8
- package/dist/editor/editor-utils.js +42 -20
- package/dist/editor/entry-search.d.ts +20 -0
- package/dist/editor/entry-search.js +34 -0
- package/dist/editor/field-breadcrumb.d.ts +12 -0
- package/dist/editor/field-breadcrumb.js +85 -0
- package/dist/editor/field-props.d.ts +86 -0
- package/dist/editor/field-props.js +27 -0
- package/dist/editor/field-target.d.ts +30 -0
- package/dist/editor/field-target.js +77 -0
- package/dist/editor/fields/BlockField.d.ts +12 -0
- package/dist/editor/fields/BlockField.js +89 -73
- package/dist/editor/fields/CodeField.d.ts +2 -0
- package/dist/editor/fields/CodeField.js +6 -2
- package/dist/editor/fields/DateTimeField.d.ts +4 -29
- package/dist/editor/fields/DateTimeField.js +79 -41
- package/dist/editor/fields/ExpandAllButton.d.ts +6 -0
- package/dist/editor/fields/ExpandAllButton.js +4 -0
- package/dist/editor/fields/FieldCrashFallback.d.ts +17 -0
- package/dist/editor/fields/FieldCrashFallback.js +30 -0
- package/dist/editor/fields/FieldLabel.d.ts +37 -0
- package/dist/editor/fields/FieldLabel.js +19 -0
- package/dist/editor/fields/ImageField.d.ts +4 -0
- package/dist/editor/fields/ImageField.js +29 -14
- package/dist/editor/fields/InlineGroupField.js +4 -3
- package/dist/editor/fields/ItemList.d.ts +42 -0
- package/dist/editor/fields/ItemList.js +130 -0
- package/dist/editor/fields/MarkdownField.d.ts +32 -0
- package/dist/editor/fields/MarkdownField.js +223 -46
- package/dist/editor/fields/MdxImageDialog.js +1 -1
- package/dist/editor/fields/NumberField.d.ts +2 -0
- package/dist/editor/fields/NumberField.js +8 -5
- package/dist/editor/fields/NumberListField.d.ts +2 -0
- package/dist/editor/fields/NumberListField.js +19 -16
- package/dist/editor/fields/ObjectField.d.ts +2 -7
- package/dist/editor/fields/ObjectField.js +15 -5
- package/dist/editor/fields/ObjectListField.d.ts +29 -0
- package/dist/editor/fields/ObjectListField.js +57 -0
- package/dist/editor/fields/ReferenceField.d.ts +2 -0
- package/dist/editor/fields/ReferenceField.js +34 -9
- package/dist/editor/fields/SelectField.d.ts +2 -0
- package/dist/editor/fields/SelectField.js +11 -2
- package/dist/editor/fields/StringListField.d.ts +4 -1
- package/dist/editor/fields/StringListField.js +22 -8
- package/dist/editor/fields/TextField.d.ts +2 -0
- package/dist/editor/fields/TextField.js +6 -2
- package/dist/editor/fields/ToggleField.d.ts +2 -0
- package/dist/editor/fields/ToggleField.js +8 -3
- package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +1 -1
- package/dist/editor/fields/entry-link/InsertEntryLink.js +1 -1
- package/dist/editor/fields/form-expansion.d.ts +9 -0
- package/dist/editor/fields/form-expansion.js +2 -0
- package/dist/editor/fields/item-expansion.d.ts +15 -0
- package/dist/editor/fields/item-expansion.js +60 -0
- package/dist/editor/fields/list-item-keys.d.ts +8 -0
- package/dist/editor/fields/list-item-keys.js +50 -0
- package/dist/editor/fields/list-item-title.d.ts +20 -0
- package/dist/editor/fields/list-item-title.js +85 -0
- package/dist/editor/fields/markdown-export-options.d.ts +2 -0
- package/dist/editor/fields/markdown-export-options.js +8 -0
- package/dist/editor/fields/markdown-fidelity-visitors.d.ts +11 -0
- package/dist/editor/fields/markdown-fidelity-visitors.js +160 -0
- package/dist/editor/fields/mdx-jsx-support.d.ts +5 -1
- package/dist/editor/fields/mdx-jsx-support.js +157 -69
- package/dist/editor/fields/rich-text-failures.d.ts +5 -0
- package/dist/editor/fields/rich-text-failures.js +26 -0
- package/dist/editor/fields/toolbar-wrap.d.ts +7 -0
- package/dist/editor/fields/toolbar-wrap.js +35 -0
- package/dist/editor/form-outline.d.ts +13 -0
- package/dist/editor/form-outline.js +70 -0
- package/dist/editor/group-manager/GroupCard.d.ts +4 -1
- package/dist/editor/group-manager/GroupCard.js +12 -3
- package/dist/editor/group-manager/GroupForm.js +1 -1
- package/dist/editor/group-manager/InternalGroupsTab.d.ts +2 -1
- package/dist/editor/group-manager/InternalGroupsTab.js +4 -4
- package/dist/editor/group-manager/MemberList.d.ts +2 -1
- package/dist/editor/group-manager/MemberList.js +15 -4
- package/dist/editor/group-manager/hooks/useGroupState.d.ts +5 -0
- package/dist/editor/group-manager/hooks/useGroupState.js +30 -7
- package/dist/editor/group-manager/index.js +34 -5
- package/dist/editor/group-manager/types.d.ts +5 -2
- package/dist/editor/hooks/create-branch-request.d.ts +20 -0
- package/dist/editor/hooks/create-branch-request.js +54 -0
- package/dist/editor/hooks/save-all.d.ts +68 -0
- package/dist/editor/hooks/save-all.js +61 -0
- package/dist/editor/hooks/useBranchActions.d.ts +11 -1
- package/dist/editor/hooks/useBranchActions.js +42 -19
- package/dist/editor/hooks/useBranchManager.d.ts +21 -0
- package/dist/editor/hooks/useBranchManager.js +321 -125
- package/dist/editor/hooks/useBranchesData.d.ts +8 -4
- package/dist/editor/hooks/useBranchesData.js +9 -5
- package/dist/editor/hooks/useCommentSystem.d.ts +14 -2
- package/dist/editor/hooks/useCommentSystem.js +79 -55
- package/dist/editor/hooks/useCommentsData.d.ts +11 -7
- package/dist/editor/hooks/useCommentsData.js +20 -19
- package/dist/editor/hooks/useDraftManager.d.ts +77 -3
- package/dist/editor/hooks/useDraftManager.js +887 -94
- package/dist/editor/hooks/useEditorLayout.d.ts +53 -7
- package/dist/editor/hooks/useEditorLayout.js +98 -20
- package/dist/editor/hooks/useEntriesData.d.ts +2 -1
- package/dist/editor/hooks/useEntriesData.js +18 -4
- package/dist/editor/hooks/useEntryManager.d.ts +41 -2
- package/dist/editor/hooks/useEntryManager.js +227 -41
- package/dist/editor/hooks/useGroupManager.js +13 -16
- package/dist/editor/hooks/usePermissionManager.js +14 -6
- package/dist/editor/hooks/usePreviewMarks.d.ts +21 -0
- package/dist/editor/hooks/usePreviewMarks.js +33 -0
- package/dist/editor/hooks/useReferenceResolution.d.ts +10 -3
- package/dist/editor/hooks/useReferenceResolution.js +34 -177
- package/dist/editor/hooks/useSchemaManager.d.ts +25 -6
- package/dist/editor/hooks/useSchemaManager.js +97 -39
- package/dist/editor/hooks/useUserMetadata.d.ts +14 -4
- package/dist/editor/hooks/useUserMetadata.js +76 -47
- package/dist/editor/hooks/user-metadata-batcher.d.ts +8 -0
- package/dist/editor/hooks/user-metadata-batcher.js +33 -0
- package/dist/editor/media/AssetCard.d.ts +6 -7
- package/dist/editor/media/AssetCard.js +24 -31
- package/dist/editor/media/AssetListRow.d.ts +16 -0
- package/dist/editor/media/AssetListRow.js +41 -0
- package/dist/editor/media/CropStep.js +6 -1
- package/dist/editor/media/MediaLibrary.d.ts +4 -3
- package/dist/editor/media/MediaLibrary.js +11 -4
- package/dist/editor/media/MediaLibraryBody.d.ts +3 -3
- package/dist/editor/media/MediaLibraryBody.js +195 -80
- package/dist/editor/media/MediaLibrarySkeleton.d.ts +6 -0
- package/dist/editor/media/MediaLibrarySkeleton.js +14 -0
- package/dist/editor/media/crop-math.d.ts +3 -4
- package/dist/editor/media/crop-math.js +11 -22
- package/dist/editor/media/editor-image-src.d.ts +8 -0
- package/dist/editor/media/editor-image-src.js +10 -0
- package/dist/editor/media/format-bytes.d.ts +2 -0
- package/dist/editor/media/format-bytes.js +23 -0
- package/dist/editor/media/media-library-prefs.d.ts +23 -0
- package/dist/editor/media/media-library-prefs.js +49 -0
- package/dist/editor/media/media-library-view.d.ts +34 -0
- package/dist/editor/media/media-library-view.js +40 -0
- package/dist/editor/media/useAssetLibrary.d.ts +30 -0
- package/dist/editor/media/useAssetLibrary.js +126 -0
- package/dist/editor/media/useStableAssetOrder.d.ts +11 -0
- package/dist/editor/media/useStableAssetOrder.js +37 -0
- package/dist/editor/media/useThumbnailFailure.d.ts +6 -0
- package/dist/editor/media/useThumbnailFailure.js +16 -0
- package/dist/editor/permission-manager/GroupSelector.js +2 -2
- package/dist/editor/permission-manager/PermissionEditor.d.ts +1 -1
- package/dist/editor/permission-manager/PermissionEditor.js +15 -4
- package/dist/editor/permission-manager/PermissionLevelBadge.js +1 -1
- package/dist/editor/permission-manager/PermissionTree.d.ts +1 -1
- package/dist/editor/permission-manager/UserSelector.d.ts +1 -1
- package/dist/editor/permission-manager/UserSelector.js +3 -3
- package/dist/editor/permission-manager/index.js +12 -3
- package/dist/editor/permission-manager/types.d.ts +5 -2
- package/dist/editor/platform.d.ts +3 -0
- package/dist/editor/platform.js +9 -0
- package/dist/editor/preview-asset-base.d.ts +9 -0
- package/dist/editor/preview-asset-base.js +17 -0
- package/dist/editor/preview-bridge.d.ts +51 -27
- package/dist/editor/preview-bridge.js +103 -144
- package/dist/editor/preview-marks.d.ts +15 -0
- package/dist/editor/preview-marks.js +74 -0
- package/dist/editor/preview-path.d.ts +12 -0
- package/dist/editor/preview-path.js +45 -1
- package/dist/editor/preview-scale.d.ts +27 -0
- package/dist/editor/preview-scale.js +34 -0
- package/dist/editor/raw-asset-base.d.ts +5 -0
- package/dist/editor/raw-asset-base.js +14 -0
- package/dist/editor/relative-time.d.ts +4 -4
- package/dist/editor/relative-time.js +16 -8
- package/dist/editor/schema-editor/CollectionEditor.d.ts +20 -3
- package/dist/editor/schema-editor/CollectionEditor.js +361 -62
- package/dist/editor/schema-editor/EntryTypeEditor.d.ts +5 -1
- package/dist/editor/schema-editor/EntryTypeEditor.js +11 -6
- package/dist/editor/schema-editor/collection-draft.d.ts +22 -0
- package/dist/editor/schema-editor/collection-draft.js +40 -0
- package/dist/editor/schema-editor/index.d.ts +1 -1
- package/dist/editor/schema-label.d.ts +10 -0
- package/dist/editor/schema-label.js +17 -0
- package/dist/editor/settings-conflict.d.ts +5 -0
- package/dist/editor/settings-conflict.js +8 -0
- package/dist/editor/shell/ActivityRail.d.ts +37 -0
- package/dist/editor/shell/ActivityRail.js +91 -0
- package/dist/editor/shell/EditorShell.d.ts +17 -0
- package/dist/editor/shell/EditorShell.js +31 -0
- package/dist/editor/shell/PaneLayout.d.ts +28 -0
- package/dist/editor/shell/PaneLayout.js +116 -0
- package/dist/editor/shell/SidePanelHost.d.ts +35 -0
- package/dist/editor/shell/SidePanelHost.js +184 -0
- package/dist/editor/shell/TopBar.d.ts +12 -0
- package/dist/editor/shell/TopBar.js +14 -0
- package/dist/editor/shell/host-chrome.d.ts +16 -0
- package/dist/editor/shell/host-chrome.js +69 -0
- package/dist/editor/slug.d.ts +16 -0
- package/dist/editor/slug.js +43 -0
- package/dist/editor/theme.d.ts +2 -1
- package/dist/editor/theme.js +314 -13
- package/dist/editor/unanswered.d.ts +17 -0
- package/dist/editor/unanswered.js +26 -0
- package/dist/editor/unavailable-entry-type.d.ts +20 -0
- package/dist/editor/unavailable-entry-type.js +28 -0
- package/dist/editor/undo-removal.d.ts +57 -0
- package/dist/editor/undo-removal.js +163 -0
- package/dist/editor/user-display.d.ts +4 -0
- package/dist/editor/user-display.js +5 -0
- package/dist/editor/utils/confirm-modal.d.ts +8 -0
- package/dist/editor/utils/confirm-modal.js +12 -0
- package/dist/editor/utils/editor-errors.d.ts +19 -0
- package/dist/editor/utils/editor-errors.js +32 -0
- package/dist/editor/utils/focus-return.d.ts +56 -0
- package/dist/editor/utils/focus-return.js +106 -0
- package/dist/entry-link-resolver.d.ts +11 -1
- package/dist/entry-link-resolver.js +65 -5
- package/dist/entry-schema-registry.d.ts +3 -3
- package/dist/entry-schema-registry.js +7 -4
- package/dist/entry-schema.d.ts +49 -3
- package/dist/entry-schema.js +18 -0
- package/dist/git-manager.d.ts +172 -10
- package/dist/git-manager.js +449 -107
- package/dist/github-service.d.ts +39 -2
- package/dist/github-service.js +101 -7
- package/dist/http/handler.js +74 -9
- package/dist/http/types.d.ts +2 -0
- package/dist/http/worker-not-ready.d.ts +9 -4
- package/dist/http/worker-not-ready.js +59 -6
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/item-keys.d.ts +46 -0
- package/dist/item-keys.js +235 -0
- package/dist/operating-mode/editor-mode-check.d.ts +15 -0
- package/dist/operating-mode/editor-mode-check.js +24 -0
- package/dist/operating-mode/mode-env.d.ts +13 -14
- package/dist/operating-mode/mode-env.js +13 -14
- package/dist/operating-mode/types.d.ts +2 -2
- package/dist/paths/branch.d.ts +0 -1
- package/dist/paths/branch.js +1 -8
- package/dist/paths/index.d.ts +1 -1
- package/dist/paths/index.js +1 -1
- package/dist/paths/validation.js +0 -2
- package/dist/preview.d.ts +8 -0
- package/dist/preview.js +7 -0
- package/dist/reference-resolver.js +1 -0
- package/dist/resolve-canopy-user.d.ts +1 -1
- package/dist/resolve-canopy-user.js +1 -1
- package/dist/schema/meta-loader.d.ts +18 -8
- package/dist/schema/meta-loader.js +42 -9
- package/dist/schema/registry-fingerprint.d.ts +14 -0
- package/dist/schema/registry-fingerprint.js +63 -0
- package/dist/schema/resolver.d.ts +7 -4
- package/dist/schema/resolver.js +7 -6
- package/dist/schema/schema-store.d.ts +7 -10
- package/dist/schema/schema-store.js +13 -11
- package/dist/schema/schema-unavailable-error.d.ts +11 -0
- package/dist/schema/schema-unavailable-error.js +15 -0
- package/dist/schema/types.d.ts +22 -0
- package/dist/schema-registry-record.d.ts +35 -0
- package/dist/schema-registry-record.js +134 -0
- package/dist/server.d.ts +79 -9
- package/dist/server.js +62 -8
- package/dist/services.d.ts +33 -5
- package/dist/services.js +155 -37
- package/dist/settings-workspace.d.ts +23 -3
- package/dist/settings-workspace.js +159 -45
- package/dist/stamp-on-publish.d.ts +36 -0
- package/dist/stamp-on-publish.js +71 -0
- package/dist/static/index.d.ts +58 -5
- package/dist/static/index.js +133 -3
- package/dist/static/seo.d.ts +5 -5
- package/dist/static/seo.js +5 -5
- package/dist/submission-attribution.d.ts +8 -0
- package/dist/submission-attribution.js +22 -0
- package/dist/system-users.d.ts +12 -0
- package/dist/system-users.js +12 -0
- package/dist/task-queue/cms-task-queue.d.ts +1 -1
- package/dist/task-queue/cms-task-queue.js +1 -1
- package/dist/task-queue/index.d.ts +1 -1
- package/dist/task-queue/index.js +1 -1
- package/dist/task-queue/task-queue.d.ts +6 -0
- package/dist/task-queue/task-queue.js +29 -0
- package/dist/task-queue/worker-status.d.ts +35 -9
- package/dist/task-queue/worker-status.js +84 -17
- package/dist/types.d.ts +90 -9
- package/dist/url-collision.js +3 -3
- package/dist/url-exclusivity-fixtures.d.ts +8 -1
- package/dist/url-exclusivity-fixtures.js +11 -1
- package/dist/user.js +2 -1
- package/dist/utils/atomic-write.js +2 -1
- package/dist/utils/base-branch.d.ts +13 -0
- package/dist/utils/base-branch.js +23 -0
- package/dist/utils/content-serialize.d.ts +15 -7
- package/dist/utils/content-serialize.js +353 -51
- package/dist/utils/content-write-lock.d.ts +6 -1
- package/dist/utils/content-write-lock.js +21 -6
- package/dist/utils/debug.d.ts +1 -1
- package/dist/utils/debug.js +5 -3
- package/dist/utils/error.js +13 -2
- package/dist/utils/escape-text.d.ts +7 -0
- package/dist/utils/escape-text.js +27 -0
- package/dist/utils/fs.d.ts +12 -4
- package/dist/utils/fs.js +18 -5
- package/dist/utils/git.d.ts +21 -1
- package/dist/utils/git.js +63 -8
- package/dist/utils/json-source-splice.d.ts +14 -0
- package/dist/utils/json-source-splice.js +120 -0
- package/dist/utils/markdown-body-splice.d.ts +39 -0
- package/dist/utils/markdown-body-splice.js +421 -0
- package/dist/utils/occ-json-write.js +18 -12
- package/dist/utils/provision-log.d.ts +25 -0
- package/dist/utils/provision-log.js +49 -0
- package/dist/utils/provisioning-lock.d.ts +32 -1
- package/dist/utils/provisioning-lock.js +78 -32
- package/dist/utils/sanitize-href.d.ts +9 -23
- package/dist/utils/sanitize-href.js +14 -28
- package/dist/utils/title-field.d.ts +10 -0
- package/dist/utils/title-field.js +47 -0
- package/dist/utils/yaml-source-splice.d.ts +58 -0
- package/dist/utils/yaml-source-splice.js +515 -0
- package/dist/validation/block-structural-keys.d.ts +1 -1
- package/dist/validation/block-structural-keys.js +1 -1
- package/dist/validation/deletion-checker.d.ts +21 -29
- package/dist/validation/deletion-checker.js +41 -117
- package/dist/validation/entry-validator.d.ts +6 -10
- package/dist/validation/entry-validator.js +19 -26
- package/dist/validation/field-traversal.d.ts +22 -0
- package/dist/validation/field-traversal.js +39 -8
- package/dist/validation/markdown-safety.d.ts +68 -0
- package/dist/validation/markdown-safety.js +596 -0
- package/dist/validation/mdx-allowlist.d.ts +55 -0
- package/dist/validation/mdx-allowlist.js +183 -0
- package/dist/validation/reference-validator.d.ts +2 -0
- package/dist/validation/reference-validator.js +3 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker/branch-policy.d.ts +124 -0
- package/dist/worker/branch-policy.js +243 -0
- package/dist/worker/bundle-header.d.ts +117 -0
- package/dist/worker/bundle-header.js +253 -0
- package/dist/worker/cms-worker.d.ts +236 -142
- package/dist/worker/cms-worker.js +772 -285
- package/dist/worker/gateway-egress.d.ts +43 -0
- package/dist/worker/gateway-egress.js +209 -0
- package/dist/worker/gateway-instance.d.ts +42 -0
- package/dist/worker/gateway-instance.js +129 -0
- package/dist/worker/git-process.d.ts +81 -0
- package/dist/worker/git-process.js +234 -0
- package/dist/worker/git-sync.d.ts +34 -17
- package/dist/worker/git-sync.js +394 -131
- package/dist/worker/github-auth.d.ts +9 -9
- package/dist/worker/github-auth.js +13 -15
- package/dist/worker/github-gateway-http.d.ts +62 -0
- package/dist/worker/github-gateway-http.js +977 -0
- package/dist/worker/github-gateway-wire.d.ts +590 -0
- package/dist/worker/github-gateway-wire.js +488 -0
- package/dist/worker/github-gateway.d.ts +238 -0
- package/dist/worker/github-gateway.js +726 -0
- package/dist/worker/github-mirror-upkeep.d.ts +75 -0
- package/dist/worker/github-mirror-upkeep.js +266 -0
- package/dist/worker/github-mirror.d.ts +364 -0
- package/dist/worker/github-mirror.js +1030 -0
- package/dist/worker/github-transfer.d.ts +56 -0
- package/dist/worker/github-transfer.js +444 -0
- package/dist/worker/history-rewrite.d.ts +4 -5
- package/dist/worker/history-rewrite.js +12 -17
- package/dist/worker/provisioned-workspace.d.ts +5 -5
- package/dist/worker/provisioned-workspace.js +5 -5
- package/dist/worker/rebase.d.ts +1 -1
- package/dist/worker/rebase.js +58 -54
- package/dist/worker/remote-git-maintenance.d.ts +3 -0
- package/dist/worker/remote-git-maintenance.js +12 -0
- package/dist/worker/schema-gate.d.ts +49 -0
- package/dist/worker/schema-gate.js +226 -0
- package/dist/worker/self-checks.d.ts +107 -0
- package/dist/worker/self-checks.js +358 -0
- package/dist/worker/shared-repo-git.d.ts +96 -0
- package/dist/worker/shared-repo-git.js +459 -0
- package/dist/worker/sparse-cone.d.ts +20 -0
- package/dist/worker/sparse-cone.js +136 -0
- package/dist/worker/stale-mirror.d.ts +82 -0
- package/dist/worker/stale-mirror.js +130 -0
- package/dist/worker/task-runner.d.ts +5 -3
- package/dist/worker/task-runner.js +287 -186
- package/dist/worker/worker-context.d.ts +36 -37
- package/package.json +35 -7
- package/dist/editor/EditorPanes.d.ts +0 -10
- package/dist/editor/EditorPanes.js +0 -98
- package/dist/editor/components/EditorFooter.d.ts +0 -11
- package/dist/editor/components/EditorFooter.js +0 -9
- package/dist/editor/components/EditorSidebar.d.ts +0 -67
- package/dist/editor/components/EditorSidebar.js +0 -22
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type GitHubGateway, type GitHubPushOutcome, type GitHubPushRequest } from './github-gateway.js';
|
|
2
|
+
/** What the transfers need from the worker. */
|
|
3
|
+
export interface TransferContext {
|
|
4
|
+
github(): GitHubGateway;
|
|
5
|
+
readonly remoteGitPath: string;
|
|
6
|
+
/**
|
|
7
|
+
* The inactivity bound on each git here run through worker/git-process.ts; its simple-git calls
|
|
8
|
+
* (init, for-each-ref, rev-parse) carry none.
|
|
9
|
+
*/
|
|
10
|
+
readonly taskTimeoutMs: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Fetch every GitHub branch into `remote.git`'s tracking namespace (`GITHUB_TRACKING_REF_PREFIX`),
|
|
14
|
+
* which then holds exactly GitHub's branches. `have` is every tip `remote.git` holds, so the
|
|
15
|
+
* bundle carries only what it lacks. Returns GitHub's branches, and what an operator must fix in
|
|
16
|
+
* remote.git for the namespace to keep up, if anything (see {@link moveTrackingRefs}).
|
|
17
|
+
*/
|
|
18
|
+
export declare function fetchGitHubIntoRemoteGit(ctx: TransferContext, signal?: AbortSignal): Promise<{
|
|
19
|
+
refs: ReadonlyMap<string, string>;
|
|
20
|
+
needsOperator: string | null;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Seed the new bare repository at `gitDir`, which must not exist yet, with every GitHub branch as
|
|
24
|
+
* `refs/heads/*`, and return those branches. Refuses, before creating anything, when GitHub has no
|
|
25
|
+
* `baseBranch`.
|
|
26
|
+
*/
|
|
27
|
+
export declare function seedFromGitHub(ctx: TransferContext, gitDir: string, baseBranch: string, signal?: AbortSignal): Promise<ReadonlyMap<string, string>>;
|
|
28
|
+
/**
|
|
29
|
+
* Of `ids`, the ones that are not a commit reachable from one of `tips` in the repository at
|
|
30
|
+
* `gitDir`, an annotated tag counting as the commit it points at. One `cat-file --batch-check`
|
|
31
|
+
* and one walk, so the answer is exactly what that repository holds.
|
|
32
|
+
*/
|
|
33
|
+
export declare function unreachableFrom(ctx: TransferContext, gitDir: string, ids: readonly string[], tips: readonly string[]): Promise<Set<string>>;
|
|
34
|
+
/** A push to GitHub of the commit `readSha` finds, as {@link pushToGitHub} takes it. */
|
|
35
|
+
export interface TransferPushRequest extends Omit<GitHubPushRequest, 'sha' | 'prerequisites'> {
|
|
36
|
+
/**
|
|
37
|
+
* Branches whose GitHub tips, as `remote.git`'s tracking namespace holds them, a bundle of
|
|
38
|
+
* `branch` is built on: the branch itself, and the base for a content branch. Missing ones are
|
|
39
|
+
* skipped.
|
|
40
|
+
*/
|
|
41
|
+
prerequisiteBranches: readonly string[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Push the commit `readSha` reads to GitHub, and resolve with it and what the push did. The push
|
|
45
|
+
* is asked for without objects first, which covers everything GitHub already holds; only when the
|
|
46
|
+
* gateway answers `need-objects` is a bundle built from `remote.git` and sent.
|
|
47
|
+
*
|
|
48
|
+
* The bundle must say what was read: its one head is `<sha> refs/heads/<branch>`, checked as it
|
|
49
|
+
* starts to stream. When the Lambda moved the branch in between, the push starts again from
|
|
50
|
+
* `readSha` (the caller's lease and history-rewrite marker are keyed to that commit), at most
|
|
51
|
+
* {@link MAX_PUSH_RESTARTS} times, so a ref moved on every pass cannot hold a task for ever.
|
|
52
|
+
*/
|
|
53
|
+
export declare function pushToGitHub(ctx: TransferContext, request: TransferPushRequest, readSha: () => Promise<string>, signal?: AbortSignal): Promise<{
|
|
54
|
+
sha: string;
|
|
55
|
+
outcome: GitHubPushOutcome;
|
|
56
|
+
}>;
|
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { Readable } from 'node:stream';
|
|
4
|
+
import { GITHUB_TRACKING_REF_PREFIX } from '../git-manager.js';
|
|
5
|
+
import { getErrorMessage } from '../utils/error.js';
|
|
6
|
+
import { BundleHeaderReader, hasOnlyHead } from './bundle-header.js';
|
|
7
|
+
import { runGit, spawnGit } from './git-process.js';
|
|
8
|
+
import { MAX_FETCH_HAVE, } from './github-gateway.js';
|
|
9
|
+
import { GitHubTransientError } from './github-mirror.js';
|
|
10
|
+
import { workerLogWarn } from './log.js';
|
|
11
|
+
import { sharedRepoGit, sharedRepoProcessOptions } from './shared-repo-git.js';
|
|
12
|
+
/**
|
|
13
|
+
* The worker's side of moving objects between `remote.git` and GitHub, through the GitHub
|
|
14
|
+
* gateway (worker/github-gateway.ts), which never runs git in, or opens a path in, anything the
|
|
15
|
+
* Lambda can write. Objects cross as git bundles:
|
|
16
|
+
* - **GitHub → remote.git:** the gateway answers a fetch with GitHub's branches and a bundle of
|
|
17
|
+
* what `remote.git` lacks; the worker unbundles it here, under the pins, and moves the tracking
|
|
18
|
+
* namespace to those branches itself ({@link fetchGitHubIntoRemoteGit}, {@link seedFromGitHub});
|
|
19
|
+
* - **remote.git → GitHub:** the worker asks for the push first, and only when the gateway answers
|
|
20
|
+
* `need-objects` builds a bundle here and sends it ({@link pushToGitHub}).
|
|
21
|
+
*
|
|
22
|
+
* The worker does not fsck what it receives: its peer is the gateway, and the objects came from
|
|
23
|
+
* GitHub. The gateway checks every object it is sent.
|
|
24
|
+
*/
|
|
25
|
+
const GIT_ZERO_OID = '0000000000000000000000000000000000000000';
|
|
26
|
+
/** How many times a push restarts because the branch moved while its bundle was built. */
|
|
27
|
+
const MAX_PUSH_RESTARTS = 3;
|
|
28
|
+
/**
|
|
29
|
+
* Fetch every GitHub branch into `remote.git`'s tracking namespace (`GITHUB_TRACKING_REF_PREFIX`),
|
|
30
|
+
* which then holds exactly GitHub's branches. `have` is every tip `remote.git` holds, so the
|
|
31
|
+
* bundle carries only what it lacks. Returns GitHub's branches, and what an operator must fix in
|
|
32
|
+
* remote.git for the namespace to keep up, if anything (see {@link moveTrackingRefs}).
|
|
33
|
+
*/
|
|
34
|
+
export async function fetchGitHubIntoRemoteGit(ctx, signal) {
|
|
35
|
+
const gitDir = ctx.remoteGitPath;
|
|
36
|
+
const { refs, bundleId } = await ctx.github().fetch({ have: await haveOf(gitDir) }, signal);
|
|
37
|
+
if (bundleId !== null)
|
|
38
|
+
await unbundle(ctx, gitDir, bundleId, signal);
|
|
39
|
+
const needsOperator = await moveTrackingRefs(ctx, gitDir, refs, signal);
|
|
40
|
+
return { refs, needsOperator };
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Seed the new bare repository at `gitDir`, which must not exist yet, with every GitHub branch as
|
|
44
|
+
* `refs/heads/*`, and return those branches. Refuses, before creating anything, when GitHub has no
|
|
45
|
+
* `baseBranch`.
|
|
46
|
+
*/
|
|
47
|
+
export async function seedFromGitHub(ctx, gitDir, baseBranch, signal) {
|
|
48
|
+
const { refs, bundleId } = await ctx.github().fetch({ have: [] }, signal);
|
|
49
|
+
if (!refs.has(baseBranch))
|
|
50
|
+
throw new Error(`GitHub has no branch '${baseBranch}'`);
|
|
51
|
+
await fs.mkdir(gitDir);
|
|
52
|
+
await sharedRepoGit(gitDir, 'bare').raw(['init', '--quiet', '--bare']);
|
|
53
|
+
if (bundleId !== null)
|
|
54
|
+
await unbundle(ctx, gitDir, bundleId, signal);
|
|
55
|
+
await updateRefs(ctx, gitDir, [...refs].map(([name, sha]) => ({ ref: `refs/heads/${name}`, to: sha, from: GIT_ZERO_OID })), signal);
|
|
56
|
+
return refs;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Of `ids`, the ones that are not a commit reachable from one of `tips` in the repository at
|
|
60
|
+
* `gitDir`, an annotated tag counting as the commit it points at. One `cat-file --batch-check`
|
|
61
|
+
* and one walk, so the answer is exactly what that repository holds.
|
|
62
|
+
*/
|
|
63
|
+
export async function unreachableFrom(ctx, gitDir, ids, tips) {
|
|
64
|
+
const unreachable = new Set();
|
|
65
|
+
const peeled = new Map();
|
|
66
|
+
const valid = ids.filter((id) => {
|
|
67
|
+
if (OBJECT_ID.test(id))
|
|
68
|
+
return true;
|
|
69
|
+
unreachable.add(id);
|
|
70
|
+
return false;
|
|
71
|
+
});
|
|
72
|
+
if (valid.length > 0) {
|
|
73
|
+
const lines = (await runGit(['cat-file', '--batch-check=%(objectname) %(objecttype)', '--end-of-options'], {
|
|
74
|
+
...sharedRepoProcessOptions(gitDir, 'bare'),
|
|
75
|
+
stdin: valid.map((id) => `${id}^{commit}\n`).join(''),
|
|
76
|
+
inactivityTimeoutMs: ctx.taskTimeoutMs,
|
|
77
|
+
})).split('\n');
|
|
78
|
+
valid.forEach((id, i) => {
|
|
79
|
+
const match = /^([0-9a-f]{40}|[0-9a-f]{64}) commit$/.exec(lines[i] ?? '');
|
|
80
|
+
if (match)
|
|
81
|
+
peeled.set(id, match[1]);
|
|
82
|
+
else
|
|
83
|
+
unreachable.add(id);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const commits = [...new Set(peeled.values())];
|
|
87
|
+
if (commits.length > 0) {
|
|
88
|
+
const notReached = new Set((await runGit(['rev-list', '--stdin', '--end-of-options'], {
|
|
89
|
+
...sharedRepoProcessOptions(gitDir, 'bare'),
|
|
90
|
+
stdin: [...commits, ...tips.map((tip) => `^${tip}`)].map((l) => `${l}\n`).join(''),
|
|
91
|
+
inactivityTimeoutMs: ctx.taskTimeoutMs,
|
|
92
|
+
}))
|
|
93
|
+
.split('\n')
|
|
94
|
+
.filter(Boolean));
|
|
95
|
+
for (const [id, commit] of peeled)
|
|
96
|
+
if (notReached.has(commit))
|
|
97
|
+
unreachable.add(id);
|
|
98
|
+
}
|
|
99
|
+
return unreachable;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Push the commit `readSha` reads to GitHub, and resolve with it and what the push did. The push
|
|
103
|
+
* is asked for without objects first, which covers everything GitHub already holds; only when the
|
|
104
|
+
* gateway answers `need-objects` is a bundle built from `remote.git` and sent.
|
|
105
|
+
*
|
|
106
|
+
* The bundle must say what was read: its one head is `<sha> refs/heads/<branch>`, checked as it
|
|
107
|
+
* starts to stream. When the Lambda moved the branch in between, the push starts again from
|
|
108
|
+
* `readSha` (the caller's lease and history-rewrite marker are keyed to that commit), at most
|
|
109
|
+
* {@link MAX_PUSH_RESTARTS} times, so a ref moved on every pass cannot hold a task for ever.
|
|
110
|
+
*/
|
|
111
|
+
export async function pushToGitHub(ctx, request, readSha, signal) {
|
|
112
|
+
const { prerequisiteBranches, ...rest } = request;
|
|
113
|
+
for (let restarts = 0;; restarts++) {
|
|
114
|
+
const sha = await readSha();
|
|
115
|
+
const prerequisites = await trackingTips(ctx.remoteGitPath, prerequisiteBranches);
|
|
116
|
+
const ask = { ...rest, sha, prerequisites };
|
|
117
|
+
const first = await ctx.github().push(ask, undefined, signal);
|
|
118
|
+
if (first.kind === 'pushed')
|
|
119
|
+
return { sha, outcome: outcomeOf(first) };
|
|
120
|
+
const bundle = await startBundle(ctx, request.branch, sha, first.usable, signal);
|
|
121
|
+
if (bundle === 'moved') {
|
|
122
|
+
if (restarts < MAX_PUSH_RESTARTS)
|
|
123
|
+
continue;
|
|
124
|
+
throw new GitHubTransientError('ref-kept-moving', `${request.branch} moved in remote.git while its push was being prepared, ` +
|
|
125
|
+
`${MAX_PUSH_RESTARTS + 1} times in a row`);
|
|
126
|
+
}
|
|
127
|
+
// Nothing to bundle: what is left to send, GitHub has. A second `need-objects` would only
|
|
128
|
+
// ask for the same again.
|
|
129
|
+
const second = await (bundle === 'empty'
|
|
130
|
+
? ctx.github().push(ask, undefined, signal)
|
|
131
|
+
: sendBundle(ctx, ask, bundle, signal));
|
|
132
|
+
if (second.kind === 'pushed')
|
|
133
|
+
return { sha, outcome: outcomeOf(second) };
|
|
134
|
+
throw new GitHubTransientError('objects-still-needed', `The GitHub gateway still lacks objects for ${request.branch} after they were offered`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function outcomeOf(answer) {
|
|
138
|
+
const { kind: _kind, ...outcome } = answer;
|
|
139
|
+
return outcome;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Start `bundle create` of `refs/heads/<branch>` in `remote.git`, built on `usable`, and read its
|
|
143
|
+
* header: `moved` when its head is not `sha`, `empty` when git refused an empty bundle (GitHub
|
|
144
|
+
* already has every commit it would hold), else the bundle to send, each prerequisite's comment
|
|
145
|
+
* shortened to what the gateway takes.
|
|
146
|
+
*/
|
|
147
|
+
async function startBundle(ctx, branch, sha, usable, signal) {
|
|
148
|
+
const proc = spawnGit(['bundle', 'create', '--progress', '--end-of-options', '-', `refs/heads/${branch}`, '--stdin'], {
|
|
149
|
+
...sharedRepoProcessOptions(ctx.remoteGitPath, 'bare'),
|
|
150
|
+
stdin: usable
|
|
151
|
+
.filter((id) => OBJECT_ID.test(id))
|
|
152
|
+
.map((id) => `^${id}\n`)
|
|
153
|
+
.join(''),
|
|
154
|
+
inactivityTimeoutMs: ctx.taskTimeoutMs,
|
|
155
|
+
signal,
|
|
156
|
+
});
|
|
157
|
+
const chunks = proc.stdout[Symbol.asyncIterator]();
|
|
158
|
+
// A prerequisite's comment is a commit subject, any length; the gateway takes only a short one.
|
|
159
|
+
const reader = new BundleHeaderReader('shorten');
|
|
160
|
+
let unreadable = null;
|
|
161
|
+
try {
|
|
162
|
+
for (;;) {
|
|
163
|
+
const next = await chunks.next();
|
|
164
|
+
if (next.done)
|
|
165
|
+
break;
|
|
166
|
+
let read;
|
|
167
|
+
try {
|
|
168
|
+
read = reader.push(next.value);
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
unreadable = err;
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
if (read === null)
|
|
175
|
+
continue;
|
|
176
|
+
if (!hasOnlyHead(read.header, sha, branch)) {
|
|
177
|
+
proc.kill('the branch moved');
|
|
178
|
+
return 'moved';
|
|
179
|
+
}
|
|
180
|
+
const { bytes, rest: first } = read;
|
|
181
|
+
const stream = Readable.from((async function* () {
|
|
182
|
+
yield bytes;
|
|
183
|
+
if (first.length > 0)
|
|
184
|
+
yield first;
|
|
185
|
+
for (;;) {
|
|
186
|
+
const rest = await chunks.next();
|
|
187
|
+
if (rest.done)
|
|
188
|
+
return;
|
|
189
|
+
yield rest.value;
|
|
190
|
+
}
|
|
191
|
+
})());
|
|
192
|
+
return { process: proc, stream };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
throw await causeOf(proc, err, 'its header could not be read');
|
|
197
|
+
}
|
|
198
|
+
if (unreadable !== null) {
|
|
199
|
+
// git writes a header with no head before it refuses an empty bundle, so its exit says which
|
|
200
|
+
// this is. Otherwise the header is the failure, whatever git makes of losing its reader.
|
|
201
|
+
proc.stdout.destroy();
|
|
202
|
+
if (await refusedAsEmpty(proc).catch(() => false))
|
|
203
|
+
return 'empty';
|
|
204
|
+
throw unreadable;
|
|
205
|
+
}
|
|
206
|
+
// stdout ended before a whole header: git failed, or found nothing to bundle.
|
|
207
|
+
if (await refusedAsEmpty(proc))
|
|
208
|
+
return 'empty';
|
|
209
|
+
throw new Error(`git bundle create printed no header for ${branch}`);
|
|
210
|
+
}
|
|
211
|
+
/** Whether `bundle create` exited refusing an empty bundle; any other failure is thrown. */
|
|
212
|
+
async function refusedAsEmpty(proc) {
|
|
213
|
+
try {
|
|
214
|
+
await proc.exited;
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
if (/Refusing to create empty bundle/.test(getErrorMessage(err)))
|
|
219
|
+
return true;
|
|
220
|
+
throw err;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Send a started bundle with the push. When the push fails, git's own failure, if it had one,
|
|
225
|
+
* is the cause; otherwise the gateway's.
|
|
226
|
+
*/
|
|
227
|
+
async function sendBundle(ctx, request, bundle, signal) {
|
|
228
|
+
let answer;
|
|
229
|
+
try {
|
|
230
|
+
answer = await ctx.github().push(request, bundle.stream, signal);
|
|
231
|
+
}
|
|
232
|
+
catch (err) {
|
|
233
|
+
throw await causeOf(bundle.process, err, 'the push failed');
|
|
234
|
+
}
|
|
235
|
+
// An answer is the push's outcome; how git exits after it changes nothing.
|
|
236
|
+
await bundle.process.exited.catch(() => undefined);
|
|
237
|
+
return answer;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* What to report for a failure while `proc` was writing a bundle: git's own failure when it had
|
|
241
|
+
* one first (an abort, an inactivity kill, an error of its own), of which a stream error is only
|
|
242
|
+
* the symptom, else `err`. Stops git either way, with `reason`.
|
|
243
|
+
*/
|
|
244
|
+
async function causeOf(proc, err, reason) {
|
|
245
|
+
proc.kill(reason);
|
|
246
|
+
const own = await proc.exited.then(() => null, (gitErr) => gitErr);
|
|
247
|
+
return own !== null && getErrorMessage(own) !== reason ? own : err;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Unbundle the gateway's bundle `bundleId` into the repository at `gitDir`, under the pins. It
|
|
251
|
+
* adds objects and moves no ref.
|
|
252
|
+
*/
|
|
253
|
+
async function unbundle(ctx, gitDir, bundleId, signal) {
|
|
254
|
+
const stream = await ctx.github().openBundle(bundleId);
|
|
255
|
+
try {
|
|
256
|
+
await runGit(['bundle', 'unbundle', '--progress', '--end-of-options', '-'], {
|
|
257
|
+
...sharedRepoProcessOptions(gitDir, 'bare'),
|
|
258
|
+
stdin: stream,
|
|
259
|
+
inactivityTimeoutMs: ctx.taskTimeoutMs,
|
|
260
|
+
signal,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
finally {
|
|
264
|
+
stream.destroy();
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Move the tracking namespace to exactly `refs`, every move stating the value it expects: all
|
|
269
|
+
* deletions in one `update-ref` transaction, then every create and update in another. One
|
|
270
|
+
* transaction cannot do both: deleting `a` and creating `a/b` together fails on the
|
|
271
|
+
* directory/file conflict, and a transaction is all-or-nothing, so a GitHub-side rename of
|
|
272
|
+
* `release` to `release/1.0` would freeze the namespace for ever. When a transaction fails on a
|
|
273
|
+
* ref (see {@link lostRace}), each of its moves is tried on its own, and the losers are logged;
|
|
274
|
+
* the next fetch retries them. The Lambda only reads this namespace, so per-ref
|
|
275
|
+
* atomicity is all it needs.
|
|
276
|
+
*/
|
|
277
|
+
async function moveTrackingRefs(ctx, gitDir, refs, signal) {
|
|
278
|
+
let needsOperator = null;
|
|
279
|
+
const current = new Map();
|
|
280
|
+
const listing = await sharedRepoGit(gitDir, 'bare').raw([
|
|
281
|
+
'for-each-ref',
|
|
282
|
+
'--format=%(objectname) %(refname)',
|
|
283
|
+
'--end-of-options',
|
|
284
|
+
GITHUB_TRACKING_REF_PREFIX,
|
|
285
|
+
]);
|
|
286
|
+
for (const line of listing.split('\n')) {
|
|
287
|
+
const space = line.indexOf(' ');
|
|
288
|
+
if (space !== -1)
|
|
289
|
+
current.set(line.slice(space + 1), line.slice(0, space));
|
|
290
|
+
}
|
|
291
|
+
const deletions = [];
|
|
292
|
+
for (const [ref, sha] of current) {
|
|
293
|
+
if (!refs.has(ref.slice(GITHUB_TRACKING_REF_PREFIX.length))) {
|
|
294
|
+
deletions.push({ ref, to: null, from: sha });
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const updates = [];
|
|
298
|
+
for (const [name, sha] of refs) {
|
|
299
|
+
const ref = `${GITHUB_TRACKING_REF_PREFIX}${name}`;
|
|
300
|
+
const from = current.get(ref);
|
|
301
|
+
if (from !== sha)
|
|
302
|
+
updates.push({ ref, to: sha, from: from ?? GIT_ZERO_OID });
|
|
303
|
+
}
|
|
304
|
+
for (const moves of [deletions, updates]) {
|
|
305
|
+
if (moves.length === 0)
|
|
306
|
+
continue;
|
|
307
|
+
try {
|
|
308
|
+
await updateRefs(ctx, gitDir, moves, signal);
|
|
309
|
+
}
|
|
310
|
+
catch (err) {
|
|
311
|
+
if (!lostRace(err))
|
|
312
|
+
throw err;
|
|
313
|
+
const losers = [];
|
|
314
|
+
if (PACKED_REFS_LOCKED.test(getErrorMessage(err))) {
|
|
315
|
+
// Every deletion takes packed-refs.lock, so each would wait for it and lose the same way.
|
|
316
|
+
losers.push(...moves.map((move) => move.ref));
|
|
317
|
+
needsOperator = await stalePackedRefsLock(gitDir);
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
for (const move of moves) {
|
|
321
|
+
await updateRefs(ctx, gitDir, [move], signal).catch((moveErr) => {
|
|
322
|
+
if (!lostRace(moveErr))
|
|
323
|
+
throw moveErr;
|
|
324
|
+
losers.push(move.ref);
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (losers.length > 0) {
|
|
329
|
+
workerLogWarn(`Could not move ${losers.length} GitHub tracking ref(s), retrying next sync: ` +
|
|
330
|
+
`${losers.join(', ')} (${getErrorMessage(err).trim()})`);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return needsOperator;
|
|
335
|
+
}
|
|
336
|
+
const PACKED_REFS_LOCKED = /Unable to create '[^']*packed-refs\.lock': File exists/;
|
|
337
|
+
/** How old remote.git's packed-refs.lock must be before the worker reports it as left behind. */
|
|
338
|
+
const STALE_PACKED_REFS_LOCK_MS = 10 * 60 * 1000;
|
|
339
|
+
/**
|
|
340
|
+
* What to tell an operator about remote.git's `packed-refs.lock` once it is older than
|
|
341
|
+
* {@link STALE_PACKED_REFS_LOCK_MS}, which no git holds it for: a writer killed mid-delete left
|
|
342
|
+
* it, and it blocks every branch deletion there, the Lambda's included. The worker never removes
|
|
343
|
+
* it: the Lambda shares the repository, and the worker cannot tell a lock left behind from one
|
|
344
|
+
* a live writer holds on a host whose clock or NFS attributes it does not see.
|
|
345
|
+
*/
|
|
346
|
+
async function stalePackedRefsLock(gitDir) {
|
|
347
|
+
const lock = path.join(gitDir, 'packed-refs.lock');
|
|
348
|
+
const stat = await fs.stat(lock).catch(() => null);
|
|
349
|
+
if (stat === null || Date.now() - stat.mtimeMs < STALE_PACKED_REFS_LOCK_MS)
|
|
350
|
+
return null;
|
|
351
|
+
return (`${lock} has been there since ${stat.mtime.toISOString()}: a git killed while it deleted a ` +
|
|
352
|
+
`branch left it, and every branch deletion in remote.git fails until it is removed. ` +
|
|
353
|
+
`Check that no git is running in remote.git, then remove that file.`);
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Whether `update-ref` failed because a ref was not at the value a move stated, a lock was held
|
|
357
|
+
* (a ref's own, or `packed-refs.lock`, which every deletion takes), or a directory/file conflict
|
|
358
|
+
* stood in the way: a failure confined to the namespace's refs, logged and retried by the next
|
|
359
|
+
* fetch, which never holds back the other transaction. Anything else (an abort, a missing object)
|
|
360
|
+
* is thrown.
|
|
361
|
+
*/
|
|
362
|
+
function lostRace(err) {
|
|
363
|
+
return /cannot lock ref|Unable to create '[^']*\.lock': File exists|exists; cannot create/.test(getErrorMessage(err));
|
|
364
|
+
}
|
|
365
|
+
/** Apply `moves` as one `update-ref` transaction, NUL-separated, so no refname can split a line. */
|
|
366
|
+
async function updateRefs(ctx, gitDir, moves, signal) {
|
|
367
|
+
const input = moves
|
|
368
|
+
.map((move) => {
|
|
369
|
+
if (move.ref.includes('\0'))
|
|
370
|
+
throw new Error(`A ref name holds a NUL: ${JSON.stringify(move.ref)}`);
|
|
371
|
+
return move.to === null
|
|
372
|
+
? `delete ${move.ref}\0${move.from}\0`
|
|
373
|
+
: `update ${move.ref}\0${move.to}\0${move.from}\0`;
|
|
374
|
+
})
|
|
375
|
+
.join('');
|
|
376
|
+
await runGit(['update-ref', '-z', '--stdin', '--end-of-options'], {
|
|
377
|
+
...sharedRepoProcessOptions(gitDir, 'bare'),
|
|
378
|
+
stdin: input,
|
|
379
|
+
inactivityTimeoutMs: ctx.taskTimeoutMs,
|
|
380
|
+
signal,
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* What `gitDir` has, for a fetch's `have`, up to {@link MAX_FETCH_HAVE} IDs: its GitHub tracking
|
|
385
|
+
* tips first, which describe most of what GitHub has, then its branches' tips. With no tracking
|
|
386
|
+
* ref at all (a remote.git no fetch has written yet), a branch ahead of GitHub names no commit
|
|
387
|
+
* the gateway holds, and the bundle would resend history remote.git already has, so each branch
|
|
388
|
+
* then adds its first-parent ancestors 1, 2, 4, … commits back, as git's own negotiation does.
|
|
389
|
+
*/
|
|
390
|
+
async function haveOf(gitDir) {
|
|
391
|
+
const list = async (namespace) => (await sharedRepoGit(gitDir, 'bare').raw([
|
|
392
|
+
'for-each-ref',
|
|
393
|
+
'--format=%(objectname)',
|
|
394
|
+
'--end-of-options',
|
|
395
|
+
namespace,
|
|
396
|
+
]))
|
|
397
|
+
.split('\n')
|
|
398
|
+
.filter((id) => OBJECT_ID.test(id));
|
|
399
|
+
const tracking = await list(GITHUB_TRACKING_REF_PREFIX);
|
|
400
|
+
const heads = await list('refs/heads/');
|
|
401
|
+
const have = new Set([...tracking, ...heads]);
|
|
402
|
+
if (tracking.length === 0) {
|
|
403
|
+
for (const tip of new Set(heads)) {
|
|
404
|
+
if (have.size >= MAX_FETCH_HAVE)
|
|
405
|
+
break;
|
|
406
|
+
const ancestors = (await sharedRepoGit(gitDir, 'bare').raw([
|
|
407
|
+
'rev-list',
|
|
408
|
+
'--first-parent',
|
|
409
|
+
`--max-count=${SKIP_LIST_DEPTH}`,
|
|
410
|
+
'--end-of-options',
|
|
411
|
+
tip,
|
|
412
|
+
]))
|
|
413
|
+
.split('\n')
|
|
414
|
+
.filter((id) => OBJECT_ID.test(id));
|
|
415
|
+
for (let step = 1; step < ancestors.length; step *= 2)
|
|
416
|
+
have.add(ancestors[step]);
|
|
417
|
+
if (ancestors.length > 0)
|
|
418
|
+
have.add(ancestors[ancestors.length - 1]);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return [...have].slice(0, MAX_FETCH_HAVE);
|
|
422
|
+
}
|
|
423
|
+
/** How far back {@link haveOf} looks along one branch. */
|
|
424
|
+
const SKIP_LIST_DEPTH = 4096;
|
|
425
|
+
/** The tracking-namespace tips of `branches` in `gitDir`, skipping any it lacks. */
|
|
426
|
+
async function trackingTips(gitDir, branches) {
|
|
427
|
+
const tips = [];
|
|
428
|
+
for (const branch of new Set(branches)) {
|
|
429
|
+
const sha = await sharedRepoGit(gitDir, 'bare')
|
|
430
|
+
.raw([
|
|
431
|
+
'rev-parse',
|
|
432
|
+
'--verify',
|
|
433
|
+
'--quiet',
|
|
434
|
+
'--end-of-options',
|
|
435
|
+
`${GITHUB_TRACKING_REF_PREFIX}${branch}`,
|
|
436
|
+
])
|
|
437
|
+
.then((out) => out.split('\n')[0] ?? '')
|
|
438
|
+
.catch(() => '');
|
|
439
|
+
if (OBJECT_ID.test(sha) && !tips.includes(sha))
|
|
440
|
+
tips.push(sha);
|
|
441
|
+
}
|
|
442
|
+
return tips;
|
|
443
|
+
}
|
|
444
|
+
const OBJECT_ID = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/;
|
|
@@ -23,10 +23,9 @@ export type HistoryRewriteContext = Pick<WorkerContext, 'remoteGitPath' | 'conte
|
|
|
23
23
|
* What `remote.git` currently holds for `branchRef`, or null when this branch
|
|
24
24
|
* was never published there (never submitted) or the ref is unreadable.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
* reading a bare repo that way does
|
|
28
|
-
*
|
|
29
|
-
* override the test-only `openBareRepo` helper uses.
|
|
26
|
+
* Names the repository outright (sharedRepoGit's GIT_DIR), like
|
|
27
|
+
* verifyBaseBranchExists() in cms-worker.ts: reading a bare repo that way does
|
|
28
|
+
* not depend on `safe.bareRepository` being permissive.
|
|
30
29
|
*/
|
|
31
30
|
export declare function readPublishedSha(ctx: Pick<HistoryRewriteContext, 'remoteGitPath'>, branchRef: string): Promise<string | null>;
|
|
32
31
|
/**
|
|
@@ -55,7 +54,7 @@ export declare function markHistoryRewritten(ctx: Pick<HistoryRewriteContext, 'c
|
|
|
55
54
|
* it on GitHub" diagnosis that is false -- we did.
|
|
56
55
|
*
|
|
57
56
|
* Tracked, with the concurrent-clear race that can drop a marker mid-arming,
|
|
58
|
-
* in
|
|
57
|
+
* in safeinsights/canopycms#902.
|
|
59
58
|
*/
|
|
60
59
|
export declare function clearHistoryRewrittenMarker(ctx: Pick<HistoryRewriteContext, 'contentBranchesPath'>, branchPath: string, branchDir: string): Promise<void>;
|
|
61
60
|
/**
|
|
@@ -1,26 +1,22 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { simpleGit } from 'simple-git';
|
|
3
2
|
import { BranchMetadataFileManager, getBranchMetadataFileManager } from '../branch-metadata.js';
|
|
4
|
-
import { gitChildEnv } from '../git-manager.js';
|
|
5
3
|
import { sanitizeBranchName } from '../paths/branch-name.js';
|
|
6
4
|
import { getErrorMessage, redactCredentials } from '../utils/error.js';
|
|
7
5
|
import { isStaleLeaseRejection } from '../utils/git.js';
|
|
8
6
|
import { enqueueTask, listTasks } from '../task-queue/cms-task-queue.js';
|
|
7
|
+
import { pinnedReceivePack, sharedRepoGit } from './shared-repo-git.js';
|
|
9
8
|
import { workerLog, workerLogWarn } from './log.js';
|
|
10
9
|
/**
|
|
11
10
|
* What `remote.git` currently holds for `branchRef`, or null when this branch
|
|
12
11
|
* was never published there (never submitted) or the ref is unreadable.
|
|
13
12
|
*
|
|
14
|
-
*
|
|
15
|
-
* reading a bare repo that way does
|
|
16
|
-
*
|
|
17
|
-
* override the test-only `openBareRepo` helper uses.
|
|
13
|
+
* Names the repository outright (sharedRepoGit's GIT_DIR), like
|
|
14
|
+
* verifyBaseBranchExists() in cms-worker.ts: reading a bare repo that way does
|
|
15
|
+
* not depend on `safe.bareRepository` being permissive.
|
|
18
16
|
*/
|
|
19
17
|
export async function readPublishedSha(ctx, branchRef) {
|
|
20
18
|
try {
|
|
21
|
-
const out = await
|
|
22
|
-
'--git-dir',
|
|
23
|
-
ctx.remoteGitPath,
|
|
19
|
+
const out = await sharedRepoGit(ctx.remoteGitPath, 'bare').raw([
|
|
24
20
|
'rev-parse',
|
|
25
21
|
'--verify',
|
|
26
22
|
`refs/heads/${branchRef}`,
|
|
@@ -66,7 +62,7 @@ export async function markHistoryRewritten(ctx, branchPath, branchDir, expectedS
|
|
|
66
62
|
* it on GitHub" diagnosis that is false -- we did.
|
|
67
63
|
*
|
|
68
64
|
* Tracked, with the concurrent-clear race that can drop a marker mid-arming,
|
|
69
|
-
* in
|
|
65
|
+
* in safeinsights/canopycms#902.
|
|
70
66
|
*/
|
|
71
67
|
export async function clearHistoryRewrittenMarker(ctx, branchPath, branchDir) {
|
|
72
68
|
try {
|
|
@@ -94,17 +90,16 @@ export async function clearHistoryRewrittenMarker(ctx, branchPath, branchDir) {
|
|
|
94
90
|
* push moved the ref; logged and retried by the self-heal pass, never thrown.
|
|
95
91
|
*/
|
|
96
92
|
export async function forcePublishToLocalRemote(ctx, branchPath, branchRef, expectedSha) {
|
|
97
|
-
//
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
|
|
101
|
-
// below from silently becoming a no-op on a non-English host.
|
|
102
|
-
const pushGit = simpleGit({ baseDir: branchPath, timeout: { block: ctx.taskTimeoutMs } });
|
|
103
|
-
pushGit.env(gitChildEnv({}));
|
|
93
|
+
// sharedRepoGit's env is gitChildEnv's, whose C-locale pin is what keeps
|
|
94
|
+
// isStaleLeaseRejection below from silently becoming a no-op on a
|
|
95
|
+
// non-English host.
|
|
96
|
+
const pushGit = sharedRepoGit(branchPath, 'worktree', { timeout: { block: ctx.taskTimeoutMs } });
|
|
104
97
|
try {
|
|
105
98
|
await pushGit.raw([
|
|
106
99
|
'push',
|
|
107
100
|
`--force-with-lease=${branchRef}:${expectedSha}`,
|
|
101
|
+
// Otherwise remote.git's own hooks run, as the worker.
|
|
102
|
+
`--receive-pack=${pinnedReceivePack()}`,
|
|
108
103
|
// Real flags must precede --end-of-options; everything after it is
|
|
109
104
|
// positional (see GitManager.push() for the same guard).
|
|
110
105
|
'--end-of-options',
|
|
@@ -18,17 +18,17 @@ export type ProvisionedWorkspaceHold = {
|
|
|
18
18
|
};
|
|
19
19
|
/**
|
|
20
20
|
* Take a branch workspace's provisioning lock for the sync loop, the same cross-host lock the
|
|
21
|
-
* Lambda holds while it
|
|
22
|
-
*
|
|
21
|
+
* Lambda holds while it publishes the workspace (branch-provisioning.ts) and admin actions hold
|
|
22
|
+
* while they repair or purge it. The caller holds it across its dirty check and every git step, and
|
|
23
23
|
* releases it in a `finally`.
|
|
24
24
|
*
|
|
25
25
|
* Zero retries: the worker skips and retries next cycle rather than wait, so it never blocks on
|
|
26
26
|
* the Lambda and cannot deadlock with it. The rebase nests the content-write lock inside this one;
|
|
27
27
|
* the worker takes that one try-only as well, so the nesting cannot deadlock either.
|
|
28
28
|
*
|
|
29
|
-
* Provisioned means a `.git` directory AND `branch.json`.
|
|
30
|
-
*
|
|
31
|
-
*
|
|
29
|
+
* Provisioned means a `.git` directory AND `branch.json`. A workspace is published complete with
|
|
30
|
+
* both ([PROV-1], branch-provisioning.ts), so anything else at a branch name is a leftover for
|
|
31
|
+
* `repairBranchDirResidue` (git-sync.ts).
|
|
32
32
|
*/
|
|
33
33
|
export declare function holdProvisionedWorkspace(contentBranchesPath: string, dirName: string): Promise<ProvisionedWorkspaceHold>;
|
|
34
34
|
/** Release a hold, logging rather than throwing: the sync loop's callers never throw. */
|
|
@@ -6,17 +6,17 @@ import { branchProvisioningLockName, tryAcquireProvisioningLock } from '../utils
|
|
|
6
6
|
import { workerLogWarn } from './log.js';
|
|
7
7
|
/**
|
|
8
8
|
* Take a branch workspace's provisioning lock for the sync loop, the same cross-host lock the
|
|
9
|
-
* Lambda holds while it
|
|
10
|
-
*
|
|
9
|
+
* Lambda holds while it publishes the workspace (branch-provisioning.ts) and admin actions hold
|
|
10
|
+
* while they repair or purge it. The caller holds it across its dirty check and every git step, and
|
|
11
11
|
* releases it in a `finally`.
|
|
12
12
|
*
|
|
13
13
|
* Zero retries: the worker skips and retries next cycle rather than wait, so it never blocks on
|
|
14
14
|
* the Lambda and cannot deadlock with it. The rebase nests the content-write lock inside this one;
|
|
15
15
|
* the worker takes that one try-only as well, so the nesting cannot deadlock either.
|
|
16
16
|
*
|
|
17
|
-
* Provisioned means a `.git` directory AND `branch.json`.
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* Provisioned means a `.git` directory AND `branch.json`. A workspace is published complete with
|
|
18
|
+
* both ([PROV-1], branch-provisioning.ts), so anything else at a branch name is a leftover for
|
|
19
|
+
* `repairBranchDirResidue` (git-sync.ts).
|
|
20
20
|
*/
|
|
21
21
|
export async function holdProvisionedWorkspace(contentBranchesPath, dirName) {
|
|
22
22
|
let release;
|
package/dist/worker/rebase.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ import type { WorkerContext } from './worker-context.js';
|
|
|
20
20
|
* but still need their PR's resolution polled, and this loop is the only thing
|
|
21
21
|
* that walks every branch workspace.
|
|
22
22
|
*/
|
|
23
|
-
export type RebaseContext = Pick<WorkerContext, '
|
|
23
|
+
export type RebaseContext = Pick<WorkerContext, 'baseBranch' | 'sanitizedBaseBranch' | 'contentBranchesPath' | 'contentRoot' | 'remoteGitPath' | 'taskDir' | 'taskTimeoutMs' | 'github' | 'afterConflictDetectedForTesting' | 'afterRebaseCompletedForTesting' | 'ensureSettingsBranch' | 'isDraining'>;
|
|
24
24
|
/**
|
|
25
25
|
* Per-cycle outcome of `rebaseActiveBranches()`, folded by `syncGit()` into the
|
|
26
26
|
* worker's self-reported status (`WorkerStatusReport.lastGitSync`, see
|