@bobfrankston/rmfmail 1.2.291 → 1.2.293

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 (57) hide show
  1. package/.commitmsg +24 -27
  2. package/client/android-bootstrap.bundle.js +34 -2
  3. package/client/android-bootstrap.bundle.js.map +2 -2
  4. package/client/app.bundle.js +37 -1
  5. package/client/app.bundle.js.map +2 -2
  6. package/client/components/message-viewer.js +56 -1
  7. package/client/components/message-viewer.js.map +1 -1
  8. package/client/components/message-viewer.ts +54 -1
  9. package/client/compose/compose.bundle.js +5 -1
  10. package/client/compose/compose.bundle.js.map +2 -2
  11. package/client/lib/api-client.js +7 -1
  12. package/client/lib/api-client.js.map +1 -1
  13. package/client/lib/api-client.ts +9 -2
  14. package/client/lib/mailxapi.js +3 -0
  15. package/client/styles/components.css +25 -0
  16. package/npmchanges.md +66 -0
  17. package/package.json +6 -6
  18. package/packages/mailx-imap/package-lock.json +2 -2
  19. package/packages/mailx-imap/package.json +1 -1
  20. package/packages/mailx-service/index.d.ts +20 -0
  21. package/packages/mailx-service/index.d.ts.map +1 -1
  22. package/packages/mailx-service/index.js +37 -0
  23. package/packages/mailx-service/index.js.map +1 -1
  24. package/packages/mailx-service/index.ts +37 -1
  25. package/packages/mailx-service/jsonrpc.js +2 -0
  26. package/packages/mailx-service/jsonrpc.js.map +1 -1
  27. package/packages/mailx-service/jsonrpc.ts +2 -0
  28. package/packages/mailx-service/package.json +1 -1
  29. package/packages/mailx-settings/index.d.ts +19 -0
  30. package/packages/mailx-settings/index.d.ts.map +1 -1
  31. package/packages/mailx-settings/index.js +33 -10
  32. package/packages/mailx-settings/index.js.map +1 -1
  33. package/packages/mailx-settings/index.ts +33 -11
  34. package/packages/mailx-settings/package.json +1 -1
  35. package/packages/mailx-store/package.json +1 -1
  36. package/packages/mailx-store/store.d.ts.map +1 -1
  37. package/packages/mailx-store/store.js +17 -2
  38. package/packages/mailx-store/store.js.map +1 -1
  39. package/packages/mailx-store/store.ts +17 -2
  40. package/packages/mailx-store-web/android-bootstrap.js +3 -0
  41. package/packages/mailx-store-web/android-bootstrap.js.map +1 -1
  42. package/packages/mailx-store-web/android-bootstrap.ts +3 -0
  43. package/packages/mailx-store-web/package.json +1 -1
  44. package/packages/mailx-store-web/web-jsonrpc.js +2 -0
  45. package/packages/mailx-store-web/web-jsonrpc.js.map +1 -1
  46. package/packages/mailx-store-web/web-jsonrpc.ts +2 -0
  47. package/packages/mailx-store-web/web-service.d.ts +9 -0
  48. package/packages/mailx-store-web/web-service.d.ts.map +1 -1
  49. package/packages/mailx-store-web/web-service.js +28 -0
  50. package/packages/mailx-store-web/web-service.js.map +1 -1
  51. package/packages/mailx-store-web/web-service.ts +23 -1
  52. package/packages/mailx-store-web/web-settings.d.ts +2 -0
  53. package/packages/mailx-store-web/web-settings.d.ts.map +1 -1
  54. package/packages/mailx-store-web/web-settings.js +2 -0
  55. package/packages/mailx-store-web/web-settings.js.map +1 -1
  56. package/packages/mailx-store-web/web-settings.ts +2 -0
  57. /package/packages/mailx-imap/{node_modules.npmglobalize-stash-27960 → node_modules.npmglobalize-stash-29688}/.package-lock.json +0 -0
@@ -9,7 +9,7 @@
9
9
  * drift impossible: there is exactly one path into this pane.
10
10
  */
11
11
 
12
- import { getMessage, updateFlags, allowRemoteContent, flagSenderOrDomain, getAttachment, openAttachment, getMessageSource, addContact, listContacts, upsertContact, unsubscribeOneClick, addPreferredContact, onEvent, subscribeStore } from "../lib/api-client.js";
12
+ import { getMessage, updateFlags, allowRemoteContent, flagSenderOrDomain, trustSenderOrDomain, getAttachment, openAttachment, getMessageSource, addContact, listContacts, upsertContact, unsubscribeOneClick, addPreferredContact, onEvent, subscribeStore } from "../lib/api-client.js";
13
13
  import { isSenderApproved, noteApprovedLocally, refreshApprovedSenders } from "../lib/approved-senders.js";
14
14
  import { buildInviteCard } from "./invite-card.js";
15
15
  import { showContextMenu } from "./context-menu.js";
@@ -1730,6 +1730,59 @@ export async function showMessage(accountId: string, uid: number, folderId?: num
1730
1730
  `</div>`).join("") +
1731
1731
  (worst === "info" ? ""
1732
1732
  : `<div class="mv-trust-foot">Links and attachments here should not be opened.</div>`);
1733
+
1734
+ // "Stop warning me about this sender" — the action the note was
1735
+ // missing. Bob 2026-08-28: "I don't need the spam reminder but I
1736
+ // don't want to say show remote content in order to prevent
1737
+ // tracking." Until now the only way to vouch for a sender was the
1738
+ // remote-content banner, which turns on their tracking pixels; this
1739
+ // writes the separate trustedSenders/trustedDomains list instead.
1740
+ //
1741
+ // Offered only where the server's own verdict is the whole finding
1742
+ // and the sender is proved. A forgery banner has no such button: no
1743
+ // list should be able to silence "this message is not what it says
1744
+ // it is", and there is nothing to trust when the identity is the
1745
+ // thing in doubt.
1746
+ const spamOnly = trust.length === 1 && trust[0].id === "server-spam-verdict" && worst !== "danger";
1747
+ const fromAddr = (msg.from?.address || "").toLowerCase();
1748
+ const fromDomain = fromAddr.split("@")[1] || "";
1749
+ if (spamOnly && spam?.proved && fromAddr) {
1750
+ const actions = document.createElement("div");
1751
+ actions.className = "mv-trust-actions";
1752
+ // Name the sender in the label — a button that says "trust" with
1753
+ // no object tells the reader nothing they can verify later.
1754
+ for (const [label, type, value] of [
1755
+ [`Stop warning about ${fromAddr}`, "sender", fromAddr],
1756
+ [`Stop warning about *@${fromDomain}`, "domain", fromDomain],
1757
+ ] as const) {
1758
+ if (!value) continue;
1759
+ const b = document.createElement("button");
1760
+ b.className = "mv-trust-action";
1761
+ b.textContent = label;
1762
+ b.addEventListener("click", async () => {
1763
+ b.disabled = true;
1764
+ try {
1765
+ // The button only ever ADDS, so anything but
1766
+ // `trusted: true` means the write did not land —
1767
+ // a missing bridge method, a merge that dropped
1768
+ // the list (2026-08-28), a refused cloud write.
1769
+ // Removing the banner on a failed save is the
1770
+ // worst outcome: it looks saved and comes back.
1771
+ const res = await trustSenderOrDomain(type, value);
1772
+ if (!res?.trusted) throw new Error("the sender list did not save");
1773
+ warn.remove();
1774
+ document.querySelector(".mv-spamscore")?.remove();
1775
+ } catch (e: any) {
1776
+ // Never fail silently: the reader pressed a button
1777
+ // and must know whether it took.
1778
+ b.disabled = false;
1779
+ b.textContent = `Could not save: ${e?.message || e}`;
1780
+ }
1781
+ });
1782
+ actions.appendChild(b);
1783
+ }
1784
+ warn.appendChild(actions);
1785
+ }
1733
1786
  bodyEl.appendChild(warn);
1734
1787
  }
1735
1788
 
@@ -1122,6 +1122,7 @@ __export(api_client_exports, {
1122
1122
  syncAccount: () => syncAccount,
1123
1123
  syncFolderNow: () => syncFolderNow,
1124
1124
  triggerSync: () => triggerSync,
1125
+ trustSenderOrDomain: () => trustSenderOrDomain,
1125
1126
  undeleteMessage: () => undeleteMessage,
1126
1127
  unsubscribeOneClick: () => unsubscribeOneClick,
1127
1128
  updateCalendarEvent: () => updateCalendarEvent,
@@ -1348,8 +1349,11 @@ function addUserDictWords(words) {
1348
1349
  function removeUserDictWord(word) {
1349
1350
  return ipc().removeUserDictWord?.(word) ?? Promise.resolve([]);
1350
1351
  }
1352
+ function trustSenderOrDomain(type, value) {
1353
+ return ipc().trustSenderOrDomain?.(type, value) ?? Promise.resolve({ trusted: false });
1354
+ }
1351
1355
  function getAllowlist() {
1352
- return ipc().getAllowlist?.() ?? Promise.resolve({ senders: [], domains: [], recipients: [], flaggedSenders: [], flaggedDomains: [] });
1356
+ return ipc().getAllowlist?.() ?? Promise.resolve({ senders: [], domains: [], recipients: [], flaggedSenders: [], flaggedDomains: [], trustedSenders: [], trustedDomains: [] });
1353
1357
  }
1354
1358
  function flagSenderOrDomain(type, value) {
1355
1359
  return ipc().flagSenderOrDomain?.(type, value) ?? Promise.resolve({ flagged: false });