@camstack/system 1.0.6 → 1.0.8
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/addon-runner.js +40 -23
- package/dist/addon-runner.mjs +20 -4
- package/dist/addon-utils.d.ts +20 -0
- package/dist/addon-utils.js +11 -0
- package/dist/addon-utils.mjs +3 -0
- package/dist/builtins/device-manager/device-manager.addon.js +8 -8
- package/dist/builtins/device-manager/device-manager.addon.mjs +8 -8
- package/dist/builtins/native-metrics/native-metrics.addon.d.ts +8 -0
- package/dist/builtins/native-metrics/native-metrics.addon.js +50 -3
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +50 -3
- package/dist/builtins/platform-probe/index.js +27 -139
- package/dist/builtins/platform-probe/index.mjs +28 -140
- package/dist/builtins/platform-probe/platform-scorer.d.ts +17 -10
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +2 -2
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +2 -2
- package/dist/custom-action-registry-BEXwC-oo.mjs +38 -0
- package/dist/custom-action-registry-vLYEFTtv.js +43 -0
- package/dist/index.js +129 -779
- package/dist/index.mjs +100 -750
- package/dist/kernel/config-manager.d.ts +4 -4
- package/dist/kernel/fs-utils.d.ts +16 -6
- package/dist/kernel/index.d.ts +1 -1
- package/dist/kernel/moleculer/device-cap-proxy.d.ts +2 -1
- package/dist/kernel/moleculer/readiness-context.d.ts +2 -1
- package/dist/kernel/transport/child-cap-protocol.d.ts +10 -0
- package/dist/{manifest-python-deps-B4BmMoGT.js → manifest-python-deps-BWURo7dc.js} +62 -88
- package/dist/{manifest-python-deps-CXbKrOdk.mjs → manifest-python-deps-BcrTzHH_.mjs} +55 -75
- package/dist/model-download-service-C7AjBsX9.mjs +668 -0
- package/dist/model-download-service-JtVQtbb6.js +752 -0
- package/dist/process/resource-monitor.d.ts +9 -0
- package/dist/{resource-monitor-ClDGFyf6.mjs → resource-monitor-BkP504Vq.mjs} +20 -1
- package/dist/{resource-monitor-IIEanuJt.js → resource-monitor-DNNomR-i.js} +21 -1
- package/package.json +6 -1
package/dist/addon-runner.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
2
|
-
const require_manifest_python_deps = require("./manifest-python-deps-
|
|
2
|
+
const require_manifest_python_deps = require("./manifest-python-deps-BWURo7dc.js");
|
|
3
|
+
const require_custom_action_registry = require("./custom-action-registry-vLYEFTtv.js");
|
|
3
4
|
let node_fs = require("node:fs");
|
|
4
5
|
node_fs = require_chunk.__toESM(node_fs);
|
|
5
6
|
let node_path = require("node:path");
|
|
6
7
|
node_path = require_chunk.__toESM(node_path);
|
|
7
|
-
let
|
|
8
|
+
let _camstack_types_addon = require("@camstack/types/addon");
|
|
8
9
|
let node_url = require("node:url");
|
|
10
|
+
let node_v8 = require("node:v8");
|
|
11
|
+
node_v8 = require_chunk.__toESM(node_v8);
|
|
9
12
|
let node_module = require("node:module");
|
|
10
13
|
//#region src/kernel/moleculer/worker-device-restore.ts
|
|
11
14
|
/**
|
|
@@ -41,7 +44,7 @@ async function runWorkerDeviceRestoreWithRetry(addon, context, addonId, sourceNo
|
|
|
41
44
|
return;
|
|
42
45
|
}
|
|
43
46
|
const shared = context.kernel?.readinessRegistry ?? null;
|
|
44
|
-
const registry = shared ?? new
|
|
47
|
+
const registry = shared ?? new _camstack_types_addon.ReadinessRegistry({
|
|
45
48
|
eventBus: bus,
|
|
46
49
|
sourceNodeId,
|
|
47
50
|
logger: context.logger
|
|
@@ -54,13 +57,13 @@ async function runWorkerDeviceRestoreWithRetry(addon, context, addonId, sourceNo
|
|
|
54
57
|
}, { timeoutMs: 6e4 });
|
|
55
58
|
log?.debug?.(`[worker-restore] "${addonId}": device-manager READY`);
|
|
56
59
|
} catch (err) {
|
|
57
|
-
if (err instanceof
|
|
60
|
+
if (err instanceof _camstack_types_addon.ReadinessTimeoutError) {
|
|
58
61
|
context.logger?.warn?.(`[worker-restore] device-manager not ready within ${err.waitedMs}ms — skipping for "${addonId}"`);
|
|
59
62
|
return;
|
|
60
63
|
}
|
|
61
64
|
throw err;
|
|
62
65
|
} finally {
|
|
63
|
-
if (!shared && registry instanceof
|
|
66
|
+
if (!shared && registry instanceof _camstack_types_addon.ReadinessRegistry) registry.close();
|
|
64
67
|
}
|
|
65
68
|
try {
|
|
66
69
|
const deviceManager = Reflect.get(api, "deviceManager");
|
|
@@ -86,7 +89,7 @@ async function runWorkerDeviceRestoreWithRetry(addon, context, addonId, sourceNo
|
|
|
86
89
|
await restoreFn.call(addon, savedDevices);
|
|
87
90
|
log?.info?.(`[worker-restore] "${addonId}": restored ${savedDevices.length} device(s)`);
|
|
88
91
|
} catch (err) {
|
|
89
|
-
log?.warn?.(`[worker-restore] "${addonId}": restoreDevices threw: ${(0,
|
|
92
|
+
log?.warn?.(`[worker-restore] "${addonId}": restoreDevices threw: ${(0, _camstack_types_addon.errMsg)(err)}`);
|
|
90
93
|
}
|
|
91
94
|
}
|
|
92
95
|
//#endregion
|
|
@@ -167,10 +170,10 @@ function toSerializableRoute(route) {
|
|
|
167
170
|
*/
|
|
168
171
|
async function dispatchSettings(addon, addonId, method, args) {
|
|
169
172
|
switch (method) {
|
|
170
|
-
case "getGlobalSettings": return typeof addon.getGlobalSettings === "function" ? await addon.getGlobalSettings(args.overlay, args.cap) ?? null : null;
|
|
173
|
+
case "getGlobalSettings": return typeof addon.getGlobalSettings === "function" ? await addon.getGlobalSettings(args.overlay, args.cap, args.nodeId) ?? null : null;
|
|
171
174
|
case "updateGlobalSettings":
|
|
172
175
|
if (typeof addon.updateGlobalSettings !== "function") throw new Error(`child-addon-call: addon "${addonId}" does not implement updateGlobalSettings`);
|
|
173
|
-
await addon.updateGlobalSettings(args.patch ?? {});
|
|
176
|
+
await addon.updateGlobalSettings(args.patch ?? {}, args.nodeId);
|
|
174
177
|
return { success: true };
|
|
175
178
|
case "getDeviceSettings": return typeof addon.getDeviceSettings === "function" && typeof args.deviceId === "number" ? await addon.getDeviceSettings(args.deviceId) ?? null : null;
|
|
176
179
|
case "updateDeviceSettings":
|
|
@@ -272,11 +275,11 @@ function createChildAddonCallDispatch(deps) {
|
|
|
272
275
|
* every loaded addon before closing the UDS channel.
|
|
273
276
|
*/
|
|
274
277
|
process.on("uncaughtException", (err) => {
|
|
275
|
-
console.error(`[addon-runner CRASH] uncaughtException: ${(0,
|
|
278
|
+
console.error(`[addon-runner CRASH] uncaughtException: ${(0, _camstack_types_addon.errMsg)(err)}\n${err instanceof Error ? err.stack ?? "" : ""}`);
|
|
276
279
|
process.exit(1);
|
|
277
280
|
});
|
|
278
281
|
process.on("unhandledRejection", (reason) => {
|
|
279
|
-
console.error(`[addon-runner CRASH] unhandledRejection: ${(0,
|
|
282
|
+
console.error(`[addon-runner CRASH] unhandledRejection: ${(0, _camstack_types_addon.errMsg)(reason)}\n${reason instanceof Error ? reason.stack ?? "" : ""}`);
|
|
280
283
|
});
|
|
281
284
|
process.on("exit", (code) => {
|
|
282
285
|
console.error(`[addon-runner EXIT] code=${String(code)} nodeId=${process.env["CAMSTACK_RUNNER_ID"] ?? "?"}`);
|
|
@@ -297,7 +300,7 @@ function parseAddonsSpec(raw) {
|
|
|
297
300
|
try {
|
|
298
301
|
parsed = JSON.parse(raw);
|
|
299
302
|
} catch (err) {
|
|
300
|
-
throw new Error(`[addon-runner] CAMSTACK_RUNNER_ADDONS is not valid JSON: ${(0,
|
|
303
|
+
throw new Error(`[addon-runner] CAMSTACK_RUNNER_ADDONS is not valid JSON: ${(0, _camstack_types_addon.errMsg)(err)}`, { cause: err });
|
|
301
304
|
}
|
|
302
305
|
if (!Array.isArray(parsed)) throw new Error(`[addon-runner] CAMSTACK_RUNNER_ADDONS must be a JSON array`);
|
|
303
306
|
const specs = [];
|
|
@@ -370,7 +373,7 @@ async function main() {
|
|
|
370
373
|
try {
|
|
371
374
|
specs = parseAddonsSpec(addonsJson);
|
|
372
375
|
} catch (err) {
|
|
373
|
-
console.error((0,
|
|
376
|
+
console.error((0, _camstack_types_addon.errMsg)(err));
|
|
374
377
|
process.exit(1);
|
|
375
378
|
}
|
|
376
379
|
if (specs.length === 0) {
|
|
@@ -393,7 +396,7 @@ async function main() {
|
|
|
393
396
|
AddonClass
|
|
394
397
|
});
|
|
395
398
|
} catch (err) {
|
|
396
|
-
console.error(`[addon-runner] Failed to load "${spec.addonId}": ${(0,
|
|
399
|
+
console.error(`[addon-runner] Failed to load "${spec.addonId}": ${(0, _camstack_types_addon.errMsg)(err)}`);
|
|
397
400
|
process.exit(1);
|
|
398
401
|
}
|
|
399
402
|
let storageProvider;
|
|
@@ -463,7 +466,7 @@ async function main() {
|
|
|
463
466
|
* removed `custom.<action>` Moleculer action). Constructed up front so the
|
|
464
467
|
* addon-call handler can close over it at client-construction time.
|
|
465
468
|
*/
|
|
466
|
-
const customActionRegistry = new
|
|
469
|
+
const customActionRegistry = new require_custom_action_registry.CustomActionRegistry();
|
|
467
470
|
let shuttingDown = false;
|
|
468
471
|
const udsChildClient = new require_manifest_python_deps.LocalChildClient({
|
|
469
472
|
nodeId: parentNodeId,
|
|
@@ -488,12 +491,12 @@ async function main() {
|
|
|
488
491
|
try {
|
|
489
492
|
await udsChildClient.start();
|
|
490
493
|
} catch (err) {
|
|
491
|
-
console.error(`[addon-runner] "${nodeId}" UDS connect failed — exiting: ${(0,
|
|
494
|
+
console.error(`[addon-runner] "${nodeId}" UDS connect failed — exiting: ${(0, _camstack_types_addon.errMsg)(err)}`);
|
|
492
495
|
process.exit(1);
|
|
493
496
|
}
|
|
494
497
|
runnerLog.info("UDS child transport connected", { meta: { childId: runnerId } });
|
|
495
498
|
if (storageProvider) runnerLog.info(`"${nodeId}" storage provider rooted at ${dataDir}`);
|
|
496
|
-
else runnerLog.warn(`"${nodeId}" failed to load FilesystemStorageProvider`, { meta: { error: (0,
|
|
499
|
+
else runnerLog.warn(`"${nodeId}" failed to load FilesystemStorageProvider`, { meta: { error: (0, _camstack_types_addon.errMsg)(storageProviderError) } });
|
|
497
500
|
const refreshChildCaps = (reason) => {
|
|
498
501
|
const freshDescriptors = buildChildCapDescriptors(runnerManifest, require_manifest_python_deps.getWorkerNativeCapSnapshot());
|
|
499
502
|
udsChildClient.updateCaps(freshDescriptors).catch((err) => {
|
|
@@ -523,12 +526,12 @@ async function main() {
|
|
|
523
526
|
const pkgRaw = JSON.parse(node_fs.readFileSync(node_path.join(spec.addonDir, "package.json"), "utf-8"));
|
|
524
527
|
await require_manifest_python_deps.installManifestNativeDeps(spec.addonDir, pkgRaw, context.logger);
|
|
525
528
|
} catch (nativeErr) {
|
|
526
|
-
console.error(`[addon-runner] native deps install failed for "${spec.addonId}": ${(0,
|
|
529
|
+
console.error(`[addon-runner] native deps install failed for "${spec.addonId}": ${(0, _camstack_types_addon.errMsg)(nativeErr)}`);
|
|
527
530
|
process.exit(1);
|
|
528
531
|
}
|
|
529
532
|
await require_manifest_python_deps.installManifestPythonDeps(declaration, spec.addonDir, context.deps, context.logger);
|
|
530
533
|
const registeredProviders = /* @__PURE__ */ new Map();
|
|
531
|
-
const initResult = (0,
|
|
534
|
+
const initResult = (0, _camstack_types_addon.normalizeAddonInitResult)(await addon.initialize(context));
|
|
532
535
|
for (const reg of initResult?.providers ?? []) {
|
|
533
536
|
const capName = reg.capability.name;
|
|
534
537
|
registeredProviders.set(capName, reg.provider);
|
|
@@ -564,7 +567,7 @@ async function main() {
|
|
|
564
567
|
initResult: initResult ?? null
|
|
565
568
|
});
|
|
566
569
|
} catch (err) {
|
|
567
|
-
console.error(`[addon-runner] Init failed for "${spec.addonId}": ${(0,
|
|
570
|
+
console.error(`[addon-runner] Init failed for "${spec.addonId}": ${(0, _camstack_types_addon.errMsg)(err)}`);
|
|
568
571
|
process.exit(1);
|
|
569
572
|
}
|
|
570
573
|
if (deviceRestorePromises.length > 0 && !shuttingDown) await Promise.allSettled(deviceRestorePromises);
|
|
@@ -574,7 +577,7 @@ async function main() {
|
|
|
574
577
|
if (hubReachableFired) return;
|
|
575
578
|
hubReachableFired = true;
|
|
576
579
|
for (const entry of loaded) if (typeof entry.addon.onHubReachable === "function") Promise.resolve(entry.addon.onHubReachable()).catch((err) => {
|
|
577
|
-
runnerLog.error(`"${entry.addonId}" onHubReachable() threw`, { meta: { error: (0,
|
|
580
|
+
runnerLog.error(`"${entry.addonId}" onHubReachable() threw`, { meta: { error: (0, _camstack_types_addon.errMsg)(err) } });
|
|
578
581
|
});
|
|
579
582
|
};
|
|
580
583
|
udsChildClient.onConnected(() => {
|
|
@@ -584,6 +587,20 @@ async function main() {
|
|
|
584
587
|
fireHubReachableOnce();
|
|
585
588
|
runnerLog.info(`"${nodeId}" started — ${loaded.length} addon(s) ready (UDS connected)`);
|
|
586
589
|
process.stdout.write(`READY:${nodeId}\n`);
|
|
590
|
+
process.on("SIGUSR2", () => {
|
|
591
|
+
const MB = (x) => Math.round(x / 1048576 * 10) / 10;
|
|
592
|
+
try {
|
|
593
|
+
const mu = process.memoryUsage();
|
|
594
|
+
const spaces = node_v8.getHeapSpaceStatistics().filter((s) => s.space_used_size > 0).map((s) => `${s.space_name}=${MB(s.space_used_size)}`).join(" ");
|
|
595
|
+
const addons = loaded.map((e) => e.addonId).join(",");
|
|
596
|
+
runnerLog.info(`[mem] node="${nodeId}" addons=[${addons}] rss=${MB(mu.rss)} heapUsed=${MB(mu.heapUsed)} heapTotal=${MB(mu.heapTotal)} external=${MB(mu.external)} arrayBuffers=${MB(mu.arrayBuffers)} | ${spaces}`);
|
|
597
|
+
const snapPath = `/tmp/heap-${nodeId.replace(/[^\w.-]/g, "_")}.heapsnapshot`;
|
|
598
|
+
node_v8.writeHeapSnapshot(snapPath);
|
|
599
|
+
runnerLog.info(`[mem] node="${nodeId}" heap snapshot written -> ${snapPath}`);
|
|
600
|
+
} catch (err) {
|
|
601
|
+
runnerLog.warn(`[mem] snapshot failed: ${(0, _camstack_types_addon.errMsg)(err)}`);
|
|
602
|
+
}
|
|
603
|
+
});
|
|
587
604
|
const shutdown = async () => {
|
|
588
605
|
shuttingDown = true;
|
|
589
606
|
require_manifest_python_deps.setWorkerNativeCapsChangeListener(null);
|
|
@@ -595,12 +612,12 @@ async function main() {
|
|
|
595
612
|
for (const entry of loaded) try {
|
|
596
613
|
await entry.addon.shutdown();
|
|
597
614
|
} catch (err) {
|
|
598
|
-
runnerLog.error(`"${entry.addonId}" shutdown threw`, { meta: { error: (0,
|
|
615
|
+
runnerLog.error(`"${entry.addonId}" shutdown threw`, { meta: { error: (0, _camstack_types_addon.errMsg)(err) } });
|
|
599
616
|
}
|
|
600
617
|
try {
|
|
601
618
|
await udsChildClient.close();
|
|
602
619
|
} catch (err) {
|
|
603
|
-
runnerLog.warn("UDS child transport close threw during shutdown", { meta: { error: (0,
|
|
620
|
+
runnerLog.warn("UDS child transport close threw during shutdown", { meta: { error: (0, _camstack_types_addon.errMsg)(err) } });
|
|
604
621
|
}
|
|
605
622
|
process.exit(0);
|
|
606
623
|
};
|
|
@@ -619,7 +636,7 @@ async function main() {
|
|
|
619
636
|
}, 5e3);
|
|
620
637
|
}
|
|
621
638
|
main().catch((err) => {
|
|
622
|
-
console.error(`[addon-runner] Fatal error: ${(0,
|
|
639
|
+
console.error(`[addon-runner] Fatal error: ${(0, _camstack_types_addon.errMsg)(err)}`);
|
|
623
640
|
process.exit(1);
|
|
624
641
|
});
|
|
625
642
|
//#endregion
|
package/dist/addon-runner.mjs
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { $ as setWorkerNativeCapsChangeListener, A as createUdsLoggerWithControl, L as LocalChildClient, X as getWorkerNativeCapProvider, Z as getWorkerNativeCapSnapshot,
|
|
1
|
+
import { $ as setWorkerNativeCapsChangeListener, A as createUdsLoggerWithControl, L as LocalChildClient, X as getWorkerNativeCapProvider, Z as getWorkerNativeCapSnapshot, i as createUdsAddonContext, mt as resolveAddonClass, pt as installManifestNativeDeps, t as installManifestPythonDeps, tt as validateProviderRegistrations } from "./manifest-python-deps-BcrTzHH_.mjs";
|
|
2
|
+
import { t as CustomActionRegistry } from "./custom-action-registry-BEXwC-oo.mjs";
|
|
2
3
|
import { register } from "node:module";
|
|
3
4
|
import * as fs from "node:fs";
|
|
4
5
|
import * as path$1 from "node:path";
|
|
5
|
-
import { ReadinessRegistry, ReadinessTimeoutError, errMsg, normalizeAddonInitResult } from "@camstack/types";
|
|
6
|
+
import { ReadinessRegistry, ReadinessTimeoutError, errMsg, normalizeAddonInitResult } from "@camstack/types/addon";
|
|
6
7
|
import { pathToFileURL } from "node:url";
|
|
8
|
+
import * as v8 from "node:v8";
|
|
7
9
|
//#region src/kernel/moleculer/worker-device-restore.ts
|
|
8
10
|
/**
|
|
9
11
|
* Worker-side device restore helper.
|
|
@@ -164,10 +166,10 @@ function toSerializableRoute(route) {
|
|
|
164
166
|
*/
|
|
165
167
|
async function dispatchSettings(addon, addonId, method, args) {
|
|
166
168
|
switch (method) {
|
|
167
|
-
case "getGlobalSettings": return typeof addon.getGlobalSettings === "function" ? await addon.getGlobalSettings(args.overlay, args.cap) ?? null : null;
|
|
169
|
+
case "getGlobalSettings": return typeof addon.getGlobalSettings === "function" ? await addon.getGlobalSettings(args.overlay, args.cap, args.nodeId) ?? null : null;
|
|
168
170
|
case "updateGlobalSettings":
|
|
169
171
|
if (typeof addon.updateGlobalSettings !== "function") throw new Error(`child-addon-call: addon "${addonId}" does not implement updateGlobalSettings`);
|
|
170
|
-
await addon.updateGlobalSettings(args.patch ?? {});
|
|
172
|
+
await addon.updateGlobalSettings(args.patch ?? {}, args.nodeId);
|
|
171
173
|
return { success: true };
|
|
172
174
|
case "getDeviceSettings": return typeof addon.getDeviceSettings === "function" && typeof args.deviceId === "number" ? await addon.getDeviceSettings(args.deviceId) ?? null : null;
|
|
173
175
|
case "updateDeviceSettings":
|
|
@@ -581,6 +583,20 @@ async function main() {
|
|
|
581
583
|
fireHubReachableOnce();
|
|
582
584
|
runnerLog.info(`"${nodeId}" started — ${loaded.length} addon(s) ready (UDS connected)`);
|
|
583
585
|
process.stdout.write(`READY:${nodeId}\n`);
|
|
586
|
+
process.on("SIGUSR2", () => {
|
|
587
|
+
const MB = (x) => Math.round(x / 1048576 * 10) / 10;
|
|
588
|
+
try {
|
|
589
|
+
const mu = process.memoryUsage();
|
|
590
|
+
const spaces = v8.getHeapSpaceStatistics().filter((s) => s.space_used_size > 0).map((s) => `${s.space_name}=${MB(s.space_used_size)}`).join(" ");
|
|
591
|
+
const addons = loaded.map((e) => e.addonId).join(",");
|
|
592
|
+
runnerLog.info(`[mem] node="${nodeId}" addons=[${addons}] rss=${MB(mu.rss)} heapUsed=${MB(mu.heapUsed)} heapTotal=${MB(mu.heapTotal)} external=${MB(mu.external)} arrayBuffers=${MB(mu.arrayBuffers)} | ${spaces}`);
|
|
593
|
+
const snapPath = `/tmp/heap-${nodeId.replace(/[^\w.-]/g, "_")}.heapsnapshot`;
|
|
594
|
+
v8.writeHeapSnapshot(snapPath);
|
|
595
|
+
runnerLog.info(`[mem] node="${nodeId}" heap snapshot written -> ${snapPath}`);
|
|
596
|
+
} catch (err) {
|
|
597
|
+
runnerLog.warn(`[mem] snapshot failed: ${errMsg(err)}`);
|
|
598
|
+
}
|
|
599
|
+
});
|
|
584
600
|
const shutdown = async () => {
|
|
585
601
|
shuttingDown = true;
|
|
586
602
|
setWorkerNativeCapsChangeListener(null);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight addon-facing utility surface for `@camstack/system`.
|
|
3
|
+
*
|
|
4
|
+
* Importing the root barrel (`@camstack/system`) loads the ENTIRE framework —
|
|
5
|
+
* the kernel (moleculer) + every builtin addon (sqlite-storage, winston-logging,
|
|
6
|
+
* device-manager, …) — ~64MB of V8 heap PER process, even when an addon only
|
|
7
|
+
* needs a model-download or data-plane helper. Node has no runtime tree-shaking
|
|
8
|
+
* and the package is host-provided (loaded as the prebuilt barrel), so every
|
|
9
|
+
* addon that imported one util from the barrel paid the full ~64MB — multiplied
|
|
10
|
+
* across every forked pipeline runner.
|
|
11
|
+
*
|
|
12
|
+
* This subpath re-exports ONLY the addon-facing helpers, each from its DEEP,
|
|
13
|
+
* kernel-free source module, so importing it costs a few MB instead of ~64MB.
|
|
14
|
+
*
|
|
15
|
+
* See memory: camstack_runner_ram_and_build_rootcause.
|
|
16
|
+
*/
|
|
17
|
+
export { downloadFile, ensureModel, isModelDownloaded, deleteModelFromDisk, } from './download/model-downloader.js';
|
|
18
|
+
export { ModelDownloadService } from './download/model-download-service.js';
|
|
19
|
+
export { createFileDataPlaneHandler } from './http/file-data-plane.js';
|
|
20
|
+
export { CustomActionRegistry } from './kernel/custom-action-registry.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
require("./chunk-Cek0wNdY.js");
|
|
3
|
+
const require_model_download_service = require("./model-download-service-JtVQtbb6.js");
|
|
4
|
+
const require_custom_action_registry = require("./custom-action-registry-vLYEFTtv.js");
|
|
5
|
+
exports.CustomActionRegistry = require_custom_action_registry.CustomActionRegistry;
|
|
6
|
+
exports.ModelDownloadService = require_model_download_service.ModelDownloadService;
|
|
7
|
+
exports.createFileDataPlaneHandler = require_model_download_service.createFileDataPlaneHandler;
|
|
8
|
+
exports.deleteModelFromDisk = require_model_download_service.deleteModelFromDisk;
|
|
9
|
+
exports.downloadFile = require_model_download_service.downloadFile;
|
|
10
|
+
exports.ensureModel = require_model_download_service.ensureModel;
|
|
11
|
+
exports.isModelDownloaded = require_model_download_service.isModelDownloaded;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { a as ensureModel, c as isModelDownloaded, l as createFileDataPlaneHandler, n as deleteModelFromDisk, r as downloadFile, t as ModelDownloadService } from "./model-download-service-C7AjBsX9.mjs";
|
|
2
|
+
import { t as CustomActionRegistry } from "./custom-action-registry-BEXwC-oo.mjs";
|
|
3
|
+
export { CustomActionRegistry, ModelDownloadService, createFileDataPlaneHandler, deleteModelFromDisk, downloadFile, ensureModel, isModelDownloaded };
|
|
@@ -1638,8 +1638,8 @@ var DeviceManagerAddon = class DeviceManagerAddon extends _camstack_types.BaseAd
|
|
|
1638
1638
|
if (!persisted) return null;
|
|
1639
1639
|
const links = (persisted.meta.deviceLinks ?? []).filter((l) => l.target.cap === cap);
|
|
1640
1640
|
if (links.length === 0) return null;
|
|
1641
|
-
const
|
|
1642
|
-
const schema =
|
|
1641
|
+
const capRegistry = this.capabilityRegistry;
|
|
1642
|
+
const schema = capRegistry?.getDefinition(cap)?.status?.schema;
|
|
1643
1643
|
if (!schema) return null;
|
|
1644
1644
|
const allMeta = await readMeta();
|
|
1645
1645
|
let containerStableId = persisted.stableId;
|
|
@@ -1655,7 +1655,7 @@ var DeviceManagerAddon = class DeviceManagerAddon extends _camstack_types.BaseAd
|
|
|
1655
1655
|
const srcId = resolveSourceDeviceId(containerStableId, link.source.sourceKey, allMeta);
|
|
1656
1656
|
if (srcId === null) continue;
|
|
1657
1657
|
try {
|
|
1658
|
-
const srcProvider =
|
|
1658
|
+
const srcProvider = capRegistry?.getProviderForDevice(link.source.cap, srcId);
|
|
1659
1659
|
const raw = (0, _camstack_types.getByPath)(typeof srcProvider?.getStatus === "function" ? await srcProvider.getStatus({ deviceId: srcId }) : void 0, link.source.fieldPath);
|
|
1660
1660
|
resolved.push({
|
|
1661
1661
|
link,
|
|
@@ -1840,7 +1840,7 @@ var DeviceManagerAddon = class DeviceManagerAddon extends _camstack_types.BaseAd
|
|
|
1840
1840
|
this.capabilityRegistry?.unregisterAllNativeForDevice(deviceId);
|
|
1841
1841
|
idToAddonId.delete(deviceId);
|
|
1842
1842
|
this.devicesWithLinks.delete(deviceId);
|
|
1843
|
-
for (const
|
|
1843
|
+
for (const overlayKey of this.lastEmittedOverlay.keys()) if (overlayKey.startsWith(`${deviceId}:`)) this.lastEmittedOverlay.delete(overlayKey);
|
|
1844
1844
|
await rebuildLinkDependents();
|
|
1845
1845
|
this.ctx.logger.info("removed device", { tags: {
|
|
1846
1846
|
deviceId,
|
|
@@ -2386,7 +2386,7 @@ var DeviceManagerAddon = class DeviceManagerAddon extends _camstack_types.BaseAd
|
|
|
2386
2386
|
listLocations: async () => {
|
|
2387
2387
|
const store = await settings.readAddonStore();
|
|
2388
2388
|
const meta = store.deviceMeta ?? {};
|
|
2389
|
-
const
|
|
2389
|
+
const locations = store.locations ?? [];
|
|
2390
2390
|
const seen = /* @__PURE__ */ new Map();
|
|
2391
2391
|
const consider = (raw) => {
|
|
2392
2392
|
if (typeof raw !== "string") return;
|
|
@@ -2395,7 +2395,7 @@ var DeviceManagerAddon = class DeviceManagerAddon extends _camstack_types.BaseAd
|
|
|
2395
2395
|
const key = trimmed.toLowerCase();
|
|
2396
2396
|
if (!seen.has(key)) seen.set(key, trimmed);
|
|
2397
2397
|
};
|
|
2398
|
-
for (const label of
|
|
2398
|
+
for (const label of locations) consider(label);
|
|
2399
2399
|
for (const m of Object.values(meta)) consider(m.location);
|
|
2400
2400
|
return [...seen.values()].toSorted((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
|
|
2401
2401
|
},
|
|
@@ -2960,9 +2960,9 @@ var DeviceManagerAddon = class DeviceManagerAddon extends _camstack_types.BaseAd
|
|
|
2960
2960
|
return this.getDeviceAggregate(input.deviceId, "live");
|
|
2961
2961
|
},
|
|
2962
2962
|
getDeviceAggregate: async (input) => {
|
|
2963
|
-
const [
|
|
2963
|
+
const [settingsAggregate, live] = await Promise.all([this.getDeviceAggregate(input.deviceId, "settings"), this.getDeviceAggregate(input.deviceId, "live")]);
|
|
2964
2964
|
return {
|
|
2965
|
-
settings,
|
|
2965
|
+
settings: settingsAggregate,
|
|
2966
2966
|
live
|
|
2967
2967
|
};
|
|
2968
2968
|
},
|
|
@@ -1633,8 +1633,8 @@ var DeviceManagerAddon = class DeviceManagerAddon extends BaseAddon {
|
|
|
1633
1633
|
if (!persisted) return null;
|
|
1634
1634
|
const links = (persisted.meta.deviceLinks ?? []).filter((l) => l.target.cap === cap);
|
|
1635
1635
|
if (links.length === 0) return null;
|
|
1636
|
-
const
|
|
1637
|
-
const schema =
|
|
1636
|
+
const capRegistry = this.capabilityRegistry;
|
|
1637
|
+
const schema = capRegistry?.getDefinition(cap)?.status?.schema;
|
|
1638
1638
|
if (!schema) return null;
|
|
1639
1639
|
const allMeta = await readMeta();
|
|
1640
1640
|
let containerStableId = persisted.stableId;
|
|
@@ -1650,7 +1650,7 @@ var DeviceManagerAddon = class DeviceManagerAddon extends BaseAddon {
|
|
|
1650
1650
|
const srcId = resolveSourceDeviceId(containerStableId, link.source.sourceKey, allMeta);
|
|
1651
1651
|
if (srcId === null) continue;
|
|
1652
1652
|
try {
|
|
1653
|
-
const srcProvider =
|
|
1653
|
+
const srcProvider = capRegistry?.getProviderForDevice(link.source.cap, srcId);
|
|
1654
1654
|
const raw = getByPath(typeof srcProvider?.getStatus === "function" ? await srcProvider.getStatus({ deviceId: srcId }) : void 0, link.source.fieldPath);
|
|
1655
1655
|
resolved.push({
|
|
1656
1656
|
link,
|
|
@@ -1835,7 +1835,7 @@ var DeviceManagerAddon = class DeviceManagerAddon extends BaseAddon {
|
|
|
1835
1835
|
this.capabilityRegistry?.unregisterAllNativeForDevice(deviceId);
|
|
1836
1836
|
idToAddonId.delete(deviceId);
|
|
1837
1837
|
this.devicesWithLinks.delete(deviceId);
|
|
1838
|
-
for (const
|
|
1838
|
+
for (const overlayKey of this.lastEmittedOverlay.keys()) if (overlayKey.startsWith(`${deviceId}:`)) this.lastEmittedOverlay.delete(overlayKey);
|
|
1839
1839
|
await rebuildLinkDependents();
|
|
1840
1840
|
this.ctx.logger.info("removed device", { tags: {
|
|
1841
1841
|
deviceId,
|
|
@@ -2381,7 +2381,7 @@ var DeviceManagerAddon = class DeviceManagerAddon extends BaseAddon {
|
|
|
2381
2381
|
listLocations: async () => {
|
|
2382
2382
|
const store = await settings.readAddonStore();
|
|
2383
2383
|
const meta = store.deviceMeta ?? {};
|
|
2384
|
-
const
|
|
2384
|
+
const locations = store.locations ?? [];
|
|
2385
2385
|
const seen = /* @__PURE__ */ new Map();
|
|
2386
2386
|
const consider = (raw) => {
|
|
2387
2387
|
if (typeof raw !== "string") return;
|
|
@@ -2390,7 +2390,7 @@ var DeviceManagerAddon = class DeviceManagerAddon extends BaseAddon {
|
|
|
2390
2390
|
const key = trimmed.toLowerCase();
|
|
2391
2391
|
if (!seen.has(key)) seen.set(key, trimmed);
|
|
2392
2392
|
};
|
|
2393
|
-
for (const label of
|
|
2393
|
+
for (const label of locations) consider(label);
|
|
2394
2394
|
for (const m of Object.values(meta)) consider(m.location);
|
|
2395
2395
|
return [...seen.values()].toSorted((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
|
|
2396
2396
|
},
|
|
@@ -2955,9 +2955,9 @@ var DeviceManagerAddon = class DeviceManagerAddon extends BaseAddon {
|
|
|
2955
2955
|
return this.getDeviceAggregate(input.deviceId, "live");
|
|
2956
2956
|
},
|
|
2957
2957
|
getDeviceAggregate: async (input) => {
|
|
2958
|
-
const [
|
|
2958
|
+
const [settingsAggregate, live] = await Promise.all([this.getDeviceAggregate(input.deviceId, "settings"), this.getDeviceAggregate(input.deviceId, "live")]);
|
|
2959
2959
|
return {
|
|
2960
|
-
settings,
|
|
2960
|
+
settings: settingsAggregate,
|
|
2961
2961
|
live
|
|
2962
2962
|
};
|
|
2963
2963
|
},
|
|
@@ -66,6 +66,14 @@ export default class NativeMetricsAddon extends BaseAddon<NativeMetricsConfig> {
|
|
|
66
66
|
* the dedicated `$process.restart` action, not this kill API.
|
|
67
67
|
*/
|
|
68
68
|
private killProcess;
|
|
69
|
+
/**
|
|
70
|
+
* Ask the addon's forked runner to write a V8 heap snapshot (SIGUSR2 → the
|
|
71
|
+
* runner's diagnostic handler in addon-runner.ts), for deep per-addon memory
|
|
72
|
+
* attribution. Resolves the addon's worker pid from the kernel `$process.list`
|
|
73
|
+
* and signals it; the runner writes `/tmp/heap-<sanitized nodeId>.heapsnapshot`
|
|
74
|
+
* and logs its memoryUsage + heap-space breakdown. '$hub' targets this process.
|
|
75
|
+
*/
|
|
76
|
+
private dumpHeapSnapshot;
|
|
69
77
|
/** Raw `ps` scan returning every pid + command + resource stats. */
|
|
70
78
|
private runPs;
|
|
71
79
|
protected globalSettingsSchema(): import('@camstack/types').ConfigUISchema;
|
|
@@ -123,13 +123,15 @@ var NativeMetricsProvider = class {
|
|
|
123
123
|
return getCpuTemperatureInternal();
|
|
124
124
|
}
|
|
125
125
|
async getProcessStats(input) {
|
|
126
|
-
const { getPidStats } = await Promise.resolve().then(() => require("../../resource-monitor-
|
|
126
|
+
const { getPidStats } = await Promise.resolve().then(() => require("../../resource-monitor-DNNomR-i.js")).then((n) => n.resource_monitor_exports);
|
|
127
127
|
const raw = await getPidStats(input.pids);
|
|
128
128
|
const result = [];
|
|
129
129
|
for (const [pid, s] of raw) result.push({
|
|
130
130
|
pid,
|
|
131
131
|
cpu: s.cpu,
|
|
132
|
-
memory: s.memory
|
|
132
|
+
memory: s.memory,
|
|
133
|
+
privateBytes: s.privateBytes,
|
|
134
|
+
sharedBytes: s.sharedBytes
|
|
133
135
|
});
|
|
134
136
|
return result;
|
|
135
137
|
}
|
|
@@ -596,7 +598,8 @@ var NativeMetricsAddon = class extends _camstack_types.BaseAddon {
|
|
|
596
598
|
listAddonInstances: () => this.listAddonInstances(),
|
|
597
599
|
getAddonStats: (params) => this.getAddonStats(params.addonId),
|
|
598
600
|
listNodeProcesses: () => this.listNodeProcesses(),
|
|
599
|
-
killProcess: (params) => this.killProcess(params)
|
|
601
|
+
killProcess: (params) => this.killProcess(params),
|
|
602
|
+
dumpHeapSnapshot: (params) => this.dumpHeapSnapshot(params)
|
|
600
603
|
};
|
|
601
604
|
this.snapshotTimer = setInterval(() => this.emitMetricsSnapshots(), METRICS_SNAPSHOT_INTERVAL_MS);
|
|
602
605
|
return [{
|
|
@@ -845,6 +848,50 @@ var NativeMetricsAddon = class extends _camstack_types.BaseAddon {
|
|
|
845
848
|
};
|
|
846
849
|
}
|
|
847
850
|
}
|
|
851
|
+
/**
|
|
852
|
+
* Ask the addon's forked runner to write a V8 heap snapshot (SIGUSR2 → the
|
|
853
|
+
* runner's diagnostic handler in addon-runner.ts), for deep per-addon memory
|
|
854
|
+
* attribution. Resolves the addon's worker pid from the kernel `$process.list`
|
|
855
|
+
* and signals it; the runner writes `/tmp/heap-<sanitized nodeId>.heapsnapshot`
|
|
856
|
+
* and logs its memoryUsage + heap-space breakdown. '$hub' targets this process.
|
|
857
|
+
*/
|
|
858
|
+
async dumpHeapSnapshot(input) {
|
|
859
|
+
const sanitize = (nodeId) => nodeId.replace(/[^\w.-]/g, "_");
|
|
860
|
+
let pid;
|
|
861
|
+
let nodeId;
|
|
862
|
+
if (input.addonId === "$hub") {
|
|
863
|
+
pid = process.pid;
|
|
864
|
+
nodeId = this.ctx.kernel.cluster?.broker?.nodeID ?? "$hub";
|
|
865
|
+
} else {
|
|
866
|
+
const target = (await this.listWorkerInstances()).find((w) => w.addonId === input.addonId);
|
|
867
|
+
if (!target) return {
|
|
868
|
+
success: false,
|
|
869
|
+
reason: `no runner process for addon '${input.addonId}'`
|
|
870
|
+
};
|
|
871
|
+
pid = target.pid;
|
|
872
|
+
nodeId = target.nodeId;
|
|
873
|
+
}
|
|
874
|
+
const path = `/tmp/heap-${sanitize(nodeId)}.heapsnapshot`;
|
|
875
|
+
try {
|
|
876
|
+
process.kill(pid, "SIGUSR2");
|
|
877
|
+
this.ctx.logger.info("Requested heap snapshot from runner", { meta: {
|
|
878
|
+
addonId: input.addonId,
|
|
879
|
+
pid,
|
|
880
|
+
path
|
|
881
|
+
} });
|
|
882
|
+
return {
|
|
883
|
+
success: true,
|
|
884
|
+
pid,
|
|
885
|
+
path
|
|
886
|
+
};
|
|
887
|
+
} catch (err) {
|
|
888
|
+
return {
|
|
889
|
+
success: false,
|
|
890
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
891
|
+
pid
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
}
|
|
848
895
|
/** Raw `ps` scan returning every pid + command + resource stats. */
|
|
849
896
|
async runPs() {
|
|
850
897
|
try {
|
|
@@ -116,13 +116,15 @@ var NativeMetricsProvider = class {
|
|
|
116
116
|
return getCpuTemperatureInternal();
|
|
117
117
|
}
|
|
118
118
|
async getProcessStats(input) {
|
|
119
|
-
const { getPidStats } = await import("../../resource-monitor-
|
|
119
|
+
const { getPidStats } = await import("../../resource-monitor-BkP504Vq.mjs").then((n) => n.r);
|
|
120
120
|
const raw = await getPidStats(input.pids);
|
|
121
121
|
const result = [];
|
|
122
122
|
for (const [pid, s] of raw) result.push({
|
|
123
123
|
pid,
|
|
124
124
|
cpu: s.cpu,
|
|
125
|
-
memory: s.memory
|
|
125
|
+
memory: s.memory,
|
|
126
|
+
privateBytes: s.privateBytes,
|
|
127
|
+
sharedBytes: s.sharedBytes
|
|
126
128
|
});
|
|
127
129
|
return result;
|
|
128
130
|
}
|
|
@@ -589,7 +591,8 @@ var NativeMetricsAddon = class extends BaseAddon {
|
|
|
589
591
|
listAddonInstances: () => this.listAddonInstances(),
|
|
590
592
|
getAddonStats: (params) => this.getAddonStats(params.addonId),
|
|
591
593
|
listNodeProcesses: () => this.listNodeProcesses(),
|
|
592
|
-
killProcess: (params) => this.killProcess(params)
|
|
594
|
+
killProcess: (params) => this.killProcess(params),
|
|
595
|
+
dumpHeapSnapshot: (params) => this.dumpHeapSnapshot(params)
|
|
593
596
|
};
|
|
594
597
|
this.snapshotTimer = setInterval(() => this.emitMetricsSnapshots(), METRICS_SNAPSHOT_INTERVAL_MS);
|
|
595
598
|
return [{
|
|
@@ -838,6 +841,50 @@ var NativeMetricsAddon = class extends BaseAddon {
|
|
|
838
841
|
};
|
|
839
842
|
}
|
|
840
843
|
}
|
|
844
|
+
/**
|
|
845
|
+
* Ask the addon's forked runner to write a V8 heap snapshot (SIGUSR2 → the
|
|
846
|
+
* runner's diagnostic handler in addon-runner.ts), for deep per-addon memory
|
|
847
|
+
* attribution. Resolves the addon's worker pid from the kernel `$process.list`
|
|
848
|
+
* and signals it; the runner writes `/tmp/heap-<sanitized nodeId>.heapsnapshot`
|
|
849
|
+
* and logs its memoryUsage + heap-space breakdown. '$hub' targets this process.
|
|
850
|
+
*/
|
|
851
|
+
async dumpHeapSnapshot(input) {
|
|
852
|
+
const sanitize = (nodeId) => nodeId.replace(/[^\w.-]/g, "_");
|
|
853
|
+
let pid;
|
|
854
|
+
let nodeId;
|
|
855
|
+
if (input.addonId === "$hub") {
|
|
856
|
+
pid = process.pid;
|
|
857
|
+
nodeId = this.ctx.kernel.cluster?.broker?.nodeID ?? "$hub";
|
|
858
|
+
} else {
|
|
859
|
+
const target = (await this.listWorkerInstances()).find((w) => w.addonId === input.addonId);
|
|
860
|
+
if (!target) return {
|
|
861
|
+
success: false,
|
|
862
|
+
reason: `no runner process for addon '${input.addonId}'`
|
|
863
|
+
};
|
|
864
|
+
pid = target.pid;
|
|
865
|
+
nodeId = target.nodeId;
|
|
866
|
+
}
|
|
867
|
+
const path = `/tmp/heap-${sanitize(nodeId)}.heapsnapshot`;
|
|
868
|
+
try {
|
|
869
|
+
process.kill(pid, "SIGUSR2");
|
|
870
|
+
this.ctx.logger.info("Requested heap snapshot from runner", { meta: {
|
|
871
|
+
addonId: input.addonId,
|
|
872
|
+
pid,
|
|
873
|
+
path
|
|
874
|
+
} });
|
|
875
|
+
return {
|
|
876
|
+
success: true,
|
|
877
|
+
pid,
|
|
878
|
+
path
|
|
879
|
+
};
|
|
880
|
+
} catch (err) {
|
|
881
|
+
return {
|
|
882
|
+
success: false,
|
|
883
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
884
|
+
pid
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
}
|
|
841
888
|
/** Raw `ps` scan returning every pid + command + resource stats. */
|
|
842
889
|
async runPs() {
|
|
843
890
|
try {
|