@git.zone/cli 3.2.1 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/.smartconfig.json +0 -1
  2. package/dist_ts/00_commitinfo_data.js +2 -2
  3. package/dist_ts/classes.gitzoneconfig.js +1 -1
  4. package/dist_ts/classes.project.js +1 -1
  5. package/dist_ts/gitzone.cli.js +1 -1
  6. package/dist_ts/gitzone.logging.js +1 -1
  7. package/dist_ts/helpers.changelog.js +1 -1
  8. package/dist_ts/helpers.climode.js +1 -1
  9. package/dist_ts/helpers.smartconfig.js +61 -11
  10. package/dist_ts/helpers.smartconfigmigrations.js +1 -1
  11. package/dist_ts/helpers.tsdocker.js +1 -1
  12. package/dist_ts/helpers.workflow.d.ts +0 -2
  13. package/dist_ts/helpers.workflow.js +23 -12
  14. package/dist_ts/index.js +1 -1
  15. package/dist_ts/mod_audit/index.js +1 -1
  16. package/dist_ts/mod_commit/index.js +1 -1
  17. package/dist_ts/mod_commit/mod.helpers.d.ts +3 -3
  18. package/dist_ts/mod_commit/mod.helpers.js +10 -10
  19. package/dist_ts/mod_commit/mod.plugins.js +1 -1
  20. package/dist_ts/mod_commit/mod.ui.js +1 -1
  21. package/dist_ts/mod_config/classes.commitconfig.js +1 -1
  22. package/dist_ts/mod_config/classes.releaseconfig.js +1 -1
  23. package/dist_ts/mod_config/index.js +23 -24
  24. package/dist_ts/mod_config/mod.plugins.js +1 -1
  25. package/dist_ts/mod_deprecate/index.js +1 -1
  26. package/dist_ts/mod_deprecate/mod.plugins.js +1 -1
  27. package/dist_ts/mod_docker/classes.dockerpruner.js +7 -1
  28. package/dist_ts/mod_docker/index.js +1 -1
  29. package/dist_ts/mod_docker/mod.plugins.js +1 -1
  30. package/dist_ts/mod_format/classes.baseformatter.js +1 -1
  31. package/dist_ts/mod_format/classes.diffreporter.js +1 -1
  32. package/dist_ts/mod_format/classes.formatcontext.js +1 -1
  33. package/dist_ts/mod_format/classes.formatplanner.js +1 -1
  34. package/dist_ts/mod_format/classes.formatstats.js +1 -1
  35. package/dist_ts/mod_format/formatters/assets.formatter.js +1 -1
  36. package/dist_ts/mod_format/formatters/cleanup.formatter.js +1 -1
  37. package/dist_ts/mod_format/formatters/copy.formatter.js +1 -1
  38. package/dist_ts/mod_format/formatters/gitignore.formatter.js +1 -1
  39. package/dist_ts/mod_format/formatters/license.formatter.js +1 -1
  40. package/dist_ts/mod_format/formatters/packagejson.formatter.js +1 -1
  41. package/dist_ts/mod_format/formatters/prettier.formatter.js +1 -1
  42. package/dist_ts/mod_format/formatters/readme.formatter.js +1 -1
  43. package/dist_ts/mod_format/formatters/smartconfig.formatter.js +1 -1
  44. package/dist_ts/mod_format/formatters/templates.formatter.js +1 -1
  45. package/dist_ts/mod_format/formatters/tsconfig.formatter.js +1 -1
  46. package/dist_ts/mod_format/index.js +1 -1
  47. package/dist_ts/mod_format/interfaces.format.js +1 -1
  48. package/dist_ts/mod_format/mod.plugins.js +1 -1
  49. package/dist_ts/mod_helpers/index.js +1 -1
  50. package/dist_ts/mod_helpers/mod.plugins.js +1 -1
  51. package/dist_ts/mod_meta/index.js +1 -1
  52. package/dist_ts/mod_meta/meta.classes.meta.js +1 -1
  53. package/dist_ts/mod_meta/meta.interfaces.js +1 -1
  54. package/dist_ts/mod_meta/meta.plugins.js +1 -1
  55. package/dist_ts/mod_open/index.js +1 -1
  56. package/dist_ts/mod_open/mod.plugins.js +1 -1
  57. package/dist_ts/mod_release/helpers.releasebranch.d.ts +46 -0
  58. package/dist_ts/mod_release/helpers.releasebranch.js +579 -0
  59. package/dist_ts/mod_release/index.d.ts +10 -0
  60. package/dist_ts/mod_release/index.js +300 -92
  61. package/dist_ts/mod_release/mod.plugins.js +1 -1
  62. package/dist_ts/mod_services/classes.dockercontainer.d.ts +50 -3
  63. package/dist_ts/mod_services/classes.dockercontainer.js +646 -84
  64. package/dist_ts/mod_services/classes.globalregistry.d.ts +10 -24
  65. package/dist_ts/mod_services/classes.globalregistry.js +210 -62
  66. package/dist_ts/mod_services/classes.globalregistrystore.d.ts +48 -0
  67. package/dist_ts/mod_services/classes.globalregistrystore.js +156 -0
  68. package/dist_ts/mod_services/classes.interprocesslock.d.ts +21 -0
  69. package/dist_ts/mod_services/classes.interprocesslock.js +141 -0
  70. package/dist_ts/mod_services/classes.serviceconfiguration.d.ts +15 -12
  71. package/dist_ts/mod_services/classes.serviceconfiguration.js +188 -91
  72. package/dist_ts/mod_services/classes.servicedatamarker.d.ts +32 -7
  73. package/dist_ts/mod_services/classes.servicedatamarker.js +145 -49
  74. package/dist_ts/mod_services/classes.servicemanager.d.ts +70 -28
  75. package/dist_ts/mod_services/classes.servicemanager.js +995 -421
  76. package/dist_ts/mod_services/classes.servicenames.d.ts +8 -0
  77. package/dist_ts/mod_services/classes.servicenames.js +54 -0
  78. package/dist_ts/mod_services/classes.serviceoptions.js +1 -1
  79. package/dist_ts/mod_services/classes.servicepruner.d.ts +3 -0
  80. package/dist_ts/mod_services/classes.servicepruner.js +208 -46
  81. package/dist_ts/mod_services/helpers.js +1 -1
  82. package/dist_ts/mod_services/index.d.ts +2 -0
  83. package/dist_ts/mod_services/index.js +81 -58
  84. package/dist_ts/mod_services/mod.plugins.js +1 -1
  85. package/dist_ts/mod_standard/index.js +2 -2
  86. package/dist_ts/mod_standard/mod.plugins.js +1 -1
  87. package/dist_ts/mod_start/index.js +1 -1
  88. package/dist_ts/mod_start/mod.plugins.js +1 -1
  89. package/dist_ts/mod_template/index.js +1 -1
  90. package/dist_ts/mod_template/mod.plugins.js +1 -1
  91. package/dist_ts/mod_tools/classes.packagemanager.js +1 -1
  92. package/dist_ts/mod_tools/index.js +1 -1
  93. package/dist_ts/mod_tools/mod.plugins.js +1 -1
  94. package/dist_ts/paths.js +1 -1
  95. package/dist_ts/plugins.d.ts +3 -1
  96. package/dist_ts/plugins.js +4 -2
  97. package/dist_ts_migration/001.service-selection.d.ts +9 -0
  98. package/dist_ts_migration/001.service-selection.js +51 -0
  99. package/dist_ts_migration/002.runtime-config.d.ts +19 -0
  100. package/dist_ts_migration/002.runtime-config.js +170 -0
  101. package/dist_ts_migration/003.service-data-marker.d.ts +9 -0
  102. package/dist_ts_migration/003.service-data-marker.js +156 -0
  103. package/dist_ts_migration/004.global-registry.d.ts +13 -0
  104. package/dist_ts_migration/004.global-registry.js +165 -0
  105. package/dist_ts_migration/index.d.ts +11 -0
  106. package/dist_ts_migration/index.js +59 -0
  107. package/package.json +6 -3
  108. package/readme.hints.md +102 -25
  109. package/readme.md +144 -41
  110. package/readme.plan.md +29 -16
  111. package/ts/00_commitinfo_data.ts +1 -1
  112. package/ts/helpers.smartconfig.ts +63 -10
  113. package/ts/helpers.workflow.ts +41 -12
  114. package/ts/mod_commit/mod.helpers.ts +12 -8
  115. package/ts/mod_config/index.ts +22 -23
  116. package/ts/mod_docker/classes.dockerpruner.ts +6 -0
  117. package/ts/mod_release/helpers.releasebranch.ts +1282 -0
  118. package/ts/mod_release/index.ts +608 -129
  119. package/ts/mod_services/classes.dockercontainer.ts +912 -96
  120. package/ts/mod_services/classes.globalregistry.ts +290 -89
  121. package/ts/mod_services/classes.globalregistrystore.ts +279 -0
  122. package/ts/mod_services/classes.interprocesslock.ts +189 -0
  123. package/ts/mod_services/classes.serviceconfiguration.ts +215 -108
  124. package/ts/mod_services/classes.servicedatamarker.ts +210 -52
  125. package/ts/mod_services/classes.servicemanager.ts +1332 -512
  126. package/ts/mod_services/classes.servicenames.ts +76 -0
  127. package/ts/mod_services/classes.servicepruner.ts +310 -52
  128. package/ts/mod_services/index.ts +89 -62
  129. package/ts/mod_standard/index.ts +1 -1
  130. package/ts/plugins.ts +4 -0
  131. package/ts_migration/001.service-selection.ts +77 -0
  132. package/ts_migration/002.runtime-config.ts +218 -0
  133. package/ts_migration/003.service-data-marker.ts +216 -0
  134. package/ts_migration/004.global-registry.ts +272 -0
  135. package/ts_migration/index.ts +83 -0
@@ -0,0 +1,156 @@
1
+ import * as plugins from '../plugins.js';
2
+ import { InterProcessLock } from './classes.interprocesslock.js';
3
+ const isPlainObject = (valueArg) => {
4
+ return typeof valueArg === 'object' && valueArg !== null && !Array.isArray(valueArg);
5
+ };
6
+ const assertAllowedKeys = (valueArg, allowedKeysArg, contextArg) => {
7
+ if (Object.keys(valueArg).some((keyArg) => !allowedKeysArg.includes(keyArg))) {
8
+ throw new Error(`Global services registry ${contextArg} contains unsupported fields.`);
9
+ }
10
+ };
11
+ const assertOptionalStrings = (valueArg, keysArg, contextArg) => {
12
+ for (const key of keysArg) {
13
+ if (valueArg[key] !== undefined && (typeof valueArg[key] !== 'string' || !valueArg[key])) {
14
+ throw new Error(`Global services registry ${contextArg}.${key} must be a non-empty string.`);
15
+ }
16
+ }
17
+ };
18
+ const assertOptionalNumbers = (valueArg, keysArg, contextArg) => {
19
+ for (const key of keysArg) {
20
+ const value = valueArg[key];
21
+ if (value !== undefined && (typeof value !== 'number' || !Number.isFinite(value))) {
22
+ throw new Error(`Global services registry ${contextArg}.${key} must be a finite number.`);
23
+ }
24
+ }
25
+ };
26
+ /** Validate the canonical runtime schema after startup migrations have completed. */
27
+ export const assertCanonicalGlobalRegistryData = (dataArg) => {
28
+ if (!isPlainObject(dataArg)) {
29
+ throw new Error('Global services registry root must be a JSON object.');
30
+ }
31
+ assertAllowedKeys(dataArg, ['schemaVersion', 'projects'], 'root');
32
+ if (dataArg.schemaVersion !== 2 || !isPlainObject(dataArg.projects)) {
33
+ throw new Error('Global services registry requires canonical schema version 2.');
34
+ }
35
+ for (const [projectPath, rawProject] of Object.entries(dataArg.projects)) {
36
+ if (!isPlainObject(rawProject)) {
37
+ throw new Error(`Global services registry project ${projectPath} must be a JSON object.`);
38
+ }
39
+ assertAllowedKeys(rawProject, [
40
+ 'projectPath',
41
+ 'projectName',
42
+ 'containers',
43
+ 'ports',
44
+ 'legacy',
45
+ 'enabledServices',
46
+ 'lastActive',
47
+ ], `project ${projectPath}`);
48
+ if (typeof rawProject.projectPath !== 'string' ||
49
+ !rawProject.projectPath ||
50
+ plugins.path.resolve(rawProject.projectPath) !== plugins.path.resolve(projectPath)) {
51
+ throw new Error(`Global services registry project ${projectPath} has an invalid or inconsistent path.`);
52
+ }
53
+ if (typeof rawProject.projectName !== 'string' || !rawProject.projectName) {
54
+ throw new Error(`Global services registry project ${projectPath} has an invalid name.`);
55
+ }
56
+ if (!isPlainObject(rawProject.containers) || !isPlainObject(rawProject.ports)) {
57
+ throw new Error(`Global services registry project ${projectPath} requires container and port objects.`);
58
+ }
59
+ if (!Array.isArray(rawProject.enabledServices)) {
60
+ throw new Error(`Global services registry project ${projectPath} has invalid enabled services.`);
61
+ }
62
+ const canonicalServices = ['mongodb', 'objectstorage', 'elasticsearch'];
63
+ if (!rawProject.enabledServices.every((serviceArg) => typeof serviceArg === 'string' && canonicalServices.includes(serviceArg)) ||
64
+ new Set(rawProject.enabledServices).size !== rawProject.enabledServices.length) {
65
+ throw new Error(`Global services registry project ${projectPath} has noncanonical enabled services.`);
66
+ }
67
+ if (typeof rawProject.lastActive !== 'number' || !Number.isFinite(rawProject.lastActive)) {
68
+ throw new Error(`Global services registry project ${projectPath} has an invalid lastActive value.`);
69
+ }
70
+ const rawContainers = rawProject.containers;
71
+ const rawPorts = rawProject.ports;
72
+ assertAllowedKeys(rawContainers, ['mongo', 'objectstorage', 'elasticsearch'], `project ${projectPath} containers`);
73
+ assertOptionalStrings(rawContainers, ['mongo', 'objectstorage', 'elasticsearch'], `project ${projectPath}.containers`);
74
+ assertAllowedKeys(rawPorts, ['mongo', 's3', 's3Ui', 'elasticsearch'], `project ${projectPath} ports`);
75
+ assertOptionalNumbers(rawPorts, ['mongo', 's3', 's3Ui', 'elasticsearch'], `project ${projectPath}.ports`);
76
+ if (rawProject.legacy !== undefined) {
77
+ if (!isPlainObject(rawProject.legacy)) {
78
+ throw new Error(`Global services registry project ${projectPath} has invalid legacy evidence.`);
79
+ }
80
+ assertAllowedKeys(rawProject.legacy, ['minioContainer'], `project ${projectPath} legacy`);
81
+ assertOptionalStrings(rawProject.legacy, ['minioContainer'], `project ${projectPath}.legacy`);
82
+ if (!rawProject.legacy.minioContainer) {
83
+ throw new Error(`Global services registry project ${projectPath} has empty legacy evidence.`);
84
+ }
85
+ }
86
+ }
87
+ return dataArg;
88
+ };
89
+ /** Raw, atomically replaced registry storage shared by runtime and migrations. */
90
+ export class GlobalRegistryStore {
91
+ filePath;
92
+ lock;
93
+ constructor(optionsArg = {}) {
94
+ this.filePath = plugins.path.resolve(optionsArg.filePath ||
95
+ plugins.path.join(plugins.smartpath.get.home(), '.smartconfig', 'kv', 'gitzone-services.json'));
96
+ this.lock = new InterProcessLock({
97
+ lockPath: `${this.filePath}.lock`,
98
+ description: 'Global services registry',
99
+ timeoutMs: optionsArg.lockTimeoutMs,
100
+ pollMs: optionsArg.lockPollMs,
101
+ });
102
+ }
103
+ async readRaw() {
104
+ let content;
105
+ try {
106
+ content = await plugins.fs.readFile(this.filePath, 'utf8');
107
+ }
108
+ catch (error) {
109
+ if (error.code === 'ENOENT') {
110
+ return {};
111
+ }
112
+ throw new Error('Global services registry could not be read.', { cause: error });
113
+ }
114
+ try {
115
+ return JSON.parse(content);
116
+ }
117
+ catch (error) {
118
+ throw new Error('Global services registry contains invalid JSON.', { cause: error });
119
+ }
120
+ }
121
+ async readCanonical() {
122
+ return assertCanonicalGlobalRegistryData(await this.readRaw());
123
+ }
124
+ async transact(operationArg) {
125
+ return this.lock.runExclusive(async () => {
126
+ const transaction = await operationArg(await this.readRaw());
127
+ if (transaction.writeData) {
128
+ await this.writeAtomic(assertCanonicalGlobalRegistryData(transaction.writeData));
129
+ }
130
+ return transaction.result;
131
+ });
132
+ }
133
+ async writeAtomic(dataArg) {
134
+ await plugins.fs.mkdir(plugins.path.dirname(this.filePath), { recursive: true });
135
+ const tempPath = `${this.filePath}.tmp-${process.pid}-${plugins.crypto
136
+ .randomBytes(12)
137
+ .toString('hex')}`;
138
+ let handle;
139
+ try {
140
+ handle = await plugins.fs.open(tempPath, 'wx', 0o600);
141
+ await handle.writeFile(`${JSON.stringify(dataArg, null, 2)}\n`, 'utf8');
142
+ await handle.sync();
143
+ await handle.close();
144
+ handle = undefined;
145
+ await plugins.fs.rename(tempPath, this.filePath);
146
+ }
147
+ catch (error) {
148
+ await handle?.close().catch(() => { });
149
+ await plugins.fs.rm(tempPath, { force: true }).catch(() => { });
150
+ throw new Error('Global services registry could not be written atomically.', {
151
+ cause: error,
152
+ });
153
+ }
154
+ }
155
+ }
156
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5nbG9iYWxyZWdpc3RyeXN0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvbW9kX3NlcnZpY2VzL2NsYXNzZXMuZ2xvYmFscmVnaXN0cnlzdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQTZCakUsTUFBTSxhQUFhLEdBQUcsQ0FBQyxRQUFpQixFQUF1QyxFQUFFO0lBQy9FLE9BQU8sT0FBTyxRQUFRLEtBQUssUUFBUSxJQUFJLFFBQVEsS0FBSyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBQ3ZGLENBQUMsQ0FBQztBQUVGLE1BQU0saUJBQWlCLEdBQUcsQ0FDeEIsUUFBaUMsRUFDakMsY0FBaUMsRUFDakMsVUFBa0IsRUFDWixFQUFFO0lBQ1IsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUM3RSxNQUFNLElBQUksS0FBSyxDQUFDLDRCQUE0QixVQUFVLCtCQUErQixDQUFDLENBQUM7SUFDekYsQ0FBQztBQUNILENBQUMsQ0FBQztBQUVGLE1BQU0scUJBQXFCLEdBQUcsQ0FDNUIsUUFBaUMsRUFDakMsT0FBMEIsRUFDMUIsVUFBa0IsRUFDWixFQUFFO0lBQ1IsS0FBSyxNQUFNLEdBQUcsSUFBSSxPQUFPLEVBQUUsQ0FBQztRQUMxQixJQUFJLFFBQVEsQ0FBQyxHQUFHLENBQUMsS0FBSyxTQUFTLElBQUksQ0FBQyxPQUFPLFFBQVEsQ0FBQyxHQUFHLENBQUMsS0FBSyxRQUFRLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFD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
@@ -0,0 +1,21 @@
1
+ import type { TServiceName } from './classes.servicedatamarker.js';
2
+ export interface IInterProcessLockOptions {
3
+ lockPath: string;
4
+ description: string;
5
+ timeoutMs?: number;
6
+ pollMs?: number;
7
+ }
8
+ /** Atomic-mkdir lock with bounded waiting and manual-only stale-lock recovery. */
9
+ export declare class InterProcessLock {
10
+ readonly lockPath: string;
11
+ private readonly description;
12
+ private readonly timeoutMs;
13
+ private readonly pollMs;
14
+ constructor(optionsArg: IInterProcessLockOptions);
15
+ runExclusive<T>(operationArg: () => Promise<T>): Promise<T>;
16
+ private acquire;
17
+ private release;
18
+ }
19
+ export declare const withInterProcessLock: <T>(optionsArg: IInterProcessLockOptions, operationArg: () => Promise<T>) => Promise<T>;
20
+ export declare const getServiceDataOperationLockPath: (projectPathArg: string, serviceArg: TServiceName) => string;
21
+ export declare const withServiceDataOperationLock: <T>(projectPathArg: string, serviceArg: TServiceName, operationArg: () => Promise<T>) => Promise<T>;
@@ -0,0 +1,141 @@
1
+ import * as plugins from '../plugins.js';
2
+ const isPlainObject = (valueArg) => {
3
+ return typeof valueArg === 'object' && valueArg !== null && !Array.isArray(valueArg);
4
+ };
5
+ /** Atomic-mkdir lock with bounded waiting and manual-only stale-lock recovery. */
6
+ export class InterProcessLock {
7
+ lockPath;
8
+ description;
9
+ timeoutMs;
10
+ pollMs;
11
+ constructor(optionsArg) {
12
+ this.lockPath = plugins.path.resolve(optionsArg.lockPath);
13
+ this.description = optionsArg.description;
14
+ this.timeoutMs = optionsArg.timeoutMs ?? 5_000;
15
+ this.pollMs = optionsArg.pollMs ?? 25;
16
+ if (!this.description) {
17
+ throw new Error('Interprocess lock description must not be empty.');
18
+ }
19
+ if (!Number.isSafeInteger(this.timeoutMs) || this.timeoutMs <= 0) {
20
+ throw new Error('Interprocess lock timeout must be a positive safe integer.');
21
+ }
22
+ if (!Number.isSafeInteger(this.pollMs) || this.pollMs <= 0) {
23
+ throw new Error('Interprocess lock poll interval must be a positive safe integer.');
24
+ }
25
+ }
26
+ async runExclusive(operationArg) {
27
+ const release = await this.acquire();
28
+ let result;
29
+ let primaryError;
30
+ try {
31
+ result = await operationArg();
32
+ }
33
+ catch (error) {
34
+ primaryError = error;
35
+ }
36
+ let releaseError;
37
+ try {
38
+ await release();
39
+ }
40
+ catch (error) {
41
+ releaseError = error;
42
+ }
43
+ if (primaryError && releaseError) {
44
+ throw new AggregateError([primaryError, releaseError], `${this.description} failed and its lock could not be released.`);
45
+ }
46
+ if (primaryError) {
47
+ throw primaryError;
48
+ }
49
+ if (releaseError) {
50
+ throw releaseError;
51
+ }
52
+ return result;
53
+ }
54
+ async acquire() {
55
+ await plugins.fs.mkdir(plugins.path.dirname(this.lockPath), { recursive: true });
56
+ const owner = {
57
+ token: plugins.crypto.randomBytes(16).toString('hex'),
58
+ pid: process.pid,
59
+ createdAt: new Date().toISOString(),
60
+ };
61
+ const ownerPath = plugins.path.join(this.lockPath, 'owner.json');
62
+ const deadlineAt = Date.now() + this.timeoutMs;
63
+ while (true) {
64
+ try {
65
+ await plugins.fs.mkdir(this.lockPath);
66
+ try {
67
+ await plugins.fs.writeFile(ownerPath, `${JSON.stringify(owner)}\n`, {
68
+ encoding: 'utf8',
69
+ flag: 'wx',
70
+ mode: 0o600,
71
+ });
72
+ }
73
+ catch (error) {
74
+ await this.release(owner.token, false).catch(() => { });
75
+ throw error;
76
+ }
77
+ return async () => this.release(owner.token, true);
78
+ }
79
+ catch (error) {
80
+ if (error.code !== 'EEXIST') {
81
+ throw new Error(`${this.description} lock could not be acquired.`, { cause: error });
82
+ }
83
+ const remaining = deadlineAt - Date.now();
84
+ if (remaining <= 0) {
85
+ let ownerDescription = 'owner metadata unavailable';
86
+ try {
87
+ const existingOwner = JSON.parse(await plugins.fs.readFile(ownerPath, 'utf8'));
88
+ if (typeof existingOwner.pid === 'number' &&
89
+ typeof existingOwner.createdAt === 'string') {
90
+ ownerDescription = `pid ${existingOwner.pid}, created ${existingOwner.createdAt}`;
91
+ }
92
+ }
93
+ catch {
94
+ // Incomplete stale locks remain fail-closed and require operator review.
95
+ }
96
+ throw new Error(`${this.description} is locked (${ownerDescription}). ` +
97
+ `If that process no longer exists, inspect and remove ${this.lockPath}.`);
98
+ }
99
+ await plugins.smartdelay.delayFor(Math.min(this.pollMs, remaining));
100
+ }
101
+ }
102
+ }
103
+ async release(tokenArg, requireOwnerArg) {
104
+ const ownerPath = plugins.path.join(this.lockPath, 'owner.json');
105
+ if (requireOwnerArg) {
106
+ let owner;
107
+ try {
108
+ owner = JSON.parse(await plugins.fs.readFile(ownerPath, 'utf8'));
109
+ }
110
+ catch (error) {
111
+ throw new Error(`${this.description} lock ownership could not be verified.`, {
112
+ cause: error,
113
+ });
114
+ }
115
+ if (!isPlainObject(owner) || owner.token !== tokenArg) {
116
+ throw new Error(`${this.description} lock ownership changed before release.`);
117
+ }
118
+ }
119
+ const tombstonePath = `${this.lockPath}.release-${tokenArg}`;
120
+ await plugins.fs.rename(this.lockPath, tombstonePath);
121
+ await plugins.fs.rm(tombstonePath, { recursive: true, force: false });
122
+ }
123
+ }
124
+ export const withInterProcessLock = async (optionsArg, operationArg) => {
125
+ return new InterProcessLock(optionsArg).runExclusive(operationArg);
126
+ };
127
+ export const getServiceDataOperationLockPath = (projectPathArg, serviceArg) => {
128
+ const projectHash = plugins.crypto
129
+ .createHash('sha256')
130
+ .update(plugins.path.resolve(projectPathArg))
131
+ .digest('hex')
132
+ .slice(0, 32);
133
+ return plugins.path.join(plugins.smartpath.get.home(), '.smartconfig', 'kv', 'gitzone-services-locks', `${projectHash}-${serviceArg}.lock`);
134
+ };
135
+ export const withServiceDataOperationLock = async (projectPathArg, serviceArg, operationArg) => {
136
+ return withInterProcessLock({
137
+ lockPath: getServiceDataOperationLockPath(projectPathArg, serviceArg),
138
+ description: `${serviceArg} service data operation`,
139
+ }, operationArg);
140
+ };
141
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5pbnRlcnByb2Nlc3Nsb2NrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvbW9kX3NlcnZpY2VzL2NsYXNzZXMuaW50ZXJwcm9jZXNzbG9jay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQWdCekMsTUFBTSxhQUFhLEdBQUcsQ0FBQyxRQUFpQixFQUF1QyxFQUFFO0lBQy9FLE9BQU8sT0FBTyxRQUFRLEtBQUssUUFBUSxJQUFJLFFBQVEsS0FBSyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBQ3ZGLENBQUMsQ0FBQztBQUVGLGtGQUFrRjtBQUNsRixNQUFNLE9BQU8sZ0JBQWdCO0lBQ1gsUUFBUSxDQUFTO0lBQ2hCLFdBQVcsQ0FBUztJQUNwQixTQUFTLENBQVM7SUFDbEIsTUFBTSxDQUFTO0lBRWhDLFlBQVksVUFBb0M7UUFDOUMsSUFBSSxDQUFDLFFBQVEsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDMUQsSUFBSSxDQUFDLFdBQVcsR0FBRyxVQUFVLENBQUMsV0FBVyxDQUFDO1FBQzFDLElBQUksQ0FBQyxTQUFTLEdBQUcsVUFBVSxDQUFDLFNBQVMsSUFBSSxLQUFLLENBQUM7UUFDL0MsSUFBSSxDQUFDLE1BQU0sR0FBRyxVQUFVLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQztRQUN0QyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ3RCLE1BQU0sSUFBSSxLQUFLLENBQUMsa0RBQWtELENBQUMsQ0FBQztRQUN0RSxDQUFDO1FBQ0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLElBQUksQ0FBQyxTQUFTLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDakUsTUFB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
@@ -8,15 +8,6 @@ export declare const isValidS3BucketName: (bucketArg: unknown) => bucketArg is s
8
8
  * alphabet than custom S3 names. Long names retain a stable hash suffix.
9
9
  */
10
10
  export declare const deriveS3BucketName: (projectNameArg: string) => string;
11
- export type TLegacyS3BucketRepair = {
12
- bucket: unknown;
13
- repaired: false;
14
- } | {
15
- bucket: string;
16
- repaired: true;
17
- };
18
- /** Repair only the exact invalid value emitted by older GitZone releases. */
19
- export declare const repairLegacyGeneratedS3Bucket: (projectNameArg: string, bucketArg: unknown) => TLegacyS3BucketRepair;
20
11
  export interface IServiceConfig {
21
12
  PROJECT_NAME: string;
22
13
  MONGODB_HOST: string;
@@ -33,9 +24,11 @@ export interface IServiceConfig {
33
24
  MONGODB_AUTH_ENABLED: boolean;
34
25
  S3_HOST: string;
35
26
  S3_PORT: string;
36
- S3_CONSOLE_PORT: string;
27
+ S3_UI_PORT: string;
37
28
  S3_ACCESSKEY: string;
38
29
  S3_SECRETKEY: string;
30
+ S3_ADMIN_PASSWORD: string;
31
+ S3_REGION: string;
39
32
  S3_BUCKET: string;
40
33
  S3_ENDPOINT: string;
41
34
  S3_USESSL: boolean;
@@ -45,9 +38,12 @@ export interface IServiceConfig {
45
38
  ELASTICSEARCH_PASS: string;
46
39
  ELASTICSEARCH_URL: string;
47
40
  }
41
+ /** Validate the complete canonical env.json shape before runtime use or persistence. */
42
+ export declare const assertCanonicalServiceRuntimeConfig: (configArg: unknown) => asserts configArg is IServiceConfig;
48
43
  export declare class ServiceConfiguration {
49
44
  private configPath;
50
45
  private config;
46
+ private persistedConfigSnapshot?;
51
47
  private docker;
52
48
  /** Where the effective MongoDB auth mode came from. */
53
49
  private mongoAuthSource;
@@ -56,6 +52,8 @@ export declare class ServiceConfiguration {
56
52
  * Load or create the configuration
57
53
  */
58
54
  loadOrCreate(): Promise<IServiceConfig>;
55
+ /** Reload and validate persisted runtime state without deriving or writing fields. */
56
+ reloadFromDisk(): Promise<IServiceConfig>;
59
57
  /**
60
58
  * Fold `@git.zone/cli.serviceOptions` into the runtime configuration.
61
59
  */
@@ -90,6 +88,8 @@ export declare class ServiceConfiguration {
90
88
  * closed on the combination.
91
89
  */
92
90
  assertMongoExposureIsSafe(): void;
91
+ /** Reject ObjectStorage's prohibited defaults and credential reuse before Docker mutation. */
92
+ assertObjectStorageCredentialsAreSafe(): void;
93
93
  /**
94
94
  * Persist the MongoDB auth mode.
95
95
  *
@@ -131,7 +131,8 @@ export declare class ServiceConfiguration {
131
131
  */
132
132
  getContainerNames(): {
133
133
  mongo: string;
134
- minio: string;
134
+ objectstorage: string;
135
+ legacyMinio: string;
135
136
  elasticsearch: string;
136
137
  };
137
138
  /**
@@ -142,7 +143,7 @@ export declare class ServiceConfiguration {
142
143
  */
143
144
  getDataDirectories(): {
144
145
  mongo: string;
145
- minio: string;
146
+ objectstorage: string;
146
147
  elasticsearch: string;
147
148
  };
148
149
  /**
@@ -153,6 +154,8 @@ export declare class ServiceConfiguration {
153
154
  * Validate and update ports if they're not available
154
155
  */
155
156
  validateAndUpdatePorts(): Promise<boolean>;
157
+ /** Validate ObjectStorage host ports only after legacy/conflict checks pass. */
158
+ validateObjectStoragePorts(): Promise<boolean>;
156
159
  /**
157
160
  * Force reconfigure all ports with new available ones
158
161
  */