@camstack/addon-import-alexa 0.2.196 → 0.2.197

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 (4) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/addon.js +1356 -1295
  3. package/dist/addon.mjs +1356 -1295
  4. package/package.json +2 -2
package/dist/addon.mjs CHANGED
@@ -46,1194 +46,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
46
46
  var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
47
47
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
48
48
  //#endregion
49
- //#region ../types/dist/event-category-78tcBemo.mjs
50
- var EventCategory = /* @__PURE__ */ function(EventCategory) {
51
- EventCategory["SystemBoot"] = "system.boot";
52
- EventCategory["SystemAddonsReady"] = "system.addons-ready";
53
- EventCategory["SystemRestarting"] = "system.restarting";
54
- /**
55
- * Fired exactly once after the hub finishes booting following a
56
- * restart that was triggered by `RestartCoordinator` (today: framework
57
- * live-update). Payload is the marker that was on disk at boot
58
- * (`PendingRestartMarkerPayload`); admin UI listens for it to display a
59
- * success toast describing what changed.
60
- *
61
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
62
- */
63
- EventCategory["SystemRestartCompleted"] = "system.restart-completed";
64
- /**
65
- * The hub reissued its own TLS certificate at boot (`ensureTlsCert`).
66
- * Emitted only when the material on disk actually changed, so an
67
- * operator who trusted the old certificate by hand is told rather than
68
- * discovering it as a browser error. Payload `TlsCertChangedPayload`.
69
- *
70
- * Rule: docs/decisions/adr-0227-*.md
71
- */
72
- EventCategory["SystemTlsCertChanged"] = "system.tls-cert-changed";
73
- /**
74
- * A newer addon or server-root package version was found by the
75
- * authoritative registry check. Emitted once when any observed
76
- * `latestVersion` changes (or a package/node first appears behind);
77
- * the payload carries the full currently-available list. Repeated
78
- * polling of the same latests is silent.
79
- */
80
- EventCategory["UpdateAvailable"] = "update.available";
81
- /**
82
- * Readiness transition for a capability provider. Every producer emits
83
- * this event on `onInitialize` completion, `onDestroy`, and
84
- * `$node.reconnect`; every consumer that needs to gate on a cross-process
85
- * cap subscribes via the kernel's readiness module (`awaitReady` /
86
- * `onReadyState`) instead of polling. Payload is
87
- * `SystemReadyStatePayload` — see event-bus.ts.
88
- */
89
- EventCategory["SystemReadyState"] = "system.ready-state";
90
- EventCategory["AddonStarted"] = "addon.started";
91
- EventCategory["AddonStopped"] = "addon.stopped";
92
- EventCategory["AddonRestarted"] = "addon.restarted";
93
- EventCategory["AddonUpdated"] = "addon.updated";
94
- EventCategory["AddonInstalled"] = "addon.installed";
95
- EventCategory["AddonUninstalled"] = "addon.uninstalled";
96
- EventCategory["AddonCrashed"] = "addon.crashed";
97
- /**
98
- * A RUNNER the D6 crash circuit-breaker gave up on — terminal.
99
- *
100
- * `AddonCrashed` is the routine, self-healing fact ("it crashed; it is being
101
- * respawned"); this is the one that never resolves itself. Emitted exactly
102
- * once per trip, by `process-service.ts`, carrying the node, the runner, the
103
- * addons it hosted and the crash count that tripped the breaker.
104
- *
105
- * It exists because a runner marked terminally `failed` used to be SILENT:
106
- * on 2026-08-18 the `recorder` runner died of three unhandled ffmpeg spawn
107
- * errors, the breaker stopped respawning it (correctly), `/health` kept
108
- * returning 200, and fleet-wide recording was gone for 3h15 before the
109
- * operator's phone told him. The Notification Center's system-event intake
110
- * consumes this category and maps it to the `addon-crash-loop` kind.
111
- */
112
- EventCategory["AddonRunnerFailed"] = "addon.runner-failed";
113
- /**
114
- * A runner whose addon refused to start with a typed reason (D877) - parked
115
- * in `refused`, never counted by the crash breaker, retried on operator
116
- * action. One event per refusal.
117
- */
118
- EventCategory["AddonRunnerRefused"] = "addon.runner-refused";
119
- /**
120
- * A runner settled on a state (D877): `running` (READY), `crashed`, `failed` or
121
- * `refused`. In-process telemetry for the boot check (re-evaluate while any
122
- * runner is still pending) and the alert centre (close a recovered runner).
123
- */
124
- EventCategory["ProcessStateChanged"] = "process.state-changed";
125
- /**
126
- * The node's one-shot runner boot check (D877): planned runners against the
127
- * process service, `degraded` when any is failed, refused or missing. The
128
- * alert centre turns it into one critical alert.
129
- */
130
- EventCategory["SystemRunnerCheck"] = "system.runner-check";
131
- /**
132
- * An alert EPISODE opened or closed, emitted by the alert centre for alerts
133
- * of severity `critical` or `error` (`AlertEpisodePayload`). The alert
134
- * centre sends no notification of its own: Notification Center turns this
135
- * into the `alert-critical` / `alert-error` / `alert-critical-resolved`
136
- * system-event kinds, and reconciles from the alerts store because a bus
137
- * event may be dropped (D8, D11).
138
- */
139
- EventCategory["AlertEpisode"] = "alert.episode";
140
- EventCategory["AddonError"] = "addon.error";
141
- EventCategory["AddonPageReady"] = "addon.page-ready";
142
- EventCategory["AddonWidgetReady"] = "addon.widget-ready";
143
- /**
144
- * Addon failed to load (import or initialize). Emitted by the kernel's
145
- * AddonHealthMonitor only AFTER the boot grace period ends — failures
146
- * during the first 5 minutes are silently retried without alerting
147
- * (slow-starting addons must have time to come up). Post-grace, this
148
- * event is emitted exactly once per failure-streak; AlertCenter
149
- * consumes it to create a persistent operator-visible alert.
150
- *
151
- * Payload: `{ packageName, addonId?, error: { message, stack }, retryCount, nextRetryAt }`.
152
- */
153
- EventCategory["AddonLoadFailed"] = "addon.load-failed";
154
- /**
155
- * A keychain value was stored or removed (D787). Carries the ref, its
156
- * owner and the new version — NEVER the value. A process holding the ref
157
- * drops its cached copy and the owning `BaseAddon` re-resolves its config.
158
- * Telemetry (D8): a process that misses it still revalidates by version.
159
- */
160
- EventCategory["KeychainChanged"] = "keychain.changed";
161
- /**
162
- * Addon recovered from a previous failure. Emitted when an addon
163
- * transitions from `failed` back to `healthy` (typically via the
164
- * monitor's auto-retry loop, or after manual `addons.retryLoad`).
165
- * AlertCenter dismisses the corresponding `AddonLoadFailed` alert
166
- * on this event.
167
- */
168
- EventCategory["AddonLoadRecovered"] = "addon.load-recovered";
169
- /**
170
- * An addon is RUNNING although its installed package is below what the
171
- * running server requires (`camstack.requires.addons` of the server, or the
172
- * addon's own `requires.server`). Raised once per streak by the unsupported-
173
- * addon tracker, on the hub and on agents; AlertCenter turns it into one
174
- * operator alert per node and package. The addon is never held back for it.
175
- *
176
- * Payload: `{ packageName, addonId, nodeId, installedVersion, requiredMinimum, serverVersion, unmet }`.
177
- */
178
- EventCategory["AddonUnsupportedVersion"] = "addon.unsupported-version";
179
- /**
180
- * The package of an {@link AddonUnsupportedVersion} alert reached a supported
181
- * version, or is no longer installed on the node. AlertCenter dismisses the matching alert.
182
- *
183
- * Payload: `{ packageName, addonId, nodeId }`.
184
- */
185
- EventCategory["AddonUnsupportedResolved"] = "addon.unsupported-resolved";
186
- /**
187
- * Monitor scheduled the next retry for a failed addon. Transient —
188
- * surfaced to the UI for live-updating the "next retry in Ns"
189
- * countdown on the Addons page row, NOT persisted as an alert.
190
- */
191
- EventCategory["AddonRetryScheduled"] = "addon.retry-scheduled";
192
- /**
193
- * A liveness invariant of this node is false — it has no devices, every
194
- * camera is offline, or a camera that was recording has stopped producing
195
- * segments. Emitted by the `liveness-monitor` builtin, once per fault (the
196
- * `findingId` is stable across ticks), only after its boot grace period.
197
- * AlertCenter raises a persistent operator-visible alert.
198
- *
199
- * It exists because on 2026-08-03 the hub ran four hours with zero devices
200
- * and zero recordings while every surface stayed quiet.
201
- *
202
- * Payload: `{ findingId, severity, title, message, deviceId? }`.
203
- */
204
- EventCategory["SystemLivenessFailed"] = "system.liveness-failed";
205
- /**
206
- * A previously reported liveness fault is true again. AlertCenter dismisses
207
- * the matching `SystemLivenessFailed` alert.
208
- *
209
- * Payload: `{ findingId }`.
210
- */
211
- EventCategory["SystemLivenessRecovered"] = "system.liveness-recovered";
212
- /**
213
- * Monitor is attempting to reload a failed addon NOW. UI uses this
214
- * to show a spinner during the retry attempt. Same transient nature
215
- * as AddonRetryScheduled.
216
- */
217
- EventCategory["AddonRetryAttempting"] = "addon.retry-attempting";
218
- EventCategory["DeviceRegistered"] = "device.registered";
219
- EventCategory["DeviceUnregistered"] = "device.unregistered";
220
- EventCategory["DeviceEnabled"] = "device.enabled";
221
- EventCategory["DeviceDisabled"] = "device.disabled";
222
- EventCategory["DeviceSettingsUpdated"] = "device.settings-updated";
223
- /**
224
- * Emitted when the set of native capability providers bound to a device
225
- * changes — e.g. an addon registers a new native cap via
226
- * `DeviceContext.registerNativeCap`, or all native bindings for a device
227
- * are cleared on removal. Hub consumers re-resolve device-proxy routes
228
- * when this fires.
229
- */
230
- EventCategory["DeviceBindingsChanged"] = "device.bindings-changed";
231
- /**
232
- * Emitted when the operator-organisational meta surface changes
233
- * (`name` / `location` / `disabled`). Payload: `{deviceId, field,
234
- * value}`. Live consumers (UI device list, alert center) react
235
- * without polling. Distinct from `DeviceSettingsUpdated` which
236
- * fires on hardware-config changes (host/port/credentials/etc).
237
- */
238
- EventCategory["DeviceMetaChanged"] = "device.meta-changed";
239
- /**
240
- * Emitted by `BaseDevice.updateSourceInfo()` after a successful patch
241
- * to the device's upstream-system identity / rendering envelope. The
242
- * full new SourceInfo travels in the payload so cross-process listeners
243
- * (UI, export adapters) don't need to re-read the meta blob.
244
- *
245
- * Payload: `{deviceId, sourceInfo}`.
246
- *
247
- * Distinct from `DeviceMetaChanged` which covers the operator-edited
248
- * surface (`name` / `location` / `disabled`). The two share the
249
- * persistence layer (both ride on `device-manager.setMetadata` for
250
- * SourceInfo, or `setName`/`setLocation`/`setDisabled` for the meta
251
- * fields) but consumers care about different subsets.
252
- */
253
- EventCategory["DeviceSourceInfoChanged"] = "device.source-info-changed";
254
- /**
255
- * Emitted by DeviceStreamWiringService after a successful
256
- * `stream-broker.registerDeviceStreams` call. Payload includes
257
- * deviceId — consumers look up the full registered device info via
258
- * `brokerManager.getRegisteredDevice(deviceId)`.
259
- *
260
- * Replaces the legacy `StreamRouterService.onDeviceRegistered` callback.
261
- */
262
- EventCategory["DeviceStreamsRegistered"] = "device.streams-registered";
263
- /**
264
- * Device-level "fully provisioned" signal — the EXPORT trigger. Emitted once
265
- * a device's persisted export-relevant shape (its `DeviceFeature` set) is
266
- * established or changes, carrying `{deviceId, fingerprint, generation}`.
267
- * Export adapters (Alexa / HAP) react to THIS instead of the chatty per-cap
268
- * `DeviceBindingsChanged`, turning a boot's incomplete→complete trickle into
269
- * one clean delta. `fingerprint` is `canonicalDeviceFingerprint(shape)`.
270
- *
271
- * Spec: docs/superpowers/specs/2026-06-01-alexa-hap-export-reconciler-design.md
272
- */
273
- EventCategory["DeviceProvisioned"] = "device.provisioned";
274
- /**
275
- * Fires once when a device's initial feature-probe completes successfully
276
- * (lastProbedAt 0→>0); exported shape is now stable. Telemetry (may be
277
- * dropped) — consumers MUST also gate on the device record's `probed` flag.
278
- */
279
- EventCategory["DeviceReady"] = "device.ready";
280
- EventCategory["IntegrationEnabled"] = "integration.enabled";
281
- EventCategory["IntegrationDisabled"] = "integration.disabled";
282
- EventCategory["IntegrationDeleted"] = "integration.deleted";
283
- /** Emitted when a broker connection's status flips (connected /
284
- * disconnected / error). Carries `{ brokerId, status, error? }`. */
285
- EventCategory["BrokerStatusChanged"] = "broker.status-changed";
286
- /** Emitted for every subscription-matched message routed by a
287
- * broker provider. Carries `{ brokerId, subscriptionId, key, payload }`.
288
- * Consumers filter by `brokerId` + `subscriptionId` in the handler. */
289
- EventCategory["BrokerMessage"] = "broker.message";
290
- EventCategory["ProviderStarted"] = "provider.started";
291
- EventCategory["ProviderStopped"] = "provider.stopped";
292
- EventCategory["ProcessCrashed"] = "process.crashed";
293
- EventCategory["ProcessRestartScheduled"] = "process.restart_scheduled";
294
- EventCategory["ProcessRestarted"] = "process.restarted";
295
- /**
296
- * The SET of storage locations changed — one was created, edited, enabled,
297
- * disabled or deleted through the location instances or the forced-delete action.
298
- *
299
- * Telemetry, not a transaction (D8/D11): every consumer that re-resolves on
300
- * it must also converge on its own periodic path, because a dropped event
301
- * must not leave a node writing to yesterday's disk set forever. It exists
302
- * because there was NO signal at all — an operator who added a second
303
- * recordings disk in the admin UI got nothing, and the recorder kept its
304
- * resolved locations until something else happened to re-resolve them
305
- * (D387). Payload `StorageLocationsChangedPayload`.
306
- */
307
- EventCategory["StorageLocationsChanged"] = "storage.locations-changed";
308
- EventCategory["RecordingStarted"] = "recording.started";
309
- EventCategory["RecordingStopped"] = "recording.stopped";
310
- EventCategory["RecordingError"] = "recording.error";
311
- EventCategory["RecordingHealthDegraded"] = "recording.health.degraded";
312
- /** Recording enabled but no segment finalized for the NC stall window. */
313
- EventCategory["RecordingHealthStalled"] = "recording.health.stalled";
314
- /** Recovery from {@link RecordingHealthStalled}. */
315
- EventCategory["RecordingHealthOk"] = "recording.health.ok";
316
- EventCategory["RecordingStorageCritical"] = "recording.storage.critical";
317
- /** Free space on a storage location crossed the warn bar. */
318
- EventCategory["StorageLocationLow"] = "storage.location.low";
319
- /** Free space at/under the critical bar, or capacity probe failed (`null`). */
320
- EventCategory["StorageLocationCritical"] = "storage.location.critical";
321
- /** Recovery from low/critical on a storage location. */
322
- EventCategory["StorageLocationOk"] = "storage.location.ok";
323
- EventCategory["RecordingSegmentWritten"] = "recording.segment.written";
324
- EventCategory["RecordingPolicyFallback"] = "recording.policy.fallback";
325
- EventCategory["RecordingRetentionCompleted"] = "recording.retention.completed";
326
- /** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
327
- * progress bar the client reconciles via `recordingExport.getExport`. */
328
- EventCategory["RecordingExportProgress"] = "recording.export.progress";
329
- EventCategory["RecordingExportCompleted"] = "recording.export.completed";
330
- EventCategory["RecordingExportFailed"] = "recording.export.failed";
331
- EventCategory["DetectionEvent"] = "detection.event";
332
- EventCategory["SessionTrackNew"] = "session.track.new";
333
- EventCategory["SessionTrackExpired"] = "session.track.expired";
334
- EventCategory["BenchmarkProgress"] = "benchmark.progress";
335
- EventCategory["PlatformProbePhase"] = "platform-probe.phase";
336
- EventCategory["PipelineProgress"] = "pipeline.progress";
337
- /** Per-frame execution trace emitted by the pipeline executor for live observability. */
338
- EventCategory["PipelineTrace"] = "pipeline.trace";
339
- /**
340
- * Raw inference output emitted by `addon-pipeline-runner` after running the
341
- * detection pipeline on a frame. Carries the `FrameResult` (with
342
- * `detections[]`, `width`/`height`, timing debug) — never the frame
343
- * buffer itself. Hub-side consumers (analysis pipeline, class filters,
344
- * notifications) subscribe to this and re-emit `detection.result` after
345
- * post-processing.
346
- */
347
- EventCategory["PipelineInferenceResult"] = "pipeline.inference-result";
348
- /**
349
- * Camera lifecycle event emitted by `addon-pipeline-orchestrator` when it
350
- * assigns or unassigns a camera to/from an agent. Carries no frame data;
351
- * pure observability for UI dashboards and metrics consumers.
352
- */
353
- EventCategory["PipelineCameraAssigned"] = "pipeline.camera-assigned";
354
- EventCategory["PipelineCameraUnassigned"] = "pipeline.camera-unassigned";
355
- /**
356
- * A node the orchestrator would otherwise place cameras on has NO usable
357
- * inference device: the operator enabled one or more accelerators there and
358
- * the live probe reports every one of them unavailable. Emitted once per
359
- * TRANSITION into that state (never per dispatch), and the node is dropped
360
- * from the placement candidate set for as long as it holds.
361
- *
362
- * This exists because the state was previously invisible: agent-a
363
- * absorbed 283k inference errors in a day while still being handed cameras,
364
- * and nothing in the system said so.
365
- *
366
- * A node with no accelerators configured at all is NOT this — its devices
367
- * are `disabled`, not `unavailable`, and the runner's default CPU pool
368
- * serves it exactly as before.
369
- */
370
- EventCategory["PipelineNodeInferenceUnavailable"] = "pipeline.node-inference-unavailable";
371
- /**
372
- * A camera has an OPEN detection session and has produced no detection at
373
- * all for longer than the blind threshold — the camera is being decoded and
374
- * inferred and is returning nothing. Emitted once per transition into blind,
375
- * per camera.
376
- *
377
- * The failure it reports: a 1h43 detection blackout on the entrance camera
378
- * that nobody noticed, because "a camera that detects nothing" and "a quiet
379
- * camera" produce byte-identical silence.
380
- */
381
- EventCategory["PipelineDetectionBlind"] = "pipeline.detection-blind";
382
- /**
383
- * A camera's motion source has fired constantly with no subject for an hour
384
- * (motion duty or session count over the bar, zero detections) — it is not
385
- * blind, its motion zones or sensitivity want tuning (D907). Paired with
386
- * {@link PipelineMotionCalm}.
387
- */
388
- EventCategory["PipelineMotionNoisy"] = "pipeline.motion-noisy";
389
- /** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
390
- EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
391
- /**
392
- * A camera's package LLM confirm has failed closed three times in a row
393
- * (D931, 2026-10-26). One edge per camera until
394
- * {@link PipelinePackageLlmAnswered}.
395
- */
396
- EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
397
- /** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
398
- EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
399
- /**
400
- * Per-camera pipeline config was mutated by the orchestrator
401
- * (a settings change via `setAgentInferenceDevices` /
402
- * `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
403
- * subscribes to its own emission to hot-reload the assigned runner
404
- * via `attachCamera` so the next frame executes against the new
405
- * engine/steps without waiting for a rebalance or the next
406
- * `DeviceStreamsRegistered` cycle.
407
- */
408
- EventCategory["PipelineCameraUpdated"] = "pipeline.camera-updated";
409
- /**
410
- * The cluster camera-source OWNER changed (`clusterRoles.ingestNode`).
411
- * Emitted by addon-pipeline-orchestrator whenever it (re)derives node
412
- * capabilities — at boot, on agent online/offline, and on an ingest-node
413
- * flip. Carries the resolved `ownerNodeId`. The stream-broker consumes it to
414
- * keep its ingest-owner-gate decision current WITHOUT a per-`ensureBroker`
415
- * cross-process `getIngestOwner` query (push the authority's decision instead
416
- * of polling it on the hot path). Idempotent state — re-emitted on every
417
- * topology change, so a dropped event self-heals on the next one (plus the
418
- * broker's long backstop reconcile query).
419
- */
420
- EventCategory["PipelineIngestOwnerChanged"] = "pipeline.ingest-owner-changed";
421
- /**
422
- * Periodic snapshot of per-node pipeline-runner load
423
- * (`RunnerLocalLoad`). Emitted ~1Hz by every runner so UI dashboards
424
- * subscribe instead of polling `pipelineRunner.getLocalLoad`.
425
- * `nodeId` carried in the payload + on `event.source.nodeId`.
426
- */
427
- EventCategory["PipelineRunnerLoadSnapshot"] = "pipeline.runner-load-snapshot";
428
- /**
429
- * Periodic snapshot of per-camera pipeline metrics (`CameraMetrics`
430
- * + `deviceId` + `nodeId`). Emitted ~1Hz by every runner for each
431
- * attached camera. UI subscribes to drive overlay phase / fps /
432
- * inference time without polling `getCameraMetrics`.
433
- */
434
- EventCategory["PipelineCameraMetricsSnapshot"] = "pipeline.camera-metrics-snapshot";
435
- /**
436
- * Periodic snapshot of stream-broker per-broker statistics (input
437
- * fps, decoded fps, bitrate, codec). Emitted ~1Hz by every
438
- * stream-broker process for each active broker so the UI can drive
439
- * the Stream / Cluster dashboards without polling
440
- * `streamBroker.listAllProfileSlots` and friends.
441
- */
442
- EventCategory["StreamBrokerMetricsSnapshot"] = "stream-broker.metrics-snapshot";
443
- /**
444
- * Cap event fired by `stream-broker` when a profile slot enters
445
- * "demanded" state — a cam stream has been assigned and at least one
446
- * consumer (RTSP restream, decoded subscriber, WebRTC session, …) is
447
- * present. Camera-provider addons (Reolink Baichuan push, …)
448
- * subscribe to this category to start their underlying transport
449
- * lazily. Payload: `{ deviceId, camStreamId, profile }`.
450
- */
451
- EventCategory["StreamBrokerOnCamStreamDemand"] = "stream-broker.onCamStreamDemand";
452
- /**
453
- * Cap event fired by `stream-broker` when the last consumer leaves a
454
- * previously-demanded cam stream. Providers tear down their
455
- * underlying transport on receipt. Payload: `{ deviceId, camStreamId }`.
456
- */
457
- EventCategory["StreamBrokerOnCamStreamIdle"] = "stream-broker.onCamStreamIdle";
458
- /**
459
- * Cap event fired by `stream-broker` when a broker fails to dial a
460
- * managed-loopback source (today: `pull-rfc4571`) and the publisher
461
- * needs to refresh the cached URL. The lib's TCP server idle-tears-down
462
- * on its own schedule, so a re-publish with a fresh `host:port` is the
463
- * only way to keep the broker dialable. Camera providers (Reolink
464
- * Baichuan native, …) subscribe and respond by re-running their publish
465
- * pipeline.
466
- * Payload: `{ deviceId, camStreamId, brokerId }`.
467
- */
468
- EventCategory["StreamBrokerOnRequestStreamSourceRefresh"] = "stream-broker.onRequestStreamSourceRefresh";
469
- /**
470
- * A camera provider changed a device's stream parameters (codec /
471
- * resolution / bitrate / a stream added or removed). A LOW-LATENCY NUDGE
472
- * for the stream-broker's catalog reconcile: it carries NO authoritative
473
- * data — the broker re-PULLS that device's `stream-catalog` cap on receipt
474
- * (the 30s reconcile poll is the backstop if this nudge is dropped). Emitted
475
- * by providers from `stream-params.setProfile`. Payload: `{ deviceId }`.
476
- */
477
- EventCategory["StreamParamsChanged"] = "stream-params.changed";
478
- /**
479
- * Generic per-device runtime-state change. Fired by `device-manager`
480
- * whenever a persisted slice in any cap's `runtimeState` shape
481
- * mutates. Payload: `{deviceId, capName, slice}`. Subscribers are
482
- * the `deviceState` cap router (cross-process listeners) and the
483
- * deviceProxy reactive bindings (`device.state.<capName>.value`).
484
- * Cap-specific events (`battery.onStatusChanged`, …) still fire
485
- * — they're authoritative for callers that want a typed payload
486
- * without filtering on `capName`.
487
- */
488
- EventCategory["DeviceStateChanged"] = "device.state-changed";
489
- /**
490
- * The NATIVE shadow of a cap a composition has claimed fields of moved
491
- * (D663). Payload: `{ deviceId, capName, native }` — what the provider
492
- * wrote, BEFORE the owned fields are overlaid. Owner-only (D224): it is for
493
- * the composer's native self-reads, and the public event routers refuse it
494
- * (`isOwnerOnlyEventCategory`) so no consumer surface ever shows a second
495
- * truth beside the merged `DeviceStateChanged.slice`. Emitted only under a
496
- * `replace` claim, one per native write of that cap.
497
- */
498
- EventCategory["DeviceNativeShadowChanged"] = "device.native-shadow-changed";
499
- /**
500
- * Frame occupancy for a camera CHANGED — a tracked object was gained or
501
- * lost. Carries `{ deviceId, totalObjects, byClass, zones }`.
502
- *
503
- * Emitted only on a change, so a steady scene is silent. It exists so a
504
- * client can stop polling `zoneAnalytics.getCurrentSnapshot`: that was the
505
- * one live badge with no push signal at all, and it cost a request every
506
- * four seconds per visible camera.
507
- *
508
- * Like every event it is telemetry and may be dropped ([D8]) — a consumer
509
- * keeps a slow reconcile rather than trusting it alone.
510
- */
511
- EventCategory["ZoneAnalyticsOccupancyChanged"] = "zone-analytics.occupancy-changed";
512
- /**
513
- * Cap event fired by every device that registers the `battery`
514
- * capability. Mirrors the cap definition's `onStatusChanged`. Carries
515
- * `{ deviceId, status: BatteryStatus }`. Subscribers (alert center,
516
- * snapshot wrapper, UI) react to charge/sleep transitions without
517
- * polling `batteryCapability.getStatus`.
518
- */
519
- EventCategory["BatteryOnStatusChanged"] = "battery.onStatusChanged";
520
- /**
521
- * Cap event fired by every device that registers the `network-link`
522
- * capability. Mirrors the cap definition's `onStatusChanged`. Carries
523
- * `{ deviceId, status: NetworkLinkStatus }` — a link switch or a signal
524
- * reading that moved.
525
- */
526
- EventCategory["NetworkLinkOnStatusChanged"] = "network-link.onStatusChanged";
527
- /**
528
- * Emitted by the battery cap provider WHEN `wakeForStream` enters the
529
- * "wake in progress" window — between the Baichuan wake-up issue and
530
- * the camera's first dialed-back RTP packet. The stream-broker
531
- * manager subscribes to flip the per-broker placeholder reason to
532
- * `'waking'` so viewers see a labelled "WAKING UP" tile instead of
533
- * the generic `'reconnecting'` frame. Carries `{ deviceId }`. The
534
- * complementary "wake complete" signal is the existing
535
- * `BatteryOnStatusChanged { sleeping: false }` event.
536
- */
537
- EventCategory["BatteryOnWakeStarted"] = "battery.onWakeStarted";
538
- /**
539
- * Cap event fired by every device that registers the `doorbell`
540
- * capability. Mirrors `doorbellCapability.events.onPressed`. Carries
541
- * `{ deviceId, timestamp }`. Operators consuming the UI subscribe
542
- * here to render transient ring toasts and a "Recent presses" row
543
- * on the device detail page.
544
- */
545
- EventCategory["DoorbellOnPressed"] = "doorbell.onPressed";
546
- /** Mirrors `runningStateCapability.events.onStarted`. */
547
- EventCategory["RunningStarted"] = "running.started";
548
- /** Mirrors `runningStateCapability.events.onFinished`. */
549
- EventCategory["RunningFinished"] = "running.finished";
550
- /** Mirrors `deviceRunsCapability.events.onRunOpened` - a durable run record opened. */
551
- EventCategory["DeviceRunOpened"] = "device-run.opened";
552
- /** Mirrors `deviceRunsCapability.events.onRunClosed` - a durable run record closed. */
553
- EventCategory["DeviceRunClosed"] = "device-run.closed";
554
- /**
555
- * Cap event fired by every device that registers the `event-emitter`
556
- * capability. Mirrors `eventEmitterCapability.events.onEvent`. Carries
557
- * `{ deviceId, eventType, data, timestamp, seq }` — the device's EXACT
558
- * declared event verbatim (NO normalization). Subscribers (UI event
559
- * stream, advanced-notifier rules) react to fired events without
560
- * holding a cap reference.
561
- */
562
- EventCategory["EventEmitted"] = "event-emitter.event";
563
- /**
564
- * Periodic snapshot of the per-node detection-pipeline engine
565
- * registry (loaded engines, models resident, in-use cameras, idle
566
- * TTL). Emitted ~0.2Hz (every 5 s) by every detection-pipeline
567
- * process. The Engines tab subscribes to drive its inventory view
568
- * without polling `pipelineExecutor.listLoadedEngines`.
569
- */
570
- EventCategory["PipelineEngineMetricsSnapshot"] = "pipeline.engine-metrics-snapshot";
571
- /**
572
- * Per-node detection-engine runtime-provisioning transition. Emitted by
573
- * the detection-pipeline provider on every state change of its lazy
574
- * engine-provisioning machine (idle → installing → verifying → ready,
575
- * or → failed with a `nextRetryAt`). Payload is the
576
- * `EngineProvisioningState` snapshot; `event.source.nodeId` carries the
577
- * node. The Pipeline page subscribes to drive a live "installing
578
- * OpenVINO… / ready" indicator per node without polling
579
- * `pipelineExecutor.getEngineProvisioning`. Telemetry-grade (D8): the UI
580
- * also reads the cap snapshot on mount / reconnect. Phase 2.
581
- */
582
- EventCategory["PipelineEngineProvisioning"] = "pipeline.engine-provisioning";
583
- /**
584
- * Cluster topology snapshot. Carries the same payload returned by
585
- * `nodes.topology` (every reachable node + addons + processes).
586
- * Emitted by the hub on any agent / addon lifecycle change
587
- * (debounced) plus a periodic safety net. Replaces UI polling on
588
- * `nodes.topology` — admin-ui dashboards subscribe to drive the
589
- * cluster view directly from the event payload.
590
- */
591
- EventCategory["ClusterTopologySnapshot"] = "cluster.topology-snapshot";
592
- /**
593
- * Periodic per-node system metrics snapshot (CPU / memory / GPU /
594
- * disk / network). Emitted ~0.2 Hz by the metrics-provider addon
595
- * for each node. Drives the dashboard SystemStatus / ProcessResources
596
- * widgets without polling `metricsProvider.getCurrent`.
597
- */
598
- EventCategory["MetricsNodeResourcesSnapshot"] = "metrics.node-resources-snapshot";
599
- /**
600
- * Periodic per-node process-tree snapshot (camstack-related pids
601
- * with root / managed / system classification). Emitted ~0.2 Hz by
602
- * the metrics-provider addon. Drives the Cluster → Processes tab
603
- * without polling `metricsProvider.listNodeProcesses`.
604
- */
605
- EventCategory["MetricsNodeProcessesSnapshot"] = "metrics.node-processes-snapshot";
606
- /**
607
- * Capability binding change event emitted by `addon-pipeline-orchestrator`
608
- * when a user changes which addon implements a cap on a node. Subscribed
609
- * by every kernel process to update its local `preferredProviderRegistry`
610
- * so future capability lookups respect the new binding.
611
- */
612
- /**
613
- * A capability binding was changed for a node — addon X now provides
614
- * capability `cap` on node `nodeId`. Lives under the generic
615
- * `capability.*` namespace because capability bindings are a kernel-
616
- * level concept used by many addons, not strictly pipeline-scoped.
617
- */
618
- EventCategory["CapabilityBindingChanged"] = "capability.binding-changed";
619
- EventCategory["ModelDownloadProgress"] = "model.download.progress";
620
- EventCategory["AgentRegistered"] = "agent.registered";
621
- EventCategory["AgentUnregistered"] = "agent.unregistered";
622
- EventCategory["AgentOnline"] = "agent.online";
623
- EventCategory["AgentOffline"] = "agent.offline";
624
- /** Forked worker process (e.g. hub/pipeline) connected to the broker. */
625
- EventCategory["WorkerOnline"] = "worker.online";
626
- /** Forked worker process disconnected from the broker. */
627
- EventCategory["WorkerOffline"] = "worker.offline";
628
- EventCategory["AgentTaskDispatched"] = "agent.task.dispatched";
629
- EventCategory["AgentTaskAssigned"] = "agent.task.assigned";
630
- EventCategory["AgentTrpcConnected"] = "agent.trpc.connected";
631
- EventCategory["AgentWsConnected"] = "agent.ws.connected";
632
- EventCategory["AgentWsDisconnected"] = "agent.ws.disconnected";
633
- EventCategory["AgentBackupActivated"] = "agent.backup.activated";
634
- EventCategory["OrchestrationSettingsUpdated"] = "orchestration.settings-updated";
635
- EventCategory["MotionAnalysis"] = "detection.motion-analysis";
636
- /** All raw motion zones from CCL before minArea filter — for UI debug overlay. */
637
- EventCategory["MotionZonesRaw"] = "detection.motion-zones-raw";
638
- /**
639
- * Per-camera motion phase transition (`watching ↔ active`) emitted
640
- * by the runner. Mirrors the `motion.onMotionChanged` cap event
641
- * surface — payload `MotionOnMotionChangedPayload` carries
642
- * `{deviceId, detected, timestamp, source, regions?}`. Subscribers
643
- * include addons that need to react to motion state without
644
- * polling the runtime-state mirror.
645
- */
646
- EventCategory["MotionOnMotionChanged"] = "motion.on-motion-changed";
647
- EventCategory["DetectionResult"] = "detection.result";
648
- EventCategory["DetectionRaw"] = "detection.raw";
649
- EventCategory["DetectionCameraNative"] = "detection.camera-native";
650
- /**
651
- * Canonical per-chunk live audio pipeline output. Payload is
652
- * `PipelineAudioInferenceResultPayload` carrying a full `AudioResult`
653
- * (level + detections + debug). Lives on the pipeline.* namespace
654
- * alongside `pipeline.inference-result` (video) for symmetry.
655
- */
656
- EventCategory["PipelineAudioInferenceResult"] = "pipeline.audio-inference-result";
657
- EventCategory["DetectionPhaseTransition"] = "detection.phase-transition";
658
- /**
659
- * A camera provider's RAW onboard motion push (D673): the `MotionOnMotionChanged`
660
- * data shape without `triggeredBy`, built by `providerMotionEvent`. Its one
661
- * consumer is the orchestrator's camera-sensors bridge, which re-emits the
662
- * camera's EFFECTIVE onboard motion as `MotionOnMotionChanged` (a pass-through
663
- * for a camera with no attached sensor). Providers must not emit
664
- * `MotionOnMotionChanged` themselves; `scripts/check-onboard-motion-emitters.ts`
665
- * keeps it so (camera-grid is a named, deferred exception).
666
- */
667
- EventCategory["ProviderMotion"] = "provider.motion";
668
- EventCategory["ProviderDetection"] = "provider.detection";
669
- EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
670
- EventCategory["EnrichmentSceneStateChanged"] = "enrichment.scene.state-changed";
671
- EventCategory["EnrichmentActivitySummary"] = "enrichment.activity.summary";
672
- /**
673
- * Unified track-lifecycle event: ONE category carrying `phase:
674
- * 'start' | 'update' | 'end'` with a rich, typed
675
- * `PipelineAnalyticsTrackLifecyclePayload`. Supersedes the thin
676
- * `PipelineAnalyticsTrackStarted` / `PipelineAnalyticsTrackEnded`
677
- * pair — a consumer subscribes once and branches on `phase`.
678
- */
679
- EventCategory["PipelineAnalyticsTrackLifecycle"] = "pipeline-analytics.track-lifecycle";
680
- /**
681
- * @deprecated Superseded by {@link PipelineAnalyticsTrackLifecycle}
682
- * (`phase:'start'`). Kept as a soft alias — no known subscribers.
683
- */
684
- EventCategory["PipelineAnalyticsTrackStarted"] = "pipeline-analytics.track-started";
685
- /**
686
- * @deprecated Superseded by {@link PipelineAnalyticsTrackLifecycle}
687
- * (`phase:'end'`). Kept as a soft alias — no known subscribers.
688
- */
689
- EventCategory["PipelineAnalyticsTrackEnded"] = "pipeline-analytics.track-ended";
690
- EventCategory["PipelineAnalyticsDetectionEvent"] = "pipeline-analytics.detection-event";
691
- EventCategory["PipelineAnalyticsFrameTracked"] = "pipeline-analytics.frame-tracked";
692
- /**
693
- * Fired by `addon-post-analysis` when a parked (stationary) object appears
694
- * (a track was promoted to a stationary-registry entry) or departs (the
695
- * object moved / was removed). Telemetry (D8): lossy, drives a UI refresh of
696
- * the dedicated "Stationary" section — never the live event feed. Payload:
697
- * `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp, observedAt, zones }`.
698
- */
699
- EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
700
- /**
701
- * Fired by `addon-post-analysis` when a package-drop is confirmed inside
702
- * a package zone — a newly-appeared stationary object of a package class
703
- * that cleared the class / zone / dwell / size gates. Payload:
704
- * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
705
- * entryId, className, zoneIds, keyFrameMediaId?, bbox, timestamp }`.
706
- * Telemetry (D8): the durable record is the `package-events` store row;
707
- * this bus topic drives notifier rules + live UI. See
708
- * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
709
- */
710
- EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
711
- /**
712
- * Fired by `addon-post-analysis` when a previously-delivered package
713
- * leaves its zone (the stationary entry departed — moved or swept).
714
- * Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
715
- * `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
716
- * Telemetry (D8). See package-zones-design §5.2.
717
- */
718
- EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
719
- /**
720
- * Fired by `addon-post-analysis` whenever a gallery face row changes:
721
- * `kind:'buffered'` a new detected face was persisted, `'assigned'` /
722
- * `'unassigned'` its identity link changed, `'deleted'` the row was
723
- * removed. Telemetry semantics (D8): a lost event only delays a refresh,
724
- * never a correctness issue. Payload `PipelineAnalyticsFaceGalleryChangedPayload`.
725
- */
726
- EventCategory["PipelineAnalyticsFaceGalleryChanged"] = "pipeline-analytics.face-gallery-changed";
727
- /**
728
- * Fired by `addon-post-analysis` whenever a gallery plate row changes:
729
- * `kind:'buffered'` a new read was persisted (`PlateRecognizer.onTrackEnd`),
730
- * `'assigned'` / `'unassigned'` its vehicle link changed
731
- * (`PlateGalleryProvider`), `'deleted'` the row was removed. Telemetry
732
- * semantics (D8): a lost event only delays a refresh, never a correctness
733
- * issue. Payload `PipelineAnalyticsPlateGalleryChangedPayload`.
734
- */
735
- EventCategory["PipelineAnalyticsPlateGalleryChanged"] = "pipeline-analytics.plate-gallery-changed";
736
- EventCategory["CameraStreamsProfileSlotsChanged"] = "camera-streams.onProfileSlotsChanged";
737
- /**
738
- * Stream-broker health watchdog. Per-broker (deviceId/profile) emission.
739
- * `stream.offline` fires after STREAM_STALE_TIMEOUT_MS without an encoded
740
- * packet on an active broker. `stream.online` fires on first packet
741
- * after a stale gap (or on initial first packet). Payload includes
742
- * the assigned camStreamId as `profileKey`.
743
- */
744
- EventCategory["StreamOnline"] = "stream.online";
745
- EventCategory["StreamOffline"] = "stream.offline";
746
- EventCategory["NetworkTunnelStarted"] = "network.tunnel.started";
747
- EventCategory["NetworkTunnelStopped"] = "network.tunnel.stopped";
748
- /** Fired by the `local-network` cap when the host's interface set
749
- * changes (new IP from DHCP, VPN connect, docker bridge added). */
750
- EventCategory["LocalNetworkChanged"] = "network.local.changed";
751
- /**
752
- * Fired by a `mesh-network` provider (Tailscale, …) when its
753
- * mesh-reachable host changes (join / leave / MagicDNS or 100.x IP
754
- * change). Lets `local-network` fold the mesh endpoint into its
755
- * connection-endpoint list without a cross-package import. Payload
756
- * carries the preferred host (`host: ''` = no longer reachable),
757
- * the hub port, and the scheme. Telemetry-grade (D8): consumers
758
- * pull-reconcile from the provider's `getStatus` on reconnect. */
759
- EventCategory["MeshNetworkChanged"] = "network.mesh.changed";
760
- EventCategory["BackupCompleted"] = "backup.completed";
761
- /**
762
- * A whole backup RUN finished — every destination attempted, win or lose.
763
- *
764
- * `backup.completed` fires once per DESTINATION, which is the right grain for
765
- * a progress UI and the wrong one for a notification: an operator with three
766
- * destinations would be told three times. And a run where two of three
767
- * destinations succeeded is not a clean success — a single "backup
768
- * completed" that hid the failed one would be a lie, so the count of each is
769
- * carried here and the message says both.
770
- *
771
- * Emitted by the backup orchestrator only after the destination loop, so a
772
- * run that dies during the BUILD phase produces no completion at all.
773
- */
774
- EventCategory["BackupRunCompleted"] = "backup.run-completed";
775
- EventCategory["BackupRestored"] = "backup.restored";
776
- EventCategory["NotificationDispatched"] = "notification.dispatched";
777
- EventCategory["NotificationFailed"] = "notification.failed";
778
- /**
779
- * A notification rule that cannot work (D905): its stored row does not load,
780
- * or it still names a device / delivery target the prune CONFIRMED deleted.
781
- * One edge per rule per distinct set of reasons; never on an unanswered read.
782
- */
783
- EventCategory["NotificationRuleBroken"] = "notification.rule-broken";
784
- /** The clear of {@link NotificationRuleBroken}: the rule loads and names nothing deleted. */
785
- EventCategory["NotificationRuleRepaired"] = "notification.rule-repaired";
786
- /** A migration failed or was blocked; the Alert Center re-reads the ledger. */
787
- EventCategory["MigrationFailed"] = "migration.failed";
788
- /** A migration applied or a failure cleared; the Alert Center re-reads the ledger. */
789
- EventCategory["MigrationApplied"] = "migration.applied";
790
- EventCategory["DeviceUpdated"] = "device.updated";
791
- /**
792
- * Transport-level connectivity. Emitted by the device driver when
793
- * the underlying control socket actually connects / disconnects
794
- * (Baichuan TCP, ONVIF probe response, RTSP DESCRIBE, …) — NOT for
795
- * power-state transitions on a battery camera. For battery wake /
796
- * doze cycles see `DeviceAwake` / `DeviceSleeping`.
797
- */
798
- EventCategory["DeviceOnline"] = "device.online";
799
- /**
800
- * Stream-broker watchdog — emitted when no encoded packet has been
801
- * received for STREAM_STALE_TIMEOUT_MS on an active broker (rtsp or
802
- * push). Paired with DeviceOnline which fires on first packet after
803
- * a stale gap. Payload: DeviceStreamHealthPayload.
804
- */
805
- EventCategory["DeviceOffline"] = "device.offline";
806
- /**
807
- * Battery cam woke up — physical power-state transition reported
808
- * by the device firmware. Distinct from `DeviceOnline` so a UI panel
809
- * watching power state doesn't flap on every UDP socket reconnect.
810
- */
811
- EventCategory["DeviceAwake"] = "device.awake";
812
- /**
813
- * Battery cam went to sleep. See `DeviceAwake`.
814
- */
815
- EventCategory["DeviceSleeping"] = "device.sleeping";
816
- EventCategory["RetentionCleanup"] = "retention.cleanup";
817
- /**
818
- * Legacy bulk-update progress snapshot (payload `BulkUpdateState`). No longer
819
- * emitted — F3 removed the coordinator that produced it; "Update all" now runs
820
- * as one lifecycle engine job (`AddonsJobProgress`/`AddonsJobLog`). Retained
821
- * (with `BulkUpdateState`) only to avoid regenerating the event maps; removed
822
- * in F4 once live bulk progress is re-implemented over the engine events.
823
- */
824
- EventCategory["AddonsBulkUpdateProgress"] = "addons.bulk-update-progress";
825
- EventCategory["AddonsJobProgress"] = "addons.job-progress";
826
- EventCategory["AddonsJobLog"] = "addons.job-log";
827
- /**
828
- * A container's child visibility toggled (hidden/shown). Emitted by the
829
- * `accessories` cap when a child device is hidden or revealed.
830
- * Payload: `{ deviceId, childDeviceId, hidden }`.
831
- */
832
- EventCategory["AccessoriesChildVisibilityChanged"] = "accessories.onChildVisibilityChanged";
833
- /**
834
- * A container's child set changed (children added/removed/reordered).
835
- * Payload: `{ deviceId, childDeviceIds, hiddenChildIds }`.
836
- */
837
- EventCategory["AccessoriesChanged"] = "accessories.onAccessoriesChanged";
838
- /**
839
- * An action run started or ended. Emitted by the `actions` surface.
840
- * Payload: `ActionRunChanged` (`{ actionId, runId, isRunning, outcome?, lastRunAt, lastError }`).
841
- */
842
- EventCategory["ActionsRunChanged"] = "actions.onRunChanged";
843
- /**
844
- * Progress update from a running model conversion job.
845
- * Payload: `{ kind: 'model-convert', phase, sessionId?, pct?, detail? }`.
846
- * Emitted by `addon-model-studio` on the converting node.
847
- */
848
- EventCategory["ModelConvertProgress"] = "model-convert.progress";
849
- return EventCategory;
850
- }({});
851
- //#endregion
852
- //#region ../types/dist/device-type-D1fH5kaC.mjs
853
- /**
854
- import { errMsg } from '@camstack/types'
855
- * Extract a human-readable message from an unknown error value.
856
- * Replaces the ubiquitous `errMsg(err)` pattern.
857
- */
858
- function errMsg(err) {
859
- if (err instanceof Error) return err.message;
860
- if (typeof err === "string") return err;
861
- return String(err);
862
- }
863
- var DeviceType = /* @__PURE__ */ function(DeviceType) {
864
- DeviceType["Camera"] = "camera";
865
- DeviceType["Hub"] = "hub";
866
- DeviceType["Light"] = "light";
867
- DeviceType["Siren"] = "siren";
868
- DeviceType["Switch"] = "switch";
869
- DeviceType["Sensor"] = "sensor";
870
- DeviceType["Thermostat"] = "thermostat";
871
- /** Air-conditioner / heat-pump climate device (HVAC) — shares the
872
- * `climate-control` cap surface with `Thermostat` but renders a
873
- * dedicated AC-appropriate control UI (mode chips, fan speed,
874
- * independent vertical/horizontal swing). Sources: native Gree, and
875
- * reusable by other AC integrations. */
876
- DeviceType["Climate"] = "climate";
877
- DeviceType["Button"] = "button";
878
- /** Generic stateless event emitter — carries a device's EXACT declared
879
- * event vocabulary verbatim (no normalization). Installed with the
880
- * `event-emitter` cap. Sources: HA `event.*` entities (structured) and
881
- * HA bus events (e.g. `zha_event`, generic). */
882
- DeviceType["EventEmitter"] = "event-emitter";
883
- /** Firmware/software update entity — current vs available version,
884
- * updatable flag, update state, and an install action. Installed with
885
- * the `update` cap. Sources: Homematic firmware-update channels (and
886
- * reusable by other providers, e.g. HA `update.*` entities). */
887
- DeviceType["Update"] = "update";
888
- DeviceType["Generic"] = "generic";
889
- /** Generic notification delivery target (HA `notify.<service>`, future
890
- * Telegram / Discord / ntfy / SMTP, …). One device per delivery
891
- * endpoint; the `notifier` cap defines the send surface. */
892
- DeviceType["Notifier"] = "notifier";
893
- /** Pre-recorded action sequence with optional parameters
894
- * (HA `script.*`). Runnable via `script-runner` cap. */
895
- DeviceType["Script"] = "script";
896
- /** Automation rule (HA `automation.*`) — enable/disable + manual
897
- * trigger surface exposed via `automation-control` cap. */
898
- DeviceType["Automation"] = "automation";
899
- /** Door / smart lock device (HA `lock.*`). `lock-control` cap. */
900
- DeviceType["Lock"] = "lock";
901
- /** Window covering, blinds, garage door, valve, etc. (HA `cover.*`,
902
- * `valve.*`). `cover` cap with sub-roles for variant. */
903
- DeviceType["Cover"] = "cover";
904
- /** Pipe / water / gas valve with open/close/stop and optional
905
- * position (HA `valve.*`). `valve` cap — a cover-sibling actuator
906
- * modelled on the same open/closed lifecycle. */
907
- DeviceType["Valve"] = "valve";
908
- /** Humidifier / dehumidifier with on/off + target humidity + mode
909
- * (HA `humidifier.*`). `humidifier` cap — a climate-family actuator
910
- * modelled on the same target / mode lifecycle. */
911
- DeviceType["Humidifier"] = "humidifier";
912
- /** Water heater / boiler with target temperature + operation mode +
913
- * away mode (HA `water_heater.*`). `water-heater` cap — a
914
- * climate-family actuator. */
915
- DeviceType["WaterHeater"] = "water-heater";
916
- /** Ceiling / standing / exhaust fan (HA `fan.*`). `fan-control` cap. */
917
- DeviceType["Fan"] = "fan";
918
- /** Audio / video playback endpoint (HA `media_player.*`). Disjoint from
919
- * the camera surface — those use `Camera`. `media-player` cap. */
920
- DeviceType["MediaPlayer"] = "media-player";
921
- /** Security panel / alarm system (HA `alarm_control_panel.*`).
922
- * `alarm-panel` cap. */
923
- DeviceType["AlarmPanel"] = "alarm-panel";
924
- /** Generic user-settable input (HA `number` / `input_number` / `select`
925
- * / `input_select` / `text` / `input_text` / `input_datetime`).
926
- * Sub-type via `DeviceRole`: NumericControl / SelectControl /
927
- * TextControl / DateTimeControl. */
928
- DeviceType["Control"] = "control";
929
- /** Person / device-tracker presence (HA `person.*`, `device_tracker.*`).
930
- * `presence` cap. */
931
- DeviceType["Presence"] = "presence";
932
- /** Weather provider (HA `weather.*`). Tier-3, low MVP priority.
933
- * `weather` cap. */
934
- DeviceType["Weather"] = "weather";
935
- /** Robot vacuum (HA `vacuum.*`). Tier-3. `vacuum-control` cap. */
936
- DeviceType["Vacuum"] = "vacuum";
937
- /** Robotic lawn mower (HA `lawn_mower.*`). Tier-3.
938
- * `lawn-mower-control` cap. */
939
- DeviceType["LawnMower"] = "lawn-mower";
940
- /** Physical HA device group — parent container for entity-children
941
- * adopted from a single HA device entry. Not renderable as a
942
- * standalone device; exists only to anchor child entities. */
943
- DeviceType["Container"] = "container";
944
- /** Single still-image entity (HA `image.*`). Read-only display of an
945
- * `entity_picture` signed URL the browser loads directly. `image` cap. */
946
- DeviceType["Image"] = "image";
947
- /** Smart pet feeder — cloud-connected food dispenser with a bowl food
948
- * level, battery, desiccant life, feeding state and manual-feed /
949
- * call-pet / maintenance actions. Installed with the `pet-feeder` cap;
950
- * dual-hopper models (D4S/D4SH) expose per-hopper portions. Sources:
951
- * native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
952
- * integrations sharing the same food/desiccant/hopper surface. */
953
- DeviceType["PetFeeder"] = "pet-feeder";
954
- /** Pet water fountain — tank level, water drunk, pump and its duty cycle.
955
- * Installed with the `pet-fountain` cap. Reaches CamStack as loose entities
956
- * of a container and is BUILT as a composed device (D967). */
957
- DeviceType["PetFountain"] = "pet-fountain";
958
- /** Built-in dishwasher — program lifecycle, door / remote-start gates,
959
- * salt and rinse-aid levels. Installed with the `dishwasher` cap.
960
- * Sources: native Bosch Home Connect, reusable by similar integrations.
961
- * A plug-built dishwasher carries running-state and power instead. */
962
- DeviceType["Dishwasher"] = "dishwasher";
963
- /** Washing machine. A plug-built one is running while its power stays
964
- * above a threshold. No program cap — that surface is the dishwasher's. */
965
- DeviceType["Washer"] = "washer";
966
- /** A dumb plug-in stove or heater: a switch (and, with a meter, a power
967
- * reading) that only runs while the plug is on. Built from a smart plug;
968
- * the `timed-run` cap switches it off again after a chosen time. */
969
- DeviceType["Heater"] = "heater";
970
- /** Tumble dryer. Same plug-built running surface as {@link Washer}. */
971
- DeviceType["Dryer"] = "dryer";
972
- /** The physical bridge box of a vendor ecosystem (Velux KLF-200, and later
973
- * other radio-to-IP bridges). It carries the box's own facts (firmware,
974
- * address, connection state) and the actions the box really supports
975
- * (`reboot`, `device-admin-link`). Products are NOT its children — they are
976
- * adopted beside it — and its connection settings stay on the integration. */
977
- DeviceType["Gateway"] = "gateway";
978
- return DeviceType;
979
- }({});
980
- var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
981
- DeviceFeature["BatteryOperated"] = "battery-operated";
982
- DeviceFeature["Rebootable"] = "rebootable";
983
- /**
984
- * Device supports an on-demand re-sync of its derived spec with its
985
- * upstream source — drives the generic Re-sync button. The owning
986
- * provider implements the action via the `device-adoption.resync` cap.
987
- */
988
- DeviceFeature["Resyncable"] = "resyncable";
989
- DeviceFeature["NativeSnapshot"] = "native-snapshot";
990
- DeviceFeature["DoorbellButton"] = "doorbell-button";
991
- DeviceFeature["TwoWayAudio"] = "two-way-audio";
992
- DeviceFeature["PanTiltZoom"] = "pan-tilt-zoom";
993
- /**
994
- * Camera supports the on-firmware autotrack subsystem (subject-
995
- * following). Distinct from `PanTiltZoom` because not every PTZ
996
- * camera ships autotrack — the admin UI uses this flag to gate
997
- * the autotrack toggle / settings card without re-deriving from
998
- * the cap registry. Mirrors `ptz-autotrack` cap registration:
999
- * driver sets this feature when probe confirms the firmware
1000
- * surface, and registers the cap in the same code path.
1001
- */
1002
- DeviceFeature["PtzAutotrack"] = "ptz-autotrack";
1003
- /**
1004
- * Accessory exposes a "trigger on motion" toggle — the parent camera's
1005
- * motion detection automatically activates this device. Mirrors
1006
- * `motion-trigger` cap registration: drivers set this feature in the
1007
- * same code path that calls `ctx.registerNativeCap(motionTriggerCapability, ...)`.
1008
- *
1009
- * Used by admin UI (gate the in-hero `MotionTriggerToggle` against a
1010
- * fast scalar without binding fetch), notifier rules, and `listAll`
1011
- * filters that want "all devices with on-motion behaviour".
1012
- */
1013
- DeviceFeature["MotionTrigger"] = "motion-trigger";
1014
- /** Light supports rgb-triplet color via `color` cap. */
1015
- DeviceFeature["LightColorRgb"] = "light-color-rgb";
1016
- /** Light supports HSV color via `color` cap. */
1017
- DeviceFeature["LightColorHsv"] = "light-color-hsv";
1018
- /** Light supports color-temperature (mired) via `color` cap. */
1019
- DeviceFeature["LightColorMired"] = "light-color-mired";
1020
- /** Thermostat supports a `heat_cool` dual setpoint (targetLow +
1021
- * targetHigh). Gates the range slider UI. */
1022
- DeviceFeature["ClimateDualSetpoint"] = "climate-dual-setpoint";
1023
- /** Thermostat exposes target humidity and/or current humidity
1024
- * readings. Gates the humidity controls. */
1025
- DeviceFeature["ClimateHumidity"] = "climate-humidity";
1026
- /** Thermostat exposes a fan-mode selector. */
1027
- DeviceFeature["ClimateFanMode"] = "climate-fan-mode";
1028
- /** Thermostat exposes preset modes (eco / away / sleep / vendor). */
1029
- DeviceFeature["ClimatePreset"] = "climate-preset";
1030
- /** Thermostat exposes a vertical louver swing toggle. Gates the
1031
- * vertical-swing switch in the climate UI. Independent of horizontal. */
1032
- DeviceFeature["ClimateSwingVertical"] = "climate-swing-vertical";
1033
- /** Thermostat exposes a horizontal louver swing toggle. Gates the
1034
- * horizontal-swing switch in the climate UI. Independent of vertical. */
1035
- DeviceFeature["ClimateSwingHorizontal"] = "climate-swing-horizontal";
1036
- /** Cover exposes intermediate position control (0..100). Gates the
1037
- * position slider UI. */
1038
- DeviceFeature["CoverPositionable"] = "cover-positionable";
1039
- /** Cover exposes slat-tilt control. Gates the tilt slider UI. */
1040
- DeviceFeature["CoverTilt"] = "cover-tilt";
1041
- /** Cover has a real stop: `stop` halts the travel in place. Gates the stop
1042
- * control in exporters; a provider whose `stop` is a no-op never declares it. */
1043
- DeviceFeature["CoverStoppable"] = "cover-stoppable";
1044
- /** Valve exposes intermediate position control (0..100). Gates the
1045
- * position slider / drag surface UI. */
1046
- DeviceFeature["ValvePositionable"] = "valve-positionable";
1047
- /** Fan exposes a speed-percentage setter. Gates the speed slider UI. */
1048
- DeviceFeature["FanSpeed"] = "fan-speed";
1049
- /** Fan exposes a preset mode selector. */
1050
- DeviceFeature["FanPreset"] = "fan-preset";
1051
- /** Fan exposes blade direction (forward/reverse) — typical of
1052
- * ceiling fans. */
1053
- DeviceFeature["FanDirection"] = "fan-direction";
1054
- /** Fan exposes an oscillation toggle. */
1055
- DeviceFeature["FanOscillating"] = "fan-oscillating";
1056
- /** Lock requires a PIN code on lock/unlock. Gates the code-entry
1057
- * field on the UI lock-controls panel. */
1058
- DeviceFeature["LockPinRequired"] = "lock-pin-required";
1059
- /** Lock supports a latch-release ("open door") action distinct from
1060
- * unlock. Mirrors HA `LockEntityFeature.OPEN` (bit 1) in
1061
- * `supported_features`. Gates the Open Door button in the UI. */
1062
- DeviceFeature["LockOpen"] = "lock-open";
1063
- /** Media player exposes a seek-to-position surface. */
1064
- DeviceFeature["MediaPlayerSeek"] = "media-player-seek";
1065
- /** Media player exposes a volume-level setter. */
1066
- DeviceFeature["MediaPlayerVolume"] = "media-player-volume";
1067
- /** Media player exposes a mute toggle distinct from volume=0. */
1068
- DeviceFeature["MediaPlayerMute"] = "media-player-mute";
1069
- /** Media player exposes a shuffle toggle. */
1070
- DeviceFeature["MediaPlayerShuffle"] = "media-player-shuffle";
1071
- /** Media player exposes a repeat mode (off / all / one). */
1072
- DeviceFeature["MediaPlayerRepeat"] = "media-player-repeat";
1073
- /** Media player exposes a source / input selector. */
1074
- DeviceFeature["MediaPlayerSelectSource"] = "media-player-select-source";
1075
- /** Media player exposes a play-arbitrary-media surface (URL / id). */
1076
- DeviceFeature["MediaPlayerPlayMedia"] = "media-player-play-media";
1077
- /** Media player exposes next-track. */
1078
- DeviceFeature["MediaPlayerNext"] = "media-player-next";
1079
- /** Media player exposes previous-track. */
1080
- DeviceFeature["MediaPlayerPrevious"] = "media-player-previous";
1081
- /** Media player exposes stop distinct from pause. */
1082
- DeviceFeature["MediaPlayerStop"] = "media-player-stop";
1083
- /** Media player exposes volume up / down in steps (an infrared TV has no level). */
1084
- DeviceFeature["MediaPlayerVolumeStep"] = "media-player-volume-step";
1085
- /** Media player exposes channel up / down in steps. */
1086
- DeviceFeature["MediaPlayerChannelStep"] = "media-player-channel-step";
1087
- /** Media player exposes power on / off. */
1088
- DeviceFeature["MediaPlayerPower"] = "media-player-power";
1089
- /** Alarm panel requires a PIN code on arm/disarm. */
1090
- DeviceFeature["AlarmPinRequired"] = "alarm-pin-required";
1091
- /** Presence device carries GPS coordinates (lat/lng/accuracy) in
1092
- * addition to a textual location. */
1093
- DeviceFeature["PresenceGps"] = "presence-gps";
1094
- /** Notifier accepts an inline / URL image attachment. */
1095
- DeviceFeature["NotifierImage"] = "notifier-image";
1096
- /** Notifier accepts a priority hint (high/normal/low). */
1097
- DeviceFeature["NotifierPriority"] = "notifier-priority";
1098
- /** Notifier accepts a free-form `data` payload for platform-specific
1099
- * fields. */
1100
- DeviceFeature["NotifierData"] = "notifier-data";
1101
- /** Notifier supports interactive action buttons / callbacks. */
1102
- DeviceFeature["NotifierActions"] = "notifier-actions";
1103
- /** Notifier supports per-call recipient targeting (multi-user). */
1104
- DeviceFeature["NotifierRecipients"] = "notifier-recipients";
1105
- /** Script runner accepts a variables map on each run invocation. */
1106
- DeviceFeature["ScriptVariables"] = "script-variables";
1107
- /** Automation `trigger` accepts a skipCondition flag — fires the
1108
- * automation's actions while bypassing its condition block. */
1109
- DeviceFeature["AutomationSkipCondition"] = "automation-skip-condition";
1110
- /** Robot vacuum exposes a live cleaning map (image child). Gates the
1111
- * map tile in the vacuum UI. */
1112
- DeviceFeature["VacuumHasMap"] = "vacuum-has-map";
1113
- /** Robot vacuum exposes AI obstacle-detection toggles. Gates the AI
1114
- * switches group. */
1115
- DeviceFeature["VacuumHasAi"] = "vacuum-has-ai";
1116
- /** Robot mower exposes a live mowing map (SVG image child). Gates the
1117
- * mower map tile. */
1118
- DeviceFeature["MowerHasMap"] = "mower-has-map";
1119
- /** Robot mower exposes targeted mowing (all-area / zones / edges /
1120
- * spots) — gates the Mow action + map selectors. */
1121
- DeviceFeature["MowerHasTargetedMowing"] = "mower-has-targeted-mowing";
1122
- return DeviceFeature;
1123
- }({});
1124
- /**
1125
- * Semantic role a device plays within its parent. Populated by driver
1126
- * addons when creating accessory devices (Reolink siren/floodlight/
1127
- * PIR/chime/autotrack/doorbell, ONVIF relay outputs, …). Used by the
1128
- * admin UI to pick icons, labels, and widgets — a `Switch` with
1129
- * `role: Floodlight` renders as a bulb with a brightness slider,
1130
- * whereas a `Switch` with `role: Siren` renders as a klaxon.
1131
- *
1132
- * Undefined for top-level devices (cameras, NVRs, hubs). Persisted in
1133
- * sqlite as a nullable TEXT column — old rows keep working unchanged.
1134
- */
1135
- var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
1136
- DeviceRole["Siren"] = "siren";
1137
- DeviceRole["Floodlight"] = "floodlight";
1138
- DeviceRole["Spotlight"] = "spotlight";
1139
- DeviceRole["PirSensor"] = "pir-sensor";
1140
- DeviceRole["Chime"] = "chime";
1141
- DeviceRole["Autotrack"] = "autotrack";
1142
- DeviceRole["Nightvision"] = "nightvision";
1143
- DeviceRole["PrivacyMask"] = "privacy-mask";
1144
- DeviceRole["Doorbell"] = "doorbell";
1145
- /** Interior blind / shade / roller blind. HA `device_class: blind|shade`. */
1146
- DeviceRole["CoverBlind"] = "cover-blind";
1147
- /** Exterior roller shutter. HA `device_class: shutter`; Homematic BROLL. */
1148
- DeviceRole["CoverShutter"] = "cover-shutter";
1149
- /** Exterior awning. HA `device_class: awning`. */
1150
- DeviceRole["CoverAwning"] = "cover-awning";
1151
- /** Curtain / drape. HA `device_class: curtain`. */
1152
- DeviceRole["CoverCurtain"] = "cover-curtain";
1153
- /** Garage door. HA `device_class: garage`. A security actuator: exports gate it. */
1154
- DeviceRole["CoverGarage"] = "cover-garage";
1155
- /** Gate. HA `device_class: gate`. A security actuator: exports gate it. */
1156
- DeviceRole["CoverGate"] = "cover-gate";
1157
- /** Door. HA `device_class: door`. A security actuator: exports gate it. */
1158
- DeviceRole["CoverDoor"] = "cover-door";
1159
- /** Window. HA `device_class: window`. */
1160
- DeviceRole["CoverWindow"] = "cover-window";
1161
- /** Virtual HA toggle (input_boolean.*) — distinguishable from a
1162
- * real Switch device for UI rendering / export adapters. */
1163
- DeviceRole["BinaryHelper"] = "binary-helper";
1164
- /** A smart plug: a `switch` whose source says it is an outlet (HA
1165
- * `device_class: outlet`). The Alexa export shows it as a SMARTPLUG. */
1166
- DeviceRole["Outlet"] = "outlet";
1167
- /** Generic motion / occupancy / moving event source. Distinct from
1168
- * the camera accessory PirSensor role: that one is a camera child;
1169
- * this is a standalone HA / 3rd-party motion sensor. */
1170
- DeviceRole["MotionSensor"] = "motion-sensor";
1171
- DeviceRole["ContactSensor"] = "contact-sensor";
1172
- DeviceRole["LeakSensor"] = "leak-sensor";
1173
- DeviceRole["SmokeSensor"] = "smoke-sensor";
1174
- DeviceRole["COSensor"] = "co-sensor";
1175
- DeviceRole["GasSensor"] = "gas-sensor";
1176
- DeviceRole["TamperSensor"] = "tamper-sensor";
1177
- DeviceRole["VibrationSensor"] = "vibration-sensor";
1178
- DeviceRole["ConnectivitySensor"] = "connectivity-sensor";
1179
- DeviceRole["SoundSensor"] = "sound-sensor";
1180
- /** Fallback for `binary_sensor` without a known `device_class`. */
1181
- DeviceRole["BinarySensor"] = "binary-sensor";
1182
- DeviceRole["TemperatureSensor"] = "temperature-sensor";
1183
- DeviceRole["HumiditySensor"] = "humidity-sensor";
1184
- DeviceRole["AmbientLightSensor"] = "ambient-light-sensor";
1185
- DeviceRole["PressureSensor"] = "pressure-sensor";
1186
- /** Wind speed or direction (weather-station `wind-sensor` cap). */
1187
- DeviceRole["WindSensor"] = "wind-sensor";
1188
- /** Rain accumulation or rate (weather-station `rain-sensor` cap). */
1189
- DeviceRole["RainSensor"] = "rain-sensor";
1190
- /** UV index (weather-station `uv-sensor` cap). */
1191
- DeviceRole["UvSensor"] = "uv-sensor";
1192
- /** Solar irradiance W/m² (weather-station `solar-radiation-sensor` cap).
1193
- * Distinct from AmbientLightSensor (lux). */
1194
- DeviceRole["SolarRadiationSensor"] = "solar-radiation-sensor";
1195
- /** Soil moisture % (garden/weather `soil-moisture-sensor` cap). */
1196
- DeviceRole["SoilMoistureSensor"] = "soil-moisture-sensor";
1197
- DeviceRole["PowerSensor"] = "power-sensor";
1198
- DeviceRole["EnergySensor"] = "energy-sensor";
1199
- DeviceRole["VoltageSensor"] = "voltage-sensor";
1200
- DeviceRole["CurrentSensor"] = "current-sensor";
1201
- DeviceRole["AirQualitySensor"] = "air-quality-sensor";
1202
- /** Battery level (numeric % via `sensor` OR low-bool via
1203
- * `binary_sensor` — the cap distinguishes via the value type). */
1204
- DeviceRole["BatterySensor"] = "battery-sensor";
1205
- /** Fallback for `sensor` numeric without a known `device_class`. */
1206
- DeviceRole["NumericSensor"] = "numeric-sensor";
1207
- /** String / enum state (HA `sensor` with `state_class: enum` or
1208
- * `attributes.options`). */
1209
- DeviceRole["EnumSensor"] = "enum-sensor";
1210
- /** Date / timestamp state (HA `sensor` with `device_class: timestamp`
1211
- * or `date`). The slice carries the raw ISO string verbatim (hosted on
1212
- * the `enum-sensor` cap); the UI renders it locale-formatted. */
1213
- DeviceRole["DateTimeSensor"] = "datetime-sensor";
1214
- /** Last-resort fallback when nothing else matches. */
1215
- DeviceRole["GenericSensor"] = "generic-sensor";
1216
- DeviceRole["NumericControl"] = "numeric-control";
1217
- DeviceRole["SelectControl"] = "select-control";
1218
- DeviceRole["TextControl"] = "text-control";
1219
- DeviceRole["DateTimeControl"] = "datetime-control";
1220
- /** Mobile push notifier (HA `notify.mobile_app_*`) — supports
1221
- * rich features (image, priority, channel routing). */
1222
- DeviceRole["MobilePushNotifier"] = "mobile-push-notifier";
1223
- /** Chat / messaging service (HA `notify.telegram_*`,
1224
- * `notify.discord_*`, etc.). */
1225
- DeviceRole["MessagingNotifier"] = "messaging-notifier";
1226
- /** Email-based delivery (HA `notify.smtp`, etc.). */
1227
- DeviceRole["EmailNotifier"] = "email-notifier";
1228
- /** Fallback when the notifier service name doesn't match a known
1229
- * pattern. */
1230
- DeviceRole["GenericNotifier"] = "generic-notifier";
1231
- /** Emits a pulse train (infrared or RF) on request — the `ir-transmitter`
1232
- * cap. A `DeviceType.Generic` device. */
1233
- DeviceRole["IrTransmitter"] = "ir-transmitter";
1234
- return DeviceRole;
1235
- }({});
1236
- //#endregion
1237
49
  //#region ../../node_modules/zod/v4/core/core.js
1238
50
  var _a$1;
1239
51
  function $constructor(name, initializer, params) {
@@ -6054,10 +4866,1198 @@ var ZodIssueCode = {
6054
4866
  var ZodFirstPartyTypeKind;
6055
4867
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
6056
4868
  //#endregion
6057
- //#region ../../node_modules/zod/v4/classic/coerce.js
6058
- function number(params) {
6059
- return /* @__PURE__ */ _coercedNumber(ZodNumber, params);
4869
+ //#region ../../node_modules/zod/v4/classic/coerce.js
4870
+ function number(params) {
4871
+ return /* @__PURE__ */ _coercedNumber(ZodNumber, params);
4872
+ }
4873
+ //#endregion
4874
+ //#region ../types/dist/event-category-78tcBemo.mjs
4875
+ var EventCategory = /* @__PURE__ */ function(EventCategory) {
4876
+ EventCategory["SystemBoot"] = "system.boot";
4877
+ EventCategory["SystemAddonsReady"] = "system.addons-ready";
4878
+ EventCategory["SystemRestarting"] = "system.restarting";
4879
+ /**
4880
+ * Fired exactly once after the hub finishes booting following a
4881
+ * restart that was triggered by `RestartCoordinator` (today: framework
4882
+ * live-update). Payload is the marker that was on disk at boot
4883
+ * (`PendingRestartMarkerPayload`); admin UI listens for it to display a
4884
+ * success toast describing what changed.
4885
+ *
4886
+ * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
4887
+ */
4888
+ EventCategory["SystemRestartCompleted"] = "system.restart-completed";
4889
+ /**
4890
+ * The hub reissued its own TLS certificate at boot (`ensureTlsCert`).
4891
+ * Emitted only when the material on disk actually changed, so an
4892
+ * operator who trusted the old certificate by hand is told rather than
4893
+ * discovering it as a browser error. Payload `TlsCertChangedPayload`.
4894
+ *
4895
+ * Rule: docs/decisions/adr-0227-*.md
4896
+ */
4897
+ EventCategory["SystemTlsCertChanged"] = "system.tls-cert-changed";
4898
+ /**
4899
+ * A newer addon or server-root package version was found by the
4900
+ * authoritative registry check. Emitted once when any observed
4901
+ * `latestVersion` changes (or a package/node first appears behind);
4902
+ * the payload carries the full currently-available list. Repeated
4903
+ * polling of the same latests is silent.
4904
+ */
4905
+ EventCategory["UpdateAvailable"] = "update.available";
4906
+ /**
4907
+ * Readiness transition for a capability provider. Every producer emits
4908
+ * this event on `onInitialize` completion, `onDestroy`, and
4909
+ * `$node.reconnect`; every consumer that needs to gate on a cross-process
4910
+ * cap subscribes via the kernel's readiness module (`awaitReady` /
4911
+ * `onReadyState`) instead of polling. Payload is
4912
+ * `SystemReadyStatePayload` — see event-bus.ts.
4913
+ */
4914
+ EventCategory["SystemReadyState"] = "system.ready-state";
4915
+ EventCategory["AddonStarted"] = "addon.started";
4916
+ EventCategory["AddonStopped"] = "addon.stopped";
4917
+ EventCategory["AddonRestarted"] = "addon.restarted";
4918
+ EventCategory["AddonUpdated"] = "addon.updated";
4919
+ EventCategory["AddonInstalled"] = "addon.installed";
4920
+ EventCategory["AddonUninstalled"] = "addon.uninstalled";
4921
+ EventCategory["AddonCrashed"] = "addon.crashed";
4922
+ /**
4923
+ * A RUNNER the D6 crash circuit-breaker gave up on — terminal.
4924
+ *
4925
+ * `AddonCrashed` is the routine, self-healing fact ("it crashed; it is being
4926
+ * respawned"); this is the one that never resolves itself. Emitted exactly
4927
+ * once per trip, by `process-service.ts`, carrying the node, the runner, the
4928
+ * addons it hosted and the crash count that tripped the breaker.
4929
+ *
4930
+ * It exists because a runner marked terminally `failed` used to be SILENT:
4931
+ * on 2026-08-18 the `recorder` runner died of three unhandled ffmpeg spawn
4932
+ * errors, the breaker stopped respawning it (correctly), `/health` kept
4933
+ * returning 200, and fleet-wide recording was gone for 3h15 before the
4934
+ * operator's phone told him. The Notification Center's system-event intake
4935
+ * consumes this category and maps it to the `addon-crash-loop` kind.
4936
+ */
4937
+ EventCategory["AddonRunnerFailed"] = "addon.runner-failed";
4938
+ /**
4939
+ * A runner whose addon refused to start with a typed reason (D877) - parked
4940
+ * in `refused`, never counted by the crash breaker, retried on operator
4941
+ * action. One event per refusal.
4942
+ */
4943
+ EventCategory["AddonRunnerRefused"] = "addon.runner-refused";
4944
+ /**
4945
+ * A runner settled on a state (D877): `running` (READY), `crashed`, `failed` or
4946
+ * `refused`. In-process telemetry for the boot check (re-evaluate while any
4947
+ * runner is still pending) and the alert centre (close a recovered runner).
4948
+ */
4949
+ EventCategory["ProcessStateChanged"] = "process.state-changed";
4950
+ /**
4951
+ * The node's one-shot runner boot check (D877): planned runners against the
4952
+ * process service, `degraded` when any is failed, refused or missing. The
4953
+ * alert centre turns it into one critical alert.
4954
+ */
4955
+ EventCategory["SystemRunnerCheck"] = "system.runner-check";
4956
+ /**
4957
+ * An alert EPISODE opened or closed, emitted by the alert centre for alerts
4958
+ * of severity `critical` or `error` (`AlertEpisodePayload`). The alert
4959
+ * centre sends no notification of its own: Notification Center turns this
4960
+ * into the `alert-critical` / `alert-error` / `alert-critical-resolved`
4961
+ * system-event kinds, and reconciles from the alerts store because a bus
4962
+ * event may be dropped (D8, D11).
4963
+ */
4964
+ EventCategory["AlertEpisode"] = "alert.episode";
4965
+ EventCategory["AddonError"] = "addon.error";
4966
+ EventCategory["AddonPageReady"] = "addon.page-ready";
4967
+ EventCategory["AddonWidgetReady"] = "addon.widget-ready";
4968
+ /**
4969
+ * Addon failed to load (import or initialize). Emitted by the kernel's
4970
+ * AddonHealthMonitor only AFTER the boot grace period ends — failures
4971
+ * during the first 5 minutes are silently retried without alerting
4972
+ * (slow-starting addons must have time to come up). Post-grace, this
4973
+ * event is emitted exactly once per failure-streak; AlertCenter
4974
+ * consumes it to create a persistent operator-visible alert.
4975
+ *
4976
+ * Payload: `{ packageName, addonId?, error: { message, stack }, retryCount, nextRetryAt }`.
4977
+ */
4978
+ EventCategory["AddonLoadFailed"] = "addon.load-failed";
4979
+ /**
4980
+ * A keychain value was stored or removed (D787). Carries the ref, its
4981
+ * owner and the new version — NEVER the value. A process holding the ref
4982
+ * drops its cached copy and the owning `BaseAddon` re-resolves its config.
4983
+ * Telemetry (D8): a process that misses it still revalidates by version.
4984
+ */
4985
+ EventCategory["KeychainChanged"] = "keychain.changed";
4986
+ /**
4987
+ * Addon recovered from a previous failure. Emitted when an addon
4988
+ * transitions from `failed` back to `healthy` (typically via the
4989
+ * monitor's auto-retry loop, or after manual `addons.retryLoad`).
4990
+ * AlertCenter dismisses the corresponding `AddonLoadFailed` alert
4991
+ * on this event.
4992
+ */
4993
+ EventCategory["AddonLoadRecovered"] = "addon.load-recovered";
4994
+ /**
4995
+ * An addon is RUNNING although its installed package is below what the
4996
+ * running server requires (`camstack.requires.addons` of the server, or the
4997
+ * addon's own `requires.server`). Raised once per streak by the unsupported-
4998
+ * addon tracker, on the hub and on agents; AlertCenter turns it into one
4999
+ * operator alert per node and package. The addon is never held back for it.
5000
+ *
5001
+ * Payload: `{ packageName, addonId, nodeId, installedVersion, requiredMinimum, serverVersion, unmet }`.
5002
+ */
5003
+ EventCategory["AddonUnsupportedVersion"] = "addon.unsupported-version";
5004
+ /**
5005
+ * The package of an {@link AddonUnsupportedVersion} alert reached a supported
5006
+ * version, or is no longer installed on the node. AlertCenter dismisses the matching alert.
5007
+ *
5008
+ * Payload: `{ packageName, addonId, nodeId }`.
5009
+ */
5010
+ EventCategory["AddonUnsupportedResolved"] = "addon.unsupported-resolved";
5011
+ /**
5012
+ * Monitor scheduled the next retry for a failed addon. Transient —
5013
+ * surfaced to the UI for live-updating the "next retry in Ns"
5014
+ * countdown on the Addons page row, NOT persisted as an alert.
5015
+ */
5016
+ EventCategory["AddonRetryScheduled"] = "addon.retry-scheduled";
5017
+ /**
5018
+ * A liveness invariant of this node is false — it has no devices, every
5019
+ * camera is offline, or a camera that was recording has stopped producing
5020
+ * segments. Emitted by the `liveness-monitor` builtin, once per fault (the
5021
+ * `findingId` is stable across ticks), only after its boot grace period.
5022
+ * AlertCenter raises a persistent operator-visible alert.
5023
+ *
5024
+ * It exists because on 2026-08-03 the hub ran four hours with zero devices
5025
+ * and zero recordings while every surface stayed quiet.
5026
+ *
5027
+ * Payload: `{ findingId, severity, title, message, deviceId? }`.
5028
+ */
5029
+ EventCategory["SystemLivenessFailed"] = "system.liveness-failed";
5030
+ /**
5031
+ * A previously reported liveness fault is true again. AlertCenter dismisses
5032
+ * the matching `SystemLivenessFailed` alert.
5033
+ *
5034
+ * Payload: `{ findingId }`.
5035
+ */
5036
+ EventCategory["SystemLivenessRecovered"] = "system.liveness-recovered";
5037
+ /**
5038
+ * Monitor is attempting to reload a failed addon NOW. UI uses this
5039
+ * to show a spinner during the retry attempt. Same transient nature
5040
+ * as AddonRetryScheduled.
5041
+ */
5042
+ EventCategory["AddonRetryAttempting"] = "addon.retry-attempting";
5043
+ EventCategory["DeviceRegistered"] = "device.registered";
5044
+ EventCategory["DeviceUnregistered"] = "device.unregistered";
5045
+ EventCategory["DeviceEnabled"] = "device.enabled";
5046
+ EventCategory["DeviceDisabled"] = "device.disabled";
5047
+ EventCategory["DeviceSettingsUpdated"] = "device.settings-updated";
5048
+ /**
5049
+ * Emitted when the set of native capability providers bound to a device
5050
+ * changes — e.g. an addon registers a new native cap via
5051
+ * `DeviceContext.registerNativeCap`, or all native bindings for a device
5052
+ * are cleared on removal. Hub consumers re-resolve device-proxy routes
5053
+ * when this fires.
5054
+ */
5055
+ EventCategory["DeviceBindingsChanged"] = "device.bindings-changed";
5056
+ /**
5057
+ * Emitted when the operator-organisational meta surface changes
5058
+ * (`name` / `location` / `disabled`). Payload: `{deviceId, field,
5059
+ * value}`. Live consumers (UI device list, alert center) react
5060
+ * without polling. Distinct from `DeviceSettingsUpdated` which
5061
+ * fires on hardware-config changes (host/port/credentials/etc).
5062
+ */
5063
+ EventCategory["DeviceMetaChanged"] = "device.meta-changed";
5064
+ /**
5065
+ * Emitted by `BaseDevice.updateSourceInfo()` after a successful patch
5066
+ * to the device's upstream-system identity / rendering envelope. The
5067
+ * full new SourceInfo travels in the payload so cross-process listeners
5068
+ * (UI, export adapters) don't need to re-read the meta blob.
5069
+ *
5070
+ * Payload: `{deviceId, sourceInfo}`.
5071
+ *
5072
+ * Distinct from `DeviceMetaChanged` which covers the operator-edited
5073
+ * surface (`name` / `location` / `disabled`). The two share the
5074
+ * persistence layer (both ride on `device-manager.setMetadata` for
5075
+ * SourceInfo, or `setName`/`setLocation`/`setDisabled` for the meta
5076
+ * fields) but consumers care about different subsets.
5077
+ */
5078
+ EventCategory["DeviceSourceInfoChanged"] = "device.source-info-changed";
5079
+ /**
5080
+ * Emitted by DeviceStreamWiringService after a successful
5081
+ * `stream-broker.registerDeviceStreams` call. Payload includes
5082
+ * deviceId — consumers look up the full registered device info via
5083
+ * `brokerManager.getRegisteredDevice(deviceId)`.
5084
+ *
5085
+ * Replaces the legacy `StreamRouterService.onDeviceRegistered` callback.
5086
+ */
5087
+ EventCategory["DeviceStreamsRegistered"] = "device.streams-registered";
5088
+ /**
5089
+ * Device-level "fully provisioned" signal — the EXPORT trigger. Emitted once
5090
+ * a device's persisted export-relevant shape (its `DeviceFeature` set) is
5091
+ * established or changes, carrying `{deviceId, fingerprint, generation}`.
5092
+ * Export adapters (Alexa / HAP) react to THIS instead of the chatty per-cap
5093
+ * `DeviceBindingsChanged`, turning a boot's incomplete→complete trickle into
5094
+ * one clean delta. `fingerprint` is `canonicalDeviceFingerprint(shape)`.
5095
+ *
5096
+ * Spec: docs/superpowers/specs/2026-06-01-alexa-hap-export-reconciler-design.md
5097
+ */
5098
+ EventCategory["DeviceProvisioned"] = "device.provisioned";
5099
+ /**
5100
+ * Fires once when a device's initial feature-probe completes successfully
5101
+ * (lastProbedAt 0→>0); exported shape is now stable. Telemetry (may be
5102
+ * dropped) — consumers MUST also gate on the device record's `probed` flag.
5103
+ */
5104
+ EventCategory["DeviceReady"] = "device.ready";
5105
+ EventCategory["IntegrationEnabled"] = "integration.enabled";
5106
+ EventCategory["IntegrationDisabled"] = "integration.disabled";
5107
+ EventCategory["IntegrationDeleted"] = "integration.deleted";
5108
+ /** Emitted when a broker connection's status flips (connected /
5109
+ * disconnected / error). Carries `{ brokerId, status, error? }`. */
5110
+ EventCategory["BrokerStatusChanged"] = "broker.status-changed";
5111
+ /** Emitted for every subscription-matched message routed by a
5112
+ * broker provider. Carries `{ brokerId, subscriptionId, key, payload }`.
5113
+ * Consumers filter by `brokerId` + `subscriptionId` in the handler. */
5114
+ EventCategory["BrokerMessage"] = "broker.message";
5115
+ EventCategory["ProviderStarted"] = "provider.started";
5116
+ EventCategory["ProviderStopped"] = "provider.stopped";
5117
+ EventCategory["ProcessCrashed"] = "process.crashed";
5118
+ EventCategory["ProcessRestartScheduled"] = "process.restart_scheduled";
5119
+ EventCategory["ProcessRestarted"] = "process.restarted";
5120
+ /**
5121
+ * The SET of storage locations changed — one was created, edited, enabled,
5122
+ * disabled or deleted through the location instances or the forced-delete action.
5123
+ *
5124
+ * Telemetry, not a transaction (D8/D11): every consumer that re-resolves on
5125
+ * it must also converge on its own periodic path, because a dropped event
5126
+ * must not leave a node writing to yesterday's disk set forever. It exists
5127
+ * because there was NO signal at all — an operator who added a second
5128
+ * recordings disk in the admin UI got nothing, and the recorder kept its
5129
+ * resolved locations until something else happened to re-resolve them
5130
+ * (D387). Payload `StorageLocationsChangedPayload`.
5131
+ */
5132
+ EventCategory["StorageLocationsChanged"] = "storage.locations-changed";
5133
+ EventCategory["RecordingStarted"] = "recording.started";
5134
+ EventCategory["RecordingStopped"] = "recording.stopped";
5135
+ EventCategory["RecordingError"] = "recording.error";
5136
+ EventCategory["RecordingHealthDegraded"] = "recording.health.degraded";
5137
+ /** Recording enabled but no segment finalized for the NC stall window. */
5138
+ EventCategory["RecordingHealthStalled"] = "recording.health.stalled";
5139
+ /** Recovery from {@link RecordingHealthStalled}. */
5140
+ EventCategory["RecordingHealthOk"] = "recording.health.ok";
5141
+ EventCategory["RecordingStorageCritical"] = "recording.storage.critical";
5142
+ /** Free space on a storage location crossed the warn bar. */
5143
+ EventCategory["StorageLocationLow"] = "storage.location.low";
5144
+ /** Free space at/under the critical bar, or capacity probe failed (`null`). */
5145
+ EventCategory["StorageLocationCritical"] = "storage.location.critical";
5146
+ /** Recovery from low/critical on a storage location. */
5147
+ EventCategory["StorageLocationOk"] = "storage.location.ok";
5148
+ EventCategory["RecordingSegmentWritten"] = "recording.segment.written";
5149
+ EventCategory["RecordingPolicyFallback"] = "recording.policy.fallback";
5150
+ EventCategory["RecordingRetentionCompleted"] = "recording.retention.completed";
5151
+ /** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
5152
+ * progress bar the client reconciles via `recordingExport.getExport`. */
5153
+ EventCategory["RecordingExportProgress"] = "recording.export.progress";
5154
+ EventCategory["RecordingExportCompleted"] = "recording.export.completed";
5155
+ EventCategory["RecordingExportFailed"] = "recording.export.failed";
5156
+ EventCategory["DetectionEvent"] = "detection.event";
5157
+ EventCategory["SessionTrackNew"] = "session.track.new";
5158
+ EventCategory["SessionTrackExpired"] = "session.track.expired";
5159
+ EventCategory["BenchmarkProgress"] = "benchmark.progress";
5160
+ EventCategory["PlatformProbePhase"] = "platform-probe.phase";
5161
+ EventCategory["PipelineProgress"] = "pipeline.progress";
5162
+ /** Per-frame execution trace emitted by the pipeline executor for live observability. */
5163
+ EventCategory["PipelineTrace"] = "pipeline.trace";
5164
+ /**
5165
+ * Raw inference output emitted by `addon-pipeline-runner` after running the
5166
+ * detection pipeline on a frame. Carries the `FrameResult` (with
5167
+ * `detections[]`, `width`/`height`, timing debug) — never the frame
5168
+ * buffer itself. Hub-side consumers (analysis pipeline, class filters,
5169
+ * notifications) subscribe to this and re-emit `detection.result` after
5170
+ * post-processing.
5171
+ */
5172
+ EventCategory["PipelineInferenceResult"] = "pipeline.inference-result";
5173
+ /**
5174
+ * Camera lifecycle event emitted by `addon-pipeline-orchestrator` when it
5175
+ * assigns or unassigns a camera to/from an agent. Carries no frame data;
5176
+ * pure observability for UI dashboards and metrics consumers.
5177
+ */
5178
+ EventCategory["PipelineCameraAssigned"] = "pipeline.camera-assigned";
5179
+ EventCategory["PipelineCameraUnassigned"] = "pipeline.camera-unassigned";
5180
+ /**
5181
+ * A node the orchestrator would otherwise place cameras on has NO usable
5182
+ * inference device: the operator enabled one or more accelerators there and
5183
+ * the live probe reports every one of them unavailable. Emitted once per
5184
+ * TRANSITION into that state (never per dispatch), and the node is dropped
5185
+ * from the placement candidate set for as long as it holds.
5186
+ *
5187
+ * This exists because the state was previously invisible: agent-a
5188
+ * absorbed 283k inference errors in a day while still being handed cameras,
5189
+ * and nothing in the system said so.
5190
+ *
5191
+ * A node with no accelerators configured at all is NOT this — its devices
5192
+ * are `disabled`, not `unavailable`, and the runner's default CPU pool
5193
+ * serves it exactly as before.
5194
+ */
5195
+ EventCategory["PipelineNodeInferenceUnavailable"] = "pipeline.node-inference-unavailable";
5196
+ /**
5197
+ * A camera has an OPEN detection session and has produced no detection at
5198
+ * all for longer than the blind threshold — the camera is being decoded and
5199
+ * inferred and is returning nothing. Emitted once per transition into blind,
5200
+ * per camera.
5201
+ *
5202
+ * The failure it reports: a 1h43 detection blackout on the entrance camera
5203
+ * that nobody noticed, because "a camera that detects nothing" and "a quiet
5204
+ * camera" produce byte-identical silence.
5205
+ */
5206
+ EventCategory["PipelineDetectionBlind"] = "pipeline.detection-blind";
5207
+ /**
5208
+ * A camera's motion source has fired constantly with no subject for an hour
5209
+ * (motion duty or session count over the bar, zero detections) — it is not
5210
+ * blind, its motion zones or sensitivity want tuning (D907). Paired with
5211
+ * {@link PipelineMotionCalm}.
5212
+ */
5213
+ EventCategory["PipelineMotionNoisy"] = "pipeline.motion-noisy";
5214
+ /** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
5215
+ EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
5216
+ /**
5217
+ * A camera's package LLM confirm has failed closed three times in a row
5218
+ * (D931, 2026-10-26). One edge per camera until
5219
+ * {@link PipelinePackageLlmAnswered}.
5220
+ */
5221
+ EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
5222
+ /** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
5223
+ EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
5224
+ /**
5225
+ * Per-camera pipeline config was mutated by the orchestrator
5226
+ * (a settings change via `setAgentInferenceDevices` /
5227
+ * `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
5228
+ * subscribes to its own emission to hot-reload the assigned runner
5229
+ * via `attachCamera` so the next frame executes against the new
5230
+ * engine/steps without waiting for a rebalance or the next
5231
+ * `DeviceStreamsRegistered` cycle.
5232
+ */
5233
+ EventCategory["PipelineCameraUpdated"] = "pipeline.camera-updated";
5234
+ /**
5235
+ * The cluster camera-source OWNER changed (`clusterRoles.ingestNode`).
5236
+ * Emitted by addon-pipeline-orchestrator whenever it (re)derives node
5237
+ * capabilities — at boot, on agent online/offline, and on an ingest-node
5238
+ * flip. Carries the resolved `ownerNodeId`. The stream-broker consumes it to
5239
+ * keep its ingest-owner-gate decision current WITHOUT a per-`ensureBroker`
5240
+ * cross-process `getIngestOwner` query (push the authority's decision instead
5241
+ * of polling it on the hot path). Idempotent state — re-emitted on every
5242
+ * topology change, so a dropped event self-heals on the next one (plus the
5243
+ * broker's long backstop reconcile query).
5244
+ */
5245
+ EventCategory["PipelineIngestOwnerChanged"] = "pipeline.ingest-owner-changed";
5246
+ /**
5247
+ * Periodic snapshot of per-node pipeline-runner load
5248
+ * (`RunnerLocalLoad`). Emitted ~1Hz by every runner so UI dashboards
5249
+ * subscribe instead of polling `pipelineRunner.getLocalLoad`.
5250
+ * `nodeId` carried in the payload + on `event.source.nodeId`.
5251
+ */
5252
+ EventCategory["PipelineRunnerLoadSnapshot"] = "pipeline.runner-load-snapshot";
5253
+ /**
5254
+ * Periodic snapshot of per-camera pipeline metrics (`CameraMetrics`
5255
+ * + `deviceId` + `nodeId`). Emitted ~1Hz by every runner for each
5256
+ * attached camera. UI subscribes to drive overlay phase / fps /
5257
+ * inference time without polling `getCameraMetrics`.
5258
+ */
5259
+ EventCategory["PipelineCameraMetricsSnapshot"] = "pipeline.camera-metrics-snapshot";
5260
+ /**
5261
+ * Periodic snapshot of stream-broker per-broker statistics (input
5262
+ * fps, decoded fps, bitrate, codec). Emitted ~1Hz by every
5263
+ * stream-broker process for each active broker so the UI can drive
5264
+ * the Stream / Cluster dashboards without polling
5265
+ * `streamBroker.listAllProfileSlots` and friends.
5266
+ */
5267
+ EventCategory["StreamBrokerMetricsSnapshot"] = "stream-broker.metrics-snapshot";
5268
+ /**
5269
+ * Cap event fired by `stream-broker` when a profile slot enters
5270
+ * "demanded" state — a cam stream has been assigned and at least one
5271
+ * consumer (RTSP restream, decoded subscriber, WebRTC session, …) is
5272
+ * present. Camera-provider addons (Reolink Baichuan push, …)
5273
+ * subscribe to this category to start their underlying transport
5274
+ * lazily. Payload: `{ deviceId, camStreamId, profile }`.
5275
+ */
5276
+ EventCategory["StreamBrokerOnCamStreamDemand"] = "stream-broker.onCamStreamDemand";
5277
+ /**
5278
+ * Cap event fired by `stream-broker` when the last consumer leaves a
5279
+ * previously-demanded cam stream. Providers tear down their
5280
+ * underlying transport on receipt. Payload: `{ deviceId, camStreamId }`.
5281
+ */
5282
+ EventCategory["StreamBrokerOnCamStreamIdle"] = "stream-broker.onCamStreamIdle";
5283
+ /**
5284
+ * Cap event fired by `stream-broker` when a broker fails to dial a
5285
+ * managed-loopback source (today: `pull-rfc4571`) and the publisher
5286
+ * needs to refresh the cached URL. The lib's TCP server idle-tears-down
5287
+ * on its own schedule, so a re-publish with a fresh `host:port` is the
5288
+ * only way to keep the broker dialable. Camera providers (Reolink
5289
+ * Baichuan native, …) subscribe and respond by re-running their publish
5290
+ * pipeline.
5291
+ * Payload: `{ deviceId, camStreamId, brokerId }`.
5292
+ */
5293
+ EventCategory["StreamBrokerOnRequestStreamSourceRefresh"] = "stream-broker.onRequestStreamSourceRefresh";
5294
+ /**
5295
+ * A camera provider changed a device's stream parameters (codec /
5296
+ * resolution / bitrate / a stream added or removed). A LOW-LATENCY NUDGE
5297
+ * for the stream-broker's catalog reconcile: it carries NO authoritative
5298
+ * data — the broker re-PULLS that device's `stream-catalog` cap on receipt
5299
+ * (the 30s reconcile poll is the backstop if this nudge is dropped). Emitted
5300
+ * by providers from `stream-params.setProfile`. Payload: `{ deviceId }`.
5301
+ */
5302
+ EventCategory["StreamParamsChanged"] = "stream-params.changed";
5303
+ /**
5304
+ * Generic per-device runtime-state change. Fired by `device-manager`
5305
+ * whenever a persisted slice in any cap's `runtimeState` shape
5306
+ * mutates. Payload: `{deviceId, capName, slice}`. Subscribers are
5307
+ * the `deviceState` cap router (cross-process listeners) and the
5308
+ * deviceProxy reactive bindings (`device.state.<capName>.value`).
5309
+ * Cap-specific events (`battery.onStatusChanged`, …) still fire
5310
+ * — they're authoritative for callers that want a typed payload
5311
+ * without filtering on `capName`.
5312
+ */
5313
+ EventCategory["DeviceStateChanged"] = "device.state-changed";
5314
+ /**
5315
+ * The NATIVE shadow of a cap a composition has claimed fields of moved
5316
+ * (D663). Payload: `{ deviceId, capName, native }` — what the provider
5317
+ * wrote, BEFORE the owned fields are overlaid. Owner-only (D224): it is for
5318
+ * the composer's native self-reads, and the public event routers refuse it
5319
+ * (`isOwnerOnlyEventCategory`) so no consumer surface ever shows a second
5320
+ * truth beside the merged `DeviceStateChanged.slice`. Emitted only under a
5321
+ * `replace` claim, one per native write of that cap.
5322
+ */
5323
+ EventCategory["DeviceNativeShadowChanged"] = "device.native-shadow-changed";
5324
+ /**
5325
+ * Frame occupancy for a camera CHANGED — a tracked object was gained or
5326
+ * lost. Carries `{ deviceId, totalObjects, byClass, zones }`.
5327
+ *
5328
+ * Emitted only on a change, so a steady scene is silent. It exists so a
5329
+ * client can stop polling `zoneAnalytics.getCurrentSnapshot`: that was the
5330
+ * one live badge with no push signal at all, and it cost a request every
5331
+ * four seconds per visible camera.
5332
+ *
5333
+ * Like every event it is telemetry and may be dropped ([D8]) — a consumer
5334
+ * keeps a slow reconcile rather than trusting it alone.
5335
+ */
5336
+ EventCategory["ZoneAnalyticsOccupancyChanged"] = "zone-analytics.occupancy-changed";
5337
+ /**
5338
+ * Cap event fired by every device that registers the `battery`
5339
+ * capability. Mirrors the cap definition's `onStatusChanged`. Carries
5340
+ * `{ deviceId, status: BatteryStatus }`. Subscribers (alert center,
5341
+ * snapshot wrapper, UI) react to charge/sleep transitions without
5342
+ * polling `batteryCapability.getStatus`.
5343
+ */
5344
+ EventCategory["BatteryOnStatusChanged"] = "battery.onStatusChanged";
5345
+ /**
5346
+ * Cap event fired by every device that registers the `network-link`
5347
+ * capability. Mirrors the cap definition's `onStatusChanged`. Carries
5348
+ * `{ deviceId, status: NetworkLinkStatus }` — a link switch or a signal
5349
+ * reading that moved.
5350
+ */
5351
+ EventCategory["NetworkLinkOnStatusChanged"] = "network-link.onStatusChanged";
5352
+ /**
5353
+ * Emitted by the battery cap provider WHEN `wakeForStream` enters the
5354
+ * "wake in progress" window — between the Baichuan wake-up issue and
5355
+ * the camera's first dialed-back RTP packet. The stream-broker
5356
+ * manager subscribes to flip the per-broker placeholder reason to
5357
+ * `'waking'` so viewers see a labelled "WAKING UP" tile instead of
5358
+ * the generic `'reconnecting'` frame. Carries `{ deviceId }`. The
5359
+ * complementary "wake complete" signal is the existing
5360
+ * `BatteryOnStatusChanged { sleeping: false }` event.
5361
+ */
5362
+ EventCategory["BatteryOnWakeStarted"] = "battery.onWakeStarted";
5363
+ /**
5364
+ * Cap event fired by every device that registers the `doorbell`
5365
+ * capability. Mirrors `doorbellCapability.events.onPressed`. Carries
5366
+ * `{ deviceId, timestamp }`. Operators consuming the UI subscribe
5367
+ * here to render transient ring toasts and a "Recent presses" row
5368
+ * on the device detail page.
5369
+ */
5370
+ EventCategory["DoorbellOnPressed"] = "doorbell.onPressed";
5371
+ /** Mirrors `runningStateCapability.events.onStarted`. */
5372
+ EventCategory["RunningStarted"] = "running.started";
5373
+ /** Mirrors `runningStateCapability.events.onFinished`. */
5374
+ EventCategory["RunningFinished"] = "running.finished";
5375
+ /** Mirrors `deviceRunsCapability.events.onRunOpened` - a durable run record opened. */
5376
+ EventCategory["DeviceRunOpened"] = "device-run.opened";
5377
+ /** Mirrors `deviceRunsCapability.events.onRunClosed` - a durable run record closed. */
5378
+ EventCategory["DeviceRunClosed"] = "device-run.closed";
5379
+ /**
5380
+ * Cap event fired by every device that registers the `event-emitter`
5381
+ * capability. Mirrors `eventEmitterCapability.events.onEvent`. Carries
5382
+ * `{ deviceId, eventType, data, timestamp, seq }` — the device's EXACT
5383
+ * declared event verbatim (NO normalization). Subscribers (UI event
5384
+ * stream, advanced-notifier rules) react to fired events without
5385
+ * holding a cap reference.
5386
+ */
5387
+ EventCategory["EventEmitted"] = "event-emitter.event";
5388
+ /**
5389
+ * Periodic snapshot of the per-node detection-pipeline engine
5390
+ * registry (loaded engines, models resident, in-use cameras, idle
5391
+ * TTL). Emitted ~0.2Hz (every 5 s) by every detection-pipeline
5392
+ * process. The Engines tab subscribes to drive its inventory view
5393
+ * without polling `pipelineExecutor.listLoadedEngines`.
5394
+ */
5395
+ EventCategory["PipelineEngineMetricsSnapshot"] = "pipeline.engine-metrics-snapshot";
5396
+ /**
5397
+ * Per-node detection-engine runtime-provisioning transition. Emitted by
5398
+ * the detection-pipeline provider on every state change of its lazy
5399
+ * engine-provisioning machine (idle → installing → verifying → ready,
5400
+ * or → failed with a `nextRetryAt`). Payload is the
5401
+ * `EngineProvisioningState` snapshot; `event.source.nodeId` carries the
5402
+ * node. The Pipeline page subscribes to drive a live "installing
5403
+ * OpenVINO… / ready" indicator per node without polling
5404
+ * `pipelineExecutor.getEngineProvisioning`. Telemetry-grade (D8): the UI
5405
+ * also reads the cap snapshot on mount / reconnect. Phase 2.
5406
+ */
5407
+ EventCategory["PipelineEngineProvisioning"] = "pipeline.engine-provisioning";
5408
+ /**
5409
+ * Cluster topology snapshot. Carries the same payload returned by
5410
+ * `nodes.topology` (every reachable node + addons + processes).
5411
+ * Emitted by the hub on any agent / addon lifecycle change
5412
+ * (debounced) plus a periodic safety net. Replaces UI polling on
5413
+ * `nodes.topology` — admin-ui dashboards subscribe to drive the
5414
+ * cluster view directly from the event payload.
5415
+ */
5416
+ EventCategory["ClusterTopologySnapshot"] = "cluster.topology-snapshot";
5417
+ /**
5418
+ * Periodic per-node system metrics snapshot (CPU / memory / GPU /
5419
+ * disk / network). Emitted ~0.2 Hz by the metrics-provider addon
5420
+ * for each node. Drives the dashboard SystemStatus / ProcessResources
5421
+ * widgets without polling `metricsProvider.getCurrent`.
5422
+ */
5423
+ EventCategory["MetricsNodeResourcesSnapshot"] = "metrics.node-resources-snapshot";
5424
+ /**
5425
+ * Periodic per-node process-tree snapshot (camstack-related pids
5426
+ * with root / managed / system classification). Emitted ~0.2 Hz by
5427
+ * the metrics-provider addon. Drives the Cluster → Processes tab
5428
+ * without polling `metricsProvider.listNodeProcesses`.
5429
+ */
5430
+ EventCategory["MetricsNodeProcessesSnapshot"] = "metrics.node-processes-snapshot";
5431
+ /**
5432
+ * Capability binding change event emitted by `addon-pipeline-orchestrator`
5433
+ * when a user changes which addon implements a cap on a node. Subscribed
5434
+ * by every kernel process to update its local `preferredProviderRegistry`
5435
+ * so future capability lookups respect the new binding.
5436
+ */
5437
+ /**
5438
+ * A capability binding was changed for a node — addon X now provides
5439
+ * capability `cap` on node `nodeId`. Lives under the generic
5440
+ * `capability.*` namespace because capability bindings are a kernel-
5441
+ * level concept used by many addons, not strictly pipeline-scoped.
5442
+ */
5443
+ EventCategory["CapabilityBindingChanged"] = "capability.binding-changed";
5444
+ EventCategory["ModelDownloadProgress"] = "model.download.progress";
5445
+ EventCategory["AgentRegistered"] = "agent.registered";
5446
+ EventCategory["AgentUnregistered"] = "agent.unregistered";
5447
+ EventCategory["AgentOnline"] = "agent.online";
5448
+ EventCategory["AgentOffline"] = "agent.offline";
5449
+ /** Forked worker process (e.g. hub/pipeline) connected to the broker. */
5450
+ EventCategory["WorkerOnline"] = "worker.online";
5451
+ /** Forked worker process disconnected from the broker. */
5452
+ EventCategory["WorkerOffline"] = "worker.offline";
5453
+ EventCategory["AgentTaskDispatched"] = "agent.task.dispatched";
5454
+ EventCategory["AgentTaskAssigned"] = "agent.task.assigned";
5455
+ EventCategory["AgentTrpcConnected"] = "agent.trpc.connected";
5456
+ EventCategory["AgentWsConnected"] = "agent.ws.connected";
5457
+ EventCategory["AgentWsDisconnected"] = "agent.ws.disconnected";
5458
+ EventCategory["AgentBackupActivated"] = "agent.backup.activated";
5459
+ EventCategory["OrchestrationSettingsUpdated"] = "orchestration.settings-updated";
5460
+ EventCategory["MotionAnalysis"] = "detection.motion-analysis";
5461
+ /** All raw motion zones from CCL before minArea filter — for UI debug overlay. */
5462
+ EventCategory["MotionZonesRaw"] = "detection.motion-zones-raw";
5463
+ /**
5464
+ * Per-camera motion phase transition (`watching ↔ active`) emitted
5465
+ * by the runner. Mirrors the `motion.onMotionChanged` cap event
5466
+ * surface — payload `MotionOnMotionChangedPayload` carries
5467
+ * `{deviceId, detected, timestamp, source, regions?}`. Subscribers
5468
+ * include addons that need to react to motion state without
5469
+ * polling the runtime-state mirror.
5470
+ */
5471
+ EventCategory["MotionOnMotionChanged"] = "motion.on-motion-changed";
5472
+ EventCategory["DetectionResult"] = "detection.result";
5473
+ EventCategory["DetectionRaw"] = "detection.raw";
5474
+ EventCategory["DetectionCameraNative"] = "detection.camera-native";
5475
+ /**
5476
+ * Canonical per-chunk live audio pipeline output. Payload is
5477
+ * `PipelineAudioInferenceResultPayload` carrying a full `AudioResult`
5478
+ * (level + detections + debug). Lives on the pipeline.* namespace
5479
+ * alongside `pipeline.inference-result` (video) for symmetry.
5480
+ */
5481
+ EventCategory["PipelineAudioInferenceResult"] = "pipeline.audio-inference-result";
5482
+ EventCategory["DetectionPhaseTransition"] = "detection.phase-transition";
5483
+ /**
5484
+ * A camera provider's RAW onboard motion push (D673): the `MotionOnMotionChanged`
5485
+ * data shape without `triggeredBy`, built by `providerMotionEvent`. Its one
5486
+ * consumer is the orchestrator's camera-sensors bridge, which re-emits the
5487
+ * camera's EFFECTIVE onboard motion as `MotionOnMotionChanged` (a pass-through
5488
+ * for a camera with no attached sensor). Providers must not emit
5489
+ * `MotionOnMotionChanged` themselves; `scripts/check-onboard-motion-emitters.ts`
5490
+ * keeps it so (camera-grid is a named, deferred exception).
5491
+ */
5492
+ EventCategory["ProviderMotion"] = "provider.motion";
5493
+ EventCategory["ProviderDetection"] = "provider.detection";
5494
+ EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
5495
+ EventCategory["EnrichmentSceneStateChanged"] = "enrichment.scene.state-changed";
5496
+ EventCategory["EnrichmentActivitySummary"] = "enrichment.activity.summary";
5497
+ /**
5498
+ * Unified track-lifecycle event: ONE category carrying `phase:
5499
+ * 'start' | 'update' | 'end'` with a rich, typed
5500
+ * `PipelineAnalyticsTrackLifecyclePayload`. Supersedes the thin
5501
+ * `PipelineAnalyticsTrackStarted` / `PipelineAnalyticsTrackEnded`
5502
+ * pair — a consumer subscribes once and branches on `phase`.
5503
+ */
5504
+ EventCategory["PipelineAnalyticsTrackLifecycle"] = "pipeline-analytics.track-lifecycle";
5505
+ /**
5506
+ * @deprecated Superseded by {@link PipelineAnalyticsTrackLifecycle}
5507
+ * (`phase:'start'`). Kept as a soft alias — no known subscribers.
5508
+ */
5509
+ EventCategory["PipelineAnalyticsTrackStarted"] = "pipeline-analytics.track-started";
5510
+ /**
5511
+ * @deprecated Superseded by {@link PipelineAnalyticsTrackLifecycle}
5512
+ * (`phase:'end'`). Kept as a soft alias — no known subscribers.
5513
+ */
5514
+ EventCategory["PipelineAnalyticsTrackEnded"] = "pipeline-analytics.track-ended";
5515
+ EventCategory["PipelineAnalyticsDetectionEvent"] = "pipeline-analytics.detection-event";
5516
+ EventCategory["PipelineAnalyticsFrameTracked"] = "pipeline-analytics.frame-tracked";
5517
+ /**
5518
+ * Fired by `addon-post-analysis` when a parked (stationary) object appears
5519
+ * (a track was promoted to a stationary-registry entry) or departs (the
5520
+ * object moved / was removed). Telemetry (D8): lossy, drives a UI refresh of
5521
+ * the dedicated "Stationary" section — never the live event feed. Payload:
5522
+ * `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp, observedAt, zones }`.
5523
+ */
5524
+ EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
5525
+ /**
5526
+ * Fired by `addon-post-analysis` when a package-drop is confirmed inside
5527
+ * a package zone — a newly-appeared stationary object of a package class
5528
+ * that cleared the class / zone / dwell / size gates. Payload:
5529
+ * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
5530
+ * entryId, className, zoneIds, keyFrameMediaId?, bbox, timestamp }`.
5531
+ * Telemetry (D8): the durable record is the `package-events` store row;
5532
+ * this bus topic drives notifier rules + live UI. See
5533
+ * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
5534
+ */
5535
+ EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
5536
+ /**
5537
+ * Fired by `addon-post-analysis` when a previously-delivered package
5538
+ * leaves its zone (the stationary entry departed — moved or swept).
5539
+ * Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
5540
+ * `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
5541
+ * Telemetry (D8). See package-zones-design §5.2.
5542
+ */
5543
+ EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
5544
+ /**
5545
+ * Fired by `addon-post-analysis` whenever a gallery face row changes:
5546
+ * `kind:'buffered'` a new detected face was persisted, `'assigned'` /
5547
+ * `'unassigned'` its identity link changed, `'deleted'` the row was
5548
+ * removed. Telemetry semantics (D8): a lost event only delays a refresh,
5549
+ * never a correctness issue. Payload `PipelineAnalyticsFaceGalleryChangedPayload`.
5550
+ */
5551
+ EventCategory["PipelineAnalyticsFaceGalleryChanged"] = "pipeline-analytics.face-gallery-changed";
5552
+ /**
5553
+ * Fired by `addon-post-analysis` whenever a gallery plate row changes:
5554
+ * `kind:'buffered'` a new read was persisted (`PlateRecognizer.onTrackEnd`),
5555
+ * `'assigned'` / `'unassigned'` its vehicle link changed
5556
+ * (`PlateGalleryProvider`), `'deleted'` the row was removed. Telemetry
5557
+ * semantics (D8): a lost event only delays a refresh, never a correctness
5558
+ * issue. Payload `PipelineAnalyticsPlateGalleryChangedPayload`.
5559
+ */
5560
+ EventCategory["PipelineAnalyticsPlateGalleryChanged"] = "pipeline-analytics.plate-gallery-changed";
5561
+ EventCategory["CameraStreamsProfileSlotsChanged"] = "camera-streams.onProfileSlotsChanged";
5562
+ /**
5563
+ * Stream-broker health watchdog. Per-broker (deviceId/profile) emission.
5564
+ * `stream.offline` fires after STREAM_STALE_TIMEOUT_MS without an encoded
5565
+ * packet on an active broker. `stream.online` fires on first packet
5566
+ * after a stale gap (or on initial first packet). Payload includes
5567
+ * the assigned camStreamId as `profileKey`.
5568
+ */
5569
+ EventCategory["StreamOnline"] = "stream.online";
5570
+ EventCategory["StreamOffline"] = "stream.offline";
5571
+ EventCategory["NetworkTunnelStarted"] = "network.tunnel.started";
5572
+ EventCategory["NetworkTunnelStopped"] = "network.tunnel.stopped";
5573
+ /** Fired by the `local-network` cap when the host's interface set
5574
+ * changes (new IP from DHCP, VPN connect, docker bridge added). */
5575
+ EventCategory["LocalNetworkChanged"] = "network.local.changed";
5576
+ /**
5577
+ * Fired by a `mesh-network` provider (Tailscale, …) when its
5578
+ * mesh-reachable host changes (join / leave / MagicDNS or 100.x IP
5579
+ * change). Lets `local-network` fold the mesh endpoint into its
5580
+ * connection-endpoint list without a cross-package import. Payload
5581
+ * carries the preferred host (`host: ''` = no longer reachable),
5582
+ * the hub port, and the scheme. Telemetry-grade (D8): consumers
5583
+ * pull-reconcile from the provider's `getStatus` on reconnect. */
5584
+ EventCategory["MeshNetworkChanged"] = "network.mesh.changed";
5585
+ EventCategory["BackupCompleted"] = "backup.completed";
5586
+ /**
5587
+ * A whole backup RUN finished — every destination attempted, win or lose.
5588
+ *
5589
+ * `backup.completed` fires once per DESTINATION, which is the right grain for
5590
+ * a progress UI and the wrong one for a notification: an operator with three
5591
+ * destinations would be told three times. And a run where two of three
5592
+ * destinations succeeded is not a clean success — a single "backup
5593
+ * completed" that hid the failed one would be a lie, so the count of each is
5594
+ * carried here and the message says both.
5595
+ *
5596
+ * Emitted by the backup orchestrator only after the destination loop, so a
5597
+ * run that dies during the BUILD phase produces no completion at all.
5598
+ */
5599
+ EventCategory["BackupRunCompleted"] = "backup.run-completed";
5600
+ EventCategory["BackupRestored"] = "backup.restored";
5601
+ EventCategory["NotificationDispatched"] = "notification.dispatched";
5602
+ EventCategory["NotificationFailed"] = "notification.failed";
5603
+ /**
5604
+ * A notification rule that cannot work (D905): its stored row does not load,
5605
+ * or it still names a device / delivery target the prune CONFIRMED deleted.
5606
+ * One edge per rule per distinct set of reasons; never on an unanswered read.
5607
+ */
5608
+ EventCategory["NotificationRuleBroken"] = "notification.rule-broken";
5609
+ /** The clear of {@link NotificationRuleBroken}: the rule loads and names nothing deleted. */
5610
+ EventCategory["NotificationRuleRepaired"] = "notification.rule-repaired";
5611
+ /** A migration failed or was blocked; the Alert Center re-reads the ledger. */
5612
+ EventCategory["MigrationFailed"] = "migration.failed";
5613
+ /** A migration applied or a failure cleared; the Alert Center re-reads the ledger. */
5614
+ EventCategory["MigrationApplied"] = "migration.applied";
5615
+ EventCategory["DeviceUpdated"] = "device.updated";
5616
+ /**
5617
+ * Transport-level connectivity. Emitted by the device driver when
5618
+ * the underlying control socket actually connects / disconnects
5619
+ * (Baichuan TCP, ONVIF probe response, RTSP DESCRIBE, …) — NOT for
5620
+ * power-state transitions on a battery camera. For battery wake /
5621
+ * doze cycles see `DeviceAwake` / `DeviceSleeping`.
5622
+ */
5623
+ EventCategory["DeviceOnline"] = "device.online";
5624
+ /**
5625
+ * Stream-broker watchdog — emitted when no encoded packet has been
5626
+ * received for STREAM_STALE_TIMEOUT_MS on an active broker (rtsp or
5627
+ * push). Paired with DeviceOnline which fires on first packet after
5628
+ * a stale gap. Payload: DeviceStreamHealthPayload.
5629
+ */
5630
+ EventCategory["DeviceOffline"] = "device.offline";
5631
+ /**
5632
+ * Battery cam woke up — physical power-state transition reported
5633
+ * by the device firmware. Distinct from `DeviceOnline` so a UI panel
5634
+ * watching power state doesn't flap on every UDP socket reconnect.
5635
+ */
5636
+ EventCategory["DeviceAwake"] = "device.awake";
5637
+ /**
5638
+ * Battery cam went to sleep. See `DeviceAwake`.
5639
+ */
5640
+ EventCategory["DeviceSleeping"] = "device.sleeping";
5641
+ EventCategory["RetentionCleanup"] = "retention.cleanup";
5642
+ /**
5643
+ * Legacy bulk-update progress snapshot (payload `BulkUpdateState`). No longer
5644
+ * emitted — F3 removed the coordinator that produced it; "Update all" now runs
5645
+ * as one lifecycle engine job (`AddonsJobProgress`/`AddonsJobLog`). Retained
5646
+ * (with `BulkUpdateState`) only to avoid regenerating the event maps; removed
5647
+ * in F4 once live bulk progress is re-implemented over the engine events.
5648
+ */
5649
+ EventCategory["AddonsBulkUpdateProgress"] = "addons.bulk-update-progress";
5650
+ EventCategory["AddonsJobProgress"] = "addons.job-progress";
5651
+ EventCategory["AddonsJobLog"] = "addons.job-log";
5652
+ /**
5653
+ * A container's child visibility toggled (hidden/shown). Emitted by the
5654
+ * `accessories` cap when a child device is hidden or revealed.
5655
+ * Payload: `{ deviceId, childDeviceId, hidden }`.
5656
+ */
5657
+ EventCategory["AccessoriesChildVisibilityChanged"] = "accessories.onChildVisibilityChanged";
5658
+ /**
5659
+ * A container's child set changed (children added/removed/reordered).
5660
+ * Payload: `{ deviceId, childDeviceIds, hiddenChildIds }`.
5661
+ */
5662
+ EventCategory["AccessoriesChanged"] = "accessories.onAccessoriesChanged";
5663
+ /**
5664
+ * An action run started or ended. Emitted by the `actions` surface.
5665
+ * Payload: `ActionRunChanged` (`{ actionId, runId, isRunning, outcome?, lastRunAt, lastError }`).
5666
+ */
5667
+ EventCategory["ActionsRunChanged"] = "actions.onRunChanged";
5668
+ /**
5669
+ * Progress update from a running model conversion job.
5670
+ * Payload: `{ kind: 'model-convert', phase, sessionId?, pct?, detail? }`.
5671
+ * Emitted by `addon-model-studio` on the converting node.
5672
+ */
5673
+ EventCategory["ModelConvertProgress"] = "model-convert.progress";
5674
+ return EventCategory;
5675
+ }({});
5676
+ //#endregion
5677
+ //#region ../types/dist/device-type-D1fH5kaC.mjs
5678
+ /**
5679
+ import { errMsg } from '@camstack/types'
5680
+ * Extract a human-readable message from an unknown error value.
5681
+ * Replaces the ubiquitous `errMsg(err)` pattern.
5682
+ */
5683
+ function errMsg(err) {
5684
+ if (err instanceof Error) return err.message;
5685
+ if (typeof err === "string") return err;
5686
+ return String(err);
6060
5687
  }
5688
+ var DeviceType = /* @__PURE__ */ function(DeviceType) {
5689
+ DeviceType["Camera"] = "camera";
5690
+ DeviceType["Hub"] = "hub";
5691
+ DeviceType["Light"] = "light";
5692
+ DeviceType["Siren"] = "siren";
5693
+ DeviceType["Switch"] = "switch";
5694
+ DeviceType["Sensor"] = "sensor";
5695
+ DeviceType["Thermostat"] = "thermostat";
5696
+ /** Air-conditioner / heat-pump climate device (HVAC) — shares the
5697
+ * `climate-control` cap surface with `Thermostat` but renders a
5698
+ * dedicated AC-appropriate control UI (mode chips, fan speed,
5699
+ * independent vertical/horizontal swing). Sources: native Gree, and
5700
+ * reusable by other AC integrations. */
5701
+ DeviceType["Climate"] = "climate";
5702
+ DeviceType["Button"] = "button";
5703
+ /** Generic stateless event emitter — carries a device's EXACT declared
5704
+ * event vocabulary verbatim (no normalization). Installed with the
5705
+ * `event-emitter` cap. Sources: HA `event.*` entities (structured) and
5706
+ * HA bus events (e.g. `zha_event`, generic). */
5707
+ DeviceType["EventEmitter"] = "event-emitter";
5708
+ /** Firmware/software update entity — current vs available version,
5709
+ * updatable flag, update state, and an install action. Installed with
5710
+ * the `update` cap. Sources: Homematic firmware-update channels (and
5711
+ * reusable by other providers, e.g. HA `update.*` entities). */
5712
+ DeviceType["Update"] = "update";
5713
+ DeviceType["Generic"] = "generic";
5714
+ /** Generic notification delivery target (HA `notify.<service>`, future
5715
+ * Telegram / Discord / ntfy / SMTP, …). One device per delivery
5716
+ * endpoint; the `notifier` cap defines the send surface. */
5717
+ DeviceType["Notifier"] = "notifier";
5718
+ /** Pre-recorded action sequence with optional parameters
5719
+ * (HA `script.*`). Runnable via `script-runner` cap. */
5720
+ DeviceType["Script"] = "script";
5721
+ /** Automation rule (HA `automation.*`) — enable/disable + manual
5722
+ * trigger surface exposed via `automation-control` cap. */
5723
+ DeviceType["Automation"] = "automation";
5724
+ /** Door / smart lock device (HA `lock.*`). `lock-control` cap. */
5725
+ DeviceType["Lock"] = "lock";
5726
+ /** Window covering, blinds, garage door, valve, etc. (HA `cover.*`,
5727
+ * `valve.*`). `cover` cap with sub-roles for variant. */
5728
+ DeviceType["Cover"] = "cover";
5729
+ /** Pipe / water / gas valve with open/close/stop and optional
5730
+ * position (HA `valve.*`). `valve` cap — a cover-sibling actuator
5731
+ * modelled on the same open/closed lifecycle. */
5732
+ DeviceType["Valve"] = "valve";
5733
+ /** Humidifier / dehumidifier with on/off + target humidity + mode
5734
+ * (HA `humidifier.*`). `humidifier` cap — a climate-family actuator
5735
+ * modelled on the same target / mode lifecycle. */
5736
+ DeviceType["Humidifier"] = "humidifier";
5737
+ /** Water heater / boiler with target temperature + operation mode +
5738
+ * away mode (HA `water_heater.*`). `water-heater` cap — a
5739
+ * climate-family actuator. */
5740
+ DeviceType["WaterHeater"] = "water-heater";
5741
+ /** Ceiling / standing / exhaust fan (HA `fan.*`). `fan-control` cap. */
5742
+ DeviceType["Fan"] = "fan";
5743
+ /** Audio / video playback endpoint (HA `media_player.*`). Disjoint from
5744
+ * the camera surface — those use `Camera`. `media-player` cap. */
5745
+ DeviceType["MediaPlayer"] = "media-player";
5746
+ /** Security panel / alarm system (HA `alarm_control_panel.*`).
5747
+ * `alarm-panel` cap. */
5748
+ DeviceType["AlarmPanel"] = "alarm-panel";
5749
+ /** Generic user-settable input (HA `number` / `input_number` / `select`
5750
+ * / `input_select` / `text` / `input_text` / `input_datetime`).
5751
+ * Sub-type via `DeviceRole`: NumericControl / SelectControl /
5752
+ * TextControl / DateTimeControl. */
5753
+ DeviceType["Control"] = "control";
5754
+ /** Person / device-tracker presence (HA `person.*`, `device_tracker.*`).
5755
+ * `presence` cap. */
5756
+ DeviceType["Presence"] = "presence";
5757
+ /** Weather provider (HA `weather.*`). Tier-3, low MVP priority.
5758
+ * `weather` cap. */
5759
+ DeviceType["Weather"] = "weather";
5760
+ /** Robot vacuum (HA `vacuum.*`). Tier-3. `vacuum-control` cap. */
5761
+ DeviceType["Vacuum"] = "vacuum";
5762
+ /** Robotic lawn mower (HA `lawn_mower.*`). Tier-3.
5763
+ * `lawn-mower-control` cap. */
5764
+ DeviceType["LawnMower"] = "lawn-mower";
5765
+ /** Physical HA device group — parent container for entity-children
5766
+ * adopted from a single HA device entry. Not renderable as a
5767
+ * standalone device; exists only to anchor child entities. */
5768
+ DeviceType["Container"] = "container";
5769
+ /** Single still-image entity (HA `image.*`). Read-only display of an
5770
+ * `entity_picture` signed URL the browser loads directly. `image` cap. */
5771
+ DeviceType["Image"] = "image";
5772
+ /** Smart pet feeder — cloud-connected food dispenser with a bowl food
5773
+ * level, battery, desiccant life, feeding state and manual-feed /
5774
+ * call-pet / maintenance actions. Installed with the `pet-feeder` cap;
5775
+ * dual-hopper models (D4S/D4SH) expose per-hopper portions. Sources:
5776
+ * native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
5777
+ * integrations sharing the same food/desiccant/hopper surface. */
5778
+ DeviceType["PetFeeder"] = "pet-feeder";
5779
+ /** Pet water fountain — tank level, water drunk, pump and its duty cycle.
5780
+ * Installed with the `pet-fountain` cap. Reaches CamStack as loose entities
5781
+ * of a container and is BUILT as a composed device (D967). */
5782
+ DeviceType["PetFountain"] = "pet-fountain";
5783
+ /** Built-in dishwasher — program lifecycle, door / remote-start gates,
5784
+ * salt and rinse-aid levels. Installed with the `dishwasher` cap.
5785
+ * Sources: native Bosch Home Connect, reusable by similar integrations.
5786
+ * A plug-built dishwasher carries running-state and power instead. */
5787
+ DeviceType["Dishwasher"] = "dishwasher";
5788
+ /** Washing machine. A plug-built one is running while its power stays
5789
+ * above a threshold. No program cap — that surface is the dishwasher's. */
5790
+ DeviceType["Washer"] = "washer";
5791
+ /** A dumb plug-in stove or heater: a switch (and, with a meter, a power
5792
+ * reading) that only runs while the plug is on. Built from a smart plug;
5793
+ * the `timed-run` cap switches it off again after a chosen time. */
5794
+ DeviceType["Heater"] = "heater";
5795
+ /** Tumble dryer. Same plug-built running surface as {@link Washer}. */
5796
+ DeviceType["Dryer"] = "dryer";
5797
+ /** The physical bridge box of a vendor ecosystem (Velux KLF-200, and later
5798
+ * other radio-to-IP bridges). It carries the box's own facts (firmware,
5799
+ * address, connection state) and the actions the box really supports
5800
+ * (`reboot`, `device-admin-link`). Products are NOT its children — they are
5801
+ * adopted beside it — and its connection settings stay on the integration. */
5802
+ DeviceType["Gateway"] = "gateway";
5803
+ return DeviceType;
5804
+ }({});
5805
+ var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
5806
+ DeviceFeature["BatteryOperated"] = "battery-operated";
5807
+ DeviceFeature["Rebootable"] = "rebootable";
5808
+ /**
5809
+ * Device supports an on-demand re-sync of its derived spec with its
5810
+ * upstream source — drives the generic Re-sync button. The owning
5811
+ * provider implements the action via the `device-adoption.resync` cap.
5812
+ */
5813
+ DeviceFeature["Resyncable"] = "resyncable";
5814
+ DeviceFeature["NativeSnapshot"] = "native-snapshot";
5815
+ DeviceFeature["DoorbellButton"] = "doorbell-button";
5816
+ DeviceFeature["TwoWayAudio"] = "two-way-audio";
5817
+ DeviceFeature["PanTiltZoom"] = "pan-tilt-zoom";
5818
+ /**
5819
+ * Camera supports the on-firmware autotrack subsystem (subject-
5820
+ * following). Distinct from `PanTiltZoom` because not every PTZ
5821
+ * camera ships autotrack — the admin UI uses this flag to gate
5822
+ * the autotrack toggle / settings card without re-deriving from
5823
+ * the cap registry. Mirrors `ptz-autotrack` cap registration:
5824
+ * driver sets this feature when probe confirms the firmware
5825
+ * surface, and registers the cap in the same code path.
5826
+ */
5827
+ DeviceFeature["PtzAutotrack"] = "ptz-autotrack";
5828
+ /**
5829
+ * Accessory exposes a "trigger on motion" toggle — the parent camera's
5830
+ * motion detection automatically activates this device. Mirrors
5831
+ * `motion-trigger` cap registration: drivers set this feature in the
5832
+ * same code path that calls `ctx.registerNativeCap(motionTriggerCapability, ...)`.
5833
+ *
5834
+ * Used by admin UI (gate the in-hero `MotionTriggerToggle` against a
5835
+ * fast scalar without binding fetch), notifier rules, and `listAll`
5836
+ * filters that want "all devices with on-motion behaviour".
5837
+ */
5838
+ DeviceFeature["MotionTrigger"] = "motion-trigger";
5839
+ /** Light supports rgb-triplet color via `color` cap. */
5840
+ DeviceFeature["LightColorRgb"] = "light-color-rgb";
5841
+ /** Light supports HSV color via `color` cap. */
5842
+ DeviceFeature["LightColorHsv"] = "light-color-hsv";
5843
+ /** Light supports color-temperature (mired) via `color` cap. */
5844
+ DeviceFeature["LightColorMired"] = "light-color-mired";
5845
+ /** Thermostat supports a `heat_cool` dual setpoint (targetLow +
5846
+ * targetHigh). Gates the range slider UI. */
5847
+ DeviceFeature["ClimateDualSetpoint"] = "climate-dual-setpoint";
5848
+ /** Thermostat exposes target humidity and/or current humidity
5849
+ * readings. Gates the humidity controls. */
5850
+ DeviceFeature["ClimateHumidity"] = "climate-humidity";
5851
+ /** Thermostat exposes a fan-mode selector. */
5852
+ DeviceFeature["ClimateFanMode"] = "climate-fan-mode";
5853
+ /** Thermostat exposes preset modes (eco / away / sleep / vendor). */
5854
+ DeviceFeature["ClimatePreset"] = "climate-preset";
5855
+ /** Thermostat exposes a vertical louver swing toggle. Gates the
5856
+ * vertical-swing switch in the climate UI. Independent of horizontal. */
5857
+ DeviceFeature["ClimateSwingVertical"] = "climate-swing-vertical";
5858
+ /** Thermostat exposes a horizontal louver swing toggle. Gates the
5859
+ * horizontal-swing switch in the climate UI. Independent of vertical. */
5860
+ DeviceFeature["ClimateSwingHorizontal"] = "climate-swing-horizontal";
5861
+ /** Cover exposes intermediate position control (0..100). Gates the
5862
+ * position slider UI. */
5863
+ DeviceFeature["CoverPositionable"] = "cover-positionable";
5864
+ /** Cover exposes slat-tilt control. Gates the tilt slider UI. */
5865
+ DeviceFeature["CoverTilt"] = "cover-tilt";
5866
+ /** Cover has a real stop: `stop` halts the travel in place. Gates the stop
5867
+ * control in exporters; a provider whose `stop` is a no-op never declares it. */
5868
+ DeviceFeature["CoverStoppable"] = "cover-stoppable";
5869
+ /** Valve exposes intermediate position control (0..100). Gates the
5870
+ * position slider / drag surface UI. */
5871
+ DeviceFeature["ValvePositionable"] = "valve-positionable";
5872
+ /** Fan exposes a speed-percentage setter. Gates the speed slider UI. */
5873
+ DeviceFeature["FanSpeed"] = "fan-speed";
5874
+ /** Fan exposes a preset mode selector. */
5875
+ DeviceFeature["FanPreset"] = "fan-preset";
5876
+ /** Fan exposes blade direction (forward/reverse) — typical of
5877
+ * ceiling fans. */
5878
+ DeviceFeature["FanDirection"] = "fan-direction";
5879
+ /** Fan exposes an oscillation toggle. */
5880
+ DeviceFeature["FanOscillating"] = "fan-oscillating";
5881
+ /** Lock requires a PIN code on lock/unlock. Gates the code-entry
5882
+ * field on the UI lock-controls panel. */
5883
+ DeviceFeature["LockPinRequired"] = "lock-pin-required";
5884
+ /** Lock supports a latch-release ("open door") action distinct from
5885
+ * unlock. Mirrors HA `LockEntityFeature.OPEN` (bit 1) in
5886
+ * `supported_features`. Gates the Open Door button in the UI. */
5887
+ DeviceFeature["LockOpen"] = "lock-open";
5888
+ /** Media player exposes a seek-to-position surface. */
5889
+ DeviceFeature["MediaPlayerSeek"] = "media-player-seek";
5890
+ /** Media player exposes a volume-level setter. */
5891
+ DeviceFeature["MediaPlayerVolume"] = "media-player-volume";
5892
+ /** Media player exposes a mute toggle distinct from volume=0. */
5893
+ DeviceFeature["MediaPlayerMute"] = "media-player-mute";
5894
+ /** Media player exposes a shuffle toggle. */
5895
+ DeviceFeature["MediaPlayerShuffle"] = "media-player-shuffle";
5896
+ /** Media player exposes a repeat mode (off / all / one). */
5897
+ DeviceFeature["MediaPlayerRepeat"] = "media-player-repeat";
5898
+ /** Media player exposes a source / input selector. */
5899
+ DeviceFeature["MediaPlayerSelectSource"] = "media-player-select-source";
5900
+ /** Media player exposes a play-arbitrary-media surface (URL / id). */
5901
+ DeviceFeature["MediaPlayerPlayMedia"] = "media-player-play-media";
5902
+ /** Media player exposes next-track. */
5903
+ DeviceFeature["MediaPlayerNext"] = "media-player-next";
5904
+ /** Media player exposes previous-track. */
5905
+ DeviceFeature["MediaPlayerPrevious"] = "media-player-previous";
5906
+ /** Media player exposes stop distinct from pause. */
5907
+ DeviceFeature["MediaPlayerStop"] = "media-player-stop";
5908
+ /** Media player exposes volume up / down in steps (an infrared TV has no level). */
5909
+ DeviceFeature["MediaPlayerVolumeStep"] = "media-player-volume-step";
5910
+ /** Media player exposes channel up / down in steps. */
5911
+ DeviceFeature["MediaPlayerChannelStep"] = "media-player-channel-step";
5912
+ /** Media player exposes power on / off. */
5913
+ DeviceFeature["MediaPlayerPower"] = "media-player-power";
5914
+ /** Alarm panel requires a PIN code on arm/disarm. */
5915
+ DeviceFeature["AlarmPinRequired"] = "alarm-pin-required";
5916
+ /** Presence device carries GPS coordinates (lat/lng/accuracy) in
5917
+ * addition to a textual location. */
5918
+ DeviceFeature["PresenceGps"] = "presence-gps";
5919
+ /** Notifier accepts an inline / URL image attachment. */
5920
+ DeviceFeature["NotifierImage"] = "notifier-image";
5921
+ /** Notifier accepts a priority hint (high/normal/low). */
5922
+ DeviceFeature["NotifierPriority"] = "notifier-priority";
5923
+ /** Notifier accepts a free-form `data` payload for platform-specific
5924
+ * fields. */
5925
+ DeviceFeature["NotifierData"] = "notifier-data";
5926
+ /** Notifier supports interactive action buttons / callbacks. */
5927
+ DeviceFeature["NotifierActions"] = "notifier-actions";
5928
+ /** Notifier supports per-call recipient targeting (multi-user). */
5929
+ DeviceFeature["NotifierRecipients"] = "notifier-recipients";
5930
+ /** Script runner accepts a variables map on each run invocation. */
5931
+ DeviceFeature["ScriptVariables"] = "script-variables";
5932
+ /** Automation `trigger` accepts a skipCondition flag — fires the
5933
+ * automation's actions while bypassing its condition block. */
5934
+ DeviceFeature["AutomationSkipCondition"] = "automation-skip-condition";
5935
+ /** Robot vacuum exposes a live cleaning map (image child). Gates the
5936
+ * map tile in the vacuum UI. */
5937
+ DeviceFeature["VacuumHasMap"] = "vacuum-has-map";
5938
+ /** Robot vacuum exposes AI obstacle-detection toggles. Gates the AI
5939
+ * switches group. */
5940
+ DeviceFeature["VacuumHasAi"] = "vacuum-has-ai";
5941
+ /** Robot mower exposes a live mowing map (SVG image child). Gates the
5942
+ * mower map tile. */
5943
+ DeviceFeature["MowerHasMap"] = "mower-has-map";
5944
+ /** Robot mower exposes targeted mowing (all-area / zones / edges /
5945
+ * spots) — gates the Mow action + map selectors. */
5946
+ DeviceFeature["MowerHasTargetedMowing"] = "mower-has-targeted-mowing";
5947
+ return DeviceFeature;
5948
+ }({});
5949
+ /**
5950
+ * Semantic role a device plays within its parent. Populated by driver
5951
+ * addons when creating accessory devices (Reolink siren/floodlight/
5952
+ * PIR/chime/autotrack/doorbell, ONVIF relay outputs, …). Used by the
5953
+ * admin UI to pick icons, labels, and widgets — a `Switch` with
5954
+ * `role: Floodlight` renders as a bulb with a brightness slider,
5955
+ * whereas a `Switch` with `role: Siren` renders as a klaxon.
5956
+ *
5957
+ * Undefined for top-level devices (cameras, NVRs, hubs). Persisted in
5958
+ * sqlite as a nullable TEXT column — old rows keep working unchanged.
5959
+ */
5960
+ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
5961
+ DeviceRole["Siren"] = "siren";
5962
+ DeviceRole["Floodlight"] = "floodlight";
5963
+ DeviceRole["Spotlight"] = "spotlight";
5964
+ DeviceRole["PirSensor"] = "pir-sensor";
5965
+ DeviceRole["Chime"] = "chime";
5966
+ DeviceRole["Autotrack"] = "autotrack";
5967
+ DeviceRole["Nightvision"] = "nightvision";
5968
+ DeviceRole["PrivacyMask"] = "privacy-mask";
5969
+ DeviceRole["Doorbell"] = "doorbell";
5970
+ /** Interior blind / shade / roller blind. HA `device_class: blind|shade`. */
5971
+ DeviceRole["CoverBlind"] = "cover-blind";
5972
+ /** Exterior roller shutter. HA `device_class: shutter`; Homematic BROLL. */
5973
+ DeviceRole["CoverShutter"] = "cover-shutter";
5974
+ /** Exterior awning. HA `device_class: awning`. */
5975
+ DeviceRole["CoverAwning"] = "cover-awning";
5976
+ /** Curtain / drape. HA `device_class: curtain`. */
5977
+ DeviceRole["CoverCurtain"] = "cover-curtain";
5978
+ /** Garage door. HA `device_class: garage`. A security actuator: exports gate it. */
5979
+ DeviceRole["CoverGarage"] = "cover-garage";
5980
+ /** Gate. HA `device_class: gate`. A security actuator: exports gate it. */
5981
+ DeviceRole["CoverGate"] = "cover-gate";
5982
+ /** Door. HA `device_class: door`. A security actuator: exports gate it. */
5983
+ DeviceRole["CoverDoor"] = "cover-door";
5984
+ /** Window. HA `device_class: window`. */
5985
+ DeviceRole["CoverWindow"] = "cover-window";
5986
+ /** Virtual HA toggle (input_boolean.*) — distinguishable from a
5987
+ * real Switch device for UI rendering / export adapters. */
5988
+ DeviceRole["BinaryHelper"] = "binary-helper";
5989
+ /** A smart plug: a `switch` whose source says it is an outlet (HA
5990
+ * `device_class: outlet`). The Alexa export shows it as a SMARTPLUG. */
5991
+ DeviceRole["Outlet"] = "outlet";
5992
+ /** Generic motion / occupancy / moving event source. Distinct from
5993
+ * the camera accessory PirSensor role: that one is a camera child;
5994
+ * this is a standalone HA / 3rd-party motion sensor. */
5995
+ DeviceRole["MotionSensor"] = "motion-sensor";
5996
+ DeviceRole["ContactSensor"] = "contact-sensor";
5997
+ DeviceRole["LeakSensor"] = "leak-sensor";
5998
+ DeviceRole["SmokeSensor"] = "smoke-sensor";
5999
+ DeviceRole["COSensor"] = "co-sensor";
6000
+ DeviceRole["GasSensor"] = "gas-sensor";
6001
+ DeviceRole["TamperSensor"] = "tamper-sensor";
6002
+ DeviceRole["VibrationSensor"] = "vibration-sensor";
6003
+ DeviceRole["ConnectivitySensor"] = "connectivity-sensor";
6004
+ DeviceRole["SoundSensor"] = "sound-sensor";
6005
+ /** Fallback for `binary_sensor` without a known `device_class`. */
6006
+ DeviceRole["BinarySensor"] = "binary-sensor";
6007
+ DeviceRole["TemperatureSensor"] = "temperature-sensor";
6008
+ DeviceRole["HumiditySensor"] = "humidity-sensor";
6009
+ DeviceRole["AmbientLightSensor"] = "ambient-light-sensor";
6010
+ DeviceRole["PressureSensor"] = "pressure-sensor";
6011
+ /** Wind speed or direction (weather-station `wind-sensor` cap). */
6012
+ DeviceRole["WindSensor"] = "wind-sensor";
6013
+ /** Rain accumulation or rate (weather-station `rain-sensor` cap). */
6014
+ DeviceRole["RainSensor"] = "rain-sensor";
6015
+ /** UV index (weather-station `uv-sensor` cap). */
6016
+ DeviceRole["UvSensor"] = "uv-sensor";
6017
+ /** Solar irradiance W/m² (weather-station `solar-radiation-sensor` cap).
6018
+ * Distinct from AmbientLightSensor (lux). */
6019
+ DeviceRole["SolarRadiationSensor"] = "solar-radiation-sensor";
6020
+ /** Soil moisture % (garden/weather `soil-moisture-sensor` cap). */
6021
+ DeviceRole["SoilMoistureSensor"] = "soil-moisture-sensor";
6022
+ DeviceRole["PowerSensor"] = "power-sensor";
6023
+ DeviceRole["EnergySensor"] = "energy-sensor";
6024
+ DeviceRole["VoltageSensor"] = "voltage-sensor";
6025
+ DeviceRole["CurrentSensor"] = "current-sensor";
6026
+ DeviceRole["AirQualitySensor"] = "air-quality-sensor";
6027
+ /** Battery level (numeric % via `sensor` OR low-bool via
6028
+ * `binary_sensor` — the cap distinguishes via the value type). */
6029
+ DeviceRole["BatterySensor"] = "battery-sensor";
6030
+ /** Fallback for `sensor` numeric without a known `device_class`. */
6031
+ DeviceRole["NumericSensor"] = "numeric-sensor";
6032
+ /** String / enum state (HA `sensor` with `state_class: enum` or
6033
+ * `attributes.options`). */
6034
+ DeviceRole["EnumSensor"] = "enum-sensor";
6035
+ /** Date / timestamp state (HA `sensor` with `device_class: timestamp`
6036
+ * or `date`). The slice carries the raw ISO string verbatim (hosted on
6037
+ * the `enum-sensor` cap); the UI renders it locale-formatted. */
6038
+ DeviceRole["DateTimeSensor"] = "datetime-sensor";
6039
+ /** Last-resort fallback when nothing else matches. */
6040
+ DeviceRole["GenericSensor"] = "generic-sensor";
6041
+ DeviceRole["NumericControl"] = "numeric-control";
6042
+ DeviceRole["SelectControl"] = "select-control";
6043
+ DeviceRole["TextControl"] = "text-control";
6044
+ DeviceRole["DateTimeControl"] = "datetime-control";
6045
+ /** Mobile push notifier (HA `notify.mobile_app_*`) — supports
6046
+ * rich features (image, priority, channel routing). */
6047
+ DeviceRole["MobilePushNotifier"] = "mobile-push-notifier";
6048
+ /** Chat / messaging service (HA `notify.telegram_*`,
6049
+ * `notify.discord_*`, etc.). */
6050
+ DeviceRole["MessagingNotifier"] = "messaging-notifier";
6051
+ /** Email-based delivery (HA `notify.smtp`, etc.). */
6052
+ DeviceRole["EmailNotifier"] = "email-notifier";
6053
+ /** Fallback when the notifier service name doesn't match a known
6054
+ * pattern. */
6055
+ DeviceRole["GenericNotifier"] = "generic-notifier";
6056
+ /** Emits a pulse train (infrared or RF) on request — the `ir-transmitter`
6057
+ * cap. A `DeviceType.Generic` device. */
6058
+ DeviceRole["IrTransmitter"] = "ir-transmitter";
6059
+ return DeviceRole;
6060
+ }({});
6061
6061
  //#endregion
6062
6062
  //#region ../types/dist/sleep-CQP-REJp.mjs
6063
6063
  /**
@@ -6813,7 +6813,7 @@ function switchRecordsOverMigrationApi(api) {
6813
6813
  };
6814
6814
  } };
6815
6815
  }
6816
- function integrationRowsApiOver(api) {
6816
+ function integrationRowsApiOver$1(api) {
6817
6817
  return {
6818
6818
  list: async () => (await api.integrations.list({})).integrations,
6819
6819
  readLegacyIntegrationRows: (input) => api.legacyRows.read(input),
@@ -8645,7 +8645,7 @@ var BaseAddon = class {
8645
8645
  seq: 1e3,
8646
8646
  initialBody: spec.initialBody
8647
8647
  })], (a) => registrySwitchPortsOver({
8648
- api: integrationRowsApiOver(a),
8648
+ api: integrationRowsApiOver$1(a),
8649
8649
  records: switchRecordsOverMigrationApi(a),
8650
8650
  kind: spec.kind
8651
8651
  })).bind(api);
@@ -16242,20 +16242,6 @@ async function flattenNestedRecords(ports, spec) {
16242
16242
  summary: { converted: rows.size }
16243
16243
  };
16244
16244
  }
16245
- /** The ports over one kind's records handle. */
16246
- function flattenPortsOver(handle) {
16247
- return {
16248
- listNested: async (legacyKey) => (await handle.query({ limit: 1e3 })).records.filter((r) => legacyKey in r.data).map((r) => r.id),
16249
- readResolved: async (id) => {
16250
- const row = await handle.getResolved(id);
16251
- if (row === null) throw new Error("the record is gone");
16252
- return row.data;
16253
- },
16254
- patch: async (id, patch) => {
16255
- await handle.patch(id, patch);
16256
- }
16257
- };
16258
- }
16259
16245
  /**
16260
16246
  * The addon-side ports of `moveIntegrationRowsToRecords` (planning#416). An addon runs the move
16261
16247
  * from its own process, so the leftover rows are reached through the migration-only door
@@ -16303,25 +16289,6 @@ function integrationRowsPortsOverApi(deps) {
16303
16289
  }
16304
16290
  };
16305
16291
  }
16306
- function defaultIntegrationApiOver(api) {
16307
- return {
16308
- list: () => api.integrations.list.query(),
16309
- readLegacyIntegrationRows: (input) => api.migrations.readLegacyIntegrationRows.query(input),
16310
- clearLegacyIntegrationRows: (input) => api.migrations.clearLegacyIntegrationRows.mutate(input),
16311
- listDevices: (addonId) => api.deviceManager.listAll.query({
16312
- addonId,
16313
- projection: "slim"
16314
- }),
16315
- setDeviceIntegrationId: async (deviceId, integrationId) => {
16316
- await api.deviceManager.setIntegrationId.mutate({
16317
- deviceId,
16318
- integrationId
16319
- });
16320
- },
16321
- readDeviceHasConfig: async (deviceId) => Object.keys((await api.deviceManager.getDevice.query({ deviceId }))?.config ?? {}).length > 0,
16322
- readDeviceIntegrationId: async (deviceId) => (await api.deviceManager.getDevice.query({ deviceId }))?.integrationId ?? null
16323
- };
16324
- }
16325
16292
  /**
16326
16293
  * The trainer contract — what the hub hands the cloud trainer and what it
16327
16294
  * gets back (cloud training, D805+).
@@ -98944,7 +98911,6 @@ function buildLinkedInstances(records, spec) {
98944
98911
  });
98945
98912
  return instances;
98946
98913
  }
98947
- var BROKER_ROWS_MAX = 1e3;
98948
98914
  var STRAY_REGISTRY_ID = /^int_\d+$/;
98949
98915
  async function moveBrokerLinksToConnections(ports) {
98950
98916
  const brokers = await ports.listBrokers();
@@ -98976,36 +98942,6 @@ async function moveBrokerLinksToConnections(ports) {
98976
98942
  }
98977
98943
  };
98978
98944
  }
98979
- /** The ports over the two record kinds of the addon. */
98980
- function brokerLinkPortsOver(deps) {
98981
- return {
98982
- warn: deps.warn,
98983
- listBrokers: async () => {
98984
- return (await deps.brokers.query({ limit: BROKER_ROWS_MAX })).records.map((row) => {
98985
- const name = row.data["name"];
98986
- const link = row.data["integrationId"];
98987
- return {
98988
- id: row.id,
98989
- name: typeof name === "string" && name.length > 0 ? name : row.id,
98990
- integrationId: typeof link === "string" ? link : void 0
98991
- };
98992
- });
98993
- },
98994
- readConnection: async (id) => {
98995
- const row = await deps.connections.get(id);
98996
- return row === null ? null : { brokerId: row.data.brokerId };
98997
- },
98998
- putConnection: async (id, body) => {
98999
- await deps.connections.put({
99000
- id,
99001
- data: body
99002
- }, { ifRev: 0 });
99003
- },
99004
- clearBrokerLink: async (brokerId) => {
99005
- await deps.brokers.patch(brokerId, { integrationId: null });
99006
- }
99007
- };
99008
- }
99009
98945
  //#endregion
99010
98946
  //#region src/speak/constants.ts
99011
98947
  /** Echo speech limits and the worker restart bound (same window as CrashSupervisor). */
@@ -145962,7 +145898,7 @@ function echoTargetStoreOver(records, options = {}) {
145962
145898
  /** The `echoTargets` setting as the legacy source: a row the migration left there is still served. */
145963
145899
  function legacyEchoTargetsOver(setting) {
145964
145900
  return {
145965
- list: async () => readEchoTargets({ echoTargets: setting.readRows() }).map((row) => ({
145901
+ list: async () => readEchoTargets({ echoTargets: await setting.readRows() }).map((row) => ({
145966
145902
  id: row.id,
145967
145903
  name: row.name,
145968
145904
  kind: alexaTargetKind().kind,
@@ -145974,11 +145910,12 @@ function legacyEchoTargetsOver(setting) {
145974
145910
  }
145975
145911
  })),
145976
145912
  delete: async (id) => {
145977
- const rest = setting.readRows().filter((row) => {
145913
+ const rows = await setting.readRows();
145914
+ const rest = rows.filter((row) => {
145978
145915
  const parsed = alexaEchoTargetSchema.safeParse(row);
145979
145916
  return !(parsed.success && parsed.data.id === id);
145980
145917
  });
145981
- if (rest.length !== setting.readRows().length) await setting.writeRows(rest);
145918
+ if (rest.length !== rows.length) await setting.writeRows(rest);
145982
145919
  }
145983
145920
  };
145984
145921
  }
@@ -145995,8 +145932,9 @@ function echoRowOf(target) {
145995
145932
  }
145996
145933
  /** The migration's ports over the `notify-alexa-echo` record kind. */
145997
145934
  function echoRecordPortsOver(records, logger) {
145998
- const handle = echoTargetStoreOver(records).handlesByKind().get(alexaTargetKind().kind);
145999
- if (handle === void 0) throw new Error("import-alexa: the Echo target record kind is not declared");
145935
+ const [kind] = Object.values(alexaNotifyRecordKinds);
145936
+ if (kind === void 0) throw new Error("import-alexa: the Echo target record kind is not declared");
145937
+ const handle = records.kind(kind);
146000
145938
  return {
146001
145939
  readEchoRecord: async (id) => (await handle.getResolved(id))?.data ?? null,
146002
145940
  writeEchoRecord: async (id, body) => {
@@ -147081,17 +147019,42 @@ async function flattenBrokerRecords(ports) {
147081
147019
  //#endregion
147082
147020
  //#region src/migrations/broker-links-to-connections.ts
147083
147021
  var BROKER_LINKS_TO_CONNECTIONS_ID = "import-alexa/2026-11-05-broker-links-to-connections";
147022
+ var BROKER_ROWS_MAX = 1e3;
147084
147023
  /** The broker records and the integration (`connections`) records of this addon. */
147085
147024
  function alexaBrokerLinkPorts(records, warn) {
147086
- return brokerLinkPortsOver({
147087
- brokers: records.kind({
147088
- name: alexaBrokersEntryKind.name,
147089
- declaration: alexaBrokersEntryKind.declaration,
147090
- schema: record(string(), unknown())
147091
- }),
147092
- connections: records.kind(alexaConnectionsEntryKind),
147093
- warn
147025
+ const brokers = records.kind({
147026
+ name: alexaBrokersEntryKind.name,
147027
+ declaration: alexaBrokersEntryKind.declaration,
147028
+ schema: record(string(), unknown())
147094
147029
  });
147030
+ const connections = records.kind(alexaConnectionsEntryKind);
147031
+ return {
147032
+ warn,
147033
+ listBrokers: async () => {
147034
+ return (await brokers.query({ limit: BROKER_ROWS_MAX })).records.map((row) => {
147035
+ const name = row.data["name"];
147036
+ const link = row.data["integrationId"];
147037
+ return {
147038
+ id: row.id,
147039
+ name: typeof name === "string" && name.length > 0 ? name : row.id,
147040
+ integrationId: typeof link === "string" ? link : void 0
147041
+ };
147042
+ });
147043
+ },
147044
+ readConnection: async (id) => {
147045
+ const row = await connections.get(id);
147046
+ return row === null ? null : { brokerId: row.data.brokerId };
147047
+ },
147048
+ putConnection: async (id, body) => {
147049
+ await connections.put({
147050
+ id,
147051
+ data: body
147052
+ }, { ifRev: 0 });
147053
+ },
147054
+ clearBrokerLink: async (brokerId) => {
147055
+ await brokers.patch(brokerId, { integrationId: null });
147056
+ }
147057
+ };
147095
147058
  }
147096
147059
  //#endregion
147097
147060
  //#region src/migrations/strip-echo-target-volume-and-mode.ts
@@ -147107,7 +147070,7 @@ function strippedRow(row) {
147107
147070
  return Object.fromEntries(Object.entries(row).filter(([key]) => !RETIRED_KEYS.includes(key)));
147108
147071
  }
147109
147072
  async function stripEchoTargetVolumeAndMode(ports) {
147110
- const rows = ports.readRows();
147073
+ const rows = await ports.readRows();
147111
147074
  const stripped = rows.filter(carriesRetiredKey).length;
147112
147075
  if (stripped === 0) return {
147113
147076
  outcome: "already-done",
@@ -147140,7 +147103,7 @@ async function stripEchoTargetVolumeAndMode(ports) {
147140
147103
  */
147141
147104
  var ECHO_TARGETS_TO_RECORDS_ID = "import-alexa/2026-11-06-echo-targets-to-records";
147142
147105
  async function moveEchoTargetsToRecords(ports) {
147143
- const rows = ports.readRows();
147106
+ const rows = await ports.readRows();
147144
147107
  if (rows.length === 0) return {
147145
147108
  outcome: "already-done",
147146
147109
  summary: { converted: 0 }
@@ -147291,6 +147254,118 @@ var BROKER_RECORD_MIGRATION_IDS = [
147291
147254
  BROKER_LINKS_TO_CONNECTIONS_ID
147292
147255
  ];
147293
147256
  //#endregion
147257
+ //#region src/migrations/records-door.ts
147258
+ function positionalHandleOver(handle) {
147259
+ return {
147260
+ get: (id) => handle.get({ id }),
147261
+ getResolved: (id) => handle.getResolved({ id }),
147262
+ put: (input, opts) => handle.put({
147263
+ ...input,
147264
+ ...opts?.ifRev === void 0 ? {} : { ifRev: opts.ifRev }
147265
+ }),
147266
+ patch: (id, partial) => handle.patch({
147267
+ id,
147268
+ partial
147269
+ }),
147270
+ delete: (id) => handle.delete({ id }),
147271
+ query: ({ limit }) => handle.query({ limit })
147272
+ };
147273
+ }
147274
+ /** The records door of the migration API, in the shape the migrations call. */
147275
+ function positionalRecordsOver(api) {
147276
+ return { kind: (definition) => positionalHandleOver(api.records.kind(definition)) };
147277
+ }
147278
+ //#endregion
147279
+ //#region src/migrations/ports.ts
147280
+ var NESTED_MAX = 1e3;
147281
+ /** The registry list and the migration-only rows door, over the migration API. */
147282
+ function integrationRowsApiOver(api) {
147283
+ return {
147284
+ list: async () => (await api.integrations.list({})).integrations,
147285
+ readLegacyIntegrationRows: (input) => api.legacyRows.read(input),
147286
+ clearLegacyIntegrationRows: (input) => api.legacyRows.clear(input)
147287
+ };
147288
+ }
147289
+ /** The keychain handle of the migration API: resolve and delete, owner-scoped by the transport. */
147290
+ function secretsOver(api) {
147291
+ return {
147292
+ resolve: async (refs) => {
147293
+ const { values } = await api.secrets.resolve({ refs: [...refs] });
147294
+ const out = {};
147295
+ for (const ref of refs) {
147296
+ const value = values[ref];
147297
+ out[ref] = value === null || value === void 0 ? { kind: "missing" } : {
147298
+ kind: "value",
147299
+ value,
147300
+ version: 0
147301
+ };
147302
+ }
147303
+ return out;
147304
+ },
147305
+ delete: async (refs) => (await api.secrets.delete({ refs: [...refs] })).deleted
147306
+ };
147307
+ }
147308
+ /** The Echo targets kept in the addon's `echoTargets` setting, read and written as stored. */
147309
+ function echoSettingPortsOver(api) {
147310
+ return {
147311
+ readRows: async () => {
147312
+ const { store } = await api.settings.read({});
147313
+ const rows = store["echoTargets"];
147314
+ return Array.isArray(rows) ? rows : [];
147315
+ },
147316
+ writeRows: async (rows) => {
147317
+ await api.settings.write({ patch: { echoTargets: [...rows] } });
147318
+ }
147319
+ };
147320
+ }
147321
+ /** The broker rows' flatten ports over the records door. */
147322
+ function flattenPortsOverDoor(records) {
147323
+ const handle = records.kind({
147324
+ name: alexaBrokersEntryKind.name,
147325
+ declaration: alexaBrokersEntryKind.declaration,
147326
+ schema: record(string(), unknown())
147327
+ });
147328
+ return {
147329
+ listNested: async (legacyKey) => (await handle.query({ limit: NESTED_MAX })).records.filter((row) => legacyKey in row.data).map((row) => row.id),
147330
+ readResolved: async (id) => {
147331
+ const row = await handle.getResolved(id);
147332
+ if (row === null) throw new Error("the record is gone");
147333
+ return row.data;
147334
+ },
147335
+ patch: async (id, patch) => {
147336
+ await handle.patch(id, patch);
147337
+ }
147338
+ };
147339
+ }
147340
+ /**
147341
+ * The catalogue's ports over {@link MigrationApiV1}, and nothing else (planning#447): the addon's
147342
+ * own settings store (the Echo rows), its keychain handle, the legacy integration rows door and its
147343
+ * broker, connection and Echo target records.
147344
+ */
147345
+ function alexaPortsOver(api) {
147346
+ const records = positionalRecordsOver(api);
147347
+ const warn = (message) => {
147348
+ api.log.warn({ message });
147349
+ };
147350
+ return {
147351
+ ...echoSettingPortsOver(api),
147352
+ ...flattenPortsOverDoor(records),
147353
+ ...alexaBrokerLinkPorts(records, warn),
147354
+ ...echoRecordPortsOver(records, { warn: (message, extras) => {
147355
+ api.log.warn({
147356
+ message,
147357
+ ...extras?.meta === void 0 ? {} : { meta: extras.meta }
147358
+ });
147359
+ } }),
147360
+ ...alexaIntegrationRowsPorts({
147361
+ api: integrationRowsApiOver(api),
147362
+ records,
147363
+ secrets: secretsOver(api),
147364
+ warn
147365
+ })
147366
+ };
147367
+ }
147368
+ //#endregion
147294
147369
  //#region src/speak/icon-routes.ts
147295
147370
  var ALEXA_ICON_SVG = "<svg role=\"img\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"#00CAFF\"><title>Amazon Alexa</title><path d=\"M12 0C5.37 0 0 5.37 0 12C0 18.09 4.53 23.11 10.4 23.9V21.5A1.59 1.59 0 0 0 9.32 19.97A8.41 8.41 0 0 1 3.6 11.8A8.37 8.37 0 0 1 12.09 3.6A8.4 8.4 0 0 1 20.4 12.31L20.39 12.38A8.68 8.68 0 0 1 20.36 12.76C20.36 12.83 20.35 12.9 20.34 12.96C20.34 13.04 20.33 13.12 20.32 13.19L20.3 13.29C19.27 20.07 10.45 23.87 10.4 23.9C10.92 23.97 11.46 24 12 24C18.63 24 24 18.63 24 12S18.63 0 12 0Z\"/></svg>";
147296
147371
  /** One day; the mark is immutable per addon version. */
@@ -147410,7 +147485,7 @@ var AlexaImportAddon = class extends BaseDeviceProvider {
147410
147485
  infoOf: (id) => this.registry?.get(id) ?? null,
147411
147486
  onChanged: (id) => this.syncBrokerRuntime(id)
147412
147487
  });
147413
- await this.runMigrations(defineAddonMigrations(ADDON_MIGRATIONS, this.migrationPorts(records)), { only: BROKER_RECORD_MIGRATION_IDS });
147488
+ await this.runMigrations(ADDON_MIGRATIONS, (api) => alexaPortsOver(api), { only: BROKER_RECORD_MIGRATION_IDS });
147414
147489
  this.activeBrokers = await this.loadPersistedBrokers();
147415
147490
  await this.adoptSessionFiles();
147416
147491
  this.registry = new AlexaBrokerRegistry(this.ctx.logger, {
@@ -147451,7 +147526,7 @@ var AlexaImportAddon = class extends BaseDeviceProvider {
147451
147526
  deviceCode: this.deviceCodeLogin,
147452
147527
  commitCookie: (input) => this.commitCapturedCookie(input)
147453
147528
  }), ...speakIconRoutes()];
147454
- await this.runMigrations(defineAddonMigrations(ADDON_MIGRATIONS, this.migrationPorts(records)), { only: ADDON_MIGRATIONS.map((m) => m.meta.id).filter((id) => !BROKER_RECORD_MIGRATION_IDS.includes(id)) });
147529
+ await this.runMigrations(ADDON_MIGRATIONS, (api) => alexaPortsOver(api), { only: ADDON_MIGRATIONS.map((m) => m.meta.id).filter((id) => !BROKER_RECORD_MIGRATION_IDS.includes(id)) });
147455
147530
  const echoStore = echoTargetStoreOver(records, {
147456
147531
  logger: this.ctx.logger,
147457
147532
  legacy: legacyEchoTargetsOver(this.echoSettingPorts())
@@ -147502,29 +147577,15 @@ var AlexaImportAddon = class extends BaseDeviceProvider {
147502
147577
  }
147503
147578
  ] };
147504
147579
  }
147505
- /** The `echoTargets` setting, read and written as the migration and the legacy store see it. */
147580
+ /**
147581
+ * The `echoTargets` setting the legacy Echo store still serves: the addon's own durable state
147582
+ * under the key it was always stored at, so a row an older release left there is still read.
147583
+ */
147506
147584
  echoSettingPorts() {
147585
+ const rows = this.state("echoTargets", array(unknown()), []);
147507
147586
  return {
147508
- readRows: () => Array.isArray(this.config.echoTargets) ? this.config.echoTargets : [],
147509
- writeRows: async (rows) => {
147510
- await this.updateGlobalSettings({ echoTargets: [...readEchoTargets({ echoTargets: rows })] });
147511
- }
147512
- };
147513
- }
147514
- migrationPorts(records) {
147515
- const secrets = this.ctx.secrets;
147516
- if (secrets === void 0) throw new Error("import-alexa: ctx.secrets is required");
147517
- return {
147518
- ...this.echoSettingPorts(),
147519
- ...flattenPortsOver(records.kind(alexaBrokersEntryKind)),
147520
- ...alexaBrokerLinkPorts(records, (message) => this.ctx.logger.warn(message)),
147521
- ...echoRecordPortsOver(records, this.ctx.logger),
147522
- ...alexaIntegrationRowsPorts({
147523
- api: defaultIntegrationApiOver(this.ctx.api),
147524
- records,
147525
- secrets,
147526
- warn: (message) => this.ctx.logger.warn(message)
147527
- })
147587
+ readRows: () => rows.get(),
147588
+ writeRows: (next) => rows.set([...readEchoTargets({ echoTargets: next })])
147528
147589
  };
147529
147590
  }
147530
147591
  /** One provider over the two record kinds: the account (broker) and the integrations using it. */