@mega-yfue/eufy-sdk 0.6.0-beta.14 → 0.6.0-beta.15

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.
@@ -20,8 +20,8 @@ import { type P2PSession } from "../transport/p2p/p2p-session.js";
20
20
  import { type CleanRecordPage } from "../model/clean-records.js";
21
21
  import { type AvailabilityObservation, type EufyDevice } from "../core/types.js";
22
22
  import { Device, type DeviceInspection } from "../model/index.js";
23
- import type { EufyMegaOptions, EufyMegaEvent, EufyMegaEventMap, DeviceState, RealtimeReadiness, StationFace, StationFacesOptions, WaitForRealtimeOptions } from "./types.js";
24
- export type { EufyMegaOptions, EufyMegaEvent, EufyMegaEventMap, AnyDeviceEvent, DeviceState, RealtimePlaneReadiness, RealtimeReadiness, StationFace, StationFacesOptions, WaitForRealtimeOptions, } from "./types.js";
23
+ import type { EufyMegaOptions, EufyMegaEvent, EufyMegaEventMap, DeviceState, RealtimeReadiness, StationFace, StationReadOptions, WaitForRealtimeOptions } from "./types.js";
24
+ export type { EufyMegaOptions, EufyMegaEvent, EufyMegaEventMap, AnyDeviceEvent, DeviceState, RealtimePlaneReadiness, RealtimeReadiness, StationFace, StationReadOptions, WaitForRealtimeOptions, } from "./types.js";
25
25
  export interface EufyMega {
26
26
  on<E extends EufyMegaEvent>(event: E, listener: (...args: EufyMegaEventMap[E]) => void): this;
27
27
  once<E extends EufyMegaEvent>(event: E, listener: (...args: EufyMegaEventMap[E]) => void): this;
@@ -385,7 +385,9 @@ export declare class EufyMega extends EventEmitter {
385
385
  /**
386
386
  * On a successful login, kick off auto-realtime (unless `autoRealtime:false`). Fire-and-forget so
387
387
  * `login()` returns as soon as the session is ready — realtime channels come up in the background and
388
- * surface failures via `error`. Idempotent through the retained generation promise.
388
+ * surface failures via `error`. Idempotent through the retained generation promise. A login for a
389
+ * different account drops every stored image; one for the same account drops only the lifecycle
390
+ * failures recorded against the session it replaces.
389
391
  */
390
392
  private afterLogin;
391
393
  /**
@@ -627,6 +629,9 @@ export declare class EufyMega extends EventEmitter {
627
629
  * device absent from the previous pass is skipped — first sight is discovery, not a transition;
628
630
  * {@link deviceState} answers an initial reading.
629
631
  *
632
+ * A device with changed params is re-resolved by {@link widenCapabilities} once per pass, however many
633
+ * of its params moved, since each re-resolution is a cloud param-list read.
634
+ *
630
635
  * Then re-reads every Tuya clean-line robot from the Tuya cloud ({@link readTuyaDevices}): its state
631
636
  * is not in the cloud record this pass diffs and no live channel carries it, so the poll is where it
632
637
  * stays fresh. That read runs after the `try`, not inside it, so a cloud error on the list diff does
@@ -838,19 +843,45 @@ export declare class EufyMega extends EventEmitter {
838
843
  */
839
844
  getP2pSessions(): Map<string, P2PSession>;
840
845
  /**
841
- * The people enrolled on a station, read from its own `person_basic_info` table over P2P.
846
+ * The people enrolled on a station, read from its own `person_basic_info` table through
847
+ * {@link readStationTable}.
842
848
  *
843
849
  * The cloud roster (`api.getFaces()`) answers empty for an account that keeps its faces on the
844
850
  * station, because they were never uploaded — the station holds them.
845
851
  *
846
- * Resolves with the rows the station returned. Rejects on a station that cannot be reached, on a
847
- * record stating no `admin_user_id`, and on the reply not arriving whole in time. Assembling that
848
- * reply is `P2PSession.readDatabase`'s; this resolves which station and which account id.
852
+ * Resolves with the rows the station returned that are objects. Rejects as {@link readStationTable}
853
+ * does.
849
854
  *
850
855
  * `stranger<n>` names are the station's own placeholders for a face nobody has named, and are
851
856
  * returned as they arrive; a caller that wants only named people filters them.
852
857
  */
853
- getStationFaces(stationSn: string, opts?: StationFacesOptions): Promise<StationFace[]>;
858
+ getStationFaces(stationSn: string, opts?: StationReadOptions): Promise<StationFace[]>;
859
+ /**
860
+ * The rows of one of a station's own tables (`history_record_info`, `person_basic_info`, …), read over
861
+ * the transport the station speaks: the control channel of a HomeBase S1 Pro (T9000), P2P for any
862
+ * other station. The query is the table's whole content; the rows are the station's, shaped by it.
863
+ *
864
+ * Resolves with the rows the station returned. Rejects on a serial not in the device list, on a record
865
+ * stating no `admin_user_id`, on a station that cannot be reached, on a query the station refuses, and
866
+ * on the reply not arriving in time. Assembling the reply is the transport's; this resolves which
867
+ * station, which transport and which account id.
868
+ */
869
+ readStationTable(stationSn: string, table: string, opts?: StationReadOptions): Promise<unknown[]>;
870
+ /**
871
+ * One image stored on a HomeBase S1 Pro (T9000), by the on-station path a table row names
872
+ * (`thumb_path`, …), read over the station's control channel.
873
+ *
874
+ * Resolves with the image bytes as the station holds them. Rejects on a serial not in the device list,
875
+ * on a record stating no `admin_user_id`, on a station other than a T9000, on a station that cannot be
876
+ * reached, and on the reply not arriving in time. Fetching the image is the transport's; this resolves
877
+ * which station and which account id.
878
+ */
879
+ readStationImage(stationSn: string, filePath: string, opts?: StationReadOptions): Promise<Buffer>;
880
+ /**
881
+ * The station a database read goes to, its `admin_user_id` and, for a T9000, its RTC route. Throws,
882
+ * prefixed with `op`, on a serial the device list does not carry and on a record stating no admin id.
883
+ */
884
+ private stationReadTarget;
854
885
  /** The station's own `admin_user_id`, which its database refuses the query without. */
855
886
  private adminUserIdOf;
856
887
  /**
@@ -962,6 +993,9 @@ export declare class EufyMega extends EventEmitter {
962
993
  * Returns the connected client rather than installing it. Registration can outlive a `disconnect()`,
963
994
  * and {@link ensureRealtime} owns the decision of whether a finished bring-up is still the current
964
995
  * one — so this never overwrites a channel a later login already brought up.
996
+ *
997
+ * Persisting the seen ids after each push reports a failed `save` through `error` rather than throwing:
998
+ * the push handler runs inside the MCS socket's `data` callback, where a throw is an uncaught exception.
965
999
  */
966
1000
  private startPush;
967
1001
  /**
@@ -240,9 +240,9 @@ export interface StationFace {
240
240
  group_id?: number | string;
241
241
  [column: string]: unknown;
242
242
  }
243
- /** How long to wait for a station's database reply, and how to give up early. */
244
- export interface StationFacesOptions {
245
- /** Default 15s. A full table is a handful of frames; a station that will not answer says nothing. */
243
+ /** How long to wait for a station's reply to a read, and how to give up early. */
244
+ export interface StationReadOptions {
245
+ /** Default 15s. A station that will not answer says nothing. */
246
246
  timeoutMs?: number;
247
247
  signal?: AbortSignal;
248
248
  }
@@ -852,7 +852,9 @@ export interface MediaProvider {
852
852
  * {@link ReceivedVideoFrame} envelopes whose original source-arrival time survives retained replay.
853
853
  * Raw mode ignores arrivalTime. Audio is available separately through {@link live} or muxed through
854
854
  * {@link recordFragments}; it is never interleaved into raw video. The caller owns the Readable's
855
- * lifetime, and destroying it releases the shared pull.
855
+ * lifetime, and destroying it releases the shared pull. On a battery-budgeted source the Readable
856
+ * emits a `budget` event with a {@link StreamBudgetNotice}; unless `extend()` is called within its
857
+ * grace, the Readable ends.
856
858
  */
857
859
  openReadable?(opts?: {
858
860
  objectMode?: boolean;
@@ -48,7 +48,18 @@ export declare class MemorySessionStore<T = PersistedSession> implements Session
48
48
  save(s: T): void;
49
49
  clear(): void;
50
50
  }
51
- /** JSON-file store, e.g. new FileSessionStore("./.eufy-session.json"). */
51
+ /**
52
+ * JSON-file store, e.g. new FileSessionStore("./.eufy-session.json").
53
+ *
54
+ * `save` resolves a symlinked path to its real file (the file a dangling symlink names, created with its
55
+ * directory), writes a fresh owner-only (`0o600`) temp file under a random name beside that file and
56
+ * renames it over it, so where the directory allows it the file on disk is always a complete record — the
57
+ * old one until the rename, the new one after — and the symlink itself stays in place. When the directory
58
+ * refuses the temp file or the rename (`EACCES`, `EPERM`, `EBUSY`, `EXDEV`, `EROFS`: a read-only directory
59
+ * around a writable file, a single-file bind mount), `save` rewrites the file in place instead, which is
60
+ * not atomic and keeps an existing file's mode. The atomic path always leaves `0o600`, whatever mode an
61
+ * existing file had. Any other failure removes the temp file and throws.
62
+ */
52
63
  export declare class FileSessionStore<T = PersistedSession> implements SessionStore<T> {
53
64
  private readonly path;
54
65
  constructor(path: string);