@camstack/system 1.2.122 → 1.2.124

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 (59) hide show
  1. package/dist/addon-runner.js +1 -1
  2. package/dist/addon-runner.mjs +1 -1
  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/core-blocks/core-blocks.addon.js +1 -1
  14. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  15. package/dist/builtins/device-manager/device-bindings-store.d.ts +20 -0
  16. package/dist/builtins/device-manager/device-linked-devices.d.ts +16 -0
  17. package/dist/builtins/device-manager/device-manager.addon.d.ts +6 -0
  18. package/dist/builtins/device-manager/device-manager.addon.js +73 -7
  19. package/dist/builtins/device-manager/device-manager.addon.mjs +73 -7
  20. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  21. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  22. package/dist/builtins/hub-forwarder/index.js +1 -1
  23. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  24. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  25. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  26. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  27. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  28. package/dist/builtins/local-network/local-network.addon.js +1 -1
  29. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  30. package/dist/builtins/loki-logging/index.js +1 -1
  31. package/dist/builtins/loki-logging/index.mjs +1 -1
  32. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  33. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  34. package/dist/builtins/platform-probe/index.js +1 -1
  35. package/dist/builtins/platform-probe/index.mjs +1 -1
  36. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  37. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  38. package/dist/builtins/snapshot/index.js +1 -1
  39. package/dist/builtins/snapshot/index.mjs +1 -1
  40. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  41. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  42. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +2 -2
  43. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +2 -2
  44. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  45. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  46. package/dist/builtins/system-config/system-config.addon.js +1 -1
  47. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  48. package/dist/builtins/winston-logging/index.js +1 -1
  49. package/dist/builtins/winston-logging/index.mjs +1 -1
  50. package/dist/{dist-DnhGRFEn.js → dist-CIDgcxPk.js} +97 -21
  51. package/dist/{dist-CEhrHp3u.mjs → dist-CvJrtLkw.mjs} +97 -21
  52. package/dist/index.js +2 -2
  53. package/dist/index.mjs +2 -2
  54. package/dist/kernel/heap-watch.d.ts +80 -1
  55. package/dist/{manifest-python-deps-DZSNlHjU.mjs → manifest-python-deps-D1Ydw7J0.mjs} +93 -8
  56. package/dist/{manifest-python-deps-76dZLxD0.js → manifest-python-deps-DB_4H3tR.js} +93 -8
  57. package/dist/{retired-settings-keys-VAyOhu_a.mjs → retired-settings-keys-B1aZcoS0.mjs} +1 -1
  58. package/dist/{retired-settings-keys-D6Jy_SsO.js → retired-settings-keys-D7c0n9jO.js} +1 -1
  59. package/package.json +1 -1
@@ -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-DnhGRFEn.js");
6
+ const require_dist = require("../../dist-CIDgcxPk.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 { Gt as EventCategory, yt as BaseAddon } from "../../dist-CEhrHp3u.mjs";
1
+ import { Gt as EventCategory, yt as BaseAddon } from "../../dist-CvJrtLkw.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
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-DnhGRFEn.js");
6
+ const require_dist = require("../../dist-CIDgcxPk.js");
7
7
  let zod = require("zod");
8
8
  let node_crypto = require("node:crypto");
9
9
  let _camstack_types_node = require("@camstack/types/node");
@@ -1,4 +1,4 @@
1
- import { Ct as DeviceFeature, Gt as EventCategory, M as deriveBatteryPresence, Rt as nodePin, T as batteryCapability, Tt as DeviceType, i as BatteryStatusSchema, mt as streamQualityLabel, ut as snapshotCapability, vt as errMsg, w as bareAddonId, yt as BaseAddon } from "../../dist-CEhrHp3u.mjs";
1
+ import { Ct as DeviceFeature, Gt as EventCategory, M as deriveBatteryPresence, Rt as nodePin, T as batteryCapability, Tt as DeviceType, i as BatteryStatusSchema, mt as streamQualityLabel, ut as snapshotCapability, vt as errMsg, w as bareAddonId, yt as BaseAddon } from "../../dist-CvJrtLkw.mjs";
2
2
  import { z } from "zod";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { signExpiringUrl, verifyExpiringUrl } from "@camstack/types/node";
@@ -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-DnhGRFEn.js");
6
+ const require_dist = require("../../dist-CIDgcxPk.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let node_fs_promises = require("node:fs/promises");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { V as filesystemBrowseCapability, pt as storageProviderCapability, yt as BaseAddon } from "../../dist-CEhrHp3u.mjs";
1
+ import { V as filesystemBrowseCapability, pt as storageProviderCapability, yt as BaseAddon } from "../../dist-CvJrtLkw.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { mkdir, readdir, realpath, statfs } from "node:fs/promises";
4
4
  import * as path$1 from "node:path";
@@ -3,8 +3,8 @@ 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-DnhGRFEn.js");
7
- const require_retired_settings_keys = require("../../retired-settings-keys-D6Jy_SsO.js");
6
+ const require_dist = require("../../dist-CIDgcxPk.js");
7
+ const require_retired_settings_keys = require("../../retired-settings-keys-D7c0n9jO.js");
8
8
  let node_crypto = require("node:crypto");
9
9
  let node_fs = require("node:fs");
10
10
  let node_module = require("node:module");
@@ -1,5 +1,5 @@
1
- import { A as dataStoreProviderCapability, Bt as parseJsonUnknown, _t as vectorStoreCapability, f as RUNTIME_DEFAULTS, gt as vectorDimFromBase64, j as decodeVectorBase64, kt as asJsonObject, vt as errMsg, w as bareAddonId, yt as BaseAddon } from "../../dist-CEhrHp3u.mjs";
2
- import { r as retiredKeyStoreOf, t as purgeRetiredSettingsKeys } from "../../retired-settings-keys-VAyOhu_a.mjs";
1
+ import { A as dataStoreProviderCapability, Bt as parseJsonUnknown, _t as vectorStoreCapability, f as RUNTIME_DEFAULTS, gt as vectorDimFromBase64, j as decodeVectorBase64, kt as asJsonObject, vt as errMsg, w as bareAddonId, yt as BaseAddon } from "../../dist-CvJrtLkw.mjs";
2
+ import { r as retiredKeyStoreOf, t as purgeRetiredSettingsKeys } from "../../retired-settings-keys-B1aZcoS0.mjs";
3
3
  import { createRequire } from "node:module";
4
4
  import { randomUUID } from "node:crypto";
5
5
  import { statSync } 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-DnhGRFEn.js");
6
+ const require_dist = require("../../dist-CIDgcxPk.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let node_fs_promises = require("node:fs/promises");
9
9
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -1,4 +1,4 @@
1
- import { dt as storageCapability, ft as storageMigrationCapability, g as StorageMigrationJobSchema, h as StorageLocationTypeSchema, lt as settingsStoreCapability, yt as BaseAddon, zt as parseJsonObject } from "../../dist-CEhrHp3u.mjs";
1
+ import { dt as storageCapability, ft as storageMigrationCapability, g as StorageMigrationJobSchema, h as StorageLocationTypeSchema, lt as settingsStoreCapability, yt as BaseAddon, zt as parseJsonObject } from "../../dist-CvJrtLkw.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import * as fs from "node:fs/promises";
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-DnhGRFEn.js");
6
+ const require_dist = require("../../dist-CIDgcxPk.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 { It as hydrateSchema, vt as errMsg, yt as BaseAddon } from "../../dist-CEhrHp3u.mjs";
1
+ import { It as hydrateSchema, vt as errMsg, yt as BaseAddon } from "../../dist-CvJrtLkw.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-DnhGRFEn.js");
6
+ const require_dist = require("../../dist-CIDgcxPk.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 { X as logDestinationCapability, yt as BaseAddon } from "../../dist-CEhrHp3u.mjs";
1
+ import { X as logDestinationCapability, yt as BaseAddon } from "../../dist-CvJrtLkw.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";
@@ -9213,6 +9213,27 @@ var LinkedDeviceSchema = zod.z.object({
9213
9213
  features: zod.z.array(zod.z.string()),
9214
9214
  producesTrackedEvents: zod.z.boolean().optional()
9215
9215
  });
9216
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
9217
+ * The batch answer needs the tag; the single-device answer already has it
9218
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
9219
+ var LinkedDevicesForDeviceSchema = zod.z.object({
9220
+ deviceId: zod.z.number(),
9221
+ mode: LinkedDevicesModeSchema,
9222
+ devices: zod.z.array(LinkedDeviceSchema)
9223
+ });
9224
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
9225
+ * `getAllBindings` all answer in. Declared once: three copies of the same
9226
+ * object literal is exactly how the three drift apart. */
9227
+ var DeviceBindingsForDeviceSchema = zod.z.object({
9228
+ deviceId: zod.z.number(),
9229
+ entries: zod.z.array(zod.z.object({
9230
+ capName: zod.z.string(),
9231
+ kind: zod.z.enum(["native", "wrapped"]),
9232
+ providerAddonId: zod.z.string(),
9233
+ providerNodeId: zod.z.string(),
9234
+ nativeAddonId: zod.z.string()
9235
+ }))
9236
+ });
9216
9237
  var SavedDeviceRowSchema = zod.z.object({
9217
9238
  /** Numeric id reserved at allocateDeviceId time. */
9218
9239
  id: zod.z.number(),
@@ -9575,7 +9596,21 @@ var deviceManagerCapability = {
9575
9596
  projection: zod.z.enum(["full", "slim"]).optional(),
9576
9597
  /** Return only camera devices. Filtering server-side instead of
9577
9598
  * shipping 293 rows to find 12. */
9578
- isCamera: zod.z.boolean().optional()
9599
+ isCamera: zod.z.boolean().optional(),
9600
+ /**
9601
+ * Return only these device ids. For the caller that already KNOWS the
9602
+ * handful it wants and needs a field the id-bearing answer does not
9603
+ * carry — the viewer's linked-devices panel joins `type` and `online`
9604
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
9605
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
9606
+ * refetches on the reconcile interval, on a phone.
9607
+ *
9608
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
9609
+ * keys rather than rejecting them (verified against the live hub
9610
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
9611
+ * it answers today and the caller filters as it already does.
9612
+ */
9613
+ deviceIds: zod.z.array(zod.z.number()).optional()
9579
9614
  }), zod.z.array(DeviceInfoSchema)),
9580
9615
  /** Get a single device by numeric deviceId. */
9581
9616
  getDevice: method(zod.z.object({ deviceId: zod.z.number() }), DeviceInfoSchema.nullable()),
@@ -9594,6 +9629,23 @@ var deviceManagerCapability = {
9594
9629
  mode: LinkedDevicesModeSchema,
9595
9630
  devices: zod.z.array(LinkedDeviceSchema)
9596
9631
  })),
9632
+ /**
9633
+ * `getLinkedDevices` for MANY cameras, in one call.
9634
+ *
9635
+ * Not a convenience wrapper — a cost fix. Resolving one camera's linked set
9636
+ * needs the whole fleet as candidates (children ∪ same-location), so the
9637
+ * single-device path runs a full `listAll` per call. Asked per camera that
9638
+ * is N full-fleet sweeps of device-manager's event loop, and they do not
9639
+ * overlap: measured on the live hub 2026-08-25, 30 concurrent
9640
+ * `getLinkedDevices` took 4110 ms wall (median 4060 ms each) to return
9641
+ * 7260 bytes in total. The batch takes ONE sweep and one settings read per
9642
+ * camera.
9643
+ *
9644
+ * A device id that resolves to nothing still gets a row (`devices: []`) —
9645
+ * a caller that asked for thirty and got twenty-eight cannot tell which two
9646
+ * are missing, or that any are.
9647
+ */
9648
+ getLinkedDevicesBatch: method(zod.z.object({ deviceIds: zod.z.array(zod.z.number()) }), zod.z.array(LinkedDevicesForDeviceSchema)),
9597
9649
  /** Get stream sources for a camera device. */
9598
9650
  getStreamSources: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.array(StreamSourceEntrySchema$1)),
9599
9651
  /** Get config entries (key + value + description) for a device. */
@@ -9651,16 +9703,22 @@ var deviceManagerCapability = {
9651
9703
  * currently-active provider (native or wrapper) + the underlying native
9652
9704
  * addon id, so consumers can decide routing without re-running discovery.
9653
9705
  */
9654
- getBindings: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.object({
9655
- deviceId: zod.z.number(),
9656
- entries: zod.z.array(zod.z.object({
9657
- capName: zod.z.string(),
9658
- kind: zod.z.enum(["native", "wrapped"]),
9659
- providerAddonId: zod.z.string(),
9660
- providerNodeId: zod.z.string(),
9661
- nativeAddonId: zod.z.string()
9662
- }))
9663
- })),
9706
+ getBindings: method(zod.z.object({ deviceId: zod.z.number() }), DeviceBindingsForDeviceSchema),
9707
+ /**
9708
+ * `getBindings` for a NAMED set of devices, in one call.
9709
+ *
9710
+ * Between `getBindings` (one device) and `getAllBindings` (all 988) there
9711
+ * was nothing, so a caller that needs seventy-five either pays
9712
+ * seventy-five round-trips or drags the whole fleet across. Measured on
9713
+ * the live hub 2026-08-25: 75 concurrent `getBindings` = 1211 ms / 118 KB,
9714
+ * `getAllBindings({})` = 511 ms / 679 KB. Neither is the right answer to
9715
+ * "these seventy-five".
9716
+ *
9717
+ * Same resolver, same routing rules, same per-device shape as
9718
+ * `getBindings`; ids are deduped and a device with no bindings answers
9719
+ * `entries: []` rather than dropping out.
9720
+ */
9721
+ getBindingsBatch: method(zod.z.object({ deviceIds: zod.z.array(zod.z.number()) }), zod.z.array(DeviceBindingsForDeviceSchema)),
9664
9722
  /**
9665
9723
  * Return the binding map for every device known to the hub. Used by
9666
9724
  * `SystemManager` warm-boot: a single round-trip resolves the
@@ -9669,16 +9727,7 @@ var deviceManagerCapability = {
9669
9727
  * device add/remove) — clients invalidate via the
9670
9728
  * `capability.binding-changed` event.
9671
9729
  */
9672
- getAllBindings: method(zod.z.object({}), zod.z.array(zod.z.object({
9673
- deviceId: zod.z.number(),
9674
- entries: zod.z.array(zod.z.object({
9675
- capName: zod.z.string(),
9676
- kind: zod.z.enum(["native", "wrapped"]),
9677
- providerAddonId: zod.z.string(),
9678
- providerNodeId: zod.z.string(),
9679
- nativeAddonId: zod.z.string()
9680
- }))
9681
- }))),
9730
+ getAllBindings: method(zod.z.object({}), zod.z.array(DeviceBindingsForDeviceSchema)),
9682
9731
  /**
9683
9732
  * Activate (or deactivate) a wrapper addon for a (device, cap) pair.
9684
9733
  * Persists the binding via ctx.settings. active=false clears the wrapper
@@ -31810,6 +31859,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
31810
31859
  addonId: null,
31811
31860
  access: "view"
31812
31861
  },
31862
+ "deviceManager.getBindingsBatch": {
31863
+ capName: "device-manager",
31864
+ capScope: "system",
31865
+ addonId: null,
31866
+ access: "view"
31867
+ },
31813
31868
  "deviceManager.getChildren": {
31814
31869
  capName: "device-manager",
31815
31870
  capScope: "system",
@@ -31870,6 +31925,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
31870
31925
  addonId: null,
31871
31926
  access: "view"
31872
31927
  },
31928
+ "deviceManager.getLinkedDevicesBatch": {
31929
+ capName: "device-manager",
31930
+ capScope: "system",
31931
+ addonId: null,
31932
+ access: "view"
31933
+ },
31873
31934
  "deviceManager.getRoleDisplayDefaults": {
31874
31935
  capName: "device-manager",
31875
31936
  capScope: "system",
@@ -36517,6 +36578,11 @@ Object.freeze({
36517
36578
  form: "single",
36518
36579
  optional: false
36519
36580
  }],
36581
+ "deviceManager.getBindingsBatch": [{
36582
+ name: "deviceIds",
36583
+ form: "array",
36584
+ optional: false
36585
+ }],
36520
36586
  "deviceManager.getChildren": [{
36521
36587
  name: "parentDeviceId",
36522
36588
  form: "single",
@@ -36562,6 +36628,11 @@ Object.freeze({
36562
36628
  form: "single",
36563
36629
  optional: false
36564
36630
  }],
36631
+ "deviceManager.getLinkedDevicesBatch": [{
36632
+ name: "deviceIds",
36633
+ form: "array",
36634
+ optional: false
36635
+ }],
36565
36636
  "deviceManager.getSettingsSchema": [{
36566
36637
  name: "deviceId",
36567
36638
  form: "single",
@@ -36582,6 +36653,11 @@ Object.freeze({
36582
36653
  form: "single",
36583
36654
  optional: false
36584
36655
  }],
36656
+ "deviceManager.listAll": [{
36657
+ name: "deviceIds",
36658
+ form: "array",
36659
+ optional: true
36660
+ }],
36585
36661
  "deviceManager.loadConfig": [{
36586
36662
  name: "deviceId",
36587
36663
  form: "single",
@@ -9213,6 +9213,27 @@ var LinkedDeviceSchema = z.object({
9213
9213
  features: z.array(z.string()),
9214
9214
  producesTrackedEvents: z.boolean().optional()
9215
9215
  });
9216
+ /** One camera's resolved linked set, tagged with the camera it belongs to.
9217
+ * The batch answer needs the tag; the single-device answer already has it
9218
+ * from the input, which is why `getLinkedDevices` keeps the untagged shape. */
9219
+ var LinkedDevicesForDeviceSchema = z.object({
9220
+ deviceId: z.number(),
9221
+ mode: LinkedDevicesModeSchema,
9222
+ devices: z.array(LinkedDeviceSchema)
9223
+ });
9224
+ /** One device's binding map — the shape `getBindings`, `getBindingsBatch` and
9225
+ * `getAllBindings` all answer in. Declared once: three copies of the same
9226
+ * object literal is exactly how the three drift apart. */
9227
+ var DeviceBindingsForDeviceSchema = z.object({
9228
+ deviceId: z.number(),
9229
+ entries: z.array(z.object({
9230
+ capName: z.string(),
9231
+ kind: z.enum(["native", "wrapped"]),
9232
+ providerAddonId: z.string(),
9233
+ providerNodeId: z.string(),
9234
+ nativeAddonId: z.string()
9235
+ }))
9236
+ });
9216
9237
  var SavedDeviceRowSchema = z.object({
9217
9238
  /** Numeric id reserved at allocateDeviceId time. */
9218
9239
  id: z.number(),
@@ -9575,7 +9596,21 @@ var deviceManagerCapability = {
9575
9596
  projection: z.enum(["full", "slim"]).optional(),
9576
9597
  /** Return only camera devices. Filtering server-side instead of
9577
9598
  * shipping 293 rows to find 12. */
9578
- isCamera: z.boolean().optional()
9599
+ isCamera: z.boolean().optional(),
9600
+ /**
9601
+ * Return only these device ids. For the caller that already KNOWS the
9602
+ * handful it wants and needs a field the id-bearing answer does not
9603
+ * carry — the viewer's linked-devices panel joins `type` and `online`
9604
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
9605
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
9606
+ * refetches on the reconcile interval, on a phone.
9607
+ *
9608
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
9609
+ * keys rather than rejecting them (verified against the live hub
9610
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
9611
+ * it answers today and the caller filters as it already does.
9612
+ */
9613
+ deviceIds: z.array(z.number()).optional()
9579
9614
  }), z.array(DeviceInfoSchema)),
9580
9615
  /** Get a single device by numeric deviceId. */
9581
9616
  getDevice: method(z.object({ deviceId: z.number() }), DeviceInfoSchema.nullable()),
@@ -9594,6 +9629,23 @@ var deviceManagerCapability = {
9594
9629
  mode: LinkedDevicesModeSchema,
9595
9630
  devices: z.array(LinkedDeviceSchema)
9596
9631
  })),
9632
+ /**
9633
+ * `getLinkedDevices` for MANY cameras, in one call.
9634
+ *
9635
+ * Not a convenience wrapper — a cost fix. Resolving one camera's linked set
9636
+ * needs the whole fleet as candidates (children ∪ same-location), so the
9637
+ * single-device path runs a full `listAll` per call. Asked per camera that
9638
+ * is N full-fleet sweeps of device-manager's event loop, and they do not
9639
+ * overlap: measured on the live hub 2026-08-25, 30 concurrent
9640
+ * `getLinkedDevices` took 4110 ms wall (median 4060 ms each) to return
9641
+ * 7260 bytes in total. The batch takes ONE sweep and one settings read per
9642
+ * camera.
9643
+ *
9644
+ * A device id that resolves to nothing still gets a row (`devices: []`) —
9645
+ * a caller that asked for thirty and got twenty-eight cannot tell which two
9646
+ * are missing, or that any are.
9647
+ */
9648
+ getLinkedDevicesBatch: method(z.object({ deviceIds: z.array(z.number()) }), z.array(LinkedDevicesForDeviceSchema)),
9597
9649
  /** Get stream sources for a camera device. */
9598
9650
  getStreamSources: method(z.object({ deviceId: z.number() }), z.array(StreamSourceEntrySchema$1)),
9599
9651
  /** Get config entries (key + value + description) for a device. */
@@ -9651,16 +9703,22 @@ var deviceManagerCapability = {
9651
9703
  * currently-active provider (native or wrapper) + the underlying native
9652
9704
  * addon id, so consumers can decide routing without re-running discovery.
9653
9705
  */
9654
- getBindings: method(z.object({ deviceId: z.number() }), z.object({
9655
- deviceId: z.number(),
9656
- entries: z.array(z.object({
9657
- capName: z.string(),
9658
- kind: z.enum(["native", "wrapped"]),
9659
- providerAddonId: z.string(),
9660
- providerNodeId: z.string(),
9661
- nativeAddonId: z.string()
9662
- }))
9663
- })),
9706
+ getBindings: method(z.object({ deviceId: z.number() }), DeviceBindingsForDeviceSchema),
9707
+ /**
9708
+ * `getBindings` for a NAMED set of devices, in one call.
9709
+ *
9710
+ * Between `getBindings` (one device) and `getAllBindings` (all 988) there
9711
+ * was nothing, so a caller that needs seventy-five either pays
9712
+ * seventy-five round-trips or drags the whole fleet across. Measured on
9713
+ * the live hub 2026-08-25: 75 concurrent `getBindings` = 1211 ms / 118 KB,
9714
+ * `getAllBindings({})` = 511 ms / 679 KB. Neither is the right answer to
9715
+ * "these seventy-five".
9716
+ *
9717
+ * Same resolver, same routing rules, same per-device shape as
9718
+ * `getBindings`; ids are deduped and a device with no bindings answers
9719
+ * `entries: []` rather than dropping out.
9720
+ */
9721
+ getBindingsBatch: method(z.object({ deviceIds: z.array(z.number()) }), z.array(DeviceBindingsForDeviceSchema)),
9664
9722
  /**
9665
9723
  * Return the binding map for every device known to the hub. Used by
9666
9724
  * `SystemManager` warm-boot: a single round-trip resolves the
@@ -9669,16 +9727,7 @@ var deviceManagerCapability = {
9669
9727
  * device add/remove) — clients invalidate via the
9670
9728
  * `capability.binding-changed` event.
9671
9729
  */
9672
- getAllBindings: method(z.object({}), z.array(z.object({
9673
- deviceId: z.number(),
9674
- entries: z.array(z.object({
9675
- capName: z.string(),
9676
- kind: z.enum(["native", "wrapped"]),
9677
- providerAddonId: z.string(),
9678
- providerNodeId: z.string(),
9679
- nativeAddonId: z.string()
9680
- }))
9681
- }))),
9730
+ getAllBindings: method(z.object({}), z.array(DeviceBindingsForDeviceSchema)),
9682
9731
  /**
9683
9732
  * Activate (or deactivate) a wrapper addon for a (device, cap) pair.
9684
9733
  * Persists the binding via ctx.settings. active=false clears the wrapper
@@ -31810,6 +31859,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
31810
31859
  addonId: null,
31811
31860
  access: "view"
31812
31861
  },
31862
+ "deviceManager.getBindingsBatch": {
31863
+ capName: "device-manager",
31864
+ capScope: "system",
31865
+ addonId: null,
31866
+ access: "view"
31867
+ },
31813
31868
  "deviceManager.getChildren": {
31814
31869
  capName: "device-manager",
31815
31870
  capScope: "system",
@@ -31870,6 +31925,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
31870
31925
  addonId: null,
31871
31926
  access: "view"
31872
31927
  },
31928
+ "deviceManager.getLinkedDevicesBatch": {
31929
+ capName: "device-manager",
31930
+ capScope: "system",
31931
+ addonId: null,
31932
+ access: "view"
31933
+ },
31873
31934
  "deviceManager.getRoleDisplayDefaults": {
31874
31935
  capName: "device-manager",
31875
31936
  capScope: "system",
@@ -36517,6 +36578,11 @@ Object.freeze({
36517
36578
  form: "single",
36518
36579
  optional: false
36519
36580
  }],
36581
+ "deviceManager.getBindingsBatch": [{
36582
+ name: "deviceIds",
36583
+ form: "array",
36584
+ optional: false
36585
+ }],
36520
36586
  "deviceManager.getChildren": [{
36521
36587
  name: "parentDeviceId",
36522
36588
  form: "single",
@@ -36562,6 +36628,11 @@ Object.freeze({
36562
36628
  form: "single",
36563
36629
  optional: false
36564
36630
  }],
36631
+ "deviceManager.getLinkedDevicesBatch": [{
36632
+ name: "deviceIds",
36633
+ form: "array",
36634
+ optional: false
36635
+ }],
36565
36636
  "deviceManager.getSettingsSchema": [{
36566
36637
  name: "deviceId",
36567
36638
  form: "single",
@@ -36582,6 +36653,11 @@ Object.freeze({
36582
36653
  form: "single",
36583
36654
  optional: false
36584
36655
  }],
36656
+ "deviceManager.listAll": [{
36657
+ name: "deviceIds",
36658
+ form: "array",
36659
+ optional: true
36660
+ }],
36585
36661
  "deviceManager.loadConfig": [{
36586
36662
  name: "deviceId",
36587
36663
  form: "single",
package/dist/index.js CHANGED
@@ -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-DnhGRFEn.js");
3
+ const require_dist = require("./dist-CIDgcxPk.js");
4
4
  const require_builtins_alerts_alerts_addon = require("./builtins/alerts/alerts.addon.js");
5
5
  require("./builtins/alerts/index.js");
6
6
  const require_formatter = require("./formatter-DqAKDlvN.js");
@@ -25,7 +25,7 @@ const require_builtins_system_config_system_config_addon = require("./builtins/s
25
25
  require("./builtins/system-config/index.js");
26
26
  const require_builtins_winston_logging_index = require("./builtins/winston-logging/index.js");
27
27
  const require_file_data_plane = require("./file-data-plane-DO8KbxCe.js");
28
- const require_manifest_python_deps = require("./manifest-python-deps-76dZLxD0.js");
28
+ const require_manifest_python_deps = require("./manifest-python-deps-DB_4H3tR.js");
29
29
  const require_resource_monitor = require("./resource-monitor-CdnzxBLP.js");
30
30
  const require_lan_http_bind = require("./lan-http-bind-DmgpFP6_.js");
31
31
  const require_custom_action_registry = require("./custom-action-registry-jY0NOZK8.js");
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM$1, r as __exportAll, t as __commonJSMin$1 } from "./chunk-CNf5ZN-e.mjs";
2
- import { At as asNumber, B as extractNestedAddonId, Bt as parseJsonUnknown$1, Dt as ReadinessTimeoutError, Et as ReadinessRegistry, Ft as expandCapMethods, Gt as EventCategory$1, H as isArrayOutputSchema, Ht as resolveCapMount, J as lifecycleJobSchema, K as isVoidInput, Mt as createEvent, Nt as emitDownForOwnedCaps, Q as looseSchema, St as DEVICE_STATUS_METHOD, U as isCollectionArrayMethod, Ut as scopeKey, Vt as readinessKey, W as isObjectInput, Z as logLevelAtMost, bt as DATAPLANE_SECRET_HEADER$1, d as METHOD_ACCESS_MAP, f as RUNTIME_DEFAULTS, it as procedureAuthKey, jt as asString$1, kt as asJsonObject$1, ot as scopesAllowAddon, q as kebabToCamel, st as scopesAllowDeviceCap, t as ALL_CAPABILITY_DEFINITIONS, tt as objectInputDeclaresAddonId, vt as errMsg$1, xt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, y as addonSettingsCapability, zt as parseJsonObject } from "./dist-CEhrHp3u.mjs";
2
+ import { At as asNumber, B as extractNestedAddonId, Bt as parseJsonUnknown$1, Dt as ReadinessTimeoutError, Et as ReadinessRegistry, Ft as expandCapMethods, Gt as EventCategory$1, H as isArrayOutputSchema, Ht as resolveCapMount, J as lifecycleJobSchema, K as isVoidInput, Mt as createEvent, Nt as emitDownForOwnedCaps, Q as looseSchema, St as DEVICE_STATUS_METHOD, U as isCollectionArrayMethod, Ut as scopeKey, Vt as readinessKey, W as isObjectInput, Z as logLevelAtMost, bt as DATAPLANE_SECRET_HEADER$1, d as METHOD_ACCESS_MAP, f as RUNTIME_DEFAULTS, it as procedureAuthKey, jt as asString$1, kt as asJsonObject$1, ot as scopesAllowAddon, q as kebabToCamel, st as scopesAllowDeviceCap, t as ALL_CAPABILITY_DEFINITIONS, tt as objectInputDeclaresAddonId, vt as errMsg$1, xt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, y as addonSettingsCapability, zt as parseJsonObject } from "./dist-CvJrtLkw.mjs";
3
3
  import { AlertCenterAddon } from "./builtins/alerts/alerts.addon.mjs";
4
4
  import "./builtins/alerts/index.mjs";
5
5
  import { t as formatLogLine } from "./formatter-B7qW8bPJ.mjs";
@@ -24,7 +24,7 @@ import { SystemConfigAddon } from "./builtins/system-config/system-config.addon.
24
24
  import "./builtins/system-config/index.mjs";
25
25
  import { WinstonDestination, WinstonLoggingAddon } from "./builtins/winston-logging/index.mjs";
26
26
  import { a as parseTokenizedUrl, c as collectModelFiles, d as downloadModel, f as ensureModel, h as isModelDownloaded, i as parseRangeHeader, l as deleteModelFromDisk, m as getModelFilePath, n as contentTypeFor, o as resolveFilePath, p as fetchJson, r as createAuthenticatedFileServer, s as ModelDownloadService, t as createFileDataPlaneHandler, u as downloadFile } from "./file-data-plane-BhKdxJgf.mjs";
27
- import { $ as buildNativeCapProxy, A as createHubCapForwardService, At as buildHeapSample, B as AGENT_CAP_FWD_ACTION, C as brokerTransportLink, Ct as runNpm, D as localProviderLink, Dt as HEAP_WATCH_INTERVAL_MS, E as ipcParentLink, Et as HEAP_RECLAIM_TRIGGER_MB, F as createUdsLogger, Ft as strandedMb, G as callWithServiceDiscovery, H as CapRouteResolver, I as createUdsLoggerWithControl, J as UdsLocalTransportServer, K as createLocalTransport, L as LocalChildClient, M as createUdsEventBridge, Mt as shouldReclaim, N as createUdsEventBus, Nt as startHeapWatch, O as HUB_CAP_FWD_ACTION, Ot as HEAP_WATCH_WARN_RATIO, P as udsChildLogToWorkerEntry, Pt as startRunnerHeapWatch, Q as encodeFrame, R as LocalChildRegistry, S as brokerCallForCap, St as resolveNpmInvocation, T as ipcChildLink, Tt as HEAP_RECLAIM_MIN_INTERVAL_MS, 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 installManifestNativeDeps, 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, jt as createV8Reclaimer, k as HUB_CAP_FWD_SERVICE, kt as RUNNER_HEAP_WATCH_INTERVAL_MS, 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, wt as createAddonDataPlaneFacility, x as getCapUsageRegistry, xt as resolveAddonClass, y as CapUsageRegistry, yt as copyBundledNativeModules, z as UDS_NO_ROUTE_PREFIX } from "./manifest-python-deps-DZSNlHjU.mjs";
27
+ import { $ as buildNativeCapProxy, A as createHubCapForwardService, At as buildHeapSample, B as AGENT_CAP_FWD_ACTION, C as brokerTransportLink, Ct as runNpm, D as localProviderLink, Dt as HEAP_WATCH_INTERVAL_MS, E as ipcParentLink, Et as HEAP_RECLAIM_TRIGGER_MB, F as createUdsLogger, Ft as strandedMb, G as callWithServiceDiscovery, H as CapRouteResolver, I as createUdsLoggerWithControl, J as UdsLocalTransportServer, K as createLocalTransport, L as LocalChildClient, M as createUdsEventBridge, Mt as shouldReclaim, N as createUdsEventBus, Nt as startHeapWatch, O as HUB_CAP_FWD_ACTION, Ot as HEAP_WATCH_WARN_RATIO, P as udsChildLogToWorkerEntry, Pt as startRunnerHeapWatch, Q as encodeFrame, R as LocalChildRegistry, S as brokerCallForCap, St as resolveNpmInvocation, T as ipcChildLink, Tt as HEAP_RECLAIM_MIN_INTERVAL_MS, 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 installManifestNativeDeps, 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, jt as createV8Reclaimer, k as HUB_CAP_FWD_SERVICE, kt as RUNNER_HEAP_WATCH_INTERVAL_MS, 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, wt as createAddonDataPlaneFacility, x as getCapUsageRegistry, xt as resolveAddonClass, y as CapUsageRegistry, yt as copyBundledNativeModules, z as UDS_NO_ROUTE_PREFIX } from "./manifest-python-deps-D1Ydw7J0.mjs";
28
28
  import { n as getSinglePidStats, t as getPidStats } from "./resource-monitor-BWmQ5i-o.mjs";
29
29
  import { C as evaluateExistingCert, S as SERVER_AUTH_OID, _ as CA_COMMON_NAME, a as closeLanHttp, b as LEAF_RENEWAL_WINDOW_DAYS, c as readExtraSans, d as writeExtraSans, f as writeTlsMode, g as reissueTlsLeaf, h as loadTlsCert, i as bindPendingLanHttp, l as readTlsAccessStatus, m as ensureTlsCert, n as allFamiliesListenHost, o as readLanHttpState, p as validateUploadedTls, r as applyLanHttp, s as registerLanHttpHandler, t as DEFAULT_LAN_HTTP_PORT, u as readTlsMode, v as collectCertIdentity, x as MAX_LEAF_VALIDITY_DAYS, y as CA_VALIDITY_DAYS } from "./lan-http-bind-jKrj6OjQ.mjs";
30
30
  import { t as CustomActionRegistry } from "./custom-action-registry-F__gp_VX.mjs";
@@ -99,6 +99,85 @@ export declare const HEAP_RECLAIM_TRIGGER_MB = 1024;
99
99
  * router's time, against a ~1.5GiB peak it removes each pass.
100
100
  */
101
101
  export declare const HEAP_RECLAIM_MIN_INTERVAL_MS = 120000;
102
+ /**
103
+ * Consecutive floor-to-floor passes after which the reclaim is announced as
104
+ * STEADY STATE rather than a rescue.
105
+ *
106
+ * The floor above is documented as a bound on a BURST, on the measured premise
107
+ * that re-stranding the trigger takes ~20 minutes. Measured on the live hub
108
+ * 2026-08-25 it takes under two: 13 passes in 30 minutes, every one of them
109
+ * firing the instant {@link HEAP_RECLAIM_MIN_INTERVAL_MS} elapsed, `took=`
110
+ * 556-695ms each. Nothing in the record said so, because a pass that fires
111
+ * every floor period and a pass that fires once an hour print the same line.
112
+ *
113
+ * Six is 12 minutes of back-to-back passes: long enough that a genuine burst
114
+ * (which subsides) never reaches it, short enough that a process which has
115
+ * quietly made the stop-the-world part of its steady state is named within the
116
+ * quarter-hour. The warn changes no behaviour — the pass is load-bearing and
117
+ * keeps running. It exists so the OPERATOR is told that the safety net has
118
+ * become the mechanism, which is the moment to go after the allocation source
119
+ * instead of the symptom.
120
+ */
121
+ export declare const RECLAIM_STEADY_STATE_PASSES = 6;
122
+ /**
123
+ * Event-loop delay over the window since the previous read, in milliseconds.
124
+ *
125
+ * Why the heartbeat carries this at all: hub-main's event loop is the cluster's
126
+ * only queue (D181 — every settings read from every runner and every agent,
127
+ * every UDS handshake and every cross-runner cap call is served on it, and a
128
+ * live CPU profile of a boot put `(idle)` at 0.1%). The reclaim pass is a
129
+ * stop-the-world ON that loop, and `took=` prices the PASS without ever pricing
130
+ * what it delays. 590ms against a p99 of 4ms is a visible stall; the same 590ms
131
+ * against a p99 of 900ms is noise inside a queue that was already saturated.
132
+ * Those are opposite conclusions, and until now the log could not tell them
133
+ * apart.
134
+ */
135
+ export interface LoopDelaySample {
136
+ readonly p50Ms: number;
137
+ readonly p99Ms: number;
138
+ readonly maxMs: number;
139
+ }
140
+ /** What a loop with nothing recorded yet reports. */
141
+ export declare const ZERO_LOOP_DELAY: LoopDelaySample;
142
+ export interface LoopDelayMeter {
143
+ /** Percentiles over the window since the previous read. Reading RESETS it. */
144
+ readonly read: () => LoopDelaySample;
145
+ readonly stop: () => void;
146
+ }
147
+ /**
148
+ * A `perf_hooks` interval histogram, read once per LOGGED line.
149
+ *
150
+ * The histogram samples in libuv at `resolutionMs` and costs nothing to keep
151
+ * enabled; the expensive part would be reading it on every 2s probe, which
152
+ * would also destroy the window the line claims to describe (probe and log
153
+ * cadences are deliberately different — see {@link startHeapWatch}).
154
+ *
155
+ * An EMPTY histogram is the trap: Node answers `min = 9223372036854776000` and
156
+ * `percentile()` throws on some versions, so a first heartbeat that read it
157
+ * naively would print `loopMax=9223372036854ms` and be read as a catastrophe on
158
+ * every boot. `count === 0` short-circuits to {@link ZERO_LOOP_DELAY}.
159
+ *
160
+ * Returns undefined if the platform declines, so the caller keeps a heartbeat
161
+ * either way.
162
+ */
163
+ export declare function createLoopDelayMeter(resolutionMs?: number): LoopDelayMeter | undefined;
164
+ /** Whether anyone CHOSE this process's old-space ceiling, or V8 derived one. */
165
+ export type HeapCeilingOrigin = 'explicit' | 'v8-default';
166
+ /**
167
+ * Read the origin of the old-space ceiling off node's own options.
168
+ *
169
+ * hub-main is the only process in the cluster whose ceiling nobody chose. Every
170
+ * forked runner is given V8 heap flags by `process-service.ts`; hub-main gets
171
+ * `--max-old-space-size` from `docker-entrypoint.sh` ONLY when the operator sets
172
+ * `CAMSTACK_HUB_HEAP_MB`, and on the live container it is unset — verified
173
+ * 2026-08-25 by reading pid 7's argv, a bare `node .../starter.js`. So the
174
+ * ceiling in force is whatever V8 derives from the host (4288MB there), and the
175
+ * only record of that was a comment inside an image nobody rebuilds to read.
176
+ *
177
+ * A fact about the running process belongs in the running process's log, and
178
+ * `execArgv` answers it for free at boot.
179
+ */
180
+ export declare function heapCeilingOrigin(execArgv?: readonly string[]): HeapCeilingOrigin;
102
181
  export interface HeapSample {
103
182
  readonly rssMb: number;
104
183
  readonly heapUsedMb: number;
@@ -167,7 +246,7 @@ export interface HeapReclaimOptions {
167
246
  * `unref`ed so it can never hold the process open, and every read is wrapped:
168
247
  * a diagnostic that can crash the process it watches is worse than none.
169
248
  */
170
- export declare function startHeapWatch(label?: string, sink?: HeapWatchSink, intervalMs?: number, reclaimOptions?: HeapReclaimOptions): () => void;
249
+ export declare function startHeapWatch(label?: string, sink?: HeapWatchSink, intervalMs?: number, reclaimOptions?: HeapReclaimOptions, loopDelay?: LoopDelayMeter | undefined, execArgv?: readonly string[], announceCeilingOrigin?: boolean): () => void;
171
250
  /**
172
251
  * Steady heartbeat period for a HEAVY addon runner.
173
252
  *