@mega-yfue/eufy-sdk 0.0.4 → 0.1.0-beta.0
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/README.md +31 -12
- package/dist/client/device-registry.d.ts +343 -0
- package/dist/client/eufy-mega.d.ts +872 -0
- package/dist/client/index.d.ts +1 -6
- package/dist/client/map-channels.d.ts +22 -0
- package/dist/client/types.d.ts +383 -0
- package/dist/core/contracts.d.ts +898 -0
- package/dist/core/crypto.d.ts +98 -0
- package/dist/core/index.d.ts +9 -7
- package/dist/core/logger.d.ts +53 -0
- package/dist/core/lz4-block.d.ts +35 -0
- package/dist/core/raw-dp-hex.d.ts +32 -0
- package/dist/core/raw-dp-writer.d.ts +83 -0
- package/dist/core/store.d.ts +43 -0
- package/dist/core/types.d.ts +169 -0
- package/dist/core/util.d.ts +78 -0
- package/dist/index.d.ts +4 -7
- package/dist/index.js +25526 -14
- package/dist/index.js.map +7 -1
- package/dist/model/capabilities/access.d.ts +127 -0
- package/dist/model/capabilities/arming.d.ts +201 -0
- package/dist/model/capabilities/audio.d.ts +154 -0
- package/dist/model/capabilities/battery.d.ts +363 -0
- package/dist/model/capabilities/camera.d.ts +564 -0
- package/dist/model/capabilities/co.d.ts +40 -0
- package/dist/model/capabilities/contact.d.ts +133 -0
- package/dist/model/capabilities/doorbell.d.ts +345 -0
- package/dist/model/capabilities/dp-catalog.d.ts +38 -0
- package/dist/model/capabilities/index.d.ts +561 -0
- package/dist/model/capabilities/info.d.ts +28 -0
- package/dist/model/capabilities/keypad.d.ts +61 -0
- package/dist/model/capabilities/leak.d.ts +43 -0
- package/dist/model/capabilities/light.d.ts +174 -0
- package/dist/model/capabilities/locate.d.ts +63 -0
- package/dist/model/capabilities/lock.d.ts +242 -0
- package/dist/model/capabilities/manifest.d.ts +107 -0
- package/dist/model/capabilities/members.d.ts +647 -0
- package/dist/model/capabilities/motion.d.ts +377 -0
- package/dist/model/capabilities/person-detection.d.ts +8 -0
- package/dist/model/capabilities/ptz.d.ts +289 -0
- package/dist/model/capabilities/rtsp.d.ts +221 -0
- package/dist/model/capabilities/siren.d.ts +218 -0
- package/dist/model/capabilities/smart-light.d.ts +172 -0
- package/dist/model/capabilities/smoke.d.ts +40 -0
- package/dist/model/capabilities/snapshot.d.ts +6 -0
- package/dist/model/capabilities/storage.d.ts +11 -0
- package/dist/model/capabilities/suction.d.ts +104 -0
- package/dist/model/capabilities/types.d.ts +484 -0
- package/dist/model/capabilities/vacuum-clean.d.ts +1946 -0
- package/dist/model/capabilities/vacuum-dock.d.ts +208 -0
- package/dist/model/capabilities/video.d.ts +6 -0
- package/dist/model/classify.d.ts +78 -0
- package/dist/model/clean-record-detail.d.ts +65 -0
- package/dist/model/clean-records.d.ts +69 -0
- package/dist/model/device-family.d.ts +73 -0
- package/dist/model/device-types.d.ts +123 -0
- package/dist/model/device.d.ts +265 -0
- package/dist/model/index.d.ts +29 -4
- package/dist/model/infer.d.ts +23 -0
- package/dist/model/inspect.d.ts +61 -0
- package/dist/model/life-params.d.ts +21 -0
- package/dist/model/map-pixels.d.ts +70 -0
- package/dist/model/param-dictionary.d.ts +28 -0
- package/dist/model/param-namespace.d.ts +21 -0
- package/dist/model/proto-read.d.ts +53 -0
- package/dist/model/push-events.d.ts +147 -0
- package/dist/model/registry.d.ts +54 -0
- package/dist/model/types.d.ts +301 -0
- package/dist/model/vacuum-map-store.d.ts +92 -0
- package/dist/model/vacuum-map.d.ts +286 -0
- package/dist/model/vacuum-scenes.d.ts +76 -0
- package/dist/model/vacuum-schedules.d.ts +85 -0
- package/dist/transport/dp-preset.d.ts +102 -0
- package/dist/transport/ff09.d.ts +444 -0
- package/dist/transport/ffmpeg.d.ts +86 -0
- package/dist/transport/http/decodeImageV1.d.ts +20 -0
- package/dist/transport/http/decodeImageV2.d.ts +19 -0
- package/dist/transport/http/index.d.ts +5 -0
- package/dist/transport/http/light-catalog.d.ts +62 -0
- package/dist/transport/http/media-download.d.ts +14 -0
- package/dist/transport/http/mega-client.d.ts +514 -0
- package/dist/transport/http/phone-model.d.ts +21 -0
- package/dist/transport/index.d.ts +10 -7
- package/dist/transport/mqtt/app-client-id.d.ts +16 -0
- package/dist/transport/mqtt/availability.d.ts +14 -0
- package/dist/transport/mqtt/bare-ip-tls.d.ts +46 -0
- package/dist/transport/mqtt/biz-stream.d.ts +98 -0
- package/dist/transport/mqtt/broker-discovery.d.ts +55 -0
- package/dist/transport/mqtt/clean-codec.d.ts +14 -0
- package/dist/transport/mqtt/command-router.d.ts +285 -0
- package/dist/transport/mqtt/dp-codec.d.ts +58 -0
- package/dist/transport/mqtt/dp-color.d.ts +14 -0
- package/dist/transport/mqtt/engine.d.ts +16 -0
- package/dist/transport/mqtt/index.d.ts +5 -0
- package/dist/transport/mqtt/secure-mqtt.d.ts +107 -0
- package/dist/transport/mqtt/topics.d.ts +80 -0
- package/dist/transport/p2p/adts.d.ts +91 -0
- package/dist/transport/p2p/annexb.d.ts +124 -0
- package/dist/transport/p2p/codec.d.ts +166 -0
- package/dist/transport/p2p/command-router.d.ts +655 -0
- package/dist/transport/p2p/commands.d.ts +550 -0
- package/dist/transport/p2p/envelope.d.ts +46 -0
- package/dist/transport/p2p/fmp4.d.ts +89 -0
- package/dist/transport/p2p/fragment-recording.d.ts +33 -0
- package/dist/transport/p2p/index.d.ts +13 -0
- package/dist/transport/p2p/lan-ip.d.ts +25 -0
- package/dist/transport/p2p/live-stream.d.ts +223 -0
- package/dist/transport/p2p/live-trace.d.ts +123 -0
- package/dist/transport/p2p/media.d.ts +105 -0
- package/dist/transport/p2p/p2p-session.d.ts +620 -0
- package/dist/transport/p2p/readable-egress.d.ts +27 -0
- package/dist/transport/p2p/session-manager.d.ts +154 -0
- package/dist/transport/p2p/shared-live-source.d.ts +431 -0
- package/dist/transport/p2p/talkback.d.ts +187 -0
- package/dist/transport/p2p/video.d.ts +150 -0
- package/dist/transport/p2p/write-commands.d.ts +21 -0
- package/dist/transport/protobuf.d.ts +5 -0
- package/dist/transport/push/fcm.d.ts +23 -0
- package/dist/transport/push/index.d.ts +6 -0
- package/dist/transport/push/message-tags.d.ts +26 -0
- package/dist/transport/push/parser.d.ts +27 -0
- package/dist/transport/push/proto.d.ts +11 -0
- package/dist/transport/push/push-client.d.ts +64 -0
- package/dist/transport/push/store.d.ts +23 -0
- package/dist/transport/push/types.d.ts +180 -0
- package/dist/transport/raw-dp.d.ts +6 -0
- package/dist/transport/stored-image-cache.d.ts +23 -0
- package/dist/transport/tuya/account.d.ts +44 -0
- package/dist/transport/tuya/client.d.ts +89 -0
- package/dist/transport/tuya/command-router.d.ts +79 -0
- package/dist/transport/tuya/dp-codec.d.ts +56 -0
- package/dist/transport/tuya/index.d.ts +28 -0
- package/dist/transport/tuya/request.d.ts +157 -0
- package/dist/transport/tuya/sign.d.ts +64 -0
- package/package.json +12 -13
- package/dist/client/index.js +0 -2
- package/dist/client/index.js.map +0 -1
- package/dist/core/index.js +0 -2
- package/dist/core/index.js.map +0 -1
- package/dist/model/index.js +0 -2
- package/dist/model/index.js.map +0 -1
- package/dist/transport/index.js +0 -2
- package/dist/transport/index.js.map +0 -1
|
@@ -0,0 +1,647 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A capability's surface, declared once per feature.
|
|
3
|
+
*
|
|
4
|
+
* Each entry in a module's `members` table is one thing a device exposes, and everything else is
|
|
5
|
+
* DERIVED from it: the property schema the model consumes, the TYPE of the bound `dev.<cap>()` object,
|
|
6
|
+
* the evidence-gated getter, the setter beside it, the intent name `setProperty` resolves through, and
|
|
7
|
+
* the description published for it.
|
|
8
|
+
*
|
|
9
|
+
* The alternative — a table per concern, joined by name — is how one feature ends up spelled in six
|
|
10
|
+
* places and disagreeing with itself. Here a rename moves everything at once, because there is only one
|
|
11
|
+
* declaration to rename.
|
|
12
|
+
*
|
|
13
|
+
* The surface TYPE is derived from the same table the runtime installs from: `dev.motion()`
|
|
14
|
+
* autocompletes with no hand-written `*Actions`.
|
|
15
|
+
*
|
|
16
|
+
* @module model/capabilities/members
|
|
17
|
+
*/
|
|
18
|
+
import { type Command, type CommandSink, type Ff09SettingsReader, type MediaProvider, type RawDpCodec } from "../../core/contracts.js";
|
|
19
|
+
import type { ActionArgSpec, AvailabilityContext, CapabilityStateReader, CommandContext } from "./types.js";
|
|
20
|
+
import type { Capability } from "../types.js";
|
|
21
|
+
import type { PropertySpec, PropertyValueType, ValueKind } from "../types.js";
|
|
22
|
+
/** A member backed by a device property: a getter, plus a setter when `write` is declared. */
|
|
23
|
+
export interface ValueMember {
|
|
24
|
+
/**
|
|
25
|
+
* The wire id carrying this value. Optional only for a {@link writeOnly} member whose write is not a
|
|
26
|
+
* param at all — camera privacy is a frame BURST, and the id that burst is built from belongs to the
|
|
27
|
+
* transport that plays it, not to a capability that would be naming another layer's vocabulary.
|
|
28
|
+
*/
|
|
29
|
+
param?: number;
|
|
30
|
+
/**
|
|
31
|
+
* The name this value takes in the device's FLAT property namespace, when the member key would
|
|
32
|
+
* collide there. The key is the accessor and is scoped by its capability (`dev.battery().level`);
|
|
33
|
+
* a property is not — `level` alone is claimed by both `battery` and `suction`, `volume` by three
|
|
34
|
+
* capabilities. Defaults to the key, which is right for the ~70% that do not collide.
|
|
35
|
+
*/
|
|
36
|
+
property?: string;
|
|
37
|
+
type: PropertyValueType;
|
|
38
|
+
kind?: ValueKind;
|
|
39
|
+
unit?: string;
|
|
40
|
+
enumValues?: Record<number, string>;
|
|
41
|
+
/**
|
|
42
|
+
* A per-device enum resolved at manifest time from the device context — for a value whose options
|
|
43
|
+
* are real but vary by model, so a single static {@link enumValues} cannot state them (e.g.
|
|
44
|
+
* `workingMode`, whose indices number differently per camera). `mergeProperties` calls this with the
|
|
45
|
+
* device context and stamps the result onto that device's spec. Returning `undefined` leaves the
|
|
46
|
+
* static `enumValues` (or none) in place.
|
|
47
|
+
*/
|
|
48
|
+
enumValuesFor?: (ctx: AvailabilityContext) => Record<number, string> | undefined;
|
|
49
|
+
provenance?: PropertySpec["provenance"];
|
|
50
|
+
invert?: boolean;
|
|
51
|
+
description: string;
|
|
52
|
+
/** The wire, or absent for read-only. `undefined` from it = this value is not one we accept. */
|
|
53
|
+
write?: (value: boolean | number | string, ctx: CommandContext) => Command | undefined;
|
|
54
|
+
/** @internal Policy for confirming this write through bounded readback before emitting its transition event. */
|
|
55
|
+
observation?: {
|
|
56
|
+
event: string;
|
|
57
|
+
/**
|
|
58
|
+
* The param this write will be reflected under and the raw value to expect there, resolved together for
|
|
59
|
+
* THIS device — because on some members the family decides both at once.
|
|
60
|
+
*
|
|
61
|
+
* Both, not just the value, because the wire written and the wire reported are not always the same one:
|
|
62
|
+
* camera enablement is written on the enablement param on every family, while the standalone
|
|
63
|
+
* indoor/outdoor cameras report their state under a read alias and never the param that was written.
|
|
64
|
+
* Polling the written param there would never converge, so the readback has to name the param the device
|
|
65
|
+
* actually reports.
|
|
66
|
+
*
|
|
67
|
+
* `undefined` means this device offers no readback to confirm against — it reported no such param, or its
|
|
68
|
+
* write lands on a wire its read does not observe. The command is then dispatched unobserved rather than
|
|
69
|
+
* waiting out a timeout that could never be satisfied.
|
|
70
|
+
*/
|
|
71
|
+
reflects(value: boolean | number | string, ctx: CommandContext): {
|
|
72
|
+
param: number;
|
|
73
|
+
expected: boolean | number | string;
|
|
74
|
+
observed?: boolean | number | string;
|
|
75
|
+
} | undefined;
|
|
76
|
+
resetStandaloneSession?: boolean;
|
|
77
|
+
timeoutMs: number;
|
|
78
|
+
};
|
|
79
|
+
/** Setter name when `set` + the key reads wrong (`isOn` → `set`, not `setIsOn`). */
|
|
80
|
+
writeAs?: string;
|
|
81
|
+
/**
|
|
82
|
+
* A setter for this value EXISTS, but is not this member's own {@link write} — so the published
|
|
83
|
+
* schema's `writable` cannot be derived from `write` alone.
|
|
84
|
+
*
|
|
85
|
+
* `writable` means "a setter exists", and one legitimately lives elsewhere when a `method` member
|
|
86
|
+
* drives the value because a single `write` cannot (rtsp's recording mode sends a two-frame pair), or
|
|
87
|
+
* the setter needs per-bind state the table cannot hold (a vacuum's suction level validates against
|
|
88
|
+
* the model's own range). Guarded by `action-specs.spec.ts`,
|
|
89
|
+
* which asserts every `writable` property has a reachable setter — so this cannot drift into a lie.
|
|
90
|
+
*/
|
|
91
|
+
writtenElsewhere?: true;
|
|
92
|
+
/** Extra intent verbs routed to `write`, each carrying the value it stands for. */
|
|
93
|
+
aliases?: Record<string, boolean | number | string>;
|
|
94
|
+
/**
|
|
95
|
+
* Install the WRITE only on a device that reported one of these params.
|
|
96
|
+
*
|
|
97
|
+
* Distinct from the getter's own evidence gate: a siren's volume write was captured on a real siren,
|
|
98
|
+
* and the evidence that a device IS one is that it reports a siren param — so handing the write to a
|
|
99
|
+
* camera the name hint gave this capability to would send a frame that family never accepts. A member
|
|
100
|
+
* that declares this lands OPTIONAL on the surface, since whether it exists is a runtime fact.
|
|
101
|
+
*
|
|
102
|
+
* Absent = install on any device with the capability, which is right for a wire the whole family
|
|
103
|
+
* speaks.
|
|
104
|
+
*/
|
|
105
|
+
requires?: readonly number[];
|
|
106
|
+
/** Install the write only when this member's family-valid primary param or read alias was reported. */
|
|
107
|
+
requiresRead?: true;
|
|
108
|
+
/** Whether the primary read parameter carries this member on the current device family. */
|
|
109
|
+
readAvailable?: (ctx: AvailabilityContext) => boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Install the write only where this predicate holds — the general form of {@link requires}, for a gate
|
|
112
|
+
* no list of params can express.
|
|
113
|
+
*
|
|
114
|
+
* A lock's rain mode exists on the P2P video lock and not on the MQTT garage door: a TOPOLOGY fact, not
|
|
115
|
+
* a reported param. Audio's controls split the same way on device FAMILY — a HomeBase has an alarm
|
|
116
|
+
* volume, a camera has a microphone, and neither reports the other's params. Like `requires`, a member
|
|
117
|
+
* that declares this lands OPTIONAL on the surface, because whether it exists is a runtime fact.
|
|
118
|
+
*
|
|
119
|
+
* Takes an {@link AvailabilityContext} (not a full CommandContext): the manifest applies the same
|
|
120
|
+
* gate at resolve time, before a live session exists. May read any field the {@link CloudRecord}
|
|
121
|
+
* can supply — `codec`, `model`, `category`, `deviceType`, `capabilities`, `paramIds` — but never
|
|
122
|
+
* transport-only fields (`channel`).
|
|
123
|
+
*/
|
|
124
|
+
available?: (ctx: AvailabilityContext) => boolean;
|
|
125
|
+
/**
|
|
126
|
+
* The write wire is NOT confirmed on a real device.
|
|
127
|
+
*
|
|
128
|
+
* A fire-and-forget write that is wrong looks exactly like success, so it must not ship as a callable
|
|
129
|
+
* method: any {@link write} declared beside this is NOT installed, and the setter lands optional on the
|
|
130
|
+
* surface so a caller learns at COMPILE time. Declare it with no `write` at all when the frame shape is
|
|
131
|
+
* unknown — the flag is what states "the device accepts this, we have not captured how", which is the
|
|
132
|
+
* distinction the intent path answers with rather than a generic "not supported".
|
|
133
|
+
*/
|
|
134
|
+
unverified?: true;
|
|
135
|
+
/**
|
|
136
|
+
* Extra names the intent path should route here, taking the caller's value as-is. Unlike
|
|
137
|
+
* {@link aliases}, no value is supplied: it is the same write under a second name.
|
|
138
|
+
*/
|
|
139
|
+
intentNames?: readonly string[];
|
|
140
|
+
/** Extra wire ids that also carry this value on some families, with their own polarity and family gate. */
|
|
141
|
+
readAliases?: readonly {
|
|
142
|
+
paramType: number;
|
|
143
|
+
invert?: boolean;
|
|
144
|
+
available?: (ctx: AvailabilityContext) => boolean;
|
|
145
|
+
}[];
|
|
146
|
+
/**
|
|
147
|
+
* What the setter accepts, when the member's own kind and bounds do not say it well enough — an
|
|
148
|
+
* argument whose name reads better than the member's, or one the caller may omit.
|
|
149
|
+
*/
|
|
150
|
+
args?: readonly ActionArgSpec[];
|
|
151
|
+
/**
|
|
152
|
+
* A value the setter takes BEYOND what the getter answers — declare it with {@link accepts}.
|
|
153
|
+
*
|
|
154
|
+
* A video-quality tier is stored and read as a number, but the write also resolves the resolution
|
|
155
|
+
* NAME it maps to; without this the derived setter would narrow to the stored type and a caller
|
|
156
|
+
* would lose the names it can pass. Only the TYPE is used — nothing reads the value.
|
|
157
|
+
*/
|
|
158
|
+
accepts?: unknown;
|
|
159
|
+
/** Numeric bounds the value must fall within — the same constants `write` clamps with. */
|
|
160
|
+
min?: number;
|
|
161
|
+
max?: number;
|
|
162
|
+
/**
|
|
163
|
+
* Install the getter on capability alone, not on having seen the param — for state that only ever
|
|
164
|
+
* arrives over realtime, where "has reported already" is the wrong evidence.
|
|
165
|
+
*/
|
|
166
|
+
realtime?: boolean;
|
|
167
|
+
/**
|
|
168
|
+
* Whether this member's READ observes the same wire its write lands on, for a given device. Absent means
|
|
169
|
+
* yes — the ordinary case, where the setter's effect shows up in the getter.
|
|
170
|
+
*
|
|
171
|
+
* Declared only where a family routes the write elsewhere: the read then answers honestly about the param
|
|
172
|
+
* it observes while disagreeing with what the setter did, and a caller has no reason to distrust it. Such a
|
|
173
|
+
* member is named by {@link unreflectedMembers} for the devices where it applies, so the disagreement is
|
|
174
|
+
* stated rather than left to be discovered.
|
|
175
|
+
*/
|
|
176
|
+
readReflectsWrite?: (ctx: CommandContext) => boolean;
|
|
177
|
+
/**
|
|
178
|
+
* A setting the device ACCEPTS but never reports back.
|
|
179
|
+
*
|
|
180
|
+
* No getter (it could only ever answer `undefined`) and no entry in the property schema, which
|
|
181
|
+
* describes what a device reports. It still declares its param and type, because that is what the
|
|
182
|
+
* write needs. Camera privacy is one of these.
|
|
183
|
+
*/
|
|
184
|
+
writeOnly?: true;
|
|
185
|
+
/**
|
|
186
|
+
* Reported by the device — so it IS in the property schema and reachable through `getProperty` — but
|
|
187
|
+
* given no typed getter, because its value space is not evidenced.
|
|
188
|
+
*
|
|
189
|
+
* The distinction from {@link writeOnly} is which half is missing: there the device says nothing, here
|
|
190
|
+
* WE cannot yet say what the value means. Publishing a typed getter over a meaning we have not
|
|
191
|
+
* confirmed is the same guess the never-ship-a-guessed-param rule forbids.
|
|
192
|
+
*/
|
|
193
|
+
unexposed?: true;
|
|
194
|
+
/**
|
|
195
|
+
* Reinterpret the RAW wire value at ingest, for a param the app reads as something other than its face
|
|
196
|
+
* value — a bitfield the device reports as an object, a code that means a flag.
|
|
197
|
+
*
|
|
198
|
+
* Distinct from {@link decode}, and the two are not interchangeable: this runs once when params are
|
|
199
|
+
* applied and REPLACES the default type coercion, so the stored property already holds the corrected
|
|
200
|
+
* value and every reader sees it. `decode` runs per read, inside the getter, where the injected codec
|
|
201
|
+
* is in scope — which is the only way to reach a field inside a payload.
|
|
202
|
+
*/
|
|
203
|
+
coerce?: (raw: string | number | boolean) => boolean | number | string;
|
|
204
|
+
/**
|
|
205
|
+
* Derive the getter's value from the stored one, for a param delivered as a payload rather than a
|
|
206
|
+
* scalar. Its return type wins over {@link type} on the surface, since it IS the value a caller gets —
|
|
207
|
+
* and it is kept EXACTLY, so a decode answering a named union (`VacuumActivity`) surfaces that union
|
|
208
|
+
* rather than the `string` it is stored as. Widening the declared return here would quietly erase it.
|
|
209
|
+
*
|
|
210
|
+
* `codec` is the injected {@link RawDpCodec}, `undefined` on an unbound device — the only place a
|
|
211
|
+
* capability gets one, and the reason a structured DP payload can be read without the transport
|
|
212
|
+
* knowing what its fields mean.
|
|
213
|
+
*/
|
|
214
|
+
decode?: (raw: unknown, codec: RawDpCodec | undefined, ctx: CommandContext) => boolean | number | string | undefined;
|
|
215
|
+
/**
|
|
216
|
+
* This member's value is also a FIELD of another member's payload.
|
|
217
|
+
*
|
|
218
|
+
* Names the member KEY that owns that payload's `param`. The owner's stored property is what this
|
|
219
|
+
* member's {@link decode} is handed, and the owner's evidence installs this member — so a device that
|
|
220
|
+
* never reported the DP gets neither getter, and one that did gets both.
|
|
221
|
+
*
|
|
222
|
+
* The inverse of {@link readAliases}, which is one value across several wire ids. This is several
|
|
223
|
+
* values inside ONE wire id, which is how the clean line reports most of what it knows: nine
|
|
224
|
+
* consumable counters arrive as nine sub-messages of a single `ConsumableRuntime` on DP 168, and a
|
|
225
|
+
* `CleanParam` on DP 154 carries the carpet strategy and the clean type together.
|
|
226
|
+
*
|
|
227
|
+
* **Two shapes, by whether the member also declares a `param` of its own.**
|
|
228
|
+
*
|
|
229
|
+
* *Derived only* (no `param`): the member contributes NO {@link PropertySpec}. The schema describes
|
|
230
|
+
* what a device REPORTS and the device reports one DP, so a second spec for that id would give
|
|
231
|
+
* `Device` two names for one param — and it stores under only the first, leaving the extra getters
|
|
232
|
+
* answering `undefined` forever. That is exactly the failure the evidence gate exists to prevent.
|
|
233
|
+
*
|
|
234
|
+
* *Second source* (with a `param`): the member keeps its own wire and its own spec, and reaches into
|
|
235
|
+
* the owner's payload only on a device that did not report that wire. This is what lets ONE property
|
|
236
|
+
* span both clean lines when the two report it differently — the legacy Tuya line puts the lifetime
|
|
237
|
+
* cleaned area on its own DP, the AIoT line buries it inside `CleanStatistics` on DP 167. Without it,
|
|
238
|
+
* the same value would need two names and every host would branch on device family to ask for it.
|
|
239
|
+
* The `decode` sees whichever raw value the device actually has, so it discriminates on SHAPE, the way
|
|
240
|
+
* the clean line's cross-family decoders already do.
|
|
241
|
+
*
|
|
242
|
+
* **Watch what the owner was installed BY.** An owner with {@link readAliases} can be present because
|
|
243
|
+
* of an alias, and the value stored under its property is then the ALIAS's — a different wire carrying
|
|
244
|
+
* a different figure. A borrowing member that cannot come from that wire has to screen for it, either
|
|
245
|
+
* with its own {@link available} gate or in its `decode`; `lifetimeCleanCount` does both.
|
|
246
|
+
*
|
|
247
|
+
* Read-only either way. Setting a field inside a shared payload means re-encoding the whole message,
|
|
248
|
+
* which needs an encoder and a captured write this SDK does not have; the owner keeps that wire.
|
|
249
|
+
* Guarded by `property-id-integrity.spec.ts`.
|
|
250
|
+
*
|
|
251
|
+
* **Naming an owner in ANOTHER capability.** A string names a sibling in this table, which covers
|
|
252
|
+
* every payload whose readings all belong to one capability. Some do not: `DeviceInfo` on DP 169
|
|
253
|
+
* carries the robot's MAC, SSID and IP beside the DOCK's firmware version, and the one-owner rule is
|
|
254
|
+
* per product LINE — so one capability must own that id and the other's reading would otherwise have
|
|
255
|
+
* to hang off the wrong object. The `{ property, param }` form says "read the property another module
|
|
256
|
+
* owns, gated on the param that carries it", which works because `Device` keys state by NAME in one
|
|
257
|
+
* flat namespace shared across capabilities. Both halves are stated rather than looked up: a member
|
|
258
|
+
* declaring this cannot see the other module's table, and the guard checks the pair against the
|
|
259
|
+
* line's real owner so a rename cannot leave it pointing at nothing.
|
|
260
|
+
*/
|
|
261
|
+
readsFrom?: string | {
|
|
262
|
+
property: string;
|
|
263
|
+
param: number;
|
|
264
|
+
};
|
|
265
|
+
/** What the decoded value means, when it differs from the stored property's own {@link kind}. */
|
|
266
|
+
decodedKind?: ValueKind;
|
|
267
|
+
/**
|
|
268
|
+
* The option set of a decoded `enum` — the counterpart to a property schema's `enumValues`, for a
|
|
269
|
+
* getter whose value that schema cannot express. Legal only alongside {@link decode}, since without
|
|
270
|
+
* one the property's own set is the answer and a second copy could only drift.
|
|
271
|
+
*/
|
|
272
|
+
decodedValues?: readonly (string | number)[];
|
|
273
|
+
}
|
|
274
|
+
/** A member with no readable state: a momentary command. */
|
|
275
|
+
export interface ActionMember {
|
|
276
|
+
action: (ctx: CommandContext) => Command;
|
|
277
|
+
description: string;
|
|
278
|
+
/** Install only on a device reporting one of these params — see {@link ValueMember.requires}. */
|
|
279
|
+
requires?: readonly number[];
|
|
280
|
+
/** Install only where this holds — see {@link ValueMember.available}. */
|
|
281
|
+
available?: (ctx: CommandContext) => boolean;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* What a member's binder is handed — the same providers `actions()` receives today, so a member that
|
|
285
|
+
* needs live state or a transport provider is expressible without leaving the table.
|
|
286
|
+
*/
|
|
287
|
+
export interface MemberDeps {
|
|
288
|
+
ctx: CommandContext;
|
|
289
|
+
sink: CommandSink;
|
|
290
|
+
read: CapabilityStateReader;
|
|
291
|
+
rawDp?: RawDpCodec;
|
|
292
|
+
/**
|
|
293
|
+
* The media provider, when the device is bound to one.
|
|
294
|
+
*
|
|
295
|
+
* Distinct from `provided`("media"), which makes a member EXIST only with a provider. A method
|
|
296
|
+
* that merely uses one when available takes it here instead: a doorbell's quick response plays over an
|
|
297
|
+
* already-open stream with no provider at all, and only needs one to open a stream itself.
|
|
298
|
+
*/
|
|
299
|
+
media?: MediaProvider;
|
|
300
|
+
/**
|
|
301
|
+
* The `ff09` settings reader, when the device is bound to one. Named for the frame family it reads,
|
|
302
|
+
* so any device driven by that frame can use it — see {@link Ff09SettingsReader}.
|
|
303
|
+
*/
|
|
304
|
+
ff09Settings?: Ff09SettingsReader;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* A method the table cannot derive: its value is not one param's, so it owns its whole signature.
|
|
308
|
+
*
|
|
309
|
+
* The escape hatch that keeps the table honest instead of pretending everything is a property — a
|
|
310
|
+
* sensitivity STEP is resolved across four wire ids and two numeric directions, so it is neither a
|
|
311
|
+
* getter over one param nor a momentary command. Its signature flows through to the surface type.
|
|
312
|
+
*/
|
|
313
|
+
export interface MethodMember<F> {
|
|
314
|
+
method: (deps: MemberDeps) => F;
|
|
315
|
+
description: string;
|
|
316
|
+
/** Install only where this holds — see {@link ValueMember.available}. */
|
|
317
|
+
available?: (ctx: CommandContext) => boolean;
|
|
318
|
+
/**
|
|
319
|
+
* What the method accepts, for a signature whose arity does not state it: a parameter with a DEFAULT is
|
|
320
|
+
* absent from `Function.length`, so `locate(on = true)` would otherwise be described as taking nothing
|
|
321
|
+
* at all.
|
|
322
|
+
*
|
|
323
|
+
* Only needed for that case. A method taking its arguments plainly is described as existing with its
|
|
324
|
+
* arguments unstated, and a nullary one has them derived (see `describe`).
|
|
325
|
+
*/
|
|
326
|
+
args?: readonly ActionArgSpec[];
|
|
327
|
+
/**
|
|
328
|
+
* This member ANSWERS rather than ACTS: a sub-API namespace (`ptz.preset()`) or a live query whose
|
|
329
|
+
* returned value is the whole point (`lock.getAutoLockState()`).
|
|
330
|
+
*
|
|
331
|
+
* Both take no arguments, but that arity says nothing about a control — calling one and discarding the
|
|
332
|
+
* answer is not what it is for. So the empty argument list is NOT derived here, leaving the arguments
|
|
333
|
+
* unstated, which is exactly what keeps it from being auto-offered. It stays described, and callable.
|
|
334
|
+
*/
|
|
335
|
+
answers?: true;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* What a `readsFrom` member actually borrows: the property name holding the payload, and the param
|
|
339
|
+
* whose presence is the evidence for it.
|
|
340
|
+
*
|
|
341
|
+
* One resolution for both forms and for every reader of them — `bindMembers` and the three guards that
|
|
342
|
+
* check this mechanism all come through here, so a change to the declaration cannot leave one of them
|
|
343
|
+
* reading the old shape.
|
|
344
|
+
*
|
|
345
|
+
* Answers `undefined` when the member borrows nothing, and for a string that names no sibling: that
|
|
346
|
+
* fallback costs the borrowing member its getter rather than throwing at bind time, which is the
|
|
347
|
+
* failure a guard catches at build time anyway.
|
|
348
|
+
*/
|
|
349
|
+
export declare function borrowedBy(m: Pick<ValueMember, "readsFrom">, members: Members): {
|
|
350
|
+
property: string;
|
|
351
|
+
param: number;
|
|
352
|
+
} | undefined;
|
|
353
|
+
/**
|
|
354
|
+
* Declare a `MethodMember` — the wrapper exists so `F` is inferred from the returned function.
|
|
355
|
+
* Pass `available` for a method only some devices have; it then lands optional on the surface.
|
|
356
|
+
*/
|
|
357
|
+
export declare function method<F>(build: (deps: MemberDeps) => F, description: string): MethodMember<F>;
|
|
358
|
+
/**
|
|
359
|
+
* The gate has to survive into the TYPE, which is why passing one widens the return rather than only
|
|
360
|
+
* setting a field: `available` is optional on `MethodMember`, and an optional property never
|
|
361
|
+
* satisfies the `extends { available: unknown }` test that lands a member optional on the surface.
|
|
362
|
+
*/
|
|
363
|
+
export declare function method<F>(build: (deps: MemberDeps) => F, description: string, available: (ctx: CommandContext) => boolean): MethodMember<F> & {
|
|
364
|
+
available: (ctx: CommandContext) => boolean;
|
|
365
|
+
};
|
|
366
|
+
/** The injected providers a member may be built from, by the technical job each names. */
|
|
367
|
+
export interface Providers {
|
|
368
|
+
media: MediaProvider;
|
|
369
|
+
ff09Settings: Ff09SettingsReader;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* A member only a device bound to a given provider has. Its signature is taken FROM that provider, so
|
|
373
|
+
* the surface cannot claim a shape the provider does not have, and it lands OPTIONAL because an unbound
|
|
374
|
+
* device — or one bound without that provider — genuinely does not have it.
|
|
375
|
+
*/
|
|
376
|
+
export interface ProvidedMember<P extends keyof Providers, F> {
|
|
377
|
+
needs: P;
|
|
378
|
+
provided: (provider: Providers[P], deps: MemberDeps) => F;
|
|
379
|
+
description: string;
|
|
380
|
+
/** This member ANSWERS rather than ACTS — see {@link MethodMember.answers}. */
|
|
381
|
+
answers?: true;
|
|
382
|
+
/** Additional resolved capability evidence required before this provider method is installed. */
|
|
383
|
+
requiredCapabilities?: readonly Capability[];
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Widen a setter's argument past the value its getter answers — see {@link ValueMember.accepts}.
|
|
387
|
+
* Spread into the member (`...accepts<RecordingQualityName>()`); the carried value is never read.
|
|
388
|
+
*/
|
|
389
|
+
export declare function accepts<T>(): {
|
|
390
|
+
accepts: T;
|
|
391
|
+
};
|
|
392
|
+
/** Declare a {@link ProvidedMember} — the wrapper exists so `F` is inferred from the returned function. */
|
|
393
|
+
export declare function provided<P extends keyof Providers, F>(needs: P, build: (provider: Providers[P], deps: MemberDeps) => F, description: string, requiredCapabilities?: readonly Capability[]): ProvidedMember<P, F>;
|
|
394
|
+
/** Whether the resolved capability set satisfies a provider member's additional evidence gate. */
|
|
395
|
+
export declare function hasRequiredCapabilities(member: {
|
|
396
|
+
requiredCapabilities?: readonly Capability[];
|
|
397
|
+
}, capabilities: ReadonlySet<Capability> | undefined): boolean;
|
|
398
|
+
/**
|
|
399
|
+
* The provider-backed shape as the union sees it. `never` in the provider position is deliberate: a
|
|
400
|
+
* parameter is contravariant, so a member built from ONE provider is only assignable to the union when
|
|
401
|
+
* the union's parameter is the bottom type.
|
|
402
|
+
*/
|
|
403
|
+
export type AnyProvidedMember = {
|
|
404
|
+
needs: keyof Providers;
|
|
405
|
+
provided: (provider: never, deps: MemberDeps) => unknown;
|
|
406
|
+
description: string;
|
|
407
|
+
answers?: true;
|
|
408
|
+
requiredCapabilities?: readonly Capability[];
|
|
409
|
+
};
|
|
410
|
+
export type Member = ValueMember | ActionMember | MethodMember<unknown> | AnyProvidedMember;
|
|
411
|
+
export type Members = Record<string, Member>;
|
|
412
|
+
/** The runtime narrowing (`bool`→boolean, `number`/`enum`→number, `string`→string), at type level. */
|
|
413
|
+
export type ValueOf<T> = T extends "bool" ? boolean : T extends "string" ? string : number;
|
|
414
|
+
/**
|
|
415
|
+
* The members a getter is derived for: those backed by a device property, minus the two kinds that
|
|
416
|
+
* declare a param but publish no read — a `writeOnly` setting the device never reports back, and an
|
|
417
|
+
* `unexposed` one whose value space is not evidenced yet.
|
|
418
|
+
*/
|
|
419
|
+
export type ValueKeys<M extends Members> = {
|
|
420
|
+
[K in keyof M]: M[K] extends ValueMember ? M[K] extends {
|
|
421
|
+
writeOnly: true;
|
|
422
|
+
} | {
|
|
423
|
+
unexposed: true;
|
|
424
|
+
} ? never : K : never;
|
|
425
|
+
}[keyof M];
|
|
426
|
+
/** The members that declare their own write wire, so a setter is derived beside the getter. */
|
|
427
|
+
export type WritableKeys<M extends Members> = {
|
|
428
|
+
[K in keyof M]: M[K] extends {
|
|
429
|
+
write: unknown;
|
|
430
|
+
} ? K : never;
|
|
431
|
+
}[keyof M];
|
|
432
|
+
/** The momentary commands — a member with no readable state to reflect. */
|
|
433
|
+
export type ActionKeys<M extends Members> = {
|
|
434
|
+
[K in keyof M]: M[K] extends ActionMember ? K : never;
|
|
435
|
+
}[keyof M];
|
|
436
|
+
/** The members owning their whole signature, which the table cannot derive from one param. */
|
|
437
|
+
export type MethodKeys<M extends Members> = {
|
|
438
|
+
[K in keyof M]: M[K] extends MethodMember<unknown> ? K : never;
|
|
439
|
+
}[keyof M];
|
|
440
|
+
/** The members that exist only on a device bound to the provider they name. */
|
|
441
|
+
export type ProvidedKeys<M extends Members> = {
|
|
442
|
+
[K in keyof M]: M[K] extends {
|
|
443
|
+
needs: unknown;
|
|
444
|
+
} ? K : never;
|
|
445
|
+
}[keyof M];
|
|
446
|
+
/**
|
|
447
|
+
* Writes whose wire is not confirmed on a real device. Declared here so the capability documents what
|
|
448
|
+
* the device has, but NOT installed — and therefore OPTIONAL on the surface, which is how a caller
|
|
449
|
+
* learns at COMPILE time that it is not settable yet.
|
|
450
|
+
*
|
|
451
|
+
* This is the type-level half of the never-guess rule: a present method means a verified wire. Flipping
|
|
452
|
+
* `unverified` off once a capture lands is the only edit needed to promote one.
|
|
453
|
+
*/
|
|
454
|
+
export type UnverifiedKeys<M extends Members> = {
|
|
455
|
+
[K in keyof M]: M[K] extends {
|
|
456
|
+
unverified: true;
|
|
457
|
+
} ? K : never;
|
|
458
|
+
}[keyof M];
|
|
459
|
+
/**
|
|
460
|
+
* Members whose presence is a runtime fact, so the surface must make a caller check: a write installed
|
|
461
|
+
* only on the devices that prove they speak it ({@link ValueMember.requires}), or one whose wire is not
|
|
462
|
+
* captured ({@link ValueMember.unverified}).
|
|
463
|
+
*/
|
|
464
|
+
export type ConditionalKeys<M extends Members> = UnverifiedKeys<M> | {
|
|
465
|
+
[K in keyof M]: M[K] extends {
|
|
466
|
+
requires: readonly number[];
|
|
467
|
+
} ? K : never;
|
|
468
|
+
}[keyof M] | {
|
|
469
|
+
[K in keyof M]: M[K] extends {
|
|
470
|
+
requiresRead: true;
|
|
471
|
+
} ? K : never;
|
|
472
|
+
}[keyof M] | {
|
|
473
|
+
[K in keyof M]: M[K] extends {
|
|
474
|
+
available: unknown;
|
|
475
|
+
} ? K : never;
|
|
476
|
+
}[keyof M];
|
|
477
|
+
/**
|
|
478
|
+
* What a getter answers: a `decode`'s own return type when there is one, otherwise the narrowing of the
|
|
479
|
+
* stored `type`. A decode IS the value a caller receives, so its type has to win — that is exactly the
|
|
480
|
+
* case (`snoozeTime`, a duration lifted out of a config blob) where the stored type is not the answer.
|
|
481
|
+
*/
|
|
482
|
+
export type ReadValue<T> = T extends {
|
|
483
|
+
decode: (...a: never[]) => infer R;
|
|
484
|
+
} ? Exclude<R, undefined> : T extends {
|
|
485
|
+
type: infer P;
|
|
486
|
+
} ? ValueOf<P> : never;
|
|
487
|
+
/**
|
|
488
|
+
* What a setter takes: the getter's own value, plus anything the member declares it {@link ValueMember.accepts} on
|
|
489
|
+
* top — a name for a value stored as a number. The two are a union because both reach the same wire.
|
|
490
|
+
*/
|
|
491
|
+
export type WriteValue<T> = T extends {
|
|
492
|
+
accepts: infer A;
|
|
493
|
+
} ? ReadValue<T> | A : ReadValue<T>;
|
|
494
|
+
/** `brightness` → `setBrightness`, unless the member names its own setter. */
|
|
495
|
+
export type SetterName<K extends string, T> = T extends {
|
|
496
|
+
writeAs: infer W extends string;
|
|
497
|
+
} ? W : `set${Capitalize<K>}`;
|
|
498
|
+
/**
|
|
499
|
+
* The bound `dev.<cap>()` object, derived from the member table.
|
|
500
|
+
*
|
|
501
|
+
* Getters are optional because they are evidence-gated at runtime — the device may never have reported
|
|
502
|
+
* the param. A write is offered on any device with the capability unless the member gates it.
|
|
503
|
+
*
|
|
504
|
+
* Every branch maps over `keyof M` and filters in the `as` clause rather than over a pre-filtered key
|
|
505
|
+
* union. The two describe the same keys, but only the first is HOMOMORPHIC, and a homomorphic mapped type
|
|
506
|
+
* carries each member's JSDoc through to the projection — so hovering `dev.lock().lock()` in an editor
|
|
507
|
+
* shows what the member table says about it. Mapping over `[K in MethodKeys<M>]` silently drops it, which
|
|
508
|
+
* costs the derived surface the one thing a hand-written `*Actions` type still had over it.
|
|
509
|
+
*
|
|
510
|
+
* The provider branch matches STRUCTURALLY on the built function rather than on `ProvidedMember<P, F>`:
|
|
511
|
+
* the provider sits in a contravariant position, so a nominal match against the union's provider type
|
|
512
|
+
* never succeeds. A builder's falsy half is its way of DECLINING, which the optional `?` already says,
|
|
513
|
+
* so it is stripped rather than leaking into what a caller holds after the guard.
|
|
514
|
+
*/
|
|
515
|
+
export type Surface<M extends Members> = {
|
|
516
|
+
readonly [K in keyof M as K extends ValueKeys<M> ? K : never]?: ReadValue<M[K]>;
|
|
517
|
+
} & {
|
|
518
|
+
[K in keyof M as K extends Exclude<WritableKeys<M>, ConditionalKeys<M>> & string ? SetterName<K, M[K]> : never]: (value: WriteValue<M[K]>) => Promise<void>;
|
|
519
|
+
} & {
|
|
520
|
+
[K in keyof M as K extends Extract<WritableKeys<M>, ConditionalKeys<M>> & string ? SetterName<K, M[K]> : never]?: (value: WriteValue<M[K]>) => Promise<void>;
|
|
521
|
+
} & {
|
|
522
|
+
[K in keyof M as K extends Exclude<ActionKeys<M>, ConditionalKeys<M>> & string ? K : never]: () => Promise<void>;
|
|
523
|
+
} & {
|
|
524
|
+
[K in keyof M as K extends Extract<ActionKeys<M>, ConditionalKeys<M>> & string ? K : never]?: () => Promise<void>;
|
|
525
|
+
} & {
|
|
526
|
+
[K in keyof M as K extends Exclude<MethodKeys<M>, ConditionalKeys<M>> ? K : never]: M[K] extends MethodMember<infer F> ? F : never;
|
|
527
|
+
} & {
|
|
528
|
+
[K in keyof M as K extends Extract<MethodKeys<M>, ConditionalKeys<M>> ? K : never]?: M[K] extends MethodMember<infer F> ? F : never;
|
|
529
|
+
} & {
|
|
530
|
+
[K in keyof M as K extends ProvidedKeys<M> ? K : never]?: M[K] extends {
|
|
531
|
+
provided: (...args: never[]) => infer F;
|
|
532
|
+
} ? Exclude<F, false | undefined> : never;
|
|
533
|
+
};
|
|
534
|
+
/**
|
|
535
|
+
* Resolve a member's enum options for a device, evaluating `enumValuesFor` at most once. Returns the
|
|
536
|
+
* options and whether they came from the device context (`dynamic`), so the option set and the enum
|
|
537
|
+
* `kind` both come from a single result. A context domain (`enumValuesFor(ctx)`) is
|
|
538
|
+
* returned when present; absent that (or with no context) the static `enumValues`; a member with
|
|
539
|
+
* neither yields no options.
|
|
540
|
+
*/
|
|
541
|
+
export declare function resolvedEnum(m: ValueMember, ctx?: AvailabilityContext): {
|
|
542
|
+
values?: Record<number, string>;
|
|
543
|
+
dynamic: boolean;
|
|
544
|
+
};
|
|
545
|
+
/**
|
|
546
|
+
* The property schema the rest of the model consumes, derived from the same table.
|
|
547
|
+
*
|
|
548
|
+
* A write-only member contributes nothing: the schema describes what a device REPORTS, and a setting it
|
|
549
|
+
* accepts but never reports back has no state to publish. Its wire still reaches `setProperty` through
|
|
550
|
+
* the member's own `write`.
|
|
551
|
+
*
|
|
552
|
+
* When `ctx` is given, a member's availability gate is applied (a gated-out member contributes no spec)
|
|
553
|
+
* and its enum options are resolved for the device via {@link resolvedEnum}; a context-resolved domain
|
|
554
|
+
* makes the spec's `kind` `"enum"` rather than the member's stored scalar kind. A throwing gate
|
|
555
|
+
* propagates.
|
|
556
|
+
*/
|
|
557
|
+
export declare function propertiesOf(members: Members, ctx?: AvailabilityContext): PropertySpec[];
|
|
558
|
+
/**
|
|
559
|
+
* Build a member's wire for a value, or throw the reason it will not.
|
|
560
|
+
*
|
|
561
|
+
* The ONE write path: the fluent setter and the intent route both come through here, so the declared
|
|
562
|
+
* domain is enforced once and refused with one message. Splitting them would let `setProperty` report an
|
|
563
|
+
* out-of-range value as a device that lacks the feature while the setter beside it named the set the
|
|
564
|
+
* value had to come from.
|
|
565
|
+
* @internal
|
|
566
|
+
*/
|
|
567
|
+
export declare function memberWrite(name: string, m: ValueMember, value: boolean | number | string, ctx: CommandContext): Command;
|
|
568
|
+
/**
|
|
569
|
+
* Narrow a stored property to the member's declared type, answering `undefined` on a mismatch rather
|
|
570
|
+
* than lie-casting — the guard {@link ReadValue} promises a caller at compile time.
|
|
571
|
+
*
|
|
572
|
+
* A stored value is not always the declared type: `coerceByType` keeps a non-numeric wire value as the
|
|
573
|
+
* raw string so the mismatch is visible in the log, and a param the dictionary declares `json`-encoded
|
|
574
|
+
* is stored as a decoded object. Handing either through a getter typed `number` is the one lie this
|
|
575
|
+
* table exists to prevent.
|
|
576
|
+
*
|
|
577
|
+
* Exported so the ONE narrowing the getters use is also the one a property-change announcement carries.
|
|
578
|
+
* A second conversion of the wire value is precisely how a payload comes to disagree with the getter
|
|
579
|
+
* beside it, which would defeat the point of announcing the change at all.
|
|
580
|
+
* @internal
|
|
581
|
+
*/
|
|
582
|
+
export declare function narrow(type: PropertyValueType, read: CapabilityStateReader, prop: string): boolean | number | string | undefined;
|
|
583
|
+
/**
|
|
584
|
+
* Both presence gates at once: the params a member requires, and its own {@link ValueMember.available}.
|
|
585
|
+
*
|
|
586
|
+
* Shared with the intent path, so `setProperty("alarmVolume", …)` is gated by exactly what decides
|
|
587
|
+
* whether the fluent setter exists — one declaration, both entry points. Missing the `available` half
|
|
588
|
+
* here would let the intent path build a HomeBase's station frame for an NVR.
|
|
589
|
+
* @internal
|
|
590
|
+
*/
|
|
591
|
+
export declare function installs(m: {
|
|
592
|
+
requires?: readonly number[];
|
|
593
|
+
requiresRead?: true;
|
|
594
|
+
available?: (c: CommandContext) => boolean;
|
|
595
|
+
param?: number;
|
|
596
|
+
realtime?: boolean;
|
|
597
|
+
readAvailable?: ValueMember["readAvailable"];
|
|
598
|
+
readAliases?: ValueMember["readAliases"];
|
|
599
|
+
}, ctx: CommandContext): boolean;
|
|
600
|
+
/**
|
|
601
|
+
* Bind the table: evidence-gated getters, derived setters, momentary actions.
|
|
602
|
+
*
|
|
603
|
+
* Three rules the loop enforces for every member, so no module restates them:
|
|
604
|
+
*
|
|
605
|
+
* - **One evidence gate for every read, decoded or not.** A `decode` changes how a value is READ, never
|
|
606
|
+
* whether the device reports it, so gating only the plain branch would publish a getter for a param
|
|
607
|
+
* the device never sent — one answering `undefined` forever. `realtime` is the opt-out.
|
|
608
|
+
* - **A provider builder answering nothing DECLINES.** The provider is there but the member is not
|
|
609
|
+
* available on it (an optional method, or one the device gave no evidence for), so the member is
|
|
610
|
+
* ABSENT rather than a key holding `undefined` — `"talkback" in cam` has to mean the camera can talk.
|
|
611
|
+
* Any falsy answer counts, so a builder can guard with `&&` instead of spelling out a ternary.
|
|
612
|
+
* - **A derived setter never throws synchronously.** A builder may throw (arming's needs the account
|
|
613
|
+
* identity and says so by throwing) and a method returning `Promise<void>` must not surprise a caller
|
|
614
|
+
* chaining `.catch()`. Caught here once rather than in each module's own wrapper.
|
|
615
|
+
*
|
|
616
|
+
* A getter is skipped for a `writeOnly` or `unexposed` member, and a setter for an `unverified` one —
|
|
617
|
+
* declared so the capability documents the device, never installed.
|
|
618
|
+
*/
|
|
619
|
+
export declare function bindMembers<M extends Members>(members: M, deps: MemberDeps): Surface<M>;
|
|
620
|
+
/**
|
|
621
|
+
* The members this device can be told to change but will never report back.
|
|
622
|
+
*
|
|
623
|
+
* `cam.privacy === undefined` reads identically for a device that reports the value as unset and one that
|
|
624
|
+
* never reports it, and the two must not be guessed between.
|
|
625
|
+
*
|
|
626
|
+
* Only members whose setter is actually installed for this device are listed. A member whose write is
|
|
627
|
+
* unverified has no setter and its intent path throws, so calling it something the device "accepts" would
|
|
628
|
+
* put exactly the guess the unverified-write rule excludes back into the typed story.
|
|
629
|
+
*
|
|
630
|
+
* `unexposed` members are deliberately absent: the device DOES report those — they are in the property schema
|
|
631
|
+
* and reachable through `getProperty` — what is missing is a confirmed meaning for the value.
|
|
632
|
+
*
|
|
633
|
+
* Empty for any object that is not a bound capability.
|
|
634
|
+
*/
|
|
635
|
+
export declare const unobservableMembers: (surface: object) => readonly string[];
|
|
636
|
+
/**
|
|
637
|
+
* The members this device reports, but whose value does NOT reflect what its own setter writes — because on
|
|
638
|
+
* this device family the write lands on a different wire than the read observes.
|
|
639
|
+
*
|
|
640
|
+
* A readable value that silently disagrees with the write is worse than an unreadable one: a caller has no
|
|
641
|
+
* reason to distrust it. Camera enablement is one on the families whose power rides the privacy envelope —
|
|
642
|
+
* the write goes there while the read still observes the on/off param, so a camera that has been turned off
|
|
643
|
+
* still reads as on.
|
|
644
|
+
*
|
|
645
|
+
* Empty for any object that is not a bound capability.
|
|
646
|
+
*/
|
|
647
|
+
export declare const unreflectedMembers: (surface: object) => readonly string[];
|