@bobfrankston/mailx-imap 0.1.46 → 0.1.48

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 +28 -1
  2. package/package.json +9 -9
package/index.js CHANGED
@@ -1213,10 +1213,18 @@ export class ImapManager extends EventEmitter {
1213
1213
  // emits them only via state-change FETCH if their flags
1214
1214
  // changed since modSeq, which is unreliable. Pull them
1215
1215
  // explicitly via the existing incremental path.
1216
+ // INSTRUMENTATION (2026-05-15): phase timestamps so the
1217
+ // log pinpoints which operation eats wall-clock during a
1218
+ // slow sync. The 27 s INBOX block had a silent log hole;
1219
+ // these markers fill it.
1220
+ const __t1 = Date.now();
1216
1221
  const fetched = await client.fetchMessagesSinceUid(folder.path, highestUid, { source: false });
1222
+ console.log(` [qr-phase] ${folder.path}: fetchMessagesSinceUid → ${fetched.length} msgs in ${Date.now() - __t1}ms`);
1217
1223
  const newOnes = fetched.filter((m) => m.uid > highestUid);
1218
1224
  if (newOnes.length > 0) {
1225
+ const __t2 = Date.now();
1219
1226
  await this.storeMessages(accountId, folderId, folder, newOnes, highestUid);
1227
+ console.log(` [qr-phase] ${folder.path}: storeMessages(${newOnes.length}) in ${Date.now() - __t2}ms`);
1220
1228
  }
1221
1229
  // Persist new watermark — next resync starts here.
1222
1230
  if (qr.newHighestModSeq !== undefined) {
@@ -2439,10 +2447,29 @@ export class ImapManager extends EventEmitter {
2439
2447
  this.syncFolder(accountId, folder.id).catch(e => console.error(` [notify] sync ${mailboxPath} failed: ${e.message}`));
2440
2448
  }
2441
2449
  : undefined;
2450
+ // Deletion push: when the server expunges a message from
2451
+ // INBOX while we're parked in IDLE (e.g. the user deletes it
2452
+ // in Thunderbird), reconcile it locally right away instead of
2453
+ // waiting for the 5-minute poll. Debounced — a cleanup pass
2454
+ // fires a burst of EXPUNGE notifications; collapse them into
2455
+ // one syncFolder. syncFolder's set-diff drops the gone rows.
2456
+ let expungeTimer = null;
2457
+ const onExpunge = () => {
2458
+ if (expungeTimer)
2459
+ clearTimeout(expungeTimer);
2460
+ expungeTimer = setTimeout(() => {
2461
+ expungeTimer = null;
2462
+ const inbox = this.db.getFolders(accountId).find(f => f.specialUse === "inbox");
2463
+ if (!inbox)
2464
+ return;
2465
+ console.log(` [idle] ${accountId}: INBOX expunge pushed → reconcile`);
2466
+ this.syncFolder(accountId, inbox.id).catch(e => console.error(` [idle] expunge reconcile failed: ${e.message}`));
2467
+ }, 2000);
2468
+ };
2442
2469
  const stop = await watchClient.watchMailbox("INBOX", (newCount) => {
2443
2470
  console.log(` [idle] ${accountId}: ${newCount} new message(s)`);
2444
2471
  this.syncInboxNewOnly(accountId).catch(e => console.error(` [idle] sync error: ${e.message}`));
2445
- }, { notifySpec, onMailboxStatus });
2472
+ }, { notifySpec, onMailboxStatus, onExpunge });
2446
2473
  this.watchers.set(accountId, async () => {
2447
2474
  await stop();
2448
2475
  await watchClient.logout();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx-imap",
3
- "version": "0.1.46",
3
+ "version": "0.1.48",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -9,13 +9,13 @@
9
9
  },
10
10
  "license": "ISC",
11
11
  "dependencies": {
12
- "@bobfrankston/mailx-types": "^0.1.13",
12
+ "@bobfrankston/mailx-types": "^0.1.14",
13
13
  "@bobfrankston/mailx-settings": "^0.1.17",
14
- "@bobfrankston/mailx-store": "^0.1.25",
15
- "@bobfrankston/iflow-direct": "^0.1.44",
14
+ "@bobfrankston/mailx-store": "^0.1.27",
15
+ "@bobfrankston/iflow-direct": "^0.1.50",
16
16
  "@bobfrankston/tcp-transport": "^0.1.6",
17
17
  "@bobfrankston/smtp-direct": "^0.1.8",
18
- "@bobfrankston/mailx-sync": "^0.1.16",
18
+ "@bobfrankston/mailx-sync": "^0.1.17",
19
19
  "@bobfrankston/oauthsupport": "^1.0.26"
20
20
  },
21
21
  "repository": {
@@ -37,13 +37,13 @@
37
37
  },
38
38
  ".transformedSnapshot": {
39
39
  "dependencies": {
40
- "@bobfrankston/mailx-types": "^0.1.13",
40
+ "@bobfrankston/mailx-types": "^0.1.14",
41
41
  "@bobfrankston/mailx-settings": "^0.1.17",
42
- "@bobfrankston/mailx-store": "^0.1.25",
43
- "@bobfrankston/iflow-direct": "^0.1.44",
42
+ "@bobfrankston/mailx-store": "^0.1.27",
43
+ "@bobfrankston/iflow-direct": "^0.1.50",
44
44
  "@bobfrankston/tcp-transport": "^0.1.6",
45
45
  "@bobfrankston/smtp-direct": "^0.1.8",
46
- "@bobfrankston/mailx-sync": "^0.1.16",
46
+ "@bobfrankston/mailx-sync": "^0.1.17",
47
47
  "@bobfrankston/oauthsupport": "^1.0.26"
48
48
  }
49
49
  }