@mega-yfue/eufy-sdk 0.2.0-beta.20 → 0.2.0-beta.21

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.
@@ -71,9 +71,34 @@ export declare class MegaApiError extends Error {
71
71
  * device-list params carry the same `{param_type, param_value, update_time}` and are not owner-gated.
72
72
  */
73
73
  export declare const OWNER_ONLY_CODE = 20004;
74
- /** Thrown when a persisted/expired session is rejected (401). Re-login to recover. */
74
+ /**
75
+ * Thrown when a persisted/expired session is rejected (401). Re-login to recover.
76
+ *
77
+ * It carries the rate the client has already worked out for replacing a rejected token, because the
78
+ * rejection is where that rate stops being the client's alone: a login driven from here spends the same
79
+ * session the client's own recovery would have, and repeated logins are what makes an account start
80
+ * demanding captchas. {@link retryAfterMs} is how long the next replacement is barred for, and
81
+ * {@link contended} whether this rejection landed inside that bar — the shape repeated displacement has.
82
+ */
75
83
  export declare class SessionExpiredError extends Error {
76
- constructor(message: string);
84
+ /**
85
+ * How long the next session replacement is barred for, in milliseconds; `0` when nothing bars one now.
86
+ *
87
+ * The remainder of the client's own hold-off, which doubles per consecutive replacement and is capped —
88
+ * and which every replacement extends, whether the client spent it or a login made on this error did.
89
+ */
90
+ readonly retryAfterMs: number;
91
+ /**
92
+ * Whether this rejection landed inside that bar — a token replaced recently and rejected again since.
93
+ *
94
+ * It says the session is being DISPLACED rather than expiring: something else is signing in on this
95
+ * account, and replacing the token again only trades one login for another.
96
+ */
97
+ readonly contended: boolean;
98
+ constructor(message: string, opts?: {
99
+ retryAfterMs?: number;
100
+ contended?: boolean;
101
+ });
77
102
  }
78
103
  /**
79
104
  * eufy cloud gateway error codes — the numeric `code` carried in a response envelope alongside the
@@ -223,9 +248,11 @@ export declare class MegaHttpClient {
223
248
  private loggingIn;
224
249
  /** The one in-flight re-login every call rejected on the same dead token waits on. */
225
250
  private reauthAttempt?;
226
- /** Replacements since the held session last proved stable, and when the last one ran — see {@link recoveryDue}. */
251
+ /** Replacements since the held session last proved stable, and when the last one ran — see {@link holdOffRemainingMs}. */
227
252
  private recoveries;
228
253
  private lastRecoveryAt;
254
+ /** A token of ours has been rejected and not yet replaced — see {@link noteTokenReplacement}. */
255
+ private rejectedTokenPending;
229
256
  constructor(cfg: MegaClientConfig);
230
257
  /**
231
258
  * Install the session the store holds, if it holds a usable one: the token + its bound ECDH key, skipping
@@ -500,6 +527,26 @@ export declare class MegaHttpClient {
500
527
  * and a caller is told the honest reason instead of being served a fight.
501
528
  */
502
529
  private recoveryDue;
530
+ /**
531
+ * How much longer a token replacement must wait, in milliseconds; `0` when one may run now.
532
+ *
533
+ * The wait doubles per consecutive replacement and is capped, and it is what {@link recoveryDue} gates
534
+ * this client's own recovery on — and what {@link SessionExpiredError.retryAfterMs} hands a host that
535
+ * drives its own. One function so the two cannot disagree about the rate, which they would have to for
536
+ * a host to be told it may retry while this client is still holding off.
537
+ */
538
+ private holdOffRemainingMs;
539
+ /**
540
+ * Count one token replacement against the hold-off, and clear the rejection it answered.
541
+ *
542
+ * Every replacement passes through here, wherever it was spent from: {@link recoverRejectedSession}, and
543
+ * a {@link login} that follows a rejection this client surfaced. A hold-off that counted only its own
544
+ * would be no bound at all — the wait would sit at its first value however many sessions had been spent,
545
+ * and {@link SessionExpiredError.retryAfterMs} would report a minute while logins ran every few seconds.
546
+ * Which of the two counted a given replacement is the flag: the recovery path clears it before logging
547
+ * in, so the login cannot count the same one again.
548
+ */
549
+ private noteTokenReplacement;
503
550
  /**
504
551
  * Note that the held session is working. A replacement that keeps serving calls for long enough is not
505
552
  * contention, so the hold-off is forgotten and the next genuine expiry recovers immediately.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mega-yfue/eufy-sdk",
3
- "version": "0.2.0-beta.20",
3
+ "version": "0.2.0-beta.21",
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",