@bobfrankston/rmfmail 1.1.115 → 1.1.117
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.bundle.js.map +1 -1
- package/client/app.js +1 -1
- package/client/app.ts +1 -1
- package/client/components/message-viewer.js +1 -1
- package/client/components/message-viewer.js.map +1 -1
- package/client/components/message-viewer.ts +1 -1
- package/package.json +1 -2
- package/packages/mailx-service/index.d.ts +1 -0
- package/packages/mailx-service/index.d.ts.map +1 -1
- package/packages/mailx-service/index.js +34 -14
- package/packages/mailx-service/index.js.map +1 -1
- package/packages/mailx-service/index.ts +34 -15
- /package/packages/mailx-imap/{node_modules.npmglobalize-stash-77936 → node_modules.npmglobalize-stash-48732}/.package-lock.json +0 -0
|
@@ -12,7 +12,6 @@ import { MailxDB, parseSerial } from "@bobfrankston/mailx-store";
|
|
|
12
12
|
const __dirname = import.meta.dirname;
|
|
13
13
|
import { ImapManager } from "@bobfrankston/mailx-imap";
|
|
14
14
|
import * as gsync from "./google-sync.js";
|
|
15
|
-
import { sniffAndFixCharset } from "./charset.js";
|
|
16
15
|
import { Store } from "@bobfrankston/mailx-store";
|
|
17
16
|
import { SyncQueue } from "./sync-queue.js";
|
|
18
17
|
import { Reconciler } from "./reconciler.js";
|
|
@@ -20,18 +19,10 @@ import { loadSettings, saveSettings, loadAccounts, loadAccountsAsync, saveAccoun
|
|
|
20
19
|
import type { AccountConfig, Folder, AutocompleteRequest, AutocompleteResponse, AutocompleteSettings, AiTransformRequest, AiTransformResponse, ExtractedEvent, MailxApi } from "@bobfrankston/mailx-types";
|
|
21
20
|
import { sanitizeHtml, encodeQuotedPrintable, htmlToPlainText } from "@bobfrankston/mailx-types";
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
* faithfully decodes as Latin-1 and produces "â??" garbage. We only
|
|
28
|
-
* override the obviously-wrong declarations (`iso-8859-1`, `us-ascii`,
|
|
29
|
-
* `windows-1252`, `latin1`); anything else passes through unchanged.
|
|
30
|
-
* Operates byte-wise so MIME boundaries / base64 / etc. are preserved.
|
|
31
|
-
* The `utf-8` validity test rejects 0xC0–0xC1 / 0xF5–0xFF and continuation
|
|
32
|
-
* bytes out of place, which would be common in genuine Latin-1 text. */
|
|
33
|
-
// sniffAndFixCharset moved to ./charset.ts so LocalStore can use it
|
|
34
|
-
// without creating a circular dep with index.ts.
|
|
22
|
+
// Charset normalization (sniffAndFixCharset) is owned solely by
|
|
23
|
+
// mailx-store/charset.ts — the single live parse path (LocalStore.getMessage)
|
|
24
|
+
// calls it there. mailx-service used to keep a duplicate copy that nothing
|
|
25
|
+
// invoked; removed 2026-05-21 (economy of mechanism — one charset fixer).
|
|
35
26
|
|
|
36
27
|
// parseListUnsubscribe moved to ./local-store.ts (only consumer is the
|
|
37
28
|
// body-read path, which is now part of LocalStore).
|
|
@@ -131,6 +122,10 @@ export class MailxService implements MailxApi {
|
|
|
131
122
|
// comment in loadContactsConfig() for why we don't re-walk on
|
|
132
123
|
// every fs.watch firing of contacts.jsonc.
|
|
133
124
|
private _contactsCorpusSeeded = false;
|
|
125
|
+
// Retry bookkeeping for loadContactsConfig when the cloud isn't ready
|
|
126
|
+
// yet at startup. Without retries, a failed first read left the denylist
|
|
127
|
+
// / preferred list unloaded for the whole session.
|
|
128
|
+
private _contactsRetries = 0;
|
|
134
129
|
// Settings cache. `loadSettings()` does a synchronous read of
|
|
135
130
|
// accounts.jsonc (via loadAccounts) AND preferences.jsonc — both of
|
|
136
131
|
// which may live on a GDrive-mounted shared dir where readFileSync
|
|
@@ -258,9 +253,33 @@ export class MailxService implements MailxApi {
|
|
|
258
253
|
cloudAvailable = true;
|
|
259
254
|
} catch { /* cloud unavailable */ }
|
|
260
255
|
|
|
256
|
+
// Cloud not ready — the read THREW (GDrive auth/init still in
|
|
257
|
+
// progress; loadContactsConfig() is fired from the constructor). Do
|
|
258
|
+
// NOT fall through to applyContactsConfig({denylist:[]}): that wipes
|
|
259
|
+
// the in-memory denylist for the whole session, so every "never
|
|
260
|
+
// suggest this address" choice silently comes back next run (Bob
|
|
261
|
+
// 2026-05-21: "it's on drive but not read for the new session").
|
|
262
|
+
// Retry with backoff until the cloud is actually up.
|
|
263
|
+
if (!cloudAvailable) {
|
|
264
|
+
const RETRY_DELAYS = [3_000, 8_000, 20_000, 45_000, 90_000, 90_000];
|
|
265
|
+
if (this._contactsRetries < RETRY_DELAYS.length) {
|
|
266
|
+
const delay = RETRY_DELAYS[this._contactsRetries];
|
|
267
|
+
this._contactsRetries++;
|
|
268
|
+
console.log(` [contacts] cloud not ready — retry ${this._contactsRetries} in ${delay / 1000}s`);
|
|
269
|
+
setTimeout(() => { this.loadContactsConfig().catch(() => { /* */ }); }, delay);
|
|
270
|
+
} else {
|
|
271
|
+
console.error(` [contacts] cloud unreachable after ${RETRY_DELAYS.length} retries — denylist/preferred NOT loaded this session`);
|
|
272
|
+
}
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
// Cloud reachable — clear the retry counter so a later fs.watch
|
|
276
|
+
// reload that briefly fails can retry afresh.
|
|
277
|
+
this._contactsRetries = 0;
|
|
278
|
+
|
|
261
279
|
if (!raw) {
|
|
262
|
-
// No file (yet)
|
|
263
|
-
//
|
|
280
|
+
// No file (yet) — genuinely missing, cloud confirmed reachable.
|
|
281
|
+
// Reset in-memory denylist and seed discovered from the local
|
|
282
|
+
// message corpus so autocomplete works immediately.
|
|
264
283
|
await this.db.applyContactsConfig({ preferred: [], denylist: [], discovered: [] });
|
|
265
284
|
try { await this.db.seedContactsFromMessages(); } catch { /* corpus may be empty */ }
|
|
266
285
|
// Auto-bootstrap GDrive copy if cloud is reachable. The file gets
|