@mega-yfue/eufy-sdk 0.6.0-beta.31 → 0.6.0-beta.33

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.
@@ -263,6 +263,8 @@ export type CameraActions = Surface<typeof CAMERA_MEMBERS> & {
263
263
  };
264
264
  /** T8442 has a binary night-vision wire, unlike cameras with the three-mode 1277 control. */
265
265
  declare function isT8442(ctx: AvailabilityContext): boolean;
266
+ /** A C30/C31 has reported no 1716 and no doorbell LED write was tried on it, so it keeps 1045. */
267
+ declare const doorbellLed: (ctx: AvailabilityContext) => boolean;
266
268
  /**
267
269
  * Every `camera` feature, declared once. The property schema, the typed getters, the derived setters,
268
270
  * the intent routes, the media methods and the descriptions all come out of this table.
@@ -566,7 +568,7 @@ export declare const CAMERA_MEMBERS: {
566
568
  readonly readAvailable: (ctx: AvailabilityContext) => boolean;
567
569
  readonly readAliases: readonly [{
568
570
  readonly paramType: 1716;
569
- readonly available: (ctx: AvailabilityContext) => boolean;
571
+ readonly available: typeof doorbellLed;
570
572
  }];
571
573
  readonly requiresRead: true;
572
574
  readonly description: "Camera status LED. Video doorbells report the same state under their button-ring LED parameter.";
@@ -1,5 +1,7 @@
1
1
  import { type Surface } from "./members.js";
2
- import type { CapabilityModule } from "./types.js";
2
+ import type { AvailabilityContext, CapabilityModule } from "./types.js";
3
+ /** No doorbell write has been tried on a C30/C31, so only their ring event binds. */
4
+ declare const writable: (ctx: AvailabilityContext) => boolean;
3
5
  /**
4
6
  * The P2P **feature-command ids** this doorbell capability drives. Capability-owned wire vocabulary
5
7
  * (transport forwards `cmd.param` opaquely; full id→name catalog in the generated
@@ -191,6 +193,7 @@ export declare const DOORBELL_MEMBERS: {
191
193
  */
192
194
  readonly chimeSwitch: {
193
195
  readonly param: 1702;
196
+ readonly available: typeof writable;
194
197
  readonly type: "bool";
195
198
  readonly kind: "boolean";
196
199
  readonly provenance: "verified";
@@ -203,6 +206,7 @@ export declare const DOORBELL_MEMBERS: {
203
206
  */
204
207
  readonly mechanicalChimeSwitch: {
205
208
  readonly param: 1703;
209
+ readonly available: typeof writable;
206
210
  readonly type: "bool";
207
211
  readonly kind: "boolean";
208
212
  readonly provenance: "verified";
@@ -212,6 +216,7 @@ export declare const DOORBELL_MEMBERS: {
212
216
  /** Same reasoning and the same capture session as {@link DOORBELL_MEMBERS.mechanicalChimeSwitch}. */
213
217
  readonly wdrSwitch: {
214
218
  readonly param: 1704;
219
+ readonly available: typeof writable;
215
220
  readonly type: "bool";
216
221
  readonly kind: "boolean";
217
222
  readonly provenance: "verified";
@@ -242,6 +247,7 @@ export declare const DOORBELL_MEMBERS: {
242
247
  */
243
248
  readonly dingdongVolume: {
244
249
  readonly param: 1717;
250
+ readonly available: typeof writable;
245
251
  readonly type: "number";
246
252
  readonly unit: "%";
247
253
  readonly kind: "percent";
@@ -259,6 +265,7 @@ export declare const DOORBELL_MEMBERS: {
259
265
  */
260
266
  readonly dingdongRingtone: {
261
267
  readonly param: 1718;
268
+ readonly available: typeof writable;
262
269
  readonly type: "number";
263
270
  readonly kind: "enum";
264
271
  readonly enumValues: Record<number, string>;
@@ -313,7 +320,9 @@ export declare const DOORBELL_MEMBERS: {
313
320
  * reads {@link DOORBELL_MEMBERS.videoQuality} and {@link DOORBELL_MEMBERS.highCompressionEncoding}
314
321
  * and passes what it wants, instead of the SDK guessing from a stale copy.
315
322
  */
316
- readonly setVideoQuality: import("./members.js").MethodMember<(quality: DoorbellVideoQualityValue, highCompression: boolean) => Promise<void>>;
323
+ readonly setVideoQuality: import("./members.js").MethodMember<(quality: DoorbellVideoQualityValue, highCompression: boolean) => Promise<void>> & {
324
+ available: (ctx: import("./types.js").CommandContext) => boolean;
325
+ };
317
326
  /**
318
327
  * A config blob the device reports WHOLE, so it is typed `string` and handed back unparsed — three
319
328
  * settings live inside it (motion notifications, ring notifications, notification style) and the SDK
@@ -339,7 +348,9 @@ export declare const DOORBELL_MEMBERS: {
339
348
  */
340
349
  readonly playQuickResponse: import("./members.js").MethodMember<(voiceId: number, opts?: {
341
350
  engage?: boolean;
342
- }) => Promise<void>>;
351
+ }) => Promise<void>> & {
352
+ available: (ctx: import("./types.js").CommandContext) => boolean;
353
+ };
343
354
  /**
344
355
  * Fetch the doorbell's quick-response list — a P2P request/reply query that returns data, so it
345
356
  * exists only on a device bound to a media provider that offers one.
@@ -352,3 +363,4 @@ export declare const DOORBELL_MEMBERS: {
352
363
  }) => Promise<QuickResponse[]>) | undefined>;
353
364
  };
354
365
  export declare const DOORBELL: CapabilityModule;
366
+ export {};
@@ -212,6 +212,8 @@ export declare class MegaHttpClient {
212
212
  private region;
213
213
  /** The host `estimate_domain` answered, persisted with the session. */
214
214
  private estimatedDomain;
215
+ /** The in-flight (then settled, so cached) RTC-sign shard request from {@link portalShard}. */
216
+ private portalShardInFlight?;
215
217
  private bootstrapDomain?;
216
218
  private sessionKey?;
217
219
  /** Per-host ECDH session keys for non-mega gateways (e.g. eufylife) keyed by host. */
@@ -283,11 +285,19 @@ export declare class MegaHttpClient {
283
285
  /** The active region shard (e.g. `"eu-pr"`, `"us-pr"`), set after {@link login} or a region override. */
284
286
  get regionShard(): RegionShard;
285
287
  /**
286
- * The shard the RTC signalling signs on: the regional prefix of the estimated domain
287
- * (`…-ie-…`/`…-ie.` → `ie-pr`), else {@link regionShard}. The eu/us classification cannot name shards
288
- * like `ie-pr`, whose accounts need the IE sign host and cluster.
288
+ * The shard the estimated domain names (`…-ie-…`/`…-ie.` → `ie-pr`), else {@link regionShard}. The
289
+ * eu/us classification cannot name shards like `ie-pr`.
289
290
  */
290
291
  get rtcShard(): string;
292
+ /**
293
+ * The shard the RTC signalling signs on, from `estimate_domain` asked with the portal's WEB identity
294
+ * (`Model-Type: WEB`, `App-Name: eufy_mega`) — the identity the sign itself is sent with, which can name
295
+ * a different shard than the PHONE identity does for one account. The in-flight request is shared by
296
+ * concurrent first callers, and once it settles to a shard the resolved promise is the cache; a call
297
+ * that fails or names no shard answers {@link rtcShard}, clears the field and is asked again next time.
298
+ */
299
+ portalShard(): Promise<string>;
300
+ private fetchPortalShard;
291
301
  /**
292
302
  * The credentials the RTC signalling needs; `undefined` while logged out. The sign is refused
293
303
  * ("gtoken not equal userid") unless its gtoken is the one every authed HTTP call carries.
@@ -334,6 +344,8 @@ export declare class MegaHttpClient {
334
344
  * raw text. Never throws on HTTP status (the callers classify the envelope themselves). 20s timeout.
335
345
  */
336
346
  private httpPost;
347
+ /** POST `estimate_domain` with the given identity headers. */
348
+ private estimateDomainRequest;
337
349
  /** Step 1: discover the account's region shard (and the bootstrap host). */
338
350
  estimateDomain(): Promise<void>;
339
351
  /**
@@ -61,8 +61,8 @@ export interface RtcLiveRoute extends RtcRoute {
61
61
  export interface RtcCommandRouterDeps {
62
62
  /** The logged-in session's credentials; `undefined` while logged out. */
63
63
  identity: () => RtcIdentity | undefined;
64
- /** The mega shard the account signs on (`"ie-pr"`, `"eu-pr"`, `"us-pr"`); picks the smart host. */
65
- shard: () => string;
64
+ /** The signing shard for the route (`"ie-pr"`, `"eu-pr"`, `"us-pr"`); picks the smart host. */
65
+ shard: (route: RtcRoute) => string | Promise<string>;
66
66
  /** ISO country sent on the sign request (default `US`). */
67
67
  country?: string;
68
68
  logger?: Logger;
@@ -78,6 +78,8 @@ export declare class RtcCommandRouter {
78
78
  private readonly warm;
79
79
  private readonly callSources;
80
80
  private lastTransaction;
81
+ /** The latest shard each `call` source resolved, read by its `makeStream` (see {@link callMediaProviderFor}). */
82
+ private readonly callShards;
81
83
  constructor(deps: RtcCommandRouterDeps);
82
84
  dispatchCommand(route: RtcRoute, cmd: Command): Promise<void>;
83
85
  /**
@@ -132,7 +134,13 @@ export declare class RtcCommandRouter {
132
134
  trackMediaProviderFor(route: RtcRoute): MediaProvider;
133
135
  /** NVR media uses a dedicated call per camera, independent of station commands. */
134
136
  nvrMediaProviderFor(route: RtcLiveRoute, views: readonly number[]): MediaProvider;
135
- /** Share a dedicated-call source and its consumer operations under one route key. */
137
+ /**
138
+ * Share a dedicated-call source and its consumer operations under one route key.
139
+ *
140
+ * `SharedLiveSource` calls `makeStream` synchronously, so the shard cannot be awaited inside it. Each
141
+ * async entry point resolves the shard and records it in {@link callShards} before touching the source;
142
+ * `makeStream` reads the latest recorded value.
143
+ */
136
144
  private callMediaProviderFor;
137
145
  /**
138
146
  * Tear down every station session (logout / shutdown). Each live source is disposed before its session
@@ -174,6 +182,14 @@ export declare class RtcCommandRouter {
174
182
  */
175
183
  private sendAwaitAck;
176
184
  private newSession;
185
+ /** A connected session for `sn` to reuse, or undefined (dropping a dead one). */
186
+ private reusable;
187
+ /**
188
+ * Get or open the station's session. A connected session is reused before the shard is awaited, so a
189
+ * command on an already-connected station never waits on the unauthenticated `estimate_domain` round
190
+ * trip — only the create path awaits it. After the await the map is re-checked, with no `await` between
191
+ * the lookup and `this.sessions.set`, so concurrent creators still share one session.
192
+ */
177
193
  private stationSession;
178
194
  /**
179
195
  * One bounded bring-up: the session is up when its command channel opens, and it fails, with the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mega-yfue/eufy-sdk",
3
- "version": "0.6.0-beta.31",
3
+ "version": "0.6.0-beta.33",
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",