import type { ReactNode, ComponentType } from "react"; import type { ResolvedSegment, SlotState } from "../types.js"; import type { ResolvedThemeConfig, Theme } from "../theme/types.js"; import type { RenderSegmentsOptions } from "../segment-system.js"; /** * RSC payload received from server */ export interface RscPayload { root: ReactNode | Promise | null; metadata?: TMetadata; returnValue?: ActionResult; formState?: unknown; } /** * Handle data structure: handleName -> segmentId -> entries[] * * @internal This type is an implementation detail and may change without notice. */ export type HandleData = Record>; /** * Metadata included in RSC responses * * @internal This type is an implementation detail and may change without notice. */ export interface RscMetadata { pathname: string; segments: ResolvedSegment[]; isPartial?: boolean; isError?: boolean; matched?: string[]; diff?: string[]; /** * State of named slots for this route match * Key is slot name (e.g., "@modal"), value is slot state * Slots are used for intercepting routes during soft navigation */ slots?: Record; /** Root layout component for browser-side re-renders */ rootLayout?: ComponentType<{ children: ReactNode; }>; /** Handle data accumulated across route segments (async generator that yields on each push) */ handles?: AsyncGenerator; /** Cached handle data (for back/forward navigation from cache) */ cachedHandleData?: HandleData; /** * RSC version string from the server. * Used to detect version mismatches after HMR/deployment. */ version?: string; /** * Theme configuration from router. * Included when theme is enabled in router config. */ themeConfig?: ResolvedThemeConfig | null; /** * Initial theme from cookie (for SSR hydration). * Included when theme is enabled in router config. */ initialTheme?: Theme; /** Whether connection warmup is enabled */ warmupEnabled?: boolean; } /** * Result from server action execution * * @internal This type is an implementation detail and may change without notice. */ export interface ActionResult { ok: boolean; data: unknown; } /** * Location object representing current URL * Uses URL for full URL parsing (origin, host, hostname, port, protocol, searchParams, etc.) */ export type NavigationLocation = URL; /** * Inflight server action being tracked * * @internal This type is an implementation detail and may change without notice. */ export interface InflightAction { /** Unique identifier for this action invocation */ id: string; /** Server action function ID */ actionId: string; /** Action arguments */ payload: unknown[]; /** Timestamp when action started */ startedAt: number; } /** * Internal navigation state (includes inflight actions for store use) * * @internal This type is an implementation detail. Use PublicNavigationState instead. */ export interface NavigationState { /** Navigation lifecycle state (idle or loading during navigation) */ state: "idle" | "loading"; /** Whether RSC data is currently streaming (initial load or navigation) */ isStreaming: boolean; /** Current location (updated optimistically) */ location: NavigationLocation; /** URL being navigated to (null when idle) */ pendingUrl: string | null; /** List of inflight server actions (internal use only) */ inflightActions: InflightAction[]; } /** * Public navigation state exposed via useNavigation hook * Excludes internal properties like inflightActions */ export type PublicNavigationState = Omit; /** * Action lifecycle state */ export type ActionLifecycleState = "idle" | "loading" | "streaming"; /** * State for a tracked server action * Used by useAction hook to observe action lifecycle * * @internal This type is an implementation detail and may change without notice. */ export interface TrackedActionState { /** Current lifecycle state of the action */ state: ActionLifecycleState; /** Server action function ID (e.g., "addToCart") */ actionId: string | null; /** Action arguments (array for JSON, FormData for form submissions) */ payload: unknown[] | FormData | null; /** Error if action failed */ error: unknown | null; /** Result data from the action (preserved after completion) */ result: unknown | null; } /** * Listener for action state changes * * @internal This type is an implementation detail and may change without notice. */ export type ActionStateListener = (state: TrackedActionState) => void; /** * Cache interface for storing segments * Compatible with both Map and LRUCache * * @internal This type is an implementation detail and may change without notice. */ export interface SegmentCache { get(key: string): ResolvedSegment | undefined; set(key: string, value: ResolvedSegment): void; has(key: string): boolean; delete(key: string): boolean; keys(): IterableIterator; readonly size: number; } /** * Internal segment state managed by the store * * @internal This type is an implementation detail and may change without notice. */ export interface SegmentState { path: string; currentUrl: string; currentSegmentIds: string[]; } /** * Navigation update emitted when UI should re-render * * @internal This type is an implementation detail and may change without notice. */ export interface NavigationUpdate { root: ReactNode | Promise; metadata: RscMetadata; } /** * State value for navigate/Link * - LocationStateEntry[]: Type-safe state entries (recommended) * - unknown: Legacy format for backwards compatibility */ export type HistoryState = import("./react/location-state-shared.js").LocationStateEntry[] | unknown; /** * Options for navigation operations */ export interface NavigateOptions { replace?: boolean; scroll?: boolean; /** * State to pass to history.pushState/replaceState * Accessible via useLocationState() hook. * * @example * ```tsx * // Type-safe state (recommended) * const ProductState = createLocationState<{ name: string }>("product"); * navigate("/product/123", { state: [ProductState({ name: "Widget" })] }); * * // Multiple states * navigate("/checkout", { state: [ProductState(p), CartState(c)] }); * * // Legacy format (backwards compatible) * navigate("/product", { state: { from: "list" } }); * ``` */ state?: HistoryState; } /** * RSC runtime functions from @vitejs/plugin-rsc/browser * * These are injected as dependencies to avoid direct coupling * to the RSC runtime implementation. */ export interface RscBrowserDependencies { createFromFetch: (response: Promise, options?: { temporaryReferences?: any; }) => Promise; createFromReadableStream: (stream: ReadableStream) => Promise; encodeReply: (args: any[], options?: { temporaryReferences?: any; }) => Promise; setServerCallback: (callback: (id: string, args: any[]) => Promise) => void; createTemporaryReferenceSet: () => any; } /** * Update subscriber callback for UI updates */ export type UpdateSubscriber = (update: NavigationUpdate) => void; /** * State change listener for useNavigation hook subscriptions */ export type StateListener = () => void; /** * Navigation store interface * * Manages both: * - NavigationState: Public state exposed via useNavigation hook * - SegmentState: Internal segment management for partial updates */ export interface NavigationStore { getState(): NavigationState; setState(partial: Partial): void; subscribe(listener: StateListener): () => void; addInflightAction(action: InflightAction): void; removeInflightAction(id: string): void; isActionInProgress(): boolean; setActionInProgress(value: boolean): void; getSegmentState(): SegmentState; setPath(path: string): void; setCurrentUrl(url: string): void; setSegmentIds(ids: string[]): void; getHistoryKey(): string; setHistoryKey(key: string): void; cacheSegmentsForHistory(historyKey: string, segments: ResolvedSegment[], handleData?: HandleData): void; getCachedSegments(historyKey: string): { segments: ResolvedSegment[]; stale: boolean; handleData?: HandleData; } | undefined; hasHistoryCache(historyKey: string): boolean; updateCacheHandleData(historyKey: string, handleData: HandleData): void; markCacheAsStale(): void; markCacheAsStaleAndBroadcast(): void; clearHistoryCache(): void; broadcastCacheInvalidation(): void; setCrossTabRefreshCallback(callback: () => void): void; getInterceptSourceUrl(): string | null; setInterceptSourceUrl(url: string | null): void; onUpdate(callback: UpdateSubscriber): () => void; emitUpdate(update: NavigationUpdate): void; getActionState(actionId: string): TrackedActionState; setActionState(actionId: string, state: Partial): void; subscribeToAction(actionId: string, listener: ActionStateListener): () => void; } /** * Disposable abort controller with automatic cleanup */ export interface DisposableAbortController extends Disposable { controller: AbortController; } /** * Request controller for managing concurrent requests * * Separates navigation requests (aborted on new navigation) from * action requests (complete independently of navigation). */ export interface RequestController { create(): AbortController; createDisposable(): DisposableAbortController; /** Create a disposable controller for actions (not aborted by navigation) */ createActionDisposable(): DisposableAbortController; /** Abort all navigation requests (not actions) */ abortAll(): void; /** Abort all action requests (used for error handling) */ abortAllActions(): void; remove(controller: AbortController): void; } /** * Options for partial navigation fetch */ export interface FetchPartialOptions { targetUrl: string; segmentIds: string[]; previousUrl: string; signal?: AbortSignal; /** If true, this is a stale cache revalidation request - server should force revalidators */ staleRevalidation?: boolean; interceptSourceUrl?: string; /** RSC version for cache invalidation detection */ version?: string; /** If true, this is an HMR refetch - server should invalidate manifest cache */ hmr?: boolean; } /** * Result of a partial fetch including stream completion tracking */ export interface FetchPartialResult { payload: RscPayload; /** Promise that resolves when the response stream is fully consumed */ streamComplete: Promise; } /** * Navigation client for fetching RSC payloads */ export interface NavigationClient { fetchPartial(options: FetchPartialOptions): Promise; } /** * Options for link interception */ export interface LinkInterceptorOptions { shouldIntercept?: (link: HTMLAnchorElement) => boolean; } /** * Server action bridge for handling server actions */ export interface ServerActionBridge { register(): void; unregister(): void; } /** * Configuration for server action bridge */ export interface ServerActionBridgeConfig { store: NavigationStore; client: NavigationClient; deps: RscBrowserDependencies; onUpdate: UpdateSubscriber; renderSegments: (segments: ResolvedSegment[], options?: RenderSegmentsOptions) => Promise | ReactNode; } /** * Navigation bridge for handling client-side navigation */ export interface NavigationBridge { navigate(url: string, options?: NavigateOptions): Promise; refresh(): Promise; handlePopstate(): Promise; registerLinkInterception(): () => void; } /** * Configuration for navigation bridge */ export interface NavigationBridgeConfig { store: NavigationStore; client: NavigationClient; onUpdate: UpdateSubscriber; renderSegments: (segments: ResolvedSegment[], options?: RenderSegmentsOptions) => Promise | ReactNode; } export type { ResolvedSegment }; //# sourceMappingURL=types.d.ts.map