@bobfrankston/mailx 1.0.83 → 1.0.85
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/package.json
CHANGED
|
@@ -31,6 +31,8 @@ export declare class ImapManager extends EventEmitter {
|
|
|
31
31
|
private inboxSyncing;
|
|
32
32
|
/** Use native IMAP client instead of imapflow. Set to true to enable. */
|
|
33
33
|
useNativeClient: boolean;
|
|
34
|
+
/** Accounts hitting connection limits — back off until this time */
|
|
35
|
+
private connectionBackoff;
|
|
34
36
|
constructor(db: MailxDB);
|
|
35
37
|
/** Get OAuth access token for an account (for SMTP auth) */
|
|
36
38
|
getOAuthToken(accountId: string): Promise<string | null>;
|
|
@@ -71,6 +71,8 @@ export class ImapManager extends EventEmitter {
|
|
|
71
71
|
inboxSyncing = false;
|
|
72
72
|
/** Use native IMAP client instead of imapflow. Set to true to enable. */
|
|
73
73
|
useNativeClient = false;
|
|
74
|
+
/** Accounts hitting connection limits — back off until this time */
|
|
75
|
+
connectionBackoff = new Map();
|
|
74
76
|
constructor(db) {
|
|
75
77
|
super();
|
|
76
78
|
this.db = db;
|
|
@@ -169,6 +171,11 @@ export class ImapManager extends EventEmitter {
|
|
|
169
171
|
createClient(accountId) {
|
|
170
172
|
if (this.reauthenticating.has(accountId))
|
|
171
173
|
throw new Error(`Account ${accountId} is re-authenticating`);
|
|
174
|
+
// Check connection backoff
|
|
175
|
+
const backoffUntil = this.connectionBackoff.get(accountId);
|
|
176
|
+
if (backoffUntil && Date.now() < backoffUntil) {
|
|
177
|
+
throw new Error(`Account ${accountId} in connection backoff (${Math.round((backoffUntil - Date.now()) / 1000)}s remaining)`);
|
|
178
|
+
}
|
|
172
179
|
const config = this.configs.get(accountId);
|
|
173
180
|
if (!config)
|
|
174
181
|
throw new Error(`No config for account ${accountId}`);
|
|
@@ -457,15 +464,23 @@ export class ImapManager extends EventEmitter {
|
|
|
457
464
|
}
|
|
458
465
|
}
|
|
459
466
|
catch (e) {
|
|
460
|
-
|
|
461
|
-
|
|
467
|
+
const errMsg = imapError(e);
|
|
468
|
+
this.emit("syncError", accountId, errMsg);
|
|
469
|
+
console.error(`Sync error for ${accountId}: ${errMsg}`);
|
|
470
|
+
// Connection limit — back off for 60 seconds
|
|
471
|
+
if (errMsg.includes("max_userip_connections") || errMsg.includes("Too many simultaneous")) {
|
|
472
|
+
this.connectionBackoff.set(accountId, Date.now() + 60000);
|
|
473
|
+
console.log(` [backoff] ${accountId}: connection limit hit, backing off 60s`);
|
|
474
|
+
}
|
|
462
475
|
// Emit user-facing error once per account per session
|
|
463
476
|
if (!this.accountErrorShown.has(accountId)) {
|
|
464
477
|
this.accountErrorShown.add(accountId);
|
|
465
478
|
const config = this.configs.get(accountId);
|
|
466
479
|
const isOAuth = !!config?.tokenProvider;
|
|
467
|
-
const hint =
|
|
468
|
-
|
|
480
|
+
const hint = errMsg.includes("max_userip_connections") || errMsg.includes("Too many")
|
|
481
|
+
? "Too many connections — backing off"
|
|
482
|
+
: isOAuth ? "Authentication may have expired" : "Check server connectivity";
|
|
483
|
+
this.emit("accountError", accountId, errMsg, hint);
|
|
469
484
|
}
|
|
470
485
|
}
|
|
471
486
|
finally {
|