@bobfrankston/rmfmail 1.1.218 → 1.1.220
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/android-bootstrap.bundle.js +8 -3
- package/client/android-bootstrap.bundle.js.map +2 -2
- package/package.json +5 -5
- package/packages/mailx-imap/index.d.ts.map +1 -1
- package/packages/mailx-imap/index.js +33 -14
- package/packages/mailx-imap/index.js.map +1 -1
- package/packages/mailx-imap/index.ts +32 -14
- 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-36044 → node_modules.npmglobalize-stash-86748}/.package-lock.json +0 -0
|
@@ -187,18 +187,29 @@ async function extractPreview(source: string): Promise<{ bodyHtml: string; bodyT
|
|
|
187
187
|
// remaining base64 data: URIs (rare: text/plain copies generated
|
|
188
188
|
// from a Quill compose pasted-image HTML) collapsed to [image] too.
|
|
189
189
|
let raw: string;
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
190
|
+
// PREFER the plain-text rendering for the summary. The HTML→[image]
|
|
191
|
+
// path turns an image-heavy marketing/tracking email into a useless
|
|
192
|
+
// "[image] [image] [image]…" wall — the "[no summary]" Bob hit
|
|
193
|
+
// 2026-06-04. mailparser's `text` is the text/plain alternative when
|
|
194
|
+
// present, otherwise a tags-and-images-stripped rendering of the HTML,
|
|
195
|
+
// i.e. the actual words. Only fall back to HTML when there's no usable
|
|
196
|
+
// text at all (genuinely image-only mail).
|
|
197
|
+
const textCandidate = (bodyText || "").replace(/\s+/g, " ").trim();
|
|
198
|
+
if (textCandidate.length >= 3) {
|
|
199
|
+
raw = bodyText;
|
|
200
|
+
} else if (bodyHtml) {
|
|
201
|
+
// No usable text part. Strip style/script/head + comments (CSS would
|
|
202
|
+
// otherwise leak into the preview — Bob 2026-05-31), then prefer an
|
|
203
|
+
// <img alt="…"> caption over the bare "[image]" token, and collapse
|
|
204
|
+
// runs of placeholders so even this fallback isn't a wall.
|
|
197
205
|
raw = bodyHtml
|
|
198
206
|
.replace(/<!--[\s\S]*?-->/g, " ")
|
|
199
207
|
.replace(/<(style|script|head)\b[^>]*>[\s\S]*?<\/\1>/gi, " ")
|
|
208
|
+
.replace(/<img\b[^>]*\balt\s*=\s*"([^"]+)"[^>]*>/gi, " $1 ")
|
|
209
|
+
.replace(/<img\b[^>]*\balt\s*=\s*'([^']+)'[^>]*>/gi, " $1 ")
|
|
200
210
|
.replace(/<img\b[^>]*>/gi, " [image] ")
|
|
201
|
-
.replace(/<[^>]+>/g, " ")
|
|
211
|
+
.replace(/<[^>]+>/g, " ")
|
|
212
|
+
.replace(/(\[image\]\s*){2,}/g, "[image] ");
|
|
202
213
|
} else {
|
|
203
214
|
raw = bodyText;
|
|
204
215
|
}
|
|
@@ -1323,13 +1334,20 @@ export class ImapManager extends EventEmitter {
|
|
|
1323
1334
|
// from wiping anything we shouldn't.
|
|
1324
1335
|
console.log(` [qresync] ${accountId}/${folder.path}: UIDVALIDITY changed (was ${prevUidValidity}, now ${qr.exists}); falling back to full sync`);
|
|
1325
1336
|
} else if (qr.vanishedUids.length > VANISHED_ABSURD_CAP) {
|
|
1326
|
-
// Refuse the absurd VANISHED set; do NOT iterate/apply it
|
|
1327
|
-
// do NOT return — fall through to the bounded set-diff
|
|
1328
|
-
// reconcile (same as the UIDVALIDITY-changed path). The
|
|
1329
|
-
// modseq watermark is left intact, so a healthy later QRESYNC
|
|
1330
|
-
// can still succeed.
|
|
1337
|
+
// Refuse the absurd VANISHED set; do NOT iterate/apply it.
|
|
1331
1338
|
const localCount = this.db.getMessageCount(accountId, folderId);
|
|
1332
|
-
console.error(` [qresync] ${accountId}/${folder.path}: REFUSING VANISHED of ${qr.vanishedUids.length} UIDs (folder has ${localCount} locally) —
|
|
1339
|
+
console.error(` [qresync] ${accountId}/${folder.path}: REFUSING VANISHED of ${qr.vanishedUids.length} UIDs (folder has ${localCount} locally) — mis-parsed range; self-healing (advance watermark) + falling back to set-diff.`);
|
|
1340
|
+
// SELF-HEAL: advance the modseq watermark to the server's
|
|
1341
|
+
// CURRENT value. Without this the next QRESYNC re-requests the
|
|
1342
|
+
// same giant `(EARLIER) 1:N` range every cycle forever (Bob saw
|
|
1343
|
+
// it recur 21:03 → 21:20) — refusing without advancing isn't
|
|
1344
|
+
// self-healing. The set-diff reconcile below discovers + applies
|
|
1345
|
+
// the ACTUAL deletions via Message-ID identity (bounded, 50%
|
|
1346
|
+
// guard), so skipping the literal VANISHED loses nothing; it
|
|
1347
|
+
// just breaks the stale-modseq loop so future QRESYNCs are clean.
|
|
1348
|
+
if (qr.newHighestModSeq !== undefined) {
|
|
1349
|
+
this.db.updateFolderSync(folderId, prevUidValidity, String(qr.newHighestModSeq));
|
|
1350
|
+
}
|
|
1333
1351
|
} else {
|
|
1334
1352
|
// Apply VANISHED — server says these UIDs are gone. No
|
|
1335
1353
|
// tombstone, no diff, just delete the local rows.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/mailx-imap",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.85",
|
|
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.85",
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@bobfrankston/iflow-direct": "^0.1.27",
|