@bobfrankston/mailx-imap 0.1.71 → 0.1.73

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 (3) hide show
  1. package/index.d.ts +7 -0
  2. package/index.js +21 -0
  3. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -398,6 +398,13 @@ export declare class ImapManager extends EventEmitter {
398
398
  private prefetchFailures;
399
399
  private markPrefetchEmpty;
400
400
  private isPrefetchEmpty;
401
+ /** Clear a UID's prefetch-failure record after a successful fetch, so a
402
+ * message that healed (e.g. a transient iflow protocol desync that
403
+ * resolved on retry) doesn't carry a stale backoff count into the
404
+ * future. Without this, a once-failed-then-succeeded UID keeps its
405
+ * count and would back off longer than warranted if it ever re-enters
406
+ * the candidate set. */
407
+ private clearPrefetchEmpty;
401
408
  /** Background body-cache backfill. Public so the Reconciler can schedule
402
409
  * the periodic tick under its priority/back-pressure rules; existing
403
410
  * in-method post-sync nudges (sync, fetchSince, fetchOne) call this
package/index.js CHANGED
@@ -2870,6 +2870,15 @@ export class ImapManager extends EventEmitter {
2870
2870
  : 12 * 3600_000;
2871
2871
  return Date.now() - f.lastTried < backoffMs;
2872
2872
  }
2873
+ /** Clear a UID's prefetch-failure record after a successful fetch, so a
2874
+ * message that healed (e.g. a transient iflow protocol desync that
2875
+ * resolved on retry) doesn't carry a stale backoff count into the
2876
+ * future. Without this, a once-failed-then-succeeded UID keeps its
2877
+ * count and would back off longer than warranted if it ever re-enters
2878
+ * the candidate set. */
2879
+ clearPrefetchEmpty(accountId, folderId, uid) {
2880
+ this.prefetchFailures.delete(`${accountId}:${folderId}:${uid}`);
2881
+ }
2873
2882
  /** Background body-cache backfill. Public so the Reconciler can schedule
2874
2883
  * the periodic tick under its priority/back-pressure rules; existing
2875
2884
  * in-method post-sync nudges (sync, fetchSince, fetchOne) call this
@@ -3095,11 +3104,23 @@ export class ImapManager extends EventEmitter {
3095
3104
  const parsed = await extractPreview(source);
3096
3105
  this.db.updateBodyMeta(accountId, uid, bodyPath, parsed.hasAttachments, parsed.preview);
3097
3106
  this.emit("bodyCached", accountId, uid);
3107
+ this.clearPrefetchEmpty(accountId, folderId, uid); // healed — drop stale backoff
3098
3108
  counters.totalFetched++;
3099
3109
  madeProgress = true;
3100
3110
  }
3101
3111
  catch (e) {
3102
3112
  console.error(` [prefetch] ${accountId}/${uid}: store write failed: ${e.message}`);
3113
+ // Back off this UID. A corrupt body (the
3114
+ // putMessage guard rejecting an IMAP command
3115
+ // leaked into the FETCH response — iflow
3116
+ // protocol desync) was NOT marked, so the
3117
+ // same poisoned UID got re-fetched every
3118
+ // prefetch cycle forever, spamming the log
3119
+ // and wasting fetch turns (Bob 2026-05-28
3120
+ // "why is prefetching still broken" — UID
3121
+ // 59686 failing on a loop). markPrefetchEmpty
3122
+ // applies the 5m→30m→2h→12h backoff.
3123
+ this.markPrefetchEmpty(accountId, folderId, uid);
3103
3124
  }
3104
3125
  })());
3105
3126
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx-imap",
3
- "version": "0.1.71",
3
+ "version": "0.1.73",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",