@bobfrankston/rmfmail 1.0.548 → 1.0.550
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 +7 -4
- package/client/app.js.map +1 -1
- package/client/app.ts +10 -7
- package/client/compose/compose.js +2 -2
- package/client/compose/compose.js.map +1 -1
- package/client/compose/compose.ts +2 -2
- package/package.json +3 -3
- package/packages/mailx-imap/index.d.ts +9 -1
- package/packages/mailx-imap/index.d.ts.map +1 -1
- package/packages/mailx-imap/index.js +92 -51
- package/packages/mailx-imap/index.js.map +1 -1
- package/packages/mailx-imap/index.ts +83 -55
- package/packages/mailx-imap/package-lock.json +2 -2
- package/packages/mailx-imap/package.json +1 -1
- package/packages/mailx-service/local-store.d.ts.map +1 -1
- package/packages/mailx-service/local-store.js +5 -1
- package/packages/mailx-service/local-store.js.map +1 -1
- package/packages/mailx-service/local-store.ts +5 -1
- package/packages/mailx-service/reconciler.d.ts +28 -0
- package/packages/mailx-service/reconciler.d.ts.map +1 -1
- package/packages/mailx-service/reconciler.js +70 -2
- package/packages/mailx-service/reconciler.js.map +1 -1
- package/packages/mailx-service/reconciler.ts +81 -2
- package/packages/mailx-settings/docs/contacts.md +6 -1
- package/packages/mailx-settings/docs/search.md +99 -0
- package/packages/mailx-settings/package.json +1 -1
- package/packages/mailx-store/file-store.d.ts +6 -0
- package/packages/mailx-store/file-store.d.ts.map +1 -1
- package/packages/mailx-store/file-store.js +8 -0
- package/packages/mailx-store/file-store.js.map +1 -1
- package/packages/mailx-store/file-store.ts +9 -0
- package/packages/mailx-store/package.json +1 -1
|
@@ -1855,51 +1855,35 @@ export class ImapManager extends EventEmitter {
|
|
|
1855
1855
|
}, 30000);
|
|
1856
1856
|
this.syncIntervals.set("actions", actionsInterval);
|
|
1857
1857
|
|
|
1858
|
-
// Body prefetch
|
|
1859
|
-
//
|
|
1860
|
-
//
|
|
1861
|
-
//
|
|
1862
|
-
//
|
|
1863
|
-
//
|
|
1864
|
-
|
|
1865
|
-
//
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
};
|
|
1874
|
-
// Fire once now so the "not downloaded" dots start filling in
|
|
1875
|
-
// immediately on app start, don't make the user wait a minute.
|
|
1876
|
-
setTimeout(kickPrefetch, 2000);
|
|
1877
|
-
const prefetchInterval = setInterval(kickPrefetch, 60000);
|
|
1878
|
-
this.syncIntervals.set("prefetch", prefetchInterval);
|
|
1879
|
-
console.log(` [periodic] body prefetch every 60s (independent of sync)`);
|
|
1880
|
-
}
|
|
1881
|
-
|
|
1882
|
-
// Tombstone prune: age out local-delete records older than 30 days.
|
|
1883
|
-
// Runs hourly — cheap (one indexed DELETE).
|
|
1884
|
-
const TOMBSTONE_RETENTION_DAYS = 30;
|
|
1885
|
-
const pruneTombstones = (): void => {
|
|
1886
|
-
const cutoff = Date.now() - TOMBSTONE_RETENTION_DAYS * 86400_000;
|
|
1887
|
-
const n = this.db.pruneTombstones(cutoff);
|
|
1888
|
-
if (n > 0) console.log(` [tombstones] pruned ${n} older than ${TOMBSTONE_RETENTION_DAYS} days`);
|
|
1889
|
-
};
|
|
1890
|
-
setTimeout(pruneTombstones, 30_000); // first run after startup settles
|
|
1891
|
-
this.syncIntervals.set("tombstone-prune", setInterval(pruneTombstones, 3600_000));
|
|
1892
|
-
|
|
1893
|
-
// Full sync (all folders + IDLE restart) at configured interval
|
|
1894
|
-
const fullInterval = setInterval(async () => {
|
|
1895
|
-
console.log(` [periodic] Full sync at ${new Date().toLocaleTimeString()}`);
|
|
1896
|
-
await this.syncAll();
|
|
1897
|
-
await this.stopWatching();
|
|
1898
|
-
await this.startWatching();
|
|
1858
|
+
// Body prefetch + tombstone prune moved to Reconciler.start —
|
|
1859
|
+
// prefetch needs back-pressure from the body-fetch lane, and
|
|
1860
|
+
// tombstone prune is pure DB bookkeeping with no IMAP coupling.
|
|
1861
|
+
// Quick STATUS check (above) and actions/outbox drain (above)
|
|
1862
|
+
// stay here because they're tightly tied to IMAP connection state
|
|
1863
|
+
// and the `syncing` flag.
|
|
1864
|
+
|
|
1865
|
+
// Full sync (all folders + IDLE restart) at configured interval.
|
|
1866
|
+
// Stays here because callers pass `intervalMinutes` directly —
|
|
1867
|
+
// moving it would mean threading the value through MailxService
|
|
1868
|
+
// → Reconciler with a separate setter, for no behavior gain.
|
|
1869
|
+
const fullInterval = setInterval(() => {
|
|
1870
|
+
this.runFullSync().catch(e =>
|
|
1871
|
+
console.error(` [periodic] full sync error: ${e?.message || e}`)
|
|
1872
|
+
);
|
|
1899
1873
|
}, intervalMinutes * 60000);
|
|
1900
1874
|
this.syncIntervals.set("all", fullInterval);
|
|
1901
1875
|
}
|
|
1902
1876
|
|
|
1877
|
+
/** One-shot full sync + IDLE restart. Public so callers (Reconciler,
|
|
1878
|
+
* user-initiated "Sync now") can fire it on demand. The original body
|
|
1879
|
+
* that lived inline in startPeriodicSync was lifted verbatim. */
|
|
1880
|
+
async runFullSync(): Promise<void> {
|
|
1881
|
+
console.log(` [periodic] Full sync at ${new Date().toLocaleTimeString()}`);
|
|
1882
|
+
await this.syncAll();
|
|
1883
|
+
await this.stopWatching();
|
|
1884
|
+
await this.startWatching();
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1903
1887
|
/** Stop periodic sync */
|
|
1904
1888
|
stopPeriodicSync(): void {
|
|
1905
1889
|
for (const [key, interval] of this.syncIntervals) {
|
|
@@ -1923,19 +1907,56 @@ export class ImapManager extends EventEmitter {
|
|
|
1923
1907
|
// is parked in IDLE, it's unusable for any other command, so
|
|
1924
1908
|
// it can't share the ops queue. Counts against the per-host
|
|
1925
1909
|
// semaphore (one slot for the IDLE socket).
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
}
|
|
1910
|
+
//
|
|
1911
|
+
// We watch INBOX (incoming mail) and Sent + Drafts (outgoing
|
|
1912
|
+
// changes from another client — Thunderbird, phone, web).
|
|
1913
|
+
// Without IDLE on Sent, a message just sent from another
|
|
1914
|
+
// device would only show in mailx after the next periodic
|
|
1915
|
+
// full sync.
|
|
1916
|
+
const stops: Array<() => Promise<void>> = [];
|
|
1917
|
+
const clients: Array<{ logout(): Promise<void> }> = [];
|
|
1918
|
+
|
|
1919
|
+
const watchOne = async (mailboxLabel: "inbox" | "sent" | "drafts", path: string): Promise<void> => {
|
|
1920
|
+
const client = await this.createClient(accountId, "idle");
|
|
1921
|
+
clients.push(client);
|
|
1922
|
+
const stop = await client.watchMailbox(path, (newCount: number) => {
|
|
1923
|
+
console.log(` [idle] ${accountId} ${path}: ${newCount} new message(s)`);
|
|
1924
|
+
if (mailboxLabel === "inbox") {
|
|
1925
|
+
// Fast path: incremental fetch of NEW UIDs only.
|
|
1926
|
+
// Heavy reconcile runs on the 5-minute STATUS poll.
|
|
1927
|
+
this.syncInboxNewOnly(accountId).catch(e =>
|
|
1928
|
+
console.error(` [idle] inbox sync error: ${e.message}`));
|
|
1929
|
+
} else {
|
|
1930
|
+
// Sent / Drafts changed elsewhere. Use the
|
|
1931
|
+
// standard folder sync — picks up the new UID,
|
|
1932
|
+
// rebinds any optimistic local row by Message-ID.
|
|
1933
|
+
const folder = this.findFolder(accountId, mailboxLabel);
|
|
1934
|
+
if (folder) {
|
|
1935
|
+
this.syncFolder(accountId, folder.id).catch(e =>
|
|
1936
|
+
console.error(` [idle] ${path} sync error: ${e.message}`));
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
});
|
|
1940
|
+
stops.push(stop);
|
|
1941
|
+
};
|
|
1942
|
+
|
|
1943
|
+
await watchOne("inbox", "INBOX");
|
|
1944
|
+
const sent = this.findFolder(accountId, "sent");
|
|
1945
|
+
if (sent) {
|
|
1946
|
+
try { await watchOne("sent", sent.path); }
|
|
1947
|
+
catch (e: any) { console.error(` [idle] Failed to watch ${sent.path}: ${e.message}`); }
|
|
1948
|
+
}
|
|
1949
|
+
const drafts = this.findFolder(accountId, "drafts");
|
|
1950
|
+
if (drafts) {
|
|
1951
|
+
try { await watchOne("drafts", drafts.path); }
|
|
1952
|
+
catch (e: any) { console.error(` [idle] Failed to watch ${drafts.path}: ${e.message}`); }
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1934
1955
|
this.watchers.set(accountId, async () => {
|
|
1935
|
-
await stop();
|
|
1936
|
-
await
|
|
1956
|
+
for (const stop of stops) { try { await stop(); } catch { /* ignore */ } }
|
|
1957
|
+
for (const c of clients) { try { await c.logout(); } catch { /* ignore */ } }
|
|
1937
1958
|
});
|
|
1938
|
-
console.log(` [idle] Watching INBOX for ${accountId}`);
|
|
1959
|
+
console.log(` [idle] Watching INBOX${sent ? "+Sent" : ""}${drafts ? "+Drafts" : ""} for ${accountId}`);
|
|
1939
1960
|
} catch (e: any) {
|
|
1940
1961
|
console.error(` [idle] Failed to watch ${accountId}: ${e.message}`);
|
|
1941
1962
|
}
|
|
@@ -2097,7 +2118,11 @@ export class ImapManager extends EventEmitter {
|
|
|
2097
2118
|
this.folderErrorCooldown.delete(`${accountId}:${folderPath}`);
|
|
2098
2119
|
}
|
|
2099
2120
|
|
|
2100
|
-
|
|
2121
|
+
/** Background body-cache backfill. Public so the Reconciler can schedule
|
|
2122
|
+
* the periodic tick under its priority/back-pressure rules; existing
|
|
2123
|
+
* in-method post-sync nudges (sync, fetchSince, fetchOne) call this
|
|
2124
|
+
* too and the per-account `prefetchingAccounts` set deduplicates. */
|
|
2125
|
+
async prefetchBodies(accountId: string): Promise<void> {
|
|
2101
2126
|
if (this.prefetchingAccounts.has(accountId)) return;
|
|
2102
2127
|
this.prefetchingAccounts.add(accountId);
|
|
2103
2128
|
try { await this._prefetchBodies(accountId); }
|
|
@@ -2648,9 +2673,12 @@ export class ImapManager extends EventEmitter {
|
|
|
2648
2673
|
bodyPath,
|
|
2649
2674
|
});
|
|
2650
2675
|
// Folder-tree badge refresh + message-list reload if the user
|
|
2651
|
-
// is currently on Sent — same event the sync path emits.
|
|
2676
|
+
// is currently on Sent — same event shape the sync path emits.
|
|
2677
|
+
// (Was sending {accountId,folderId} as a single arg, which the
|
|
2678
|
+
// IPC forwarder + UI handler decoded as garbage — the optimistic
|
|
2679
|
+
// row landed in the DB but never appeared in the list.)
|
|
2652
2680
|
this.db.recalcFolderCounts(sent.id);
|
|
2653
|
-
this.emit("folderCountsChanged",
|
|
2681
|
+
this.emit("folderCountsChanged", accountId, {});
|
|
2654
2682
|
console.log(` [sent-local] wrote optimistic row in Sent (uid=${synthUid}) for ${accountId}: ${envelope.subject}`);
|
|
2655
2683
|
} catch (e: any) {
|
|
2656
2684
|
// Non-fatal — send continues, Sent folder just won't show the
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/mailx-imap",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.24",
|
|
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.24",
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@bobfrankston/iflow-direct": "^0.1.27",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-store.d.ts","sourceRoot":"","sources":["local-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,KAAK,EACR,eAAe,EAAW,YAAY,EAAE,WAAW,EACtD,MAAM,2BAA2B,CAAC;AAuCnC;;;;mEAImE;AACnE,MAAM,WAAW,YAAa,SAAQ,eAAe;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxG,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,uBAAuB,EAAE,OAAO,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;CACtB;AAED,qBAAa,UAAU;IAEf,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,SAAS;gBADT,EAAE,EAAE,OAAO,EACX,SAAS,EAAE,gBAAgB;IAMvC;;;6DAGyD;IACzD,WAAW,IAAI;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE;IAM9E,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,EAAE;IAMpC;;4CAEwC;IACxC,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI;IAK7F,iEAAiE;IACjE,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,WAAW,CAAC,eAAe,CAAC;IAI9D,mEAAmE;IACnE,eAAe,CAAC,IAAI,SAAI,EAAE,QAAQ,SAAK,GAAG,WAAW,CAAC,eAAe,CAAC;IAItE,sEAAsE;IACtE,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,SAAI,EAAE,QAAQ,SAAK,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC,eAAe,CAAC;IAM3H;;;;;;;sEAOkE;IAC5D,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"local-store.d.ts","sourceRoot":"","sources":["local-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,KAAK,EACR,eAAe,EAAW,YAAY,EAAE,WAAW,EACtD,MAAM,2BAA2B,CAAC;AAuCnC;;;;mEAImE;AACnE,MAAM,WAAW,YAAa,SAAQ,eAAe;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxG,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,uBAAuB,EAAE,OAAO,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;CACtB;AAED,qBAAa,UAAU;IAEf,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,SAAS;gBADT,EAAE,EAAE,OAAO,EACX,SAAS,EAAE,gBAAgB;IAMvC;;;6DAGyD;IACzD,WAAW,IAAI;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE;IAM9E,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,EAAE;IAMpC;;4CAEwC;IACxC,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI;IAK7F,iEAAiE;IACjE,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,WAAW,CAAC,eAAe,CAAC;IAI9D,mEAAmE;IACnE,eAAe,CAAC,IAAI,SAAI,EAAE,QAAQ,SAAK,GAAG,WAAW,CAAC,eAAe,CAAC;IAItE,sEAAsE;IACtE,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,SAAI,EAAE,QAAQ,SAAK,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC,eAAe,CAAC;IAM3H;;;;;;;sEAOkE;IAC5D,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAuJvH,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,EAAE;IAIzE,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,gBAAgB,UAAQ,GAAG,GAAG,EAAE;IAI5D,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,GAAG,EAAE;IAIhD,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,SAAI,EAAE,QAAQ,SAAM,GAAG,GAAG;CAK7D"}
|
|
@@ -238,7 +238,11 @@ export class LocalStore {
|
|
|
238
238
|
cached: true,
|
|
239
239
|
deliveredTo, returnPath,
|
|
240
240
|
listUnsubscribe, listUnsubscribeMail, listUnsubscribeHttp, listUnsubscribeOneClick,
|
|
241
|
-
|
|
241
|
+
// body_path in the DB is stored relative to the body-store
|
|
242
|
+
// basePath; resolve to absolute so the UI's "Source" button
|
|
243
|
+
// can hand the path to an OS file open without re-deriving
|
|
244
|
+
// basePath every time.
|
|
245
|
+
emlPath: this.bodyStore.absolutePath(storedPath),
|
|
242
246
|
isFlagged,
|
|
243
247
|
};
|
|
244
248
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-store.js","sourceRoot":"","sources":["local-store.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"local-store.js","sourceRoot":"","sources":["local-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -280,7 +280,11 @@ export class LocalStore {
|
|
|
280
280
|
cached: true,
|
|
281
281
|
deliveredTo, returnPath,
|
|
282
282
|
listUnsubscribe, listUnsubscribeMail, listUnsubscribeHttp, listUnsubscribeOneClick,
|
|
283
|
-
|
|
283
|
+
// body_path in the DB is stored relative to the body-store
|
|
284
|
+
// basePath; resolve to absolute so the UI's "Source" button
|
|
285
|
+
// can hand the path to an OS file open without re-deriving
|
|
286
|
+
// basePath every time.
|
|
287
|
+
emlPath: this.bodyStore.absolutePath(storedPath),
|
|
284
288
|
isFlagged,
|
|
285
289
|
};
|
|
286
290
|
}
|
|
@@ -37,6 +37,19 @@ export interface ReconcilerOptions {
|
|
|
37
37
|
bodyFetchConcurrency?: number;
|
|
38
38
|
/** Periodic emit of syncStateChanged — drives the UI status pill. */
|
|
39
39
|
statusEmitIntervalMs?: number;
|
|
40
|
+
/** How often to fire the prefetch tick. Default 60s. */
|
|
41
|
+
prefetchIntervalMs?: number;
|
|
42
|
+
/** First prefetch fires this soon after start so the "not downloaded"
|
|
43
|
+
* dots fill in without making the user wait a minute. */
|
|
44
|
+
prefetchInitialDelayMs?: number;
|
|
45
|
+
/** Skip prefetch when the interactive body-fetch lane has at least
|
|
46
|
+
* this many items pending. Back-pressure keeps clicks responsive. */
|
|
47
|
+
prefetchBackpressureThreshold?: number;
|
|
48
|
+
/** Tombstone prune interval — bookkeeping only, hourly default. */
|
|
49
|
+
tombstonePruneIntervalMs?: number;
|
|
50
|
+
/** Tombstone retention — local-delete records older than this are
|
|
51
|
+
* removed by the periodic prune. */
|
|
52
|
+
tombstoneRetentionDays?: number;
|
|
40
53
|
}
|
|
41
54
|
export declare class Reconciler {
|
|
42
55
|
private db;
|
|
@@ -45,10 +58,25 @@ export declare class Reconciler {
|
|
|
45
58
|
private opts;
|
|
46
59
|
private running;
|
|
47
60
|
private statusTimer;
|
|
61
|
+
private prefetchTimer;
|
|
62
|
+
private tombstoneTimer;
|
|
48
63
|
private inFlightFetches;
|
|
64
|
+
/** Last status payload — used to suppress no-op syncStateChanged events.
|
|
65
|
+
* During a heavy multi-folder sync the 5s tick fires a lot of identical
|
|
66
|
+
* events; the WebView's event handler runs DOM work for each, which
|
|
67
|
+
* stacks up under load. Diff-only emits keep the channel quiet. */
|
|
68
|
+
private lastStatus;
|
|
49
69
|
constructor(db: MailxDB, imapManager: ImapManager, queue: SyncQueue, opts?: ReconcilerOptions);
|
|
50
70
|
start(): void;
|
|
51
71
|
stop(): void;
|
|
72
|
+
/** Hourly bookkeeping — drop tombstones older than the retention window
|
|
73
|
+
* so the deleted-message lookup stays fast. */
|
|
74
|
+
private runTombstonePrune;
|
|
75
|
+
/** Fire prefetchBodies on each account unless the interactive body-fetch
|
|
76
|
+
* lane has user-clicked work pending — in which case skip this tick.
|
|
77
|
+
* ImapManager's per-account `prefetchingAccounts` guard de-dupes if
|
|
78
|
+
* the previous tick is still in flight. */
|
|
79
|
+
private runPrefetchTick;
|
|
52
80
|
/** User-visible "sync now" — runs an immediate poll on all accounts
|
|
53
81
|
* (or just one) without waiting for the next periodic tick. */
|
|
54
82
|
syncNow(accountId?: string): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconciler.d.ts","sourceRoot":"","sources":["reconciler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,WAAW,iBAAiB;IAC9B;;sDAEkD;IAClD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,qEAAqE;IACrE,oBAAoB,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"reconciler.d.ts","sourceRoot":"","sources":["reconciler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,WAAW,iBAAiB;IAC9B;;sDAEkD;IAClD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,qEAAqE;IACrE,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,wDAAwD;IACxD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;8DAC0D;IAC1D,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC;0EACsE;IACtE,6BAA6B,CAAC,EAAE,MAAM,CAAC;IACvC,mEAAmE;IACnE,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC;yCACqC;IACrC,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACnC;AAYD,qBAAa,UAAU;IAcf,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,KAAK;IAfjB,OAAO,CAAC,IAAI,CAA8B;IAC1C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAA+C;IAClE,OAAO,CAAC,aAAa,CAA+C;IACpE,OAAO,CAAC,cAAc,CAA+C;IACrE,OAAO,CAAC,eAAe,CAAK;IAC5B;;;wEAGoE;IACpE,OAAO,CAAC,UAAU,CAAgE;gBAGtE,EAAE,EAAE,OAAO,EACX,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,SAAS,EACxB,IAAI,GAAE,iBAAsB;IAKhC,KAAK,IAAI,IAAI;IAyCb,IAAI,IAAI,IAAI;IAOZ;oDACgD;IAChD,OAAO,CAAC,iBAAiB;IAMzB;;;gDAG4C;IAC5C,OAAO,CAAC,eAAe;IAcvB;oEACgE;IAChE,OAAO,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;IAOjC;;2DAEuD;IACvD,OAAO,CAAC,eAAe;IAmDvB,yEAAyE;IACzE,IAAI,IAAI,IAAI;CAGf"}
|
|
@@ -30,6 +30,11 @@
|
|
|
30
30
|
const DEFAULTS = {
|
|
31
31
|
bodyFetchConcurrency: 2,
|
|
32
32
|
statusEmitIntervalMs: 5_000,
|
|
33
|
+
prefetchIntervalMs: 60_000,
|
|
34
|
+
prefetchInitialDelayMs: 2_000,
|
|
35
|
+
prefetchBackpressureThreshold: 1,
|
|
36
|
+
tombstonePruneIntervalMs: 3600_000, // hourly
|
|
37
|
+
tombstoneRetentionDays: 30,
|
|
33
38
|
};
|
|
34
39
|
export class Reconciler {
|
|
35
40
|
db;
|
|
@@ -38,7 +43,14 @@ export class Reconciler {
|
|
|
38
43
|
opts;
|
|
39
44
|
running = false;
|
|
40
45
|
statusTimer = null;
|
|
46
|
+
prefetchTimer = null;
|
|
47
|
+
tombstoneTimer = null;
|
|
41
48
|
inFlightFetches = 0;
|
|
49
|
+
/** Last status payload — used to suppress no-op syncStateChanged events.
|
|
50
|
+
* During a heavy multi-folder sync the 5s tick fires a lot of identical
|
|
51
|
+
* events; the WebView's event handler runs DOM work for each, which
|
|
52
|
+
* stacks up under load. Diff-only emits keep the channel quiet. */
|
|
53
|
+
lastStatus = { messageActions: -1, bodyFetches: -1, inFlightFetches: -1 };
|
|
42
54
|
constructor(db, imapManager, queue, opts = {}) {
|
|
43
55
|
this.db = db;
|
|
44
56
|
this.imapManager = imapManager;
|
|
@@ -50,11 +62,35 @@ export class Reconciler {
|
|
|
50
62
|
return;
|
|
51
63
|
this.running = true;
|
|
52
64
|
// Status pill: emit current totals every few seconds so the UI
|
|
53
|
-
// can show "Syncing N items" without polling.
|
|
65
|
+
// can show "Syncing N items" without polling. Diff-only — emit
|
|
66
|
+
// ONLY when something actually changed since the last tick so
|
|
67
|
+
// we don't pipe a constant idle stream through the WebView's
|
|
68
|
+
// event channel during a heavy sync (where the WebView main
|
|
69
|
+
// thread is already busy painting list updates).
|
|
54
70
|
this.statusTimer = setInterval(() => {
|
|
55
71
|
const counts = this.queue.pendingCount();
|
|
56
|
-
|
|
72
|
+
const next = { ...counts, inFlightFetches: this.inFlightFetches };
|
|
73
|
+
if (next.messageActions === this.lastStatus.messageActions
|
|
74
|
+
&& next.bodyFetches === this.lastStatus.bodyFetches
|
|
75
|
+
&& next.inFlightFetches === this.lastStatus.inFlightFetches) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.lastStatus = next;
|
|
79
|
+
this.imapManager.emit("syncStateChanged", next);
|
|
57
80
|
}, this.opts.statusEmitIntervalMs);
|
|
81
|
+
// Periodic prefetch tick — owned here (not in ImapManager) so it
|
|
82
|
+
// can back off when the interactive body-fetch lane has work.
|
|
83
|
+
// First tick fires soon after startup so "not downloaded" dots
|
|
84
|
+
// start filling in promptly.
|
|
85
|
+
const prefetchTick = () => this.runPrefetchTick();
|
|
86
|
+
setTimeout(prefetchTick, this.opts.prefetchInitialDelayMs);
|
|
87
|
+
this.prefetchTimer = setInterval(prefetchTick, this.opts.prefetchIntervalMs);
|
|
88
|
+
// Tombstone prune — bookkeeping only. Trivial cost (one indexed
|
|
89
|
+
// DELETE per hour), kept off the IMAP-touching code path because
|
|
90
|
+
// it has nothing to do with sync.
|
|
91
|
+
const pruneTick = () => this.runTombstonePrune();
|
|
92
|
+
setTimeout(pruneTick, 30_000); // first run after startup settles
|
|
93
|
+
this.tombstoneTimer = setInterval(pruneTick, this.opts.tombstonePruneIntervalMs);
|
|
58
94
|
// Kick the body-fetch loop.
|
|
59
95
|
this.pumpBodyFetches();
|
|
60
96
|
}
|
|
@@ -64,6 +100,38 @@ export class Reconciler {
|
|
|
64
100
|
clearInterval(this.statusTimer);
|
|
65
101
|
this.statusTimer = null;
|
|
66
102
|
}
|
|
103
|
+
if (this.prefetchTimer) {
|
|
104
|
+
clearInterval(this.prefetchTimer);
|
|
105
|
+
this.prefetchTimer = null;
|
|
106
|
+
}
|
|
107
|
+
if (this.tombstoneTimer) {
|
|
108
|
+
clearInterval(this.tombstoneTimer);
|
|
109
|
+
this.tombstoneTimer = null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/** Hourly bookkeeping — drop tombstones older than the retention window
|
|
113
|
+
* so the deleted-message lookup stays fast. */
|
|
114
|
+
runTombstonePrune() {
|
|
115
|
+
const cutoff = Date.now() - this.opts.tombstoneRetentionDays * 86400_000;
|
|
116
|
+
const n = this.db.pruneTombstones(cutoff);
|
|
117
|
+
if (n > 0)
|
|
118
|
+
console.log(` [tombstones] pruned ${n} older than ${this.opts.tombstoneRetentionDays} days`);
|
|
119
|
+
}
|
|
120
|
+
/** Fire prefetchBodies on each account unless the interactive body-fetch
|
|
121
|
+
* lane has user-clicked work pending — in which case skip this tick.
|
|
122
|
+
* ImapManager's per-account `prefetchingAccounts` guard de-dupes if
|
|
123
|
+
* the previous tick is still in flight. */
|
|
124
|
+
runPrefetchTick() {
|
|
125
|
+
if (!this.running)
|
|
126
|
+
return;
|
|
127
|
+
const counts = this.queue.pendingCount();
|
|
128
|
+
if (counts.bodyFetches >= this.opts.prefetchBackpressureThreshold) {
|
|
129
|
+
// Interactive work pending — let it drain. Next tick reconsiders.
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
for (const acct of this.db.getAccounts()) {
|
|
133
|
+
this.imapManager.prefetchBodies(acct.id).catch(e => console.error(` [prefetch] ${acct.id}: ${e?.message || e}`));
|
|
134
|
+
}
|
|
67
135
|
}
|
|
68
136
|
/** User-visible "sync now" — runs an immediate poll on all accounts
|
|
69
137
|
* (or just one) without waiting for the next periodic tick. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconciler.js","sourceRoot":"","sources":["reconciler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;
|
|
1
|
+
{"version":3,"file":"reconciler.js","sourceRoot":"","sources":["reconciler.ts"],"names":[],"mappings":"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"}
|
|
@@ -39,18 +39,43 @@ export interface ReconcilerOptions {
|
|
|
39
39
|
bodyFetchConcurrency?: number;
|
|
40
40
|
/** Periodic emit of syncStateChanged — drives the UI status pill. */
|
|
41
41
|
statusEmitIntervalMs?: number;
|
|
42
|
+
/** How often to fire the prefetch tick. Default 60s. */
|
|
43
|
+
prefetchIntervalMs?: number;
|
|
44
|
+
/** First prefetch fires this soon after start so the "not downloaded"
|
|
45
|
+
* dots fill in without making the user wait a minute. */
|
|
46
|
+
prefetchInitialDelayMs?: number;
|
|
47
|
+
/** Skip prefetch when the interactive body-fetch lane has at least
|
|
48
|
+
* this many items pending. Back-pressure keeps clicks responsive. */
|
|
49
|
+
prefetchBackpressureThreshold?: number;
|
|
50
|
+
/** Tombstone prune interval — bookkeeping only, hourly default. */
|
|
51
|
+
tombstonePruneIntervalMs?: number;
|
|
52
|
+
/** Tombstone retention — local-delete records older than this are
|
|
53
|
+
* removed by the periodic prune. */
|
|
54
|
+
tombstoneRetentionDays?: number;
|
|
42
55
|
}
|
|
43
56
|
|
|
44
57
|
const DEFAULTS: Required<ReconcilerOptions> = {
|
|
45
58
|
bodyFetchConcurrency: 2,
|
|
46
59
|
statusEmitIntervalMs: 5_000,
|
|
60
|
+
prefetchIntervalMs: 60_000,
|
|
61
|
+
prefetchInitialDelayMs: 2_000,
|
|
62
|
+
prefetchBackpressureThreshold: 1,
|
|
63
|
+
tombstonePruneIntervalMs: 3600_000, // hourly
|
|
64
|
+
tombstoneRetentionDays: 30,
|
|
47
65
|
};
|
|
48
66
|
|
|
49
67
|
export class Reconciler {
|
|
50
68
|
private opts: Required<ReconcilerOptions>;
|
|
51
69
|
private running = false;
|
|
52
70
|
private statusTimer: ReturnType<typeof setInterval> | null = null;
|
|
71
|
+
private prefetchTimer: ReturnType<typeof setInterval> | null = null;
|
|
72
|
+
private tombstoneTimer: ReturnType<typeof setInterval> | null = null;
|
|
53
73
|
private inFlightFetches = 0;
|
|
74
|
+
/** Last status payload — used to suppress no-op syncStateChanged events.
|
|
75
|
+
* During a heavy multi-folder sync the 5s tick fires a lot of identical
|
|
76
|
+
* events; the WebView's event handler runs DOM work for each, which
|
|
77
|
+
* stacks up under load. Diff-only emits keep the channel quiet. */
|
|
78
|
+
private lastStatus = { messageActions: -1, bodyFetches: -1, inFlightFetches: -1 };
|
|
54
79
|
|
|
55
80
|
constructor(
|
|
56
81
|
private db: MailxDB,
|
|
@@ -66,12 +91,38 @@ export class Reconciler {
|
|
|
66
91
|
this.running = true;
|
|
67
92
|
|
|
68
93
|
// Status pill: emit current totals every few seconds so the UI
|
|
69
|
-
// can show "Syncing N items" without polling.
|
|
94
|
+
// can show "Syncing N items" without polling. Diff-only — emit
|
|
95
|
+
// ONLY when something actually changed since the last tick so
|
|
96
|
+
// we don't pipe a constant idle stream through the WebView's
|
|
97
|
+
// event channel during a heavy sync (where the WebView main
|
|
98
|
+
// thread is already busy painting list updates).
|
|
70
99
|
this.statusTimer = setInterval(() => {
|
|
71
100
|
const counts = this.queue.pendingCount();
|
|
72
|
-
|
|
101
|
+
const next = { ...counts, inFlightFetches: this.inFlightFetches };
|
|
102
|
+
if (next.messageActions === this.lastStatus.messageActions
|
|
103
|
+
&& next.bodyFetches === this.lastStatus.bodyFetches
|
|
104
|
+
&& next.inFlightFetches === this.lastStatus.inFlightFetches) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
this.lastStatus = next;
|
|
108
|
+
this.imapManager.emit("syncStateChanged", next);
|
|
73
109
|
}, this.opts.statusEmitIntervalMs);
|
|
74
110
|
|
|
111
|
+
// Periodic prefetch tick — owned here (not in ImapManager) so it
|
|
112
|
+
// can back off when the interactive body-fetch lane has work.
|
|
113
|
+
// First tick fires soon after startup so "not downloaded" dots
|
|
114
|
+
// start filling in promptly.
|
|
115
|
+
const prefetchTick = (): void => this.runPrefetchTick();
|
|
116
|
+
setTimeout(prefetchTick, this.opts.prefetchInitialDelayMs);
|
|
117
|
+
this.prefetchTimer = setInterval(prefetchTick, this.opts.prefetchIntervalMs);
|
|
118
|
+
|
|
119
|
+
// Tombstone prune — bookkeeping only. Trivial cost (one indexed
|
|
120
|
+
// DELETE per hour), kept off the IMAP-touching code path because
|
|
121
|
+
// it has nothing to do with sync.
|
|
122
|
+
const pruneTick = (): void => this.runTombstonePrune();
|
|
123
|
+
setTimeout(pruneTick, 30_000); // first run after startup settles
|
|
124
|
+
this.tombstoneTimer = setInterval(pruneTick, this.opts.tombstonePruneIntervalMs);
|
|
125
|
+
|
|
75
126
|
// Kick the body-fetch loop.
|
|
76
127
|
this.pumpBodyFetches();
|
|
77
128
|
}
|
|
@@ -79,6 +130,34 @@ export class Reconciler {
|
|
|
79
130
|
stop(): void {
|
|
80
131
|
this.running = false;
|
|
81
132
|
if (this.statusTimer) { clearInterval(this.statusTimer); this.statusTimer = null; }
|
|
133
|
+
if (this.prefetchTimer) { clearInterval(this.prefetchTimer); this.prefetchTimer = null; }
|
|
134
|
+
if (this.tombstoneTimer) { clearInterval(this.tombstoneTimer); this.tombstoneTimer = null; }
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Hourly bookkeeping — drop tombstones older than the retention window
|
|
138
|
+
* so the deleted-message lookup stays fast. */
|
|
139
|
+
private runTombstonePrune(): void {
|
|
140
|
+
const cutoff = Date.now() - this.opts.tombstoneRetentionDays * 86400_000;
|
|
141
|
+
const n = this.db.pruneTombstones(cutoff);
|
|
142
|
+
if (n > 0) console.log(` [tombstones] pruned ${n} older than ${this.opts.tombstoneRetentionDays} days`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Fire prefetchBodies on each account unless the interactive body-fetch
|
|
146
|
+
* lane has user-clicked work pending — in which case skip this tick.
|
|
147
|
+
* ImapManager's per-account `prefetchingAccounts` guard de-dupes if
|
|
148
|
+
* the previous tick is still in flight. */
|
|
149
|
+
private runPrefetchTick(): void {
|
|
150
|
+
if (!this.running) return;
|
|
151
|
+
const counts = this.queue.pendingCount();
|
|
152
|
+
if (counts.bodyFetches >= this.opts.prefetchBackpressureThreshold) {
|
|
153
|
+
// Interactive work pending — let it drain. Next tick reconsiders.
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
for (const acct of this.db.getAccounts()) {
|
|
157
|
+
this.imapManager.prefetchBodies(acct.id).catch(e =>
|
|
158
|
+
console.error(` [prefetch] ${acct.id}: ${e?.message || e}`)
|
|
159
|
+
);
|
|
160
|
+
}
|
|
82
161
|
}
|
|
83
162
|
|
|
84
163
|
/** User-visible "sync now" — runs an immediate poll on all accounts
|
|
@@ -18,7 +18,11 @@
|
|
|
18
18
|
],
|
|
19
19
|
"discovered": [
|
|
20
20
|
{ "name": "Bob", "email": "bob@example.com", "useCount": 715, "lastUsed": 1777921829000 }
|
|
21
|
-
]
|
|
21
|
+
],
|
|
22
|
+
"groups": {
|
|
23
|
+
"Joes": ["joe@example.com", "jo@example.com"],
|
|
24
|
+
"Family": ["alice@example.com", "Joes"]
|
|
25
|
+
}
|
|
22
26
|
}
|
|
23
27
|
```
|
|
24
28
|
|
|
@@ -27,6 +31,7 @@
|
|
|
27
31
|
- **preferred** — manually-curated, top-ranked in autocomplete. Add people you actually want to reach quickly.
|
|
28
32
|
- **denylist** — addresses (lowercased) excluded from autocomplete entirely.
|
|
29
33
|
- **discovered** — auto-collected from sent/received mail. `useCount` × recency drives autocomplete ranking. Junk patterns (see below) are dropped at insertion.
|
|
34
|
+
- **groups** — mailing lists. Type the group name in To/Cc/Bcc and compose expands it into the member addresses on send. Each value is an array of either email addresses (`"a@b.com"` or `"Name <a@b.com>"`) or other group names (recursive aliasing — cycles are detected, depth capped at 10). Group lookup is case-insensitive on the key. The two `Joes` example above plus the `Family` example show flat membership and one group nested inside another.
|
|
30
35
|
|
|
31
36
|
## Global junk filter
|
|
32
37
|
|