@bobfrankston/rmfmail 1.2.208 → 1.2.210

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 CHANGED
@@ -2266,24 +2266,46 @@ RFC 5322 with CRLF line endings. Bodies are quoted-printable encoded (readable i
2266
2266
  // crash) the main window's browser process — see S67 note on the
2267
2267
  // popout windows below. Service-supplied opts may override.
2268
2268
  const { popupKey, ...boxOpts } = opts || {};
2269
+ // ONE window per occurrence, however many app windows are open.
2270
+ // Every window runs its own alarm poller (alarms.ts is client-side),
2271
+ // so a second main window meant the same reminder spawned two
2272
+ // identical popups — and the second registration clobbered the
2273
+ // first's closer, leaving a popup that cross-machine retraction
2274
+ // could no longer close (Bob 2026-07-31: "two instances running,
2275
+ // two popups"). The late caller joins the SAME result, so both
2276
+ // pollers persist the same dismiss/snooze.
2277
+ if (popupKey) {
2278
+ const open = reminderPopups.get(popupKey);
2279
+ if (open) {
2280
+ console.log(` [reminder] popup ${popupKey} already open — joining it instead of opening a second`);
2281
+ return await open.result;
2282
+ }
2283
+ }
2269
2284
  const h = showMessageBoxEx({ profile: "popout", ...boxOpts });
2270
2285
  if (typeof h.pid === "number")
2271
2286
  addChildPid(h.pid);
2272
- if (popupKey)
2273
- reminderPopups.set(popupKey, { close: () => { try {
2274
- h.close();
2275
- }
2276
- catch { /* already gone */ } } });
2277
- try {
2287
+ const result = (async () => {
2278
2288
  const r = await h.result;
2279
2289
  return { button: r.button, closed: r.closed, dismissed: r.dismissed, form: r.form };
2280
- }
2281
- finally {
2290
+ })();
2291
+ // Cleanup rides on the shared promise, not on this caller — joiners
2292
+ // must not tear down registration out from under the real window.
2293
+ void result.catch(() => { }).finally(() => {
2282
2294
  if (typeof h.pid === "number")
2283
2295
  removeChildPid(h.pid);
2284
2296
  if (popupKey)
2285
2297
  reminderPopups.delete(popupKey);
2298
+ });
2299
+ if (popupKey) {
2300
+ reminderPopups.set(popupKey, {
2301
+ close: () => { try {
2302
+ h.close();
2303
+ }
2304
+ catch { /* already gone */ } },
2305
+ result,
2306
+ });
2286
2307
  }
2308
+ return await result;
2287
2309
  });
2288
2310
  svc.setPopupCloserFn((key) => {
2289
2311
  const p = reminderPopups.get(key);