@bobfrankston/rmfmail 1.2.241 → 1.2.243

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/client/android-bootstrap.bundle.js +24 -2
  2. package/client/android-bootstrap.bundle.js.map +2 -2
  3. package/client/app.bundle.js +59 -5
  4. package/client/app.bundle.js.map +3 -3
  5. package/client/app.js +6 -1
  6. package/client/app.js.map +1 -1
  7. package/client/app.ts +6 -1
  8. package/client/components/message-list.js +13 -2
  9. package/client/components/message-list.js.map +1 -1
  10. package/client/components/message-list.ts +13 -2
  11. package/client/components/message-viewer.js +110 -3
  12. package/client/components/message-viewer.js.map +1 -1
  13. package/client/components/message-viewer.ts +123 -3
  14. package/client/compose/compose.bundle.js +14 -0
  15. package/client/compose/compose.bundle.js.map +2 -2
  16. package/client/compose/compose.css +11 -0
  17. package/client/lib/rmf-tiny.js +14 -0
  18. package/package.json +7 -7
  19. package/packages/mailx-imap/index.d.ts +9 -0
  20. package/packages/mailx-imap/index.d.ts.map +1 -1
  21. package/packages/mailx-imap/index.js +86 -0
  22. package/packages/mailx-imap/index.js.map +1 -1
  23. package/packages/mailx-imap/index.ts +73 -0
  24. package/packages/mailx-imap/package-lock.json +2 -2
  25. package/packages/mailx-imap/package.json +1 -1
  26. package/packages/mailx-service/index.d.ts.map +1 -1
  27. package/packages/mailx-service/index.js +37 -4
  28. package/packages/mailx-service/index.js.map +1 -1
  29. package/packages/mailx-service/index.ts +34 -4
  30. package/packages/mailx-types/mime-inline-images.d.ts +0 -4
  31. package/packages/mailx-types/mime-inline-images.d.ts.map +1 -1
  32. package/packages/mailx-types/mime-inline-images.js +48 -4
  33. package/packages/mailx-types/mime-inline-images.js.map +1 -1
  34. package/packages/mailx-types/mime-inline-images.ts +45 -5
  35. package/packages/mailx-types/package.json +1 -1
  36. package/packages/mailx-types/test/inline-images.test.mjs +79 -0
  37. /package/packages/mailx-imap/{node_modules.npmglobalize-stash-26520 → node_modules.npmglobalize-stash-17784}/.package-lock.json +0 -0
@@ -1848,6 +1848,23 @@ function showPreviewBodyMenu(absX, absY, selectedText, sourceWindow, linkUrl, li
1848
1848
  );
1849
1849
  showContextMenu(absX, absY, items);
1850
1850
  }
1851
+ function renderBodyFetchGaveUp(bodyEl, accountId, uid, folderId, secs, previewText, specialUse, envelope) {
1852
+ const looksImapUidOnApiAccount = uid > 0 && uid < 1e9;
1853
+ const why = looksImapUidOnApiAccount ? `This message was indexed over IMAP, but its account fetches bodies through the Gmail API, which addresses messages by a different id. The body can't be requested for this row.` : `The server accepted the request but never returned the body.`;
1854
+ const snippet = previewText ? `<div class="mv-preview-placeholder">${escapeHtml3(previewText)}<div class="mv-tear-line"><span>\u2702 snippet \u2014 this is all that arrived \u2702</span></div></div>` : "";
1855
+ bodyEl.innerHTML = `${snippet}<div class="mv-system-message mv-system-error">
1856
+ <div class="mv-system-tag">rmfmail</div>
1857
+ <div class="mv-system-title">Body didn't arrive after ${secs}s \u2014 not still loading</div>
1858
+ <div class="mv-system-body">${escapeHtml3(why)}
1859
+ <div style="margin-top:8px;display:flex;gap:8px;flex-wrap:wrap">
1860
+ <button id="mv-body-retry" class="tb-btn">Try again</button>
1861
+ </div></div></div>`;
1862
+ bodyEl.querySelector("#mv-body-retry")?.addEventListener("click", () => {
1863
+ invalidateParsedCache(accountId, folderId, uid);
1864
+ showMessage(accountId, uid, folderId, specialUse, true, envelope).catch(() => {
1865
+ });
1866
+ });
1867
+ }
1851
1868
  function toggleFullscreenPreview() {
1852
1869
  const body = document.body;
1853
1870
  const on = !body.classList.contains("fullscreen-preview");
@@ -2205,8 +2222,14 @@ async function showMessage(accountId, uid, folderId, specialUse, isRetry = false
2205
2222
  span.textContent = secs >= 60 ? `(${Math.floor(secs / 60)}m ${secs % 60}s)` : `(${secs}s)`;
2206
2223
  if (secs === 30)
2207
2224
  span.classList.add("mv-wait-slow");
2225
+ if (secs >= WAIT_GIVE_UP_SECS) {
2226
+ clearInterval(tick);
2227
+ off?.();
2228
+ renderBodyFetchGaveUp(bodyEl, accountId, uid, folderId, secs, previewText, specialUse, envelope || cached || void 0);
2229
+ }
2208
2230
  }, 1e3);
2209
- const off = subscribeStore("*", (ev) => {
2231
+ let off;
2232
+ off = subscribeStore("*", (ev) => {
2210
2233
  if (ev.kind !== "bodyAvailable")
2211
2234
  return;
2212
2235
  if (ev.accountId !== accountId || ev.uid !== uid)
@@ -3480,7 +3503,10 @@ function buildPrintableDoc(m) {
3480
3503
  function printCurrentMessage() {
3481
3504
  if (!currentMessage)
3482
3505
  return;
3483
- const doc = buildPrintableDoc(currentMessage);
3506
+ printMessage(currentMessage);
3507
+ }
3508
+ function printMessage(msg) {
3509
+ const doc = buildPrintableDoc(msg);
3484
3510
  if (!doc)
3485
3511
  return;
3486
3512
  const iframe = document.createElement("iframe");
@@ -3581,6 +3607,30 @@ function spawnDesktopPopout(msg, accountId) {
3581
3607
  closeBtn.addEventListener("mouseleave", () => closeBtn.style.color = "#666");
3582
3608
  closeBtn.addEventListener("click", () => wrapper.remove());
3583
3609
  titleBar.appendChild(closeBtn);
3610
+ const actions = document.createElement("div");
3611
+ actions.style.cssText = "display:flex;gap:4px;padding:6px 10px;border-bottom:1px solid var(--color-border, #ddd);flex-shrink:0;flex-wrap:wrap;";
3612
+ const compose = (mode) => {
3613
+ document.dispatchEvent(new CustomEvent("mailx-compose", {
3614
+ detail: { mode, message: msg, accountId }
3615
+ }));
3616
+ };
3617
+ const mkBtn = (label, title, onClick) => {
3618
+ const b = document.createElement("button");
3619
+ b.className = "tb-btn";
3620
+ b.textContent = label;
3621
+ b.title = title;
3622
+ b.style.cssText = "padding:3px 10px;font-size:13px;cursor:pointer;";
3623
+ b.addEventListener("click", onClick);
3624
+ return b;
3625
+ };
3626
+ actions.appendChild(mkBtn("\u21A9 Reply", "Reply to the sender of this message", () => compose("reply")));
3627
+ actions.appendChild(mkBtn("\u21A9\u21A9 Reply All", "Reply to everyone on this message", () => compose("replyAll")));
3628
+ actions.appendChild(mkBtn("\u2192 Forward", "Forward this message", () => compose("forward")));
3629
+ actions.appendChild(mkBtn("\u270E Edit as new", "Open a copy of this message in compose \u2014 the way to rework and resend one you sent", () => compose("editAsNew")));
3630
+ const spacer = document.createElement("span");
3631
+ spacer.style.cssText = "flex:1;";
3632
+ actions.appendChild(spacer);
3633
+ actions.appendChild(mkBtn("\u{1F5A8}", "Print this message", () => printMessage(msg)));
3584
3634
  const headerInfo = document.createElement("div");
3585
3635
  headerInfo.style.cssText = "padding:8px 12px;border-bottom:1px solid var(--color-border, #ddd);font-size:13px;line-height:1.4;flex-shrink:0;";
3586
3636
  const formatAddrLocal = (a) => a.name ? `${a.name} <${a.address}>` : a.address;
@@ -3671,6 +3721,7 @@ function spawnDesktopPopout(msg, accountId) {
3671
3721
  wrapper.remove();
3672
3722
  }));
3673
3723
  wrapper.appendChild(titleBar);
3724
+ wrapper.appendChild(actions);
3674
3725
  wrapper.appendChild(headerInfo);
3675
3726
  wrapper.appendChild(toolbar);
3676
3727
  wrapper.appendChild(bodyContainer);
@@ -3679,7 +3730,7 @@ function spawnDesktopPopout(msg, accountId) {
3679
3730
  function escapeHtmlLocal(s) {
3680
3731
  return (s || "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
3681
3732
  }
3682
- var currentMessage, currentAccountId, dragOutUrls, showMessageGeneration, retryCount, lastEnvelope, PARSED_CACHE_LIMIT, parsedCache, sessionAllowedRemote, recentFetchErrors, ZOOM_KEY, ZOOM_MIN, ZOOM_MAX, ZOOM_STEP, previewZoom, RENDER_MARK_KEY, RENDER_MARK_MAX_AGE_MS, poisonedMessages, renderKey, PROGRESSIVE_TEXT_THRESHOLD, TEXT_CHUNK_BYTES;
3733
+ var currentMessage, currentAccountId, dragOutUrls, showMessageGeneration, retryCount, lastEnvelope, PARSED_CACHE_LIMIT, parsedCache, sessionAllowedRemote, recentFetchErrors, WAIT_GIVE_UP_SECS, ZOOM_KEY, ZOOM_MIN, ZOOM_MAX, ZOOM_STEP, previewZoom, RENDER_MARK_KEY, RENDER_MARK_MAX_AGE_MS, poisonedMessages, renderKey, PROGRESSIVE_TEXT_THRESHOLD, TEXT_CHUNK_BYTES;
3683
3734
  var init_message_viewer = __esm({
3684
3735
  "client/components/message-viewer.js"() {
3685
3736
  "use strict";
@@ -3698,6 +3749,7 @@ var init_message_viewer = __esm({
3698
3749
  parsedCache = /* @__PURE__ */ new Map();
3699
3750
  sessionAllowedRemote = /* @__PURE__ */ new Set();
3700
3751
  recentFetchErrors = /* @__PURE__ */ new Map();
3752
+ WAIT_GIVE_UP_SECS = 45;
3701
3753
  ZOOM_KEY = "mailx-preview-zoom";
3702
3754
  ZOOM_MIN = 0.5;
3703
3755
  ZOOM_MAX = 3;
@@ -4667,7 +4719,9 @@ async function loadSearchResults(query, scope = "all", accountId = "", folderId
4667
4719
  const partial = !!result.partial;
4668
4720
  const foldersFailed = result.foldersFailed || 0;
4669
4721
  const foldersSearched = result.foldersSearched || 0;
4670
- const partialNote = partial ? `<div class="ml-search-warning">\u26A0 Searched ${foldersSearched} folder(s); ${foldersFailed} could not be searched (timeout / connection). Results may be incomplete \u2014 retry to search them again.</div>` : "";
4722
+ const foldersGone = result.foldersGone || 0;
4723
+ const goneNote = foldersGone > 0 ? `<div class="ml-search-warning">Removed ${foldersGone} stale folder(s) that no longer exist on the server \u2014 they won't be searched again.</div>` : "";
4724
+ const partialNote = (partial && foldersFailed > 0 ? `<div class="ml-search-warning">\u26A0 Searched ${foldersSearched} folder(s); ${foldersFailed} timed out. Results may be incomplete \u2014 search again to retry those.</div>` : "") + goneNote;
4671
4725
  if (result.items.length === 0) {
4672
4726
  setMessages([]);
4673
4727
  body.innerHTML = partialNote + `<div class="ml-empty">No messages found by "${escapeHtmlText(query)}"${partial ? " in the folders that responded" : ""}</div>`;
@@ -10312,7 +10366,7 @@ document.addEventListener("mailx-compose", ((e) => {
10312
10366
  if (e.detail.mode === "draft" && sessionStorage.getItem("composeInit")) {
10313
10367
  showComposeOverlay();
10314
10368
  } else {
10315
- openCompose(e.detail.mode);
10369
+ openCompose(e.detail.mode, e.detail.message, e.detail.accountId);
10316
10370
  }
10317
10371
  }));
10318
10372
  document.addEventListener("mailx-delete", () => deleteSelection());