@camstack/system 1.2.330 → 1.2.331
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/dist/addon-runner.js +1 -1
- package/dist/addon-runner.mjs +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/autotrack/index.js +3 -3
- package/dist/builtins/autotrack/index.mjs +3 -3
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
- package/dist/builtins/camera-grid/index.js +1 -1
- package/dist/builtins/camera-grid/index.mjs +1 -1
- package/dist/builtins/composer/composer.addon.js +27 -8
- package/dist/builtins/composer/composer.addon.mjs +21 -3
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
- package/dist/builtins/device-manager/device-bindings-store.d.ts +7 -0
- package/dist/builtins/device-manager/device-manager.addon.d.ts +3 -0
- package/dist/builtins/device-manager/device-manager.addon.js +130 -3
- package/dist/builtins/device-manager/device-manager.addon.mjs +130 -3
- package/dist/builtins/device-manager/stale-wrapper-activations.d.ts +26 -0
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
- package/dist/builtins/local-network/local-network.addon.js +1 -1
- package/dist/builtins/local-network/local-network.addon.mjs +1 -1
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/shared/device-state-changed.d.ts +3 -4
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{child-cap-dispatch-C8uts1P4.js → child-cap-dispatch-93MfsaZL.js} +1 -0
- package/dist/{child-cap-dispatch-C2VINHu1.mjs → child-cap-dispatch-kLIiU1CG.mjs} +1 -0
- package/dist/{composition-sources-2XxNEet3.js → composition-sources-BXZorHDO.js} +1 -1
- package/dist/{composition-sources-Wj2kWund.mjs → composition-sources-aEEer5gE.mjs} +1 -1
- package/dist/{dist-Dp043AI0.mjs → dist-CoG8lY6H.mjs} +222 -374
- package/dist/{dist-Bx4zxM9N.js → dist-DRUzy1SF.js} +221 -421
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{retired-settings-keys-DR2WMe5d.js → retired-settings-keys-BY9H1I2b.js} +1 -1
- package/dist/{retired-settings-keys-Dxf9vELs.mjs → retired-settings-keys-BcJDpASY.mjs} +1 -1
- package/package.json +1 -16
- package/dist/builtins/doorbell/binding-mirror.d.ts +0 -110
- package/dist/builtins/doorbell/doorbell-composition-migration.d.ts +0 -47
- package/dist/builtins/doorbell/doorbell-extension-slot.d.ts +0 -67
- package/dist/builtins/doorbell/doorbell-settings.d.ts +0 -58
- package/dist/builtins/doorbell/index.d.ts +0 -2
- package/dist/builtins/doorbell/index.js +0 -8
- package/dist/builtins/doorbell/index.mjs +0 -2
- package/dist/builtins/doorbell/trigger-engine.d.ts +0 -92
- package/dist/builtins/doorbell/virtual-doorbell.addon.d.ts +0 -218
- package/dist/builtins/doorbell/virtual-doorbell.addon.js +0 -1413
- package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +0 -1407
- package/dist/device-state-changed-Bk7cvTnz.js +0 -31
- package/dist/device-state-changed-DoBbkyEI.mjs +0 -20
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
import { ProviderRegistration, BaseAddon } from '@camstack/types';
|
|
2
|
-
interface VirtualDoorbellAddonConfig {
|
|
3
|
-
/** Per-camera debounce window (ms) against sensor chatter. */
|
|
4
|
-
readonly debounceMs: number;
|
|
5
|
-
/**
|
|
6
|
-
* Reload the camera→source assignment map (and the binding mirror) at
|
|
7
|
-
* most this often — lazily, on trigger traffic. Covers devices/settings
|
|
8
|
-
* appearing after boot without a save, and is the cadence on
|
|
9
|
-
* which an unbind gets corroborated.
|
|
10
|
-
*/
|
|
11
|
-
readonly assignmentsTtlMs: number;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* VirtualDoorbellAddon — WRAPPER over the `doorbell` capability.
|
|
15
|
-
*
|
|
16
|
-
* Turns any binary sensor or switch (contact, motion, flood/gas/CO/smoke,
|
|
17
|
-
* vibration, tamper, generic binary, or a switch) into a doorbell for a
|
|
18
|
-
* camera:
|
|
19
|
-
*
|
|
20
|
-
* 1. The operator binds the wrapper to a camera in the bindings UI
|
|
21
|
-
* (`defaultActive: false` — never auto-bound).
|
|
22
|
-
* 2. In the camera's Extensions section (the `doorbell-source` slot,
|
|
23
|
-
* D648/D655) the operator picks one or more SOURCE devices — that is
|
|
24
|
-
* the ONLY choice. The reaction is derived automatically per
|
|
25
|
-
* device type: a binary sensor rings when it goes active, a switch
|
|
26
|
-
* rings when it turns on (see `trigger-engine.ts`). The persisted
|
|
27
|
-
* shape (`doorbellSources: [{deviceId}]`) stays extensible for a
|
|
28
|
-
* future custom-trigger override.
|
|
29
|
-
* 3. At runtime the addon watches `EventCategory.DeviceStateChanged`
|
|
30
|
-
* (binary/switch slice transitions — false→true edge detected). On a
|
|
31
|
-
* matching, debounced rise it emits `EventCategory.DoorbellOnPressed`
|
|
32
|
-
* with the CAMERA as source (`{deviceId: cameraId, timestamp}` — the
|
|
33
|
-
* same shape Reolink's native `emitDoorbellPressed` produces) and
|
|
34
|
-
* bumps the camera's `doorbell` runtime-state counters via the
|
|
35
|
-
* standard `deviceState.setCapSlice` plumbing.
|
|
36
|
-
*
|
|
37
|
-
* Fires ONLY for cameras with at least one configured source device that
|
|
38
|
-
* this wrapper is BOUND to. The binding is NOT re-derived on the ring path:
|
|
39
|
-
* it is mirrored in memory (`binding-mirror.ts`) and refreshed on the
|
|
40
|
-
* assignment-reload cadence, because a fallible read must never be able to
|
|
41
|
-
* destroy a one-shot press.
|
|
42
|
-
*/
|
|
43
|
-
export declare class VirtualDoorbellAddon extends BaseAddon<VirtualDoorbellAddonConfig> {
|
|
44
|
-
private engine;
|
|
45
|
-
private compositionMigration;
|
|
46
|
-
private providerRegisteredUnsubscribe;
|
|
47
|
-
/** Monotonic guard: assignments are reloaded lazily on trigger traffic. */
|
|
48
|
-
private assignmentsLoadedAt;
|
|
49
|
-
private assignmentsLoading;
|
|
50
|
-
/**
|
|
51
|
-
* Per-camera mirror of "is this wrapper still the active doorbell
|
|
52
|
-
* binding". Written ONLY off the ring path; read on it. See
|
|
53
|
-
* `binding-mirror.ts` for why a single negative read is not believed.
|
|
54
|
-
*/
|
|
55
|
-
private readonly bindingMirror;
|
|
56
|
-
/**
|
|
57
|
-
* Per camera, the last NEGATIVE refresh this addon reported — its state,
|
|
58
|
-
* the authority's verdict and who else serves the doorbell. A refresh runs
|
|
59
|
-
* every reload cycle (about once a minute); the same answer repeated is not
|
|
60
|
-
* news, so it is reported once per change and forgotten on a positive read.
|
|
61
|
-
* Camera 615 logged the same WARN 607 times in 14 h after D671.
|
|
62
|
-
*/
|
|
63
|
-
private readonly reportedNegative;
|
|
64
|
-
/** Cameras whose last durable-authority read THREW — reported once per outage. */
|
|
65
|
-
private readonly durableReadFailing;
|
|
66
|
-
/**
|
|
67
|
-
* Per camera, the OTHER providers of `doorbell` the last successful derived
|
|
68
|
-
* read named (the composer after D671). Written off the ring path with the
|
|
69
|
-
* mirror; read on it, to decide whether erring open would double a ring.
|
|
70
|
-
*/
|
|
71
|
-
private readonly servedElsewhere;
|
|
72
|
-
/** Cameras whose store-over-derived disagreement has been reported, until a derived read agrees. */
|
|
73
|
-
private readonly reportedStoreOverride;
|
|
74
|
-
constructor();
|
|
75
|
-
protected onInitialize(): Promise<ProviderRegistration[]>;
|
|
76
|
-
protected onShutdown(): Promise<void>;
|
|
77
|
-
/**
|
|
78
|
-
* The `device-extension` provider: the only editor of a camera's trigger
|
|
79
|
-
* devices since D655 (see `doorbell-extension-slot.ts`).
|
|
80
|
-
*/
|
|
81
|
-
private buildExtensionProvider;
|
|
82
|
-
private handleStateChanged;
|
|
83
|
-
/**
|
|
84
|
-
* Say out loud every case where a rise did NOT become a ring. Silence
|
|
85
|
-
* reads as "never happened": three real presses on camera 615 produced
|
|
86
|
-
* zero operator-visible lines because the drop logged at `debug`.
|
|
87
|
-
*/
|
|
88
|
-
private logSuppressions;
|
|
89
|
-
/**
|
|
90
|
-
* Ring the camera's virtual doorbell: bump the `doorbell` runtime-state
|
|
91
|
-
* counters through the canonical `deviceState.setCapSlice` write, and
|
|
92
|
-
* emit the typed `DoorbellOnPressed` event with the CAMERA as source —
|
|
93
|
-
* byte-shaped like a native firmware ring so every downstream consumer
|
|
94
|
-
* (UI toast, notifier rules, exporters) is agnostic to the origin.
|
|
95
|
-
*
|
|
96
|
-
* The binding gate here is a pure in-memory read on the path that RINGS:
|
|
97
|
-
* a `bound` mirror, or an open one on a camera nobody else serves, performs
|
|
98
|
-
* NO I/O and cannot fail. Every other case asks the durable authority once
|
|
99
|
-
* before deciding — see `needsDurableRead` and `ringsAfterDurableRead`.
|
|
100
|
-
*
|
|
101
|
-
* `sourceDeviceId`/`capName` are the source that produced this rise —
|
|
102
|
-
* carried through purely so the terminal `pressed` line can name it. Every
|
|
103
|
-
* suppression branch beside it already reports its source
|
|
104
|
-
* (`logSuppressions`); the successful path was the one place that did not,
|
|
105
|
-
* which meant answering "what rang it" required hand-correlating a
|
|
106
|
-
* timestamp against provider logs (proven live 2026-08-25, camera 615).
|
|
107
|
-
*/
|
|
108
|
-
private fireDoorbell;
|
|
109
|
-
/**
|
|
110
|
-
* The addon id as the REGISTRY and the bindings store spell it.
|
|
111
|
-
*
|
|
112
|
-
* `ctx.id` does NOT: hub-main prefixes it (`addon:virtual-doorbell`) while
|
|
113
|
-
* a forked runner does not, and this builtin runs in hub-main. Comparing
|
|
114
|
-
* the raw `ctx.id` to a `providerAddonId` was false for every entry for
|
|
115
|
-
* twelve hours on 2026-08-07 (D72).
|
|
116
|
-
*/
|
|
117
|
-
private get ownAddonId();
|
|
118
|
-
/**
|
|
119
|
-
* One read of the DERIVED binding view. `null` when the read could not be
|
|
120
|
-
* answered at all — which carries no information and must leave the mirror
|
|
121
|
-
* untouched.
|
|
122
|
-
*/
|
|
123
|
-
private readDerivedBinding;
|
|
124
|
-
/**
|
|
125
|
-
* One read of the DURABLE authority: the wrapper activation device-manager
|
|
126
|
-
* STORED for this camera (`deviceManager.getWrapperActivation`, D675) — the
|
|
127
|
-
* row the operator's bindings toggle writes. `deviceManager.getBindings` is
|
|
128
|
-
* a VIEW derived from it plus the capability registry.
|
|
129
|
-
*
|
|
130
|
-
* This is deliberately NOT `getBindings`. The derived view folds the store
|
|
131
|
-
* together with the capability registry, `defaultActive` auto-binding and
|
|
132
|
-
* the cluster native-cap feeds — any of which can make it disagree with
|
|
133
|
-
* what the operator actually persisted, and one of which (an addon-id
|
|
134
|
-
* spelling mismatch) made it disagree *systematically* while looking
|
|
135
|
-
* exactly like a genuine unbind. The raw row cannot: it is what the
|
|
136
|
-
* bindings toggle wrote, and it grades its own trustworthiness (D44).
|
|
137
|
-
*
|
|
138
|
-
* A read that throws is reported when the outage STARTS and when it ends —
|
|
139
|
-
* never per read: this runs on every reload cycle.
|
|
140
|
-
*/
|
|
141
|
-
private readDurableAuthority;
|
|
142
|
-
/**
|
|
143
|
-
* Reconcile `cameraId`'s mirror against the authority. Runs on the
|
|
144
|
-
* assignment-reload cadence, never while firing — and it runs on EVERY
|
|
145
|
-
* cycle regardless of the current verdict, so a camera sitting in
|
|
146
|
-
* `unbound` returns to `bound` on its own the moment the authority says
|
|
147
|
-
* so. There is no latch here that an operator has to clear.
|
|
148
|
-
*
|
|
149
|
-
* A positive derived read is believed immediately. A NEGATIVE one never
|
|
150
|
-
* is: the durable authority is asked, and it outranks the derived view in
|
|
151
|
-
* the direction that destroys work. Only when the authority agrees does
|
|
152
|
-
* the negative get folded, and even then `nextBindingState` still wants a
|
|
153
|
-
* second consecutive one (D49).
|
|
154
|
-
*/
|
|
155
|
-
private refreshBindingMirror;
|
|
156
|
-
/** The ring gate's in-memory input for one camera — no I/O. */
|
|
157
|
-
private mirrorRead;
|
|
158
|
-
/**
|
|
159
|
-
* Report a negative refresh ONCE per change of what it says (D391: a
|
|
160
|
-
* repeated identical line is noise that buries the next real one).
|
|
161
|
-
*
|
|
162
|
-
* The level follows what the answer MEANS:
|
|
163
|
-
* - the durable store could not grade it (`unreadable`) — WARN: the
|
|
164
|
-
* camera's ring now depends on erring open, and nobody can say whether
|
|
165
|
-
* that is right;
|
|
166
|
-
* - the store CONFIRMS the wrapper is not bound — an operator's unbind or
|
|
167
|
-
* the D671 cutover to a composition. That is a state, not an anomaly:
|
|
168
|
-
* INFO when it is believed (`unbound`), DEBUG for the first,
|
|
169
|
-
* not-yet-believed read.
|
|
170
|
-
*/
|
|
171
|
-
private reportNegativeRefresh;
|
|
172
|
-
/**
|
|
173
|
-
* A real press arrived on a camera the in-memory gate cannot clear on its
|
|
174
|
-
* own: the mirror is `unbound`, or it is short of `bound` while another
|
|
175
|
-
* provider serves the doorbell. Decide, with ONE read of the durable
|
|
176
|
-
* authority, whether this wrapper rings.
|
|
177
|
-
*
|
|
178
|
-
* D49 forbade I/O on the ring path because the read it would have made was
|
|
179
|
-
* the same fallible derived read that caused the problem. This read is
|
|
180
|
-
* different in both directions: it is the authority rather than a view of
|
|
181
|
-
* it, and it is paid ONLY where erring open could be wrong — a dropped ring
|
|
182
|
-
* (an `unbound` mirror) or a DOUBLED one (another provider rings this
|
|
183
|
-
* camera). A ring is rare and one query is cheap. An unreadable store still
|
|
184
|
-
* rings: it carries no information.
|
|
185
|
-
*
|
|
186
|
-
* Returns `true` when the ring must proceed.
|
|
187
|
-
*/
|
|
188
|
-
private ringsAfterDurableRead;
|
|
189
|
-
/**
|
|
190
|
-
* Lazily (re)build the camera→source assignment set from every
|
|
191
|
-
* camera's device store. TTL-bounded so devices/settings appearing
|
|
192
|
-
* after boot are picked up without a save; invalidated eagerly by
|
|
193
|
-
* `persistDoorbellSources`.
|
|
194
|
-
*/
|
|
195
|
-
private ensureAssignments;
|
|
196
|
-
private loadAssignments;
|
|
197
|
-
private invalidateAssignments;
|
|
198
|
-
/**
|
|
199
|
-
* Status from the kernel-managed `doorbell` runtime-state slice —
|
|
200
|
-
* the wrapper keeps NO parallel counter fields (the slice is the
|
|
201
|
-
* single source of truth, persisted across restarts).
|
|
202
|
-
*/
|
|
203
|
-
private getStatus;
|
|
204
|
-
/**
|
|
205
|
-
* The camera's configured doorbell sources, parsed tolerantly (new
|
|
206
|
-
* `doorbellSources` shape + legacy single-source migration).
|
|
207
|
-
*/
|
|
208
|
-
private readDeviceSources;
|
|
209
|
-
/**
|
|
210
|
-
* THE write path for a camera's trigger sources — the `doorbell-source`
|
|
211
|
-
* extension slot lands here (D648; its only caller since D655): normalise
|
|
212
|
-
* to `doorbellSources: [{deviceId}]`, strip the legacy keys, and invalidate
|
|
213
|
-
* the assignment cache so the next rise (and the binding mirror's next
|
|
214
|
-
* refresh, off the ring path) sees the new wiring.
|
|
215
|
-
*/
|
|
216
|
-
private persistDoorbellSources;
|
|
217
|
-
}
|
|
218
|
-
export default VirtualDoorbellAddon;
|