@bobfrankston/rmfmail 1.2.102 → 1.2.105

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 (37) hide show
  1. package/TODO.md +1 -1
  2. package/bin/mailx.js +60 -3
  3. package/bin/mailx.js.map +1 -1
  4. package/bin/mailx.ts +52 -3
  5. package/bin/popout-server.js +73 -11
  6. package/bin/popout-server.js.map +1 -1
  7. package/bin/popout-server.ts +76 -11
  8. package/client/app.bundle.js +72 -33
  9. package/client/app.bundle.js.map +3 -3
  10. package/client/app.js +50 -12
  11. package/client/app.js.map +1 -1
  12. package/client/app.ts +48 -12
  13. package/client/components/folder-tree.js +18 -0
  14. package/client/components/folder-tree.js.map +1 -1
  15. package/client/components/folder-tree.ts +17 -0
  16. package/client/components/message-list.js +24 -2
  17. package/client/components/message-list.js.map +1 -1
  18. package/client/components/message-list.ts +22 -2
  19. package/client/components/message-viewer.js +18 -36
  20. package/client/components/message-viewer.js.map +1 -1
  21. package/client/components/message-viewer.ts +21 -35
  22. package/client/compose/compose.bundle.js +7 -0
  23. package/client/compose/compose.bundle.js.map +2 -2
  24. package/client/index.html +1 -1
  25. package/client/lib/api-client.js +9 -0
  26. package/client/lib/api-client.js.map +1 -1
  27. package/client/lib/api-client.ts +9 -0
  28. package/client/lib/mailxapi.js +6 -0
  29. package/package.json +1 -1
  30. package/packages/mailx-service/index.d.ts +25 -0
  31. package/packages/mailx-service/index.d.ts.map +1 -1
  32. package/packages/mailx-service/index.js +17 -0
  33. package/packages/mailx-service/index.js.map +1 -1
  34. package/packages/mailx-service/index.ts +24 -0
  35. package/packages/mailx-service/jsonrpc.js +2 -0
  36. package/packages/mailx-service/jsonrpc.js.map +1 -1
  37. package/packages/mailx-service/jsonrpc.ts +2 -0
package/client/app.js CHANGED
@@ -2,8 +2,8 @@
2
2
  * mailx client entry point.
3
3
  * Wires together all UI components and WebSocket connection.
4
4
  */
5
- import { initFolderTree, refreshFolderTree, updateFolderCounts, setFolderSynced, getFolderSynced, setOutboxTotal } from "./components/folder-tree.js";
6
- import { initMessageList, loadMessages, loadUnifiedInbox, loadSearchResults, reloadCurrentFolder, clearSearchMode, getSelectedMessages, markBodiesCached, getCurrentFocused, releaseFocus, removeMessagesAndReconcile, setRowFlagged, scrollFocusedIntoView, refreshPriorityIndex, revealMessage, selectAllVisible, exitMultiSelect, getDateBasis, setDateBasis } from "./components/message-list.js";
5
+ import { initFolderTree, refreshFolderTree, updateFolderCounts, setFolderSynced, getFolderSynced, setOutboxTotal, highlightFolder } from "./components/folder-tree.js";
6
+ import { initMessageList, loadMessages, loadUnifiedInbox, loadSearchResults, reloadCurrentFolder, clearSearchMode, getSelectedMessages, markBodiesCached, getCurrentFocused, releaseFocus, removeMessagesAndReconcile, setRowFlagged, scrollFocusedIntoView, refreshPriorityIndex, revealMessage, getCurrentView, selectAllVisible, exitMultiSelect, getDateBasis, setDateBasis } from "./components/message-list.js";
7
7
  import { seenOf, flaggedOf, draftOf, setSeen, setFlagged } from "@bobfrankston/mailx-types";
8
8
  import { initTabs, setActiveView as setActiveTabView, openTab } from "./components/tabs.js";
9
9
  import { getCurrentMessage, initViewer, popOutCurrentMessage, popOutToWindow, printCurrentMessage, toggleFullscreenPreview, showPreviewBodyMenu, wrapHtmlBody } from "./components/message-viewer.js";
@@ -2637,21 +2637,42 @@ let lastListReloadAt = 0;
2637
2637
  // BEFORE clearing search mode, then navigate to that message's folder and
2638
2638
  // reselect it. With no selected result (or no folderId) fall back to the old
2639
2639
  // reloadCurrentFolder behavior.
2640
- function closeSearchAndReveal() {
2640
+ async function closeSearchAndReveal() {
2641
2641
  const focused = getCurrentFocused();
2642
2642
  clearSearchMode();
2643
2643
  const body = document.getElementById("ml-body");
2644
2644
  if (body)
2645
2645
  body.querySelectorAll(".filter-hidden").forEach(r => r.classList.remove("filter-hidden"));
2646
2646
  if (focused && focused.folderId) {
2647
- currentAccountId = focused.accountId;
2648
- currentFolderId = focused.folderId;
2649
- revealMessage(focused.accountId, focused.folderId, focused.uid);
2647
+ await revealMessage(focused.accountId, focused.folderId, focused.uid);
2650
2648
  }
2651
2649
  else {
2652
2650
  reloadCurrentFolder();
2653
2651
  }
2654
- setTitle(APP_NAME);
2652
+ // Leaving search must leave search STATE behind too. Before this, the
2653
+ // active tab kept its "Search: …" view (re-running the dead query on any
2654
+ // tab re-activation) and the folder tree kept the pre-search highlight —
2655
+ // so when the reveal landed somewhere unexpected (a Drafts result, a
2656
+ // stale folderId after a server-side rebind), every indicator still
2657
+ // claimed search-on-All-Inboxes and the list looked broken (Bob
2658
+ // 2026-07-04 "cleared the search but it isn't restoring the list").
2659
+ // Sync tab, tree highlight and titles to what the list actually shows.
2660
+ const vw = getCurrentView();
2661
+ if (vw.unified) {
2662
+ highlightFolder(null, -1);
2663
+ setActiveTabView({ kind: "unified" }, "All Inboxes");
2664
+ setTitle(`${APP_NAME} - All Inboxes`);
2665
+ setNarrowFolderTitle("All Inboxes");
2666
+ }
2667
+ else {
2668
+ currentAccountId = vw.accountId;
2669
+ currentFolderId = vw.folderId;
2670
+ currentFolderSpecialUse = vw.specialUse;
2671
+ const name = highlightFolder(vw.accountId, vw.folderId) || "Mail";
2672
+ setActiveTabView({ kind: "folder", accountId: vw.accountId, folderId: vw.folderId, specialUse: vw.specialUse }, name);
2673
+ setTitle(`${APP_NAME} - ${name}`);
2674
+ setNarrowFolderTitle(name);
2675
+ }
2655
2676
  }
2656
2677
  searchInput?.addEventListener("input", () => {
2657
2678
  clearTimeout(searchTimeout);
@@ -3545,6 +3566,23 @@ onWsEvent((event) => {
3545
3566
  }).catch((e) => console.error("openComposeFromMailto failed:", e?.message || e));
3546
3567
  break;
3547
3568
  }
3569
+ case "popoutAction": {
3570
+ // Toolbar click inside a NATIVE popout window (msger, spawned by
3571
+ // the daemon). That window has no IPC bridge and can't host
3572
+ // compose, so the daemon forwards the action here; we load the
3573
+ // message locally and reuse the overlay-popout action path —
3574
+ // reply/replyAll/forward/editAsNew open the real editable
3575
+ // compose, flag/delete act directly.
3576
+ const { action, accountId, uid, folderId } = event;
3577
+ if (!action || !accountId || !uid)
3578
+ break;
3579
+ (async () => {
3580
+ const { getMessage } = await import("./lib/api-client.js");
3581
+ const msg = await getMessage(accountId, uid, false, folderId);
3582
+ document.dispatchEvent(new CustomEvent("mailx-popout-action", { detail: { action, msg, accountId } }));
3583
+ })().catch((e) => console.error(`[popout-window] ${action} failed: ${e?.message || e}`));
3584
+ break;
3585
+ }
3548
3586
  }
3549
3587
  });
3550
3588
  // Store-bus consumers (post-refactor). The list's mailx-remove-stale
@@ -5868,11 +5906,11 @@ function renderDiagnosticsBadge(snapshot) {
5868
5906
  }).join("\n");
5869
5907
  host.title = `Connection issues — ${summary}\n\n${detail}`;
5870
5908
  }
5871
- // Q64: pop-out a message into a floating overlay (real-OS-window pending C44).
5872
- // Action buttons on the message pop-out window Reply / Reply All / Forward
5873
- // act on the popped-out message specifically (not the main viewer's), Delete
5874
- // removes it. The pop-out lives in message-viewer.ts and can't import
5875
- // openCompose directly, so it fires this event.
5909
+ // Q64/C44: pop-out message actions. Fired by the floating-overlay popout's
5910
+ // toolbar (message-viewer.ts can't import openCompose directly) AND by the
5911
+ // native popout window via the `popoutAction` daemon event above. Reply /
5912
+ // Reply All / Forward act on the popped-out message specifically (not the
5913
+ // main viewer's), Delete removes it.
5876
5914
  document.addEventListener("mailx-popout-action", ((e) => {
5877
5915
  const { action, msg, accountId } = e.detail || {};
5878
5916
  if (!msg)