@bobfrankston/rmfmail 1.1.228 → 1.1.231

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.
Files changed (41) hide show
  1. package/client/android-bootstrap.bundle.js +4 -1
  2. package/client/android-bootstrap.bundle.js.map +2 -2
  3. package/client/app.bundle.js +54 -20
  4. package/client/app.bundle.js.map +2 -2
  5. package/client/app.js +42 -7
  6. package/client/app.js.map +1 -1
  7. package/client/app.ts +43 -7
  8. package/client/components/message-viewer.js +30 -9
  9. package/client/components/message-viewer.js.map +1 -1
  10. package/client/components/message-viewer.ts +28 -9
  11. package/client/compose/compose.bundle.js +9 -9
  12. package/client/compose/compose.bundle.js.map +2 -2
  13. package/client/compose/compose.js +2 -2
  14. package/client/compose/compose.js.map +1 -1
  15. package/client/compose/compose.ts +2 -2
  16. package/client/lib/api-client.js +7 -7
  17. package/client/lib/api-client.js.map +1 -1
  18. package/client/lib/api-client.ts +7 -7
  19. package/client/lib/mailxapi.js +4 -4
  20. package/package.json +5 -5
  21. package/packages/mailx-service/index.d.ts +3 -3
  22. package/packages/mailx-service/index.d.ts.map +1 -1
  23. package/packages/mailx-service/index.js +148 -29
  24. package/packages/mailx-service/index.js.map +1 -1
  25. package/packages/mailx-service/index.ts +135 -23
  26. package/packages/mailx-service/jsonrpc.js +3 -3
  27. package/packages/mailx-service/jsonrpc.js.map +1 -1
  28. package/packages/mailx-service/jsonrpc.ts +3 -3
  29. package/packages/mailx-store/db.d.ts.map +1 -1
  30. package/packages/mailx-store/db.js +30 -8
  31. package/packages/mailx-store/db.js.map +1 -1
  32. package/packages/mailx-store/db.ts +27 -8
  33. package/packages/mailx-types/index.d.ts +7 -3
  34. package/packages/mailx-types/index.d.ts.map +1 -1
  35. package/packages/mailx-types/index.js.map +1 -1
  36. package/packages/mailx-types/index.ts +7 -3
  37. package/packages/mailx-types/mailx-api.d.ts +1 -1
  38. package/packages/mailx-types/mailx-api.d.ts.map +1 -1
  39. package/packages/mailx-types/mailx-api.ts +1 -1
  40. package/tsconfig.base.json +1 -0
  41. package/packages/mailx-imap/node_modules.npmglobalize-stash-126048/.package-lock.json +0 -116
package/client/app.js CHANGED
@@ -601,6 +601,29 @@ function refreshSyncTooltip() {
601
601
  // Refresh the tooltip every 30s so the "(12m ago)" stays current even with
602
602
  // no new sync events.
603
603
  setInterval(refreshSyncTooltip, 30_000);
604
+ // Honest "Synced" indicator. "Synced HH:MM" must mean sync is IDLE, not fire
605
+ // on every tick — folderCountsChanged/syncProgress fire repeatedly during a
606
+ // catch-up backfill (e.g. after the daemon was offline) while messages are
607
+ // STILL arriving, so stamping "Synced" each time misled (Bob 2026-06-06: "it
608
+ // says synced but I don't see this afternoon's mail" — they were mid-backfill).
609
+ // Any sync activity (re)arms this settle timer; only when activity goes quiet
610
+ // for SYNC_SETTLE_MS do we stamp the time. While the storm runs, the handlers
611
+ // keep the bar on "Syncing…".
612
+ let syncSettleTimer = null;
613
+ const SYNC_SETTLE_MS = 4000;
614
+ function scheduleSyncedStamp() {
615
+ if (syncSettleTimer)
616
+ clearTimeout(syncSettleTimer);
617
+ syncSettleTimer = setTimeout(() => {
618
+ syncSettleTimer = null;
619
+ const el = document.getElementById("status-sync");
620
+ // Only flip a "Syncing…" display to "Synced" — never clobber an error
621
+ // ("Sync error: …") or a transient action message ("Trashed 1 …").
622
+ if (el && (el.textContent || "").startsWith("Syncing")) {
623
+ el.textContent = `Synced ${new Date().toLocaleTimeString(undefined, { hour: "2-digit", minute: "2-digit", hour12: false })}`;
624
+ }
625
+ }, SYNC_SETTLE_MS);
626
+ }
604
627
  // ── Auto two-line when message list is narrow ──
605
628
  const messageList = document.getElementById("message-list");
606
629
  if (messageList) {
@@ -1495,14 +1518,19 @@ async function deleteSelectedMessages() {
1495
1518
  // An IPC 120s timeout doesn't mean the trash failed — surfacing it
1496
1519
  // as a status-bar error would only mislead. Real errors are still
1497
1520
  // reported by next sync's diagnostics.
1521
+ // Carry folderId per message so the daemon trashes the exact (folder, uid),
1522
+ // not whatever folder a bare (account, uid) lookup happens to resolve to
1523
+ // (Bob 2026-06-06: Del trashed the wrong message). uids/folderIds stay
1524
+ // index-aligned per account.
1498
1525
  const byAccount = new Map();
1499
1526
  for (const msg of snapshot) {
1500
- const uids = byAccount.get(msg.accountId) || [];
1501
- uids.push(msg.uid);
1502
- byAccount.set(msg.accountId, uids);
1527
+ const g = byAccount.get(msg.accountId) || { uids: [], folderIds: [] };
1528
+ g.uids.push(msg.uid);
1529
+ g.folderIds.push(msg.folderId);
1530
+ byAccount.set(msg.accountId, g);
1503
1531
  }
1504
- for (const [accountId, uids] of byAccount) {
1505
- deleteMessages(accountId, uids).catch((e) => {
1532
+ for (const [accountId, g] of byAccount) {
1533
+ deleteMessages(accountId, g.uids, g.folderIds).catch((e) => {
1506
1534
  console.error(`Delete failed for ${accountId}: ${e?.message || e}`);
1507
1535
  if (statusSync)
1508
1536
  statusSync.textContent = `Delete sync issue (${accountId}): ${e?.message || e}`;
@@ -2767,6 +2795,7 @@ onWsEvent((event) => {
2767
2795
  statusSync.textContent = `Syncing ${event.accountId}: ${label}`;
2768
2796
  if (startupStatus)
2769
2797
  startupStatus.textContent = `Syncing ${event.accountId}: ${label}`;
2798
+ scheduleSyncedStamp(); // re-arm the settle timer; stamp "Synced" when this quiets
2770
2799
  // Mark syncing folder in tree — bubble up to visible parent if collapsed
2771
2800
  const syncPath = event.phase?.startsWith("sync:") ? event.phase.slice(5) : null;
2772
2801
  // Clear previous syncing markers for this account
@@ -2795,6 +2824,7 @@ onWsEvent((event) => {
2795
2824
  refreshFolderTree();
2796
2825
  // Q53: track per-account last-sync timestamp for the status-bar hover.
2797
2826
  recordAccountSync(event.accountId);
2827
+ scheduleSyncedStamp(); // settle → "Synced HH:MM" once activity stops
2798
2828
  // Earlier I added reloadCurrentFolder() here to fix the
2799
2829
  // "phone INBOX stays on placeholder" report. That broke desktop
2800
2830
  // because syncComplete fires repeatedly on the desktop sync
@@ -2839,8 +2869,13 @@ onWsEvent((event) => {
2839
2869
  syncBtn.disabled = false;
2840
2870
  syncBtn.classList.remove("syncing");
2841
2871
  }
2842
- if (statusSync)
2843
- statusSync.textContent = `Synced ${new Date().toLocaleTimeString(undefined, { hour: "2-digit", minute: "2-digit", hour12: false })}`;
2872
+ // Honest indicator: a count change means activity, not necessarily
2873
+ // "done". Show "Syncing…" and let the settle timer stamp the time
2874
+ // once the backfill goes quiet (see scheduleSyncedStamp).
2875
+ if (statusSync && !(statusSync.textContent || "").startsWith("Sync error")) {
2876
+ statusSync.textContent = "Syncing…";
2877
+ }
2878
+ scheduleSyncedStamp();
2844
2879
  break;
2845
2880
  }
2846
2881
  case "updateAvailable": {