AkurAI Build
Menu

Public repository / 22202d1bde69be4ace8a299dffd91f8ff24378df

AkurAI-Mail / src/lib/webmail/sync.ts

Latest change 22202d1bde69be4ace8a299dffd91f8ff24378df - Recover deployed webmail frontend (frontend parity with EC2 a6afffc) by Ólafur Búi Ólafsson

/** Pure helpers behind the webmail sync status and error banner. */

export type SyncErrorKind = "offline" | "auth-expired" | "server-error";

export const SYNC_ERROR_MESSAGES: Record<SyncErrorKind, string> = {
  offline: "You're offline. Showing the last synced messages.",
  "auth-expired": "Your session expired. Sign in again to resume syncing.",
  "server-error": "The mail server had a problem. Showing the last synced messages.",
};

export const RETRY_BASE_MS = 2000;
export const RETRY_MAX_MS = 60000;

/** Exponential backoff: 2s, 4s, 8s ... capped at one minute. */
export function retryDelay(attempt: number) {
  return Math.min(RETRY_BASE_MS * 2 ** attempt, RETRY_MAX_MS);
}

export function classifySyncError(error: unknown, response?: { status: number }, online = typeof navigator === "undefined" ? true : navigator.onLine): SyncErrorKind {
  if (response?.status === 401) return "auth-expired";
  if (online === false || error instanceof TypeError) return "offline";
  return "server-error";
}

/** "Synced just now", "Synced 12s ago", "Synced 3m ago", "Synced 2h ago". */
export function syncedLabel(lastSyncAt: number | null, now = Date.now()) {
  if (!lastSyncAt) return "Never synced";
  const seconds = Math.max(0, Math.round((now - lastSyncAt) / 1000));
  if (seconds < 5) return "Synced just now";
  if (seconds < 60) return `Synced ${seconds}s ago`;
  const minutes = Math.round(seconds / 60);
  if (minutes < 60) return `Synced ${minutes}m ago`;
  return `Synced ${Math.round(minutes / 60)}h ago`;
}