@bobfrankston/mailx-imap 0.1.80 → 0.1.82
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.
- package/index.d.ts +0 -1
- package/index.js +29 -11
- package/package.json +3 -3
package/index.d.ts
CHANGED
|
@@ -395,7 +395,6 @@ export declare class ImapManager extends EventEmitter {
|
|
|
395
395
|
* no teal mark). With TTL, transient misses self-heal in 5 minutes;
|
|
396
396
|
* genuine zombies back off to once-per-12-hour retries — bounded load.
|
|
397
397
|
* Key shape `${accountId}:${folderId}:${uid}`. */
|
|
398
|
-
private prefetchFailures;
|
|
399
398
|
private markPrefetchEmpty;
|
|
400
399
|
private isPrefetchEmpty;
|
|
401
400
|
/** Clear a UID's prefetch-failure record after a successful fetch, so a
|
package/index.js
CHANGED
|
@@ -1864,8 +1864,19 @@ export class ImapManager extends EventEmitter {
|
|
|
1864
1864
|
// a "never-touched" non-special folder is deferred until the
|
|
1865
1865
|
// user opens that folder (on-demand syncFolder call) or until
|
|
1866
1866
|
// ~3 minutes after startup when the event loop is quiet.
|
|
1867
|
-
|
|
1868
|
-
|
|
1867
|
+
// TRUE lazy folder sync (C119, completed 2026-06-01). A folder is
|
|
1868
|
+
// "lazy" if it's neither a priority special-use folder NOR one
|
|
1869
|
+
// mailx has ever pulled a message from (highestUid===0). Lazy
|
|
1870
|
+
// folders are NOT auto-synced at all — they sync on-demand the
|
|
1871
|
+
// moment the user opens them (the client fires `syncFolderNow` on
|
|
1872
|
+
// folder-open) and then join the periodic set automatically once
|
|
1873
|
+
// they have a message (highestUid>0). Previously they were only
|
|
1874
|
+
// deferred for a 3-minute startup window, after which a full
|
|
1875
|
+
// 96-folder sweep ran every cycle — re-saturating the IMAP
|
|
1876
|
+
// connection and pegging the event loop (the "mailx DOSes itself,
|
|
1877
|
+
// TB doesn't" storm, Bob 2026-06-01). Permanent deferral closes it:
|
|
1878
|
+
// a fresh rebuild now syncs only INBOX + special-use, and the rest
|
|
1879
|
+
// fill in as the user actually visits them.
|
|
1869
1880
|
const isLazyEligible = (f) => {
|
|
1870
1881
|
if (f.specialUse && priorityOrder.includes(f.specialUse))
|
|
1871
1882
|
return false;
|
|
@@ -1873,15 +1884,15 @@ export class ImapManager extends EventEmitter {
|
|
|
1873
1884
|
return false;
|
|
1874
1885
|
return true;
|
|
1875
1886
|
};
|
|
1876
|
-
const remaining = folders.filter(f => f.specialUse !== "inbox" && !
|
|
1887
|
+
const remaining = folders.filter(f => f.specialUse !== "inbox" && !isLazyEligible(f));
|
|
1877
1888
|
remaining.sort((a, b) => {
|
|
1878
1889
|
const pa = priorityOrder.indexOf(a.specialUse || "") >= 0 ? priorityOrder.indexOf(a.specialUse || "") : 5;
|
|
1879
1890
|
const pb = priorityOrder.indexOf(b.specialUse || "") >= 0 ? priorityOrder.indexOf(b.specialUse || "") : 5;
|
|
1880
1891
|
return pa - pb;
|
|
1881
1892
|
});
|
|
1882
|
-
const deferredCount = folders.filter(f => f.specialUse !== "inbox" && isLazyEligible(f)
|
|
1893
|
+
const deferredCount = folders.filter(f => f.specialUse !== "inbox" && isLazyEligible(f)).length;
|
|
1883
1894
|
if (deferredCount > 0) {
|
|
1884
|
-
console.log(` [sync] ${accountId}:
|
|
1895
|
+
console.log(` [sync] ${accountId}: lazy — ${deferredCount} never-touched folder(s) will sync on-demand when opened (not auto-swept)`);
|
|
1885
1896
|
}
|
|
1886
1897
|
const CONCURRENCY = 2;
|
|
1887
1898
|
// First-sync of a fresh account on a cold Dovecot is dominated by
|
|
@@ -2896,14 +2907,18 @@ export class ImapManager extends EventEmitter {
|
|
|
2896
2907
|
* no teal mark). With TTL, transient misses self-heal in 5 minutes;
|
|
2897
2908
|
* genuine zombies back off to once-per-12-hour retries — bounded load.
|
|
2898
2909
|
* Key shape `${accountId}:${folderId}:${uid}`. */
|
|
2899
|
-
|
|
2910
|
+
// Backed by the persistent `prefetch_failures` table (was an in-memory
|
|
2911
|
+
// Map that every daemon restart wiped — so ghost UIDs re-clogged prefetch
|
|
2912
|
+
// on every launch; Bob 2026-06-01). markPrefetchEmpty/isPrefetchEmpty now
|
|
2913
|
+
// read/write the DB so the 5min→12h backoff survives restarts.
|
|
2900
2914
|
markPrefetchEmpty(accountId, folderId, uid) {
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2915
|
+
try {
|
|
2916
|
+
this.db.recordPrefetchFailure(accountId, folderId, uid);
|
|
2917
|
+
}
|
|
2918
|
+
catch { /* non-fatal */ }
|
|
2904
2919
|
}
|
|
2905
2920
|
isPrefetchEmpty(accountId, folderId, uid) {
|
|
2906
|
-
const f = this.
|
|
2921
|
+
const f = this.db.getPrefetchFailure(accountId, folderId, uid);
|
|
2907
2922
|
if (!f)
|
|
2908
2923
|
return false;
|
|
2909
2924
|
const backoffMs = f.count <= 1 ? 5 * 60_000
|
|
@@ -2919,7 +2934,10 @@ export class ImapManager extends EventEmitter {
|
|
|
2919
2934
|
* count and would back off longer than warranted if it ever re-enters
|
|
2920
2935
|
* the candidate set. */
|
|
2921
2936
|
clearPrefetchEmpty(accountId, folderId, uid) {
|
|
2922
|
-
|
|
2937
|
+
try {
|
|
2938
|
+
this.db.clearPrefetchFailure(accountId, folderId, uid);
|
|
2939
|
+
}
|
|
2940
|
+
catch { /* non-fatal */ }
|
|
2923
2941
|
}
|
|
2924
2942
|
/** Background body-cache backfill. Public so the Reconciler can schedule
|
|
2925
2943
|
* the periodic tick under its priority/back-pressure rules; existing
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/mailx-imap",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.82",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@bobfrankston/mailx-types": "^0.1.18",
|
|
13
13
|
"@bobfrankston/mailx-settings": "^0.1.26",
|
|
14
|
-
"@bobfrankston/mailx-store": "^0.1.
|
|
14
|
+
"@bobfrankston/mailx-store": "^0.1.44",
|
|
15
15
|
"@bobfrankston/iflow-direct": "^0.1.51",
|
|
16
16
|
"@bobfrankston/tcp-transport": "^0.1.6",
|
|
17
17
|
"@bobfrankston/smtp-direct": "^0.1.8",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@bobfrankston/mailx-types": "^0.1.18",
|
|
41
41
|
"@bobfrankston/mailx-settings": "^0.1.26",
|
|
42
|
-
"@bobfrankston/mailx-store": "^0.1.
|
|
42
|
+
"@bobfrankston/mailx-store": "^0.1.44",
|
|
43
43
|
"@bobfrankston/iflow-direct": "^0.1.51",
|
|
44
44
|
"@bobfrankston/tcp-transport": "^0.1.6",
|
|
45
45
|
"@bobfrankston/smtp-direct": "^0.1.8",
|