@camstack/server 1.1.71 → 1.1.73

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.
@@ -371,6 +371,38 @@ var require_dist = __commonJS({
371
371
  __name(validateVersionDir, "validateVersionDir");
372
372
  var fs3 = __toESM2(require("fs"));
373
373
  var path3 = __toESM2(require("path"));
374
+ function parse(version) {
375
+ const dashIdx = version.indexOf("-");
376
+ const base = dashIdx === -1 ? version : version.slice(0, dashIdx);
377
+ const prerelease = dashIdx === -1 ? null : version.slice(dashIdx + 1);
378
+ const nums = base.split(".").map((seg) => {
379
+ const n = Number.parseInt(seg, 10);
380
+ return Number.isNaN(n) ? 0 : n;
381
+ });
382
+ return {
383
+ nums,
384
+ prerelease
385
+ };
386
+ }
387
+ __name(parse, "parse");
388
+ function compareSemver(a, b) {
389
+ const pa = parse(a);
390
+ const pb = parse(b);
391
+ const len = Math.max(pa.nums.length, pb.nums.length);
392
+ for (let i = 0; i < len; i++) {
393
+ const na = pa.nums[i] ?? 0;
394
+ const nb = pb.nums[i] ?? 0;
395
+ if (na < nb) return -1;
396
+ if (na > nb) return 1;
397
+ }
398
+ if (pa.prerelease === null && pb.prerelease === null) return 0;
399
+ if (pa.prerelease === null) return 1;
400
+ if (pb.prerelease === null) return -1;
401
+ if (pa.prerelease < pb.prerelease) return -1;
402
+ if (pa.prerelease > pb.prerelease) return 1;
403
+ return 0;
404
+ }
405
+ __name(compareSemver, "compareSemver");
374
406
  var CURRENT_DIRNAME = "current";
375
407
  var PENDING_ROOT_SWAP_FILE = ".pending-root-swap.json";
376
408
  var LEGACY_FRAMEWORK_MARKERS = [
@@ -566,17 +598,43 @@ var require_dist = __commonJS({
566
598
  };
567
599
  }
568
600
  __name(applyPendingRootSwap, "applyPendingRootSwap");
601
+ function readClosureVersion(closureDir, spec) {
602
+ try {
603
+ const raw = JSON.parse(fs3.readFileSync(path3.join(rootPackageDir2(closureDir, spec), "package.json"), "utf-8"));
604
+ if (typeof raw === "object" && raw !== null) {
605
+ const version = raw["version"];
606
+ if (typeof version === "string") return version;
607
+ }
608
+ } catch {
609
+ }
610
+ return null;
611
+ }
612
+ __name(readClosureVersion, "readClosureVersion");
613
+ function isAdoptablePendingClosure(rootDir, version, nodeMajor, spec) {
614
+ const dir = versionDir(rootDir, version);
615
+ return validateClosureDir(dir, nodeMajor, spec, version) === null && findMissingNativePrebuilds(dir).length === 0;
616
+ }
617
+ __name(isAdoptablePendingClosure, "isAdoptablePendingClosure");
569
618
  function migrateToSingleCopy(rootDir, spec, nodeMajor, now, log) {
570
619
  const dest = currentDir(rootDir);
571
- if (fs3.existsSync(dest) && validateClosureDir(dest, nodeMajor, spec) === null) {
572
- return {
573
- migrated: false,
574
- version: null,
575
- reason: "current already present"
576
- };
620
+ const legacyState = readServerRootState(rootDir);
621
+ const pendingVersion = legacyState?.pendingBoot?.version ?? null;
622
+ const pendingAdoptable = pendingVersion !== null && isAdoptablePendingClosure(rootDir, pendingVersion, nodeMajor, spec);
623
+ const currentValid = fs3.existsSync(dest) && validateClosureDir(dest, nodeMajor, spec) === null;
624
+ if (currentValid) {
625
+ const currentVersion = readClosureVersion(dest, spec);
626
+ const pendingSupersedes = pendingAdoptable && pendingVersion !== null && (currentVersion === null || compareSemver(pendingVersion, currentVersion) > 0);
627
+ if (!pendingSupersedes) {
628
+ return {
629
+ migrated: false,
630
+ version: null,
631
+ reason: "current already present"
632
+ };
633
+ }
634
+ log(`[single-copy] in-flight pending ${pendingVersion} supersedes older current ${currentVersion ?? "?"}`);
577
635
  }
578
636
  const candidates = [];
579
- const legacyState = readServerRootState(rootDir);
637
+ if (pendingAdoptable && pendingVersion !== null) candidates.push(pendingVersion);
580
638
  if (legacyState !== null) {
581
639
  for (const v of [
582
640
  legacyState.currentVersion,
@@ -662,38 +720,6 @@ var require_dist = __commonJS({
662
720
  };
663
721
  }
664
722
  __name(planBoot, "planBoot");
665
- function parse(version) {
666
- const dashIdx = version.indexOf("-");
667
- const base = dashIdx === -1 ? version : version.slice(0, dashIdx);
668
- const prerelease = dashIdx === -1 ? null : version.slice(dashIdx + 1);
669
- const nums = base.split(".").map((seg) => {
670
- const n = Number.parseInt(seg, 10);
671
- return Number.isNaN(n) ? 0 : n;
672
- });
673
- return {
674
- nums,
675
- prerelease
676
- };
677
- }
678
- __name(parse, "parse");
679
- function compareSemver(a, b) {
680
- const pa = parse(a);
681
- const pb = parse(b);
682
- const len = Math.max(pa.nums.length, pb.nums.length);
683
- for (let i = 0; i < len; i++) {
684
- const na = pa.nums[i] ?? 0;
685
- const nb = pb.nums[i] ?? 0;
686
- if (na < nb) return -1;
687
- if (na > nb) return 1;
688
- }
689
- if (pa.prerelease === null && pb.prerelease === null) return 0;
690
- if (pa.prerelease === null) return 1;
691
- if (pb.prerelease === null) return -1;
692
- if (pa.prerelease < pb.prerelease) return -1;
693
- if (pa.prerelease > pb.prerelease) return 1;
694
- return 0;
695
- }
696
- __name(compareSemver, "compareSemver");
697
723
  var fs4 = __toESM2(require("fs"));
698
724
  var path4 = __toESM2(require("path"));
699
725
  function detectWorkspaceRoot(fromDir) {
@@ -756,7 +782,7 @@ var require_dist = __commonJS({
756
782
  registerHooks(hooks);
757
783
  }
758
784
  __name(registerActiveRootResolver, "registerActiveRootResolver");
759
- function readClosureVersion(closureDir, spec) {
785
+ function readClosureVersion2(closureDir, spec) {
760
786
  try {
761
787
  const raw = JSON.parse(fs5.readFileSync(path5.join(rootPackageDir2(closureDir, spec), "package.json"), "utf-8"));
762
788
  if (typeof raw === "object" && raw !== null) {
@@ -767,7 +793,7 @@ var require_dist = __commonJS({
767
793
  }
768
794
  return null;
769
795
  }
770
- __name(readClosureVersion, "readClosureVersion");
796
+ __name(readClosureVersion2, "readClosureVersion2");
771
797
  function runNodeStarter(options) {
772
798
  const env = options.env ?? process.env;
773
799
  const now = options.now ?? Date.now;
@@ -800,7 +826,7 @@ var require_dist = __commonJS({
800
826
  }
801
827
  const plan = planBoot(invalid === null);
802
828
  if (plan.kind === "current") {
803
- const version = readClosureVersion(activeRootDir, options.spec);
829
+ const version = readClosureVersion2(activeRootDir, options.spec);
804
830
  const entry = currentEntryPath(rootDir, options.spec);
805
831
  console.log(`[starter] booting ${options.spec.packageName}@${version ?? "?"} from ${activeRootDir}`);
806
832
  env[options.envNames.bootMode] = "data-root";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.1.71",
3
+ "version": "1.1.73",
4
4
  "private": false,
5
5
  "files": [
6
6
  "dist",
@@ -23,19 +23,19 @@
23
23
  "test:watch": "vitest"
24
24
  },
25
25
  "dependencies": {
26
- "@camstack/addon-admin-ui": "1.1.58",
26
+ "@camstack/addon-admin-ui": "1.1.60",
27
27
  "@camstack/addon-advanced-notifier": "1.1.30",
28
28
  "@camstack/addon-auth": "1.1.15",
29
29
  "@camstack/addon-decoder-nodeav": "1.1.18",
30
30
  "@camstack/addon-notifiers": "1.1.30",
31
- "@camstack/addon-pipeline": "1.1.64",
32
- "@camstack/addon-pipeline-orchestrator": "1.1.53",
33
- "@camstack/addon-post-analysis": "1.1.36",
31
+ "@camstack/addon-pipeline": "1.1.66",
32
+ "@camstack/addon-pipeline-orchestrator": "1.1.55",
33
+ "@camstack/addon-post-analysis": "1.1.38",
34
34
  "@camstack/sdk": "1.1.30",
35
35
  "@camstack/shm-ring": "1.0.29",
36
- "@camstack/system": "1.1.57",
37
- "@camstack/types": "1.1.51",
38
- "@camstack/ui-library": "1.1.42",
36
+ "@camstack/system": "1.1.59",
37
+ "@camstack/types": "1.1.53",
38
+ "@camstack/ui-library": "1.1.44",
39
39
  "@fastify/compress": "^9.0.0",
40
40
  "@fastify/cookie": "^11.0.2",
41
41
  "@fastify/multipart": "^10.0.0",
@@ -1,119 +0,0 @@
1
- "use strict";
2
- /**
3
- * Boot-time framework-swap job resume + health confirm.
4
- *
5
- * After a framework swap reboot, `post-boot.service.ts` calls this once the
6
- * hub is healthy. It:
7
- * 1. Reads `.framework-swap-confirm.json` (written by the launcher on apply).
8
- * 2. Marks the journal task `applied` → `done`, then finalises the job →
9
- * `completed`.
10
- * 3. Calls `confirmFrameworkSwapHealthy` to delete the confirm marker +
11
- * backup dirs (disarms the crash-loop rollback).
12
- *
13
- * Best-effort: a missing/corrupt journal is tolerated — `confirmFrameworkSwapHealthy`
14
- * is still called so the rollback is always disarmed when the hub boots healthy.
15
- */
16
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
17
- if (k2 === undefined) k2 = k;
18
- var desc = Object.getOwnPropertyDescriptor(m, k);
19
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
20
- desc = { enumerable: true, get: function() { return m[k]; } };
21
- }
22
- Object.defineProperty(o, k2, desc);
23
- }) : (function(o, m, k, k2) {
24
- if (k2 === undefined) k2 = k;
25
- o[k2] = m[k];
26
- }));
27
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
28
- Object.defineProperty(o, "default", { enumerable: true, value: v });
29
- }) : function(o, v) {
30
- o["default"] = v;
31
- });
32
- var __importStar = (this && this.__importStar) || (function () {
33
- var ownKeys = function(o) {
34
- ownKeys = Object.getOwnPropertyNames || function (o) {
35
- var ar = [];
36
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
37
- return ar;
38
- };
39
- return ownKeys(o);
40
- };
41
- return function (mod) {
42
- if (mod && mod.__esModule) return mod;
43
- var result = {};
44
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
45
- __setModuleDefault(result, mod);
46
- return result;
47
- };
48
- })();
49
- Object.defineProperty(exports, "__esModule", { value: true });
50
- exports.resumeFrameworkSwapJob = resumeFrameworkSwapJob;
51
- const fs = __importStar(require("node:fs"));
52
- const path = __importStar(require("node:path"));
53
- const types_1 = require("@camstack/types");
54
- const system_1 = require("@camstack/system");
55
- const launcher_framework_swap_js_1 = require("../launcher-framework-swap.js");
56
- const lifecycle_journal_path_js_1 = require("../lifecycle-journal-path.js");
57
- const SWAP_CONFIRM_FILE = '.framework-swap-confirm.json';
58
- /**
59
- * Resume a framework-swap journal job to `done`/`completed` and confirm the
60
- * hub is healthy (deletes the confirm marker + backups).
61
- *
62
- * @returns `{ resumed: false }` when no confirm marker exists.
63
- * `{ resumed: true, jobId }` when the marker was found and processed.
64
- * Never throws — errors are swallowed to avoid crashing the post-boot path.
65
- */
66
- async function resumeFrameworkSwapJob(dataDir) {
67
- try {
68
- const confirmMarker = readConfirmMarker(dataDir);
69
- if (confirmMarker === null) {
70
- return { resumed: false };
71
- }
72
- const { jobId, taskId } = confirmMarker;
73
- let journalPatched = false;
74
- try {
75
- const journal = new system_1.JobJournal((0, lifecycle_journal_path_js_1.lifecycleJobsDir)(dataDir));
76
- const job = journal.getJob(jobId);
77
- if (job !== null) {
78
- const task = job.tasks.find((t) => t.taskId === taskId);
79
- if (task !== undefined && task.phase === 'applied') {
80
- journal.patchTask(jobId, taskId, { phase: 'done', finishedAtMs: Date.now() });
81
- // Single-task framework job: if all tasks are now terminal and none
82
- // failed, mark the job completed (mirrors the engine's finalize logic).
83
- const updatedJob = journal.getJob(jobId);
84
- if (updatedJob !== null) {
85
- const allTerminal = updatedJob.tasks.every((t) => t.phase === 'done' || t.phase === 'failed' || t.phase === 'skipped');
86
- const anyFailed = updatedJob.tasks.some((t) => t.phase === 'failed');
87
- if (allTerminal && !anyFailed) {
88
- journal.setJobState(jobId, 'completed');
89
- }
90
- }
91
- journalPatched = true;
92
- }
93
- }
94
- }
95
- catch {
96
- // Journal is missing or corrupt — still clean up the confirm marker so
97
- // the rollback is disarmed on a healthy hub boot.
98
- }
99
- (0, launcher_framework_swap_js_1.confirmFrameworkSwapHealthy)(dataDir);
100
- return journalPatched ? { resumed: true, jobId } : { resumed: false };
101
- }
102
- catch {
103
- // Never crash the caller (post-boot service).
104
- return { resumed: false };
105
- }
106
- }
107
- /** Read and shape-check the confirm marker. Returns null on any error. */
108
- function readConfirmMarker(dataDir) {
109
- try {
110
- const raw = JSON.parse(fs.readFileSync(path.join(dataDir, SWAP_CONFIRM_FILE), 'utf-8'));
111
- const parsed = types_1.frameworkSwapConfirmSchema.safeParse(raw);
112
- if (!parsed.success)
113
- return null;
114
- return { jobId: parsed.data.jobId, taskId: parsed.data.taskId };
115
- }
116
- catch {
117
- return null;
118
- }
119
- }