@bobfrankston/rmfmail 1.0.498 → 1.0.500

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 (45) hide show
  1. package/client/app.js +86 -1
  2. package/client/app.js.map +1 -1
  3. package/client/app.ts +71 -1
  4. package/client/components/message-list.js +34 -1
  5. package/client/components/message-list.js.map +1 -1
  6. package/client/components/message-list.ts +31 -1
  7. package/client/components/message-viewer.js +58 -14
  8. package/client/components/message-viewer.js.map +1 -1
  9. package/client/components/message-viewer.ts +56 -14
  10. package/client/index.html +9 -4
  11. package/client/lib/api-client.js +9 -0
  12. package/client/lib/api-client.js.map +1 -1
  13. package/client/lib/api-client.ts +12 -0
  14. package/client/lib/mailxapi.js +9 -0
  15. package/client/styles/components.css +47 -0
  16. package/package.json +1 -1
  17. package/packages/mailx-service/index.d.ts +16 -0
  18. package/packages/mailx-service/index.d.ts.map +1 -1
  19. package/packages/mailx-service/index.js +70 -0
  20. package/packages/mailx-service/index.js.map +1 -1
  21. package/packages/mailx-service/index.ts +50 -0
  22. package/packages/mailx-service/jsonrpc.js +8 -0
  23. package/packages/mailx-service/jsonrpc.js.map +1 -1
  24. package/packages/mailx-service/jsonrpc.ts +8 -0
  25. package/packages/mailx-store/db.d.ts +13 -0
  26. package/packages/mailx-store/db.d.ts.map +1 -1
  27. package/packages/mailx-store/db.js +31 -0
  28. package/packages/mailx-store/db.js.map +1 -1
  29. package/packages/mailx-store/db.ts +33 -1
  30. package/packages/mailx-store-web/android-bootstrap.js +12 -0
  31. package/packages/mailx-store-web/android-bootstrap.js.map +1 -1
  32. package/packages/mailx-store-web/android-bootstrap.ts +10 -0
  33. package/packages/mailx-store-web/web-jsonrpc.js +10 -0
  34. package/packages/mailx-store-web/web-jsonrpc.js.map +1 -1
  35. package/packages/mailx-store-web/web-jsonrpc.ts +10 -0
  36. package/packages/mailx-store-web/web-service.d.ts +17 -0
  37. package/packages/mailx-store-web/web-service.d.ts.map +1 -1
  38. package/packages/mailx-store-web/web-service.js +107 -4
  39. package/packages/mailx-store-web/web-service.js.map +1 -1
  40. package/packages/mailx-store-web/web-service.ts +100 -4
  41. package/packages/mailx-store-web/web-settings.d.ts +2 -0
  42. package/packages/mailx-store-web/web-settings.d.ts.map +1 -1
  43. package/packages/mailx-store-web/web-settings.js +2 -0
  44. package/packages/mailx-store-web/web-settings.js.map +1 -1
  45. package/packages/mailx-store-web/web-settings.ts +2 -0
package/client/app.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * Wires together all UI components and WebSocket connection.
4
4
  */
5
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 } from "./components/message-list.js";
6
+ import { initMessageList, loadMessages, loadUnifiedInbox, loadSearchResults, reloadCurrentFolder, clearSearchMode, getSelectedMessages, markBodiesCached, getCurrentFocused, releaseFocus, removeMessagesAndReconcile, setRowFlagged, scrollFocusedIntoView, refreshPriorityIndex } from "./components/message-list.js";
7
7
  import { showMessage, getCurrentMessage, initViewer, popOutCurrentMessage, toggleFullscreenPreview, showPreviewBodyMenu } from "./components/message-viewer.js";
8
8
  import { connectWebSocket, onWsEvent, triggerSync, syncAccount, reauthenticate, getAccounts, getFolders, deleteMessages, undeleteMessage, restartServer, getSyncPending, getVersion, getSettings, saveSettings, getAutocompleteSettings, saveAutocompleteSettings, repairAccounts, updateFlags, markAsSpamMessages, logClientEvent, sendMessage as apiSendMessage } from "./lib/api-client.js";
9
9
  import * as messageState from "./lib/message-state.js";
@@ -1294,6 +1294,11 @@ function applyTheme(theme) {
1294
1294
  const radio = document.getElementById(`opt-theme-${theme}`);
1295
1295
  if (radio)
1296
1296
  radio.checked = true;
1297
+ // Update the submenu's "current" badge so the user sees the choice
1298
+ // without expanding.
1299
+ const cur = document.getElementById("theme-submenu-current");
1300
+ if (cur)
1301
+ cur.textContent = theme.charAt(0).toUpperCase() + theme.slice(1);
1297
1302
  }
1298
1303
  // Restore saved theme + wire the Settings radios. Defaults to "system".
1299
1304
  (() => {
@@ -1310,6 +1315,24 @@ function applyTheme(theme) {
1310
1315
  applyTheme(t);
1311
1316
  });
1312
1317
  }
1318
+ // Wire the submenu toggle. Click to expand; click outside / on a radio closes.
1319
+ const togBtn = document.getElementById("theme-submenu-toggle");
1320
+ const popout = document.getElementById("theme-submenu-popout");
1321
+ if (togBtn && popout) {
1322
+ togBtn.addEventListener("click", (e) => {
1323
+ e.stopPropagation();
1324
+ const open = popout.hidden;
1325
+ popout.hidden = !open;
1326
+ togBtn.setAttribute("aria-expanded", String(open));
1327
+ });
1328
+ // Close on radio change so the menu doesn't linger after the choice.
1329
+ popout.querySelectorAll('input[type="radio"]').forEach(r => {
1330
+ r.addEventListener("change", () => {
1331
+ popout.hidden = true;
1332
+ togBtn.setAttribute("aria-expanded", "false");
1333
+ });
1334
+ });
1335
+ }
1313
1336
  })();
1314
1337
  // Highlight the current rail target. For now just inbox is the default; once
1315
1338
  // calendar/tasks ship, update this on view change.
@@ -1329,6 +1352,47 @@ document.addEventListener("mailx-compose", ((e) => {
1329
1352
  }
1330
1353
  }));
1331
1354
  document.addEventListener("mailx-delete", () => deleteSelectedMessages());
1355
+ // Share / mailto intents (Android-side: MainActivity routes share-sheet
1356
+ // invocations and mailto: links here. Desktop has no equivalent today —
1357
+ // MSIX / Windows share-target requires packaging changes we deferred).
1358
+ // Payload: { action, text, subject, mailto }. Mailto URLs are parsed
1359
+ // (RFC 2368: mailto:to?subject=...&body=...&cc=...&bcc=...) and used to
1360
+ // pre-fill compose. Plain shares (text/url) drop into the body / subject.
1361
+ document.addEventListener("mailx-share-intent", ((e) => {
1362
+ const detail = e.detail || {};
1363
+ const init = { mode: "new", to: [], cc: [], bcc: [], subject: "", bodyHtml: "" };
1364
+ if (detail.mailto) {
1365
+ try {
1366
+ const url = new URL(detail.mailto);
1367
+ const to = decodeURIComponent(url.pathname).split(",").map((s) => s.trim()).filter(Boolean);
1368
+ init.to = to;
1369
+ const sp = url.searchParams;
1370
+ const subj = sp.get("subject");
1371
+ if (subj)
1372
+ init.subject = subj;
1373
+ const body = sp.get("body");
1374
+ if (body)
1375
+ init.bodyHtml = `<p>${body.replace(/\n/g, "<br>")}</p>`;
1376
+ const cc = sp.get("cc");
1377
+ if (cc)
1378
+ init.cc = cc.split(",").map(s => s.trim()).filter(Boolean);
1379
+ const bcc = sp.get("bcc");
1380
+ if (bcc)
1381
+ init.bcc = bcc.split(",").map(s => s.trim()).filter(Boolean);
1382
+ }
1383
+ catch { /* malformed mailto: — drop the URL into body so user can fix */
1384
+ init.bodyHtml = `<p>${escapeHtml(detail.mailto)}</p>`;
1385
+ }
1386
+ }
1387
+ else {
1388
+ if (detail.subject)
1389
+ init.subject = detail.subject;
1390
+ if (detail.text)
1391
+ init.bodyHtml = `<p>${escapeHtml(String(detail.text)).replace(/\n/g, "<br>")}</p>`;
1392
+ }
1393
+ sessionStorage.setItem("composeInit", JSON.stringify(init));
1394
+ showComposeOverlay(init.subject || "Compose");
1395
+ }));
1332
1396
  // ── Search ──
1333
1397
  let searchTimeout;
1334
1398
  const searchInput = document.getElementById("search-input");
@@ -1785,6 +1849,10 @@ if (splitter) {
1785
1849
  }
1786
1850
  // ── WebSocket for live updates ──
1787
1851
  connectWebSocket();
1852
+ // Priority-sender index — fetch once on load. Refreshed on the contacts
1853
+ // configChanged event (below) so changes from another device propagate
1854
+ // without a full reload.
1855
+ refreshPriorityIndex().catch(() => { });
1788
1856
  onWsEvent((event) => {
1789
1857
  const statusSync = document.getElementById("status-sync");
1790
1858
  const startupStatus = document.getElementById("startup-status");
@@ -3172,6 +3240,23 @@ optFlagged?.addEventListener("change", () => {
3172
3240
  localStorage.setItem("mailx-flagged", String(optFlagged.checked));
3173
3241
  reloadCurrentFolder();
3174
3242
  });
3243
+ // Priority-senders-only filter — same pattern as flagged-only. Adds
3244
+ // .priority-only to the list body; CSS hides any row without .priority.
3245
+ const optPriorityOnly = document.getElementById("opt-priority-only");
3246
+ if (optPriorityOnly) {
3247
+ optPriorityOnly.checked = localStorage.getItem("mailx-priority-only") === "true";
3248
+ const body0 = document.getElementById("ml-body");
3249
+ if (optPriorityOnly.checked)
3250
+ body0?.classList.add("priority-only");
3251
+ optPriorityOnly.addEventListener("change", () => {
3252
+ const body = document.getElementById("ml-body");
3253
+ if (optPriorityOnly.checked)
3254
+ body?.classList.add("priority-only");
3255
+ else
3256
+ body?.classList.remove("priority-only");
3257
+ localStorage.setItem("mailx-priority-only", String(optPriorityOnly.checked));
3258
+ });
3259
+ }
3175
3260
  // Folder counts toggle
3176
3261
  optFolderCounts?.addEventListener("change", () => {
3177
3262
  const tree = document.getElementById("folder-tree");