canopycms 0.0.61-int.74 → 0.0.61
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/dist/ai/handler.js +1 -1
- package/dist/ai/handler.js.map +1 -1
- package/dist/api/assets.d.ts.map +1 -1
- package/dist/api/assets.js +36 -4
- package/dist/api/assets.js.map +1 -1
- package/dist/api/branch-status.d.ts.map +1 -1
- package/dist/api/branch-status.js +56 -0
- package/dist/api/branch-status.js.map +1 -1
- package/dist/api/branch-withdraw.d.ts.map +1 -1
- package/dist/api/branch-withdraw.js +14 -3
- package/dist/api/branch-withdraw.js.map +1 -1
- package/dist/api/branch.d.ts +31 -2
- package/dist/api/branch.d.ts.map +1 -1
- package/dist/api/branch.js +252 -13
- package/dist/api/branch.js.map +1 -1
- package/dist/api/content.d.ts.map +1 -1
- package/dist/api/content.js +12 -4
- package/dist/api/content.js.map +1 -1
- package/dist/api/entries.d.ts.map +1 -1
- package/dist/api/entries.js +11 -9
- package/dist/api/entries.js.map +1 -1
- package/dist/api/guards.d.ts.map +1 -1
- package/dist/api/guards.js +12 -5
- package/dist/api/guards.js.map +1 -1
- package/dist/api/permissions.d.ts +2 -2
- package/dist/api/permissions.d.ts.map +1 -1
- package/dist/api/permissions.js +51 -3
- package/dist/api/permissions.js.map +1 -1
- package/dist/api/reference-options.d.ts.map +1 -1
- package/dist/api/reference-options.js +10 -17
- package/dist/api/reference-options.js.map +1 -1
- package/dist/api/resolve-references.d.ts.map +1 -1
- package/dist/api/resolve-references.js +3 -1
- package/dist/api/resolve-references.js.map +1 -1
- package/dist/api/schema.d.ts.map +1 -1
- package/dist/api/schema.js +3 -2
- package/dist/api/schema.js.map +1 -1
- package/dist/api/settings-helpers.d.ts.map +1 -1
- package/dist/api/settings-helpers.js +6 -5
- package/dist/api/settings-helpers.js.map +1 -1
- package/dist/assets/pipeline.d.ts +11 -2
- package/dist/assets/pipeline.d.ts.map +1 -1
- package/dist/assets/pipeline.js +114 -2
- package/dist/assets/pipeline.js.map +1 -1
- package/dist/assets/transform-directives.d.ts +18 -0
- package/dist/assets/transform-directives.d.ts.map +1 -1
- package/dist/assets/transform-directives.js +18 -0
- package/dist/assets/transform-directives.js.map +1 -1
- package/dist/assets/transform.d.ts.map +1 -1
- package/dist/assets/transform.js +1 -10
- package/dist/assets/transform.js.map +1 -1
- package/dist/auth/types.d.ts +29 -0
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/authorization/index.d.ts +1 -1
- package/dist/authorization/index.d.ts.map +1 -1
- package/dist/authorization/index.js +1 -1
- package/dist/authorization/index.js.map +1 -1
- package/dist/authorization/protected-branch.d.ts +75 -0
- package/dist/authorization/protected-branch.d.ts.map +1 -1
- package/dist/authorization/protected-branch.js +39 -0
- package/dist/authorization/protected-branch.js.map +1 -1
- package/dist/branch-registry.d.ts.map +1 -1
- package/dist/branch-registry.js +5 -1
- package/dist/branch-registry.js.map +1 -1
- package/dist/branch-schema-cache.d.ts.map +1 -1
- package/dist/branch-schema-cache.js +9 -0
- package/dist/branch-schema-cache.js.map +1 -1
- package/dist/build/generate-ai-content.js +1 -1
- package/dist/build/generate-ai-content.js.map +1 -1
- package/dist/cli/cli.js +1442 -828
- package/dist/cli/generate-ai-content.js +404 -136
- package/dist/cli/init.d.ts +8 -2
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +440 -151
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/project-detect.d.ts +89 -0
- package/dist/cli/project-detect.d.ts.map +1 -0
- package/dist/cli/project-detect.js +240 -0
- package/dist/cli/project-detect.js.map +1 -0
- package/dist/cli/template-files/Dockerfile.cms.template +11 -6
- package/dist/cli/template-files/cdk-app.ts.template +82 -0
- package/dist/cli/template-files/cdk.json.template +9 -0
- package/dist/cli/template-files/cms-stack.ts.template +124 -0
- package/dist/cli/template-files/deploy-cms.yml.template +125 -13
- package/dist/cli/template-files/dockerignore.template +2 -1
- package/dist/cli/templates.d.ts +26 -2
- package/dist/cli/templates.d.ts.map +1 -1
- package/dist/cli/templates.js +36 -4
- package/dist/cli/templates.js.map +1 -1
- package/dist/config/schemas/config.d.ts +2 -3
- package/dist/config/schemas/config.d.ts.map +1 -1
- package/dist/config/schemas/config.js +21 -1
- package/dist/config/schemas/config.js.map +1 -1
- package/dist/config/validation.d.ts +9 -0
- package/dist/config/validation.d.ts.map +1 -1
- package/dist/config/validation.js +22 -12
- package/dist/config/validation.js.map +1 -1
- package/dist/content-reader.js +1 -1
- package/dist/content-reader.js.map +1 -1
- package/dist/content-store.d.ts +11 -0
- package/dist/content-store.d.ts.map +1 -1
- package/dist/content-store.js +2 -1
- package/dist/content-store.js.map +1 -1
- package/dist/dev-content-watcher.d.ts.map +1 -1
- package/dist/dev-content-watcher.js +4 -1
- package/dist/dev-content-watcher.js.map +1 -1
- package/dist/editor/BranchManager.d.ts +15 -0
- package/dist/editor/BranchManager.d.ts.map +1 -1
- package/dist/editor/BranchManager.js +43 -9
- package/dist/editor/BranchManager.js.map +1 -1
- package/dist/editor/CanopyEditor.d.ts.map +1 -1
- package/dist/editor/CanopyEditor.js +2 -2
- package/dist/editor/CanopyEditor.js.map +1 -1
- package/dist/editor/Editor.d.ts.map +1 -1
- package/dist/editor/Editor.js +110 -48
- package/dist/editor/Editor.js.map +1 -1
- package/dist/editor/admin/SystemHealthPanel.d.ts.map +1 -1
- package/dist/editor/admin/SystemHealthPanel.js +9 -8
- package/dist/editor/admin/SystemHealthPanel.js.map +1 -1
- package/dist/editor/components/EditorHeader.d.ts +6 -0
- package/dist/editor/components/EditorHeader.d.ts.map +1 -1
- package/dist/editor/components/EditorHeader.js +76 -23
- package/dist/editor/components/EditorHeader.js.map +1 -1
- package/dist/editor/components/EntryCreateModal.d.ts.map +1 -1
- package/dist/editor/components/EntryCreateModal.js +21 -6
- package/dist/editor/components/EntryCreateModal.js.map +1 -1
- package/dist/editor/context/SWRProvider.d.ts +31 -0
- package/dist/editor/context/SWRProvider.d.ts.map +1 -0
- package/dist/editor/context/SWRProvider.js +12 -0
- package/dist/editor/context/SWRProvider.js.map +1 -0
- package/dist/editor/context/index.d.ts +3 -0
- package/dist/editor/context/index.d.ts.map +1 -1
- package/dist/editor/context/index.js +3 -0
- package/dist/editor/context/index.js.map +1 -1
- package/dist/editor/editor-utils.d.ts.map +1 -1
- package/dist/editor/editor-utils.js +8 -2
- package/dist/editor/editor-utils.js.map +1 -1
- package/dist/editor/fields/ImageField.d.ts.map +1 -1
- package/dist/editor/fields/ImageField.js +27 -3
- package/dist/editor/fields/ImageField.js.map +1 -1
- package/dist/editor/fields/ReferenceField.d.ts.map +1 -1
- package/dist/editor/fields/ReferenceField.js +52 -31
- package/dist/editor/fields/ReferenceField.js.map +1 -1
- package/dist/editor/hooks/__test__/test-utils.d.ts +38 -3
- package/dist/editor/hooks/__test__/test-utils.d.ts.map +1 -1
- package/dist/editor/hooks/__test__/test-utils.js +50 -4
- package/dist/editor/hooks/__test__/test-utils.js.map +1 -1
- package/dist/editor/hooks/index.d.ts +4 -1
- package/dist/editor/hooks/index.d.ts.map +1 -1
- package/dist/editor/hooks/index.js +4 -1
- package/dist/editor/hooks/index.js.map +1 -1
- package/dist/editor/hooks/useBranchManager.d.ts +21 -1
- package/dist/editor/hooks/useBranchManager.d.ts.map +1 -1
- package/dist/editor/hooks/useBranchManager.js +68 -32
- package/dist/editor/hooks/useBranchManager.js.map +1 -1
- package/dist/editor/hooks/useBranchesData.d.ts +57 -0
- package/dist/editor/hooks/useBranchesData.d.ts.map +1 -0
- package/dist/editor/hooks/useBranchesData.js +69 -0
- package/dist/editor/hooks/useBranchesData.js.map +1 -0
- package/dist/editor/hooks/useCommentSystem.d.ts.map +1 -1
- package/dist/editor/hooks/useCommentSystem.js +24 -22
- package/dist/editor/hooks/useCommentSystem.js.map +1 -1
- package/dist/editor/hooks/useCommentsData.d.ts +29 -0
- package/dist/editor/hooks/useCommentsData.d.ts.map +1 -0
- package/dist/editor/hooks/useCommentsData.js +40 -0
- package/dist/editor/hooks/useCommentsData.js.map +1 -0
- package/dist/editor/hooks/useDraftManager.d.ts.map +1 -1
- package/dist/editor/hooks/useDraftManager.js +32 -18
- package/dist/editor/hooks/useDraftManager.js.map +1 -1
- package/dist/editor/hooks/useEntriesData.d.ts +35 -0
- package/dist/editor/hooks/useEntriesData.d.ts.map +1 -0
- package/dist/editor/hooks/useEntriesData.js +96 -0
- package/dist/editor/hooks/useEntriesData.js.map +1 -0
- package/dist/editor/hooks/useEntryManager.d.ts +8 -15
- package/dist/editor/hooks/useEntryManager.d.ts.map +1 -1
- package/dist/editor/hooks/useEntryManager.js +259 -117
- package/dist/editor/hooks/useEntryManager.js.map +1 -1
- package/dist/editor/hooks/usePermissionManager.d.ts +2 -2
- package/dist/editor/hooks/usePermissionManager.d.ts.map +1 -1
- package/dist/editor/hooks/usePermissionManager.js +11 -9
- package/dist/editor/hooks/usePermissionManager.js.map +1 -1
- package/dist/editor/hooks/useReferenceResolution.d.ts.map +1 -1
- package/dist/editor/hooks/useReferenceResolution.js +24 -1
- package/dist/editor/hooks/useReferenceResolution.js.map +1 -1
- package/dist/editor/media/MediaLibraryBody.d.ts.map +1 -1
- package/dist/editor/media/MediaLibraryBody.js +12 -2
- package/dist/editor/media/MediaLibraryBody.js.map +1 -1
- package/dist/editor/permission-manager/GroupSelector.d.ts.map +1 -1
- package/dist/editor/permission-manager/GroupSelector.js +7 -2
- package/dist/editor/permission-manager/GroupSelector.js.map +1 -1
- package/dist/editor/permission-manager/hooks/useGroupsAndUsers.d.ts +3 -3
- package/dist/editor/permission-manager/hooks/useGroupsAndUsers.d.ts.map +1 -1
- package/dist/editor/permission-manager/hooks/useGroupsAndUsers.js +1 -0
- package/dist/editor/permission-manager/hooks/useGroupsAndUsers.js.map +1 -1
- package/dist/editor/permission-manager/types.d.ts +6 -4
- package/dist/editor/permission-manager/types.d.ts.map +1 -1
- package/dist/editor/test-setup.js +8 -0
- package/dist/editor/test-setup.js.map +1 -1
- package/dist/git-manager.d.ts +126 -9
- package/dist/git-manager.d.ts.map +1 -1
- package/dist/git-manager.js +251 -27
- package/dist/git-manager.js.map +1 -1
- package/dist/github-service.d.ts.map +1 -1
- package/dist/github-service.js +13 -7
- package/dist/github-service.js.map +1 -1
- package/dist/http/handler.d.ts.map +1 -1
- package/dist/http/handler.js +8 -2
- package/dist/http/handler.js.map +1 -1
- package/dist/operating-mode/client-unsafe-strategy.d.ts.map +1 -1
- package/dist/operating-mode/client-unsafe-strategy.js +7 -8
- package/dist/operating-mode/client-unsafe-strategy.js.map +1 -1
- package/dist/operating-mode/deployment-name.d.ts +28 -0
- package/dist/operating-mode/deployment-name.d.ts.map +1 -0
- package/dist/operating-mode/deployment-name.js +78 -0
- package/dist/operating-mode/deployment-name.js.map +1 -0
- package/dist/operating-mode/index.d.ts +5 -1
- package/dist/operating-mode/index.d.ts.map +1 -1
- package/dist/operating-mode/index.js +7 -1
- package/dist/operating-mode/index.js.map +1 -1
- package/dist/operating-mode/types.d.ts +13 -3
- package/dist/operating-mode/types.d.ts.map +1 -1
- package/dist/paths/branch-name.d.ts +38 -0
- package/dist/paths/branch-name.d.ts.map +1 -1
- package/dist/paths/branch-name.js +46 -0
- package/dist/paths/branch-name.js.map +1 -1
- package/dist/paths/index.d.ts +1 -1
- package/dist/paths/index.d.ts.map +1 -1
- package/dist/paths/index.js +1 -1
- package/dist/paths/index.js.map +1 -1
- package/dist/reference-resolver.d.ts +6 -2
- package/dist/reference-resolver.d.ts.map +1 -1
- package/dist/reference-resolver.js +8 -1
- package/dist/reference-resolver.js.map +1 -1
- package/dist/schema/meta-loader.d.ts.map +1 -1
- package/dist/schema/meta-loader.js +10 -2
- package/dist/schema/meta-loader.js.map +1 -1
- package/dist/schema/schema-store.d.ts +11 -2
- package/dist/schema/schema-store.d.ts.map +1 -1
- package/dist/schema/schema-store.js +23 -11
- package/dist/schema/schema-store.js.map +1 -1
- package/dist/settings-workspace.d.ts +0 -15
- package/dist/settings-workspace.d.ts.map +1 -1
- package/dist/settings-workspace.js +97 -1
- package/dist/settings-workspace.js.map +1 -1
- package/dist/types.d.ts +63 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/debug.d.ts +11 -0
- package/dist/utils/debug.d.ts.map +1 -1
- package/dist/utils/debug.js +12 -1
- package/dist/utils/debug.js.map +1 -1
- package/dist/utils/git.d.ts +38 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +69 -0
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/logger.d.ts +71 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +85 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/validation/entry-type-reference-validator.d.ts +33 -0
- package/dist/validation/entry-type-reference-validator.d.ts.map +1 -0
- package/dist/validation/entry-type-reference-validator.js +110 -0
- package/dist/validation/entry-type-reference-validator.js.map +1 -0
- package/dist/worker/cms-worker.d.ts +232 -3
- package/dist/worker/cms-worker.d.ts.map +1 -1
- package/dist/worker/cms-worker.js +856 -87
- package/dist/worker/cms-worker.js.map +1 -1
- package/dist/worker/log.d.ts +61 -0
- package/dist/worker/log.d.ts.map +1 -0
- package/dist/worker/log.js +74 -0
- package/dist/worker/log.js.map +1 -0
- package/package.json +3 -1
|
@@ -38,6 +38,21 @@ var init_normalize = __esm({
|
|
|
38
38
|
}
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
+
// dist/utils/logger.js
|
|
42
|
+
function canopyLogWarn(...args) {
|
|
43
|
+
active.warn(...args);
|
|
44
|
+
}
|
|
45
|
+
function canopyLogError(...args) {
|
|
46
|
+
active.error(...args);
|
|
47
|
+
}
|
|
48
|
+
var active;
|
|
49
|
+
var init_logger = __esm({
|
|
50
|
+
"dist/utils/logger.js"() {
|
|
51
|
+
"use strict";
|
|
52
|
+
active = console;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
41
56
|
// dist/paths/types.js
|
|
42
57
|
var ROOT_COLLECTION_ID;
|
|
43
58
|
var init_types = __esm({
|
|
@@ -150,100 +165,6 @@ var init_flatten = __esm({
|
|
|
150
165
|
}
|
|
151
166
|
});
|
|
152
167
|
|
|
153
|
-
// dist/operating-mode/client-safe-strategy.js
|
|
154
|
-
function clientOperatingStrategy(mode) {
|
|
155
|
-
const cached = clientStrategyCache.get(mode);
|
|
156
|
-
if (cached)
|
|
157
|
-
return cached;
|
|
158
|
-
let strategy;
|
|
159
|
-
switch (mode) {
|
|
160
|
-
case "prod":
|
|
161
|
-
strategy = new ProdClientSafeStrategy();
|
|
162
|
-
break;
|
|
163
|
-
case "dev":
|
|
164
|
-
strategy = new DevClientSafeStrategy();
|
|
165
|
-
break;
|
|
166
|
-
default: {
|
|
167
|
-
const _exhaustive = mode;
|
|
168
|
-
throw new Error(`Unknown operating mode: ${_exhaustive}`);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
clientStrategyCache.set(mode, strategy);
|
|
172
|
-
return strategy;
|
|
173
|
-
}
|
|
174
|
-
function clearClientStrategyCache() {
|
|
175
|
-
clientStrategyCache.clear();
|
|
176
|
-
}
|
|
177
|
-
var ProdClientSafeStrategy, DevClientSafeStrategy, clientStrategyCache;
|
|
178
|
-
var init_client_safe_strategy = __esm({
|
|
179
|
-
"dist/operating-mode/client-safe-strategy.js"() {
|
|
180
|
-
"use strict";
|
|
181
|
-
ProdClientSafeStrategy = class {
|
|
182
|
-
constructor() {
|
|
183
|
-
this.mode = "prod";
|
|
184
|
-
}
|
|
185
|
-
// UI Feature Flags
|
|
186
|
-
supportsBranching() {
|
|
187
|
-
return true;
|
|
188
|
-
}
|
|
189
|
-
supportsStatusBadge() {
|
|
190
|
-
return true;
|
|
191
|
-
}
|
|
192
|
-
supportsComments() {
|
|
193
|
-
return true;
|
|
194
|
-
}
|
|
195
|
-
supportsPullRequests() {
|
|
196
|
-
return true;
|
|
197
|
-
}
|
|
198
|
-
// Simple Data
|
|
199
|
-
getPermissionsFileName() {
|
|
200
|
-
return "permissions.json";
|
|
201
|
-
}
|
|
202
|
-
getGroupsFileName() {
|
|
203
|
-
return "groups.json";
|
|
204
|
-
}
|
|
205
|
-
shouldCommit() {
|
|
206
|
-
return true;
|
|
207
|
-
}
|
|
208
|
-
shouldPush() {
|
|
209
|
-
return true;
|
|
210
|
-
}
|
|
211
|
-
};
|
|
212
|
-
DevClientSafeStrategy = class {
|
|
213
|
-
constructor() {
|
|
214
|
-
this.mode = "dev";
|
|
215
|
-
}
|
|
216
|
-
// UI Feature Flags
|
|
217
|
-
supportsBranching() {
|
|
218
|
-
return true;
|
|
219
|
-
}
|
|
220
|
-
supportsStatusBadge() {
|
|
221
|
-
return true;
|
|
222
|
-
}
|
|
223
|
-
supportsComments() {
|
|
224
|
-
return true;
|
|
225
|
-
}
|
|
226
|
-
supportsPullRequests() {
|
|
227
|
-
return false;
|
|
228
|
-
}
|
|
229
|
-
// Simple Data
|
|
230
|
-
getPermissionsFileName() {
|
|
231
|
-
return "permissions.json";
|
|
232
|
-
}
|
|
233
|
-
getGroupsFileName() {
|
|
234
|
-
return "groups.json";
|
|
235
|
-
}
|
|
236
|
-
shouldCommit() {
|
|
237
|
-
return true;
|
|
238
|
-
}
|
|
239
|
-
shouldPush() {
|
|
240
|
-
return true;
|
|
241
|
-
}
|
|
242
|
-
};
|
|
243
|
-
clientStrategyCache = /* @__PURE__ */ new Map();
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
|
|
247
168
|
// dist/config/types.js
|
|
248
169
|
var primitiveFieldTypes, fieldTypes;
|
|
249
170
|
var init_types2 = __esm({
|
|
@@ -502,6 +423,16 @@ var init_config = __esm({
|
|
|
502
423
|
allowNetworkRemoteInProd: z5.boolean().optional(),
|
|
503
424
|
settingsBranch: z5.string().optional(),
|
|
504
425
|
autoCreateSettingsPR: z5.boolean().optional(),
|
|
426
|
+
// Deliberately `deploymentNameSchema.optional()`, NOT `deploymentNameSchema` alone.
|
|
427
|
+
// deploymentNameSchema.default('prod') would make `parse(undefined)` resolve to
|
|
428
|
+
// the literal 'prod' instead of staying `undefined` — collapsing the
|
|
429
|
+
// env > config > modeDefault precedence chain that resolveDeploymentName
|
|
430
|
+
// (operating-mode/deployment-name.ts) implements: config would then always
|
|
431
|
+
// "win" over modeDefault (masking dev's real default of 'local'), and the env
|
|
432
|
+
// var would just be racing config's baked-in 'prod' instead of a true absence.
|
|
433
|
+
// `.optional()` here is what keeps an omitted deploymentName reaching
|
|
434
|
+
// resolveDeploymentName as `undefined`, so it can fall through to modeDefault.
|
|
435
|
+
// Do not "fix" this by removing `.optional()`.
|
|
505
436
|
deploymentName: deploymentNameSchema.optional(),
|
|
506
437
|
contentRoot: contentRootSchema.default("content"),
|
|
507
438
|
sourceRoot: sourceRootSchema.optional(),
|
|
@@ -515,6 +446,154 @@ var init_config = __esm({
|
|
|
515
446
|
}
|
|
516
447
|
});
|
|
517
448
|
|
|
449
|
+
// dist/config/validation.js
|
|
450
|
+
var forEachReferenceField;
|
|
451
|
+
var init_validation = __esm({
|
|
452
|
+
"dist/config/validation.js"() {
|
|
453
|
+
"use strict";
|
|
454
|
+
init_config();
|
|
455
|
+
init_flatten();
|
|
456
|
+
forEachReferenceField = (fields, visit) => {
|
|
457
|
+
if (!Array.isArray(fields))
|
|
458
|
+
return;
|
|
459
|
+
for (const field of fields) {
|
|
460
|
+
const f = field;
|
|
461
|
+
if (f?.type === "reference") {
|
|
462
|
+
visit(f);
|
|
463
|
+
}
|
|
464
|
+
if (f?.type === "group" || f?.type === "object") {
|
|
465
|
+
forEachReferenceField(f.fields, visit);
|
|
466
|
+
}
|
|
467
|
+
if (f?.type === "block" && Array.isArray(f.templates)) {
|
|
468
|
+
for (const template of f.templates) {
|
|
469
|
+
forEachReferenceField(template.fields, visit);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
// dist/operating-mode/client-safe-strategy.js
|
|
478
|
+
function clientOperatingStrategy(mode) {
|
|
479
|
+
const cached = clientStrategyCache.get(mode);
|
|
480
|
+
if (cached)
|
|
481
|
+
return cached;
|
|
482
|
+
let strategy;
|
|
483
|
+
switch (mode) {
|
|
484
|
+
case "prod":
|
|
485
|
+
strategy = new ProdClientSafeStrategy();
|
|
486
|
+
break;
|
|
487
|
+
case "dev":
|
|
488
|
+
strategy = new DevClientSafeStrategy();
|
|
489
|
+
break;
|
|
490
|
+
default: {
|
|
491
|
+
const _exhaustive = mode;
|
|
492
|
+
throw new Error(`Unknown operating mode: ${_exhaustive}`);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
clientStrategyCache.set(mode, strategy);
|
|
496
|
+
return strategy;
|
|
497
|
+
}
|
|
498
|
+
function clearClientStrategyCache() {
|
|
499
|
+
clientStrategyCache.clear();
|
|
500
|
+
}
|
|
501
|
+
var ProdClientSafeStrategy, DevClientSafeStrategy, clientStrategyCache;
|
|
502
|
+
var init_client_safe_strategy = __esm({
|
|
503
|
+
"dist/operating-mode/client-safe-strategy.js"() {
|
|
504
|
+
"use strict";
|
|
505
|
+
ProdClientSafeStrategy = class {
|
|
506
|
+
constructor() {
|
|
507
|
+
this.mode = "prod";
|
|
508
|
+
}
|
|
509
|
+
// UI Feature Flags
|
|
510
|
+
supportsBranching() {
|
|
511
|
+
return true;
|
|
512
|
+
}
|
|
513
|
+
supportsStatusBadge() {
|
|
514
|
+
return true;
|
|
515
|
+
}
|
|
516
|
+
supportsComments() {
|
|
517
|
+
return true;
|
|
518
|
+
}
|
|
519
|
+
supportsPullRequests() {
|
|
520
|
+
return true;
|
|
521
|
+
}
|
|
522
|
+
// Simple Data
|
|
523
|
+
getPermissionsFileName() {
|
|
524
|
+
return "permissions.json";
|
|
525
|
+
}
|
|
526
|
+
getGroupsFileName() {
|
|
527
|
+
return "groups.json";
|
|
528
|
+
}
|
|
529
|
+
shouldCommit() {
|
|
530
|
+
return true;
|
|
531
|
+
}
|
|
532
|
+
shouldPush() {
|
|
533
|
+
return true;
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
DevClientSafeStrategy = class {
|
|
537
|
+
constructor() {
|
|
538
|
+
this.mode = "dev";
|
|
539
|
+
}
|
|
540
|
+
// UI Feature Flags
|
|
541
|
+
supportsBranching() {
|
|
542
|
+
return true;
|
|
543
|
+
}
|
|
544
|
+
supportsStatusBadge() {
|
|
545
|
+
return true;
|
|
546
|
+
}
|
|
547
|
+
supportsComments() {
|
|
548
|
+
return true;
|
|
549
|
+
}
|
|
550
|
+
supportsPullRequests() {
|
|
551
|
+
return false;
|
|
552
|
+
}
|
|
553
|
+
// Simple Data
|
|
554
|
+
getPermissionsFileName() {
|
|
555
|
+
return "permissions.json";
|
|
556
|
+
}
|
|
557
|
+
getGroupsFileName() {
|
|
558
|
+
return "groups.json";
|
|
559
|
+
}
|
|
560
|
+
shouldCommit() {
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
shouldPush() {
|
|
564
|
+
return true;
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
clientStrategyCache = /* @__PURE__ */ new Map();
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
// dist/operating-mode/deployment-name.js
|
|
572
|
+
function resolveDeploymentName(config, modeDefault) {
|
|
573
|
+
const envValue = process.env.CANOPYCMS_DEPLOYMENT_NAME?.trim();
|
|
574
|
+
const configValue = config.deploymentName;
|
|
575
|
+
if (envValue && configValue && envValue !== configValue && !warned) {
|
|
576
|
+
canopyLogWarn(`CanopyCMS: CANOPYCMS_DEPLOYMENT_NAME ("${envValue}") differs from config.deploymentName ("${configValue}") \u2014 using the env var (infra-stamped env wins over shared-repo config by design; see resolveDeploymentName's doc comment). Update config.deploymentName to match if this mismatch was unintentional.`);
|
|
577
|
+
warned = true;
|
|
578
|
+
}
|
|
579
|
+
const resolved = envValue || configValue || modeDefault;
|
|
580
|
+
if (!isValidDeploymentName(resolved)) {
|
|
581
|
+
const source = envValue ? "CANOPYCMS_DEPLOYMENT_NAME" : configValue ? "config.deploymentName" : "the mode default";
|
|
582
|
+
throw new Error(`CanopyCMS: invalid deploymentName ${JSON.stringify(resolved)} (from ${source}). It is interpolated into the settings branch name (canopycms-settings-<deploymentName>), so it must start with a letter or digit, contain only letters, digits, '.', '_' or '-', and must not contain '..' or end with '.' or '.lock'.`);
|
|
583
|
+
}
|
|
584
|
+
return resolved;
|
|
585
|
+
}
|
|
586
|
+
var warned, VALID_DEPLOYMENT_NAME, isValidDeploymentName;
|
|
587
|
+
var init_deployment_name = __esm({
|
|
588
|
+
"dist/operating-mode/deployment-name.js"() {
|
|
589
|
+
"use strict";
|
|
590
|
+
init_logger();
|
|
591
|
+
warned = false;
|
|
592
|
+
VALID_DEPLOYMENT_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
593
|
+
isValidDeploymentName = (name) => VALID_DEPLOYMENT_NAME.test(name) && !name.includes("..") && !name.endsWith(".") && !name.endsWith(".lock");
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
|
|
518
597
|
// dist/config/schemas/permissions.js
|
|
519
598
|
import { z as z6 } from "zod";
|
|
520
599
|
var permissionTargetSchema, pathPermissionSchema;
|
|
@@ -534,15 +613,6 @@ var init_permissions = __esm({
|
|
|
534
613
|
}
|
|
535
614
|
});
|
|
536
615
|
|
|
537
|
-
// dist/config/validation.js
|
|
538
|
-
var init_validation = __esm({
|
|
539
|
-
"dist/config/validation.js"() {
|
|
540
|
-
"use strict";
|
|
541
|
-
init_config();
|
|
542
|
-
init_flatten();
|
|
543
|
-
}
|
|
544
|
-
});
|
|
545
|
-
|
|
546
616
|
// dist/config/helpers.js
|
|
547
617
|
var init_helpers = __esm({
|
|
548
618
|
"dist/config/helpers.js"() {
|
|
@@ -597,6 +667,7 @@ var init_client_unsafe_strategy = __esm({
|
|
|
597
667
|
"dist/operating-mode/client-unsafe-strategy.js"() {
|
|
598
668
|
"use strict";
|
|
599
669
|
init_client_safe_strategy();
|
|
670
|
+
init_deployment_name();
|
|
600
671
|
init_config2();
|
|
601
672
|
ProdStrategy = class extends ProdClientSafeStrategy {
|
|
602
673
|
// All client-safe methods inherited automatically from ProdClientSafeStrategy:
|
|
@@ -607,8 +678,8 @@ var init_client_unsafe_strategy = __esm({
|
|
|
607
678
|
getWorkspaceRoot(_sourceRoot) {
|
|
608
679
|
return path6.resolve(process.env.CANOPYCMS_WORKSPACE_ROOT ?? DEFAULT_PROD_WORKSPACE);
|
|
609
680
|
}
|
|
610
|
-
getContentRoot(sourceRoot) {
|
|
611
|
-
return path6.resolve(sourceRoot ?? process.cwd(),
|
|
681
|
+
getContentRoot(contentRoot, sourceRoot) {
|
|
682
|
+
return path6.resolve(sourceRoot ?? process.cwd(), contentRoot);
|
|
612
683
|
}
|
|
613
684
|
getContentBranchesRoot(sourceRoot) {
|
|
614
685
|
return path6.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
|
|
@@ -639,8 +710,7 @@ var init_client_unsafe_strategy = __esm({
|
|
|
639
710
|
getSettingsBranchName(config) {
|
|
640
711
|
if (config.settingsBranch)
|
|
641
712
|
return config.settingsBranch;
|
|
642
|
-
|
|
643
|
-
return `canopycms-settings-${deploymentName}`;
|
|
713
|
+
return `canopycms-settings-${resolveDeploymentName(config, "prod")}`;
|
|
644
714
|
}
|
|
645
715
|
getSettingsRoot(sourceRoot) {
|
|
646
716
|
return path6.join(this.getWorkspaceRoot(sourceRoot), "settings");
|
|
@@ -662,8 +732,8 @@ var init_client_unsafe_strategy = __esm({
|
|
|
662
732
|
getWorkspaceRoot(sourceRoot) {
|
|
663
733
|
return path6.resolve(sourceRoot ?? process.cwd(), ".canopy-dev");
|
|
664
734
|
}
|
|
665
|
-
getContentRoot(sourceRoot) {
|
|
666
|
-
return path6.resolve(sourceRoot ?? process.cwd(),
|
|
735
|
+
getContentRoot(contentRoot, sourceRoot) {
|
|
736
|
+
return path6.resolve(sourceRoot ?? process.cwd(), contentRoot);
|
|
667
737
|
}
|
|
668
738
|
getContentBranchesRoot(sourceRoot) {
|
|
669
739
|
return path6.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
|
|
@@ -693,8 +763,7 @@ var init_client_unsafe_strategy = __esm({
|
|
|
693
763
|
getSettingsBranchName(config) {
|
|
694
764
|
if (config.settingsBranch)
|
|
695
765
|
return config.settingsBranch;
|
|
696
|
-
|
|
697
|
-
return `canopycms-settings-${deploymentName}`;
|
|
766
|
+
return `canopycms-settings-${resolveDeploymentName(config, "local")}`;
|
|
698
767
|
}
|
|
699
768
|
getSettingsRoot(sourceRoot) {
|
|
700
769
|
return path6.join(this.getWorkspaceRoot(sourceRoot), "settings");
|
|
@@ -718,13 +787,15 @@ __export(operating_mode_exports, {
|
|
|
718
787
|
clearClientStrategyCache: () => clearClientStrategyCache,
|
|
719
788
|
clearStrategyCache: () => clearStrategyCache,
|
|
720
789
|
clientOperatingStrategy: () => clientOperatingStrategy,
|
|
721
|
-
operatingStrategy: () => operatingStrategy
|
|
790
|
+
operatingStrategy: () => operatingStrategy,
|
|
791
|
+
resolveDeploymentName: () => resolveDeploymentName
|
|
722
792
|
});
|
|
723
793
|
var init_operating_mode = __esm({
|
|
724
794
|
"dist/operating-mode/index.js"() {
|
|
725
795
|
"use strict";
|
|
726
796
|
init_client_safe_strategy();
|
|
727
797
|
init_client_unsafe_strategy();
|
|
798
|
+
init_deployment_name();
|
|
728
799
|
}
|
|
729
800
|
});
|
|
730
801
|
|
|
@@ -1232,10 +1303,21 @@ var DebugLogger = class {
|
|
|
1232
1303
|
const minLevel = this.options.minLevel ?? "DEBUG";
|
|
1233
1304
|
return LOG_LEVELS[level] >= LOG_LEVELS[minLevel];
|
|
1234
1305
|
}
|
|
1306
|
+
/**
|
|
1307
|
+
* The ISO-8601 timestamp leads the line BARE - not wrapped in brackets as it
|
|
1308
|
+
* once was. `CANOPYCMS_DEBUG=true` can be set on the EC2 worker, whose stdout
|
|
1309
|
+
* appends to /var/log/canopy-worker/worker.log; the CloudWatch agent's
|
|
1310
|
+
* `multi_line_start_pattern` matches the timestamp at the START of a line
|
|
1311
|
+
* (see worker/log.ts's INVARIANT and cms-service.ts's agent config), so a
|
|
1312
|
+
* leading `[` meant every debug line was silently folded into the previous
|
|
1313
|
+
* event instead of starting its own. The bracketed `[prefix:category]` and
|
|
1314
|
+
* `[level]` fields still follow, so the human-readable shape is unchanged
|
|
1315
|
+
* apart from those two characters.
|
|
1316
|
+
*/
|
|
1235
1317
|
formatMessage(level, category, message) {
|
|
1236
1318
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
1237
1319
|
const prefix = this.options.prefix ?? "CanopyCMS";
|
|
1238
|
-
return
|
|
1320
|
+
return `${timestamp} [${prefix}:${category}] [${level}] ${message}`;
|
|
1239
1321
|
}
|
|
1240
1322
|
debug(category, message, data) {
|
|
1241
1323
|
if (this.shouldLog("DEBUG")) {
|
|
@@ -1350,6 +1432,7 @@ import { promises as fs4 } from "fs";
|
|
|
1350
1432
|
import { join } from "pathe";
|
|
1351
1433
|
import { z } from "zod";
|
|
1352
1434
|
import chokidar from "chokidar";
|
|
1435
|
+
init_logger();
|
|
1353
1436
|
var entryTypeMetaSchema = z.object({
|
|
1354
1437
|
name: z.string().min(1),
|
|
1355
1438
|
format: z.enum(["md", "mdx", "json", "yaml"]),
|
|
@@ -1407,7 +1490,7 @@ async function scanForCollectionMeta(baseDir, relativePath = "") {
|
|
|
1407
1490
|
collections.push(...nestedCollections);
|
|
1408
1491
|
} catch (err) {
|
|
1409
1492
|
if (err.code !== "ENOENT") {
|
|
1410
|
-
|
|
1493
|
+
canopyLogError(`Error loading ${metaPath}:`, err);
|
|
1411
1494
|
throw new Error(`Invalid .collection.json in ${folderPath}: ${err.message}`);
|
|
1412
1495
|
}
|
|
1413
1496
|
const nestedCollections = await scanForCollectionMeta(absolutePath, folderPath);
|
|
@@ -1527,6 +1610,74 @@ function isValidSchema(schema) {
|
|
|
1527
1610
|
// dist/branch-schema-cache.js
|
|
1528
1611
|
init_flatten();
|
|
1529
1612
|
|
|
1613
|
+
// dist/validation/entry-type-reference-validator.js
|
|
1614
|
+
init_validation();
|
|
1615
|
+
var editDistance = (a, b) => {
|
|
1616
|
+
let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
1617
|
+
for (let i = 1; i <= a.length; i++) {
|
|
1618
|
+
const curr = [i];
|
|
1619
|
+
for (let j = 1; j <= b.length; j++) {
|
|
1620
|
+
curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
1621
|
+
}
|
|
1622
|
+
prev = curr;
|
|
1623
|
+
}
|
|
1624
|
+
return prev[b.length];
|
|
1625
|
+
};
|
|
1626
|
+
var closestName = (name, known) => {
|
|
1627
|
+
let best;
|
|
1628
|
+
let bestDistance = Infinity;
|
|
1629
|
+
for (const candidate of known) {
|
|
1630
|
+
const distance = editDistance(name.toLowerCase(), candidate.toLowerCase());
|
|
1631
|
+
if (distance < bestDistance) {
|
|
1632
|
+
bestDistance = distance;
|
|
1633
|
+
best = candidate;
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
const threshold = Math.max(2, Math.floor(name.length / 3));
|
|
1637
|
+
return best !== void 0 && bestDistance <= threshold ? best : void 0;
|
|
1638
|
+
};
|
|
1639
|
+
var forEachEntryType = (schema, visit) => {
|
|
1640
|
+
const walk = (node, nodePath) => {
|
|
1641
|
+
for (const entryType of node.entries ?? []) {
|
|
1642
|
+
visit(entryType, nodePath);
|
|
1643
|
+
}
|
|
1644
|
+
for (const child of node.collections ?? []) {
|
|
1645
|
+
walk(child, child.path ?? (nodePath ? `${nodePath}/${child.name}` : child.name));
|
|
1646
|
+
}
|
|
1647
|
+
};
|
|
1648
|
+
walk(schema, "");
|
|
1649
|
+
};
|
|
1650
|
+
var collectEntryTypeNames = (schema) => {
|
|
1651
|
+
const names = /* @__PURE__ */ new Set();
|
|
1652
|
+
forEachEntryType(schema, (entryType) => {
|
|
1653
|
+
if (typeof entryType.name === "string" && entryType.name.length > 0) {
|
|
1654
|
+
names.add(entryType.name);
|
|
1655
|
+
}
|
|
1656
|
+
});
|
|
1657
|
+
return names;
|
|
1658
|
+
};
|
|
1659
|
+
var validateReferenceEntryTypes = (schema) => {
|
|
1660
|
+
const known = collectEntryTypeNames(schema);
|
|
1661
|
+
const knownList = [...known].sort();
|
|
1662
|
+
const issues = [];
|
|
1663
|
+
forEachEntryType(schema, (entryType, collectionPath) => {
|
|
1664
|
+
const location = collectionPath ? `${collectionPath}/${entryType.name}` : entryType.name;
|
|
1665
|
+
forEachReferenceField(entryType.schema, (field) => {
|
|
1666
|
+
const entryTypes = field.entryTypes;
|
|
1667
|
+
if (!Array.isArray(entryTypes))
|
|
1668
|
+
return;
|
|
1669
|
+
const fieldName = typeof field.name === "string" ? field.name : "unknown";
|
|
1670
|
+
for (const value of entryTypes) {
|
|
1671
|
+
if (typeof value !== "string" || known.has(value))
|
|
1672
|
+
continue;
|
|
1673
|
+
const suggestion = closestName(value, knownList);
|
|
1674
|
+
issues.push(`Reference field "${fieldName}" in "${location}" specifies entryType "${value}", which is not defined in any collection.` + (suggestion ? ` Did you mean "${suggestion}"?` : "") + (knownList.length > 0 ? ` Known entry types: ${knownList.join(", ")}.` : " No entry types are defined in this schema."));
|
|
1675
|
+
}
|
|
1676
|
+
});
|
|
1677
|
+
});
|
|
1678
|
+
return issues;
|
|
1679
|
+
};
|
|
1680
|
+
|
|
1530
1681
|
// dist/build-mode.js
|
|
1531
1682
|
var isDeployedStatic = (config) => {
|
|
1532
1683
|
return config.deployedAs === "static";
|
|
@@ -1662,6 +1813,11 @@ var BranchSchemaCache = class {
|
|
|
1662
1813
|
if (!isValidSchema(result.schema)) {
|
|
1663
1814
|
throw new Error(`No schema found in ${contentRoot}. Create .collection.json files with references to field schemas defined in your entry schema registry.`);
|
|
1664
1815
|
}
|
|
1816
|
+
const entryTypeIssues = validateReferenceEntryTypes(result.schema);
|
|
1817
|
+
if (entryTypeIssues.length > 0) {
|
|
1818
|
+
throw new Error(`Invalid reference field entryTypes in ${contentRoot}:
|
|
1819
|
+
` + entryTypeIssues.map((issue) => ` - ${issue}`).join("\n"));
|
|
1820
|
+
}
|
|
1665
1821
|
const flatSchema = flattenSchema(result.schema, contentRootName);
|
|
1666
1822
|
if (!skipDiskCache) {
|
|
1667
1823
|
const cacheDir = path5.join(branchRoot, ".canopy-meta");
|
|
@@ -1888,6 +2044,7 @@ var ContentStore = class {
|
|
|
1888
2044
|
this.lastForcedRefreshMs = 0;
|
|
1889
2045
|
this.indexBuild = null;
|
|
1890
2046
|
this.root = path8.resolve(root);
|
|
2047
|
+
this.contentRootName = options.contentRootName || "content";
|
|
1891
2048
|
this.indexFreshnessIntervalMs = options.indexFreshnessIntervalMs ?? DEFAULT_INDEX_FRESHNESS_INTERVAL_MS;
|
|
1892
2049
|
this.schemaIndex = new Map(flatSchema.map((item) => [item.logicalPath, item]));
|
|
1893
2050
|
this._idIndex = new ContentIdIndex(this.root);
|
|
@@ -1929,7 +2086,7 @@ var ContentStore = class {
|
|
|
1929
2086
|
const build = (async () => {
|
|
1930
2087
|
const diskToken = await readContentIndexGeneration(this.root);
|
|
1931
2088
|
const fresh = new ContentIdIndex(this.root);
|
|
1932
|
-
await fresh.buildFromFilenames(
|
|
2089
|
+
await fresh.buildFromFilenames(this.contentRootName);
|
|
1933
2090
|
return { diskToken, fresh };
|
|
1934
2091
|
})();
|
|
1935
2092
|
this.indexBuild = build;
|
|
@@ -3718,6 +3875,7 @@ import path12 from "node:path";
|
|
|
3718
3875
|
// dist/branch-registry.js
|
|
3719
3876
|
import fs10 from "node:fs/promises";
|
|
3720
3877
|
import path10 from "node:path";
|
|
3878
|
+
init_logger();
|
|
3721
3879
|
var log3 = createDebugLogger({ prefix: "BranchRegistry" });
|
|
3722
3880
|
var REGISTRY_FILE = "branches.json";
|
|
3723
3881
|
var REGISTRY_STALE_FILE = "branches.stale.json";
|
|
@@ -3870,7 +4028,7 @@ var BranchRegistry = class {
|
|
|
3870
4028
|
try {
|
|
3871
4029
|
meta = await BranchMetadataFileManager.loadOnly(branchRoot);
|
|
3872
4030
|
} catch (err) {
|
|
3873
|
-
|
|
4031
|
+
canopyLogWarn(`CanopyCMS: Skipping branch directory '${entry.name}' during registry scan: ${getErrorMessage(err)}`);
|
|
3874
4032
|
continue;
|
|
3875
4033
|
}
|
|
3876
4034
|
if (meta) {
|
|
@@ -4280,15 +4438,17 @@ async function acquireProvisioningLock(lockTargetDir, lockName) {
|
|
|
4280
4438
|
// dist/git-manager.js
|
|
4281
4439
|
var log5 = createDebugLogger({ prefix: "GitManager" });
|
|
4282
4440
|
var GIT_ENV_PASSTHROUGH = /^(PATH|HOME|USER|LANG|LC_[A-Z]+|TZ|TMPDIR|GIT_(AUTHOR|COMMITTER)_(NAME|EMAIL|DATE)|GIT_TERMINAL_PROMPT|GIT_TRACE[0-9A-Z_]*)$/;
|
|
4441
|
+
var FORCE_C_LOCALE = { LC_ALL: "C", LANG: "C" };
|
|
4283
4442
|
function gitChildEnv(overrides) {
|
|
4284
4443
|
const env = {};
|
|
4285
4444
|
for (const [key, value] of Object.entries(process.env)) {
|
|
4286
4445
|
if (value !== void 0 && GIT_ENV_PASSTHROUGH.test(key))
|
|
4287
4446
|
env[key] = value;
|
|
4288
4447
|
}
|
|
4289
|
-
return { ...env, ...overrides };
|
|
4448
|
+
return { ...env, ...FORCE_C_LOCALE, ...overrides };
|
|
4290
4449
|
}
|
|
4291
4450
|
var remoteInitLocks = /* @__PURE__ */ new Map();
|
|
4451
|
+
var GITHUB_TRACKING_REF_PREFIX = "refs/remotes/github/";
|
|
4292
4452
|
async function ensureGitExcludePattern(repoPath, pattern) {
|
|
4293
4453
|
const excludePath = path14.join(repoPath, ".git", "info", "exclude");
|
|
4294
4454
|
await fs14.mkdir(path14.dirname(excludePath), { recursive: true });
|
|
@@ -4443,26 +4603,115 @@ var GitManager = class _GitManager {
|
|
|
4443
4603
|
await lockPromise;
|
|
4444
4604
|
}
|
|
4445
4605
|
/**
|
|
4446
|
-
* Whether a bare repository already has a
|
|
4606
|
+
* Whether a bare repository already has a branch of the given name, in
|
|
4607
|
+
* EITHER the local-heads namespace (`refs/heads/<branch>`) or the GitHub
|
|
4608
|
+
* tracking namespace (`GITHUB_TRACKING_REF_PREFIX<branch>`).
|
|
4609
|
+
*
|
|
4610
|
+
* Originally checked `refs/heads/*` only, for dev-mode's
|
|
4611
|
+
* `ensureLocalSimulatedRemote` (a simulated remote never gets a tracking
|
|
4612
|
+
* namespace, so that caller only ever needed the local-heads check).
|
|
4613
|
+
* Generalized/promoted to public for api/branch.ts's create-time collision
|
|
4614
|
+
* guard, which also needs the tracking namespace: `syncGit()` fetches
|
|
4615
|
+
* GitHub into `GITHUB_TRACKING_REF_PREFIX*` rather than `refs/heads/*`
|
|
4616
|
+
* directly (see that constant's doc comment above), and
|
|
4617
|
+
* `reconcileTrackedBranches()` (worker/cms-worker.ts) only
|
|
4618
|
+
* non-destructively brings `refs/heads/*` toward what's tracked there — so
|
|
4619
|
+
* a branch that another CanopyCMS deployment sharing this repo (or a
|
|
4620
|
+
* direct push to GitHub) just created can sit in the tracking namespace
|
|
4621
|
+
* for a while before, or without ever, gaining a local head here. Checking
|
|
4622
|
+
* `refs/heads/*` alone would miss exactly the two-deployments-one-repo
|
|
4623
|
+
* collision that guard exists to catch.
|
|
4447
4624
|
*
|
|
4448
4625
|
* Runs git with an explicit `--git-dir` instead of a cwd inside the repo:
|
|
4449
4626
|
* environments with `safe.bareRepository=explicit` (sandboxed/CI git setups)
|
|
4450
4627
|
* refuse cwd-based discovery of bare repos but expressly allow `--git-dir`.
|
|
4451
|
-
*
|
|
4452
|
-
* exception-based control flow —
|
|
4453
|
-
*
|
|
4454
|
-
*
|
|
4455
|
-
*
|
|
4456
|
-
*
|
|
4628
|
+
* A single `for-each-ref` call checks both candidate refs at once (no
|
|
4629
|
+
* exception-based control flow — `for-each-ref` exits 0 whether or not
|
|
4630
|
+
* either ref exists, same reason the old implementation used `branch
|
|
4631
|
+
* --list` instead of `rev-parse --verify --quiet`: simple-git only fails a
|
|
4632
|
+
* task on stderr output, and `--quiet` suppresses exactly that).
|
|
4633
|
+
* `--end-of-options` guards the ref-name positionals the same way
|
|
4634
|
+
* `push`/`forcePush` below do, since `branch` here can be a sanitized but
|
|
4635
|
+
* otherwise caller-influenced string.
|
|
4636
|
+
*
|
|
4637
|
+
* A failure here therefore means the remote itself is unreadable and is
|
|
4638
|
+
* surfaced, NOT treated as "branch absent" — that would route
|
|
4639
|
+
* `ensureLocalSimulatedRemote` to the push path against a repo it couldn't
|
|
4640
|
+
* even read, and would silently skip api/branch.ts's collision check
|
|
4641
|
+
* instead of letting that caller distinguish "unreadable" from "absent"
|
|
4642
|
+
* and decide what to do.
|
|
4457
4643
|
*/
|
|
4458
|
-
static async bareRemoteHasBranch(remotePath, branch) {
|
|
4644
|
+
static async bareRemoteHasBranch(remotePath, branch, options = {}) {
|
|
4459
4645
|
let output;
|
|
4460
4646
|
try {
|
|
4461
|
-
output = await simpleGit2().raw([
|
|
4647
|
+
output = await simpleGit2().raw([
|
|
4648
|
+
"--git-dir",
|
|
4649
|
+
remotePath,
|
|
4650
|
+
"for-each-ref",
|
|
4651
|
+
"--format=%(refname)",
|
|
4652
|
+
"--end-of-options",
|
|
4653
|
+
`refs/heads/${branch}`,
|
|
4654
|
+
`${GITHUB_TRACKING_REF_PREFIX}${branch}`
|
|
4655
|
+
]);
|
|
4462
4656
|
} catch (err) {
|
|
4463
|
-
throw new Error(`Cannot inspect
|
|
4657
|
+
throw new Error(`Cannot inspect remote mirror at ${remotePath}: ${getErrorMessage(err)}`);
|
|
4658
|
+
}
|
|
4659
|
+
const refs = output.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
4660
|
+
if (options.namespaces === "tracking") {
|
|
4661
|
+
return refs.includes(`${GITHUB_TRACKING_REF_PREFIX}${branch}`);
|
|
4464
4662
|
}
|
|
4465
|
-
return
|
|
4663
|
+
return refs.includes(`refs/heads/${branch}`) || refs.includes(`${GITHUB_TRACKING_REF_PREFIX}${branch}`);
|
|
4664
|
+
}
|
|
4665
|
+
/**
|
|
4666
|
+
* Delete `refs/heads/<branch>` from a bare local mirror, if present. A
|
|
4667
|
+
* no-op (not an error) when the ref doesn't exist.
|
|
4668
|
+
*
|
|
4669
|
+
* This is the "explicit path" for removing a deleted branch's local head
|
|
4670
|
+
* that the sync loop deliberately is not (see GITHUB_TRACKING_REF_PREFIX's
|
|
4671
|
+
* doc comment: reconcileTrackedBranches never deletes a head). Called by
|
|
4672
|
+
* api/branch.ts's deleteBranchHandler: without it, a deleted branch's head
|
|
4673
|
+
* lives in `remote.git` forever, and the ordinary create -> publish ->
|
|
4674
|
+
* squash-merge -> delete -> reuse-the-name cycle then has the REUSED
|
|
4675
|
+
* branch's first publish rejected non-fast-forward against the stale head
|
|
4676
|
+
* (`GitManager.push()` pushes `branch:branch`, and a squash-merged old tip
|
|
4677
|
+
* is not an ancestor of the new branch) -- a permanent, misleading 409.
|
|
4678
|
+
* Worse, a retried submit skips the local push (clean tree) and enqueues
|
|
4679
|
+
* the worker push of the STALE head, resurrecting the deleted branch's
|
|
4680
|
+
* content on GitHub as an apparent success.
|
|
4681
|
+
*
|
|
4682
|
+
* Deliberately leaves the tracking ref (`GITHUB_TRACKING_REF_PREFIX<branch>`)
|
|
4683
|
+
* alone: that namespace mirrors GitHub's view, and if the branch still
|
|
4684
|
+
* exists on GitHub, the create-time collision check SHOULD keep reporting
|
|
4685
|
+
* it until the remote side is actually gone.
|
|
4686
|
+
*
|
|
4687
|
+
* Same `--git-dir` invocation style as bareRemoteHasBranch above (works
|
|
4688
|
+
* under `safe.bareRepository=explicit`). The existence pre-check makes
|
|
4689
|
+
* "absent" deterministic instead of parsing update-ref's locale-dependent
|
|
4690
|
+
* failure text, and its captured SHA is passed to `update-ref -d` as the
|
|
4691
|
+
* expected old value -- same pattern as reconcileTrackedBranches'
|
|
4692
|
+
* guarded updates (worker/cms-worker.ts): a concurrent Lambda push
|
|
4693
|
+
* re-creating/moving this branch between the read and the delete makes
|
|
4694
|
+
* update-ref throw (surfaced as the caller's best-effort warning) instead
|
|
4695
|
+
* of silently deleting a commit that was just pushed. No
|
|
4696
|
+
* `--end-of-options` on update-ref (older gits don't accept it there);
|
|
4697
|
+
* the ref argument always begins with the literal `refs/heads/` prefix,
|
|
4698
|
+
* so it can never parse as an option.
|
|
4699
|
+
*/
|
|
4700
|
+
static async deleteBareRemoteHead(remotePath, branch) {
|
|
4701
|
+
const ref = `refs/heads/${branch}`;
|
|
4702
|
+
const output = await simpleGit2().raw([
|
|
4703
|
+
"--git-dir",
|
|
4704
|
+
remotePath,
|
|
4705
|
+
"for-each-ref",
|
|
4706
|
+
"--format=%(refname) %(objectname)",
|
|
4707
|
+
"--end-of-options",
|
|
4708
|
+
ref
|
|
4709
|
+
]);
|
|
4710
|
+
const match = output.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => line.split(" ")).find(([refname]) => refname === ref);
|
|
4711
|
+
if (!match)
|
|
4712
|
+
return;
|
|
4713
|
+
const [, sha] = match;
|
|
4714
|
+
await simpleGit2().raw(["--git-dir", remotePath, "update-ref", "-d", ref, sha]);
|
|
4466
4715
|
}
|
|
4467
4716
|
/**
|
|
4468
4717
|
* Push baseBranch from the source repo into the local bare remote via a
|
|
@@ -4635,6 +4884,30 @@ var GitManager = class _GitManager {
|
|
|
4635
4884
|
}
|
|
4636
4885
|
return void 0;
|
|
4637
4886
|
}
|
|
4887
|
+
/**
|
|
4888
|
+
* Check whether a git repository is already initialized at `workspacePath`.
|
|
4889
|
+
*
|
|
4890
|
+
* Uses `rev-parse --git-dir` with `GIT_CEILING_DIRECTORIES` pinned to the
|
|
4891
|
+
* parent directory so a corrupt/missing `.git` can't make git silently
|
|
4892
|
+
* traverse upward and report a false positive from an ancestor repo (the
|
|
4893
|
+
* same protection `initializeWorkspace` relies on below).
|
|
4894
|
+
*
|
|
4895
|
+
* Shared by `initializeWorkspace` (clone-vs-reuse decision) and
|
|
4896
|
+
* `SettingsWorkspaceManager`'s rename guard (settings-workspace.ts), which
|
|
4897
|
+
* must know whether a settings workspace ALREADY exists before touching it —
|
|
4898
|
+
* touching an existing orphan settings branch under a different name wipes
|
|
4899
|
+
* permissions.json/groups.json (see that guard's doc comment).
|
|
4900
|
+
*/
|
|
4901
|
+
static async repoExistsAt(workspacePath) {
|
|
4902
|
+
try {
|
|
4903
|
+
const checkGit = simpleGit2({ baseDir: workspacePath });
|
|
4904
|
+
checkGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path14.dirname(workspacePath) }));
|
|
4905
|
+
await checkGit.raw(["rev-parse", "--git-dir"]);
|
|
4906
|
+
return true;
|
|
4907
|
+
} catch {
|
|
4908
|
+
return false;
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4638
4911
|
/**
|
|
4639
4912
|
* Ensures a git workspace is initialized and ready for use.
|
|
4640
4913
|
* Handles cloning, remote configuration, and branch checkout/creation.
|
|
@@ -4653,13 +4926,8 @@ var GitManager = class _GitManager {
|
|
|
4653
4926
|
detectFrom: options.sourceRoot ? path14.resolve(process.cwd(), options.sourceRoot) : process.cwd()
|
|
4654
4927
|
});
|
|
4655
4928
|
const remoteName = options.remoteName ?? "origin";
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
const checkGit = simpleGit2({ baseDir: options.workspacePath });
|
|
4659
|
-
checkGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path14.dirname(options.workspacePath) }));
|
|
4660
|
-
await checkGit.raw(["rev-parse", "--git-dir"]);
|
|
4661
|
-
repoExists = true;
|
|
4662
|
-
} catch {
|
|
4929
|
+
const repoExists = await _GitManager.repoExistsAt(options.workspacePath);
|
|
4930
|
+
if (!repoExists) {
|
|
4663
4931
|
const gitPath = path14.join(options.workspacePath, ".git");
|
|
4664
4932
|
try {
|
|
4665
4933
|
const stat = await fs14.stat(gitPath);
|
|
@@ -5611,7 +5879,7 @@ async function generateAIContentFiles(options) {
|
|
|
5611
5879
|
}
|
|
5612
5880
|
const entriesForValidation = await listEntries(branchRoot, flatSchema, contentRootName);
|
|
5613
5881
|
assertBuildEntriesValid(entriesForValidation, "AI content generation");
|
|
5614
|
-
const store = new ContentStore(branchRoot, flatSchema);
|
|
5882
|
+
const store = new ContentStore(branchRoot, flatSchema, { contentRootName });
|
|
5615
5883
|
const result = await generateAIContent({
|
|
5616
5884
|
store,
|
|
5617
5885
|
flatSchema,
|