@bobfrankston/rmfmail 1.2.48 → 1.2.50

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.
@@ -24,15 +24,13 @@ const SMTP_PORT_STARTTLS = 587;
24
24
  const SMTP_PORT_IMPLICIT_TLS = 465;
25
25
 
26
26
  type OpsTask = () => Promise<void>;
27
- interface OpsQueue {
28
- fast: OpsTask[];
29
- slow: OpsTask[];
30
- /** Whether the fast lane is currently draining a task. Independent of
31
- * `runningSlow` both lanes can drain concurrently because each uses
32
- * its own connection (fastClient vs. opsClient). C123: the second
33
- * connection is lazy-allocated on the first fast-lane task. */
34
- runningFast: boolean;
35
- runningSlow: boolean;
27
+ /** One FIFO task queue per (account, lane). All lanes drain concurrently —
28
+ * each lane runs on its own persistent connection — so a slow op on one lane
29
+ * never blocks another. Within a lane, strictly sequential (one IMAP command
30
+ * in flight, no SELECT races). */
31
+ interface LaneQueue {
32
+ tasks: OpsTask[];
33
+ running: boolean;
36
34
  }
37
35
  interface HostSemaphore {
38
36
  permits: number;
@@ -591,39 +589,45 @@ export class ImapManager extends EventEmitter {
591
589
  // No semaphore, no pool, no per-operation connect/disconnect.
592
590
  // IDLE uses a separate connection (see startWatching).
593
591
 
594
- /** Persistent slow-lane operational connection per account. Used by sync,
595
- * prefetch, outbox-append, large backfills, and any other "this might
596
- * take a while" operation. */
597
- private opsClients = new Map<string, any>();
598
- /** Lazy-allocated fast-lane client per account (C123). Lives alongside
599
- * `opsClients` so click-time body fetches and flag toggles don't have
600
- * to wait behind a multi-minute prefetch / backfill on the slow client.
601
- * Created on the first fast-lane `withConnection` call; reused while
602
- * alive; recreated on stale-detect or error-discard like opsClients.
603
- * Costs +1 IMAP socket per active account, well under any reasonable
604
- * per-user-IP cap (Dovecot's default is 20). */
605
- private fastClients = new Map<string, any>();
606
- /** Two-lane operation queue per account interactive ops (body fetch on
607
- * click, flag toggle) drain before background ops (sync, prefetch). FIFO
608
- * within each lane. The single ops connection means there's never a race
609
- * on which folder is SELECTed; commands run strictly sequentially. */
610
- private opsQueues = new Map<string, OpsQueue>();
592
+ /** Per-workload connection lanes. Each (lane, account) gets its OWN
593
+ * persistent IMAP connection so a slow op on one lane can't block another:
594
+ * a 90s `SELECT Sent` on "outbox" or a giant `UID FETCH` on "prefetch" no
595
+ * longer wedges INBOX sync/backfill on "sync". This is the root fix for
596
+ * the "whole sync worker goes silent" wedge (Bob 2026-06-20): before, all
597
+ * background work shared ONE slow connection and serialized behind the
598
+ * slowest command (a 90s SELECT Sent / a giant prefetch FETCH stalled
599
+ * INBOX backfill behind it). Lanes in use:
600
+ * fast — interactive: body fetch on click, flag toggle, move
601
+ * slow — folder sync + set-diff backfill (the `{slow:true}` default)
602
+ * prefetch background body download (heaviest, longest)
603
+ * outbox — send + sent-sweep + Outbox/Sent SELECT/APPEND
604
+ * Per account that's ≤4 persistent sockets + 1 IDLE, under Dovecot's 20.
605
+ * laneName (accountId persistent client). */
606
+ private laneClients = new Map<string, Map<string, any>>();
607
+ /** Per-account, per-lane FIFO task queues. accountId (laneName → queue).
608
+ * All lanes for an account drain concurrently (each on its own socket);
609
+ * within a lane, strictly sequential — no SELECT race. */
610
+ private laneQueues = new Map<string, Map<string, LaneQueue>>();
611
611
  /** Per-host semaphore — caps simultaneous IMAP socket opens to one server.
612
- * Defensive guardrail: with the single-ops-per-account model an individual
613
- * user's mailx never hits more than (#accounts × 2) sockets per host, well
614
- * under any reasonable server cap. Exists for the multi-account-on-one-host
615
- * case (e.g. bobma + bobma2 both on imap.iecc.com). */
612
+ * Defensive guardrail for the multi-account-on-one-host case (e.g. bobma +
613
+ * bobma2 both on imap.iecc.com). NOTE: the permit is held for the
614
+ * connection's LIFETIME (released on logout/destroy), not just the open —
615
+ * so this also bounds the number of live persistent connections per host.
616
+ * Each account now keeps up to 4 persistent lanes (fast/slow/prefetch/
617
+ * outbox) + 1 IDLE (IDLE bypasses the semaphore). 8 permits covers two
618
+ * accounts' lanes with headroom, still far under Dovecot's ~20/user+IP. */
616
619
  private hostSemaphores = new Map<string, HostSemaphore>();
617
- private static readonly HOST_PERMITS = 4;
618
-
619
- /** Get (or create) a persistent connection for an account on the named
620
- * lane. Two lanes today: `slow` (the original `opsClients` map — sync,
621
- * prefetch, backfill, outbox) and `fast` (the C123 `fastClients` map —
622
- * click-time body fetch, flag toggles, anything user-driven). Same
623
- * stale-detect + reconnect semantics on both. logout() is wrapped as a
624
- * no-op so legacy callers don't close the persistent client. */
625
- private async getLaneClient(accountId: string, lane: "fast" | "slow"): Promise<any> {
626
- const map = lane === "fast" ? this.fastClients : this.opsClients;
620
+ private static readonly HOST_PERMITS = 8;
621
+
622
+ /** The (accountId → client) map for a lane, created on first use. */
623
+ private laneClientMap(lane: string): Map<string, any> {
624
+ let m = this.laneClients.get(lane);
625
+ if (!m) { m = new Map(); this.laneClients.set(lane, m); }
626
+ return m;
627
+ }
628
+
629
+ private async getLaneClient(accountId: string, lane: string): Promise<any> {
630
+ const map = this.laneClientMap(lane);
627
631
  let client = map.get(accountId);
628
632
  if (client) {
629
633
  // C38: health-check the cached client before returning. If the
@@ -640,7 +644,7 @@ export class ImapManager extends EventEmitter {
640
644
  console.log(` [conn] ${accountId}: stale ${lane} client detected — reconnecting`);
641
645
  client = undefined as any;
642
646
  }
643
- client = await this.newClient(accountId, lane === "fast" ? "fast" : "ops");
647
+ client = await this.newClient(accountId, lane);
644
648
  // Wrap logout as no-op — this is a persistent connection. The
645
649
  // newClient wrapper's close-counter runs on `_realLogout`.
646
650
  const realLogout = client.logout.bind(client);
@@ -657,33 +661,30 @@ export class ImapManager extends EventEmitter {
657
661
  return this.getLaneClient(accountId, "slow");
658
662
  }
659
663
 
660
- /** Run an operation on the account's connection — queued, sequential, no concurrency */
661
- /** Run an operation against the account's single ops connection. Tasks
662
- * queue strictly sequentially per account only one IMAP command in
663
- * flight at a time. This eliminates the SELECT-races and "stale client
664
- * recovery" paths the old multi-client design needed.
664
+ /** Run an operation against one of the account's per-workload lane
665
+ * connections. Tasks queue strictly sequentially WITHIN a lane (one IMAP
666
+ * command in flight, no SELECT race) but lanes run CONCURRENTLY, each on
667
+ * its own socket — so a slow op on one lane never blocks another.
665
668
  *
666
- * Default lane is `fast` covers virtually everything (body fetch,
667
- * flag toggle, move, incremental sync). Pass `slow: true` only for
668
- * operations the caller knows will take a long time and shouldn't
669
- * block the user (multi-folder prefetch batches, large backfills).
670
- * When both lanes have tasks, fast drains first.
669
+ * Pick the lane via `opts.lane` (e.g. "sync", "prefetch", "outbox").
670
+ * Default is "fast" interactive ops (body fetch on click, flag toggle,
671
+ * move). `slow: true` is a legacy alias for the "slow" misc lane; prefer
672
+ * a named lane so distinct workloads don't serialize behind each other.
671
673
  *
672
- * Within a lane, FIFO. The running task always finishes — IMAP can't
673
- * preempt a command mid-flight. */
674
+ * The running task always finishes — IMAP can't preempt a command
675
+ * mid-flight; the wall-clock timeout below bounds how long that can be. */
674
676
  async withConnection<T>(
675
677
  accountId: string,
676
678
  fn: (client: any) => Promise<T>,
677
- opts: { slow?: boolean; timeoutMs?: number } = {},
679
+ opts: { slow?: boolean; lane?: string; timeoutMs?: number } = {},
678
680
  ): Promise<T> {
679
- let queue = this.opsQueues.get(accountId);
680
- if (!queue) {
681
- queue = { fast: [], slow: [], runningFast: false, runningSlow: false };
682
- this.opsQueues.set(accountId, queue);
683
- }
684
- const lane: "fast" | "slow" = opts.slow ? "slow" : "fast";
681
+ const lane: string = opts.lane ?? (opts.slow ? "slow" : "fast");
682
+ let perAccount = this.laneQueues.get(accountId);
683
+ if (!perAccount) { perAccount = new Map(); this.laneQueues.set(accountId, perAccount); }
684
+ let queue = perAccount.get(lane);
685
+ if (!queue) { queue = { tasks: [], running: false }; perAccount.set(lane, queue); }
685
686
  // Per-task wall-clock cap. Without one, a wedged IMAP command (TCP
686
- // half-open, server stalled mid-FETCH) keeps the queue's running flag
687
+ // half-open, server stalled mid-FETCH) keeps the lane's running flag
687
688
  // set forever and every subsequent same-lane task — including the
688
689
  // retry button the user just hit — waits behind it. Default is
689
690
  // generous; callers driving user-visible reads pass a tighter value.
@@ -703,13 +704,12 @@ export class ImapManager extends EventEmitter {
703
704
  resolve(result);
704
705
  } catch (e: any) {
705
706
  clearTimeout(timer);
706
- // Discard the lane's client on any error — a half-broken
707
- // socket poisons every subsequent request on that lane.
708
- // Don't touch the OTHER lane's client; the lanes are
709
- // independent. Destroy synchronously kills the in-flight
710
- // command's socket so the underlying promise rejects and
711
- // stops holding state.
712
- const map = lane === "fast" ? this.fastClients : this.opsClients;
707
+ // Discard THIS lane's client on any error — a half-broken
708
+ // socket poisons every subsequent request on the lane.
709
+ // Other lanes' clients are independent and untouched.
710
+ // Destroy synchronously kills the in-flight command's
711
+ // socket so the underlying promise rejects.
712
+ const map = this.laneClientMap(lane);
713
713
  const stale = map.get(accountId);
714
714
  map.delete(accountId);
715
715
  if (stale) {
@@ -719,31 +719,27 @@ export class ImapManager extends EventEmitter {
719
719
  reject(e);
720
720
  }
721
721
  };
722
- queue![lane].push(task);
722
+ queue!.tasks.push(task);
723
723
  this.drainOpsQueue(accountId);
724
724
  });
725
725
  }
726
726
 
727
- /** Run the next queued task on each lane. Fast and slow lanes drain
728
- * CONCURRENTLY — each on its own connection (C123). FIFO within each
729
- * lane. The running flag per lane prevents reentrant draining of the
730
- * same lane. */
727
+ /** Drain the next queued task on EVERY lane for the account. Lanes run
728
+ * concurrently — each on its own connection and the per-lane running
729
+ * flag prevents reentrant draining of the same lane. */
731
730
  private drainOpsQueue(accountId: string): void {
732
- const queue = this.opsQueues.get(accountId);
733
- if (!queue) return;
734
- const drainLane = (lane: "fast" | "slow"): void => {
735
- const runningKey = lane === "fast" ? "runningFast" : "runningSlow";
736
- if (queue[runningKey]) return;
737
- const next = queue[lane].shift();
738
- if (!next) return;
739
- queue[runningKey] = true;
731
+ const perAccount = this.laneQueues.get(accountId);
732
+ if (!perAccount) return;
733
+ for (const queue of perAccount.values()) {
734
+ if (queue.running) continue;
735
+ const next = queue.tasks.shift();
736
+ if (!next) continue;
737
+ queue.running = true;
740
738
  next().finally(() => {
741
- queue[runningKey] = false;
742
- drainLane(lane);
739
+ queue.running = false;
740
+ this.drainOpsQueue(accountId);
743
741
  });
744
- };
745
- drainLane("fast");
746
- drainLane("slow");
742
+ }
747
743
  }
748
744
 
749
745
  /** Acquire one slot of the per-host connection semaphore. Returns a release
@@ -853,7 +849,7 @@ export class ImapManager extends EventEmitter {
853
849
  * so the server's connection slots free immediately rather than
854
850
  * waiting for socket idle timeouts. */
855
851
  async closeAllClients(accountId: string): Promise<void> {
856
- for (const map of [this.opsClients, this.fastClients]) {
852
+ for (const map of this.laneClients.values()) {
857
853
  const c = map.get(accountId);
858
854
  map.delete(accountId);
859
855
  if (c) { try { await (c._realLogout || c.logout)(); } catch { /* */ } try { c.destroy?.(); } catch { /* */ } }
@@ -871,7 +867,7 @@ export class ImapManager extends EventEmitter {
871
867
  /** Disconnect the persistent operational connections (both lanes) for
872
868
  * an account. */
873
869
  async disconnectOps(accountId: string): Promise<void> {
874
- for (const [name, map] of [["ops", this.opsClients], ["fast", this.fastClients]] as const) {
870
+ for (const [name, map] of this.laneClients) {
875
871
  const client = map.get(accountId);
876
872
  map.delete(accountId);
877
873
  if (client) {
@@ -1351,7 +1347,13 @@ export class ImapManager extends EventEmitter {
1351
1347
  excludeUids: Set<number>,
1352
1348
  ): Promise<{ recoveredCount: number; serverUids: number[] | null; dateBounded: boolean }> {
1353
1349
  const folderPath = folder.path;
1354
- const existingUids = this.db.getUidsForFolder(accountId, folderId);
1350
+ // Diff against UIDs we actually have a MESSAGE ROW for (messages table),
1351
+ // NOT message_folders memberships. An orphan membership (member row but
1352
+ // no message row) would otherwise look "present" and never get its real
1353
+ // data fetched — leaving the message permanently missing from the list
1354
+ // while the folder count looks full (Bob 2026-06-20: ~1k old INBOX
1355
+ // messages stuck missing behind orphan memberships).
1356
+ const existingUids = this.db.getStoredUids(accountId, folderId);
1355
1357
  // Small folders (Drafts, Sent, …) get a FULL UID fetch so server-side
1356
1358
  // deletions of OLDER messages are reflected; large folders (134k INBOX)
1357
1359
  // get a date-bounded query so we don't enumerate the whole mailbox.
@@ -1645,7 +1647,11 @@ export class ImapManager extends EventEmitter {
1645
1647
  // retries instead of locking out for RECONCILE_THROTTLE_MS
1646
1648
  // (Bob 2026-06-20: boot-time "Not connected" failure locked
1647
1649
  // INBOX recovery out for 15 min).
1648
- const localCount = this.db.getMessageCount(accountId, folderId);
1650
+ // Compare STORED-ROW count (messages table) to the server's
1651
+ // count — not getMessageCount (message_folders), which orphan
1652
+ // memberships can inflate to match the server while real rows
1653
+ // are still missing.
1654
+ const localCount = this.db.getStoredCount(accountId, folderId);
1649
1655
  const hasDeficit = statusMessageCount !== null && localCount < statusMessageCount;
1650
1656
  const lastRecon = this.lastReconcileMs.get(folderId) ?? 0;
1651
1657
  const throttleElapsed = Date.now() - lastRecon > RECONCILE_THROTTLE_MS;
@@ -2524,12 +2530,15 @@ export class ImapManager extends EventEmitter {
2524
2530
  return stored;
2525
2531
  }
2526
2532
 
2527
- /** Kill and recreate the persistent ops connection */
2533
+ /** Kill and recreate the persistent connections for an account — drops the
2534
+ * client on every lane so the next task on each reconnects fresh. */
2528
2535
  private async reconnectOps(accountId: string): Promise<void> {
2529
- const old = this.opsClients.get(accountId);
2530
- this.opsClients.delete(accountId);
2531
- if (old) { try { await (old._realLogout || old.logout)(); } catch { /* */ } }
2532
- console.log(` [conn] ${accountId}: reconnecting`);
2536
+ for (const map of this.laneClients.values()) {
2537
+ const old = map.get(accountId);
2538
+ map.delete(accountId);
2539
+ if (old) { try { await (old._realLogout || old.logout)(); } catch { /* */ } }
2540
+ }
2541
+ console.log(` [conn] ${accountId}: reconnecting (all lanes)`);
2533
2542
  }
2534
2543
 
2535
2544
  /** Handle sync errors — classify and emit appropriate UI events.
@@ -3562,7 +3571,7 @@ export class ImapManager extends EventEmitter {
3562
3571
  })());
3563
3572
  });
3564
3573
  await Promise.all(pending);
3565
- }, { slow: true, timeoutMs: 300_000 });
3574
+ }, { lane: "prefetch", timeoutMs: 300_000 });
3566
3575
  // 5-min cap, not the 90s interactive default:
3567
3576
  // prefetch is background, and a 25-message body
3568
3577
  // chunk on a slow Dovecot legitimately runs past
@@ -4326,7 +4335,7 @@ export class ImapManager extends EventEmitter {
4326
4335
  await this.withConnection(accountId, async (client) => {
4327
4336
  await client.createmailbox("Outbox");
4328
4337
  await this.syncFolders(accountId, client);
4329
- });
4338
+ }, { lane: "outbox" });
4330
4339
  } catch (e: any) {
4331
4340
  // Might already exist — benign
4332
4341
  if (!e.message?.includes("already exists")) throw e;
@@ -4437,7 +4446,7 @@ export class ImapManager extends EventEmitter {
4437
4446
  await this.withConnection(accountId, async (client) => {
4438
4447
  appendedUid = await client.appendMessage(outboxPath, rawMessage, ["\\Seen"]);
4439
4448
  console.log(` [outbox] Queued message in ${outboxPath}${appendedUid != null ? ` (UID ${appendedUid})` : ""}`);
4440
- });
4449
+ }, { lane: "outbox" });
4441
4450
  if (outboxFolder) {
4442
4451
  if (appendedUid != null) {
4443
4452
  // Inserts the row from the source bytes we already have +
@@ -4644,7 +4653,9 @@ export class ImapManager extends EventEmitter {
4644
4653
  // claim so the recovery sweeper picks it up next tick.
4645
4654
  try {
4646
4655
  const outboxPath = await this.ensureOutbox(accountId);
4647
- const client = await this.createClientWithLimit(accountId);
4656
+ // Outbox lane, not the slow/sync lane — a wedged APPEND here (which
4657
+ // withTimeout force-closes the socket on) must not disrupt sync.
4658
+ const client = await this.getLaneClient(accountId, "outbox");
4648
4659
  try {
4649
4660
  for (const { dir, file } of filesToSend) {
4650
4661
  const filePath = path.join(dir, file);
@@ -4780,9 +4791,9 @@ export class ImapManager extends EventEmitter {
4780
4791
  const account = settings.accounts.find(a => a.id === accountId);
4781
4792
  if (!account) return;
4782
4793
 
4783
- // List UIDs first — quick command, fast lane.
4794
+ // List UIDs first — quick command on the dedicated outbox lane.
4784
4795
  const uids = await this.withConnection(accountId, (client) =>
4785
- client.getUids(outboxFolder.path)
4796
+ client.getUids(outboxFolder.path), { lane: "outbox" }
4786
4797
  ) as number[];
4787
4798
  if (uids.length === 0) return;
4788
4799
 
@@ -4792,9 +4803,9 @@ export class ImapManager extends EventEmitter {
4792
4803
  const sentFolder = this.findFolder(accountId, "sent");
4793
4804
 
4794
4805
  for (const uid of uids) {
4795
- // Each iteration is one slow-lane turn — fast-lane work can run
4796
- // between iterations, so a body click during a long outbox drain
4797
- // gets serviced promptly.
4806
+ // Each iteration is one outbox-lane turn — sync, prefetch and
4807
+ // fast-lane (click) work all run on their own connections, so a
4808
+ // long outbox drain never blocks them.
4798
4809
  const result = await this.withConnection(accountId, async (client) => {
4799
4810
  const flags = await client.getFlags(outboxFolder.path, uid);
4800
4811
 
@@ -4842,7 +4853,7 @@ export class ImapManager extends EventEmitter {
4842
4853
  return { skip: true };
4843
4854
  }
4844
4855
  return { source: msg.source };
4845
- }, { slow: true });
4856
+ }, { lane: "outbox" });
4846
4857
 
4847
4858
  if ((result as any).skip) continue;
4848
4859
  const source = (result as any).source as string;
@@ -4858,13 +4869,13 @@ export class ImapManager extends EventEmitter {
4858
4869
  await this.withConnection(accountId, async (client) => {
4859
4870
  // Delete FIRST to prevent double-send if Sent-copy fails.
4860
4871
  await client.deleteMessageByUid(outboxFolder.path, uid);
4861
- }, { slow: true });
4872
+ }, { lane: "outbox" });
4862
4873
  if (sentFolder) {
4863
4874
  let appendedSentUid: number | null = null;
4864
4875
  try {
4865
4876
  await this.withConnection(accountId, async (client) => {
4866
4877
  appendedSentUid = await client.appendMessage(sentFolder.path, source, ["\\Seen"]);
4867
- }, { slow: true });
4878
+ }, { lane: "outbox" });
4868
4879
  } catch (sentErr: any) {
4869
4880
  console.error(` [outbox] Failed to copy to Sent: ${sentErr.message} — message was sent successfully`);
4870
4881
  }
@@ -4894,7 +4905,7 @@ export class ImapManager extends EventEmitter {
4894
4905
  await this.withConnection(accountId, async (client) => {
4895
4906
  await client.removeFlags(outboxFolder.path, uid, [sendingFlag]);
4896
4907
  await client.addFlags(outboxFolder.path, uid, ["$Failed"]);
4897
- }, { slow: true });
4908
+ }, { lane: "outbox" });
4898
4909
  } catch { /* best-effort */ }
4899
4910
  // Suppress the banner for transient network errors. ETIMEDOUT
4900
4911
  // on a Dovecot send is the server being slow / a TCP idle
@@ -5033,10 +5044,10 @@ export class ImapManager extends EventEmitter {
5033
5044
  this.outboxBackoffDelay.delete(accountId);
5034
5045
  } catch (e: any) {
5035
5046
  // Stale-socket errors (Dovecot silently drops idle connections,
5036
- // or the sync path timed out and destroyed the socket): force a
5037
- // fresh ops client so the next tick doesn't keep hitting the same
5038
- // dead socket. Without reconnectOps, the dead client stays in the
5039
- // opsClients map and every subsequent processOutbox call fails
5047
+ // or the sync path timed out and destroyed the socket): force
5048
+ // fresh lane clients so the next tick doesn't keep hitting the
5049
+ // same dead socket. Without reconnectOps, the dead client stays
5050
+ // in its lane map and every subsequent processOutbox call fails
5040
5051
  // immediately with "Not connected" — forever.
5041
5052
  const msg = String(e?.message || e);
5042
5053
  if (/Not connected|ECONNRESET|socket hang up|EPIPE|write after end/i.test(msg)) {
@@ -5136,19 +5147,18 @@ export class ImapManager extends EventEmitter {
5136
5147
  if (rows.length === 0) return;
5137
5148
  let reconciled = 0;
5138
5149
  let appended = 0;
5139
- // Use a DEDICATED IMAP client for sent-sweep do NOT share the
5140
- // slow-lane ops client. The priority-INBOX sync grabs the slow-lane
5141
- // client via getOpsClient() (no lane queueing) and runs SEARCH→FETCH
5142
- // as a logical transaction; if sent-sweep's searchByHeader (SELECT
5143
- // Sent SEARCH CLOSE) interleaves on the same wire between the
5144
- // sync's SEARCH and FETCH, the FETCH lands with no mailbox selected
5145
- // and Dovecot returns "BAD No mailbox selected" — new mail never
5146
- // lands locally (Bob 2026-05-25: "not seeing recent mail").
5147
- // iflow-direct serializes per-command, not per-task, so reusing the
5148
- // shared client is unsafe across logical transactions. A dedicated
5149
- // client is the smallest surgical fix.
5150
- const client = await this.createClientWithLimit(accountId);
5151
- try {
5150
+ // Run the whole sweep on the dedicated "outbox" lane its OWN
5151
+ // persistent connection, separate from the slow/sync lane. Two reasons:
5152
+ // 1. Sent-sweep's `SELECT Sent` has been observed taking 90s on this
5153
+ // server; on the shared slow lane that stalled INBOX sync/backfill
5154
+ // behind it (the "whole worker goes silent" wedge, Bob 2026-06-20).
5155
+ // 2. withConnection serializes the entire SEARCH→APPEND sweep on one
5156
+ // connection, so it can't interleave mid-transaction with another
5157
+ // task's SELECT (the "BAD No mailbox selected" class, Bob
5158
+ // 2026-05-25). Previously this used createClientWithLimit() which
5159
+ // actually returned the SHARED slow client and then destroyed it in
5160
+ // a finally, the opposite of "dedicated".
5161
+ await this.withConnection(accountId, async (client) => {
5152
5162
  for (const row of rows) {
5153
5163
  const msgId = row.message_id;
5154
5164
  if (!msgId) continue;
@@ -5185,10 +5195,7 @@ export class ImapManager extends EventEmitter {
5185
5195
  }
5186
5196
  }
5187
5197
  }
5188
- } finally {
5189
- try { await (client._realLogout || client.logout)(); } catch { /* */ }
5190
- try { client.destroy?.(); } catch { /* */ }
5191
- }
5198
+ }, { lane: "outbox", timeoutMs: 120_000 });
5192
5199
  if (reconciled + appended > 0) {
5193
5200
  this.emit("folderCountsChanged", accountId, {});
5194
5201
  console.log(` [sent-sweep] ${accountId}: ${reconciled} rebound, ${appended} re-appended`);
@@ -5469,13 +5476,13 @@ export class ImapManager extends EventEmitter {
5469
5476
  this.stopPeriodicSync();
5470
5477
  this.stopOutboxWorker();
5471
5478
  await this.stopWatching();
5472
- // Disconnect persistent connections on both lanes. Use a Set
5473
- // because fastClients can hold an entry an account doesn't have
5474
- // in opsClients (e.g. body fetches happened but no sync did).
5475
- const accountIds = new Set<string>([
5476
- ...this.opsClients.keys(),
5477
- ...this.fastClients.keys(),
5478
- ]);
5479
+ // Disconnect persistent connections on every lane. Union across all
5480
+ // lane maps because a lane can hold an account the others don't (e.g.
5481
+ // body fetches happened on "fast" but no sync ran on "sync").
5482
+ const accountIds = new Set<string>();
5483
+ for (const map of this.laneClients.values()) {
5484
+ for (const k of map.keys()) accountIds.add(k);
5485
+ }
5479
5486
  for (const accountId of accountIds) {
5480
5487
  await this.disconnectOps(accountId);
5481
5488
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx-imap",
3
- "version": "0.1.104",
3
+ "version": "0.1.106",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bobfrankston/mailx-imap",
9
- "version": "0.1.104",
9
+ "version": "0.1.106",
10
10
  "license": "ISC",
11
11
  "dependencies": {
12
12
  "@bobfrankston/iflow-direct": "^0.1.27",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx-imap",
3
- "version": "0.1.104",
3
+ "version": "0.1.106",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -435,6 +435,20 @@ export declare class MailxDB {
435
435
  * here but NOT on the server gets its membership dropped (which
436
436
  * may then GC the messages row if it has no other folders). */
437
437
  getUidsForFolder(_accountId: string, folderId: number): number[];
438
+ /** UIDs we actually have a stored MESSAGE ROW for in this folder — from the
439
+ * `messages` table, NOT `message_folders`. The two can diverge: an "orphan
440
+ * membership" (a message_folders row whose messages row was never written /
441
+ * got deleted) makes getUidsForFolder report a UID we don't truly have.
442
+ * The set-diff backfill must diff against THIS so it re-fetches the real
443
+ * message data for orphans instead of treating them as present (Bob
444
+ * 2026-06-20: ~1k old INBOX messages stuck missing — membership said
445
+ * "have it", the row didn't exist). */
446
+ getStoredUids(accountId: string, folderId: number): number[];
447
+ /** Count of stored MESSAGE ROWS in a folder (messages table). The deficit
448
+ * gate compares this to the server's count to decide whether to reconcile;
449
+ * using the messages table (not message_folders) means orphan memberships
450
+ * don't mask a real "rows are missing" deficit. */
451
+ getStoredCount(accountId: string, folderId: number): number;
438
452
  /** List recent rows in a folder for a Sent-sweep / reconciliation pass.
439
453
  * Returns only the columns the sweeper needs (uid, message_id, date,
440
454
  * subject, size, has_attachments, preview, body_path) for every row in
@@ -1 +1 @@
1
- {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["db.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["db.ts"],"names":[],"mappings":"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"}
@@ -2394,6 +2394,26 @@ export class MailxDB {
2394
2394
  const rows = this.db.prepare("SELECT uid FROM message_folders WHERE folder_id = ?").all(folderId);
2395
2395
  return rows.map(r => r.uid);
2396
2396
  }
2397
+ /** UIDs we actually have a stored MESSAGE ROW for in this folder — from the
2398
+ * `messages` table, NOT `message_folders`. The two can diverge: an "orphan
2399
+ * membership" (a message_folders row whose messages row was never written /
2400
+ * got deleted) makes getUidsForFolder report a UID we don't truly have.
2401
+ * The set-diff backfill must diff against THIS so it re-fetches the real
2402
+ * message data for orphans instead of treating them as present (Bob
2403
+ * 2026-06-20: ~1k old INBOX messages stuck missing — membership said
2404
+ * "have it", the row didn't exist). */
2405
+ getStoredUids(accountId, folderId) {
2406
+ const rows = this.db.prepare("SELECT uid FROM messages WHERE account_id = ? AND folder_id = ?").all(accountId, folderId);
2407
+ return rows.map(r => r.uid);
2408
+ }
2409
+ /** Count of stored MESSAGE ROWS in a folder (messages table). The deficit
2410
+ * gate compares this to the server's count to decide whether to reconcile;
2411
+ * using the messages table (not message_folders) means orphan memberships
2412
+ * don't mask a real "rows are missing" deficit. */
2413
+ getStoredCount(accountId, folderId) {
2414
+ const r = this.db.prepare("SELECT count(*) as cnt FROM messages WHERE account_id = ? AND folder_id = ?").get(accountId, folderId);
2415
+ return r?.cnt || 0;
2416
+ }
2397
2417
  /** List recent rows in a folder for a Sent-sweep / reconciliation pass.
2398
2418
  * Returns only the columns the sweeper needs (uid, message_id, date,
2399
2419
  * subject, size, has_attachments, preview, body_path) for every row in