@mega-yfue/eufy-sdk 0.5.0-beta.7 → 0.5.0-beta.71
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/client/device-registry.d.ts +24 -2
- package/dist/client/eufy-mega.d.ts +83 -10
- package/dist/client/types.d.ts +1 -1
- package/dist/core/contracts.d.ts +71 -30
- package/dist/core/store.d.ts +4 -0
- package/dist/core/types.d.ts +2 -0
- package/dist/index.js +3611 -603
- package/dist/index.js.map +4 -4
- package/dist/model/capabilities/arming.d.ts +39 -4
- package/dist/model/capabilities/camera.d.ts +24 -10
- package/dist/model/capabilities/dp-catalog.d.ts +4 -3
- package/dist/model/capabilities/index.d.ts +16 -3
- package/dist/model/capabilities/light.d.ts +3 -0
- package/dist/model/capabilities/lock.d.ts +21 -7
- package/dist/model/capabilities/motion.d.ts +5 -0
- package/dist/model/capabilities/mower.d.ts +230 -0
- package/dist/model/capabilities/rtsp.d.ts +16 -3
- package/dist/model/capabilities/smart-drop.d.ts +20 -0
- package/dist/model/capabilities/suction.d.ts +5 -5
- package/dist/model/capabilities/types.d.ts +10 -0
- package/dist/model/capabilities/vacuum-clean.d.ts +19 -13
- package/dist/model/classify.d.ts +1 -2
- package/dist/model/device-family.d.ts +8 -0
- package/dist/model/param-dictionary.d.ts +6 -0
- package/dist/model/param-namespace.d.ts +1 -1
- package/dist/model/registry.d.ts +3 -2
- package/dist/model/types.d.ts +26 -12
- package/dist/transport/abortable.d.ts +8 -0
- package/dist/transport/http/mega-client.d.ts +34 -2
- package/dist/transport/mqtt/broker-discovery.d.ts +2 -1
- package/dist/transport/mqtt/command-router.d.ts +3 -2
- package/dist/transport/p2p/codec.d.ts +16 -0
- package/dist/transport/p2p/command-router.d.ts +27 -35
- package/dist/transport/p2p/fmp4.d.ts +12 -2
- package/dist/transport/p2p/live-trace.d.ts +11 -2
- package/dist/transport/p2p/p2p-session.d.ts +59 -12
- package/dist/transport/p2p/readable-egress.d.ts +4 -0
- package/dist/transport/p2p/recording-download.d.ts +4 -3
- package/dist/transport/p2p/shared-live-source.d.ts +27 -13
- package/dist/transport/p2p/talkback.d.ts +21 -10
- package/dist/transport/p2p/video.d.ts +2 -0
- package/dist/transport/rtc/call-live.d.ts +41 -0
- package/dist/transport/rtc/command-router.d.ts +141 -0
- package/dist/transport/rtc/live.d.ts +69 -0
- package/dist/transport/rtc/peer.d.ts +122 -0
- package/dist/transport/rtc/portal-keepalive.d.ts +11 -0
- package/dist/transport/rtc/portal-packet.d.ts +72 -0
- package/dist/transport/rtc/ptcs-framer.d.ts +86 -0
- package/dist/transport/rtc/scall-sdp.d.ts +50 -0
- package/dist/transport/rtc/session.d.ts +95 -0
- package/dist/transport/rtc/signaling.d.ts +139 -0
- package/dist/transport/token-echo.d.ts +8 -0
- package/dist/transport/tuya/account.d.ts +8 -5
- package/dist/transport/tuya/client.d.ts +19 -5
- package/dist/transport/tuya/command-router.d.ts +10 -14
- package/dist/transport/tuya/dp-codec.d.ts +2 -23
- package/dist/transport/tuya/et3.d.ts +22 -0
- package/dist/transport/tuya/request.d.ts +18 -8
- package/dist/transport/tuya/sign.d.ts +7 -0
- package/package.json +2 -1
|
@@ -60,6 +60,8 @@ export type ProductLine = "security" | "life" | "clean" | "print" | "display" |
|
|
|
60
60
|
* `p2p-frame` shape of {@link InboundSignal}.
|
|
61
61
|
*/
|
|
62
62
|
export interface CapabilityFrame {
|
|
63
|
+
/** Cloud device type resolved from the reporting station/channel. */
|
|
64
|
+
deviceType?: number;
|
|
63
65
|
stationSn: string;
|
|
64
66
|
commandId: number;
|
|
65
67
|
channel: number;
|
|
@@ -247,8 +249,16 @@ export interface AvailabilityContext {
|
|
|
247
249
|
homeBaseAttached?: boolean;
|
|
248
250
|
/** Serial of the covering station, when the device record names one. */
|
|
249
251
|
stationSerial?: string;
|
|
252
|
+
/**
|
|
253
|
+
* The vendor DeviceType of the station the device hangs off, when it is attached
|
|
254
|
+
* and the station's record states one. Answers which station family a command addressed to an
|
|
255
|
+
* attached device is carried through.
|
|
256
|
+
*/
|
|
257
|
+
stationDeviceType?: number;
|
|
250
258
|
}
|
|
251
259
|
export interface CommandContext extends AvailabilityContext {
|
|
260
|
+
/** Vendor-formatted timezone reported by the station; never inferred from the host. */
|
|
261
|
+
timezone?: string;
|
|
252
262
|
/** Device channel (0 for standalone, `device_channel` on a HomeBase). */
|
|
253
263
|
channel: number;
|
|
254
264
|
/** eufy DeviceType, when known. */
|
|
@@ -169,12 +169,11 @@ export declare const TUYA_CLEAN_TYPES: readonly ["Sweep", "SweepMop", "Mop"];
|
|
|
169
169
|
/** @internal */
|
|
170
170
|
export type TuyaCleanType = (typeof TUYA_CLEAN_TYPES)[number];
|
|
171
171
|
/**
|
|
172
|
-
* `ModeCtrlRequest.method` values for DP 152. Live-verified on T2351:
|
|
173
|
-
*
|
|
172
|
+
* `ModeCtrlRequest.method` values for DP 152. Live-verified on T2351: START_GOHOME → 6,
|
|
173
|
+
* PAUSE_TASK → 13. An auto clean is `START_AUTO_CLEAN` (0) with a payload — see
|
|
174
|
+
* {@link ModeCtrlParamMethod}.
|
|
174
175
|
*/
|
|
175
176
|
export declare const ModeCtrlMethod: {
|
|
176
|
-
/** Live-verified on a T2351. Zero, so it is omitted from the wire per the proto3 default rule. */
|
|
177
|
-
readonly START_AUTO_CLEAN: 0;
|
|
178
177
|
/** Live-verified on a T2351. */
|
|
179
178
|
readonly START_GOHOME: 6;
|
|
180
179
|
/** Live-verified on a T2351. */
|
|
@@ -202,9 +201,11 @@ export declare const ModeCtrlMethod: {
|
|
|
202
201
|
* its argument in the signature: {@link VACUUM_CLEAN_MEMBERS.startScene},
|
|
203
202
|
* {@link VACUUM_CLEAN_MEMBERS.cleanRooms} and {@link VACUUM_CLEAN_MEMBERS.cleanZones}.
|
|
204
203
|
*
|
|
205
|
-
* The outer frame these ride in is byte-verified on a live T2351, and `SCENE`, `SELECT_ROOMS`
|
|
206
|
-
* `SELECT_ZONES` have each since been RUN on a T2351 and did what they name — so their numbers rest
|
|
207
|
-
* observed behaviour rather than on the vendor's definition alone.
|
|
204
|
+
* The outer frame these ride in is byte-verified on a live T2351, and `AUTO`, `SCENE`, `SELECT_ROOMS`
|
|
205
|
+
* and `SELECT_ZONES` have each since been RUN on a T2351 and did what they name — so their numbers rest
|
|
206
|
+
* on observed behaviour rather than on the vendor's definition alone. `AUTO` is RUN with its payload:
|
|
207
|
+
* the vendor's definition calls `AutoClean.clean_times` valid only when non-zero, and the T2351 did
|
|
208
|
+
* not start on method 0 sent without it.
|
|
208
209
|
*
|
|
209
210
|
* That distinction is the whole point of checking, and this is the one place it is argued: an AIoT
|
|
210
211
|
* data-point write is fire-and-forget, so a wrong number would be a different command arriving and
|
|
@@ -215,6 +216,11 @@ export declare const ModeCtrlMethod: {
|
|
|
215
216
|
* scene id and a map id both arrive on DP 180.
|
|
216
217
|
*/
|
|
217
218
|
export declare const ModeCtrlParamMethod: {
|
|
219
|
+
/** `START_AUTO_CLEAN` with an `AutoClean` payload — clean the whole floor. */
|
|
220
|
+
readonly AUTO: {
|
|
221
|
+
readonly method: 0;
|
|
222
|
+
readonly param: 3;
|
|
223
|
+
};
|
|
218
224
|
/** `START_SELECT_ROOMS_CLEAN` — clean the named rooms of a named map. */
|
|
219
225
|
readonly SELECT_ROOMS: {
|
|
220
226
|
readonly method: 1;
|
|
@@ -274,17 +280,17 @@ export declare function encodeSelectZonesClean(mapId: number, zones: readonly Va
|
|
|
274
280
|
* @internal
|
|
275
281
|
*/
|
|
276
282
|
export declare function encodeSceneClean(sceneId: number): string;
|
|
283
|
+
/**
|
|
284
|
+
* Build a whole-floor auto clean carrying an `AutoClean` payload of one pass.
|
|
285
|
+
* @internal
|
|
286
|
+
*/
|
|
287
|
+
export declare function encodeAutoClean(): string;
|
|
277
288
|
/**
|
|
278
289
|
* Encode a `ModeCtrlRequest` protobuf (DP 152) as a DP value: `varint(bodyLen) ++ {method:1, seq:2}`.
|
|
279
290
|
*
|
|
280
291
|
* Built on {@link RawDpWriter} rather than hand-rolled bytes. The frame is unchanged and the existing
|
|
281
292
|
* byte-level test is what proves it — that test was written against a live T2351 capture, so it holds
|
|
282
293
|
* the writer to the wire rather than to this function's own idea of the wire.
|
|
283
|
-
*
|
|
284
|
-
* Method 0 (START_AUTO_CLEAN) is omitted rather than written as an explicit zero, per the proto3
|
|
285
|
-
* default-field rule and confirmed on that same capture. The writer deliberately does not apply that
|
|
286
|
-
* rule itself: whether an explicit zero and an absent field mean the same thing is the
|
|
287
|
-
* message's business, not the encoder's.
|
|
288
294
|
* @internal
|
|
289
295
|
*/
|
|
290
296
|
export declare function encodeModeCtrl(method: number, seq: number): string;
|
|
@@ -1955,7 +1961,7 @@ export declare const VACUUM_CLEAN_MEMBERS: {
|
|
|
1955
1961
|
readonly provenance: "mega";
|
|
1956
1962
|
readonly description: "Stop smart-follow mode (ModeCtrlRequest method 18 over DP 152). Method number not captured — unverified.";
|
|
1957
1963
|
};
|
|
1958
|
-
/** Start an auto-clean run via ModeCtrlRequest method 0 (DP 152). AIoT only — Tuya write unverified. */
|
|
1964
|
+
/** Start an auto-clean run via ModeCtrlRequest method 0 with one `AutoClean` pass (DP 152). AIoT only — Tuya write unverified. */
|
|
1959
1965
|
readonly startCleaning: import("./members.js").MethodMember<() => Promise<void>> & {
|
|
1960
1966
|
available: (ctx: import("./types.js").CommandContext) => boolean;
|
|
1961
1967
|
};
|
package/dist/model/classify.d.ts
CHANGED
|
@@ -56,8 +56,7 @@ export declare function codecForType(deviceType: number): Codec | undefined;
|
|
|
56
56
|
* - `T74xx` → **lock** (SmartSafe 7400-series).
|
|
57
57
|
* - `T80xx` / `T8001` / `T8002` / `T8010` / `T8030` / `T8023` / `T8025` → **station**
|
|
58
58
|
* (HomeBase / HomeBase 2 / 3 / Mini), `T9000` (the app's own model registry files it as family
|
|
59
|
-
* `STATION_9000`, the one station family outside the T8 band), and `T8N00` (NVR)
|
|
60
|
-
* NVR) → station.
|
|
59
|
+
* `STATION_9000`, the one station family outside the T8 band), and `T8N00` (NVR) → station.
|
|
61
60
|
* - `T89xx` (entry/motion/water/siren sensors, e.g. T8900/T8910/T8920) → **sensor**.
|
|
62
61
|
* - `T87xx` keypad (`T8960`) → **keypad**.
|
|
63
62
|
* - any other `T8…` security T-code → **camera** (the default security family).
|
|
@@ -43,6 +43,12 @@ export declare const isOutdoorPanTilt: (ctx: FamilyContext) => boolean;
|
|
|
43
43
|
export declare const isFloodLight: (ctx: FamilyContext) => boolean;
|
|
44
44
|
/** HomeBase-family hub (has a speaker/alarm) — a station EXCLUDING the NVRs, per `HOMEBASE_TYPES`. */
|
|
45
45
|
export declare const isHomeBase: (ctx: FamilyContext) => boolean;
|
|
46
|
+
/** HomeBase S1 Pro (`STATION_9000`), the station the app drives over its WebRTC control channel. */
|
|
47
|
+
export declare const isStation9000: (ctx: FamilyContext) => boolean;
|
|
48
|
+
/** T8N00 NVR, identified by its reported model. */
|
|
49
|
+
export declare const isNvrT8N00: (ctx: FamilyContext) => boolean;
|
|
50
|
+
/** Video Doorbell C31 (T8223), identified by its reported model. */
|
|
51
|
+
export declare const isDoorbellT8223: (ctx: FamilyContext) => boolean;
|
|
46
52
|
/** Wired doorbell (DeviceType.DOORBELL). */
|
|
47
53
|
export declare const isWiredDoorbell: (ctx: FamilyContext) => boolean;
|
|
48
54
|
/**
|
|
@@ -72,3 +78,5 @@ export declare const isAiotVacuum: (ctx: FamilyContext) => boolean;
|
|
|
72
78
|
* vacuums receive the same write actions as AIoT ones, routed by the facade's `routeCommand`.
|
|
73
79
|
*/
|
|
74
80
|
export declare const isTuyaVacuum: (ctx: FamilyContext) => boolean;
|
|
81
|
+
/** Video Smart Lock S330, identified by its distinct cloud device type. */
|
|
82
|
+
export declare const isVideoSmartLock: (ctx: FamilyContext) => boolean;
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* `types.ts`.
|
|
10
10
|
* - CLEAN_PARAMS — RoboVac Tuya DP space (ids 1 and above), names from the cloud
|
|
11
11
|
* `get_product_data_point` data_point_list, hence provenance `mega`.
|
|
12
|
+
* - MOWER_PARAMS — robot-mower Tuya DP space, names from the mower's Tuya product schema.
|
|
12
13
|
*
|
|
13
14
|
* Which models reported an id, and the capture that named it, are in the commit that adds the entry.
|
|
14
15
|
*/
|
|
@@ -50,3 +51,8 @@ export declare const CLEAN_PARAMS: Record<number, ParamDef>;
|
|
|
50
51
|
* display settings screen, one control at a time, params diffed after each.
|
|
51
52
|
*/
|
|
52
53
|
export declare const DISPLAY_PARAMS: Record<number, ParamDef>;
|
|
54
|
+
/**
|
|
55
|
+
* Robot-mower Tuya DP space — names from the E15's Tuya product schema (`schemaInfo.schema`), each id
|
|
56
|
+
* also reported by a live E15. Only the scalar data points the `mower` capability reads are listed.
|
|
57
|
+
*/
|
|
58
|
+
export declare const MOWER_PARAMS: Record<number, ParamDef>;
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import type { Codec } from "./types.js";
|
|
15
15
|
import { type ParamDef } from "./param-dictionary.js";
|
|
16
16
|
/** The param id spaces this SDK models. */
|
|
17
|
-
export type ParamNamespace = "security" | "clean" | "life" | "print" | "display";
|
|
17
|
+
export type ParamNamespace = "security" | "clean" | "mower" | "life" | "print" | "display";
|
|
18
18
|
/** Look up a param def in the given namespace. */
|
|
19
19
|
export declare function paramDef(ns: ParamNamespace, paramType: number): ParamDef | undefined;
|
|
20
20
|
/** The param namespace a device's ids live in, from its codec, via the module-local `NAMESPACE_BY_CODEC` table. */
|
package/dist/model/registry.d.ts
CHANGED
|
@@ -48,7 +48,8 @@ export declare function resolveDevice(rec: CloudRecord): ResolvedDevice;
|
|
|
48
48
|
* The property manifest for a device, from its capabilities and the record's facts. The single place
|
|
49
49
|
* an {@link AvailabilityContext} is built — so a family-gate (`available`) and a per-model enum
|
|
50
50
|
* (`enumValuesFor`) are decided from the same truthful, session-free view on every path (initial
|
|
51
|
-
* resolve and {@link Device.reresolve}). Populated only from what a record carries
|
|
52
|
-
*
|
|
51
|
+
* resolve and {@link Device.reresolve}). Populated only from what a record carries: its cloud params and
|
|
52
|
+
* the params its device reported over realtime, the same evidence a bound getter is gated on. Never
|
|
53
|
+
* transport fields a live session hasn't produced.
|
|
53
54
|
*/
|
|
54
55
|
export declare function resolveProperties(rec: CloudRecord, codec: Codec, capabilities: Capability[]): PropertySpec[];
|
package/dist/model/types.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ export type Codec = "station" | "camera" | "sensor" | "lock" | "keypad" | "vacuu
|
|
|
39
39
|
* it maps to a {@link CapabilityModule} that owns its property schema. Extend this union as
|
|
40
40
|
* new capabilities are modelled — adding one never requires a subclass.
|
|
41
41
|
*/
|
|
42
|
-
export type Capability = "video" | "snapshot" | "motion" | "person_detection" | "battery" | "light" | "ptz" | "doorbell" | "contact" | "leak" | "smoke" | "co" | "siren" | "lock" | "keypad" | "arming" | "storage" | "rtsp" | "camera" | "audio" | "vacuum_clean" | "vacuum_dock" | "suction" | "locate" | "smart_light" | "display" | "info";
|
|
42
|
+
export type Capability = "video" | "snapshot" | "motion" | "person_detection" | "battery" | "light" | "ptz" | "doorbell" | "contact" | "leak" | "smoke" | "co" | "siren" | "lock" | "keypad" | "arming" | "storage" | "rtsp" | "camera" | "audio" | "vacuum_clean" | "vacuum_dock" | "suction" | "locate" | "mower" | "smart_drop" | "smart_light" | "display" | "info";
|
|
43
43
|
/** Value type of a property. */
|
|
44
44
|
export type PropertyValueType = "bool" | "number" | "string" | "enum";
|
|
45
45
|
/**
|
|
@@ -52,11 +52,12 @@ export type PropertyValueType = "bool" | "number" | "string" | "enum";
|
|
|
52
52
|
* one as the other is wrong in a way no type check catches.
|
|
53
53
|
*
|
|
54
54
|
* - `boolean` — an on/off state (always paired with `type: "bool"`).
|
|
55
|
-
* - `percent` / `celsius` / `dbm` / `seconds` / `hours` / `
|
|
56
|
-
* in the unit the device reports it in; each pairs with the
|
|
57
|
-
* never converted on the way out — a converted reading is an invented
|
|
58
|
-
* are separate kinds for exactly that reason: a robot reports
|
|
59
|
-
*
|
|
55
|
+
* - `percent` / `celsius` / `dbm` / `seconds` / `hours` / `minutes` / `millimetres` / `megabytes` /
|
|
56
|
+
* `degrees` — a measured quantity in the unit the device reports it in; each pairs with the
|
|
57
|
+
* matching `unit`. Values are never converted on the way out — a converted reading is an invented
|
|
58
|
+
* one. `seconds`, `minutes` and `hours` are separate kinds for exactly that reason: a robot reports
|
|
59
|
+
* a run in seconds, a mower its blade wear in minutes and a vacuum's consumable wear in hours, and
|
|
60
|
+
* normalising one into another would publish a number the device never sent.
|
|
60
61
|
* - `scalar` — a plain number in no unit at all: a step on a ladder, a mode index, a raw level, a
|
|
61
62
|
* segment count. Ordered and comparable, but its range and direction are the device's, so nothing
|
|
62
63
|
* but the device says what a given value means.
|
|
@@ -83,7 +84,7 @@ export type PropertyValueType = "bool" | "number" | "string" | "enum";
|
|
|
83
84
|
* decodes them and are exported beside that decoder; unlike an enum's options they are not carried
|
|
84
85
|
* here, which is a gap this vocabulary does not close on its own.
|
|
85
86
|
*/
|
|
86
|
-
export declare const KNOWN_VALUE_KINDS: readonly ["boolean", "percent", "celsius", "dbm", "seconds", "hours", "megabytes", "degrees", "scalar", "bitfield", "enum", "identifier", "timestamp", "text"];
|
|
87
|
+
export declare const KNOWN_VALUE_KINDS: readonly ["boolean", "percent", "celsius", "dbm", "seconds", "hours", "minutes", "millimetres", "megabytes", "degrees", "scalar", "bitfield", "enum", "identifier", "timestamp", "text"];
|
|
87
88
|
/** One of the kinds this version models — the closed half of {@link ValueKind}. */
|
|
88
89
|
export type KnownValueKind = (typeof KNOWN_VALUE_KINDS)[number];
|
|
89
90
|
/**
|
|
@@ -106,7 +107,8 @@ export declare function isKnownValueKind(kind: ValueKind): kind is KnownValueKin
|
|
|
106
107
|
/**
|
|
107
108
|
* How much a param's name and meaning can be trusted, most-trusted first. This is the one definition;
|
|
108
109
|
* the param dictionary and every `provenance` field use it.
|
|
109
|
-
* - `mega` — the vendor's cloud names it: its data-point catalog (`get_product_data_point`),
|
|
110
|
+
* - `mega` — the vendor's cloud names it: its data-point catalog (`get_product_data_point`), the
|
|
111
|
+
* Tuya product schema of an `eufy_home_tuya` device (`thing.m.device.ref.info.list`), or a
|
|
110
112
|
* reported value that matches what the cloud record already says (a model name or code).
|
|
111
113
|
* - `verified` — confirmed on a real device by this project: our own capture or observation, or
|
|
112
114
|
* identified by someone who has the hardware.
|
|
@@ -140,6 +142,11 @@ export interface PropertySpec {
|
|
|
140
142
|
kind?: ValueKind;
|
|
141
143
|
/** Whether the value can be written back to the device (a setter exists). */
|
|
142
144
|
writable: boolean;
|
|
145
|
+
/**
|
|
146
|
+
* Whether the device has reported this value: its own param, a read alias, or the payload it reads
|
|
147
|
+
* from. `false` means it never has. Absent when the manifest was built without the device's params.
|
|
148
|
+
*/
|
|
149
|
+
reported?: boolean;
|
|
143
150
|
/** Allowed values for `type: "enum"` (raw → label). */
|
|
144
151
|
enumValues?: Record<number, string>;
|
|
145
152
|
/**
|
|
@@ -170,10 +177,11 @@ export interface PropertySpec {
|
|
|
170
177
|
* consumable counters are `"number"` over one base64 string, and reading the value as a number is
|
|
171
178
|
* exactly what must NOT happen at ingest.
|
|
172
179
|
*
|
|
173
|
-
* Storage
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
180
|
+
* Storage keeps such a value intact: a non-numeric string passes a `number` coercion unchanged, and
|
|
181
|
+
* on a `bool` property a string that is not a boolean wire form (`"0"`, `"1"`, `"true"`, `"false"`)
|
|
182
|
+
* is kept rather than read as `false`. The pass-through is not reported as a mistake: a robot
|
|
183
|
+
* reporting ten Raw DPs on every push logged ten warnings a time saying its properties were
|
|
184
|
+
* misdeclared, which is how a real warning goes unread.
|
|
177
185
|
*/
|
|
178
186
|
raw?: true;
|
|
179
187
|
/**
|
|
@@ -286,6 +294,12 @@ export interface CloudRecord {
|
|
|
286
294
|
parentSn?: string;
|
|
287
295
|
/** Reported param_type → raw value. Presence of a param is a capability signal. */
|
|
288
296
|
params?: Record<number, string>;
|
|
297
|
+
/**
|
|
298
|
+
* Params the device reported over its realtime channel, keyed in the device's own namespace. A line
|
|
299
|
+
* whose state exists only on that channel carries none of it in {@link params}, so this is the
|
|
300
|
+
* evidence an availability gate on such a param is decided from.
|
|
301
|
+
*/
|
|
302
|
+
dpParams?: Record<number, string>;
|
|
289
303
|
}
|
|
290
304
|
/** The fully-resolved device shape produced by the 3-tier resolver. */
|
|
291
305
|
export interface ResolvedDevice {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settle `work` as it settles, or reject the moment `signal` aborts, whichever comes first.
|
|
3
|
+
*
|
|
4
|
+
* The underlying wait is left to finish on its own: it may be shared work other callers are waiting on, so a
|
|
5
|
+
* caller abandoning its own call does not cancel the work itself. This abandons WAITING, which is the only
|
|
6
|
+
* part that belonged to the caller.
|
|
7
|
+
*/
|
|
8
|
+
export declare function abortable<T>(work: Promise<T>, signal?: AbortSignal): Promise<T>;
|
|
@@ -209,6 +209,8 @@ export interface SignedRetry {
|
|
|
209
209
|
export declare class MegaHttpClient {
|
|
210
210
|
private readonly cfg;
|
|
211
211
|
private region;
|
|
212
|
+
/** The host `estimate_domain` answered, persisted with the session. */
|
|
213
|
+
private estimatedDomain;
|
|
212
214
|
private bootstrapDomain?;
|
|
213
215
|
private sessionKey?;
|
|
214
216
|
/** Per-host ECDH session keys for non-mega gateways (e.g. eufylife) keyed by host. */
|
|
@@ -228,6 +230,8 @@ export declare class MegaHttpClient {
|
|
|
228
230
|
/** True while a 2FA code is outstanding: `auth_` holds only the limited pre-verify token, so the
|
|
229
231
|
* restored-session short-circuit must NOT treat it as a usable session. Cleared on Ok/reset. */
|
|
230
232
|
private pending2fa;
|
|
233
|
+
/** An autonomous re-login answered captcha/2FA; see {@link canReauthenticate}. */
|
|
234
|
+
private reloginChallenged;
|
|
231
235
|
private tokenExpiresAt;
|
|
232
236
|
/**
|
|
233
237
|
* Stable per-install device id: `openudid` as configured, as restored from the session store, or as
|
|
@@ -259,10 +263,12 @@ export declare class MegaHttpClient {
|
|
|
259
263
|
constructor(cfg: MegaClientConfig);
|
|
260
264
|
/**
|
|
261
265
|
* Install the session the store holds, if it holds a usable one: the token + its bound ECDH key, skipping
|
|
262
|
-
* estimate/key-exchange/login/2FA entirely. Answers the token adopted, or `undefined`.
|
|
266
|
+
* estimate/key-exchange/login/2FA entirely. Answers the token adopted, or `undefined`. A session logged in
|
|
267
|
+
* with a country other than the configured one is not usable: its shard is the other country's.
|
|
263
268
|
*
|
|
264
269
|
* Read at construction, and again when a rejection is being recovered from — a store SHARED with another
|
|
265
270
|
* client may already hold the session that client obtained, which is cheaper to adopt than to compete with.
|
|
271
|
+
* An adopted session is a complete one, so it ends any 2FA or challenged re-login this client was left with.
|
|
266
272
|
*
|
|
267
273
|
* Note: the device identity (openudid + phone model + media UA) is NOT restored here — it is resolved once
|
|
268
274
|
* in the constructor, where an explicit config wins over the stored value, and must not be re-derived from a
|
|
@@ -275,6 +281,21 @@ export declare class MegaHttpClient {
|
|
|
275
281
|
} | undefined;
|
|
276
282
|
/** The active region shard (e.g. `"eu-pr"`, `"us-pr"`), set after {@link login} or a region override. */
|
|
277
283
|
get regionShard(): RegionShard;
|
|
284
|
+
/**
|
|
285
|
+
* The shard the RTC signalling signs on: the regional prefix of the estimated domain
|
|
286
|
+
* (`…-ie-…`/`…-ie.` → `ie-pr`), else {@link regionShard}. The eu/us classification cannot name shards
|
|
287
|
+
* like `ie-pr`, whose accounts need the IE sign host and cluster.
|
|
288
|
+
*/
|
|
289
|
+
get rtcShard(): string;
|
|
290
|
+
/**
|
|
291
|
+
* The credentials the RTC signalling needs; `undefined` while logged out. The sign is refused
|
|
292
|
+
* ("gtoken not equal userid") unless its gtoken is the one every authed HTTP call carries.
|
|
293
|
+
*/
|
|
294
|
+
rtcIdentity(): {
|
|
295
|
+
authToken: string;
|
|
296
|
+
userId: string;
|
|
297
|
+
gtoken: string;
|
|
298
|
+
} | undefined;
|
|
278
299
|
/**
|
|
279
300
|
* The name commands attribute themselves to — {@link MegaClientConfig.accountName} when the config
|
|
280
301
|
* pins one (trimmed; blank counts as unset), otherwise the logged-in account's display name, which
|
|
@@ -367,6 +388,15 @@ export declare class MegaHttpClient {
|
|
|
367
388
|
* params instead, which also carry `{param_type, param_value, update_time}` and are not owner-gated.
|
|
368
389
|
*/
|
|
369
390
|
getDeviceParamList<T = unknown>(deviceSn: string): Promise<T>;
|
|
391
|
+
/**
|
|
392
|
+
* Fetch the account's devices as the `devicerelation` service lists them, `{attribute: 7, house_id: ""}`.
|
|
393
|
+
*
|
|
394
|
+
* Each entry is `{device: {device_sn, dps, …}}`, and `dps` is the cloud's last-known value of every
|
|
395
|
+
* data point that device has reported, keyed by DP number. Answered for an account a device is shared
|
|
396
|
+
* with as well as for its owner. Sent with `category: eufy_home`, without which the service answers
|
|
397
|
+
* `10000`.
|
|
398
|
+
*/
|
|
399
|
+
getDeviceRelationList<T = unknown>(): Promise<T>;
|
|
370
400
|
/**
|
|
371
401
|
* Fetch one page of a device's **cleaning history** from the mega `clean` service.
|
|
372
402
|
*
|
|
@@ -563,7 +593,9 @@ export declare class MegaHttpClient {
|
|
|
563
593
|
* Structural rather than a list of paths: a login round trip is itself an authenticated call while a limited
|
|
564
594
|
* token is held, so re-logging in from inside one would recurse — and a path list would have to be
|
|
565
595
|
* maintained alongside every request the login flow makes. A 2FA code already outstanding is a login a human
|
|
566
|
-
* is part-way through, and restarting it silently would discard it.
|
|
596
|
+
* is part-way through, and restarting it silently would discard it. A re-login that already came back needing
|
|
597
|
+
* a captcha or a 2FA code would need the same again, and each attempt sends the account another code, so
|
|
598
|
+
* none is tried until a login completes or a stored session is adopted. No credentials means nothing to try,
|
|
567
599
|
* so the rejection surfaces instead.
|
|
568
600
|
*/
|
|
569
601
|
private canReauthenticate;
|
|
@@ -8,8 +8,9 @@ export interface BrokerCredentials {
|
|
|
8
8
|
}
|
|
9
9
|
export interface ProbeResult {
|
|
10
10
|
ip: string;
|
|
11
|
-
/** True iff SUBSCRIBE to the target topic was granted (qos 0/1/2
|
|
11
|
+
/** True iff SUBSCRIBE to the target topic was granted (qos 0/1/2). */
|
|
12
12
|
granted: boolean;
|
|
13
|
+
/** The SUBACK return code for the topic, the 0x80 deny code included. */
|
|
13
14
|
grantedQos?: number;
|
|
14
15
|
error?: string;
|
|
15
16
|
ms: number;
|
|
@@ -136,8 +136,9 @@ export declare class MqttCommandRouter {
|
|
|
136
136
|
* One exception is known: a single garage unit whose own-cert SUBSCRIBE was denied on every candidate
|
|
137
137
|
* while a phone-extracted cert granted on the same one, with a sibling of the same model on the same
|
|
138
138
|
* account granting fine. That is a per-device authorization gap on the vendor's backend, not a
|
|
139
|
-
* broker-instance problem and not something this SDK works around —
|
|
140
|
-
* (
|
|
139
|
+
* broker-instance problem and not something this SDK works around — the throw below names each
|
|
140
|
+
* candidate's outcome (its SUBACK deny code, a timeout or a connection error) until the backend grants
|
|
141
|
+
* the account's own credentials.
|
|
141
142
|
*
|
|
142
143
|
* One fresh, explicitly non-reconnecting (`reconnectPeriod: 0`) connection per call — it repays the
|
|
143
144
|
* full mTLS handshake every command and tears the socket down right after (see
|
|
@@ -111,6 +111,22 @@ export declare function eciesUnwrap(envelope: Buffer, eccPrivateKeyHex: string,
|
|
|
111
111
|
* Returns the 32-byte key, or undefined if the inputs don't parse.
|
|
112
112
|
*/
|
|
113
113
|
export declare function deriveLevel2KeyFromGatewayInfo(gwPayload: Buffer, eccPrivateKeyHex: string): Buffer | undefined;
|
|
114
|
+
/**
|
|
115
|
+
* Derive the P2P **level-2** AES-128-ECB session key from a *decrypted* `CMD_GATEWAYINFO` (1100)
|
|
116
|
+
* payload and the RSA private key of a cipher whose `get_ciphers` answer carries no ECC key.
|
|
117
|
+
*
|
|
118
|
+
* Layout of the decrypted payload: `cipher_id(2 LE) ‖ 0000 ‖ RSA ciphertext ‖ …`, the ciphertext as
|
|
119
|
+
* long as the key's modulus. It is the 16-byte session key under PKCS#1 v1.5 encryption padding
|
|
120
|
+
* (`00 02 ‖ ≥8 non-zero bytes ‖ 00 ‖ key`). The padding is checked here over the raw RSA result so a wrong
|
|
121
|
+
* key fails closed: under OpenSSL's implicit rejection, `RSA_PKCS1_PADDING` answers random bytes for it
|
|
122
|
+
* instead of throwing, and those can be 16 bytes long.
|
|
123
|
+
*
|
|
124
|
+
* `rsaPrivateKey` is the `get_ciphers` `private_key`: base64 PKCS#8 DER.
|
|
125
|
+
*
|
|
126
|
+
* Returns the 16-byte key, or `undefined` when the key does not parse, the payload is short, or the
|
|
127
|
+
* padding or key length is wrong (fails closed, never throws).
|
|
128
|
+
*/
|
|
129
|
+
export declare function deriveLevel2KeyFromRsaGatewayInfo(gwPayload: Buffer, rsaPrivateKey: string): Buffer | undefined;
|
|
114
130
|
/** Local-lookup payload: two zero bytes. */
|
|
115
131
|
export declare function buildLocalLookupPayload(): Buffer;
|
|
116
132
|
/** Cloud-lookup payload (variant 2): `[p2pDid:20][dskKey][0x00000000]`. */
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* P2P command router — the transport-side owner of the ThroughTek PPCS sessions and every wire
|
|
3
|
-
* operation over them: opening sessions, resolving a serial to its session + routing params,
|
|
4
|
-
* mapping a transport-neutral {@link Command} to a concrete frame (encryption level, wire shape),
|
|
5
|
-
* the fire-and-forget control senders, request/reply queries, and the media provider.
|
|
6
|
-
*
|
|
7
|
-
* Layering: this module knows P2P bytes; it does NOT know capabilities. Frame → semantic-event
|
|
8
|
-
* decoding is a model concern, so raw frames are handed back to the client via {@link P2PRouterDeps.onFrame}
|
|
9
|
-
* (the client gates them on device capabilities and emits typed events). This keeps transport free of
|
|
10
|
-
* any `model/` import — the capability↔transport decorrelation invariant.
|
|
11
|
-
*/
|
|
12
1
|
import type { MegaHttpClient } from "../http/mega-client.js";
|
|
13
2
|
import type { EufyDevice } from "../../core/types.js";
|
|
14
3
|
import type { Command, AutoLockSnapshot, MediaProvider, SharedSourceHints, AbortableCall } from "../../core/contracts.js";
|
|
@@ -119,7 +108,7 @@ export declare class P2PCommandRouter {
|
|
|
119
108
|
* shared — see {@link P2PCommandRouter.openTalkback}.
|
|
120
109
|
*/
|
|
121
110
|
private readonly talkbacks;
|
|
122
|
-
/** cipher_id → ECC private
|
|
111
|
+
/** cipher_id → its ECC and RSA private keys (one eufylife get_ciphers call per cipher), shared across (re)opens. */
|
|
123
112
|
private readonly cipherKeyCache;
|
|
124
113
|
/** The recording download in flight per station; a station serves one at a time. */
|
|
125
114
|
private readonly recordingDownloads;
|
|
@@ -224,7 +213,7 @@ export declare class P2PCommandRouter {
|
|
|
224
213
|
* Build + wire a {@link P2PSession} for a station (NOT yet connected — the caller awaits `connect()`).
|
|
225
214
|
*
|
|
226
215
|
* `resolveCipherKey` auto-negotiates the level-2 session key from `CMD_GATEWAYINFO` by resolving the
|
|
227
|
-
* cipher's
|
|
216
|
+
* cipher's private keys via cloud `get_ciphers`, so signCode 2/8 frames decrypt live; results are
|
|
228
217
|
* cached on the router instance so a lazy re-open (after idle-detach) reuses the lookup. Only a
|
|
229
218
|
* SUCCESSFUL lookup is cached — caching `undefined` after a transient failure would permanently
|
|
230
219
|
* disable level-2 for the session's life.
|
|
@@ -240,11 +229,12 @@ export declare class P2PCommandRouter {
|
|
|
240
229
|
*/
|
|
241
230
|
private makeSession;
|
|
242
231
|
/**
|
|
243
|
-
* The ECC private
|
|
244
|
-
*
|
|
245
|
-
*
|
|
232
|
+
* The ECC and RSA private keys of `cipherId` (`ecc_private_key`, `private_key`), from the router's cache
|
|
233
|
+
* or one `get_ciphers` call. When the cloud answers with another cipher that carries an ECC key and the
|
|
234
|
+
* asked one does not, that one is used and traced on `session`. Only a successful lookup — one that
|
|
235
|
+
* yields either key — is cached.
|
|
246
236
|
*/
|
|
247
|
-
private
|
|
237
|
+
private cipherKeysFor;
|
|
248
238
|
/**
|
|
249
239
|
* Open (or reuse) a station's P2P session and await its completed handshake. An optional abort only
|
|
250
240
|
* stops this wait; session ownership remains with {@link SessionManager} and its normal teardown.
|
|
@@ -258,11 +248,14 @@ export declare class P2PCommandRouter {
|
|
|
258
248
|
*/
|
|
259
249
|
dispatchCommand(sn: string, cmd: Command): Promise<void>;
|
|
260
250
|
/**
|
|
261
|
-
* Restart
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
251
|
+
* Restart the station that owns `sn`'s P2P session. `RESTART_HUB` (1034) is a station-scalar on the
|
|
252
|
+
* broadcast channel 255 whose body is `[u32 value][account_id padded]`, value `0`. ✅ Wire-confirmed
|
|
253
|
+
* byte-exact as a level-2 frame from a capture of the app's own HomeBase Restart (2026-08-03).
|
|
254
|
+
*
|
|
255
|
+
* The seal follows the session, as {@link sendBySessionLevel} defines it: a keyed session takes the
|
|
256
|
+
* level-2 frame, a keyless one — a standalone camera, which never negotiates a key — the same body
|
|
257
|
+
* sealed level-1. Both are replayed {@link DIRECT_CMD_SENDS}× at 200ms, as every other unacknowledged
|
|
258
|
+
* control here is.
|
|
266
259
|
*/
|
|
267
260
|
rebootStation(sn: string): Promise<void>;
|
|
268
261
|
/**
|
|
@@ -308,6 +301,11 @@ export declare class P2PCommandRouter {
|
|
|
308
301
|
* stream costs nothing extra and a talkback on an otherwise idle camera opens the session it needs
|
|
309
302
|
* instead of playing into silence.
|
|
310
303
|
*
|
|
304
|
+
* **On a model in {@link ELD_TALKBACK_MODELS}, the speaker plays the codec the camera sends.** So the first
|
|
305
|
+
* audio frame of the media session this talkback holds decides its codec ({@link speakerCodec}), within
|
|
306
|
+
* {@link TALKBACK_CODEC_WAIT_MS} of the session's first frame, and the claim is re-checked after that wait as
|
|
307
|
+
* after the warm-up. Every other model opens `aac-lc` at once.
|
|
308
|
+
*
|
|
311
309
|
* The level-2 key is waited for softly: only the HomeBase-attached path requires it, and
|
|
312
310
|
* {@link Talkback.start} reports that failure precisely, so a hard wait here would reject an
|
|
313
311
|
* own-session camera that legitimately never negotiates one.
|
|
@@ -453,15 +451,6 @@ export declare class P2PCommandRouter {
|
|
|
453
451
|
* A still with no live sibling re-asserts, so a tile refreshing on a quiet station is
|
|
454
452
|
* unaffected.
|
|
455
453
|
*/
|
|
456
|
-
/**
|
|
457
|
-
* Attach a consumer, unless the caller has already abandoned the call.
|
|
458
|
-
*
|
|
459
|
-
* The acquisition it just waited through can outlast the caller's interest, and a consumer attached for
|
|
460
|
-
* somebody who has gone keeps the pull warm for nobody. Detaching immediately gives the pull back, which
|
|
461
|
-
* lets it linger and fall away if this was the only thing holding it, and leaves it untouched if it was
|
|
462
|
-
* not.
|
|
463
|
-
*/
|
|
464
|
-
private attachUnlessAborted;
|
|
465
454
|
/**
|
|
466
455
|
* Dispose one cached live source and forget it, so the next acquisition builds a fresh one. Its claim
|
|
467
456
|
* on a session goes with it, and a media session opened for this source alone is closed: nothing else
|
|
@@ -521,11 +510,11 @@ export declare class P2PCommandRouter {
|
|
|
521
510
|
*/
|
|
522
511
|
private onLiveStartFailed;
|
|
523
512
|
/**
|
|
524
|
-
* Replace the session under a warming source
|
|
513
|
+
* Replace the session under a warming source it is not serving, and warm again on it.
|
|
525
514
|
*
|
|
526
515
|
* Only a STANDALONE device's session is replaced, for the reason {@link onLiveStartFailed} gives: an attached
|
|
527
516
|
* camera shares its HomeBase session with every other camera on it, and closing that to recover one would
|
|
528
|
-
* drop the rest. Such a source keeps the re-issue it always had.
|
|
517
|
+
* drop the rest. Such a source keeps the re-issue it always had, which the answer (false) tells it.
|
|
529
518
|
*
|
|
530
519
|
* The source is left warming throughout, holding the deadline it started, so this either produces a stream
|
|
531
520
|
* within that window or fails exactly as it would have. A replacement that cannot be opened leaves the
|
|
@@ -559,6 +548,7 @@ export declare class P2PCommandRouter {
|
|
|
559
548
|
*/
|
|
560
549
|
p2pQuery(sn: string, subCmd: number, opts?: {
|
|
561
550
|
timeoutMs?: number;
|
|
551
|
+
payload?: Record<string, unknown>;
|
|
562
552
|
}): Promise<Record<string, unknown>>;
|
|
563
553
|
/**
|
|
564
554
|
* **Generic control-payload request/reply query.** Sends a `CONTROL_PAYLOAD` (1700) `{commandType,
|
|
@@ -687,7 +677,7 @@ export declare class P2PCommandRouter {
|
|
|
687
677
|
* **`set-json-raw` intent** — bare JSON, no envelope: outer P2P cmd = `outerCmd` itself, plaintext
|
|
688
678
|
* exactly `{account_id,...data}` (`session.sendRawLevel2` with no wrapper). Reversed from a live
|
|
689
679
|
* capture of the app's own SET_SNOOZE_TIME (1271) frame — see `param-dictionary.ts`'s `1271` entry
|
|
690
|
-
* (`snoozeTime`); the alarm-delay config (1255, `arming.ts`'s `ARMING_CMD.
|
|
680
|
+
* (`snoozeTime`); the alarm-delay config (1255, `arming.ts`'s `ARMING_CMD.SET_ALL_ACTION`) reuses
|
|
691
681
|
* the same bare-JSON shape.
|
|
692
682
|
*/
|
|
693
683
|
private sendJsonRaw;
|
|
@@ -702,7 +692,9 @@ export declare class P2PCommandRouter {
|
|
|
702
692
|
* HomeBase-attached device takes the GCM signCode-8 form, a standalone one the level-1 form. A
|
|
703
693
|
* standalone camera never negotiates a level-2 key, so pinning this to level 2 makes the envelope
|
|
704
694
|
* unreachable on exactly the devices that serve their own RTSP stream. Verified live: a standalone
|
|
705
|
-
* camera accepts the level-1 form. With no `form` (default) it stays level-2 only
|
|
695
|
+
* camera accepts the level-1 form. With no `form` (default) it stays level-2 only and waits for the
|
|
696
|
+
* key every level-2 sender uses; `level2Sender: "set-payload"` also takes an RSA cipher's AES-128-ECB
|
|
697
|
+
* key (see {@link P2PSession.sendControlLevel2}). A `resolved` session keeps the wait its caller gave it.
|
|
706
698
|
*
|
|
707
699
|
* Both seals REPLAY the frame {@link DIRECT_CMD_SENDS}× at 200ms, as every other fire-and-forget
|
|
708
700
|
* control on this router does: these are unacknowledged datagrams, and a level-1 device is the one
|
|
@@ -17,9 +17,12 @@ export declare class Fmp4Muxer {
|
|
|
17
17
|
private baseDecodeTime;
|
|
18
18
|
private fragTicks;
|
|
19
19
|
private samples;
|
|
20
|
-
|
|
20
|
+
/** Ticks from the first video sample's start to the newest sample's end, at its provisional duration. */
|
|
21
|
+
private videoTicks;
|
|
21
22
|
private readonly audioRequested;
|
|
22
23
|
private audioCodec?;
|
|
24
|
+
/** Decoder config of an AAC-ELD track, taken from its frames; absent for AAC-LC, whose `esds` config is fixed. */
|
|
25
|
+
private audioConfig?;
|
|
23
26
|
private audioDisabled;
|
|
24
27
|
private audioSamples;
|
|
25
28
|
private audioBaseDecodeTime;
|
|
@@ -35,9 +38,16 @@ export declare class Fmp4Muxer {
|
|
|
35
38
|
* Push one access unit. Returns any completed segments: the `init` on the first keyframe, and/or a
|
|
36
39
|
* media fragment when this frame closed the open one. Returns `undefined` if nothing is emitted yet
|
|
37
40
|
* (e.g. delta frames before the first keyframe).
|
|
41
|
+
*
|
|
42
|
+
* A sample lasts until the next frame's `timestampMs`, measured from the first keyframe's, so the video
|
|
43
|
+
* timeline follows the arrival clock; a frame that shares the previous one's timestamp leaves that
|
|
44
|
+
* sample one tick long, and the next frame's duration absorbs the difference.
|
|
38
45
|
*/
|
|
39
46
|
push(frame: LiveVideoFrame, timestampMs?: number): MediaFragment | undefined;
|
|
40
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Add one station-declared AAC access unit to the audio track: an ADTS frame for AAC-LC, a raw access unit
|
|
49
|
+
* described by its frame's config for AAC-ELD. G.711 remains available via `live()`.
|
|
50
|
+
*/
|
|
41
51
|
pushAudio(frame: LiveAudioFrame, timestampMs?: number): MediaFragment | undefined;
|
|
42
52
|
/** Permanently omit incompatible audio while allowing the video recording to continue. */
|
|
43
53
|
private disableAudio;
|
|
@@ -118,11 +118,19 @@ export type LiveTrace =
|
|
|
118
118
|
phase: "level2-wait";
|
|
119
119
|
waitMs: number;
|
|
120
120
|
}
|
|
121
|
-
/** The station's level-2 key was negotiated, under the cipher it selected. */
|
|
121
|
+
/** The station's AES-256-GCM level-2 key was negotiated, under the cipher it selected. */
|
|
122
122
|
| {
|
|
123
123
|
phase: "level2-ready";
|
|
124
124
|
cipherId: number;
|
|
125
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* The station's cipher negotiated only the AES-128-ECB level-2 key of an RSA cipher, under the cipher it
|
|
128
|
+
* selected. That key seals a level-2 set-payload and nothing else, so this is not `level2-ready`.
|
|
129
|
+
*/
|
|
130
|
+
| {
|
|
131
|
+
phase: "level2-set-payload-only";
|
|
132
|
+
cipherId: number;
|
|
133
|
+
}
|
|
126
134
|
/**
|
|
127
135
|
* The station's key is not coming, why, and the cipher where a station named one.
|
|
128
136
|
*
|
|
@@ -145,7 +153,8 @@ export type LiveTrace =
|
|
|
145
153
|
* A station's cipher was answered with material for a DIFFERENT cipher, which was used in its place.
|
|
146
154
|
*
|
|
147
155
|
* The one lookup outcome no other phase accounts for: material for the cipher the station named is followed
|
|
148
|
-
* by `level2-ready` or
|
|
156
|
+
* by `level2-ready`, `level2-set-payload-only` or `level2-unavailable` with `derivation-failed`, an answer
|
|
157
|
+
* holding none by
|
|
149
158
|
* `no-cipher-key`, and a lookup that threw is reported as an error. Substituted material derives to
|
|
150
159
|
* nothing and otherwise reads as a station fault. `cipherId` is the cipher the station asked for,
|
|
151
160
|
* `answeredCipherId` the one whose material was used.
|