/** * Runtime resilience — auto-fallback to the last-known-good remoteEntry when * the current URL returns 404 or times out. * * Two pieces work together: * - `ResilientRemoteCache` — persists `{ remoteName → last-good entryUrl }` * with a configurable backing store (defaults to `localStorage` on the * browser, an in-memory `Map` elsewhere). * - `loadWithFallback` — wraps a loader fn: tries the current entryUrl, * records success, and re-tries with the cached URL on * `404` / `timeout` / TypeError-from-fetch failures. */ import type { FederationRemote } from './remote-loader.js'; export interface CacheRecord { /** Last-known-good entryUrl for this remote. */ entryUrl: string; /** Unix milliseconds at which it last succeeded. */ storedAt: number; } export interface CacheStore { get(name: string): CacheRecord | undefined; set(name: string, record: CacheRecord): void; delete(name: string): void; } /** In-memory store used when no `localStorage` is available. */ export declare class MemoryCacheStore implements CacheStore { private readonly map; get(name: string): CacheRecord | undefined; set(name: string, record: CacheRecord): void; delete(name: string): void; } interface StorageLike { getItem(key: string): string | null; setItem(key: string, value: string): void; removeItem(key: string): void; } /** Backed by `Storage` (localStorage/sessionStorage). Falls back gracefully. */ export declare class StorageCacheStore implements CacheStore { private readonly storage; private readonly prefix; constructor(storage: StorageLike, prefix?: string); get(name: string): CacheRecord | undefined; set(name: string, record: CacheRecord): void; delete(name: string): void; } export interface ResilientCacheOptions { /** Pluggable store. Default: `localStorage` if available, else memory. */ store?: CacheStore; /** Cap on how stale a fallback may be (ms). Older entries are ignored. */ maxAgeMs?: number; /** Time source for tests. */ now?: () => number; } export declare class ResilientRemoteCache { private readonly store; private readonly maxAgeMs; private readonly now; constructor(opts?: ResilientCacheOptions); recordSuccess(remote: { name: string; entryUrl: string; }): void; /** Return the cached `FederationRemote` for `name`, or undefined when stale/missing. */ getFallback(name: string): { name: string; entryUrl: string; } | undefined; } export interface LoaderError extends Error { /** Failure classification populated by the caller (e.g. 404, timeout). */ kind?: 'not-found' | 'timeout' | 'network' | 'other'; /** HTTP status when known. */ status?: number; } export interface LoadWithFallbackOptions { /** The function that actually loads a remote module / entry. */ loader: (remote: FederationRemote) => Promise; /** Cache holding last-good URLs. */ cache: ResilientRemoteCache; /** Should we fall back for this error? Default: 404 / timeout / network. */ shouldFallback?: (err: unknown) => boolean; /** Optional listener fired on each phase. */ onPhase?: (phase: 'attempt' | 'success' | 'fallback' | 'fail', detail: { remote: string; entryUrl: string; error?: unknown; }) => void; } /** * Try `remote`, cache success, fall back to the last-known-good URL on a * recoverable failure. Re-throws when no fallback is available or both * attempts fail. */ export declare function loadWithFallback(remote: FederationRemote, opts: LoadWithFallbackOptions): Promise; export {}; //# sourceMappingURL=resilience.d.ts.map