@bobfrankston/rmfmail 1.2.177 → 1.2.178

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 (56) hide show
  1. package/client/android-bootstrap.bundle.js +112 -0
  2. package/client/android-bootstrap.bundle.js.map +3 -3
  3. package/client/app.bundle.js +71 -7
  4. package/client/app.bundle.js.map +3 -3
  5. package/client/components/alarms.js +88 -11
  6. package/client/components/alarms.js.map +1 -1
  7. package/client/components/alarms.ts +83 -13
  8. package/client/compose/compose.bundle.js +4 -0
  9. package/client/compose/compose.bundle.js.map +2 -2
  10. package/client/lib/api-client.js +6 -0
  11. package/client/lib/api-client.js.map +1 -1
  12. package/client/lib/api-client.ts +9 -0
  13. package/client/lib/mailxapi.js +27 -5
  14. package/package.json +5 -5
  15. package/packages/mailx-imap/package-lock.json +2 -2
  16. package/packages/mailx-imap/package.json +1 -1
  17. package/packages/mailx-service/index.d.ts +5 -0
  18. package/packages/mailx-service/index.d.ts.map +1 -1
  19. package/packages/mailx-service/index.js +22 -1
  20. package/packages/mailx-service/index.js.map +1 -1
  21. package/packages/mailx-service/index.ts +25 -1
  22. package/packages/mailx-service/jsonrpc.js +4 -0
  23. package/packages/mailx-service/jsonrpc.js.map +1 -1
  24. package/packages/mailx-service/jsonrpc.ts +4 -0
  25. package/packages/mailx-service/package.json +1 -1
  26. package/packages/mailx-settings/index.d.ts +8 -1
  27. package/packages/mailx-settings/index.d.ts.map +1 -1
  28. package/packages/mailx-settings/index.js +71 -0
  29. package/packages/mailx-settings/index.js.map +1 -1
  30. package/packages/mailx-settings/index.ts +61 -1
  31. package/packages/mailx-settings/package.json +1 -1
  32. package/packages/mailx-store/package.json +1 -1
  33. package/packages/mailx-store-web/android-bootstrap.js +4 -0
  34. package/packages/mailx-store-web/android-bootstrap.js.map +1 -1
  35. package/packages/mailx-store-web/android-bootstrap.ts +4 -0
  36. package/packages/mailx-store-web/package.json +1 -1
  37. package/packages/mailx-store-web/web-service.d.ts +4 -0
  38. package/packages/mailx-store-web/web-service.d.ts.map +1 -1
  39. package/packages/mailx-store-web/web-service.js +48 -2
  40. package/packages/mailx-store-web/web-service.js.map +1 -1
  41. package/packages/mailx-store-web/web-service.ts +41 -2
  42. package/packages/mailx-types/index.d.ts +2 -0
  43. package/packages/mailx-types/index.d.ts.map +1 -1
  44. package/packages/mailx-types/index.js +3 -0
  45. package/packages/mailx-types/index.js.map +1 -1
  46. package/packages/mailx-types/index.ts +7 -0
  47. package/packages/mailx-types/mailx-api.d.ts +14 -0
  48. package/packages/mailx-types/mailx-api.d.ts.map +1 -1
  49. package/packages/mailx-types/mailx-api.ts +5 -0
  50. package/packages/mailx-types/package.json +1 -1
  51. package/packages/mailx-types/reminder-state.d.ts +42 -0
  52. package/packages/mailx-types/reminder-state.d.ts.map +1 -0
  53. package/packages/mailx-types/reminder-state.js +85 -0
  54. package/packages/mailx-types/reminder-state.js.map +1 -0
  55. package/packages/mailx-types/reminder-state.ts +88 -0
  56. /package/packages/mailx-imap/{node_modules.npmglobalize-stash-69680 → node_modules.npmglobalize-stash-7544}/.package-lock.json +0 -0
@@ -2328,10 +2328,69 @@ var init_groups = __esm({
2328
2328
  }
2329
2329
  });
2330
2330
 
2331
+ // packages/mailx-types/reminder-state.js
2332
+ function normalizeReminderState(raw, now) {
2333
+ const out = { dismissed: {}, snoozed: {} };
2334
+ if (raw && typeof raw === "object") {
2335
+ for (const [k, v] of Object.entries(raw.dismissed || {})) {
2336
+ if (v === true)
2337
+ out.dismissed[k] = now;
2338
+ else if (Number.isFinite(v) && v > 0)
2339
+ out.dismissed[k] = v;
2340
+ }
2341
+ for (const [k, v] of Object.entries(raw.snoozed || {})) {
2342
+ if (Number.isFinite(v) && v > 0)
2343
+ out.snoozed[k] = v;
2344
+ }
2345
+ }
2346
+ return out;
2347
+ }
2348
+ function mergeReminderStates(a, b, now) {
2349
+ const out = { dismissed: {}, snoozed: {} };
2350
+ const dismissedCutoff = now - DISMISSED_RETENTION_MS;
2351
+ const snoozedCutoff = now - SNOOZED_RETENTION_MS;
2352
+ for (const src of [a.dismissed, b.dismissed]) {
2353
+ for (const [k, v] of Object.entries(src)) {
2354
+ if (v < dismissedCutoff)
2355
+ continue;
2356
+ if (!(k in out.dismissed) || v > out.dismissed[k])
2357
+ out.dismissed[k] = v;
2358
+ }
2359
+ }
2360
+ for (const src of [a.snoozed, b.snoozed]) {
2361
+ for (const [k, v] of Object.entries(src)) {
2362
+ if (v < snoozedCutoff)
2363
+ continue;
2364
+ if (!(k in out.snoozed) || v > out.snoozed[k])
2365
+ out.snoozed[k] = v;
2366
+ }
2367
+ }
2368
+ return out;
2369
+ }
2370
+ function reminderStatesEqual(a, b) {
2371
+ const mapsEqual = (x, y) => {
2372
+ const xk = Object.keys(x);
2373
+ if (xk.length !== Object.keys(y).length)
2374
+ return false;
2375
+ return xk.every((k) => y[k] === x[k]);
2376
+ };
2377
+ return mapsEqual(a.dismissed, b.dismissed) && mapsEqual(a.snoozed, b.snoozed);
2378
+ }
2379
+ var REMINDER_STATE_FILE, DISMISSED_RETENTION_MS, SNOOZED_RETENTION_MS;
2380
+ var init_reminder_state = __esm({
2381
+ "packages/mailx-types/reminder-state.js"() {
2382
+ "use strict";
2383
+ REMINDER_STATE_FILE = "reminders.jsonc";
2384
+ DISMISSED_RETENTION_MS = 30 * 864e5;
2385
+ SNOOZED_RETENTION_MS = 7 * 864e5;
2386
+ }
2387
+ });
2388
+
2331
2389
  // packages/mailx-types/index.js
2332
2390
  var mailx_types_exports = {};
2333
2391
  __export(mailx_types_exports, {
2334
2392
  CONTACT_RULES: () => CONTACT_RULES,
2393
+ REMINDER_STATE_FILE: () => REMINDER_STATE_FILE,
2335
2394
  addContactsDenylistEntry: () => addContactsDenylistEntry,
2336
2395
  addContactsPreferredEntry: () => addContactsPreferredEntry,
2337
2396
  answeredOf: () => answeredOf,
@@ -2343,7 +2402,10 @@ __export(mailx_types_exports, {
2343
2402
  flaggedOf: () => flaggedOf,
2344
2403
  htmlToPlainText: () => htmlToPlainText,
2345
2404
  isAddressToken: () => isAddressToken,
2405
+ mergeReminderStates: () => mergeReminderStates,
2406
+ normalizeReminderState: () => normalizeReminderState,
2346
2407
  parseSearchQuery: () => parseSearchQuery,
2408
+ reminderStatesEqual: () => reminderStatesEqual,
2347
2409
  sanitizeHtml: () => sanitizeHtml,
2348
2410
  seenOf: () => seenOf,
2349
2411
  setAnswered: () => setAnswered,
@@ -2544,6 +2606,7 @@ var init_mailx_types = __esm({
2544
2606
  init_contact_rules();
2545
2607
  init_contacts_config();
2546
2608
  init_groups();
2609
+ init_reminder_state();
2547
2610
  _SEEN = "\\Seen";
2548
2611
  _FLAGGED = "\\Flagged";
2549
2612
  _ANSWERED = "\\Answered";
@@ -6640,6 +6703,51 @@ ${bodyEncoded}`;
6640
6703
  async deleteTask(_uuid) {
6641
6704
  return this.notImpl("deleteTask");
6642
6705
  }
6706
+ // Reminder dismissed/snoozed state — same reminders.jsonc on the shared
6707
+ // Drive folder the desktop uses, same mailx-types merge. Alarms don't
6708
+ // fire on Android today (getCalendarEvents/getTasks return []), but the
6709
+ // API is live so this device still contributes its state and adopts the
6710
+ // desktops' — the moment calendar lands here, sync just works.
6711
+ reminderStateCache = null;
6712
+ async getReminderState() {
6713
+ if (this.reminderStateCache && Date.now() - this.reminderStateCache.at < 6e4) {
6714
+ return this.reminderStateCache.state;
6715
+ }
6716
+ const now = Date.now();
6717
+ let state = { dismissed: {}, snoozed: {} };
6718
+ try {
6719
+ const json = await cloudRead(REMINDER_STATE_FILE);
6720
+ if (json != null)
6721
+ state = normalizeReminderState(JSON.parse(json), now);
6722
+ } catch {
6723
+ }
6724
+ this.reminderStateCache = { state, at: Date.now() };
6725
+ return state;
6726
+ }
6727
+ async mergeReminderState(patch) {
6728
+ const now = Date.now();
6729
+ const local = normalizeReminderState(patch, now);
6730
+ let cloud = { dismissed: {}, snoozed: {} };
6731
+ let hadCloud = false;
6732
+ try {
6733
+ const json = await cloudRead(REMINDER_STATE_FILE);
6734
+ if (json != null) {
6735
+ cloud = normalizeReminderState(JSON.parse(json), now);
6736
+ hadCloud = true;
6737
+ }
6738
+ } catch {
6739
+ }
6740
+ const merged = mergeReminderStates(cloud, local, now);
6741
+ if (!(hadCloud && reminderStatesEqual(merged, cloud))) {
6742
+ try {
6743
+ await cloudWrite(REMINDER_STATE_FILE, JSON.stringify(merged, null, 2) + "\n");
6744
+ } catch (e) {
6745
+ console.error(`[reminders] cloud write failed: ${e?.message || e}`);
6746
+ }
6747
+ }
6748
+ this.reminderStateCache = { state: merged, at: Date.now() };
6749
+ return merged;
6750
+ }
6643
6751
  // User dictionary (cloud-mirrored) — Android can implement these via
6644
6752
  // the same userdict.csv cloud round-trip the desktop uses; until that
6645
6753
  // wire-up lands, return safe defaults so spellcheck.ts catch() paths
@@ -11346,6 +11454,10 @@ function installBridge() {
11346
11454
  return { ok: true };
11347
11455
  },
11348
11456
  loadContactsConfig: () => service.loadContactsConfig(),
11457
+ // Cross-device reminder dismissed/snoozed state (reminders.jsonc on
11458
+ // Drive) — alarm poller pushes/pulls through these.
11459
+ getReminderState: () => service.getReminderState(),
11460
+ mergeReminderState: (patch) => service.mergeReminderState(patch),
11349
11461
  syncAll: async () => {
11350
11462
  await service.syncAll();
11351
11463
  return { ok: true };