AkurAI Build
Menu

Public repository / 4f0b1d374fab4075f2b552b5f250bca5f28afee9

AkurAI-Mail / src/framework/sync-state.js

Latest change 3af23b0e937520000e1aa43c7e2eb9de2675abd1 - OLI-248: webmail list and reader as framework islands on a signals store by Ólafur Búi Ólafsson

// Sync status store on the framework signals runtime (replaces the Svelte-rune sync.svelte.ts).
import { signal } from "./vendor/signals.js";
import { retryDelay } from "../lib/webmail/sync.js";

/**
 * @param {() => number} [now]
 * @param {(fn: () => void, ms: number) => any} [schedule]
 * @param {(id: any) => void} [cancel]
 */
export function createSyncState(now = Date.now, schedule = setTimeout, cancel = clearTimeout) {
  const status = signal(/** @type {"idle"|"syncing"} */ ("idle"));
  const lastSyncAt = signal(/** @type {number|null} */ (null));
  const errorKind = signal(/** @type {string|null} */ (null));
  const dismissed = signal(false);
  const retryCount = signal(0);
  /** @type {unknown} */
  let timer = null;

  function clearTimer() {
    if (timer !== null) cancel(timer);
    timer = null;
  }

  /** @param {string} kind @param {() => void} [retry] */
  function reportError(kind, retry) {
    status("idle");
    errorKind(kind);
    dismissed(false);
    clearTimer();
    if (retry && kind !== "auth-expired") {
      const delay = retryDelay(retryCount());
      retryCount(retryCount() + 1);
      timer = schedule(retry, delay);
    }
  }

  function reportSuccess() {
    status("idle");
    errorKind(null);
    retryCount(0);
    lastSyncAt(now());
    clearTimer();
  }

  /** @param {() => void} run */
  function retryNow(run) {
    clearTimer();
    run();
  }

  return { status, lastSyncAt, errorKind, dismissed, retryCount, reportError, reportSuccess, retryNow, dismiss: () => dismissed(true) };
}