@bobfrankston/rmfmail 1.2.173 → 1.2.175

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 (42) hide show
  1. package/TODO.md +3 -3
  2. package/bin/build-rmfshare-exe.js +79 -0
  3. package/bin/mailx.js +52 -1
  4. package/bin/mailx.js.map +1 -1
  5. package/bin/mailx.ts +51 -1
  6. package/bin/rmfshare-src/Program.cs +225 -0
  7. package/bin/rmfshare-src/rmfshare.csproj +36 -0
  8. package/bin/rmfshare.exe +0 -0
  9. package/bin/share-target.js +314 -0
  10. package/bin/share-target.js.map +1 -0
  11. package/bin/share-target.ts +331 -0
  12. package/client/app.bundle.js +62 -0
  13. package/client/app.bundle.js.map +3 -3
  14. package/client/app.js +69 -0
  15. package/client/app.js.map +1 -1
  16. package/client/app.ts +72 -0
  17. package/client/compose/compose.bundle.js +4 -0
  18. package/client/compose/compose.bundle.js.map +2 -2
  19. package/client/lib/api-client.js +7 -0
  20. package/client/lib/api-client.js.map +1 -1
  21. package/client/lib/api-client.ts +12 -0
  22. package/client/package.json +1 -1
  23. package/package.json +6 -6
  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 +22 -0
  27. package/packages/mailx-service/index.d.ts.map +1 -1
  28. package/packages/mailx-service/index.js +82 -0
  29. package/packages/mailx-service/index.js.map +1 -1
  30. package/packages/mailx-service/index.ts +76 -0
  31. package/packages/mailx-service/jsonrpc.js +2 -0
  32. package/packages/mailx-service/jsonrpc.js.map +1 -1
  33. package/packages/mailx-service/jsonrpc.ts +2 -0
  34. package/packages/mailx-service/package.json +1 -1
  35. package/packages/mailx-settings/package.json +1 -1
  36. package/packages/mailx-store/package.json +1 -1
  37. package/packages/mailx-store-web/package.json +1 -1
  38. package/packages/mailx-types/mailx-api.d.ts +3 -0
  39. package/packages/mailx-types/mailx-api.d.ts.map +1 -1
  40. package/packages/mailx-types/mailx-api.ts +3 -0
  41. package/packages/mailx-types/package.json +1 -1
  42. /package/packages/mailx-imap/{node_modules.npmglobalize-stash-7284 → node_modules.npmglobalize-stash-33656}/.package-lock.json +0 -0
package/client/app.ts CHANGED
@@ -3495,6 +3495,19 @@ onWsEvent((event) => {
3495
3495
  }).catch((e: any) => console.error("openComposeFromMailto failed:", e?.message || e));
3496
3496
  break;
3497
3497
  }
3498
+ case "openShare": {
3499
+ // C46: Windows Share sheet → rmfmail. rmfshare.exe staged the
3500
+ // shared content; the daemon base64'd any files and pushed this
3501
+ // event. Open compose with the content attached/inlined.
3502
+ openComposeFromShare({
3503
+ title: event.title || "",
3504
+ text: event.text || "",
3505
+ url: event.url || "",
3506
+ attachments: Array.isArray(event.attachments) ? event.attachments : [],
3507
+ skipped: Array.isArray(event.skipped) ? event.skipped : [],
3508
+ }).catch((e: any) => console.error("openComposeFromShare failed:", e?.message || e));
3509
+ break;
3510
+ }
3498
3511
  case "debugEval": {
3499
3512
  // --debug-server /api/eval: the daemon pushes {id, code}; we
3500
3513
  // evaluate in the live page and answer via debugEvalResult. This
@@ -3602,6 +3615,50 @@ async function openComposeFromMailto(m: {
3602
3615
  try { frame?.contentWindow?.postMessage({ type: "compose-init-ready" }, "*"); } catch { /* */ }
3603
3616
  }
3604
3617
 
3618
+ /** C46: open compose from a Windows Share sheet drop. Shared files become
3619
+ * attachments; shared text/links become the body; a shared page title (or
3620
+ * the first filename) seeds the subject. Skipped files (oversize or
3621
+ * unreadable) are called out in the body — the user must see that a file
3622
+ * they shared is NOT on the outgoing message. */
3623
+ async function openComposeFromShare(s: {
3624
+ title: string; text: string; url: string;
3625
+ attachments: { filename: string; mimeType: string; dataBase64: string }[];
3626
+ skipped: { name: string; reason: string }[];
3627
+ }): Promise<void> {
3628
+ const accountsP = getAccounts();
3629
+ let subject = s.title;
3630
+ if (!subject && s.attachments.length) {
3631
+ subject = s.attachments[0].filename +
3632
+ (s.attachments.length > 1 ? ` (+${s.attachments.length - 1} more)` : "");
3633
+ }
3634
+ const frame = showComposeOverlay(subject ? `Compose: ${subject}` : "Compose");
3635
+ const accounts = await accountsP;
3636
+ const escape = (str: string) => str.replace(/[&<>]/g, c =>
3637
+ ({ "&": "&amp;", "<": "&lt;", ">": "&gt;" }[c]!));
3638
+ const paras: string[] = [];
3639
+ if (s.text && s.text !== s.url) {
3640
+ paras.push("<p>" + escape(s.text).replace(/\r?\n/g, "</p><p>") + "</p>");
3641
+ }
3642
+ if (s.url) {
3643
+ const u = escape(s.url);
3644
+ paras.push(`<p><a href="${u}">${u}</a></p>`);
3645
+ }
3646
+ for (const sk of s.skipped) {
3647
+ paras.push(`<p>[Attachment "${escape(sk.name)}" was not added — ${escape(sk.reason)}]</p>`);
3648
+ }
3649
+ const init: any = {
3650
+ mode: "new",
3651
+ accountId: accounts[0]?.id || "",
3652
+ to: [], cc: [], bcc: [],
3653
+ subject,
3654
+ bodyHtml: paras.join(""),
3655
+ attachments: s.attachments,
3656
+ accounts: accounts.map((a: any) => ({ id: a.id, name: a.name, email: a.email, signature: a.signature, sig: a.sig })),
3657
+ };
3658
+ sessionStorage.setItem("composeInit", JSON.stringify(init));
3659
+ try { frame?.contentWindow?.postMessage({ type: "compose-init-ready" }, "*"); } catch { /* */ }
3660
+ }
3661
+
3605
3662
  // ── Keyboard shortcuts ──
3606
3663
 
3607
3664
  // Capture-phase pre-handler: intercept WebView accelerator keys that would
@@ -4447,6 +4504,21 @@ function applyThreadFilter(): void {
4447
4504
  }
4448
4505
  })();
4449
4506
 
4507
+ // C46: same startup pickup for a pending Windows-share drop (rmfshare.exe
4508
+ // spawned the daemon before its fs.watch armed). Live shares during this
4509
+ // session arrive via the `openShare` event handled in onEvent above.
4510
+ (async () => {
4511
+ try {
4512
+ const { consumePendingShare } = await import("./lib/api-client.js");
4513
+ const data = await consumePendingShare();
4514
+ if (data && (data.attachments.length || data.text || data.url || data.title || data.skipped.length)) {
4515
+ await openComposeFromShare(data);
4516
+ }
4517
+ } catch (e: any) {
4518
+ console.error("pending share pickup failed:", e?.message || e);
4519
+ }
4520
+ })();
4521
+
4450
4522
  // Two-line toggle
4451
4523
  optTwoLine?.addEventListener("change", () => {
4452
4524
  const list = document.getElementById("message-list");
@@ -1029,6 +1029,7 @@ __export(api_client_exports, {
1029
1029
  connectEvents: () => connectEvents,
1030
1030
  connectWebSocket: () => connectWebSocket,
1031
1031
  consumePendingMailto: () => consumePendingMailto,
1032
+ consumePendingShare: () => consumePendingShare,
1032
1033
  consumePopoutComposeInit: () => consumePopoutComposeInit,
1033
1034
  copyMessages: () => copyMessages,
1034
1035
  createCalendarEvent: () => createCalendarEvent,
@@ -1615,6 +1616,9 @@ function showReminderPopup(opts) {
1615
1616
  function consumePendingMailto() {
1616
1617
  return ipc().consumePendingMailto?.() ?? Promise.resolve(null);
1617
1618
  }
1619
+ function consumePendingShare() {
1620
+ return ipc().consumePendingShare?.() ?? Promise.resolve(null);
1621
+ }
1618
1622
  function aiTransform(req) {
1619
1623
  return ipc().aiTransform?.(req) ?? Promise.resolve({ text: "", reason: "AI not available in this host" });
1620
1624
  }