@camstack/addon-import-alexa 0.2.196 → 0.2.198
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.
- package/CHANGELOG.md +12 -0
- package/dist/addon.js +2033 -1985
- package/dist/addon.mjs +2033 -1985
- 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,12 +4866,1207 @@ 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-DxCT0krO.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
|
+
/**
|
|
5840
|
+
* Device can be run for a chosen time and then stopped. Mirrors the
|
|
5841
|
+
* `timed-run` wrapper cap — the cap is bound by the core-blocks addon, not by
|
|
5842
|
+
* a driver, so the flag is derived from the device's bindings
|
|
5843
|
+
* (`featuresOfBoundCaps`). Gates the quick-run control in the viewer.
|
|
5844
|
+
*/
|
|
5845
|
+
DeviceFeature["TimedRun"] = "timed-run";
|
|
5846
|
+
/** Light supports rgb-triplet color via `color` cap. */
|
|
5847
|
+
DeviceFeature["LightColorRgb"] = "light-color-rgb";
|
|
5848
|
+
/** Light supports HSV color via `color` cap. */
|
|
5849
|
+
DeviceFeature["LightColorHsv"] = "light-color-hsv";
|
|
5850
|
+
/** Light supports color-temperature (mired) via `color` cap. */
|
|
5851
|
+
DeviceFeature["LightColorMired"] = "light-color-mired";
|
|
5852
|
+
/** Thermostat supports a `heat_cool` dual setpoint (targetLow +
|
|
5853
|
+
* targetHigh). Gates the range slider UI. */
|
|
5854
|
+
DeviceFeature["ClimateDualSetpoint"] = "climate-dual-setpoint";
|
|
5855
|
+
/** Thermostat exposes target humidity and/or current humidity
|
|
5856
|
+
* readings. Gates the humidity controls. */
|
|
5857
|
+
DeviceFeature["ClimateHumidity"] = "climate-humidity";
|
|
5858
|
+
/** Thermostat exposes a fan-mode selector. */
|
|
5859
|
+
DeviceFeature["ClimateFanMode"] = "climate-fan-mode";
|
|
5860
|
+
/** Thermostat exposes preset modes (eco / away / sleep / vendor). */
|
|
5861
|
+
DeviceFeature["ClimatePreset"] = "climate-preset";
|
|
5862
|
+
/** Thermostat exposes a vertical louver swing toggle. Gates the
|
|
5863
|
+
* vertical-swing switch in the climate UI. Independent of horizontal. */
|
|
5864
|
+
DeviceFeature["ClimateSwingVertical"] = "climate-swing-vertical";
|
|
5865
|
+
/** Thermostat exposes a horizontal louver swing toggle. Gates the
|
|
5866
|
+
* horizontal-swing switch in the climate UI. Independent of vertical. */
|
|
5867
|
+
DeviceFeature["ClimateSwingHorizontal"] = "climate-swing-horizontal";
|
|
5868
|
+
/** Cover exposes intermediate position control (0..100). Gates the
|
|
5869
|
+
* position slider UI. */
|
|
5870
|
+
DeviceFeature["CoverPositionable"] = "cover-positionable";
|
|
5871
|
+
/** Cover exposes slat-tilt control. Gates the tilt slider UI. */
|
|
5872
|
+
DeviceFeature["CoverTilt"] = "cover-tilt";
|
|
5873
|
+
/** Cover has a real stop: `stop` halts the travel in place. Gates the stop
|
|
5874
|
+
* control in exporters; a provider whose `stop` is a no-op never declares it. */
|
|
5875
|
+
DeviceFeature["CoverStoppable"] = "cover-stoppable";
|
|
5876
|
+
/** Valve exposes intermediate position control (0..100). Gates the
|
|
5877
|
+
* position slider / drag surface UI. */
|
|
5878
|
+
DeviceFeature["ValvePositionable"] = "valve-positionable";
|
|
5879
|
+
/** Fan exposes a speed-percentage setter. Gates the speed slider UI. */
|
|
5880
|
+
DeviceFeature["FanSpeed"] = "fan-speed";
|
|
5881
|
+
/** Fan exposes a preset mode selector. */
|
|
5882
|
+
DeviceFeature["FanPreset"] = "fan-preset";
|
|
5883
|
+
/** Fan exposes blade direction (forward/reverse) — typical of
|
|
5884
|
+
* ceiling fans. */
|
|
5885
|
+
DeviceFeature["FanDirection"] = "fan-direction";
|
|
5886
|
+
/** Fan exposes an oscillation toggle. */
|
|
5887
|
+
DeviceFeature["FanOscillating"] = "fan-oscillating";
|
|
5888
|
+
/** Lock requires a PIN code on lock/unlock. Gates the code-entry
|
|
5889
|
+
* field on the UI lock-controls panel. */
|
|
5890
|
+
DeviceFeature["LockPinRequired"] = "lock-pin-required";
|
|
5891
|
+
/** Lock supports a latch-release ("open door") action distinct from
|
|
5892
|
+
* unlock. Mirrors HA `LockEntityFeature.OPEN` (bit 1) in
|
|
5893
|
+
* `supported_features`. Gates the Open Door button in the UI. */
|
|
5894
|
+
DeviceFeature["LockOpen"] = "lock-open";
|
|
5895
|
+
/** Media player exposes a seek-to-position surface. */
|
|
5896
|
+
DeviceFeature["MediaPlayerSeek"] = "media-player-seek";
|
|
5897
|
+
/** Media player exposes a volume-level setter. */
|
|
5898
|
+
DeviceFeature["MediaPlayerVolume"] = "media-player-volume";
|
|
5899
|
+
/** Media player exposes a mute toggle distinct from volume=0. */
|
|
5900
|
+
DeviceFeature["MediaPlayerMute"] = "media-player-mute";
|
|
5901
|
+
/** Media player exposes a shuffle toggle. */
|
|
5902
|
+
DeviceFeature["MediaPlayerShuffle"] = "media-player-shuffle";
|
|
5903
|
+
/** Media player exposes a repeat mode (off / all / one). */
|
|
5904
|
+
DeviceFeature["MediaPlayerRepeat"] = "media-player-repeat";
|
|
5905
|
+
/** Media player exposes a source / input selector. */
|
|
5906
|
+
DeviceFeature["MediaPlayerSelectSource"] = "media-player-select-source";
|
|
5907
|
+
/** Media player exposes a play-arbitrary-media surface (URL / id). */
|
|
5908
|
+
DeviceFeature["MediaPlayerPlayMedia"] = "media-player-play-media";
|
|
5909
|
+
/** Media player exposes next-track. */
|
|
5910
|
+
DeviceFeature["MediaPlayerNext"] = "media-player-next";
|
|
5911
|
+
/** Media player exposes previous-track. */
|
|
5912
|
+
DeviceFeature["MediaPlayerPrevious"] = "media-player-previous";
|
|
5913
|
+
/** Media player exposes stop distinct from pause. */
|
|
5914
|
+
DeviceFeature["MediaPlayerStop"] = "media-player-stop";
|
|
5915
|
+
/** Media player exposes volume up / down in steps (an infrared TV has no level). */
|
|
5916
|
+
DeviceFeature["MediaPlayerVolumeStep"] = "media-player-volume-step";
|
|
5917
|
+
/** Media player exposes channel up / down in steps. */
|
|
5918
|
+
DeviceFeature["MediaPlayerChannelStep"] = "media-player-channel-step";
|
|
5919
|
+
/** Media player exposes power on / off. */
|
|
5920
|
+
DeviceFeature["MediaPlayerPower"] = "media-player-power";
|
|
5921
|
+
/** Alarm panel requires a PIN code on arm/disarm. */
|
|
5922
|
+
DeviceFeature["AlarmPinRequired"] = "alarm-pin-required";
|
|
5923
|
+
/** Presence device carries GPS coordinates (lat/lng/accuracy) in
|
|
5924
|
+
* addition to a textual location. */
|
|
5925
|
+
DeviceFeature["PresenceGps"] = "presence-gps";
|
|
5926
|
+
/** Notifier accepts an inline / URL image attachment. */
|
|
5927
|
+
DeviceFeature["NotifierImage"] = "notifier-image";
|
|
5928
|
+
/** Notifier accepts a priority hint (high/normal/low). */
|
|
5929
|
+
DeviceFeature["NotifierPriority"] = "notifier-priority";
|
|
5930
|
+
/** Notifier accepts a free-form `data` payload for platform-specific
|
|
5931
|
+
* fields. */
|
|
5932
|
+
DeviceFeature["NotifierData"] = "notifier-data";
|
|
5933
|
+
/** Notifier supports interactive action buttons / callbacks. */
|
|
5934
|
+
DeviceFeature["NotifierActions"] = "notifier-actions";
|
|
5935
|
+
/** Notifier supports per-call recipient targeting (multi-user). */
|
|
5936
|
+
DeviceFeature["NotifierRecipients"] = "notifier-recipients";
|
|
5937
|
+
/** Script runner accepts a variables map on each run invocation. */
|
|
5938
|
+
DeviceFeature["ScriptVariables"] = "script-variables";
|
|
5939
|
+
/** Automation `trigger` accepts a skipCondition flag — fires the
|
|
5940
|
+
* automation's actions while bypassing its condition block. */
|
|
5941
|
+
DeviceFeature["AutomationSkipCondition"] = "automation-skip-condition";
|
|
5942
|
+
/** Robot vacuum exposes a live cleaning map (image child). Gates the
|
|
5943
|
+
* map tile in the vacuum UI. */
|
|
5944
|
+
DeviceFeature["VacuumHasMap"] = "vacuum-has-map";
|
|
5945
|
+
/** Robot vacuum exposes AI obstacle-detection toggles. Gates the AI
|
|
5946
|
+
* switches group. */
|
|
5947
|
+
DeviceFeature["VacuumHasAi"] = "vacuum-has-ai";
|
|
5948
|
+
/** Robot mower exposes a live mowing map (SVG image child). Gates the
|
|
5949
|
+
* mower map tile. */
|
|
5950
|
+
DeviceFeature["MowerHasMap"] = "mower-has-map";
|
|
5951
|
+
/** Robot mower exposes targeted mowing (all-area / zones / edges /
|
|
5952
|
+
* spots) — gates the Mow action + map selectors. */
|
|
5953
|
+
DeviceFeature["MowerHasTargetedMowing"] = "mower-has-targeted-mowing";
|
|
5954
|
+
return DeviceFeature;
|
|
5955
|
+
}({});
|
|
5956
|
+
/**
|
|
5957
|
+
* Semantic role a device plays within its parent. Populated by driver
|
|
5958
|
+
* addons when creating accessory devices (Reolink siren/floodlight/
|
|
5959
|
+
* PIR/chime/autotrack/doorbell, ONVIF relay outputs, …). Used by the
|
|
5960
|
+
* admin UI to pick icons, labels, and widgets — a `Switch` with
|
|
5961
|
+
* `role: Floodlight` renders as a bulb with a brightness slider,
|
|
5962
|
+
* whereas a `Switch` with `role: Siren` renders as a klaxon.
|
|
5963
|
+
*
|
|
5964
|
+
* Undefined for top-level devices (cameras, NVRs, hubs). Persisted in
|
|
5965
|
+
* sqlite as a nullable TEXT column — old rows keep working unchanged.
|
|
5966
|
+
*/
|
|
5967
|
+
var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
5968
|
+
DeviceRole["Siren"] = "siren";
|
|
5969
|
+
DeviceRole["Floodlight"] = "floodlight";
|
|
5970
|
+
DeviceRole["Spotlight"] = "spotlight";
|
|
5971
|
+
DeviceRole["PirSensor"] = "pir-sensor";
|
|
5972
|
+
DeviceRole["Chime"] = "chime";
|
|
5973
|
+
DeviceRole["Autotrack"] = "autotrack";
|
|
5974
|
+
DeviceRole["Nightvision"] = "nightvision";
|
|
5975
|
+
DeviceRole["PrivacyMask"] = "privacy-mask";
|
|
5976
|
+
DeviceRole["Doorbell"] = "doorbell";
|
|
5977
|
+
/** Interior blind / shade / roller blind. HA `device_class: blind|shade`. */
|
|
5978
|
+
DeviceRole["CoverBlind"] = "cover-blind";
|
|
5979
|
+
/** Exterior roller shutter. HA `device_class: shutter`; Homematic BROLL. */
|
|
5980
|
+
DeviceRole["CoverShutter"] = "cover-shutter";
|
|
5981
|
+
/** Exterior awning. HA `device_class: awning`. */
|
|
5982
|
+
DeviceRole["CoverAwning"] = "cover-awning";
|
|
5983
|
+
/** Curtain / drape. HA `device_class: curtain`. */
|
|
5984
|
+
DeviceRole["CoverCurtain"] = "cover-curtain";
|
|
5985
|
+
/** Garage door. HA `device_class: garage`. A security actuator: exports gate it. */
|
|
5986
|
+
DeviceRole["CoverGarage"] = "cover-garage";
|
|
5987
|
+
/** Gate. HA `device_class: gate`. A security actuator: exports gate it. */
|
|
5988
|
+
DeviceRole["CoverGate"] = "cover-gate";
|
|
5989
|
+
/** Door. HA `device_class: door`. A security actuator: exports gate it. */
|
|
5990
|
+
DeviceRole["CoverDoor"] = "cover-door";
|
|
5991
|
+
/** Window. HA `device_class: window`. */
|
|
5992
|
+
DeviceRole["CoverWindow"] = "cover-window";
|
|
5993
|
+
/** Virtual HA toggle (input_boolean.*) — distinguishable from a
|
|
5994
|
+
* real Switch device for UI rendering / export adapters. */
|
|
5995
|
+
DeviceRole["BinaryHelper"] = "binary-helper";
|
|
5996
|
+
/** A smart plug: a `switch` whose source says it is an outlet (HA
|
|
5997
|
+
* `device_class: outlet`). The Alexa export shows it as a SMARTPLUG. */
|
|
5998
|
+
DeviceRole["Outlet"] = "outlet";
|
|
5999
|
+
/** Generic motion / occupancy / moving event source. Distinct from
|
|
6000
|
+
* the camera accessory PirSensor role: that one is a camera child;
|
|
6001
|
+
* this is a standalone HA / 3rd-party motion sensor. */
|
|
6002
|
+
DeviceRole["MotionSensor"] = "motion-sensor";
|
|
6003
|
+
DeviceRole["ContactSensor"] = "contact-sensor";
|
|
6004
|
+
DeviceRole["LeakSensor"] = "leak-sensor";
|
|
6005
|
+
DeviceRole["SmokeSensor"] = "smoke-sensor";
|
|
6006
|
+
DeviceRole["COSensor"] = "co-sensor";
|
|
6007
|
+
DeviceRole["GasSensor"] = "gas-sensor";
|
|
6008
|
+
DeviceRole["TamperSensor"] = "tamper-sensor";
|
|
6009
|
+
DeviceRole["VibrationSensor"] = "vibration-sensor";
|
|
6010
|
+
DeviceRole["ConnectivitySensor"] = "connectivity-sensor";
|
|
6011
|
+
DeviceRole["SoundSensor"] = "sound-sensor";
|
|
6012
|
+
/** Fallback for `binary_sensor` without a known `device_class`. */
|
|
6013
|
+
DeviceRole["BinarySensor"] = "binary-sensor";
|
|
6014
|
+
DeviceRole["TemperatureSensor"] = "temperature-sensor";
|
|
6015
|
+
DeviceRole["HumiditySensor"] = "humidity-sensor";
|
|
6016
|
+
DeviceRole["AmbientLightSensor"] = "ambient-light-sensor";
|
|
6017
|
+
DeviceRole["PressureSensor"] = "pressure-sensor";
|
|
6018
|
+
/** Wind speed or direction (weather-station `wind-sensor` cap). */
|
|
6019
|
+
DeviceRole["WindSensor"] = "wind-sensor";
|
|
6020
|
+
/** Rain accumulation or rate (weather-station `rain-sensor` cap). */
|
|
6021
|
+
DeviceRole["RainSensor"] = "rain-sensor";
|
|
6022
|
+
/** UV index (weather-station `uv-sensor` cap). */
|
|
6023
|
+
DeviceRole["UvSensor"] = "uv-sensor";
|
|
6024
|
+
/** Solar irradiance W/m² (weather-station `solar-radiation-sensor` cap).
|
|
6025
|
+
* Distinct from AmbientLightSensor (lux). */
|
|
6026
|
+
DeviceRole["SolarRadiationSensor"] = "solar-radiation-sensor";
|
|
6027
|
+
/** Soil moisture % (garden/weather `soil-moisture-sensor` cap). */
|
|
6028
|
+
DeviceRole["SoilMoistureSensor"] = "soil-moisture-sensor";
|
|
6029
|
+
DeviceRole["PowerSensor"] = "power-sensor";
|
|
6030
|
+
DeviceRole["EnergySensor"] = "energy-sensor";
|
|
6031
|
+
DeviceRole["VoltageSensor"] = "voltage-sensor";
|
|
6032
|
+
DeviceRole["CurrentSensor"] = "current-sensor";
|
|
6033
|
+
DeviceRole["AirQualitySensor"] = "air-quality-sensor";
|
|
6034
|
+
/** Battery level (numeric % via `sensor` OR low-bool via
|
|
6035
|
+
* `binary_sensor` — the cap distinguishes via the value type). */
|
|
6036
|
+
DeviceRole["BatterySensor"] = "battery-sensor";
|
|
6037
|
+
/** Fallback for `sensor` numeric without a known `device_class`. */
|
|
6038
|
+
DeviceRole["NumericSensor"] = "numeric-sensor";
|
|
6039
|
+
/** String / enum state (HA `sensor` with `state_class: enum` or
|
|
6040
|
+
* `attributes.options`). */
|
|
6041
|
+
DeviceRole["EnumSensor"] = "enum-sensor";
|
|
6042
|
+
/** Date / timestamp state (HA `sensor` with `device_class: timestamp`
|
|
6043
|
+
* or `date`). The slice carries the raw ISO string verbatim (hosted on
|
|
6044
|
+
* the `enum-sensor` cap); the UI renders it locale-formatted. */
|
|
6045
|
+
DeviceRole["DateTimeSensor"] = "datetime-sensor";
|
|
6046
|
+
/** Last-resort fallback when nothing else matches. */
|
|
6047
|
+
DeviceRole["GenericSensor"] = "generic-sensor";
|
|
6048
|
+
DeviceRole["NumericControl"] = "numeric-control";
|
|
6049
|
+
DeviceRole["SelectControl"] = "select-control";
|
|
6050
|
+
DeviceRole["TextControl"] = "text-control";
|
|
6051
|
+
DeviceRole["DateTimeControl"] = "datetime-control";
|
|
6052
|
+
/** Mobile push notifier (HA `notify.mobile_app_*`) — supports
|
|
6053
|
+
* rich features (image, priority, channel routing). */
|
|
6054
|
+
DeviceRole["MobilePushNotifier"] = "mobile-push-notifier";
|
|
6055
|
+
/** Chat / messaging service (HA `notify.telegram_*`,
|
|
6056
|
+
* `notify.discord_*`, etc.). */
|
|
6057
|
+
DeviceRole["MessagingNotifier"] = "messaging-notifier";
|
|
6058
|
+
/** Email-based delivery (HA `notify.smtp`, etc.). */
|
|
6059
|
+
DeviceRole["EmailNotifier"] = "email-notifier";
|
|
6060
|
+
/** Fallback when the notifier service name doesn't match a known
|
|
6061
|
+
* pattern. */
|
|
6062
|
+
DeviceRole["GenericNotifier"] = "generic-notifier";
|
|
6063
|
+
/** Emits a pulse train (infrared or RF) on request — the `ir-transmitter`
|
|
6064
|
+
* cap. A `DeviceType.Generic` device. */
|
|
6065
|
+
DeviceRole["IrTransmitter"] = "ir-transmitter";
|
|
6066
|
+
return DeviceRole;
|
|
6067
|
+
}({});
|
|
6061
6068
|
//#endregion
|
|
6062
|
-
//#region ../types/dist/sleep-
|
|
6069
|
+
//#region ../types/dist/sleep-7El4r5Bl.mjs
|
|
6063
6070
|
/**
|
|
6064
6071
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6065
6072
|
* window to float samples (D455).
|
|
@@ -6813,7 +6820,7 @@ function switchRecordsOverMigrationApi(api) {
|
|
|
6813
6820
|
};
|
|
6814
6821
|
} };
|
|
6815
6822
|
}
|
|
6816
|
-
function integrationRowsApiOver(api) {
|
|
6823
|
+
function integrationRowsApiOver$1(api) {
|
|
6817
6824
|
return {
|
|
6818
6825
|
list: async () => (await api.integrations.list({})).integrations,
|
|
6819
6826
|
readLegacyIntegrationRows: (input) => api.legacyRows.read(input),
|
|
@@ -8444,7 +8451,7 @@ function boundOf(list) {
|
|
|
8444
8451
|
* Base class for CamStack addons. Eliminates settings boilerplate:
|
|
8445
8452
|
*
|
|
8446
8453
|
* - Typed `config` property with automatic resolution from store + defaults
|
|
8447
|
-
* -
|
|
8454
|
+
* - the scoped settings API (`clusterSettings` / `nodeSettings` / `deviceDefaults`) auto-implemented
|
|
8448
8455
|
* - `getAddonSettings()` / `updateAddonSettings()` auto-implemented
|
|
8449
8456
|
* - `getDeviceSettings()` / `updateDeviceSettings()` auto-implemented
|
|
8450
8457
|
* - `ctx` accessor for the AddonContext (no manual `this.ctxRef` storage)
|
|
@@ -8454,7 +8461,7 @@ function boundOf(list) {
|
|
|
8454
8461
|
* Subclasses override:
|
|
8455
8462
|
* - `onInitialize()` — addon-specific init logic, return ProviderRegistration[]
|
|
8456
8463
|
* - `onShutdown()` — cleanup
|
|
8457
|
-
* - `
|
|
8464
|
+
* - `clusterSettingsSchema()` / `nodeSettingsSchema()` / `deviceSettingsSchema()` — UI schemas
|
|
8458
8465
|
*
|
|
8459
8466
|
* @example
|
|
8460
8467
|
* ```ts
|
|
@@ -8468,7 +8475,7 @@ function boundOf(list) {
|
|
|
8468
8475
|
* super({ maxRetries: 3, endpoint: 'http://localhost' })
|
|
8469
8476
|
* }
|
|
8470
8477
|
*
|
|
8471
|
-
* protected
|
|
8478
|
+
* protected clusterSettingsSchema() {
|
|
8472
8479
|
* return this.schema({
|
|
8473
8480
|
* sections: [{
|
|
8474
8481
|
* id: 'main', title: 'Settings',
|
|
@@ -8511,7 +8518,7 @@ var BaseAddon = class {
|
|
|
8511
8518
|
defaults;
|
|
8512
8519
|
/**
|
|
8513
8520
|
* Hidden-state paths that hold secrets (D787) — values the addon writes
|
|
8514
|
-
* itself (`
|
|
8521
|
+
* itself (`state()`, the scoped writers) that no form field declares.
|
|
8515
8522
|
* Stored in the keychain exactly like a `password` field. Syntax:
|
|
8516
8523
|
* `'snapshotSigningKey'`, `'identity.pincode'`, `'tokens[userId].accessToken'`
|
|
8517
8524
|
* (`key[<id field>]` addresses array items by id, never by index).
|
|
@@ -8521,7 +8528,7 @@ var BaseAddon = class {
|
|
|
8521
8528
|
/**
|
|
8522
8529
|
* D986 M4: the scoped schemas this addon declared, resolved once per capability
|
|
8523
8530
|
* (`loadScopedSchemas`) so the sync readers (`perNodeKeys`, the secret tree, the restart check)
|
|
8524
|
-
* see them. Empty until loaded
|
|
8531
|
+
* see them. Empty until loaded.
|
|
8525
8532
|
*/
|
|
8526
8533
|
_scopedByCap = /* @__PURE__ */ new Map();
|
|
8527
8534
|
_nodeKeysByCap = /* @__PURE__ */ new Map();
|
|
@@ -8645,7 +8652,7 @@ var BaseAddon = class {
|
|
|
8645
8652
|
seq: 1e3,
|
|
8646
8653
|
initialBody: spec.initialBody
|
|
8647
8654
|
})], (a) => registrySwitchPortsOver({
|
|
8648
|
-
api: integrationRowsApiOver(a),
|
|
8655
|
+
api: integrationRowsApiOver$1(a),
|
|
8649
8656
|
records: switchRecordsOverMigrationApi(a),
|
|
8650
8657
|
kind: spec.kind
|
|
8651
8658
|
})).bind(api);
|
|
@@ -8707,7 +8714,7 @@ var BaseAddon = class {
|
|
|
8707
8714
|
/** Addon-specific cleanup. Override if needed. */
|
|
8708
8715
|
async onShutdown() {}
|
|
8709
8716
|
/**
|
|
8710
|
-
* Called after config is resolved during
|
|
8717
|
+
* Called after config is resolved during a settings write.
|
|
8711
8718
|
* Override to react to config changes (e.g. restart a sampler, reconnect a service).
|
|
8712
8719
|
* Not called during initialize() — use onInitialize() for initial setup.
|
|
8713
8720
|
*/
|
|
@@ -8736,82 +8743,12 @@ var BaseAddon = class {
|
|
|
8736
8743
|
scopedSettingsCapabilities() {
|
|
8737
8744
|
return [];
|
|
8738
8745
|
}
|
|
8739
|
-
/** Override to provide global-level settings UI schema. */
|
|
8740
|
-
globalSettingsSchema(_cap) {
|
|
8741
|
-
return null;
|
|
8742
|
-
}
|
|
8743
8746
|
/** Override to provide device-level settings UI schema. */
|
|
8744
8747
|
deviceSettingsSchema() {
|
|
8745
8748
|
return null;
|
|
8746
8749
|
}
|
|
8747
8750
|
/**
|
|
8748
|
-
*
|
|
8749
|
-
* ARE the configuration of its integration.
|
|
8750
|
-
*
|
|
8751
|
-
* Return the `ConfigSection.id`s, from {@link globalSettingsSchema}, that an
|
|
8752
|
-
* operator should find on the addon's integration page (System →
|
|
8753
|
-
* Integrations → <name>) rather than only in the cluster-wide list of every
|
|
8754
|
-
* addon. Empty (the default) means the addon has no integration-level
|
|
8755
|
-
* settings and no such surface is offered — this is opt-in, because whether
|
|
8756
|
-
* an addon's configuration IS its integration's configuration depends on the
|
|
8757
|
-
* nature of the integration.
|
|
8758
|
-
*
|
|
8759
|
-
* WHAT THIS IS NOT. It is not a scope. The selected sections keep living in
|
|
8760
|
-
* the ONE global schema, in the ONE addon store, written by the ONE
|
|
8761
|
-
* `updateGlobalSettings` path. There is deliberately no
|
|
8762
|
-
* `updateIntegrationSettings`: a second write path is how a surface acquires
|
|
8763
|
-
* a second store key, and this repo has shipped that twice (`btmPath@hub`,
|
|
8764
|
-
* D266). Selecting sections cannot introduce a key that selecting cannot.
|
|
8765
|
-
*
|
|
8766
|
-
* WHY IT IS A LIST OF SECTION IDS AND NOT A MARKER ON THE SECTION.
|
|
8767
|
-
* `ConfigFieldBase` used to carry `scope?: 'device' | 'global'` and it was
|
|
8768
|
-
* removed with the reason recorded at
|
|
8769
|
-
* `packages/types/src/interfaces/config-ui.ts:249` — *"a field's scope is
|
|
8770
|
-
* determined by WHICH schema it lives in, not by a field-level marker."* A
|
|
8771
|
-
* marker sprinkled across sections also has to borrow a field that already
|
|
8772
|
-
* means something else; borrowing `section.tab` put the literal word
|
|
8773
|
-
* "integration" into an operator-facing tab bar, because `tab` means "how to
|
|
8774
|
-
* GROUP this visually" and cannot also mean "where this lives" (D269
|
|
8775
|
-
* supersedes D268). One declaration, in one place, next to the schema whose
|
|
8776
|
-
* ids it names.
|
|
8777
|
-
*/
|
|
8778
|
-
integrationSettingSections() {
|
|
8779
|
-
return [];
|
|
8780
|
-
}
|
|
8781
|
-
async getGlobalSettings(overlay, cap, nodeId) {
|
|
8782
|
-
await this.loadScopedSchemas(cap);
|
|
8783
|
-
const schema = this.globalSettingsSchema(cap) ?? this.scopedFormSchema(cap);
|
|
8784
|
-
if (!schema) return { sections: [] };
|
|
8785
|
-
const projected = await this.readRawProjectedStore(nodeId, cap);
|
|
8786
|
-
return hydrateSchema(schema, overlay ? await this.overlayKeepingMarkers(projected, overlay) : projected, { inlineSecretsAsViews: true });
|
|
8787
|
-
}
|
|
8788
|
-
/**
|
|
8789
|
-
* The integration-level view of this addon's settings: exactly the sections
|
|
8790
|
-
* named by {@link integrationSettingSections}, hydrated from the SAME store
|
|
8791
|
-
* `getGlobalSettings` reads, and narrowed to cluster-scoped fields.
|
|
8792
|
-
*
|
|
8793
|
-
* Returns `null` when the addon declared nothing — an addon that opts out has
|
|
8794
|
-
* no integration settings surface at all, rather than an empty one that reads
|
|
8795
|
-
* as a failed load.
|
|
8796
|
-
*
|
|
8797
|
-
* Three properties hold BY CONSTRUCTION, which is why they are here in core
|
|
8798
|
-
* and not in whichever UI happens to render this:
|
|
8799
|
-
*
|
|
8800
|
-
* 1. **One key.** The payload is a SUBSET of the global schema, so a field
|
|
8801
|
-
* shown here is the same field, with the same bare key, that the addon's
|
|
8802
|
-
* own page shows. There is no integration-specific writer — callers save
|
|
8803
|
-
* through `updateGlobalSettings` — so a second store key is unreachable,
|
|
8804
|
-
* not merely discouraged.
|
|
8805
|
-
* 2. **No node scope.** `perNode: true` fields are DROPPED. Their store key
|
|
8806
|
-
* is `<key>@<nodeId>` and an integration is not a node; whichever node
|
|
8807
|
-
* such a field silently picked would be a wrong answer for the operator
|
|
8808
|
-
* who opened the page (D266).
|
|
8809
|
-
* 3. **No silent typo.** A declared id that names no section throws. The
|
|
8810
|
-
* alternative — skip it — turns a rename into a surface that quietly
|
|
8811
|
-
* empties, which looks exactly like an addon with nothing to configure.
|
|
8812
|
-
*/
|
|
8813
|
-
/**
|
|
8814
|
-
* The form schema of ONE integration instance, or `null` to use {@link globalSettingsSchema}.
|
|
8751
|
+
* The form schema of ONE integration instance, or `null` to use the scoped form.
|
|
8815
8752
|
*
|
|
8816
8753
|
* Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
|
|
8817
8754
|
* needs its connection fields, the default integration the addon's own sections. It is the
|
|
@@ -8984,6 +8921,19 @@ var BaseAddon = class {
|
|
|
8984
8921
|
const overlay = await this.scopedSettingsOverlay(scope, cap, nodeId);
|
|
8985
8922
|
return hydrateSchema(schema, overlay ? await this.overlayKeepingMarkers(stored, overlay) : stored, { inlineSecretsAsViews: true });
|
|
8986
8923
|
}
|
|
8924
|
+
/**
|
|
8925
|
+
* The scoped schemas this addon serves: one entry per loaded (capability, scope), capabilities
|
|
8926
|
+
* in declaration order, scopes in {@link SCOPED_SETTINGS_SCOPES} order. `[]` when it declares
|
|
8927
|
+
* nothing.
|
|
8928
|
+
*/
|
|
8929
|
+
async listScopedSettings() {
|
|
8930
|
+
await this.loadScopedSchemas();
|
|
8931
|
+
return [...this._scopedByCap].flatMap(([cap, entries]) => entries.map((entry) => ({
|
|
8932
|
+
cap,
|
|
8933
|
+
scope: entry.scope,
|
|
8934
|
+
sectionIds: entry.schema.sections.map((section) => section.id)
|
|
8935
|
+
})));
|
|
8936
|
+
}
|
|
8987
8937
|
/** The OPERATOR's write of declared keys of one scope (D787 secret semantics). */
|
|
8988
8938
|
async updateScopedSettings(scope, cap, patch, nodeId) {
|
|
8989
8939
|
this._operatorWriteDepth++;
|
|
@@ -9009,32 +8959,15 @@ var BaseAddon = class {
|
|
|
9009
8959
|
*/
|
|
9010
8960
|
async getIntegrationFormSchema(instance, nodeId) {
|
|
9011
8961
|
const scoped = await this.integrationFormSchema(instance);
|
|
9012
|
-
if (scoped === null) return this.
|
|
8962
|
+
if (scoped === null) return this.scopedForm(nodeId);
|
|
9013
8963
|
return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
|
|
9014
8964
|
}
|
|
9015
|
-
|
|
9016
|
-
|
|
9017
|
-
|
|
9018
|
-
const schema = this.
|
|
9019
|
-
if (!schema)
|
|
9020
|
-
|
|
9021
|
-
const sections = [];
|
|
9022
|
-
for (const id of declared) {
|
|
9023
|
-
const section = byId.get(id);
|
|
9024
|
-
if (!section) throw new Error(`${this.constructor.name}: integrationSettingSections() names unknown section "${id}". Known sections: [${[...byId.keys()].join(", ")}].`);
|
|
9025
|
-
const fields = dropPerNodeFields(section.fields);
|
|
9026
|
-
if (fields.length === 0) continue;
|
|
9027
|
-
sections.push({
|
|
9028
|
-
...section,
|
|
9029
|
-
fields
|
|
9030
|
-
});
|
|
9031
|
-
}
|
|
9032
|
-
if (sections.length === 0) return null;
|
|
9033
|
-
const projected = await this.readRawProjectedStore(nodeId);
|
|
9034
|
-
return hydrateSchema({
|
|
9035
|
-
...schema,
|
|
9036
|
-
sections
|
|
9037
|
-
}, projected, { inlineSecretsAsViews: true });
|
|
8965
|
+
/** The form of the scoped schemas this addon declared, hydrated from its store. */
|
|
8966
|
+
async scopedForm(nodeId) {
|
|
8967
|
+
await this.loadScopedSchemas();
|
|
8968
|
+
const schema = this.scopedFormSchema();
|
|
8969
|
+
if (!schema) return { sections: [] };
|
|
8970
|
+
return hydrateSchema(schema, await this.readRawProjectedStore(nodeId), { inlineSecretsAsViews: true });
|
|
9038
8971
|
}
|
|
9039
8972
|
/**
|
|
9040
8973
|
* The raw addon store PROJECTED onto the target node's bare per-node keys:
|
|
@@ -9043,8 +8976,8 @@ var BaseAddon = class {
|
|
|
9043
8976
|
* bare fallback), all `@`-scoped and stray bare per-node keys are dropped.
|
|
9044
8977
|
* A no-op passthrough when the schema declares no `perNode` field.
|
|
9045
8978
|
*
|
|
9046
|
-
* This is the sanctioned way for
|
|
9047
|
-
* the store for custom
|
|
8979
|
+
* This is the sanctioned way for an addon that needs
|
|
8980
|
+
* the store for custom logic (option narrowing, value snapping) to
|
|
9048
8981
|
* read it per-node — never `ctx.settings.readAddonStore()` directly.
|
|
9049
8982
|
* `nodeId` omitted ⇒ the local node (node-blind injection from ctx).
|
|
9050
8983
|
*
|
|
@@ -9096,7 +9029,7 @@ var BaseAddon = class {
|
|
|
9096
9029
|
}
|
|
9097
9030
|
/**
|
|
9098
9031
|
* Whether ONE global key of this addon's store was written, read three-way
|
|
9099
|
-
* (D651). For a question a hydrated view cannot answer:
|
|
9032
|
+
* (D651). For a question a hydrated view cannot answer: a hydrated form
|
|
9100
9033
|
* reports `value ?? default`, so "the operator chose the default" and "nobody
|
|
9101
9034
|
* chose" look the same, and a failed read looks like both. A `perNode` key is
|
|
9102
9035
|
* not supported here: its stored name is scoped.
|
|
@@ -9130,7 +9063,7 @@ var BaseAddon = class {
|
|
|
9130
9063
|
}
|
|
9131
9064
|
/**
|
|
9132
9065
|
* The OPERATOR's write — a settings form or an admin API call, dispatched by
|
|
9133
|
-
* the kernel.
|
|
9066
|
+
* the kernel. The one in-process write of the addon blob that is not a scoped write; a secret
|
|
9134
9067
|
* the operator sends is stored as sent even when it equals a pre-keychain
|
|
9135
9068
|
* inline value: the operator re-entering a password is a change, an addon
|
|
9136
9069
|
* writing back what it read is not (D787).
|
|
@@ -9143,9 +9076,6 @@ var BaseAddon = class {
|
|
|
9143
9076
|
this._operatorWriteDepth--;
|
|
9144
9077
|
}
|
|
9145
9078
|
}
|
|
9146
|
-
async updateGlobalSettings(patch, nodeId) {
|
|
9147
|
-
await this.applyGlobalPatch(patch, nodeId);
|
|
9148
|
-
}
|
|
9149
9079
|
/**
|
|
9150
9080
|
* REMOVE stored secrets — their keychain values and their markers (D787).
|
|
9151
9081
|
*
|
|
@@ -9188,8 +9118,7 @@ var BaseAddon = class {
|
|
|
9188
9118
|
await this.resolveConfig();
|
|
9189
9119
|
await this.onConfigChanged();
|
|
9190
9120
|
this.emitLifecycle(EventCategory.AddonUpdated, { level: "global" });
|
|
9191
|
-
|
|
9192
|
-
this.maybeAutoRestart(Object.keys(barePatch), [...legacy === null ? [] : [legacy], ...this.loadedScopedSchemas().map((entry) => entry.schema)]);
|
|
9121
|
+
this.maybeAutoRestart(Object.keys(barePatch), this.loadedScopedSchemas().map((entry) => entry.schema));
|
|
9193
9122
|
return true;
|
|
9194
9123
|
}
|
|
9195
9124
|
/**
|
|
@@ -9227,10 +9156,7 @@ var BaseAddon = class {
|
|
|
9227
9156
|
this._nodeKeysByCap = /* @__PURE__ */ new Map();
|
|
9228
9157
|
this._addonSecretTree = null;
|
|
9229
9158
|
}
|
|
9230
|
-
/**
|
|
9231
|
-
* The form the settings API serves while an addon declares no {@link globalSettingsSchema}: the
|
|
9232
|
-
* sections of its scoped schemas, so dropping the old hook does not blank the form.
|
|
9233
|
-
*/
|
|
9159
|
+
/** The form of an addon's scoped schemas: their sections, each shown once. */
|
|
9234
9160
|
scopedFormSchema(cap) {
|
|
9235
9161
|
const byId = /* @__PURE__ */ new Map();
|
|
9236
9162
|
for (const entry of this.loadedScopedSchemas(cap)) for (const section of entry.schema.sections) if (!byId.has(section.id)) byId.set(section.id, section);
|
|
@@ -9242,8 +9168,7 @@ var BaseAddon = class {
|
|
|
9242
9168
|
return [...this._scopedByCap.values()].flat();
|
|
9243
9169
|
}
|
|
9244
9170
|
/**
|
|
9245
|
-
* The field keys that are stored per node: every field of a {@link nodeSettingsSchema}
|
|
9246
|
-
* the fields the legacy {@link globalSettingsSchema} still marks `perNode: true`. Derived once
|
|
9171
|
+
* The field keys that are stored per node: every field of a {@link nodeSettingsSchema}. Derived once
|
|
9247
9172
|
* per `cap` argument and memoized (schemas are static declarations). Empty set ⇒ every
|
|
9248
9173
|
* per-node code path is bypassed and the settings API behaves like the node-agnostic one.
|
|
9249
9174
|
* Call {@link loadScopedSchemas} first (the async seams do).
|
|
@@ -9252,8 +9177,7 @@ var BaseAddon = class {
|
|
|
9252
9177
|
const cacheKey = cap ?? "";
|
|
9253
9178
|
const cached = this._nodeKeysByCap.get(cacheKey);
|
|
9254
9179
|
if (cached) return cached;
|
|
9255
|
-
const
|
|
9256
|
-
const keys = new Set(legacy ? legacy.sections.flatMap((section) => collectPerNodeFieldKeys(section.fields)) : []);
|
|
9180
|
+
const keys = /* @__PURE__ */ new Set();
|
|
9257
9181
|
for (const { scope, schema } of this.loadedScopedSchemas(cap)) {
|
|
9258
9182
|
if (scope !== "node") continue;
|
|
9259
9183
|
for (const section of schema.sections) for (const key of collectValueFieldKeys(section.fields)) keys.add(key);
|
|
@@ -9471,8 +9395,6 @@ var BaseAddon = class {
|
|
|
9471
9395
|
}
|
|
9472
9396
|
declaredKeySet() {
|
|
9473
9397
|
const keys = new Set(Object.keys(this.defaults));
|
|
9474
|
-
const schema = this.globalSettingsSchema();
|
|
9475
|
-
if (schema) for (const section of schema.sections) for (const key of collectFieldKeys(section.fields)) keys.add(key);
|
|
9476
9398
|
for (const { schema: scoped } of this.loadedScopedSchemas()) for (const section of scoped.sections) for (const key of collectFieldKeys(section.fields)) keys.add(key);
|
|
9477
9399
|
for (const key of this._declaredStateKeys) keys.add(key);
|
|
9478
9400
|
for (const path of this.secretStatePaths) {
|
|
@@ -9570,7 +9492,7 @@ var BaseAddon = class {
|
|
|
9570
9492
|
/** The addon store's secret tree: schema fields by TYPE, plus `secretStatePaths`. */
|
|
9571
9493
|
addonSecretTree() {
|
|
9572
9494
|
if (this._addonSecretTree === null) {
|
|
9573
|
-
const tree = new Map(
|
|
9495
|
+
const tree = /* @__PURE__ */ new Map();
|
|
9574
9496
|
for (const { schema } of this.loadedScopedSchemas()) for (const [key, node] of secretTreeFromSchema(schema)) tree.set(key, node);
|
|
9575
9497
|
this._addonSecretTree = mergeSecretStatePaths(tree, this.secretStatePaths);
|
|
9576
9498
|
}
|
|
@@ -9782,47 +9704,6 @@ function classifyStoreError(err) {
|
|
|
9782
9704
|
if (TRANSPORT_PHRASES.some((f) => message.includes(f))) return "transport";
|
|
9783
9705
|
return "permanent";
|
|
9784
9706
|
}
|
|
9785
|
-
/**
|
|
9786
|
-
* Collect the keys of every field marked `perNode: true`, recursing into
|
|
9787
|
-
* layout containers (`group` fields and `sub-tabs` tabs) the same way
|
|
9788
|
-
* `hydrateSchema` does. Valueless structural fields (separator/info/…)
|
|
9789
|
-
* don't declare `perNode` and are excluded by the `in` narrowing.
|
|
9790
|
-
*/
|
|
9791
|
-
/**
|
|
9792
|
-
* The same fields with every `perNode: true` one removed, recursing into layout
|
|
9793
|
-
* containers exactly as {@link collectPerNodeFieldKeys} does. A container left
|
|
9794
|
-
* with no child is dropped rather than rendered empty.
|
|
9795
|
-
*
|
|
9796
|
-
* Used by `getIntegrationSettings`: an integration is not a node, so a field
|
|
9797
|
-
* whose store key is `<key>@<nodeId>` has no node to belong to there.
|
|
9798
|
-
*/
|
|
9799
|
-
function dropPerNodeFields(fields) {
|
|
9800
|
-
const kept = [];
|
|
9801
|
-
for (const field of fields) {
|
|
9802
|
-
if (field.type === "group") {
|
|
9803
|
-
const inner = dropPerNodeFields(field.fields);
|
|
9804
|
-
if (inner.length > 0) kept.push({
|
|
9805
|
-
...field,
|
|
9806
|
-
fields: inner
|
|
9807
|
-
});
|
|
9808
|
-
continue;
|
|
9809
|
-
}
|
|
9810
|
-
if (field.type === "sub-tabs") {
|
|
9811
|
-
const tabs = field.tabs.map((tab) => ({
|
|
9812
|
-
...tab,
|
|
9813
|
-
fields: dropPerNodeFields(tab.fields)
|
|
9814
|
-
})).filter((tab) => tab.fields.length > 0);
|
|
9815
|
-
if (tabs.length > 0) kept.push({
|
|
9816
|
-
...field,
|
|
9817
|
-
tabs
|
|
9818
|
-
});
|
|
9819
|
-
continue;
|
|
9820
|
-
}
|
|
9821
|
-
if ("perNode" in field && field.perNode === true) continue;
|
|
9822
|
-
kept.push(field);
|
|
9823
|
-
}
|
|
9824
|
-
return kept;
|
|
9825
|
-
}
|
|
9826
9707
|
/** The keys of the value-holding fields, recursing into layout containers. */
|
|
9827
9708
|
function collectValueFieldKeys(fields) {
|
|
9828
9709
|
const collected = [];
|
|
@@ -9855,21 +9736,6 @@ function collectFieldKeys(fields) {
|
|
|
9855
9736
|
}
|
|
9856
9737
|
return collected;
|
|
9857
9738
|
}
|
|
9858
|
-
function collectPerNodeFieldKeys(fields) {
|
|
9859
|
-
const collected = [];
|
|
9860
|
-
for (const field of fields) {
|
|
9861
|
-
if (field.type === "group") {
|
|
9862
|
-
collected.push(...collectPerNodeFieldKeys(field.fields));
|
|
9863
|
-
continue;
|
|
9864
|
-
}
|
|
9865
|
-
if (field.type === "sub-tabs") {
|
|
9866
|
-
for (const tab of field.tabs) collected.push(...collectPerNodeFieldKeys(tab.fields));
|
|
9867
|
-
continue;
|
|
9868
|
-
}
|
|
9869
|
-
if ("perNode" in field && field.perNode === true) collected.push(field.key);
|
|
9870
|
-
}
|
|
9871
|
-
return collected;
|
|
9872
|
-
}
|
|
9873
9739
|
/**
|
|
9874
9740
|
* Normalize an `ICamstackAddon.initialize()` return value into the
|
|
9875
9741
|
* `AddonInitResult` envelope. Arrays are wrapped into `{ providers }`;
|
|
@@ -12630,13 +12496,25 @@ Object.freeze({
|
|
|
12630
12496
|
"path": "temperature",
|
|
12631
12497
|
"valueType": "number"
|
|
12632
12498
|
}],
|
|
12633
|
-
"timed-run": [
|
|
12634
|
-
|
|
12635
|
-
|
|
12636
|
-
|
|
12637
|
-
|
|
12638
|
-
|
|
12639
|
-
|
|
12499
|
+
"timed-run": [
|
|
12500
|
+
{
|
|
12501
|
+
"path": "activeUntil",
|
|
12502
|
+
"valueType": "number"
|
|
12503
|
+
},
|
|
12504
|
+
{
|
|
12505
|
+
"path": "requestedBy",
|
|
12506
|
+
"valueType": "string"
|
|
12507
|
+
},
|
|
12508
|
+
{
|
|
12509
|
+
"path": "quickRun.duration",
|
|
12510
|
+
"valueType": "number"
|
|
12511
|
+
},
|
|
12512
|
+
{
|
|
12513
|
+
"path": "quickRun.unit",
|
|
12514
|
+
"valueType": "enum",
|
|
12515
|
+
"enumValues": ["s", "min"]
|
|
12516
|
+
}
|
|
12517
|
+
],
|
|
12640
12518
|
"update": [
|
|
12641
12519
|
{
|
|
12642
12520
|
"path": "currentVersion",
|
|
@@ -12860,7 +12738,7 @@ object({
|
|
|
12860
12738
|
params: record(string(), union([string(), number$1()])).optional()
|
|
12861
12739
|
});
|
|
12862
12740
|
//#endregion
|
|
12863
|
-
//#region ../types/dist/composition-
|
|
12741
|
+
//#region ../types/dist/composition-Bx0JvKUU.mjs
|
|
12864
12742
|
/**
|
|
12865
12743
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
12866
12744
|
*
|
|
@@ -14022,6 +13900,387 @@ var NodeColorIdSchema = _enum([
|
|
|
14022
13900
|
"node-h"
|
|
14023
13901
|
]);
|
|
14024
13902
|
//#endregion
|
|
13903
|
+
//#region ../types/dist/convert-BAzH15HU.mjs
|
|
13904
|
+
/**
|
|
13905
|
+
* Frozen unit → spec table. `•` in the doc marks each dimension's canonical
|
|
13906
|
+
* unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
|
|
13907
|
+
* `factor = 5/9`, `offset = -160/9` (kept as exact expressions, not rounded
|
|
13908
|
+
* decimals). K derives from `°C = K − 273.15`.
|
|
13909
|
+
*/
|
|
13910
|
+
var UNIT_TABLE = {
|
|
13911
|
+
"°C": {
|
|
13912
|
+
dimension: "temperature",
|
|
13913
|
+
factor: 1,
|
|
13914
|
+
offset: 0
|
|
13915
|
+
},
|
|
13916
|
+
"°F": {
|
|
13917
|
+
dimension: "temperature",
|
|
13918
|
+
factor: 5 / 9,
|
|
13919
|
+
offset: -160 / 9
|
|
13920
|
+
},
|
|
13921
|
+
K: {
|
|
13922
|
+
dimension: "temperature",
|
|
13923
|
+
factor: 1,
|
|
13924
|
+
offset: -273.15
|
|
13925
|
+
},
|
|
13926
|
+
hPa: {
|
|
13927
|
+
dimension: "pressure",
|
|
13928
|
+
factor: 1,
|
|
13929
|
+
offset: 0
|
|
13930
|
+
},
|
|
13931
|
+
kPa: {
|
|
13932
|
+
dimension: "pressure",
|
|
13933
|
+
factor: 10,
|
|
13934
|
+
offset: 0
|
|
13935
|
+
},
|
|
13936
|
+
Pa: {
|
|
13937
|
+
dimension: "pressure",
|
|
13938
|
+
factor: .01,
|
|
13939
|
+
offset: 0
|
|
13940
|
+
},
|
|
13941
|
+
mbar: {
|
|
13942
|
+
dimension: "pressure",
|
|
13943
|
+
factor: 1,
|
|
13944
|
+
offset: 0
|
|
13945
|
+
},
|
|
13946
|
+
bar: {
|
|
13947
|
+
dimension: "pressure",
|
|
13948
|
+
factor: 1e3,
|
|
13949
|
+
offset: 0
|
|
13950
|
+
},
|
|
13951
|
+
inHg: {
|
|
13952
|
+
dimension: "pressure",
|
|
13953
|
+
factor: 33.8639,
|
|
13954
|
+
offset: 0
|
|
13955
|
+
},
|
|
13956
|
+
mmHg: {
|
|
13957
|
+
dimension: "pressure",
|
|
13958
|
+
factor: 1.33322,
|
|
13959
|
+
offset: 0
|
|
13960
|
+
},
|
|
13961
|
+
psi: {
|
|
13962
|
+
dimension: "pressure",
|
|
13963
|
+
factor: 68.9476,
|
|
13964
|
+
offset: 0
|
|
13965
|
+
},
|
|
13966
|
+
"m/s": {
|
|
13967
|
+
dimension: "speed",
|
|
13968
|
+
factor: 1,
|
|
13969
|
+
offset: 0
|
|
13970
|
+
},
|
|
13971
|
+
"km/h": {
|
|
13972
|
+
dimension: "speed",
|
|
13973
|
+
factor: 1 / 3.6,
|
|
13974
|
+
offset: 0
|
|
13975
|
+
},
|
|
13976
|
+
mph: {
|
|
13977
|
+
dimension: "speed",
|
|
13978
|
+
factor: .44704,
|
|
13979
|
+
offset: 0
|
|
13980
|
+
},
|
|
13981
|
+
kn: {
|
|
13982
|
+
dimension: "speed",
|
|
13983
|
+
factor: .514444,
|
|
13984
|
+
offset: 0
|
|
13985
|
+
},
|
|
13986
|
+
"mm/h": {
|
|
13987
|
+
dimension: "precipitation-rate",
|
|
13988
|
+
factor: 1,
|
|
13989
|
+
offset: 0
|
|
13990
|
+
},
|
|
13991
|
+
"in/h": {
|
|
13992
|
+
dimension: "precipitation-rate",
|
|
13993
|
+
factor: 25.4,
|
|
13994
|
+
offset: 0
|
|
13995
|
+
},
|
|
13996
|
+
m: {
|
|
13997
|
+
dimension: "length",
|
|
13998
|
+
factor: 1,
|
|
13999
|
+
offset: 0
|
|
14000
|
+
},
|
|
14001
|
+
mm: {
|
|
14002
|
+
dimension: "length",
|
|
14003
|
+
factor: .001,
|
|
14004
|
+
offset: 0
|
|
14005
|
+
},
|
|
14006
|
+
cm: {
|
|
14007
|
+
dimension: "length",
|
|
14008
|
+
factor: .01,
|
|
14009
|
+
offset: 0
|
|
14010
|
+
},
|
|
14011
|
+
km: {
|
|
14012
|
+
dimension: "length",
|
|
14013
|
+
factor: 1e3,
|
|
14014
|
+
offset: 0
|
|
14015
|
+
},
|
|
14016
|
+
in: {
|
|
14017
|
+
dimension: "length",
|
|
14018
|
+
factor: .0254,
|
|
14019
|
+
offset: 0
|
|
14020
|
+
},
|
|
14021
|
+
ft: {
|
|
14022
|
+
dimension: "length",
|
|
14023
|
+
factor: .3048,
|
|
14024
|
+
offset: 0
|
|
14025
|
+
},
|
|
14026
|
+
mi: {
|
|
14027
|
+
dimension: "length",
|
|
14028
|
+
factor: 1609.344,
|
|
14029
|
+
offset: 0
|
|
14030
|
+
},
|
|
14031
|
+
"m²": {
|
|
14032
|
+
dimension: "area",
|
|
14033
|
+
factor: 1,
|
|
14034
|
+
offset: 0
|
|
14035
|
+
},
|
|
14036
|
+
lx: {
|
|
14037
|
+
dimension: "illuminance",
|
|
14038
|
+
factor: 1,
|
|
14039
|
+
offset: 0
|
|
14040
|
+
},
|
|
14041
|
+
"W/m²": {
|
|
14042
|
+
dimension: "irradiance",
|
|
14043
|
+
factor: 1,
|
|
14044
|
+
offset: 0
|
|
14045
|
+
},
|
|
14046
|
+
W: {
|
|
14047
|
+
dimension: "power",
|
|
14048
|
+
factor: 1,
|
|
14049
|
+
offset: 0
|
|
14050
|
+
},
|
|
14051
|
+
kW: {
|
|
14052
|
+
dimension: "power",
|
|
14053
|
+
factor: 1e3,
|
|
14054
|
+
offset: 0
|
|
14055
|
+
},
|
|
14056
|
+
VA: {
|
|
14057
|
+
dimension: "apparent-power",
|
|
14058
|
+
factor: 1,
|
|
14059
|
+
offset: 0
|
|
14060
|
+
},
|
|
14061
|
+
Wh: {
|
|
14062
|
+
dimension: "energy",
|
|
14063
|
+
factor: 1,
|
|
14064
|
+
offset: 0
|
|
14065
|
+
},
|
|
14066
|
+
kWh: {
|
|
14067
|
+
dimension: "energy",
|
|
14068
|
+
factor: 1e3,
|
|
14069
|
+
offset: 0
|
|
14070
|
+
},
|
|
14071
|
+
MWh: {
|
|
14072
|
+
dimension: "energy",
|
|
14073
|
+
factor: 1e6,
|
|
14074
|
+
offset: 0
|
|
14075
|
+
},
|
|
14076
|
+
V: {
|
|
14077
|
+
dimension: "voltage",
|
|
14078
|
+
factor: 1,
|
|
14079
|
+
offset: 0
|
|
14080
|
+
},
|
|
14081
|
+
mV: {
|
|
14082
|
+
dimension: "voltage",
|
|
14083
|
+
factor: .001,
|
|
14084
|
+
offset: 0
|
|
14085
|
+
},
|
|
14086
|
+
A: {
|
|
14087
|
+
dimension: "current",
|
|
14088
|
+
factor: 1,
|
|
14089
|
+
offset: 0
|
|
14090
|
+
},
|
|
14091
|
+
mA: {
|
|
14092
|
+
dimension: "current",
|
|
14093
|
+
factor: .001,
|
|
14094
|
+
offset: 0
|
|
14095
|
+
},
|
|
14096
|
+
ppm: {
|
|
14097
|
+
dimension: "concentration-volume",
|
|
14098
|
+
factor: 1,
|
|
14099
|
+
offset: 0
|
|
14100
|
+
},
|
|
14101
|
+
ppb: {
|
|
14102
|
+
dimension: "concentration-volume",
|
|
14103
|
+
factor: .001,
|
|
14104
|
+
offset: 0
|
|
14105
|
+
},
|
|
14106
|
+
"µg/m³": {
|
|
14107
|
+
dimension: "concentration-mass",
|
|
14108
|
+
factor: 1,
|
|
14109
|
+
offset: 0
|
|
14110
|
+
},
|
|
14111
|
+
"mg/m³": {
|
|
14112
|
+
dimension: "concentration-mass",
|
|
14113
|
+
factor: 1e3,
|
|
14114
|
+
offset: 0
|
|
14115
|
+
},
|
|
14116
|
+
kg: {
|
|
14117
|
+
dimension: "mass",
|
|
14118
|
+
factor: 1,
|
|
14119
|
+
offset: 0
|
|
14120
|
+
},
|
|
14121
|
+
g: {
|
|
14122
|
+
dimension: "mass",
|
|
14123
|
+
factor: .001,
|
|
14124
|
+
offset: 0
|
|
14125
|
+
},
|
|
14126
|
+
lb: {
|
|
14127
|
+
dimension: "mass",
|
|
14128
|
+
factor: .453592,
|
|
14129
|
+
offset: 0
|
|
14130
|
+
},
|
|
14131
|
+
oz: {
|
|
14132
|
+
dimension: "mass",
|
|
14133
|
+
factor: .0283495,
|
|
14134
|
+
offset: 0
|
|
14135
|
+
},
|
|
14136
|
+
"%": {
|
|
14137
|
+
dimension: "percentage",
|
|
14138
|
+
factor: 1,
|
|
14139
|
+
offset: 0
|
|
14140
|
+
},
|
|
14141
|
+
L: {
|
|
14142
|
+
dimension: "volume",
|
|
14143
|
+
factor: 1,
|
|
14144
|
+
offset: 0
|
|
14145
|
+
},
|
|
14146
|
+
mL: {
|
|
14147
|
+
dimension: "volume",
|
|
14148
|
+
factor: .001,
|
|
14149
|
+
offset: 0
|
|
14150
|
+
},
|
|
14151
|
+
gal: {
|
|
14152
|
+
dimension: "volume",
|
|
14153
|
+
factor: 3.785411784,
|
|
14154
|
+
offset: 0
|
|
14155
|
+
},
|
|
14156
|
+
s: {
|
|
14157
|
+
dimension: "duration",
|
|
14158
|
+
factor: 1,
|
|
14159
|
+
offset: 0
|
|
14160
|
+
},
|
|
14161
|
+
ms: {
|
|
14162
|
+
dimension: "duration",
|
|
14163
|
+
factor: .001,
|
|
14164
|
+
offset: 0
|
|
14165
|
+
},
|
|
14166
|
+
min: {
|
|
14167
|
+
dimension: "duration",
|
|
14168
|
+
factor: 60,
|
|
14169
|
+
offset: 0
|
|
14170
|
+
},
|
|
14171
|
+
h: {
|
|
14172
|
+
dimension: "duration",
|
|
14173
|
+
factor: 3600,
|
|
14174
|
+
offset: 0
|
|
14175
|
+
},
|
|
14176
|
+
d: {
|
|
14177
|
+
dimension: "duration",
|
|
14178
|
+
factor: 86400,
|
|
14179
|
+
offset: 0
|
|
14180
|
+
},
|
|
14181
|
+
B: {
|
|
14182
|
+
dimension: "information",
|
|
14183
|
+
factor: 1,
|
|
14184
|
+
offset: 0
|
|
14185
|
+
},
|
|
14186
|
+
KiB: {
|
|
14187
|
+
dimension: "information",
|
|
14188
|
+
factor: 1024,
|
|
14189
|
+
offset: 0
|
|
14190
|
+
},
|
|
14191
|
+
MiB: {
|
|
14192
|
+
dimension: "information",
|
|
14193
|
+
factor: 1024 ** 2,
|
|
14194
|
+
offset: 0
|
|
14195
|
+
},
|
|
14196
|
+
GiB: {
|
|
14197
|
+
dimension: "information",
|
|
14198
|
+
factor: 1024 ** 3,
|
|
14199
|
+
offset: 0
|
|
14200
|
+
},
|
|
14201
|
+
TiB: {
|
|
14202
|
+
dimension: "information",
|
|
14203
|
+
factor: 1024 ** 4,
|
|
14204
|
+
offset: 0
|
|
14205
|
+
},
|
|
14206
|
+
kB: {
|
|
14207
|
+
dimension: "information",
|
|
14208
|
+
factor: 1e3,
|
|
14209
|
+
offset: 0
|
|
14210
|
+
},
|
|
14211
|
+
MB: {
|
|
14212
|
+
dimension: "information",
|
|
14213
|
+
factor: 1e6,
|
|
14214
|
+
offset: 0
|
|
14215
|
+
},
|
|
14216
|
+
GB: {
|
|
14217
|
+
dimension: "information",
|
|
14218
|
+
factor: 1e9,
|
|
14219
|
+
offset: 0
|
|
14220
|
+
},
|
|
14221
|
+
"°": {
|
|
14222
|
+
dimension: "angle",
|
|
14223
|
+
factor: 1,
|
|
14224
|
+
offset: 0
|
|
14225
|
+
},
|
|
14226
|
+
dBFS: {
|
|
14227
|
+
dimension: "sound-level",
|
|
14228
|
+
factor: 1,
|
|
14229
|
+
offset: 0
|
|
14230
|
+
},
|
|
14231
|
+
dBm: {
|
|
14232
|
+
dimension: "signal-level",
|
|
14233
|
+
factor: 1,
|
|
14234
|
+
offset: 0
|
|
14235
|
+
},
|
|
14236
|
+
mired: {
|
|
14237
|
+
dimension: "colour-temperature",
|
|
14238
|
+
factor: 1,
|
|
14239
|
+
offset: 0
|
|
14240
|
+
},
|
|
14241
|
+
kbps: {
|
|
14242
|
+
dimension: "bitrate",
|
|
14243
|
+
factor: 1,
|
|
14244
|
+
offset: 0
|
|
14245
|
+
},
|
|
14246
|
+
Mbps: {
|
|
14247
|
+
dimension: "bitrate",
|
|
14248
|
+
factor: 1e3,
|
|
14249
|
+
offset: 0
|
|
14250
|
+
},
|
|
14251
|
+
fps: {
|
|
14252
|
+
dimension: "rate",
|
|
14253
|
+
factor: 1,
|
|
14254
|
+
offset: 0
|
|
14255
|
+
}
|
|
14256
|
+
};
|
|
14257
|
+
/** Resolve a unit's `UnitSpec`, or `undefined` when the spelling is unknown. */
|
|
14258
|
+
function specFor(unit) {
|
|
14259
|
+
return Object.hasOwn(UNIT_TABLE, unit) ? UNIT_TABLE[unit] : void 0;
|
|
14260
|
+
}
|
|
14261
|
+
/** Value in `spec`'s unit → its dimension's canonical unit. */
|
|
14262
|
+
function toCanonical(value, spec) {
|
|
14263
|
+
return value * spec.factor + spec.offset;
|
|
14264
|
+
}
|
|
14265
|
+
/** Canonical-unit value → the unit described by `spec`. */
|
|
14266
|
+
function fromCanonical(canonical, spec) {
|
|
14267
|
+
return (canonical - spec.offset) / spec.factor;
|
|
14268
|
+
}
|
|
14269
|
+
/**
|
|
14270
|
+
* Graceful variant for the render path: returns the converted value, or
|
|
14271
|
+
* `undefined` when the conversion is refused (unknown unit / cross-dimension).
|
|
14272
|
+
* Never throws — a render caller falls back to the raw value + source unit.
|
|
14273
|
+
*/
|
|
14274
|
+
function tryConvertUnit(value, from, to) {
|
|
14275
|
+
if (from === to) return value;
|
|
14276
|
+
const fromSpec = specFor(from);
|
|
14277
|
+
if (!fromSpec) return void 0;
|
|
14278
|
+
const toSpec = specFor(to);
|
|
14279
|
+
if (!toSpec) return void 0;
|
|
14280
|
+
if (fromSpec.dimension !== toSpec.dimension) return void 0;
|
|
14281
|
+
return fromCanonical(toCanonical(value, fromSpec), toSpec);
|
|
14282
|
+
}
|
|
14283
|
+
//#endregion
|
|
14025
14284
|
//#region ../types/dist/index.mjs
|
|
14026
14285
|
var SMTP_INBOUND_DEFAULT_PORT = 2525;
|
|
14027
14286
|
var SMTP_INBOUND_DEFAULT_DOMAIN = "camstack.local";
|
|
@@ -16242,20 +16501,6 @@ async function flattenNestedRecords(ports, spec) {
|
|
|
16242
16501
|
summary: { converted: rows.size }
|
|
16243
16502
|
};
|
|
16244
16503
|
}
|
|
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
16504
|
/**
|
|
16260
16505
|
* The addon-side ports of `moveIntegrationRowsToRecords` (planning#416). An addon runs the move
|
|
16261
16506
|
* from its own process, so the leftover rows are reached through the migration-only door
|
|
@@ -16303,25 +16548,6 @@ function integrationRowsPortsOverApi(deps) {
|
|
|
16303
16548
|
}
|
|
16304
16549
|
};
|
|
16305
16550
|
}
|
|
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
16551
|
/**
|
|
16326
16552
|
* The trainer contract — what the hub hands the cloud trainer and what it
|
|
16327
16553
|
* gets back (cloud training, D805+).
|
|
@@ -43519,6 +43745,7 @@ var ExpressionBindingSourceSchema = union([
|
|
|
43519
43745
|
object({
|
|
43520
43746
|
kind: literal("global"),
|
|
43521
43747
|
sourceStableId: string(),
|
|
43748
|
+
addonId: string().optional(),
|
|
43522
43749
|
cap: string(),
|
|
43523
43750
|
fieldPath: string()
|
|
43524
43751
|
})
|
|
@@ -43645,385 +43872,6 @@ function extractSourceInfoFromMetadata(metadata) {
|
|
|
43645
43872
|
return parsed.data;
|
|
43646
43873
|
}
|
|
43647
43874
|
/**
|
|
43648
|
-
* Frozen unit → spec table. `•` in the doc marks each dimension's canonical
|
|
43649
|
-
* unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
|
|
43650
|
-
* `factor = 5/9`, `offset = -160/9` (kept as exact expressions, not rounded
|
|
43651
|
-
* decimals). K derives from `°C = K − 273.15`.
|
|
43652
|
-
*/
|
|
43653
|
-
var UNIT_TABLE = {
|
|
43654
|
-
"°C": {
|
|
43655
|
-
dimension: "temperature",
|
|
43656
|
-
factor: 1,
|
|
43657
|
-
offset: 0
|
|
43658
|
-
},
|
|
43659
|
-
"°F": {
|
|
43660
|
-
dimension: "temperature",
|
|
43661
|
-
factor: 5 / 9,
|
|
43662
|
-
offset: -160 / 9
|
|
43663
|
-
},
|
|
43664
|
-
K: {
|
|
43665
|
-
dimension: "temperature",
|
|
43666
|
-
factor: 1,
|
|
43667
|
-
offset: -273.15
|
|
43668
|
-
},
|
|
43669
|
-
hPa: {
|
|
43670
|
-
dimension: "pressure",
|
|
43671
|
-
factor: 1,
|
|
43672
|
-
offset: 0
|
|
43673
|
-
},
|
|
43674
|
-
kPa: {
|
|
43675
|
-
dimension: "pressure",
|
|
43676
|
-
factor: 10,
|
|
43677
|
-
offset: 0
|
|
43678
|
-
},
|
|
43679
|
-
Pa: {
|
|
43680
|
-
dimension: "pressure",
|
|
43681
|
-
factor: .01,
|
|
43682
|
-
offset: 0
|
|
43683
|
-
},
|
|
43684
|
-
mbar: {
|
|
43685
|
-
dimension: "pressure",
|
|
43686
|
-
factor: 1,
|
|
43687
|
-
offset: 0
|
|
43688
|
-
},
|
|
43689
|
-
bar: {
|
|
43690
|
-
dimension: "pressure",
|
|
43691
|
-
factor: 1e3,
|
|
43692
|
-
offset: 0
|
|
43693
|
-
},
|
|
43694
|
-
inHg: {
|
|
43695
|
-
dimension: "pressure",
|
|
43696
|
-
factor: 33.8639,
|
|
43697
|
-
offset: 0
|
|
43698
|
-
},
|
|
43699
|
-
mmHg: {
|
|
43700
|
-
dimension: "pressure",
|
|
43701
|
-
factor: 1.33322,
|
|
43702
|
-
offset: 0
|
|
43703
|
-
},
|
|
43704
|
-
psi: {
|
|
43705
|
-
dimension: "pressure",
|
|
43706
|
-
factor: 68.9476,
|
|
43707
|
-
offset: 0
|
|
43708
|
-
},
|
|
43709
|
-
"m/s": {
|
|
43710
|
-
dimension: "speed",
|
|
43711
|
-
factor: 1,
|
|
43712
|
-
offset: 0
|
|
43713
|
-
},
|
|
43714
|
-
"km/h": {
|
|
43715
|
-
dimension: "speed",
|
|
43716
|
-
factor: 1 / 3.6,
|
|
43717
|
-
offset: 0
|
|
43718
|
-
},
|
|
43719
|
-
mph: {
|
|
43720
|
-
dimension: "speed",
|
|
43721
|
-
factor: .44704,
|
|
43722
|
-
offset: 0
|
|
43723
|
-
},
|
|
43724
|
-
kn: {
|
|
43725
|
-
dimension: "speed",
|
|
43726
|
-
factor: .514444,
|
|
43727
|
-
offset: 0
|
|
43728
|
-
},
|
|
43729
|
-
"mm/h": {
|
|
43730
|
-
dimension: "precipitation-rate",
|
|
43731
|
-
factor: 1,
|
|
43732
|
-
offset: 0
|
|
43733
|
-
},
|
|
43734
|
-
"in/h": {
|
|
43735
|
-
dimension: "precipitation-rate",
|
|
43736
|
-
factor: 25.4,
|
|
43737
|
-
offset: 0
|
|
43738
|
-
},
|
|
43739
|
-
m: {
|
|
43740
|
-
dimension: "length",
|
|
43741
|
-
factor: 1,
|
|
43742
|
-
offset: 0
|
|
43743
|
-
},
|
|
43744
|
-
mm: {
|
|
43745
|
-
dimension: "length",
|
|
43746
|
-
factor: .001,
|
|
43747
|
-
offset: 0
|
|
43748
|
-
},
|
|
43749
|
-
cm: {
|
|
43750
|
-
dimension: "length",
|
|
43751
|
-
factor: .01,
|
|
43752
|
-
offset: 0
|
|
43753
|
-
},
|
|
43754
|
-
km: {
|
|
43755
|
-
dimension: "length",
|
|
43756
|
-
factor: 1e3,
|
|
43757
|
-
offset: 0
|
|
43758
|
-
},
|
|
43759
|
-
in: {
|
|
43760
|
-
dimension: "length",
|
|
43761
|
-
factor: .0254,
|
|
43762
|
-
offset: 0
|
|
43763
|
-
},
|
|
43764
|
-
ft: {
|
|
43765
|
-
dimension: "length",
|
|
43766
|
-
factor: .3048,
|
|
43767
|
-
offset: 0
|
|
43768
|
-
},
|
|
43769
|
-
mi: {
|
|
43770
|
-
dimension: "length",
|
|
43771
|
-
factor: 1609.344,
|
|
43772
|
-
offset: 0
|
|
43773
|
-
},
|
|
43774
|
-
"m²": {
|
|
43775
|
-
dimension: "area",
|
|
43776
|
-
factor: 1,
|
|
43777
|
-
offset: 0
|
|
43778
|
-
},
|
|
43779
|
-
lx: {
|
|
43780
|
-
dimension: "illuminance",
|
|
43781
|
-
factor: 1,
|
|
43782
|
-
offset: 0
|
|
43783
|
-
},
|
|
43784
|
-
"W/m²": {
|
|
43785
|
-
dimension: "irradiance",
|
|
43786
|
-
factor: 1,
|
|
43787
|
-
offset: 0
|
|
43788
|
-
},
|
|
43789
|
-
W: {
|
|
43790
|
-
dimension: "power",
|
|
43791
|
-
factor: 1,
|
|
43792
|
-
offset: 0
|
|
43793
|
-
},
|
|
43794
|
-
kW: {
|
|
43795
|
-
dimension: "power",
|
|
43796
|
-
factor: 1e3,
|
|
43797
|
-
offset: 0
|
|
43798
|
-
},
|
|
43799
|
-
VA: {
|
|
43800
|
-
dimension: "apparent-power",
|
|
43801
|
-
factor: 1,
|
|
43802
|
-
offset: 0
|
|
43803
|
-
},
|
|
43804
|
-
Wh: {
|
|
43805
|
-
dimension: "energy",
|
|
43806
|
-
factor: 1,
|
|
43807
|
-
offset: 0
|
|
43808
|
-
},
|
|
43809
|
-
kWh: {
|
|
43810
|
-
dimension: "energy",
|
|
43811
|
-
factor: 1e3,
|
|
43812
|
-
offset: 0
|
|
43813
|
-
},
|
|
43814
|
-
MWh: {
|
|
43815
|
-
dimension: "energy",
|
|
43816
|
-
factor: 1e6,
|
|
43817
|
-
offset: 0
|
|
43818
|
-
},
|
|
43819
|
-
V: {
|
|
43820
|
-
dimension: "voltage",
|
|
43821
|
-
factor: 1,
|
|
43822
|
-
offset: 0
|
|
43823
|
-
},
|
|
43824
|
-
mV: {
|
|
43825
|
-
dimension: "voltage",
|
|
43826
|
-
factor: .001,
|
|
43827
|
-
offset: 0
|
|
43828
|
-
},
|
|
43829
|
-
A: {
|
|
43830
|
-
dimension: "current",
|
|
43831
|
-
factor: 1,
|
|
43832
|
-
offset: 0
|
|
43833
|
-
},
|
|
43834
|
-
mA: {
|
|
43835
|
-
dimension: "current",
|
|
43836
|
-
factor: .001,
|
|
43837
|
-
offset: 0
|
|
43838
|
-
},
|
|
43839
|
-
ppm: {
|
|
43840
|
-
dimension: "concentration-volume",
|
|
43841
|
-
factor: 1,
|
|
43842
|
-
offset: 0
|
|
43843
|
-
},
|
|
43844
|
-
ppb: {
|
|
43845
|
-
dimension: "concentration-volume",
|
|
43846
|
-
factor: .001,
|
|
43847
|
-
offset: 0
|
|
43848
|
-
},
|
|
43849
|
-
"µg/m³": {
|
|
43850
|
-
dimension: "concentration-mass",
|
|
43851
|
-
factor: 1,
|
|
43852
|
-
offset: 0
|
|
43853
|
-
},
|
|
43854
|
-
"mg/m³": {
|
|
43855
|
-
dimension: "concentration-mass",
|
|
43856
|
-
factor: 1e3,
|
|
43857
|
-
offset: 0
|
|
43858
|
-
},
|
|
43859
|
-
kg: {
|
|
43860
|
-
dimension: "mass",
|
|
43861
|
-
factor: 1,
|
|
43862
|
-
offset: 0
|
|
43863
|
-
},
|
|
43864
|
-
g: {
|
|
43865
|
-
dimension: "mass",
|
|
43866
|
-
factor: .001,
|
|
43867
|
-
offset: 0
|
|
43868
|
-
},
|
|
43869
|
-
lb: {
|
|
43870
|
-
dimension: "mass",
|
|
43871
|
-
factor: .453592,
|
|
43872
|
-
offset: 0
|
|
43873
|
-
},
|
|
43874
|
-
oz: {
|
|
43875
|
-
dimension: "mass",
|
|
43876
|
-
factor: .0283495,
|
|
43877
|
-
offset: 0
|
|
43878
|
-
},
|
|
43879
|
-
"%": {
|
|
43880
|
-
dimension: "percentage",
|
|
43881
|
-
factor: 1,
|
|
43882
|
-
offset: 0
|
|
43883
|
-
},
|
|
43884
|
-
L: {
|
|
43885
|
-
dimension: "volume",
|
|
43886
|
-
factor: 1,
|
|
43887
|
-
offset: 0
|
|
43888
|
-
},
|
|
43889
|
-
mL: {
|
|
43890
|
-
dimension: "volume",
|
|
43891
|
-
factor: .001,
|
|
43892
|
-
offset: 0
|
|
43893
|
-
},
|
|
43894
|
-
gal: {
|
|
43895
|
-
dimension: "volume",
|
|
43896
|
-
factor: 3.785411784,
|
|
43897
|
-
offset: 0
|
|
43898
|
-
},
|
|
43899
|
-
s: {
|
|
43900
|
-
dimension: "duration",
|
|
43901
|
-
factor: 1,
|
|
43902
|
-
offset: 0
|
|
43903
|
-
},
|
|
43904
|
-
ms: {
|
|
43905
|
-
dimension: "duration",
|
|
43906
|
-
factor: .001,
|
|
43907
|
-
offset: 0
|
|
43908
|
-
},
|
|
43909
|
-
min: {
|
|
43910
|
-
dimension: "duration",
|
|
43911
|
-
factor: 60,
|
|
43912
|
-
offset: 0
|
|
43913
|
-
},
|
|
43914
|
-
h: {
|
|
43915
|
-
dimension: "duration",
|
|
43916
|
-
factor: 3600,
|
|
43917
|
-
offset: 0
|
|
43918
|
-
},
|
|
43919
|
-
d: {
|
|
43920
|
-
dimension: "duration",
|
|
43921
|
-
factor: 86400,
|
|
43922
|
-
offset: 0
|
|
43923
|
-
},
|
|
43924
|
-
B: {
|
|
43925
|
-
dimension: "information",
|
|
43926
|
-
factor: 1,
|
|
43927
|
-
offset: 0
|
|
43928
|
-
},
|
|
43929
|
-
KiB: {
|
|
43930
|
-
dimension: "information",
|
|
43931
|
-
factor: 1024,
|
|
43932
|
-
offset: 0
|
|
43933
|
-
},
|
|
43934
|
-
MiB: {
|
|
43935
|
-
dimension: "information",
|
|
43936
|
-
factor: 1024 ** 2,
|
|
43937
|
-
offset: 0
|
|
43938
|
-
},
|
|
43939
|
-
GiB: {
|
|
43940
|
-
dimension: "information",
|
|
43941
|
-
factor: 1024 ** 3,
|
|
43942
|
-
offset: 0
|
|
43943
|
-
},
|
|
43944
|
-
TiB: {
|
|
43945
|
-
dimension: "information",
|
|
43946
|
-
factor: 1024 ** 4,
|
|
43947
|
-
offset: 0
|
|
43948
|
-
},
|
|
43949
|
-
kB: {
|
|
43950
|
-
dimension: "information",
|
|
43951
|
-
factor: 1e3,
|
|
43952
|
-
offset: 0
|
|
43953
|
-
},
|
|
43954
|
-
MB: {
|
|
43955
|
-
dimension: "information",
|
|
43956
|
-
factor: 1e6,
|
|
43957
|
-
offset: 0
|
|
43958
|
-
},
|
|
43959
|
-
GB: {
|
|
43960
|
-
dimension: "information",
|
|
43961
|
-
factor: 1e9,
|
|
43962
|
-
offset: 0
|
|
43963
|
-
},
|
|
43964
|
-
"°": {
|
|
43965
|
-
dimension: "angle",
|
|
43966
|
-
factor: 1,
|
|
43967
|
-
offset: 0
|
|
43968
|
-
},
|
|
43969
|
-
dBFS: {
|
|
43970
|
-
dimension: "sound-level",
|
|
43971
|
-
factor: 1,
|
|
43972
|
-
offset: 0
|
|
43973
|
-
},
|
|
43974
|
-
dBm: {
|
|
43975
|
-
dimension: "signal-level",
|
|
43976
|
-
factor: 1,
|
|
43977
|
-
offset: 0
|
|
43978
|
-
},
|
|
43979
|
-
mired: {
|
|
43980
|
-
dimension: "colour-temperature",
|
|
43981
|
-
factor: 1,
|
|
43982
|
-
offset: 0
|
|
43983
|
-
},
|
|
43984
|
-
kbps: {
|
|
43985
|
-
dimension: "bitrate",
|
|
43986
|
-
factor: 1,
|
|
43987
|
-
offset: 0
|
|
43988
|
-
},
|
|
43989
|
-
Mbps: {
|
|
43990
|
-
dimension: "bitrate",
|
|
43991
|
-
factor: 1e3,
|
|
43992
|
-
offset: 0
|
|
43993
|
-
},
|
|
43994
|
-
fps: {
|
|
43995
|
-
dimension: "rate",
|
|
43996
|
-
factor: 1,
|
|
43997
|
-
offset: 0
|
|
43998
|
-
}
|
|
43999
|
-
};
|
|
44000
|
-
/** Resolve a unit's `UnitSpec`, or `undefined` when the spelling is unknown. */
|
|
44001
|
-
function specFor(unit) {
|
|
44002
|
-
return Object.hasOwn(UNIT_TABLE, unit) ? UNIT_TABLE[unit] : void 0;
|
|
44003
|
-
}
|
|
44004
|
-
/** Value in `spec`'s unit → its dimension's canonical unit. */
|
|
44005
|
-
function toCanonical(value, spec) {
|
|
44006
|
-
return value * spec.factor + spec.offset;
|
|
44007
|
-
}
|
|
44008
|
-
/** Canonical-unit value → the unit described by `spec`. */
|
|
44009
|
-
function fromCanonical(canonical, spec) {
|
|
44010
|
-
return (canonical - spec.offset) / spec.factor;
|
|
44011
|
-
}
|
|
44012
|
-
/**
|
|
44013
|
-
* Graceful variant for the render path: returns the converted value, or
|
|
44014
|
-
* `undefined` when the conversion is refused (unknown unit / cross-dimension).
|
|
44015
|
-
* Never throws — a render caller falls back to the raw value + source unit.
|
|
44016
|
-
*/
|
|
44017
|
-
function tryConvertUnit(value, from, to) {
|
|
44018
|
-
if (from === to) return value;
|
|
44019
|
-
const fromSpec = specFor(from);
|
|
44020
|
-
if (!fromSpec) return void 0;
|
|
44021
|
-
const toSpec = specFor(to);
|
|
44022
|
-
if (!toSpec) return void 0;
|
|
44023
|
-
if (fromSpec.dimension !== toSpec.dimension) return void 0;
|
|
44024
|
-
return fromCanonical(toCanonical(value, fromSpec), toSpec);
|
|
44025
|
-
}
|
|
44026
|
-
/**
|
|
44027
43875
|
* A number a person types for a physical quantity — the input side of the
|
|
44028
43876
|
* value + unit contract (D972).
|
|
44029
43877
|
*
|
|
@@ -45721,26 +45569,23 @@ var SettingsSchemaWithValuesSchema = object({
|
|
|
45721
45569
|
var SettingsPatchSchema = record(string(), unknown());
|
|
45722
45570
|
/** The scope of a scoped-settings call (D986): where the capability declared the values. */
|
|
45723
45571
|
var ScopedSettingsScopeSchema = _enum(SCOPED_SETTINGS_SCOPES);
|
|
45572
|
+
/** One scoped schema an addon serves: its capability, scope and section ids. */
|
|
45573
|
+
var ScopedSettingsDeclarationSchema = object({
|
|
45574
|
+
cap: string(),
|
|
45575
|
+
scope: ScopedSettingsScopeSchema,
|
|
45576
|
+
sectionIds: array(string())
|
|
45577
|
+
});
|
|
45724
45578
|
/** Standard success response for update operations. */
|
|
45725
45579
|
var SettingsUpdateResultSchema = object({ success: literal(true) });
|
|
45726
45580
|
method(object({
|
|
45727
|
-
addonId: string(),
|
|
45728
|
-
nodeId: string().optional(),
|
|
45729
|
-
overlay: record(string(), unknown()).optional(),
|
|
45730
|
-
cap: string().optional()
|
|
45731
|
-
}), SettingsSchemaWithValuesSchema.nullable()), method(object({
|
|
45732
|
-
addonId: string(),
|
|
45733
|
-
nodeId: string().optional(),
|
|
45734
|
-
patch: SettingsPatchSchema
|
|
45735
|
-
}), SettingsUpdateResultSchema, {
|
|
45736
|
-
kind: "mutation",
|
|
45737
|
-
auth: "admin"
|
|
45738
|
-
}), method(object({
|
|
45739
45581
|
addonId: string(),
|
|
45740
45582
|
cap: string(),
|
|
45741
45583
|
scope: ScopedSettingsScopeSchema,
|
|
45742
45584
|
nodeId: string().optional()
|
|
45743
45585
|
}), SettingsSchemaWithValuesSchema.nullable()), method(object({
|
|
45586
|
+
addonId: string(),
|
|
45587
|
+
nodeId: string().optional()
|
|
45588
|
+
}), array(ScopedSettingsDeclarationSchema).nullable()), method(object({
|
|
45744
45589
|
addonId: string(),
|
|
45745
45590
|
cap: string(),
|
|
45746
45591
|
scope: ScopedSettingsScopeSchema,
|
|
@@ -45755,9 +45600,6 @@ method(object({
|
|
|
45755
45600
|
scope: ScopedSettingsScopeSchema,
|
|
45756
45601
|
nodeId: string().optional()
|
|
45757
45602
|
}), record(string(), unknown()).nullable()), method(object({
|
|
45758
|
-
addonId: string(),
|
|
45759
|
-
nodeId: string().optional()
|
|
45760
|
-
}), SettingsSchemaWithValuesSchema.nullable()), method(object({
|
|
45761
45603
|
addonId: string(),
|
|
45762
45604
|
nodeId: string().optional(),
|
|
45763
45605
|
instance: IntegrationInstanceRefSchema
|
|
@@ -47320,7 +47162,7 @@ var BackupDestinationInfoSchema = object({
|
|
|
47320
47162
|
id: string(),
|
|
47321
47163
|
/**
|
|
47322
47164
|
* Manifest id of the owning addon. The Settings button on the
|
|
47323
|
-
* destination card opens that addon's
|
|
47165
|
+
* destination card opens that addon's scoped settings panel.
|
|
47324
47166
|
*/
|
|
47325
47167
|
addonId: string(),
|
|
47326
47168
|
/** Operator-toggled enable flag from the destination-policy table. */
|
|
@@ -52797,6 +52639,7 @@ method(InstancePinSchema, DeviceExportStatusSchema), method(_void(), array(Expor
|
|
|
52797
52639
|
kind: "mutation",
|
|
52798
52640
|
auth: "admin"
|
|
52799
52641
|
});
|
|
52642
|
+
var DeviceAliasSchema = string().max(64).regex(/^[a-z][a-z0-9_]*$/);
|
|
52800
52643
|
/**
|
|
52801
52644
|
* A SITE ZONE — a named part of the property that several locations belong to.
|
|
52802
52645
|
*
|
|
@@ -53283,6 +53126,12 @@ var DeviceInfoSchema = object({
|
|
|
53283
53126
|
addonId: string(),
|
|
53284
53127
|
type: _enum(DeviceType),
|
|
53285
53128
|
name: string(),
|
|
53129
|
+
/** The name a value template uses for this device (`{{ stufa_veranda.temperature }}`),
|
|
53130
|
+
* entity_id style. Generated once from the name at first registration, unique
|
|
53131
|
+
* cluster-wide, editable through `setAlias`, NOT changed by a rename (D1021).
|
|
53132
|
+
* Optional: a record produced by an older build omits it until the boot
|
|
53133
|
+
* backfill has run. */
|
|
53134
|
+
alias: DeviceAliasSchema.optional(),
|
|
53286
53135
|
/** Operator-organisational location label. `null` when unset. */
|
|
53287
53136
|
location: string().nullable(),
|
|
53288
53137
|
/** Soft-disabled flag. */
|
|
@@ -53602,6 +53451,25 @@ method(object({
|
|
|
53602
53451
|
}), _void(), {
|
|
53603
53452
|
kind: "mutation",
|
|
53604
53453
|
auth: "admin"
|
|
53454
|
+
}), method(object({
|
|
53455
|
+
deviceId: number$1(),
|
|
53456
|
+
alias: string()
|
|
53457
|
+
}), discriminatedUnion("ok", [object({
|
|
53458
|
+
ok: literal(true),
|
|
53459
|
+
alias: DeviceAliasSchema
|
|
53460
|
+
}), object({
|
|
53461
|
+
ok: literal(false),
|
|
53462
|
+
reason: _enum([
|
|
53463
|
+
"empty",
|
|
53464
|
+
"too-long",
|
|
53465
|
+
"grammar",
|
|
53466
|
+
"reserved",
|
|
53467
|
+
"taken"
|
|
53468
|
+
]),
|
|
53469
|
+
takenBy: number$1().optional()
|
|
53470
|
+
})]), {
|
|
53471
|
+
kind: "mutation",
|
|
53472
|
+
auth: "admin"
|
|
53605
53473
|
}), method(object({
|
|
53606
53474
|
deviceId: number$1(),
|
|
53607
53475
|
location: string().nullable()
|
|
@@ -67702,6 +67570,11 @@ var NcScheduleSchema = object({
|
|
|
67702
67570
|
* as a STATE SUMMARY at the end of each window of `schedule`.
|
|
67703
67571
|
*/
|
|
67704
67572
|
var NcSystemEventDeliveryModeSchema = _enum(["instant", "summary"]);
|
|
67573
|
+
_enum([
|
|
67574
|
+
"activation",
|
|
67575
|
+
"deactivation",
|
|
67576
|
+
"schedule"
|
|
67577
|
+
]);
|
|
67705
67578
|
/**
|
|
67706
67579
|
* How a summary window is SENT (D698): `rule` (absent) = ONE notification with
|
|
67707
67580
|
* every section; `section` = one notification per section with something to
|
|
@@ -67718,11 +67591,26 @@ var NcStateSummarySplitSchema = _enum(["rule", "section"]);
|
|
|
67718
67591
|
* midnight crossing); the send time is each window's END. Refused on the
|
|
67719
67592
|
* `alarm` family, which stays instant (`systemEventDeliveryProblems`).
|
|
67720
67593
|
*/
|
|
67721
|
-
var NcSystemEventDeliverySchema = discriminatedUnion("mode", [
|
|
67722
|
-
mode: literal("
|
|
67723
|
-
|
|
67724
|
-
|
|
67725
|
-
|
|
67594
|
+
var NcSystemEventDeliverySchema = discriminatedUnion("mode", [
|
|
67595
|
+
object({ mode: literal("instant") }),
|
|
67596
|
+
object({
|
|
67597
|
+
mode: literal("summary"),
|
|
67598
|
+
schedule: NcScheduleSchema,
|
|
67599
|
+
split: NcStateSummarySplitSchema.optional()
|
|
67600
|
+
}),
|
|
67601
|
+
object({
|
|
67602
|
+
mode: literal("modes"),
|
|
67603
|
+
/** The bad edge, and every kind that has a single edge. */
|
|
67604
|
+
onActivation: boolean(),
|
|
67605
|
+
/** The recovery edges of the classes of the selected kinds (derived, never stored per kind). */
|
|
67606
|
+
onDeactivation: boolean(),
|
|
67607
|
+
/** A state summary at the end of each window; absent = no summary. */
|
|
67608
|
+
onSchedule: object({
|
|
67609
|
+
schedule: NcScheduleSchema,
|
|
67610
|
+
grouping: NcStateSummarySplitSchema
|
|
67611
|
+
}).optional()
|
|
67612
|
+
})
|
|
67613
|
+
]);
|
|
67726
67614
|
/** Fuzzy plate matcher — OCR noise makes exact match useless (spec row 12/13). */
|
|
67727
67615
|
var NcPlateMatcherSchema = object({
|
|
67728
67616
|
/**
|
|
@@ -75813,93 +75701,27 @@ var RunningFlipEventDataSchema = object({
|
|
|
75813
75701
|
phase: string().nullable()
|
|
75814
75702
|
});
|
|
75815
75703
|
var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
75816
|
-
/**
|
|
75817
|
-
|
|
75818
|
-
|
|
75819
|
-
|
|
75820
|
-
|
|
75821
|
-
|
|
75822
|
-
|
|
75823
|
-
|
|
75824
|
-
|
|
75825
|
-
|
|
75826
|
-
|
|
75827
|
-
|
|
75828
|
-
|
|
75829
|
-
|
|
75830
|
-
|
|
75831
|
-
|
|
75832
|
-
|
|
75833
|
-
|
|
75834
|
-
|
|
75835
|
-
|
|
75836
|
-
|
|
75837
|
-
DeviceType.WaterHeater,
|
|
75838
|
-
DeviceType.Humidifier,
|
|
75839
|
-
DeviceType.Fan,
|
|
75840
|
-
DeviceType.Climate,
|
|
75841
|
-
DeviceType.Thermostat,
|
|
75842
|
-
DeviceType.PetFeeder,
|
|
75843
|
-
DeviceType.Heater
|
|
75844
|
-
],
|
|
75845
|
-
apply: "add",
|
|
75846
|
-
path: "running",
|
|
75847
|
-
sources: [
|
|
75848
|
-
{
|
|
75849
|
-
kind: "switch",
|
|
75850
|
-
transforms: [{ kind: "identity" }]
|
|
75851
|
-
},
|
|
75852
|
-
{
|
|
75853
|
-
kind: "binary",
|
|
75854
|
-
transforms: [{ kind: "identity" }, { kind: "invert" }]
|
|
75855
|
-
},
|
|
75856
|
-
{
|
|
75857
|
-
kind: "numeric",
|
|
75858
|
-
requiredUnit: "W",
|
|
75859
|
-
transforms: [{
|
|
75860
|
-
kind: "threshold",
|
|
75861
|
-
comparisons: ["gte", "lte"],
|
|
75862
|
-
comparison: "gte",
|
|
75863
|
-
defaultThreshold: 5,
|
|
75864
|
-
defaultStartDwellMs: RUNNING_POWER_START_DELAY_MS,
|
|
75865
|
-
defaultStopDwellMs: RUNNING_POWER_STOP_DELAY_MS,
|
|
75866
|
-
thresholdUnit: "W"
|
|
75867
|
-
}]
|
|
75868
|
-
}
|
|
75869
|
-
],
|
|
75870
|
-
companions: [
|
|
75871
|
-
{
|
|
75872
|
-
kind: "constant",
|
|
75873
|
-
path: "source",
|
|
75874
|
-
value: "assigned",
|
|
75875
|
-
when: "always"
|
|
75876
|
-
},
|
|
75877
|
-
{
|
|
75878
|
-
kind: "constant",
|
|
75879
|
-
path: "phase",
|
|
75880
|
-
value: null,
|
|
75881
|
-
when: "add"
|
|
75882
|
-
},
|
|
75883
|
-
{
|
|
75884
|
-
kind: "clock",
|
|
75885
|
-
path: "lastFetchedAt",
|
|
75886
|
-
when: "always"
|
|
75887
|
-
},
|
|
75888
|
-
{
|
|
75889
|
-
kind: "transition-time",
|
|
75890
|
-
path: "since",
|
|
75891
|
-
sourceChangedAt: "prefer"
|
|
75892
|
-
}
|
|
75893
|
-
],
|
|
75894
|
-
sourceReport: {
|
|
75895
|
-
status: "assignment-status",
|
|
75896
|
-
runtimeField: "source",
|
|
75897
|
-
nativeValue: "native",
|
|
75898
|
-
assignedValue: "assigned"
|
|
75899
|
-
},
|
|
75900
|
-
advancedExpression: true
|
|
75901
|
-
}]
|
|
75902
|
-
};
|
|
75704
|
+
/**
|
|
75705
|
+
* Customize offers "running" only where a job makes sense (D933): a cycle,
|
|
75706
|
+
* a clean, a mow, playback, or another appliance that is on and working.
|
|
75707
|
+
* The cap itself stays on every type — a camera can still report running
|
|
75708
|
+
* natively; it just has no card.
|
|
75709
|
+
*/
|
|
75710
|
+
var RUNNING_CUSTOMIZE_DEVICE_TYPES = [
|
|
75711
|
+
DeviceType.Washer,
|
|
75712
|
+
DeviceType.Dryer,
|
|
75713
|
+
DeviceType.Dishwasher,
|
|
75714
|
+
DeviceType.Vacuum,
|
|
75715
|
+
DeviceType.LawnMower,
|
|
75716
|
+
DeviceType.MediaPlayer,
|
|
75717
|
+
DeviceType.WaterHeater,
|
|
75718
|
+
DeviceType.Humidifier,
|
|
75719
|
+
DeviceType.Fan,
|
|
75720
|
+
DeviceType.Climate,
|
|
75721
|
+
DeviceType.Thermostat,
|
|
75722
|
+
DeviceType.PetFeeder,
|
|
75723
|
+
DeviceType.Heater
|
|
75724
|
+
];
|
|
75903
75725
|
var runningStateCapability = {
|
|
75904
75726
|
name: "running-state",
|
|
75905
75727
|
scope: "device",
|
|
@@ -75919,7 +75741,78 @@ var runningStateCapability = {
|
|
|
75919
75741
|
durability: "restored",
|
|
75920
75742
|
history: { fields: { running: { kind: "boolean" } } },
|
|
75921
75743
|
volatileStateFields: ["lastFetchedAt"],
|
|
75922
|
-
customize:
|
|
75744
|
+
customize: {
|
|
75745
|
+
version: 1,
|
|
75746
|
+
overridable: [{
|
|
75747
|
+
path: "running",
|
|
75748
|
+
by: "running"
|
|
75749
|
+
}],
|
|
75750
|
+
targets: [{
|
|
75751
|
+
id: "running",
|
|
75752
|
+
cardinality: "scalar",
|
|
75753
|
+
vocabulary: {
|
|
75754
|
+
cap: "running-state",
|
|
75755
|
+
stateField: "running"
|
|
75756
|
+
},
|
|
75757
|
+
deviceTypes: RUNNING_CUSTOMIZE_DEVICE_TYPES,
|
|
75758
|
+
apply: "add",
|
|
75759
|
+
path: "running",
|
|
75760
|
+
sources: [
|
|
75761
|
+
{
|
|
75762
|
+
kind: "switch",
|
|
75763
|
+
transforms: [{ kind: "identity" }]
|
|
75764
|
+
},
|
|
75765
|
+
{
|
|
75766
|
+
kind: "binary",
|
|
75767
|
+
transforms: [{ kind: "identity" }, { kind: "invert" }]
|
|
75768
|
+
},
|
|
75769
|
+
{
|
|
75770
|
+
kind: "numeric",
|
|
75771
|
+
requiredUnit: "W",
|
|
75772
|
+
transforms: [{
|
|
75773
|
+
kind: "threshold",
|
|
75774
|
+
comparisons: ["gte", "lte"],
|
|
75775
|
+
comparison: "gte",
|
|
75776
|
+
defaultThreshold: 5,
|
|
75777
|
+
defaultStartDwellMs: RUNNING_POWER_START_DELAY_MS,
|
|
75778
|
+
defaultStopDwellMs: RUNNING_POWER_STOP_DELAY_MS,
|
|
75779
|
+
thresholdUnit: "W"
|
|
75780
|
+
}]
|
|
75781
|
+
}
|
|
75782
|
+
],
|
|
75783
|
+
companions: [
|
|
75784
|
+
{
|
|
75785
|
+
kind: "constant",
|
|
75786
|
+
path: "source",
|
|
75787
|
+
value: "assigned",
|
|
75788
|
+
when: "always"
|
|
75789
|
+
},
|
|
75790
|
+
{
|
|
75791
|
+
kind: "constant",
|
|
75792
|
+
path: "phase",
|
|
75793
|
+
value: null,
|
|
75794
|
+
when: "add"
|
|
75795
|
+
},
|
|
75796
|
+
{
|
|
75797
|
+
kind: "clock",
|
|
75798
|
+
path: "lastFetchedAt",
|
|
75799
|
+
when: "always"
|
|
75800
|
+
},
|
|
75801
|
+
{
|
|
75802
|
+
kind: "transition-time",
|
|
75803
|
+
path: "since",
|
|
75804
|
+
sourceChangedAt: "prefer"
|
|
75805
|
+
}
|
|
75806
|
+
],
|
|
75807
|
+
sourceReport: {
|
|
75808
|
+
status: "assignment-status",
|
|
75809
|
+
runtimeField: "source",
|
|
75810
|
+
nativeValue: "native",
|
|
75811
|
+
assignedValue: "assigned"
|
|
75812
|
+
},
|
|
75813
|
+
advancedExpression: true
|
|
75814
|
+
}]
|
|
75815
|
+
}
|
|
75923
75816
|
};
|
|
75924
75817
|
/**
|
|
75925
75818
|
* scene-monitor — device-scoped reference-region state cap. An operator marks
|
|
@@ -78853,6 +78746,11 @@ var TimedRunUnitSchema = _enum(["s", "min"]);
|
|
|
78853
78746
|
_enum(["switch", "pet-fountain"]);
|
|
78854
78747
|
DeviceType.Heater, DeviceType.PetFountain;
|
|
78855
78748
|
var TIMED_RUN_DEVICE_TYPES = [DeviceType.Heater, DeviceType.PetFountain];
|
|
78749
|
+
/** One duration, as the one-tap run asks for it. */
|
|
78750
|
+
var TimedRunQuickRunSchema = object({
|
|
78751
|
+
duration: number$1().positive().finite(),
|
|
78752
|
+
unit: TimedRunUnitSchema
|
|
78753
|
+
});
|
|
78856
78754
|
/** Why a request was not carried out. Typed, so a caller can say it in words. */
|
|
78857
78755
|
var TimedRunRefusalSchema = _enum([
|
|
78858
78756
|
"unsupported-device",
|
|
@@ -78873,8 +78771,23 @@ var TimedRunStatusSchema = object({
|
|
|
78873
78771
|
activeUntil: number$1().nullable(),
|
|
78874
78772
|
/** Who asked for the run (a user id or an addon id); `null` when nothing is armed or it did not say. */
|
|
78875
78773
|
requestedBy: string().nullable(),
|
|
78774
|
+
/**
|
|
78775
|
+
* The one-tap run of THIS device: what a "Run" button on any surface starts. `null` when
|
|
78776
|
+
* the device is gone or its type has no timed run; a status from before this field
|
|
78777
|
+
* existed has none, and a surface falls back to the type's default.
|
|
78778
|
+
*/
|
|
78779
|
+
quickRun: TimedRunQuickRunSchema.nullable(),
|
|
78876
78780
|
lastFetchedAt: number$1()
|
|
78877
78781
|
});
|
|
78782
|
+
/** What the settings form needs: the unit, the bounds and the type's default. */
|
|
78783
|
+
var TimedRunOptionsSchema = object({
|
|
78784
|
+
unit: TimedRunUnitSchema,
|
|
78785
|
+
/** The longest run, in `unit`. */
|
|
78786
|
+
maxDuration: number$1(),
|
|
78787
|
+
defaultDuration: number$1()
|
|
78788
|
+
});
|
|
78789
|
+
/** The one-tap run duration, in the type's unit; `null` returns to the type's default. */
|
|
78790
|
+
var TimedRunSettingsPatchSchema = object({ quickRunDuration: number$1().positive().finite().nullable().optional() });
|
|
78878
78791
|
var timedRunCapability = {
|
|
78879
78792
|
name: "timed-run",
|
|
78880
78793
|
scope: "device",
|
|
@@ -78882,7 +78795,24 @@ var timedRunCapability = {
|
|
|
78882
78795
|
kind: "wrapper",
|
|
78883
78796
|
defaultActive: true,
|
|
78884
78797
|
deviceTypes: TIMED_RUN_DEVICE_TYPES,
|
|
78798
|
+
deviceConfig: { ui: {
|
|
78799
|
+
kind: "derived-form",
|
|
78800
|
+
builderId: "timed-run",
|
|
78801
|
+
tab: "general"
|
|
78802
|
+
} },
|
|
78885
78803
|
methods: {
|
|
78804
|
+
getOptions: method(object({ deviceId: number$1().int() }), TimedRunOptionsSchema),
|
|
78805
|
+
/**
|
|
78806
|
+
* The one-tap run of this device. A duration above the type's maximum is
|
|
78807
|
+
* REFUSED (thrown), like `runFor`: the maximum is a safety bound.
|
|
78808
|
+
*/
|
|
78809
|
+
setSettings: method(object({
|
|
78810
|
+
deviceId: number$1().int(),
|
|
78811
|
+
settings: TimedRunSettingsPatchSchema
|
|
78812
|
+
}), _void(), {
|
|
78813
|
+
kind: "mutation",
|
|
78814
|
+
auth: "admin"
|
|
78815
|
+
}),
|
|
78886
78816
|
/**
|
|
78887
78817
|
* Turn the device on and arm its off. A run already armed is replaced (the
|
|
78888
78818
|
* new deadline wins). Refuses with a typed reason above the type's maximum.
|
|
@@ -83583,13 +83513,6 @@ Object.freeze({
|
|
|
83583
83513
|
access: "view",
|
|
83584
83514
|
role: "admin"
|
|
83585
83515
|
},
|
|
83586
|
-
"addonSettings.getGlobalSettings": {
|
|
83587
|
-
capName: "addon-settings",
|
|
83588
|
-
capScope: "system",
|
|
83589
|
-
addonId: null,
|
|
83590
|
-
access: "view",
|
|
83591
|
-
role: "admin"
|
|
83592
|
-
},
|
|
83593
83516
|
"addonSettings.getIntegrationFormSchema": {
|
|
83594
83517
|
capName: "addon-settings",
|
|
83595
83518
|
capScope: "system",
|
|
@@ -83597,14 +83520,14 @@ Object.freeze({
|
|
|
83597
83520
|
access: "view",
|
|
83598
83521
|
role: "admin"
|
|
83599
83522
|
},
|
|
83600
|
-
"addonSettings.
|
|
83523
|
+
"addonSettings.getScopedSettings": {
|
|
83601
83524
|
capName: "addon-settings",
|
|
83602
83525
|
capScope: "system",
|
|
83603
83526
|
addonId: null,
|
|
83604
83527
|
access: "view",
|
|
83605
83528
|
role: "admin"
|
|
83606
83529
|
},
|
|
83607
|
-
"addonSettings.
|
|
83530
|
+
"addonSettings.listScopedSettings": {
|
|
83608
83531
|
capName: "addon-settings",
|
|
83609
83532
|
capScope: "system",
|
|
83610
83533
|
addonId: null,
|
|
@@ -83632,13 +83555,6 @@ Object.freeze({
|
|
|
83632
83555
|
access: "create",
|
|
83633
83556
|
role: "admin"
|
|
83634
83557
|
},
|
|
83635
|
-
"addonSettings.updateGlobalSettings": {
|
|
83636
|
-
capName: "addon-settings",
|
|
83637
|
-
capScope: "system",
|
|
83638
|
-
addonId: null,
|
|
83639
|
-
access: "create",
|
|
83640
|
-
role: "admin"
|
|
83641
|
-
},
|
|
83642
83558
|
"addonSettings.updateScopedSettings": {
|
|
83643
83559
|
capName: "addon-settings",
|
|
83644
83560
|
capScope: "system",
|
|
@@ -85809,6 +85725,13 @@ Object.freeze({
|
|
|
85809
85725
|
access: "create",
|
|
85810
85726
|
role: "admin"
|
|
85811
85727
|
},
|
|
85728
|
+
"deviceManager.setAlias": {
|
|
85729
|
+
capName: "device-manager",
|
|
85730
|
+
capScope: "system",
|
|
85731
|
+
addonId: null,
|
|
85732
|
+
access: "create",
|
|
85733
|
+
role: "admin"
|
|
85734
|
+
},
|
|
85812
85735
|
"deviceManager.setChildLayout": {
|
|
85813
85736
|
capName: "device-manager",
|
|
85814
85737
|
capScope: "system",
|
|
@@ -92592,6 +92515,13 @@ Object.freeze({
|
|
|
92592
92515
|
access: "create",
|
|
92593
92516
|
role: "viewer"
|
|
92594
92517
|
},
|
|
92518
|
+
"timedRun.getOptions": {
|
|
92519
|
+
capName: "timed-run",
|
|
92520
|
+
capScope: "device",
|
|
92521
|
+
addonId: null,
|
|
92522
|
+
access: "view",
|
|
92523
|
+
role: "viewer"
|
|
92524
|
+
},
|
|
92595
92525
|
"timedRun.getStatus": {
|
|
92596
92526
|
capName: "timed-run",
|
|
92597
92527
|
capScope: "device",
|
|
@@ -92606,6 +92536,13 @@ Object.freeze({
|
|
|
92606
92536
|
access: "create",
|
|
92607
92537
|
role: "viewer"
|
|
92608
92538
|
},
|
|
92539
|
+
"timedRun.setSettings": {
|
|
92540
|
+
capName: "timed-run",
|
|
92541
|
+
capScope: "device",
|
|
92542
|
+
addonId: null,
|
|
92543
|
+
access: "create",
|
|
92544
|
+
role: "admin"
|
|
92545
|
+
},
|
|
92609
92546
|
"toast.onToast": {
|
|
92610
92547
|
capName: "toast",
|
|
92611
92548
|
capScope: "system",
|
|
@@ -93536,6 +93473,7 @@ function offered(received) {
|
|
|
93536
93473
|
};
|
|
93537
93474
|
}
|
|
93538
93475
|
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
93476
|
+
string().min(1).max(4096);
|
|
93539
93477
|
Object.freeze({
|
|
93540
93478
|
"accessories.getStatus": [{
|
|
93541
93479
|
name: "deviceId",
|
|
@@ -94219,6 +94157,11 @@ Object.freeze({
|
|
|
94219
94157
|
form: "single",
|
|
94220
94158
|
optional: false
|
|
94221
94159
|
}],
|
|
94160
|
+
"deviceManager.setAlias": [{
|
|
94161
|
+
name: "deviceId",
|
|
94162
|
+
form: "single",
|
|
94163
|
+
optional: false
|
|
94164
|
+
}],
|
|
94222
94165
|
"deviceManager.setChildLayout": [{
|
|
94223
94166
|
name: "deviceId",
|
|
94224
94167
|
form: "single",
|
|
@@ -96283,6 +96226,11 @@ Object.freeze({
|
|
|
96283
96226
|
form: "single",
|
|
96284
96227
|
optional: false
|
|
96285
96228
|
}],
|
|
96229
|
+
"timedRun.getOptions": [{
|
|
96230
|
+
name: "deviceId",
|
|
96231
|
+
form: "single",
|
|
96232
|
+
optional: false
|
|
96233
|
+
}],
|
|
96286
96234
|
"timedRun.getStatus": [{
|
|
96287
96235
|
name: "deviceId",
|
|
96288
96236
|
form: "single",
|
|
@@ -96293,6 +96241,11 @@ Object.freeze({
|
|
|
96293
96241
|
form: "single",
|
|
96294
96242
|
optional: false
|
|
96295
96243
|
}],
|
|
96244
|
+
"timedRun.setSettings": [{
|
|
96245
|
+
name: "deviceId",
|
|
96246
|
+
form: "single",
|
|
96247
|
+
optional: false
|
|
96248
|
+
}],
|
|
96296
96249
|
"update.getStatus": [{
|
|
96297
96250
|
name: "deviceId",
|
|
96298
96251
|
form: "single",
|
|
@@ -97362,6 +97315,7 @@ var STATE_SUMMARY_VARS = [
|
|
|
97362
97315
|
[...RULE_TEXT],
|
|
97363
97316
|
[...RULE_TEXT],
|
|
97364
97317
|
[...RULE_TEXT],
|
|
97318
|
+
[...RULE_TEXT],
|
|
97365
97319
|
[...RULE_BODY_ONLY],
|
|
97366
97320
|
[...RULE_TEXT],
|
|
97367
97321
|
([...RULE_TEXT], [...DEVICE_EVENTS]),
|
|
@@ -98944,7 +98898,6 @@ function buildLinkedInstances(records, spec) {
|
|
|
98944
98898
|
});
|
|
98945
98899
|
return instances;
|
|
98946
98900
|
}
|
|
98947
|
-
var BROKER_ROWS_MAX = 1e3;
|
|
98948
98901
|
var STRAY_REGISTRY_ID = /^int_\d+$/;
|
|
98949
98902
|
async function moveBrokerLinksToConnections(ports) {
|
|
98950
98903
|
const brokers = await ports.listBrokers();
|
|
@@ -98976,36 +98929,6 @@ async function moveBrokerLinksToConnections(ports) {
|
|
|
98976
98929
|
}
|
|
98977
98930
|
};
|
|
98978
98931
|
}
|
|
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
98932
|
//#endregion
|
|
99010
98933
|
//#region src/speak/constants.ts
|
|
99011
98934
|
/** Echo speech limits and the worker restart bound (same window as CrashSupervisor). */
|
|
@@ -145962,7 +145885,7 @@ function echoTargetStoreOver(records, options = {}) {
|
|
|
145962
145885
|
/** The `echoTargets` setting as the legacy source: a row the migration left there is still served. */
|
|
145963
145886
|
function legacyEchoTargetsOver(setting) {
|
|
145964
145887
|
return {
|
|
145965
|
-
list: async () => readEchoTargets({ echoTargets: setting.readRows() }).map((row) => ({
|
|
145888
|
+
list: async () => readEchoTargets({ echoTargets: await setting.readRows() }).map((row) => ({
|
|
145966
145889
|
id: row.id,
|
|
145967
145890
|
name: row.name,
|
|
145968
145891
|
kind: alexaTargetKind().kind,
|
|
@@ -145974,11 +145897,12 @@ function legacyEchoTargetsOver(setting) {
|
|
|
145974
145897
|
}
|
|
145975
145898
|
})),
|
|
145976
145899
|
delete: async (id) => {
|
|
145977
|
-
const
|
|
145900
|
+
const rows = await setting.readRows();
|
|
145901
|
+
const rest = rows.filter((row) => {
|
|
145978
145902
|
const parsed = alexaEchoTargetSchema.safeParse(row);
|
|
145979
145903
|
return !(parsed.success && parsed.data.id === id);
|
|
145980
145904
|
});
|
|
145981
|
-
if (rest.length !==
|
|
145905
|
+
if (rest.length !== rows.length) await setting.writeRows(rest);
|
|
145982
145906
|
}
|
|
145983
145907
|
};
|
|
145984
145908
|
}
|
|
@@ -145995,8 +145919,9 @@ function echoRowOf(target) {
|
|
|
145995
145919
|
}
|
|
145996
145920
|
/** The migration's ports over the `notify-alexa-echo` record kind. */
|
|
145997
145921
|
function echoRecordPortsOver(records, logger) {
|
|
145998
|
-
const
|
|
145999
|
-
if (
|
|
145922
|
+
const [kind] = Object.values(alexaNotifyRecordKinds);
|
|
145923
|
+
if (kind === void 0) throw new Error("import-alexa: the Echo target record kind is not declared");
|
|
145924
|
+
const handle = records.kind(kind);
|
|
146000
145925
|
return {
|
|
146001
145926
|
readEchoRecord: async (id) => (await handle.getResolved(id))?.data ?? null,
|
|
146002
145927
|
writeEchoRecord: async (id, body) => {
|
|
@@ -147081,17 +147006,42 @@ async function flattenBrokerRecords(ports) {
|
|
|
147081
147006
|
//#endregion
|
|
147082
147007
|
//#region src/migrations/broker-links-to-connections.ts
|
|
147083
147008
|
var BROKER_LINKS_TO_CONNECTIONS_ID = "import-alexa/2026-11-05-broker-links-to-connections";
|
|
147009
|
+
var BROKER_ROWS_MAX = 1e3;
|
|
147084
147010
|
/** The broker records and the integration (`connections`) records of this addon. */
|
|
147085
147011
|
function alexaBrokerLinkPorts(records, warn) {
|
|
147086
|
-
|
|
147087
|
-
|
|
147088
|
-
|
|
147089
|
-
|
|
147090
|
-
schema: record(string(), unknown())
|
|
147091
|
-
}),
|
|
147092
|
-
connections: records.kind(alexaConnectionsEntryKind),
|
|
147093
|
-
warn
|
|
147012
|
+
const brokers = records.kind({
|
|
147013
|
+
name: alexaBrokersEntryKind.name,
|
|
147014
|
+
declaration: alexaBrokersEntryKind.declaration,
|
|
147015
|
+
schema: record(string(), unknown())
|
|
147094
147016
|
});
|
|
147017
|
+
const connections = records.kind(alexaConnectionsEntryKind);
|
|
147018
|
+
return {
|
|
147019
|
+
warn,
|
|
147020
|
+
listBrokers: async () => {
|
|
147021
|
+
return (await brokers.query({ limit: BROKER_ROWS_MAX })).records.map((row) => {
|
|
147022
|
+
const name = row.data["name"];
|
|
147023
|
+
const link = row.data["integrationId"];
|
|
147024
|
+
return {
|
|
147025
|
+
id: row.id,
|
|
147026
|
+
name: typeof name === "string" && name.length > 0 ? name : row.id,
|
|
147027
|
+
integrationId: typeof link === "string" ? link : void 0
|
|
147028
|
+
};
|
|
147029
|
+
});
|
|
147030
|
+
},
|
|
147031
|
+
readConnection: async (id) => {
|
|
147032
|
+
const row = await connections.get(id);
|
|
147033
|
+
return row === null ? null : { brokerId: row.data.brokerId };
|
|
147034
|
+
},
|
|
147035
|
+
putConnection: async (id, body) => {
|
|
147036
|
+
await connections.put({
|
|
147037
|
+
id,
|
|
147038
|
+
data: body
|
|
147039
|
+
}, { ifRev: 0 });
|
|
147040
|
+
},
|
|
147041
|
+
clearBrokerLink: async (brokerId) => {
|
|
147042
|
+
await brokers.patch(brokerId, { integrationId: null });
|
|
147043
|
+
}
|
|
147044
|
+
};
|
|
147095
147045
|
}
|
|
147096
147046
|
//#endregion
|
|
147097
147047
|
//#region src/migrations/strip-echo-target-volume-and-mode.ts
|
|
@@ -147107,7 +147057,7 @@ function strippedRow(row) {
|
|
|
147107
147057
|
return Object.fromEntries(Object.entries(row).filter(([key]) => !RETIRED_KEYS.includes(key)));
|
|
147108
147058
|
}
|
|
147109
147059
|
async function stripEchoTargetVolumeAndMode(ports) {
|
|
147110
|
-
const rows = ports.readRows();
|
|
147060
|
+
const rows = await ports.readRows();
|
|
147111
147061
|
const stripped = rows.filter(carriesRetiredKey).length;
|
|
147112
147062
|
if (stripped === 0) return {
|
|
147113
147063
|
outcome: "already-done",
|
|
@@ -147140,7 +147090,7 @@ async function stripEchoTargetVolumeAndMode(ports) {
|
|
|
147140
147090
|
*/
|
|
147141
147091
|
var ECHO_TARGETS_TO_RECORDS_ID = "import-alexa/2026-11-06-echo-targets-to-records";
|
|
147142
147092
|
async function moveEchoTargetsToRecords(ports) {
|
|
147143
|
-
const rows = ports.readRows();
|
|
147093
|
+
const rows = await ports.readRows();
|
|
147144
147094
|
if (rows.length === 0) return {
|
|
147145
147095
|
outcome: "already-done",
|
|
147146
147096
|
summary: { converted: 0 }
|
|
@@ -147291,6 +147241,118 @@ var BROKER_RECORD_MIGRATION_IDS = [
|
|
|
147291
147241
|
BROKER_LINKS_TO_CONNECTIONS_ID
|
|
147292
147242
|
];
|
|
147293
147243
|
//#endregion
|
|
147244
|
+
//#region src/migrations/records-door.ts
|
|
147245
|
+
function positionalHandleOver(handle) {
|
|
147246
|
+
return {
|
|
147247
|
+
get: (id) => handle.get({ id }),
|
|
147248
|
+
getResolved: (id) => handle.getResolved({ id }),
|
|
147249
|
+
put: (input, opts) => handle.put({
|
|
147250
|
+
...input,
|
|
147251
|
+
...opts?.ifRev === void 0 ? {} : { ifRev: opts.ifRev }
|
|
147252
|
+
}),
|
|
147253
|
+
patch: (id, partial) => handle.patch({
|
|
147254
|
+
id,
|
|
147255
|
+
partial
|
|
147256
|
+
}),
|
|
147257
|
+
delete: (id) => handle.delete({ id }),
|
|
147258
|
+
query: ({ limit }) => handle.query({ limit })
|
|
147259
|
+
};
|
|
147260
|
+
}
|
|
147261
|
+
/** The records door of the migration API, in the shape the migrations call. */
|
|
147262
|
+
function positionalRecordsOver(api) {
|
|
147263
|
+
return { kind: (definition) => positionalHandleOver(api.records.kind(definition)) };
|
|
147264
|
+
}
|
|
147265
|
+
//#endregion
|
|
147266
|
+
//#region src/migrations/ports.ts
|
|
147267
|
+
var NESTED_MAX = 1e3;
|
|
147268
|
+
/** The registry list and the migration-only rows door, over the migration API. */
|
|
147269
|
+
function integrationRowsApiOver(api) {
|
|
147270
|
+
return {
|
|
147271
|
+
list: async () => (await api.integrations.list({})).integrations,
|
|
147272
|
+
readLegacyIntegrationRows: (input) => api.legacyRows.read(input),
|
|
147273
|
+
clearLegacyIntegrationRows: (input) => api.legacyRows.clear(input)
|
|
147274
|
+
};
|
|
147275
|
+
}
|
|
147276
|
+
/** The keychain handle of the migration API: resolve and delete, owner-scoped by the transport. */
|
|
147277
|
+
function secretsOver(api) {
|
|
147278
|
+
return {
|
|
147279
|
+
resolve: async (refs) => {
|
|
147280
|
+
const { values } = await api.secrets.resolve({ refs: [...refs] });
|
|
147281
|
+
const out = {};
|
|
147282
|
+
for (const ref of refs) {
|
|
147283
|
+
const value = values[ref];
|
|
147284
|
+
out[ref] = value === null || value === void 0 ? { kind: "missing" } : {
|
|
147285
|
+
kind: "value",
|
|
147286
|
+
value,
|
|
147287
|
+
version: 0
|
|
147288
|
+
};
|
|
147289
|
+
}
|
|
147290
|
+
return out;
|
|
147291
|
+
},
|
|
147292
|
+
delete: async (refs) => (await api.secrets.delete({ refs: [...refs] })).deleted
|
|
147293
|
+
};
|
|
147294
|
+
}
|
|
147295
|
+
/** The Echo targets kept in the addon's `echoTargets` setting, read and written as stored. */
|
|
147296
|
+
function echoSettingPortsOver(api) {
|
|
147297
|
+
return {
|
|
147298
|
+
readRows: async () => {
|
|
147299
|
+
const { store } = await api.settings.read({});
|
|
147300
|
+
const rows = store["echoTargets"];
|
|
147301
|
+
return Array.isArray(rows) ? rows : [];
|
|
147302
|
+
},
|
|
147303
|
+
writeRows: async (rows) => {
|
|
147304
|
+
await api.settings.write({ patch: { echoTargets: [...rows] } });
|
|
147305
|
+
}
|
|
147306
|
+
};
|
|
147307
|
+
}
|
|
147308
|
+
/** The broker rows' flatten ports over the records door. */
|
|
147309
|
+
function flattenPortsOverDoor(records) {
|
|
147310
|
+
const handle = records.kind({
|
|
147311
|
+
name: alexaBrokersEntryKind.name,
|
|
147312
|
+
declaration: alexaBrokersEntryKind.declaration,
|
|
147313
|
+
schema: record(string(), unknown())
|
|
147314
|
+
});
|
|
147315
|
+
return {
|
|
147316
|
+
listNested: async (legacyKey) => (await handle.query({ limit: NESTED_MAX })).records.filter((row) => legacyKey in row.data).map((row) => row.id),
|
|
147317
|
+
readResolved: async (id) => {
|
|
147318
|
+
const row = await handle.getResolved(id);
|
|
147319
|
+
if (row === null) throw new Error("the record is gone");
|
|
147320
|
+
return row.data;
|
|
147321
|
+
},
|
|
147322
|
+
patch: async (id, patch) => {
|
|
147323
|
+
await handle.patch(id, patch);
|
|
147324
|
+
}
|
|
147325
|
+
};
|
|
147326
|
+
}
|
|
147327
|
+
/**
|
|
147328
|
+
* The catalogue's ports over {@link MigrationApiV1}, and nothing else (planning#447): the addon's
|
|
147329
|
+
* own settings store (the Echo rows), its keychain handle, the legacy integration rows door and its
|
|
147330
|
+
* broker, connection and Echo target records.
|
|
147331
|
+
*/
|
|
147332
|
+
function alexaPortsOver(api) {
|
|
147333
|
+
const records = positionalRecordsOver(api);
|
|
147334
|
+
const warn = (message) => {
|
|
147335
|
+
api.log.warn({ message });
|
|
147336
|
+
};
|
|
147337
|
+
return {
|
|
147338
|
+
...echoSettingPortsOver(api),
|
|
147339
|
+
...flattenPortsOverDoor(records),
|
|
147340
|
+
...alexaBrokerLinkPorts(records, warn),
|
|
147341
|
+
...echoRecordPortsOver(records, { warn: (message, extras) => {
|
|
147342
|
+
api.log.warn({
|
|
147343
|
+
message,
|
|
147344
|
+
...extras?.meta === void 0 ? {} : { meta: extras.meta }
|
|
147345
|
+
});
|
|
147346
|
+
} }),
|
|
147347
|
+
...alexaIntegrationRowsPorts({
|
|
147348
|
+
api: integrationRowsApiOver(api),
|
|
147349
|
+
records,
|
|
147350
|
+
secrets: secretsOver(api),
|
|
147351
|
+
warn
|
|
147352
|
+
})
|
|
147353
|
+
};
|
|
147354
|
+
}
|
|
147355
|
+
//#endregion
|
|
147294
147356
|
//#region src/speak/icon-routes.ts
|
|
147295
147357
|
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
147358
|
/** One day; the mark is immutable per addon version. */
|
|
@@ -147410,7 +147472,7 @@ var AlexaImportAddon = class extends BaseDeviceProvider {
|
|
|
147410
147472
|
infoOf: (id) => this.registry?.get(id) ?? null,
|
|
147411
147473
|
onChanged: (id) => this.syncBrokerRuntime(id)
|
|
147412
147474
|
});
|
|
147413
|
-
await this.runMigrations(
|
|
147475
|
+
await this.runMigrations(ADDON_MIGRATIONS, (api) => alexaPortsOver(api), { only: BROKER_RECORD_MIGRATION_IDS });
|
|
147414
147476
|
this.activeBrokers = await this.loadPersistedBrokers();
|
|
147415
147477
|
await this.adoptSessionFiles();
|
|
147416
147478
|
this.registry = new AlexaBrokerRegistry(this.ctx.logger, {
|
|
@@ -147451,7 +147513,7 @@ var AlexaImportAddon = class extends BaseDeviceProvider {
|
|
|
147451
147513
|
deviceCode: this.deviceCodeLogin,
|
|
147452
147514
|
commitCookie: (input) => this.commitCapturedCookie(input)
|
|
147453
147515
|
}), ...speakIconRoutes()];
|
|
147454
|
-
await this.runMigrations(
|
|
147516
|
+
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
147517
|
const echoStore = echoTargetStoreOver(records, {
|
|
147456
147518
|
logger: this.ctx.logger,
|
|
147457
147519
|
legacy: legacyEchoTargetsOver(this.echoSettingPorts())
|
|
@@ -147502,29 +147564,15 @@ var AlexaImportAddon = class extends BaseDeviceProvider {
|
|
|
147502
147564
|
}
|
|
147503
147565
|
] };
|
|
147504
147566
|
}
|
|
147505
|
-
/**
|
|
147567
|
+
/**
|
|
147568
|
+
* The `echoTargets` setting the legacy Echo store still serves: the addon's own durable state
|
|
147569
|
+
* under the key it was always stored at, so a row an older release left there is still read.
|
|
147570
|
+
*/
|
|
147506
147571
|
echoSettingPorts() {
|
|
147572
|
+
const rows = this.state("echoTargets", array(unknown()), []);
|
|
147507
147573
|
return {
|
|
147508
|
-
readRows: () =>
|
|
147509
|
-
writeRows:
|
|
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
|
-
})
|
|
147574
|
+
readRows: () => rows.get(),
|
|
147575
|
+
writeRows: (next) => rows.set([...readEchoTargets({ echoTargets: next })])
|
|
147528
147576
|
};
|
|
147529
147577
|
}
|
|
147530
147578
|
/** One provider over the two record kinds: the account (broker) and the integrations using it. */
|