@camstack/system 1.2.390 → 1.2.391

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 (503) hide show
  1. package/dist/addon/addon-api-factory.d.ts +30 -30
  2. package/dist/addon-routes/addon-route-registry.d.ts +31 -31
  3. package/dist/addon-runner.js +1 -1
  4. package/dist/addon-runner.mjs +1 -1
  5. package/dist/addon-utils.d.ts +22 -22
  6. package/dist/auth/admin-token-manager.d.ts +37 -67
  7. package/dist/auth/api-key-manager.d.ts +8 -8
  8. package/dist/auth/auth-audit-log.d.ts +29 -49
  9. package/dist/auth/auth-manager.d.ts +127 -126
  10. package/dist/auth/cidr.d.ts +8 -8
  11. package/dist/auth/external-identity-manager.d.ts +46 -34
  12. package/dist/auth/jwt-signing-key.d.ts +14 -14
  13. package/dist/auth/login-session-manager.d.ts +95 -135
  14. package/dist/auth/parse-record.d.ts +13 -13
  15. package/dist/auth/scope-matcher.d.ts +7 -7
  16. package/dist/auth/scoped-token-manager.d.ts +62 -62
  17. package/dist/auth/token-expiry.d.ts +49 -26
  18. package/dist/auth/totp-manager.d.ts +48 -48
  19. package/dist/auth/user-management-internal.d.ts +67 -52
  20. package/dist/auth/user-manager.d.ts +58 -58
  21. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.d.ts +54 -54
  22. package/dist/builtins/addon-pages-aggregator/dedupe-pages.d.ts +22 -4
  23. package/dist/builtins/addon-pages-aggregator/index.d.ts +1 -1
  24. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.d.ts +54 -54
  25. package/dist/builtins/addon-widgets-aggregator/index.d.ts +1 -1
  26. package/dist/builtins/alerts/alerts.addon.d.ts +88 -87
  27. package/dist/builtins/alerts/device-label.d.ts +6 -6
  28. package/dist/builtins/alerts/index.d.ts +1 -1
  29. package/dist/builtins/alerts/prune-policy.d.ts +36 -36
  30. package/dist/builtins/autotrack/autotrack-cameras.d.ts +102 -79
  31. package/dist/builtins/autotrack/autotrack-config.d.ts +81 -81
  32. package/dist/builtins/autotrack/autotrack-decision.d.ts +69 -82
  33. package/dist/builtins/autotrack/autotrack-loop.d.ts +81 -61
  34. package/dist/builtins/autotrack/autotrack.addon.d.ts +103 -66
  35. package/dist/builtins/autotrack/frame-error.d.ts +38 -38
  36. package/dist/builtins/autotrack/frame-measurements.d.ts +79 -79
  37. package/dist/builtins/autotrack/index.d.ts +2 -2
  38. package/dist/builtins/autotrack/ptz-mirror.d.ts +46 -17
  39. package/dist/builtins/autotrack/target-selection.d.ts +33 -47
  40. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +270 -269
  41. package/dist/builtins/backup-orchestrator/cron-helpers.d.ts +17 -17
  42. package/dist/builtins/backup-orchestrator/destination-policy.d.ts +99 -82
  43. package/dist/builtins/backup-orchestrator/download-helpers.d.ts +9 -9
  44. package/dist/builtins/backup-orchestrator/encryption-key-store.d.ts +40 -29
  45. package/dist/builtins/backup-orchestrator/index.d.ts +2 -2
  46. package/dist/builtins/backup-orchestrator/manifest-store.d.ts +88 -69
  47. package/dist/builtins/backup-orchestrator/restore-archive.d.ts +14 -14
  48. package/dist/builtins/backup-orchestrator/run-queue.d.ts +86 -86
  49. package/dist/builtins/backup-orchestrator/schedule-store.d.ts +53 -37
  50. package/dist/builtins/backup-orchestrator/staging-paths.d.ts +23 -23
  51. package/dist/builtins/backup-orchestrator/write-targets.d.ts +53 -53
  52. package/dist/builtins/calendars/calendar-color.d.ts +5 -1
  53. package/dist/builtins/calendars/calendar-prefs-store.d.ts +18 -12
  54. package/dist/builtins/calendars/calendars.addon.d.ts +16 -11
  55. package/dist/builtins/calendars/index.d.ts +1 -1
  56. package/dist/builtins/camera-grid/acquire-retry.d.ts +26 -26
  57. package/dist/builtins/camera-grid/addon.d.ts +200 -174
  58. package/dist/builtins/camera-grid/flv-join.d.ts +32 -58
  59. package/dist/builtins/camera-grid/grid-activity-mirror.d.ts +37 -37
  60. package/dist/builtins/camera-grid/grid-activity.d.ts +83 -42
  61. package/dist/builtins/camera-grid/grid-camera-declarations.d.ts +46 -46
  62. package/dist/builtins/camera-grid/grid-camera-device.d.ts +60 -34
  63. package/dist/builtins/camera-grid/grid-canvas-derivation.d.ts +50 -15
  64. package/dist/builtins/camera-grid/grid-canvas-seed.d.ts +96 -46
  65. package/dist/builtins/camera-grid/grid-canvas.d.ts +74 -74
  66. package/dist/builtins/camera-grid/grid-child.d.ts +29 -16
  67. package/dist/builtins/camera-grid/grid-compositor-child.d.ts +2 -2
  68. package/dist/builtins/camera-grid/grid-compositor-invocation.d.ts +39 -11
  69. package/dist/builtins/camera-grid/grid-compositor.d.ts +50 -50
  70. package/dist/builtins/camera-grid/grid-detection-mapping.d.ts +52 -22
  71. package/dist/builtins/camera-grid/grid-device-settings.d.ts +31 -7
  72. package/dist/builtins/camera-grid/grid-filter-graph.d.ts +41 -41
  73. package/dist/builtins/camera-grid/grid-frame-sample.d.ts +45 -19
  74. package/dist/builtins/camera-grid/grid-instances.d.ts +20 -50
  75. package/dist/builtins/camera-grid/grid-last-frame-store.d.ts +51 -51
  76. package/dist/builtins/camera-grid/grid-layout-native-provider.d.ts +30 -4
  77. package/dist/builtins/camera-grid/grid-plan.d.ts +30 -20
  78. package/dist/builtins/camera-grid/grid-profiles.d.ts +85 -45
  79. package/dist/builtins/camera-grid/grid-row-normalization.d.ts +6 -6
  80. package/dist/builtins/camera-grid/grid-sentry-sources.d.ts +57 -57
  81. package/dist/builtins/camera-grid/grid-snapshot.d.ts +41 -41
  82. package/dist/builtins/camera-grid/grid-stream-descriptor.d.ts +49 -21
  83. package/dist/builtins/camera-grid/grid-stream-invocation.d.ts +37 -22
  84. package/dist/builtins/camera-grid/grid-stream-relay.d.ts +26 -26
  85. package/dist/builtins/camera-grid/grid-stream-session.d.ts +123 -93
  86. package/dist/builtins/camera-grid/grid-tile-feed.d.ts +47 -47
  87. package/dist/builtins/camera-grid/grid-tile-plan.d.ts +55 -20
  88. package/dist/builtins/camera-grid/grid-wire-format.d.ts +22 -6
  89. package/dist/builtins/camera-grid/index.d.ts +44 -44
  90. package/dist/builtins/camera-grid/silence-analysis.d.ts +31 -14
  91. package/dist/builtins/composer/claim-gate.d.ts +54 -27
  92. package/dist/builtins/composer/composed-device-set.d.ts +40 -26
  93. package/dist/builtins/composer/composed-device.d.ts +39 -17
  94. package/dist/builtins/composer/composer-apply-waits.d.ts +20 -13
  95. package/dist/builtins/composer/composer-grafts.d.ts +57 -38
  96. package/dist/builtins/composer/composer-live-set.d.ts +15 -15
  97. package/dist/builtins/composer/composer-plan.d.ts +76 -60
  98. package/dist/builtins/composer/composer-runtime-factory.d.ts +21 -14
  99. package/dist/builtins/composer/composer-seeds.d.ts +20 -14
  100. package/dist/builtins/composer/composer-verdict.d.ts +28 -14
  101. package/dist/builtins/composer/composer.addon.d.ts +23 -9
  102. package/dist/builtins/composer/composer.d.ts +145 -100
  103. package/dist/builtins/composer/composition-declarations.d.ts +50 -39
  104. package/dist/builtins/composer/composition-evaluation.d.ts +38 -22
  105. package/dist/builtins/composer/composition-runtime.d.ts +178 -125
  106. package/dist/builtins/composer/composition-target.d.ts +38 -34
  107. package/dist/builtins/composer/confirmed-seed.d.ts +35 -23
  108. package/dist/builtins/composer/deadline-timer.d.ts +13 -13
  109. package/dist/builtins/composer/existing-target.d.ts +90 -73
  110. package/dist/builtins/composer/field-record.d.ts +26 -19
  111. package/dist/builtins/composer/graft-host.d.ts +56 -32
  112. package/dist/builtins/composer/held-claims.d.ts +26 -9
  113. package/dist/builtins/composer/index.d.ts +1 -1
  114. package/dist/builtins/composer/own-field-reads.d.ts +26 -15
  115. package/dist/builtins/composer/owned-fields-target.d.ts +75 -44
  116. package/dist/builtins/composer/slice-assembler.d.ts +19 -3
  117. package/dist/builtins/composer/source-readings.d.ts +67 -61
  118. package/dist/builtins/composer/source-tracker.d.ts +133 -69
  119. package/dist/builtins/console-logging/console-destination.d.ts +15 -8
  120. package/dist/builtins/console-logging/console-logging.addon.d.ts +20 -19
  121. package/dist/builtins/console-logging/index.d.ts +3 -3
  122. package/dist/builtins/core-blocks/block-package.d.ts +37 -37
  123. package/dist/builtins/core-blocks/block-settings-store.d.ts +34 -21
  124. package/dist/builtins/core-blocks/block-supervisor.d.ts +138 -117
  125. package/dist/builtins/core-blocks/block-type-defs.d.ts +21 -21
  126. package/dist/builtins/core-blocks/blocks-integration.d.ts +76 -49
  127. package/dist/builtins/core-blocks/compile-block.d.ts +37 -37
  128. package/dist/builtins/core-blocks/composition-api.d.ts +38 -24
  129. package/dist/builtins/core-blocks/composition-peers.d.ts +26 -4
  130. package/dist/builtins/core-blocks/composition-sources.d.ts +25 -10
  131. package/dist/builtins/core-blocks/core-block-store.d.ts +109 -109
  132. package/dist/builtins/core-blocks/core-blocks.addon.d.ts +72 -72
  133. package/dist/builtins/core-blocks/extract-settings-schema.d.ts +4 -4
  134. package/dist/builtins/core-blocks/index.d.ts +8 -8
  135. package/dist/builtins/device-manager/adoption-job-engine.d.ts +141 -98
  136. package/dist/builtins/device-manager/claimed-status-overlay.d.ts +42 -9
  137. package/dist/builtins/device-manager/contribution-cache.d.ts +56 -56
  138. package/dist/builtins/device-manager/day-night-config-schema.d.ts +26 -12
  139. package/dist/builtins/device-manager/device-aggregation-merge.d.ts +17 -17
  140. package/dist/builtins/device-manager/device-aggregation.d.ts +277 -254
  141. package/dist/builtins/device-manager/device-bindings-store.d.ts +232 -220
  142. package/dist/builtins/device-manager/device-config-contribution.d.ts +29 -29
  143. package/dist/builtins/device-manager/device-config-secrets.d.ts +32 -13
  144. package/dist/builtins/device-manager/device-event-propagator.d.ts +22 -22
  145. package/dist/builtins/device-manager/device-extension-linked-slot.d.ts +17 -17
  146. package/dist/builtins/device-manager/device-form-secrets.d.ts +14 -14
  147. package/dist/builtins/device-manager/device-linked-devices.d.ts +159 -98
  148. package/dist/builtins/device-manager/device-manager.addon.d.ts +223 -197
  149. package/dist/builtins/device-manager/device-meta-actions.d.ts +306 -305
  150. package/dist/builtins/device-manager/device-meta-store.d.ts +100 -90
  151. package/dist/builtins/device-manager/device-meta-types.d.ts +250 -241
  152. package/dist/builtins/device-manager/device-online-fallback.d.ts +30 -30
  153. package/dist/builtins/device-manager/device-projection.d.ts +53 -67
  154. package/dist/builtins/device-manager/device-provider-context.d.ts +109 -94
  155. package/dist/builtins/device-manager/device-queries.d.ts +63 -63
  156. package/dist/builtins/device-manager/device-row-store.d.ts +417 -365
  157. package/dist/builtins/device-manager/device-source-activation.d.ts +91 -49
  158. package/dist/builtins/device-manager/device-state-claim-views.d.ts +76 -61
  159. package/dist/builtins/device-manager/device-state-claims.d.ts +53 -30
  160. package/dist/builtins/device-manager/device-state-mirror.d.ts +256 -264
  161. package/dist/builtins/device-manager/device-sync-resolvers.d.ts +25 -25
  162. package/dist/builtins/device-manager/field-claims-index.d.ts +85 -58
  163. package/dist/builtins/device-manager/field-ownership.d.ts +54 -36
  164. package/dist/builtins/device-manager/fleet-read-census.d.ts +99 -61
  165. package/dist/builtins/device-manager/image-settings-config-schema.d.ts +18 -8
  166. package/dist/builtins/device-manager/index.d.ts +2 -2
  167. package/dist/builtins/device-manager/linked-devices-manual-backfill.d.ts +20 -9
  168. package/dist/builtins/device-manager/location-alignment.d.ts +46 -46
  169. package/dist/builtins/device-manager/migrate-device.d.ts +178 -101
  170. package/dist/builtins/device-manager/migrate-guard.d.ts +66 -34
  171. package/dist/builtins/device-manager/migrate-hardware-state.d.ts +59 -59
  172. package/dist/builtins/device-manager/migrate-reload.d.ts +42 -4
  173. package/dist/builtins/device-manager/migration-refused.d.ts +20 -20
  174. package/dist/builtins/device-manager/mirror-row-writer.d.ts +205 -179
  175. package/dist/builtins/device-manager/recording-onboard-config-schema.d.ts +56 -32
  176. package/dist/builtins/device-manager/removal-fence.d.ts +48 -48
  177. package/dist/builtins/device-manager/runtime-state-persist-gate.d.ts +54 -26
  178. package/dist/builtins/device-manager/secret-config-paths.d.ts +17 -17
  179. package/dist/builtins/device-manager/stale-wrapper-activations.d.ts +52 -25
  180. package/dist/builtins/device-manager/write-lock.d.ts +13 -13
  181. package/dist/builtins/hub-forwarder/hub-forwarder-destination.d.ts +41 -41
  182. package/dist/builtins/hub-forwarder/hub-forwarder.addon.d.ts +13 -12
  183. package/dist/builtins/hub-forwarder/index.d.ts +3 -3
  184. package/dist/builtins/keychain/index.d.ts +1 -1
  185. package/dist/builtins/keychain/key-sources.d.ts +19 -19
  186. package/dist/builtins/keychain/keychain-crypto.d.ts +4 -4
  187. package/dist/builtins/keychain/keychain-reset-trigger.d.ts +13 -13
  188. package/dist/builtins/keychain/keychain-service.d.ts +128 -128
  189. package/dist/builtins/keychain/keychain-store.d.ts +96 -87
  190. package/dist/builtins/keychain/keychain-usage.d.ts +13 -2
  191. package/dist/builtins/keychain/keychain.addon.d.ts +31 -6
  192. package/dist/builtins/keychain/platform-key-source.d.ts +15 -15
  193. package/dist/builtins/keychain/system-held-secrets.d.ts +17 -4
  194. package/dist/builtins/liveness-monitor/index.d.ts +2 -2
  195. package/dist/builtins/liveness-monitor/liveness-checks.d.ts +73 -52
  196. package/dist/builtins/liveness-monitor/liveness-monitor.addon.d.ts +57 -36
  197. package/dist/builtins/local-auth/admin-account-boot.d.ts +14 -14
  198. package/dist/builtins/local-auth/auth-config-reader.d.ts +34 -17
  199. package/dist/builtins/local-auth/auth-schema.d.ts +92 -69
  200. package/dist/builtins/local-auth/index.d.ts +1 -1
  201. package/dist/builtins/local-auth/jwt-signing-key-keeper.d.ts +22 -22
  202. package/dist/builtins/local-auth/local-auth.addon.d.ts +41 -40
  203. package/dist/builtins/local-auth/oauth-grants.d.ts +57 -57
  204. package/dist/builtins/local-auth/oauth-session-manager.d.ts +62 -62
  205. package/dist/builtins/local-network/address-book.d.ts +61 -36
  206. package/dist/builtins/local-network/index.d.ts +2 -2
  207. package/dist/builtins/local-network/ipv6-lan.d.ts +12 -17
  208. package/dist/builtins/local-network/local-hostname.d.ts +10 -10
  209. package/dist/builtins/local-network/local-network.addon.d.ts +259 -258
  210. package/dist/builtins/loki-logging/index.d.ts +4 -4
  211. package/dist/builtins/loki-logging/loki-destination.d.ts +113 -87
  212. package/dist/builtins/loki-logging/loki-logging.addon.d.ts +61 -42
  213. package/dist/builtins/loki-logging/loki-payload.d.ts +82 -39
  214. package/dist/builtins/loki-logging/retire-enabled-flag.d.ts +37 -12
  215. package/dist/builtins/native-metrics/cgroup-memory.d.ts +206 -159
  216. package/dist/builtins/native-metrics/cgroup-pids.d.ts +138 -91
  217. package/dist/builtins/native-metrics/container-memory-series.d.ts +212 -178
  218. package/dist/builtins/native-metrics/gpu-probe.d.ts +9 -9
  219. package/dist/builtins/native-metrics/index.d.ts +2 -2
  220. package/dist/builtins/native-metrics/load-series-config.d.ts +29 -57
  221. package/dist/builtins/native-metrics/load-series-reader.d.ts +52 -26
  222. package/dist/builtins/native-metrics/load-series-store.d.ts +237 -176
  223. package/dist/builtins/native-metrics/native-metrics-provider.d.ts +43 -43
  224. package/dist/builtins/native-metrics/native-metrics.addon.d.ts +230 -230
  225. package/dist/builtins/native-metrics/node-load-ring.d.ts +196 -196
  226. package/dist/builtins/native-metrics/proc-process-table.d.ts +12 -12
  227. package/dist/builtins/native-metrics/process-classification.d.ts +95 -36
  228. package/dist/builtins/native-metrics/thread-cpu-sampler.d.ts +95 -95
  229. package/dist/builtins/platform-probe/coral-accelerators.d.ts +17 -17
  230. package/dist/builtins/platform-probe/index.d.ts +38 -30
  231. package/dist/builtins/platform-probe/inference-config-resolver.d.ts +27 -27
  232. package/dist/builtins/platform-probe/intel-accelerators.d.ts +8 -8
  233. package/dist/builtins/platform-probe/intel-npu.d.ts +30 -30
  234. package/dist/builtins/platform-probe/platform-scorer.d.ts +35 -35
  235. package/dist/builtins/platform-probe/runtime-packages.d.ts +3 -3
  236. package/dist/builtins/remote-access-orchestrator/enabled-providers-reconcile.d.ts +87 -87
  237. package/dist/builtins/remote-access-orchestrator/index.d.ts +1 -1
  238. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts +66 -35
  239. package/dist/builtins/shared/device-state-changed.d.ts +9 -9
  240. package/dist/builtins/shared/settle-sources.d.ts +16 -16
  241. package/dist/builtins/snapshot/index.d.ts +2 -2
  242. package/dist/builtins/snapshot/snapshot-cache.d.ts +92 -92
  243. package/dist/builtins/snapshot/snapshot-coalescing.d.ts +108 -108
  244. package/dist/builtins/snapshot/snapshot-courtesy.d.ts +48 -48
  245. package/dist/builtins/snapshot/snapshot-durable-store.d.ts +32 -32
  246. package/dist/builtins/snapshot/snapshot-fatigue.d.ts +34 -34
  247. package/dist/builtins/snapshot/snapshot-grab-pick.d.ts +14 -14
  248. package/dist/builtins/snapshot/snapshot-link-url.d.ts +49 -49
  249. package/dist/builtins/snapshot/snapshot-media-handler.d.ts +97 -97
  250. package/dist/builtins/snapshot/snapshot-resize.d.ts +64 -103
  251. package/dist/builtins/snapshot/snapshot.addon.d.ts +569 -568
  252. package/dist/builtins/sqlite-storage/analyze-stats.d.ts +73 -29
  253. package/dist/builtins/sqlite-storage/config-store.d.ts +6 -6
  254. package/dist/builtins/sqlite-storage/device-store.d.ts +16 -16
  255. package/dist/builtins/sqlite-storage/filesystem-browse-provider.d.ts +23 -23
  256. package/dist/builtins/sqlite-storage/filesystem-storage-provider.d.ts +79 -79
  257. package/dist/builtins/sqlite-storage/filesystem-storage.addon.d.ts +27 -26
  258. package/dist/builtins/sqlite-storage/filter-compiler.d.ts +107 -107
  259. package/dist/builtins/sqlite-storage/index.d.ts +12 -12
  260. package/dist/builtins/sqlite-storage/integration-registry.d.ts +37 -37
  261. package/dist/builtins/sqlite-storage/path-guard.d.ts +5 -5
  262. package/dist/builtins/sqlite-storage/prefix-range.d.ts +44 -44
  263. package/dist/builtins/sqlite-storage/query-bounds.d.ts +100 -106
  264. package/dist/builtins/sqlite-storage/query-profiler.d.ts +217 -217
  265. package/dist/builtins/sqlite-storage/retired-collections.d.ts +124 -55
  266. package/dist/builtins/sqlite-storage/retired-settings-keys.d.ts +239 -189
  267. package/dist/builtins/sqlite-storage/shm-lock-canary.d.ts +41 -41
  268. package/dist/builtins/sqlite-storage/sqlite-pragmas.d.ts +162 -162
  269. package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +458 -458
  270. package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +59 -58
  271. package/dist/builtins/sqlite-storage/sqlite-snapshot-protocol.d.ts +37 -32
  272. package/dist/builtins/sqlite-storage/sqlite-snapshot-worker.d.ts +19 -19
  273. package/dist/builtins/sqlite-storage/sqlite-snapshotter.d.ts +76 -76
  274. package/dist/builtins/sqlite-storage/statement-shape.d.ts +54 -54
  275. package/dist/builtins/sqlite-storage/table-sizes.d.ts +71 -71
  276. package/dist/builtins/sqlite-storage/vector-index-shared.d.ts +63 -54
  277. package/dist/builtins/sqlite-storage/vector-index-vec.d.ts +133 -96
  278. package/dist/builtins/sqlite-storage/wal-checkpoint-policy.d.ts +161 -161
  279. package/dist/builtins/sqlite-storage/wal-checkpointer.d.ts +60 -60
  280. package/dist/builtins/sqlite-storage/wal-maintenance.d.ts +94 -94
  281. package/dist/builtins/storage-orchestrator/access-guards.d.ts +37 -26
  282. package/dist/builtins/storage-orchestrator/data-store-dispatch.d.ts +33 -18
  283. package/dist/builtins/storage-orchestrator/drain-ratchet.d.ts +85 -85
  284. package/dist/builtins/storage-orchestrator/drain-state-store.d.ts +20 -10
  285. package/dist/builtins/storage-orchestrator/hub-settings-forward.d.ts +113 -53
  286. package/dist/builtins/storage-orchestrator/index.d.ts +7 -7
  287. package/dist/builtins/storage-orchestrator/location-occupancy-slice.d.ts +64 -40
  288. package/dist/builtins/storage-orchestrator/location-occupancy.d.ts +14 -14
  289. package/dist/builtins/storage-orchestrator/location-protection.d.ts +13 -13
  290. package/dist/builtins/storage-orchestrator/location-repoint-move.d.ts +44 -44
  291. package/dist/builtins/storage-orchestrator/location-root-collision.d.ts +61 -25
  292. package/dist/builtins/storage-orchestrator/location-secrets.d.ts +99 -58
  293. package/dist/builtins/storage-orchestrator/location-store.d.ts +56 -47
  294. package/dist/builtins/storage-orchestrator/location-volume-capacity.d.ts +37 -37
  295. package/dist/builtins/storage-orchestrator/provider-discovery.d.ts +20 -6
  296. package/dist/builtins/storage-orchestrator/storage-cleanup-coordinator.d.ts +51 -51
  297. package/dist/builtins/storage-orchestrator/storage-migration-coordinator.d.ts +224 -224
  298. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +292 -292
  299. package/dist/builtins/storage-orchestrator/storage-orchestrator.service.d.ts +431 -450
  300. package/dist/builtins/storage-orchestrator/storage-pressure-manager.d.ts +104 -104
  301. package/dist/builtins/system-backup/backup-encryption.d.ts +60 -23
  302. package/dist/builtins/system-backup/system-backup.service.d.ts +240 -240
  303. package/dist/builtins/system-config/cluster-secret-keeper.d.ts +54 -34
  304. package/dist/builtins/system-config/index.d.ts +2 -2
  305. package/dist/builtins/system-config/mesh-actions.d.ts +2 -30
  306. package/dist/builtins/system-config/system-config.addon.d.ts +57 -100
  307. package/dist/builtins/system-config/system-config.addon.js +37 -33
  308. package/dist/builtins/system-config/system-config.addon.mjs +37 -33
  309. package/dist/builtins/winston-logging/index.d.ts +3 -3
  310. package/dist/builtins/winston-logging/winston-destination.d.ts +15 -15
  311. package/dist/builtins/winston-logging/winston-logging.addon.d.ts +14 -13
  312. package/dist/{child-cap-dispatch-nURMuVTX.js → child-cap-dispatch-Bnr8brru.js} +18 -0
  313. package/dist/{child-cap-dispatch-B1gyE35b.mjs → child-cap-dispatch-mHO_6r0G.mjs} +1 -1
  314. package/dist/download/hosted-model-revisions.d.ts +8 -8
  315. package/dist/download/model-download-service.d.ts +32 -32
  316. package/dist/download/model-downloader.d.ts +88 -88
  317. package/dist/events/event-bus.d.ts +6 -6
  318. package/dist/events/system-event-bus.d.ts +11 -11
  319. package/dist/feature/feature-manager.d.ts +6 -6
  320. package/dist/http/asset-compression.d.ts +35 -73
  321. package/dist/http/authenticated-file-server.d.ts +32 -32
  322. package/dist/http/data-plane-registry.d.ts +49 -39
  323. package/dist/http/file-data-plane.d.ts +14 -14
  324. package/dist/http/lan-http-bind.d.ts +24 -13
  325. package/dist/http/reverse-proxy.d.ts +36 -24
  326. package/dist/index.d.ts +137 -137
  327. package/dist/index.js +4 -3
  328. package/dist/index.mjs +2 -4
  329. package/dist/kernel/addon-class-resolver.d.ts +1 -1
  330. package/dist/kernel/addon-engine-manager.d.ts +20 -20
  331. package/dist/kernel/addon-health-monitor.d.ts +151 -151
  332. package/dist/kernel/addon-installer.d.ts +609 -609
  333. package/dist/kernel/addon-loader.d.ts +133 -133
  334. package/dist/kernel/addon-manifest.d.ts +118 -118
  335. package/dist/kernel/addon-residue.d.ts +28 -32
  336. package/dist/kernel/array-buffer-census.d.ts +84 -88
  337. package/dist/kernel/bootstrap-config.d.ts +3 -3
  338. package/dist/kernel/cap-router-builder.d.ts +145 -101
  339. package/dist/kernel/capability-handle.d.ts +41 -41
  340. package/dist/kernel/capability-registry.d.ts +588 -576
  341. package/dist/kernel/config-manager.d.ts +199 -199
  342. package/dist/kernel/config-schema.d.ts +132 -128
  343. package/dist/kernel/custom-action-registry.d.ts +25 -25
  344. package/dist/kernel/deps/addon-deps-manager.d.ts +17 -17
  345. package/dist/kernel/deps/closure-dedupe.d.ts +76 -76
  346. package/dist/kernel/deps/ensure-addon-natives.d.ts +34 -34
  347. package/dist/kernel/deps/ensure-native-prebuilds.d.ts +25 -25
  348. package/dist/kernel/deps/manifest-native-deps.d.ts +38 -38
  349. package/dist/kernel/deps/manifest-python-deps.d.ts +18 -18
  350. package/dist/kernel/deps/manifest-system-deps.d.ts +13 -13
  351. package/dist/kernel/deps/npm-command.d.ts +45 -45
  352. package/dist/kernel/deps/system-package-allowlist.d.ts +9 -9
  353. package/dist/kernel/deps/system-package-broker.d.ts +20 -20
  354. package/dist/kernel/deps/system-package-client.d.ts +3 -3
  355. package/dist/kernel/device-registry.d.ts +27 -27
  356. package/dist/kernel/event-loop-stall-monitor.d.ts +33 -33
  357. package/dist/kernel/event-plane-report.d.ts +174 -174
  358. package/dist/kernel/fs-utils.d.ts +70 -70
  359. package/dist/kernel/gc-census.d.ts +119 -119
  360. package/dist/kernel/heap-spaces.d.ts +87 -87
  361. package/dist/kernel/heap-watch.d.ts +706 -706
  362. package/dist/kernel/host-externals.d.ts +8 -8
  363. package/dist/kernel/hwaccel/hwaccel-resolver.d.ts +27 -27
  364. package/dist/kernel/index.d.ts +115 -113
  365. package/dist/kernel/inference/inference-resolver.d.ts +13 -13
  366. package/dist/kernel/infra-capabilities.d.ts +7 -7
  367. package/dist/kernel/isolated-builtin-phase.d.ts +42 -42
  368. package/dist/kernel/lifecycle/job-journal.d.ts +17 -17
  369. package/dist/kernel/lifecycle/lifecycle-job-engine.d.ts +99 -99
  370. package/dist/kernel/lifecycle/staging-area.d.ts +22 -22
  371. package/dist/kernel/moleculer/addon-context-factory.d.ts +90 -89
  372. package/dist/kernel/moleculer/addon-data-plane-facility.d.ts +12 -12
  373. package/dist/kernel/moleculer/addon-deploy-source.d.ts +11 -11
  374. package/dist/kernel/moleculer/addon-peer-bytes-facility.d.ts +18 -18
  375. package/dist/kernel/moleculer/addon-service-factory.d.ts +41 -41
  376. package/dist/kernel/moleculer/agent-mesh-authenticator.d.ts +60 -33
  377. package/dist/kernel/moleculer/agent-ui-unlock.d.ts +30 -30
  378. package/dist/kernel/moleculer/broker-factory.d.ts +61 -61
  379. package/dist/kernel/moleculer/cap-usage-registry.d.ts +108 -153
  380. package/dist/kernel/moleculer/capabilities-access.d.ts +19 -19
  381. package/dist/kernel/moleculer/child-addon-call-dispatch.d.ts +43 -43
  382. package/dist/kernel/moleculer/child-cap-descriptors.d.ts +26 -26
  383. package/dist/kernel/moleculer/child-cap-dispatch.d.ts +52 -52
  384. package/dist/kernel/moleculer/children-batch-loader.d.ts +86 -34
  385. package/dist/kernel/moleculer/cluster-secret.d.ts +19 -19
  386. package/dist/kernel/moleculer/core-cap-service.d.ts +53 -53
  387. package/dist/kernel/moleculer/crash-supervisor.d.ts +39 -39
  388. package/dist/kernel/moleculer/device-cap-proxy.d.ts +51 -51
  389. package/dist/kernel/moleculer/device-event-ring.d.ts +117 -75
  390. package/dist/kernel/moleculer/event-bus-core.d.ts +171 -159
  391. package/dist/kernel/moleculer/event-bus.d.ts +73 -73
  392. package/dist/kernel/moleculer/hub-log-forwarder.d.ts +30 -30
  393. package/dist/kernel/moleculer/hub-service.d.ts +42 -42
  394. package/dist/kernel/moleculer/init-watchdog.d.ts +49 -49
  395. package/dist/kernel/moleculer/mesh-access-middleware.d.ts +36 -21
  396. package/dist/kernel/moleculer/mesh-auth-mode.d.ts +33 -39
  397. package/dist/kernel/moleculer/mesh-authenticator.d.ts +58 -58
  398. package/dist/kernel/moleculer/mesh-auto-enforce.d.ts +38 -18
  399. package/dist/kernel/moleculer/mesh-join-client.d.ts +67 -45
  400. package/dist/kernel/moleculer/mesh-join-proof.d.ts +8 -8
  401. package/dist/kernel/moleculer/mesh-mtls/constants.d.ts +1 -1
  402. package/dist/kernel/moleculer/mesh-mtls/index.d.ts +10 -10
  403. package/dist/kernel/moleculer/mesh-mtls/mesh-ca-keeper.d.ts +43 -38
  404. package/dist/kernel/moleculer/mesh-mtls/mesh-ca.d.ts +29 -20
  405. package/dist/kernel/moleculer/mesh-mtls/mesh-clear-port.d.ts +32 -32
  406. package/dist/kernel/moleculer/mesh-mtls/mesh-crl.d.ts +11 -11
  407. package/dist/kernel/moleculer/mesh-mtls/mesh-enroll.d.ts +19 -16
  408. package/dist/kernel/moleculer/mesh-mtls/mesh-join-token.d.ts +40 -40
  409. package/dist/kernel/moleculer/mesh-mtls/mesh-tls-enabler.d.ts +5 -1
  410. package/dist/kernel/moleculer/mesh-mtls/tls-tcp-transporter.d.ts +131 -130
  411. package/dist/kernel/moleculer/mesh-queue-report.d.ts +39 -39
  412. package/dist/kernel/moleculer/node-registry.d.ts +120 -120
  413. package/dist/kernel/moleculer/process-context.d.ts +2 -2
  414. package/dist/kernel/moleculer/process-service.d.ts +168 -168
  415. package/dist/kernel/moleculer/provider-registry.d.ts +9 -9
  416. package/dist/kernel/moleculer/readiness-context.d.ts +58 -58
  417. package/dist/kernel/moleculer/readiness-service.d.ts +31 -16
  418. package/dist/kernel/moleculer/register-framework-resolver.d.ts +6 -6
  419. package/dist/kernel/moleculer/register-node-client.d.ts +34 -27
  420. package/dist/kernel/moleculer/remote-logger.d.ts +29 -29
  421. package/dist/kernel/moleculer/resilient-cap-call.d.ts +21 -21
  422. package/dist/kernel/moleculer/runner-native-allocator.d.ts +95 -95
  423. package/dist/kernel/moleculer/runner-process-group.d.ts +57 -57
  424. package/dist/kernel/moleculer/runtime-state-load.d.ts +21 -11
  425. package/dist/kernel/moleculer/settings-read-guard.d.ts +39 -39
  426. package/dist/kernel/moleculer/stream-probe-service.d.ts +25 -6
  427. package/dist/kernel/moleculer/trpc-links.d.ts +203 -203
  428. package/dist/kernel/moleculer/typed-array-serde.d.ts +9 -20
  429. package/dist/kernel/moleculer/worker-device-restore.d.ts +8 -8
  430. package/dist/kernel/outbound-queue-watch.d.ts +74 -74
  431. package/dist/kernel/process-cpu-census.d.ts +55 -55
  432. package/dist/kernel/provider-kind-drift.d.ts +17 -8
  433. package/dist/kernel/restart-coordinator.d.ts +71 -71
  434. package/dist/kernel/settings-door-view.d.ts +36 -25
  435. package/dist/kernel/settings-read-error.d.ts +29 -31
  436. package/dist/kernel/settings-view-types.d.ts +100 -95
  437. package/dist/kernel/socket-plane-report.d.ts +214 -153
  438. package/dist/kernel/status-overlay.d.ts +31 -11
  439. package/dist/kernel/storage-location-registry.d.ts +50 -50
  440. package/dist/kernel/store-settings-view.d.ts +13 -13
  441. package/dist/kernel/system-settings-mirror.d.ts +40 -28
  442. package/dist/kernel/system-settings-policy.d.ts +15 -34
  443. package/dist/kernel/transport/cap-action-census.d.ts +183 -183
  444. package/dist/kernel/transport/cap-action-name.d.ts +84 -84
  445. package/dist/kernel/transport/cap-child-index.d.ts +41 -41
  446. package/dist/kernel/transport/cap-route-resolver.d.ts +237 -212
  447. package/dist/kernel/transport/cap-route.d.ts +139 -139
  448. package/dist/kernel/transport/cap-routing-hints.d.ts +37 -37
  449. package/dist/kernel/transport/child-cap-protocol.d.ts +245 -245
  450. package/dist/kernel/transport/claimed-get-status.d.ts +30 -6
  451. package/dist/kernel/transport/create-local-transport.d.ts +5 -5
  452. package/dist/kernel/transport/frame-codec.d.ts +109 -109
  453. package/dist/kernel/transport/hub-cap-forward.d.ts +81 -59
  454. package/dist/kernel/transport/index.d.ts +36 -36
  455. package/dist/kernel/transport/local-child-client.d.ts +184 -184
  456. package/dist/kernel/transport/local-child-registry.d.ts +592 -592
  457. package/dist/kernel/transport/local-endpoint-path.d.ts +4 -4
  458. package/dist/kernel/transport/local-transport.d.ts +92 -92
  459. package/dist/kernel/transport/parent-unowned-call.d.ts +266 -237
  460. package/dist/kernel/transport/peer-answered-error.d.ts +14 -14
  461. package/dist/kernel/transport/socket-channel.d.ts +110 -110
  462. package/dist/kernel/transport/socket-traffic.d.ts +96 -96
  463. package/dist/kernel/transport/uds-event-bridge.d.ts +77 -50
  464. package/dist/kernel/transport/uds-event-bus.d.ts +75 -26
  465. package/dist/kernel/transport/uds-local-transport.d.ts +14 -14
  466. package/dist/kernel/transport/uds-log-ingest.d.ts +38 -23
  467. package/dist/kernel/transport/uds-logger.d.ts +33 -33
  468. package/dist/kernel/utils/ring-buffer.d.ts +12 -12
  469. package/dist/kernel/workspace-detect.d.ts +7 -7
  470. package/dist/lifecycle/lifecycle-state-machine.d.ts +24 -24
  471. package/dist/logging/formatter.d.ts +52 -25
  472. package/dist/logging/log-manager.d.ts +133 -133
  473. package/dist/logging/log-redactor.d.ts +22 -1
  474. package/dist/logging/log-ring-buffer.d.ts +57 -57
  475. package/dist/logging/logging-gate.d.ts +69 -25
  476. package/dist/logging/logging-gate.singleton.d.ts +12 -1
  477. package/dist/logging/partitioned-log-buffer.d.ts +161 -161
  478. package/dist/logging/scoped-logger.d.ts +14 -14
  479. package/dist/network/network-quality.d.ts +8 -8
  480. package/dist/notification/notification-service.d.ts +37 -37
  481. package/dist/notification/toast-service.d.ts +18 -18
  482. package/dist/pipeline/engine-manager-resolver.d.ts +12 -12
  483. package/dist/pipeline/pipeline-runner.d.ts +6 -6
  484. package/dist/pipeline/pipeline-validator.d.ts +8 -8
  485. package/dist/process/proc-stat.d.ts +51 -51
  486. package/dist/process/resource-monitor.d.ts +19 -19
  487. package/dist/python/python-env-manager.d.ts +10 -10
  488. package/dist/repl/interfaces.d.ts +21 -21
  489. package/dist/repl/repl-engine.d.ts +6 -6
  490. package/dist/storage/fs-storage-backend.d.ts +35 -35
  491. package/dist/storage/storage-location-manager.d.ts +21 -21
  492. package/dist/storage/storage-manager.d.ts +68 -68
  493. package/dist/tls/boot-tls.d.ts +24 -24
  494. package/dist/tls/cert-evaluation.d.ts +25 -25
  495. package/dist/tls/cert-identity.d.ts +39 -39
  496. package/dist/tls/cert-issue.d.ts +37 -17
  497. package/dist/tls/cert-manager.d.ts +86 -84
  498. package/dist/tls/https-listener.d.ts +16 -16
  499. package/dist/tls/index.d.ts +8 -8
  500. package/dist/tls/tls-actions.d.ts +18 -18
  501. package/dist/tls/tls-status.d.ts +15 -15
  502. package/dist/tls/uploaded-cert.d.ts +9 -9
  503. package/package.json +9 -3
@@ -1,580 +1,581 @@
1
- import { AddonApi, ProfileSlot, ProviderRegistration, RtspRestreamEntry, BaseAddon } from '@camstack/types';
2
- import { JpegResizer } from './snapshot-resize.js';
1
+ import type { AddonApi, ConfigUISchema, ProfileSlot, ProviderRegistration, RtspRestreamEntry } from "@camstack/types";
2
+ import { BaseAddon } from "@camstack/types";
3
+ import { type JpegResizer } from "./snapshot-resize.js";
3
4
  interface SnapshotAddonConfig {
4
- /**
5
- * Last-resort cache age (ms): if every live capture path fails
6
- * (native + stream-broker fallback) AND a stale entry is older
7
- * than this, the wrapper still returns the stale image rather
8
- * than `null`. Keeps the UI from going blank during transient
9
- * camera unreachability. Per-device freshness is governed by
10
- * `snapshotMaxAgeS` instead.
11
- */
12
- readonly staleTtlMs: number;
5
+ /**
6
+ * Last-resort cache age (ms): if every live capture path fails
7
+ * (native + stream-broker fallback) AND a stale entry is older
8
+ * than this, the wrapper still returns the stale image rather
9
+ * than `null`. Keeps the UI from going blank during transient
10
+ * camera unreachability. Per-device freshness is governed by
11
+ * `snapshotMaxAgeS` instead.
12
+ */
13
+ readonly staleTtlMs: number;
13
14
  }
14
15
  /**
15
- * SnapshotAddon — wrapper over the `snapshot` capability.
16
- *
17
- * Activated per-device (toggleable by user; default active). When active,
18
- * caches fresh snapshots in memory. On cache miss, delegates to the native
19
- * provider for this device via `ctx.getNativeProvider(snapshotCapability, id)`.
20
- *
21
- * No silent fallback — if the native fails, propagate the error up. Stale
22
- * cache is returned ONLY when the native throws AND a stale entry exists,
23
- * and the failure is logged so the fallback is never silent.
24
- *
25
- * Frame-grab fallback: when the native provider is absent (or returns null /
26
- * throws), we ask the `stream-broker` capability for the device's RTSP
27
- * restream URL and pipe one JPEG out of ffmpeg. stream-broker intentionally
28
- * does NOT expose a `grabFrame` method — the orchestration (native-first,
29
- * ffmpeg fallback, caching) is this addon's concern; stream-broker only
30
- * publishes stream endpoints.
31
- */
16
+ * SnapshotAddon — wrapper over the `snapshot` capability.
17
+ *
18
+ * Activated per-device (toggleable by user; default active). When active,
19
+ * caches fresh snapshots in memory. On cache miss, delegates to the native
20
+ * provider for this device via `ctx.getNativeProvider(snapshotCapability, id)`.
21
+ *
22
+ * No silent fallback — if the native fails, propagate the error up. Stale
23
+ * cache is returned ONLY when the native throws AND a stale entry exists,
24
+ * and the failure is logged so the fallback is never silent.
25
+ *
26
+ * Frame-grab fallback: when the native provider is absent (or returns null /
27
+ * throws), we ask the `stream-broker` capability for the device's RTSP
28
+ * restream URL and pipe one JPEG out of ffmpeg. stream-broker intentionally
29
+ * does NOT expose a `grabFrame` method — the orchestration (native-first,
30
+ * ffmpeg fallback, caching) is this addon's concern; stream-broker only
31
+ * publishes stream endpoints.
32
+ */
32
33
  export declare class SnapshotAddon extends BaseAddon<SnapshotAddonConfig> {
33
- /**
34
- * The frame cache. Bounded by a byte budget + an idle timeout — it used to be
35
- * unbounded in both. Every eviction is logged with the device tag: a frame
36
- * that silently left the cache is the reason a later capture had to happen,
37
- * and per-camera is the only way that question is ever asked.
38
- */
39
- /** Cameras resting after a native miss — see `snapshot-fatigue.ts`. */
40
- private readonly fatigue;
41
- /**
42
- * The last good frame per camera, on disk, so it outlives the process.
43
- *
44
- * The cache above is RAM-only and the cameras that most need it are the ones
45
- * that can never be asked for a fresh frame: a sleeping battery camera
46
- * refuses every snapshot without `force`, and the background callers that
47
- * would want one deliberately never pass it. Measured 2026-09-17 — the baby
48
- * monitor showed the courtesy card all morning because three server updates
49
- * had emptied this cache and the camera had been asleep since.
50
- */
51
- private durableStore;
52
- /**
53
- * Built on first use, never in a field initializer: `ctx` does not exist
54
- * until `initialize()`, and reading it at construction throws
55
- * "ctx accessed before initialize()" for the whole addon.
56
- */
57
- private get durable();
58
- private readonly cache;
59
- /** Card-sized derivatives of the frames above, keyed by width and validated
60
- * against the source frame's timestamp. */
61
- private readonly variants;
62
- /**
63
- * Rendered courtesy frames, by (reason, size, device name).
64
- *
65
- * A courtesy frame is a pure function of those three, so it is rendered once
66
- * and reused for as long as the process lives — a disabled camera must not
67
- * cost an ffmpeg run per poll. Unbounded on purpose: the key space is
68
- * (state reasons × this node's own cameras), not user input.
69
- */
70
- private readonly courtesyFrames;
71
- /** State overlays over real cached frames, grouped by device so invalidation
72
- * can discard every generation in O(1). */
73
- private readonly stateFrames;
74
- /** Devices inside the explicit battery wake-in-progress window. */
75
- private readonly wakingDevices;
76
- /** Last sleeping flag per battery device, for wake-EDGE detection (the map
77
- * starts empty; only an observed true→false transition is a wake). */
78
- private readonly lastKnownSleeping;
79
- /**
80
- * Short-TTL memo for `lookupDeviceMeta` (see {@link DEVICE_META_MEMO_MS}).
81
- * The PROMISE is stored (not the resolved value), so a burst of concurrent
82
- * callers — a links batch plus the image fetches it mints — joins one
83
- * in-flight lookup instead of stampeding `deviceManager.getDevice`.
84
- * `fetchDeviceMeta` never rejects (failure → null), so a settled rejection
85
- * can never be served from the memo.
86
- */
87
- private readonly deviceMetaMemo;
88
- /**
89
- * De-dupes concurrent captures per `${deviceId}:${streamId}` and holds a
90
- * settled SUCCESS for COALESCE_MS so a grid-mount burst (and a row of refresh
91
- * buttons) collapses into one capture instead of one dial per tile.
92
- */
93
- private readonly captureFlight;
94
- /** Bounds simultaneous ffmpeg keyframe grabs (the wrapper path — common case). */
95
- private readonly grabPool;
96
- /** This node's PINNED ffmpeg (D540), asked once. The keyframe grab used to
97
- * spawn a bare `'ffmpeg'` — the HOST's binary — off PATH. */
98
- private readonly pinnedFfmpeg;
99
- /** Bounds simultaneous native (vendor HTTP/ONVIF) snapshot fetches. */
100
- private readonly nativePool;
101
- /**
102
- * Cached resolution of `pipelineOrchestrator.getIngestOwner` — SnapshotAddon
103
- * has no per-request attach hook to resolve this fresh, so it's cached with
104
- * a short TTL and invalidated on `onConfigChanged` (covers the common case
105
- * of an operator re-saving cluster/agent settings). A stale owner for up to
106
- * `OWNER_CACHE_TTL_MS` just means a snapshot fallback briefly targets the
107
- * previous ingest owner — self-heals on the next resolve.
108
- */
109
- private ownerCache;
110
- private static readonly OWNER_CACHE_TTL_MS;
111
- /**
112
- * Handle for the `/addon/snapshot/media/<deviceId>.jpg` HTTP data-plane
113
- * endpoint (§3.1). Null when the host provides no `ctx.dataPlane` facility
114
- * (the tRPC `getSnapshot` base64 surface still works — the endpoint is a
115
- * strictly-additive delivery path). Disposed on shutdown.
116
- */
117
- private mediaDataPlane;
118
- /**
119
- * The PUBLIC, signature-authenticated twin of the media plane. Null when the
120
- * host has no `ctx.dataPlane` facility, or before the per-install secret has
121
- * been minted — in which case `getSnapshotLinks` reports `url: null` and the
122
- * client keeps using the authenticated plane exactly as before.
123
- */
124
- private linkDataPlane;
125
- /** Per-install HMAC secret for link signatures. Minted once and persisted: a
126
- * secret that rolled on every boot would invalidate every link a client is
127
- * currently holding, which is a fleet-wide blank grid after each restart. */
128
- private linkSecret;
129
- /**
130
- * In-flight `serveLinkDataPlane` attempt, so the retry below cannot start a
131
- * second one while the first is still awaiting the settings store.
132
- */
133
- private linkPlaneAttempt;
134
- /**
135
- * How a full frame becomes a card-sized one. Defaults to the real ffmpeg
136
- * resize; injectable so the wrapper's own logic is testable without spawning a
137
- * process for every fixture. `JpegResizer` was declared for exactly this and
138
- * had no injector — which is why the resize-failure path had never been
139
- * exercised anywhere but production.
140
- */
141
- private readonly resize;
142
- constructor(resize?: JpegResizer);
143
- protected onInitialize(): Promise<ProviderRegistration[]>;
144
- /**
145
- * Serve the per-device snapshot image endpoint on the addon data-plane
146
- * (§3.1). Delivery: `GET /addon/snapshot/media/<deviceId>.jpg` → raw JPEG with
147
- * `ETag` + `Cache-Control: private, max-age=<device maxAgeS>`, so a grid is N
148
- * independent `<Image>` tiles served from the coalesced server cache (no
149
- * base64 tax, no batch head-of-line blocking, browser/`expo-image` caching for
150
- * free). Best-effort: a host without a `dataPlane` facility keeps the tRPC
151
- * base64 path.
152
- */
153
- private serveMediaDataPlane;
154
- /**
155
- * Serve the link plane if it is not already served — at init, and again on
156
- * the first `getSnapshotLinks` after an attempt that could not finish.
157
- *
158
- * The retry is not defensive padding, it is the whole reason this wrapper
159
- * exists. The plane needs a persisted signing secret, and the secret needs
160
- * the settings store; this addon now boots in its OWN process, so "the store
161
- * is not answering yet" is a state it can genuinely observe. A one-shot
162
- * attempt turns that instant into a permanent condition: `linkDataPlane`
163
- * stays null, every `getSnapshotLinks` row answers `url: null`, and every
164
- * tile on every grid stays blank until someone restarts the runner. Nothing
165
- * in the logs would say why, because nothing failed twice.
166
- *
167
- * Single-flighted: a burst of link requests joins one attempt.
168
- */
169
- private ensureLinkDataPlane;
170
- /**
171
- * Serve the PUBLIC link plane: `GET /addon/snapshot/link/<deviceId>.jpg?w&v&exp&sig`.
172
- *
173
- * `access: 'public'` is deliberate and is the only interesting decision here.
174
- * The authority is the HMAC, exactly as for the notification artifact plane
175
- * and the Home Assistant media plane — but unlike those, what sits behind it
176
- * is a LIVE view of the operator's home, so the compensating choices are
177
- * explicit: a short TTL (`SNAPSHOT_LINK_TTL_MS`), the width inside the signed
178
- * identity so a leaked tile cannot be escalated to the full frame, and
179
- * **`force` is not honoured on this route at all** — a public URL must never
180
- * be able to wake a battery camera.
181
- *
182
- * A leaked link therefore grants: one camera, at one thumbnail width, for at
183
- * most the TTL. No token, no other device, no session.
184
- */
185
- private serveLinkDataPlane;
186
- /**
187
- * Verify first, then hand the request to the ordinary media handler with a
188
- * REWRITTEN url carrying only the signed `(deviceId, width)`.
189
- *
190
- * Rewriting rather than passing the original through is what stops an unsigned
191
- * query parameter reaching the capture path: `force`, `streamId` and any other
192
- * lever the authenticated plane honours are simply not present in what the
193
- * handler parses.
194
- */
195
- private handleLinkRequest;
196
- private linkRoutePrefix;
197
- /**
198
- * Mint-once-and-persist the signing secret. Null when it cannot be
199
- * ESTABLISHED — a secret held only in memory would break every outstanding
200
- * link on restart, so no plane is better than a plane whose links die
201
- * unpredictably.
202
- *
203
- * A null is never cached, so the next `getSnapshotLinks` tries again. That
204
- * matters now the wrapper runs in its own process: the settings store can be
205
- * a moment behind at boot, and this used to be a one-shot.
206
- *
207
- * The read-back is the gate. `state.get()` cannot distinguish "no secret
208
- * yet" from "the store could not be read" — `readAddonStoreWithRetry` gives
209
- * up and answers `{}` — so a store that is merely slow reads as empty and
210
- * this would mint a SECOND secret over a perfectly good first one, silently
211
- * invalidating every link a client is holding. Reading back what we just
212
- * wrote is the only evidence available at this layer that the store is
213
- * actually answering, and a mismatch means it is not.
214
- */
215
- private ensureLinkSecret;
216
- /**
217
- * Mint signed links for the tiles a surface is rendering — and, in the same
218
- * call, make those tiles CURRENT.
219
- *
220
- * This is the demand signal the design was missing. Under D93 enrolment rode
221
- * on the image request, and D93/D94/D95 each fixed a different way for that
222
- * request not to happen; none of them could fix the last one, because the
223
- * client's own image cache answers a repeated URL with no network at all. An
224
- * RPC has no such cache in front of it.
225
- *
226
- * So: note every target (creating a subscription, which `getSnapshotOverview`
227
- * deliberately cannot), then join the ordinary non-forced capture path and
228
- * wait a BOUNDED time for it. The Viewer never presents a frame older than
229
- * 15 seconds as current, so this path tightens a looser per-device cache
230
- * window to that contract without using `force` (and its battery-wake
231
- * semantics). What comes back is the identity of the frame the link serves.
232
- *
233
- * The bound matters more than its exact value. A cold fleet is paced by
234
- * `MAX_CONCURRENT_GRABS`, so sixteen cameras cannot all capture at once and
235
- * the last of them would hold the whole batch well past any sensible paint
236
- * budget. Devices that miss the bound return their real, older `capturedAt` —
237
- * honest rather than blocking — and the client's next poll carries them
238
- * forward.
239
- */
240
- private getSnapshotLinks;
241
- /**
242
- * The debug readout's data — the decision chain for one device, cache-only
243
- * and capture-free (a debug poll must never wake a battery camera).
244
- */
245
- private getSnapshotDebugState;
246
- /**
247
- * Join the ordinary capture path for one device and wait, bounded, for it.
248
- *
249
- * Deliberately `getSnapshot` with `force: false`: the single flight, grab
250
- * pool, and sleeping-battery refusal apply unchanged. The only override is
251
- * the Viewer's 15-second currency contract and the link-mint wait bound.
252
- */
253
- private awaitFreshEnough;
254
- /**
255
- * The one fresh frame an awake battery camera gets outside an active stream:
256
- * captured at the WAKE edge, because the link poll deliberately never
257
- * recaptures an idle-awake battery camera (every capture is a camera hit
258
- * that would keep it out of sleep — the link-mint gate documents the
259
- * incident).
260
- *
261
- * `force: true` is correct here — not a violation of "never wake for a
262
- * snapshot": the camera is ALREADY awake (the status edge is what fired),
263
- * and the battery 1 h cache default would otherwise answer the wake with
264
- * the pre-sleep frame. The single flight coalesces a burst of edges; one
265
- * delayed retry covers a camera whose status flipped a beat before its
266
- * snapshot endpoint is actually answering (firmware boot lag).
267
- */
268
- private captureOnWake;
269
- /** Resolve the state advertised by a minted link before deciding whether a
270
- * background capture is allowed. */
271
- private snapshotStateForLink;
272
- /**
273
- * Resolve a device (+ optional stream, + force) to renderable JPEG bytes for
274
- * the HTTP endpoint. Runs the same coalesced capture ladder as the tRPC
275
- * `getSnapshot` (so every consumer shares one upstream pull), then decodes the
276
- * base64 cache into raw bytes and stamps the frame identity: `capturedAt` from
277
- * the cache entry (matching the ETag `getSnapshotOverview` advertises) and the
278
- * effective per-device `maxAgeS` for `Cache-Control`. Null → 404.
279
- */
280
- private resolveSnapshotMedia;
281
- /**
282
- * Cache-only freshness peek for the data-plane's conditional-GET fast path.
283
- * Never captures, never resizes, never dials anything: a cached frame that is
284
- * still inside its per-device max-age, or null.
285
- *
286
- * Returning null for a STALE entry is the important half. A 304 there would
287
- * pin the tile to the old frame for as long as the client kept revalidating,
288
- * which is the exact staleness this change exists to remove.
289
- */
290
- private peekFreshFrame;
291
- /**
292
- * The frame at a card-sized width, derived once per
293
- * (device, stream, width, state treatment) per capture.
294
- *
295
- * A failed resize falls back to the FULL frame — a visible card beats a
296
- * broken one — but never silently: the card would otherwise keep costing a
297
- * megabyte with nothing anywhere saying why, which is the shape of the bug
298
- * this whole change came from.
299
- */
300
- private thumbnailBytes;
301
- protected onShutdown(): Promise<void>;
302
- /**
303
- * Drop the cached ingest owner whenever addon-level settings change —
304
- * cheap, correct-by-construction refresh point (BaseAddon calls this
305
- * after every `updateGlobalSettings`/`updateAddonSettings`). Combined
306
- * with the TTL in `resolveIngestOwner`, a cluster topology change is
307
- * picked up either on the next settings save or within
308
- * `OWNER_CACHE_TTL_MS`, whichever comes first.
309
- */
310
- protected onConfigChanged(): Promise<void>;
311
- protected globalSettingsSchema(): import('@camstack/types').ConfigUISchema;
312
- private getSnapshot;
313
- /**
314
- * Map a settled capture outcome onto the response, preserving the legacy
315
- * semantics: a fresh frame wins; a soft miss (native null + broker null)
316
- * falls back to stale cache (or null); a HARD native error with no frame
317
- * and no cache propagates.
318
- */
319
- private resolveOutcome;
320
- /**
321
- * Reconcile backstop for a stale hit: is the frame we are about to serve the
322
- * property of a device that no longer exists?
323
- *
324
- * Asked ONLY past `staleTtlMs`, which is already the "something is wrong"
325
- * threshold — so the common path costs nothing. A `true` answer evicts and
326
- * the caller returns null; anything else leaves the existing
327
- * keep-the-UI-from-going-blank contract untouched.
328
- */
329
- private staleHitBelongsToRemovedDevice;
330
- /**
331
- * Run the capture ladder ONCE for a device: native provider first, then the
332
- * stream-broker ffmpeg fallback. Never rejects — resolves a {@link
333
- * CaptureOutcome}. On a produced frame it populates the cache (so a
334
- * background SWR refresh lands for the next poll) and returns it. A hard
335
- * native error with no broker frame resolves `{ ok:false }` so the caller
336
- * can surface it; a soft miss resolves `{ ok:true, image:null }`.
337
- *
338
- * TODO(decoded-frame fast path): for a device whose detection pipeline is
339
- * already decoding (the always-on subscription, see docs/design/decode-path.md),
340
- * the freshest decoded frame is already in the shared-memory ring — a single
341
- * JPEG encode of the latest FrameHandle would cost zero dials and beat the
342
- * ffmpeg grab for the wrapper fleet. Slotting it as native -> latest-decoded
343
- * -> broker needs cross-addon plumbing not cheaply reachable from the hub
344
- * builtin today: frames are session-scoped (decoder `pullHandles`/`getFrame`
345
- * need the device's active session id) and raw-pixel (need a JPEG encoder the
346
- * builtin lacks). Deferred as its own slice.
347
- */
348
- private captureFresh;
349
- /**
350
- * Pull one JPEG from the device's stream-broker RTSP restream using
351
- * a short-lived ffmpeg invocation.
352
- *
353
- * Stream selection strategy (picks the broker that won't stall):
354
- * 1. Explicit `preferredStreamId` (user set in per-device settings)
355
- * — always honoured, even if currently idle. Operator choice
356
- * wins.
357
- * 2. Auto: highest-quality broker currently in `streaming` state.
358
- * This is the whole point — prefer the stream that has active
359
- * subscribers (usually `low` for detection, but `mid`/`high`
360
- * if WebRTC is watching) so ffmpeg hits a warm pipe and
361
- * doesn't race the broker's resume.
362
- * 3. Fallback: highest-quality enabled entry regardless of status
363
- * (will wake a suspended broker — retry-guarded against the
364
- * cold-start error).
365
- *
366
- * The stream-broker auto-suspends idle streams on the "no demand"
367
- * signal; snapshots used to default to `high` which was often the
368
- * first to go idle, racing every snapshot with a broker resume.
369
- * Now we ask the orchestrator of streams which one is warm and grab
370
- * from there.
371
- *
372
- * Source acquisition is pinned to the cluster's ingest owner (the node
373
- * the stream-broker actually runs on) instead of the device-scoped
374
- * `dev.cameraStreams` facade — `dev.cameraStreams` resolves against
375
- * whichever node the cap-router picks by default, which double-pulls
376
- * the camera (or dials a hub-local restream that isn't serving) when
377
- * `ingestNode != hub`. `fetchSnapshotBrokerEntries` does the pinned
378
- * fetch + owner-relative URL host rewrite; hub-owner + no reachable
379
- * host is byte-identical to the previous unpinned call.
380
- */
381
- private grabFrameFromBroker;
382
- /**
383
- * Cached, TTL-bounded resolution of the cluster's camera-source owner.
384
- * See `ownerCache` doc for the invalidation story.
385
- */
386
- private resolveIngestOwner;
387
- /**
388
- * Same graceful degrade as the recorder's `resolveIngestOwner`
389
- * (`packages/addon-pipeline/src/recorder/addon/index.ts`) — the cap may
390
- * not be mounted yet (pre-image-release) or the pipeline-orchestrator
391
- * addon may be absent entirely; either way we fall back to `'hub'`,
392
- * which is byte-identical to the previous hardcoded hub-only behaviour.
393
- */
394
- private fetchIngestOwner;
395
- /**
396
- * Ffmpeg grab with one retry on the broker-cold-start error
397
- * signature. Covers the window between "client connected" and
398
- * "first keyframe" when a suspended broker resumes.
399
- */
400
- private runGrabWithResumeRetry;
401
- private invalidateCache;
402
- /** Forget every cached artefact of one device: frames, derived variants and
403
- * any settled single-flight result that would answer the next request. */
404
- private dropDeviceCaches;
405
- /**
406
- * The device is GONE — drop its cached frames and say so.
407
- *
408
- * Distinct from `invalidateCache` (a refresh, expected and silent): this is
409
- * the terminal case, and a deleted camera that keeps answering with its last
410
- * JPEG looks to an operator exactly like a camera that was never deleted.
411
- */
412
- private evictRemovedDevice;
413
- /**
414
- * Does device-manager still know this id?
415
- *
416
- * `null` means the question could not be answered — a transport hiccup is
417
- * not a deletion (D49), and the caller keeps serving what it has. Only an
418
- * explicit "no such device" evicts.
419
- */
420
- private deviceStillExists;
421
- /**
422
- * Resolve the state that must be visible on a snapshot.
423
- *
424
- * Uses the same two canonical sources as wake-on-play:
425
- * 1. `deviceManager.getDevice` for the registry's BatteryOperated feature;
426
- * 2. `deviceState.getCapSlice('battery')` for the durable runtime mirror.
427
- *
428
- * A valid battery slice is itself positive evidence that the device is
429
- * battery-operated. That closes the field failure where "Baby monitor" had a
430
- * sleeping battery slice but a stale persisted feature projection, so the
431
- * snapshot wrapper classified it as mains and a Viewer thumbnail logged in
432
- * to the sleeping camera. The reverse is deliberately not guessed: no
433
- * feature + no valid slice remains a mains/unknown camera and follows the
434
- * ordinary capture path.
435
- *
436
- * Once battery-operated is established, a missing slice fails safe toward
437
- * `sleeping` through the shared `deriveBatteryPresence` function. This avoids
438
- * a background wake without inventing an `unreachable` fault.
439
- */
440
- private resolveSnapshotState;
441
- private isDeviceWaking;
442
- /**
443
- * True when at least one of the device's brokers is actively
444
- * streaming (status === 'streaming'). Used by the battery-cam guard
445
- * around `grabFrameFromBroker` to allow the fallback ONLY when
446
- * grabbing a frame is free (a consumer is already keeping the
447
- * stream warm). When everything is suspended, the fallback would
448
- * dial the camera and wake it — defeats the sleeping cache.
449
- *
450
- * Pinned to the ingest owner via `fetchSnapshotBrokerEntries` — same
451
- * rationale as `grabFrameFromBroker`: the device-scoped
452
- * `dev.cameraStreams` facade resolves against whichever node the
453
- * cap-router picks by default, which is wrong once `ingestNode !=
454
- * hub` (queries the hub for slots that only exist on the agent,
455
- * always reporting no streaming broker). Owner === hub (no reachable
456
- * host) is byte-identical to the previous unpinned call.
457
- */
458
- private hasStreamingBrokerForDevice;
459
- /**
460
- * Cache-only batch overview — O(n) over the in-memory cache, NEVER triggers
461
- * a capture. Lets a grid skip requesting images for devices that never
462
- * produced a frame, and hands each an ETag for conditional image fetches.
463
- */
464
- private getSnapshotOverview;
465
- /**
466
- * Diagnostic status for the `status` auto-injected cap method. Reports
467
- * the cache bookkeeping for this device — when the last snapshot was
468
- * captured, how stale the cached image is, its size, and which stream
469
- * was used. Returns null when the device has never been captured
470
- * (cache miss) since the addon started.
471
- */
472
- private getStatus;
473
- private readDeviceSettings;
474
- private buildDeviceSettingsContribution;
475
- /**
476
- * The frame a camera that CANNOT capture answers with.
477
- *
478
- * Returns null only if rendering itself fails — the caller then falls through
479
- * to its previous behaviour, so a broken courtesy path degrades to the old
480
- * 404 rather than masking a real capture failure as a placeholder.
481
- *
482
- * Rendered at the full tile size; the existing resize ladder derives the
483
- * card-sized variants from it exactly as it does for a real frame, so no
484
- * downstream consumer needs to know this frame is synthetic.
485
- */
486
- private courtesyFrame;
487
- /** A courtesy frame shaped as the cap's response, or null when unrenderable. */
488
- private courtesyImage;
489
- /**
490
- * The answer for a camera the hub cannot reach: its last good frame, with
491
- * `Offline` painted over it, and `offline` stamped on the response identity.
492
- *
493
- * Called only AFTER the ladder has run (offline is not in
494
- * {@link CAPTURE_BLOCKING_REASONS}), so this dresses a frame that could not be
495
- * refreshed — never one that just landed.
496
- *
497
- * The `stateReason` is set FIRST and unconditionally, because it is what a
498
- * surface labels the tile from and what puts `offline` in the ETag: a client
499
- * holding the live frame has to see a new identity the moment the camera
500
- * drops, or it paints the unlabelled photograph until the camera comes back.
501
- * A failed render therefore degrades to the raw frame rather than to nothing —
502
- * the metadata still says offline, so the tile is still honest.
503
- */
504
- private offlineImage;
505
- /**
506
- * Render a state-labelled answer. A cached real frame is the background, not
507
- * the answer by itself; if it cannot be decoded, fall back to the generated
508
- * courtesy background rather than leaking an unlabelled stale frame.
509
- */
510
- /** The persisted frame as a cache entry, with its real age. */
511
- private durableEntry;
512
- private stateImage;
513
- /**
514
- * Single-trip device lookup against device-manager — memoized for
515
- * {@link DEVICE_META_MEMO_MS} (promise-keyed, so bursts single-flight).
516
- * Registry facts only; nothing battery-runtime lives here, so the TTL never
517
- * masks a sleep/wake transition. Announced changes evict immediately (the
518
- * `device.*` subscriptions in `onInitialize`); the TTL bounds silent drift.
519
- */
520
- private lookupDeviceMeta;
521
- /**
522
- * The actual `deviceManager.getDevice` round trip behind
523
- * {@link lookupDeviceMeta}. Returns the stable registry fields the wrapper
524
- * consults. Battery classification is completed by `resolveSnapshotState`
525
- * from this feature flag PLUS the canonical runtime-state mirror, so a stale
526
- * persisted feature projection cannot authorize a snapshot dial against a
527
- * known sleeping battery camera.
528
- *
529
- * Logged at debug + null return on failure: every call site already
530
- * has a sensible fallback path (cache hit, conservative default, …),
531
- * so we don't want a transient device-manager hiccup to throw.
532
- */
533
- private fetchDeviceMeta;
534
- /** Settings-UI helper — battery flag drives the default max-age in the field description. */
535
- private isDeviceBattery;
536
- /**
537
- * Feeds the settings-UI stream picker. Pinned to the ingest owner via
538
- * `fetchSnapshotBrokerEntries` — the device-scoped `dev.cameraStreams`
539
- * facade this used to call resolves against whichever node the
540
- * cap-router picks by default, which is empty once `ingestNode !=
541
- * hub` (the picker would render nothing but "Auto"). Owner === hub
542
- * (no reachable host) is byte-identical to the previous unpinned call.
543
- */
544
- private getStreamOptions;
545
- private saveDeviceSettingsPatch;
34
+ /**
35
+ * The frame cache. Bounded by a byte budget + an idle timeout — it used to be
36
+ * unbounded in both. Every eviction is logged with the device tag: a frame
37
+ * that silently left the cache is the reason a later capture had to happen,
38
+ * and per-camera is the only way that question is ever asked.
39
+ */
40
+ /** Cameras resting after a native miss — see `snapshot-fatigue.ts`. */
41
+ private readonly fatigue;
42
+ /**
43
+ * The last good frame per camera, on disk, so it outlives the process.
44
+ *
45
+ * The cache above is RAM-only and the cameras that most need it are the ones
46
+ * that can never be asked for a fresh frame: a sleeping battery camera
47
+ * refuses every snapshot without `force`, and the background callers that
48
+ * would want one deliberately never pass it. Measured 2026-09-17 — the baby
49
+ * monitor showed the courtesy card all morning because three server updates
50
+ * had emptied this cache and the camera had been asleep since.
51
+ */
52
+ private durableStore;
53
+ /**
54
+ * Built on first use, never in a field initializer: `ctx` does not exist
55
+ * until `initialize()`, and reading it at construction throws
56
+ * "ctx accessed before initialize()" for the whole addon.
57
+ */
58
+ private get durable();
59
+ private readonly cache;
60
+ /** Card-sized derivatives of the frames above, keyed by width and validated
61
+ * against the source frame's timestamp. */
62
+ private readonly variants;
63
+ /**
64
+ * Rendered courtesy frames, by (reason, size, device name).
65
+ *
66
+ * A courtesy frame is a pure function of those three, so it is rendered once
67
+ * and reused for as long as the process lives — a disabled camera must not
68
+ * cost an ffmpeg run per poll. Unbounded on purpose: the key space is
69
+ * (state reasons × this node's own cameras), not user input.
70
+ */
71
+ private readonly courtesyFrames;
72
+ /** State overlays over real cached frames, grouped by device so invalidation
73
+ * can discard every generation in O(1). */
74
+ private readonly stateFrames;
75
+ /** Devices inside the explicit battery wake-in-progress window. */
76
+ private readonly wakingDevices;
77
+ /** Last sleeping flag per battery device, for wake-EDGE detection (the map
78
+ * starts empty; only an observed true→false transition is a wake). */
79
+ private readonly lastKnownSleeping;
80
+ /**
81
+ * Short-TTL memo for `lookupDeviceMeta` (see {@link DEVICE_META_MEMO_MS}).
82
+ * The PROMISE is stored (not the resolved value), so a burst of concurrent
83
+ * callers — a links batch plus the image fetches it mints — joins one
84
+ * in-flight lookup instead of stampeding `deviceManager.getDevice`.
85
+ * `fetchDeviceMeta` never rejects (failure → null), so a settled rejection
86
+ * can never be served from the memo.
87
+ */
88
+ private readonly deviceMetaMemo;
89
+ /**
90
+ * De-dupes concurrent captures per `${deviceId}:${streamId}` and holds a
91
+ * settled SUCCESS for COALESCE_MS so a grid-mount burst (and a row of refresh
92
+ * buttons) collapses into one capture instead of one dial per tile.
93
+ */
94
+ private readonly captureFlight;
95
+ /** Bounds simultaneous ffmpeg keyframe grabs (the wrapper path — common case). */
96
+ private readonly grabPool;
97
+ /** This node's PINNED ffmpeg (D540), asked once. The keyframe grab used to
98
+ * spawn a bare `'ffmpeg'` — the HOST's binary — off PATH. */
99
+ private readonly pinnedFfmpeg;
100
+ /** Bounds simultaneous native (vendor HTTP/ONVIF) snapshot fetches. */
101
+ private readonly nativePool;
102
+ /**
103
+ * Cached resolution of `pipelineOrchestrator.getIngestOwner` — SnapshotAddon
104
+ * has no per-request attach hook to resolve this fresh, so it's cached with
105
+ * a short TTL and invalidated on `onConfigChanged` (covers the common case
106
+ * of an operator re-saving cluster/agent settings). A stale owner for up to
107
+ * `OWNER_CACHE_TTL_MS` just means a snapshot fallback briefly targets the
108
+ * previous ingest owner — self-heals on the next resolve.
109
+ */
110
+ private ownerCache;
111
+ private static readonly OWNER_CACHE_TTL_MS;
112
+ /**
113
+ * Handle for the `/addon/snapshot/media/<deviceId>.jpg` HTTP data-plane
114
+ * endpoint (§3.1). Null when the host provides no `ctx.dataPlane` facility
115
+ * (the tRPC `getSnapshot` base64 surface still works — the endpoint is a
116
+ * strictly-additive delivery path). Disposed on shutdown.
117
+ */
118
+ private mediaDataPlane;
119
+ /**
120
+ * The PUBLIC, signature-authenticated twin of the media plane. Null when the
121
+ * host has no `ctx.dataPlane` facility, or before the per-install secret has
122
+ * been minted — in which case `getSnapshotLinks` reports `url: null` and the
123
+ * client keeps using the authenticated plane exactly as before.
124
+ */
125
+ private linkDataPlane;
126
+ /** Per-install HMAC secret for link signatures. Minted once and persisted: a
127
+ * secret that rolled on every boot would invalidate every link a client is
128
+ * currently holding, which is a fleet-wide blank grid after each restart. */
129
+ private linkSecret;
130
+ /**
131
+ * In-flight `serveLinkDataPlane` attempt, so the retry below cannot start a
132
+ * second one while the first is still awaiting the settings store.
133
+ */
134
+ private linkPlaneAttempt;
135
+ /**
136
+ * How a full frame becomes a card-sized one. Defaults to the real ffmpeg
137
+ * resize; injectable so the wrapper's own logic is testable without spawning a
138
+ * process for every fixture. `JpegResizer` was declared for exactly this and
139
+ * had no injector — which is why the resize-failure path had never been
140
+ * exercised anywhere but production.
141
+ */
142
+ private readonly resize;
143
+ constructor(resize?: JpegResizer);
144
+ protected onInitialize(): Promise<ProviderRegistration[]>;
145
+ /**
146
+ * Serve the per-device snapshot image endpoint on the addon data-plane
147
+ * (§3.1). Delivery: `GET /addon/snapshot/media/<deviceId>.jpg` → raw JPEG with
148
+ * `ETag` + `Cache-Control: private, max-age=<device maxAgeS>`, so a grid is N
149
+ * independent `<Image>` tiles served from the coalesced server cache (no
150
+ * base64 tax, no batch head-of-line blocking, browser/`expo-image` caching for
151
+ * free). Best-effort: a host without a `dataPlane` facility keeps the tRPC
152
+ * base64 path.
153
+ */
154
+ private serveMediaDataPlane;
155
+ /**
156
+ * Serve the link plane if it is not already served — at init, and again on
157
+ * the first `getSnapshotLinks` after an attempt that could not finish.
158
+ *
159
+ * The retry is not defensive padding, it is the whole reason this wrapper
160
+ * exists. The plane needs a persisted signing secret, and the secret needs
161
+ * the settings store; this addon now boots in its OWN process, so "the store
162
+ * is not answering yet" is a state it can genuinely observe. A one-shot
163
+ * attempt turns that instant into a permanent condition: `linkDataPlane`
164
+ * stays null, every `getSnapshotLinks` row answers `url: null`, and every
165
+ * tile on every grid stays blank until someone restarts the runner. Nothing
166
+ * in the logs would say why, because nothing failed twice.
167
+ *
168
+ * Single-flighted: a burst of link requests joins one attempt.
169
+ */
170
+ private ensureLinkDataPlane;
171
+ /**
172
+ * Serve the PUBLIC link plane: `GET /addon/snapshot/link/<deviceId>.jpg?w&v&exp&sig`.
173
+ *
174
+ * `access: 'public'` is deliberate and is the only interesting decision here.
175
+ * The authority is the HMAC, exactly as for the notification artifact plane
176
+ * and the Home Assistant media plane — but unlike those, what sits behind it
177
+ * is a LIVE view of the operator's home, so the compensating choices are
178
+ * explicit: a short TTL (`SNAPSHOT_LINK_TTL_MS`), the width inside the signed
179
+ * identity so a leaked tile cannot be escalated to the full frame, and
180
+ * **`force` is not honoured on this route at all** — a public URL must never
181
+ * be able to wake a battery camera.
182
+ *
183
+ * A leaked link therefore grants: one camera, at one thumbnail width, for at
184
+ * most the TTL. No token, no other device, no session.
185
+ */
186
+ private serveLinkDataPlane;
187
+ /**
188
+ * Verify first, then hand the request to the ordinary media handler with a
189
+ * REWRITTEN url carrying only the signed `(deviceId, width)`.
190
+ *
191
+ * Rewriting rather than passing the original through is what stops an unsigned
192
+ * query parameter reaching the capture path: `force`, `streamId` and any other
193
+ * lever the authenticated plane honours are simply not present in what the
194
+ * handler parses.
195
+ */
196
+ private handleLinkRequest;
197
+ private linkRoutePrefix;
198
+ /**
199
+ * Mint-once-and-persist the signing secret. Null when it cannot be
200
+ * ESTABLISHED — a secret held only in memory would break every outstanding
201
+ * link on restart, so no plane is better than a plane whose links die
202
+ * unpredictably.
203
+ *
204
+ * A null is never cached, so the next `getSnapshotLinks` tries again. That
205
+ * matters now the wrapper runs in its own process: the settings store can be
206
+ * a moment behind at boot, and this used to be a one-shot.
207
+ *
208
+ * The read-back is the gate. `state.get()` cannot distinguish "no secret
209
+ * yet" from "the store could not be read" — `readAddonStoreWithRetry` gives
210
+ * up and answers `{}` — so a store that is merely slow reads as empty and
211
+ * this would mint a SECOND secret over a perfectly good first one, silently
212
+ * invalidating every link a client is holding. Reading back what we just
213
+ * wrote is the only evidence available at this layer that the store is
214
+ * actually answering, and a mismatch means it is not.
215
+ */
216
+ private ensureLinkSecret;
217
+ /**
218
+ * Mint signed links for the tiles a surface is rendering — and, in the same
219
+ * call, make those tiles CURRENT.
220
+ *
221
+ * This is the demand signal the design was missing. Under D93 enrolment rode
222
+ * on the image request, and D93/D94/D95 each fixed a different way for that
223
+ * request not to happen; none of them could fix the last one, because the
224
+ * client's own image cache answers a repeated URL with no network at all. An
225
+ * RPC has no such cache in front of it.
226
+ *
227
+ * So: note every target (creating a subscription, which `getSnapshotOverview`
228
+ * deliberately cannot), then join the ordinary non-forced capture path and
229
+ * wait a BOUNDED time for it. The Viewer never presents a frame older than
230
+ * 15 seconds as current, so this path tightens a looser per-device cache
231
+ * window to that contract without using `force` (and its battery-wake
232
+ * semantics). What comes back is the identity of the frame the link serves.
233
+ *
234
+ * The bound matters more than its exact value. A cold fleet is paced by
235
+ * `MAX_CONCURRENT_GRABS`, so sixteen cameras cannot all capture at once and
236
+ * the last of them would hold the whole batch well past any sensible paint
237
+ * budget. Devices that miss the bound return their real, older `capturedAt` —
238
+ * honest rather than blocking — and the client's next poll carries them
239
+ * forward.
240
+ */
241
+ private getSnapshotLinks;
242
+ /**
243
+ * The debug readout's data — the decision chain for one device, cache-only
244
+ * and capture-free (a debug poll must never wake a battery camera).
245
+ */
246
+ private getSnapshotDebugState;
247
+ /**
248
+ * Join the ordinary capture path for one device and wait, bounded, for it.
249
+ *
250
+ * Deliberately `getSnapshot` with `force: false`: the single flight, grab
251
+ * pool, and sleeping-battery refusal apply unchanged. The only override is
252
+ * the Viewer's 15-second currency contract and the link-mint wait bound.
253
+ */
254
+ private awaitFreshEnough;
255
+ /**
256
+ * The one fresh frame an awake battery camera gets outside an active stream:
257
+ * captured at the WAKE edge, because the link poll deliberately never
258
+ * recaptures an idle-awake battery camera (every capture is a camera hit
259
+ * that would keep it out of sleep — the link-mint gate documents the
260
+ * incident).
261
+ *
262
+ * `force: true` is correct here — not a violation of "never wake for a
263
+ * snapshot": the camera is ALREADY awake (the status edge is what fired),
264
+ * and the battery 1 h cache default would otherwise answer the wake with
265
+ * the pre-sleep frame. The single flight coalesces a burst of edges; one
266
+ * delayed retry covers a camera whose status flipped a beat before its
267
+ * snapshot endpoint is actually answering (firmware boot lag).
268
+ */
269
+ private captureOnWake;
270
+ /** Resolve the state advertised by a minted link before deciding whether a
271
+ * background capture is allowed. */
272
+ private snapshotStateForLink;
273
+ /**
274
+ * Resolve a device (+ optional stream, + force) to renderable JPEG bytes for
275
+ * the HTTP endpoint. Runs the same coalesced capture ladder as the tRPC
276
+ * `getSnapshot` (so every consumer shares one upstream pull), then decodes the
277
+ * base64 cache into raw bytes and stamps the frame identity: `capturedAt` from
278
+ * the cache entry (matching the ETag `getSnapshotOverview` advertises) and the
279
+ * effective per-device `maxAgeS` for `Cache-Control`. Null → 404.
280
+ */
281
+ private resolveSnapshotMedia;
282
+ /**
283
+ * Cache-only freshness peek for the data-plane's conditional-GET fast path.
284
+ * Never captures, never resizes, never dials anything: a cached frame that is
285
+ * still inside its per-device max-age, or null.
286
+ *
287
+ * Returning null for a STALE entry is the important half. A 304 there would
288
+ * pin the tile to the old frame for as long as the client kept revalidating,
289
+ * which is the exact staleness this change exists to remove.
290
+ */
291
+ private peekFreshFrame;
292
+ /**
293
+ * The frame at a card-sized width, derived once per
294
+ * (device, stream, width, state treatment) per capture.
295
+ *
296
+ * A failed resize falls back to the FULL frame — a visible card beats a
297
+ * broken one — but never silently: the card would otherwise keep costing a
298
+ * megabyte with nothing anywhere saying why, which is the shape of the bug
299
+ * this whole change came from.
300
+ */
301
+ private thumbnailBytes;
302
+ protected onShutdown(): Promise<void>;
303
+ /**
304
+ * Drop the cached ingest owner whenever addon-level settings change —
305
+ * cheap, correct-by-construction refresh point (BaseAddon calls this
306
+ * after every `updateGlobalSettings`/`updateAddonSettings`). Combined
307
+ * with the TTL in `resolveIngestOwner`, a cluster topology change is
308
+ * picked up either on the next settings save or within
309
+ * `OWNER_CACHE_TTL_MS`, whichever comes first.
310
+ */
311
+ protected onConfigChanged(): Promise<void>;
312
+ protected globalSettingsSchema(): ConfigUISchema;
313
+ private getSnapshot;
314
+ /**
315
+ * Map a settled capture outcome onto the response, preserving the legacy
316
+ * semantics: a fresh frame wins; a soft miss (native null + broker null)
317
+ * falls back to stale cache (or null); a HARD native error with no frame
318
+ * and no cache propagates.
319
+ */
320
+ private resolveOutcome;
321
+ /**
322
+ * Reconcile backstop for a stale hit: is the frame we are about to serve the
323
+ * property of a device that no longer exists?
324
+ *
325
+ * Asked ONLY past `staleTtlMs`, which is already the "something is wrong"
326
+ * threshold — so the common path costs nothing. A `true` answer evicts and
327
+ * the caller returns null; anything else leaves the existing
328
+ * keep-the-UI-from-going-blank contract untouched.
329
+ */
330
+ private staleHitBelongsToRemovedDevice;
331
+ /**
332
+ * Run the capture ladder ONCE for a device: native provider first, then the
333
+ * stream-broker ffmpeg fallback. Never rejects — resolves a {@link
334
+ * CaptureOutcome}. On a produced frame it populates the cache (so a
335
+ * background SWR refresh lands for the next poll) and returns it. A hard
336
+ * native error with no broker frame resolves `{ ok:false }` so the caller
337
+ * can surface it; a soft miss resolves `{ ok:true, image:null }`.
338
+ *
339
+ * TODO(decoded-frame fast path): for a device whose detection pipeline is
340
+ * already decoding (the always-on subscription, see docs/design/decode-path.md),
341
+ * the freshest decoded frame is already in the shared-memory ring — a single
342
+ * JPEG encode of the latest FrameHandle would cost zero dials and beat the
343
+ * ffmpeg grab for the wrapper fleet. Slotting it as native -> latest-decoded
344
+ * -> broker needs cross-addon plumbing not cheaply reachable from the hub
345
+ * builtin today: frames are session-scoped (decoder `pullHandles`/`getFrame`
346
+ * need the device's active session id) and raw-pixel (need a JPEG encoder the
347
+ * builtin lacks). Deferred as its own slice.
348
+ */
349
+ private captureFresh;
350
+ /**
351
+ * Pull one JPEG from the device's stream-broker RTSP restream using
352
+ * a short-lived ffmpeg invocation.
353
+ *
354
+ * Stream selection strategy (picks the broker that won't stall):
355
+ * 1. Explicit `preferredStreamId` (user set in per-device settings)
356
+ * — always honoured, even if currently idle. Operator choice
357
+ * wins.
358
+ * 2. Auto: highest-quality broker currently in `streaming` state.
359
+ * This is the whole point — prefer the stream that has active
360
+ * subscribers (usually `low` for detection, but `mid`/`high`
361
+ * if WebRTC is watching) so ffmpeg hits a warm pipe and
362
+ * doesn't race the broker's resume.
363
+ * 3. Fallback: highest-quality enabled entry regardless of status
364
+ * (will wake a suspended broker — retry-guarded against the
365
+ * cold-start error).
366
+ *
367
+ * The stream-broker auto-suspends idle streams on the "no demand"
368
+ * signal; snapshots used to default to `high` which was often the
369
+ * first to go idle, racing every snapshot with a broker resume.
370
+ * Now we ask the orchestrator of streams which one is warm and grab
371
+ * from there.
372
+ *
373
+ * Source acquisition is pinned to the cluster's ingest owner (the node
374
+ * the stream-broker actually runs on) instead of the device-scoped
375
+ * `dev.cameraStreams` facade — `dev.cameraStreams` resolves against
376
+ * whichever node the cap-router picks by default, which double-pulls
377
+ * the camera (or dials a hub-local restream that isn't serving) when
378
+ * `ingestNode != hub`. `fetchSnapshotBrokerEntries` does the pinned
379
+ * fetch + owner-relative URL host rewrite; hub-owner + no reachable
380
+ * host is byte-identical to the previous unpinned call.
381
+ */
382
+ private grabFrameFromBroker;
383
+ /**
384
+ * Cached, TTL-bounded resolution of the cluster's camera-source owner.
385
+ * See `ownerCache` doc for the invalidation story.
386
+ */
387
+ private resolveIngestOwner;
388
+ /**
389
+ * Same graceful degrade as the recorder's `resolveIngestOwner`
390
+ * (`packages/addon-pipeline/src/recorder/addon/index.ts`) — the cap may
391
+ * not be mounted yet (pre-image-release) or the pipeline-orchestrator
392
+ * addon may be absent entirely; either way we fall back to `'hub'`,
393
+ * which is byte-identical to the previous hardcoded hub-only behaviour.
394
+ */
395
+ private fetchIngestOwner;
396
+ /**
397
+ * Ffmpeg grab with one retry on the broker-cold-start error
398
+ * signature. Covers the window between "client connected" and
399
+ * "first keyframe" when a suspended broker resumes.
400
+ */
401
+ private runGrabWithResumeRetry;
402
+ private invalidateCache;
403
+ /** Forget every cached artefact of one device: frames, derived variants and
404
+ * any settled single-flight result that would answer the next request. */
405
+ private dropDeviceCaches;
406
+ /**
407
+ * The device is GONE — drop its cached frames and say so.
408
+ *
409
+ * Distinct from `invalidateCache` (a refresh, expected and silent): this is
410
+ * the terminal case, and a deleted camera that keeps answering with its last
411
+ * JPEG looks to an operator exactly like a camera that was never deleted.
412
+ */
413
+ private evictRemovedDevice;
414
+ /**
415
+ * Does device-manager still know this id?
416
+ *
417
+ * `null` means the question could not be answered — a transport hiccup is
418
+ * not a deletion (D49), and the caller keeps serving what it has. Only an
419
+ * explicit "no such device" evicts.
420
+ */
421
+ private deviceStillExists;
422
+ /**
423
+ * Resolve the state that must be visible on a snapshot.
424
+ *
425
+ * Uses the same two canonical sources as wake-on-play:
426
+ * 1. `deviceManager.getDevice` for the registry's BatteryOperated feature;
427
+ * 2. `deviceState.getCapSlice('battery')` for the durable runtime mirror.
428
+ *
429
+ * A valid battery slice is itself positive evidence that the device is
430
+ * battery-operated. That closes the field failure where "Baby monitor" had a
431
+ * sleeping battery slice but a stale persisted feature projection, so the
432
+ * snapshot wrapper classified it as mains and a Viewer thumbnail logged in
433
+ * to the sleeping camera. The reverse is deliberately not guessed: no
434
+ * feature + no valid slice remains a mains/unknown camera and follows the
435
+ * ordinary capture path.
436
+ *
437
+ * Once battery-operated is established, a missing slice fails safe toward
438
+ * `sleeping` through the shared `deriveBatteryPresence` function. This avoids
439
+ * a background wake without inventing an `unreachable` fault.
440
+ */
441
+ private resolveSnapshotState;
442
+ private isDeviceWaking;
443
+ /**
444
+ * True when at least one of the device's brokers is actively
445
+ * streaming (status === 'streaming'). Used by the battery-cam guard
446
+ * around `grabFrameFromBroker` to allow the fallback ONLY when
447
+ * grabbing a frame is free (a consumer is already keeping the
448
+ * stream warm). When everything is suspended, the fallback would
449
+ * dial the camera and wake it — defeats the sleeping cache.
450
+ *
451
+ * Pinned to the ingest owner via `fetchSnapshotBrokerEntries` — same
452
+ * rationale as `grabFrameFromBroker`: the device-scoped
453
+ * `dev.cameraStreams` facade resolves against whichever node the
454
+ * cap-router picks by default, which is wrong once `ingestNode !=
455
+ * hub` (queries the hub for slots that only exist on the agent,
456
+ * always reporting no streaming broker). Owner === hub (no reachable
457
+ * host) is byte-identical to the previous unpinned call.
458
+ */
459
+ private hasStreamingBrokerForDevice;
460
+ /**
461
+ * Cache-only batch overview — O(n) over the in-memory cache, NEVER triggers
462
+ * a capture. Lets a grid skip requesting images for devices that never
463
+ * produced a frame, and hands each an ETag for conditional image fetches.
464
+ */
465
+ private getSnapshotOverview;
466
+ /**
467
+ * Diagnostic status for the `status` auto-injected cap method. Reports
468
+ * the cache bookkeeping for this device — when the last snapshot was
469
+ * captured, how stale the cached image is, its size, and which stream
470
+ * was used. Returns null when the device has never been captured
471
+ * (cache miss) since the addon started.
472
+ */
473
+ private getStatus;
474
+ private readDeviceSettings;
475
+ private buildDeviceSettingsContribution;
476
+ /**
477
+ * The frame a camera that CANNOT capture answers with.
478
+ *
479
+ * Returns null only if rendering itself fails — the caller then falls through
480
+ * to its previous behaviour, so a broken courtesy path degrades to the old
481
+ * 404 rather than masking a real capture failure as a placeholder.
482
+ *
483
+ * Rendered at the full tile size; the existing resize ladder derives the
484
+ * card-sized variants from it exactly as it does for a real frame, so no
485
+ * downstream consumer needs to know this frame is synthetic.
486
+ */
487
+ private courtesyFrame;
488
+ /** A courtesy frame shaped as the cap's response, or null when unrenderable. */
489
+ private courtesyImage;
490
+ /**
491
+ * The answer for a camera the hub cannot reach: its last good frame, with
492
+ * `Offline` painted over it, and `offline` stamped on the response identity.
493
+ *
494
+ * Called only AFTER the ladder has run (offline is not in
495
+ * {@link CAPTURE_BLOCKING_REASONS}), so this dresses a frame that could not be
496
+ * refreshed — never one that just landed.
497
+ *
498
+ * The `stateReason` is set FIRST and unconditionally, because it is what a
499
+ * surface labels the tile from and what puts `offline` in the ETag: a client
500
+ * holding the live frame has to see a new identity the moment the camera
501
+ * drops, or it paints the unlabelled photograph until the camera comes back.
502
+ * A failed render therefore degrades to the raw frame rather than to nothing —
503
+ * the metadata still says offline, so the tile is still honest.
504
+ */
505
+ private offlineImage;
506
+ /**
507
+ * Render a state-labelled answer. A cached real frame is the background, not
508
+ * the answer by itself; if it cannot be decoded, fall back to the generated
509
+ * courtesy background rather than leaking an unlabelled stale frame.
510
+ */
511
+ /** The persisted frame as a cache entry, with its real age. */
512
+ private durableEntry;
513
+ private stateImage;
514
+ /**
515
+ * Single-trip device lookup against device-manager — memoized for
516
+ * {@link DEVICE_META_MEMO_MS} (promise-keyed, so bursts single-flight).
517
+ * Registry facts only; nothing battery-runtime lives here, so the TTL never
518
+ * masks a sleep/wake transition. Announced changes evict immediately (the
519
+ * `device.*` subscriptions in `onInitialize`); the TTL bounds silent drift.
520
+ */
521
+ private lookupDeviceMeta;
522
+ /**
523
+ * The actual `deviceManager.getDevice` round trip behind
524
+ * {@link lookupDeviceMeta}. Returns the stable registry fields the wrapper
525
+ * consults. Battery classification is completed by `resolveSnapshotState`
526
+ * from this feature flag PLUS the canonical runtime-state mirror, so a stale
527
+ * persisted feature projection cannot authorize a snapshot dial against a
528
+ * known sleeping battery camera.
529
+ *
530
+ * Logged at debug + null return on failure: every call site already
531
+ * has a sensible fallback path (cache hit, conservative default, …),
532
+ * so we don't want a transient device-manager hiccup to throw.
533
+ */
534
+ private fetchDeviceMeta;
535
+ /** Settings-UI helper — battery flag drives the default max-age in the field description. */
536
+ private isDeviceBattery;
537
+ /**
538
+ * Feeds the settings-UI stream picker. Pinned to the ingest owner via
539
+ * `fetchSnapshotBrokerEntries` — the device-scoped `dev.cameraStreams`
540
+ * facade this used to call resolves against whichever node the
541
+ * cap-router picks by default, which is empty once `ingestNode !=
542
+ * hub` (the picker would render nothing but "Auto"). Owner === hub
543
+ * (no reachable host) is byte-identical to the previous unpinned call.
544
+ */
545
+ private getStreamOptions;
546
+ private saveDeviceSettingsPatch;
546
547
  }
547
548
  /** Result of {@link fetchSnapshotBrokerEntries} — this device's RTSP entries + profile slots. */
548
549
  interface SnapshotBrokerEntries {
549
- readonly entries: readonly RtspRestreamEntry[];
550
- readonly slots: readonly ProfileSlot[];
550
+ readonly entries: readonly RtspRestreamEntry[];
551
+ readonly slots: readonly ProfileSlot[];
551
552
  }
552
553
  /**
553
- * Pinned, testable fetch of this device's RTSP restream entries + profile
554
- * slots from the system `streamBroker` cap. Module-level (not a class
555
- * method) so `grabFrameFromBroker`'s owner-pin + host-rewrite contract is
556
- * directly unit-testable without instantiating the addon — mirrors
557
- * `acquireSessionDecodeRestreamFrom` in `pipeline-runner/index.ts`.
558
- *
559
- * Replaces the former `dev.cameraStreams.getRtspEntries({})` /
560
- * `getBrokerStreams({})` device-scoped facade calls, which resolve against
561
- * whichever node the cap-router picks by default — wrong once
562
- * `ingestNode != hub` (double-pulls the camera, or dials a hub-local
563
- * restream nobody is serving). `getAllRtspEntries`/`listAllProfileSlots`
564
- * are cluster-wide system-cap methods; pinning the call with `nodePin` +
565
- * filtering by the `${deviceId}/` brokerId prefix reproduces the exact
566
- * device-scoped result set the facade used to return.
567
- *
568
- * `reachableHost`, when present, rides as the cap's own `hostname` input —
569
- * the broker rewrites the returned URLs' host itself (same mechanism
570
- * `getStreamWithCodec` callers use for cross-node pulls), so no separate
571
- * client-side host-substitution is needed here. Omitting `hostname`
572
- * (owner === hub, no reachable host registered) leaves the broker's
573
- * default `127.0.0.1` URLs untouched — byte-identical to today.
574
- */
554
+ * Pinned, testable fetch of this device's RTSP restream entries + profile
555
+ * slots from the system `streamBroker` cap. Module-level (not a class
556
+ * method) so `grabFrameFromBroker`'s owner-pin + host-rewrite contract is
557
+ * directly unit-testable without instantiating the addon — mirrors
558
+ * `acquireSessionDecodeRestreamFrom` in `pipeline-runner/index.ts`.
559
+ *
560
+ * Replaces the former `dev.cameraStreams.getRtspEntries({})` /
561
+ * `getBrokerStreams({})` device-scoped facade calls, which resolve against
562
+ * whichever node the cap-router picks by default — wrong once
563
+ * `ingestNode != hub` (double-pulls the camera, or dials a hub-local
564
+ * restream nobody is serving). `getAllRtspEntries`/`listAllProfileSlots`
565
+ * are cluster-wide system-cap methods; pinning the call with `nodePin` +
566
+ * filtering by the `${deviceId}/` brokerId prefix reproduces the exact
567
+ * device-scoped result set the facade used to return.
568
+ *
569
+ * `reachableHost`, when present, rides as the cap's own `hostname` input —
570
+ * the broker rewrites the returned URLs' host itself (same mechanism
571
+ * `getStreamWithCodec` callers use for cross-node pulls), so no separate
572
+ * client-side host-substitution is needed here. Omitting `hostname`
573
+ * (owner === hub, no reachable host registered) leaves the broker's
574
+ * default `127.0.0.1` URLs untouched — byte-identical to today.
575
+ */
575
576
  export declare function fetchSnapshotBrokerEntries(api: AddonApi, params: {
576
- readonly deviceId: number;
577
- readonly ownerNodeId: string;
578
- readonly reachableHost?: string;
577
+ readonly deviceId: number;
578
+ readonly ownerNodeId: string;
579
+ readonly reachableHost?: string;
579
580
  }): Promise<SnapshotBrokerEntries>;
580
581
  export {};