@bobfrankston/rmfmail 1.2.296 → 1.2.297

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.
package/.commitmsg CHANGED
@@ -1,29 +1,32 @@
1
- A star set on the phone now reaches the desktop in seconds, not minutes
1
+ Reading a message outranks syncing it; a filter is not a selection
2
2
 
3
- Bob 2026-08-29: "how long should it take for a * on the phone to get to my
4
- desktop?" Measured, on his own log: a median of 5 minutes and up to 20.
3
+ Two things Bob hit on 2026-08-29.
5
4
 
6
- Why: gal.iecc.com does not advertise NOTIFY, so the desktop watches INBOX with
7
- plain IDLE. The server DOES push a flag change there as an unsolicited
8
- `* 1234 FETCH (FLAGS (\Seen \Flagged))` — iflow-direct dropped it (fixed in
9
- 0.1.67), and mailx had nothing to receive it with. The 5-minute quick check
10
- could not help either: it is a STATUS poll, and MESSAGES / UNSEEN / UIDNEXT do
11
- not move when a message is starred. So the only path was the periodic full
12
- sync's QRESYNC pass — which is why the numbers above are the sync cadence
13
- rather than any property of flags.
5
+ **"If I look at a letter while sync, things get confused. Eventually it reports
6
+ an error rather than retrying. Viewing the body should get priority instead of
7
+ waiting for sync."** Both halves were real:
14
8
 
15
- The IDLE watcher now takes `onFlagChange` and, debounced 1.5 s, runs the
16
- folder's normal QRESYNC pass the same one that already reconciles flags and
17
- took 53 ms in that log. Marking ten messages read on the phone arrives as ten
18
- pushes and costs one pass. Our own STOREs bounce back as flag pushes too, so
19
- the handler skips while this account has sync actions draining; the local store
20
- already has those.
9
+ - Lanes are strictly sequential, and a click-time body fetch went on the tail
10
+ of the fast lane behind whatever background work was already queued.
11
+ `withConnection` now takes `priority`, which puts the task at the FRONT of
12
+ its lane; the interactive fetch uses it and a 30 s cap instead of 90 s. It
13
+ still cannot preempt the command in flight an IMAP command cannot be
14
+ cancelled without dropping the connection — but it no longer waits out the
15
+ backlog.
16
+ - `fetchMessageBody` swallowed every error into `null`. To the reconciler that
17
+ means "the server has no body for this message", which is classified
18
+ non-transient, skips the 3-attempt retry budget, and paints a banner. A lane
19
+ timeout says nothing about whether the message has a body: transient errors
20
+ (timeout, dropped socket, discarded client) now propagate, so the existing
21
+ retry-with-backoff applies and the reader gets the message instead of an
22
+ error. Only a genuine "no body here" still arms the prefetch backoff — a
23
+ timeout used to arm it too, poisoning the next view for up to 12 h.
21
24
 
22
- INBOX only, because IDLE watches one mailbox per connection. Flags changed in
23
- other folders still wait for that folder's turn in the sync cycle.
24
-
25
- Also in this build: the log noise behind it. `[search]` / `[fetch]` per-command
26
- lines moved behind iflow's existing `verbose` flag, and the repeated
27
- per-folder reconcile lines now go through `logIfChanged` first occurrence,
28
- every change, and an hourly restatement instead of once per folder per cycle
29
- forever. On Android each of those lines was an HTTP request to the log server.
25
+ **"If I press * on search it shouldn't automatically select those letters, just
26
+ show them."** Nothing was selected the flagged-only filter washed the whole
27
+ list in the flag colour (added 2026-06-26 to make the filter unmistakable), and
28
+ a coloured background over rows is exactly how this list says "chosen". The
29
+ wash is gone; the filter now announces itself above the list, by name:
30
+ "Showing flagged (★) messages only click to show everything", and clicking it
31
+ clears the filter. Same chip covers the priority-senders filter, which had the
32
+ same shape.
@@ -13482,6 +13482,23 @@ function syncFilterFlaggedButton() {
13482
13482
  btn.classList.toggle("active", !!optFlagged?.checked);
13483
13483
  btn.setAttribute("aria-pressed", optFlagged?.checked ? "true" : "false");
13484
13484
  }
13485
+ function syncFilterChip() {
13486
+ const chip = document.getElementById("ml-filter-chip");
13487
+ if (!chip) return;
13488
+ const flagged = !!document.getElementById("opt-flagged")?.checked;
13489
+ const priority = !!document.getElementById("opt-priority-only")?.checked;
13490
+ const names = [flagged ? "flagged (\u2605) messages" : "", priority ? "priority senders" : ""].filter(Boolean);
13491
+ if (!names.length) {
13492
+ chip.hidden = true;
13493
+ return;
13494
+ }
13495
+ chip.hidden = false;
13496
+ chip.textContent = "Showing " + names.join(" and ") + " only \u2014 click to show everything";
13497
+ chip.title = "Clear the list filter";
13498
+ }
13499
+ document.getElementById("ml-filter-chip")?.addEventListener("click", () => {
13500
+ document.dispatchEvent(new CustomEvent("mailx-clear-list-filters"));
13501
+ });
13485
13502
  function applyFlaggedFilter(on) {
13486
13503
  try {
13487
13504
  logClientEvent("applyFlaggedFilter", { on, caller: new Error().stack?.split("\n").slice(2, 5).join(" | ") });
@@ -13493,6 +13510,7 @@ function applyFlaggedFilter(on) {
13493
13510
  else body?.classList.remove("flagged-only");
13494
13511
  localStorage.setItem("mailx-flagged", String(on));
13495
13512
  syncFilterFlaggedButton();
13513
+ syncFilterChip();
13496
13514
  reloadCurrentFolder();
13497
13515
  }
13498
13516
  optFlagged?.addEventListener("change", () => {
@@ -13502,6 +13520,7 @@ document.getElementById("btn-filter-flagged")?.addEventListener("click", () => {
13502
13520
  applyFlaggedFilter(!optFlagged?.checked);
13503
13521
  });
13504
13522
  syncFilterFlaggedButton();
13523
+ syncFilterChip();
13505
13524
  var optPriorityOnly = document.getElementById("opt-priority-only");
13506
13525
  if (optPriorityOnly) {
13507
13526
  optPriorityOnly.checked = localStorage.getItem("mailx-priority-only") === "true";
@@ -13512,6 +13531,7 @@ if (optPriorityOnly) {
13512
13531
  if (optPriorityOnly.checked) body?.classList.add("priority-only");
13513
13532
  else body?.classList.remove("priority-only");
13514
13533
  localStorage.setItem("mailx-priority-only", String(optPriorityOnly.checked));
13534
+ syncFilterChip();
13515
13535
  });
13516
13536
  }
13517
13537
  document.addEventListener("mailx-clear-list-filters", () => {