@bobfrankston/rmfmail 1.2.182 → 1.2.183
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.
- package/bin/mailx.js +21 -1
- package/bin/mailx.js.map +1 -1
- package/bin/mailx.ts +15 -1
- package/client/app.bundle.js +46 -4
- package/client/app.bundle.js.map +2 -2
- package/client/components/alarms.js +60 -13
- package/client/components/alarms.js.map +1 -1
- package/client/components/alarms.ts +69 -11
- package/client/compose/compose.bundle.js +4 -0
- package/client/compose/compose.bundle.js.map +2 -2
- package/client/lib/api-client.js +5 -0
- package/client/lib/api-client.js.map +1 -1
- package/client/lib/api-client.ts +8 -0
- package/client/lib/mailxapi.js +5 -0
- package/package.json +3 -3
- package/packages/mailx-service/index.d.ts +11 -0
- package/packages/mailx-service/index.d.ts.map +1 -1
- package/packages/mailx-service/index.js +15 -0
- package/packages/mailx-service/index.js.map +1 -1
- package/packages/mailx-service/index.ts +14 -0
- package/packages/mailx-service/jsonrpc.js +2 -0
- package/packages/mailx-service/jsonrpc.js.map +1 -1
- package/packages/mailx-service/jsonrpc.ts +2 -0
- package/packages/mailx-service/package.json +1 -1
- /package/packages/mailx-imap/{node_modules.npmglobalize-stash-54716 → node_modules.npmglobalize-stash-68724}/.package-lock.json +0 -0
package/bin/mailx.ts
CHANGED
|
@@ -2131,19 +2131,33 @@ RFC 5322 with CRLF line endings. Bodies are quoted-printable encoded (readable i
|
|
|
2131
2131
|
}
|
|
2132
2132
|
}, 5000);
|
|
2133
2133
|
}
|
|
2134
|
+
// Open reminder popups by occurrence key, so a dismiss/snooze made on
|
|
2135
|
+
// ANOTHER machine (seen via the reminders.jsonc state sync) can retract
|
|
2136
|
+
// a popup that's already on this machine's screen. `popupKey` is
|
|
2137
|
+
// supplied by alarms.ts and stripped before the opts reach msger.
|
|
2138
|
+
const reminderPopups = new Map<string, { close: () => void }>();
|
|
2134
2139
|
svc.setPopupFn(async (opts: any) => {
|
|
2135
2140
|
// Own WebView2 profile so a reminder popup can never share (and
|
|
2136
2141
|
// crash) the main window's browser process — see S67 note on the
|
|
2137
2142
|
// popout windows below. Service-supplied opts may override.
|
|
2138
|
-
const
|
|
2143
|
+
const { popupKey, ...boxOpts } = opts || {};
|
|
2144
|
+
const h = showMessageBoxEx({ profile: "popout", ...boxOpts });
|
|
2139
2145
|
if (typeof h.pid === "number") addChildPid(h.pid);
|
|
2146
|
+
if (popupKey) reminderPopups.set(popupKey, { close: () => { try { h.close(); } catch { /* already gone */ } } });
|
|
2140
2147
|
try {
|
|
2141
2148
|
const r = await h.result;
|
|
2142
2149
|
return { button: r.button, closed: r.closed, dismissed: r.dismissed, form: (r as any).form };
|
|
2143
2150
|
} finally {
|
|
2144
2151
|
if (typeof h.pid === "number") removeChildPid(h.pid);
|
|
2152
|
+
if (popupKey) reminderPopups.delete(popupKey);
|
|
2145
2153
|
}
|
|
2146
2154
|
});
|
|
2155
|
+
svc.setPopupCloserFn((key: string) => {
|
|
2156
|
+
const p = reminderPopups.get(key);
|
|
2157
|
+
if (!p) return false;
|
|
2158
|
+
p.close();
|
|
2159
|
+
return true;
|
|
2160
|
+
});
|
|
2147
2161
|
|
|
2148
2162
|
// Optional debug HTTP server ALONGSIDE the GUI. `--server` mode replaces
|
|
2149
2163
|
// the WebView with Express; `--debug-server` instead runs a loopback
|
package/client/app.bundle.js
CHANGED
|
@@ -29,6 +29,7 @@ __export(api_client_exports, {
|
|
|
29
29
|
cancelServerSearch: () => cancelServerSearch,
|
|
30
30
|
checkDraftNewer: () => checkDraftNewer,
|
|
31
31
|
closeComposePopout: () => closeComposePopout,
|
|
32
|
+
closeReminderPopup: () => closeReminderPopup,
|
|
32
33
|
closeWordEdit: () => closeWordEdit,
|
|
33
34
|
connectEvents: () => connectEvents,
|
|
34
35
|
connectWebSocket: () => connectWebSocket,
|
|
@@ -621,6 +622,9 @@ function closeWordEdit(editId) {
|
|
|
621
622
|
function showReminderPopup(opts) {
|
|
622
623
|
return ipc().showReminderPopup?.(opts) ?? Promise.resolve({ button: "", reason: "no host" });
|
|
623
624
|
}
|
|
625
|
+
function closeReminderPopup(key) {
|
|
626
|
+
return ipc().closeReminderPopup?.(key) ?? Promise.resolve({ ok: false });
|
|
627
|
+
}
|
|
624
628
|
function mergeReminderState(patch) {
|
|
625
629
|
return ipc().mergeReminderState?.(patch) ?? Promise.resolve(null);
|
|
626
630
|
}
|
|
@@ -6153,6 +6157,7 @@ async function syncReminderState(force = false) {
|
|
|
6153
6157
|
sn[k] = v;
|
|
6154
6158
|
}
|
|
6155
6159
|
saveSnoozed(sn);
|
|
6160
|
+
retractSuppressedPopups();
|
|
6156
6161
|
return true;
|
|
6157
6162
|
} catch (e) {
|
|
6158
6163
|
alog("state sync failed", { err: e?.message || String(e) });
|
|
@@ -6249,10 +6254,28 @@ function formatWhen(ms) {
|
|
|
6249
6254
|
const d = new Date(ms);
|
|
6250
6255
|
return d.toLocaleString(void 0, { weekday: "short", month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
|
|
6251
6256
|
}
|
|
6257
|
+
function retractSuppressedPopups() {
|
|
6258
|
+
if (openPopups.size === 0)
|
|
6259
|
+
return;
|
|
6260
|
+
const now = Date.now();
|
|
6261
|
+
const dismissed = loadDismissed();
|
|
6262
|
+
const snoozed = loadSnoozed();
|
|
6263
|
+
for (const [key, entry] of openPopups) {
|
|
6264
|
+
if (entry.retracted)
|
|
6265
|
+
continue;
|
|
6266
|
+
if (dismissed[key] || (snoozed[key] || 0) > now) {
|
|
6267
|
+
alog("retracting popup \u2014 resolved on another machine", { key, dismissed: !!dismissed[key], snoozedUntil: snoozed[key] || 0 });
|
|
6268
|
+
try {
|
|
6269
|
+
entry.retract();
|
|
6270
|
+
} catch {
|
|
6271
|
+
}
|
|
6272
|
+
}
|
|
6273
|
+
}
|
|
6274
|
+
}
|
|
6252
6275
|
function escapeHtml6(s) {
|
|
6253
6276
|
return s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
6254
6277
|
}
|
|
6255
|
-
function showInWebViewPopup(opts) {
|
|
6278
|
+
function showInWebViewPopup(opts, onRegisterClose) {
|
|
6256
6279
|
return new Promise((resolve) => {
|
|
6257
6280
|
const overlay = document.createElement("div");
|
|
6258
6281
|
overlay.className = "alarm-overlay";
|
|
@@ -6294,12 +6317,15 @@ function showInWebViewPopup(opts) {
|
|
|
6294
6317
|
panel.querySelectorAll("[data-button]").forEach((btn) => {
|
|
6295
6318
|
btn.addEventListener("click", () => cleanup(btn.dataset.button || ""));
|
|
6296
6319
|
});
|
|
6320
|
+
onRegisterClose?.(cleanup);
|
|
6297
6321
|
});
|
|
6298
6322
|
}
|
|
6299
6323
|
async function firePopupForItem(item) {
|
|
6300
6324
|
if (openPopups.has(item.uuid))
|
|
6301
6325
|
return;
|
|
6302
|
-
|
|
6326
|
+
const popupEntry = { retracted: false, retract: () => {
|
|
6327
|
+
} };
|
|
6328
|
+
openPopups.set(item.uuid, popupEntry);
|
|
6303
6329
|
const openUrl = item.kind === "calendar" ? item.htmlLink || "https://calendar.google.com/" : "https://tasks.google.com/";
|
|
6304
6330
|
const buttons = ["snooze", "Dismiss", "Open"];
|
|
6305
6331
|
if (item.kind === "calendar")
|
|
@@ -6401,17 +6427,28 @@ async function firePopupForItem(item) {
|
|
|
6401
6427
|
let r;
|
|
6402
6428
|
try {
|
|
6403
6429
|
if (hasHost) {
|
|
6430
|
+
popupEntry.retract = () => {
|
|
6431
|
+
popupEntry.retracted = true;
|
|
6432
|
+
closeReminderPopup(item.uuid).catch(() => {
|
|
6433
|
+
});
|
|
6434
|
+
};
|
|
6404
6435
|
r = await showReminderPopup({
|
|
6405
6436
|
title,
|
|
6406
6437
|
html,
|
|
6407
6438
|
buttons,
|
|
6439
|
+
popupKey: item.uuid,
|
|
6408
6440
|
// Sized for the new snooze form (chips row + custom input
|
|
6409
6441
|
// row + action buttons) plus title/when/kind. Width fits
|
|
6410
6442
|
// "5m 15m 30m 1h 2h 1d" on one line in Segoe UI.
|
|
6411
6443
|
size: { width: 560, height: 300 }
|
|
6412
6444
|
});
|
|
6413
6445
|
} else {
|
|
6414
|
-
r = await showInWebViewPopup({ title, html, buttons })
|
|
6446
|
+
r = await showInWebViewPopup({ title, html, buttons }, (close) => {
|
|
6447
|
+
popupEntry.retract = () => {
|
|
6448
|
+
popupEntry.retracted = true;
|
|
6449
|
+
close("retracted");
|
|
6450
|
+
};
|
|
6451
|
+
});
|
|
6415
6452
|
}
|
|
6416
6453
|
} catch (e) {
|
|
6417
6454
|
alog("popup IPC failed \u2014 treating as Dismiss", { key: item.uuid, err: e?.message || String(e) });
|
|
@@ -6419,6 +6456,11 @@ async function firePopupForItem(item) {
|
|
|
6419
6456
|
} finally {
|
|
6420
6457
|
openPopups.delete(item.uuid);
|
|
6421
6458
|
}
|
|
6459
|
+
if (popupEntry.retracted) {
|
|
6460
|
+
alog("popup closed by retraction \u2014 skipping result handling", { key: item.uuid });
|
|
6461
|
+
firedThisSession.delete(item.uuid);
|
|
6462
|
+
return;
|
|
6463
|
+
}
|
|
6422
6464
|
if (!r || typeof r !== "object" || typeof r.button !== "string") {
|
|
6423
6465
|
alog("popup returned empty / malformed \u2014 treating as Dismiss", { key: item.uuid, raw: r });
|
|
6424
6466
|
r = { button: "Dismiss" };
|
|
@@ -6570,7 +6612,7 @@ var init_alarms = __esm({
|
|
|
6570
6612
|
_lastStateSync = 0;
|
|
6571
6613
|
STATE_SYNC_MIN_MS = 6e4;
|
|
6572
6614
|
firedThisSession = /* @__PURE__ */ new Set();
|
|
6573
|
-
openPopups = /* @__PURE__ */ new
|
|
6615
|
+
openPopups = /* @__PURE__ */ new Map();
|
|
6574
6616
|
}
|
|
6575
6617
|
});
|
|
6576
6618
|
|