@bobfrankston/rmfmail 1.2.205 → 1.2.206
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/bin/mailx.js +15 -0
- package/bin/mailx.js.map +1 -1
- package/bin/mailx.ts +15 -0
- package/package.json +5 -5
- package/packages/mailx-host/package.json +1 -1
- package/packages/mailx-imap/index.d.ts.map +1 -1
- package/packages/mailx-imap/index.js +29 -1
- package/packages/mailx-imap/index.js.map +1 -1
- package/packages/mailx-imap/index.ts +26 -1
- package/packages/mailx-imap/package-lock.json +2 -2
- package/packages/mailx-imap/package.json +1 -1
- /package/packages/mailx-imap/{node_modules.npmglobalize-stash-37404 → node_modules.npmglobalize-stash-1560}/.package-lock.json +0 -0
|
@@ -2710,7 +2710,32 @@ export class ImapManager extends EventEmitter {
|
|
|
2710
2710
|
} else {
|
|
2711
2711
|
const toDelete = localUids.filter(uid => !serverUids.has(uid));
|
|
2712
2712
|
const RECONCILE_DELETE_THRESHOLD = 0.5; // refuse to delete >50% in one pass
|
|
2713
|
-
|
|
2713
|
+
const overThreshold = localUids.length > 0 && toDelete.length / localUids.length > RECONCILE_DELETE_THRESHOLD;
|
|
2714
|
+
// Over-threshold self-heal. The IMAP path has had an
|
|
2715
|
+
// "authoritative listing" carve-out since 2026-05-12; this
|
|
2716
|
+
// Gmail path never did, so stale local rows a server-side
|
|
2717
|
+
// delete left behind were refused FOREVER — 11 ghost gmail
|
|
2718
|
+
// drafts re-refused every cycle (Bob 2026-07-30), 105/106 on
|
|
2719
|
+
// Eleanor's machine (v1.2.188 notes). A non-truncated listing
|
|
2720
|
+
// already is the server's full truth; for a bounded candidate
|
|
2721
|
+
// set, DOUBLE-CONFIRM with a second independent listing — two
|
|
2722
|
+
// complete listings agreeing on absence is positive evidence,
|
|
2723
|
+
// not a transient. Beyond the cap keep refusing (rebuild is
|
|
2724
|
+
// the escape hatch for corruption-scale divergence).
|
|
2725
|
+
let confirmed = !overThreshold;
|
|
2726
|
+
if (overThreshold && toDelete.length <= 200 && !(serverUidsArr as any)._truncated) {
|
|
2727
|
+
try {
|
|
2728
|
+
const second = await api.getUids(folder.path);
|
|
2729
|
+
const secondSet = new Set(second);
|
|
2730
|
+
confirmed = !(second as any)._truncated
|
|
2731
|
+
&& second.length === serverUidsArr.length
|
|
2732
|
+
&& toDelete.every(uid => !secondSet.has(uid));
|
|
2733
|
+
if (confirmed) {
|
|
2734
|
+
console.log(` [api] ${accountId}/${folder.path}: over-threshold reconcile DOUBLE-CONFIRMED (${toDelete.length}/${localUids.length} absent in two independent listings) — deleting`);
|
|
2735
|
+
}
|
|
2736
|
+
} catch { confirmed = false; }
|
|
2737
|
+
}
|
|
2738
|
+
if (!confirmed) {
|
|
2714
2739
|
console.log(` [api] ${accountId}/${folder.path}: reconcile refused — would delete ${toDelete.length}/${localUids.length} (${Math.round(toDelete.length / localUids.length * 100)}%) — probably a sync bug, skipping`);
|
|
2715
2740
|
} else {
|
|
2716
2741
|
for (const uid of toDelete) {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/mailx-imap",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.139",
|
|
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.139",
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@bobfrankston/iflow-direct": "^0.1.27",
|