camstack 1.2.40 → 1.2.41

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.
@@ -14522,7 +14522,7 @@ function date4(params) {
14522
14522
  // ../../node_modules/zod/v4/classic/external.js
14523
14523
  config(en_default());
14524
14524
 
14525
- // ../types/dist/sleep-Cs9MWLcT.mjs
14525
+ // ../types/dist/sleep-BLxqGLY0.mjs
14526
14526
  var WELL_KNOWN_TABS = [
14527
14527
  {
14528
14528
  id: "overview",
@@ -19872,6 +19872,21 @@ var LinkedDeviceSchema = external_exports.object({
19872
19872
  features: external_exports.array(external_exports.string()),
19873
19873
  producesTrackedEvents: external_exports.boolean().optional()
19874
19874
  });
19875
+ var LinkedDevicesForDeviceSchema = external_exports.object({
19876
+ deviceId: external_exports.number(),
19877
+ mode: LinkedDevicesModeSchema,
19878
+ devices: external_exports.array(LinkedDeviceSchema)
19879
+ });
19880
+ var DeviceBindingsForDeviceSchema = external_exports.object({
19881
+ deviceId: external_exports.number(),
19882
+ entries: external_exports.array(external_exports.object({
19883
+ capName: external_exports.string(),
19884
+ kind: external_exports.enum(["native", "wrapped"]),
19885
+ providerAddonId: external_exports.string(),
19886
+ providerNodeId: external_exports.string(),
19887
+ nativeAddonId: external_exports.string()
19888
+ }))
19889
+ });
19875
19890
  var SavedDeviceRowSchema = external_exports.object({
19876
19891
  /** Numeric id reserved at allocateDeviceId time. */
19877
19892
  id: external_exports.number(),
@@ -20229,7 +20244,21 @@ var deviceManagerCapability = {
20229
20244
  projection: external_exports.enum(["full", "slim"]).optional(),
20230
20245
  /** Return only camera devices. Filtering server-side instead of
20231
20246
  * shipping 293 rows to find 12. */
20232
- isCamera: external_exports.boolean().optional()
20247
+ isCamera: external_exports.boolean().optional(),
20248
+ /**
20249
+ * Return only these device ids. For the caller that already KNOWS the
20250
+ * handful it wants and needs a field the id-bearing answer does not
20251
+ * carry — the viewer's linked-devices panel joins `type` and `online`
20252
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
20253
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
20254
+ * refetches on the reconcile interval, on a phone.
20255
+ *
20256
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
20257
+ * keys rather than rejecting them (verified against the live hub
20258
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
20259
+ * it answers today and the caller filters as it already does.
20260
+ */
20261
+ deviceIds: external_exports.array(external_exports.number()).optional()
20233
20262
  }), external_exports.array(DeviceInfoSchema)),
20234
20263
  /** Get a single device by numeric deviceId. */
20235
20264
  getDevice: method(external_exports.object({ deviceId: external_exports.number() }), DeviceInfoSchema.nullable()),
@@ -20248,6 +20277,23 @@ var deviceManagerCapability = {
20248
20277
  mode: LinkedDevicesModeSchema,
20249
20278
  devices: external_exports.array(LinkedDeviceSchema)
20250
20279
  })),
20280
+ /**
20281
+ * `getLinkedDevices` for MANY cameras, in one call.
20282
+ *
20283
+ * Not a convenience wrapper — a cost fix. Resolving one camera's linked set
20284
+ * needs the whole fleet as candidates (children ∪ same-location), so the
20285
+ * single-device path runs a full `listAll` per call. Asked per camera that
20286
+ * is N full-fleet sweeps of device-manager's event loop, and they do not
20287
+ * overlap: measured on the live hub 2026-08-25, 30 concurrent
20288
+ * `getLinkedDevices` took 4110 ms wall (median 4060 ms each) to return
20289
+ * 7260 bytes in total. The batch takes ONE sweep and one settings read per
20290
+ * camera.
20291
+ *
20292
+ * A device id that resolves to nothing still gets a row (`devices: []`) —
20293
+ * a caller that asked for thirty and got twenty-eight cannot tell which two
20294
+ * are missing, or that any are.
20295
+ */
20296
+ getLinkedDevicesBatch: method(external_exports.object({ deviceIds: external_exports.array(external_exports.number()) }), external_exports.array(LinkedDevicesForDeviceSchema)),
20251
20297
  /** Get stream sources for a camera device. */
20252
20298
  getStreamSources: method(external_exports.object({ deviceId: external_exports.number() }), external_exports.array(StreamSourceEntrySchema$1)),
20253
20299
  /** Get config entries (key + value + description) for a device. */
@@ -20305,16 +20351,22 @@ var deviceManagerCapability = {
20305
20351
  * currently-active provider (native or wrapper) + the underlying native
20306
20352
  * addon id, so consumers can decide routing without re-running discovery.
20307
20353
  */
20308
- getBindings: method(external_exports.object({ deviceId: external_exports.number() }), external_exports.object({
20309
- deviceId: external_exports.number(),
20310
- entries: external_exports.array(external_exports.object({
20311
- capName: external_exports.string(),
20312
- kind: external_exports.enum(["native", "wrapped"]),
20313
- providerAddonId: external_exports.string(),
20314
- providerNodeId: external_exports.string(),
20315
- nativeAddonId: external_exports.string()
20316
- }))
20317
- })),
20354
+ getBindings: method(external_exports.object({ deviceId: external_exports.number() }), DeviceBindingsForDeviceSchema),
20355
+ /**
20356
+ * `getBindings` for a NAMED set of devices, in one call.
20357
+ *
20358
+ * Between `getBindings` (one device) and `getAllBindings` (all 988) there
20359
+ * was nothing, so a caller that needs seventy-five either pays
20360
+ * seventy-five round-trips or drags the whole fleet across. Measured on
20361
+ * the live hub 2026-08-25: 75 concurrent `getBindings` = 1211 ms / 118 KB,
20362
+ * `getAllBindings({})` = 511 ms / 679 KB. Neither is the right answer to
20363
+ * "these seventy-five".
20364
+ *
20365
+ * Same resolver, same routing rules, same per-device shape as
20366
+ * `getBindings`; ids are deduped and a device with no bindings answers
20367
+ * `entries: []` rather than dropping out.
20368
+ */
20369
+ getBindingsBatch: method(external_exports.object({ deviceIds: external_exports.array(external_exports.number()) }), external_exports.array(DeviceBindingsForDeviceSchema)),
20318
20370
  /**
20319
20371
  * Return the binding map for every device known to the hub. Used by
20320
20372
  * `SystemManager` warm-boot: a single round-trip resolves the
@@ -20323,16 +20375,7 @@ var deviceManagerCapability = {
20323
20375
  * device add/remove) — clients invalidate via the
20324
20376
  * `capability.binding-changed` event.
20325
20377
  */
20326
- getAllBindings: method(external_exports.object({}), external_exports.array(external_exports.object({
20327
- deviceId: external_exports.number(),
20328
- entries: external_exports.array(external_exports.object({
20329
- capName: external_exports.string(),
20330
- kind: external_exports.enum(["native", "wrapped"]),
20331
- providerAddonId: external_exports.string(),
20332
- providerNodeId: external_exports.string(),
20333
- nativeAddonId: external_exports.string()
20334
- }))
20335
- }))),
20378
+ getAllBindings: method(external_exports.object({}), external_exports.array(DeviceBindingsForDeviceSchema)),
20336
20379
  /**
20337
20380
  * Activate (or deactivate) a wrapper addon for a (device, cap) pair.
20338
20381
  * Persists the binding via ctx.settings. active=false clears the wrapper
@@ -38212,6 +38255,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
38212
38255
  addonId: null,
38213
38256
  access: "view"
38214
38257
  },
38258
+ "deviceManager.getBindingsBatch": {
38259
+ capName: "device-manager",
38260
+ capScope: "system",
38261
+ addonId: null,
38262
+ access: "view"
38263
+ },
38215
38264
  "deviceManager.getChildren": {
38216
38265
  capName: "device-manager",
38217
38266
  capScope: "system",
@@ -38272,6 +38321,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
38272
38321
  addonId: null,
38273
38322
  access: "view"
38274
38323
  },
38324
+ "deviceManager.getLinkedDevicesBatch": {
38325
+ capName: "device-manager",
38326
+ capScope: "system",
38327
+ addonId: null,
38328
+ access: "view"
38329
+ },
38275
38330
  "deviceManager.getRoleDisplayDefaults": {
38276
38331
  capName: "device-manager",
38277
38332
  capScope: "system",
@@ -42919,6 +42974,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
42919
42974
  form: "single",
42920
42975
  optional: false
42921
42976
  }],
42977
+ "deviceManager.getBindingsBatch": [{
42978
+ name: "deviceIds",
42979
+ form: "array",
42980
+ optional: false
42981
+ }],
42922
42982
  "deviceManager.getChildren": [{
42923
42983
  name: "parentDeviceId",
42924
42984
  form: "single",
@@ -42964,6 +43024,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
42964
43024
  form: "single",
42965
43025
  optional: false
42966
43026
  }],
43027
+ "deviceManager.getLinkedDevicesBatch": [{
43028
+ name: "deviceIds",
43029
+ form: "array",
43030
+ optional: false
43031
+ }],
42967
43032
  "deviceManager.getSettingsSchema": [{
42968
43033
  name: "deviceId",
42969
43034
  form: "single",
@@ -42984,6 +43049,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
42984
43049
  form: "single",
42985
43050
  optional: false
42986
43051
  }],
43052
+ "deviceManager.listAll": [{
43053
+ name: "deviceIds",
43054
+ form: "array",
43055
+ optional: true
43056
+ }],
42987
43057
  "deviceManager.loadConfig": [{
42988
43058
  name: "deviceId",
42989
43059
  form: "single",
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runDiscover
4
- } from "./chunk-QYPK2MRI.js";
4
+ } from "./chunk-WSQAFZ7F.js";
5
5
  import "./chunk-LMMQX4CK.js";
6
6
 
7
7
  // src/cli.ts
@@ -38,7 +38,7 @@ async function runServe(args) {
38
38
  ...typeof values.data === "string" ? { data: values.data } : {}
39
39
  };
40
40
  Object.assign(process.env, buildServeEnv(opts));
41
- await import("./launcher-WS2IUVTL.js");
41
+ await import("./launcher-V3PF4DU6.js");
42
42
  }
43
43
 
44
44
  // src/commands/agent.ts
@@ -83,7 +83,7 @@ async function runAgent(args) {
83
83
  ...typeof values.port === "string" ? { port: values.port } : {}
84
84
  };
85
85
  Object.assign(process.env, buildAgentEnv(opts));
86
- await import("./launcher-WS2IUVTL.js");
86
+ await import("./launcher-V3PF4DU6.js");
87
87
  }
88
88
 
89
89
  // src/commands/setup.ts
@@ -1130,7 +1130,7 @@ function isUnknown(_value) {
1130
1130
  return true;
1131
1131
  }
1132
1132
  async function resolveServerInteractive(presetNamespace) {
1133
- const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-HFSH57RG.js");
1133
+ const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-S6SLEJRU.js");
1134
1134
  if (presetNamespace) {
1135
1135
  const spinner4 = clack.spinner();
1136
1136
  spinner4.start(`Discovering hub on LAN (namespace "${presetNamespace}")`);
@@ -5,7 +5,7 @@ import {
5
5
  filterHubNodes,
6
6
  resolveHubFromDiscovered,
7
7
  runDiscover
8
- } from "./chunk-QYPK2MRI.js";
8
+ } from "./chunk-WSQAFZ7F.js";
9
9
  import "./chunk-LMMQX4CK.js";
10
10
  export {
11
11
  DEFAULT_HUB_HTTPS_PORT,
@@ -23631,9 +23631,9 @@ var require_zod = __commonJS({
23631
23631
  }
23632
23632
  });
23633
23633
 
23634
- // ../system/dist/dist-DnhGRFEn.js
23635
- var require_dist_DnhGRFEn = __commonJS({
23636
- "../system/dist/dist-DnhGRFEn.js"(exports) {
23634
+ // ../system/dist/dist-CIDgcxPk.js
23635
+ var require_dist_CIDgcxPk = __commonJS({
23636
+ "../system/dist/dist-CIDgcxPk.js"(exports) {
23637
23637
  "use strict";
23638
23638
  var zod = require_zod();
23639
23639
  var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
@@ -30312,6 +30312,21 @@ var require_dist_DnhGRFEn = __commonJS({
30312
30312
  features: zod.z.array(zod.z.string()),
30313
30313
  producesTrackedEvents: zod.z.boolean().optional()
30314
30314
  });
30315
+ var LinkedDevicesForDeviceSchema = zod.z.object({
30316
+ deviceId: zod.z.number(),
30317
+ mode: LinkedDevicesModeSchema,
30318
+ devices: zod.z.array(LinkedDeviceSchema)
30319
+ });
30320
+ var DeviceBindingsForDeviceSchema = zod.z.object({
30321
+ deviceId: zod.z.number(),
30322
+ entries: zod.z.array(zod.z.object({
30323
+ capName: zod.z.string(),
30324
+ kind: zod.z.enum(["native", "wrapped"]),
30325
+ providerAddonId: zod.z.string(),
30326
+ providerNodeId: zod.z.string(),
30327
+ nativeAddonId: zod.z.string()
30328
+ }))
30329
+ });
30315
30330
  var SavedDeviceRowSchema = zod.z.object({
30316
30331
  /** Numeric id reserved at allocateDeviceId time. */
30317
30332
  id: zod.z.number(),
@@ -30669,7 +30684,21 @@ var require_dist_DnhGRFEn = __commonJS({
30669
30684
  projection: zod.z.enum(["full", "slim"]).optional(),
30670
30685
  /** Return only camera devices. Filtering server-side instead of
30671
30686
  * shipping 293 rows to find 12. */
30672
- isCamera: zod.z.boolean().optional()
30687
+ isCamera: zod.z.boolean().optional(),
30688
+ /**
30689
+ * Return only these device ids. For the caller that already KNOWS the
30690
+ * handful it wants and needs a field the id-bearing answer does not
30691
+ * carry — the viewer's linked-devices panel joins `type` and `online`
30692
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
30693
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
30694
+ * refetches on the reconcile interval, on a phone.
30695
+ *
30696
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
30697
+ * keys rather than rejecting them (verified against the live hub
30698
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
30699
+ * it answers today and the caller filters as it already does.
30700
+ */
30701
+ deviceIds: zod.z.array(zod.z.number()).optional()
30673
30702
  }), zod.z.array(DeviceInfoSchema)),
30674
30703
  /** Get a single device by numeric deviceId. */
30675
30704
  getDevice: method(zod.z.object({ deviceId: zod.z.number() }), DeviceInfoSchema.nullable()),
@@ -30688,6 +30717,23 @@ var require_dist_DnhGRFEn = __commonJS({
30688
30717
  mode: LinkedDevicesModeSchema,
30689
30718
  devices: zod.z.array(LinkedDeviceSchema)
30690
30719
  })),
30720
+ /**
30721
+ * `getLinkedDevices` for MANY cameras, in one call.
30722
+ *
30723
+ * Not a convenience wrapper — a cost fix. Resolving one camera's linked set
30724
+ * needs the whole fleet as candidates (children ∪ same-location), so the
30725
+ * single-device path runs a full `listAll` per call. Asked per camera that
30726
+ * is N full-fleet sweeps of device-manager's event loop, and they do not
30727
+ * overlap: measured on the live hub 2026-08-25, 30 concurrent
30728
+ * `getLinkedDevices` took 4110 ms wall (median 4060 ms each) to return
30729
+ * 7260 bytes in total. The batch takes ONE sweep and one settings read per
30730
+ * camera.
30731
+ *
30732
+ * A device id that resolves to nothing still gets a row (`devices: []`) —
30733
+ * a caller that asked for thirty and got twenty-eight cannot tell which two
30734
+ * are missing, or that any are.
30735
+ */
30736
+ getLinkedDevicesBatch: method(zod.z.object({ deviceIds: zod.z.array(zod.z.number()) }), zod.z.array(LinkedDevicesForDeviceSchema)),
30691
30737
  /** Get stream sources for a camera device. */
30692
30738
  getStreamSources: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.array(StreamSourceEntrySchema$1)),
30693
30739
  /** Get config entries (key + value + description) for a device. */
@@ -30745,16 +30791,22 @@ var require_dist_DnhGRFEn = __commonJS({
30745
30791
  * currently-active provider (native or wrapper) + the underlying native
30746
30792
  * addon id, so consumers can decide routing without re-running discovery.
30747
30793
  */
30748
- getBindings: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.object({
30749
- deviceId: zod.z.number(),
30750
- entries: zod.z.array(zod.z.object({
30751
- capName: zod.z.string(),
30752
- kind: zod.z.enum(["native", "wrapped"]),
30753
- providerAddonId: zod.z.string(),
30754
- providerNodeId: zod.z.string(),
30755
- nativeAddonId: zod.z.string()
30756
- }))
30757
- })),
30794
+ getBindings: method(zod.z.object({ deviceId: zod.z.number() }), DeviceBindingsForDeviceSchema),
30795
+ /**
30796
+ * `getBindings` for a NAMED set of devices, in one call.
30797
+ *
30798
+ * Between `getBindings` (one device) and `getAllBindings` (all 988) there
30799
+ * was nothing, so a caller that needs seventy-five either pays
30800
+ * seventy-five round-trips or drags the whole fleet across. Measured on
30801
+ * the live hub 2026-08-25: 75 concurrent `getBindings` = 1211 ms / 118 KB,
30802
+ * `getAllBindings({})` = 511 ms / 679 KB. Neither is the right answer to
30803
+ * "these seventy-five".
30804
+ *
30805
+ * Same resolver, same routing rules, same per-device shape as
30806
+ * `getBindings`; ids are deduped and a device with no bindings answers
30807
+ * `entries: []` rather than dropping out.
30808
+ */
30809
+ getBindingsBatch: method(zod.z.object({ deviceIds: zod.z.array(zod.z.number()) }), zod.z.array(DeviceBindingsForDeviceSchema)),
30758
30810
  /**
30759
30811
  * Return the binding map for every device known to the hub. Used by
30760
30812
  * `SystemManager` warm-boot: a single round-trip resolves the
@@ -30763,16 +30815,7 @@ var require_dist_DnhGRFEn = __commonJS({
30763
30815
  * device add/remove) — clients invalidate via the
30764
30816
  * `capability.binding-changed` event.
30765
30817
  */
30766
- getAllBindings: method(zod.z.object({}), zod.z.array(zod.z.object({
30767
- deviceId: zod.z.number(),
30768
- entries: zod.z.array(zod.z.object({
30769
- capName: zod.z.string(),
30770
- kind: zod.z.enum(["native", "wrapped"]),
30771
- providerAddonId: zod.z.string(),
30772
- providerNodeId: zod.z.string(),
30773
- nativeAddonId: zod.z.string()
30774
- }))
30775
- }))),
30818
+ getAllBindings: method(zod.z.object({}), zod.z.array(DeviceBindingsForDeviceSchema)),
30776
30819
  /**
30777
30820
  * Activate (or deactivate) a wrapper addon for a (device, cap) pair.
30778
30821
  * Persists the binding via ctx.settings. active=false clears the wrapper
@@ -49192,6 +49235,12 @@ var require_dist_DnhGRFEn = __commonJS({
49192
49235
  addonId: null,
49193
49236
  access: "view"
49194
49237
  },
49238
+ "deviceManager.getBindingsBatch": {
49239
+ capName: "device-manager",
49240
+ capScope: "system",
49241
+ addonId: null,
49242
+ access: "view"
49243
+ },
49195
49244
  "deviceManager.getChildren": {
49196
49245
  capName: "device-manager",
49197
49246
  capScope: "system",
@@ -49252,6 +49301,12 @@ var require_dist_DnhGRFEn = __commonJS({
49252
49301
  addonId: null,
49253
49302
  access: "view"
49254
49303
  },
49304
+ "deviceManager.getLinkedDevicesBatch": {
49305
+ capName: "device-manager",
49306
+ capScope: "system",
49307
+ addonId: null,
49308
+ access: "view"
49309
+ },
49255
49310
  "deviceManager.getRoleDisplayDefaults": {
49256
49311
  capName: "device-manager",
49257
49312
  capScope: "system",
@@ -53899,6 +53954,11 @@ var require_dist_DnhGRFEn = __commonJS({
53899
53954
  form: "single",
53900
53955
  optional: false
53901
53956
  }],
53957
+ "deviceManager.getBindingsBatch": [{
53958
+ name: "deviceIds",
53959
+ form: "array",
53960
+ optional: false
53961
+ }],
53902
53962
  "deviceManager.getChildren": [{
53903
53963
  name: "parentDeviceId",
53904
53964
  form: "single",
@@ -53944,6 +54004,11 @@ var require_dist_DnhGRFEn = __commonJS({
53944
54004
  form: "single",
53945
54005
  optional: false
53946
54006
  }],
54007
+ "deviceManager.getLinkedDevicesBatch": [{
54008
+ name: "deviceIds",
54009
+ form: "array",
54010
+ optional: false
54011
+ }],
53947
54012
  "deviceManager.getSettingsSchema": [{
53948
54013
  name: "deviceId",
53949
54014
  form: "single",
@@ -53964,6 +54029,11 @@ var require_dist_DnhGRFEn = __commonJS({
53964
54029
  form: "single",
53965
54030
  optional: false
53966
54031
  }],
54032
+ "deviceManager.listAll": [{
54033
+ name: "deviceIds",
54034
+ form: "array",
54035
+ optional: true
54036
+ }],
53967
54037
  "deviceManager.loadConfig": [{
53968
54038
  name: "deviceId",
53969
54039
  form: "single",
@@ -56620,7 +56690,7 @@ var require_alerts_addon = __commonJS({
56620
56690
  [Symbol.toStringTag]: { value: "Module" }
56621
56691
  });
56622
56692
  require_chunk_Cek0wNdY();
56623
- var require_dist10 = require_dist_DnhGRFEn();
56693
+ var require_dist10 = require_dist_CIDgcxPk();
56624
56694
  function selectExpired(alerts, cutoffMs) {
56625
56695
  return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
56626
56696
  }
@@ -57439,7 +57509,7 @@ var require_console_logging = __commonJS({
57439
57509
  [Symbol.toStringTag]: { value: "Module" }
57440
57510
  });
57441
57511
  require_chunk_Cek0wNdY();
57442
- var require_dist10 = require_dist_DnhGRFEn();
57512
+ var require_dist10 = require_dist_CIDgcxPk();
57443
57513
  var require_formatter = require_formatter_DqAKDlvN();
57444
57514
  var LEVEL_RANK = {
57445
57515
  debug: 0,
@@ -57533,7 +57603,7 @@ var require_core_blocks_addon = __commonJS({
57533
57603
  "use strict";
57534
57604
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
57535
57605
  var require_chunk = require_chunk_Cek0wNdY();
57536
- var require_dist10 = require_dist_DnhGRFEn();
57606
+ var require_dist10 = require_dist_CIDgcxPk();
57537
57607
  var node_crypto = __require("crypto");
57538
57608
  var node_fs_promises = __require("fs/promises");
57539
57609
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -58430,11 +58500,11 @@ var require_core_blocks = __commonJS({
58430
58500
  }
58431
58501
  });
58432
58502
 
58433
- // ../system/dist/retired-settings-keys-D6Jy_SsO.js
58434
- var require_retired_settings_keys_D6Jy_SsO = __commonJS({
58435
- "../system/dist/retired-settings-keys-D6Jy_SsO.js"(exports) {
58503
+ // ../system/dist/retired-settings-keys-D7c0n9jO.js
58504
+ var require_retired_settings_keys_D7c0n9jO = __commonJS({
58505
+ "../system/dist/retired-settings-keys-D7c0n9jO.js"(exports) {
58436
58506
  "use strict";
58437
- var require_dist10 = require_dist_DnhGRFEn();
58507
+ var require_dist10 = require_dist_CIDgcxPk();
58438
58508
  function settingsStoreIsAuthoritativeHere(env) {
58439
58509
  const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
58440
58510
  return raw === "" || raw === "hub";
@@ -60477,8 +60547,8 @@ var require_device_manager_addon = __commonJS({
60477
60547
  [Symbol.toStringTag]: { value: "Module" }
60478
60548
  });
60479
60549
  require_chunk_Cek0wNdY();
60480
- var require_dist10 = require_dist_DnhGRFEn();
60481
- var require_retired_settings_keys = require_retired_settings_keys_D6Jy_SsO();
60550
+ var require_dist10 = require_dist_CIDgcxPk();
60551
+ var require_retired_settings_keys = require_retired_settings_keys_D7c0n9jO();
60482
60552
  var node_crypto = __require("crypto");
60483
60553
  var _camstack_types_node = require_node();
60484
60554
  var JOB_HISTORY = 20;
@@ -61055,6 +61125,11 @@ var require_device_manager_addon = __commonJS({
61055
61125
  entries
61056
61126
  };
61057
61127
  }
61128
+ async function getBindingsBatch(deps, input) {
61129
+ const out = [];
61130
+ for (const deviceId of new Set(input.deviceIds)) out.push(await getBindings(deps, { deviceId }));
61131
+ return out;
61132
+ }
61058
61133
  async function getAllBindings(deps) {
61059
61134
  const ids = /* @__PURE__ */ new Set();
61060
61135
  for (const row of await deps.rows.listAll()) ids.add(row.meta.id);
@@ -61500,6 +61575,7 @@ var require_device_manager_addon = __commonJS({
61500
61575
  const { addonId } = input;
61501
61576
  const slim = input.projection === "slim";
61502
61577
  const camerasOnly = input.isCamera === true;
61578
+ const idFilter = input.deviceIds === void 0 ? null : new Set(input.deviceIds);
61503
61579
  const results = [];
61504
61580
  const seen = /* @__PURE__ */ new Set();
61505
61581
  const fleet = addonId ? await pctx.metaStore.rows.listByAddon(addonId) : await pctx.metaStore.rows.listAll();
@@ -61515,6 +61591,7 @@ var require_device_manager_addon = __commonJS({
61515
61591
  const row = rowById.get(device.id);
61516
61592
  const info = toDeviceInfo(aid, device, row?.metadata ?? null, row?.meta ?? null);
61517
61593
  seen.add(key);
61594
+ if (idFilter !== null && !idFilter.has(device.id)) continue;
61518
61595
  if (camerasOnly && !info.isCamera) continue;
61519
61596
  results.push(slim ? {
61520
61597
  ...info,
@@ -61528,6 +61605,7 @@ var require_device_manager_addon = __commonJS({
61528
61605
  const aid = m.addonId;
61529
61606
  const stableId = m.stableId;
61530
61607
  if (seen.has(String(m.id))) continue;
61608
+ if (idFilter !== null && !idFilter.has(m.id)) continue;
61531
61609
  const persistedType = m.type;
61532
61610
  if (camerasOnly && persistedType !== require_dist10.DeviceType.Camera) continue;
61533
61611
  const persistedConfig = slim ? {} : await pctx.settings.readDeviceStore(m.id);
@@ -62026,11 +62104,8 @@ var require_device_manager_addon = __commonJS({
62026
62104
  }
62027
62105
  return linkedIds.filter((id) => picked.has(id));
62028
62106
  }
62029
- async function getLinkedDevices(pctx, input) {
62030
- const { deviceId } = input;
62031
- const [all, blob] = await Promise.all([listAll(pctx, {}), pctx.settings.readDeviceStore(deviceId)]);
62107
+ function resolveFor(deviceId, all, byId, blob) {
62032
62108
  const config = parseLinkedDevicesConfig(blob);
62033
- const byId = new Map(all.map((d) => [d.id, d]));
62034
62109
  const ids = resolveLinkedDeviceIds({
62035
62110
  selfId: deviceId,
62036
62111
  selfLocation: byId.get(deviceId)?.location ?? null,
@@ -62055,6 +62130,27 @@ var require_device_manager_addon = __commonJS({
62055
62130
  devices
62056
62131
  };
62057
62132
  }
62133
+ async function getLinkedDevices(pctx, input) {
62134
+ const { deviceId } = input;
62135
+ const [all, blob] = await Promise.all([listAll(pctx, {}), pctx.settings.readDeviceStore(deviceId)]);
62136
+ return resolveFor(deviceId, all, new Map(all.map((d) => [d.id, d])), blob);
62137
+ }
62138
+ async function getLinkedDevicesBatch(pctx, input) {
62139
+ const deviceIds = [...new Set(input.deviceIds)];
62140
+ if (deviceIds.length === 0) return [];
62141
+ const [all, blobs] = await Promise.all([listAll(pctx, {}), Promise.all(deviceIds.map((id) => pctx.settings.readDeviceStore(id).catch((err) => {
62142
+ pctx.host.ctx.logger.warn("getLinkedDevicesBatch: settings read failed \u2014 children only", {
62143
+ tags: { deviceId: id },
62144
+ meta: { error: err instanceof Error ? err.message : String(err) }
62145
+ });
62146
+ return {};
62147
+ })))]);
62148
+ const byId = new Map(all.map((d) => [d.id, d]));
62149
+ return deviceIds.map((deviceId, index) => ({
62150
+ deviceId,
62151
+ ...resolveFor(deviceId, all, byId, blobs[index] ?? {})
62152
+ }));
62153
+ }
62058
62154
  async function buildLinkedDevicesContribution(pctx, deviceId) {
62059
62155
  const persisted = await pctx.metaStore.resolvePersistedById(deviceId);
62060
62156
  if (!persisted || persisted.meta.type !== require_dist10.DeviceType.Camera) return null;
@@ -64496,6 +64592,9 @@ var require_device_manager_addon = __commonJS({
64496
64592
  async getBindings(input) {
64497
64593
  return getBindings(this.bindingsDeps, input);
64498
64594
  }
64595
+ async getBindingsBatch(input) {
64596
+ return getBindingsBatch(this.bindingsDeps, input);
64597
+ }
64499
64598
  async getAllBindings() {
64500
64599
  return getAllBindings(this.bindingsDeps);
64501
64600
  }
@@ -64607,6 +64706,7 @@ var require_device_manager_addon = __commonJS({
64607
64706
  getDevice: (input) => getDevice(pctx, input),
64608
64707
  getChildren: (input) => getChildren(pctx, input),
64609
64708
  getLinkedDevices: (input) => getLinkedDevices(pctx, input),
64709
+ getLinkedDevicesBatch: (input) => getLinkedDevicesBatch(pctx, input),
64610
64710
  getDeviceSettingsContribution: (input) => buildLinkedDevicesContribution(pctx, input.deviceId),
64611
64711
  getDeviceLiveContribution: async () => null,
64612
64712
  applyDeviceSettingsPatch: (input) => applyLinkedDevicesPatch(pctx, input.deviceId, input.patch),
@@ -64685,6 +64785,7 @@ var require_device_manager_addon = __commonJS({
64685
64785
  entries: result.entries
64686
64786
  };
64687
64787
  },
64788
+ getBindingsBatch: (input) => this.getBindingsBatch({ deviceIds: input.deviceIds }),
64688
64789
  getAllBindings: async () => {
64689
64790
  return this.getAllBindings();
64690
64791
  },
@@ -64805,7 +64906,7 @@ var require_hub_forwarder = __commonJS({
64805
64906
  [Symbol.toStringTag]: { value: "Module" }
64806
64907
  });
64807
64908
  require_chunk_Cek0wNdY();
64808
- var require_dist10 = require_dist_DnhGRFEn();
64909
+ var require_dist10 = require_dist_CIDgcxPk();
64809
64910
  var require_formatter = require_formatter_DqAKDlvN();
64810
64911
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
64811
64912
  var HubForwarderDestination = class {
@@ -64942,7 +65043,7 @@ var require_liveness_monitor_addon = __commonJS({
64942
65043
  "use strict";
64943
65044
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
64944
65045
  require_chunk_Cek0wNdY();
64945
- var require_dist10 = require_dist_DnhGRFEn();
65046
+ var require_dist10 = require_dist_CIDgcxPk();
64946
65047
  var NO_DEVICES = "liveness:no-devices";
64947
65048
  var ALL_OFFLINE = "liveness:all-devices-offline";
64948
65049
  var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
@@ -65132,7 +65233,7 @@ var require_local_auth_addon = __commonJS({
65132
65233
  [Symbol.toStringTag]: { value: "Module" }
65133
65234
  });
65134
65235
  var require_chunk = require_chunk_Cek0wNdY();
65135
- var require_dist10 = require_dist_DnhGRFEn();
65236
+ var require_dist10 = require_dist_CIDgcxPk();
65136
65237
  var node_crypto = __require("crypto");
65137
65238
  node_crypto = require_chunk.__toESM(node_crypto);
65138
65239
  var crypto$1 = __require("crypto");
@@ -72816,7 +72917,7 @@ var require_loki_logging = __commonJS({
72816
72917
  [Symbol.toStringTag]: { value: "Module" }
72817
72918
  });
72818
72919
  require_chunk_Cek0wNdY();
72819
- var require_dist10 = require_dist_DnhGRFEn();
72920
+ var require_dist10 = require_dist_CIDgcxPk();
72820
72921
  function sanitizeLabelName(raw) {
72821
72922
  const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
72822
72923
  return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
@@ -73381,7 +73482,7 @@ var require_native_metrics_addon = __commonJS({
73381
73482
  [Symbol.toStringTag]: { value: "Module" }
73382
73483
  });
73383
73484
  var require_chunk = require_chunk_Cek0wNdY();
73384
- var require_dist10 = require_dist_DnhGRFEn();
73485
+ var require_dist10 = require_dist_CIDgcxPk();
73385
73486
  var node_child_process = __require("child_process");
73386
73487
  var node_util = __require("util");
73387
73488
  var node_os = __require("os");
@@ -74323,7 +74424,7 @@ var require_filesystem_storage_addon = __commonJS({
74323
74424
  [Symbol.toStringTag]: { value: "Module" }
74324
74425
  });
74325
74426
  var require_chunk = require_chunk_Cek0wNdY();
74326
- var require_dist10 = require_dist_DnhGRFEn();
74427
+ var require_dist10 = require_dist_CIDgcxPk();
74327
74428
  var node_crypto = __require("crypto");
74328
74429
  var node_fs_promises = __require("fs/promises");
74329
74430
  var node_path = __require("path");
@@ -75439,8 +75540,8 @@ var require_sqlite_settings_addon = __commonJS({
75439
75540
  [Symbol.toStringTag]: { value: "Module" }
75440
75541
  });
75441
75542
  var require_chunk = require_chunk_Cek0wNdY();
75442
- var require_dist10 = require_dist_DnhGRFEn();
75443
- var require_retired_settings_keys = require_retired_settings_keys_D6Jy_SsO();
75543
+ var require_dist10 = require_dist_CIDgcxPk();
75544
+ var require_retired_settings_keys = require_retired_settings_keys_D7c0n9jO();
75444
75545
  var node_crypto = __require("crypto");
75445
75546
  var node_fs = __require("fs");
75446
75547
  var node_module = __require("module");
@@ -76996,7 +77097,7 @@ var require_storage_orchestrator_addon = __commonJS({
76996
77097
  [Symbol.toStringTag]: { value: "Module" }
76997
77098
  });
76998
77099
  var require_chunk = require_chunk_Cek0wNdY();
76999
- var require_dist10 = require_dist_DnhGRFEn();
77100
+ var require_dist10 = require_dist_CIDgcxPk();
77000
77101
  var node_crypto = __require("crypto");
77001
77102
  var node_fs_promises = __require("fs/promises");
77002
77103
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -78875,7 +78976,7 @@ var require_system_config_addon = __commonJS({
78875
78976
  [Symbol.toStringTag]: { value: "Module" }
78876
78977
  });
78877
78978
  require_chunk_Cek0wNdY();
78878
- var require_dist10 = require_dist_DnhGRFEn();
78979
+ var require_dist10 = require_dist_CIDgcxPk();
78879
78980
  var SECTION_TITLES = {
78880
78981
  server: "Server",
78881
78982
  auth: "Authentication"
@@ -96936,7 +97037,7 @@ var require_winston_logging = __commonJS({
96936
97037
  [Symbol.toStringTag]: { value: "Module" }
96937
97038
  });
96938
97039
  var require_chunk = require_chunk_Cek0wNdY();
96939
- var require_dist10 = require_dist_DnhGRFEn();
97040
+ var require_dist10 = require_dist_CIDgcxPk();
96940
97041
  var require_formatter = require_formatter_DqAKDlvN();
96941
97042
  var node_path = __require("path");
96942
97043
  node_path = require_chunk.__toESM(node_path);
@@ -98133,9 +98234,9 @@ var require_event_category_EY0GNjV9 = __commonJS({
98133
98234
  }
98134
98235
  });
98135
98236
 
98136
- // ../types/dist/sleep-CizGYrCD.js
98137
- var require_sleep_CizGYrCD = __commonJS({
98138
- "../types/dist/sleep-CizGYrCD.js"(exports) {
98237
+ // ../types/dist/sleep-CUuoW-kk.js
98238
+ var require_sleep_CUuoW_kk = __commonJS({
98239
+ "../types/dist/sleep-CUuoW-kk.js"(exports) {
98139
98240
  "use strict";
98140
98241
  var require_event_category = require_event_category_EY0GNjV9();
98141
98242
  var zod = require_zod();
@@ -100899,7 +101000,6 @@ var require_sleep_CizGYrCD = __commonJS({
100899
101000
  setStreamProfileMap: (input) => dispatchSystem("deviceManager", "setStreamProfileMap", "mutation", input),
100900
101001
  probeStreams: (input) => dispatchSystem("deviceManager", "probeStreams", "mutation", input),
100901
101002
  getBindings: (input) => dispatchSystem("deviceManager", "getBindings", "query", input),
100902
- getAllBindings: (input) => dispatchSystem("deviceManager", "getAllBindings", "query", input),
100903
101003
  setWrapperActive: (input) => dispatchSystem("deviceManager", "setWrapperActive", "mutation", input),
100904
101004
  getDeviceSettingsAggregate: (input) => dispatchSystem("deviceManager", "getDeviceSettingsAggregate", "query", input),
100905
101005
  getDeviceLiveInfoAggregate: (input) => dispatchSystem("deviceManager", "getDeviceLiveInfoAggregate", "query", input),
@@ -101660,7 +101760,7 @@ var require_addon = __commonJS({
101660
101760
  "use strict";
101661
101761
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
101662
101762
  var require_event_category = require_event_category_EY0GNjV9();
101663
- var require_sleep = require_sleep_CizGYrCD();
101763
+ var require_sleep = require_sleep_CUuoW_kk();
101664
101764
  var require_err_msg = require_err_msg_COpsHMw2();
101665
101765
  var CAP_INPUT_DEFAULTS = Object.freeze({
101666
101766
  "addons": { "getLogs": { "limit": 100 } },
@@ -108536,9 +108636,9 @@ var require_dist2 = __commonJS({
108536
108636
  }
108537
108637
  });
108538
108638
 
108539
- // ../system/dist/manifest-python-deps-B3_4YiDK.js
108540
- var require_manifest_python_deps_B3_4YiDK = __commonJS({
108541
- "../system/dist/manifest-python-deps-B3_4YiDK.js"(exports) {
108639
+ // ../system/dist/manifest-python-deps-DB_4H3tR.js
108640
+ var require_manifest_python_deps_DB_4H3tR = __commonJS({
108641
+ "../system/dist/manifest-python-deps-DB_4H3tR.js"(exports) {
108542
108642
  "use strict";
108543
108643
  var require_chunk = require_chunk_Cek0wNdY();
108544
108644
  var node_crypto = __require("crypto");
@@ -108653,7 +108753,7 @@ var require_manifest_python_deps_B3_4YiDK = __commonJS({
108653
108753
  if (loop === void 0) return line;
108654
108754
  return `${line} loopP50=${loop.p50Ms}ms loopP99=${loop.p99Ms}ms loopMax=${loop.maxMs}ms`;
108655
108755
  }
108656
- function startHeapWatch(label = "hub-main", sink = consoleSink, intervalMs = HEAP_WATCH_INTERVAL_MS, reclaimOptions, loopDelay = createLoopDelayMeter(), execArgv = process.execArgv) {
108756
+ function startHeapWatch(label = "hub-main", sink = consoleSink, intervalMs = HEAP_WATCH_INTERVAL_MS, reclaimOptions, loopDelay = createLoopDelayMeter(), execArgv = process.execArgv, announceCeilingOrigin = true) {
108657
108757
  const readMemory = reclaimOptions?.readMemory ?? (() => process.memoryUsage());
108658
108758
  const now = reclaimOptions?.now ?? (() => Date.now());
108659
108759
  const triggerMb = reclaimOptions?.triggerMb ?? 1024;
@@ -108718,7 +108818,7 @@ var require_manifest_python_deps_B3_4YiDK = __commonJS({
108718
108818
  const timer = setInterval(tick, probeIntervalMs);
108719
108819
  timer.unref?.();
108720
108820
  tick();
108721
- if (heapCeilingOrigin(execArgv) === "v8-default") sink.info(`[mem] ${label} heap ceiling is V8's DEFAULT (${read().heapLimitMb}MB) \u2014 no --max-old-space-size on argv. Nothing here CHOSE that number; it is derived from host RAM and moves with it.`);
108821
+ if (announceCeilingOrigin && heapCeilingOrigin(execArgv) === "v8-default") sink.info(`[mem] ${label} heap ceiling is V8's DEFAULT (${read().heapLimitMb}MB) \u2014 no --max-old-space-size on argv. Nothing here CHOSE that number; it is derived from host RAM and moves with it.`);
108722
108822
  let stopped = false;
108723
108823
  return () => {
108724
108824
  if (stopped) return;
@@ -108731,13 +108831,13 @@ var require_manifest_python_deps_B3_4YiDK = __commonJS({
108731
108831
  function startRunnerHeapWatch(options) {
108732
108832
  if (options.heapProfile !== "heavy") return void 0;
108733
108833
  const intervalMs = options.intervalMs ?? 3e5;
108734
- if (options.reclaimSwitch === "off") return startHeapWatch(options.label, options.sink, intervalMs);
108834
+ if (options.reclaimSwitch === "off") return startHeapWatch(options.label, options.sink, intervalMs, void 0, void 0, void 0, false);
108735
108835
  let reclaimOptions = options.reclaimOptions;
108736
108836
  if (reclaimOptions === void 0) {
108737
108837
  const reclaimer = createV8Reclaimer();
108738
108838
  reclaimOptions = reclaimer === void 0 ? void 0 : { reclaim: reclaimer };
108739
108839
  }
108740
- return startHeapWatch(options.label, options.sink, intervalMs, reclaimOptions);
108840
+ return startHeapWatch(options.label, options.sink, intervalMs, reclaimOptions, void 0, void 0, false);
108741
108841
  }
108742
108842
  function trimSlashes(s) {
108743
108843
  return s.replace(/^\/+/, "").replace(/\/+$/, "");
@@ -120148,7 +120248,7 @@ var require_dist3 = __commonJS({
120148
120248
  "use strict";
120149
120249
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
120150
120250
  var require_chunk = require_chunk_Cek0wNdY();
120151
- var require_dist10 = require_dist_DnhGRFEn();
120251
+ var require_dist10 = require_dist_CIDgcxPk();
120152
120252
  var require_builtins_alerts_alerts_addon = require_alerts_addon();
120153
120253
  require_alerts();
120154
120254
  var require_formatter = require_formatter_DqAKDlvN();
@@ -120173,7 +120273,7 @@ var require_dist3 = __commonJS({
120173
120273
  require_system_config();
120174
120274
  var require_builtins_winston_logging_index = require_winston_logging();
120175
120275
  var require_file_data_plane = require_file_data_plane_DO8KbxCe();
120176
- var require_manifest_python_deps = require_manifest_python_deps_B3_4YiDK();
120276
+ var require_manifest_python_deps = require_manifest_python_deps_DB_4H3tR();
120177
120277
  var require_resource_monitor = require_resource_monitor_CdnzxBLP();
120178
120278
  var require_lan_http_bind = require_lan_http_bind_DmgpFP6();
120179
120279
  var require_custom_action_registry = require_custom_action_registry_jY0NOZK8();
@@ -239410,7 +239510,7 @@ var require_dist9 = __commonJS({
239410
239510
  "use strict";
239411
239511
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
239412
239512
  var require_event_category = require_event_category_EY0GNjV9();
239413
- var require_sleep = require_sleep_CizGYrCD();
239513
+ var require_sleep = require_sleep_CUuoW_kk();
239414
239514
  var require_canonical_hash = require_canonical_hash_DNV8S5ET();
239415
239515
  var require_enums2 = require_enums();
239416
239516
  var require_err_msg = require_err_msg_COpsHMw2();
@@ -245837,6 +245937,21 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
245837
245937
  features: zod.z.array(zod.z.string()),
245838
245938
  producesTrackedEvents: zod.z.boolean().optional()
245839
245939
  });
245940
+ var LinkedDevicesForDeviceSchema = zod.z.object({
245941
+ deviceId: zod.z.number(),
245942
+ mode: LinkedDevicesModeSchema,
245943
+ devices: zod.z.array(LinkedDeviceSchema)
245944
+ });
245945
+ var DeviceBindingsForDeviceSchema = zod.z.object({
245946
+ deviceId: zod.z.number(),
245947
+ entries: zod.z.array(zod.z.object({
245948
+ capName: zod.z.string(),
245949
+ kind: zod.z.enum(["native", "wrapped"]),
245950
+ providerAddonId: zod.z.string(),
245951
+ providerNodeId: zod.z.string(),
245952
+ nativeAddonId: zod.z.string()
245953
+ }))
245954
+ });
245840
245955
  var SavedDeviceRowSchema = zod.z.object({
245841
245956
  /** Numeric id reserved at allocateDeviceId time. */
245842
245957
  id: zod.z.number(),
@@ -246194,7 +246309,21 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
246194
246309
  projection: zod.z.enum(["full", "slim"]).optional(),
246195
246310
  /** Return only camera devices. Filtering server-side instead of
246196
246311
  * shipping 293 rows to find 12. */
246197
- isCamera: zod.z.boolean().optional()
246312
+ isCamera: zod.z.boolean().optional(),
246313
+ /**
246314
+ * Return only these device ids. For the caller that already KNOWS the
246315
+ * handful it wants and needs a field the id-bearing answer does not
246316
+ * carry — the viewer's linked-devices panel joins `type` and `online`
246317
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
246318
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
246319
+ * refetches on the reconcile interval, on a phone.
246320
+ *
246321
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
246322
+ * keys rather than rejecting them (verified against the live hub
246323
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
246324
+ * it answers today and the caller filters as it already does.
246325
+ */
246326
+ deviceIds: zod.z.array(zod.z.number()).optional()
246198
246327
  }), zod.z.array(DeviceInfoSchema)),
246199
246328
  /** Get a single device by numeric deviceId. */
246200
246329
  getDevice: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), DeviceInfoSchema.nullable()),
@@ -246213,6 +246342,23 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
246213
246342
  mode: LinkedDevicesModeSchema,
246214
246343
  devices: zod.z.array(LinkedDeviceSchema)
246215
246344
  })),
246345
+ /**
246346
+ * `getLinkedDevices` for MANY cameras, in one call.
246347
+ *
246348
+ * Not a convenience wrapper — a cost fix. Resolving one camera's linked set
246349
+ * needs the whole fleet as candidates (children ∪ same-location), so the
246350
+ * single-device path runs a full `listAll` per call. Asked per camera that
246351
+ * is N full-fleet sweeps of device-manager's event loop, and they do not
246352
+ * overlap: measured on the live hub 2026-08-25, 30 concurrent
246353
+ * `getLinkedDevices` took 4110 ms wall (median 4060 ms each) to return
246354
+ * 7260 bytes in total. The batch takes ONE sweep and one settings read per
246355
+ * camera.
246356
+ *
246357
+ * A device id that resolves to nothing still gets a row (`devices: []`) —
246358
+ * a caller that asked for thirty and got twenty-eight cannot tell which two
246359
+ * are missing, or that any are.
246360
+ */
246361
+ getLinkedDevicesBatch: require_sleep.method(zod.z.object({ deviceIds: zod.z.array(zod.z.number()) }), zod.z.array(LinkedDevicesForDeviceSchema)),
246216
246362
  /** Get stream sources for a camera device. */
246217
246363
  getStreamSources: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), zod.z.array(require_sleep.StreamSourceEntrySchema)),
246218
246364
  /** Get config entries (key + value + description) for a device. */
@@ -246270,16 +246416,22 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
246270
246416
  * currently-active provider (native or wrapper) + the underlying native
246271
246417
  * addon id, so consumers can decide routing without re-running discovery.
246272
246418
  */
246273
- getBindings: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), zod.z.object({
246274
- deviceId: zod.z.number(),
246275
- entries: zod.z.array(zod.z.object({
246276
- capName: zod.z.string(),
246277
- kind: zod.z.enum(["native", "wrapped"]),
246278
- providerAddonId: zod.z.string(),
246279
- providerNodeId: zod.z.string(),
246280
- nativeAddonId: zod.z.string()
246281
- }))
246282
- })),
246419
+ getBindings: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), DeviceBindingsForDeviceSchema),
246420
+ /**
246421
+ * `getBindings` for a NAMED set of devices, in one call.
246422
+ *
246423
+ * Between `getBindings` (one device) and `getAllBindings` (all 988) there
246424
+ * was nothing, so a caller that needs seventy-five either pays
246425
+ * seventy-five round-trips or drags the whole fleet across. Measured on
246426
+ * the live hub 2026-08-25: 75 concurrent `getBindings` = 1211 ms / 118 KB,
246427
+ * `getAllBindings({})` = 511 ms / 679 KB. Neither is the right answer to
246428
+ * "these seventy-five".
246429
+ *
246430
+ * Same resolver, same routing rules, same per-device shape as
246431
+ * `getBindings`; ids are deduped and a device with no bindings answers
246432
+ * `entries: []` rather than dropping out.
246433
+ */
246434
+ getBindingsBatch: require_sleep.method(zod.z.object({ deviceIds: zod.z.array(zod.z.number()) }), zod.z.array(DeviceBindingsForDeviceSchema)),
246283
246435
  /**
246284
246436
  * Return the binding map for every device known to the hub. Used by
246285
246437
  * `SystemManager` warm-boot: a single round-trip resolves the
@@ -246288,16 +246440,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
246288
246440
  * device add/remove) — clients invalidate via the
246289
246441
  * `capability.binding-changed` event.
246290
246442
  */
246291
- getAllBindings: require_sleep.method(zod.z.object({}), zod.z.array(zod.z.object({
246292
- deviceId: zod.z.number(),
246293
- entries: zod.z.array(zod.z.object({
246294
- capName: zod.z.string(),
246295
- kind: zod.z.enum(["native", "wrapped"]),
246296
- providerAddonId: zod.z.string(),
246297
- providerNodeId: zod.z.string(),
246298
- nativeAddonId: zod.z.string()
246299
- }))
246300
- }))),
246443
+ getAllBindings: require_sleep.method(zod.z.object({}), zod.z.array(DeviceBindingsForDeviceSchema)),
246301
246444
  /**
246302
246445
  * Activate (or deactivate) a wrapper addon for a (device, cap) pair.
246303
246446
  * Persists the binding via ctx.settings. active=false clears the wrapper
@@ -268619,6 +268762,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
268619
268762
  addonId: null,
268620
268763
  access: "view"
268621
268764
  },
268765
+ "deviceManager.getBindingsBatch": {
268766
+ capName: "device-manager",
268767
+ capScope: "system",
268768
+ addonId: null,
268769
+ access: "view"
268770
+ },
268622
268771
  "deviceManager.getChildren": {
268623
268772
  capName: "device-manager",
268624
268773
  capScope: "system",
@@ -268679,6 +268828,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
268679
268828
  addonId: null,
268680
268829
  access: "view"
268681
268830
  },
268831
+ "deviceManager.getLinkedDevicesBatch": {
268832
+ capName: "device-manager",
268833
+ capScope: "system",
268834
+ addonId: null,
268835
+ access: "view"
268836
+ },
268682
268837
  "deviceManager.getRoleDisplayDefaults": {
268683
268838
  capName: "device-manager",
268684
268839
  capScope: "system",
@@ -273578,6 +273733,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
273578
273733
  form: "single",
273579
273734
  optional: false
273580
273735
  }],
273736
+ "deviceManager.getBindingsBatch": [{
273737
+ name: "deviceIds",
273738
+ form: "array",
273739
+ optional: false
273740
+ }],
273581
273741
  "deviceManager.getChildren": [{
273582
273742
  name: "parentDeviceId",
273583
273743
  form: "single",
@@ -273623,6 +273783,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
273623
273783
  form: "single",
273624
273784
  optional: false
273625
273785
  }],
273786
+ "deviceManager.getLinkedDevicesBatch": [{
273787
+ name: "deviceIds",
273788
+ form: "array",
273789
+ optional: false
273790
+ }],
273626
273791
  "deviceManager.getSettingsSchema": [{
273627
273792
  name: "deviceId",
273628
273793
  form: "single",
@@ -273643,6 +273808,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
273643
273808
  form: "single",
273644
273809
  optional: false
273645
273810
  }],
273811
+ "deviceManager.listAll": [{
273812
+ name: "deviceIds",
273813
+ form: "array",
273814
+ optional: true
273815
+ }],
273646
273816
  "deviceManager.loadConfig": [{
273647
273817
  name: "deviceId",
273648
273818
  form: "single",
@@ -275031,6 +275201,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
275031
275201
  "deviceManager.disable",
275032
275202
  "deviceManager.enable",
275033
275203
  "deviceManager.getBindings",
275204
+ "deviceManager.getBindingsBatch",
275034
275205
  "deviceManager.getChildren",
275035
275206
  "deviceManager.getConfigSchema",
275036
275207
  "deviceManager.getDevice",
@@ -275040,10 +275211,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
275040
275211
  "deviceManager.getDeviceStatusAggregate",
275041
275212
  "deviceManager.getDeviceStatusAggregateBatch",
275042
275213
  "deviceManager.getLinkedDevices",
275214
+ "deviceManager.getLinkedDevicesBatch",
275043
275215
  "deviceManager.getSettingsSchema",
275044
275216
  "deviceManager.getStreamProfileMap",
275045
275217
  "deviceManager.getStreamSources",
275046
275218
  "deviceManager.getWireableFields",
275219
+ "deviceManager.listAll",
275047
275220
  "deviceManager.loadConfig",
275048
275221
  "deviceManager.loadMeta",
275049
275222
  "deviceManager.loadRuntimeState",
@@ -275721,7 +275894,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
275721
275894
  listPersistedByAddon: (input) => dispatch("deviceManager", "listPersistedByAddon", "query", input),
275722
275895
  listAll: (input) => dispatch("deviceManager", "listAll", "query", input),
275723
275896
  getChildren: (input) => dispatch("deviceManager", "getChildren", "query", input),
275897
+ getLinkedDevicesBatch: (input) => dispatch("deviceManager", "getLinkedDevicesBatch", "query", input),
275724
275898
  removeByIntegration: (input) => dispatch("deviceManager", "removeByIntegration", "mutation", input),
275899
+ getBindingsBatch: (input) => dispatch("deviceManager", "getBindingsBatch", "query", input),
275900
+ getAllBindings: (input) => dispatch("deviceManager", "getAllBindings", "query", input),
275725
275901
  listWrappersForCap: (input) => dispatch("deviceManager", "listWrappersForCap", "query", input),
275726
275902
  listBindableCapsForDeviceType: (input) => dispatch("deviceManager", "listBindableCapsForDeviceType", "query", input),
275727
275903
  discoverDevices: (input) => dispatch("deviceManager", "discoverDevices", "mutation", input),
@@ -409366,7 +409542,7 @@ var require_moleculer_service = __commonJS({
409366
409542
  const params = buildChildUdsManifest(childNodeId, child.childId, child.caps);
409367
409543
  if (!this.childManifestGate.shouldApply(child.childId, child.incarnation, params)) {
409368
409544
  if (this.childManifestGate.sampleDue()) {
409369
- logger.debug("UDS child re-registered with an unchanged manifest \u2014 skipped", {
409545
+ logger.info("UDS child re-registered with an unchanged manifest \u2014 skipped", {
409370
409546
  meta: {
409371
409547
  nodeId: childNodeId,
409372
409548
  incarnation: child.incarnation,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "camstack",
3
- "version": "1.2.40",
3
+ "version": "1.2.41",
4
4
  "description": "CLI tool for managing and running CamStack server",
5
5
  "keywords": [
6
6
  "camstack",