canopycms 0.0.67 → 0.0.68-int.100
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 +21 -14
- package/dist/ai/handler.js +8 -0
- package/dist/api/admin-branch-health.js +17 -20
- package/dist/api/admin.d.ts +30 -9
- package/dist/api/admin.js +32 -2
- package/dist/api/assets.js +84 -76
- package/dist/api/branch-create-window.d.ts +12 -0
- package/dist/api/branch-create-window.js +13 -0
- package/dist/api/branch-review.d.ts +3 -3
- package/dist/api/branch-review.js +14 -5
- package/dist/api/branch-status.d.ts +5 -5
- package/dist/api/branch-status.js +26 -6
- package/dist/api/branch-withdraw.d.ts +2 -2
- package/dist/api/branch-withdraw.js +7 -2
- package/dist/api/branch.d.ts +15 -2
- package/dist/api/branch.js +111 -92
- package/dist/api/client.d.ts +18 -6
- package/dist/api/client.js +79 -12
- package/dist/api/content.d.ts +6 -5
- package/dist/api/content.js +44 -41
- package/dist/api/entries.js +16 -15
- package/dist/api/github-sync.d.ts +10 -1
- package/dist/api/github-sync.js +20 -10
- package/dist/api/index.d.ts +1 -1
- package/dist/api/reference-options.js +1 -1
- package/dist/api/resolve-references.js +14 -40
- package/dist/api/settings-helpers.d.ts +1 -1
- package/dist/api/settings-helpers.js +1 -4
- package/dist/api/user.d.ts +3 -0
- package/dist/api/user.js +3 -0
- package/dist/assets/asset-url.d.ts +22 -16
- package/dist/assets/asset-url.js +42 -25
- package/dist/assets/factory.d.ts +5 -0
- package/dist/assets/factory.js +5 -0
- package/dist/assets/index.d.ts +1 -1
- package/dist/assets/materialize.d.ts +122 -0
- package/dist/assets/materialize.js +305 -0
- package/dist/assets/store-local.d.ts +4 -0
- package/dist/assets/store-local.js +11 -0
- package/dist/assets/store-s3.d.ts +10 -1
- package/dist/assets/store-s3.js +55 -3
- 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 +14 -1
- package/dist/auth/file-based-auth-cache.js +7 -8
- package/dist/authorization/content.d.ts +5 -4
- package/dist/authorization/content.js +5 -5
- package/dist/authorization/path.d.ts +11 -6
- package/dist/authorization/path.js +11 -6
- package/dist/authorization/types.d.ts +2 -2
- package/dist/branch-health.d.ts +7 -1
- package/dist/branch-health.js +8 -3
- package/dist/branch-metadata.d.ts +5 -5
- package/dist/branch-metadata.js +44 -36
- package/dist/branch-provisioning.d.ts +167 -0
- package/dist/branch-provisioning.js +501 -0
- package/dist/branch-schema-cache.d.ts +5 -3
- package/dist/branch-schema-cache.js +29 -11
- 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 +240 -94
- package/dist/build/asset-refs.d.ts +93 -0
- package/dist/build/asset-refs.js +251 -0
- package/dist/build-identity.d.ts +3 -0
- package/dist/build-identity.js +13 -0
- package/dist/cli/asset-refs.d.ts +30 -0
- package/dist/cli/asset-refs.js +168 -0
- package/dist/cli/cli.d.ts +2 -1
- package/dist/cli/cli.js +4843 -1870
- package/dist/cli/generate-ai-content.js +1584 -444
- package/dist/cli/github-app-manifest.d.ts +4 -3
- package/dist/cli/github-app-manifest.js +4 -3
- package/dist/cli/init.js +30 -27
- package/dist/cli/migrate.js +12 -8
- package/dist/cli/sync.js +83 -37
- package/dist/cli/template-files/Dockerfile.cms.template +8 -0
- package/dist/cli/template-files/cdk-app.ts.template +4 -0
- package/dist/cli/template-files/cms-stack.ts.template +23 -12
- package/dist/cli/template-files/deploy-cms.yml.template +2 -0
- package/dist/config/helpers.js +1 -2
- package/dist/config/schemas/config.d.ts +19 -32
- package/dist/config/schemas/config.js +9 -11
- package/dist/config/schemas/field.js +1 -0
- package/dist/config/schemas/media.d.ts +4 -13
- package/dist/config/schemas/media.js +5 -8
- package/dist/config/schemas/url.d.ts +4 -20
- package/dist/config/schemas/url.js +6 -22
- package/dist/config/types.d.ts +30 -20
- package/dist/config/validation.d.ts +6 -0
- package/dist/config/validation.js +37 -0
- package/dist/content-listing.d.ts +12 -12
- package/dist/content-listing.js +10 -6
- package/dist/content-reader.d.ts +11 -2
- package/dist/content-reader.js +22 -14
- package/dist/content-store.d.ts +37 -9
- package/dist/content-store.js +70 -43
- package/dist/content-tree.d.ts +1 -1
- package/dist/content-tree.js +2 -2
- package/dist/context.d.ts +27 -9
- package/dist/context.js +154 -70
- package/dist/editor/BranchManager.d.ts +7 -1
- package/dist/editor/BranchManager.js +29 -14
- package/dist/editor/CanopyEditor.d.ts +1 -1
- package/dist/editor/CanopyEditor.js +2 -6
- package/dist/editor/Editor.d.ts +4 -3
- package/dist/editor/Editor.js +24 -20
- package/dist/editor/FormRenderer.js +34 -18
- package/dist/editor/admin/SystemHealthPanel.js +47 -7
- package/dist/editor/components/BranchesDrawer.d.ts +9 -0
- package/dist/editor/components/BranchesDrawer.js +4 -0
- package/dist/editor/components/NoEditPermissionNotice.d.ts +10 -0
- package/dist/editor/components/NoEditPermissionNotice.js +17 -0
- package/dist/editor/context/AssetContext.d.ts +18 -35
- package/dist/editor/context/AssetContext.js +20 -29
- package/dist/editor/context/index.d.ts +1 -1
- package/dist/editor/context/index.js +1 -1
- package/dist/editor/editor-config.d.ts +1 -2
- package/dist/editor/editor-config.js +0 -23
- package/dist/editor/editor-utils.d.ts +24 -21
- package/dist/editor/editor-utils.js +75 -62
- package/dist/editor/fields/BlockField.d.ts +1 -0
- package/dist/editor/fields/BlockField.js +6 -4
- package/dist/editor/fields/CodeField.d.ts +1 -0
- package/dist/editor/fields/CodeField.js +2 -2
- package/dist/editor/fields/DateTimeField.d.ts +1 -0
- package/dist/editor/fields/DateTimeField.js +2 -2
- package/dist/editor/fields/FieldDescription.d.ts +16 -0
- package/dist/editor/fields/FieldDescription.js +11 -0
- package/dist/editor/fields/ImageField.d.ts +1 -0
- package/dist/editor/fields/ImageField.js +3 -2
- package/dist/editor/fields/InlineGroupField.js +4 -1
- package/dist/editor/fields/MarkdownField.d.ts +1 -0
- package/dist/editor/fields/MarkdownField.js +115 -20
- package/dist/editor/fields/NumberField.d.ts +1 -0
- package/dist/editor/fields/NumberField.js +2 -2
- package/dist/editor/fields/NumberListField.d.ts +1 -0
- package/dist/editor/fields/NumberListField.js +2 -2
- package/dist/editor/fields/ObjectField.d.ts +1 -0
- package/dist/editor/fields/ObjectField.js +5 -2
- package/dist/editor/fields/ReferenceField.d.ts +1 -0
- package/dist/editor/fields/ReferenceField.js +5 -4
- package/dist/editor/fields/SelectField.d.ts +1 -0
- package/dist/editor/fields/SelectField.js +2 -2
- package/dist/editor/fields/StringListField.d.ts +1 -0
- package/dist/editor/fields/StringListField.js +2 -2
- package/dist/editor/fields/TextField.d.ts +1 -0
- package/dist/editor/fields/TextField.js +2 -2
- package/dist/editor/fields/ToggleField.d.ts +1 -0
- package/dist/editor/fields/ToggleField.js +7 -4
- package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +1 -1
- package/dist/editor/fields/entry-link/InsertEntryLink.js +3 -2
- package/dist/editor/fields/mdx-jsx-support.d.ts +1 -0
- package/dist/editor/fields/mdx-jsx-support.js +137 -0
- package/dist/editor/hooks/create-branch-request.d.ts +20 -0
- package/dist/editor/hooks/create-branch-request.js +52 -0
- package/dist/editor/hooks/useBranchActions.d.ts +13 -2
- package/dist/editor/hooks/useBranchActions.js +48 -17
- package/dist/editor/hooks/useBranchManager.d.ts +11 -0
- package/dist/editor/hooks/useBranchManager.js +80 -2
- package/dist/editor/hooks/useBranchesData.d.ts +6 -0
- package/dist/editor/hooks/useBranchesData.js +9 -3
- package/dist/editor/hooks/useCommentSystem.js +25 -6
- package/dist/editor/hooks/useDraftManager.d.ts +16 -1
- package/dist/editor/hooks/useDraftManager.js +193 -36
- package/dist/editor/hooks/useEntriesData.js +3 -3
- package/dist/editor/hooks/useEntryManager.d.ts +2 -1
- package/dist/editor/hooks/useEntryManager.js +34 -19
- package/dist/editor/media/AssetCard.d.ts +1 -1
- 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 +7 -0
- package/dist/editor/media/editor-image-src.js +12 -0
- package/dist/editor/preview-asset-base.d.ts +8 -0
- package/dist/editor/preview-asset-base.js +13 -0
- package/dist/editor/preview-bridge.d.ts +8 -1
- package/dist/editor/preview-bridge.js +15 -2
- package/dist/editor/preview-path.d.ts +10 -0
- package/dist/editor/preview-path.js +20 -0
- package/dist/editor/theme.js +2 -2
- package/dist/entry-schema-registry.d.ts +4 -4
- package/dist/entry-schema-registry.js +10 -6
- package/dist/entry-schema.d.ts +27 -4
- package/dist/entry-schema.js +20 -3
- package/dist/git-manager.d.ts +173 -6
- package/dist/git-manager.js +594 -76
- package/dist/github-service.d.ts +8 -0
- package/dist/github-service.js +5 -1
- package/dist/http/handler.js +37 -13
- package/dist/http/index.d.ts +2 -0
- package/dist/http/index.js +2 -0
- package/dist/http/router.d.ts +2 -0
- package/dist/http/router.js +2 -1
- package/dist/http/types.d.ts +2 -0
- package/dist/http/worker-not-ready.d.ts +10 -0
- package/dist/http/worker-not-ready.js +24 -0
- package/dist/operating-mode/client-unsafe-strategy.js +0 -6
- package/dist/operating-mode/types.d.ts +1 -4
- package/dist/paths/branch-name.d.ts +5 -0
- package/dist/paths/branch-name.js +9 -0
- package/dist/paths/branch.d.ts +6 -2
- package/dist/paths/branch.js +16 -10
- package/dist/paths/index.d.ts +3 -3
- package/dist/paths/index.js +3 -3
- package/dist/paths/normalize.d.ts +7 -0
- package/dist/paths/normalize.js +9 -0
- package/dist/paths/validation.js +0 -2
- package/dist/reference-resolver.d.ts +5 -21
- package/dist/reference-resolver.js +9 -44
- package/dist/resolve-canopy-user.js +2 -1
- package/dist/schema/schema-store.d.ts +54 -31
- package/dist/schema/schema-store.js +77 -31
- package/dist/server.d.ts +24 -9
- package/dist/server.js +22 -8
- package/dist/services.d.ts +18 -6
- package/dist/services.js +85 -70
- package/dist/settings-workspace.d.ts +23 -3
- package/dist/settings-workspace.js +197 -45
- package/dist/static/seo.d.ts +2 -14
- package/dist/static/seo.js +2 -25
- package/dist/submission-attribution.d.ts +73 -0
- package/dist/submission-attribution.js +221 -0
- package/dist/sync-core.d.ts +12 -1
- package/dist/sync-core.js +31 -13
- package/dist/task-queue/worker-status.d.ts +8 -0
- package/dist/task-queue/worker-status.js +17 -0
- package/dist/types.d.ts +31 -2
- package/dist/utils/content-write-lock.d.ts +18 -7
- package/dist/utils/content-write-lock.js +18 -9
- package/dist/utils/debug.d.ts +8 -0
- package/dist/utils/debug.js +10 -2
- package/dist/utils/git.d.ts +32 -0
- package/dist/utils/git.js +42 -0
- package/dist/utils/occ-json-write.js +10 -2
- package/dist/utils/provision-log.d.ts +25 -0
- package/dist/utils/provision-log.js +49 -0
- package/dist/utils/provisioning-lock.d.ts +35 -5
- package/dist/utils/provisioning-lock.js +73 -12
- package/dist/utils/request-timing.d.ts +25 -0
- package/dist/utils/request-timing.js +101 -0
- package/dist/utils/sanitize-href.d.ts +8 -22
- package/dist/utils/sanitize-href.js +11 -28
- package/dist/utils/url-prefix.d.ts +30 -0
- package/dist/utils/url-prefix.js +61 -0
- package/dist/validation/entry-validator.js +9 -3
- package/dist/version.d.ts +1 -0
- package/dist/version.js +3 -0
- package/dist/worker/canopy-state.d.ts +45 -0
- package/dist/worker/canopy-state.js +75 -0
- package/dist/worker/cms-worker.d.ts +8 -3
- package/dist/worker/cms-worker.js +38 -2
- package/dist/worker/git-sync.d.ts +30 -12
- package/dist/worker/git-sync.js +253 -58
- package/dist/worker/history-rewrite.d.ts +1 -1
- package/dist/worker/history-rewrite.js +1 -1
- package/dist/worker/provisioned-workspace.d.ts +35 -0
- package/dist/worker/provisioned-workspace.js +50 -0
- package/dist/worker/rebase.d.ts +1 -1
- package/dist/worker/rebase.js +95 -23
- package/dist/worker/remote-git-maintenance.d.ts +3 -0
- package/dist/worker/remote-git-maintenance.js +11 -0
- package/dist/worker/sparse-cone.d.ts +20 -0
- package/dist/worker/sparse-cone.js +132 -0
- package/dist/worker/task-runner.js +39 -4
- package/dist/worker/worker-context.d.ts +6 -1
- package/package.json +2 -1
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
4
|
+
import { toSameOriginPath } from '../utils/url-prefix.js';
|
|
4
5
|
import { formatCanopyPath } from './canopy-path.js';
|
|
6
|
+
import { setPreviewAssetBase } from './preview-asset-base.js';
|
|
7
|
+
import { isSamePreviewPath } from './preview-path.js';
|
|
5
8
|
export const __CANOPY_PREVIEW_CLIENT__ = true;
|
|
6
9
|
export const CANOPY_PREVIEW_MESSAGE = 'canopycms:draft:update';
|
|
7
10
|
export const CANOPY_PREVIEW_FOCUS = 'canopycms:preview:focus';
|
|
8
11
|
export const CANOPY_PREVIEW_HIGHLIGHT = 'canopycms:preview:highlight';
|
|
9
12
|
export const CANOPY_PREVIEW_READY = 'canopycms:preview:ready';
|
|
10
13
|
export const CANOPY_PREVIEW_ERROR = 'canopycms:preview:error';
|
|
14
|
+
/** `assetBase` from a draft, only if it is a same-origin path: nothing else may steer `<img>`s. */
|
|
15
|
+
const readAssetBase = (value) => typeof value === 'string' && value.startsWith('/') && toSameOriginPath(value) === value
|
|
16
|
+
? value
|
|
17
|
+
: undefined;
|
|
11
18
|
/**
|
|
12
19
|
* Resolve a (possibly relative) URL to an origin for postMessage targeting.
|
|
13
20
|
* Falls back to the page's own origin, so same-origin editor/preview setups
|
|
@@ -116,8 +123,12 @@ export const usePreviewData = (path, initialData, opts) => {
|
|
|
116
123
|
if (!isTrustedEditorMessage(event, editorOrigin))
|
|
117
124
|
return;
|
|
118
125
|
const msg = event.data;
|
|
119
|
-
if (!msg || msg.type !== CANOPY_PREVIEW_MESSAGE
|
|
126
|
+
if (!msg || msg.type !== CANOPY_PREVIEW_MESSAGE)
|
|
120
127
|
return;
|
|
128
|
+
if (typeof msg.path !== 'string' || !isSamePreviewPath(msg.path, path))
|
|
129
|
+
return;
|
|
130
|
+
// Before setData, so the render the draft triggers already reads it.
|
|
131
|
+
setPreviewAssetBase(readAssetBase(msg.assetBase));
|
|
121
132
|
setData(msg.data);
|
|
122
133
|
if (msg.isLoading !== undefined) {
|
|
123
134
|
setIsLoading(msg.isLoading);
|
|
@@ -208,7 +219,7 @@ export const usePreviewFocusEmitter = (entryPath, opts) => {
|
|
|
208
219
|
* Lightweight iframe wrapper to keep the preview in sync with form state.
|
|
209
220
|
* It posts the latest draft data to the iframe after load and when data changes.
|
|
210
221
|
*/
|
|
211
|
-
export const PreviewFrame = ({ src, path, data, isLoading, className, style, highlightEnabled, onPreviewError, }) => {
|
|
222
|
+
export const PreviewFrame = ({ src, path, data, isLoading, className, style, highlightEnabled, onPreviewError, assetBase, }) => {
|
|
212
223
|
const iframeRef = useRef(null);
|
|
213
224
|
// Pin the preview origin from the src prop: outbound messages target it (never '*'),
|
|
214
225
|
// and inbound messages must come from it. An iframe that navigates cross-origin
|
|
@@ -235,11 +246,13 @@ export const PreviewFrame = ({ src, path, data, isLoading, className, style, hig
|
|
|
235
246
|
const post = () => {
|
|
236
247
|
if (data === undefined)
|
|
237
248
|
return;
|
|
249
|
+
const sameOrigin = previewOrigin === window.location.origin;
|
|
238
250
|
sendDraftUpdate(iframeRef.current, {
|
|
239
251
|
type: CANOPY_PREVIEW_MESSAGE,
|
|
240
252
|
path,
|
|
241
253
|
data,
|
|
242
254
|
isLoading,
|
|
255
|
+
...(assetBase !== undefined && sameOrigin ? { assetBase } : {}),
|
|
243
256
|
}, previewOrigin);
|
|
244
257
|
};
|
|
245
258
|
const postHighlight = () => {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reduces a preview URL to what identifies the page, its path and query, with no origin,
|
|
3
|
+
* fragment or trailing slash. The editor names a page by the `src` it built and the framed page
|
|
4
|
+
* by its own location. An absolute `src`, or a host redirect that adds or drops a trailing slash,
|
|
5
|
+
* spells the same page two ways, and the bridge must still match them.
|
|
6
|
+
* @internal Exported for tests.
|
|
7
|
+
*/
|
|
8
|
+
export declare const normalizePreviewPath: (url: string) => string;
|
|
9
|
+
/** Whether two preview URLs name the same page; see `normalizePreviewPath`. */
|
|
10
|
+
export declare const isSamePreviewPath: (a: string, b: string) => boolean;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { stripTrailingSlashes } from '../utils/url-prefix.js';
|
|
2
|
+
/**
|
|
3
|
+
* Reduces a preview URL to what identifies the page, its path and query, with no origin,
|
|
4
|
+
* fragment or trailing slash. The editor names a page by the `src` it built and the framed page
|
|
5
|
+
* by its own location. An absolute `src`, or a host redirect that adds or drops a trailing slash,
|
|
6
|
+
* spells the same page two ways, and the bridge must still match them.
|
|
7
|
+
* @internal Exported for tests.
|
|
8
|
+
*/
|
|
9
|
+
export const normalizePreviewPath = (url) => {
|
|
10
|
+
let parsed;
|
|
11
|
+
try {
|
|
12
|
+
parsed = new URL(url, 'http://preview.invalid');
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return url;
|
|
16
|
+
}
|
|
17
|
+
return `${stripTrailingSlashes(parsed.pathname) || '/'}${parsed.search}`;
|
|
18
|
+
};
|
|
19
|
+
/** Whether two preview URLs name the same page; see `normalizePreviewPath`. */
|
|
20
|
+
export const isSamePreviewPath = (a, b) => normalizePreviewPath(a) === normalizePreviewPath(b);
|
package/dist/editor/theme.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useMemo } from 'react';
|
|
4
|
-
import { DEFAULT_THEME, MantineProvider, createTheme, } from '@mantine/core';
|
|
4
|
+
import { DEFAULT_THEME, MantineProvider, getDefaultZIndex, createTheme, } from '@mantine/core';
|
|
5
5
|
import { Notifications } from '@mantine/notifications';
|
|
6
6
|
import { ModalsProvider } from '@mantine/modals';
|
|
7
7
|
import { generateColors } from '@mantine/colors-generator';
|
|
@@ -62,5 +62,5 @@ export const createCanopyTheme = (options) => {
|
|
|
62
62
|
};
|
|
63
63
|
export const CanopyCMSProvider = ({ children, colors, colorScheme = 'light', themeOverride, withNotifications = true, }) => {
|
|
64
64
|
const theme = useMemo(() => createCanopyTheme({ colors, themeOverride }), [colors, themeOverride]);
|
|
65
|
-
return (_jsx(MantineProvider, { theme: theme, defaultColorScheme: colorScheme, children: _jsxs(ModalsProvider, { children: [withNotifications ? _jsx(Notifications, { position: "bottom-left" }) : null, children] }) }));
|
|
65
|
+
return (_jsx(MantineProvider, { theme: theme, defaultColorScheme: colorScheme, children: _jsxs(ModalsProvider, { modalProps: { zIndex: getDefaultZIndex('popover') }, children: [withNotifications ? _jsx(Notifications, { position: "bottom-left" }) : null, children] }) }));
|
|
66
66
|
};
|
|
@@ -12,10 +12,10 @@ import type { EntrySchemaRegistry } from './schema/types.js';
|
|
|
12
12
|
* interface to maintain. Keyed any other way, the derived map is keyed by that
|
|
13
13
|
* string instead and will not plug into `TEntryTypes`.
|
|
14
14
|
*
|
|
15
|
-
* Rejected at call time: an empty registry; a schema that is not a non-empty
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* Rejected at call time: an empty registry; a schema that is not a non-empty `EntrySchema`
|
|
16
|
+
* array; more than one `isTitle` per schema, or one on a non-string field or inside a list;
|
|
17
|
+
* more than one `isBody`, or one on a field that is not markdown/mdx or is named one of
|
|
18
|
+
* `RESOLVED_REFERENCE_KEYS`; a top-level or inline-group field named `unavailable`. This is also the one
|
|
19
19
|
* place the shared field-shape checks run: select fields must have options,
|
|
20
20
|
* reference fields must have `collections` or `entryTypes`, no inline groups
|
|
21
21
|
* inside object/block fields, no field-name collisions after group flattening.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { countTitleFields, findInvalidTitleFields, findTitleFieldsInLists, } from './utils/title-field.js';
|
|
2
2
|
import { countBodyFields, findInvalidBodyFields, findReservedBodyFieldName, } from './utils/body-field.js';
|
|
3
|
-
import { RESOLVED_REFERENCE_KEYS } from './entry-schema.js';
|
|
3
|
+
import { RESOLVED_REFERENCE_KEYS, RESTRICTED_REFERENCE_MARKER } from './entry-schema.js';
|
|
4
4
|
import { flattenGroupFields } from './utils/flatten-group-fields.js';
|
|
5
|
-
import { ensureSelectFieldsHaveOptions, ensureReferenceFieldsHaveScope, ensureNoFlattenedFieldNameCollisions, ensureNoGroupsInsideComplexFields, } from './config/validation.js';
|
|
5
|
+
import { ensureSelectFieldsHaveOptions, ensureReferenceFieldsHaveScope, ensureItemTitleFieldsExist, ensureNoFlattenedFieldNameCollisions, ensureNoGroupsInsideComplexFields, } from './config/validation.js';
|
|
6
6
|
/** Look up a field's type by dotted path (e.g., "meta.order").
|
|
7
7
|
* Groups are transparent — their children are searched at the same path level. */
|
|
8
8
|
function findFieldType(fields, dottedPath) {
|
|
@@ -35,10 +35,10 @@ function findFieldType(fields, dottedPath) {
|
|
|
35
35
|
* interface to maintain. Keyed any other way, the derived map is keyed by that
|
|
36
36
|
* string instead and will not plug into `TEntryTypes`.
|
|
37
37
|
*
|
|
38
|
-
* Rejected at call time: an empty registry; a schema that is not a non-empty
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
38
|
+
* Rejected at call time: an empty registry; a schema that is not a non-empty `EntrySchema`
|
|
39
|
+
* array; more than one `isTitle` per schema, or one on a non-string field or inside a list;
|
|
40
|
+
* more than one `isBody`, or one on a field that is not markdown/mdx or is named one of
|
|
41
|
+
* `RESOLVED_REFERENCE_KEYS`; a top-level or inline-group field named `unavailable`. This is also the one
|
|
42
42
|
* place the shared field-shape checks run: select fields must have options,
|
|
43
43
|
* reference fields must have `collections` or `entryTypes`, no inline groups
|
|
44
44
|
* inside object/block fields, no field-name collisions after group flattening.
|
|
@@ -92,8 +92,12 @@ export function createEntrySchemaRegistry(registry) {
|
|
|
92
92
|
if (reservedBodyField) {
|
|
93
93
|
throw new Error(`Entry schema registry entry "${key}": field "${reservedBodyField}" has isBody: true but "${reservedBodyField}" is reserved — reference resolution sets ${RESOLVED_REFERENCE_KEYS.map((k) => `"${k}"`).join(', ')} on a resolved reference, and a body field with one of those names would overwrite it. Rename the field (the body's field name is yours to choose; only these four are reserved).`);
|
|
94
94
|
}
|
|
95
|
+
if (flattenGroupFields(schema).some((f) => f.name === RESTRICTED_REFERENCE_MARKER)) {
|
|
96
|
+
throw new Error(`Entry schema registry entry "${key}": field "${RESTRICTED_REFERENCE_MARKER}" is reserved — a resolved reference carries "${RESTRICTED_REFERENCE_MARKER}: true" only when the reader may not read its target, so a field with that name cannot be delivered on a reference to this entry type. Rename the field.`);
|
|
97
|
+
}
|
|
95
98
|
ensureSelectFieldsHaveOptions(schema);
|
|
96
99
|
ensureReferenceFieldsHaveScope(schema);
|
|
100
|
+
ensureItemTitleFieldsExist(schema);
|
|
97
101
|
ensureNoGroupsInsideComplexFields(schema);
|
|
98
102
|
ensureNoFlattenedFieldNameCollisions(schema, `entry schema "${key}"`);
|
|
99
103
|
}
|
package/dist/entry-schema.d.ts
CHANGED
|
@@ -81,9 +81,6 @@ export interface ResolvedReferenceMeta {
|
|
|
81
81
|
* Assemble a resolved reference: the target's own data, then its body if the field asked to
|
|
82
82
|
* embed it, then the reserved metadata.
|
|
83
83
|
*
|
|
84
|
-
* Exists so the two places that construct one — the server resolver in content-store.ts and
|
|
85
|
-
* the editor's live-preview endpoint in api/resolve-references.ts — cannot drift.
|
|
86
|
-
*
|
|
87
84
|
* The ordering is the contract, not a detail. Metadata LAST means a target that models `id` as
|
|
88
85
|
* a content field cannot shadow the real content ID, which the write boundary recovers from
|
|
89
86
|
* `value.id` (`referenceValueId`) — a shadowed id makes a re-save persist the wrong value and
|
|
@@ -95,6 +92,30 @@ export declare function buildResolvedReference(data: Record<string, unknown>, me
|
|
|
95
92
|
fieldName: string;
|
|
96
93
|
value: string | undefined;
|
|
97
94
|
}): Record<string, unknown>;
|
|
95
|
+
/**
|
|
96
|
+
* The key that marks a `RestrictedReference`. Reserved as an entry field name, at the top level
|
|
97
|
+
* of any schema, because any schema can be a reference target.
|
|
98
|
+
*/
|
|
99
|
+
export declare const RESTRICTED_REFERENCE_MARKER = "unavailable";
|
|
100
|
+
/**
|
|
101
|
+
* What a reference resolves to when the reader may not read its target: enough to render a
|
|
102
|
+
* link (a title and the URL, which a denied reader can follow to a sign-in page) and nothing
|
|
103
|
+
* else of the target's data.
|
|
104
|
+
*
|
|
105
|
+
* `unavailable: true` is the marker a renderer branches on, so a denied target never arrives
|
|
106
|
+
* looking like a full one with its fields `undefined`; `reason` says why, leaving room for
|
|
107
|
+
* other reasons a target cannot be shown. A reference the reader may see in full never carries
|
|
108
|
+
* `unavailable`. `id` is always present, so a save of the referring entry writes the reference
|
|
109
|
+
* back unchanged (`normalizeReferenceValues` recovers it from `value.id`).
|
|
110
|
+
*/
|
|
111
|
+
export type RestrictedReference = Simplify<ResolvedReferenceMeta & {
|
|
112
|
+
/** The target's display title, by `resolveEntryTitle`'s fallback chain. */
|
|
113
|
+
title: string;
|
|
114
|
+
unavailable: true;
|
|
115
|
+
reason: 'restricted';
|
|
116
|
+
}>;
|
|
117
|
+
/** Assemble a {@link RestrictedReference}. Takes no target data, so none can leak into it. */
|
|
118
|
+
export declare function buildRestrictedReference(meta: ResolvedReferenceMeta, title: string): RestrictedReference;
|
|
98
119
|
/**
|
|
99
120
|
* Recursively flatten inline groups (type: 'group') out of a field tuple: they contribute
|
|
100
121
|
* no key to the content shape, so their children merge into the parent level and
|
|
@@ -205,7 +226,9 @@ type FieldValue<F extends InferableField> = F extends {
|
|
|
205
226
|
} ? ScalarValue<F, SelectValue<F>> : F extends {
|
|
206
227
|
type: 'reference';
|
|
207
228
|
resolvedSchema: infer S;
|
|
208
|
-
} ? ScalarValue<F, (InferContentShape<Extract<S, readonly InferableField[]>> & ResolvedReferenceMeta
|
|
229
|
+
} ? ScalarValue<F, (InferContentShape<Extract<S, readonly InferableField[]>> & ResolvedReferenceMeta & {
|
|
230
|
+
unavailable?: undefined;
|
|
231
|
+
}) | RestrictedReference | null> : F extends {
|
|
209
232
|
type: 'reference';
|
|
210
233
|
} ? ScalarValue<F, string | null> : F extends {
|
|
211
234
|
type: 'image';
|
package/dist/entry-schema.js
CHANGED
|
@@ -14,9 +14,6 @@ export const RESOLVED_REFERENCE_KEYS = ['id', 'slug', 'collection', 'urlPath'];
|
|
|
14
14
|
* Assemble a resolved reference: the target's own data, then its body if the field asked to
|
|
15
15
|
* embed it, then the reserved metadata.
|
|
16
16
|
*
|
|
17
|
-
* Exists so the two places that construct one — the server resolver in content-store.ts and
|
|
18
|
-
* the editor's live-preview endpoint in api/resolve-references.ts — cannot drift.
|
|
19
|
-
*
|
|
20
17
|
* The ordering is the contract, not a detail. Metadata LAST means a target that models `id` as
|
|
21
18
|
* a content field cannot shadow the real content ID, which the write boundary recovers from
|
|
22
19
|
* `value.id` (`referenceValueId`) — a shadowed id makes a re-save persist the wrong value and
|
|
@@ -35,8 +32,28 @@ export function buildResolvedReference(data, meta, body) {
|
|
|
35
32
|
resolved.slug = meta.slug;
|
|
36
33
|
resolved.collection = meta.collection;
|
|
37
34
|
resolved.urlPath = meta.urlPath;
|
|
35
|
+
// Backstop for the registry's rejection of a field with this name (entry-schema-registry.ts):
|
|
36
|
+
// a full reference carrying the marker would read as one the reader may not see.
|
|
37
|
+
delete resolved[RESTRICTED_REFERENCE_MARKER];
|
|
38
38
|
return resolved;
|
|
39
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* The key that marks a `RestrictedReference`. Reserved as an entry field name, at the top level
|
|
42
|
+
* of any schema, because any schema can be a reference target.
|
|
43
|
+
*/
|
|
44
|
+
export const RESTRICTED_REFERENCE_MARKER = 'unavailable';
|
|
45
|
+
/** Assemble a {@link RestrictedReference}. Takes no target data, so none can leak into it. */
|
|
46
|
+
export function buildRestrictedReference(meta, title) {
|
|
47
|
+
return {
|
|
48
|
+
id: meta.id,
|
|
49
|
+
slug: meta.slug,
|
|
50
|
+
collection: meta.collection,
|
|
51
|
+
urlPath: meta.urlPath,
|
|
52
|
+
title,
|
|
53
|
+
unavailable: true,
|
|
54
|
+
reason: 'restricted',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
40
57
|
/** Define an entry schema's field array with literal inference, without sprinkling `as const`. */
|
|
41
58
|
export const defineEntrySchema = (fields) => fields;
|
|
42
59
|
/**
|
package/dist/git-manager.d.ts
CHANGED
|
@@ -1,7 +1,64 @@
|
|
|
1
1
|
import { type SimpleGitOptions, type StatusResult } from 'simple-git';
|
|
2
2
|
import type { OperatingMode } from './operating-mode/index.js';
|
|
3
|
+
import type { ProvisionLog } from './utils/provision-log.js';
|
|
3
4
|
export declare function gitChildEnv(overrides: Record<string, string>): Record<string, string>;
|
|
4
5
|
export declare function gitNetworkChildEnv(): Record<string, string>;
|
|
6
|
+
/**
|
|
7
|
+
* Settings written into every bare `remote.git` CanopyCMS creates: the worker's (prod) and the
|
|
8
|
+
* simulated remote (dev). A push runs `receive-pack` with remote.git's own config and none of the
|
|
9
|
+
* pusher's: git unsets `GIT_CONFIG_PARAMETERS` before spawning it for a local-path push. Unset, a
|
|
10
|
+
* push starts auto-housekeeping there (detached, or inside a Lambda that is frozen mid-run) that
|
|
11
|
+
* repacks while another process clones, and pushes under the default `unpackLimit` (100) leave
|
|
12
|
+
* loose objects that every local clone copies one NFS round trip at a time.
|
|
13
|
+
*
|
|
14
|
+
* Never an `extensions.*` key: once a repo is at `repositoryformatversion` 1, a git that does not
|
|
15
|
+
* know the key refuses it, and Lambda runs git 2.39.
|
|
16
|
+
* @internal Exported for tests.
|
|
17
|
+
*/
|
|
18
|
+
export declare const REMOTE_GIT_CONFIG: ReadonlyArray<readonly [key: string, value: string]>;
|
|
19
|
+
/** Write each of {@link REMOTE_GIT_CONFIG} into the bare repo `gitDir` only where it differs. */
|
|
20
|
+
export declare function ensureRemoteGitConfig(gitDir: string): Promise<void>;
|
|
21
|
+
interface BareRemoteObjectCounts {
|
|
22
|
+
loose: number;
|
|
23
|
+
packs: number;
|
|
24
|
+
}
|
|
25
|
+
export type BareRemoteRepackResult = {
|
|
26
|
+
repacked: false;
|
|
27
|
+
before: BareRemoteObjectCounts;
|
|
28
|
+
} | {
|
|
29
|
+
repacked: true;
|
|
30
|
+
before: BareRemoteObjectCounts;
|
|
31
|
+
after: BareRemoteObjectCounts;
|
|
32
|
+
ms: number;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Repack the bare repo `gitDir` once it holds more than {@link REMOTE_GIT_MAX_LOOSE_OBJECTS}
|
|
36
|
+
* loose objects or {@link REMOTE_GIT_MAX_PACKS} packs, then pack its refs. Under
|
|
37
|
+
* {@link REMOTE_GIT_CONFIG} every push adds a pack, and nothing else ever compacts them.
|
|
38
|
+
*
|
|
39
|
+
* Safe beside concurrent pushes and clones, which is why it is `--cruft` with no expiry:
|
|
40
|
+
* unreachable objects move into a cruft pack rather than being dropped, so a push that read an
|
|
41
|
+
* old object before the repack still finds it, and a repack only deletes packs it listed when it
|
|
42
|
+
* began. A clone that hardlinked a pack keeps that inode when the repack unlinks the remote's
|
|
43
|
+
* name for it, and packs are never modified in place. `repack -d` also removes the loose objects
|
|
44
|
+
* it packed and their emptied fan-out directories.
|
|
45
|
+
*/
|
|
46
|
+
export declare function repackBareRemoteIfNeeded(gitDir: string): Promise<BareRemoteRepackResult>;
|
|
47
|
+
/**
|
|
48
|
+
* Config every workspace clone writes into its own `.git/config`: the managed
|
|
49
|
+
* marker that ensureRemote's guard checks, and a fallback author for internal
|
|
50
|
+
* commits such as the orphan settings init (ensureAuthor() sets the real one
|
|
51
|
+
* before user-facing commits).
|
|
52
|
+
*/
|
|
53
|
+
export declare function managedWorkspaceConfig(gitBotAuthorName: string, gitBotAuthorEmail: string): Record<string, string>;
|
|
54
|
+
export interface CloneRepoOptions {
|
|
55
|
+
/** The clone's remote name; git's default is `origin`. */
|
|
56
|
+
remoteName?: string;
|
|
57
|
+
/** Leave the working tree unpopulated for the caller to check out. */
|
|
58
|
+
noCheckout?: boolean;
|
|
59
|
+
/** Written into the new repo's own config by the clone (`git clone -c`). */
|
|
60
|
+
config?: Record<string, string>;
|
|
61
|
+
}
|
|
5
62
|
/**
|
|
6
63
|
* Remote-tracking namespace that `syncGit()`'s GitHub fetch lands refs in
|
|
7
64
|
* (`+refs/heads/*:${GITHUB_TRACKING_REF_PREFIX}*`), instead of writing
|
|
@@ -69,6 +126,17 @@ export declare class GitRemoteRefMissingError extends Error {
|
|
|
69
126
|
*/
|
|
70
127
|
gitError?: unknown | undefined);
|
|
71
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* No git remote is configured and the one the strategy auto-detects does not
|
|
131
|
+
* exist yet: in prod, the EC2 worker creates `{workspaceRoot}/remote.git` on
|
|
132
|
+
* its first boot, so until then every request that needs a workspace fails
|
|
133
|
+
* here. Usually transient, unlike a missing remote in a mode with nothing to wait for.
|
|
134
|
+
* The HTTP layer maps it to a 503 (`http/worker-not-ready.ts`).
|
|
135
|
+
*/
|
|
136
|
+
export declare class RemoteNotReadyError extends Error {
|
|
137
|
+
readonly expectedRemotePath: string;
|
|
138
|
+
constructor(expectedRemotePath: string);
|
|
139
|
+
}
|
|
72
140
|
export interface ResolveRemoteUrlOptions {
|
|
73
141
|
mode: OperatingMode;
|
|
74
142
|
remoteUrl?: string;
|
|
@@ -108,6 +176,8 @@ export interface InitializeWorkspaceOptions {
|
|
|
108
176
|
* only; settings workspaces commit by explicit path and don't need it.
|
|
109
177
|
*/
|
|
110
178
|
gitExcludePattern?: string;
|
|
179
|
+
/** Times each provisioning step; no step lines are printed without one. */
|
|
180
|
+
provisionLog?: ProvisionLog;
|
|
111
181
|
}
|
|
112
182
|
export declare class GitManager {
|
|
113
183
|
private readonly git;
|
|
@@ -116,7 +186,13 @@ export declare class GitManager {
|
|
|
116
186
|
private readonly remote;
|
|
117
187
|
private readonly skipIndexMarker;
|
|
118
188
|
constructor(options: GitManagerOptions, gitOptions?: Partial<SimpleGitOptions>);
|
|
119
|
-
|
|
189
|
+
/**
|
|
190
|
+
* Single-branch clone of `baseBranch`, retried once: a clone can lose a race
|
|
191
|
+
* with the worker's repack of `remote.git` deleting a pack it had just
|
|
192
|
+
* listed. Before the retry it clears only what it created itself, so a
|
|
193
|
+
* target that held files beforehand is never touched.
|
|
194
|
+
*/
|
|
195
|
+
static cloneRepo(remoteUrl: string, targetPath: string, baseBranch?: string, options?: CloneRepoOptions): Promise<void>;
|
|
120
196
|
/**
|
|
121
197
|
* Initializes a local bare git repository to simulate a remote for dev mode,
|
|
122
198
|
* seeded with the current state of baseBranch. Idempotent: an existing remote
|
|
@@ -173,7 +249,7 @@ export declare class GitManager {
|
|
|
173
249
|
* deleteBranchHandler: a head left in `remote.git` forever makes the
|
|
174
250
|
* create -> publish -> squash-merge -> delete -> reuse-the-name cycle reject
|
|
175
251
|
* the reused branch's first publish non-fast-forward against the stale head
|
|
176
|
-
* (`GitManager.push()` pushes
|
|
252
|
+
* (`GitManager.push()` pushes the branch to the same name, and a squash-merged old tip is
|
|
177
253
|
* not an ancestor of the new branch), and a retried submit then skips the
|
|
178
254
|
* local push on a clean tree and enqueues the worker push of the STALE head,
|
|
179
255
|
* resurrecting the deleted branch's content on GitHub as an apparent success.
|
|
@@ -223,6 +299,8 @@ export declare class GitManager {
|
|
|
223
299
|
* @param source - Where `url` came from, for the thrown error message only.
|
|
224
300
|
*/
|
|
225
301
|
private static assertRemoteUrlAllowedInMode;
|
|
302
|
+
/** The not-ready error for a mode whose remote is auto-detected, or `undefined` for other modes. */
|
|
303
|
+
private static remoteNotReadyError;
|
|
226
304
|
/**
|
|
227
305
|
* Resolves the remote URL for git operations following the priority:
|
|
228
306
|
* 1. Explicit remoteUrl parameter
|
|
@@ -239,6 +317,17 @@ export declare class GitManager {
|
|
|
239
317
|
* @returns Remote URL or undefined if no remote is needed
|
|
240
318
|
*/
|
|
241
319
|
static resolveRemoteUrl(options: ResolveRemoteUrlOptions): Promise<string | undefined>;
|
|
320
|
+
/**
|
|
321
|
+
* {@link resolveRemoteUrl} for a workspace about to be cloned, which needs a
|
|
322
|
+
* remote: none resolving is the worker-not-ready error in a mode whose
|
|
323
|
+
* remote the worker creates, and a configuration error otherwise.
|
|
324
|
+
*/
|
|
325
|
+
static resolveCloneRemoteUrl(options: ResolveRemoteUrlOptions): Promise<string>;
|
|
326
|
+
/**
|
|
327
|
+
* {@link cloneRepo} for a workspace, failing with one message that names the
|
|
328
|
+
* workspace, the remote and the base branch, which git's own error mixes.
|
|
329
|
+
*/
|
|
330
|
+
static cloneWorkspace(remoteUrl: string, workspacePath: string, baseBranch: string, options: CloneRepoOptions): Promise<void>;
|
|
242
331
|
/**
|
|
243
332
|
* Check whether a git repository is already initialized at `workspacePath`.
|
|
244
333
|
*
|
|
@@ -275,6 +364,14 @@ export declare class GitManager {
|
|
|
275
364
|
*/
|
|
276
365
|
private invalidateContentIndexes;
|
|
277
366
|
checkoutBranch(branch: string): Promise<void>;
|
|
367
|
+
/**
|
|
368
|
+
* The one checkout of a `--no-checkout` clone, which has the base branch
|
|
369
|
+
* and its remote-tracking ref and nothing else, so neither the branch
|
|
370
|
+
* listing nor the fetch that {@link checkoutBranch} starts with is needed.
|
|
371
|
+
* The missing index makes git populate the whole tree, even for the base
|
|
372
|
+
* branch HEAD already names.
|
|
373
|
+
*/
|
|
374
|
+
checkoutFreshClone(branch: string): Promise<void>;
|
|
278
375
|
private checkoutBranchInner;
|
|
279
376
|
pullBase(): Promise<void>;
|
|
280
377
|
private pullBaseInner;
|
|
@@ -282,9 +379,22 @@ export declare class GitManager {
|
|
|
282
379
|
private pullCurrentBranchInner;
|
|
283
380
|
rebaseOntoBase(): Promise<void>;
|
|
284
381
|
private rebaseOntoBaseInner;
|
|
382
|
+
/** `--sparse` stages a named path outside a sparse clone's cone (branch-sparse.ts). */
|
|
285
383
|
add(files: string | string[]): Promise<void>;
|
|
384
|
+
/**
|
|
385
|
+
* Restrict the working tree to `dirs` in cone mode, which always keeps the root-level files.
|
|
386
|
+
* Runs before a `--no-checkout` clone's one checkout, which invalidates the content caches.
|
|
387
|
+
*/
|
|
388
|
+
setSparseCone(dirs: readonly string[]): Promise<void>;
|
|
389
|
+
/** Stage every working-tree change except canopycms's own state. See {@link stageAllExceptCanopyState}. */
|
|
390
|
+
addAllExceptCanopyState(): Promise<void>;
|
|
286
391
|
commit(message: string): Promise<void>;
|
|
287
392
|
push(branch?: string): Promise<void>;
|
|
393
|
+
/**
|
|
394
|
+
* The checked-out branch's plain name. `rev-parse --abbrev-ref HEAD` prints
|
|
395
|
+
* `heads/<name>` when a same-named tag exists, which is not a branch name.
|
|
396
|
+
*/
|
|
397
|
+
private currentBranchName;
|
|
288
398
|
/**
|
|
289
399
|
* Whether the local branch has commits the remote mirror doesn't -- i.e.
|
|
290
400
|
* whether push() would move the remote ref forward.
|
|
@@ -303,10 +413,19 @@ export declare class GitManager {
|
|
|
303
413
|
* ("couldn't find remote ref"); that counts as "ahead", not an error.
|
|
304
414
|
*/
|
|
305
415
|
hasUnpushedCommits(branch?: string): Promise<boolean>;
|
|
416
|
+
/**
|
|
417
|
+
* Repo-relative paths that differ between HEAD and its merge base with the
|
|
418
|
+
* base branch: everything the branch changes, across all of its commits.
|
|
419
|
+
* Diffs against the just-fetched base tip pinned to a SHA — the pullBaseInner
|
|
420
|
+
* constraint.
|
|
421
|
+
*/
|
|
422
|
+
listChangedPathsSinceBase(): Promise<string[]>;
|
|
306
423
|
ensureAuthor(author: {
|
|
307
424
|
name: string;
|
|
308
425
|
email: string;
|
|
309
426
|
}): Promise<void>;
|
|
427
|
+
/** Writes each key into this repo's own config only where it differs. */
|
|
428
|
+
ensureLocalConfig(values: Record<string, string>): Promise<void>;
|
|
310
429
|
ensureRemote(remoteUrl: string): Promise<void>;
|
|
311
430
|
hasUncommittedChanges(): Promise<boolean>;
|
|
312
431
|
getUncommittedFiles(): Promise<string[]>;
|
|
@@ -317,11 +436,59 @@ export declare class GitManager {
|
|
|
317
436
|
*/
|
|
318
437
|
ensureGitExclude(pattern: string): Promise<void>;
|
|
319
438
|
/**
|
|
320
|
-
*
|
|
321
|
-
* deployment-specific settings never pollute content history. It holds
|
|
322
|
-
* settings files committed by explicit path (permissions.json,
|
|
323
|
-
* the workspace root).
|
|
439
|
+
* Put the workspace on the settings branch: an orphan (no shared history),
|
|
440
|
+
* so deployment-specific settings never pollute content history. It holds
|
|
441
|
+
* only settings files committed by explicit path (permissions.json,
|
|
442
|
+
* groups.json at the workspace root).
|
|
443
|
+
*
|
|
444
|
+
* The remote is the settings branch's durable copy, and the workspace clone
|
|
445
|
+
* is `--single-branch` at the base branch, so the remote is asked first:
|
|
446
|
+
* - no local branch: check out the remote's, or create an empty orphan only
|
|
447
|
+
* when the remote has none. An unreadable remote throws
|
|
448
|
+
* {@link SettingsRemoteUnreadableError} rather than guess "none".
|
|
449
|
+
* - local branch present: a history unrelated to the remote's is repaired
|
|
450
|
+
* onto the remote's when the local branch is still its empty initial
|
|
451
|
+
* commit with a clean working tree, and otherwise throws
|
|
452
|
+
* {@link SettingsBranchDivergedError}; local commits are never discarded.
|
|
453
|
+
* An unreadable remote throws only for that empty branch, since one that
|
|
454
|
+
* holds settings can serve them and the next save surfaces the remote error.
|
|
455
|
+
* Either way a remote branch holding content is never adopted:
|
|
456
|
+
* {@link SettingsBranchHasContentHistoryError}.
|
|
324
457
|
*/
|
|
325
458
|
createOrphanSettingsBranch(branchName: string, initialFiles: Record<string, string>): Promise<void>;
|
|
326
459
|
private createOrphanSettingsBranchInner;
|
|
460
|
+
/**
|
|
461
|
+
* Compares the checked-out local settings branch with the remote's tip.
|
|
462
|
+
* Related histories are left for the next settings pull to reconcile; only
|
|
463
|
+
* an unrelated one is acted on here.
|
|
464
|
+
*/
|
|
465
|
+
private reconcileLocalSettingsBranch;
|
|
466
|
+
/**
|
|
467
|
+
* The remote's tip for `branch`, or `undefined` when the remote has no such
|
|
468
|
+
* branch. A remote that cannot be read throws: `ls-remote` exits 0 with no
|
|
469
|
+
* output only for a reachable remote without the ref.
|
|
470
|
+
*/
|
|
471
|
+
private remoteBranchTip;
|
|
472
|
+
/**
|
|
473
|
+
* Fetch `branch` from the remote and return the fetched commit, pinned as
|
|
474
|
+
* pullBaseInner explains. The full ref: a bare name resolves to a
|
|
475
|
+
* same-named tag first.
|
|
476
|
+
*/
|
|
477
|
+
private fetchBranchTip;
|
|
478
|
+
/**
|
|
479
|
+
* Refuse to adopt a remote settings branch that holds content: its tip has a file other than
|
|
480
|
+
* the settings files, or its roots include the base branch's (a settings branch is an orphan).
|
|
481
|
+
* Neither alone suffices: a base can have a root of its own, and a content tree can be pruned.
|
|
482
|
+
* The base comes from the remote when the clone lacks it (it was cloned at an earlier base).
|
|
483
|
+
*/
|
|
484
|
+
private assertNotContentHistory;
|
|
485
|
+
private baseBranchRev;
|
|
486
|
+
private rootCommits;
|
|
487
|
+
/**
|
|
488
|
+
* Whether `branch` is a single parentless commit with an empty tree, as
|
|
489
|
+
* orphan creation leaves it. Full refs throughout: a bare name resolves to a
|
|
490
|
+
* same-named tag first, and clones fetch tags.
|
|
491
|
+
*/
|
|
492
|
+
private isEmptyInitialBranch;
|
|
327
493
|
}
|
|
494
|
+
export {};
|