@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.
Files changed (33) hide show
  1. package/dist/addon-runner.js +40 -23
  2. package/dist/addon-runner.mjs +20 -4
  3. package/dist/addon-utils.d.ts +20 -0
  4. package/dist/addon-utils.js +11 -0
  5. package/dist/addon-utils.mjs +3 -0
  6. package/dist/builtins/device-manager/device-manager.addon.js +8 -8
  7. package/dist/builtins/device-manager/device-manager.addon.mjs +8 -8
  8. package/dist/builtins/native-metrics/native-metrics.addon.d.ts +8 -0
  9. package/dist/builtins/native-metrics/native-metrics.addon.js +50 -3
  10. package/dist/builtins/native-metrics/native-metrics.addon.mjs +50 -3
  11. package/dist/builtins/platform-probe/index.js +27 -139
  12. package/dist/builtins/platform-probe/index.mjs +28 -140
  13. package/dist/builtins/platform-probe/platform-scorer.d.ts +17 -10
  14. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +2 -2
  15. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +2 -2
  16. package/dist/custom-action-registry-BEXwC-oo.mjs +38 -0
  17. package/dist/custom-action-registry-vLYEFTtv.js +43 -0
  18. package/dist/index.js +129 -779
  19. package/dist/index.mjs +100 -750
  20. package/dist/kernel/config-manager.d.ts +4 -4
  21. package/dist/kernel/fs-utils.d.ts +16 -6
  22. package/dist/kernel/index.d.ts +1 -1
  23. package/dist/kernel/moleculer/device-cap-proxy.d.ts +2 -1
  24. package/dist/kernel/moleculer/readiness-context.d.ts +2 -1
  25. package/dist/kernel/transport/child-cap-protocol.d.ts +10 -0
  26. package/dist/{manifest-python-deps-B4BmMoGT.js → manifest-python-deps-BWURo7dc.js} +62 -88
  27. package/dist/{manifest-python-deps-CXbKrOdk.mjs → manifest-python-deps-BcrTzHH_.mjs} +55 -75
  28. package/dist/model-download-service-C7AjBsX9.mjs +668 -0
  29. package/dist/model-download-service-JtVQtbb6.js +752 -0
  30. package/dist/process/resource-monitor.d.ts +9 -0
  31. package/dist/{resource-monitor-ClDGFyf6.mjs → resource-monitor-BkP504Vq.mjs} +20 -1
  32. package/dist/{resource-monitor-IIEanuJt.js → resource-monitor-DNNomR-i.js} +21 -1
  33. package/package.json +6 -1
package/dist/index.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM$1, r as __exportAll, t as __commonJSMin$1 } from "./chunk-CNf5ZN-e.mjs";
2
- import { n as getSinglePidStats, t as getPidStats } from "./resource-monitor-ClDGFyf6.mjs";
2
+ import { a as ensureModel, c as isModelDownloaded, d as createAuthenticatedFileServer, f as parseRangeHeader, i as downloadModel, l as createFileDataPlaneHandler, m as resolveFilePath, n as deleteModelFromDisk, o as fetchJson, p as parseTokenizedUrl, r as downloadFile, s as getModelFilePath, t as ModelDownloadService, u as contentTypeFor } from "./model-download-service-C7AjBsX9.mjs";
3
+ import { n as getSinglePidStats, t as getPidStats } from "./resource-monitor-BkP504Vq.mjs";
3
4
  import { FilesystemStorageAddon, t as FilesystemStorageProvider } from "./builtins/sqlite-storage/filesystem-storage.addon.mjs";
4
5
  import { SqliteSettingsAddon, t as SqliteSettingsBackend } from "./builtins/sqlite-storage/sqlite-settings.addon.mjs";
5
6
  import { ConfigStore, DeviceStore } from "./builtins/sqlite-storage/index.mjs";
@@ -18,23 +19,25 @@ import { LocalAuthAddon, a as require_safe_buffer, i as AuthManager, n as ApiKey
18
19
  import "./builtins/local-auth/index.mjs";
19
20
  import { DeviceManagerAddon } from "./builtins/device-manager/device-manager.addon.mjs";
20
21
  import "./builtins/device-manager/index.mjs";
21
- import { A as createUdsLoggerWithControl, B as createLocalTransport, C as ipcParentLink, D as createUdsEventBus, E as createUdsEventBridge, F as CapRouteError, G as FrameDecoder, H as UdsLocalTransportServer, I as classifyCapRoute, J as buildUdsNativeCapProxy, K as encodeFrame, L as LocalChildClient, M as AGENT_CAP_FWD_SERVICE, N as CapRouteResolver, O as udsChildLogToWorkerEntry, P as callWithServiceDiscovery, Q as mountNativeCapService, R as LocalChildRegistry, S as ipcChildLink, T as createParentUnownedCallHandler, U as SocketChannel, V as UdsLocalTransportClient, W as localEndpointPath, Y as createBrokerDeviceManagerApi, _ as __resetCapUsageRegistryForTests, a as getWorkerDeviceRegistry, at as capBareAction, b as brokerTransportLink, c as setHubConnected, ct as deserializeTypedArrays, d as registerEventBusService, dt as CustomActionRegistry, et as createAddonService, f as AddonDepsManager, ft as CapabilityHandle, g as CapUsageRegistry, h as createHwAccelService, ht as resolveAddonClass, i as createUdsAddonContext, it as capActionSuffix, j as AGENT_CAP_FWD_ACTION, k as createUdsLogger, l as EVENT_TOPIC_PREFIX, lt as serializeTypedArrays, m as resolveHwAccel, mt as installManifestNativeDeps, n as adaptBrokerToCluster, nt as NATIVE_PROVIDER_SERVICE_INFIX, o as getOrInitReadinessRegistry, ot as capServiceName, p as createKernelHwAccel, pt as CapabilityUnavailableError, q as buildNativeCapProxy, r as createAddonContext, rt as capActionName, s as getOrInitReadinessRegistryForClient, st as parseCapAction, t as installManifestPythonDeps, tt as validateProviderRegistrations, u as getBrokerEventBus, ut as DeviceRegistry, v as getCapUsageRegistry, w as localProviderLink, x as buildLinkChain, y as brokerCallForCap, z as UDS_NO_ROUTE_PREFIX } from "./manifest-python-deps-CXbKrOdk.mjs";
22
+ import { A as createUdsLoggerWithControl, B as createLocalTransport, C as ipcParentLink, D as createUdsEventBus, E as createUdsEventBridge, F as CapRouteError, G as FrameDecoder, H as UdsLocalTransportServer, I as classifyCapRoute, J as buildUdsNativeCapProxy, K as encodeFrame, L as LocalChildClient, M as AGENT_CAP_FWD_SERVICE, N as CapRouteResolver, O as udsChildLogToWorkerEntry, P as callWithServiceDiscovery, Q as mountNativeCapService, R as LocalChildRegistry, S as ipcChildLink, T as createParentUnownedCallHandler, U as SocketChannel, V as UdsLocalTransportClient, W as localEndpointPath, Y as createBrokerDeviceManagerApi, _ as __resetCapUsageRegistryForTests, a as getWorkerDeviceRegistry, at as capBareAction, b as brokerTransportLink, c as setHubConnected, ct as deserializeTypedArrays, d as registerEventBusService, dt as CapabilityHandle, et as createAddonService, f as AddonDepsManager, ft as CapabilityUnavailableError, g as CapUsageRegistry, h as createHwAccelService, i as createUdsAddonContext, it as capActionSuffix, j as AGENT_CAP_FWD_ACTION, k as createUdsLogger, l as EVENT_TOPIC_PREFIX, lt as serializeTypedArrays, m as resolveHwAccel, mt as resolveAddonClass, n as adaptBrokerToCluster, nt as NATIVE_PROVIDER_SERVICE_INFIX, o as getOrInitReadinessRegistry, ot as capServiceName, p as createKernelHwAccel, pt as installManifestNativeDeps, q as buildNativeCapProxy, r as createAddonContext, rt as capActionName, s as getOrInitReadinessRegistryForClient, st as parseCapAction, t as installManifestPythonDeps, tt as validateProviderRegistrations, u as getBrokerEventBus, ut as DeviceRegistry, v as getCapUsageRegistry, w as localProviderLink, x as buildLinkChain, y as brokerCallForCap, z as UDS_NO_ROUTE_PREFIX } from "./manifest-python-deps-BcrTzHH_.mjs";
23
+ import { t as CustomActionRegistry } from "./custom-action-registry-BEXwC-oo.mjs";
22
24
  import { n as require_src, t as require_graceful_fs } from "./graceful-fs-BoR9GuPS.mjs";
23
25
  import { PYTHON_VERSION, buildBinaryPath, downloadBinary, ensureBinary, ensureFfmpeg, ensurePython, findInPath, getFfmpegDownloadUrl, getPlatformInfo, getPythonDownloadUrl, installPythonPackages, installPythonRequirements } from "@camstack/types/node";
24
- import { createServer, request } from "node:http";
26
+ import { request } from "node:http";
25
27
  import * as fs$17 from "node:fs";
26
- import { accessSync, constants, createReadStream, existsSync, mkdirSync, promises, readFileSync } from "node:fs";
28
+ import { accessSync, constants, existsSync, mkdirSync, readFileSync } from "node:fs";
27
29
  import * as path$40 from "node:path";
28
- import path, { dirname, isAbsolute, join, posix, resolve, win32 } from "node:path";
30
+ import { dirname, isAbsolute, join, posix, resolve, win32 } from "node:path";
29
31
  import { DATAPLANE_SECRET_HEADER, EventCategory, RUNTIME_DEFAULTS, ReadinessRegistry, ReadinessTimeoutError, asJsonObject, asNumber, asString, createEvent, emitDownForOwnedCaps, errMsg, lifecycleJobSchema, parseJsonObject, parseJsonUnknown, readinessKey, scopeKey } from "@camstack/types";
30
32
  import { X509Certificate, createHash, randomUUID, timingSafeEqual } from "node:crypto";
31
- import { execFile, execFileSync, spawn } from "node:child_process";
33
+ import { execFile, spawn } from "node:child_process";
32
34
  import * as util$8 from "node:util";
33
35
  import { promisify } from "node:util";
34
36
  import * as vm from "node:vm";
35
37
  import * as os$17 from "node:os";
36
38
  import { lstat, readdir, readlink, realpath } from "node:fs/promises";
37
39
  import { z } from "zod";
40
+ import { asJsonObject as asJsonObject$1, parseJsonUnknown as parseJsonUnknown$1 } from "@camstack/types/addon";
38
41
  import { lstatSync, readdir as readdir$1, readdirSync, readlinkSync, realpathSync } from "fs";
39
42
  import { EventEmitter } from "node:events";
40
43
  import Pe from "node:stream";
@@ -73,216 +76,6 @@ var EventBus = class {
73
76
  }
74
77
  };
75
78
  //#endregion
76
- //#region src/http/authenticated-file-server.ts
77
- /**
78
- * Authenticated data-plane file-server — a shared host primitive for addons that
79
- * must serve files (media segments, scrub-frame stores, exported clips) directly
80
- * to browsers/players, node-direct (NOT through the hub tRPC, per the recording
81
- * design's "no media bytes traverse the hub").
82
- *
83
- * It bundles the three things every such server needs so addons don't re-roll
84
- * them: CORS (the data plane is cross-origin from the admin-ui — a native
85
- * `<video src>` is exempt but hls.js / WebCodecs fetch via XHR and are blocked
86
- * without it), HTTP `Range` (seeking / partial fetch), and a SCOPED TOKEN check.
87
- *
88
- * The token rides as the FIRST path segment (`<urlPrefix><token>/<relPath>`) so
89
- * a player resolving a manifest's RELATIVE child URIs carries it on every
90
- * sub-request automatically — no per-URI rewriting, no cookies/headers a dumb
91
- * player can't set. The caller supplies `verifyToken(token, relPath)`; the
92
- * primitive stays auth-scheme-agnostic.
93
- *
94
- * Pure helpers (`parseTokenizedUrl`, `resolveFilePath`, `contentTypeFor`,
95
- * `parseRangeHeader`) are exported for unit testing; `createAuthenticatedFileServer`
96
- * is the thin `node:http` glue.
97
- */
98
- function corsHeaders(origin) {
99
- return {
100
- "access-control-allow-origin": origin,
101
- "access-control-allow-methods": "GET, HEAD, OPTIONS",
102
- "access-control-allow-headers": "range",
103
- "access-control-expose-headers": "content-length, content-range, accept-ranges",
104
- "access-control-max-age": "86400"
105
- };
106
- }
107
- /**
108
- * Split a request URL (`<urlPrefix><token>/<relPath>`) into its token + rel
109
- * path. Returns null for anything outside the prefix or missing either part.
110
- * `relPath` is URL-decoded; a decode failure → null.
111
- */
112
- function parseTokenizedUrl(urlPrefix, urlPath) {
113
- if (!urlPath.startsWith(urlPrefix)) return null;
114
- const after = urlPath.slice(urlPrefix.length);
115
- const slash = after.indexOf("/");
116
- if (slash <= 0) return null;
117
- const token = after.slice(0, slash);
118
- let rel;
119
- try {
120
- rel = decodeURIComponent(after.slice(slash + 1));
121
- } catch {
122
- return null;
123
- }
124
- if (rel.length === 0) return null;
125
- return {
126
- token,
127
- rel
128
- };
129
- }
130
- /**
131
- * Map a rel path to one candidate absolute path PER root, keeping only roots the
132
- * path stays within (traversal guard). The handler serves the first candidate
133
- * that exists. Rejects a path that escapes every root.
134
- */
135
- function resolveFilePath(roots, rel) {
136
- if (rel.length === 0) return { error: "forbidden" };
137
- const candidates = [];
138
- for (const rootDir of roots) {
139
- const root = path.resolve(rootDir);
140
- const abs = path.resolve(root, rel);
141
- if (abs === root || abs.startsWith(root + path.sep)) candidates.push(abs);
142
- }
143
- if (candidates.length === 0) return { error: "forbidden" };
144
- return { candidates };
145
- }
146
- var DEFAULT_CONTENT_TYPES = {
147
- ".m3u8": "application/vnd.apple.mpegurl",
148
- ".m4s": "video/mp4",
149
- ".mp4": "video/mp4",
150
- ".idx": "application/octet-stream",
151
- ".html": "text/html; charset=utf-8",
152
- ".js": "application/javascript; charset=utf-8",
153
- ".mjs": "application/javascript; charset=utf-8",
154
- ".css": "text/css; charset=utf-8",
155
- ".json": "application/json; charset=utf-8",
156
- ".map": "application/json; charset=utf-8",
157
- ".svg": "image/svg+xml",
158
- ".png": "image/png",
159
- ".jpg": "image/jpeg",
160
- ".jpeg": "image/jpeg",
161
- ".ico": "image/x-icon",
162
- ".woff2": "font/woff2",
163
- ".woff": "font/woff",
164
- ".ttf": "font/ttf"
165
- };
166
- function contentTypeFor(filePath, overrides) {
167
- const ext = path.extname(filePath).toLowerCase();
168
- return overrides?.[ext] ?? DEFAULT_CONTENT_TYPES[ext] ?? "application/octet-stream";
169
- }
170
- /** Parse an HTTP `Range` header against a known size. Null = serve whole file. */
171
- function parseRangeHeader(header, size) {
172
- if (!header) return null;
173
- const m = /^bytes=(\d*)-(\d*)$/.exec(header.trim());
174
- if (!m) return null;
175
- const [, rawStart, rawEnd] = m;
176
- if (rawStart === "" && rawEnd === "") return null;
177
- let start;
178
- let end;
179
- if (rawStart === "") {
180
- const n = Number(rawEnd);
181
- if (n <= 0) return null;
182
- start = Math.max(0, size - n);
183
- end = size - 1;
184
- } else {
185
- start = Number(rawStart);
186
- end = rawEnd === "" ? size - 1 : Number(rawEnd);
187
- }
188
- if (!Number.isFinite(start) || !Number.isFinite(end) || start > end || start >= size) return null;
189
- return {
190
- start,
191
- end: Math.min(end, size - 1)
192
- };
193
- }
194
- /**
195
- * Start an authenticated file-server. Returns the bound port so the caller can
196
- * build URLs. `getRoots`/`verifyToken` are invoked per request, so they always
197
- * reflect the live config.
198
- */
199
- async function createAuthenticatedFileServer(opts) {
200
- const cors = corsHeaders(opts.corsOrigin ?? "*");
201
- const server = createServer((req, res) => {
202
- handle(opts, cors, req, res);
203
- });
204
- await new Promise((resolve, reject) => {
205
- server.once("error", reject);
206
- server.listen(opts.port, () => resolve());
207
- });
208
- const addr = server.address();
209
- return {
210
- port: typeof addr === "object" && addr ? addr.port : opts.port,
211
- close: () => new Promise((resolve) => server.close(() => resolve()))
212
- };
213
- }
214
- async function handle(opts, cors, req, res) {
215
- if (req.method === "OPTIONS") {
216
- res.writeHead(204, cors).end();
217
- return;
218
- }
219
- if (req.method !== "GET" && req.method !== "HEAD") {
220
- res.writeHead(405, cors).end();
221
- return;
222
- }
223
- const urlPath = (req.url ?? "").split("?")[0] ?? "";
224
- const parsed = parseTokenizedUrl(opts.urlPrefix, urlPath);
225
- if (!parsed) {
226
- res.writeHead(403, cors).end();
227
- return;
228
- }
229
- if (!opts.verifyToken(parsed.token, parsed.rel)) {
230
- res.writeHead(401, cors).end();
231
- return;
232
- }
233
- const resolved = resolveFilePath(opts.getRoots(), parsed.rel);
234
- if ("error" in resolved) {
235
- res.writeHead(403, cors).end();
236
- return;
237
- }
238
- let absPath = null;
239
- let size = 0;
240
- for (const candidate of resolved.candidates) try {
241
- const st = await promises.stat(candidate);
242
- if (st.isFile()) {
243
- absPath = candidate;
244
- size = st.size;
245
- break;
246
- }
247
- } catch {}
248
- if (absPath === null) {
249
- res.writeHead(404, cors).end();
250
- return;
251
- }
252
- const baseHeaders = {
253
- ...cors,
254
- "content-type": contentTypeFor(absPath, opts.contentTypes),
255
- "accept-ranges": "bytes",
256
- "cache-control": "no-cache"
257
- };
258
- const range = parseRangeHeader(req.headers.range, size);
259
- if (range) {
260
- res.writeHead(206, {
261
- ...baseHeaders,
262
- "content-range": `bytes ${range.start}-${range.end}/${size}`,
263
- "content-length": String(range.end - range.start + 1)
264
- });
265
- if (req.method === "HEAD") {
266
- res.end();
267
- return;
268
- }
269
- createReadStream(absPath, {
270
- start: range.start,
271
- end: range.end
272
- }).pipe(res);
273
- return;
274
- }
275
- res.writeHead(200, {
276
- ...baseHeaders,
277
- "content-length": String(size)
278
- });
279
- if (req.method === "HEAD") {
280
- res.end();
281
- return;
282
- }
283
- createReadStream(absPath).pipe(res);
284
- }
285
- //#endregion
286
79
  //#region src/http/data-plane-registry.ts
287
80
  function trimSlashes(s) {
288
81
  return s.replace(/^\/+/, "").replace(/\/+$/, "");
@@ -383,459 +176,8 @@ function proxyToUpstream(opts) {
383
176
  clientReq.pipe(upstream);
384
177
  }
385
178
  //#endregion
386
- //#region src/http/file-data-plane.ts
387
- /**
388
- * A ready-made data-plane request handler that serves files from a set of roots
389
- * with HTTP `Range`, for addons whose data-plane is "stream files off disk"
390
- * (recording playback, scrub-frame stores, exported clips).
391
- *
392
- * This is the addon-side handler the addon hands to `ctx.dataPlane.serve({ handler })`.
393
- * It receives the REAL Node `req`/`res`, resolves the request path against the
394
- * addon's roots (traversal-guarded), and streams the file. NO token and NO CORS:
395
- * the hub already authenticated the caller and the data plane is same-origin
396
- * through the hub's port. Reuses the shared Range/content-type/traversal helpers
397
- * so there is one implementation across the standalone file-server and this.
398
- */
399
- /** Build a `(req, res)` handler that serves `getRoots()` files with Range. */
400
- function createFileDataPlaneHandler(opts) {
401
- return async (req, res) => {
402
- if (req.method !== "GET" && req.method !== "HEAD") {
403
- res.writeHead(405).end();
404
- return;
405
- }
406
- const urlPath = (req.url ?? "/").split("?")[0] ?? "/";
407
- let rel;
408
- try {
409
- rel = decodeURIComponent(urlPath.replace(/^\/+/, ""));
410
- } catch {
411
- res.writeHead(400).end();
412
- return;
413
- }
414
- if (rel.length === 0) {
415
- res.writeHead(404).end();
416
- return;
417
- }
418
- const resolved = resolveFilePath(opts.getRoots(), rel);
419
- if ("error" in resolved) {
420
- res.writeHead(403).end();
421
- return;
422
- }
423
- let absPath = null;
424
- let size = 0;
425
- for (const candidate of resolved.candidates) try {
426
- const st = await promises.stat(candidate);
427
- if (st.isFile()) {
428
- absPath = candidate;
429
- size = st.size;
430
- break;
431
- }
432
- } catch {}
433
- if (absPath === null) {
434
- res.writeHead(404).end();
435
- return;
436
- }
437
- const baseHeaders = {
438
- "content-type": contentTypeFor(absPath, opts.contentTypes),
439
- "accept-ranges": "bytes",
440
- "cache-control": "no-cache"
441
- };
442
- const range = parseRangeHeader(req.headers.range, size);
443
- if (range) {
444
- res.writeHead(206, {
445
- ...baseHeaders,
446
- "content-range": `bytes ${range.start}-${range.end}/${size}`,
447
- "content-length": String(range.end - range.start + 1)
448
- });
449
- if (req.method === "HEAD") {
450
- res.end();
451
- return;
452
- }
453
- createReadStream(absPath, {
454
- start: range.start,
455
- end: range.end
456
- }).pipe(res);
457
- return;
458
- }
459
- res.writeHead(200, {
460
- ...baseHeaders,
461
- "content-length": String(size)
462
- });
463
- if (req.method === "HEAD") {
464
- res.end();
465
- return;
466
- }
467
- createReadStream(absPath).pipe(res);
468
- };
469
- }
470
- //#endregion
471
- //#region src/download/model-downloader.ts
472
- /** Build fetch headers, including HF auth token for huggingface.co URLs */
473
- function buildHeaders(url) {
474
- const headers = { "User-Agent": "CamStack/1.0" };
475
- const hfToken = process.env["HF_TOKEN"] ?? process.env["HUGGING_FACE_HUB_TOKEN"];
476
- if (hfToken && url.includes("huggingface.co")) headers["Authorization"] = `Bearer ${hfToken}`;
477
- return headers;
478
- }
479
- /**
480
- * Download a single file from a URL to a destination path.
481
- * Uses native fetch() (Node 22+) which handles redirects natively.
482
- * Streams to disk with optional progress callback.
483
- * Returns the destination path. Skips download if file already exists.
484
- */
485
- async function downloadFile(url, destPath, onProgress) {
486
- if (fs$17.existsSync(destPath)) return destPath;
487
- fs$17.mkdirSync(path$40.dirname(destPath), { recursive: true });
488
- const tmpPath = destPath + ".downloading";
489
- try {
490
- const response = await fetch(url, {
491
- redirect: "follow",
492
- headers: buildHeaders(url)
493
- });
494
- if (!response.ok) throw new Error(`HTTP ${response.status} downloading ${url}`);
495
- if (!response.body) throw new Error(`No response body from ${url}`);
496
- const total = parseInt(response.headers.get("content-length") ?? "0", 10);
497
- let downloaded = 0;
498
- const fileStream = fs$17.createWriteStream(tmpPath);
499
- const reader = response.body.getReader();
500
- try {
501
- for (;;) {
502
- const { done, value } = await reader.read();
503
- if (done || !value) break;
504
- fileStream.write(value);
505
- downloaded += value.length;
506
- onProgress?.(downloaded, total);
507
- }
508
- } finally {
509
- fileStream.end();
510
- await new Promise((resolve, reject) => {
511
- fileStream.on("finish", resolve);
512
- fileStream.on("error", reject);
513
- });
514
- }
515
- fs$17.renameSync(tmpPath, destPath);
516
- return destPath;
517
- } catch (err) {
518
- try {
519
- fs$17.unlinkSync(tmpPath);
520
- } catch {}
521
- throw err;
522
- }
523
- }
524
- /**
525
- * Fetch JSON from a URL using native fetch().
526
- */
527
- async function fetchJson(url) {
528
- const response = await fetch(url, {
529
- redirect: "follow",
530
- headers: buildHeaders(url)
531
- });
532
- if (!response.ok) throw new Error(`HTTP ${response.status} fetching ${url}`);
533
- return response.json();
534
- }
535
- /**
536
- * Download a model with fallback URLs and optional SHA256 verification.
537
- * Legacy API preserved for backward compatibility -- delegates to downloadFile().
538
- */
539
- async function downloadModel(options) {
540
- const { url, fallbackUrls = [], destDir, filename, expectedSha256, onProgress } = options;
541
- const fname = filename ?? url.split("/").pop() ?? "model.bin";
542
- const destPath = path$40.join(destDir, fname);
543
- if (fs$17.existsSync(destPath)) return {
544
- filePath: destPath,
545
- downloadedBytes: 0,
546
- fromCache: true
547
- };
548
- fs$17.mkdirSync(destDir, { recursive: true });
549
- const urls = [url, ...fallbackUrls];
550
- let lastError = null;
551
- for (const tryUrl of urls) try {
552
- await downloadFile(tryUrl, destPath, onProgress);
553
- if (expectedSha256) {
554
- const hash = await computeSha256(destPath);
555
- if (hash !== expectedSha256) {
556
- fs$17.unlinkSync(destPath);
557
- throw new Error(`SHA256 mismatch: expected ${expectedSha256}, got ${hash}`);
558
- }
559
- }
560
- return {
561
- filePath: destPath,
562
- downloadedBytes: fs$17.statSync(destPath).size,
563
- fromCache: false
564
- };
565
- } catch (e) {
566
- lastError = e;
567
- if (fs$17.existsSync(destPath)) fs$17.unlinkSync(destPath);
568
- }
569
- throw lastError ?? /* @__PURE__ */ new Error(`Failed to download model from ${url}`);
570
- }
571
- async function computeSha256(filePath) {
572
- return new Promise((resolve, reject) => {
573
- const hash = createHash("sha256");
574
- const stream = fs$17.createReadStream(filePath);
575
- stream.on("data", (chunk) => hash.update(chunk));
576
- stream.on("end", () => resolve(hash.digest("hex")));
577
- stream.on("error", reject);
578
- });
579
- }
580
- /**
581
- * Download every file in a HuggingFace directory bundle (e.g.,
582
- * `.mlpackage` / OpenVINO IR pair) atomically. `knownFiles` lists the
583
- * relative paths inside the directory; the function fetches each from
584
- * `${url}/${file}` and renames the staging directory only on full
585
- * success. Mirrors `ModelDownloadService.downloadDirectory` but
586
- * exposed as a standalone for catalog-less callers.
587
- */
588
- async function downloadDirectory(url, destDir, knownFiles, onProgress) {
589
- const match = url.match(/huggingface\.co\/([^/]+\/[^/]+)\/resolve\/main\/(.+)/);
590
- if (!match) throw new Error(`Cannot parse HuggingFace URL: ${url}`);
591
- const [, repo, dirPath] = match;
592
- const files = (knownFiles ?? []).map((f) => ({
593
- relativePath: f,
594
- fileUrl: `https://huggingface.co/${repo}/resolve/main/${dirPath}/${f}`
595
- }));
596
- if (files.length === 0) throw new Error(`Directory bundle requires explicit \`files\` list (got none for ${url})`);
597
- const tmpDir = destDir + ".downloading";
598
- fs$17.rmSync(tmpDir, {
599
- recursive: true,
600
- force: true
601
- });
602
- fs$17.mkdirSync(tmpDir, { recursive: true });
603
- let totalDownloaded = 0;
604
- try {
605
- for (const file of files) {
606
- const destPath = path$40.join(tmpDir, file.relativePath);
607
- fs$17.mkdirSync(path$40.dirname(destPath), { recursive: true });
608
- await downloadFile(file.fileUrl, destPath, (downloaded, _total) => {
609
- onProgress?.(totalDownloaded + downloaded, void 0);
610
- });
611
- totalDownloaded += fs$17.statSync(destPath).size;
612
- }
613
- fs$17.rmSync(destDir, {
614
- recursive: true,
615
- force: true
616
- });
617
- fs$17.renameSync(tmpDir, destDir);
618
- } catch (err) {
619
- fs$17.rmSync(tmpDir, {
620
- recursive: true,
621
- force: true
622
- });
623
- throw err;
624
- }
625
- }
626
- /**
627
- * Resolve a `ModelCatalogEntry` against `modelsDir`: download model file
628
- * (or directory bundle) + extra files (labels JSON, charset dict, …),
629
- * skip if already on disk. Returns the local model path.
630
- */
631
- async function ensureModel(modelsDir, entry, format, onProgress) {
632
- const formatEntry = entry.formats[format];
633
- if (!formatEntry) throw new Error(`Model "${entry.id}" has no ${format} format. Available: ${Object.keys(entry.formats).join(", ")}`);
634
- if (entry.extraFiles) for (const extra of entry.extraFiles) await downloadFile(extra.url, path$40.join(modelsDir, extra.filename));
635
- const filename = formatEntry.url.split("/").pop() ?? `${entry.id}.${format}`;
636
- const modelPath = path$40.join(modelsDir, filename);
637
- if (fs$17.existsSync(modelPath)) if (formatEntry.isDirectory && !fs$17.existsSync(path$40.join(modelPath, "Manifest.json"))) fs$17.rmSync(modelPath, {
638
- recursive: true,
639
- force: true
640
- });
641
- else return modelPath;
642
- fs$17.mkdirSync(modelsDir, { recursive: true });
643
- if (formatEntry.isDirectory) await downloadDirectory(formatEntry.url, modelPath, formatEntry.files, onProgress);
644
- else await downloadFile(formatEntry.url, modelPath, (downloaded, total) => onProgress?.(downloaded, total === 0 ? void 0 : total));
645
- return modelPath;
646
- }
647
- /** Compute the on-disk path for a given model + format, even when not yet downloaded. */
648
- function getModelFilePath(modelsDir, entry, format) {
649
- const formatEntry = entry.formats[format];
650
- if (!formatEntry) return null;
651
- const filename = formatEntry.url.split("/").pop() ?? `${entry.id}.${format}`;
652
- return path$40.join(modelsDir, filename);
653
- }
654
- /** True iff the model file (or `Manifest.json` for directory bundles) exists and is non-empty. */
655
- function isModelDownloaded(modelsDir, entry, format) {
656
- const formatEntry = entry.formats[format];
657
- if (!formatEntry) return false;
658
- const modelPath = getModelFilePath(modelsDir, entry, format);
659
- if (!modelPath || !fs$17.existsSync(modelPath)) return false;
660
- if (formatEntry.isDirectory) return fs$17.existsSync(path$40.join(modelPath, "Manifest.json"));
661
- return fs$17.statSync(modelPath).size > 0;
662
- }
663
- /** Remove the on-disk model file/directory. Returns true if something was deleted. */
664
- function deleteModelFromDisk(modelsDir, entry, format) {
665
- const modelPath = getModelFilePath(modelsDir, entry, format);
666
- if (!modelPath || !fs$17.existsSync(modelPath)) return false;
667
- if (entry.formats[format]?.isDirectory) fs$17.rmSync(modelPath, {
668
- recursive: true,
669
- force: true
670
- });
671
- else fs$17.unlinkSync(modelPath);
672
- return true;
673
- }
674
- //#endregion
675
- //#region src/download/model-download-service.ts
676
- /**
677
- * Unified model download service.
678
- *
679
- * Handles downloading model files and extra files (labels, dicts) from a
680
- * catalog of ModelCatalogEntry items. Supports single-file models and
681
- * directory bundles (e.g., .mlpackage for CoreML).
682
- *
683
- * Addons use this via `context.models.ensure(modelId, format)`.
684
- */
685
- var ModelDownloadService = class {
686
- modelsDir;
687
- onProgress;
688
- catalog;
689
- constructor(modelsDir, catalog, onProgress) {
690
- this.modelsDir = modelsDir;
691
- this.onProgress = onProgress;
692
- const map = /* @__PURE__ */ new Map();
693
- for (const entry of catalog) map.set(entry.id, entry);
694
- this.catalog = map;
695
- }
696
- /**
697
- * Ensure a model (and its extra files) is downloaded.
698
- * Returns the local filesystem path to the model file/directory.
699
- */
700
- async ensure(modelId, format) {
701
- const entry = this.catalog.get(modelId);
702
- if (!entry) throw new Error(`ModelDownloadService: unknown model "${modelId}"`);
703
- const selectedFormat = format ?? this.pickDefaultFormat(entry);
704
- const formatEntry = entry.formats[selectedFormat];
705
- if (!formatEntry) throw new Error(`ModelDownloadService: model "${modelId}" has no ${selectedFormat} format`);
706
- await this.ensureExtraFiles(modelId);
707
- const modelPath = this.modelFilePath(entry, selectedFormat);
708
- if (fs$17.existsSync(modelPath)) if (formatEntry.isDirectory) if (!fs$17.existsSync(path$40.join(modelPath, "Manifest.json"))) fs$17.rmSync(modelPath, {
709
- recursive: true,
710
- force: true
711
- });
712
- else return modelPath;
713
- else return modelPath;
714
- fs$17.mkdirSync(this.modelsDir, { recursive: true });
715
- if (formatEntry.isDirectory) await this.downloadDirectory(formatEntry.url, modelPath, formatEntry.files, modelId);
716
- else await downloadFile(formatEntry.url, modelPath, this.onProgress ? (downloaded, total) => this.onProgress(modelId, downloaded, total) : void 0);
717
- return modelPath;
718
- }
719
- /**
720
- * Ensure extra files for a model are downloaded.
721
- * Returns the local paths of all extra files.
722
- */
723
- async ensureExtraFiles(modelId) {
724
- const entry = this.catalog.get(modelId);
725
- if (!entry) throw new Error(`ModelDownloadService: unknown model "${modelId}"`);
726
- const extras = entry.extraFiles;
727
- if (!extras || extras.length === 0) return [];
728
- const paths = [];
729
- for (const extra of extras) {
730
- const destPath = path$40.join(this.modelsDir, extra.filename);
731
- await downloadFile(extra.url, destPath);
732
- paths.push(destPath);
733
- }
734
- return paths;
735
- }
736
- /** Absolute path to the shared models directory. */
737
- getModelsDir() {
738
- return this.modelsDir;
739
- }
740
- /** Check if a model file is already present on disk. */
741
- isDownloaded(modelId, format) {
742
- const entry = this.catalog.get(modelId);
743
- if (!entry) return false;
744
- const selectedFormat = format ?? this.pickDefaultFormat(entry);
745
- const formatEntry = entry.formats[selectedFormat];
746
- if (!formatEntry) return false;
747
- const modelPath = this.modelFilePath(entry, selectedFormat);
748
- if (!fs$17.existsSync(modelPath)) return false;
749
- if (formatEntry.isDirectory) return fs$17.existsSync(path$40.join(modelPath, "Manifest.json"));
750
- return fs$17.statSync(modelPath).size > 0;
751
- }
752
- /** Get the catalog entry for a model by ID. */
753
- getEntry(modelId) {
754
- return this.catalog.get(modelId);
755
- }
756
- pickDefaultFormat(entry) {
757
- for (const fmt of [
758
- "onnx",
759
- "coreml",
760
- "openvino",
761
- "tflite",
762
- "pt"
763
- ]) if (entry.formats[fmt]) return fmt;
764
- const first = Object.keys(entry.formats)[0];
765
- if (first) return first;
766
- throw new Error(`ModelDownloadService: model "${entry.id}" has no formats`);
767
- }
768
- modelFilePath(entry, format) {
769
- const formatEntry = entry.formats[format];
770
- if (!formatEntry) throw new Error(`Model ${entry.id} has no ${format} format`);
771
- const urlParts = formatEntry.url.split("/");
772
- const filename = urlParts[urlParts.length - 1] ?? `${entry.id}.${format}`;
773
- return path$40.join(this.modelsDir, filename);
774
- }
775
- /**
776
- * Download a directory bundle (e.g., .mlpackage) from HuggingFace.
777
- * ATOMIC: downloads to temp dir, renames only on complete success.
778
- */
779
- async downloadDirectory(url, destDir, knownFiles, _modelId) {
780
- const match = url.match(/huggingface\.co\/([^/]+\/[^/]+)\/resolve\/main\/(.+)/);
781
- if (!match) throw new Error(`Cannot parse HuggingFace URL: ${url}`);
782
- const [, repo, dirPath] = match;
783
- let filesToDownload;
784
- if (knownFiles && knownFiles.length > 0) filesToDownload = knownFiles.map((f) => ({
785
- relativePath: f,
786
- fileUrl: `https://huggingface.co/${repo}/resolve/main/${dirPath}/${f}`
787
- }));
788
- else {
789
- const hfFiles = await this.listHfFiles(repo, dirPath);
790
- if (hfFiles.length === 0) throw new Error(`No files found in HuggingFace directory: ${dirPath}`);
791
- filesToDownload = hfFiles.map((f) => ({
792
- relativePath: f.path.substring(dirPath.length + 1),
793
- fileUrl: `https://huggingface.co/${repo}/resolve/main/${f.path}`
794
- }));
795
- }
796
- const tmpDir = destDir + ".downloading";
797
- fs$17.rmSync(tmpDir, {
798
- recursive: true,
799
- force: true
800
- });
801
- fs$17.mkdirSync(tmpDir, { recursive: true });
802
- try {
803
- for (const file of filesToDownload) {
804
- const destPath = path$40.join(tmpDir, file.relativePath);
805
- fs$17.mkdirSync(path$40.dirname(destPath), { recursive: true });
806
- await downloadFile(file.fileUrl, destPath);
807
- }
808
- fs$17.rmSync(destDir, {
809
- recursive: true,
810
- force: true
811
- });
812
- fs$17.renameSync(tmpDir, destDir);
813
- } catch (err) {
814
- fs$17.rmSync(tmpDir, {
815
- recursive: true,
816
- force: true
817
- });
818
- throw err;
819
- }
820
- }
821
- /** Recursively list all files in a HuggingFace directory via API. */
822
- async listHfFiles(repo, dirPath) {
823
- const entries = await fetchJson(`https://huggingface.co/api/models/${repo}/tree/main/${dirPath}`);
824
- const files = [];
825
- for (const entry of entries) if (entry.type === "file") files.push({
826
- path: entry.path,
827
- size: entry.size ?? entry.lfs?.size ?? 0
828
- });
829
- else if (entry.type === "directory") {
830
- const subFiles = await this.listHfFiles(repo, entry.path);
831
- files.push(...subFiles);
832
- }
833
- return files;
834
- }
835
- };
836
- //#endregion
837
179
  //#region src/python/python-env-manager.ts
838
- var execFileAsync$2 = promisify(execFile);
180
+ var execFileAsync$3 = promisify(execFile);
839
181
  var PythonEnvManager = class {
840
182
  venvPath;
841
183
  cachedProbe = null;
@@ -845,12 +187,12 @@ var PythonEnvManager = class {
845
187
  async probe() {
846
188
  if (this.cachedProbe) return this.cachedProbe;
847
189
  for (const cmd of ["python3", "python"]) try {
848
- const { stdout } = await execFileAsync$2(cmd, ["--version"]);
190
+ const { stdout } = await execFileAsync$3(cmd, ["--version"]);
849
191
  const version = stdout.trim().replace("Python ", "");
850
192
  const major = parseInt(version.split(".")[0] ?? "0", 10);
851
193
  const minor = parseInt(version.split(".")[1] ?? "0", 10);
852
194
  if (major < 3 || major === 3 && minor < 10) continue;
853
- const { stdout: pathOut } = await execFileAsync$2(cmd, ["-c", "import sys; print(sys.executable)"]);
195
+ const { stdout: pathOut } = await execFileAsync$3(cmd, ["-c", "import sys; print(sys.executable)"]);
854
196
  this.cachedProbe = {
855
197
  available: true,
856
198
  version,
@@ -866,13 +208,13 @@ var PythonEnvManager = class {
866
208
  async ensure(options) {
867
209
  const probe = await this.probe();
868
210
  if (!probe.available || !probe.path) throw new Error("Python 3.10+ is required but not found on this system");
869
- if (!fs$17.existsSync(path$40.join(this.venvPath, "bin", "python"))) await execFileAsync$2(probe.path, [
211
+ if (!fs$17.existsSync(path$40.join(this.venvPath, "bin", "python"))) await execFileAsync$3(probe.path, [
870
212
  "-m",
871
213
  "venv",
872
214
  this.venvPath
873
215
  ]);
874
216
  const venvPython = path$40.join(this.venvPath, "bin", "python");
875
- if (options.packages.length > 0) await execFileAsync$2(venvPython, [
217
+ if (options.packages.length > 0) await execFileAsync$3(venvPython, [
876
218
  "-m",
877
219
  "pip",
878
220
  "install",
@@ -2071,12 +1413,11 @@ var StorageManager = class {
2071
1413
  return namespace ? this.createNamespacedLocation(location, namespace) : location;
2072
1414
  }
2073
1415
  createLegacyShim() {
2074
- const self = this;
2075
1416
  return {
2076
1417
  async initialize() {},
2077
1418
  async shutdown() {},
2078
- getLocation(name) {
2079
- return self.getLocation(name);
1419
+ getLocation: (name) => {
1420
+ return this.getLocation(name);
2080
1421
  }
2081
1422
  };
2082
1423
  }
@@ -2352,7 +1693,7 @@ function matchPath(pattern, path) {
2352
1693
  }
2353
1694
  //#endregion
2354
1695
  //#region src/tls/cert-manager.ts
2355
- var execFileAsync$1 = promisify(execFile);
1696
+ var execFileAsync$2 = promisify(execFile);
2356
1697
  /**
2357
1698
  * Ensure a self-signed TLS certificate exists in the given directory.
2358
1699
  * Generates one if missing. Returns paths to cert and key files.
@@ -2389,7 +1730,7 @@ async function ensureTlsCert(dataDir, options) {
2389
1730
  for (const dns of sanDns) sanParts.push(`DNS:${dns}`);
2390
1731
  for (const ip of sanIps) sanParts.push(`IP:${ip}`);
2391
1732
  const sanString = sanParts.join(",");
2392
- await execFileAsync$1("openssl", [
1733
+ await execFileAsync$2("openssl", [
2393
1734
  "req",
2394
1735
  "-x509",
2395
1736
  "-newkey",
@@ -3222,6 +2563,7 @@ var AddonEngineManager = class {
3222
2563
  };
3223
2564
  //#endregion
3224
2565
  //#region src/kernel/fs-utils.ts
2566
+ var execFileAsync$1 = promisify(execFile);
3225
2567
  /**
3226
2568
  * Ensure a directory exists (recursive).
3227
2569
  * Single source of truth — replaces scattered mkdirSync calls.
@@ -3230,18 +2572,20 @@ function ensureDir(dirPath) {
3230
2572
  fs$17.mkdirSync(dirPath, { recursive: true });
3231
2573
  }
3232
2574
  /**
3233
- * Copy a directory recursively.
3234
- * Single source of truth — extracted from addon-installer + first-boot-installer.
2575
+ * Copy a directory recursively — ASYNC so it never blocks the event loop.
2576
+ *
2577
+ * The hub installs addons into `/data/addons`, which on Unraid is a slow
2578
+ * shfs/FUSE mount. The former synchronous `fs.copyFileSync`-per-file loop
2579
+ * blocked the Node event loop for the whole copy of a large bundle (e.g.
2580
+ * `addon-pipeline`), which froze the hub's HTTP listener mid-`camstack deploy`
2581
+ * (accept backlog piling up, existing connections stuck in CLOSE_WAIT). Using
2582
+ * `fs.promises.cp` keeps the I/O off the event loop. (Node ≥18 stable.)
3235
2583
  */
3236
- function copyDirRecursive(src, dest) {
3237
- ensureDir(dest);
3238
- const entries = fs$17.readdirSync(src, { withFileTypes: true });
3239
- for (const entry of entries) {
3240
- const srcPath = path$40.join(src, entry.name);
3241
- const destPath = path$40.join(dest, entry.name);
3242
- if (entry.isDirectory()) copyDirRecursive(srcPath, destPath);
3243
- else fs$17.copyFileSync(srcPath, destPath);
3244
- }
2584
+ async function copyDirRecursive(src, dest) {
2585
+ await fs$17.promises.cp(src, dest, {
2586
+ recursive: true,
2587
+ force: true
2588
+ });
3245
2589
  }
3246
2590
  /**
3247
2591
  * Strip @camstack/* dependencies and devDependencies from a package.json object.
@@ -3271,7 +2615,7 @@ function stripCamstackDeps(pkg) {
3271
2615
  * Copies directories (not individual files) from source to destination.
3272
2616
  * Skips "dist" (already handled) and glob patterns.
3273
2617
  */
3274
- function copyExtraFileDirs(pkgJson, sourceDir, destDir) {
2618
+ async function copyExtraFileDirs(pkgJson, sourceDir, destDir) {
3275
2619
  const rawFiles = pkgJson.files;
3276
2620
  if (!Array.isArray(rawFiles)) return;
3277
2621
  for (const fileEntry of rawFiles) {
@@ -3280,11 +2624,11 @@ function copyExtraFileDirs(pkgJson, sourceDir, destDir) {
3280
2624
  const srcPath = path$40.join(sourceDir, fileEntry);
3281
2625
  if (!fs$17.existsSync(srcPath)) continue;
3282
2626
  const destPath = path$40.join(destDir, fileEntry);
3283
- const stat = fs$17.statSync(srcPath);
3284
- if (stat.isDirectory()) copyDirRecursive(srcPath, destPath);
2627
+ const stat = await fs$17.promises.stat(srcPath);
2628
+ if (stat.isDirectory()) await copyDirRecursive(srcPath, destPath);
3285
2629
  else if (stat.isFile()) {
3286
2630
  ensureDir(path$40.dirname(destPath));
3287
- fs$17.copyFileSync(srcPath, destPath);
2631
+ await fs$17.promises.copyFile(srcPath, destPath);
3288
2632
  }
3289
2633
  }
3290
2634
  }
@@ -3329,12 +2673,16 @@ function ensureLibraryBuilt(packageName, packagesDir) {
3329
2673
  /**
3330
2674
  * Install a single npm package into a target directory (package.json + dist/).
3331
2675
  * No validation on camstack.addons -- works for any @camstack/* package.
3332
- * Uses synchronous child_process calls (suitable for first-boot and update paths).
2676
+ *
2677
+ * ASYNC: uses `execFile`/`fs.promises` throughout so a package install on a
2678
+ * live node never blocks the event loop (the `npm pack` + tar extract + copy to
2679
+ * the slow shfs/FUSE `/data` would otherwise freeze the HTTP listener). See
2680
+ * `copyDirRecursive` for the wedge this prevents.
3333
2681
  */
3334
- function installPackageFromNpmSync(packageName, targetDir) {
3335
- const tmpDir = fs$17.mkdtempSync(path$40.join(os$17.tmpdir(), "camstack-install-"));
2682
+ async function installPackageFromNpm(packageName, targetDir) {
2683
+ const tmpDir = await fs$17.promises.mkdtemp(path$40.join(os$17.tmpdir(), "camstack-install-"));
3336
2684
  try {
3337
- const tgzFilename = execFileSync("npm", [
2685
+ const { stdout } = await execFileAsync$1("npm", [
3338
2686
  "pack",
3339
2687
  packageName,
3340
2688
  "--pack-destination",
@@ -3342,12 +2690,13 @@ function installPackageFromNpmSync(packageName, targetDir) {
3342
2690
  ], {
3343
2691
  timeout: 12e4,
3344
2692
  encoding: "utf-8"
3345
- }).trim().split("\n").pop()?.trim();
2693
+ });
2694
+ const tgzFilename = stdout.trim().split("\n").pop()?.trim();
3346
2695
  if (!tgzFilename) throw new Error("npm pack produced no output");
3347
2696
  const tgzPath = path$40.join(tmpDir, tgzFilename);
3348
2697
  const extractDir = path$40.join(tmpDir, "extracted");
3349
2698
  ensureDir(extractDir);
3350
- execFileSync("tar", [
2699
+ await execFileAsync$1("tar", [
3351
2700
  "-xzf",
3352
2701
  tgzPath,
3353
2702
  "-C",
@@ -3355,20 +2704,20 @@ function installPackageFromNpmSync(packageName, targetDir) {
3355
2704
  ], { timeout: 3e4 });
3356
2705
  const packageSubDir = path$40.join(extractDir, "package");
3357
2706
  const srcPkgJsonDir = fs$17.existsSync(path$40.join(packageSubDir, "package.json")) ? packageSubDir : extractDir;
3358
- fs$17.rmSync(targetDir, {
2707
+ await fs$17.promises.rm(targetDir, {
3359
2708
  recursive: true,
3360
2709
  force: true
3361
2710
  });
3362
2711
  ensureDir(targetDir);
3363
- fs$17.copyFileSync(path$40.join(srcPkgJsonDir, "package.json"), path$40.join(targetDir, "package.json"));
2712
+ await fs$17.promises.copyFile(path$40.join(srcPkgJsonDir, "package.json"), path$40.join(targetDir, "package.json"));
3364
2713
  const distSrc = path$40.join(srcPkgJsonDir, "dist");
3365
- if (fs$17.existsSync(distSrc)) copyDirRecursive(distSrc, path$40.join(targetDir, "dist"));
2714
+ if (fs$17.existsSync(distSrc)) await copyDirRecursive(distSrc, path$40.join(targetDir, "dist"));
3366
2715
  try {
3367
- const npmPkg = asJsonObject(parseJsonUnknown(fs$17.readFileSync(path$40.join(srcPkgJsonDir, "package.json"), "utf-8")));
3368
- if (npmPkg) copyExtraFileDirs(npmPkg, srcPkgJsonDir, targetDir);
2716
+ const npmPkg = asJsonObject(parseJsonUnknown(await fs$17.promises.readFile(path$40.join(srcPkgJsonDir, "package.json"), "utf-8")));
2717
+ if (npmPkg) await copyExtraFileDirs(npmPkg, srcPkgJsonDir, targetDir);
3369
2718
  } catch {}
3370
2719
  } finally {
3371
- fs$17.rmSync(tmpDir, {
2720
+ await fs$17.promises.rm(tmpDir, {
3372
2721
  recursive: true,
3373
2722
  force: true
3374
2723
  });
@@ -3818,15 +3167,15 @@ var AddonInstaller = class AddonInstaller {
3818
3167
  await this.ensureBuilt(packageName, sourceDir, pkgData);
3819
3168
  const distDir = path$40.join(sourceDir, "dist");
3820
3169
  if (!fs$17.existsSync(distDir)) throw new Error(`${packageName} has no dist/ after build`);
3821
- fs$17.rmSync(targetDir, {
3170
+ await fs$17.promises.rm(targetDir, {
3822
3171
  recursive: true,
3823
3172
  force: true
3824
3173
  });
3825
3174
  ensureDir(targetDir);
3826
- fs$17.writeFileSync(path$40.join(targetDir, "package.json"), JSON.stringify(stripCamstackDeps(pkgData), null, 2));
3827
- copyDirRecursive(distDir, path$40.join(targetDir, "dist"));
3828
- copyExtraFileDirs(pkgData, sourceDir, targetDir);
3829
- fs$17.writeFileSync(path$40.join(targetDir, ".install-source"), "local");
3175
+ await fs$17.promises.writeFile(path$40.join(targetDir, "package.json"), JSON.stringify(stripCamstackDeps(pkgData), null, 2));
3176
+ await copyDirRecursive(distDir, path$40.join(targetDir, "dist"));
3177
+ await copyExtraFileDirs(pkgData, sourceDir, targetDir);
3178
+ await fs$17.promises.writeFile(path$40.join(targetDir, ".install-source"), "local");
3830
3179
  const localPkgVersion = asString(pkgData.version, "0.0.0");
3831
3180
  this.manifest.upsert(packageName, {
3832
3181
  version: localPkgVersion,
@@ -3946,17 +3295,17 @@ var AddonInstaller = class AddonInstaller {
3946
3295
  if (!pkgView) throw new Error(`Invalid package.json at ${pkgJsonPath}`);
3947
3296
  if (!pkgView.camstackAddons) throw new Error(`Package ${pkgView.name} has no camstack.addons manifest`);
3948
3297
  const targetDir = path$40.join(this.addonsDir, pkgView.name);
3949
- fs$17.rmSync(targetDir, {
3298
+ await fs$17.promises.rm(targetDir, {
3950
3299
  recursive: true,
3951
3300
  force: true
3952
3301
  });
3953
3302
  ensureDir(targetDir);
3954
3303
  const sourceDir = path$40.dirname(pkgJsonPath);
3955
3304
  const strippedManifest = stripCamstackDeps(pkgView.raw);
3956
- fs$17.writeFileSync(path$40.join(targetDir, "package.json"), JSON.stringify(strippedManifest, null, 2));
3305
+ await fs$17.promises.writeFile(path$40.join(targetDir, "package.json"), JSON.stringify(strippedManifest, null, 2));
3957
3306
  const sourceDist = path$40.join(sourceDir, "dist");
3958
- if (fs$17.existsSync(sourceDist)) copyDirRecursive(sourceDist, path$40.join(targetDir, "dist"));
3959
- copyExtraFileDirs(pkgView.raw, sourceDir, targetDir);
3307
+ if (fs$17.existsSync(sourceDist)) await copyDirRecursive(sourceDist, path$40.join(targetDir, "dist"));
3308
+ await copyExtraFileDirs(pkgView.raw, sourceDir, targetDir);
3960
3309
  const strippedRuntimeDeps = strippedManifest["dependencies"];
3961
3310
  if (strippedRuntimeDeps != null && typeof strippedRuntimeDeps === "object" && Object.keys(strippedRuntimeDeps).length > 0) {
3962
3311
  this.logger.info(`${pkgView.name} — installing runtime dependencies`, { meta: { targetDir } });
@@ -3980,7 +3329,7 @@ var AddonInstaller = class AddonInstaller {
3980
3329
  try {
3981
3330
  await installManifestNativeDeps(targetDir, pkgView.raw, this.logger, this.registry);
3982
3331
  } catch (nativeErr) {
3983
- fs$17.rmSync(targetDir, {
3332
+ await fs$17.promises.rm(targetDir, {
3984
3333
  recursive: true,
3985
3334
  force: true
3986
3335
  });
@@ -3995,7 +3344,7 @@ var AddonInstaller = class AddonInstaller {
3995
3344
  version: pkgView.version
3996
3345
  };
3997
3346
  } finally {
3998
- fs$17.rmSync(tmpDir, {
3347
+ await fs$17.promises.rm(tmpDir, {
3999
3348
  recursive: true,
4000
3349
  force: true
4001
3350
  });
@@ -4763,7 +4112,7 @@ var CapabilityRegistry = class CapabilityRegistry {
4763
4112
  const bare = this.bareAddonId(addonId);
4764
4113
  const nodeMap = this.singletonNodeOverrides.get(capabilityName);
4765
4114
  if (nodeMap) {
4766
- for (const [nodeId, ov] of [...nodeMap]) if (ov === bare) nodeMap.delete(nodeId);
4115
+ for (const [nodeId, ov] of Array.from(nodeMap)) if (ov === bare) nodeMap.delete(nodeId);
4767
4116
  if (nodeMap.size === 0) this.singletonNodeOverrides.delete(capabilityName);
4768
4117
  }
4769
4118
  this.logger.info("Provider unregistered from capability", {
@@ -8025,7 +7374,7 @@ var ConfigManager = class ConfigManager {
8025
7374
  constructor(configPath) {
8026
7375
  this.configPath = configPath;
8027
7376
  const rawYaml = this.loadYaml();
8028
- const merged = this.applyEnvOverrides(asJsonObject(rawYaml) ?? {});
7377
+ const merged = this.applyEnvOverrides(asJsonObject$1(rawYaml) ?? {});
8029
7378
  this.bootstrapConfig = bootstrapSchema.parse(merged);
8030
7379
  this.warnDefaultCredentials();
8031
7380
  const dataPath = this.bootstrapConfig.server.dataPath ?? "camstack-data";
@@ -8040,20 +7389,20 @@ var ConfigManager = class ConfigManager {
8040
7389
  setSettingsStore(store) {
8041
7390
  this.settingsStore = store;
8042
7391
  }
8043
- get(path) {
8044
- return this.resolveConfigValue(path);
7392
+ get(configPath) {
7393
+ return this.resolveConfigValue(configPath);
8045
7394
  }
8046
- resolveConfigValue(path) {
8047
- const bootstrapValue = this.getFromBootstrap(path);
7395
+ resolveConfigValue(configPath) {
7396
+ const bootstrapValue = this.getFromBootstrap(configPath);
8048
7397
  if (bootstrapValue !== void 0) return bootstrapValue;
8049
7398
  if (this.settingsStore !== null) {
8050
- const storeValue = this.settingsStore.getSystem(path);
7399
+ const storeValue = this.settingsStore.getSystem(configPath);
8051
7400
  if (storeValue !== void 0) return storeValue;
8052
- const nested = this.getNestedFromSystemSettings(path);
7401
+ const nested = this.getNestedFromSystemSettings(configPath);
8053
7402
  if (nested !== null) return nested;
8054
7403
  }
8055
- if (path in RUNTIME_DEFAULTS) return RUNTIME_DEFAULTS[path];
8056
- return this.getFromRuntimeDefaults(path) ?? void 0;
7404
+ if (configPath in RUNTIME_DEFAULTS) return RUNTIME_DEFAULTS[configPath];
7405
+ return this.getFromRuntimeDefaults(configPath) ?? void 0;
8057
7406
  }
8058
7407
  /**
8059
7408
  * Write a value to the settings-store.
@@ -8080,9 +7429,9 @@ var ConfigManager = class ConfigManager {
8080
7429
  */
8081
7430
  getSection(section) {
8082
7431
  const merged = {};
8083
- const defaults = asJsonObject(this.getFromRuntimeDefaults(section));
7432
+ const defaults = asJsonObject$1(this.getFromRuntimeDefaults(section));
8084
7433
  if (defaults) Object.assign(merged, defaults);
8085
- const bootstrapSection = asJsonObject({ ...this.bootstrapConfig }[section]);
7434
+ const bootstrapSection = asJsonObject$1({ ...this.bootstrapConfig }[section]);
8086
7435
  if (bootstrapSection) Object.assign(merged, bootstrapSection);
8087
7436
  if (this.settingsStore !== null) {
8088
7437
  const nested = this.getNestedFromSystemSettings(section);
@@ -8101,7 +7450,7 @@ var ConfigManager = class ConfigManager {
8101
7450
  /** Read all config for an addon from addon_settings. */
8102
7451
  getAddonConfig(addonId) {
8103
7452
  if (this.settingsStore !== null) return this.settingsStore.getAllAddon(addonId);
8104
- return asJsonObject(this.getFromBootstrap(`addons.${addonId}`)) ?? {};
7453
+ return asJsonObject$1(this.getFromBootstrap(`addons.${addonId}`)) ?? {};
8105
7454
  }
8106
7455
  /** Write (bulk-replace) config for an addon to addon_settings. */
8107
7456
  setAddonConfig(addonId, config) {
@@ -8269,8 +7618,8 @@ var ConfigManager = class ConfigManager {
8269
7618
  };
8270
7619
  this.saveRuntimeState();
8271
7620
  }
8272
- getBootstrap(path) {
8273
- return this.getFromBootstrap(path);
7621
+ getBootstrap(configPath) {
7622
+ return this.getFromBootstrap(configPath);
8274
7623
  }
8275
7624
  /** Features accessor -- reads from settings-store when available, falls back to RUNTIME_DEFAULTS */
8276
7625
  get features() {
@@ -8339,8 +7688,8 @@ var ConfigManager = class ConfigManager {
8339
7688
  update(section, data) {
8340
7689
  if (!ConfigManager.BOOTSTRAP_SECTIONS.has(section)) throw new Error(`[ConfigManager] Section "${section}" is a runtime setting — use setSection() to persist via the settings-store, not update() which writes to config.yaml`);
8341
7690
  let raw = {};
8342
- if (fs$17.existsSync(this.configPath)) raw = asJsonObject(load$1(fs$17.readFileSync(this.configPath, "utf-8"))) ?? {};
8343
- const existing = asJsonObject(raw[section]) ?? {};
7691
+ if (fs$17.existsSync(this.configPath)) raw = asJsonObject$1(load$1(fs$17.readFileSync(this.configPath, "utf-8"))) ?? {};
7692
+ const existing = asJsonObject$1(raw[section]) ?? {};
8344
7693
  raw[section] = {
8345
7694
  ...existing,
8346
7695
  ...data
@@ -8360,8 +7709,8 @@ var ConfigManager = class ConfigManager {
8360
7709
  * Deep-set a value in a nested plain object using a dot-notation path.
8361
7710
  * Returns a new object (immutable).
8362
7711
  */
8363
- setNested(obj, path, value) {
8364
- const [head, ...rest] = path.split(".");
7712
+ setNested(obj, configPath, value) {
7713
+ const [head, ...rest] = configPath.split(".");
8365
7714
  if (!head) return obj;
8366
7715
  if (rest.length === 0) return {
8367
7716
  ...obj,
@@ -8401,8 +7750,8 @@ var ConfigManager = class ConfigManager {
8401
7750
  warnDefaultCredentials() {
8402
7751
  if (this.bootstrapConfig.auth.adminPassword === "changeme") console.warn("[ConfigManager] Warning: Using default admin password \"changeme\". Set auth.adminPassword in your config.yaml or the CAMSTACK_ADMIN_PASS env var.");
8403
7752
  }
8404
- getFromBootstrap(path) {
8405
- const keys = path.split(".");
7753
+ getFromBootstrap(configPath) {
7754
+ const keys = configPath.split(".");
8406
7755
  let current = this.bootstrapConfig;
8407
7756
  for (const key of keys) {
8408
7757
  if (!isRecord(current)) return void 0;
@@ -8410,8 +7759,8 @@ var ConfigManager = class ConfigManager {
8410
7759
  }
8411
7760
  return current;
8412
7761
  }
8413
- getFromRuntimeDefaults(path) {
8414
- const prefix = path + ".";
7762
+ getFromRuntimeDefaults(configPath) {
7763
+ const prefix = configPath + ".";
8415
7764
  const result = {};
8416
7765
  let found = false;
8417
7766
  for (const [key, value] of Object.entries(RUNTIME_DEFAULTS)) if (key.startsWith(prefix)) {
@@ -8426,10 +7775,10 @@ var ConfigManager = class ConfigManager {
8426
7775
  * e.g. path='features' matches keys 'features.streaming', 'features.notifications', etc.
8427
7776
  * Returns an object keyed by the sub-key, or undefined if nothing is found.
8428
7777
  */
8429
- getNestedFromSystemSettings(path) {
7778
+ getNestedFromSystemSettings(configPath) {
8430
7779
  if (this.settingsStore === null) return null;
8431
7780
  const all = this.settingsStore.getAllSystem();
8432
- const prefix = path + ".";
7781
+ const prefix = configPath + ".";
8433
7782
  const result = {};
8434
7783
  let found = false;
8435
7784
  for (const [key, value] of Object.entries(all)) if (key.startsWith(prefix)) {
@@ -8441,13 +7790,13 @@ var ConfigManager = class ConfigManager {
8441
7790
  loadRuntimeState() {
8442
7791
  if (!fs$17.existsSync(this.runtimeStatePath)) return EMPTY_RUNTIME_STATE;
8443
7792
  try {
8444
- const parsed = asJsonObject(parseJsonUnknown(fs$17.readFileSync(this.runtimeStatePath, "utf-8")));
7793
+ const parsed = asJsonObject$1(parseJsonUnknown$1(fs$17.readFileSync(this.runtimeStatePath, "utf-8")));
8445
7794
  if (parsed === null) return EMPTY_RUNTIME_STATE;
8446
- const systemActivation = asJsonObject(parsed.systemActivation) ?? {};
8447
- const deviceActivationRaw = asJsonObject(parsed.deviceActivation) ?? {};
7795
+ const systemActivation = asJsonObject$1(parsed.systemActivation) ?? {};
7796
+ const deviceActivationRaw = asJsonObject$1(parsed.deviceActivation) ?? {};
8448
7797
  const deviceActivation = {};
8449
7798
  for (const [deviceId, entry] of Object.entries(deviceActivationRaw)) {
8450
- const nested = asJsonObject(entry);
7799
+ const nested = asJsonObject$1(entry);
8451
7800
  if (nested === null) continue;
8452
7801
  const bools = {};
8453
7802
  for (const [k, v] of Object.entries(nested)) if (typeof v === "boolean") bools[k] = v;
@@ -91590,7 +90939,7 @@ function createProcessService(parentNodeId, dataDir, deps, parentTcpPort, parent
91590
90939
  respawned.restartCount = prevRestartCount + 1;
91591
90940
  });
91592
90941
  restarted.push(name);
91593
- } catch (err) {
90942
+ } catch {
91594
90943
  failed.push(name);
91595
90944
  }
91596
90945
  return {
@@ -91985,8 +91334,8 @@ var LifecycleJobEngine = class {
91985
91334
  } finally {
91986
91335
  clearTimeout(timer);
91987
91336
  }
91988
- if (packages.length === 0) throw new Error("stageFramework returned no packages");
91989
91337
  const [firstPackage] = packages;
91338
+ if (!firstPackage) throw new Error("stageFramework returned no packages");
91990
91339
  this.advance(job.jobId, task, "staged", { stagedPath: firstPackage.stagedPath });
91991
91340
  requestFrameworkSwap({
91992
91341
  jobId: job.jobId,
@@ -92009,14 +91358,15 @@ var LifecycleJobEngine = class {
92009
91358
  */
92010
91359
  async fetchAddonsBounded(job, addonTasks) {
92011
91360
  const limit = Math.max(1, this.deps.fetchConcurrency ?? DEFAULT_FETCH_CONCURRENCY);
92012
- const outcomes = new Array(addonTasks.length);
91361
+ const outcomes = Array.from({ length: addonTasks.length });
92013
91362
  let nextIndex = 0;
92014
91363
  const worker = async () => {
92015
91364
  for (;;) {
92016
91365
  const index = nextIndex;
92017
91366
  nextIndex += 1;
92018
- if (index >= addonTasks.length) return;
92019
- outcomes[index] = await this.fetchAddonTask(job, addonTasks[index]);
91367
+ const addonTask = addonTasks[index];
91368
+ if (addonTask === void 0) return;
91369
+ outcomes[index] = await this.fetchAddonTask(job, addonTask);
92020
91370
  }
92021
91371
  };
92022
91372
  const workerCount = Math.min(limit, addonTasks.length);
@@ -92142,4 +91492,4 @@ async function stageFrameworkLockstep(input) {
92142
91492
  return results;
92143
91493
  }
92144
91494
  //#endregion
92145
- export { AGENT_CAP_FWD_ACTION, AGENT_CAP_FWD_SERVICE, AddonApiFactory, AddonDepsManager, AddonEngineManager, AddonHealthMonitor, AddonInstaller, AddonLoader, AddonManifest, AddonRouteRegistry, AlertCenterAddon, ApiKeyManager, AuthManager, CLUSTER_SECRET_MISMATCH_TYPE, CLUSTER_SECRET_REJECTED_EXIT_CODE, CORE_CAP_SERVICE_NAME, CapRouteError, CapRouteResolver, CapUsageRegistry, CapabilityHandle, CapabilityRegistry, CapabilityUnavailableError, ConfigManager, ConfigStore, ConsoleDestination, ConsoleLoggingAddon, CustomActionRegistry, DEFAULT_DATA_PATH, DataPlaneRegistry, DeviceManagerAddon, DeviceRegistry, DeviceStore, EVENT_TOPIC_PREFIX, EngineManagerResolver, EventBus, FRAMEWORK_LOCKSTEP, FeatureManager, FilesystemStorageAddon, FilesystemStorageProvider, FrameDecoder, FsStorageBackend, HEALTH_MONITOR_GRACE_PERIOD_MS, HEALTH_MONITOR_RETRY_INTERVALS_MS, HEALTH_MONITOR_TICK_MS, HubForwarderAddon, HubForwarderDestination, HubLogForwarder, HubNodeRegistry, INFRA_CAPABILITIES, IntegrationRegistry, JobJournal, LifecycleJobEngine, LifecycleStateMachine, LocalAuthAddon, LocalChildClient, LocalChildRegistry, LogManager, LogRingBuffer, ModelDownloadService, NATIVE_PROVIDER_SERVICE_INFIX, NativeMetricsAddon, NativeMetricsProvider, NetworkQualityTracker, NotificationService, PYTHON_VERSION, PipelineRunner, PipelineValidator, PythonEnvManager, RESTART_MARKER_FILE, RUNTIME_DEFAULTS, ReadinessRegistry, ReadinessTimeoutError, ReplEngine, RingBuffer, ScopedLogger, ScopedTokenManager, SocketChannel, SqliteSettingsAddon, SqliteSettingsBackend, StagingArea, StorageLocationManager, StorageManager, StorageOrchestratorAddon, StorageOrchestratorService, SystemConfigAddon, SystemEventBus, ToastService, UDS_NO_ROUTE_PREFIX, UdsLocalTransportClient, UdsLocalTransportServer, UserManager, WinstonDestination, WinstonLoggingAddon, __resetCapUsageRegistryForTests, adaptBrokerToCluster, bootstrapSchema, brokerCallForCap, brokerTransportLink, buildBinaryPath, buildLinkChain, buildNativeCapProxy, buildNodeManifest, buildStorageLocationRegistry, buildUdsNativeCapProxy, callRegisterNodeWithRetry, callWithServiceDiscovery, capActionName, capActionSuffix, capBareAction, capServiceName, classifyCapRoute, clearPendingRestart, clusterSecretMatches, contentTypeFor, copyDirRecursive, copyExtraFileDirs, createAddonContext, createAddonService, createAuthenticatedFileServer, createBroker, createBrokerDeviceManagerApi, createCoreCapService, createFileDataPlaneHandler, createHubService, createHwAccelService, createKernelHwAccel, createLocalTransport, createParentUnownedCallHandler, createProcessService, createReadinessService, createReadinessServiceForRegistry, createScopedProcessManager, createStreamProbeBrokerService, createUdsAddonContext, createUdsEventBridge, createUdsEventBus, createUdsLogger, createUdsLoggerWithControl, deleteModelFromDisk, deriveAgentListenPort, describeProviderKindDrift, detectWorkspacePackagesDir, downloadBinary, downloadFile, downloadModel, emitDownForOwnedCaps, encodeFrame, ensureBinary, ensureDir, ensureFfmpeg, ensureLibraryBuilt, ensureModel, ensurePython, ensureTlsCert, fetchJson, findInPath, formatLogLine, getBrokerEventBus, getCapUsageRegistry, getFfmpegDownloadUrl, getModelFilePath, getOrInitReadinessRegistry, getOrInitReadinessRegistryForClient, getPidStats, getPlatformInfo, getPythonDownloadUrl, getRestartMarkerPath, getSinglePidStats, getWorkerDeviceRegistry, hashClusterSecret, installManifestNativeDeps, installManifestPythonDeps, installPackageFromNpmSync, installPythonPackages, installPythonRequirements, ipcChildLink, ipcParentLink, isClusterSecretMismatchError, isInfraCapability, isModelDownloaded, isSourceNewer, loadTlsCert, localEndpointPath, localProviderLink, mountNativeCapService, parseCapAction, parseRangeHeader, parseTokenizedUrl, proxyToUpstream, readPendingRestart, readinessKey, registerEventBusService, resolveFilePath, resolveHwAccel, scheduleSelfRestart, scopeKey, scopesAllowDeviceCap, serializeTypedArrays, setHubConnected, stageFrameworkLockstep, stripCamstackDeps, udsChildLogToWorkerEntry, validateProviderRegistrations, writePendingRestart };
91495
+ export { AGENT_CAP_FWD_ACTION, AGENT_CAP_FWD_SERVICE, AddonApiFactory, AddonDepsManager, AddonEngineManager, AddonHealthMonitor, AddonInstaller, AddonLoader, AddonManifest, AddonRouteRegistry, AlertCenterAddon, ApiKeyManager, AuthManager, CLUSTER_SECRET_MISMATCH_TYPE, CLUSTER_SECRET_REJECTED_EXIT_CODE, CORE_CAP_SERVICE_NAME, CapRouteError, CapRouteResolver, CapUsageRegistry, CapabilityHandle, CapabilityRegistry, CapabilityUnavailableError, ConfigManager, ConfigStore, ConsoleDestination, ConsoleLoggingAddon, CustomActionRegistry, DEFAULT_DATA_PATH, DataPlaneRegistry, DeviceManagerAddon, DeviceRegistry, DeviceStore, EVENT_TOPIC_PREFIX, EngineManagerResolver, EventBus, FRAMEWORK_LOCKSTEP, FeatureManager, FilesystemStorageAddon, FilesystemStorageProvider, FrameDecoder, FsStorageBackend, HEALTH_MONITOR_GRACE_PERIOD_MS, HEALTH_MONITOR_RETRY_INTERVALS_MS, HEALTH_MONITOR_TICK_MS, HubForwarderAddon, HubForwarderDestination, HubLogForwarder, HubNodeRegistry, INFRA_CAPABILITIES, IntegrationRegistry, JobJournal, LifecycleJobEngine, LifecycleStateMachine, LocalAuthAddon, LocalChildClient, LocalChildRegistry, LogManager, LogRingBuffer, ModelDownloadService, NATIVE_PROVIDER_SERVICE_INFIX, NativeMetricsAddon, NativeMetricsProvider, NetworkQualityTracker, NotificationService, PYTHON_VERSION, PipelineRunner, PipelineValidator, PythonEnvManager, RESTART_MARKER_FILE, RUNTIME_DEFAULTS, ReadinessRegistry, ReadinessTimeoutError, ReplEngine, RingBuffer, ScopedLogger, ScopedTokenManager, SocketChannel, SqliteSettingsAddon, SqliteSettingsBackend, StagingArea, StorageLocationManager, StorageManager, StorageOrchestratorAddon, StorageOrchestratorService, SystemConfigAddon, SystemEventBus, ToastService, UDS_NO_ROUTE_PREFIX, UdsLocalTransportClient, UdsLocalTransportServer, UserManager, WinstonDestination, WinstonLoggingAddon, __resetCapUsageRegistryForTests, adaptBrokerToCluster, bootstrapSchema, brokerCallForCap, brokerTransportLink, buildBinaryPath, buildLinkChain, buildNativeCapProxy, buildNodeManifest, buildStorageLocationRegistry, buildUdsNativeCapProxy, callRegisterNodeWithRetry, callWithServiceDiscovery, capActionName, capActionSuffix, capBareAction, capServiceName, classifyCapRoute, clearPendingRestart, clusterSecretMatches, contentTypeFor, copyDirRecursive, copyExtraFileDirs, createAddonContext, createAddonService, createAuthenticatedFileServer, createBroker, createBrokerDeviceManagerApi, createCoreCapService, createFileDataPlaneHandler, createHubService, createHwAccelService, createKernelHwAccel, createLocalTransport, createParentUnownedCallHandler, createProcessService, createReadinessService, createReadinessServiceForRegistry, createScopedProcessManager, createStreamProbeBrokerService, createUdsAddonContext, createUdsEventBridge, createUdsEventBus, createUdsLogger, createUdsLoggerWithControl, deleteModelFromDisk, deriveAgentListenPort, describeProviderKindDrift, detectWorkspacePackagesDir, downloadBinary, downloadFile, downloadModel, emitDownForOwnedCaps, encodeFrame, ensureBinary, ensureDir, ensureFfmpeg, ensureLibraryBuilt, ensureModel, ensurePython, ensureTlsCert, fetchJson, findInPath, formatLogLine, getBrokerEventBus, getCapUsageRegistry, getFfmpegDownloadUrl, getModelFilePath, getOrInitReadinessRegistry, getOrInitReadinessRegistryForClient, getPidStats, getPlatformInfo, getPythonDownloadUrl, getRestartMarkerPath, getSinglePidStats, getWorkerDeviceRegistry, hashClusterSecret, installManifestNativeDeps, installManifestPythonDeps, installPackageFromNpm, installPythonPackages, installPythonRequirements, ipcChildLink, ipcParentLink, isClusterSecretMismatchError, isInfraCapability, isModelDownloaded, isSourceNewer, loadTlsCert, localEndpointPath, localProviderLink, mountNativeCapService, parseCapAction, parseRangeHeader, parseTokenizedUrl, proxyToUpstream, readPendingRestart, readinessKey, registerEventBusService, resolveFilePath, resolveHwAccel, scheduleSelfRestart, scopeKey, scopesAllowDeviceCap, serializeTypedArrays, setHubConnected, stageFrameworkLockstep, stripCamstackDeps, udsChildLogToWorkerEntry, validateProviderRegistrations, writePendingRestart };