@camstack/agent 1.1.43 → 1.1.45
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/{chunk-L34OOQI3.mjs → chunk-Y6BUFOWG.mjs} +236 -67
- package/dist/chunk-Y6BUFOWG.mjs.map +1 -0
- package/dist/{chunk-MMKRM4RT.mjs → chunk-Z7VZQCFX.mjs} +60 -2
- package/dist/chunk-Z7VZQCFX.mjs.map +1 -0
- package/dist/cli.js +297 -70
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +2 -2
- package/dist/index.js +293 -66
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/starter.js +235 -66
- package/dist/starter.js.map +1 -1
- package/dist/starter.mjs +1 -1
- package/package.json +4 -4
- package/dist/chunk-L34OOQI3.mjs.map +0 -1
- package/dist/chunk-MMKRM4RT.mjs.map +0 -1
package/dist/index.mjs
CHANGED
package/dist/starter.js
CHANGED
|
@@ -59,6 +59,9 @@ var require_dist = __commonJS({
|
|
|
59
59
|
var src_exports = {};
|
|
60
60
|
__export(src_exports, {
|
|
61
61
|
AGENT_ROOT_SPEC: () => AGENT_ROOT_SPEC2,
|
|
62
|
+
DEV_UPLOADS_DIRNAME: () => DEV_UPLOADS_DIRNAME,
|
|
63
|
+
DEV_UPLOADS_KEEP_COUNT: () => DEV_UPLOADS_KEEP_COUNT,
|
|
64
|
+
DEV_UPLOAD_MANIFEST_FILE: () => DEV_UPLOAD_MANIFEST_FILE,
|
|
62
65
|
HOST_EXTERNAL_SPECIFIERS: () => HOST_EXTERNAL_SPECIFIERS,
|
|
63
66
|
HUB_ROOT_SPEC: () => HUB_ROOT_SPEC,
|
|
64
67
|
RESTART_INTENT_FILE: () => RESTART_INTENT_FILE,
|
|
@@ -68,11 +71,17 @@ var require_dist = __commonJS({
|
|
|
68
71
|
clearRestartIntentMarker: () => clearRestartIntentMarker,
|
|
69
72
|
compareSemver: () => compareSemver,
|
|
70
73
|
detectWorkspaceRoot: () => detectWorkspaceRoot,
|
|
74
|
+
devChannelEpoch: () => devChannelEpoch,
|
|
75
|
+
devUploadManifestPath: () => devUploadManifestPath,
|
|
76
|
+
devUploadVersionDir: () => devUploadVersionDir,
|
|
77
|
+
devUploadsDir: () => devUploadsDir,
|
|
71
78
|
emptyServerRootState: () => emptyServerRootState,
|
|
79
|
+
isDevChannelVersion: () => isDevChannelVersion,
|
|
72
80
|
isHostExternal: () => isHostExternal,
|
|
73
81
|
isServerRootState: () => isServerRootState,
|
|
74
82
|
minNodeMajorOf: () => minNodeMajorOf,
|
|
75
83
|
planBoot: () => planBoot,
|
|
84
|
+
readDevUploadManifest: () => readDevUploadManifest,
|
|
76
85
|
readRestartIntentMarker: () => readRestartIntentMarker,
|
|
77
86
|
readServerRootState: () => readServerRootState,
|
|
78
87
|
registerActiveRootResolver: () => registerActiveRootResolver,
|
|
@@ -85,10 +94,58 @@ var require_dist = __commonJS({
|
|
|
85
94
|
validateVersionDir: () => validateVersionDir,
|
|
86
95
|
versionDir: () => versionDir,
|
|
87
96
|
versionsDir: () => versionsDir,
|
|
97
|
+
writeDevUploadManifest: () => writeDevUploadManifest,
|
|
88
98
|
writeRestartIntentMarker: () => writeRestartIntentMarker,
|
|
89
99
|
writeServerRootState: () => writeServerRootState
|
|
90
100
|
});
|
|
91
101
|
module2.exports = __toCommonJS(src_exports);
|
|
102
|
+
var fs = __toESM2(require("fs"));
|
|
103
|
+
var path2 = __toESM2(require("path"));
|
|
104
|
+
var DEV_UPLOADS_DIRNAME = "dev-uploads";
|
|
105
|
+
var DEV_UPLOAD_MANIFEST_FILE = "manifest.json";
|
|
106
|
+
var DEV_UPLOADS_KEEP_COUNT = 3;
|
|
107
|
+
var DEV_CHANNEL_VERSION_RE = /-dev\.\d+$/;
|
|
108
|
+
function isDevChannelVersion(version) {
|
|
109
|
+
return DEV_CHANNEL_VERSION_RE.test(version);
|
|
110
|
+
}
|
|
111
|
+
function devChannelEpoch(version) {
|
|
112
|
+
const match = /-dev\.(\d+)$/.exec(version);
|
|
113
|
+
if (match === null) return null;
|
|
114
|
+
const epoch = Number.parseInt(match[1] ?? "", 10);
|
|
115
|
+
return Number.isNaN(epoch) ? null : epoch;
|
|
116
|
+
}
|
|
117
|
+
function devUploadsDir(rootDir) {
|
|
118
|
+
return path2.join(rootDir, DEV_UPLOADS_DIRNAME);
|
|
119
|
+
}
|
|
120
|
+
function devUploadVersionDir(rootDir, version) {
|
|
121
|
+
return path2.join(devUploadsDir(rootDir), version);
|
|
122
|
+
}
|
|
123
|
+
function devUploadManifestPath(versionDirPath) {
|
|
124
|
+
return path2.join(versionDirPath, DEV_UPLOAD_MANIFEST_FILE);
|
|
125
|
+
}
|
|
126
|
+
function isDevUploadManifest(v) {
|
|
127
|
+
if (typeof v !== "object" || v === null) return false;
|
|
128
|
+
const m = v;
|
|
129
|
+
if (typeof m["version"] !== "string") return false;
|
|
130
|
+
const packages = m["packages"];
|
|
131
|
+
if (typeof packages !== "object" || packages === null || Array.isArray(packages)) return false;
|
|
132
|
+
return Object.values(packages).every((filename) => typeof filename === "string");
|
|
133
|
+
}
|
|
134
|
+
function readDevUploadManifest(versionDirPath) {
|
|
135
|
+
try {
|
|
136
|
+
const raw = JSON.parse(fs.readFileSync(devUploadManifestPath(versionDirPath), "utf-8"));
|
|
137
|
+
return isDevUploadManifest(raw) ? raw : null;
|
|
138
|
+
} catch {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function writeDevUploadManifest(versionDirPath, manifest) {
|
|
143
|
+
fs.mkdirSync(versionDirPath, { recursive: true });
|
|
144
|
+
const target = devUploadManifestPath(versionDirPath);
|
|
145
|
+
const tmp = `${target}.tmp`;
|
|
146
|
+
fs.writeFileSync(tmp, JSON.stringify(manifest, null, 2), "utf-8");
|
|
147
|
+
fs.renameSync(tmp, target);
|
|
148
|
+
}
|
|
92
149
|
var HUB_ROOT_SPEC = {
|
|
93
150
|
packageName: "@camstack/server",
|
|
94
151
|
entryRelPath: ["dist", "launcher.js"]
|
|
@@ -97,8 +154,8 @@ var require_dist = __commonJS({
|
|
|
97
154
|
packageName: "@camstack/agent",
|
|
98
155
|
entryRelPath: ["dist", "cli.js"]
|
|
99
156
|
};
|
|
100
|
-
var
|
|
101
|
-
var
|
|
157
|
+
var fs2 = __toESM2(require("fs"));
|
|
158
|
+
var path22 = __toESM2(require("path"));
|
|
102
159
|
var SERVER_ROOT_DIRNAME = "server-root";
|
|
103
160
|
var SERVER_ROOT_STATE_FILE = "state.json";
|
|
104
161
|
var RESTART_INTENT_FILE = ".restart-intent";
|
|
@@ -112,22 +169,22 @@ var require_dist = __commonJS({
|
|
|
112
169
|
};
|
|
113
170
|
}
|
|
114
171
|
function serverRootDir(dataDir) {
|
|
115
|
-
return
|
|
172
|
+
return path22.join(dataDir, SERVER_ROOT_DIRNAME);
|
|
116
173
|
}
|
|
117
174
|
function versionsDir(rootDir) {
|
|
118
|
-
return
|
|
175
|
+
return path22.join(rootDir, "versions");
|
|
119
176
|
}
|
|
120
177
|
function versionDir(rootDir, version) {
|
|
121
|
-
return
|
|
178
|
+
return path22.join(versionsDir(rootDir), version);
|
|
122
179
|
}
|
|
123
180
|
function rootPackageDir(versionDirPath, spec) {
|
|
124
|
-
return
|
|
181
|
+
return path22.join(versionDirPath, "node_modules", ...spec.packageName.split("/"));
|
|
125
182
|
}
|
|
126
183
|
function rootEntryPath(versionDirPath, spec) {
|
|
127
|
-
return
|
|
184
|
+
return path22.join(rootPackageDir(versionDirPath, spec), ...spec.entryRelPath);
|
|
128
185
|
}
|
|
129
186
|
function stateFilePath(rootDir) {
|
|
130
|
-
return
|
|
187
|
+
return path22.join(rootDir, SERVER_ROOT_STATE_FILE);
|
|
131
188
|
}
|
|
132
189
|
function isNullableString(v) {
|
|
133
190
|
return v === null || typeof v === "string";
|
|
@@ -154,21 +211,21 @@ var require_dist = __commonJS({
|
|
|
154
211
|
}
|
|
155
212
|
function readServerRootState(rootDir) {
|
|
156
213
|
try {
|
|
157
|
-
const raw = JSON.parse(
|
|
214
|
+
const raw = JSON.parse(fs2.readFileSync(stateFilePath(rootDir), "utf-8"));
|
|
158
215
|
return isServerRootState(raw) ? raw : null;
|
|
159
216
|
} catch {
|
|
160
217
|
return null;
|
|
161
218
|
}
|
|
162
219
|
}
|
|
163
220
|
function writeServerRootState(rootDir, state) {
|
|
164
|
-
|
|
221
|
+
fs2.mkdirSync(rootDir, { recursive: true });
|
|
165
222
|
const target = stateFilePath(rootDir);
|
|
166
223
|
const tmp = `${target}.tmp`;
|
|
167
|
-
|
|
168
|
-
|
|
224
|
+
fs2.writeFileSync(tmp, JSON.stringify(state, null, 2), "utf-8");
|
|
225
|
+
fs2.renameSync(tmp, target);
|
|
169
226
|
}
|
|
170
227
|
function restartIntentMarkerPath(rootDir) {
|
|
171
|
-
return
|
|
228
|
+
return path22.join(rootDir, RESTART_INTENT_FILE);
|
|
172
229
|
}
|
|
173
230
|
function isRestartIntentMarker(v) {
|
|
174
231
|
if (typeof v !== "object" || v === null) return false;
|
|
@@ -176,15 +233,15 @@ var require_dist = __commonJS({
|
|
|
176
233
|
return typeof m["requestedAtMs"] === "number" && typeof m["reason"] === "string";
|
|
177
234
|
}
|
|
178
235
|
function writeRestartIntentMarker(rootDir, marker) {
|
|
179
|
-
|
|
236
|
+
fs2.mkdirSync(rootDir, { recursive: true });
|
|
180
237
|
const target = restartIntentMarkerPath(rootDir);
|
|
181
238
|
const tmp = `${target}.tmp`;
|
|
182
|
-
|
|
183
|
-
|
|
239
|
+
fs2.writeFileSync(tmp, JSON.stringify(marker, null, 2), "utf-8");
|
|
240
|
+
fs2.renameSync(tmp, target);
|
|
184
241
|
}
|
|
185
242
|
function readRestartIntentMarker(rootDir) {
|
|
186
243
|
try {
|
|
187
|
-
const raw = JSON.parse(
|
|
244
|
+
const raw = JSON.parse(fs2.readFileSync(restartIntentMarkerPath(rootDir), "utf-8"));
|
|
188
245
|
return isRestartIntentMarker(raw) ? raw : null;
|
|
189
246
|
} catch {
|
|
190
247
|
return null;
|
|
@@ -192,7 +249,7 @@ var require_dist = __commonJS({
|
|
|
192
249
|
}
|
|
193
250
|
function clearRestartIntentMarker(rootDir) {
|
|
194
251
|
try {
|
|
195
|
-
|
|
252
|
+
fs2.rmSync(restartIntentMarkerPath(rootDir), { force: true });
|
|
196
253
|
} catch {
|
|
197
254
|
}
|
|
198
255
|
}
|
|
@@ -205,13 +262,13 @@ var require_dist = __commonJS({
|
|
|
205
262
|
function validateVersionDir(rootDir, version, nodeMajor, spec) {
|
|
206
263
|
const vDir = versionDir(rootDir, version);
|
|
207
264
|
const entry = rootEntryPath(vDir, spec);
|
|
208
|
-
if (!
|
|
265
|
+
if (!fs2.existsSync(entry)) {
|
|
209
266
|
return `root entry missing: ${entry}`;
|
|
210
267
|
}
|
|
211
|
-
const pkgJsonPath =
|
|
268
|
+
const pkgJsonPath = path22.join(rootPackageDir(vDir, spec), "package.json");
|
|
212
269
|
let pkg;
|
|
213
270
|
try {
|
|
214
|
-
const raw = JSON.parse(
|
|
271
|
+
const raw = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
|
|
215
272
|
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
216
273
|
return `package.json malformed: ${pkgJsonPath}`;
|
|
217
274
|
}
|
|
@@ -358,25 +415,25 @@ var require_dist = __commonJS({
|
|
|
358
415
|
if (pa.prerelease > pb.prerelease) return 1;
|
|
359
416
|
return 0;
|
|
360
417
|
}
|
|
361
|
-
var
|
|
362
|
-
var
|
|
418
|
+
var fs3 = __toESM2(require("fs"));
|
|
419
|
+
var path3 = __toESM2(require("path"));
|
|
363
420
|
function detectWorkspaceRoot(fromDir) {
|
|
364
|
-
let dir =
|
|
421
|
+
let dir = path3.resolve(fromDir);
|
|
365
422
|
for (; ; ) {
|
|
366
|
-
const pkgPath =
|
|
423
|
+
const pkgPath = path3.join(dir, "package.json");
|
|
367
424
|
try {
|
|
368
|
-
const raw = JSON.parse(
|
|
425
|
+
const raw = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
|
|
369
426
|
if (typeof raw === "object" && raw !== null && raw["workspaces"] !== void 0) {
|
|
370
427
|
return dir;
|
|
371
428
|
}
|
|
372
429
|
} catch {
|
|
373
430
|
}
|
|
374
|
-
const parent =
|
|
431
|
+
const parent = path3.dirname(dir);
|
|
375
432
|
if (parent === dir) return null;
|
|
376
433
|
dir = parent;
|
|
377
434
|
}
|
|
378
435
|
}
|
|
379
|
-
var
|
|
436
|
+
var path4 = __toESM2(require("path"));
|
|
380
437
|
var import_node_url = require("url");
|
|
381
438
|
var HOST_EXTERNAL_SPECIFIERS = [
|
|
382
439
|
"@camstack/system",
|
|
@@ -404,7 +461,7 @@ var require_dist = __commonJS({
|
|
|
404
461
|
return;
|
|
405
462
|
}
|
|
406
463
|
const anchorURL = (0, import_node_url.pathToFileURL)(
|
|
407
|
-
|
|
464
|
+
path4.join(activeRootDir, "node_modules", "__camstack_starter_anchor__.js")
|
|
408
465
|
).href;
|
|
409
466
|
const hooks = {
|
|
410
467
|
resolve: (specifier, context, nextResolve) => {
|
|
@@ -482,8 +539,8 @@ var require_dist = __commonJS({
|
|
|
482
539
|
options.loadEntry(options.seedEntry);
|
|
483
540
|
}
|
|
484
541
|
var import_node_child_process = require("child_process");
|
|
485
|
-
var
|
|
486
|
-
var
|
|
542
|
+
var fs4 = __toESM2(require("fs"));
|
|
543
|
+
var path5 = __toESM2(require("path"));
|
|
487
544
|
var import_node_util = require("util");
|
|
488
545
|
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
489
546
|
function buildNpmRegistryArgs(registry) {
|
|
@@ -495,7 +552,7 @@ var require_dist = __commonJS({
|
|
|
495
552
|
var RESTART_REASON_PREFIX = "server-update";
|
|
496
553
|
function readPackageVersion(pkgJsonPath) {
|
|
497
554
|
try {
|
|
498
|
-
const raw = JSON.parse(
|
|
555
|
+
const raw = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
|
|
499
556
|
if (typeof raw === "object" && raw !== null) {
|
|
500
557
|
const version = raw["version"];
|
|
501
558
|
if (typeof version === "string") return version;
|
|
@@ -522,7 +579,7 @@ var require_dist = __commonJS({
|
|
|
522
579
|
this.envNames = options.envNames;
|
|
523
580
|
this.logger = options.logger;
|
|
524
581
|
this.restartServerFn = options.restartServer;
|
|
525
|
-
this.dataDir =
|
|
582
|
+
this.dataDir = path5.resolve(options.dataDir);
|
|
526
583
|
this.execNpm = options.execNpm ?? (async (args, opts) => {
|
|
527
584
|
const { stdout } = await execFileAsync("npm", [...args], {
|
|
528
585
|
cwd: opts.cwd,
|
|
@@ -551,7 +608,7 @@ var require_dist = __commonJS({
|
|
|
551
608
|
seedVersion() {
|
|
552
609
|
const seedDir = this.env[this.envNames.seedDir];
|
|
553
610
|
if (seedDir === void 0 || seedDir.length === 0) return null;
|
|
554
|
-
return readPackageVersion(
|
|
611
|
+
return readPackageVersion(path5.join(seedDir, "package.json"));
|
|
555
612
|
}
|
|
556
613
|
rootDir() {
|
|
557
614
|
return serverRootDir(this.dataDir);
|
|
@@ -569,7 +626,7 @@ var require_dist = __commonJS({
|
|
|
569
626
|
const rootDir = this.rootDir();
|
|
570
627
|
const raw = readServerRootState(rootDir);
|
|
571
628
|
if (raw !== null) return { state: raw, corrupt: false };
|
|
572
|
-
return { state: emptyServerRootState(), corrupt:
|
|
629
|
+
return { state: emptyServerRootState(), corrupt: fs4.existsSync(stateFilePath(rootDir)) };
|
|
573
630
|
}
|
|
574
631
|
updateState(state) {
|
|
575
632
|
if (this.inFlight === "checking") return "checking";
|
|
@@ -709,6 +766,17 @@ var require_dist = __commonJS({
|
|
|
709
766
|
message: `Refused: ${this.spec.packageName}@${target} is already running.`
|
|
710
767
|
};
|
|
711
768
|
}
|
|
769
|
+
if (isDevChannelVersion(target)) {
|
|
770
|
+
const uploadsDir = devUploadVersionDir(this.rootDir(), target);
|
|
771
|
+
if (!fs4.existsSync(uploadsDir)) {
|
|
772
|
+
return {
|
|
773
|
+
accepted: false,
|
|
774
|
+
targetVersion: target,
|
|
775
|
+
restarting: false,
|
|
776
|
+
message: `Refused: dev-channel version ${target} has no uploaded tarballs on this node (${uploadsDir} is missing). Dev server deploys are hub-only in this phase \u2014 upload via \`camstack deploy-server\` against this node first.`
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
}
|
|
712
780
|
this.inFlight = "staging";
|
|
713
781
|
try {
|
|
714
782
|
await this.stageAndActivate(target);
|
|
@@ -755,34 +823,40 @@ var require_dist = __commonJS({
|
|
|
755
823
|
async stageAndActivate(target) {
|
|
756
824
|
const rootDir = this.rootDir();
|
|
757
825
|
const vDir = versionsDir(rootDir);
|
|
758
|
-
|
|
759
|
-
const stagingDir =
|
|
760
|
-
|
|
826
|
+
fs4.mkdirSync(vDir, { recursive: true });
|
|
827
|
+
const stagingDir = path5.join(vDir, `.staging-${target}-${process.pid}-${this.now()}`);
|
|
828
|
+
fs4.mkdirSync(stagingDir, { recursive: true });
|
|
761
829
|
try {
|
|
762
|
-
|
|
763
|
-
path4.join(stagingDir, "package.json"),
|
|
764
|
-
JSON.stringify({ name: "camstack-node-root", private: true }, null, 2),
|
|
765
|
-
"utf-8"
|
|
766
|
-
);
|
|
830
|
+
const devDir = devUploadVersionDir(rootDir, target);
|
|
767
831
|
const registry = this.env["CAMSTACK_NPM_REGISTRY"];
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
"
|
|
772
|
-
|
|
773
|
-
"
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
832
|
+
const installArgs = ["install", "--omit=dev", "--no-audit", "--no-fund", "--loglevel=error"];
|
|
833
|
+
if (fs4.existsSync(devDir)) {
|
|
834
|
+
fs4.writeFileSync(
|
|
835
|
+
path5.join(stagingDir, "package.json"),
|
|
836
|
+
JSON.stringify(this.buildDevUploadsPackageJson(devDir, target), null, 2),
|
|
837
|
+
"utf-8"
|
|
838
|
+
);
|
|
839
|
+
await this.execNpm([...installArgs, ...buildNpmRegistryArgs(registry)], {
|
|
840
|
+
cwd: stagingDir,
|
|
841
|
+
timeoutMs: NPM_INSTALL_TIMEOUT_MS
|
|
842
|
+
});
|
|
843
|
+
} else {
|
|
844
|
+
fs4.writeFileSync(
|
|
845
|
+
path5.join(stagingDir, "package.json"),
|
|
846
|
+
JSON.stringify({ name: "camstack-node-root", private: true }, null, 2),
|
|
847
|
+
"utf-8"
|
|
848
|
+
);
|
|
849
|
+
await this.execNpm(
|
|
850
|
+
[...installArgs, `${this.spec.packageName}@${target}`, ...buildNpmRegistryArgs(registry)],
|
|
851
|
+
{ cwd: stagingDir, timeoutMs: NPM_INSTALL_TIMEOUT_MS }
|
|
852
|
+
);
|
|
853
|
+
}
|
|
780
854
|
const entry = rootEntryPath(stagingDir, this.spec);
|
|
781
|
-
if (!
|
|
855
|
+
if (!fs4.existsSync(entry)) {
|
|
782
856
|
throw new Error(`staged closure is missing the root entry (${entry})`);
|
|
783
857
|
}
|
|
784
858
|
const stagedVersion = readPackageVersion(
|
|
785
|
-
|
|
859
|
+
path5.join(rootPackageDir(stagingDir, this.spec), "package.json")
|
|
786
860
|
);
|
|
787
861
|
if (stagedVersion !== target) {
|
|
788
862
|
throw new Error(
|
|
@@ -790,17 +864,61 @@ var require_dist = __commonJS({
|
|
|
790
864
|
);
|
|
791
865
|
}
|
|
792
866
|
const dest = versionDir(rootDir, target);
|
|
793
|
-
if (
|
|
867
|
+
if (fs4.existsSync(dest)) {
|
|
794
868
|
const aside = `${dest}.evicted-${this.now()}`;
|
|
795
|
-
await
|
|
796
|
-
await
|
|
869
|
+
await fs4.promises.rename(dest, aside);
|
|
870
|
+
await fs4.promises.rm(aside, { recursive: true, force: true }).catch(() => void 0);
|
|
797
871
|
}
|
|
798
|
-
await
|
|
872
|
+
await fs4.promises.rename(stagingDir, dest);
|
|
799
873
|
} catch (err) {
|
|
800
|
-
await
|
|
874
|
+
await fs4.promises.rm(stagingDir, { recursive: true, force: true }).catch(() => void 0);
|
|
801
875
|
throw err;
|
|
802
876
|
}
|
|
803
877
|
}
|
|
878
|
+
/**
|
|
879
|
+
* Synthetic staging package.json for the dev server-deploy channel:
|
|
880
|
+
* `dependencies` carries the root package as a `file:` ref to its uploaded
|
|
881
|
+
* tgz; `overrides` maps EVERY OTHER uploaded `@camstack/<name>` to its tgz
|
|
882
|
+
* so any transitive occurrence resolves to the uploaded copy, never npm.
|
|
883
|
+
* Fail-closed: a missing/invalid manifest, a manifest for a different
|
|
884
|
+
* version, a missing root package, or a listed-but-absent tgz all throw
|
|
885
|
+
* (surfaced by `applyServerUpdate` as a staging failure).
|
|
886
|
+
*/
|
|
887
|
+
buildDevUploadsPackageJson(devDir, target) {
|
|
888
|
+
const manifest = readDevUploadManifest(devDir);
|
|
889
|
+
if (manifest === null) {
|
|
890
|
+
throw new Error(`dev-uploads manifest missing or invalid in ${devDir}`);
|
|
891
|
+
}
|
|
892
|
+
if (manifest.version !== target) {
|
|
893
|
+
throw new Error(
|
|
894
|
+
`dev-uploads manifest version mismatch: dir is for ${target}, manifest says ${manifest.version}`
|
|
895
|
+
);
|
|
896
|
+
}
|
|
897
|
+
const rootTgz = manifest.packages[this.spec.packageName];
|
|
898
|
+
if (rootTgz === void 0) {
|
|
899
|
+
throw new Error(
|
|
900
|
+
`dev-uploads for ${target} do not include the root package ${this.spec.packageName}`
|
|
901
|
+
);
|
|
902
|
+
}
|
|
903
|
+
const fileRef = (filename) => {
|
|
904
|
+
const abs = path5.join(devDir, filename);
|
|
905
|
+
if (!fs4.existsSync(abs)) {
|
|
906
|
+
throw new Error(`dev-uploads tarball listed in the manifest is missing: ${abs}`);
|
|
907
|
+
}
|
|
908
|
+
return `file:${abs}`;
|
|
909
|
+
};
|
|
910
|
+
const overrides = {};
|
|
911
|
+
for (const [pkgName, filename] of Object.entries(manifest.packages)) {
|
|
912
|
+
if (pkgName === this.spec.packageName) continue;
|
|
913
|
+
overrides[pkgName] = fileRef(filename);
|
|
914
|
+
}
|
|
915
|
+
return {
|
|
916
|
+
name: "camstack-node-root",
|
|
917
|
+
private: true,
|
|
918
|
+
dependencies: { [this.spec.packageName]: fileRef(rootTgz) },
|
|
919
|
+
...Object.keys(overrides).length > 0 ? { overrides } : {}
|
|
920
|
+
};
|
|
921
|
+
}
|
|
804
922
|
// ── Rollback ──────────────────────────────────────────────────────────
|
|
805
923
|
async rollbackServerUpdate() {
|
|
806
924
|
if (this.inFlight !== "idle") {
|
|
@@ -930,6 +1048,7 @@ var require_dist = __commonJS({
|
|
|
930
1048
|
(v) => typeof v === "string"
|
|
931
1049
|
)
|
|
932
1050
|
);
|
|
1051
|
+
this.sweepDevUploads(DEV_UPLOADS_KEEP_COUNT);
|
|
933
1052
|
this.logger.info("root package update confirmed healthy", {
|
|
934
1053
|
meta: {
|
|
935
1054
|
version: promoted.currentVersion,
|
|
@@ -953,23 +1072,23 @@ var require_dist = __commonJS({
|
|
|
953
1072
|
const vDir = versionsDir(this.rootDir());
|
|
954
1073
|
let entries;
|
|
955
1074
|
try {
|
|
956
|
-
entries =
|
|
1075
|
+
entries = fs4.readdirSync(vDir);
|
|
957
1076
|
} catch {
|
|
958
1077
|
return;
|
|
959
1078
|
}
|
|
960
1079
|
for (const entry of entries) {
|
|
961
1080
|
if (keep.includes(entry)) continue;
|
|
962
|
-
const full =
|
|
1081
|
+
const full = path5.join(vDir, entry);
|
|
963
1082
|
if (entry.startsWith(".")) {
|
|
964
1083
|
try {
|
|
965
|
-
const ageMs = this.now() -
|
|
1084
|
+
const ageMs = this.now() - fs4.statSync(full).mtimeMs;
|
|
966
1085
|
if (ageMs < _RootUpdateService.STALE_TRANSIENT_MS) continue;
|
|
967
1086
|
} catch {
|
|
968
1087
|
continue;
|
|
969
1088
|
}
|
|
970
1089
|
}
|
|
971
1090
|
try {
|
|
972
|
-
|
|
1091
|
+
fs4.rmSync(full, { recursive: true, force: true });
|
|
973
1092
|
this.logger.debug("pruned server-root version dir", { meta: { entry } });
|
|
974
1093
|
} catch (err) {
|
|
975
1094
|
this.logger.warn("failed to prune server-root version dir", {
|
|
@@ -978,6 +1097,56 @@ var require_dist = __commonJS({
|
|
|
978
1097
|
}
|
|
979
1098
|
}
|
|
980
1099
|
}
|
|
1100
|
+
/**
|
|
1101
|
+
* Promote-time sweep of `server-root/dev-uploads/`: keep only the
|
|
1102
|
+
* `keepCount` most recent entries (ordered by the self-describing
|
|
1103
|
+
* `-dev.<epochSeconds>` suffix; non-dev-shaped residue counts as oldest).
|
|
1104
|
+
* Uses the same rename-aside graveyard pattern as the addon installer —
|
|
1105
|
+
* a rename is a metadata op that succeeds even when a tarball is held
|
|
1106
|
+
* open, and residue in the graveyard is re-swept on the next promote.
|
|
1107
|
+
*/
|
|
1108
|
+
sweepDevUploads(keepCount) {
|
|
1109
|
+
const dir = devUploadsDir(this.rootDir());
|
|
1110
|
+
let entries;
|
|
1111
|
+
try {
|
|
1112
|
+
entries = fs4.readdirSync(dir);
|
|
1113
|
+
} catch {
|
|
1114
|
+
return;
|
|
1115
|
+
}
|
|
1116
|
+
const graveyard = path5.join(dir, ".sweeping");
|
|
1117
|
+
try {
|
|
1118
|
+
for (const residue of fs4.readdirSync(graveyard)) {
|
|
1119
|
+
try {
|
|
1120
|
+
fs4.rmSync(path5.join(graveyard, residue), { recursive: true, force: true });
|
|
1121
|
+
} catch {
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
} catch {
|
|
1125
|
+
}
|
|
1126
|
+
const versions = entries.filter((name) => !name.startsWith("."));
|
|
1127
|
+
const byNewestFirst = [...versions].sort(
|
|
1128
|
+
(a, b) => (devChannelEpoch(b) ?? -1) - (devChannelEpoch(a) ?? -1)
|
|
1129
|
+
);
|
|
1130
|
+
const doomed = byNewestFirst.slice(keepCount);
|
|
1131
|
+
if (doomed.length === 0) return;
|
|
1132
|
+
fs4.mkdirSync(graveyard, { recursive: true });
|
|
1133
|
+
for (const entry of doomed) {
|
|
1134
|
+
const aside = path5.join(graveyard, `${entry}-${this.now()}`);
|
|
1135
|
+
try {
|
|
1136
|
+
fs4.renameSync(path5.join(dir, entry), aside);
|
|
1137
|
+
} catch (err) {
|
|
1138
|
+
this.logger.warn("failed to move dev-uploads entry aside for sweep", {
|
|
1139
|
+
meta: { entry, error: err instanceof Error ? err.message : String(err) }
|
|
1140
|
+
});
|
|
1141
|
+
continue;
|
|
1142
|
+
}
|
|
1143
|
+
try {
|
|
1144
|
+
fs4.rmSync(aside, { recursive: true, force: true });
|
|
1145
|
+
this.logger.debug("swept dev-uploads entry", { meta: { entry } });
|
|
1146
|
+
} catch {
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
981
1150
|
/** Transient (.staging- / .evicted-) dirs younger than this are never pruned. */
|
|
982
1151
|
static STALE_TRANSIENT_MS = 24 * 60 * 60 * 1e3;
|
|
983
1152
|
};
|