@bobfrankston/rmfmail 1.1.228 → 1.1.231

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 (41) hide show
  1. package/client/android-bootstrap.bundle.js +4 -1
  2. package/client/android-bootstrap.bundle.js.map +2 -2
  3. package/client/app.bundle.js +54 -20
  4. package/client/app.bundle.js.map +2 -2
  5. package/client/app.js +42 -7
  6. package/client/app.js.map +1 -1
  7. package/client/app.ts +43 -7
  8. package/client/components/message-viewer.js +30 -9
  9. package/client/components/message-viewer.js.map +1 -1
  10. package/client/components/message-viewer.ts +28 -9
  11. package/client/compose/compose.bundle.js +9 -9
  12. package/client/compose/compose.bundle.js.map +2 -2
  13. package/client/compose/compose.js +2 -2
  14. package/client/compose/compose.js.map +1 -1
  15. package/client/compose/compose.ts +2 -2
  16. package/client/lib/api-client.js +7 -7
  17. package/client/lib/api-client.js.map +1 -1
  18. package/client/lib/api-client.ts +7 -7
  19. package/client/lib/mailxapi.js +4 -4
  20. package/package.json +5 -5
  21. package/packages/mailx-service/index.d.ts +3 -3
  22. package/packages/mailx-service/index.d.ts.map +1 -1
  23. package/packages/mailx-service/index.js +148 -29
  24. package/packages/mailx-service/index.js.map +1 -1
  25. package/packages/mailx-service/index.ts +135 -23
  26. package/packages/mailx-service/jsonrpc.js +3 -3
  27. package/packages/mailx-service/jsonrpc.js.map +1 -1
  28. package/packages/mailx-service/jsonrpc.ts +3 -3
  29. package/packages/mailx-store/db.d.ts.map +1 -1
  30. package/packages/mailx-store/db.js +30 -8
  31. package/packages/mailx-store/db.js.map +1 -1
  32. package/packages/mailx-store/db.ts +27 -8
  33. package/packages/mailx-types/index.d.ts +7 -3
  34. package/packages/mailx-types/index.d.ts.map +1 -1
  35. package/packages/mailx-types/index.js.map +1 -1
  36. package/packages/mailx-types/index.ts +7 -3
  37. package/packages/mailx-types/mailx-api.d.ts +1 -1
  38. package/packages/mailx-types/mailx-api.d.ts.map +1 -1
  39. package/packages/mailx-types/mailx-api.ts +1 -1
  40. package/tsconfig.base.json +1 -0
  41. package/packages/mailx-imap/node_modules.npmglobalize-stash-126048/.package-lock.json +0 -116
@@ -329,13 +329,13 @@ function removeUserDictWord(word) {
329
329
  function flagSenderOrDomain(type, value) {
330
330
  return ipc().flagSenderOrDomain?.(type, value) ?? Promise.resolve({ flagged: false });
331
331
  }
332
- function deleteMessage(accountId, uid) {
333
- return ipc().deleteMessage?.(accountId, uid);
332
+ function deleteMessage(accountId, uid, folderId) {
333
+ return ipc().deleteMessage?.(accountId, uid, folderId);
334
334
  }
335
- function deleteMessages(accountId, uids) {
335
+ function deleteMessages(accountId, uids, folderIds) {
336
336
  if (uids.length === 1)
337
- return deleteMessage(accountId, uids[0]);
338
- return ipc().deleteMessages?.(accountId, uids);
337
+ return deleteMessage(accountId, uids[0], folderIds?.[0]);
338
+ return ipc().deleteMessages?.(accountId, uids, folderIds);
339
339
  }
340
340
  function moveMessages(accountId, uids, targetFolderId, targetAccountId) {
341
341
  if (uids.length === 1)
@@ -600,9 +600,9 @@ function setupAccount(name, email, password) {
600
600
  async function getAttachment(accountId, uid, attachmentId, folderId) {
601
601
  return ipc().getAttachment(accountId, uid, attachmentId, folderId);
602
602
  }
603
- async function openAttachment(accountId, uid, attachmentId, folderId) {
603
+ async function openAttachment(accountId, uid, attachmentId, folderId, filename) {
604
604
  const fn = ipc().openAttachment;
605
- return fn ? fn(accountId, uid, attachmentId, folderId) : void 0;
605
+ return fn ? fn(accountId, uid, attachmentId, folderId, filename) : void 0;
606
606
  }
607
607
  async function getDeviceAccounts() {
608
608
  return ipc().getDeviceAccounts?.() ?? [];
@@ -1816,14 +1816,30 @@ async function showMessage(accountId, uid, folderId, specialUse, isRetry = false
1816
1816
  attEl.hidden = false;
1817
1817
  const saveAttachmentAt = async (idx) => {
1818
1818
  const a0 = msg.attachments[idx];
1819
+ const name = a0.filename || "attachment";
1819
1820
  try {
1820
- const data = await getAttachment(accountId, uid, idx, msg.folderId);
1821
+ const data = await getAttachment(accountId, uid, a0.id, msg.folderId);
1821
1822
  const bytes = Uint8Array.from(atob(data.content), (c) => c.charCodeAt(0));
1822
1823
  const blob = new Blob([bytes], { type: data.contentType || "application/octet-stream" });
1824
+ const picker = window.showSaveFilePicker;
1825
+ if (typeof picker === "function") {
1826
+ let handle;
1827
+ try {
1828
+ handle = await picker({ suggestedName: name });
1829
+ } catch (e) {
1830
+ if (e?.name === "AbortError")
1831
+ return;
1832
+ throw e;
1833
+ }
1834
+ const writable = await handle.createWritable();
1835
+ await writable.write(blob);
1836
+ await writable.close();
1837
+ return;
1838
+ }
1823
1839
  const url = URL.createObjectURL(blob);
1824
1840
  const a = document.createElement("a");
1825
1841
  a.href = url;
1826
- a.download = a0.filename || "attachment";
1842
+ a.download = name;
1827
1843
  a.style.display = "none";
1828
1844
  document.body.appendChild(a);
1829
1845
  a.click();
@@ -1832,7 +1848,7 @@ async function showMessage(accountId, uid, folderId, specialUse, isRetry = false
1832
1848
  URL.revokeObjectURL(url);
1833
1849
  }, 5e3);
1834
1850
  } catch (err) {
1835
- window.dispatchEvent(new CustomEvent("mailx-alert", { detail: { message: `Couldn't save "${a0.filename}": ${err?.message || err}`, key: "attachment-save" } }));
1851
+ window.dispatchEvent(new CustomEvent("mailx-alert", { detail: { message: `Couldn't save "${name}": ${err?.message || err}`, key: "attachment-save" } }));
1836
1852
  }
1837
1853
  };
1838
1854
  const saveAllAttachments = async () => {
@@ -1866,14 +1882,14 @@ async function showMessage(accountId, uid, folderId, specialUse, isRetry = false
1866
1882
  try {
1867
1883
  const bridge = window._nativeBridge;
1868
1884
  if (bridge?.openAttachment) {
1869
- const data2 = await getAttachment(accountId, uid, i, msg.folderId);
1885
+ const data2 = await getAttachment(accountId, uid, att.id, msg.folderId);
1870
1886
  await bridge.openAttachment(att.filename, data2.contentType, data2.content);
1871
1887
  return;
1872
1888
  }
1873
- const res = await openAttachment(accountId, uid, i, msg.folderId);
1889
+ const res = await openAttachment(accountId, uid, att.id, msg.folderId, att.filename);
1874
1890
  if (res)
1875
1891
  return;
1876
- const data = await getAttachment(accountId, uid, i, msg.folderId);
1892
+ const data = await getAttachment(accountId, uid, att.id, msg.folderId);
1877
1893
  const bytes = Uint8Array.from(atob(data.content), (c) => c.charCodeAt(0));
1878
1894
  const blob = new Blob([bytes], { type: data.contentType });
1879
1895
  const url = URL.createObjectURL(blob);
@@ -1900,7 +1916,7 @@ async function showMessage(accountId, uid, folderId, specialUse, isRetry = false
1900
1916
  if (!e.dataTransfer)
1901
1917
  return;
1902
1918
  try {
1903
- const data = await getAttachment(accountId, uid, i, msg.folderId);
1919
+ const data = await getAttachment(accountId, uid, att.id, msg.folderId);
1904
1920
  const bytes = Uint8Array.from(atob(data.content), (c) => c.charCodeAt(0));
1905
1921
  const blob = new Blob([bytes], { type: data.contentType || "application/octet-stream" });
1906
1922
  const url = URL.createObjectURL(blob);
@@ -7407,6 +7423,18 @@ function refreshSyncTooltip() {
7407
7423
  }).join("\n");
7408
7424
  }
7409
7425
  setInterval(refreshSyncTooltip, 3e4);
7426
+ var syncSettleTimer = null;
7427
+ var SYNC_SETTLE_MS = 4e3;
7428
+ function scheduleSyncedStamp() {
7429
+ if (syncSettleTimer) clearTimeout(syncSettleTimer);
7430
+ syncSettleTimer = setTimeout(() => {
7431
+ syncSettleTimer = null;
7432
+ const el = document.getElementById("status-sync");
7433
+ if (el && (el.textContent || "").startsWith("Syncing")) {
7434
+ el.textContent = `Synced ${(/* @__PURE__ */ new Date()).toLocaleTimeString(void 0, { hour: "2-digit", minute: "2-digit", hour12: false })}`;
7435
+ }
7436
+ }, SYNC_SETTLE_MS);
7437
+ }
7410
7438
  var messageList = document.getElementById("message-list");
7411
7439
  if (messageList) {
7412
7440
  const twoLineThreshold = 600;
@@ -7993,12 +8021,13 @@ async function deleteSelectedMessages() {
7993
8021
  }
7994
8022
  const byAccount = /* @__PURE__ */ new Map();
7995
8023
  for (const msg of snapshot) {
7996
- const uids = byAccount.get(msg.accountId) || [];
7997
- uids.push(msg.uid);
7998
- byAccount.set(msg.accountId, uids);
8024
+ const g = byAccount.get(msg.accountId) || { uids: [], folderIds: [] };
8025
+ g.uids.push(msg.uid);
8026
+ g.folderIds.push(msg.folderId);
8027
+ byAccount.set(msg.accountId, g);
7999
8028
  }
8000
- for (const [accountId, uids] of byAccount) {
8001
- deleteMessages(accountId, uids).catch((e) => {
8029
+ for (const [accountId, g] of byAccount) {
8030
+ deleteMessages(accountId, g.uids, g.folderIds).catch((e) => {
8002
8031
  console.error(`Delete failed for ${accountId}: ${e?.message || e}`);
8003
8032
  if (statusSync) statusSync.textContent = `Delete sync issue (${accountId}): ${e?.message || e}`;
8004
8033
  });
@@ -8934,6 +8963,7 @@ onWsEvent((event) => {
8934
8963
  }
8935
8964
  if (statusSync) statusSync.textContent = `Syncing ${event.accountId}: ${label}`;
8936
8965
  if (startupStatus) startupStatus.textContent = `Syncing ${event.accountId}: ${label}`;
8966
+ scheduleSyncedStamp();
8937
8967
  const syncPath = event.phase?.startsWith("sync:") ? event.phase.slice(5) : null;
8938
8968
  document.querySelectorAll(`.ft-folder.ft-syncing[data-account-id="${event.accountId}"]`).forEach((el) => el.classList.remove("ft-syncing"));
8939
8969
  if (syncPath && event.progress < 100) {
@@ -8953,6 +8983,7 @@ onWsEvent((event) => {
8953
8983
  case "syncComplete":
8954
8984
  refreshFolderTree();
8955
8985
  recordAccountSync(event.accountId);
8986
+ scheduleSyncedStamp();
8956
8987
  break;
8957
8988
  case "folderSynced":
8958
8989
  for (const entry of event.entries || []) {
@@ -8977,7 +9008,10 @@ onWsEvent((event) => {
8977
9008
  syncBtn.disabled = false;
8978
9009
  syncBtn.classList.remove("syncing");
8979
9010
  }
8980
- if (statusSync) statusSync.textContent = `Synced ${(/* @__PURE__ */ new Date()).toLocaleTimeString(void 0, { hour: "2-digit", minute: "2-digit", hour12: false })}`;
9011
+ if (statusSync && !(statusSync.textContent || "").startsWith("Sync error")) {
9012
+ statusSync.textContent = "Syncing\u2026";
9013
+ }
9014
+ scheduleSyncedStamp();
8981
9015
  break;
8982
9016
  }
8983
9017
  case "updateAvailable": {