@bobfrankston/mailx 1.0.128 → 1.0.130
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/app.js +13 -0
- package/package.json +1 -1
- package/packages/mailx-imap/index.js +24 -20
package/client/app.js
CHANGED
|
@@ -116,6 +116,17 @@ alertDismiss?.addEventListener("click", hideAlert);
|
|
|
116
116
|
// ── Wire up components ──
|
|
117
117
|
const folderTree = document.getElementById("folder-tree");
|
|
118
118
|
let currentFolderSpecialUse = "";
|
|
119
|
+
function clearViewer() {
|
|
120
|
+
const body = document.getElementById("mv-body");
|
|
121
|
+
const header = document.getElementById("mv-header");
|
|
122
|
+
const att = document.getElementById("mv-attachments");
|
|
123
|
+
if (body)
|
|
124
|
+
body.innerHTML = "";
|
|
125
|
+
if (header)
|
|
126
|
+
header.hidden = true;
|
|
127
|
+
if (att)
|
|
128
|
+
att.hidden = true;
|
|
129
|
+
}
|
|
119
130
|
initFolderTree(folderTree, (accountId, folderId, folderName, specialUse) => {
|
|
120
131
|
currentFolderSpecialUse = specialUse;
|
|
121
132
|
currentAccountId = accountId;
|
|
@@ -123,11 +134,13 @@ initFolderTree(folderTree, (accountId, folderId, folderName, specialUse) => {
|
|
|
123
134
|
if (searchInput)
|
|
124
135
|
searchInput.value = "";
|
|
125
136
|
markAsSeen();
|
|
137
|
+
clearViewer();
|
|
126
138
|
loadMessages(accountId, folderId, 1, specialUse);
|
|
127
139
|
setTitle(`mailx - ${folderName}`);
|
|
128
140
|
}, () => {
|
|
129
141
|
// Unified inbox handler
|
|
130
142
|
currentFolderSpecialUse = "inbox";
|
|
143
|
+
clearViewer();
|
|
131
144
|
loadUnifiedInbox();
|
|
132
145
|
setTitle("mailx - All Inboxes");
|
|
133
146
|
});
|
package/package.json
CHANGED
|
@@ -315,29 +315,30 @@ export class ImapManager extends EventEmitter {
|
|
|
315
315
|
let messages;
|
|
316
316
|
const firstSync = highestUid === 0;
|
|
317
317
|
const historyDays = getHistoryDays(accountId);
|
|
318
|
-
|
|
319
|
-
|
|
318
|
+
// For first sync with unlimited history, start with 30 days — backfill extends later
|
|
319
|
+
const effectiveDays = (historyDays === 0 && firstSync) ? 30 : historyDays;
|
|
320
|
+
const startDate = effectiveDays > 0
|
|
321
|
+
? new Date(Date.now() - effectiveDays * 86400000)
|
|
320
322
|
: new Date(0);
|
|
321
323
|
if (highestUid > 0) {
|
|
322
324
|
// Incremental: fetch new messages — metadata only for speed, bodies on demand
|
|
323
325
|
const fetched = await client.fetchMessagesSinceUid(folder.path, highestUid, { source: false });
|
|
324
326
|
// Filter out the last known message (IMAP * always returns at least one)
|
|
325
327
|
messages = fetched.filter(m => m.uid > highestUid);
|
|
326
|
-
// Gap detection:
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
const
|
|
335
|
-
const
|
|
336
|
-
const
|
|
337
|
-
const missingUids =
|
|
338
|
-
if (missingUids.length > 0) {
|
|
339
|
-
console.log(` ${folder.path}:
|
|
340
|
-
// Fetch in chunks to avoid huge commands
|
|
328
|
+
// Gap detection: check for missing UIDs within the range we've already synced
|
|
329
|
+
// Only reconcile between our lowest and highest UID — don't try to fetch the entire folder history
|
|
330
|
+
const existingUids = this.db.getUidsForFolder(accountId, folderId);
|
|
331
|
+
if (existingUids.length > 0) {
|
|
332
|
+
try {
|
|
333
|
+
const lowestUid = Math.min(...existingUids);
|
|
334
|
+
// Fetch UIDs in our known range from IMAP
|
|
335
|
+
const rangeUids = await client.getUids(folder.path);
|
|
336
|
+
const rangeInScope = rangeUids.filter((uid) => uid >= lowestUid && uid <= highestUid);
|
|
337
|
+
const existingSet = new Set(existingUids);
|
|
338
|
+
const newSet = new Set(messages.map(m => m.uid));
|
|
339
|
+
const missingUids = rangeInScope.filter((uid) => !existingSet.has(uid) && !newSet.has(uid));
|
|
340
|
+
if (missingUids.length > 0 && missingUids.length <= 5000) {
|
|
341
|
+
console.log(` ${folder.path}: gap detected — ${missingUids.length} missing UIDs in range ${lowestUid}..${highestUid}`);
|
|
341
342
|
const chunkSize = 500;
|
|
342
343
|
for (let i = 0; i < missingUids.length; i += chunkSize) {
|
|
343
344
|
const chunk = missingUids.slice(i, i + chunkSize);
|
|
@@ -346,10 +347,13 @@ export class ImapManager extends EventEmitter {
|
|
|
346
347
|
messages.push(...recovered);
|
|
347
348
|
}
|
|
348
349
|
}
|
|
350
|
+
else if (missingUids.length > 5000) {
|
|
351
|
+
console.log(` ${folder.path}: ${missingUids.length} missing UIDs — too many, skipping reconciliation (delete DB to force full re-sync)`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
catch (e) {
|
|
355
|
+
console.error(` ${folder.path}: gap detection failed: ${e.message}`);
|
|
349
356
|
}
|
|
350
|
-
}
|
|
351
|
-
catch (e) {
|
|
352
|
-
console.error(` ${folder.path}: gap detection failed: ${e.message}`);
|
|
353
357
|
}
|
|
354
358
|
// Backfill: if historyDays extends further back than our oldest message, fetch the gap
|
|
355
359
|
const oldestDate = this.db.getOldestDate(accountId, folderId);
|