@camstack/system 1.2.123 → 1.2.125

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 (61) hide show
  1. package/dist/addon-runner.js +224 -224
  2. package/dist/addon-runner.mjs +224 -224
  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 +43 -4
  53. package/dist/index.mjs +43 -4
  54. package/dist/kernel/heap-watch.d.ts +12 -9
  55. package/dist/kernel/moleculer/process-service.d.ts +12 -1
  56. package/dist/kernel/moleculer/runner-native-allocator.d.ts +95 -0
  57. package/dist/{manifest-python-deps-B3_4YiDK.js → manifest-python-deps-BTkFwAk_.js} +15 -12
  58. package/dist/{manifest-python-deps-DIIXlR1x.mjs → manifest-python-deps-Dmcnb287.mjs} +15 -12
  59. package/dist/{retired-settings-keys-VAyOhu_a.mjs → retired-settings-keys-B1aZcoS0.mjs} +1 -1
  60. package/dist/{retired-settings-keys-D6Jy_SsO.js → retired-settings-keys-D7c0n9jO.js} +1 -1
  61. package/package.json +1 -1
@@ -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-B3_4YiDK.js");
28
+ const require_manifest_python_deps = require("./manifest-python-deps-BTkFwAk_.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");
@@ -93976,6 +93976,33 @@ var CrashSupervisor = class {
93976
93976
  this.crashes.delete(runnerId);
93977
93977
  }
93978
93978
  };
93979
+ /**
93980
+ * Resolve the native-allocator env for a child runner from the parent's env.
93981
+ *
93982
+ * Precedence, highest first:
93983
+ * 1. `CAMSTACK_RUNNER_NATIVE_ALLOCATOR=off` — kill switch, returns nothing and
93984
+ * restores the glibc/sharp defaults. Recoverable without a rebuild.
93985
+ * 2. A value the operator already put in the environment (`MALLOC_ARENA_MAX`,
93986
+ * `VIPS_CONCURRENCY`) — inherited verbatim, never overwritten.
93987
+ * 3. `CAMSTACK_RUNNER_MALLOC_ARENA_MAX` — the CamStack override.
93988
+ * 4. The defaults above.
93989
+ *
93990
+ * A nonsense override falls back to the default rather than being passed through:
93991
+ * glibc reads `MALLOC_ARENA_MAX=0` as "unbounded", which is the very state this
93992
+ * exists to leave.
93993
+ */
93994
+ function runnerNativeAllocatorEnv(parentEnv) {
93995
+ if (parentEnv["CAMSTACK_RUNNER_NATIVE_ALLOCATOR"] === "off") return {};
93996
+ return {
93997
+ MALLOC_ARENA_MAX: parentEnv["MALLOC_ARENA_MAX"] ?? String(positiveInt(parentEnv["CAMSTACK_RUNNER_MALLOC_ARENA_MAX"], 2)),
93998
+ VIPS_CONCURRENCY: parentEnv["VIPS_CONCURRENCY"] ?? String(1)
93999
+ };
94000
+ }
94001
+ function positiveInt(raw, fallback) {
94002
+ if (raw === void 0) return fallback;
94003
+ const n = Number.parseInt(raw, 10);
94004
+ return Number.isFinite(n) && n > 0 ? n : fallback;
94005
+ }
93979
94006
  //#endregion
93980
94007
  //#region src/kernel/moleculer/process-service.ts
93981
94008
  /**
@@ -94136,7 +94163,18 @@ function isHeavyRunner(addons) {
94136
94163
  *
94137
94164
  * A runner whose working set genuinely does not fit declares its own number in its manifest
94138
94165
  * (`execution.maxOldSpaceMb`) — the number belongs next to the addon that knows its working set.
94139
- * `stream-broker` (1323 MB measured, frame buffers) is the one shipped addon that does.
94166
+ * `recorder` (3072 MB; peak 2341 MB heapTotal during the deferred archive walk) is the one
94167
+ * shipped addon that does. `stream-broker` does NOT, despite 1585 MB peak RSS: ~1 GB of that is
94168
+ * `arrayBuffers` (47 RTP rings), which this flag does not bound and never will — its actual old
94169
+ * space peaks at 224 MB. Size the declaration from `heapTotal` in the `[mem]` heartbeat, never
94170
+ * from RSS.
94171
+ *
94172
+ * ## What this flag CANNOT do
94173
+ *
94174
+ * It bounds old space and nothing else — not `external`, not `arrayBuffers`, not what a native
94175
+ * addon mallocs. `hub/pipeline-analytics` reached 7334 MB RSS with this flag set to 1024 the
94176
+ * whole time, because 96% of it was native. That half is bounded in `runner-native-allocator.ts`.
94177
+ * Reaching for a bigger number here when RSS is the complaint is the standard wrong move.
94140
94178
  */
94141
94179
  var HEAVY_MAX_OLD_MB_DEFAULT = 1024;
94142
94180
  /**
@@ -94262,10 +94300,11 @@ function createProcessService(parentNodeId, dataDir, deps, parentTcpPort, parent
94262
94300
  CAMSTACK_LOG_LEVEL: process.env["CAMSTACK_LOG_LEVEL"] ?? "info",
94263
94301
  ...parentTcpPort !== void 0 ? { CAMSTACK_PARENT_TCP_PORT: String(parentTcpPort) } : {},
94264
94302
  ...parentUdsPath !== void 0 ? { CAMSTACK_PARENT_UDS_PATH: parentUdsPath } : {},
94303
+ ...runnerNativeAllocatorEnv(process.env),
94265
94304
  ...env
94266
94305
  };
94267
94306
  const heapFlags = runnerHeapFlags(addons);
94268
- capturedBroker?.logger.info(`[${runnerId}] heap profile: ${heavy ? "heavy" : "light"} flags=[${heapFlags.join(" ")}]`);
94307
+ capturedBroker?.logger.info(`[${runnerId}] heap profile: ${heavy ? "heavy" : "light"} flags=[${heapFlags.join(" ")}] arenas=${childEnv["MALLOC_ARENA_MAX"] ?? "glibc-default"} vips=${childEnv["VIPS_CONCURRENCY"] ?? "sharp-default"}`);
94269
94308
  const child = spawnFn(process.execPath, [...heapFlags, runnerPath], {
94270
94309
  env: childEnv,
94271
94310
  stdio: [
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-DIIXlR1x.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-Dmcnb287.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";
@@ -93969,6 +93969,33 @@ var CrashSupervisor = class {
93969
93969
  this.crashes.delete(runnerId);
93970
93970
  }
93971
93971
  };
93972
+ /**
93973
+ * Resolve the native-allocator env for a child runner from the parent's env.
93974
+ *
93975
+ * Precedence, highest first:
93976
+ * 1. `CAMSTACK_RUNNER_NATIVE_ALLOCATOR=off` — kill switch, returns nothing and
93977
+ * restores the glibc/sharp defaults. Recoverable without a rebuild.
93978
+ * 2. A value the operator already put in the environment (`MALLOC_ARENA_MAX`,
93979
+ * `VIPS_CONCURRENCY`) — inherited verbatim, never overwritten.
93980
+ * 3. `CAMSTACK_RUNNER_MALLOC_ARENA_MAX` — the CamStack override.
93981
+ * 4. The defaults above.
93982
+ *
93983
+ * A nonsense override falls back to the default rather than being passed through:
93984
+ * glibc reads `MALLOC_ARENA_MAX=0` as "unbounded", which is the very state this
93985
+ * exists to leave.
93986
+ */
93987
+ function runnerNativeAllocatorEnv(parentEnv) {
93988
+ if (parentEnv["CAMSTACK_RUNNER_NATIVE_ALLOCATOR"] === "off") return {};
93989
+ return {
93990
+ MALLOC_ARENA_MAX: parentEnv["MALLOC_ARENA_MAX"] ?? String(positiveInt(parentEnv["CAMSTACK_RUNNER_MALLOC_ARENA_MAX"], 2)),
93991
+ VIPS_CONCURRENCY: parentEnv["VIPS_CONCURRENCY"] ?? String(1)
93992
+ };
93993
+ }
93994
+ function positiveInt(raw, fallback) {
93995
+ if (raw === void 0) return fallback;
93996
+ const n = Number.parseInt(raw, 10);
93997
+ return Number.isFinite(n) && n > 0 ? n : fallback;
93998
+ }
93972
93999
  //#endregion
93973
94000
  //#region src/kernel/moleculer/process-service.ts
93974
94001
  /**
@@ -94129,7 +94156,18 @@ function isHeavyRunner(addons) {
94129
94156
  *
94130
94157
  * A runner whose working set genuinely does not fit declares its own number in its manifest
94131
94158
  * (`execution.maxOldSpaceMb`) — the number belongs next to the addon that knows its working set.
94132
- * `stream-broker` (1323 MB measured, frame buffers) is the one shipped addon that does.
94159
+ * `recorder` (3072 MB; peak 2341 MB heapTotal during the deferred archive walk) is the one
94160
+ * shipped addon that does. `stream-broker` does NOT, despite 1585 MB peak RSS: ~1 GB of that is
94161
+ * `arrayBuffers` (47 RTP rings), which this flag does not bound and never will — its actual old
94162
+ * space peaks at 224 MB. Size the declaration from `heapTotal` in the `[mem]` heartbeat, never
94163
+ * from RSS.
94164
+ *
94165
+ * ## What this flag CANNOT do
94166
+ *
94167
+ * It bounds old space and nothing else — not `external`, not `arrayBuffers`, not what a native
94168
+ * addon mallocs. `hub/pipeline-analytics` reached 7334 MB RSS with this flag set to 1024 the
94169
+ * whole time, because 96% of it was native. That half is bounded in `runner-native-allocator.ts`.
94170
+ * Reaching for a bigger number here when RSS is the complaint is the standard wrong move.
94133
94171
  */
94134
94172
  var HEAVY_MAX_OLD_MB_DEFAULT = 1024;
94135
94173
  /**
@@ -94255,10 +94293,11 @@ function createProcessService(parentNodeId, dataDir, deps, parentTcpPort, parent
94255
94293
  CAMSTACK_LOG_LEVEL: process.env["CAMSTACK_LOG_LEVEL"] ?? "info",
94256
94294
  ...parentTcpPort !== void 0 ? { CAMSTACK_PARENT_TCP_PORT: String(parentTcpPort) } : {},
94257
94295
  ...parentUdsPath !== void 0 ? { CAMSTACK_PARENT_UDS_PATH: parentUdsPath } : {},
94296
+ ...runnerNativeAllocatorEnv(process.env),
94258
94297
  ...env
94259
94298
  };
94260
94299
  const heapFlags = runnerHeapFlags(addons);
94261
- capturedBroker?.logger.info(`[${runnerId}] heap profile: ${heavy ? "heavy" : "light"} flags=[${heapFlags.join(" ")}]`);
94300
+ capturedBroker?.logger.info(`[${runnerId}] heap profile: ${heavy ? "heavy" : "light"} flags=[${heapFlags.join(" ")}] arenas=${childEnv["MALLOC_ARENA_MAX"] ?? "glibc-default"} vips=${childEnv["VIPS_CONCURRENCY"] ?? "sharp-default"}`);
94262
94301
  const child = spawnFn(process.execPath, [...heapFlags, runnerPath], {
94263
94302
  env: childEnv,
94264
94303
  stdio: [
@@ -246,7 +246,7 @@ export interface HeapReclaimOptions {
246
246
  * `unref`ed so it can never hold the process open, and every read is wrapped:
247
247
  * a diagnostic that can crash the process it watches is worse than none.
248
248
  */
249
- export declare function startHeapWatch(label?: string, sink?: HeapWatchSink, intervalMs?: number, reclaimOptions?: HeapReclaimOptions, loopDelay?: LoopDelayMeter | undefined, execArgv?: readonly string[]): () => void;
249
+ export declare function startHeapWatch(label?: string, sink?: HeapWatchSink, intervalMs?: number, reclaimOptions?: HeapReclaimOptions, loopDelay?: LoopDelayMeter | undefined, execArgv?: readonly string[], announceCeilingOrigin?: boolean): () => void;
250
250
  /**
251
251
  * Steady heartbeat period for a HEAVY addon runner.
252
252
  *
@@ -291,14 +291,17 @@ export interface RunnerHeapWatchOptions {
291
291
  *
292
292
  * ## Why heavy runners get hub-main's mechanism
293
293
  *
294
- * The media-path runners deliberately run with NO old-space ceiling
295
- * (`maxOldSpaceMb: 0` a flat cap turned a disk-stall backlog into
296
- * `Ineffective mark-compacts near heap limit` and killed recording, twice on
297
- * 2026-08-17). Uncapped, V8 feels no pressure, so a one-off burst becomes the
298
- * runner's permanent RSS: the recorder measured 2122MB holding a ~50MB index.
299
- * hub-main had exactly this shape and its reclaimer is proven live — 11 passes
300
- * in 4h, 375–1652MB returned per pass at 550–680ms each. Same mechanism, same
301
- * `shouldReclaim` stranded-over-trigger gate; never a second implementation.
294
+ * Because a heap ceiling cannot reach what actually strands in them. Every
295
+ * media-path runner now carries an old-space ceiling sized from its own
296
+ * measured peak (`addon-pipeline` manifest + its `manifest-heap-ceilings` spec),
297
+ * and that changes nothing here: what a heavy runner strands is NATIVE —
298
+ * `external`, `arrayBuffers`, glibc arena free lists none of which
299
+ * `--max-old-space-size` bounds. Measured 2026-08-25, `hub/pipeline-analytics`
300
+ * reported `stranded=2552MB` while holding an 81MB V8 heap under a 1024MB
301
+ * ceiling that was in force the whole time. hub-main had exactly this shape and
302
+ * its reclaimer is proven live — 11 passes in 4h, 375–1652MB returned per pass
303
+ * at 550–680ms each. Same mechanism, same `shouldReclaim` stranded-over-trigger
304
+ * gate; never a second implementation.
302
305
  *
303
306
  * ## The stall, priced for the runners that get it
304
307
  *
@@ -36,7 +36,18 @@ interface RunnerAddonSpec {
36
36
  *
37
37
  * A runner whose working set genuinely does not fit declares its own number in its manifest
38
38
  * (`execution.maxOldSpaceMb`) — the number belongs next to the addon that knows its working set.
39
- * `stream-broker` (1323 MB measured, frame buffers) is the one shipped addon that does.
39
+ * `recorder` (3072 MB; peak 2341 MB heapTotal during the deferred archive walk) is the one
40
+ * shipped addon that does. `stream-broker` does NOT, despite 1585 MB peak RSS: ~1 GB of that is
41
+ * `arrayBuffers` (47 RTP rings), which this flag does not bound and never will — its actual old
42
+ * space peaks at 224 MB. Size the declaration from `heapTotal` in the `[mem]` heartbeat, never
43
+ * from RSS.
44
+ *
45
+ * ## What this flag CANNOT do
46
+ *
47
+ * It bounds old space and nothing else — not `external`, not `arrayBuffers`, not what a native
48
+ * addon mallocs. `hub/pipeline-analytics` reached 7334 MB RSS with this flag set to 1024 the
49
+ * whole time, because 96% of it was native. That half is bounded in `runner-native-allocator.ts`.
50
+ * Reaching for a bigger number here when RSS is the complaint is the standard wrong move.
40
51
  */
41
52
  export declare const HEAVY_MAX_OLD_MB_DEFAULT = 1024;
42
53
  interface SpawnedProcess {