@bobfrankston/mailx-imap 0.1.68 → 0.1.70
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 +27 -1
- package/package.json +3 -3
package/index.js
CHANGED
|
@@ -1049,6 +1049,18 @@ export class ImapManager extends EventEmitter {
|
|
|
1049
1049
|
*
|
|
1050
1050
|
* Fires the same emits as a normal sync so the UI updates. */
|
|
1051
1051
|
async insertLocalRowFromSource(accountId, folder, uid, source, flags) {
|
|
1052
|
+
// Guard against uid <= 0. Valid IMAP UIDs are always ≥ 1; a 0 here
|
|
1053
|
+
// means the APPENDUID capture failed (server returned no UIDPLUS, or
|
|
1054
|
+
// appendMessage resolved to 0 instead of null) and the caller didn't
|
|
1055
|
+
// catch it. Inserting uid=0 created a phantom INBOX row with no
|
|
1056
|
+
// message_id, no body, no subject — the "blank line in the summary"
|
|
1057
|
+
// (Bob 2026-05-28). Refuse it; the caller's syncFolder fallback will
|
|
1058
|
+
// pick the message up with its real UID on the next sync.
|
|
1059
|
+
if (!uid || uid <= 0) {
|
|
1060
|
+
console.error(` [insert] refusing uid=${uid} for ${accountId}/${folder.path} — invalid IMAP UID (APPENDUID likely failed); deferring to sync`);
|
|
1061
|
+
this.syncFolder(accountId, folder.id).catch(() => { });
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1052
1064
|
// insertLocalRowFromSource runs right after sendMessage — that's a
|
|
1053
1065
|
// user-initiated path but the parse cost is on the post-send
|
|
1054
1066
|
// background work, not the click-through. Tag as background so a
|
|
@@ -1250,7 +1262,7 @@ export class ImapManager extends EventEmitter {
|
|
|
1250
1262
|
for (const m of qr.changedMessages) {
|
|
1251
1263
|
try {
|
|
1252
1264
|
const flagsArr = Array.from(m.flags || []).map(f => String(f));
|
|
1253
|
-
this.db.updateMessageFlags(accountId, m.uid, flagsArr);
|
|
1265
|
+
this.db.updateMessageFlags(accountId, folderId, m.uid, flagsArr);
|
|
1254
1266
|
}
|
|
1255
1267
|
catch { /* row may have just been VANISHED */ }
|
|
1256
1268
|
}
|
|
@@ -3467,6 +3479,12 @@ export class ImapManager extends EventEmitter {
|
|
|
3467
3479
|
// Delete previous draft — try UID first (fast path), and ALWAYS also try
|
|
3468
3480
|
// searchByHeader(X-Mailx-Draft-ID) as a safety net. Running both catches
|
|
3469
3481
|
// orphans from a crash-mid-save or a UID delete that failed silently.
|
|
3482
|
+
//
|
|
3483
|
+
// CRITICAL: also delete the LOCAL DB row for the superseded UID. Without
|
|
3484
|
+
// that, every checkpoint save left a stale row behind — IMAP had only
|
|
3485
|
+
// the latest copy but the local Drafts view rendered every past UID as
|
|
3486
|
+
// its own row, producing the "Drafts is flooded with droppings" symptom
|
|
3487
|
+
// (Bob 2026-05-27 — 8+ rows for a single in-progress reply).
|
|
3470
3488
|
if (previousDraftUid) {
|
|
3471
3489
|
try {
|
|
3472
3490
|
await client.deleteMessageByUid(drafts.path, previousDraftUid);
|
|
@@ -3474,6 +3492,10 @@ export class ImapManager extends EventEmitter {
|
|
|
3474
3492
|
catch (e) {
|
|
3475
3493
|
console.error(` [drafts] Delete prev UID ${previousDraftUid} failed: ${e.message}`);
|
|
3476
3494
|
}
|
|
3495
|
+
try {
|
|
3496
|
+
this.db.deleteMessage(accountId, drafts.id, previousDraftUid, "previous draft superseded", "saveDraft");
|
|
3497
|
+
}
|
|
3498
|
+
catch { /* */ }
|
|
3477
3499
|
}
|
|
3478
3500
|
if (draftId) {
|
|
3479
3501
|
try {
|
|
@@ -3483,6 +3505,10 @@ export class ImapManager extends EventEmitter {
|
|
|
3483
3505
|
await client.deleteMessageByUid(drafts.path, uid);
|
|
3484
3506
|
}
|
|
3485
3507
|
catch { /* next */ }
|
|
3508
|
+
try {
|
|
3509
|
+
this.db.deleteMessage(accountId, drafts.id, uid, `draft superseded by newer save (id=${draftId})`, "saveDraft");
|
|
3510
|
+
}
|
|
3511
|
+
catch { /* */ }
|
|
3486
3512
|
}
|
|
3487
3513
|
if (uids.length > 0)
|
|
3488
3514
|
console.log(` [drafts] Deleted ${uids.length} stale draft(s) by ID ${draftId}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/mailx-imap",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.70",
|
|
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.25",
|
|
14
|
-
"@bobfrankston/mailx-store": "^0.1.
|
|
14
|
+
"@bobfrankston/mailx-store": "^0.1.41",
|
|
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.25",
|
|
42
|
-
"@bobfrankston/mailx-store": "^0.1.
|
|
42
|
+
"@bobfrankston/mailx-store": "^0.1.41",
|
|
43
43
|
"@bobfrankston/iflow-direct": "^0.1.51",
|
|
44
44
|
"@bobfrankston/tcp-transport": "^0.1.6",
|
|
45
45
|
"@bobfrankston/smtp-direct": "^0.1.8",
|