foundation library

The DOM-free foundation: state primitives, error mapping, storage contracts.

Everything here runs on the Dart VM as well as in a browser, because none of it imports package:web. That is the whole point of the split: a consuming app's service and controller layers can be unit-tested with dart test — no headless Chrome, no DOM — while only the parts that genuinely touch the page need a browser.

Import client.dart instead when you also need the browser-bound pieces (LocalStorageStore, Router, OmnyShellService and the controllers built on them); it re-exports everything here.

Classes

AsyncState<T>
An immutable snapshot of an asynchronous value with explicit loading/error states — the shape every data screen renders. Carries optional data even while LoadStatus.loading or LoadStatus.error so the UI can show last-known content (e.g. cached nodes) under a spinner or error banner.
KeyValueStore
A minimal synchronous string key/value store. Abstracts localStorage so that storage-backed logic can be unit-tested with MemoryKeyValueStore without a browser.
MemoryKeyValueStore
An in-memory KeyValueStore for tests and non-browser contexts.
NodeCache
Caches the last-known node list so the nodes screen can paint instantly on reload while a fresh fetch runs. Backed by KeyValueStore; the cache is best-effort — any decode error yields null (treated as a cold cache).
Observable<T>
A minimal observable value: holds a current value and notifies listeners on change via a broadcast stream. The web app's lightweight alternative to a state-management framework — screens subscribe and re-render their DOM subtree when the value changes.
RouteMatch
A matched route: the pattern that matched, the concrete path, and any extracted path params (e.g. /nodes/:id against /nodes/web-01 yields {id: web-01}).
SettingsStore
Typed, namespaced access to persisted app settings over a KeyValueStore.

Enums

AppErrorKind
A user-facing error category, mapped from the lower-level OmnyShell exceptions so the UI can show a tailored message and recovery hint without switching on raw exception types everywhere.
LoadStatus
Where an async load currently stands.

Functions

hashToPath(String hash) String
Normalizes a URL hash (#/foo) to a path (/foo); empty hash → /.
matchRoute(List<String> patterns, String path) RouteMatch
Matches path against patterns, returning the first match. Patterns use :name segments for parameters. Pure and DOM-free.
relativeTime(DateTime time, DateTime now) String
Formats time as a compact relative age from now (e.g. 5m ago, 2h ago, 3d ago). Pure for unit testing — the live caller passes DateTime.now().
untilExpiry(DateTime expiresAt, DateTime now) String
Formats a Duration until expiry as in 5m / in 2h / expired.

Exceptions / Errors

AppError
A normalized error with a human-readable message and an optional recovery hint. Built from any thrown object via AppError.from.