@bobfrankston/rmfmail 1.2.274 → 1.2.276

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 (33) hide show
  1. package/.commitmsg +26 -0
  2. package/client/android-bootstrap.bundle.js +169 -0
  3. package/client/android-bootstrap.bundle.js.map +2 -2
  4. package/client/app.bundle.js +123 -23
  5. package/client/app.bundle.js.map +4 -4
  6. package/client/app.js +16 -1
  7. package/client/app.js.map +1 -1
  8. package/client/app.ts +16 -1
  9. package/client/components/invite-card.js +107 -0
  10. package/client/components/invite-card.js.map +1 -0
  11. package/client/components/invite-card.ts +119 -0
  12. package/client/components/message-viewer.js +42 -17
  13. package/client/components/message-viewer.js.map +1 -1
  14. package/client/components/message-viewer.ts +42 -16
  15. package/client/package.json +1 -1
  16. package/client/styles/components.css +48 -0
  17. package/package.json +8 -8
  18. package/packages/mailx-imap/package-lock.json +2 -2
  19. package/packages/mailx-imap/package.json +2 -2
  20. package/packages/mailx-settings/package.json +1 -1
  21. package/packages/mailx-store/package.json +1 -1
  22. package/packages/mailx-store/store.d.ts +5 -0
  23. package/packages/mailx-store/store.d.ts.map +1 -1
  24. package/packages/mailx-store/store.js +21 -0
  25. package/packages/mailx-store/store.js.map +1 -1
  26. package/packages/mailx-store/store.ts +27 -0
  27. package/packages/mailx-types/index.d.ts +56 -0
  28. package/packages/mailx-types/index.d.ts.map +1 -1
  29. package/packages/mailx-types/index.js +187 -0
  30. package/packages/mailx-types/index.js.map +1 -1
  31. package/packages/mailx-types/index.ts +192 -0
  32. package/packages/mailx-types/package.json +1 -1
  33. /package/packages/mailx-imap/{node_modules.npmglobalize-stash-31304 → node_modules.npmglobalize-stash-59216}/.package-lock.json +0 -0
@@ -1467,6 +1467,11 @@ function formatSender(addr) {
1467
1467
  return { text: address, claimed: null };
1468
1468
  return { text: `${name} <${address}>`, claimed: displayNameClaimsOtherAddress(name, address) };
1469
1469
  }
1470
+ function inviteHasGoogleRsvp(bodyHtml) {
1471
+ if (!bodyHtml)
1472
+ return false;
1473
+ return /calendar\.google\.com\/calendar\/event\?action=RESPOND/i.test(bodyHtml);
1474
+ }
1470
1475
  var _SEEN, _FLAGGED, _DRAFT, seenOf, flaggedOf, draftOf, setSeen, setFlagged;
1471
1476
  var init_mailx_types = __esm({
1472
1477
  "packages/mailx-types/index.js"() {
@@ -1488,6 +1493,100 @@ var init_mailx_types = __esm({
1488
1493
  }
1489
1494
  });
1490
1495
 
1496
+ // client/components/invite-card.js
1497
+ function formatWhen(inv) {
1498
+ if (!inv.start)
1499
+ return "";
1500
+ if (inv.allDay) {
1501
+ try {
1502
+ const d = /* @__PURE__ */ new Date(inv.start + "T00:00:00");
1503
+ return d.toLocaleDateString(void 0, { weekday: "long", year: "numeric", month: "long", day: "numeric" }) + " (all day)";
1504
+ } catch {
1505
+ return inv.start + " (all day)";
1506
+ }
1507
+ }
1508
+ const instant = (() => {
1509
+ if (/Z$/.test(inv.start))
1510
+ return new Date(inv.start);
1511
+ if (!inv.tzid)
1512
+ return new Date(inv.start);
1513
+ try {
1514
+ const guess = /* @__PURE__ */ new Date(inv.start + "Z");
1515
+ const asZone = new Date(guess.toLocaleString("en-US", { timeZone: inv.tzid }));
1516
+ const asUtc = new Date(guess.toLocaleString("en-US", { timeZone: "UTC" }));
1517
+ return new Date(guess.getTime() + (asUtc.getTime() - asZone.getTime()));
1518
+ } catch {
1519
+ return new Date(inv.start);
1520
+ }
1521
+ })();
1522
+ if (isNaN(instant.getTime()))
1523
+ return inv.start;
1524
+ const localZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
1525
+ const opts = {
1526
+ weekday: "short",
1527
+ month: "short",
1528
+ day: "numeric",
1529
+ hour: "numeric",
1530
+ minute: "2-digit"
1531
+ };
1532
+ let out = instant.toLocaleString(void 0, opts);
1533
+ if (inv.end && !/Z$/.test(inv.end)) {
1534
+ try {
1535
+ const endInstant = new Date(instant.getTime() + ((/* @__PURE__ */ new Date(inv.end + "Z")).getTime() - (/* @__PURE__ */ new Date(inv.start + "Z")).getTime()));
1536
+ out += " \u2013 " + endInstant.toLocaleString(void 0, { hour: "numeric", minute: "2-digit" });
1537
+ } catch {
1538
+ }
1539
+ }
1540
+ if (inv.tzid && inv.tzid !== localZone) {
1541
+ out += ` (sent as ${inv.start.slice(11, 16)} ${inv.tzid})`;
1542
+ }
1543
+ return out;
1544
+ }
1545
+ function buildInviteCard(inv, bodyHtml) {
1546
+ if (!inv || !inv.summary && !inv.start)
1547
+ return null;
1548
+ const card = document.createElement("div");
1549
+ card.className = "mv-invite";
1550
+ if (inv.method === "CANCEL")
1551
+ card.classList.add("mv-invite-cancelled");
1552
+ const when = formatWhen(inv);
1553
+ const isMeetLink = /^https?:/;
1554
+ const googleHandles = inv.fromGoogle && inviteHasGoogleRsvp(bodyHtml);
1555
+ const rows = [];
1556
+ if (when)
1557
+ rows.push(`<div class="mv-invite-when">${esc(when)}</div>`);
1558
+ if (inv.location) {
1559
+ rows.push(isMeetLink ? `<div class="mv-invite-row"><span class="mv-invite-label">Where</span><a href="${esc(inv.location)}" target="_blank" rel="noopener noreferrer">${esc(inv.location)}</a></div>` : `<div class="mv-invite-row"><span class="mv-invite-label">Where</span>${esc(inv.location)}</div>`);
1560
+ }
1561
+ if (inv.organizer.email) {
1562
+ rows.push(`<div class="mv-invite-row"><span class="mv-invite-label">Organizer</span>${esc(inv.organizer.name)}${inv.organizer.name !== inv.organizer.email ? " &lt;" + esc(inv.organizer.email) + "&gt;" : ""}</div>`);
1563
+ }
1564
+ if (inv.attendees.length) {
1565
+ const who = inv.attendees.map((a) => `${esc(a.name || a.email)} <span class="mv-invite-partstat">(${esc(PARTSTAT_LABEL[a.status] || a.status.toLowerCase())})</span>`).join(", ");
1566
+ rows.push(`<div class="mv-invite-row"><span class="mv-invite-label">Guests</span>${who}</div>`);
1567
+ }
1568
+ if (inv.rrule)
1569
+ rows.push(`<div class="mv-invite-row"><span class="mv-invite-label">Repeats</span><code>${esc(inv.rrule)}</code></div>`);
1570
+ const badge = inv.method === "CANCEL" ? "Cancelled" : inv.method === "REPLY" ? "Reply" : inv.status === "TENTATIVE" ? "Tentative" : "Invitation";
1571
+ card.innerHTML = `<div class="mv-invite-head"><span class="mv-invite-badge">${esc(badge)}</span><span class="mv-invite-summary">${esc(inv.summary || "(no title)")}</span></div>` + rows.join("") + (googleHandles ? `<div class="mv-invite-note">Respond with the Yes / No / Maybe buttons in the message below \u2014 they go straight to Google Calendar.</div>` : "");
1572
+ return card;
1573
+ }
1574
+ var PARTSTAT_LABEL, esc;
1575
+ var init_invite_card = __esm({
1576
+ "client/components/invite-card.js"() {
1577
+ "use strict";
1578
+ init_mailx_types();
1579
+ PARTSTAT_LABEL = {
1580
+ "ACCEPTED": "accepted",
1581
+ "DECLINED": "declined",
1582
+ "TENTATIVE": "maybe",
1583
+ "NEEDS-ACTION": "no reply yet",
1584
+ "DELEGATED": "delegated"
1585
+ };
1586
+ esc = (s) => (s || "").replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
1587
+ }
1588
+ });
1589
+
1491
1590
  // client/components/address-book.js
1492
1591
  var address_book_exports = {};
1493
1592
  __export(address_book_exports, {
@@ -2361,19 +2460,6 @@ function installPreviewControls(iframe) {
2361
2460
  }
2362
2461
  if (e.ctrlKey && !e.altKey && !e.metaKey && (e.key === "a" || e.key === "A"))
2363
2462
  return;
2364
- const synth = new KeyboardEvent("keydown", {
2365
- key: e.key,
2366
- code: e.code,
2367
- ctrlKey: e.ctrlKey,
2368
- shiftKey: e.shiftKey,
2369
- altKey: e.altKey,
2370
- metaKey: e.metaKey,
2371
- bubbles: true,
2372
- cancelable: true
2373
- });
2374
- const allowDefault = document.dispatchEvent(synth);
2375
- if (!allowDefault)
2376
- e.preventDefault();
2377
2463
  });
2378
2464
  doc.addEventListener("wheel", (e) => {
2379
2465
  if (!e.ctrlKey)
@@ -2410,6 +2496,7 @@ function clearViewer() {
2410
2496
  headerEl.hidden = true;
2411
2497
  if (attEl)
2412
2498
  attEl.hidden = true;
2499
+ document.getElementById("mv-invite")?.remove();
2413
2500
  setTimeout(() => {
2414
2501
  try {
2415
2502
  const stillPlaceholder = !!document.querySelector("#mv-body .mv-empty");
@@ -2669,6 +2756,16 @@ async function showMessage(accountId, uid, folderId, specialUse, isRetry = false
2669
2756
  fromEl.textContent = formatAddr(msg.from);
2670
2757
  setRecipientLine(toEl, msg.to, msg.cc, msg.deliveredTo);
2671
2758
  headerEl.querySelector(".mv-subject").textContent = msg.subject;
2759
+ document.getElementById("mv-invite")?.remove();
2760
+ try {
2761
+ const card = buildInviteCard(msg.invite, String(msg.bodyHtml || ""));
2762
+ if (card) {
2763
+ card.id = "mv-invite";
2764
+ headerEl.insertAdjacentElement("afterend", card);
2765
+ }
2766
+ } catch (e) {
2767
+ console.warn("[viewer] invite card failed:", e?.message || e);
2768
+ }
2672
2769
  document.dispatchEvent(new CustomEvent("mailx-message-shown", { detail: { accountId } }));
2673
2770
  for (const el of [fromEl, toEl]) {
2674
2771
  el.addEventListener("contextmenu", (e) => {
@@ -3980,11 +4077,11 @@ function buildPrintableDoc(m) {
3980
4077
  if (!m)
3981
4078
  return null;
3982
4079
  const fmt = (a) => a?.name ? `${a.name} <${a.address || ""}>` : a?.address || "";
3983
- const esc = escapeHtmlLocal;
3984
- const row = (label, value) => value ? `<div><strong>${label}:</strong> ${esc(value)}</div>` : "";
4080
+ const esc2 = escapeHtmlLocal;
4081
+ const row = (label, value) => value ? `<div><strong>${label}:</strong> ${esc2(value)}</div>` : "";
3985
4082
  const headerHtml = `<div style="font-family:system-ui,Segoe UI,sans-serif;font-size:11pt;border-bottom:1px solid #999;padding-bottom:8px;margin-bottom:14px;line-height:1.5;">` + row("From", fmt(m.from || {})) + row("To", (m.to || []).map(fmt).join(", ")) + (m.cc?.length ? row("Cc", m.cc.map(fmt).join(", ")) : "") + row("Subject", m.subject || "") + row("Date", m.date ? new Date(m.date).toLocaleString() : "") + `</div>`;
3986
- const bodyHtml = m.bodyHtml ? m.bodyHtml : `<pre style="white-space:pre-wrap;word-break:break-word;font-family:system-ui,sans-serif;">${esc(m.bodyText || "")}</pre>`;
3987
- return `<!DOCTYPE html><html><head><meta charset="utf-8"><title>${esc(m.subject || "Message")}</title><style>@media print{body{margin:0;}}body{margin:16px;}img{max-width:100%;}</style></head><body>${headerHtml}${bodyHtml}</body></html>`;
4083
+ const bodyHtml = m.bodyHtml ? m.bodyHtml : `<pre style="white-space:pre-wrap;word-break:break-word;font-family:system-ui,sans-serif;">${esc2(m.bodyText || "")}</pre>`;
4084
+ return `<!DOCTYPE html><html><head><meta charset="utf-8"><title>${esc2(m.subject || "Message")}</title><style>@media print{body{margin:0;}}body{margin:16px;}img{max-width:100%;}</style></head><body>${headerHtml}${bodyHtml}</body></html>`;
3988
4085
  }
3989
4086
  function printCurrentMessage() {
3990
4087
  if (!currentMessage)
@@ -4197,6 +4294,7 @@ var init_message_viewer = __esm({
4197
4294
  "use strict";
4198
4295
  init_api_client();
4199
4296
  init_approved_senders();
4297
+ init_invite_card();
4200
4298
  init_context_menu();
4201
4299
  init_message_state();
4202
4300
  init_message_list();
@@ -7386,7 +7484,7 @@ async function collectDueAlarms(now) {
7386
7484
  }
7387
7485
  return items;
7388
7486
  }
7389
- function formatWhen(ms) {
7487
+ function formatWhen2(ms) {
7390
7488
  if (!ms)
7391
7489
  return "";
7392
7490
  const d = new Date(ms);
@@ -7509,7 +7607,7 @@ async function firePopupForItem(item) {
7509
7607
  .actions button.action[data-btn="Delete"]:hover { background: #800; }
7510
7608
  </style></head><body>
7511
7609
  <div class="title"><span class="icon">${icon}</span>${escapeHtml7(item.title)}</div>
7512
- <div class="when">${escapeHtml7(formatWhen(item.whenMs))}</div>
7610
+ <div class="when">${escapeHtml7(formatWhen2(item.whenMs))}</div>
7513
7611
  <div class="kind">${kindLabel}</div>
7514
7612
  <div class="row">
7515
7613
  <span class="row-label">Snooze:</span>
@@ -9261,6 +9359,7 @@ window.__btick && window.__btick("app.ts module body executing");
9261
9359
  var baseTitle = APP_NAME;
9262
9360
  var lastSeenCount = 0;
9263
9361
  var badgeCount = 0;
9362
+ var lastOverlayCount = -1;
9264
9363
  function updateBadge(count) {
9265
9364
  badgeCount = count;
9266
9365
  document.title = count > 0 ? `(${count}) ${baseTitle}` : baseTitle;
@@ -9297,7 +9396,8 @@ function updateBadge(count) {
9297
9396
  link.href = dataUrl;
9298
9397
  try {
9299
9398
  const hostApi = window.mailxapi;
9300
- if (hostApi?.setTaskbarOverlay) {
9399
+ if (hostApi?.setTaskbarOverlay && count !== lastOverlayCount) {
9400
+ lastOverlayCount = count;
9301
9401
  if (count > 0) {
9302
9402
  const bc = document.createElement("canvas");
9303
9403
  bc.width = 32;
@@ -13006,11 +13106,11 @@ function offsetToLineCol(src, pos) {
13006
13106
  return { pos, line, col };
13007
13107
  }
13008
13108
  function renderMarkdown(md) {
13009
- const esc = (s) => s.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
13109
+ const esc2 = (s) => s.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
13010
13110
  const blocks = [];
13011
13111
  let src = md.replace(/```(\w*)\n([\s\S]*?)```/g, (_m, _lang, code) => {
13012
13112
  const i = blocks.length;
13013
- blocks.push(`<pre class="mailx-help-code"><code>${esc(code)}</code></pre>`);
13113
+ blocks.push(`<pre class="mailx-help-code"><code>${esc2(code)}</code></pre>`);
13014
13114
  return `\0BLOCK${i}\0`;
13015
13115
  });
13016
13116
  const lines = src.split(/\r?\n/);
@@ -13030,7 +13130,7 @@ function renderMarkdown(md) {
13030
13130
  }
13031
13131
  };
13032
13132
  function inline(s) {
13033
- s = esc(s);
13133
+ s = esc2(s);
13034
13134
  s = s.replace(/`([^`]+)`/g, (_m, c) => `<code>${c}</code>`);
13035
13135
  s = s.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
13036
13136
  s = s.replace(/(^|[^*])\*([^*\n]+)\*/g, "$1<em>$2</em>");