/** * Framework-neutral async boundaries. A boundary owns one named piece of UI data; the web core owns * lifecycle, concurrency, and isolation while each adapter decides how its `render` result is mounted. * The contract deliberately contains no React/Svelte/Vue/Preact types. */ /** Request-scoped inputs available to dynamic and intercepting boundaries. */ export interface BoundaryRequestCtx { readonly request: Request; readonly params: Readonly>; readonly api: unknown; readonly env: unknown; readonly draft: boolean; readonly search: Readonly>; readonly signal: AbortSignal; } /** Build-safe inputs available to a static boundary. It intentionally has no request/session/params API. */ export interface StaticCtx { readonly phase: "build"; readonly origin?: string; } export type BoundaryMode = "static" | "dynamic" | { readonly intercept: string; }; interface BoundaryBase { readonly name: string; readonly render: (data: Data) => UI; readonly fallback?: UI; /** Adapter-provided error slot name. The neutral core never imports a UI component. */ readonly errorId?: string; } export type StaticBoundary = BoundaryBase & { readonly mode: "static"; readonly load?: (ctx: StaticCtx) => Data | Promise; }; export type DynamicBoundary = BoundaryBase & { readonly mode: "dynamic"; readonly load?: (ctx: BoundaryRequestCtx) => Data | Promise; }; export type InterceptBoundary = BoundaryBase & { readonly mode: { readonly intercept: string; }; readonly load?: (ctx: BoundaryRequestCtx) => Data | Promise; }; /** A discriminated union: the `mode` selects the context type accepted by `load`. */ export type Boundary = StaticBoundary | DynamicBoundary | InterceptBoundary; /** * Erased runtime registration shape used by a route/layout manifest. This is intentionally a * structural union rather than `Boundary`: a registration keeps its loader's * concrete data type at the declaration site, and function-parameter variance must not turn that * loader into `Promise` when the manifest erases it. */ type ErasedBoundaryBase = { readonly name: string; readonly render: (data: never) => unknown; readonly fallback?: unknown; readonly errorId?: string; }; export type BoundaryRegistration = (ErasedBoundaryBase & { readonly mode: "static"; readonly load?: (ctx: StaticCtx) => unknown | Promise; }) | (ErasedBoundaryBase & { readonly mode: "dynamic"; readonly load?: (ctx: BoundaryRequestCtx) => unknown | Promise; }) | (ErasedBoundaryBase & { readonly mode: { readonly intercept: string; }; readonly load?: (ctx: BoundaryRequestCtx) => unknown | Promise; }); /** Neutral manifest descriptor: no framework component crosses the web core boundary. */ export interface BoundaryDescriptor { readonly name: string; readonly mode: BoundaryMode; readonly hasLoad: boolean; readonly errorId?: string; } export type BoundaryStatus = "unresolved" | "pending" | "ready" | "error"; export interface BoundaryError { readonly name: string; readonly message: string; } /** Serializable boundary state passed to the adapter's render seam. */ export interface BoundaryState { readonly name: string; readonly mode: BoundaryMode; readonly status: BoundaryStatus; readonly data?: unknown; readonly error?: BoundaryError; readonly errorId?: string; } export type BoundaryStates = Readonly>; /** A dynamic load that has started but is not part of the initial render barrier. */ export interface PendingBoundary { readonly name: string; readonly mode: BoundaryMode; readonly errorId?: string; readonly promise: Promise; } /** Runtime handles for a concurrent boundary batch. `initial` is renderable immediately. */ export interface DynamicBoundaryBatch { readonly initial: BoundaryStates; readonly pending: ReadonlyArray; /** Resolves to final per-boundary states for non-streaming consumers and tests. */ readonly complete: Promise; } /** Public in-memory reference cache for build-safe static boundary values. It holds no payload outside * the process and is intentionally not a durable or tenant-aware cache implementation. */ export interface StaticBoundaryCache { get(boundary: BoundaryRegistration): Promise | undefined; set(boundary: BoundaryRegistration, value: Promise): void; } export declare class MemoryStaticBoundaryCache implements StaticBoundaryCache { #private; get(boundary: BoundaryRegistration): Promise | undefined; set(boundary: BoundaryRegistration, value: Promise): void; } export interface StaticBoundaryImportEdge { readonly from: string; readonly to: string; } export interface StaticBoundaryRoot { readonly name: string; readonly module: string; } /** * Enforce the second half of the static-boundary safety boundary. A build adapter supplies the * transitive module graph and the modules it has classified as request-scoped; a static root that * reaches one fails before any shared shell is emitted. Keeping this check graph-shaped makes it * usable by Bun/Vite without making the neutral web runtime depend on either bundler. */ export declare function assertStaticBoundaryImports(roots: readonly StaticBoundaryRoot[], edges: readonly StaticBoundaryImportEdge[], requestScopedModules: ReadonlySet): void; /** Validate and serialize the neutral boundary manifest. Duplicate names fail closed at startup. */ export declare function boundaryDescriptors(boundaries: readonly BoundaryRegistration[]): ReadonlyArray; /** * Resolve all dynamic boundaries concurrently. Each receives a fresh frozen context object; one * failure becomes that boundary's error state and never rejects a sibling or exposes sibling data. * Static/intercepting modes remain `unresolved` until their phase-specific runtime owns them. */ export declare function resolveDynamicBoundaries(boundaries: readonly BoundaryRegistration[], context: BoundaryRequestCtx): Promise; /** * Start all dynamic boundary loads at once without making the page wait for the slowest sibling. * The initial states contain `status: "pending"`; callers that support deferred values can attach * each `pending.promise` to its own slot. `complete` still provides settled, isolated states to * non-streaming callers, preserving the simple reference API. */ export declare function startDynamicBoundaries(boundaries: readonly BoundaryRegistration[], context: BoundaryRequestCtx): DynamicBoundaryBatch; /** * Resolve only explicitly annotated static boundaries with a request-free build context. Dynamic * and intercepting boundaries remain unresolved. Values are cached by boundary object identity in * the supplied in-memory cache, so a worker instance does not repeat a build-safe computation per * request. A rejected static load becomes that slot's error state; it never fabricates shared data. */ export declare function resolveStaticBoundaries(boundaries: readonly BoundaryRegistration[], context: StaticCtx, cache?: StaticBoundaryCache): Promise; /** Stable mode label for adapter registries and diagnostics. */ export declare function boundaryModeKey(mode: BoundaryMode): string; export {}; //# sourceMappingURL=boundary.d.ts.map