@camstack/system 1.2.0 → 1.2.2

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 (48) hide show
  1. package/dist/addon-runner.js +2 -2
  2. package/dist/addon-runner.mjs +2 -2
  3. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/alerts/alerts.addon.js +1 -1
  8. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  9. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  10. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  11. package/dist/builtins/console-logging/index.js +1 -1
  12. package/dist/builtins/console-logging/index.mjs +1 -1
  13. package/dist/builtins/device-manager/device-linked-devices.d.ts +13 -0
  14. package/dist/builtins/device-manager/device-manager.addon.js +86 -26
  15. package/dist/builtins/device-manager/device-manager.addon.mjs +86 -26
  16. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  17. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  18. package/dist/builtins/hub-forwarder/index.js +1 -1
  19. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  20. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  21. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  22. package/dist/builtins/local-network/local-network.addon.js +1 -1
  23. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  24. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  25. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  26. package/dist/builtins/platform-probe/index.js +1 -1
  27. package/dist/builtins/platform-probe/index.mjs +1 -1
  28. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  29. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  30. package/dist/builtins/snapshot/index.js +1 -1
  31. package/dist/builtins/snapshot/index.mjs +1 -1
  32. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  33. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  34. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +1 -1
  35. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +1 -1
  36. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  37. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  38. package/dist/builtins/system-config/system-config.addon.js +1 -1
  39. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  40. package/dist/builtins/winston-logging/index.js +1 -1
  41. package/dist/builtins/winston-logging/index.mjs +1 -1
  42. package/dist/{dist-B9OD5Tdn.js → dist-CkdNC8US.js} +95 -13
  43. package/dist/{dist-D7-BTTgZ.mjs → dist-DTTTjPCL.mjs} +95 -13
  44. package/dist/index.js +2 -2
  45. package/dist/index.mjs +2 -2
  46. package/dist/{manifest-python-deps-DXqcuOha.js → manifest-python-deps-DRq5MreI.js} +1 -1
  47. package/dist/{manifest-python-deps-D7EIakIT.mjs → manifest-python-deps-s_-uULmp.mjs} +1 -1
  48. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  const require_chunk = require("./chunk-Cek0wNdY.js");
2
- const require_dist = require("./dist-B9OD5Tdn.js");
3
- const require_manifest_python_deps = require("./manifest-python-deps-DXqcuOha.js");
2
+ const require_dist = require("./dist-CkdNC8US.js");
3
+ const require_manifest_python_deps = require("./manifest-python-deps-DRq5MreI.js");
4
4
  const require_custom_action_registry = require("./custom-action-registry-vLYEFTtv.js");
5
5
  let node_fs = require("node:fs");
6
6
  node_fs = require_chunk.__toESM(node_fs);
@@ -1,5 +1,5 @@
1
- import { M as isCollectionArrayMethod, t as ALL_CAPABILITY_DEFINITIONS } from "./dist-D7-BTTgZ.mjs";
2
- import { I as createUdsLoggerWithControl, L as LocalChildClient, St as resolveAddonClass, at as setWorkerNativeCapsChangeListener, i as createUdsAddonContext, nt as getWorkerNativeCapProvider, rt as getWorkerNativeCapSnapshot, st as validateProviderRegistrations, t as installManifestPythonDeps, yt as installManifestNativeDeps } from "./manifest-python-deps-D7EIakIT.mjs";
1
+ import { M as isCollectionArrayMethod, t as ALL_CAPABILITY_DEFINITIONS } from "./dist-DTTTjPCL.mjs";
2
+ import { I as createUdsLoggerWithControl, L as LocalChildClient, St as resolveAddonClass, at as setWorkerNativeCapsChangeListener, i as createUdsAddonContext, nt as getWorkerNativeCapProvider, rt as getWorkerNativeCapSnapshot, st as validateProviderRegistrations, t as installManifestPythonDeps, yt as installManifestNativeDeps } from "./manifest-python-deps-s_-uULmp.mjs";
3
3
  import { t as CustomActionRegistry } from "./custom-action-registry-BEXwC-oo.mjs";
4
4
  import { register } from "node:module";
5
5
  import * as fs from "node:fs";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let node_fs = require("node:fs");
9
9
  node_fs = require_chunk.__toESM(node_fs);
@@ -1,4 +1,4 @@
1
- import { At as EventCategory, at as BaseAddon, f as addonPagesCapability, it as errMsg } from "../../dist-D7-BTTgZ.mjs";
1
+ import { At as EventCategory, at as BaseAddon, f as addonPagesCapability, it as errMsg } from "../../dist-DTTTjPCL.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import * as fs from "node:fs";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let node_fs = require("node:fs");
9
9
  node_fs = require_chunk.__toESM(node_fs);
@@ -1,4 +1,4 @@
1
- import { At as EventCategory, at as BaseAddon, it as errMsg, m as addonWidgetsCapability } from "../../dist-D7-BTTgZ.mjs";
1
+ import { At as EventCategory, at as BaseAddon, it as errMsg, m as addonWidgetsCapability } from "../../dist-DTTTjPCL.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import * as fs from "node:fs";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  //#region src/builtins/alerts/alerts.addon.ts
8
8
  var CATEGORY_MAPPINGS = {
9
9
  "addon.crashed": {
@@ -1,4 +1,4 @@
1
- import { At as EventCategory, at as BaseAddon, h as alertsCapability, it as errMsg, n as AlertSchema, vt as createEvent } from "../../dist-D7-BTTgZ.mjs";
1
+ import { At as EventCategory, at as BaseAddon, h as alertsCapability, it as errMsg, n as AlertSchema, vt as createEvent } from "../../dist-DTTTjPCL.mjs";
2
2
  //#region src/builtins/alerts/alerts.addon.ts
3
3
  var CATEGORY_MAPPINGS = {
4
4
  "addon.crashed": {
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  let node_fs = require("node:fs");
8
8
  let node_fs$1 = require_chunk.__toESM(node_fs, 1);
9
9
  node_fs = require_chunk.__toESM(node_fs);
@@ -1,4 +1,4 @@
1
- import { At as EventCategory, at as BaseAddon, v as backupCapability } from "../../dist-D7-BTTgZ.mjs";
1
+ import { At as EventCategory, at as BaseAddon, v as backupCapability } from "../../dist-DTTTjPCL.mjs";
2
2
  import * as fs from "node:fs";
3
3
  import Kt from "node:fs";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  const require_formatter = require("../../formatter-DqAKDlvN.js");
8
8
  //#region src/builtins/console-logging/console-destination.ts
9
9
  var LEVEL_RANK = {
@@ -1,4 +1,4 @@
1
- import { R as logDestinationCapability, at as BaseAddon } from "../../dist-D7-BTTgZ.mjs";
1
+ import { R as logDestinationCapability, at as BaseAddon } from "../../dist-DTTTjPCL.mjs";
2
2
  import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
3
3
  //#region src/builtins/console-logging/console-destination.ts
4
4
  var LEVEL_RANK = {
@@ -3,6 +3,9 @@ import { ProviderContext } from './device-provider-context.js';
3
3
  /** Reserved device-config keys (cf. `_profileMap`). */
4
4
  export declare const LINKED_MODE_CONFIG_KEY = "_linkedDevicesMode";
5
5
  export declare const LINKED_IDS_CONFIG_KEY = "_linkedDeviceIds";
6
+ /** Reserved key: subset of linked devices that materialize synthetic tracked
7
+ * events on the camera. Absent ⇒ ALL linked devices produce tracked events. */
8
+ export declare const LINKED_TRACKED_IDS_CONFIG_KEY = "_linkedDeviceTrackedIds";
6
9
  export interface LinkedDevicesConfig {
7
10
  readonly mode: DeviceLinkMode;
8
11
  readonly manualIds: readonly number[];
@@ -27,6 +30,16 @@ export declare function resolveLinkedDeviceIds(params: {
27
30
  readonly config: LinkedDevicesConfig;
28
31
  readonly candidates: readonly LinkCandidate[];
29
32
  }): readonly number[];
33
+ /**
34
+ * Which linked devices materialize synthetic tracked events on the camera.
35
+ * Absent / non-array config key ⇒ ALL linked devices (back-compat with the
36
+ * pre-existing "every linked device produces events" behaviour). Otherwise the
37
+ * configured subset intersected with the currently-resolved linked set (a
38
+ * picked id no longer linked is dropped). Ids may arrive as numbers or numeric
39
+ * strings (the multiselect stores string option values); non-numeric entries
40
+ * are ignored.
41
+ */
42
+ export declare function resolveTrackedEventDeviceIds(config: Record<string, unknown>, linkedIds: readonly number[]): readonly number[];
30
43
  /** Cap implementation of `getLinkedDevices`. */
31
44
  export declare function getLinkedDevices(pctx: ProviderContext, input: Parameters<IDeviceManagerProvider['getLinkedDevices']>[0]): ReturnType<IDeviceManagerProvider['getLinkedDevices']>;
32
45
  /**
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  let _camstack_types_node = require("@camstack/types/node");
8
8
  let zod = require("zod");
9
9
  let node_crypto = require("node:crypto");
@@ -1209,6 +1209,9 @@ async function testField(pctx, input) {
1209
1209
  /** Reserved device-config keys (cf. `_profileMap`). */
1210
1210
  var LINKED_MODE_CONFIG_KEY = "_linkedDevicesMode";
1211
1211
  var LINKED_IDS_CONFIG_KEY = "_linkedDeviceIds";
1212
+ /** Reserved key: subset of linked devices that materialize synthetic tracked
1213
+ * events on the camera. Absent ⇒ ALL linked devices produce tracked events. */
1214
+ var LINKED_TRACKED_IDS_CONFIG_KEY = "_linkedDeviceTrackedIds";
1212
1215
  /** Parse the two reserved keys out of a device-config blob. Tolerant:
1213
1216
  * ids may arrive as numbers or numeric strings (the multiselect field
1214
1217
  * stores string option values); anything else is dropped. */
@@ -1244,6 +1247,25 @@ function resolveLinkedDeviceIds(params) {
1244
1247
  ids.delete(selfId);
1245
1248
  return [...ids];
1246
1249
  }
1250
+ /**
1251
+ * Which linked devices materialize synthetic tracked events on the camera.
1252
+ * Absent / non-array config key ⇒ ALL linked devices (back-compat with the
1253
+ * pre-existing "every linked device produces events" behaviour). Otherwise the
1254
+ * configured subset intersected with the currently-resolved linked set (a
1255
+ * picked id no longer linked is dropped). Ids may arrive as numbers or numeric
1256
+ * strings (the multiselect stores string option values); non-numeric entries
1257
+ * are ignored.
1258
+ */
1259
+ function resolveTrackedEventDeviceIds(config, linkedIds) {
1260
+ const raw = config[LINKED_TRACKED_IDS_CONFIG_KEY];
1261
+ if (!Array.isArray(raw)) return linkedIds;
1262
+ const picked = /* @__PURE__ */ new Set();
1263
+ for (const v of raw) {
1264
+ const n = typeof v === "number" ? v : typeof v === "string" ? Number(v) : NaN;
1265
+ if (Number.isInteger(n)) picked.add(n);
1266
+ }
1267
+ return linkedIds.filter((id) => picked.has(id));
1268
+ }
1247
1269
  /** Cap implementation of `getLinkedDevices`. */
1248
1270
  async function getLinkedDevices(pctx, input) {
1249
1271
  const { deviceId } = input;
@@ -1256,6 +1278,7 @@ async function getLinkedDevices(pctx, input) {
1256
1278
  config,
1257
1279
  candidates: all
1258
1280
  });
1281
+ const trackedIds = new Set(resolveTrackedEventDeviceIds(blob, ids));
1259
1282
  const devices = [];
1260
1283
  for (const id of ids) {
1261
1284
  const d = byId.get(id);
@@ -1264,7 +1287,8 @@ async function getLinkedDevices(pctx, input) {
1264
1287
  deviceId: d.id,
1265
1288
  name: d.name,
1266
1289
  location: d.location,
1267
- features: d.features
1290
+ features: d.features,
1291
+ producesTrackedEvents: trackedIds.has(d.id)
1268
1292
  });
1269
1293
  }
1270
1294
  return {
@@ -1287,36 +1311,63 @@ async function buildLinkedDevicesContribution(pctx, deviceId) {
1287
1311
  value: String(d.id),
1288
1312
  label: d.location !== null ? `${d.name} (${d.location})` : d.name
1289
1313
  }));
1314
+ const linkedIds = resolveLinkedDeviceIds({
1315
+ selfId: deviceId,
1316
+ selfLocation: all.find((d) => d.id === deviceId)?.location ?? null,
1317
+ config,
1318
+ candidates: all
1319
+ });
1320
+ const byId = new Map(all.map((d) => [d.id, d]));
1321
+ const trackedOptions = linkedIds.flatMap((id) => {
1322
+ const d = byId.get(id);
1323
+ if (!d) return [];
1324
+ return [{
1325
+ value: String(d.id),
1326
+ label: d.location !== null ? `${d.name} (${d.location})` : d.name
1327
+ }];
1328
+ });
1329
+ const trackedValue = resolveTrackedEventDeviceIds(blob, linkedIds).map(String);
1290
1330
  return { sections: [{
1291
1331
  id: "linked-devices",
1292
1332
  title: "Linked devices",
1293
1333
  description: "Companion devices associated with this camera. Device-tree children are always linked; auto mode also links every device sharing the camera location, manual mode links the picked list instead.",
1294
1334
  order: 70,
1295
- fields: [{
1296
- type: "select",
1297
- key: LINKED_MODE_CONFIG_KEY,
1298
- label: "Link mode",
1299
- description: "Auto: children + same-location devices. Manual: children + the list below.",
1300
- options: [{
1301
- value: "auto",
1302
- label: "Auto (location-based)"
1303
- }, {
1304
- value: "manual",
1305
- label: "Manual"
1306
- }],
1307
- value: config.mode
1308
- }, {
1309
- type: "multiselect",
1310
- key: LINKED_IDS_CONFIG_KEY,
1311
- label: "Manually linked devices",
1312
- description: "Used in manual mode (children stay linked regardless).",
1313
- showWhen: {
1314
- field: LINKED_MODE_CONFIG_KEY,
1315
- equals: "manual"
1335
+ fields: [
1336
+ {
1337
+ type: "select",
1338
+ key: LINKED_MODE_CONFIG_KEY,
1339
+ label: "Link mode",
1340
+ description: "Auto: children + same-location devices. Manual: children + the list below.",
1341
+ options: [{
1342
+ value: "auto",
1343
+ label: "Auto (location-based)"
1344
+ }, {
1345
+ value: "manual",
1346
+ label: "Manual"
1347
+ }],
1348
+ value: config.mode
1316
1349
  },
1317
- options,
1318
- value: config.manualIds.map(String)
1319
- }]
1350
+ {
1351
+ type: "multiselect",
1352
+ key: LINKED_IDS_CONFIG_KEY,
1353
+ label: "Manually linked devices",
1354
+ description: "Used in manual mode (children stay linked regardless).",
1355
+ showWhen: {
1356
+ field: LINKED_MODE_CONFIG_KEY,
1357
+ equals: "manual"
1358
+ },
1359
+ options,
1360
+ value: config.manualIds.map(String)
1361
+ },
1362
+ {
1363
+ type: "multiselect",
1364
+ key: LINKED_TRACKED_IDS_CONFIG_KEY,
1365
+ label: "Devices that produce tracked events",
1366
+ description: "Linked devices whose state changes materialize a synthetic tracked event on this camera. Default: all linked devices.",
1367
+ options: trackedOptions,
1368
+ value: trackedValue
1369
+ }
1370
+ ]
1320
1371
  }] };
1321
1372
  }
1322
1373
  /**
@@ -1329,6 +1380,15 @@ async function applyLinkedDevicesPatch(pctx, deviceId, patch) {
1329
1380
  const next = { ...await pctx.settings.readDeviceStore(deviceId) };
1330
1381
  if ("_linkedDevicesMode" in patch) next[LINKED_MODE_CONFIG_KEY] = patch["_linkedDevicesMode"] === "manual" ? "manual" : "auto";
1331
1382
  if ("_linkedDeviceIds" in patch) next[LINKED_IDS_CONFIG_KEY] = [...parseLinkedDevicesConfig({ [LINKED_IDS_CONFIG_KEY]: patch[LINKED_IDS_CONFIG_KEY] }).manualIds];
1383
+ if ("_linkedDeviceTrackedIds" in patch) {
1384
+ const raw = patch[LINKED_TRACKED_IDS_CONFIG_KEY];
1385
+ const ids = [];
1386
+ if (Array.isArray(raw)) for (const v of raw) {
1387
+ const n = typeof v === "number" ? v : typeof v === "string" ? Number(v) : NaN;
1388
+ if (Number.isInteger(n) && !ids.includes(n)) ids.push(n);
1389
+ }
1390
+ next[LINKED_TRACKED_IDS_CONFIG_KEY] = ids;
1391
+ }
1332
1392
  await pctx.settings.writeDeviceStore(deviceId, next);
1333
1393
  return { success: true };
1334
1394
  }
@@ -1,4 +1,4 @@
1
- import { A as getByPath, At as EventCategory, Ct as isDeviceConfigCap, D as evaluateLinkExpression, E as enumerateSchemaFields, H as normalizeUnit, S as deviceStatusCapability, T as enumerateItemArrayFields, W as parseStreamParamsFormPatch, Y as setByPath, a as DeviceStatusSchema, at as BaseAddon, b as deviceManagerCapability, c as STREAM_PROFILE_META, dt as DeviceType, g as applyTransform, i as CAP_NAMES_WITH_STATUS, it as errMsg, kt as sleep, lt as DeviceFeature, mt as WELL_KNOWN_TAB_MAP, rt as validateExpressionSource, t as ALL_CAPABILITY_DEFINITIONS, tt as toExpressionValue, ut as DeviceRole, x as deviceStateCapability, y as buildStreamParamsConfigSchema } from "../../dist-D7-BTTgZ.mjs";
1
+ import { A as getByPath, At as EventCategory, Ct as isDeviceConfigCap, D as evaluateLinkExpression, E as enumerateSchemaFields, H as normalizeUnit, S as deviceStatusCapability, T as enumerateItemArrayFields, W as parseStreamParamsFormPatch, Y as setByPath, a as DeviceStatusSchema, at as BaseAddon, b as deviceManagerCapability, c as STREAM_PROFILE_META, dt as DeviceType, g as applyTransform, i as CAP_NAMES_WITH_STATUS, it as errMsg, kt as sleep, lt as DeviceFeature, mt as WELL_KNOWN_TAB_MAP, rt as validateExpressionSource, t as ALL_CAPABILITY_DEFINITIONS, tt as toExpressionValue, ut as DeviceRole, x as deviceStateCapability, y as buildStreamParamsConfigSchema } from "../../dist-DTTTjPCL.mjs";
2
2
  import { canonicalDeviceFingerprint } from "@camstack/types/node";
3
3
  import { z } from "zod";
4
4
  import { randomUUID } from "node:crypto";
@@ -1204,6 +1204,9 @@ async function testField(pctx, input) {
1204
1204
  /** Reserved device-config keys (cf. `_profileMap`). */
1205
1205
  var LINKED_MODE_CONFIG_KEY = "_linkedDevicesMode";
1206
1206
  var LINKED_IDS_CONFIG_KEY = "_linkedDeviceIds";
1207
+ /** Reserved key: subset of linked devices that materialize synthetic tracked
1208
+ * events on the camera. Absent ⇒ ALL linked devices produce tracked events. */
1209
+ var LINKED_TRACKED_IDS_CONFIG_KEY = "_linkedDeviceTrackedIds";
1207
1210
  /** Parse the two reserved keys out of a device-config blob. Tolerant:
1208
1211
  * ids may arrive as numbers or numeric strings (the multiselect field
1209
1212
  * stores string option values); anything else is dropped. */
@@ -1239,6 +1242,25 @@ function resolveLinkedDeviceIds(params) {
1239
1242
  ids.delete(selfId);
1240
1243
  return [...ids];
1241
1244
  }
1245
+ /**
1246
+ * Which linked devices materialize synthetic tracked events on the camera.
1247
+ * Absent / non-array config key ⇒ ALL linked devices (back-compat with the
1248
+ * pre-existing "every linked device produces events" behaviour). Otherwise the
1249
+ * configured subset intersected with the currently-resolved linked set (a
1250
+ * picked id no longer linked is dropped). Ids may arrive as numbers or numeric
1251
+ * strings (the multiselect stores string option values); non-numeric entries
1252
+ * are ignored.
1253
+ */
1254
+ function resolveTrackedEventDeviceIds(config, linkedIds) {
1255
+ const raw = config[LINKED_TRACKED_IDS_CONFIG_KEY];
1256
+ if (!Array.isArray(raw)) return linkedIds;
1257
+ const picked = /* @__PURE__ */ new Set();
1258
+ for (const v of raw) {
1259
+ const n = typeof v === "number" ? v : typeof v === "string" ? Number(v) : NaN;
1260
+ if (Number.isInteger(n)) picked.add(n);
1261
+ }
1262
+ return linkedIds.filter((id) => picked.has(id));
1263
+ }
1242
1264
  /** Cap implementation of `getLinkedDevices`. */
1243
1265
  async function getLinkedDevices(pctx, input) {
1244
1266
  const { deviceId } = input;
@@ -1251,6 +1273,7 @@ async function getLinkedDevices(pctx, input) {
1251
1273
  config,
1252
1274
  candidates: all
1253
1275
  });
1276
+ const trackedIds = new Set(resolveTrackedEventDeviceIds(blob, ids));
1254
1277
  const devices = [];
1255
1278
  for (const id of ids) {
1256
1279
  const d = byId.get(id);
@@ -1259,7 +1282,8 @@ async function getLinkedDevices(pctx, input) {
1259
1282
  deviceId: d.id,
1260
1283
  name: d.name,
1261
1284
  location: d.location,
1262
- features: d.features
1285
+ features: d.features,
1286
+ producesTrackedEvents: trackedIds.has(d.id)
1263
1287
  });
1264
1288
  }
1265
1289
  return {
@@ -1282,36 +1306,63 @@ async function buildLinkedDevicesContribution(pctx, deviceId) {
1282
1306
  value: String(d.id),
1283
1307
  label: d.location !== null ? `${d.name} (${d.location})` : d.name
1284
1308
  }));
1309
+ const linkedIds = resolveLinkedDeviceIds({
1310
+ selfId: deviceId,
1311
+ selfLocation: all.find((d) => d.id === deviceId)?.location ?? null,
1312
+ config,
1313
+ candidates: all
1314
+ });
1315
+ const byId = new Map(all.map((d) => [d.id, d]));
1316
+ const trackedOptions = linkedIds.flatMap((id) => {
1317
+ const d = byId.get(id);
1318
+ if (!d) return [];
1319
+ return [{
1320
+ value: String(d.id),
1321
+ label: d.location !== null ? `${d.name} (${d.location})` : d.name
1322
+ }];
1323
+ });
1324
+ const trackedValue = resolveTrackedEventDeviceIds(blob, linkedIds).map(String);
1285
1325
  return { sections: [{
1286
1326
  id: "linked-devices",
1287
1327
  title: "Linked devices",
1288
1328
  description: "Companion devices associated with this camera. Device-tree children are always linked; auto mode also links every device sharing the camera location, manual mode links the picked list instead.",
1289
1329
  order: 70,
1290
- fields: [{
1291
- type: "select",
1292
- key: LINKED_MODE_CONFIG_KEY,
1293
- label: "Link mode",
1294
- description: "Auto: children + same-location devices. Manual: children + the list below.",
1295
- options: [{
1296
- value: "auto",
1297
- label: "Auto (location-based)"
1298
- }, {
1299
- value: "manual",
1300
- label: "Manual"
1301
- }],
1302
- value: config.mode
1303
- }, {
1304
- type: "multiselect",
1305
- key: LINKED_IDS_CONFIG_KEY,
1306
- label: "Manually linked devices",
1307
- description: "Used in manual mode (children stay linked regardless).",
1308
- showWhen: {
1309
- field: LINKED_MODE_CONFIG_KEY,
1310
- equals: "manual"
1330
+ fields: [
1331
+ {
1332
+ type: "select",
1333
+ key: LINKED_MODE_CONFIG_KEY,
1334
+ label: "Link mode",
1335
+ description: "Auto: children + same-location devices. Manual: children + the list below.",
1336
+ options: [{
1337
+ value: "auto",
1338
+ label: "Auto (location-based)"
1339
+ }, {
1340
+ value: "manual",
1341
+ label: "Manual"
1342
+ }],
1343
+ value: config.mode
1311
1344
  },
1312
- options,
1313
- value: config.manualIds.map(String)
1314
- }]
1345
+ {
1346
+ type: "multiselect",
1347
+ key: LINKED_IDS_CONFIG_KEY,
1348
+ label: "Manually linked devices",
1349
+ description: "Used in manual mode (children stay linked regardless).",
1350
+ showWhen: {
1351
+ field: LINKED_MODE_CONFIG_KEY,
1352
+ equals: "manual"
1353
+ },
1354
+ options,
1355
+ value: config.manualIds.map(String)
1356
+ },
1357
+ {
1358
+ type: "multiselect",
1359
+ key: LINKED_TRACKED_IDS_CONFIG_KEY,
1360
+ label: "Devices that produce tracked events",
1361
+ description: "Linked devices whose state changes materialize a synthetic tracked event on this camera. Default: all linked devices.",
1362
+ options: trackedOptions,
1363
+ value: trackedValue
1364
+ }
1365
+ ]
1315
1366
  }] };
1316
1367
  }
1317
1368
  /**
@@ -1324,6 +1375,15 @@ async function applyLinkedDevicesPatch(pctx, deviceId, patch) {
1324
1375
  const next = { ...await pctx.settings.readDeviceStore(deviceId) };
1325
1376
  if ("_linkedDevicesMode" in patch) next[LINKED_MODE_CONFIG_KEY] = patch["_linkedDevicesMode"] === "manual" ? "manual" : "auto";
1326
1377
  if ("_linkedDeviceIds" in patch) next[LINKED_IDS_CONFIG_KEY] = [...parseLinkedDevicesConfig({ [LINKED_IDS_CONFIG_KEY]: patch[LINKED_IDS_CONFIG_KEY] }).manualIds];
1378
+ if ("_linkedDeviceTrackedIds" in patch) {
1379
+ const raw = patch[LINKED_TRACKED_IDS_CONFIG_KEY];
1380
+ const ids = [];
1381
+ if (Array.isArray(raw)) for (const v of raw) {
1382
+ const n = typeof v === "number" ? v : typeof v === "string" ? Number(v) : NaN;
1383
+ if (Number.isInteger(n) && !ids.includes(n)) ids.push(n);
1384
+ }
1385
+ next[LINKED_TRACKED_IDS_CONFIG_KEY] = ids;
1386
+ }
1327
1387
  await pctx.settings.writeDeviceStore(deviceId, next);
1328
1388
  return { success: true };
1329
1389
  }
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  //#region src/builtins/doorbell/trigger-engine.ts
8
8
  /**
9
9
  * Pure trigger logic for the virtual-doorbell builtin — edge detection over
@@ -1,4 +1,4 @@
1
- import { At as EventCategory, C as doorbellCapability, at as BaseAddon, dt as DeviceType, it as errMsg, vt as createEvent } from "../../dist-D7-BTTgZ.mjs";
1
+ import { At as EventCategory, C as doorbellCapability, at as BaseAddon, dt as DeviceType, it as errMsg, vt as createEvent } from "../../dist-DTTTjPCL.mjs";
2
2
  //#region src/builtins/doorbell/trigger-engine.ts
3
3
  /**
4
4
  * Pure trigger logic for the virtual-doorbell builtin — edge detection over
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  const require_formatter = require("../../formatter-DqAKDlvN.js");
8
8
  //#region src/builtins/hub-forwarder/hub-forwarder-destination.ts
9
9
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
@@ -1,4 +1,4 @@
1
- import { R as logDestinationCapability, at as BaseAddon } from "../../dist-D7-BTTgZ.mjs";
1
+ import { R as logDestinationCapability, at as BaseAddon } from "../../dist-DTTTjPCL.mjs";
2
2
  import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
3
3
  //#region src/builtins/hub-forwarder/hub-forwarder-destination.ts
4
4
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  node_crypto = require_chunk.__toESM(node_crypto);
9
9
  let crypto$1 = require("crypto");
@@ -1,4 +1,4 @@
1
- import { _ as authProviderCapability, at as BaseAddon, d as UserRecordSchema, l as ScopedTokenSchema, nt as userManagementCapability, r as ApiKeyRecordSchema } from "../../dist-D7-BTTgZ.mjs";
1
+ import { _ as authProviderCapability, at as BaseAddon, d as UserRecordSchema, l as ScopedTokenSchema, nt as userManagementCapability, r as ApiKeyRecordSchema } from "../../dist-DTTTjPCL.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import * as crypto$1 from "node:crypto";
4
4
  import { randomUUID } from "node:crypto";
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("../../chunk-Cek0wNdY.js");
3
- const require_dist = require("../../dist-B9OD5Tdn.js");
3
+ const require_dist = require("../../dist-CkdNC8US.js");
4
4
  let node_os = require("node:os");
5
5
  node_os = require_chunk.__toESM(node_os);
6
6
  //#region src/builtins/local-network/local-network.addon.ts
@@ -1,4 +1,4 @@
1
- import { At as EventCategory, L as localNetworkCapability, at as BaseAddon } from "../../dist-D7-BTTgZ.mjs";
1
+ import { At as EventCategory, L as localNetworkCapability, at as BaseAddon } from "../../dist-DTTTjPCL.mjs";
2
2
  import * as os from "node:os";
3
3
  //#region src/builtins/local-network/local-network.addon.ts
4
4
  /**
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  let node_fs = require("node:fs");
8
8
  node_fs = require_chunk.__toESM(node_fs);
9
9
  let node_child_process = require("node:child_process");
@@ -1,4 +1,4 @@
1
- import { At as EventCategory, B as metricsProviderCapability, at as BaseAddon, vt as createEvent } from "../../dist-D7-BTTgZ.mjs";
1
+ import { At as EventCategory, B as metricsProviderCapability, at as BaseAddon, vt as createEvent } from "../../dist-DTTTjPCL.mjs";
2
2
  import * as fs from "node:fs";
3
3
  import { execFile, execFileSync } from "node:child_process";
4
4
  import { promisify } from "node:util";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  let node_fs = require("node:fs");
8
8
  node_fs = require_chunk.__toESM(node_fs);
9
9
  let node_child_process = require("node:child_process");
@@ -1,4 +1,4 @@
1
- import { At as EventCategory, G as platformProbeCapability, J as scoreRuntimes, at as BaseAddon, bt as emitReadiness, it as errMsg, w as enumerateInferenceDevices } from "../../dist-D7-BTTgZ.mjs";
1
+ import { At as EventCategory, G as platformProbeCapability, J as scoreRuntimes, at as BaseAddon, bt as emitReadiness, it as errMsg, w as enumerateInferenceDevices } from "../../dist-DTTTjPCL.mjs";
2
2
  import * as fs from "node:fs";
3
3
  import { execFile } from "node:child_process";
4
4
  import { promisify } from "node:util";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  //#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
8
8
  /**
9
9
  * Reconcile the durable `enabledProviders` set against authoritative
@@ -1,4 +1,4 @@
1
- import { At as EventCategory, at as BaseAddon } from "../../dist-D7-BTTgZ.mjs";
1
+ import { At as EventCategory, at as BaseAddon } from "../../dist-DTTTjPCL.mjs";
2
2
  //#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
3
3
  /**
4
4
  * Reconcile the durable `enabledProviders` set against authoritative
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  let node_child_process = require("node:child_process");
8
8
  //#region src/builtins/snapshot/snapshot-coalescing.ts
9
9
  /**
@@ -1,4 +1,4 @@
1
- import { V as nodePin, Z as snapshotCapability, at as BaseAddon, dt as DeviceType, et as streamQualityLabel, it as errMsg, lt as DeviceFeature } from "../../dist-D7-BTTgZ.mjs";
1
+ import { V as nodePin, Z as snapshotCapability, at as BaseAddon, dt as DeviceType, et as streamQualityLabel, it as errMsg, lt as DeviceFeature } from "../../dist-DTTTjPCL.mjs";
2
2
  import { execFile } from "node:child_process";
3
3
  //#region src/builtins/snapshot/snapshot-coalescing.ts
4
4
  /**
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  let node_fs = require("node:fs");
8
8
  node_fs = require_chunk.__toESM(node_fs);
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { $ as storageProviderCapability, at as BaseAddon, k as filesystemBrowseCapability } from "../../dist-D7-BTTgZ.mjs";
1
+ import { $ as storageProviderCapability, at as BaseAddon, k as filesystemBrowseCapability } from "../../dist-DTTTjPCL.mjs";
2
2
  import * as fs from "node:fs";
3
3
  import * as path$1 from "node:path";
4
4
  import { basename, dirname, join, resolve, sep } from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let better_sqlite3 = require("better-sqlite3");
9
9
  better_sqlite3 = require_chunk.__toESM(better_sqlite3);
@@ -1,4 +1,4 @@
1
- import { Tt as parseJsonUnknown, X as settingsStoreCapability, at as BaseAddon, ht as asJsonObject, it as errMsg, s as RUNTIME_DEFAULTS } from "../../dist-D7-BTTgZ.mjs";
1
+ import { Tt as parseJsonUnknown, X as settingsStoreCapability, at as BaseAddon, ht as asJsonObject, it as errMsg, s as RUNTIME_DEFAULTS } from "../../dist-DTTTjPCL.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import Database from "better-sqlite3";
4
4
  //#region src/builtins/sqlite-storage/sqlite-settings-backend.ts
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  let node_path = require("node:path");
8
8
  node_path = require_chunk.__toESM(node_path);
9
9
  let node_fs_promises = require("node:fs/promises");
@@ -1,4 +1,4 @@
1
- import { Q as storageCapability, at as BaseAddon, u as StorageLocationTypeSchema, wt as parseJsonObject } from "../../dist-D7-BTTgZ.mjs";
1
+ import { Q as storageCapability, at as BaseAddon, u as StorageLocationTypeSchema, wt as parseJsonObject } from "../../dist-DTTTjPCL.mjs";
2
2
  import * as path$1 from "node:path";
3
3
  import * as fs from "node:fs/promises";
4
4
  import { buildStorageLocationRegistry } from "@camstack/system";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  //#region src/builtins/system-config/system-config.addon.ts
8
8
  /**
9
9
  * Built-in `system-config` addon — Phase 4 of the settings redesign.
@@ -1,4 +1,4 @@
1
- import { St as hydrateSchema, at as BaseAddon, it as errMsg } from "../../dist-D7-BTTgZ.mjs";
1
+ import { St as hydrateSchema, at as BaseAddon, it as errMsg } from "../../dist-DTTTjPCL.mjs";
2
2
  //#region src/builtins/system-config/system-config.addon.ts
3
3
  /**
4
4
  * Built-in `system-config` addon — Phase 4 of the settings redesign.
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-B9OD5Tdn.js");
6
+ const require_dist = require("../../dist-CkdNC8US.js");
7
7
  const require_formatter = require("../../formatter-DqAKDlvN.js");
8
8
  let node_path = require("node:path");
9
9
  node_path = require_chunk.__toESM(node_path);
@@ -1,4 +1,4 @@
1
- import { R as logDestinationCapability, at as BaseAddon } from "../../dist-D7-BTTgZ.mjs";
1
+ import { R as logDestinationCapability, at as BaseAddon } from "../../dist-DTTTjPCL.mjs";
2
2
  import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
3
3
  import * as path$1 from "node:path";
4
4
  import path from "node:path";
@@ -8495,7 +8495,8 @@ var PipelineStepInputSchema = zod.z.lazy(() => zod.z.object({
8495
8495
  modelId: zod.z.string().optional(),
8496
8496
  enabled: zod.z.boolean().default(true),
8497
8497
  children: zod.z.array(PipelineStepInputSchema).optional(),
8498
- settings: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
8498
+ settings: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
8499
+ jumpDeviceKey: zod.z.string().optional()
8499
8500
  }));
8500
8501
  var ModelSubstitutionSchema = zod.z.object({
8501
8502
  addonId: zod.z.string(),
@@ -8986,10 +8987,40 @@ var NativeCropBboxSchema = zod.z.object({
8986
8987
  });
8987
8988
  /** Result of a best-effort native-resolution crop (`getNativeCrop`). */
8988
8989
  var NativeCropResultSchema = zod.z.object({
8989
- /** Packed rgb (24-bit) pixels of the crop. */
8990
- bytes: zod.z.instanceof(Uint8Array),
8990
+ /**
8991
+ * Packed rgb (24-bit) pixels of the crop. Present on the DEFAULT (raw) path —
8992
+ * same-node (in-process / UDS) callers get zero-copy RGB and encode locally.
8993
+ * OMITTED when the caller requested `encodeJpeg` (the cross-node compressed
8994
+ * path below), where shipping raw RGB is both an invariant violation and, for
8995
+ * a native full frame (~26 MB at 4K), larger than Moleculer's 10 MB
8996
+ * `maxPacketSize` → the packet is dropped and the call 60s-times-out. That is
8997
+ * the cross-node native-media miss: `bytes` is replaced by `jpeg`.
8998
+ */
8999
+ bytes: zod.z.instanceof(Uint8Array).optional(),
9000
+ /**
9001
+ * Base64 JPEG of the crop — the COMPRESSED cross-node payload. The OWNING node
9002
+ * (which holds the native surface) encodes it in-process, so a native 4K frame
9003
+ * ships as ~0.5–2 MB (well under `maxPacketSize`) and NO raw pixels ever cross
9004
+ * a process boundary (CLAUDE.md invariant #21). Present ONLY when the request
9005
+ * set `encodeJpeg: true`; `bytes` is then absent.
9006
+ */
9007
+ jpeg: zod.z.string().optional(),
8991
9008
  width: zod.z.number().int().positive(),
8992
- height: zod.z.number().int().positive()
9009
+ height: zod.z.number().int().positive(),
9010
+ /**
9011
+ * Which source served this crop, so a quality-sensitive consumer (the native
9012
+ * `keyFrame`) can reject a degraded fallback:
9013
+ * - `native` — cut from the decode worker's retained NATIVE surface (the
9014
+ * quality path).
9015
+ * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
9016
+ * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
9017
+ * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
9018
+ *
9019
+ * OPTIONAL: a pre-tier runner (version skew) omits it — an ABSENT `tier` MUST be
9020
+ * treated as `native` (accepted) by every consumer so mixed-version clusters
9021
+ * keep the pre-tier behaviour. An ROI miss returns `null` (no tier at all).
9022
+ */
9023
+ tier: zod.z.enum(["native", "ram-fullframe"]).optional()
8993
9024
  });
8994
9025
  /** Parent detection context passed to `runDetailSubtree` — the crop's
8995
9026
  * originating detection, in FRAME-space coordinates. Reuses
@@ -9119,6 +9150,20 @@ var RunnerFrameSourceSchema = zod.z.discriminatedUnion("kind", [zod.z.object({ k
9119
9150
  hubHostnameOverride: zod.z.string().optional()
9120
9151
  })]).describe("Per-camera frame-source mode for the runner (P2c)");
9121
9152
  /**
9153
+ * One ENABLED inference device on the runner's node, as the step-tree
9154
+ * device-jump resolver sees it (phase 1). The orchestrator populates this
9155
+ * roster on the attach payload whenever the camera is elected onto a specific
9156
+ * `deviceKey` and the node has ≥2 enabled devices — it is the candidate set the
9157
+ * runner auto-jumps an enrichment step to when the elected device's format
9158
+ * cannot run that step's model. `weight`/`maxSessions` mirror the balancer's
9159
+ * per-device knobs so the auto choice is weighted-least-loaded.
9160
+ */
9161
+ var RunnerInferenceDeviceSchema = zod.z.object({
9162
+ deviceKey: zod.z.string(),
9163
+ weight: zod.z.number().positive().default(1),
9164
+ maxSessions: zod.z.number().int().positive().nullable().default(null)
9165
+ });
9166
+ /**
9122
9167
  * Camera assignment payload sent by `addon-pipeline-orchestrator` to a
9123
9168
  * specific runner instance via `attachCamera`. Carries everything the
9124
9169
  * runner needs to subscribe to the local broker and execute inference.
@@ -9236,7 +9281,16 @@ var RunnerCameraConfigSchema = zod.z.object({
9236
9281
  * omitted ⇒ the runner's default device. The engine itself stays node-local —
9237
9282
  * this only selects WHICH device pool of that node runs the session.
9238
9283
  */
9239
- deviceKey: zod.z.string().optional()
9284
+ deviceKey: zod.z.string().optional(),
9285
+ /**
9286
+ * Step-tree device-jump roster (phase 1): the node's ENABLED inference
9287
+ * devices, populated by the orchestrator ONLY when `deviceKey` is set and the
9288
+ * node has ≥2 enabled devices. The runner uses it to AUTO-jump an enrichment
9289
+ * step whose model has no build for the elected device's format onto another
9290
+ * enabled device of the SAME node (weighted-least-loaded). Absent/single-entry
9291
+ * ⇒ no jump possible; the step runs on `deviceKey`.
9292
+ */
9293
+ inferenceDevices: zod.z.array(RunnerInferenceDeviceSchema).readonly().optional()
9240
9294
  });
9241
9295
  motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
9242
9296
  /**
@@ -9343,15 +9397,31 @@ var pipelineRunnerCapability = {
9343
9397
  * `FrameHandle` that rode an inference-result event and a normalized `bbox`,
9344
9398
  * the runner asks the decode worker still holding that frame's NATIVE
9345
9399
  * surface to GPU/CPU-crop ONLY the ROI at native res and download just the
9346
- * crop. Returns `null` on a miss (handle not registered, or the worker's
9347
- * tiny native-retention ring already evicted the frame) — the caller falls
9348
- * back to a detection-frame crop. Routed to the frame's owning node by
9349
- * `handle.nodeId`; NEVER ships a full native frame.
9400
+ * crop. Routed to the frame's owning node by `handle.nodeId`; NEVER ships a
9401
+ * full native frame.
9402
+ *
9403
+ * Miss behaviour differs by request shape (see `NativeCropResultSchema.tier`):
9404
+ * - an ROI (subject-crop) miss returns `null` — the caller reports the miss
9405
+ * and retries; it is NEVER handed a ≤640 crop masquerading as native.
9406
+ * - a FULL-FRAME miss falls back to the ≤640 RAM `RetainedFrameStore`, tagged
9407
+ * `tier: 'ram-fullframe'` (honest lower-res for the blank-frame guard /
9408
+ * 640-snapshot resolve). A native hit is tagged `tier: 'native'`.
9350
9409
  */
9351
9410
  getNativeCrop: method(zod.z.object({
9352
9411
  handle: FrameHandleSchema,
9353
9412
  bbox: NativeCropBboxSchema,
9354
- maxWidth: zod.z.number().int().positive().optional()
9413
+ maxWidth: zod.z.number().int().positive().optional(),
9414
+ /**
9415
+ * When `true`, the runner encodes the resolved crop to JPEG ON THE
9416
+ * OWNING NODE and returns it in `jpeg` (base64) INSTEAD of raw `bytes`.
9417
+ * Callers set this for CROSS-NODE fetches (`handle.nodeId` is a remote
9418
+ * agent) so the compressed payload fits Moleculer's `maxPacketSize` and
9419
+ * no raw pixels cross the process boundary. Same-node callers omit it
9420
+ * and keep the zero-copy raw `bytes` path. Additive + optional: a
9421
+ * pre-encode runner (version skew) ignores it and returns `bytes`, so
9422
+ * the caller falls back to encoding locally.
9423
+ */
9424
+ encodeJpeg: zod.z.boolean().optional()
9355
9425
  }), NativeCropResultSchema.nullable()),
9356
9426
  /**
9357
9427
  * Two-plane design: run the DETAIL subtree (crop children —
@@ -14081,7 +14151,8 @@ var LinkedDeviceSchema = zod.z.object({
14081
14151
  deviceId: zod.z.number(),
14082
14152
  name: zod.z.string(),
14083
14153
  location: zod.z.string().nullable(),
14084
- features: zod.z.array(zod.z.string())
14154
+ features: zod.z.array(zod.z.string()),
14155
+ producesTrackedEvents: zod.z.boolean().optional()
14085
14156
  });
14086
14157
  var SavedDeviceRowSchema = zod.z.object({
14087
14158
  /** Numeric id reserved at allocateDeviceId time. */
@@ -16307,6 +16378,7 @@ var TrackSchema = zod.z.object({
16307
16378
  deviceId: zod.z.number(),
16308
16379
  className: zod.z.string(),
16309
16380
  label: zod.z.string().optional(),
16381
+ producingDeviceName: zod.z.string().optional(),
16310
16382
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
16311
16383
  source: TrackSourceSchema.optional(),
16312
16384
  firstSeen: zod.z.number(),
@@ -16444,7 +16516,8 @@ var MediaFileKindEnum = zod.z.enum([
16444
16516
  "fullFrameBoxed",
16445
16517
  "faceCrop",
16446
16518
  "plateCrop",
16447
- "keyFrame"
16519
+ "keyFrame",
16520
+ "keyFrameSmall"
16448
16521
  ]);
16449
16522
  var MediaFileSchema = zod.z.object({
16450
16523
  key: zod.z.string(),
@@ -16926,7 +16999,16 @@ var PipelineTemplateSchema = zod.z.object({
16926
16999
  });
16927
17000
  var DeviceStepConfigSchema = zod.z.object({
16928
17001
  modelId: zod.z.string().optional(),
16929
- settings: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
17002
+ settings: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
17003
+ /**
17004
+ * Step-tree device jump (same-node, phase 1) — OPTIONAL manual override.
17005
+ * When set, this step runs on the named enabled device of the SAME node
17006
+ * (`<backend>:<device>`) instead of the camera's elected device, bypassing
17007
+ * the runtime AUTO-jump. The orchestrator rejects a `jumpDeviceKey` pointing
17008
+ * at a disabled/absent device on that node at save time. Absent ⇒ the runner
17009
+ * auto-jumps only when the effective device's format cannot run the step.
17010
+ */
17011
+ jumpDeviceKey: zod.z.string().optional()
16930
17012
  });
16931
17013
  var AgentPipelineSettingsSchema = zod.z.object({
16932
17014
  maxCameras: zod.z.number().int().nonnegative().nullable().default(null),
@@ -8495,7 +8495,8 @@ var PipelineStepInputSchema = z.lazy(() => z.object({
8495
8495
  modelId: z.string().optional(),
8496
8496
  enabled: z.boolean().default(true),
8497
8497
  children: z.array(PipelineStepInputSchema).optional(),
8498
- settings: z.record(z.string(), z.unknown()).optional()
8498
+ settings: z.record(z.string(), z.unknown()).optional(),
8499
+ jumpDeviceKey: z.string().optional()
8499
8500
  }));
8500
8501
  var ModelSubstitutionSchema = z.object({
8501
8502
  addonId: z.string(),
@@ -8986,10 +8987,40 @@ var NativeCropBboxSchema = z.object({
8986
8987
  });
8987
8988
  /** Result of a best-effort native-resolution crop (`getNativeCrop`). */
8988
8989
  var NativeCropResultSchema = z.object({
8989
- /** Packed rgb (24-bit) pixels of the crop. */
8990
- bytes: z.instanceof(Uint8Array),
8990
+ /**
8991
+ * Packed rgb (24-bit) pixels of the crop. Present on the DEFAULT (raw) path —
8992
+ * same-node (in-process / UDS) callers get zero-copy RGB and encode locally.
8993
+ * OMITTED when the caller requested `encodeJpeg` (the cross-node compressed
8994
+ * path below), where shipping raw RGB is both an invariant violation and, for
8995
+ * a native full frame (~26 MB at 4K), larger than Moleculer's 10 MB
8996
+ * `maxPacketSize` → the packet is dropped and the call 60s-times-out. That is
8997
+ * the cross-node native-media miss: `bytes` is replaced by `jpeg`.
8998
+ */
8999
+ bytes: z.instanceof(Uint8Array).optional(),
9000
+ /**
9001
+ * Base64 JPEG of the crop — the COMPRESSED cross-node payload. The OWNING node
9002
+ * (which holds the native surface) encodes it in-process, so a native 4K frame
9003
+ * ships as ~0.5–2 MB (well under `maxPacketSize`) and NO raw pixels ever cross
9004
+ * a process boundary (CLAUDE.md invariant #21). Present ONLY when the request
9005
+ * set `encodeJpeg: true`; `bytes` is then absent.
9006
+ */
9007
+ jpeg: z.string().optional(),
8991
9008
  width: z.number().int().positive(),
8992
- height: z.number().int().positive()
9009
+ height: z.number().int().positive(),
9010
+ /**
9011
+ * Which source served this crop, so a quality-sensitive consumer (the native
9012
+ * `keyFrame`) can reject a degraded fallback:
9013
+ * - `native` — cut from the decode worker's retained NATIVE surface (the
9014
+ * quality path).
9015
+ * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
9016
+ * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
9017
+ * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
9018
+ *
9019
+ * OPTIONAL: a pre-tier runner (version skew) omits it — an ABSENT `tier` MUST be
9020
+ * treated as `native` (accepted) by every consumer so mixed-version clusters
9021
+ * keep the pre-tier behaviour. An ROI miss returns `null` (no tier at all).
9022
+ */
9023
+ tier: z.enum(["native", "ram-fullframe"]).optional()
8993
9024
  });
8994
9025
  /** Parent detection context passed to `runDetailSubtree` — the crop's
8995
9026
  * originating detection, in FRAME-space coordinates. Reuses
@@ -9119,6 +9150,20 @@ var RunnerFrameSourceSchema = z.discriminatedUnion("kind", [z.object({ kind: z.l
9119
9150
  hubHostnameOverride: z.string().optional()
9120
9151
  })]).describe("Per-camera frame-source mode for the runner (P2c)");
9121
9152
  /**
9153
+ * One ENABLED inference device on the runner's node, as the step-tree
9154
+ * device-jump resolver sees it (phase 1). The orchestrator populates this
9155
+ * roster on the attach payload whenever the camera is elected onto a specific
9156
+ * `deviceKey` and the node has ≥2 enabled devices — it is the candidate set the
9157
+ * runner auto-jumps an enrichment step to when the elected device's format
9158
+ * cannot run that step's model. `weight`/`maxSessions` mirror the balancer's
9159
+ * per-device knobs so the auto choice is weighted-least-loaded.
9160
+ */
9161
+ var RunnerInferenceDeviceSchema = z.object({
9162
+ deviceKey: z.string(),
9163
+ weight: z.number().positive().default(1),
9164
+ maxSessions: z.number().int().positive().nullable().default(null)
9165
+ });
9166
+ /**
9122
9167
  * Camera assignment payload sent by `addon-pipeline-orchestrator` to a
9123
9168
  * specific runner instance via `attachCamera`. Carries everything the
9124
9169
  * runner needs to subscribe to the local broker and execute inference.
@@ -9236,7 +9281,16 @@ var RunnerCameraConfigSchema = z.object({
9236
9281
  * omitted ⇒ the runner's default device. The engine itself stays node-local —
9237
9282
  * this only selects WHICH device pool of that node runs the session.
9238
9283
  */
9239
- deviceKey: z.string().optional()
9284
+ deviceKey: z.string().optional(),
9285
+ /**
9286
+ * Step-tree device-jump roster (phase 1): the node's ENABLED inference
9287
+ * devices, populated by the orchestrator ONLY when `deviceKey` is set and the
9288
+ * node has ≥2 enabled devices. The runner uses it to AUTO-jump an enrichment
9289
+ * step whose model has no build for the elected device's format onto another
9290
+ * enabled device of the SAME node (weighted-least-loaded). Absent/single-entry
9291
+ * ⇒ no jump possible; the step runs on `deviceKey`.
9292
+ */
9293
+ inferenceDevices: z.array(RunnerInferenceDeviceSchema).readonly().optional()
9240
9294
  });
9241
9295
  motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
9242
9296
  /**
@@ -9343,15 +9397,31 @@ var pipelineRunnerCapability = {
9343
9397
  * `FrameHandle` that rode an inference-result event and a normalized `bbox`,
9344
9398
  * the runner asks the decode worker still holding that frame's NATIVE
9345
9399
  * surface to GPU/CPU-crop ONLY the ROI at native res and download just the
9346
- * crop. Returns `null` on a miss (handle not registered, or the worker's
9347
- * tiny native-retention ring already evicted the frame) — the caller falls
9348
- * back to a detection-frame crop. Routed to the frame's owning node by
9349
- * `handle.nodeId`; NEVER ships a full native frame.
9400
+ * crop. Routed to the frame's owning node by `handle.nodeId`; NEVER ships a
9401
+ * full native frame.
9402
+ *
9403
+ * Miss behaviour differs by request shape (see `NativeCropResultSchema.tier`):
9404
+ * - an ROI (subject-crop) miss returns `null` — the caller reports the miss
9405
+ * and retries; it is NEVER handed a ≤640 crop masquerading as native.
9406
+ * - a FULL-FRAME miss falls back to the ≤640 RAM `RetainedFrameStore`, tagged
9407
+ * `tier: 'ram-fullframe'` (honest lower-res for the blank-frame guard /
9408
+ * 640-snapshot resolve). A native hit is tagged `tier: 'native'`.
9350
9409
  */
9351
9410
  getNativeCrop: method(z.object({
9352
9411
  handle: FrameHandleSchema,
9353
9412
  bbox: NativeCropBboxSchema,
9354
- maxWidth: z.number().int().positive().optional()
9413
+ maxWidth: z.number().int().positive().optional(),
9414
+ /**
9415
+ * When `true`, the runner encodes the resolved crop to JPEG ON THE
9416
+ * OWNING NODE and returns it in `jpeg` (base64) INSTEAD of raw `bytes`.
9417
+ * Callers set this for CROSS-NODE fetches (`handle.nodeId` is a remote
9418
+ * agent) so the compressed payload fits Moleculer's `maxPacketSize` and
9419
+ * no raw pixels cross the process boundary. Same-node callers omit it
9420
+ * and keep the zero-copy raw `bytes` path. Additive + optional: a
9421
+ * pre-encode runner (version skew) ignores it and returns `bytes`, so
9422
+ * the caller falls back to encoding locally.
9423
+ */
9424
+ encodeJpeg: z.boolean().optional()
9355
9425
  }), NativeCropResultSchema.nullable()),
9356
9426
  /**
9357
9427
  * Two-plane design: run the DETAIL subtree (crop children —
@@ -14081,7 +14151,8 @@ var LinkedDeviceSchema = z.object({
14081
14151
  deviceId: z.number(),
14082
14152
  name: z.string(),
14083
14153
  location: z.string().nullable(),
14084
- features: z.array(z.string())
14154
+ features: z.array(z.string()),
14155
+ producesTrackedEvents: z.boolean().optional()
14085
14156
  });
14086
14157
  var SavedDeviceRowSchema = z.object({
14087
14158
  /** Numeric id reserved at allocateDeviceId time. */
@@ -16307,6 +16378,7 @@ var TrackSchema = z.object({
16307
16378
  deviceId: z.number(),
16308
16379
  className: z.string(),
16309
16380
  label: z.string().optional(),
16381
+ producingDeviceName: z.string().optional(),
16310
16382
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
16311
16383
  source: TrackSourceSchema.optional(),
16312
16384
  firstSeen: z.number(),
@@ -16444,7 +16516,8 @@ var MediaFileKindEnum = z.enum([
16444
16516
  "fullFrameBoxed",
16445
16517
  "faceCrop",
16446
16518
  "plateCrop",
16447
- "keyFrame"
16519
+ "keyFrame",
16520
+ "keyFrameSmall"
16448
16521
  ]);
16449
16522
  var MediaFileSchema = z.object({
16450
16523
  key: z.string(),
@@ -16926,7 +16999,16 @@ var PipelineTemplateSchema = z.object({
16926
16999
  });
16927
17000
  var DeviceStepConfigSchema = z.object({
16928
17001
  modelId: z.string().optional(),
16929
- settings: z.record(z.string(), z.unknown()).optional()
17002
+ settings: z.record(z.string(), z.unknown()).optional(),
17003
+ /**
17004
+ * Step-tree device jump (same-node, phase 1) — OPTIONAL manual override.
17005
+ * When set, this step runs on the named enabled device of the SAME node
17006
+ * (`<backend>:<device>`) instead of the camera's elected device, bypassing
17007
+ * the runtime AUTO-jump. The orchestrator rejects a `jumpDeviceKey` pointing
17008
+ * at a disabled/absent device on that node at save time. Absent ⇒ the runner
17009
+ * auto-jumps only when the effective device's format cannot run the step.
17010
+ */
17011
+ jumpDeviceKey: z.string().optional()
16930
17012
  });
16931
17013
  var AgentPipelineSettingsSchema = z.object({
16932
17014
  maxCameras: z.number().int().nonnegative().nullable().default(null),
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("./chunk-Cek0wNdY.js");
3
- const require_dist = require("./dist-B9OD5Tdn.js");
3
+ const require_dist = require("./dist-CkdNC8US.js");
4
4
  const require_model_download_service = require("./model-download-service-hf0ookyy.js");
5
- const require_manifest_python_deps = require("./manifest-python-deps-DXqcuOha.js");
5
+ const require_manifest_python_deps = require("./manifest-python-deps-DRq5MreI.js");
6
6
  const require_resource_monitor = require("./resource-monitor-DNNomR-i.js");
7
7
  const require_builtins_sqlite_storage_filesystem_storage_addon = require("./builtins/sqlite-storage/filesystem-storage.addon.js");
8
8
  const require_builtins_sqlite_storage_sqlite_settings_addon = require("./builtins/sqlite-storage/sqlite-settings.addon.js");
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { At as EventCategory$1, Dt as resolveCapMount, Et as readinessKey, F as kebabToCamel, I as lifecycleJobSchema, K as procedureAuthKey, M as isCollectionArrayMethod, N as isObjectInput, O as extractNestedAddonId, Ot as scopeKey, P as isVoidInput, Tt as parseJsonUnknown$1, U as objectInputDeclaresAddonId, _t as asString$1, ct as DEVICE_STATUS_METHOD, ft as ReadinessRegistry, gt as asNumber, ht as asJsonObject$1, it as errMsg$1, j as isArrayOutputSchema, o as METHOD_ACCESS_MAP, ot as DATAPLANE_SECRET_HEADER$1, p as addonSettingsCapability, pt as ReadinessTimeoutError, s as RUNTIME_DEFAULTS, st as DEVICE_SETTINGS_CONTRIBUTION_METHODS, t as ALL_CAPABILITY_DEFINITIONS, vt as createEvent, wt as parseJsonObject, xt as expandCapMethods, yt as emitDownForOwnedCaps, z as looseSchema } from "./dist-D7-BTTgZ.mjs";
1
+ import { At as EventCategory$1, Dt as resolveCapMount, Et as readinessKey, F as kebabToCamel, I as lifecycleJobSchema, K as procedureAuthKey, M as isCollectionArrayMethod, N as isObjectInput, O as extractNestedAddonId, Ot as scopeKey, P as isVoidInput, Tt as parseJsonUnknown$1, U as objectInputDeclaresAddonId, _t as asString$1, ct as DEVICE_STATUS_METHOD, ft as ReadinessRegistry, gt as asNumber, ht as asJsonObject$1, it as errMsg$1, j as isArrayOutputSchema, o as METHOD_ACCESS_MAP, ot as DATAPLANE_SECRET_HEADER$1, p as addonSettingsCapability, pt as ReadinessTimeoutError, s as RUNTIME_DEFAULTS, st as DEVICE_SETTINGS_CONTRIBUTION_METHODS, t as ALL_CAPABILITY_DEFINITIONS, vt as createEvent, wt as parseJsonObject, xt as expandCapMethods, yt as emitDownForOwnedCaps, z as looseSchema } from "./dist-DTTTjPCL.mjs";
2
2
  import { a as downloadModel, c as getModelFilePath, d as contentTypeFor, f as createAuthenticatedFileServer, h as resolveFilePath, i as downloadFile, l as isModelDownloaded, m as parseTokenizedUrl, n as collectModelFiles, o as ensureModel, p as parseRangeHeader, r as deleteModelFromDisk, s as fetchJson, t as ModelDownloadService, u as createFileDataPlaneHandler } from "./model-download-service-Cp9f4dk6.mjs";
3
- import { $ as buildNativeCapProxy, A as createHubCapForwardService, B as AGENT_CAP_FWD_ACTION, C as brokerTransportLink, Ct as createAddonDataPlaneFacility, D as localProviderLink, E as ipcParentLink, F as createUdsLogger, G as callWithServiceDiscovery, H as CapRouteResolver, I as createUdsLoggerWithControl, J as UdsLocalTransportServer, K as createLocalTransport, L as LocalChildClient, M as createUdsEventBridge, N as createUdsEventBus, O as HUB_CAP_FWD_ACTION, P as udsChildLogToWorkerEntry, Q as encodeFrame, R as LocalChildRegistry, S as brokerCallForCap, St as resolveAddonClass, T as ipcChildLink, U as CapRouteError, V as AGENT_CAP_FWD_SERVICE, W as classifyCapRoute, X as localEndpointPath, Y as SocketChannel, Z as FrameDecoder, _ as createKernelHwAccel, _t as CapabilityHandle, a as getWorkerDeviceRegistry, b as __resetCapUsageRegistryForTests, bt as resolveNpmInvocation, c as setHubConnected, ct as NATIVE_PROVIDER_SERVICE_INFIX, d as getBrokerEventBus, dt as capBareAction, et as buildUdsNativeCapProxy, f as getMoleculerEventStats, ft as capServiceName, g as AddonDepsManager, gt as DeviceRegistry, h as subscribePassthrough, ht as serializeTypedArrays, i as createUdsAddonContext, it as mountNativeCapService, j as createParentUnownedCallHandler, k as HUB_CAP_FWD_SERVICE, l as EVENT_TOPIC_PREFIX, lt as capActionName, m as setNodeEventInterest, mt as deserializeTypedArrays, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as createAddonService, p as registerEventBusService, pt as parseCapAction, q as UdsLocalTransportClient, r as createAddonContext, s as getOrInitReadinessRegistryForClient, st as validateProviderRegistrations, t as installManifestPythonDeps, tt as createBrokerDeviceManagerApi, u as clusterEventTopic, ut as capActionSuffix, v as resolveHwAccel, vt as CapabilityUnavailableError, w as buildLinkChain, x as getCapUsageRegistry, xt as runNpm, y as CapUsageRegistry, yt as installManifestNativeDeps, z as UDS_NO_ROUTE_PREFIX } from "./manifest-python-deps-D7EIakIT.mjs";
3
+ import { $ as buildNativeCapProxy, A as createHubCapForwardService, B as AGENT_CAP_FWD_ACTION, C as brokerTransportLink, Ct as createAddonDataPlaneFacility, D as localProviderLink, E as ipcParentLink, F as createUdsLogger, G as callWithServiceDiscovery, H as CapRouteResolver, I as createUdsLoggerWithControl, J as UdsLocalTransportServer, K as createLocalTransport, L as LocalChildClient, M as createUdsEventBridge, N as createUdsEventBus, O as HUB_CAP_FWD_ACTION, P as udsChildLogToWorkerEntry, Q as encodeFrame, R as LocalChildRegistry, S as brokerCallForCap, St as resolveAddonClass, T as ipcChildLink, U as CapRouteError, V as AGENT_CAP_FWD_SERVICE, W as classifyCapRoute, X as localEndpointPath, Y as SocketChannel, Z as FrameDecoder, _ as createKernelHwAccel, _t as CapabilityHandle, a as getWorkerDeviceRegistry, b as __resetCapUsageRegistryForTests, bt as resolveNpmInvocation, c as setHubConnected, ct as NATIVE_PROVIDER_SERVICE_INFIX, d as getBrokerEventBus, dt as capBareAction, et as buildUdsNativeCapProxy, f as getMoleculerEventStats, ft as capServiceName, g as AddonDepsManager, gt as DeviceRegistry, h as subscribePassthrough, ht as serializeTypedArrays, i as createUdsAddonContext, it as mountNativeCapService, j as createParentUnownedCallHandler, k as HUB_CAP_FWD_SERVICE, l as EVENT_TOPIC_PREFIX, lt as capActionName, m as setNodeEventInterest, mt as deserializeTypedArrays, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as createAddonService, p as registerEventBusService, pt as parseCapAction, q as UdsLocalTransportClient, r as createAddonContext, s as getOrInitReadinessRegistryForClient, st as validateProviderRegistrations, t as installManifestPythonDeps, tt as createBrokerDeviceManagerApi, u as clusterEventTopic, ut as capActionSuffix, v as resolveHwAccel, vt as CapabilityUnavailableError, w as buildLinkChain, x as getCapUsageRegistry, xt as runNpm, y as CapUsageRegistry, yt as installManifestNativeDeps, z as UDS_NO_ROUTE_PREFIX } from "./manifest-python-deps-s_-uULmp.mjs";
4
4
  import { n as getSinglePidStats, t as getPidStats } from "./resource-monitor-Le3l0qS2.mjs";
5
5
  import { FilesystemStorageAddon, t as FilesystemStorageProvider } from "./builtins/sqlite-storage/filesystem-storage.addon.mjs";
6
6
  import { SqliteSettingsAddon, t as SqliteSettingsBackend } from "./builtins/sqlite-storage/sqlite-settings.addon.mjs";
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-Cek0wNdY.js");
2
- const require_dist = require("./dist-B9OD5Tdn.js");
2
+ const require_dist = require("./dist-CkdNC8US.js");
3
3
  let _camstack_types_node = require("@camstack/types/node");
4
4
  let node_http = require("node:http");
5
5
  let node_fs = require("node:fs");
@@ -1,4 +1,4 @@
1
- import { q as readNodePin } from "./dist-D7-BTTgZ.mjs";
1
+ import { q as readNodePin } from "./dist-DTTTjPCL.mjs";
2
2
  import { ensureBinary, ensureFfmpeg, ensurePython, installPythonPackages, installPythonRequirements } from "@camstack/types/node";
3
3
  import { createServer } from "node:http";
4
4
  import * as fs from "node:fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",