@bobfrankston/rmfmail 1.2.209 → 1.2.211
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/bin/mailx.js +30 -8
- package/bin/mailx.js.map +1 -1
- package/bin/mailx.ts +28 -4
- package/client/android-bootstrap.bundle.js +8 -1
- package/client/android-bootstrap.bundle.js.map +2 -2
- package/client/app.bundle.js +24 -3
- package/client/app.bundle.js.map +2 -2
- package/client/app.js +15 -0
- package/client/app.js.map +1 -1
- package/client/app.ts +13 -0
- package/client/components/folder-tree.js +45 -3
- package/client/components/folder-tree.js.map +1 -1
- package/client/components/folder-tree.ts +42 -3
- package/client/index.html +1 -1
- package/package.json +5 -5
- package/packages/mailx-store-web/android-bootstrap.d.ts.map +1 -1
- package/packages/mailx-store-web/android-bootstrap.js +20 -1
- package/packages/mailx-store-web/android-bootstrap.js.map +1 -1
- package/packages/mailx-store-web/android-bootstrap.ts +20 -1
- package/packages/mailx-store-web/package.json +1 -1
- /package/packages/mailx-imap/{node_modules.npmglobalize-stash-35212 → node_modules.npmglobalize-stash-1872}/.package-lock.json +0 -0
package/bin/mailx.ts
CHANGED
|
@@ -2179,22 +2179,46 @@ RFC 5322 with CRLF line endings. Bodies are quoted-printable encoded (readable i
|
|
|
2179
2179
|
// ANOTHER machine (seen via the reminders.jsonc state sync) can retract
|
|
2180
2180
|
// a popup that's already on this machine's screen. `popupKey` is
|
|
2181
2181
|
// supplied by alarms.ts and stripped before the opts reach msger.
|
|
2182
|
-
const reminderPopups = new Map<string, { close: () => void }>();
|
|
2182
|
+
const reminderPopups = new Map<string, { close: () => void; result: Promise<any> }>();
|
|
2183
2183
|
svc.setPopupFn(async (opts: any) => {
|
|
2184
2184
|
// Own WebView2 profile so a reminder popup can never share (and
|
|
2185
2185
|
// crash) the main window's browser process — see S67 note on the
|
|
2186
2186
|
// popout windows below. Service-supplied opts may override.
|
|
2187
2187
|
const { popupKey, ...boxOpts } = opts || {};
|
|
2188
|
+
// ONE window per occurrence, however many app windows are open.
|
|
2189
|
+
// Every window runs its own alarm poller (alarms.ts is client-side),
|
|
2190
|
+
// so a second main window meant the same reminder spawned two
|
|
2191
|
+
// identical popups — and the second registration clobbered the
|
|
2192
|
+
// first's closer, leaving a popup that cross-machine retraction
|
|
2193
|
+
// could no longer close (Bob 2026-07-31: "two instances running,
|
|
2194
|
+
// two popups"). The late caller joins the SAME result, so both
|
|
2195
|
+
// pollers persist the same dismiss/snooze.
|
|
2196
|
+
if (popupKey) {
|
|
2197
|
+
const open = reminderPopups.get(popupKey);
|
|
2198
|
+
if (open) {
|
|
2199
|
+
console.log(` [reminder] popup ${popupKey} already open — joining it instead of opening a second`);
|
|
2200
|
+
return await open.result;
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2188
2203
|
const h = showMessageBoxEx({ profile: "popout", ...boxOpts });
|
|
2189
2204
|
if (typeof h.pid === "number") addChildPid(h.pid);
|
|
2190
|
-
|
|
2191
|
-
try {
|
|
2205
|
+
const result = (async () => {
|
|
2192
2206
|
const r = await h.result;
|
|
2193
2207
|
return { button: r.button, closed: r.closed, dismissed: r.dismissed, form: (r as any).form };
|
|
2194
|
-
}
|
|
2208
|
+
})();
|
|
2209
|
+
// Cleanup rides on the shared promise, not on this caller — joiners
|
|
2210
|
+
// must not tear down registration out from under the real window.
|
|
2211
|
+
void result.catch(() => { /* surfaced to the awaiting callers */ }).finally(() => {
|
|
2195
2212
|
if (typeof h.pid === "number") removeChildPid(h.pid);
|
|
2196
2213
|
if (popupKey) reminderPopups.delete(popupKey);
|
|
2214
|
+
});
|
|
2215
|
+
if (popupKey) {
|
|
2216
|
+
reminderPopups.set(popupKey, {
|
|
2217
|
+
close: () => { try { h.close(); } catch { /* already gone */ } },
|
|
2218
|
+
result,
|
|
2219
|
+
});
|
|
2197
2220
|
}
|
|
2221
|
+
return await result;
|
|
2198
2222
|
});
|
|
2199
2223
|
svc.setPopupCloserFn((key: string) => {
|
|
2200
2224
|
const p = reminderPopups.get(key);
|
|
@@ -11344,6 +11344,7 @@ function initAndroid() {
|
|
|
11344
11344
|
}
|
|
11345
11345
|
async function initAndroidOnce() {
|
|
11346
11346
|
console.log("[android] Initializing mailx (main-thread mode)...");
|
|
11347
|
+
narrate("Initializing\u2026");
|
|
11347
11348
|
await waitForNativeBridge();
|
|
11348
11349
|
if (window._nativeBridge && !window.msgapi) {
|
|
11349
11350
|
window.msgapi = window._nativeBridge;
|
|
@@ -11355,6 +11356,7 @@ async function initAndroidOnce() {
|
|
|
11355
11356
|
service = new WebMailxService(db, bodyStore, syncManager);
|
|
11356
11357
|
let accounts = await loadAccounts();
|
|
11357
11358
|
console.log(`[android] ${accounts.length} account(s) found`);
|
|
11359
|
+
narrate(accounts.length ? `Opening ${accounts.map((a) => a.email || a.id).join(", ")}\u2026` : "No local accounts yet \u2014 checking Google Drive\u2026");
|
|
11358
11360
|
let gmailTokenProvider = null;
|
|
11359
11361
|
for (const account of accounts) {
|
|
11360
11362
|
if (!account.enabled) continue;
|
|
@@ -11424,12 +11426,16 @@ async function initAndroidOnce() {
|
|
|
11424
11426
|
console.log(`[android] GDrive returned ${gdriveAccounts.length} accounts: ${gdriveAccounts.map((a) => a.id).join(",")}`);
|
|
11425
11427
|
if (gdriveAccounts.length > 0) {
|
|
11426
11428
|
accounts = gdriveAccounts;
|
|
11429
|
+
const enabled = accounts.filter((a) => a.enabled);
|
|
11430
|
+
narrate(`Found ${enabled.length} account(s): ${enabled.map((a) => a.email || a.id).join(", ")}`);
|
|
11431
|
+
let setUp = 0;
|
|
11427
11432
|
for (const account of accounts) {
|
|
11428
11433
|
vlog(`init: registering ${account.id} email=${account.email} enabled=${account.enabled} imap=${JSON.stringify(account.imap)}`);
|
|
11429
11434
|
if (!account.enabled) {
|
|
11430
11435
|
vlog(`init: ${account.id} disabled, skipping`);
|
|
11431
11436
|
continue;
|
|
11432
11437
|
}
|
|
11438
|
+
narrate(`Setting up ${account.email || account.id}\u2026 (${++setUp}/${enabled.length})`);
|
|
11433
11439
|
const domain = account.email?.split("@")[1]?.toLowerCase() || "";
|
|
11434
11440
|
if (domain === "gmail.com" || domain === "googlemail.com") {
|
|
11435
11441
|
syncManager.setTokenProvider(account.id, createNativeTokenProvider(account.email));
|
|
@@ -11437,7 +11443,7 @@ async function initAndroidOnce() {
|
|
|
11437
11443
|
await syncManager.addAccount(account);
|
|
11438
11444
|
}
|
|
11439
11445
|
console.log(`[android] Loaded ${accounts.length} accounts from GDrive`);
|
|
11440
|
-
narrate(`Syncing ${
|
|
11446
|
+
narrate(`Syncing ${enabled.map((a) => a.email || a.id).join(", ")}\u2026`);
|
|
11441
11447
|
syncManager.syncAll().catch((e) => console.error(`[android] post-reconcile sync: ${e.message}`));
|
|
11442
11448
|
}
|
|
11443
11449
|
await registerDeviceInGDrive(tp, folderId, accounts.map((a) => a.id));
|
|
@@ -11477,6 +11483,7 @@ async function initAndroidOnce() {
|
|
|
11477
11483
|
}
|
|
11478
11484
|
syncManager.syncAll().catch((e) => console.error(`[android] Periodic sync error: ${e.message}`));
|
|
11479
11485
|
service.maybeRefreshContactsConfig().catch((e) => console.error(`[android] contacts.jsonc freshness check: ${e?.message || e}`));
|
|
11486
|
+
primeSharedConfigs(false).catch((e) => console.error(`[android] shared config freshness check: ${e?.message || e}`));
|
|
11480
11487
|
if (++contactsSyncTickCounter % 8 === 0) {
|
|
11481
11488
|
for (const account of db.getAccounts()) {
|
|
11482
11489
|
if (!account.email || !isGoogleAccount(account)) continue;
|