@bobfrankston/rmfmail 1.2.252 → 1.2.254

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 (49) hide show
  1. package/client/android-bootstrap.bundle.js +29 -31
  2. package/client/android-bootstrap.bundle.js.map +2 -2
  3. package/client/app.bundle.js +23 -0
  4. package/client/app.bundle.js.map +3 -3
  5. package/client/app.js +26 -0
  6. package/client/app.js.map +1 -1
  7. package/client/app.ts +24 -0
  8. package/client/compose/compose.bundle.js +37 -3
  9. package/client/compose/compose.bundle.js.map +3 -3
  10. package/client/compose/compose.css +13 -0
  11. package/client/compose/compose.js +41 -1
  12. package/client/compose/compose.js.map +1 -1
  13. package/client/compose/compose.ts +38 -1
  14. package/client/lib/api-client.js +7 -0
  15. package/client/lib/api-client.js.map +1 -1
  16. package/client/lib/api-client.ts +8 -0
  17. package/client/lib/mailxapi.js +10 -2
  18. package/package.json +5 -5
  19. package/packages/mailx-imap/package-lock.json +2 -2
  20. package/packages/mailx-imap/package.json +1 -1
  21. package/packages/mailx-service/index.d.ts +19 -1
  22. package/packages/mailx-service/index.d.ts.map +1 -1
  23. package/packages/mailx-service/index.js +27 -2
  24. package/packages/mailx-service/index.js.map +1 -1
  25. package/packages/mailx-service/index.ts +28 -2
  26. package/packages/mailx-service/jsonrpc.js +3 -1
  27. package/packages/mailx-service/jsonrpc.js.map +1 -1
  28. package/packages/mailx-service/jsonrpc.ts +3 -1
  29. package/packages/mailx-service/package.json +1 -1
  30. package/packages/mailx-settings/package.json +1 -1
  31. package/packages/mailx-store/package.json +1 -1
  32. package/packages/mailx-store-web/android-bootstrap.js +1 -1
  33. package/packages/mailx-store-web/android-bootstrap.js.map +1 -1
  34. package/packages/mailx-store-web/android-bootstrap.ts +1 -1
  35. package/packages/mailx-store-web/package.json +1 -1
  36. package/packages/mailx-store-web/web-service.d.ts +5 -1
  37. package/packages/mailx-store-web/web-service.d.ts.map +1 -1
  38. package/packages/mailx-store-web/web-service.js +5 -1
  39. package/packages/mailx-store-web/web-service.js.map +1 -1
  40. package/packages/mailx-store-web/web-service.ts +5 -1
  41. package/packages/mailx-types/mailx-api.d.ts +17 -1
  42. package/packages/mailx-types/mailx-api.d.ts.map +1 -1
  43. package/packages/mailx-types/mailx-api.ts +10 -1
  44. package/packages/mailx-types/mime-build.d.ts.map +1 -1
  45. package/packages/mailx-types/mime-build.js +42 -30
  46. package/packages/mailx-types/mime-build.js.map +1 -1
  47. package/packages/mailx-types/mime-build.ts +51 -32
  48. package/packages/mailx-types/package.json +1 -1
  49. /package/packages/mailx-imap/{node_modules.npmglobalize-stash-85680 → node_modules.npmglobalize-stash-77932}/.package-lock.json +0 -0
package/client/app.ts CHANGED
@@ -6066,6 +6066,30 @@ document.addEventListener("mailx-popout-message", (async (e: any) => {
6066
6066
  draftFolderId: msg.folderId,
6067
6067
  draftId: msg.mailxDraftId || "",
6068
6068
  };
6069
+ // Reopening a draft must bring its attachments back into compose,
6070
+ // exactly as forward / edit-as-new do. Drafts had none to bring until
6071
+ // saveDraft started including them (2026-08-11); without this, editing
6072
+ // a draft and re-saving would strip the files a second time.
6073
+ if (Array.isArray(msg.attachments) && msg.attachments.length) {
6074
+ const loaded: { filename: string; mimeType: string; dataBase64: string }[] = [];
6075
+ for (const att of msg.attachments) {
6076
+ try {
6077
+ const data = await getAttachment(accountId, msg.uid, att.id, msg.folderId);
6078
+ if (data?.content) {
6079
+ loaded.push({
6080
+ filename: data.filename || att.filename || "attachment",
6081
+ mimeType: data.contentType || att.contentType || "application/octet-stream",
6082
+ dataBase64: data.content,
6083
+ });
6084
+ }
6085
+ } catch (e: any) {
6086
+ // Loud: a dropped attachment here means the next autosave
6087
+ // writes a draft without it.
6088
+ console.error(`[compose] edit draft: failed to load attachment ${att.id} ("${att.filename}"): ${e?.message || e}`);
6089
+ }
6090
+ }
6091
+ if (loaded.length) (init as any).attachments = loaded;
6092
+ }
6069
6093
  sessionStorage.setItem("composeInit", JSON.stringify(init));
6070
6094
  showComposeOverlay(msg.subject ? `Edit: ${msg.subject}` : "Edit draft");
6071
6095
  return;
@@ -1093,6 +1093,7 @@ __export(api_client_exports, {
1093
1093
  openInTextEditor: () => openInTextEditor,
1094
1094
  openInWord: () => openInWord,
1095
1095
  openLocalPath: () => openLocalPath,
1096
+ openPendingAttachment: () => openPendingAttachment,
1096
1097
  popoutCompose: () => popoutCompose,
1097
1098
  popoutMainWindow: () => popoutMainWindow,
1098
1099
  popoutWindow: () => popoutWindow,
@@ -1656,6 +1657,10 @@ async function openAttachment(accountId, uid, attachmentId, folderId, filename)
1656
1657
  const fn = ipc().openAttachment;
1657
1658
  return fn ? fn(accountId, uid, attachmentId, folderId, filename) : void 0;
1658
1659
  }
1660
+ async function openPendingAttachment(filename, mimeType, dataBase64) {
1661
+ const fn = ipc().openPendingAttachment;
1662
+ return fn ? fn(filename, mimeType, dataBase64) : void 0;
1663
+ }
1659
1664
  async function getMessageSource(accountId, uid, folderId) {
1660
1665
  return ipc().getMessageSource(accountId, uid, folderId);
1661
1666
  }
@@ -6002,7 +6007,13 @@ function getContentSnapshot() {
6002
6007
  to: toInput?.value || "",
6003
6008
  cc: ccInput?.value || "",
6004
6009
  bcc: bccInput?.value || "",
6005
- subject: subjectInput?.value || ""
6010
+ subject: subjectInput?.value || "",
6011
+ // Attaching or removing a file IS a change. Without it here, adding an
6012
+ // attachment to an otherwise-untouched draft left the snapshot equal
6013
+ // and autosave skipped the save entirely. Fingerprint only — the
6014
+ // base64 would make this string megabytes and it is compared on every
6015
+ // 5s tick.
6016
+ atts: attachments.map((a) => `${a.filename}:${a.size}`).join("|")
6006
6017
  });
6007
6018
  }
6008
6019
  function recordContentBaseline() {
@@ -6050,7 +6061,11 @@ async function saveDraft2() {
6050
6061
  cc: ccInput.value,
6051
6062
  bcc: bccInput.value,
6052
6063
  previousDraftUid: draftUid,
6053
- draftId
6064
+ draftId,
6065
+ // Same shape the send path uses. Omitted until 2026-08-11, which
6066
+ // meant a draft never carried its attachments — reopening one
6067
+ // silently lost them.
6068
+ attachments: attachments.map((a) => ({ filename: a.filename, mimeType: a.mimeType, dataBase64: a.dataBase64 }))
6054
6069
  });
6055
6070
  if (data?.draftUid) draftUid = data.draftUid;
6056
6071
  if (data?.draftId) draftId = data.draftId;
@@ -6593,7 +6608,25 @@ function renderAttachmentChips() {
6593
6608
  const a = attachments[i];
6594
6609
  const chip = document.createElement("span");
6595
6610
  chip.className = "compose-att-chip";
6596
- chip.innerHTML = `\u{1F4CE} ${escapeHtml2(a.filename)} (${formatSize(a.size)}) `;
6611
+ const open = document.createElement("button");
6612
+ open.type = "button";
6613
+ open.className = "compose-att-open";
6614
+ open.title = `Open ${a.filename}`;
6615
+ open.textContent = `\u{1F4CE} ${a.filename} (${formatSize(a.size)})`;
6616
+ open.addEventListener("click", async () => {
6617
+ const was = open.textContent;
6618
+ open.textContent = `\u{1F4CE} Opening ${a.filename}\u2026`;
6619
+ try {
6620
+ const { openPendingAttachment: openPendingAttachment2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
6621
+ const r = await openPendingAttachment2(a.filename, a.mimeType, a.dataBase64);
6622
+ if (!r?.ok) throw new Error("the host could not open it");
6623
+ } catch (e) {
6624
+ showDraftStatus(`Couldn't open "${a.filename}": ${e?.message || e}`, true);
6625
+ } finally {
6626
+ open.textContent = was;
6627
+ }
6628
+ });
6629
+ chip.appendChild(open);
6597
6630
  const rm = document.createElement("button");
6598
6631
  rm.type = "button";
6599
6632
  rm.title = "Remove attachment";
@@ -6601,6 +6634,7 @@ function renderAttachmentChips() {
6601
6634
  rm.addEventListener("click", () => {
6602
6635
  attachments.splice(i, 1);
6603
6636
  renderAttachmentChips();
6637
+ void saveDraft2();
6604
6638
  });
6605
6639
  chip.appendChild(rm);
6606
6640
  attEl.appendChild(chip);