@camstack/server 1.2.88 → 1.2.90

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.
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.SERVER_ROOT_PACKAGE_NAME = exports.SERVER_ROOT_STATE_FILE = exports.SERVER_ROOT_DIRNAME = void 0;
37
+ exports.emptyServerRootState = emptyServerRootState;
38
+ exports.serverRootDir = serverRootDir;
39
+ exports.versionsDir = versionsDir;
40
+ exports.versionDir = versionDir;
41
+ exports.serverPackageDir = serverPackageDir;
42
+ exports.serverEntryPath = serverEntryPath;
43
+ exports.stateFilePath = stateFilePath;
44
+ exports.isServerRootState = isServerRootState;
45
+ exports.readServerRootState = readServerRootState;
46
+ exports.writeServerRootState = writeServerRootState;
47
+ exports.minNodeMajorOf = minNodeMajorOf;
48
+ exports.validateVersionDir = validateVersionDir;
49
+ /**
50
+ * Data-dir server-root layout + state file — ZERO-DEP (node:fs/node:path only).
51
+ *
52
+ * Loaded by the baked STARTER before any node_modules resolution is trusted,
53
+ * so this module must never import from `@camstack/*` or any npm package.
54
+ * The hub-side `ServerUpdateService` imports the same module — one source of
55
+ * truth for the layout and the state shape.
56
+ *
57
+ * Layout (`<dataDir>/server-root/`):
58
+ * versions/<semver>/ npm-installed closure for one version
59
+ * node_modules/@camstack/server/dist/launcher.js ← the loadable entry
60
+ * state.json pointer file (ServerRootState, atomic)
61
+ *
62
+ * A POINTER FILE (state.json) is used instead of `current`/`previous`
63
+ * symlinks: atomic via tmp+rename, works on every fs, and carries the
64
+ * probation/rollback bookkeeping in the same durable record.
65
+ *
66
+ * Spec: docs/superpowers/specs/2026-07-12-runtime-updatable-node-packages-design.md
67
+ */
68
+ const fs = __importStar(require("node:fs"));
69
+ const path = __importStar(require("node:path"));
70
+ exports.SERVER_ROOT_DIRNAME = 'server-root';
71
+ exports.SERVER_ROOT_STATE_FILE = 'state.json';
72
+ exports.SERVER_ROOT_PACKAGE_NAME = '@camstack/server';
73
+ function emptyServerRootState() {
74
+ return {
75
+ schemaVersion: 1,
76
+ currentVersion: null,
77
+ previousVersion: null,
78
+ pendingBoot: null,
79
+ rolledBack: null,
80
+ };
81
+ }
82
+ // ---------------------------------------------------------------------------
83
+ // Layout helpers
84
+ // ---------------------------------------------------------------------------
85
+ function serverRootDir(dataDir) {
86
+ return path.join(dataDir, exports.SERVER_ROOT_DIRNAME);
87
+ }
88
+ function versionsDir(rootDir) {
89
+ return path.join(rootDir, 'versions');
90
+ }
91
+ function versionDir(rootDir, version) {
92
+ return path.join(versionsDir(rootDir), version);
93
+ }
94
+ function serverPackageDir(versionDirPath) {
95
+ return path.join(versionDirPath, 'node_modules', '@camstack', 'server');
96
+ }
97
+ function serverEntryPath(versionDirPath) {
98
+ return path.join(serverPackageDir(versionDirPath), 'dist', 'launcher.js');
99
+ }
100
+ function stateFilePath(rootDir) {
101
+ return path.join(rootDir, exports.SERVER_ROOT_STATE_FILE);
102
+ }
103
+ // ---------------------------------------------------------------------------
104
+ // State IO (atomic, corruption-tolerant)
105
+ // ---------------------------------------------------------------------------
106
+ function isNullableString(v) {
107
+ return v === null || typeof v === 'string';
108
+ }
109
+ function isPendingBoot(v) {
110
+ if (typeof v !== 'object' || v === null)
111
+ return false;
112
+ const p = v;
113
+ return (typeof p['version'] === 'string' &&
114
+ isNullableString(p['fromVersion']) &&
115
+ typeof p['requestedAtMs'] === 'number' &&
116
+ typeof p['bootAttempts'] === 'number');
117
+ }
118
+ function isRollbackInfo(v) {
119
+ if (typeof v !== 'object' || v === null)
120
+ return false;
121
+ const r = v;
122
+ return (typeof r['fromVersion'] === 'string' &&
123
+ isNullableString(r['toVersion']) &&
124
+ typeof r['atMs'] === 'number' &&
125
+ typeof r['reason'] === 'string');
126
+ }
127
+ function isServerRootState(v) {
128
+ if (typeof v !== 'object' || v === null)
129
+ return false;
130
+ const s = v;
131
+ if (s['schemaVersion'] !== 1)
132
+ return false;
133
+ if (!isNullableString(s['currentVersion']))
134
+ return false;
135
+ if (!isNullableString(s['previousVersion']))
136
+ return false;
137
+ if (s['pendingBoot'] !== null && !isPendingBoot(s['pendingBoot']))
138
+ return false;
139
+ if (s['rolledBack'] !== null && !isRollbackInfo(s['rolledBack']))
140
+ return false;
141
+ return true;
142
+ }
143
+ /** Read + validate the state file. Returns null when missing/corrupt/mismatched. */
144
+ function readServerRootState(rootDir) {
145
+ try {
146
+ const raw = JSON.parse(fs.readFileSync(stateFilePath(rootDir), 'utf-8'));
147
+ return isServerRootState(raw) ? raw : null;
148
+ }
149
+ catch {
150
+ return null;
151
+ }
152
+ }
153
+ /** Write the state file atomically (tmp sibling + rename). Creates rootDir. */
154
+ function writeServerRootState(rootDir, state) {
155
+ fs.mkdirSync(rootDir, { recursive: true });
156
+ const target = stateFilePath(rootDir);
157
+ const tmp = `${target}.tmp`;
158
+ fs.writeFileSync(tmp, JSON.stringify(state, null, 2), 'utf-8');
159
+ fs.renameSync(tmp, target);
160
+ }
161
+ // ---------------------------------------------------------------------------
162
+ // Version-dir validation
163
+ // ---------------------------------------------------------------------------
164
+ /**
165
+ * Extract the minimum required Node major from an `engines.node` range like
166
+ * `>=22`, `>= 22.12`, `^24.0.0`, `22.x`. Returns null when unparseable
167
+ * (validation is then permissive — a bogus range must not brick boot).
168
+ */
169
+ function minNodeMajorOf(enginesNode) {
170
+ const match = /(\d+)/.exec(enginesNode);
171
+ if (match === null)
172
+ return null;
173
+ const major = Number.parseInt(match[1] ?? '', 10);
174
+ return Number.isNaN(major) ? null : major;
175
+ }
176
+ /**
177
+ * Validate that `versions/<version>` holds a loadable `@camstack/server`
178
+ * closure. Returns null when valid, else a human-readable reason. Checks:
179
+ * 1. the launcher entry file exists,
180
+ * 2. the package.json parses with the right `name` + `version`,
181
+ * 3. `engines.node` (when parseable) is satisfied by the running runtime —
182
+ * the starter refuses a native-ABI mismatch with a clear error instead
183
+ * of segfaulting (design risk: node bump vs shm-ring prebuilds).
184
+ */
185
+ function validateVersionDir(rootDir, version, nodeMajor) {
186
+ const vDir = versionDir(rootDir, version);
187
+ const entry = serverEntryPath(vDir);
188
+ if (!fs.existsSync(entry)) {
189
+ return `server entry missing: ${entry}`;
190
+ }
191
+ const pkgJsonPath = path.join(serverPackageDir(vDir), 'package.json');
192
+ let pkg;
193
+ try {
194
+ const raw = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
195
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
196
+ return `package.json malformed: ${pkgJsonPath}`;
197
+ }
198
+ pkg = raw;
199
+ }
200
+ catch {
201
+ return `package.json unreadable: ${pkgJsonPath}`;
202
+ }
203
+ if (pkg['name'] !== exports.SERVER_ROOT_PACKAGE_NAME) {
204
+ return `package name mismatch: expected ${exports.SERVER_ROOT_PACKAGE_NAME}, got ${String(pkg['name'])}`;
205
+ }
206
+ if (pkg['version'] !== version) {
207
+ return `package version mismatch: dir says ${version}, package.json says ${String(pkg['version'])}`;
208
+ }
209
+ const engines = pkg['engines'];
210
+ if (typeof engines === 'object' && engines !== null) {
211
+ const enginesNode = engines['node'];
212
+ if (typeof enginesNode === 'string') {
213
+ const minMajor = minNodeMajorOf(enginesNode);
214
+ if (minMajor !== null && nodeMajor < minMajor) {
215
+ return `engines.node "${enginesNode}" requires Node >= ${minMajor}, runtime is ${nodeMajor}`;
216
+ }
217
+ }
218
+ }
219
+ return null;
220
+ }
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.detectWorkspaceRoot = detectWorkspaceRoot;
37
+ /**
38
+ * Workspace-checkout detection for the starter — ZERO-DEP.
39
+ *
40
+ * The starter must defer to plain resolution in a dev checkout (`npm run
41
+ * dev:full` / `npm start` from the monorepo): the data-dir server root is a
42
+ * production mechanism and must never shadow freshly-built workspace code.
43
+ * Detection = any ancestor package.json declaring `workspaces` (the monorepo
44
+ * root has one; the baked image run-dir's `npm init -y` package.json and the
45
+ * data-dir version closures never do).
46
+ */
47
+ const fs = __importStar(require("node:fs"));
48
+ const path = __importStar(require("node:path"));
49
+ /**
50
+ * Walk up from `fromDir` looking for a package.json with a `workspaces`
51
+ * field. Returns the directory containing it, or null when none exists.
52
+ */
53
+ function detectWorkspaceRoot(fromDir) {
54
+ let dir = path.resolve(fromDir);
55
+ for (;;) {
56
+ const pkgPath = path.join(dir, 'package.json');
57
+ try {
58
+ const raw = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
59
+ if (typeof raw === 'object' &&
60
+ raw !== null &&
61
+ raw['workspaces'] !== undefined) {
62
+ return dir;
63
+ }
64
+ }
65
+ catch {
66
+ // missing / unreadable package.json — keep walking
67
+ }
68
+ const parent = path.dirname(dir);
69
+ if (parent === dir)
70
+ return null;
71
+ dir = parent;
72
+ }
73
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.2.88",
3
+ "version": "1.2.90",
4
4
  "private": false,
5
5
  "files": [
6
6
  "dist",
@@ -33,19 +33,19 @@
33
33
  ]
34
34
  },
35
35
  "dependencies": {
36
- "@camstack/addon-admin-ui": "1.2.42",
37
- "@camstack/addon-agent-ui": "1.2.10",
38
- "@camstack/addon-auth": "1.2.11",
39
- "@camstack/addon-decoder-nodeav": "1.2.9",
40
- "@camstack/addon-notifiers": "1.2.13",
41
- "@camstack/addon-pipeline": "1.2.54",
42
- "@camstack/addon-pipeline-orchestrator": "1.2.36",
43
- "@camstack/addon-post-analysis": "1.2.56",
44
- "@camstack/sdk": "1.2.11",
45
- "@camstack/shm-ring": "1.1.9",
46
- "@camstack/system": "1.2.75",
47
- "@camstack/types": "1.2.55",
48
- "@camstack/ui-library": "1.2.38",
36
+ "@camstack/addon-admin-ui": "*",
37
+ "@camstack/addon-agent-ui": "*",
38
+ "@camstack/addon-auth": "*",
39
+ "@camstack/addon-decoder-nodeav": "*",
40
+ "@camstack/addon-notifiers": "*",
41
+ "@camstack/addon-pipeline": "*",
42
+ "@camstack/addon-pipeline-orchestrator": "*",
43
+ "@camstack/addon-post-analysis": "*",
44
+ "@camstack/sdk": "*",
45
+ "@camstack/shm-ring": "*",
46
+ "@camstack/system": "*",
47
+ "@camstack/types": "*",
48
+ "@camstack/ui-library": "*",
49
49
  "@fastify/compress": "^9.0.0",
50
50
  "@fastify/cookie": "^11.0.2",
51
51
  "@fastify/cors": "^11.2.0",