@bobfrankston/mailx-imap 0.1.116 → 0.1.118
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 +24 -4
- package/package.json +3 -3
package/index.js
CHANGED
|
@@ -2216,10 +2216,17 @@ export class ImapManager extends EventEmitter {
|
|
|
2216
2216
|
// to dest), the (acc, folder, uid) lookup at fire time
|
|
2217
2217
|
// won't match — skip. If still at original (truly gone
|
|
2218
2218
|
// from server, not just moved), commit the delete.
|
|
2219
|
+
// Drafts/Sent never receive server-side Sieve moves — the long
|
|
2220
|
+
// grace only helps INBOX-class folders rebind moves. Worse, the
|
|
2221
|
+
// 30-min timer dies on every daemon restart and re-detection
|
|
2222
|
+
// restarts the clock, so on a restart-heavy day a sent-and-
|
|
2223
|
+
// deleted draft's local orphan NEVER got reaped (Bob 2026-07-13
|
|
2224
|
+
// "still getting sent messages left in drafts"). Short grace there.
|
|
2225
|
+
const quickReap = folder.specialUse === "drafts" || folder.specialUse === "sent" || folder.specialUse === "outbox";
|
|
2219
2226
|
for (const uid of toDelete) {
|
|
2220
|
-
this.scheduleDeferredReconcileDelete(accountId, folderId, uid, folder.path);
|
|
2227
|
+
this.scheduleDeferredReconcileDelete(accountId, folderId, uid, folder.path, quickReap ? 60_000 : undefined);
|
|
2221
2228
|
}
|
|
2222
|
-
console.log(` [reconcile-defer] ${accountId}/${folder.path}: scheduled ${toDelete.length} deletes (${ImapManager.RECONCILE_DELETE_GRACE_MS / 60_000}min grace
|
|
2229
|
+
console.log(` [reconcile-defer] ${accountId}/${folder.path}: scheduled ${toDelete.length} deletes (${quickReap ? "60s" : `${ImapManager.RECONCILE_DELETE_GRACE_MS / 60_000}min`} grace)`);
|
|
2223
2230
|
}
|
|
2224
2231
|
}
|
|
2225
2232
|
catch (e) {
|
|
@@ -3303,7 +3310,7 @@ export class ImapManager extends EventEmitter {
|
|
|
3303
3310
|
* in production — the grace expired and rows were committed-deleted
|
|
3304
3311
|
* before _Spam / Sent / archive folders had a chance to rebind. */
|
|
3305
3312
|
static RECONCILE_DELETE_GRACE_MS = 30 * 60_000;
|
|
3306
|
-
scheduleDeferredReconcileDelete(accountId, folderId, uid, folderPath) {
|
|
3313
|
+
scheduleDeferredReconcileDelete(accountId, folderId, uid, folderPath, graceMs) {
|
|
3307
3314
|
const key = `${accountId}:${folderId}:${uid}`;
|
|
3308
3315
|
// If already pending, don't reset — the grace clock runs from the
|
|
3309
3316
|
// FIRST detection so a flapping server can't keep deferring.
|
|
@@ -3341,7 +3348,7 @@ export class ImapManager extends EventEmitter {
|
|
|
3341
3348
|
}
|
|
3342
3349
|
this.db.recalcFolderCounts(folderId);
|
|
3343
3350
|
this.emit("folderCountsChanged", accountId, {});
|
|
3344
|
-
}, ImapManager.RECONCILE_DELETE_GRACE_MS);
|
|
3351
|
+
}, graceMs ?? ImapManager.RECONCILE_DELETE_GRACE_MS);
|
|
3345
3352
|
this.deferredDeletes.set(key, t);
|
|
3346
3353
|
}
|
|
3347
3354
|
/** Delete local rows whose uid >= the server's UIDNEXT for this folder.
|
|
@@ -4501,9 +4508,11 @@ export class ImapManager extends EventEmitter {
|
|
|
4501
4508
|
// seem to still leave it in draft so I don't know if it has been
|
|
4502
4509
|
// sent or not. Once you hand it off it must leave draft."
|
|
4503
4510
|
let localDeletedUid = 0;
|
|
4511
|
+
let localDeletedUuid;
|
|
4504
4512
|
if (draftUid) {
|
|
4505
4513
|
const existing = this.db.getMessageByUid(accountId, draftUid, drafts.id);
|
|
4506
4514
|
if (existing) {
|
|
4515
|
+
localDeletedUuid = existing.uuid;
|
|
4507
4516
|
this.unlinkBodyFile(accountId, draftUid, drafts.id).catch(() => { });
|
|
4508
4517
|
this.db.deleteMessage(accountId, drafts.id, draftUid, "user sent the message (draft cleanup)", "mailx-imap deleteDraft (local)");
|
|
4509
4518
|
localDeletedUid = draftUid;
|
|
@@ -4520,6 +4529,17 @@ export class ImapManager extends EventEmitter {
|
|
|
4520
4529
|
if (localDeletedUid > 0) {
|
|
4521
4530
|
this.db.recalcFolderCounts(drafts.id);
|
|
4522
4531
|
this.emit("folderCountsChanged", accountId, {});
|
|
4532
|
+
// messageRemoved drives the list's remove-stale flow AND the
|
|
4533
|
+
// viewer clear. Without it, discarding a draft that was open in
|
|
4534
|
+
// the preview pane left it displayed after the row vanished
|
|
4535
|
+
// (Bob 2026-07-18: "I discarded a message but it is still
|
|
4536
|
+
// showing in preview"). Same shape the reconciler publishes on
|
|
4537
|
+
// server-side EXPUNGE.
|
|
4538
|
+
storeBus.publish({
|
|
4539
|
+
topic: localDeletedUuid ? `message:${localDeletedUuid}` : `folder:${drafts.id}`,
|
|
4540
|
+
kind: "messageRemoved",
|
|
4541
|
+
accountId, folderId: drafts.id, uid: localDeletedUid, msgUuid: localDeletedUuid,
|
|
4542
|
+
});
|
|
4523
4543
|
}
|
|
4524
4544
|
let succeeded = false;
|
|
4525
4545
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/mailx-imap",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.118",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"@bobfrankston/mailx-types": "^0.1.24",
|
|
13
13
|
"@bobfrankston/mailx-settings": "^0.1.35",
|
|
14
14
|
"@bobfrankston/mailx-store": "^0.1.58",
|
|
15
|
-
"@bobfrankston/iflow-direct": "^0.1.
|
|
15
|
+
"@bobfrankston/iflow-direct": "^0.1.59",
|
|
16
16
|
"@bobfrankston/tcp-transport": "^0.1.8",
|
|
17
17
|
"@bobfrankston/smtp-direct": "^0.1.9",
|
|
18
18
|
"@bobfrankston/mailx-sync": "^0.1.27",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@bobfrankston/mailx-types": "^0.1.24",
|
|
41
41
|
"@bobfrankston/mailx-settings": "^0.1.35",
|
|
42
42
|
"@bobfrankston/mailx-store": "^0.1.58",
|
|
43
|
-
"@bobfrankston/iflow-direct": "^0.1.
|
|
43
|
+
"@bobfrankston/iflow-direct": "^0.1.59",
|
|
44
44
|
"@bobfrankston/tcp-transport": "^0.1.8",
|
|
45
45
|
"@bobfrankston/smtp-direct": "^0.1.9",
|
|
46
46
|
"@bobfrankston/mailx-sync": "^0.1.27",
|