@bobfrankston/mailx-imap 0.1.96 → 0.1.98

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 +17 -23
  2. package/package.json +5 -5
package/index.js CHANGED
@@ -1197,6 +1197,7 @@ export class ImapManager extends EventEmitter {
1197
1197
  to: toEmailAddresses(msg.to || []),
1198
1198
  cc: toEmailAddresses(msg.cc || []),
1199
1199
  flags, size: msg.size || 0, hasAttachments, preview, bodyPath,
1200
+ exclusive: true, // IMAP path → one folder per message
1200
1201
  },
1201
1202
  ftsBody,
1202
1203
  });
@@ -1755,6 +1756,7 @@ export class ImapManager extends EventEmitter {
1755
1756
  hasAttachments: parsed.hasAttachments,
1756
1757
  preview: parsed.preview,
1757
1758
  bodyPath,
1759
+ exclusive: true, // IMAP path → one folder per message
1758
1760
  },
1759
1761
  ftsBody: parsed.bodyText || "",
1760
1762
  });
@@ -3430,27 +3432,19 @@ export class ImapManager extends EventEmitter {
3430
3432
  }
3431
3433
  }
3432
3434
  catch (e) {
3433
- const emsg = String(e?.message || e);
3434
- // "IMAP command leaked into response stream" /
3435
- // "corrupt body" means the byte-buffer parser lost
3436
- // sync a partial/flaky read shifted a literal
3437
- // boundary so this FETCH body captured a later
3438
- // command's bytes. The MESSAGE is probably fine; the
3439
- // CONNECTION is poisoned (every subsequent read on
3440
- // it is now garbage). Re-throw so withConnection
3441
- // discards this client and the next chunk reconnects
3442
- // clean instead of marking a good message as poison
3443
- // and limping on a dead socket until the 300s timeout,
3444
- // which left bobma INBOX stuck and "no new mail"
3445
- // (Bob 2026-06-15). Do NOT back the UID off; it
3446
- // retries next tick on a clean connection.
3447
- if (/command leaked|corrupt body|desync/i.test(emsg)) {
3448
- console.error(` [prefetch] ${accountId}/${uid}: connection desync — discarding socket to resync: ${emsg.slice(0, 90)}`);
3449
- throw new Error(`imap-desync: ${emsg.slice(0, 80)}`);
3450
- }
3451
- console.error(` [prefetch] ${accountId}/${uid}: store write failed: ${emsg}`);
3452
- // Genuine poison body (not a desync): back off
3453
- // 5m→30m→2h→12h so it isn't re-fetched on a loop.
3435
+ console.error(` [prefetch] ${accountId}/${uid}: store write failed: ${e?.message || e}`);
3436
+ // "IMAP command leaked into response stream" is NOT
3437
+ // a live connection desync — the DESYNC CAPTURE
3438
+ // (2026-06-16) proved the parser is perfectly aligned
3439
+ // (server announces BODY[] {N}, we read exactly N).
3440
+ // It's a message whose body is PERMANENTLY corrupt on
3441
+ // the server (mailx APPENDed it with a leaked command
3442
+ // prepended in some past session). Discarding the
3443
+ // connection (my 1.2.12 mistake) just re-fetches the
3444
+ // same bad message and thrashes the socket which
3445
+ // disrupted the SHARED slow-lane connection that sync
3446
+ // uses. Correct handling: back this one message off
3447
+ // (5m→30m→2h→12h) and leave the connection alone.
3454
3448
  this.markPrefetchEmpty(accountId, folderId, uid);
3455
3449
  }
3456
3450
  })());
@@ -3496,9 +3490,9 @@ export class ImapManager extends EventEmitter {
3496
3490
  // (markPrefetchEmpty is per-message poison only) —
3497
3491
  // they retry next tick. Genuine per-body errors are
3498
3492
  // handled per-UID above and never reach here.
3499
- const dead = /not connected|ETIMEDOUT|ECONNRESET|ECONNREFUSED|EPIPE|socket|connection (closed|reset|lost)|disconnect|imap-desync/i.test(msg);
3493
+ const dead = /not connected|ETIMEDOUT|ECONNRESET|ECONNREFUSED|EPIPE|socket|connection (closed|reset|lost)|disconnect/i.test(msg);
3500
3494
  if (dead) {
3501
- console.log(` [prefetch] ${accountId}/${folder.path}: connection down/desync — deferring rest to next tick (fresh socket)`);
3495
+ console.log(` [prefetch] ${accountId}/${folder.path}: connection down — deferring rest to next tick (fresh socket)`);
3502
3496
  break;
3503
3497
  }
3504
3498
  if (counters.errors >= ERROR_BUDGET)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx-imap",
3
- "version": "0.1.96",
3
+ "version": "0.1.98",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -11,8 +11,8 @@
11
11
  "dependencies": {
12
12
  "@bobfrankston/mailx-types": "^0.1.19",
13
13
  "@bobfrankston/mailx-settings": "^0.1.28",
14
- "@bobfrankston/mailx-store": "^0.1.50",
15
- "@bobfrankston/iflow-direct": "^0.1.53",
14
+ "@bobfrankston/mailx-store": "^0.1.52",
15
+ "@bobfrankston/iflow-direct": "^0.1.54",
16
16
  "@bobfrankston/tcp-transport": "^0.1.7",
17
17
  "@bobfrankston/smtp-direct": "^0.1.9",
18
18
  "@bobfrankston/mailx-sync": "^0.1.22",
@@ -39,8 +39,8 @@
39
39
  "dependencies": {
40
40
  "@bobfrankston/mailx-types": "^0.1.19",
41
41
  "@bobfrankston/mailx-settings": "^0.1.28",
42
- "@bobfrankston/mailx-store": "^0.1.50",
43
- "@bobfrankston/iflow-direct": "^0.1.53",
42
+ "@bobfrankston/mailx-store": "^0.1.52",
43
+ "@bobfrankston/iflow-direct": "^0.1.54",
44
44
  "@bobfrankston/tcp-transport": "^0.1.7",
45
45
  "@bobfrankston/smtp-direct": "^0.1.9",
46
46
  "@bobfrankston/mailx-sync": "^0.1.22",