/** * Runtime remote registry — discovery service for federated apps. * * The host registry holds the canonical map of `name → entryUrl`. Remotes self * register at boot (or are configured statically). The host re-resolves the * manifest on a schedule, falling back to the last-known-good map when fetches * fail. * * Two surfaces: * - `ManifestRegistry` — host-side cache, polling, health-aware lookup. * - `createRegistryHandler` — server-side `/jorvel/registry` endpoint emitting * the manifest JSON. */ import type { FederationRemote } from './remote-loader.js'; import { type EdgeLikeRequest, type EdgeLikeResponse, type HealthDocument } from './health.js'; export interface RegistryEntry { name: string; entryUrl: string; /** Optional SRI hash. */ integrity?: string; /** Optional semver — surfaces in telemetry + version checks. */ version?: string; /** When false, callers should treat the remote as down. */ enabled?: boolean; /** Free-form tags for routing (locale, region, …). */ tags?: Record; } export interface RegistryManifest { /** ISO timestamp the manifest was produced. */ generatedAt: string; entries: RegistryEntry[]; } export interface RegistryHandlerOptions { entries: () => RegistryEntry[] | Promise; /** URL path the handler answers. Default: `/jorvel/registry`. */ path?: string; /** Cache-Control for the response. Default: `'no-store'`. */ cacheControl?: string; now?: () => number; } export declare function createRegistryHandler(opts: RegistryHandlerOptions): (req: EdgeLikeRequest) => Promise; export type RegistryEventType = 'updated' | 'fetch-error'; export interface RegistryEvent { type: RegistryEventType; manifest?: RegistryManifest; error?: unknown; } export interface ManifestRegistryOptions { /** Initial manifest. Used until the first fetch lands. */ initial?: RegistryEntry[]; /** Manifest URL (e.g. `https://host/jorvel/registry`). When omitted, registry never polls. */ url?: string; /** Poll interval in ms. Default: 30_000. 0 disables polling. */ pollIntervalMs?: number; /** Override `fetch` for tests. */ fetch?: typeof fetch; /** Health probe used by `withHealth()`. Defaults to `fetchHealth`. */ healthFetch?: (url: string) => Promise; /** Pluggable timer. */ setTimer?: (fn: () => void, ms: number) => unknown; clearTimer?: (handle: unknown) => void; } export declare class ManifestRegistry { private readonly opts; private map; private listeners; private timer; private destroyed; constructor(opts?: ManifestRegistryOptions); /** Replace the manifest (e.g. from a fresh fetch). */ set(entries: RegistryEntry[]): void; /** Lookup a remote by name. Returns the entry or `undefined`. */ get(name: string): RegistryEntry | undefined; /** Lookup as a `FederationRemote` (drops registry-only fields). */ remote(name: string): FederationRemote | undefined; /** All currently-enabled entries. */ entries(): RegistryEntry[]; /** Subscribe to manifest changes / fetch failures. Returns unsubscribe. */ subscribe(listener: (e: RegistryEvent) => void): () => void; /** Fetch the manifest once. Throws on network / parse error. */ refresh(): Promise; /** * Fetch a remote's `/jorvel/health` and disable the registry entry when it * answers DOWN. Use after `refresh()` to apply health-aware filtering. */ withHealth(healthUrlFor: (entry: RegistryEntry) => string): Promise; /** Begin polling. Idempotent — calling twice is a no-op. */ start(): void; /** Stop polling and release listeners. */ destroy(): void; private emit; } //# sourceMappingURL=registry.d.ts.map