@bobfrankston/mailx-imap 0.1.82 → 0.1.83

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 (2) hide show
  1. package/index.js +18 -0
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1272,6 +1272,15 @@ export class ImapManager extends EventEmitter {
1272
1272
  const __qrT0 = Date.now();
1273
1273
  const qr = await client.resyncFolder(folder.path, prevUidValidity, prevModSeq);
1274
1274
  console.log(` [qresync] ${accountId}/${folder.path}: vanished=${qr.vanishedUids.length} changed=${qr.changedMessages.length} newModSeq=${qr.newHighestModSeq} in ${Date.now() - __qrT0}ms`);
1275
+ // No real folder vanishes this many UIDs in one QRESYNC cycle.
1276
+ // iflow-direct can mis-expand a VANISHED *range* (e.g. the
1277
+ // server reports "VANISHED 1:4828883" when our modseq watermark
1278
+ // is stale) into millions of individual UIDs. Applying that
1279
+ // literally = 4.8M synchronous DB calls that wedge the whole
1280
+ // event loop (frozen window) AND delete every local row caught
1281
+ // in the range (INBOX wiped → the viewer's open message
1282
+ // vanishes / shows a stale unrelated eml). Bob 2026-06-04.
1283
+ const VANISHED_ABSURD_CAP = 50000;
1275
1284
  if (qr.uidValidityChanged) {
1276
1285
  // UIDVALIDITY rolled — our local UIDs are stale. Fall through
1277
1286
  // to the full set-diff path; that'll discover the new state
@@ -1279,6 +1288,15 @@ export class ImapManager extends EventEmitter {
1279
1288
  // from wiping anything we shouldn't.
1280
1289
  console.log(` [qresync] ${accountId}/${folder.path}: UIDVALIDITY changed (was ${prevUidValidity}, now ${qr.exists}); falling back to full sync`);
1281
1290
  }
1291
+ else if (qr.vanishedUids.length > VANISHED_ABSURD_CAP) {
1292
+ // Refuse the absurd VANISHED set; do NOT iterate/apply it and
1293
+ // do NOT return — fall through to the bounded set-diff
1294
+ // reconcile (same as the UIDVALIDITY-changed path). The
1295
+ // modseq watermark is left intact, so a healthy later QRESYNC
1296
+ // can still succeed.
1297
+ const localCount = this.db.getMessageCount(accountId, folderId);
1298
+ console.error(` [qresync] ${accountId}/${folder.path}: REFUSING VANISHED of ${qr.vanishedUids.length} UIDs (folder has ${localCount} locally) — almost certainly a mis-parsed range; falling back to set-diff reconcile instead of mass-deleting/wedging.`);
1299
+ }
1282
1300
  else {
1283
1301
  // Apply VANISHED — server says these UIDs are gone. No
1284
1302
  // tombstone, no diff, just delete the local rows.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx-imap",
3
- "version": "0.1.82",
3
+ "version": "0.1.83",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",