@camstack/server 1.2.689 → 1.2.690

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/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.2.690] - 2026-10-29
11
+
12
+ ### Changed
13
+
14
+ - The agent reports its memory, reclaims stranded pages and gets a heap ceiling sized to the host; a node's launch parameters (heap ceiling, allocator) come from the server and can be overridden per node from the hub
15
+
10
16
  ## [1.2.689] - 2026-10-29
11
17
 
12
18
  ### Added
@@ -17,6 +23,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
17
23
  - Generated routers for the pet-fountain capability
18
24
  - Agents report their own process memory in the topology (the core process showed 0), and an unreadable memory shows as unknown
19
25
 
26
+ ### Changed
27
+
28
+ - The agent now reports its own [mem] agent-main heartbeat and reclaims stranded memory, as the hub does
29
+ - The hub tells its addon runners which telemetry categories anyone consumes, so unused ones stop crossing the process boundary
30
+ - Node launch parameters (heap ceiling, allocator env) are decided by a closure module, with a per-node override and a source line in the boot log
31
+ - A node's heap-ceiling override can be read and set through server-management (applies at the next restart)
32
+
20
33
  ## [1.2.688] - 2026-10-29
21
34
 
22
35
  ### Changed
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startAgentHeapWatch = startAgentHeapWatch;
4
+ /**
5
+ * The agent root's own memory, on the record and returned to the OS.
6
+ *
7
+ * hub-main has had the `[mem]` heartbeat and the stranded-page reclaimer since
8
+ * 2026-08; the agent root process (container AND desktop — both reach
9
+ * `startAgent` through the same launcher) had neither, so a measured 0.8–1.4 GB
10
+ * agent root emitted no line at all and never gave a page back. This is the same
11
+ * mechanism, not a second one: `startHeapWatch` with the V8 reclaimer, labelled
12
+ * `agent-main`.
13
+ */
14
+ const system_1 = require("@camstack/system");
15
+ const DEFAULT_DEPS = {
16
+ start: system_1.startHeapWatch,
17
+ createReclaimer: system_1.createV8Reclaimer,
18
+ };
19
+ /**
20
+ * Start the heartbeat + reclaim for the agent root. Returns the stop function.
21
+ * `createV8Reclaimer()` returns undefined when V8 declines; the heartbeat then
22
+ * runs report-only, exactly as hub-main does.
23
+ */
24
+ function startAgentHeapWatch(logger, deps = DEFAULT_DEPS) {
25
+ const reclaimer = deps.createReclaimer();
26
+ const sink = {
27
+ info: (line) => {
28
+ logger.info(line);
29
+ },
30
+ warn: (line) => {
31
+ logger.warn(line);
32
+ },
33
+ };
34
+ return deps.start(system_1.AGENT_MAIN_HEAP_WATCH_LABEL, sink, undefined, reclaimer === undefined ? undefined : { reclaim: reclaimer }, undefined, undefined,
35
+ // Say who chose the ceiling: the default ceiling below is applied by the
36
+ // launcher's argv, and an absent flag means the image/desktop predates it.
37
+ true);
38
+ }
@@ -76,6 +76,7 @@ const register_agent_cap_dispatch_js_1 = require("./register-agent-cap-dispatch.
76
76
  // entries flow through it (console output + hub forwarding).
77
77
  // ---------------------------------------------------------------------------
78
78
  const system_2 = require("@camstack/system");
79
+ const agent_heap_watch_js_1 = require("./agent-heap-watch.js");
79
80
  /** A reconnect (stop + rebuild + start) that takes longer than this is abandoned. */
80
81
  const RECONNECT_DEADLINE_MS = 90_000;
81
82
  /** How often the agent re-evaluates whether to ask its hub "am I still a member?" (D857). */
@@ -97,6 +98,11 @@ const DATA_NODEID_CAPS = new Set(types_2.ALL_CAPABILITY_DEFINITIONS.filter((c) =
97
98
  // Main
98
99
  // ---------------------------------------------------------------------------
99
100
  async function startAgent(configPath) {
101
+ // The agent root's own memory: `[mem] agent-main` heartbeat + the stranded-page
102
+ // reclaim hub-main has had since 2026-08. Started first so a slow boot is on the
103
+ // record; lines reach the hub through the same LogManager the addons use.
104
+ const heapWatchLogger = agentLogManager.createLogger().withTags({ addonId: 'heap-watch' });
105
+ (0, agent_heap_watch_js_1.startAgentHeapWatch)(heapWatchLogger);
100
106
  const config = (0, agent_config_js_1.loadAgentConfig)(configPath);
101
107
  // Derive CAMSTACK_HUB_URL from the configured hub address so remote agents
102
108
  // no longer need a second, redundant env var set by hand (the cross-node
@@ -480,7 +486,7 @@ async function startAgent(configPath) {
480
486
  dataDir: config.dataDir,
481
487
  runnerBootCheck: () => agentRunnerBootCheck?.current(),
482
488
  });
483
- capabilityRegistry.registerProvider('server-management', agent_update_service_js_1.AGENT_RUNTIME_ADDON_ID, (0, server_management_provider_js_1.buildServerManagementProvider)(agentUpdateService));
489
+ capabilityRegistry.registerProvider('server-management', agent_update_service_js_1.AGENT_RUNTIME_ADDON_ID, (0, server_management_provider_js_1.buildServerManagementProvider)(agentUpdateService, config.dataDir));
484
490
  // The agent's certificates (D856): mesh leaf swap with automatic rollback, and the
485
491
  // hub-issued HTTPS leaf hot-swapped into the sniffing listener. The listener is
486
492
  // created later in boot, so it is read through a getter.
@@ -1,7 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildLaunchOverrideMethods = buildLaunchOverrideMethods;
3
4
  exports.buildServerManagementProvider = buildServerManagementProvider;
4
- function buildServerManagementProvider(service) {
5
+ const launch_args_js_1 = require("../../launch-args.js");
6
+ /** The per-node launch override methods (ADR 0970), backed by the node's data dir. */
7
+ function buildLaunchOverrideMethods(dataDir) {
8
+ return {
9
+ getLaunchOverrides: () => Promise.resolve({ heapMb: (0, launch_args_js_1.readHeapOverrideMb)(dataDir) }),
10
+ setLaunchOverrides: (input) => {
11
+ (0, launch_args_js_1.writeHeapOverrideMb)(dataDir, input.heapMb);
12
+ return Promise.resolve({ heapMb: input.heapMb, restartRequired: true });
13
+ },
14
+ };
15
+ }
16
+ function buildServerManagementProvider(service, dataDir) {
5
17
  if (service === null)
6
18
  return null;
7
19
  return {
@@ -10,5 +22,6 @@ function buildServerManagementProvider(service) {
10
22
  applyServerUpdate: (input) => service.applyServerUpdate(input),
11
23
  rollbackServerUpdate: () => service.rollbackServerUpdate(),
12
24
  restartServer: () => Promise.resolve(service.restartNode()),
25
+ ...buildLaunchOverrideMethods(dataDir),
13
26
  };
14
27
  }
@@ -11047,6 +11047,22 @@ function createCapRouter_serverManagement(getProvider, createRemoteProxy) {
11047
11047
  const p = resolveProvider('server-management', input?.nodeId, () => getProvider(ctx), createRemoteProxy);
11048
11048
  return p.restartServer();
11049
11049
  }),
11050
+ getLaunchOverrides: trpc_middleware_js_1.adminProcedure
11051
+ .input(zod_1.z.object({ nodeId: zod_1.z.string().optional() }).optional())
11052
+ .output(types_126.serverManagementCapability.methods.getLaunchOverrides.output)
11053
+ .query(async ({ input, ctx }) => {
11054
+ const p = resolveProvider('server-management', input?.nodeId, () => getProvider(ctx), createRemoteProxy);
11055
+ return p.getLaunchOverrides();
11056
+ }),
11057
+ setLaunchOverrides: trpc_middleware_js_1.adminProcedure
11058
+ .input(types_126.serverManagementCapability.methods.setLaunchOverrides.input.loose())
11059
+ .output(types_126.serverManagementCapability.methods.setLaunchOverrides.output)
11060
+ .mutation(async ({ input, ctx }) => {
11061
+ const { nodeId, ...methodInput } = input;
11062
+ const p = resolveProvider('server-management', nodeId, () => getProvider(ctx), createRemoteProxy);
11063
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
11064
+ return p.setLaunchOverrides(methodInput);
11065
+ }),
11050
11066
  });
11051
11067
  }
11052
11068
  function createCapRouter_settingsStore(getProvider, createRemoteProxy) {
@@ -254,7 +254,7 @@ function buildServerProviders(services) {
254
254
  integrations: wrap(() => (0, cap_providers_js_1.buildIntegrationsProvider)(services.addonRegistry, services.eventBus, services.loggingService, services.capabilityRegistry)),
255
255
  nodes: wrap(() => (0, cap_providers_js_1.buildNodesProvider)(services.agentRegistry, services.moleculer, services.addonRegistry, (0, cap_providers_js_1.createNodeRootPackageLookup)(services.moleculer, services.serverUpdateService), services.loggingService.createLogger('nodes'))),
256
256
  // server-management — runtime-updatable root package (phase 1: hub only).
257
- 'server-management': wrap(() => (0, server_management_provider_js_1.buildServerManagementProvider)(services.serverUpdateService)),
257
+ 'server-management': wrap(() => (0, server_management_provider_js_1.buildServerManagementProvider)(services.serverUpdateService, path.resolve(process.env['CAMSTACK_DATA'] ?? 'camstack-data'))),
258
258
  addons: wrap((ctx) => (0, cap_providers_js_1.buildAddonsProvider)(services.addonRegistry, services.addonPackageService, services.loggingService, services.moleculer, services.configService, ctx, services.agentRegistry)),
259
259
  // webrtc-session — the resolved broker singleton, wrapped per request to
260
260
  // inject the server-read User-Agent into signaling attribution (the broker
@@ -759,6 +759,14 @@ class MoleculerService {
759
759
  // agents (non-retaining nodes).
760
760
  const hubChildRegistry = this.localChildRegistry;
761
761
  (0, system_1.setNodeEventInterest)(this.broker, () => hubChildRegistry.aggregateEventInterest());
762
+ // Producer-side suppression (D8): tell each forked child which categories
763
+ // someone else wants — siblings plus the hub's own in-process subscribers
764
+ // (the admin live stream is one) — so a high-frequency category nobody
765
+ // wants never leaves its process. Hub only: an agent cannot see the hub's
766
+ // subscribers, so its children keep sending everything. A remote node's
767
+ // interest in a ring-denied category is NOT visible here (ADR 0969).
768
+ hubChildRegistry.setEventInterestSource(() => (0, system_1.getLocalEventInterest)(this.broker));
769
+ (0, system_1.onLocalEventInterestChange)(this.broker, () => hubChildRegistry.refreshEventInterest());
762
770
  }
763
771
  }
764
772
  /**
@@ -0,0 +1,255 @@
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.ALLOCATOR_ENV_DEFAULTS = exports.OVERRIDE_MAX_MB = exports.OVERRIDE_MIN_MB = exports.AGENT_HEAP_CAP_MB = exports.AGENT_HEAP_FLOOR_MB = exports.HEAP_CEILING_SOURCE_ENV = exports.LAUNCH_OVERRIDES_FILE = void 0;
37
+ exports.computedAgentHeapMb = computedAgentHeapMb;
38
+ exports.planLaunch = planLaunch;
39
+ exports.renderLaunchPlan = renderLaunchPlan;
40
+ exports.overridesPath = overridesPath;
41
+ exports.readHeapOverrideMb = readHeapOverrideMb;
42
+ exports.writeHeapOverrideMb = writeHeapOverrideMb;
43
+ exports.readCgroupLimitBytes = readCgroupLimitBytes;
44
+ exports.runLaunchCli = runLaunchCli;
45
+ /**
46
+ * NODE LAUNCH ARGUMENTS — decided by the server closure, executed by the image.
47
+ *
48
+ * `node <closure>/dist/launch-args.js --role hub|agent [--allocator-env]` prints
49
+ * what the launcher should add to the node's command line, so the Docker
50
+ * entrypoint, the Electron shell and the Windows service supervisor carry NO copy
51
+ * of the formula: changing it (or a node's override) needs a closure update and a
52
+ * restart, never a new image or app.
53
+ *
54
+ * Zero dependencies (node built-ins only): it runs BEFORE the closure's own
55
+ * `node_modules` resolution, from either the active closure or the baked seed.
56
+ *
57
+ * ## Output (stdout, one record per line, `\n` separated)
58
+ *
59
+ * arg --max-old-space-size=2048 an extra node argv entry (flags only)
60
+ * env NAME=value an environment variable to export
61
+ * source override|legacy-env|computed|v8-default
62
+ * warn <free text> something the launcher should log
63
+ *
64
+ * Nothing else is printed. A launcher treats any line it does not recognise as
65
+ * absent, and a non-zero exit, a timeout or empty output as "no extra args".
66
+ *
67
+ * ## The heap ceiling
68
+ *
69
+ * - `override` — `<dataDir>/launch-overrides.json` `{ "heapMb": N }`, set from
70
+ * the hub (`serverManagement.setLaunchOverrides`) and persisted on the node.
71
+ * - `legacy-env` — `CAMSTACK_HUB_HEAP_MB` (hub) / `CAMSTACK_AGENT_HEAP_MB`
72
+ * (agent), still honoured when no override is set.
73
+ * - `computed` — AGENT only: clamp(min(RAM, cgroup limit) / 4, 1536, 4096) MB.
74
+ * V8's own quarter-of-RAM rule with a floor above every measured agent RSS
75
+ * (0.8-1.4 GB), so it bounds a runaway and never a healthy root.
76
+ * - `v8-default` — HUB only, nothing set: no flag. A hardcoded 1536 killed the
77
+ * hub four times in 15 h (see the history in the Dockerfile); V8's default
78
+ * here was 4288 MB and is still bounded.
79
+ *
80
+ * Set on argv, never NODE_OPTIONS: forked addon runners are sized separately.
81
+ */
82
+ const fs = __importStar(require("node:fs"));
83
+ const os = __importStar(require("node:os"));
84
+ const path = __importStar(require("node:path"));
85
+ exports.LAUNCH_OVERRIDES_FILE = 'launch-overrides.json';
86
+ /** Env var carrying {@link CeilingSource} to the node so its heartbeat can say who chose. */
87
+ exports.HEAP_CEILING_SOURCE_ENV = 'CAMSTACK_HEAP_CEILING_SOURCE';
88
+ exports.AGENT_HEAP_FLOOR_MB = 1536;
89
+ exports.AGENT_HEAP_CAP_MB = 4096;
90
+ /** An override outside this range is ignored with a warning, never applied. */
91
+ exports.OVERRIDE_MIN_MB = 512;
92
+ exports.OVERRIDE_MAX_MB = 65536;
93
+ /**
94
+ * The native allocator pair, welded: glibc reads MALLOC_ARENA_MAX once at malloc
95
+ * init, so it must exist before `exec node`; sharp restores libvips concurrency
96
+ * from 1 to `availableParallelism()` the moment it appears, so the pair travels
97
+ * together or not at all. Defaults only: an operator value already in the
98
+ * environment wins (the launcher applies them with `: "${NAME:=value}"` semantics).
99
+ */
100
+ exports.ALLOCATOR_ENV_DEFAULTS = {
101
+ MALLOC_ARENA_MAX: '2',
102
+ VIPS_CONCURRENCY: '1',
103
+ };
104
+ const BYTES_PER_MB = 1024 * 1024;
105
+ /** cgroup v1 reports "unlimited" as a value near 2^63. */
106
+ const CGROUP_UNLIMITED_BYTES = 2 ** 60;
107
+ function validMb(value) {
108
+ return Number.isInteger(value) && value >= exports.OVERRIDE_MIN_MB && value <= exports.OVERRIDE_MAX_MB;
109
+ }
110
+ /** The agent's computed ceiling for `host`, in MB. */
111
+ function computedAgentHeapMb(host) {
112
+ const limits = [host.totalMemBytes, host.cgroupLimitBytes ?? Number.POSITIVE_INFINITY].filter((n) => Number.isFinite(n) && n > 0);
113
+ if (limits.length === 0)
114
+ return exports.AGENT_HEAP_FLOOR_MB;
115
+ const quarterMb = Math.floor(Math.min(...limits) / BYTES_PER_MB / 4);
116
+ return Math.min(exports.AGENT_HEAP_CAP_MB, Math.max(exports.AGENT_HEAP_FLOOR_MB, quarterMb));
117
+ }
118
+ function planLaunch(input) {
119
+ const warnings = [];
120
+ let source = input.role === 'agent' ? 'computed' : 'v8-default';
121
+ let heapMb = input.role === 'agent' ? computedAgentHeapMb(input.host) : null;
122
+ const legacy = input.legacyEnv;
123
+ if (legacy !== undefined && legacy !== '') {
124
+ const mb = /^[1-9][0-9]*$/.test(legacy) ? Number(legacy) : Number.NaN;
125
+ if (validMb(mb)) {
126
+ source = 'legacy-env';
127
+ heapMb = mb;
128
+ }
129
+ else {
130
+ warnings.push(`ignoring the legacy heap env "${legacy}": not an integer in ${exports.OVERRIDE_MIN_MB}-${exports.OVERRIDE_MAX_MB} MB`);
131
+ }
132
+ }
133
+ if (input.overrideMb !== null) {
134
+ if (validMb(input.overrideMb)) {
135
+ source = 'override';
136
+ heapMb = input.overrideMb;
137
+ }
138
+ else {
139
+ warnings.push(`ignoring the heap override ${input.overrideMb}: not an integer in ${exports.OVERRIDE_MIN_MB}-${exports.OVERRIDE_MAX_MB} MB`);
140
+ }
141
+ }
142
+ return {
143
+ args: heapMb === null ? [] : [`--max-old-space-size=${heapMb}`],
144
+ env: {
145
+ [exports.HEAP_CEILING_SOURCE_ENV]: source,
146
+ ...(input.allocatorEnv ? exports.ALLOCATOR_ENV_DEFAULTS : {}),
147
+ },
148
+ source,
149
+ warnings,
150
+ };
151
+ }
152
+ function renderLaunchPlan(plan) {
153
+ const lines = [
154
+ ...plan.args.map((a) => `arg ${a}`),
155
+ ...Object.entries(plan.env).map(([k, v]) => `env ${k}=${v}`),
156
+ `source ${plan.source}`,
157
+ ...plan.warnings.map((w) => `warn ${w.replace(/[\r\n]+/g, ' ')}`),
158
+ ];
159
+ return `${lines.join('\n')}\n`;
160
+ }
161
+ const realFs = {
162
+ readFile(file) {
163
+ try {
164
+ return fs.readFileSync(file, 'utf8');
165
+ }
166
+ catch {
167
+ return null;
168
+ }
169
+ },
170
+ };
171
+ function overridesPath(dataDir) {
172
+ return path.join(dataDir, exports.LAUNCH_OVERRIDES_FILE);
173
+ }
174
+ /** The persisted heap override in MB; `null` when absent, unreadable or not a number. */
175
+ function readHeapOverrideMb(dataDir, io = realFs) {
176
+ const raw = io.readFile(overridesPath(dataDir));
177
+ if (raw === null)
178
+ return null;
179
+ try {
180
+ const parsed = JSON.parse(raw);
181
+ if (typeof parsed !== 'object' || parsed === null || !('heapMb' in parsed))
182
+ return null;
183
+ const value = parsed.heapMb;
184
+ return typeof value === 'number' ? value : null;
185
+ }
186
+ catch {
187
+ return null;
188
+ }
189
+ }
190
+ /**
191
+ * Persist (or, with `null`, clear) the heap override. Validated against the same
192
+ * range the launcher enforces, so a value the next launch would ignore is refused
193
+ * here instead of silently doing nothing. Written atomically (temp + rename).
194
+ */
195
+ function writeHeapOverrideMb(dataDir, heapMb) {
196
+ const file = overridesPath(dataDir);
197
+ if (heapMb === null) {
198
+ fs.rmSync(file, { force: true });
199
+ return;
200
+ }
201
+ if (!validMb(heapMb)) {
202
+ throw new Error(`heap override must be an integer in ${exports.OVERRIDE_MIN_MB}-${exports.OVERRIDE_MAX_MB} MB, got ${heapMb}`);
203
+ }
204
+ fs.mkdirSync(dataDir, { recursive: true });
205
+ const tmp = `${file}.${process.pid}.tmp`;
206
+ fs.writeFileSync(tmp, `${JSON.stringify({ heapMb })}\n`, { mode: 0o600 });
207
+ fs.renameSync(tmp, file);
208
+ }
209
+ function readCgroupLimitBytes(io = realFs, files) {
210
+ for (const file of files ?? [
211
+ '/sys/fs/cgroup/memory.max',
212
+ '/sys/fs/cgroup/memory/memory.limit_in_bytes',
213
+ ]) {
214
+ const raw = io.readFile(file)?.trim();
215
+ if (raw === undefined || !/^[0-9]+$/.test(raw))
216
+ continue;
217
+ const bytes = Number(raw);
218
+ if (bytes > 0 && bytes < CGROUP_UNLIMITED_BYTES)
219
+ return bytes;
220
+ }
221
+ return null;
222
+ }
223
+ function parseRole(argv) {
224
+ const i = argv.indexOf('--role');
225
+ const value = i >= 0 ? argv[i + 1] : undefined;
226
+ return value === 'hub' || value === 'agent' ? value : null;
227
+ }
228
+ /** Run the CLI; returns the stdout text and the exit code. Never throws. */
229
+ function runLaunchCli(argv, deps) {
230
+ const role = parseRole(argv);
231
+ if (role === null)
232
+ return { stdout: '', code: 2 };
233
+ const dataDir = path.resolve(deps.env['CAMSTACK_DATA'] ?? 'camstack-data');
234
+ const legacyName = role === 'hub' ? 'CAMSTACK_HUB_HEAP_MB' : 'CAMSTACK_AGENT_HEAP_MB';
235
+ const plan = planLaunch({
236
+ role,
237
+ host: {
238
+ totalMemBytes: deps.totalMemBytes,
239
+ cgroupLimitBytes: readCgroupLimitBytes(deps.io, deps.cgroupFiles),
240
+ },
241
+ overrideMb: readHeapOverrideMb(dataDir, deps.io),
242
+ legacyEnv: deps.env[legacyName],
243
+ allocatorEnv: argv.includes('--allocator-env'),
244
+ });
245
+ return { stdout: renderLaunchPlan(plan), code: 0 };
246
+ }
247
+ if (require.main === module) {
248
+ const result = runLaunchCli(process.argv.slice(2), {
249
+ env: process.env,
250
+ io: realFs,
251
+ totalMemBytes: os.totalmem(),
252
+ });
253
+ process.stdout.write(result.stdout);
254
+ process.exitCode = result.code;
255
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.2.689",
3
+ "version": "1.2.690",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,7 +24,8 @@
24
24
  "./package.json": "./package.json",
25
25
  "./main.js": "./dist/main.js",
26
26
  "./launcher.js": "./dist/launcher.js",
27
- "./starter.js": "./dist/starter.js"
27
+ "./starter.js": "./dist/starter.js",
28
+ "./launch-args.js": "./dist/launch-args.js"
28
29
  },
29
30
  "scripts": {
30
31
  "build": "../../scripts/tsc7 -p tsconfig.build.json && tsup && node scripts/copy-closure-patches.mjs",
@@ -49,10 +50,10 @@
49
50
  ]
50
51
  },
51
52
  "dependencies": {
52
- "@camstack/addon-admin-ui": "1.2.517",
53
- "@camstack/addon-agent-ui": "1.2.292",
53
+ "@camstack/addon-admin-ui": "1.2.518",
54
+ "@camstack/addon-agent-ui": "1.2.293",
54
55
  "@camstack/addon-auth": "1.2.170",
55
- "@camstack/addon-benchmark": "1.2.291",
56
+ "@camstack/addon-benchmark": "1.2.292",
56
57
  "@camstack/addon-decoder-nodeav": "1.2.144",
57
58
  "@camstack/addon-notifiers": "1.2.623",
58
59
  "@camstack/addon-pipeline": "1.2.634",
@@ -60,9 +61,9 @@
60
61
  "@camstack/addon-post-analysis": "1.2.651",
61
62
  "@camstack/develop": "0.1.39",
62
63
  "@camstack/sdk": "1.2.154",
63
- "@camstack/system": "1.2.518",
64
- "@camstack/types": "1.2.444",
65
- "@camstack/ui-library": "1.2.350",
64
+ "@camstack/system": "1.2.519",
65
+ "@camstack/types": "1.2.445",
66
+ "@camstack/ui-library": "1.2.351",
66
67
  "@fastify/compress": "^9.0.0",
67
68
  "@fastify/cookie": "^11.0.2",
68
69
  "@fastify/cors": "^11.2.0",