API reference@evolu/commonlocal‑first/Evolu › EvoluErrorDep

Defined in: packages/common/src/local-first/Evolu.ts:829

Dependency wrapper for the shared EvoluError store.

Properties

evoluError

readonly evoluError: ReadonlyStore<
  | EvoluError
| null>;

Defined in: packages/common/src/local-first/Evolu.ts:906

ReadonlyStore of EvoluError shared by all Evolu instances created from the same createEvoluDeps result.

Starts at null and otherwise holds the latest reported error until the first UnsupportedDbVersionError. That refusal remains for the lifetime of these dependencies, even if a tenant is disposed and recreated. Later errors are still logged but do not replace it or notify this store's subscribers. Fresh dependencies start with a fresh error store.

Subscribe once to show user-facing error messages across all instances. While a refused database's tenant remains alive, the SharedWorker sends the refusal to each tab once, including tabs that connect later, and starts no replacement database workers. After all instances release that tenant and it is disposed when idle, creating another instance retries startup and may send the refusal again. Show that blocking message outside any query-loading boundary, so pending queries do not hide it.

Example

import {
  assertEqual,
  createStore,
  PositiveInt,
  type EvoluError,
} from "@evolu/common";
import type { EvoluErrorDep } from "@evolu/common/local-first";

// Stand-in for run.deps.evoluError from createEvoluDeps.
using evoluError = createStore<EvoluError | null>(null);
const deps = { evoluError } satisfies EvoluErrorDep;
const displayedMessages: Array<string> = [];
const showMessage = (message: string) => {
  displayedMessages.push(message);
};

deps.evoluError.subscribe(() => {
  const error = deps.evoluError.get();
  if (!error) return;

  // oxlint-disable-next-line typescript/switch-exhaustiveness-check -- The default intentionally handles every other EvoluError.
  switch (error.type) {
    case "TimestampTimeOutOfRangeError":
      // Show guidance specific to the detected error.
      showMessage(
        "Your system clock appears incorrect. Fix it and restart the app.",
      );
      break;
    case "UnsupportedDbVersionError":
      showMessage(
        "Your data requires a newer app version. Close all tabs of this app, then open it again.",
      );
      break;
    default:
      // Show a generic user message for other operational errors.
      showMessage("Something went wrong. Please try again.");
  }
});

deps.evoluError.set({ type: "TimestampTimeOutOfRangeError" });
assertEqual(displayedMessages, [
  "Your system clock appears incorrect. Fix it and restart the app.",
]);

deps.evoluError.set({
  type: "UnsupportedDbVersionError",
  storedVersion: PositiveInt.orThrow(3),
  supportedVersion: PositiveInt.orThrow(2),
});
assertEqual(displayedMessages, [
  "Your system clock appears incorrect. Fix it and restart the app.",
  "Your data requires a newer app version. Close all tabs of this app, then open it again.",
]);