@mega-yfue/eufy-sdk 0.2.0-beta.1 → 0.2.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/client/eufy-mega.d.ts +5 -5
  2. package/dist/core/contracts.d.ts +58 -3
  3. package/dist/core/crypto.d.ts +10 -0
  4. package/dist/core/index.d.ts +1 -0
  5. package/dist/core/logger.d.ts +5 -3
  6. package/dist/core/solix-types.d.ts +36 -0
  7. package/dist/core/store.d.ts +20 -9
  8. package/dist/index.js +1142 -71
  9. package/dist/index.js.map +4 -4
  10. package/dist/model/capabilities/arming.d.ts +58 -28
  11. package/dist/model/capabilities/display.d.ts +85 -0
  12. package/dist/model/capabilities/index.d.ts +11 -5
  13. package/dist/model/capabilities/solix.d.ts +75 -0
  14. package/dist/model/capabilities/types.d.ts +16 -4
  15. package/dist/model/capabilities/vacuum-clean.d.ts +74 -25
  16. package/dist/model/index.d.ts +3 -0
  17. package/dist/model/param-dictionary.d.ts +24 -0
  18. package/dist/model/param-namespace.d.ts +1 -1
  19. package/dist/model/solix-catalog.d.ts +20 -0
  20. package/dist/model/solix-device.d.ts +102 -0
  21. package/dist/model/types.d.ts +5 -5
  22. package/dist/transport/ff09.d.ts +7 -0
  23. package/dist/transport/http/index.d.ts +1 -0
  24. package/dist/transport/http/solix-client.d.ts +158 -0
  25. package/dist/transport/http/solix-constants.d.ts +29 -0
  26. package/dist/transport/mqtt/index.d.ts +2 -0
  27. package/dist/transport/mqtt/secure-mqtt.d.ts +14 -1
  28. package/dist/transport/mqtt/solix-mqtt.d.ts +214 -0
  29. package/dist/transport/mqtt/topics.d.ts +20 -0
  30. package/dist/transport/p2p/command-router.d.ts +23 -0
  31. package/dist/transport/p2p/index.d.ts +1 -0
  32. package/dist/transport/p2p/live-trace.d.ts +100 -6
  33. package/dist/transport/p2p/media.d.ts +11 -0
  34. package/dist/transport/p2p/p2p-session.d.ts +4 -0
  35. package/package.json +3 -2
@@ -10,4 +10,5 @@ export * from "./envelope.js";
10
10
  export * from "./write-commands.js";
11
11
  export * from "./lan-ip.js";
12
12
  export { LIVE_TRACE_MESSAGE, type LiveTrace } from "./live-trace.js";
13
+ export { P2P_STATION_WAITS } from "./command-router.js";
13
14
  export * as p2pCodec from "./codec.js";
@@ -63,12 +63,37 @@ export type LiveTrace =
63
63
  phase: "sequence-restart";
64
64
  dataType: number;
65
65
  }
66
+ /**
67
+ * Work on a station is holding for its session to connect, with the milliseconds it will wait.
68
+ *
69
+ * The earliest phase there is: nothing else on a station can be attempted until its session is up, and a
70
+ * caller whose own deadline expires inside this wait has this record and no other. Emitted only where a wait
71
+ * actually happens, so its absence states that the session was already connected.
72
+ */
73
+ | {
74
+ phase: "session-connect-wait";
75
+ waitMs: number;
76
+ }
77
+ /** The session connected, after this long. */
78
+ | {
79
+ phase: "session-connected";
80
+ waitedMs: number;
81
+ }
82
+ /**
83
+ * The session did not connect within its wait, so nothing on this station can be attempted.
84
+ *
85
+ * The one outcome that is otherwise indistinguishable from a station that answered and then refused: both
86
+ * leave a caller with no media and no phase naming a station.
87
+ */
88
+ | {
89
+ phase: "session-unreachable";
90
+ waitedMs: number;
91
+ }
66
92
  /**
67
93
  * A live start is holding for the station's level-2 key, with the milliseconds it will wait.
68
94
  *
69
- * The first of three phases that account for the wait before any media command is sent. A start that looks
70
- * slow is either waiting here, waiting for the station to serve the channel it was asked for, or being
71
- * re-issued — and only these separate them.
95
+ * A start that looks slow is either waiting here, waiting for its session to connect, waiting for the station
96
+ * to serve the channel it was asked for, or being re-issued — and only these phases separate them.
72
97
  */
73
98
  | {
74
99
  phase: "level2-wait";
@@ -79,10 +104,63 @@ export type LiveTrace =
79
104
  phase: "level2-ready";
80
105
  cipherId: number;
81
106
  }
82
- /** The level-2 key did not arrive in its grace, so the start proceeds at level 1 or not at all. */
107
+ /**
108
+ * The station's key is not coming, why, and the cipher where a station named one.
109
+ *
110
+ * Every ending of a level-2 wait carries one of these reasons, so a start refused for want of a key is
111
+ * accounted for however it ended. `grace-elapsed` is a wait that ran out and states how long was waited;
112
+ * the rest are answered without waiting, because the negotiation is one-shot per connection and a
113
+ * concluded one is final. `no-cipher-key` and `derivation-failed` are about this account's cipher
114
+ * material, `not-negotiating` and `session-closed` about the station or its connection — and only a
115
+ * reason reached under a negotiation has a cipher to name.
116
+ *
117
+ * A `grace-elapsed` start proceeds at level 1 where it has such a form, and not at all where it does not.
118
+ */
83
119
  | {
84
- phase: "level2-absent";
85
- waitedMs: number;
120
+ phase: "level2-unavailable";
121
+ reason: "no-cipher-key" | "derivation-failed" | "not-negotiating" | "session-closed" | "grace-elapsed";
122
+ cipherId?: number;
123
+ waitedMs?: number;
124
+ }
125
+ /**
126
+ * A station's cipher was answered with material for a DIFFERENT cipher, which was used in its place.
127
+ *
128
+ * The one lookup outcome no other phase accounts for: material for the cipher the station named is followed
129
+ * by `level2-ready` or by `level2-unavailable` with `derivation-failed`, an answer holding none by
130
+ * `no-cipher-key`, and a lookup that threw is reported as an error. Substituted material derives to
131
+ * nothing and otherwise reads as a station fault. `cipherId` is the cipher the station asked for,
132
+ * `answeredCipherId` the one whose material was used.
133
+ */
134
+ | {
135
+ phase: "cipher-fallback";
136
+ cipherId: number;
137
+ answeredCipherId: number;
138
+ }
139
+ /**
140
+ * The station answered its gateway-info prompt, so a key derivation has begun under the cipher it named.
141
+ *
142
+ * What separates a station that never answered the prompt from one that answered and produced no usable key:
143
+ * without it, `level2-unavailable` with `not-negotiating` covers both, and they are a station or network
144
+ * problem and an account cipher-material problem respectively.
145
+ */
146
+ | {
147
+ phase: "level2-negotiating";
148
+ cipherId: number;
149
+ }
150
+ /**
151
+ * A station was resolved for a call, stating what the caller's device is on it and whose station it is.
152
+ *
153
+ * Emitted before anything is sent, so it is the only account of the intended topology on a call that fails
154
+ * during resolution: an attached camera's media start has no unencrypted form, so whether a device was taken
155
+ * as attached decides what its failure means. `stationAdmin` states whether the signed-in account is the
156
+ * station's administrator, which is what a key the account cannot resolve turns on; `unstated` is a device
157
+ * record that names no administrator, which is not the same as naming another.
158
+ */
159
+ | {
160
+ phase: "station-resolved";
161
+ topology: "attached" | "own";
162
+ channel: number;
163
+ stationAdmin: "self" | "other" | "unstated";
86
164
  }
87
165
  /** A shared source began warming, with the interval it re-issues on and the deadline it fails at. */
88
166
  | {
@@ -110,6 +188,22 @@ export type LiveTrace =
110
188
  | {
111
189
  phase: "path-stale";
112
190
  silentMs: number;
191
+ }
192
+ /**
193
+ * A stream received nothing on its own channel for the stall window, and what was done about it.
194
+ *
195
+ * A station that switches to a sibling leaves the stream it was serving with no frames, no error and no
196
+ * stop, so this silence is the only statement that it happened. `reasserted` re-issued the media start,
197
+ * which is the repair; `declined` left the channel alone because nothing is attached to this pull and
198
+ * taking the station back would take it from a camera someone is watching.
199
+ *
200
+ * Media still arriving means this never fires, so a picture that stopped advancing while this is silent
201
+ * stopped for a reason upstream of the station's attention.
202
+ */
203
+ | {
204
+ phase: "channel-silent";
205
+ silentMs: number;
206
+ outcome: "reasserted" | "declined";
113
207
  };
114
208
  /**
115
209
  * Record one startup observation at debug level.
@@ -34,11 +34,22 @@ export declare function openLiveStream(session: P2PSession, opts?: LiveStreamOpt
34
34
  * The header states the stream's geometry when the capture started, and a stream that reconfigures
35
35
  * mid-burst leaves it describing something the returned bytes contradict; the return value describes an
36
36
  * image, so the image is its source of truth.
37
+ *
38
+ * The consumer is detached the moment the collected run is complete, and the decode that follows holds no
39
+ * station: it works on bytes already in memory. A station serves one camera at a time and the SDK refuses a
40
+ * second channel on one that is busy, so a still that kept its pull attached across its own decode would deny
41
+ * that station to every live request for the length of an FFmpeg run — measured on a real base as a live
42
+ * request refused 370ms after the still it was waiting on had already collected everything it needed.
43
+ *
44
+ * `signal` ends the collection itself, not only the wait for it, and rejects with the signal's own reason
45
+ * because the abandonment is the caller's fact and not a failure of the source. It reaches only the
46
+ * collection: past that the station is already free, so there is nothing left for it to release.
37
47
  */
38
48
  export declare function captureSnapshotFromShared(source: SharedLiveSource, opts?: {
39
49
  timeoutMs?: number;
40
50
  collectMs?: number;
41
51
  skipKeyframes?: number;
52
+ signal?: AbortSignal;
42
53
  logger?: Logger;
43
54
  ffmpegLevel?: FfmpegLevel;
44
55
  ffmpegPath?: string;
@@ -208,6 +208,10 @@ export declare class P2PSession extends EventEmitter {
208
208
  * cameras from that second group streamed normally at level-1 — including one of the same firmware as an
209
209
  * own-session camera that delivered no video at all for a reason of its own. An expired grace therefore
210
210
  * separates nothing on this path, and a start failure on such a session is not evidence about it.
211
+ *
212
+ * Every `false` answer carries a `level2-unavailable` trace naming its reason, wherever the wait ended: a
213
+ * `terminal` outcome is the one already stated where the negotiation concluded, since that is where the
214
+ * cipher and the cause are known, and re-stating it here would double every settled negotiation.
211
215
  */
212
216
  awaitLevel2Key(graceMs: number, graceFrom?: "call" | "session"): Promise<boolean>;
213
217
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mega-yfue/eufy-sdk",
3
- "version": "0.2.0-beta.1",
3
+ "version": "0.2.0-beta.10",
4
4
  "description": "One typed TypeScript client for the Anker eufy v6 cloud — capability-driven devices, realtime events over P2P/MQTT/push, and live media",
5
5
  "license": "Apache-2.0",
6
6
  "author": "mega-yfue",
@@ -64,7 +64,8 @@
64
64
  "guard:docrefs": "bash scripts/ci/guard-doc-refs.sh",
65
65
  "guard:lines": "bash scripts/ci/guard-lines.sh",
66
66
  "check:esm": "node -e \"import('./dist/index.js').then(m=>console.log('ESM OK:',Object.keys(m).length,'exports'))\"",
67
- "verify": "npm run format:check && npm run typecheck && npm run guard:decorrelation && npm run guard:lines && npm run guard:docrefs && npm run guard:consumer-agnostic && npm run guard:capability-ownership && npm run build && npm run check:esm && npm run typecheck:examples && npm test",
67
+ "check:snippets": "node scripts/ci/check-doc-snippets.mjs",
68
+ "verify": "npm run format:check && npm run typecheck && npm run guard:decorrelation && npm run guard:lines && npm run guard:docrefs && npm run guard:consumer-agnostic && npm run guard:capability-ownership && npm run build && npm run check:esm && npm run check:snippets && npm run typecheck:examples && npm test",
68
69
  "release": "bash scripts/release.sh"
69
70
  },
70
71
  "engines": {