@bobfrankston/mailx-imap 0.1.53 → 0.1.55
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.js +28 -16
- package/package.json +5 -5
package/index.js
CHANGED
|
@@ -2874,16 +2874,16 @@ export class ImapManager extends EventEmitter {
|
|
|
2874
2874
|
// owns deletion via a 30-min grace; defer to it.
|
|
2875
2875
|
const someReceived = received.size > 0;
|
|
2876
2876
|
if (batchSucceeded && someReceived) {
|
|
2877
|
+
// Mirror of the IMAP-path fix: never delete on a
|
|
2878
|
+
// partial batch — Gmail API has its own transient
|
|
2879
|
+
// miss modes (rate-limit retry losing a message,
|
|
2880
|
+
// /batch response parse error) that look exactly
|
|
2881
|
+
// like server-side expunge. Set-diff reconcile in
|
|
2882
|
+
// syncAccountViaApi owns deletion.
|
|
2877
2883
|
for (const uid of uidsInFolder) {
|
|
2878
2884
|
if (received.has(uid))
|
|
2879
2885
|
continue;
|
|
2880
|
-
|
|
2881
|
-
this.unlinkBodyFile(accountId, uid, folderId).catch(() => { });
|
|
2882
|
-
this.db.deleteMessage(accountId, uid, "prefetch batch: server didn't return body for queued UID — assumed deleted", "mailx-imap prefetchBodies (Gmail batch)");
|
|
2883
|
-
counters.deleted++;
|
|
2884
|
-
madeProgress = true;
|
|
2885
|
-
}
|
|
2886
|
-
catch { /* ignore */ }
|
|
2886
|
+
this.markPrefetchEmpty(accountId, folderId, uid);
|
|
2887
2887
|
}
|
|
2888
2888
|
}
|
|
2889
2889
|
else if (batchSucceeded && !someReceived) {
|
|
@@ -2981,7 +2981,13 @@ export class ImapManager extends EventEmitter {
|
|
|
2981
2981
|
})());
|
|
2982
2982
|
});
|
|
2983
2983
|
await Promise.all(pending);
|
|
2984
|
-
}, { slow: true });
|
|
2984
|
+
}, { slow: true, timeoutMs: 300_000 });
|
|
2985
|
+
// 5-min cap, not the 90s interactive default:
|
|
2986
|
+
// prefetch is background, and a 25-message body
|
|
2987
|
+
// chunk on a slow Dovecot legitimately runs past
|
|
2988
|
+
// 90s. The short cap was tripping the folder-error
|
|
2989
|
+
// cooldown 17×/session, so INBOX bodies stopped
|
|
2990
|
+
// prefetching entirely (Bob 2026-05-21 log).
|
|
2985
2991
|
batchSucceeded = true;
|
|
2986
2992
|
this.clearFolderErrors(accountId, folder.path);
|
|
2987
2993
|
}
|
|
@@ -3007,18 +3013,24 @@ export class ImapManager extends EventEmitter {
|
|
|
3007
3013
|
// authoritative deletion path with a 30-min
|
|
3008
3014
|
// grace window; prefetch defers to it.
|
|
3009
3015
|
const someReceived = received.size > 0;
|
|
3010
|
-
if (batchSucceeded && someReceived)
|
|
3016
|
+
if (batchSucceeded && someReceived) {
|
|
3017
|
+
// DO NOT DELETE missing UIDs. A partial response is
|
|
3018
|
+
// an iflow parser miss / mid-stream hiccup MUCH more
|
|
3019
|
+
// often than a real server expunge — and deleting on
|
|
3020
|
+
// that signal cost Bob a Bambu Labs verification
|
|
3021
|
+
// code (audit id 3785, 2026-05-20), plus dozens of
|
|
3022
|
+
// other valid messages over the day. Set-diff
|
|
3023
|
+
// reconcile in syncFolder is the authoritative
|
|
3024
|
+
// deletion path with a 30-min grace window; prefetch
|
|
3025
|
+
// defers to it. Mark the UIDs as prefetch-empty so
|
|
3026
|
+
// the TTL backoff (5min → 12h) retries them — that
|
|
3027
|
+
// path is non-destructive.
|
|
3011
3028
|
for (const uid of chunk) {
|
|
3012
3029
|
if (received.has(uid))
|
|
3013
3030
|
continue;
|
|
3014
|
-
|
|
3015
|
-
this.unlinkBodyFile(accountId, uid, folderId).catch(() => { });
|
|
3016
|
-
this.db.deleteMessage(accountId, uid, "prefetch batch: server didn't return body for queued UID — assumed deleted", "mailx-imap prefetchBodies (IMAP batch)");
|
|
3017
|
-
counters.deleted++;
|
|
3018
|
-
madeProgress = true;
|
|
3019
|
-
}
|
|
3020
|
-
catch { /* ignore */ }
|
|
3031
|
+
this.markPrefetchEmpty(accountId, folderId, uid);
|
|
3021
3032
|
}
|
|
3033
|
+
}
|
|
3022
3034
|
else if (batchSucceeded && !someReceived) {
|
|
3023
3035
|
console.error(` [prefetch] ${accountId}/${folder.path}: chunk ${chunkStart}-${chunkStart + chunk.length - 1} returned 0/${chunk.length} bodies — NOT pruning (set-diff reconcile owns deletion). UIDs: ${chunk.slice(0, 5).join(",")}${chunk.length > 5 ? "..." : ""}`);
|
|
3024
3036
|
for (const uid of chunk)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/mailx-imap",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.55",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@bobfrankston/mailx-types": "^0.1.18",
|
|
13
|
-
"@bobfrankston/mailx-settings": "^0.1.
|
|
14
|
-
"@bobfrankston/mailx-store": "^0.1.
|
|
13
|
+
"@bobfrankston/mailx-settings": "^0.1.22",
|
|
14
|
+
"@bobfrankston/mailx-store": "^0.1.32",
|
|
15
15
|
"@bobfrankston/iflow-direct": "^0.1.50",
|
|
16
16
|
"@bobfrankston/tcp-transport": "^0.1.6",
|
|
17
17
|
"@bobfrankston/smtp-direct": "^0.1.8",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
".transformedSnapshot": {
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@bobfrankston/mailx-types": "^0.1.18",
|
|
41
|
-
"@bobfrankston/mailx-settings": "^0.1.
|
|
42
|
-
"@bobfrankston/mailx-store": "^0.1.
|
|
41
|
+
"@bobfrankston/mailx-settings": "^0.1.22",
|
|
42
|
+
"@bobfrankston/mailx-store": "^0.1.32",
|
|
43
43
|
"@bobfrankston/iflow-direct": "^0.1.50",
|
|
44
44
|
"@bobfrankston/tcp-transport": "^0.1.6",
|
|
45
45
|
"@bobfrankston/smtp-direct": "^0.1.8",
|