@camstack/server 1.1.53 → 1.1.55
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/addon-upload.js +14 -124
- package/dist/api/core/auth.router.js +38 -8
- package/dist/api/health/health.routes.js +52 -7
- package/dist/api/server-upload.js +188 -0
- package/dist/api/static/spa-static.js +23 -0
- package/dist/api/tarball-manifest.js +86 -0
- package/dist/api/trpc/share-view-access.js +30 -0
- package/dist/api/trpc/trpc.middleware.js +10 -0
- package/dist/api/upload-auth.js +69 -0
- package/dist/auth/auth-rate-limit.js +76 -0
- package/dist/main.js +29 -23
- package/dist/server-root/index.js +264 -61
- package/package.json +4 -4
|
@@ -74,6 +74,9 @@ var require_dist = __commonJS({
|
|
|
74
74
|
var src_exports = {};
|
|
75
75
|
__export2(src_exports, {
|
|
76
76
|
AGENT_ROOT_SPEC: /* @__PURE__ */ __name(() => AGENT_ROOT_SPEC, "AGENT_ROOT_SPEC"),
|
|
77
|
+
DEV_UPLOADS_DIRNAME: /* @__PURE__ */ __name(() => DEV_UPLOADS_DIRNAME, "DEV_UPLOADS_DIRNAME"),
|
|
78
|
+
DEV_UPLOADS_KEEP_COUNT: /* @__PURE__ */ __name(() => DEV_UPLOADS_KEEP_COUNT, "DEV_UPLOADS_KEEP_COUNT"),
|
|
79
|
+
DEV_UPLOAD_MANIFEST_FILE: /* @__PURE__ */ __name(() => DEV_UPLOAD_MANIFEST_FILE, "DEV_UPLOAD_MANIFEST_FILE"),
|
|
77
80
|
HOST_EXTERNAL_SPECIFIERS: /* @__PURE__ */ __name(() => HOST_EXTERNAL_SPECIFIERS, "HOST_EXTERNAL_SPECIFIERS"),
|
|
78
81
|
HUB_ROOT_SPEC: /* @__PURE__ */ __name(() => HUB_ROOT_SPEC2, "HUB_ROOT_SPEC"),
|
|
79
82
|
RESTART_INTENT_FILE: /* @__PURE__ */ __name(() => RESTART_INTENT_FILE, "RESTART_INTENT_FILE"),
|
|
@@ -83,11 +86,17 @@ var require_dist = __commonJS({
|
|
|
83
86
|
clearRestartIntentMarker: /* @__PURE__ */ __name(() => clearRestartIntentMarker, "clearRestartIntentMarker"),
|
|
84
87
|
compareSemver: /* @__PURE__ */ __name(() => compareSemver, "compareSemver"),
|
|
85
88
|
detectWorkspaceRoot: /* @__PURE__ */ __name(() => detectWorkspaceRoot, "detectWorkspaceRoot"),
|
|
89
|
+
devChannelEpoch: /* @__PURE__ */ __name(() => devChannelEpoch, "devChannelEpoch"),
|
|
90
|
+
devUploadManifestPath: /* @__PURE__ */ __name(() => devUploadManifestPath, "devUploadManifestPath"),
|
|
91
|
+
devUploadVersionDir: /* @__PURE__ */ __name(() => devUploadVersionDir, "devUploadVersionDir"),
|
|
92
|
+
devUploadsDir: /* @__PURE__ */ __name(() => devUploadsDir, "devUploadsDir"),
|
|
86
93
|
emptyServerRootState: /* @__PURE__ */ __name(() => emptyServerRootState, "emptyServerRootState"),
|
|
94
|
+
isDevChannelVersion: /* @__PURE__ */ __name(() => isDevChannelVersion, "isDevChannelVersion"),
|
|
87
95
|
isHostExternal: /* @__PURE__ */ __name(() => isHostExternal, "isHostExternal"),
|
|
88
96
|
isServerRootState: /* @__PURE__ */ __name(() => isServerRootState, "isServerRootState"),
|
|
89
97
|
minNodeMajorOf: /* @__PURE__ */ __name(() => minNodeMajorOf, "minNodeMajorOf"),
|
|
90
98
|
planBoot: /* @__PURE__ */ __name(() => planBoot, "planBoot"),
|
|
99
|
+
readDevUploadManifest: /* @__PURE__ */ __name(() => readDevUploadManifest, "readDevUploadManifest"),
|
|
91
100
|
readRestartIntentMarker: /* @__PURE__ */ __name(() => readRestartIntentMarker, "readRestartIntentMarker"),
|
|
92
101
|
readServerRootState: /* @__PURE__ */ __name(() => readServerRootState, "readServerRootState"),
|
|
93
102
|
registerActiveRootResolver: /* @__PURE__ */ __name(() => registerActiveRootResolver, "registerActiveRootResolver"),
|
|
@@ -100,10 +109,68 @@ var require_dist = __commonJS({
|
|
|
100
109
|
validateVersionDir: /* @__PURE__ */ __name(() => validateVersionDir, "validateVersionDir"),
|
|
101
110
|
versionDir: /* @__PURE__ */ __name(() => versionDir, "versionDir"),
|
|
102
111
|
versionsDir: /* @__PURE__ */ __name(() => versionsDir, "versionsDir"),
|
|
112
|
+
writeDevUploadManifest: /* @__PURE__ */ __name(() => writeDevUploadManifest, "writeDevUploadManifest"),
|
|
103
113
|
writeRestartIntentMarker: /* @__PURE__ */ __name(() => writeRestartIntentMarker, "writeRestartIntentMarker"),
|
|
104
114
|
writeServerRootState: /* @__PURE__ */ __name(() => writeServerRootState, "writeServerRootState")
|
|
105
115
|
});
|
|
106
116
|
module2.exports = __toCommonJS2(src_exports);
|
|
117
|
+
var fs = __toESM2(require("fs"));
|
|
118
|
+
var path = __toESM2(require("path"));
|
|
119
|
+
var DEV_UPLOADS_DIRNAME = "dev-uploads";
|
|
120
|
+
var DEV_UPLOAD_MANIFEST_FILE = "manifest.json";
|
|
121
|
+
var DEV_UPLOADS_KEEP_COUNT = 3;
|
|
122
|
+
var DEV_CHANNEL_VERSION_RE = /-dev\.\d+$/;
|
|
123
|
+
function isDevChannelVersion(version) {
|
|
124
|
+
return DEV_CHANNEL_VERSION_RE.test(version);
|
|
125
|
+
}
|
|
126
|
+
__name(isDevChannelVersion, "isDevChannelVersion");
|
|
127
|
+
function devChannelEpoch(version) {
|
|
128
|
+
const match = /-dev\.(\d+)$/.exec(version);
|
|
129
|
+
if (match === null) return null;
|
|
130
|
+
const epoch = Number.parseInt(match[1] ?? "", 10);
|
|
131
|
+
return Number.isNaN(epoch) ? null : epoch;
|
|
132
|
+
}
|
|
133
|
+
__name(devChannelEpoch, "devChannelEpoch");
|
|
134
|
+
function devUploadsDir(rootDir) {
|
|
135
|
+
return path.join(rootDir, DEV_UPLOADS_DIRNAME);
|
|
136
|
+
}
|
|
137
|
+
__name(devUploadsDir, "devUploadsDir");
|
|
138
|
+
function devUploadVersionDir(rootDir, version) {
|
|
139
|
+
return path.join(devUploadsDir(rootDir), version);
|
|
140
|
+
}
|
|
141
|
+
__name(devUploadVersionDir, "devUploadVersionDir");
|
|
142
|
+
function devUploadManifestPath(versionDirPath) {
|
|
143
|
+
return path.join(versionDirPath, DEV_UPLOAD_MANIFEST_FILE);
|
|
144
|
+
}
|
|
145
|
+
__name(devUploadManifestPath, "devUploadManifestPath");
|
|
146
|
+
function isDevUploadManifest(v) {
|
|
147
|
+
if (typeof v !== "object" || v === null) return false;
|
|
148
|
+
const m = v;
|
|
149
|
+
if (typeof m["version"] !== "string") return false;
|
|
150
|
+
const packages = m["packages"];
|
|
151
|
+
if (typeof packages !== "object" || packages === null || Array.isArray(packages)) return false;
|
|
152
|
+
return Object.values(packages).every((filename) => typeof filename === "string");
|
|
153
|
+
}
|
|
154
|
+
__name(isDevUploadManifest, "isDevUploadManifest");
|
|
155
|
+
function readDevUploadManifest(versionDirPath) {
|
|
156
|
+
try {
|
|
157
|
+
const raw = JSON.parse(fs.readFileSync(devUploadManifestPath(versionDirPath), "utf-8"));
|
|
158
|
+
return isDevUploadManifest(raw) ? raw : null;
|
|
159
|
+
} catch {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
__name(readDevUploadManifest, "readDevUploadManifest");
|
|
164
|
+
function writeDevUploadManifest(versionDirPath, manifest) {
|
|
165
|
+
fs.mkdirSync(versionDirPath, {
|
|
166
|
+
recursive: true
|
|
167
|
+
});
|
|
168
|
+
const target = devUploadManifestPath(versionDirPath);
|
|
169
|
+
const tmp = `${target}.tmp`;
|
|
170
|
+
fs.writeFileSync(tmp, JSON.stringify(manifest, null, 2), "utf-8");
|
|
171
|
+
fs.renameSync(tmp, target);
|
|
172
|
+
}
|
|
173
|
+
__name(writeDevUploadManifest, "writeDevUploadManifest");
|
|
107
174
|
var HUB_ROOT_SPEC2 = {
|
|
108
175
|
packageName: "@camstack/server",
|
|
109
176
|
entryRelPath: [
|
|
@@ -118,8 +185,8 @@ var require_dist = __commonJS({
|
|
|
118
185
|
"cli.js"
|
|
119
186
|
]
|
|
120
187
|
};
|
|
121
|
-
var
|
|
122
|
-
var
|
|
188
|
+
var fs2 = __toESM2(require("fs"));
|
|
189
|
+
var path2 = __toESM2(require("path"));
|
|
123
190
|
var SERVER_ROOT_DIRNAME = "server-root";
|
|
124
191
|
var SERVER_ROOT_STATE_FILE = "state.json";
|
|
125
192
|
var RESTART_INTENT_FILE = ".restart-intent";
|
|
@@ -134,27 +201,27 @@ var require_dist = __commonJS({
|
|
|
134
201
|
}
|
|
135
202
|
__name(emptyServerRootState, "emptyServerRootState");
|
|
136
203
|
function serverRootDir(dataDir) {
|
|
137
|
-
return
|
|
204
|
+
return path2.join(dataDir, SERVER_ROOT_DIRNAME);
|
|
138
205
|
}
|
|
139
206
|
__name(serverRootDir, "serverRootDir");
|
|
140
207
|
function versionsDir(rootDir) {
|
|
141
|
-
return
|
|
208
|
+
return path2.join(rootDir, "versions");
|
|
142
209
|
}
|
|
143
210
|
__name(versionsDir, "versionsDir");
|
|
144
211
|
function versionDir(rootDir, version) {
|
|
145
|
-
return
|
|
212
|
+
return path2.join(versionsDir(rootDir), version);
|
|
146
213
|
}
|
|
147
214
|
__name(versionDir, "versionDir");
|
|
148
215
|
function rootPackageDir2(versionDirPath, spec) {
|
|
149
|
-
return
|
|
216
|
+
return path2.join(versionDirPath, "node_modules", ...spec.packageName.split("/"));
|
|
150
217
|
}
|
|
151
218
|
__name(rootPackageDir2, "rootPackageDir");
|
|
152
219
|
function rootEntryPath2(versionDirPath, spec) {
|
|
153
|
-
return
|
|
220
|
+
return path2.join(rootPackageDir2(versionDirPath, spec), ...spec.entryRelPath);
|
|
154
221
|
}
|
|
155
222
|
__name(rootEntryPath2, "rootEntryPath");
|
|
156
223
|
function stateFilePath(rootDir) {
|
|
157
|
-
return
|
|
224
|
+
return path2.join(rootDir, SERVER_ROOT_STATE_FILE);
|
|
158
225
|
}
|
|
159
226
|
__name(stateFilePath, "stateFilePath");
|
|
160
227
|
function isNullableString(v) {
|
|
@@ -186,7 +253,7 @@ var require_dist = __commonJS({
|
|
|
186
253
|
__name(isServerRootState, "isServerRootState");
|
|
187
254
|
function readServerRootState(rootDir) {
|
|
188
255
|
try {
|
|
189
|
-
const raw = JSON.parse(
|
|
256
|
+
const raw = JSON.parse(fs2.readFileSync(stateFilePath(rootDir), "utf-8"));
|
|
190
257
|
return isServerRootState(raw) ? raw : null;
|
|
191
258
|
} catch {
|
|
192
259
|
return null;
|
|
@@ -194,17 +261,17 @@ var require_dist = __commonJS({
|
|
|
194
261
|
}
|
|
195
262
|
__name(readServerRootState, "readServerRootState");
|
|
196
263
|
function writeServerRootState(rootDir, state) {
|
|
197
|
-
|
|
264
|
+
fs2.mkdirSync(rootDir, {
|
|
198
265
|
recursive: true
|
|
199
266
|
});
|
|
200
267
|
const target = stateFilePath(rootDir);
|
|
201
268
|
const tmp = `${target}.tmp`;
|
|
202
|
-
|
|
203
|
-
|
|
269
|
+
fs2.writeFileSync(tmp, JSON.stringify(state, null, 2), "utf-8");
|
|
270
|
+
fs2.renameSync(tmp, target);
|
|
204
271
|
}
|
|
205
272
|
__name(writeServerRootState, "writeServerRootState");
|
|
206
273
|
function restartIntentMarkerPath(rootDir) {
|
|
207
|
-
return
|
|
274
|
+
return path2.join(rootDir, RESTART_INTENT_FILE);
|
|
208
275
|
}
|
|
209
276
|
__name(restartIntentMarkerPath, "restartIntentMarkerPath");
|
|
210
277
|
function isRestartIntentMarker(v) {
|
|
@@ -214,18 +281,18 @@ var require_dist = __commonJS({
|
|
|
214
281
|
}
|
|
215
282
|
__name(isRestartIntentMarker, "isRestartIntentMarker");
|
|
216
283
|
function writeRestartIntentMarker(rootDir, marker) {
|
|
217
|
-
|
|
284
|
+
fs2.mkdirSync(rootDir, {
|
|
218
285
|
recursive: true
|
|
219
286
|
});
|
|
220
287
|
const target = restartIntentMarkerPath(rootDir);
|
|
221
288
|
const tmp = `${target}.tmp`;
|
|
222
|
-
|
|
223
|
-
|
|
289
|
+
fs2.writeFileSync(tmp, JSON.stringify(marker, null, 2), "utf-8");
|
|
290
|
+
fs2.renameSync(tmp, target);
|
|
224
291
|
}
|
|
225
292
|
__name(writeRestartIntentMarker, "writeRestartIntentMarker");
|
|
226
293
|
function readRestartIntentMarker(rootDir) {
|
|
227
294
|
try {
|
|
228
|
-
const raw = JSON.parse(
|
|
295
|
+
const raw = JSON.parse(fs2.readFileSync(restartIntentMarkerPath(rootDir), "utf-8"));
|
|
229
296
|
return isRestartIntentMarker(raw) ? raw : null;
|
|
230
297
|
} catch {
|
|
231
298
|
return null;
|
|
@@ -234,7 +301,7 @@ var require_dist = __commonJS({
|
|
|
234
301
|
__name(readRestartIntentMarker, "readRestartIntentMarker");
|
|
235
302
|
function clearRestartIntentMarker(rootDir) {
|
|
236
303
|
try {
|
|
237
|
-
|
|
304
|
+
fs2.rmSync(restartIntentMarkerPath(rootDir), {
|
|
238
305
|
force: true
|
|
239
306
|
});
|
|
240
307
|
} catch {
|
|
@@ -251,13 +318,13 @@ var require_dist = __commonJS({
|
|
|
251
318
|
function validateVersionDir(rootDir, version, nodeMajor, spec) {
|
|
252
319
|
const vDir = versionDir(rootDir, version);
|
|
253
320
|
const entry = rootEntryPath2(vDir, spec);
|
|
254
|
-
if (!
|
|
321
|
+
if (!fs2.existsSync(entry)) {
|
|
255
322
|
return `root entry missing: ${entry}`;
|
|
256
323
|
}
|
|
257
|
-
const pkgJsonPath =
|
|
324
|
+
const pkgJsonPath = path2.join(rootPackageDir2(vDir, spec), "package.json");
|
|
258
325
|
let pkg;
|
|
259
326
|
try {
|
|
260
|
-
const raw = JSON.parse(
|
|
327
|
+
const raw = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
|
|
261
328
|
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
262
329
|
return `package.json malformed: ${pkgJsonPath}`;
|
|
263
330
|
}
|
|
@@ -418,26 +485,26 @@ var require_dist = __commonJS({
|
|
|
418
485
|
return 0;
|
|
419
486
|
}
|
|
420
487
|
__name(compareSemver, "compareSemver");
|
|
421
|
-
var
|
|
422
|
-
var
|
|
488
|
+
var fs3 = __toESM2(require("fs"));
|
|
489
|
+
var path3 = __toESM2(require("path"));
|
|
423
490
|
function detectWorkspaceRoot(fromDir) {
|
|
424
|
-
let dir =
|
|
491
|
+
let dir = path3.resolve(fromDir);
|
|
425
492
|
for (; ; ) {
|
|
426
|
-
const pkgPath =
|
|
493
|
+
const pkgPath = path3.join(dir, "package.json");
|
|
427
494
|
try {
|
|
428
|
-
const raw = JSON.parse(
|
|
495
|
+
const raw = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
|
|
429
496
|
if (typeof raw === "object" && raw !== null && raw["workspaces"] !== void 0) {
|
|
430
497
|
return dir;
|
|
431
498
|
}
|
|
432
499
|
} catch {
|
|
433
500
|
}
|
|
434
|
-
const parent =
|
|
501
|
+
const parent = path3.dirname(dir);
|
|
435
502
|
if (parent === dir) return null;
|
|
436
503
|
dir = parent;
|
|
437
504
|
}
|
|
438
505
|
}
|
|
439
506
|
__name(detectWorkspaceRoot, "detectWorkspaceRoot");
|
|
440
|
-
var
|
|
507
|
+
var path4 = __toESM2(require("path"));
|
|
441
508
|
var import_node_url = require("url");
|
|
442
509
|
var HOST_EXTERNAL_SPECIFIERS = [
|
|
443
510
|
"@camstack/system",
|
|
@@ -461,7 +528,7 @@ var require_dist = __commonJS({
|
|
|
461
528
|
console.warn("[starter] module.registerHooks unavailable (Node < 22.15) \u2014 host-external redirect skipped");
|
|
462
529
|
return;
|
|
463
530
|
}
|
|
464
|
-
const anchorURL = (0, import_node_url.pathToFileURL)(
|
|
531
|
+
const anchorURL = (0, import_node_url.pathToFileURL)(path4.join(activeRootDir, "node_modules", "__camstack_starter_anchor__.js")).href;
|
|
465
532
|
const hooks = {
|
|
466
533
|
resolve: /* @__PURE__ */ __name((specifier, context, nextResolve) => {
|
|
467
534
|
if (isHostExternal(specifier)) {
|
|
@@ -537,8 +604,8 @@ var require_dist = __commonJS({
|
|
|
537
604
|
}
|
|
538
605
|
__name(runNodeStarter, "runNodeStarter");
|
|
539
606
|
var import_node_child_process = require("child_process");
|
|
540
|
-
var
|
|
541
|
-
var
|
|
607
|
+
var fs4 = __toESM2(require("fs"));
|
|
608
|
+
var path5 = __toESM2(require("path"));
|
|
542
609
|
var import_node_util = require("util");
|
|
543
610
|
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
544
611
|
function buildNpmRegistryArgs(registry) {
|
|
@@ -555,7 +622,7 @@ var require_dist = __commonJS({
|
|
|
555
622
|
var RESTART_REASON_PREFIX = "server-update";
|
|
556
623
|
function readPackageVersion(pkgJsonPath) {
|
|
557
624
|
try {
|
|
558
|
-
const raw = JSON.parse(
|
|
625
|
+
const raw = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
|
|
559
626
|
if (typeof raw === "object" && raw !== null) {
|
|
560
627
|
const version = raw["version"];
|
|
561
628
|
if (typeof version === "string") return version;
|
|
@@ -586,7 +653,7 @@ var require_dist = __commonJS({
|
|
|
586
653
|
this.envNames = options.envNames;
|
|
587
654
|
this.logger = options.logger;
|
|
588
655
|
this.restartServerFn = options.restartServer;
|
|
589
|
-
this.dataDir =
|
|
656
|
+
this.dataDir = path5.resolve(options.dataDir);
|
|
590
657
|
this.execNpm = options.execNpm ?? (async (args, opts) => {
|
|
591
658
|
const { stdout } = await execFileAsync("npm", [
|
|
592
659
|
...args
|
|
@@ -622,7 +689,7 @@ var require_dist = __commonJS({
|
|
|
622
689
|
seedVersion() {
|
|
623
690
|
const seedDir = this.env[this.envNames.seedDir];
|
|
624
691
|
if (seedDir === void 0 || seedDir.length === 0) return null;
|
|
625
|
-
return readPackageVersion(
|
|
692
|
+
return readPackageVersion(path5.join(seedDir, "package.json"));
|
|
626
693
|
}
|
|
627
694
|
rootDir() {
|
|
628
695
|
return serverRootDir(this.dataDir);
|
|
@@ -645,7 +712,7 @@ var require_dist = __commonJS({
|
|
|
645
712
|
};
|
|
646
713
|
return {
|
|
647
714
|
state: emptyServerRootState(),
|
|
648
|
-
corrupt:
|
|
715
|
+
corrupt: fs4.existsSync(stateFilePath(rootDir))
|
|
649
716
|
};
|
|
650
717
|
}
|
|
651
718
|
updateState(state) {
|
|
@@ -796,6 +863,17 @@ var require_dist = __commonJS({
|
|
|
796
863
|
message: `Refused: ${this.spec.packageName}@${target} is already running.`
|
|
797
864
|
};
|
|
798
865
|
}
|
|
866
|
+
if (isDevChannelVersion(target)) {
|
|
867
|
+
const uploadsDir = devUploadVersionDir(this.rootDir(), target);
|
|
868
|
+
if (!fs4.existsSync(uploadsDir)) {
|
|
869
|
+
return {
|
|
870
|
+
accepted: false,
|
|
871
|
+
targetVersion: target,
|
|
872
|
+
restarting: false,
|
|
873
|
+
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.`
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
}
|
|
799
877
|
this.inFlight = "staging";
|
|
800
878
|
try {
|
|
801
879
|
await this.stageAndActivate(target);
|
|
@@ -848,57 +926,116 @@ var require_dist = __commonJS({
|
|
|
848
926
|
async stageAndActivate(target) {
|
|
849
927
|
const rootDir = this.rootDir();
|
|
850
928
|
const vDir = versionsDir(rootDir);
|
|
851
|
-
|
|
929
|
+
fs4.mkdirSync(vDir, {
|
|
852
930
|
recursive: true
|
|
853
931
|
});
|
|
854
|
-
const stagingDir =
|
|
855
|
-
|
|
932
|
+
const stagingDir = path5.join(vDir, `.staging-${target}-${process.pid}-${this.now()}`);
|
|
933
|
+
fs4.mkdirSync(stagingDir, {
|
|
856
934
|
recursive: true
|
|
857
935
|
});
|
|
858
936
|
try {
|
|
859
|
-
|
|
860
|
-
name: "camstack-node-root",
|
|
861
|
-
private: true
|
|
862
|
-
}, null, 2), "utf-8");
|
|
937
|
+
const devDir = devUploadVersionDir(rootDir, target);
|
|
863
938
|
const registry = this.env["CAMSTACK_NPM_REGISTRY"];
|
|
864
|
-
|
|
939
|
+
const installArgs = [
|
|
865
940
|
"install",
|
|
866
941
|
"--omit=dev",
|
|
867
942
|
"--no-audit",
|
|
868
943
|
"--no-fund",
|
|
869
|
-
"--loglevel=error"
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
944
|
+
"--loglevel=error"
|
|
945
|
+
];
|
|
946
|
+
if (fs4.existsSync(devDir)) {
|
|
947
|
+
fs4.writeFileSync(path5.join(stagingDir, "package.json"), JSON.stringify(this.buildDevUploadsPackageJson(devDir, target), null, 2), "utf-8");
|
|
948
|
+
await this.execNpm([
|
|
949
|
+
...installArgs,
|
|
950
|
+
...buildNpmRegistryArgs(registry)
|
|
951
|
+
], {
|
|
952
|
+
cwd: stagingDir,
|
|
953
|
+
timeoutMs: NPM_INSTALL_TIMEOUT_MS
|
|
954
|
+
});
|
|
955
|
+
} else {
|
|
956
|
+
fs4.writeFileSync(path5.join(stagingDir, "package.json"), JSON.stringify({
|
|
957
|
+
name: "camstack-node-root",
|
|
958
|
+
private: true
|
|
959
|
+
}, null, 2), "utf-8");
|
|
960
|
+
await this.execNpm([
|
|
961
|
+
...installArgs,
|
|
962
|
+
`${this.spec.packageName}@${target}`,
|
|
963
|
+
...buildNpmRegistryArgs(registry)
|
|
964
|
+
], {
|
|
965
|
+
cwd: stagingDir,
|
|
966
|
+
timeoutMs: NPM_INSTALL_TIMEOUT_MS
|
|
967
|
+
});
|
|
968
|
+
}
|
|
876
969
|
const entry = rootEntryPath2(stagingDir, this.spec);
|
|
877
|
-
if (!
|
|
970
|
+
if (!fs4.existsSync(entry)) {
|
|
878
971
|
throw new Error(`staged closure is missing the root entry (${entry})`);
|
|
879
972
|
}
|
|
880
|
-
const stagedVersion = readPackageVersion(
|
|
973
|
+
const stagedVersion = readPackageVersion(path5.join(rootPackageDir2(stagingDir, this.spec), "package.json"));
|
|
881
974
|
if (stagedVersion !== target) {
|
|
882
975
|
throw new Error(`staged closure version mismatch: expected ${target}, got ${stagedVersion ?? "unknown"}`);
|
|
883
976
|
}
|
|
884
977
|
const dest = versionDir(rootDir, target);
|
|
885
|
-
if (
|
|
978
|
+
if (fs4.existsSync(dest)) {
|
|
886
979
|
const aside = `${dest}.evicted-${this.now()}`;
|
|
887
|
-
await
|
|
888
|
-
await
|
|
980
|
+
await fs4.promises.rename(dest, aside);
|
|
981
|
+
await fs4.promises.rm(aside, {
|
|
889
982
|
recursive: true,
|
|
890
983
|
force: true
|
|
891
984
|
}).catch(() => void 0);
|
|
892
985
|
}
|
|
893
|
-
await
|
|
986
|
+
await fs4.promises.rename(stagingDir, dest);
|
|
894
987
|
} catch (err) {
|
|
895
|
-
await
|
|
988
|
+
await fs4.promises.rm(stagingDir, {
|
|
896
989
|
recursive: true,
|
|
897
990
|
force: true
|
|
898
991
|
}).catch(() => void 0);
|
|
899
992
|
throw err;
|
|
900
993
|
}
|
|
901
994
|
}
|
|
995
|
+
/**
|
|
996
|
+
* Synthetic staging package.json for the dev server-deploy channel:
|
|
997
|
+
* `dependencies` carries the root package as a `file:` ref to its uploaded
|
|
998
|
+
* tgz; `overrides` maps EVERY OTHER uploaded `@camstack/<name>` to its tgz
|
|
999
|
+
* so any transitive occurrence resolves to the uploaded copy, never npm.
|
|
1000
|
+
* Fail-closed: a missing/invalid manifest, a manifest for a different
|
|
1001
|
+
* version, a missing root package, or a listed-but-absent tgz all throw
|
|
1002
|
+
* (surfaced by `applyServerUpdate` as a staging failure).
|
|
1003
|
+
*/
|
|
1004
|
+
buildDevUploadsPackageJson(devDir, target) {
|
|
1005
|
+
const manifest = readDevUploadManifest(devDir);
|
|
1006
|
+
if (manifest === null) {
|
|
1007
|
+
throw new Error(`dev-uploads manifest missing or invalid in ${devDir}`);
|
|
1008
|
+
}
|
|
1009
|
+
if (manifest.version !== target) {
|
|
1010
|
+
throw new Error(`dev-uploads manifest version mismatch: dir is for ${target}, manifest says ${manifest.version}`);
|
|
1011
|
+
}
|
|
1012
|
+
const rootTgz = manifest.packages[this.spec.packageName];
|
|
1013
|
+
if (rootTgz === void 0) {
|
|
1014
|
+
throw new Error(`dev-uploads for ${target} do not include the root package ${this.spec.packageName}`);
|
|
1015
|
+
}
|
|
1016
|
+
const fileRef = /* @__PURE__ */ __name((filename) => {
|
|
1017
|
+
const abs = path5.join(devDir, filename);
|
|
1018
|
+
if (!fs4.existsSync(abs)) {
|
|
1019
|
+
throw new Error(`dev-uploads tarball listed in the manifest is missing: ${abs}`);
|
|
1020
|
+
}
|
|
1021
|
+
return `file:${abs}`;
|
|
1022
|
+
}, "fileRef");
|
|
1023
|
+
const overrides = {};
|
|
1024
|
+
for (const [pkgName, filename] of Object.entries(manifest.packages)) {
|
|
1025
|
+
if (pkgName === this.spec.packageName) continue;
|
|
1026
|
+
overrides[pkgName] = fileRef(filename);
|
|
1027
|
+
}
|
|
1028
|
+
return {
|
|
1029
|
+
name: "camstack-node-root",
|
|
1030
|
+
private: true,
|
|
1031
|
+
dependencies: {
|
|
1032
|
+
[this.spec.packageName]: fileRef(rootTgz)
|
|
1033
|
+
},
|
|
1034
|
+
...Object.keys(overrides).length > 0 ? {
|
|
1035
|
+
overrides
|
|
1036
|
+
} : {}
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
902
1039
|
// ── Rollback ──────────────────────────────────────────────────────────
|
|
903
1040
|
async rollbackServerUpdate() {
|
|
904
1041
|
if (this.inFlight !== "idle") {
|
|
@@ -1031,6 +1168,7 @@ var require_dist = __commonJS({
|
|
|
1031
1168
|
promoted.currentVersion,
|
|
1032
1169
|
promoted.previousVersion
|
|
1033
1170
|
].filter((v) => typeof v === "string"));
|
|
1171
|
+
this.sweepDevUploads(DEV_UPLOADS_KEEP_COUNT);
|
|
1034
1172
|
this.logger.info("root package update confirmed healthy", {
|
|
1035
1173
|
meta: {
|
|
1036
1174
|
version: promoted.currentVersion,
|
|
@@ -1056,23 +1194,23 @@ var require_dist = __commonJS({
|
|
|
1056
1194
|
const vDir = versionsDir(this.rootDir());
|
|
1057
1195
|
let entries;
|
|
1058
1196
|
try {
|
|
1059
|
-
entries =
|
|
1197
|
+
entries = fs4.readdirSync(vDir);
|
|
1060
1198
|
} catch {
|
|
1061
1199
|
return;
|
|
1062
1200
|
}
|
|
1063
1201
|
for (const entry of entries) {
|
|
1064
1202
|
if (keep.includes(entry)) continue;
|
|
1065
|
-
const full =
|
|
1203
|
+
const full = path5.join(vDir, entry);
|
|
1066
1204
|
if (entry.startsWith(".")) {
|
|
1067
1205
|
try {
|
|
1068
|
-
const ageMs = this.now() -
|
|
1206
|
+
const ageMs = this.now() - fs4.statSync(full).mtimeMs;
|
|
1069
1207
|
if (ageMs < _RootUpdateService.STALE_TRANSIENT_MS) continue;
|
|
1070
1208
|
} catch {
|
|
1071
1209
|
continue;
|
|
1072
1210
|
}
|
|
1073
1211
|
}
|
|
1074
1212
|
try {
|
|
1075
|
-
|
|
1213
|
+
fs4.rmSync(full, {
|
|
1076
1214
|
recursive: true,
|
|
1077
1215
|
force: true
|
|
1078
1216
|
});
|
|
@@ -1091,6 +1229,71 @@ var require_dist = __commonJS({
|
|
|
1091
1229
|
}
|
|
1092
1230
|
}
|
|
1093
1231
|
}
|
|
1232
|
+
/**
|
|
1233
|
+
* Promote-time sweep of `server-root/dev-uploads/`: keep only the
|
|
1234
|
+
* `keepCount` most recent entries (ordered by the self-describing
|
|
1235
|
+
* `-dev.<epochSeconds>` suffix; non-dev-shaped residue counts as oldest).
|
|
1236
|
+
* Uses the same rename-aside graveyard pattern as the addon installer —
|
|
1237
|
+
* a rename is a metadata op that succeeds even when a tarball is held
|
|
1238
|
+
* open, and residue in the graveyard is re-swept on the next promote.
|
|
1239
|
+
*/
|
|
1240
|
+
sweepDevUploads(keepCount) {
|
|
1241
|
+
const dir = devUploadsDir(this.rootDir());
|
|
1242
|
+
let entries;
|
|
1243
|
+
try {
|
|
1244
|
+
entries = fs4.readdirSync(dir);
|
|
1245
|
+
} catch {
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
const graveyard = path5.join(dir, ".sweeping");
|
|
1249
|
+
try {
|
|
1250
|
+
for (const residue of fs4.readdirSync(graveyard)) {
|
|
1251
|
+
try {
|
|
1252
|
+
fs4.rmSync(path5.join(graveyard, residue), {
|
|
1253
|
+
recursive: true,
|
|
1254
|
+
force: true
|
|
1255
|
+
});
|
|
1256
|
+
} catch {
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
} catch {
|
|
1260
|
+
}
|
|
1261
|
+
const versions = entries.filter((name) => !name.startsWith("."));
|
|
1262
|
+
const byNewestFirst = [
|
|
1263
|
+
...versions
|
|
1264
|
+
].sort((a, b) => (devChannelEpoch(b) ?? -1) - (devChannelEpoch(a) ?? -1));
|
|
1265
|
+
const doomed = byNewestFirst.slice(keepCount);
|
|
1266
|
+
if (doomed.length === 0) return;
|
|
1267
|
+
fs4.mkdirSync(graveyard, {
|
|
1268
|
+
recursive: true
|
|
1269
|
+
});
|
|
1270
|
+
for (const entry of doomed) {
|
|
1271
|
+
const aside = path5.join(graveyard, `${entry}-${this.now()}`);
|
|
1272
|
+
try {
|
|
1273
|
+
fs4.renameSync(path5.join(dir, entry), aside);
|
|
1274
|
+
} catch (err) {
|
|
1275
|
+
this.logger.warn("failed to move dev-uploads entry aside for sweep", {
|
|
1276
|
+
meta: {
|
|
1277
|
+
entry,
|
|
1278
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1279
|
+
}
|
|
1280
|
+
});
|
|
1281
|
+
continue;
|
|
1282
|
+
}
|
|
1283
|
+
try {
|
|
1284
|
+
fs4.rmSync(aside, {
|
|
1285
|
+
recursive: true,
|
|
1286
|
+
force: true
|
|
1287
|
+
});
|
|
1288
|
+
this.logger.debug("swept dev-uploads entry", {
|
|
1289
|
+
meta: {
|
|
1290
|
+
entry
|
|
1291
|
+
}
|
|
1292
|
+
});
|
|
1293
|
+
} catch {
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1094
1297
|
/** Transient (.staging- / .evicted-) dirs younger than this are never pruned. */
|
|
1095
1298
|
static STALE_TRANSIENT_MS = 24 * 60 * 60 * 1e3;
|
|
1096
1299
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/server",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.55",
|
|
4
4
|
"private": false,
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -23,17 +23,17 @@
|
|
|
23
23
|
"test:watch": "vitest"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@camstack/addon-admin-ui": "1.1.
|
|
26
|
+
"@camstack/addon-admin-ui": "1.1.47",
|
|
27
27
|
"@camstack/addon-advanced-notifier": "1.1.21",
|
|
28
28
|
"@camstack/addon-auth": "1.1.6",
|
|
29
29
|
"@camstack/addon-decoder-nodeav": "1.1.9",
|
|
30
30
|
"@camstack/addon-notifiers": "1.1.21",
|
|
31
31
|
"@camstack/addon-pipeline": "1.1.51",
|
|
32
|
-
"@camstack/addon-pipeline-orchestrator": "1.1.
|
|
32
|
+
"@camstack/addon-pipeline-orchestrator": "1.1.40",
|
|
33
33
|
"@camstack/addon-post-analysis": "1.1.23",
|
|
34
34
|
"@camstack/sdk": "1.1.22",
|
|
35
35
|
"@camstack/shm-ring": "1.0.21",
|
|
36
|
-
"@camstack/system": "1.1.
|
|
36
|
+
"@camstack/system": "1.1.42",
|
|
37
37
|
"@camstack/types": "1.1.39",
|
|
38
38
|
"@camstack/ui-library": "1.1.31",
|
|
39
39
|
"@fastify/compress": "^9.0.0",
|