@bobfrankston/rmfmail 1.2.263 → 1.2.270

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 (51) hide show
  1. package/TODO.md +1 -0
  2. package/client/android-bootstrap.bundle.js +34 -1
  3. package/client/android-bootstrap.bundle.js.map +2 -2
  4. package/client/app.bundle.js +54 -108
  5. package/client/app.bundle.js.map +3 -3
  6. package/client/app.js +59 -116
  7. package/client/app.js.map +1 -1
  8. package/client/app.ts +64 -93
  9. package/client/components/message-list.js +18 -3
  10. package/client/components/message-list.js.map +1 -1
  11. package/client/components/message-list.ts +18 -3
  12. package/client/components/message-viewer.js +14 -4
  13. package/client/components/message-viewer.js.map +1 -1
  14. package/client/components/message-viewer.ts +13 -3
  15. package/client/compose/compose.bundle.js +17 -6
  16. package/client/compose/compose.bundle.js.map +2 -2
  17. package/client/compose/compose.js +13 -7
  18. package/client/compose/compose.js.map +1 -1
  19. package/client/compose/compose.ts +13 -5
  20. package/client/lib/rmf-tiny.js +15 -1
  21. package/client/package.json +1 -1
  22. package/client/styles/components.css +9 -0
  23. package/docs/thundermail-jmap.md +291 -0
  24. package/package.json +11 -11
  25. package/packages/mailx-imap/index.d.ts.map +1 -1
  26. package/packages/mailx-imap/index.js +17 -1
  27. package/packages/mailx-imap/index.js.map +1 -1
  28. package/packages/mailx-imap/index.ts +17 -1
  29. package/packages/mailx-imap/package-lock.json +2 -2
  30. package/packages/mailx-imap/package.json +1 -1
  31. package/packages/mailx-settings/docs/thundermail-jmap.md +291 -0
  32. package/packages/mailx-settings/index.d.ts +1 -0
  33. package/packages/mailx-settings/index.d.ts.map +1 -1
  34. package/packages/mailx-settings/index.js +1 -0
  35. package/packages/mailx-settings/index.js.map +1 -1
  36. package/packages/mailx-settings/index.ts +1 -0
  37. package/packages/mailx-settings/package.json +1 -1
  38. package/packages/mailx-store/package.json +1 -1
  39. package/packages/mailx-store-web/package.json +1 -1
  40. package/packages/mailx-store-web/web-settings.d.ts +1 -0
  41. package/packages/mailx-store-web/web-settings.d.ts.map +1 -1
  42. package/packages/mailx-store-web/web-settings.js +1 -0
  43. package/packages/mailx-store-web/web-settings.js.map +1 -1
  44. package/packages/mailx-store-web/web-settings.ts +1 -0
  45. package/packages/mailx-types/index.d.ts +59 -1
  46. package/packages/mailx-types/index.d.ts.map +1 -1
  47. package/packages/mailx-types/index.js +72 -0
  48. package/packages/mailx-types/index.js.map +1 -1
  49. package/packages/mailx-types/index.ts +80 -1
  50. package/packages/mailx-types/package.json +1 -1
  51. /package/packages/mailx-imap/{node_modules.npmglobalize-stash-88864 → node_modules.npmglobalize-stash-18100}/.package-lock.json +0 -0
package/TODO.md CHANGED
@@ -228,6 +228,7 @@ Items blocked on a design decision. Short-form question here; full context in th
228
228
  | **C128** | OPEN | **Body pre-parse on prefetch** — first click on any unviewed message pays `simpleParser` + `sanitizeHtml` cost (~100–500 ms on rich HTML). The parsedCache (added 2026-05-09) eliminates 2nd-and-later view costs but not the first. Fix: extend prefetch to ALSO parse + sanitize the body during background fetch and store the result alongside the .eml (e.g., `<uuid>.parsed.json` next to `<uuid>.eml`, or a `body_html_cached` column). Click-time path reads pre-parsed JSON, no parser invocation. Touches `mailx-imap/index.ts` prefetch path + `mailx-store/file-store.ts` for the parsed-blob storage. |
229
229
  | **C129** | OPEN | **Android prod/dev split via filename/URL channel** — User 2026-05-09 (revised): no separate MAUI project. Same source tree builds; output filenames distinguish channels: Phase 1 (start now) writes `rmfmaildev.apk` alongside today's `mailx-maui.apk`. Phase 2 (when a release is declared) switches to `rmfmail-<version>.apk` versioned + `rmfmaildev.apk` for latest, with promotion = re-pointing `rmfmail.apk` at a chosen version. Single APK contents per build; channel is runtime setting in AppUpdater (Settings toggle for which URL to poll). Side-by-side install on one device NOT supported by this design (single Android package id) — that's a separate need. See `docs/prod-android.md` for full plan. Phase 1 ~30 min; full flow ~2.5 hours when activated. |
230
230
  | **C130** | OPEN | **Reset prefetch error budget after fresh sync** — Android: `errors`/`failedThisSession` accumulate within a prefetch session. Already resets on next syncAll cycle (since each `prefetchBodies(account)` call is fresh). Verify this works in practice via logit; if a long sync session burns through budget and stays stuck, add an explicit reset on `bodyAvailable` events that fire while prefetch is still running. |
231
+ | **C164** | RESEARCHED | **Thundermail / JMAP provider** — full protocol survey at [`docs/thundermail-jmap.md`](thundermail-jmap.md), probed live 2026-08-17. Thundermail is Stalwart, so there is no proprietary API: IMAP 993 / SMTP 465 work **today with zero code** (an `accounts.jsonc` entry and nothing else), CardDAV `/dav/card` + CalDAV `/dav/cal` are http-basic, and JMAP is live at `https://mail.thundermail.com/jmap/` advertising core / mail / submission / calendars / contacts / filenode / sieve / quota plus **WebSocket push** (`supportsPush: true`). JMAP is the attractive bet: it kills the IDLE lane, the 5-lane connection semaphore and the Dovecot 20-conn ceiling, needs no transport injection (one path for Android and desktop, cf. C125), and `Email/changes` is native set-difference sync. **From address: resolved — good.** The 15-alias cap is `@thundermail.com`/`@tb.pro` only; custom domains get unlimited aliases plus a catch-all (empty-name alias), and with catch-all on you can send from any prefix unregistered — their own example is the per-vendor pattern already used on `bob.ma`. mailx needs ~nothing here (per-message From identity shipped v1.2.201); only Stalwart-side `MAIL FROM`/DKIM validation for an unregistered prefix is untested. **Still blocking/staged:** JMAP-calendars and `filenode` are unratified drafts; OAuth `scopes_supported` covers mail only (no calendars/contacts scope); invite-only beta so there is nothing to test against; and **no Drive equivalent** — Thunderbird Send is one-shot file *sharing*, not a listable revisable store, so mailx's shared-config dependency (`accounts.jsonc` / `contacts.jsonc` / preferences / allowlist on GDrive) has no home. **C161 is therefore the prerequisite, not JMAP** — the `_rmfmail` hidden-IMAP-folder state channel removes the Drive dependency for every account type at once and keeps working unchanged if JMAP lands later. Until C161 ships, adopting Thundermail is a half-migration that trades a Google dependency for a Thunderbird one. |
231
232
 
232
233
  <a id="concerns"></a>
233
234
 
@@ -2572,6 +2572,7 @@ __export(mailx_types_exports, {
2572
2572
  answeredOf: () => answeredOf,
2573
2573
  buildMimeMessage: () => buildMimeMessage,
2574
2574
  deletedOf: () => deletedOf,
2575
+ displayNameClaimsOtherAddress: () => displayNameClaimsOtherAddress,
2575
2576
  draftOf: () => draftOf,
2576
2577
  encodeAddressHeader: () => encodeAddressHeader,
2577
2578
  encodeHeaderWord: () => encodeHeaderWord,
@@ -2580,8 +2581,10 @@ __export(mailx_types_exports, {
2580
2581
  extractAddress: () => extractAddress,
2581
2582
  extractInlineImages: () => extractInlineImages,
2582
2583
  flaggedOf: () => flaggedOf,
2584
+ formatSender: () => formatSender,
2583
2585
  htmlToPlainText: () => htmlToPlainText,
2584
2586
  isAddressToken: () => isAddressToken,
2587
+ isJunkPreviewText: () => isJunkPreviewText,
2585
2588
  mergeReminderStates: () => mergeReminderStates,
2586
2589
  normalizeReminderState: () => normalizeReminderState,
2587
2590
  parseSearchQuery: () => parseSearchQuery,
@@ -2844,6 +2847,35 @@ function parseSearchQuery(query) {
2844
2847
  }
2845
2848
  return { conditions, params };
2846
2849
  }
2850
+ function isJunkPreviewText(s) {
2851
+ const t = (s || "").replace(/\s+/g, " ").trim().toLowerCase();
2852
+ if (!t)
2853
+ return true;
2854
+ return t === "undefined" || t === "null" || t === "nan" || t === "[object object]";
2855
+ }
2856
+ function displayNameClaimsOtherAddress(name, address) {
2857
+ const n = (name || "").trim();
2858
+ if (!n)
2859
+ return null;
2860
+ const real = (address || "").trim().toLowerCase();
2861
+ const m = n.match(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g);
2862
+ if (!m)
2863
+ return null;
2864
+ for (const claimed of m) {
2865
+ if (claimed.toLowerCase() !== real)
2866
+ return claimed;
2867
+ }
2868
+ return null;
2869
+ }
2870
+ function formatSender(addr) {
2871
+ const address = (addr?.address || "").trim();
2872
+ const name = (addr?.name || "").trim();
2873
+ if (!name)
2874
+ return { text: address, claimed: null };
2875
+ if (name.toLowerCase() === address.toLowerCase())
2876
+ return { text: address, claimed: null };
2877
+ return { text: `${name} <${address}>`, claimed: displayNameClaimsOtherAddress(name, address) };
2878
+ }
2847
2879
  var _SEEN, _FLAGGED, _ANSWERED, _DRAFT, _DELETED, seenOf, flaggedOf, answeredOf, draftOf, deletedOf, setSeen, setFlagged, setAnswered, setDraft, toggleSeen, toggleFlagged;
2848
2880
  var init_mailx_types = __esm({
2849
2881
  "packages/mailx-types/index.js"() {
@@ -3440,7 +3472,8 @@ var init_web_settings = __esm({
3440
3472
  editor: "quill",
3441
3473
  folderWidth: 220,
3442
3474
  listViewerSplit: 40,
3443
- fontSize: 15
3475
+ fontSize: 15,
3476
+ composeFontSize: 20
3444
3477
  },
3445
3478
  sync: {
3446
3479
  intervalMinutes: 5,