canopycms 0.0.59 → 0.0.60
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/api/__test__/mock-client.js +4 -4
- package/dist/api/__test__/mock-client.js.map +1 -1
- package/dist/api/branch-merge.d.ts.map +1 -1
- package/dist/api/branch-merge.js +2 -6
- package/dist/api/branch-merge.js.map +1 -1
- package/dist/api/branch-withdraw.d.ts.map +1 -1
- package/dist/api/branch-withdraw.js +19 -4
- package/dist/api/branch-withdraw.js.map +1 -1
- package/dist/api/entries.d.ts.map +1 -1
- package/dist/api/entries.js +22 -3
- package/dist/api/entries.js.map +1 -1
- package/dist/api/groups.d.ts +3 -0
- package/dist/api/groups.d.ts.map +1 -1
- package/dist/api/groups.js +89 -68
- package/dist/api/groups.js.map +1 -1
- package/dist/api/permissions.d.ts +1 -0
- package/dist/api/permissions.d.ts.map +1 -1
- package/dist/api/permissions.js +23 -20
- package/dist/api/permissions.js.map +1 -1
- package/dist/api/schema.d.ts.map +1 -1
- package/dist/api/schema.js +29 -15
- package/dist/api/schema.js.map +1 -1
- package/dist/authorization/groups/index.d.ts +1 -1
- package/dist/authorization/groups/index.d.ts.map +1 -1
- package/dist/authorization/groups/index.js +1 -1
- package/dist/authorization/groups/index.js.map +1 -1
- package/dist/authorization/groups/loader.d.ts +25 -4
- package/dist/authorization/groups/loader.d.ts.map +1 -1
- package/dist/authorization/groups/loader.js +39 -20
- package/dist/authorization/groups/loader.js.map +1 -1
- package/dist/authorization/groups/schema.d.ts +8 -7
- package/dist/authorization/groups/schema.d.ts.map +1 -1
- package/dist/authorization/groups/schema.js +8 -4
- package/dist/authorization/groups/schema.js.map +1 -1
- package/dist/authorization/index.d.ts +4 -3
- package/dist/authorization/index.d.ts.map +1 -1
- package/dist/authorization/index.js +6 -3
- package/dist/authorization/index.js.map +1 -1
- package/dist/authorization/path.d.ts +8 -0
- package/dist/authorization/path.d.ts.map +1 -1
- package/dist/authorization/path.js +16 -1
- package/dist/authorization/path.js.map +1 -1
- package/dist/authorization/permissions/index.d.ts +1 -1
- package/dist/authorization/permissions/index.d.ts.map +1 -1
- package/dist/authorization/permissions/index.js +1 -1
- package/dist/authorization/permissions/index.js.map +1 -1
- package/dist/authorization/permissions/loader.d.ts +18 -4
- package/dist/authorization/permissions/loader.d.ts.map +1 -1
- package/dist/authorization/permissions/loader.js +35 -24
- package/dist/authorization/permissions/loader.js.map +1 -1
- package/dist/authorization/permissions/schema.d.ts +8 -7
- package/dist/authorization/permissions/schema.d.ts.map +1 -1
- package/dist/authorization/permissions/schema.js +8 -4
- package/dist/authorization/permissions/schema.js.map +1 -1
- package/dist/authorization/settings-file-store.d.ts +127 -0
- package/dist/authorization/settings-file-store.d.ts.map +1 -0
- package/dist/authorization/settings-file-store.js +156 -0
- package/dist/authorization/settings-file-store.js.map +1 -0
- package/dist/branch-metadata.d.ts +11 -0
- package/dist/branch-metadata.d.ts.map +1 -1
- package/dist/branch-metadata.js +22 -0
- package/dist/branch-metadata.js.map +1 -1
- package/dist/cli/cli.js +245 -188
- package/dist/cli/generate-ai-content.js +18 -3
- package/dist/cli/init.js +12 -2
- package/dist/cli/migrate.d.ts.map +1 -1
- package/dist/cli/migrate.js +39 -11
- package/dist/cli/migrate.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/schemas/config.d.ts +55 -5
- package/dist/config/schemas/config.d.ts.map +1 -1
- package/dist/config/schemas/config.js +18 -1
- package/dist/config/schemas/config.js.map +1 -1
- package/dist/config/types.d.ts +11 -1
- package/dist/config/types.d.ts.map +1 -1
- package/dist/context.d.ts +3 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +25 -3
- package/dist/context.js.map +1 -1
- package/dist/editor/BranchManager.d.ts +3 -0
- package/dist/editor/BranchManager.d.ts.map +1 -1
- package/dist/editor/BranchManager.js +18 -5
- package/dist/editor/BranchManager.js.map +1 -1
- package/dist/editor/hooks/useBranchManager.d.ts +3 -1
- package/dist/editor/hooks/useBranchManager.d.ts.map +1 -1
- package/dist/editor/hooks/useBranchManager.js +2 -0
- package/dist/editor/hooks/useBranchManager.js.map +1 -1
- package/dist/editor/hooks/useGroupManager.d.ts.map +1 -1
- package/dist/editor/hooks/useGroupManager.js +13 -2
- package/dist/editor/hooks/useGroupManager.js.map +1 -1
- package/dist/editor/hooks/usePermissionManager.d.ts.map +1 -1
- package/dist/editor/hooks/usePermissionManager.js +13 -2
- package/dist/editor/hooks/usePermissionManager.js.map +1 -1
- package/dist/git-manager.d.ts.map +1 -1
- package/dist/git-manager.js +6 -0
- package/dist/git-manager.js.map +1 -1
- package/dist/schema/schema-store.d.ts +98 -0
- package/dist/schema/schema-store.d.ts.map +1 -1
- package/dist/schema/schema-store.js +187 -29
- package/dist/schema/schema-store.js.map +1 -1
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/worker/cms-worker.d.ts +36 -0
- package/dist/worker/cms-worker.d.ts.map +1 -1
- package/dist/worker/cms-worker.js +218 -8
- package/dist/worker/cms-worker.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/cli.js
CHANGED
|
@@ -794,7 +794,7 @@ CanopyCMS worker run-once (mode: ${mode}, auth: ${authMode})
|
|
|
794
794
|
}
|
|
795
795
|
console.log("\nDone");
|
|
796
796
|
}
|
|
797
|
-
var __defProp2, __getOwnPropNames2, __esm2, __export2, primitiveFieldTypes, fieldTypes, init_types, fieldBaseSchema, selectOptionSchema, referenceOptionSchema, primitiveFieldSchema, ASPECT_RATIO_RE, imageFieldSchema, selectFieldSchema, referenceFieldSchema, fieldHolder, blockSchema, blockFieldSchema, objectFieldSchema, inlineGroupFieldSchema, customFieldSchema, knownFieldSchema, fieldSchema, init_field, relativePathSchema, entryTypeSchema, collectionSchema, init_collection, mediaSchema, init_media, defaultBranchAccessSchema, defaultPathAccessSchema, defaultBaseBranchSchema, defaultRemoteNameSchema, defaultRemoteUrlSchema, gitBotAuthorNameSchema, gitBotAuthorEmailSchema, githubTokenEnvVarSchema, operatingModeSchema, deployedAsSchema, contentRootSchema, sourceRootSchema, deploymentNameSchema, devContentSyncSchema, devConfigSchema, editorConfigSchema, CanopyConfigSchema, DEFAULT_PROD_WORKSPACE, init_config, permissionTargetSchema, pathPermissionSchema, init_permissions, init_normalize, init_types2, init_flatten, init_validation, init_helpers, init_config2, templates_exports, __dirname, TEMPLATES_DIR, init_templates, task_queue_config_exports, init_task_queue_config, LOG_LEVELS, DebugLogger, testLogger, init_debug, init_atomic_write, DEFAULT_MAX_RETRIES, nullLogger, init_task_queue, init_task_queue2, task_queue_exports, debugLogger, cmsTaskQueueLogger, init_task_queue3, ProdClientSafeStrategy, DevClientSafeStrategy, ProdStrategy, DevStrategy, strategyCache;
|
|
797
|
+
var __defProp2, __getOwnPropNames2, __esm2, __export2, primitiveFieldTypes, fieldTypes, init_types, fieldBaseSchema, selectOptionSchema, referenceOptionSchema, primitiveFieldSchema, ASPECT_RATIO_RE, imageFieldSchema, selectFieldSchema, referenceFieldSchema, fieldHolder, blockSchema, blockFieldSchema, objectFieldSchema, inlineGroupFieldSchema, customFieldSchema, knownFieldSchema, fieldSchema, init_field, relativePathSchema, entryTypeSchema, collectionSchema, init_collection, mediaSchema, init_media, defaultBranchAccessSchema, defaultPathAccessLevelSchema, defaultPathAccessLevelsSchema, defaultPathAccessSchema, defaultBaseBranchSchema, defaultRemoteNameSchema, defaultRemoteUrlSchema, gitBotAuthorNameSchema, gitBotAuthorEmailSchema, githubTokenEnvVarSchema, operatingModeSchema, deployedAsSchema, contentRootSchema, sourceRootSchema, deploymentNameSchema, devContentSyncSchema, devConfigSchema, editorConfigSchema, CanopyConfigSchema, DEFAULT_PROD_WORKSPACE, init_config, permissionTargetSchema, pathPermissionSchema, init_permissions, init_normalize, init_types2, init_flatten, init_validation, init_helpers, init_config2, templates_exports, __dirname, TEMPLATES_DIR, init_templates, task_queue_config_exports, init_task_queue_config, LOG_LEVELS, DebugLogger, testLogger, init_debug, init_atomic_write, DEFAULT_MAX_RETRIES, nullLogger, init_task_queue, init_task_queue2, task_queue_exports, debugLogger, cmsTaskQueueLogger, init_task_queue3, ProdClientSafeStrategy, DevClientSafeStrategy, ProdStrategy, DevStrategy, strategyCache;
|
|
798
798
|
var init_init = __esm({
|
|
799
799
|
"dist/cli/init.js"() {
|
|
800
800
|
"use strict";
|
|
@@ -980,7 +980,13 @@ var init_init = __esm({
|
|
|
980
980
|
init_collection();
|
|
981
981
|
init_media();
|
|
982
982
|
defaultBranchAccessSchema = z4.enum(["allow", "deny"]).default("deny");
|
|
983
|
-
|
|
983
|
+
defaultPathAccessLevelSchema = z4.enum(["allow", "deny"]);
|
|
984
|
+
defaultPathAccessLevelsSchema = z4.object({
|
|
985
|
+
read: defaultPathAccessLevelSchema.optional(),
|
|
986
|
+
edit: defaultPathAccessLevelSchema.optional(),
|
|
987
|
+
review: defaultPathAccessLevelSchema.optional()
|
|
988
|
+
}).strict();
|
|
989
|
+
defaultPathAccessSchema = z4.union([defaultPathAccessLevelSchema, defaultPathAccessLevelsSchema]).default("deny");
|
|
984
990
|
defaultBaseBranchSchema = z4.string().default("main");
|
|
985
991
|
defaultRemoteNameSchema = z4.string().default("origin");
|
|
986
992
|
defaultRemoteUrlSchema = z4.string().min(1);
|
|
@@ -1013,6 +1019,10 @@ var init_init = __esm({
|
|
|
1013
1019
|
// have .default('deny'), so the field is optional on input but always resolves to
|
|
1014
1020
|
// 'allow'/'deny' (never undefined) on output. An outer .optional() would short-circuit
|
|
1015
1021
|
// before the inner default runs, defeating the fail-closed default (SCH-M1).
|
|
1022
|
+
// defaultPathAccessSchema's union keeps the same rule: the .default('deny') sits on the
|
|
1023
|
+
// OUTER union, not inside defaultPathAccessLevelsSchema, so an omitted top-level field
|
|
1024
|
+
// still resolves to 'deny' and an omitted level inside the object form stays undefined
|
|
1025
|
+
// (resolved to 'deny' at read time by resolveDefaultPathAccess).
|
|
1016
1026
|
defaultBranchAccess: defaultBranchAccessSchema,
|
|
1017
1027
|
defaultPathAccess: defaultPathAccessSchema,
|
|
1018
1028
|
// .optional() deliberately defeats defaultBaseBranchSchema's .default('main'):
|
|
@@ -3560,7 +3570,7 @@ async function generateAIContentCLI(options) {
|
|
|
3560
3570
|
console.log(` Output: ${result.outputDir}
|
|
3561
3571
|
`);
|
|
3562
3572
|
}
|
|
3563
|
-
var __defProp3, __getOwnPropNames3, __esm3, __export3, init_normalize2, ROOT_COLLECTION_ID, init_types3, normalizePathValue, flattenSchema, init_flatten2, ProdClientSafeStrategy2, DevClientSafeStrategy2, clientStrategyCache, init_client_safe_strategy, primitiveFieldTypes2, fieldTypes2, init_types22, fieldBaseSchema2, selectOptionSchema2, referenceOptionSchema2, primitiveFieldSchema2, ASPECT_RATIO_RE2, imageFieldSchema2, selectFieldSchema2, referenceFieldSchema2, fieldHolder2, blockSchema2, blockFieldSchema2, objectFieldSchema2, inlineGroupFieldSchema2, customFieldSchema2, knownFieldSchema2, fieldSchema2, init_field2, relativePathSchema2, entryTypeSchema2, collectionSchema2, init_collection2, mediaSchema2, init_media2, defaultBranchAccessSchema2, defaultPathAccessSchema2, defaultBaseBranchSchema2, defaultRemoteNameSchema2, defaultRemoteUrlSchema2, gitBotAuthorNameSchema2, gitBotAuthorEmailSchema2, githubTokenEnvVarSchema2, operatingModeSchema2, deployedAsSchema2, contentRootSchema2, sourceRootSchema2, deploymentNameSchema2, devContentSyncSchema2, devConfigSchema2, editorConfigSchema2, CanopyConfigSchema2, DEFAULT_PROD_WORKSPACE2, init_config3, permissionTargetSchema2, pathPermissionSchema2, init_permissions2, init_validation2, init_helpers2, init_config22, ProdStrategy2, DevStrategy2, strategyCache2, init_client_unsafe_strategy, operating_mode_exports, init_operating_mode, locks, BASE58_PATTERN, CONTENT_ID_PATTERN, PHYSICAL_SEGMENT_PATTERN, isValidId, EMPTY_LOGICAL_PATH, ContentIdIndex, registry, finalization, LOG_LEVELS2, DebugLogger2, testLogger2, log2, META_DIR, entryTypeMetaSchema, collectionMetaSchema, rootCollectionMetaSchema, isDeployedStatic, isBuildMode, STATIC_DEPLOY_USER, SCHEMA_CACHE_VERSION, MTIME_CHECK_DEBOUNCE_MS, SCHEMA_GENERATION_RESOURCE, BranchSchemaCache, RESOURCE, getFormatExtension, isDataOnlyFormat, asRecord, BranchPathError, resolveContentBranchesRoot, ContentStoreError, ContentConflictError, DEFAULT_INDEX_FRESHNESS_INTERVAL_MS, FORCED_REFRESH_MIN_INTERVAL_MS, STALE_LOOKUP, ContentStore, ATTR_CONTENT, BLOCK_PREFIX, BLOCK_SUFFIX, BLOCK_RESTORE_RE, INLINE_PREFIX, INLINE_SUFFIX, INLINE_RESTORE_RE, FLAT_CELL_TYPES, log22, BASE58_CHAR, ENTRY_LINK_PATTERN, log3, REGISTRY_FILE, REGISTRY_STALE_FILE, REGISTRY_TEMP_FILE, REGISTRY_VERSION, RESOURCE2, GET_MISS_REFRESH_MIN_INTERVAL_MS, BranchRegistry, log4, OccWriteConflictError, BRANCH_META_DIR, BRANCH_META_FILE, CURRENT_SCHEMA_VERSION, BranchMetadataConflictError, BranchMetadataFileManager, getBranchMetadataFileManager, loadBranchContext, NETWORK_SCHEME_PATTERN, TRANSPORT_HELPER_PATTERN, LEADING_OPTION_PATTERN, WINDOWS_DRIVE_PATTERN, COLON_BEFORE_SLASH_PATTERN, log5, GIT_ENV_PASSTHROUGH, remoteInitLocks, GitConflictError, GitManager, log6, workspaceInitLocks, BranchWorkspaceManager, log7, normalizePath, readEntryData, parseTypedFilename, listCollectionEntries, MAX_INPUT_PIXELS, KNOWN_FIELD_TYPES, STRING_FIELD_TYPES, selectOptionValues, jiti;
|
|
3573
|
+
var __defProp3, __getOwnPropNames3, __esm3, __export3, init_normalize2, ROOT_COLLECTION_ID, init_types3, normalizePathValue, flattenSchema, init_flatten2, ProdClientSafeStrategy2, DevClientSafeStrategy2, clientStrategyCache, init_client_safe_strategy, primitiveFieldTypes2, fieldTypes2, init_types22, fieldBaseSchema2, selectOptionSchema2, referenceOptionSchema2, primitiveFieldSchema2, ASPECT_RATIO_RE2, imageFieldSchema2, selectFieldSchema2, referenceFieldSchema2, fieldHolder2, blockSchema2, blockFieldSchema2, objectFieldSchema2, inlineGroupFieldSchema2, customFieldSchema2, knownFieldSchema2, fieldSchema2, init_field2, relativePathSchema2, entryTypeSchema2, collectionSchema2, init_collection2, mediaSchema2, init_media2, defaultBranchAccessSchema2, defaultPathAccessLevelSchema2, defaultPathAccessLevelsSchema2, defaultPathAccessSchema2, defaultBaseBranchSchema2, defaultRemoteNameSchema2, defaultRemoteUrlSchema2, gitBotAuthorNameSchema2, gitBotAuthorEmailSchema2, githubTokenEnvVarSchema2, operatingModeSchema2, deployedAsSchema2, contentRootSchema2, sourceRootSchema2, deploymentNameSchema2, devContentSyncSchema2, devConfigSchema2, editorConfigSchema2, CanopyConfigSchema2, DEFAULT_PROD_WORKSPACE2, init_config3, permissionTargetSchema2, pathPermissionSchema2, init_permissions2, init_validation2, init_helpers2, init_config22, ProdStrategy2, DevStrategy2, strategyCache2, init_client_unsafe_strategy, operating_mode_exports, init_operating_mode, locks, BASE58_PATTERN, CONTENT_ID_PATTERN, PHYSICAL_SEGMENT_PATTERN, isValidId, EMPTY_LOGICAL_PATH, ContentIdIndex, registry, finalization, LOG_LEVELS2, DebugLogger2, testLogger2, log2, META_DIR, entryTypeMetaSchema, collectionMetaSchema, rootCollectionMetaSchema, isDeployedStatic, isBuildMode, STATIC_DEPLOY_USER, SCHEMA_CACHE_VERSION, MTIME_CHECK_DEBOUNCE_MS, SCHEMA_GENERATION_RESOURCE, BranchSchemaCache, RESOURCE, getFormatExtension, isDataOnlyFormat, asRecord, BranchPathError, resolveContentBranchesRoot, ContentStoreError, ContentConflictError, DEFAULT_INDEX_FRESHNESS_INTERVAL_MS, FORCED_REFRESH_MIN_INTERVAL_MS, STALE_LOOKUP, ContentStore, ATTR_CONTENT, BLOCK_PREFIX, BLOCK_SUFFIX, BLOCK_RESTORE_RE, INLINE_PREFIX, INLINE_SUFFIX, INLINE_RESTORE_RE, FLAT_CELL_TYPES, log22, BASE58_CHAR, ENTRY_LINK_PATTERN, log3, REGISTRY_FILE, REGISTRY_STALE_FILE, REGISTRY_TEMP_FILE, REGISTRY_VERSION, RESOURCE2, GET_MISS_REFRESH_MIN_INTERVAL_MS, BranchRegistry, log4, OccWriteConflictError, BRANCH_META_DIR, BRANCH_META_FILE, CURRENT_SCHEMA_VERSION, BranchMetadataConflictError, BranchMetadataFileManager, getBranchMetadataFileManager, loadBranchContext, NETWORK_SCHEME_PATTERN, TRANSPORT_HELPER_PATTERN, LEADING_OPTION_PATTERN, WINDOWS_DRIVE_PATTERN, COLON_BEFORE_SLASH_PATTERN, log5, GIT_ENV_PASSTHROUGH, remoteInitLocks, GitConflictError, GitManager, log6, workspaceInitLocks, BranchWorkspaceManager, log7, normalizePath, readEntryData, parseTypedFilename, listCollectionEntries, MAX_INPUT_PIXELS, KNOWN_FIELD_TYPES, STRING_FIELD_TYPES, selectOptionValues, jiti;
|
|
3564
3574
|
var init_generate_ai_content = __esm({
|
|
3565
3575
|
"dist/cli/generate-ai-content.js"() {
|
|
3566
3576
|
"use strict";
|
|
@@ -3924,7 +3934,13 @@ var init_generate_ai_content = __esm({
|
|
|
3924
3934
|
init_collection2();
|
|
3925
3935
|
init_media2();
|
|
3926
3936
|
defaultBranchAccessSchema2 = z52.enum(["allow", "deny"]).default("deny");
|
|
3927
|
-
|
|
3937
|
+
defaultPathAccessLevelSchema2 = z52.enum(["allow", "deny"]);
|
|
3938
|
+
defaultPathAccessLevelsSchema2 = z52.object({
|
|
3939
|
+
read: defaultPathAccessLevelSchema2.optional(),
|
|
3940
|
+
edit: defaultPathAccessLevelSchema2.optional(),
|
|
3941
|
+
review: defaultPathAccessLevelSchema2.optional()
|
|
3942
|
+
}).strict();
|
|
3943
|
+
defaultPathAccessSchema2 = z52.union([defaultPathAccessLevelSchema2, defaultPathAccessLevelsSchema2]).default("deny");
|
|
3928
3944
|
defaultBaseBranchSchema2 = z52.string().default("main");
|
|
3929
3945
|
defaultRemoteNameSchema2 = z52.string().default("origin");
|
|
3930
3946
|
defaultRemoteUrlSchema2 = z52.string().min(1);
|
|
@@ -3957,6 +3973,10 @@ var init_generate_ai_content = __esm({
|
|
|
3957
3973
|
// have .default('deny'), so the field is optional on input but always resolves to
|
|
3958
3974
|
// 'allow'/'deny' (never undefined) on output. An outer .optional() would short-circuit
|
|
3959
3975
|
// before the inner default runs, defeating the fail-closed default (SCH-M1).
|
|
3976
|
+
// defaultPathAccessSchema's union keeps the same rule: the .default('deny') sits on the
|
|
3977
|
+
// OUTER union, not inside defaultPathAccessLevelsSchema, so an omitted top-level field
|
|
3978
|
+
// still resolves to 'deny' and an omitted level inside the object form stays undefined
|
|
3979
|
+
// (resolved to 'deny' at read time by resolveDefaultPathAccess).
|
|
3960
3980
|
defaultBranchAccess: defaultBranchAccessSchema2,
|
|
3961
3981
|
defaultPathAccess: defaultPathAccessSchema2,
|
|
3962
3982
|
// .optional() deliberately defeats defaultBaseBranchSchema's .default('main'):
|
|
@@ -5980,7 +6000,11 @@ var init_generate_ai_content = __esm({
|
|
|
5980
6000
|
createdBy: existing?.branch.createdBy ?? incoming.branch?.createdBy ?? defaults.createdBy,
|
|
5981
6001
|
createdAt: existing?.branch.createdAt ?? defaults.createdAt,
|
|
5982
6002
|
// Fork point is recorded once at creation; later saves must not move it
|
|
5983
|
-
baseBranch: existing?.branch.baseBranch ?? incoming.branch?.baseBranch
|
|
6003
|
+
baseBranch: existing?.branch.baseBranch ?? incoming.branch?.baseBranch,
|
|
6004
|
+
// Always stamped fresh — the spreads above would otherwise let
|
|
6005
|
+
// the existing (creation-time) value win forever, freezing the
|
|
6006
|
+
// timestamp the editor's Branches panel sorts and displays by
|
|
6007
|
+
updatedAt: now
|
|
5984
6008
|
}
|
|
5985
6009
|
};
|
|
5986
6010
|
const written = await this.write(merged, version);
|
|
@@ -6450,6 +6474,7 @@ var init_generate_ai_content = __esm({
|
|
|
6450
6474
|
}
|
|
6451
6475
|
if (options.branchType === "orphan") {
|
|
6452
6476
|
await git.createOrphanSettingsBranch(options.branchName, {});
|
|
6477
|
+
await git.ensureGitExclude("*.lock");
|
|
6453
6478
|
} else {
|
|
6454
6479
|
await git.checkoutBranch(options.branchName);
|
|
6455
6480
|
if (options.gitExcludePattern) {
|
|
@@ -7875,14 +7900,20 @@ var init_media3 = __esm({
|
|
|
7875
7900
|
|
|
7876
7901
|
// dist/config/schemas/config.js
|
|
7877
7902
|
import { z as z12 } from "zod";
|
|
7878
|
-
var defaultBranchAccessSchema3, defaultPathAccessSchema3, defaultBaseBranchSchema3, defaultRemoteNameSchema3, defaultRemoteUrlSchema3, gitBotAuthorNameSchema3, gitBotAuthorEmailSchema3, githubTokenEnvVarSchema3, operatingModeSchema3, deployedAsSchema3, contentRootSchema3, sourceRootSchema3, deploymentNameSchema3, devContentSyncSchema3, devConfigSchema3, editorConfigSchema3, CanopyConfigSchema3, DEFAULT_PROD_WORKSPACE3;
|
|
7903
|
+
var defaultBranchAccessSchema3, defaultPathAccessLevelSchema3, defaultPathAccessLevelsSchema3, defaultPathAccessSchema3, defaultBaseBranchSchema3, defaultRemoteNameSchema3, defaultRemoteUrlSchema3, gitBotAuthorNameSchema3, gitBotAuthorEmailSchema3, githubTokenEnvVarSchema3, operatingModeSchema3, deployedAsSchema3, contentRootSchema3, sourceRootSchema3, deploymentNameSchema3, devContentSyncSchema3, devConfigSchema3, editorConfigSchema3, CanopyConfigSchema3, DEFAULT_PROD_WORKSPACE3;
|
|
7879
7904
|
var init_config4 = __esm({
|
|
7880
7905
|
"dist/config/schemas/config.js"() {
|
|
7881
7906
|
"use strict";
|
|
7882
7907
|
init_collection3();
|
|
7883
7908
|
init_media3();
|
|
7884
7909
|
defaultBranchAccessSchema3 = z12.enum(["allow", "deny"]).default("deny");
|
|
7885
|
-
|
|
7910
|
+
defaultPathAccessLevelSchema3 = z12.enum(["allow", "deny"]);
|
|
7911
|
+
defaultPathAccessLevelsSchema3 = z12.object({
|
|
7912
|
+
read: defaultPathAccessLevelSchema3.optional(),
|
|
7913
|
+
edit: defaultPathAccessLevelSchema3.optional(),
|
|
7914
|
+
review: defaultPathAccessLevelSchema3.optional()
|
|
7915
|
+
}).strict();
|
|
7916
|
+
defaultPathAccessSchema3 = z12.union([defaultPathAccessLevelSchema3, defaultPathAccessLevelsSchema3]).default("deny");
|
|
7886
7917
|
defaultBaseBranchSchema3 = z12.string().default("main");
|
|
7887
7918
|
defaultRemoteNameSchema3 = z12.string().default("origin");
|
|
7888
7919
|
defaultRemoteUrlSchema3 = z12.string().min(1);
|
|
@@ -7915,6 +7946,10 @@ var init_config4 = __esm({
|
|
|
7915
7946
|
// have .default('deny'), so the field is optional on input but always resolves to
|
|
7916
7947
|
// 'allow'/'deny' (never undefined) on output. An outer .optional() would short-circuit
|
|
7917
7948
|
// before the inner default runs, defeating the fail-closed default (SCH-M1).
|
|
7949
|
+
// defaultPathAccessSchema's union keeps the same rule: the .default('deny') sits on the
|
|
7950
|
+
// OUTER union, not inside defaultPathAccessLevelsSchema, so an omitted top-level field
|
|
7951
|
+
// still resolves to 'deny' and an omitted level inside the object form stays undefined
|
|
7952
|
+
// (resolved to 'deny' at read time by resolveDefaultPathAccess).
|
|
7918
7953
|
defaultBranchAccess: defaultBranchAccessSchema3,
|
|
7919
7954
|
defaultPathAccess: defaultPathAccessSchema3,
|
|
7920
7955
|
// .optional() deliberately defeats defaultBaseBranchSchema's .default('main'):
|
|
@@ -8583,10 +8618,168 @@ var init_schema = __esm({
|
|
|
8583
8618
|
}
|
|
8584
8619
|
});
|
|
8585
8620
|
|
|
8586
|
-
// dist/
|
|
8621
|
+
// dist/utils/async-mutex.js
|
|
8622
|
+
async function withLock2(key, fn) {
|
|
8623
|
+
const prev = locks2.get(key) ?? Promise.resolve();
|
|
8624
|
+
let resolve2;
|
|
8625
|
+
const next = new Promise((r) => {
|
|
8626
|
+
resolve2 = r;
|
|
8627
|
+
});
|
|
8628
|
+
locks2.set(key, next);
|
|
8629
|
+
await prev;
|
|
8630
|
+
try {
|
|
8631
|
+
return await fn();
|
|
8632
|
+
} finally {
|
|
8633
|
+
resolve2();
|
|
8634
|
+
if (locks2.get(key) === next)
|
|
8635
|
+
locks2.delete(key);
|
|
8636
|
+
}
|
|
8637
|
+
}
|
|
8638
|
+
var locks2;
|
|
8639
|
+
var init_async_mutex = __esm({
|
|
8640
|
+
"dist/utils/async-mutex.js"() {
|
|
8641
|
+
"use strict";
|
|
8642
|
+
locks2 = /* @__PURE__ */ new Map();
|
|
8643
|
+
}
|
|
8644
|
+
});
|
|
8645
|
+
|
|
8646
|
+
// dist/utils/occ-json-write.js
|
|
8587
8647
|
import fs24 from "node:fs/promises";
|
|
8588
8648
|
import path27 from "node:path";
|
|
8589
|
-
|
|
8649
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
8650
|
+
import lockfile4 from "proper-lockfile";
|
|
8651
|
+
async function writeOccJsonFile2(filePath, payload, options) {
|
|
8652
|
+
const { expectedVersion, settleMs = 50, trailingNewline = false } = options;
|
|
8653
|
+
const newVersion = expectedVersion === null ? 1 : expectedVersion + 1;
|
|
8654
|
+
const writeId = randomUUID4();
|
|
8655
|
+
const data = { ...payload, version: newVersion, writeId };
|
|
8656
|
+
const content = JSON.stringify(data, null, 2) + (trailingNewline ? "\n" : "");
|
|
8657
|
+
const dir = path27.dirname(filePath);
|
|
8658
|
+
await fs24.mkdir(dir, { recursive: true });
|
|
8659
|
+
const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
8660
|
+
await fs24.writeFile(tempPath, content, "utf-8");
|
|
8661
|
+
if (expectedVersion === null) {
|
|
8662
|
+
try {
|
|
8663
|
+
await fs24.link(tempPath, filePath);
|
|
8664
|
+
} catch (err) {
|
|
8665
|
+
await fs24.unlink(tempPath).catch(() => {
|
|
8666
|
+
});
|
|
8667
|
+
if (isFileExistsError(err)) {
|
|
8668
|
+
throw new OccWriteConflictError2();
|
|
8669
|
+
}
|
|
8670
|
+
throw err;
|
|
8671
|
+
}
|
|
8672
|
+
await fs24.unlink(tempPath).catch(() => {
|
|
8673
|
+
});
|
|
8674
|
+
return { version: newVersion, writeId };
|
|
8675
|
+
}
|
|
8676
|
+
try {
|
|
8677
|
+
let currentVersion = null;
|
|
8678
|
+
try {
|
|
8679
|
+
const current = JSON.parse(await fs24.readFile(filePath, "utf-8"));
|
|
8680
|
+
currentVersion = current.version ?? 0;
|
|
8681
|
+
} catch {
|
|
8682
|
+
currentVersion = null;
|
|
8683
|
+
}
|
|
8684
|
+
if (currentVersion !== expectedVersion) {
|
|
8685
|
+
throw new OccWriteConflictError2();
|
|
8686
|
+
}
|
|
8687
|
+
await fs24.rename(tempPath, filePath);
|
|
8688
|
+
if (settleMs > 0) {
|
|
8689
|
+
await new Promise((resolve2) => setTimeout(resolve2, settleMs));
|
|
8690
|
+
}
|
|
8691
|
+
const afterWrite = JSON.parse(await fs24.readFile(filePath, "utf-8"));
|
|
8692
|
+
if (afterWrite.writeId !== writeId) {
|
|
8693
|
+
throw new OccWriteConflictError2();
|
|
8694
|
+
}
|
|
8695
|
+
} catch (err) {
|
|
8696
|
+
await fs24.unlink(tempPath).catch(() => {
|
|
8697
|
+
});
|
|
8698
|
+
throw err;
|
|
8699
|
+
}
|
|
8700
|
+
return { version: newVersion, writeId };
|
|
8701
|
+
}
|
|
8702
|
+
async function withOccRetry2(operation, options) {
|
|
8703
|
+
const maxAttempts = options?.maxAttempts ?? 10;
|
|
8704
|
+
const isRetryable = options?.isRetryable;
|
|
8705
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
8706
|
+
try {
|
|
8707
|
+
return await operation();
|
|
8708
|
+
} catch (err) {
|
|
8709
|
+
const retryable = err instanceof OccWriteConflictError2 || (isRetryable?.(err) ?? false);
|
|
8710
|
+
if (retryable && attempt < maxAttempts) {
|
|
8711
|
+
const baseDelay = Math.min(10 * Math.pow(2, attempt - 1), 100);
|
|
8712
|
+
const jitter = Math.random() * baseDelay;
|
|
8713
|
+
await new Promise((resolve2) => setTimeout(resolve2, baseDelay + jitter));
|
|
8714
|
+
continue;
|
|
8715
|
+
}
|
|
8716
|
+
throw err;
|
|
8717
|
+
}
|
|
8718
|
+
}
|
|
8719
|
+
throw new Error("Unreachable");
|
|
8720
|
+
}
|
|
8721
|
+
async function withOccFileLock2(filePath, fn) {
|
|
8722
|
+
const dir = path27.dirname(filePath);
|
|
8723
|
+
await fs24.mkdir(dir, { recursive: true });
|
|
8724
|
+
const MAX_ATTEMPTS = 14;
|
|
8725
|
+
let release = null;
|
|
8726
|
+
for (let attempt = 1; release === null; attempt++) {
|
|
8727
|
+
try {
|
|
8728
|
+
release = await lockfile4.lock(filePath, {
|
|
8729
|
+
lockfilePath: `${filePath}.lock`,
|
|
8730
|
+
realpath: false,
|
|
8731
|
+
stale: 1e4,
|
|
8732
|
+
retries: 0,
|
|
8733
|
+
// A compromised lock (the lock dir vanished or refresh failed
|
|
8734
|
+
// mid-hold, e.g. the branch directory containing it was deleted)
|
|
8735
|
+
// must not crash the process, which is proper-lockfile's default.
|
|
8736
|
+
// Our critical sections are short and idempotent-on-conflict (OCC
|
|
8737
|
+
// verify inside); log and let the section finish.
|
|
8738
|
+
onCompromised: (err) => {
|
|
8739
|
+
log11.warn("lock", `Lock compromised mid-hold for ${filePath}`, {
|
|
8740
|
+
error: getErrorMessage(err)
|
|
8741
|
+
});
|
|
8742
|
+
}
|
|
8743
|
+
});
|
|
8744
|
+
} catch (err) {
|
|
8745
|
+
const code = isNodeError(err) ? err.code : void 0;
|
|
8746
|
+
const contended = code === "ELOCKED";
|
|
8747
|
+
if (!contended || attempt >= MAX_ATTEMPTS) {
|
|
8748
|
+
throw new OccWriteConflictError2(`Could not acquire file lock: ${getErrorMessage(err)}`);
|
|
8749
|
+
}
|
|
8750
|
+
const baseDelay = Math.min(50 * Math.pow(1.6, attempt - 1), 2e3);
|
|
8751
|
+
const jitter = Math.random() * baseDelay;
|
|
8752
|
+
await new Promise((resolve2) => setTimeout(resolve2, baseDelay + jitter));
|
|
8753
|
+
}
|
|
8754
|
+
}
|
|
8755
|
+
try {
|
|
8756
|
+
return await fn();
|
|
8757
|
+
} finally {
|
|
8758
|
+
await release().catch((err) => {
|
|
8759
|
+
log11.warn("lock", `Failed to release lock for ${filePath}`, { error: getErrorMessage(err) });
|
|
8760
|
+
});
|
|
8761
|
+
}
|
|
8762
|
+
}
|
|
8763
|
+
var log11, OccWriteConflictError2;
|
|
8764
|
+
var init_occ_json_write = __esm({
|
|
8765
|
+
"dist/utils/occ-json-write.js"() {
|
|
8766
|
+
"use strict";
|
|
8767
|
+
init_error();
|
|
8768
|
+
init_debug2();
|
|
8769
|
+
log11 = createDebugLogger3({ prefix: "OccJsonWrite" });
|
|
8770
|
+
OccWriteConflictError2 = class extends Error {
|
|
8771
|
+
constructor(message = "Concurrent modification detected") {
|
|
8772
|
+
super(message);
|
|
8773
|
+
this.name = "OccWriteConflictError";
|
|
8774
|
+
}
|
|
8775
|
+
};
|
|
8776
|
+
}
|
|
8777
|
+
});
|
|
8778
|
+
|
|
8779
|
+
// dist/branch-registry.js
|
|
8780
|
+
import fs25 from "node:fs/promises";
|
|
8781
|
+
import path28 from "node:path";
|
|
8782
|
+
var log12, REGISTRY_FILE2, REGISTRY_STALE_FILE2, REGISTRY_TEMP_FILE2, REGISTRY_VERSION2, RESOURCE4, GET_MISS_REFRESH_MIN_INTERVAL_MS2, BranchRegistry2;
|
|
8590
8783
|
var init_branch_registry = __esm({
|
|
8591
8784
|
"dist/branch-registry.js"() {
|
|
8592
8785
|
"use strict";
|
|
@@ -8594,7 +8787,7 @@ var init_branch_registry = __esm({
|
|
|
8594
8787
|
init_error();
|
|
8595
8788
|
init_debug2();
|
|
8596
8789
|
init_resource_generation();
|
|
8597
|
-
|
|
8790
|
+
log12 = createDebugLogger3({ prefix: "BranchRegistry" });
|
|
8598
8791
|
REGISTRY_FILE2 = "branches.json";
|
|
8599
8792
|
REGISTRY_STALE_FILE2 = "branches.stale.json";
|
|
8600
8793
|
REGISTRY_TEMP_FILE2 = "branches.tmp.json";
|
|
@@ -8605,10 +8798,10 @@ var init_branch_registry = __esm({
|
|
|
8605
8798
|
constructor(root) {
|
|
8606
8799
|
this.regenInFlight = null;
|
|
8607
8800
|
this.lastForcedRefreshMs = 0;
|
|
8608
|
-
this.root =
|
|
8609
|
-
this.registryPath =
|
|
8610
|
-
this.stalePath =
|
|
8611
|
-
this.tempPath =
|
|
8801
|
+
this.root = path28.resolve(root);
|
|
8802
|
+
this.registryPath = path28.join(this.root, REGISTRY_FILE2);
|
|
8803
|
+
this.stalePath = path28.join(this.root, REGISTRY_STALE_FILE2);
|
|
8804
|
+
this.tempPath = path28.join(this.root, REGISTRY_TEMP_FILE2);
|
|
8612
8805
|
}
|
|
8613
8806
|
/**
|
|
8614
8807
|
* Returns all branches. Uses the cached snapshot if its embedded generation
|
|
@@ -8617,7 +8810,7 @@ var init_branch_registry = __esm({
|
|
|
8617
8810
|
async list() {
|
|
8618
8811
|
let parsed;
|
|
8619
8812
|
try {
|
|
8620
|
-
const raw = await
|
|
8813
|
+
const raw = await fs25.readFile(this.registryPath, "utf8");
|
|
8621
8814
|
parsed = JSON.parse(raw);
|
|
8622
8815
|
} catch (err) {
|
|
8623
8816
|
if (isNotFoundError(err)) {
|
|
@@ -8680,7 +8873,7 @@ var init_branch_registry = __esm({
|
|
|
8680
8873
|
});
|
|
8681
8874
|
await this.regenerate();
|
|
8682
8875
|
} catch (err) {
|
|
8683
|
-
|
|
8876
|
+
log12.warn("invalidate", "Eager regeneration after invalidate() failed", {
|
|
8684
8877
|
error: getErrorMessage(err)
|
|
8685
8878
|
});
|
|
8686
8879
|
}
|
|
@@ -8706,7 +8899,7 @@ var init_branch_registry = __esm({
|
|
|
8706
8899
|
async performRegenerate() {
|
|
8707
8900
|
const read = await readResourceGeneration2(this.root, RESOURCE4);
|
|
8708
8901
|
const branches = await this.scanBranchDirectories();
|
|
8709
|
-
await
|
|
8902
|
+
await fs25.unlink(this.stalePath).catch(() => {
|
|
8710
8903
|
});
|
|
8711
8904
|
if (!read.ok) {
|
|
8712
8905
|
return branches;
|
|
@@ -8717,12 +8910,12 @@ var init_branch_registry = __esm({
|
|
|
8717
8910
|
generation: read.token
|
|
8718
8911
|
};
|
|
8719
8912
|
const uniqueTempPath = `${this.tempPath}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
8720
|
-
await
|
|
8721
|
-
await
|
|
8913
|
+
await fs25.mkdir(this.root, { recursive: true });
|
|
8914
|
+
await fs25.writeFile(uniqueTempPath, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
|
|
8722
8915
|
try {
|
|
8723
|
-
await
|
|
8916
|
+
await fs25.rename(uniqueTempPath, this.registryPath);
|
|
8724
8917
|
} catch (err) {
|
|
8725
|
-
await
|
|
8918
|
+
await fs25.unlink(uniqueTempPath).catch(() => {
|
|
8726
8919
|
});
|
|
8727
8920
|
throw err;
|
|
8728
8921
|
}
|
|
@@ -8736,12 +8929,12 @@ var init_branch_registry = __esm({
|
|
|
8736
8929
|
async scanBranchDirectories() {
|
|
8737
8930
|
const branches = [];
|
|
8738
8931
|
try {
|
|
8739
|
-
const entries = await
|
|
8932
|
+
const entries = await fs25.readdir(this.root, { withFileTypes: true });
|
|
8740
8933
|
for (const entry of entries) {
|
|
8741
8934
|
if (!entry.isDirectory() || entry.name.startsWith(".")) {
|
|
8742
8935
|
continue;
|
|
8743
8936
|
}
|
|
8744
|
-
const branchRoot =
|
|
8937
|
+
const branchRoot = path28.join(this.root, entry.name);
|
|
8745
8938
|
const meta = await BranchMetadataFileManager2.loadOnly(branchRoot);
|
|
8746
8939
|
if (meta) {
|
|
8747
8940
|
branches.push({
|
|
@@ -8763,164 +8956,6 @@ var init_branch_registry = __esm({
|
|
|
8763
8956
|
}
|
|
8764
8957
|
});
|
|
8765
8958
|
|
|
8766
|
-
// dist/utils/async-mutex.js
|
|
8767
|
-
async function withLock2(key, fn) {
|
|
8768
|
-
const prev = locks2.get(key) ?? Promise.resolve();
|
|
8769
|
-
let resolve2;
|
|
8770
|
-
const next = new Promise((r) => {
|
|
8771
|
-
resolve2 = r;
|
|
8772
|
-
});
|
|
8773
|
-
locks2.set(key, next);
|
|
8774
|
-
await prev;
|
|
8775
|
-
try {
|
|
8776
|
-
return await fn();
|
|
8777
|
-
} finally {
|
|
8778
|
-
resolve2();
|
|
8779
|
-
if (locks2.get(key) === next)
|
|
8780
|
-
locks2.delete(key);
|
|
8781
|
-
}
|
|
8782
|
-
}
|
|
8783
|
-
var locks2;
|
|
8784
|
-
var init_async_mutex = __esm({
|
|
8785
|
-
"dist/utils/async-mutex.js"() {
|
|
8786
|
-
"use strict";
|
|
8787
|
-
locks2 = /* @__PURE__ */ new Map();
|
|
8788
|
-
}
|
|
8789
|
-
});
|
|
8790
|
-
|
|
8791
|
-
// dist/utils/occ-json-write.js
|
|
8792
|
-
import fs25 from "node:fs/promises";
|
|
8793
|
-
import path28 from "node:path";
|
|
8794
|
-
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
8795
|
-
import lockfile4 from "proper-lockfile";
|
|
8796
|
-
async function writeOccJsonFile2(filePath, payload, options) {
|
|
8797
|
-
const { expectedVersion, settleMs = 50, trailingNewline = false } = options;
|
|
8798
|
-
const newVersion = expectedVersion === null ? 1 : expectedVersion + 1;
|
|
8799
|
-
const writeId = randomUUID4();
|
|
8800
|
-
const data = { ...payload, version: newVersion, writeId };
|
|
8801
|
-
const content = JSON.stringify(data, null, 2) + (trailingNewline ? "\n" : "");
|
|
8802
|
-
const dir = path28.dirname(filePath);
|
|
8803
|
-
await fs25.mkdir(dir, { recursive: true });
|
|
8804
|
-
const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
8805
|
-
await fs25.writeFile(tempPath, content, "utf-8");
|
|
8806
|
-
if (expectedVersion === null) {
|
|
8807
|
-
try {
|
|
8808
|
-
await fs25.link(tempPath, filePath);
|
|
8809
|
-
} catch (err) {
|
|
8810
|
-
await fs25.unlink(tempPath).catch(() => {
|
|
8811
|
-
});
|
|
8812
|
-
if (isFileExistsError(err)) {
|
|
8813
|
-
throw new OccWriteConflictError2();
|
|
8814
|
-
}
|
|
8815
|
-
throw err;
|
|
8816
|
-
}
|
|
8817
|
-
await fs25.unlink(tempPath).catch(() => {
|
|
8818
|
-
});
|
|
8819
|
-
return { version: newVersion, writeId };
|
|
8820
|
-
}
|
|
8821
|
-
try {
|
|
8822
|
-
let currentVersion = null;
|
|
8823
|
-
try {
|
|
8824
|
-
const current = JSON.parse(await fs25.readFile(filePath, "utf-8"));
|
|
8825
|
-
currentVersion = current.version ?? 0;
|
|
8826
|
-
} catch {
|
|
8827
|
-
currentVersion = null;
|
|
8828
|
-
}
|
|
8829
|
-
if (currentVersion !== expectedVersion) {
|
|
8830
|
-
throw new OccWriteConflictError2();
|
|
8831
|
-
}
|
|
8832
|
-
await fs25.rename(tempPath, filePath);
|
|
8833
|
-
if (settleMs > 0) {
|
|
8834
|
-
await new Promise((resolve2) => setTimeout(resolve2, settleMs));
|
|
8835
|
-
}
|
|
8836
|
-
const afterWrite = JSON.parse(await fs25.readFile(filePath, "utf-8"));
|
|
8837
|
-
if (afterWrite.writeId !== writeId) {
|
|
8838
|
-
throw new OccWriteConflictError2();
|
|
8839
|
-
}
|
|
8840
|
-
} catch (err) {
|
|
8841
|
-
await fs25.unlink(tempPath).catch(() => {
|
|
8842
|
-
});
|
|
8843
|
-
throw err;
|
|
8844
|
-
}
|
|
8845
|
-
return { version: newVersion, writeId };
|
|
8846
|
-
}
|
|
8847
|
-
async function withOccRetry2(operation, options) {
|
|
8848
|
-
const maxAttempts = options?.maxAttempts ?? 10;
|
|
8849
|
-
const isRetryable = options?.isRetryable;
|
|
8850
|
-
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
8851
|
-
try {
|
|
8852
|
-
return await operation();
|
|
8853
|
-
} catch (err) {
|
|
8854
|
-
const retryable = err instanceof OccWriteConflictError2 || (isRetryable?.(err) ?? false);
|
|
8855
|
-
if (retryable && attempt < maxAttempts) {
|
|
8856
|
-
const baseDelay = Math.min(10 * Math.pow(2, attempt - 1), 100);
|
|
8857
|
-
const jitter = Math.random() * baseDelay;
|
|
8858
|
-
await new Promise((resolve2) => setTimeout(resolve2, baseDelay + jitter));
|
|
8859
|
-
continue;
|
|
8860
|
-
}
|
|
8861
|
-
throw err;
|
|
8862
|
-
}
|
|
8863
|
-
}
|
|
8864
|
-
throw new Error("Unreachable");
|
|
8865
|
-
}
|
|
8866
|
-
async function withOccFileLock2(filePath, fn) {
|
|
8867
|
-
const dir = path28.dirname(filePath);
|
|
8868
|
-
await fs25.mkdir(dir, { recursive: true });
|
|
8869
|
-
const MAX_ATTEMPTS = 14;
|
|
8870
|
-
let release = null;
|
|
8871
|
-
for (let attempt = 1; release === null; attempt++) {
|
|
8872
|
-
try {
|
|
8873
|
-
release = await lockfile4.lock(filePath, {
|
|
8874
|
-
lockfilePath: `${filePath}.lock`,
|
|
8875
|
-
realpath: false,
|
|
8876
|
-
stale: 1e4,
|
|
8877
|
-
retries: 0,
|
|
8878
|
-
// A compromised lock (the lock dir vanished or refresh failed
|
|
8879
|
-
// mid-hold, e.g. the branch directory containing it was deleted)
|
|
8880
|
-
// must not crash the process, which is proper-lockfile's default.
|
|
8881
|
-
// Our critical sections are short and idempotent-on-conflict (OCC
|
|
8882
|
-
// verify inside); log and let the section finish.
|
|
8883
|
-
onCompromised: (err) => {
|
|
8884
|
-
log12.warn("lock", `Lock compromised mid-hold for ${filePath}`, {
|
|
8885
|
-
error: getErrorMessage(err)
|
|
8886
|
-
});
|
|
8887
|
-
}
|
|
8888
|
-
});
|
|
8889
|
-
} catch (err) {
|
|
8890
|
-
const code = isNodeError(err) ? err.code : void 0;
|
|
8891
|
-
const contended = code === "ELOCKED";
|
|
8892
|
-
if (!contended || attempt >= MAX_ATTEMPTS) {
|
|
8893
|
-
throw new OccWriteConflictError2(`Could not acquire file lock: ${getErrorMessage(err)}`);
|
|
8894
|
-
}
|
|
8895
|
-
const baseDelay = Math.min(50 * Math.pow(1.6, attempt - 1), 2e3);
|
|
8896
|
-
const jitter = Math.random() * baseDelay;
|
|
8897
|
-
await new Promise((resolve2) => setTimeout(resolve2, baseDelay + jitter));
|
|
8898
|
-
}
|
|
8899
|
-
}
|
|
8900
|
-
try {
|
|
8901
|
-
return await fn();
|
|
8902
|
-
} finally {
|
|
8903
|
-
await release().catch((err) => {
|
|
8904
|
-
log12.warn("lock", `Failed to release lock for ${filePath}`, { error: getErrorMessage(err) });
|
|
8905
|
-
});
|
|
8906
|
-
}
|
|
8907
|
-
}
|
|
8908
|
-
var log12, OccWriteConflictError2;
|
|
8909
|
-
var init_occ_json_write = __esm({
|
|
8910
|
-
"dist/utils/occ-json-write.js"() {
|
|
8911
|
-
"use strict";
|
|
8912
|
-
init_error();
|
|
8913
|
-
init_debug2();
|
|
8914
|
-
log12 = createDebugLogger3({ prefix: "OccJsonWrite" });
|
|
8915
|
-
OccWriteConflictError2 = class extends Error {
|
|
8916
|
-
constructor(message = "Concurrent modification detected") {
|
|
8917
|
-
super(message);
|
|
8918
|
-
this.name = "OccWriteConflictError";
|
|
8919
|
-
}
|
|
8920
|
-
};
|
|
8921
|
-
}
|
|
8922
|
-
});
|
|
8923
|
-
|
|
8924
8959
|
// dist/branch-metadata.js
|
|
8925
8960
|
import fs26 from "node:fs/promises";
|
|
8926
8961
|
import path29 from "node:path";
|
|
@@ -9071,7 +9106,11 @@ var init_branch_metadata = __esm({
|
|
|
9071
9106
|
createdBy: existing?.branch.createdBy ?? incoming.branch?.createdBy ?? defaults.createdBy,
|
|
9072
9107
|
createdAt: existing?.branch.createdAt ?? defaults.createdAt,
|
|
9073
9108
|
// Fork point is recorded once at creation; later saves must not move it
|
|
9074
|
-
baseBranch: existing?.branch.baseBranch ?? incoming.branch?.baseBranch
|
|
9109
|
+
baseBranch: existing?.branch.baseBranch ?? incoming.branch?.baseBranch,
|
|
9110
|
+
// Always stamped fresh — the spreads above would otherwise let
|
|
9111
|
+
// the existing (creation-time) value win forever, freezing the
|
|
9112
|
+
// timestamp the editor's Branches panel sorts and displays by
|
|
9113
|
+
updatedAt: now
|
|
9075
9114
|
}
|
|
9076
9115
|
};
|
|
9077
9116
|
const written = await this.write(merged, version);
|
|
@@ -9256,15 +9295,31 @@ async function migrate(options) {
|
|
|
9256
9295
|
return { opCount: 0 };
|
|
9257
9296
|
}
|
|
9258
9297
|
}
|
|
9259
|
-
|
|
9260
|
-
|
|
9261
|
-
|
|
9262
|
-
|
|
9263
|
-
|
|
9298
|
+
const isBranchClone = Boolean(await BranchMetadataFileManager2.loadOnly(projectDir));
|
|
9299
|
+
const applyOps = async () => {
|
|
9300
|
+
for (const op of ops) {
|
|
9301
|
+
if (op.kind === "rename") {
|
|
9302
|
+
await fs27.rename(op.from, op.to);
|
|
9303
|
+
} else {
|
|
9304
|
+
await fs27.writeFile(op.filePath, op.content, "utf-8");
|
|
9305
|
+
}
|
|
9264
9306
|
}
|
|
9307
|
+
};
|
|
9308
|
+
if (isBranchClone) {
|
|
9309
|
+
const lockPath = path30.join(projectDir, ".canopy-meta", "schema");
|
|
9310
|
+
try {
|
|
9311
|
+
await withLock2(lockPath, () => withOccFileLock2(lockPath, applyOps));
|
|
9312
|
+
} catch (err) {
|
|
9313
|
+
if (err instanceof OccWriteConflictError2) {
|
|
9314
|
+
throw new MigrateError("Another process is modifying the schema, try again.");
|
|
9315
|
+
}
|
|
9316
|
+
throw err;
|
|
9317
|
+
}
|
|
9318
|
+
} else {
|
|
9319
|
+
await applyOps();
|
|
9265
9320
|
}
|
|
9266
9321
|
p3.log.success(`Applied ${ops.length} operation(s).`);
|
|
9267
|
-
if (
|
|
9322
|
+
if (isBranchClone) {
|
|
9268
9323
|
await invalidateBranchContentCaches2(projectDir);
|
|
9269
9324
|
}
|
|
9270
9325
|
try {
|
|
@@ -9288,6 +9343,8 @@ var init_migrate = __esm({
|
|
|
9288
9343
|
init_fs();
|
|
9289
9344
|
init_schema();
|
|
9290
9345
|
init_error();
|
|
9346
|
+
init_async_mutex();
|
|
9347
|
+
init_occ_json_write();
|
|
9291
9348
|
init_branch_metadata();
|
|
9292
9349
|
init_content_index_generation();
|
|
9293
9350
|
MIGRATE_FORMATS = ["md", "mdx", "json", "yaml"];
|
|
@@ -429,14 +429,20 @@ var init_media = __esm({
|
|
|
429
429
|
|
|
430
430
|
// dist/config/schemas/config.js
|
|
431
431
|
import { z as z5 } from "zod";
|
|
432
|
-
var defaultBranchAccessSchema, defaultPathAccessSchema, defaultBaseBranchSchema, defaultRemoteNameSchema, defaultRemoteUrlSchema, gitBotAuthorNameSchema, gitBotAuthorEmailSchema, githubTokenEnvVarSchema, operatingModeSchema, deployedAsSchema, contentRootSchema, sourceRootSchema, deploymentNameSchema, devContentSyncSchema, devConfigSchema, editorConfigSchema, CanopyConfigSchema, DEFAULT_PROD_WORKSPACE;
|
|
432
|
+
var defaultBranchAccessSchema, defaultPathAccessLevelSchema, defaultPathAccessLevelsSchema, defaultPathAccessSchema, defaultBaseBranchSchema, defaultRemoteNameSchema, defaultRemoteUrlSchema, gitBotAuthorNameSchema, gitBotAuthorEmailSchema, githubTokenEnvVarSchema, operatingModeSchema, deployedAsSchema, contentRootSchema, sourceRootSchema, deploymentNameSchema, devContentSyncSchema, devConfigSchema, editorConfigSchema, CanopyConfigSchema, DEFAULT_PROD_WORKSPACE;
|
|
433
433
|
var init_config = __esm({
|
|
434
434
|
"dist/config/schemas/config.js"() {
|
|
435
435
|
"use strict";
|
|
436
436
|
init_collection();
|
|
437
437
|
init_media();
|
|
438
438
|
defaultBranchAccessSchema = z5.enum(["allow", "deny"]).default("deny");
|
|
439
|
-
|
|
439
|
+
defaultPathAccessLevelSchema = z5.enum(["allow", "deny"]);
|
|
440
|
+
defaultPathAccessLevelsSchema = z5.object({
|
|
441
|
+
read: defaultPathAccessLevelSchema.optional(),
|
|
442
|
+
edit: defaultPathAccessLevelSchema.optional(),
|
|
443
|
+
review: defaultPathAccessLevelSchema.optional()
|
|
444
|
+
}).strict();
|
|
445
|
+
defaultPathAccessSchema = z5.union([defaultPathAccessLevelSchema, defaultPathAccessLevelsSchema]).default("deny");
|
|
440
446
|
defaultBaseBranchSchema = z5.string().default("main");
|
|
441
447
|
defaultRemoteNameSchema = z5.string().default("origin");
|
|
442
448
|
defaultRemoteUrlSchema = z5.string().min(1);
|
|
@@ -469,6 +475,10 @@ var init_config = __esm({
|
|
|
469
475
|
// have .default('deny'), so the field is optional on input but always resolves to
|
|
470
476
|
// 'allow'/'deny' (never undefined) on output. An outer .optional() would short-circuit
|
|
471
477
|
// before the inner default runs, defeating the fail-closed default (SCH-M1).
|
|
478
|
+
// defaultPathAccessSchema's union keeps the same rule: the .default('deny') sits on the
|
|
479
|
+
// OUTER union, not inside defaultPathAccessLevelsSchema, so an omitted top-level field
|
|
480
|
+
// still resolves to 'deny' and an omitted level inside the object form stays undefined
|
|
481
|
+
// (resolved to 'deny' at read time by resolveDefaultPathAccess).
|
|
472
482
|
defaultBranchAccess: defaultBranchAccessSchema,
|
|
473
483
|
defaultPathAccess: defaultPathAccessSchema,
|
|
474
484
|
// .optional() deliberately defeats defaultBaseBranchSchema's .default('main'):
|
|
@@ -4117,7 +4127,11 @@ var BranchMetadataFileManager = class _BranchMetadataFileManager {
|
|
|
4117
4127
|
createdBy: existing?.branch.createdBy ?? incoming.branch?.createdBy ?? defaults.createdBy,
|
|
4118
4128
|
createdAt: existing?.branch.createdAt ?? defaults.createdAt,
|
|
4119
4129
|
// Fork point is recorded once at creation; later saves must not move it
|
|
4120
|
-
baseBranch: existing?.branch.baseBranch ?? incoming.branch?.baseBranch
|
|
4130
|
+
baseBranch: existing?.branch.baseBranch ?? incoming.branch?.baseBranch,
|
|
4131
|
+
// Always stamped fresh — the spreads above would otherwise let
|
|
4132
|
+
// the existing (creation-time) value win forever, freezing the
|
|
4133
|
+
// timestamp the editor's Branches panel sorts and displays by
|
|
4134
|
+
updatedAt: now
|
|
4121
4135
|
}
|
|
4122
4136
|
};
|
|
4123
4137
|
const written = await this.write(merged, version);
|
|
@@ -4670,6 +4684,7 @@ var GitManager = class _GitManager {
|
|
|
4670
4684
|
}
|
|
4671
4685
|
if (options.branchType === "orphan") {
|
|
4672
4686
|
await git.createOrphanSettingsBranch(options.branchName, {});
|
|
4687
|
+
await git.ensureGitExclude("*.lock");
|
|
4673
4688
|
} else {
|
|
4674
4689
|
await git.checkoutBranch(options.branchName);
|
|
4675
4690
|
if (options.gitExcludePattern) {
|