@bobfrankston/mailx 1.0.128 → 1.0.129
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 +15 -0
- package/package.json +1 -1
- package/packages/mailx-imap/index.js +24 -20
package/client/app.js
CHANGED
|
@@ -116,6 +116,19 @@ 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.innerHTML = "";
|
|
127
|
+
if (att) {
|
|
128
|
+
att.innerHTML = "";
|
|
129
|
+
att.hidden = true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
119
132
|
initFolderTree(folderTree, (accountId, folderId, folderName, specialUse) => {
|
|
120
133
|
currentFolderSpecialUse = specialUse;
|
|
121
134
|
currentAccountId = accountId;
|
|
@@ -123,11 +136,13 @@ initFolderTree(folderTree, (accountId, folderId, folderName, specialUse) => {
|
|
|
123
136
|
if (searchInput)
|
|
124
137
|
searchInput.value = "";
|
|
125
138
|
markAsSeen();
|
|
139
|
+
clearViewer();
|
|
126
140
|
loadMessages(accountId, folderId, 1, specialUse);
|
|
127
141
|
setTitle(`mailx - ${folderName}`);
|
|
128
142
|
}, () => {
|
|
129
143
|
// Unified inbox handler
|
|
130
144
|
currentFolderSpecialUse = "inbox";
|
|
145
|
+
clearViewer();
|
|
131
146
|
loadUnifiedInbox();
|
|
132
147
|
setTitle("mailx - All Inboxes");
|
|
133
148
|
});
|
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);
|