@bobfrankston/rmfmail 1.2.133 → 1.2.136
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/client/compose/compose.bundle.js +27 -0
- package/client/compose/compose.bundle.js.map +2 -2
- package/client/compose/compose.js +42 -1
- package/client/compose/compose.js.map +1 -1
- package/client/compose/compose.ts +31 -0
- package/package.json +3 -3
- package/packages/mailx-imap/index.d.ts.map +1 -1
- package/packages/mailx-imap/index.js +11 -4
- package/packages/mailx-imap/index.js.map +1 -1
- package/packages/mailx-imap/index.ts +11 -4
- package/packages/mailx-imap/package-lock.json +2 -2
- package/packages/mailx-imap/package.json +1 -1
- package/packages/mailx-service/sync-queue.d.ts.map +1 -1
- package/packages/mailx-service/sync-queue.js +11 -0
- package/packages/mailx-service/sync-queue.js.map +1 -1
- package/packages/mailx-service/sync-queue.ts +17 -0
|
@@ -2230,10 +2230,17 @@ export class ImapManager extends EventEmitter {
|
|
|
2230
2230
|
// to dest), the (acc, folder, uid) lookup at fire time
|
|
2231
2231
|
// won't match — skip. If still at original (truly gone
|
|
2232
2232
|
// from server, not just moved), commit the delete.
|
|
2233
|
+
// Drafts/Sent never receive server-side Sieve moves — the long
|
|
2234
|
+
// grace only helps INBOX-class folders rebind moves. Worse, the
|
|
2235
|
+
// 30-min timer dies on every daemon restart and re-detection
|
|
2236
|
+
// restarts the clock, so on a restart-heavy day a sent-and-
|
|
2237
|
+
// deleted draft's local orphan NEVER got reaped (Bob 2026-07-13
|
|
2238
|
+
// "still getting sent messages left in drafts"). Short grace there.
|
|
2239
|
+
const quickReap = folder.specialUse === "drafts" || folder.specialUse === "sent" || (folder.specialUse as string) === "outbox";
|
|
2233
2240
|
for (const uid of toDelete) {
|
|
2234
|
-
this.scheduleDeferredReconcileDelete(accountId, folderId, uid, folder.path);
|
|
2241
|
+
this.scheduleDeferredReconcileDelete(accountId, folderId, uid, folder.path, quickReap ? 60_000 : undefined);
|
|
2235
2242
|
}
|
|
2236
|
-
console.log(` [reconcile-defer] ${accountId}/${folder.path}: scheduled ${toDelete.length} deletes (${ImapManager.RECONCILE_DELETE_GRACE_MS / 60_000}min grace
|
|
2243
|
+
console.log(` [reconcile-defer] ${accountId}/${folder.path}: scheduled ${toDelete.length} deletes (${quickReap ? "60s" : `${ImapManager.RECONCILE_DELETE_GRACE_MS / 60_000}min`} grace)`);
|
|
2237
2244
|
}
|
|
2238
2245
|
} catch (e: any) {
|
|
2239
2246
|
console.error(` deletion sync error: ${e.message}`);
|
|
@@ -3302,7 +3309,7 @@ export class ImapManager extends EventEmitter {
|
|
|
3302
3309
|
* before _Spam / Sent / archive folders had a chance to rebind. */
|
|
3303
3310
|
private static readonly RECONCILE_DELETE_GRACE_MS = 30 * 60_000;
|
|
3304
3311
|
|
|
3305
|
-
private scheduleDeferredReconcileDelete(accountId: string, folderId: number, uid: number, folderPath: string): void {
|
|
3312
|
+
private scheduleDeferredReconcileDelete(accountId: string, folderId: number, uid: number, folderPath: string, graceMs?: number): void {
|
|
3306
3313
|
const key = `${accountId}:${folderId}:${uid}`;
|
|
3307
3314
|
// If already pending, don't reset — the grace clock runs from the
|
|
3308
3315
|
// FIRST detection so a flapping server can't keep deferring.
|
|
@@ -3339,7 +3346,7 @@ export class ImapManager extends EventEmitter {
|
|
|
3339
3346
|
}
|
|
3340
3347
|
this.db.recalcFolderCounts(folderId);
|
|
3341
3348
|
this.emit("folderCountsChanged", accountId, {});
|
|
3342
|
-
}, ImapManager.RECONCILE_DELETE_GRACE_MS);
|
|
3349
|
+
}, graceMs ?? ImapManager.RECONCILE_DELETE_GRACE_MS);
|
|
3343
3350
|
this.deferredDeletes.set(key, t);
|
|
3344
3351
|
}
|
|
3345
3352
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/mailx-imap",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.117",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bobfrankston/mailx-imap",
|
|
9
|
-
"version": "0.1.
|
|
9
|
+
"version": "0.1.117",
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@bobfrankston/iflow-direct": "^0.1.27",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-queue.d.ts","sourceRoot":"","sources":["sync-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,MAAM,MAAM,IAAI,GAAG,aAAa,GAAG,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC;AAEpE;;;sDAGsD;AACtD,UAAU,YAAY;IAAG,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE;AAEzG,qBAAa,SAAS;
|
|
1
|
+
{"version":3,"file":"sync-queue.d.ts","sourceRoot":"","sources":["sync-queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -140,6 +140,13 @@ export class SyncQueue {
|
|
|
140
140
|
.then((uid) => {
|
|
141
141
|
if (typeof uid === "number" && uid > 0)
|
|
142
142
|
slot.lastUid = uid;
|
|
143
|
+
if (slot.cancelled && typeof uid === "number" && uid > 0) {
|
|
144
|
+
// Send/discard happened while this push was in flight —
|
|
145
|
+
// reap the copy we just created (server + local row).
|
|
146
|
+
console.log(` [sync-queue] draft push landed after send/discard — deleting own append uid=${uid} (${draftId})`);
|
|
147
|
+
this.imapManager.deleteDraft(accountId, uid, draftId)
|
|
148
|
+
.catch((e) => console.error(` [sync-queue] post-cancel draft reap failed: ${e?.message || e}`));
|
|
149
|
+
}
|
|
143
150
|
})
|
|
144
151
|
.catch((e) => {
|
|
145
152
|
console.error(` [sync-queue] draft push deferred (${draftId}): ${e?.message || e}`);
|
|
@@ -167,6 +174,10 @@ export class SyncQueue {
|
|
|
167
174
|
const slot = this.draftPushes.get(`${accountId}:${draftId || ""}`);
|
|
168
175
|
if (slot?.throttleTimer)
|
|
169
176
|
clearTimeout(slot.throttleTimer);
|
|
177
|
+
if (slot) {
|
|
178
|
+
slot.pending = null; // a held checkpoint must never push post-send
|
|
179
|
+
slot.cancelled = true; // an in-flight push reaps its own append
|
|
180
|
+
}
|
|
170
181
|
this.draftPushes.delete(`${accountId}:${draftId || ""}`);
|
|
171
182
|
}
|
|
172
183
|
/** The AUTHORITATIVE UID of the draft's current local/server row. The
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-queue.js","sourceRoot":"","sources":["sync-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAaH,MAAM,OAAO,SAAS;
|
|
1
|
+
{"version":3,"file":"sync-queue.js","sourceRoot":"","sources":["sync-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAaH,MAAM,OAAO,SAAS;IA8CN;IACA;IA9CJ,WAAW,GAAG,IAAI,GAAG,EAAwB,CAAC;IACtD;;;;;;uEAMmE;IAC3D,WAAW,GAAG,IAAI,GAAG,EA0BzB,CAAC;IACG,MAAM,CAAU,0BAA0B,GAAG,MAAM,CAAC;IAC5D;;;;uEAImE;IAC3D,WAAW,GAAG,IAAI,GAAG,EAAyC,CAAC;IAC/D,MAAM,CAAU,iBAAiB,GAAG,IAAI,CAAC;IAEjD,YACY,EAAW,EACX,WAAwB;QADxB,OAAE,GAAF,EAAE,CAAS;QACX,gBAAW,GAAX,WAAW,CAAa;IACjC,CAAC;IAEI,aAAa,CAAC,SAAiB;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,QAAQ;YAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,GAAG,EAAE;YAC5C,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACnC,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAA+B,CAAC,CAAC,CAAC;QAChG,CAAC,EAAE,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACrC,CAAC;IAED,4EAA4E;IAE5E;6EACyE;IACzE,WAAW,CAAC,SAAiB,EAAE,GAAW,EAAE,YAAoB,EAAE,UAAkB;QAChF,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,cAAc,EAAE,UAAU,EAAE,CAAC,CAAC;QAC9F,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IAED,0EAA0E;IAC1E,WAAW,CAAC,SAAiB,EAAE,GAAW,EAAE,QAAgB,EAAE,KAAe;QACzE,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACtE,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IAED;;;yEAGqE;IACrE,WAAW,CAAC,SAAiB,EAAE,GAAW,EAAE,YAAoB,EAAE,UAAkB;QAChF,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,cAAc,EAAE,UAAU,EAAE,CAAC,CAAC;QAC9F,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IAED,kEAAkE;IAClE,aAAa,CAAC,SAAiB,EAAE,GAAW,EAAE,QAAgB,EAAE,OAA2B,QAAQ;QAC/F,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC5D,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IAED;;;;;;wDAMoD;IACpD,iBAAiB,CAAC,SAAiB,EAAE,GAAW,EAAE,YAAoB,EAAE,cAAsB;QAC1F,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC;QACpG,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAC3B,IAAI,CAAC,EAAE,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACvC,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;;;;6DAKyD;IACzD,gBAAgB,CAAC,SAAiB,EAAE,UAAkB,EAAE,gBAAyB,EAAE,OAAgB;QAC/F,MAAM,GAAG,GAAG,GAAG,SAAS,IAAI,OAAO,IAAI,EAAE,EAAE,CAAC;QAC5C,IAAI,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,EAAE,CAAC;YAAC,IAAI,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAAC,CAAC;QAC1F,yEAAyE;QACzE,gEAAgE;QAChE,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,IAAI,gBAAgB;YAAE,IAAI,CAAC,OAAO,GAAG,gBAAgB,CAAC;QAC9E,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,kEAAkE;YAClE,mEAAmE;YACnE,IAAI,CAAC,OAAO,GAAG,EAAE,UAAU,EAAE,CAAC;YAC9B,OAAO;QACX,CAAC;QACD,wDAAwD;QACxD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC;QACtD,IAAI,IAAI,CAAC,UAAU,IAAI,SAAS,GAAG,SAAS,CAAC,0BAA0B,EAAE,CAAC;YACtE,IAAI,CAAC,OAAO,GAAG,EAAE,UAAU,EAAE,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;gBACtB,IAAI,CAAC,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE;oBACjC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;oBAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC;oBAC1B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;oBACpB,IAAI,IAAI;wBAAE,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;gBACpF,CAAC,EAAE,SAAS,CAAC,0BAA0B,GAAG,SAAS,CAAC,CAAC;YACzD,CAAC;YACD,OAAO;QACX,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,MAAM,GAAG,GAAG,CAAC,GAAW,EAAQ,EAAE;YAC9B,sEAAsE;YACtE,mEAAmE;YACnE,uEAAuE;YACvE,wDAAwD;YACxD,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,SAAS,EAAE,GAAG,EAAE,IAAK,CAAC,OAAO,EAAE,OAAO,CAAC;iBAC7D,IAAI,CAAC,CAAC,GAAkB,EAAE,EAAE;gBACzB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,GAAG,CAAC;oBAAE,IAAK,CAAC,OAAO,GAAG,GAAG,CAAC;gBAC5D,IAAI,IAAK,CAAC,SAAS,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;oBACxD,wDAAwD;oBACxD,sDAAsD;oBACtD,OAAO,CAAC,GAAG,CAAC,iFAAiF,GAAG,KAAK,OAAO,GAAG,CAAC,CAAC;oBACjH,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC;yBAChD,KAAK,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,iDAAiD,CAAC,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC9G,CAAC;YACL,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,CAAM,EAAE,EAAE;gBACd,OAAO,CAAC,KAAK,CAAC,uCAAuC,OAAO,MAAM,CAAC,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC,CAAC;gBACrF,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;YACvG,CAAC,CAAC;iBACD,OAAO,CAAC,GAAG,EAAE;gBACV,MAAM,IAAI,GAAG,IAAK,CAAC,OAAO,CAAC;gBAC3B,IAAK,CAAC,OAAO,GAAG,IAAI,CAAC;gBACrB,IAAI,IAAI,EAAE,CAAC;oBACP,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAG,2BAA2B;gBACvD,CAAC;qBAAM,CAAC;oBACJ,qDAAqD;oBACrD,sDAAsD;oBACtD,wDAAwD;oBACxD,IAAK,CAAC,QAAQ,GAAG,KAAK,CAAC;gBAC3B,CAAC;YACL,CAAC,CAAC,CAAC;QACX,CAAC,CAAC;QACF,GAAG,CAAC,UAAU,CAAC,CAAC;IACpB,CAAC;IAED;6EACyE;IACzE,WAAW,CAAC,SAAiB,EAAE,OAAgB;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,SAAS,IAAI,OAAO,IAAI,EAAE,EAAE,CAAC,CAAC;QACnE,IAAI,IAAI,EAAE,aAAa;YAAE,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC1D,IAAI,IAAI,EAAE,CAAC;YACP,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,CAAU,8CAA8C;YAC5E,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,CAAQ,yCAAyC;QAC3E,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,SAAS,IAAI,OAAO,IAAI,EAAE,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED;;;;;;oBAMgB;IAChB,eAAe,CAAC,SAAiB,EAAE,OAAgB;QAC/C,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,SAAS,IAAI,OAAO,IAAI,EAAE,EAAE,CAAC,EAAE,OAAO,IAAI,SAAS,CAAC;IACvF,CAAC;IAED;;2DAEuD;IACvD,WAAW,CAAC,UAAkB,EAAE,SAAiB;QAC7C,mEAAmE;IACvE,CAAC;IAED,gDAAgD;IAEhD;;;4DAGwD;IACxD,gBAAgB,CAAC,SAAiB,EAAE,QAAgB,EAAE,GAAW,EAAE,OAAa,aAAa;QACzF,wEAAwE;QACxE,uEAAuE;QACvE,kEAAkE;QAClE,oEAAoE;QACpE,kEAAkE;QAClE,qEAAqE;QACrE,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;YAC5C,OAAO,CAAC,KAAK,CAAC,iDAAiD,GAAG,QAAQ,SAAS,UAAU,QAAQ,EAAE,EAAE,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,KAAK,CAAC,CAAC;YAC/I,OAAO;QACX,CAAC;QACD,MAAM,GAAG,GAAG,GAAG,SAAS,IAAI,QAAQ,IAAI,GAAG,EAAE,CAAC;QAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,QAAQ,EAAE,CAAC;YACX,iDAAiD;YACjD,MAAM,IAAI,GAAyB,EAAE,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;YACzF,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC;YAC3D,OAAO;QACX,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/E,CAAC;IAED;;;qEAGiE;IACjE,gBAAgB,CAAC,GAAiB,EAAE,WAAW,GAAG,CAAC;QAC/C,IAAI,GAAG,CAAC,QAAQ,GAAG,CAAC,IAAI,WAAW;YAAE,OAAO,KAAK,CAAC;QAClD,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC;QACxD,uEAAuE;QACvE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,GAAG,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;2EACuE;IACvE,aAAa,CAAC,UAAgB,UAAU;QACpC,MAAM,IAAI,GAAyB,EAAE,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QACzF,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1B,IAAI,IAAI,GAAwB,IAAI,CAAC;QACrC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC;YACxC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG;gBAAE,SAAS;YACjC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,IAAI,GAAG,CAAC,CAAC;QAC1D,CAAC;QACD,IAAI,IAAI;YAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QACpF,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,4DAA4D;IAC5D,YAAY;QACR,OAAO;YACH,cAAc,EAAE,IAAI,CAAC,EAAE,CAAC,wBAAwB,EAAE;YAClD,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;SACrC,CAAC;IACN,CAAC"}
|
|
@@ -60,6 +60,12 @@ export class SyncQueue {
|
|
|
60
60
|
* server mirror is throttled. */
|
|
61
61
|
lastPushAt?: number;
|
|
62
62
|
throttleTimer?: ReturnType<typeof setTimeout> | null;
|
|
63
|
+
/** Set by forgetDraft (send/discard) while a push is IN FLIGHT: the
|
|
64
|
+
* in-flight APPEND will land AFTER the send-time cleanup already
|
|
65
|
+
* ran, resurrecting the draft ("sent but still in drafts"). When
|
|
66
|
+
* cancelled, the push completion deletes its own append instead of
|
|
67
|
+
* keeping it. */
|
|
68
|
+
cancelled?: boolean;
|
|
63
69
|
}>();
|
|
64
70
|
private static readonly DRAFT_PUSH_MIN_INTERVAL_MS = 30_000;
|
|
65
71
|
/** Per-account debounce timers. Multiple rapid enqueues (3 flag toggles,
|
|
@@ -171,6 +177,13 @@ export class SyncQueue {
|
|
|
171
177
|
this.imapManager.saveDraft(accountId, raw, slot!.lastUid, draftId)
|
|
172
178
|
.then((uid: number | null) => {
|
|
173
179
|
if (typeof uid === "number" && uid > 0) slot!.lastUid = uid;
|
|
180
|
+
if (slot!.cancelled && typeof uid === "number" && uid > 0) {
|
|
181
|
+
// Send/discard happened while this push was in flight —
|
|
182
|
+
// reap the copy we just created (server + local row).
|
|
183
|
+
console.log(` [sync-queue] draft push landed after send/discard — deleting own append uid=${uid} (${draftId})`);
|
|
184
|
+
this.imapManager.deleteDraft(accountId, uid, draftId)
|
|
185
|
+
.catch((e: any) => console.error(` [sync-queue] post-cancel draft reap failed: ${e?.message || e}`));
|
|
186
|
+
}
|
|
174
187
|
})
|
|
175
188
|
.catch((e: any) => {
|
|
176
189
|
console.error(` [sync-queue] draft push deferred (${draftId}): ${e?.message || e}`);
|
|
@@ -197,6 +210,10 @@ export class SyncQueue {
|
|
|
197
210
|
forgetDraft(accountId: string, draftId?: string): void {
|
|
198
211
|
const slot = this.draftPushes.get(`${accountId}:${draftId || ""}`);
|
|
199
212
|
if (slot?.throttleTimer) clearTimeout(slot.throttleTimer);
|
|
213
|
+
if (slot) {
|
|
214
|
+
slot.pending = null; // a held checkpoint must never push post-send
|
|
215
|
+
slot.cancelled = true; // an in-flight push reaps its own append
|
|
216
|
+
}
|
|
200
217
|
this.draftPushes.delete(`${accountId}:${draftId || ""}`);
|
|
201
218
|
}
|
|
202
219
|
|