@camstack/addon-pipeline 1.0.7 → 1.1.0

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 (34) hide show
  1. package/dist/audio-analyzer/index.js +7 -8
  2. package/dist/audio-analyzer/index.mjs +3 -4
  3. package/dist/audio-codec-nodeav/index.js +2 -2
  4. package/dist/audio-codec-nodeav/index.mjs +2 -2
  5. package/dist/decoder-nodeav/index.js +1 -1
  6. package/dist/decoder-nodeav/index.mjs +1 -1
  7. package/dist/detection-pipeline/index.js +862 -696
  8. package/dist/detection-pipeline/index.mjs +850 -684
  9. package/dist/{dist-CjrjeaDd.mjs → dist-BA6DR_jV.mjs} +128 -5
  10. package/dist/{dist-G45MVm6i.js → dist-BLcTVvol.js} +151 -4
  11. package/dist/{model-download-service-C7AjBsX9-rXY-VFDk.js → model-download-service-RxAOiYvX-C8rTRJy_.js} +36 -6
  12. package/dist/{model-download-service-C7AjBsX9-B0ekM6dF.mjs → model-download-service-RxAOiYvX-CMAvhgO7.mjs} +36 -6
  13. package/dist/motion-wasm/index.js +1 -1
  14. package/dist/motion-wasm/index.mjs +1 -1
  15. package/dist/pipeline-runner/index.js +1 -1
  16. package/dist/pipeline-runner/index.mjs +1 -1
  17. package/dist/recorder/index.js +6 -6
  18. package/dist/recorder/index.mjs +4 -4
  19. package/dist/stream-broker/_stub.js +1 -1
  20. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-Tbqpu0v3.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DrohyZ5L.mjs} +3 -3
  21. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-COa17XL2.mjs +26 -0
  22. package/dist/stream-broker/{hostInit-tIev5Gd9.mjs → hostInit-zLZbYJcg.mjs} +3 -3
  23. package/dist/stream-broker/index.js +26 -26
  24. package/dist/stream-broker/index.mjs +20 -20
  25. package/dist/stream-broker/remoteEntry.js +1 -1
  26. package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-C0kKwNX_.js → MaskShapeCanvas-DI4BY7W2-DJ7ztnFv.js} +1 -1
  27. package/embed-dist/assets/MotionZonesSettings-NcxxQN8r-CQzEnQoq.js +1 -0
  28. package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-C2SRtNe6.js → PrivacyMaskSettings-APgPLF7p-Cl0eOy_U.js} +1 -1
  29. package/embed-dist/assets/{index-B2LRyXWh.js → index-CSuLwWK-.js} +3 -3
  30. package/embed-dist/index.html +1 -1
  31. package/package.json +1 -1
  32. package/python/inference_pool.py +65 -6
  33. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DCsgcqTa.mjs +0 -26
  34. package/embed-dist/assets/MotionZonesSettings-C1EEbk2V-CYtJc892.js +0 -1
@@ -4627,7 +4627,7 @@ function _instanceof(cls, params = {}) {
4627
4627
  return inst;
4628
4628
  }
4629
4629
  //#endregion
4630
- //#region ../types/dist/sleep-D7JeS58T.mjs
4630
+ //#region ../types/dist/sleep-B1dKJAMJ.mjs
4631
4631
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4632
4632
  EventCategory["SystemBoot"] = "system.boot";
4633
4633
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -5601,7 +5601,7 @@ var BaseAddon = class {
5601
5601
  deviceSettingsSchema() {
5602
5602
  return null;
5603
5603
  }
5604
- async getGlobalSettings(overlay, cap) {
5604
+ async getGlobalSettings(overlay, cap, _nodeId) {
5605
5605
  const schema = this.globalSettingsSchema(cap);
5606
5606
  if (!schema) return { sections: [] };
5607
5607
  const raw = await this._ctx?.settings?.readAddonStore() ?? {};
@@ -5610,7 +5610,7 @@ var BaseAddon = class {
5610
5610
  ...overlay
5611
5611
  } : raw);
5612
5612
  }
5613
- async updateGlobalSettings(patch) {
5613
+ async updateGlobalSettings(patch, _nodeId) {
5614
5614
  await this._ctx?.settings?.writeAddonStore(patch);
5615
5615
  await this.resolveConfig();
5616
5616
  await this.onConfigChanged();
@@ -7164,6 +7164,36 @@ var EncodeProfileSchema = object({
7164
7164
  outputArgs: array(string()).optional()
7165
7165
  });
7166
7166
  var HF_BASE_URL = `https://huggingface.co/camstack/camstack-models/resolve/main`;
7167
+ /**
7168
+ * Per-call node pinning for `ctx.api` capability calls.
7169
+ *
7170
+ * A capability call normally resolves to its DEFAULT provider — a `singleton`
7171
+ * cap resolves to the hub, a device-scoped cap to the device's owning node. To
7172
+ * query a SPECIFIC node's provider instead (e.g. a remote agent's own
7173
+ * in-process `platform-probe` hardware, which the hub cannot probe), pin the
7174
+ * call to that node.
7175
+ *
7176
+ * The nodeId rides OUT-OF-BAND in the tRPC call context (NOT in the validated
7177
+ * method args), so capability method signatures stay `nodeId`-free — node
7178
+ * targeting is a property of the CALL, not of the method. The transport lifts
7179
+ * it from `op.context` onto the `CapCallInput.nodeId` field (`ipcParentLink`),
7180
+ * and the hub parent's `onUnownedCall` passes it to the `CapRouteResolver`,
7181
+ * which classifies a pinned agent node as `agent-child-forward`
7182
+ * (`$agent-cap-fwd.forward` → the agent's in-process provider).
7183
+ *
7184
+ * Usage at a call site:
7185
+ *
7186
+ * await api.platformProbe.getCapabilities.query(undefined, nodePin(nodeId))
7187
+ */
7188
+ /** tRPC `op.context` key carrying a per-call node pin. */
7189
+ var CAP_NODE_PIN_CONTEXT_KEY = "__camstackNodePin";
7190
+ /**
7191
+ * Build the tRPC request options that pin a single capability call to `nodeId`.
7192
+ * Pass as the second argument to `.query(input, …)` / `.mutate(input, …)`.
7193
+ */
7194
+ function nodePin(nodeId) {
7195
+ return { context: { [CAP_NODE_PIN_CONTEXT_KEY]: nodeId } };
7196
+ }
7167
7197
  function hfModelUrl(repo, path) {
7168
7198
  return `https://huggingface.co/${repo}/resolve/main/${path}`;
7169
7199
  }
@@ -22372,7 +22402,7 @@ function maskUrlCredentials(rawUrl) {
22372
22402
  u.password = "";
22373
22403
  touched = true;
22374
22404
  }
22375
- for (const key of [...u.searchParams.keys()]) if (isCredentialParam(key)) {
22405
+ for (const key of Array.from(u.searchParams.keys())) if (isCredentialParam(key)) {
22376
22406
  u.searchParams.set(key, "***");
22377
22407
  touched = true;
22378
22408
  }
@@ -22416,5 +22446,98 @@ var RingBuffer = class {
22416
22446
  return result;
22417
22447
  }
22418
22448
  };
22449
+ var AUTO = {
22450
+ value: "auto",
22451
+ label: "Auto"
22452
+ };
22453
+ var CPU = {
22454
+ value: "cpu",
22455
+ label: "CPU"
22456
+ };
22457
+ var RUNTIMES = [
22458
+ {
22459
+ id: "onnx",
22460
+ supports: () => true,
22461
+ devices: (hw) => {
22462
+ if (!hw) return [CPU];
22463
+ const out = [CPU];
22464
+ if (hw.gpu?.type === "nvidia") out.push({
22465
+ value: "cuda",
22466
+ label: "CUDA"
22467
+ });
22468
+ if (hw.npu?.type === "apple-ane") out.push({
22469
+ value: "coreml",
22470
+ label: "CoreML EP"
22471
+ });
22472
+ return out;
22473
+ },
22474
+ defaultDevice: "cpu"
22475
+ },
22476
+ {
22477
+ id: "openvino",
22478
+ supports: (hw) => hw?.arch === "x64" && hw.platform !== "darwin" && hw.gpu?.type === "intel",
22479
+ devices: (hw) => {
22480
+ if (!hw) return [AUTO];
22481
+ const out = [AUTO, CPU];
22482
+ if (hw.gpu?.type === "intel") out.push({
22483
+ value: "gpu",
22484
+ label: "GPU"
22485
+ });
22486
+ if (hw.npu?.type === "intel-npu") out.push({
22487
+ value: "npu",
22488
+ label: "NPU"
22489
+ });
22490
+ return out;
22491
+ },
22492
+ defaultDevice: "auto"
22493
+ },
22494
+ {
22495
+ id: "coreml",
22496
+ supports: (hw) => hw?.platform === "darwin",
22497
+ devices: (hw) => {
22498
+ const all = {
22499
+ value: "all",
22500
+ label: "All (ANE + GPU + CPU)"
22501
+ };
22502
+ if (!hw) return [all];
22503
+ const out = [all];
22504
+ if (hw.npu?.type === "apple-ane") out.push({
22505
+ value: "ane",
22506
+ label: "Apple Neural Engine"
22507
+ });
22508
+ out.push({
22509
+ value: "gpu",
22510
+ label: "GPU"
22511
+ }, CPU);
22512
+ return out;
22513
+ },
22514
+ defaultDevice: "all"
22515
+ }
22516
+ ];
22517
+ function def(id) {
22518
+ const d = RUNTIMES.find((r) => r.id === id);
22519
+ if (!d) throw new Error(`Unknown runtime: ${id}`);
22520
+ return d;
22521
+ }
22522
+ /**
22523
+ * Returns the list of supported runtime IDs for given hardware.
22524
+ * onnx is always included (universal floor); accelerators added when hw matches.
22525
+ */
22526
+ function supportedRuntimes(hw) {
22527
+ return RUNTIMES.filter((r) => r.supports(hw)).map((r) => r.id);
22528
+ }
22529
+ /**
22530
+ * Returns the device options for a given runtime and hardware probe.
22531
+ */
22532
+ function runtimeDevices(id, hw) {
22533
+ return def(id).devices(hw);
22534
+ }
22535
+ /**
22536
+ * Returns the default device string for a given runtime.
22537
+ * onnx → 'cpu', openvino → 'auto', coreml → 'all'
22538
+ */
22539
+ function defaultDeviceFor(id) {
22540
+ return def(id).defaultDevice;
22541
+ }
22419
22542
  //#endregion
22420
- export { boolean as $, pipelineRunnerCapability as A, EventCategory as B, evaluateZoneRules as C, migrateConfigToBands as D, maskUrlCredentials as E, errMsg as F, makeProfileBrokerId as G, createDurableState as H, BaseAddon as I, parseProfileBrokerId as J, makeSourceBrokerId as K, CAM_PROFILE_ORDER as L, storageEvictableCapability as M, streamBrokerCapability as N, motionDetectionCapability as O, webrtcSessionCapability as P, array as Q, DeviceFeature as R, detectionPipelineCapability as S, mapAudioLabelToMacro as T, createEvent as U, asJsonObject as V, hydrateSchema as W, sleep as X, selectAssignedProfileSlots as Y, _enum as Z, audioCodecCapability as _, COCO_TO_MACRO as a, record as at, decoderCapability as b, EncodeProfileSchema as c, RecordingConfigSchema as d, discriminatedUnion as et, RingBuffer as f, audioAnalyzerCapability as g, audioAnalysisCapability as h, COCO_80_LABELS as i, object as it, recordingCapability as j, pipelineExecutorCapability as k, HF_BASE_URL as l, addonWidgetsSourceCapability as m, AUDIO_BACKEND_CHOICES as n, literal as nt, DEFAULT_AUDIO_ANALYZER_CONFIG as o, string as ot, YAMNET_TO_MACRO as p, parseJsonUnknown as q, AUDIO_MACRO_LABELS as r, number as rt, DEFAULT_DECODER_HWACCEL_CONFIG as s, union as st, APPLE_SA_TO_MACRO as t, lazy as tt, HWACCEL_OPTIONS as u, cameraStreamsCapability as v, hfModelUrl as w, defineCustomActions as x, customAction as y, DeviceType as z };
22543
+ export { selectAssignedProfileSlots as $, nodePin as A, BaseAddon as B, detectionPipelineCapability as C, maskUrlCredentials as D, mapAudioLabelToMacro as E, storageEvictableCapability as F, asJsonObject as G, DeviceFeature as H, streamBrokerCapability as I, hydrateSchema as J, createDurableState as K, supportedRuntimes as L, pipelineRunnerCapability as M, recordingCapability as N, migrateConfigToBands as O, runtimeDevices as P, parseProfileBrokerId as Q, webrtcSessionCapability as R, defineCustomActions as S, hfModelUrl as T, DeviceType as U, CAM_PROFILE_ORDER as V, EventCategory as W, makeSourceBrokerId as X, makeProfileBrokerId as Y, parseJsonUnknown as Z, audioCodecCapability as _, COCO_TO_MACRO as a, lazy as at, decoderCapability as b, EncodeProfileSchema as c, object as ct, RecordingConfigSchema as d, union as dt, sleep as et, RingBuffer as f, audioAnalyzerCapability as g, audioAnalysisCapability as h, COCO_80_LABELS as i, discriminatedUnion as it, pipelineExecutorCapability as j, motionDetectionCapability as k, HF_BASE_URL as l, record as lt, addonWidgetsSourceCapability as m, AUDIO_BACKEND_CHOICES as n, array as nt, DEFAULT_AUDIO_ANALYZER_CONFIG as o, literal as ot, YAMNET_TO_MACRO as p, createEvent as q, AUDIO_MACRO_LABELS as r, boolean as rt, DEFAULT_DECODER_HWACCEL_CONFIG as s, number as st, APPLE_SA_TO_MACRO as t, _enum as tt, HWACCEL_OPTIONS as u, string as ut, cameraStreamsCapability as v, evaluateZoneRules as w, defaultDeviceFor as x, customAction as y, errMsg as z };
@@ -4627,7 +4627,7 @@ function _instanceof(cls, params = {}) {
4627
4627
  return inst;
4628
4628
  }
4629
4629
  //#endregion
4630
- //#region ../types/dist/sleep-D7JeS58T.mjs
4630
+ //#region ../types/dist/sleep-B1dKJAMJ.mjs
4631
4631
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4632
4632
  EventCategory["SystemBoot"] = "system.boot";
4633
4633
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -5601,7 +5601,7 @@ var BaseAddon = class {
5601
5601
  deviceSettingsSchema() {
5602
5602
  return null;
5603
5603
  }
5604
- async getGlobalSettings(overlay, cap) {
5604
+ async getGlobalSettings(overlay, cap, _nodeId) {
5605
5605
  const schema = this.globalSettingsSchema(cap);
5606
5606
  if (!schema) return { sections: [] };
5607
5607
  const raw = await this._ctx?.settings?.readAddonStore() ?? {};
@@ -5610,7 +5610,7 @@ var BaseAddon = class {
5610
5610
  ...overlay
5611
5611
  } : raw);
5612
5612
  }
5613
- async updateGlobalSettings(patch) {
5613
+ async updateGlobalSettings(patch, _nodeId) {
5614
5614
  await this._ctx?.settings?.writeAddonStore(patch);
5615
5615
  await this.resolveConfig();
5616
5616
  await this.onConfigChanged();
@@ -7164,6 +7164,36 @@ var EncodeProfileSchema = object({
7164
7164
  outputArgs: array(string()).optional()
7165
7165
  });
7166
7166
  var HF_BASE_URL = `https://huggingface.co/camstack/camstack-models/resolve/main`;
7167
+ /**
7168
+ * Per-call node pinning for `ctx.api` capability calls.
7169
+ *
7170
+ * A capability call normally resolves to its DEFAULT provider — a `singleton`
7171
+ * cap resolves to the hub, a device-scoped cap to the device's owning node. To
7172
+ * query a SPECIFIC node's provider instead (e.g. a remote agent's own
7173
+ * in-process `platform-probe` hardware, which the hub cannot probe), pin the
7174
+ * call to that node.
7175
+ *
7176
+ * The nodeId rides OUT-OF-BAND in the tRPC call context (NOT in the validated
7177
+ * method args), so capability method signatures stay `nodeId`-free — node
7178
+ * targeting is a property of the CALL, not of the method. The transport lifts
7179
+ * it from `op.context` onto the `CapCallInput.nodeId` field (`ipcParentLink`),
7180
+ * and the hub parent's `onUnownedCall` passes it to the `CapRouteResolver`,
7181
+ * which classifies a pinned agent node as `agent-child-forward`
7182
+ * (`$agent-cap-fwd.forward` → the agent's in-process provider).
7183
+ *
7184
+ * Usage at a call site:
7185
+ *
7186
+ * await api.platformProbe.getCapabilities.query(undefined, nodePin(nodeId))
7187
+ */
7188
+ /** tRPC `op.context` key carrying a per-call node pin. */
7189
+ var CAP_NODE_PIN_CONTEXT_KEY = "__camstackNodePin";
7190
+ /**
7191
+ * Build the tRPC request options that pin a single capability call to `nodeId`.
7192
+ * Pass as the second argument to `.query(input, …)` / `.mutate(input, …)`.
7193
+ */
7194
+ function nodePin(nodeId) {
7195
+ return { context: { [CAP_NODE_PIN_CONTEXT_KEY]: nodeId } };
7196
+ }
7167
7197
  function hfModelUrl(repo, path) {
7168
7198
  return `https://huggingface.co/${repo}/resolve/main/${path}`;
7169
7199
  }
@@ -22372,7 +22402,7 @@ function maskUrlCredentials(rawUrl) {
22372
22402
  u.password = "";
22373
22403
  touched = true;
22374
22404
  }
22375
- for (const key of [...u.searchParams.keys()]) if (isCredentialParam(key)) {
22405
+ for (const key of Array.from(u.searchParams.keys())) if (isCredentialParam(key)) {
22376
22406
  u.searchParams.set(key, "***");
22377
22407
  touched = true;
22378
22408
  }
@@ -22416,6 +22446,99 @@ var RingBuffer = class {
22416
22446
  return result;
22417
22447
  }
22418
22448
  };
22449
+ var AUTO = {
22450
+ value: "auto",
22451
+ label: "Auto"
22452
+ };
22453
+ var CPU = {
22454
+ value: "cpu",
22455
+ label: "CPU"
22456
+ };
22457
+ var RUNTIMES = [
22458
+ {
22459
+ id: "onnx",
22460
+ supports: () => true,
22461
+ devices: (hw) => {
22462
+ if (!hw) return [CPU];
22463
+ const out = [CPU];
22464
+ if (hw.gpu?.type === "nvidia") out.push({
22465
+ value: "cuda",
22466
+ label: "CUDA"
22467
+ });
22468
+ if (hw.npu?.type === "apple-ane") out.push({
22469
+ value: "coreml",
22470
+ label: "CoreML EP"
22471
+ });
22472
+ return out;
22473
+ },
22474
+ defaultDevice: "cpu"
22475
+ },
22476
+ {
22477
+ id: "openvino",
22478
+ supports: (hw) => hw?.arch === "x64" && hw.platform !== "darwin" && hw.gpu?.type === "intel",
22479
+ devices: (hw) => {
22480
+ if (!hw) return [AUTO];
22481
+ const out = [AUTO, CPU];
22482
+ if (hw.gpu?.type === "intel") out.push({
22483
+ value: "gpu",
22484
+ label: "GPU"
22485
+ });
22486
+ if (hw.npu?.type === "intel-npu") out.push({
22487
+ value: "npu",
22488
+ label: "NPU"
22489
+ });
22490
+ return out;
22491
+ },
22492
+ defaultDevice: "auto"
22493
+ },
22494
+ {
22495
+ id: "coreml",
22496
+ supports: (hw) => hw?.platform === "darwin",
22497
+ devices: (hw) => {
22498
+ const all = {
22499
+ value: "all",
22500
+ label: "All (ANE + GPU + CPU)"
22501
+ };
22502
+ if (!hw) return [all];
22503
+ const out = [all];
22504
+ if (hw.npu?.type === "apple-ane") out.push({
22505
+ value: "ane",
22506
+ label: "Apple Neural Engine"
22507
+ });
22508
+ out.push({
22509
+ value: "gpu",
22510
+ label: "GPU"
22511
+ }, CPU);
22512
+ return out;
22513
+ },
22514
+ defaultDevice: "all"
22515
+ }
22516
+ ];
22517
+ function def(id) {
22518
+ const d = RUNTIMES.find((r) => r.id === id);
22519
+ if (!d) throw new Error(`Unknown runtime: ${id}`);
22520
+ return d;
22521
+ }
22522
+ /**
22523
+ * Returns the list of supported runtime IDs for given hardware.
22524
+ * onnx is always included (universal floor); accelerators added when hw matches.
22525
+ */
22526
+ function supportedRuntimes(hw) {
22527
+ return RUNTIMES.filter((r) => r.supports(hw)).map((r) => r.id);
22528
+ }
22529
+ /**
22530
+ * Returns the device options for a given runtime and hardware probe.
22531
+ */
22532
+ function runtimeDevices(id, hw) {
22533
+ return def(id).devices(hw);
22534
+ }
22535
+ /**
22536
+ * Returns the default device string for a given runtime.
22537
+ * onnx → 'cpu', openvino → 'auto', coreml → 'all'
22538
+ */
22539
+ function defaultDeviceFor(id) {
22540
+ return def(id).defaultDevice;
22541
+ }
22419
22542
  //#endregion
22420
22543
  Object.defineProperty(exports, "APPLE_SA_TO_MACRO", {
22421
22544
  enumerable: true,
@@ -22603,6 +22726,12 @@ Object.defineProperty(exports, "decoderCapability", {
22603
22726
  return decoderCapability;
22604
22727
  }
22605
22728
  });
22729
+ Object.defineProperty(exports, "defaultDeviceFor", {
22730
+ enumerable: true,
22731
+ get: function() {
22732
+ return defaultDeviceFor;
22733
+ }
22734
+ });
22606
22735
  Object.defineProperty(exports, "defineCustomActions", {
22607
22736
  enumerable: true,
22608
22737
  get: function() {
@@ -22693,6 +22822,12 @@ Object.defineProperty(exports, "motionDetectionCapability", {
22693
22822
  return motionDetectionCapability;
22694
22823
  }
22695
22824
  });
22825
+ Object.defineProperty(exports, "nodePin", {
22826
+ enumerable: true,
22827
+ get: function() {
22828
+ return nodePin;
22829
+ }
22830
+ });
22696
22831
  Object.defineProperty(exports, "number", {
22697
22832
  enumerable: true,
22698
22833
  get: function() {
@@ -22741,6 +22876,12 @@ Object.defineProperty(exports, "recordingCapability", {
22741
22876
  return recordingCapability;
22742
22877
  }
22743
22878
  });
22879
+ Object.defineProperty(exports, "runtimeDevices", {
22880
+ enumerable: true,
22881
+ get: function() {
22882
+ return runtimeDevices;
22883
+ }
22884
+ });
22744
22885
  Object.defineProperty(exports, "selectAssignedProfileSlots", {
22745
22886
  enumerable: true,
22746
22887
  get: function() {
@@ -22771,6 +22912,12 @@ Object.defineProperty(exports, "string", {
22771
22912
  return string;
22772
22913
  }
22773
22914
  });
22915
+ Object.defineProperty(exports, "supportedRuntimes", {
22916
+ enumerable: true,
22917
+ get: function() {
22918
+ return supportedRuntimes;
22919
+ }
22920
+ });
22774
22921
  Object.defineProperty(exports, "union", {
22775
22922
  enumerable: true,
22776
22923
  get: function() {
@@ -25,7 +25,7 @@ node_fs = __toESM(node_fs, 1);
25
25
  let node_path = require("node:path");
26
26
  node_path = __toESM(node_path, 1);
27
27
  require("node:crypto");
28
- //#region ../system/dist/model-download-service-C7AjBsX9.mjs
28
+ //#region ../system/dist/model-download-service-RxAOiYvX.mjs
29
29
  /**
30
30
  * Map a rel path to one candidate absolute path PER root, keeping only roots the
31
31
  * path stays within (traversal guard). The handler serves the first candidate
@@ -173,6 +173,24 @@ function createFileDataPlaneHandler(opts) {
173
173
  (0, node_fs.createReadStream)(absPath).pipe(res);
174
174
  };
175
175
  }
176
+ function isNonEmptyFile(filePath) {
177
+ return node_fs.existsSync(filePath) && node_fs.statSync(filePath).size > 0;
178
+ }
179
+ /**
180
+ * Sibling files of a single-file (non-directory) format — extra files the
181
+ * format needs, fetched from the same remote directory as `url` and stored
182
+ * flat alongside the main file in `modelsDir`. Catalog-declared via
183
+ * `formatEntry.files`, e.g. OpenVINO IR lists its `.bin` weights next to the
184
+ * `.xml`. The downloader stays format-agnostic; the convention lives in the
185
+ * catalog data (like `MLPACKAGE_FILES` for the directory case).
186
+ */
187
+ function siblingFilesFor(formatEntry) {
188
+ return formatEntry.isDirectory ? [] : formatEntry.files ?? [];
189
+ }
190
+ /** Resolve a sibling's remote URL relative to the main file's directory. */
191
+ function siblingUrl(mainUrl, sibling) {
192
+ return mainUrl.replace(/[^/]+$/, sibling);
193
+ }
176
194
  /** Build fetch headers, including HF auth token for huggingface.co URLs */
177
195
  function buildHeaders(url) {
178
196
  const headers = { "User-Agent": "CamStack/1.0" };
@@ -282,14 +300,18 @@ async function ensureModel(modelsDir, entry, format, onProgress) {
282
300
  if (entry.extraFiles) for (const extra of entry.extraFiles) await downloadFile(extra.url, node_path.join(modelsDir, extra.filename));
283
301
  const filename = formatEntry.url.split("/").pop() ?? `${entry.id}.${format}`;
284
302
  const modelPath = node_path.join(modelsDir, filename);
303
+ const siblings = siblingFilesFor(formatEntry);
285
304
  if (node_fs.existsSync(modelPath)) if (formatEntry.isDirectory && !node_fs.existsSync(node_path.join(modelPath, "Manifest.json"))) node_fs.rmSync(modelPath, {
286
305
  recursive: true,
287
306
  force: true
288
307
  });
289
- else return modelPath;
308
+ else if (siblings.some((f) => !isNonEmptyFile(node_path.join(modelsDir, f)))) {} else return modelPath;
290
309
  node_fs.mkdirSync(modelsDir, { recursive: true });
291
310
  if (formatEntry.isDirectory) await downloadDirectory(formatEntry.url, modelPath, formatEntry.files, onProgress);
292
- else await downloadFile(formatEntry.url, modelPath, (downloaded, total) => onProgress?.(downloaded, total === 0 ? void 0 : total));
311
+ else {
312
+ await downloadFile(formatEntry.url, modelPath, (downloaded, total) => onProgress?.(downloaded, total === 0 ? void 0 : total));
313
+ for (const sibling of siblings) await downloadFile(siblingUrl(formatEntry.url, sibling), node_path.join(modelsDir, sibling));
314
+ }
293
315
  return modelPath;
294
316
  }
295
317
  /** Compute the on-disk path for a given model + format, even when not yet downloaded. */
@@ -306,17 +328,25 @@ function isModelDownloaded(modelsDir, entry, format) {
306
328
  const modelPath = getModelFilePath(modelsDir, entry, format);
307
329
  if (!modelPath || !node_fs.existsSync(modelPath)) return false;
308
330
  if (formatEntry.isDirectory) return node_fs.existsSync(node_path.join(modelPath, "Manifest.json"));
309
- return node_fs.statSync(modelPath).size > 0;
331
+ if (node_fs.statSync(modelPath).size <= 0) return false;
332
+ return siblingFilesFor(formatEntry).every((f) => isNonEmptyFile(node_path.join(modelsDir, f)));
310
333
  }
311
334
  /** Remove the on-disk model file/directory. Returns true if something was deleted. */
312
335
  function deleteModelFromDisk(modelsDir, entry, format) {
313
336
  const modelPath = getModelFilePath(modelsDir, entry, format);
314
337
  if (!modelPath || !node_fs.existsSync(modelPath)) return false;
315
- if (entry.formats[format]?.isDirectory) node_fs.rmSync(modelPath, {
338
+ const formatEntry = entry.formats[format];
339
+ if (formatEntry?.isDirectory) node_fs.rmSync(modelPath, {
316
340
  recursive: true,
317
341
  force: true
318
342
  });
319
- else node_fs.unlinkSync(modelPath);
343
+ else {
344
+ node_fs.unlinkSync(modelPath);
345
+ if (formatEntry) for (const sibling of siblingFilesFor(formatEntry)) {
346
+ const sibPath = node_path.join(modelsDir, sibling);
347
+ if (node_fs.existsSync(sibPath)) node_fs.unlinkSync(sibPath);
348
+ }
349
+ }
320
350
  return true;
321
351
  }
322
352
  //#endregion
@@ -3,7 +3,7 @@ import { createReadStream, promises } from "node:fs";
3
3
  import * as path$1 from "node:path";
4
4
  import path from "node:path";
5
5
  import "node:crypto";
6
- //#region ../system/dist/model-download-service-C7AjBsX9.mjs
6
+ //#region ../system/dist/model-download-service-RxAOiYvX.mjs
7
7
  /**
8
8
  * Map a rel path to one candidate absolute path PER root, keeping only roots the
9
9
  * path stays within (traversal guard). The handler serves the first candidate
@@ -151,6 +151,24 @@ function createFileDataPlaneHandler(opts) {
151
151
  createReadStream(absPath).pipe(res);
152
152
  };
153
153
  }
154
+ function isNonEmptyFile(filePath) {
155
+ return fs.existsSync(filePath) && fs.statSync(filePath).size > 0;
156
+ }
157
+ /**
158
+ * Sibling files of a single-file (non-directory) format — extra files the
159
+ * format needs, fetched from the same remote directory as `url` and stored
160
+ * flat alongside the main file in `modelsDir`. Catalog-declared via
161
+ * `formatEntry.files`, e.g. OpenVINO IR lists its `.bin` weights next to the
162
+ * `.xml`. The downloader stays format-agnostic; the convention lives in the
163
+ * catalog data (like `MLPACKAGE_FILES` for the directory case).
164
+ */
165
+ function siblingFilesFor(formatEntry) {
166
+ return formatEntry.isDirectory ? [] : formatEntry.files ?? [];
167
+ }
168
+ /** Resolve a sibling's remote URL relative to the main file's directory. */
169
+ function siblingUrl(mainUrl, sibling) {
170
+ return mainUrl.replace(/[^/]+$/, sibling);
171
+ }
154
172
  /** Build fetch headers, including HF auth token for huggingface.co URLs */
155
173
  function buildHeaders(url) {
156
174
  const headers = { "User-Agent": "CamStack/1.0" };
@@ -260,14 +278,18 @@ async function ensureModel(modelsDir, entry, format, onProgress) {
260
278
  if (entry.extraFiles) for (const extra of entry.extraFiles) await downloadFile(extra.url, path$1.join(modelsDir, extra.filename));
261
279
  const filename = formatEntry.url.split("/").pop() ?? `${entry.id}.${format}`;
262
280
  const modelPath = path$1.join(modelsDir, filename);
281
+ const siblings = siblingFilesFor(formatEntry);
263
282
  if (fs.existsSync(modelPath)) if (formatEntry.isDirectory && !fs.existsSync(path$1.join(modelPath, "Manifest.json"))) fs.rmSync(modelPath, {
264
283
  recursive: true,
265
284
  force: true
266
285
  });
267
- else return modelPath;
286
+ else if (siblings.some((f) => !isNonEmptyFile(path$1.join(modelsDir, f)))) {} else return modelPath;
268
287
  fs.mkdirSync(modelsDir, { recursive: true });
269
288
  if (formatEntry.isDirectory) await downloadDirectory(formatEntry.url, modelPath, formatEntry.files, onProgress);
270
- else await downloadFile(formatEntry.url, modelPath, (downloaded, total) => onProgress?.(downloaded, total === 0 ? void 0 : total));
289
+ else {
290
+ await downloadFile(formatEntry.url, modelPath, (downloaded, total) => onProgress?.(downloaded, total === 0 ? void 0 : total));
291
+ for (const sibling of siblings) await downloadFile(siblingUrl(formatEntry.url, sibling), path$1.join(modelsDir, sibling));
292
+ }
271
293
  return modelPath;
272
294
  }
273
295
  /** Compute the on-disk path for a given model + format, even when not yet downloaded. */
@@ -284,17 +306,25 @@ function isModelDownloaded(modelsDir, entry, format) {
284
306
  const modelPath = getModelFilePath(modelsDir, entry, format);
285
307
  if (!modelPath || !fs.existsSync(modelPath)) return false;
286
308
  if (formatEntry.isDirectory) return fs.existsSync(path$1.join(modelPath, "Manifest.json"));
287
- return fs.statSync(modelPath).size > 0;
309
+ if (fs.statSync(modelPath).size <= 0) return false;
310
+ return siblingFilesFor(formatEntry).every((f) => isNonEmptyFile(path$1.join(modelsDir, f)));
288
311
  }
289
312
  /** Remove the on-disk model file/directory. Returns true if something was deleted. */
290
313
  function deleteModelFromDisk(modelsDir, entry, format) {
291
314
  const modelPath = getModelFilePath(modelsDir, entry, format);
292
315
  if (!modelPath || !fs.existsSync(modelPath)) return false;
293
- if (entry.formats[format]?.isDirectory) fs.rmSync(modelPath, {
316
+ const formatEntry = entry.formats[format];
317
+ if (formatEntry?.isDirectory) fs.rmSync(modelPath, {
294
318
  recursive: true,
295
319
  force: true
296
320
  });
297
- else fs.unlinkSync(modelPath);
321
+ else {
322
+ fs.unlinkSync(modelPath);
323
+ if (formatEntry) for (const sibling of siblingFilesFor(formatEntry)) {
324
+ const sibPath = path$1.join(modelsDir, sibling);
325
+ if (fs.existsSync(sibPath)) fs.unlinkSync(sibPath);
326
+ }
327
+ }
298
328
  return true;
299
329
  }
300
330
  //#endregion
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-G45MVm6i.js");
5
+ const require_dist = require("../dist-BLcTVvol.js");
6
6
  let node_fs = require("node:fs");
7
7
  let node_path = require("node:path");
8
8
  //#region src/motion-wasm/wasm-motion-detector.ts
@@ -1,4 +1,4 @@
1
- import { C as evaluateZoneRules, I as BaseAddon, O as motionDetectionCapability, W as hydrateSchema, z as DeviceType } from "../dist-CjrjeaDd.mjs";
1
+ import { B as BaseAddon, J as hydrateSchema, U as DeviceType, k as motionDetectionCapability, w as evaluateZoneRules } from "../dist-BA6DR_jV.mjs";
2
2
  import { readFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  //#region src/motion-wasm/wasm-motion-detector.ts
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-G45MVm6i.js");
5
+ const require_dist = require("../dist-BLcTVvol.js");
6
6
  let _camstack_shm_ring = require("@camstack/shm-ring");
7
7
  //#region src/pipeline-runner/frame-queue.ts
8
8
  /**
@@ -1,4 +1,4 @@
1
- import { $ as boolean, A as pipelineRunnerCapability, B as EventCategory, F as errMsg, I as BaseAddon, K as makeSourceBrokerId, Q as array, U as createEvent, Z as _enum, it as object, ot as string, rt as number, tt as lazy, x as defineCustomActions, y as customAction } from "../dist-CjrjeaDd.mjs";
1
+ import { B as BaseAddon, M as pipelineRunnerCapability, S as defineCustomActions, W as EventCategory, X as makeSourceBrokerId, at as lazy, ct as object, nt as array, q as createEvent, rt as boolean, st as number, tt as _enum, ut as string, y as customAction, z as errMsg } from "../dist-BA6DR_jV.mjs";
2
2
  import { FrameRingReaderCache } from "@camstack/shm-ring";
3
3
  //#region src/pipeline-runner/frame-queue.ts
4
4
  /**
@@ -1,8 +1,8 @@
1
- const require_model_download_service_C7AjBsX9 = require("../model-download-service-C7AjBsX9-rXY-VFDk.js");
2
- const require_dist = require("../dist-G45MVm6i.js");
1
+ const require_model_download_service_RxAOiYvX = require("../model-download-service-RxAOiYvX-C8rTRJy_.js");
2
+ const require_dist = require("../dist-BLcTVvol.js");
3
3
  let node_fs = require("node:fs");
4
4
  let node_path = require("node:path");
5
- node_path = require_model_download_service_C7AjBsX9.__toESM(node_path);
5
+ node_path = require_model_download_service_RxAOiYvX.__toESM(node_path);
6
6
  let node_child_process = require("node:child_process");
7
7
  //#region src/recorder/segment-path.ts
8
8
  function segmentRelPath(deviceId, profile, startMs, durMs, bytes) {
@@ -1326,7 +1326,7 @@ var ReadinessRestore = class {
1326
1326
  try {
1327
1327
  do {
1328
1328
  this.rerun = false;
1329
- for (const [key, value] of [...this.pending]) try {
1329
+ for (const [key, value] of Array.from(this.pending)) try {
1330
1330
  await this.deps.attempt(key, value);
1331
1331
  this.pending.delete(key);
1332
1332
  } catch (err) {
@@ -1733,7 +1733,7 @@ var RecordingController = class {
1733
1733
  }
1734
1734
  this.restore?.stop();
1735
1735
  this.restore = null;
1736
- for (const deviceId of [...this.active.keys()]) await this.detachDevice(deviceId);
1736
+ for (const deviceId of Array.from(this.active.keys())) await this.detachDevice(deviceId);
1737
1737
  }
1738
1738
  };
1739
1739
  /** Build a `stream-broker` readiness scope for one node. */
@@ -1934,7 +1934,7 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
1934
1934
  store: this.segmentStore
1935
1935
  });
1936
1936
  try {
1937
- const handler = require_model_download_service_C7AjBsX9.createFileDataPlaneHandler({ getRoots: () => this.playbackRoots() });
1937
+ const handler = require_model_download_service_RxAOiYvX.createFileDataPlaneHandler({ getRoots: () => this.playbackRoots() });
1938
1938
  const served = await this.ctx.dataPlane?.serve({
1939
1939
  prefix: PLAYBACK_PREFIX,
1940
1940
  access: "authenticated",
@@ -1,5 +1,5 @@
1
- import { B as EventCategory, D as migrateConfigToBands, F as errMsg, H as createDurableState, I as BaseAddon, M as storageEvictableCapability, W as hydrateSchema, Y as selectAssignedProfileSlots, at as record, d as RecordingConfigSchema, j as recordingCapability, ot as string } from "../dist-CjrjeaDd.mjs";
2
- import { t as createFileDataPlaneHandler } from "../model-download-service-C7AjBsX9-B0ekM6dF.mjs";
1
+ import { $ as selectAssignedProfileSlots, B as BaseAddon, F as storageEvictableCapability, J as hydrateSchema, K as createDurableState, N as recordingCapability, O as migrateConfigToBands, W as EventCategory, d as RecordingConfigSchema, lt as record, ut as string, z as errMsg } from "../dist-BA6DR_jV.mjs";
2
+ import { t as createFileDataPlaneHandler } from "../model-download-service-RxAOiYvX-CMAvhgO7.mjs";
3
3
  import { promises } from "node:fs";
4
4
  import path from "node:path";
5
5
  import { spawn } from "node:child_process";
@@ -1325,7 +1325,7 @@ var ReadinessRestore = class {
1325
1325
  try {
1326
1326
  do {
1327
1327
  this.rerun = false;
1328
- for (const [key, value] of [...this.pending]) try {
1328
+ for (const [key, value] of Array.from(this.pending)) try {
1329
1329
  await this.deps.attempt(key, value);
1330
1330
  this.pending.delete(key);
1331
1331
  } catch (err) {
@@ -1732,7 +1732,7 @@ var RecordingController = class {
1732
1732
  }
1733
1733
  this.restore?.stop();
1734
1734
  this.restore = null;
1735
- for (const deviceId of [...this.active.keys()]) await this.detachDevice(deviceId);
1735
+ for (const deviceId of Array.from(this.active.keys())) await this.detachDevice(deviceId);
1736
1736
  }
1737
1737
  };
1738
1738
  /** Build a `stream-broker` readiness scope for one node. */