import { JSXElementType, JSXElement, Props } from '../elements.js'; import '../jsx-globals.js'; import { state } from './state.js'; import { CoreTelemetry } from './telemetry.js'; import { on } from './lifecycle.js'; import { action } from './actions.js'; /** Freshness classification for a {@link Query}'s current data. */ type QueryConsistency = 'fresh' | 'stale' | 'refreshing' | 'pending-write'; /** Why a {@link Query} is stale. */ type QueryStaleReason = 'aborted' | 'error' | 'inconsistent'; /** Isolated cache/state container backing queries and mutations, e.g. one per test or request. */ interface DataRuntime { readonly queryCache: Map; readonly queryData: Map; } /** Options for {@link createDataRuntime}. */ interface DataRuntimeOptions { queryCache?: Map; queryData?: Map; } /** Reusable query definition for {@link defineQuery}: key, fetcher, and freshness checks. */ interface QueryDefinition { readonly key: (input: TInput) => string; readonly fetch: ( input: TInput, context: { signal: AbortSignal; } ) => Promise; readonly isConsistent?: (data: TResult) => boolean; readonly reconcile?: ( data: TResult, context: { key: string; } ) => Promise | boolean; } /** Stable identity for one member of a {@link QueryCollection}. */ type QueryCollectionKey = string | number | symbol; /** One keyed input and its underlying cache-backed query reader. */ interface QueryCollectionEntry< TInput, TResult extends {}, TKey extends QueryCollectionKey = string, > { readonly key: TKey; readonly input: TInput; readonly query: Query; } /** Options for {@link createQueryCollection}. */ interface QueryCollectionOptions< TInput, TResult extends {}, TKey extends QueryCollectionKey = string, > { readonly query: QueryDefinition; readonly inputs: () => readonly TInput[]; readonly key: (input: TInput) => TKey; readonly concurrency?: number; readonly runtime?: DataRuntime; } /** Aggregate reactive state for a lifecycle-owned dynamic query collection. */ interface QueryCollection< TInput, TResult extends {}, TKey extends QueryCollectionKey = string, > { readonly entries: readonly QueryCollectionEntry[]; readonly loading: boolean; readonly settled: boolean; readonly results: ReadonlyMap; readonly errors: ReadonlyMap; get(key: TKey): QueryCollectionEntry | undefined; retry(key: TKey): Promise; } /** Context passed to server prefetch callbacks, exposing a scoped `prefetch` helper. */ interface QueryPrefetchContext { readonly runtime: DataRuntime; readonly request?: Request; /** Effective fetch signal; native runtimes compose caller cancellation and retirement. */ readonly signal: AbortSignal; readonly mode: 'ssr' | 'spa'; prefetch( query: QueryDefinition, input: TInput ): Promise; } /** Server-side handler that resolves a {@link QueryDefinition}'s data for `serveQuery`. */ type ServerQueryHandler = (context: { input: TInput; request?: Request; signal: AbortSignal; }) => Promise | TResult; /** Options for {@link invalidate} and {@link QueryScope.invalidate}. */ interface InvalidateOptions { markPendingWrite?: boolean; runtime?: DataRuntime; } /** Options for {@link invalidateOnInterval}. */ interface InvalidateOnIntervalOptions extends InvalidateOptions { intervalMs: number; activeOn?: string | readonly string[]; visibleOnly?: boolean; focusedOnly?: boolean; } /** Component-owned refresh policy for browser focus/visibility and reconnect. */ interface RefreshOnActivityOptions { /** Age since successful completion (or initial data). Zero refreshes on every event. */ staleTimeMs: number | 'always'; /** Listen to window focus and visible document transitions. Defaults to true. */ focus?: boolean; /** Listen to the window online hint. Defaults to true. */ online?: boolean; /** Disable listeners without changing hook order. Defaults to true. */ enabled?: boolean; runtime?: DataRuntime; } /** A JSON-serializable value usable as part of a query key or invalidation prefix. */ type QueryKeyPart = | string | number | boolean | null | undefined | readonly QueryKeyPart[] | { readonly [key: string]: QueryKeyPart; }; /** Namespaced key-building and invalidation helper returned by {@link queryScope}. */ interface QueryScope { key(...parts: QueryKeyPart[]): string; prefix(...parts: QueryKeyPart[]): string; invalidate(parts: readonly QueryKeyPart[], options?: InvalidateOptions): void; } type QueryControls = { refresh(): Promise; }; type QueryLoading = { data: null; error: null; loading: true; refreshing: false; stale: false; consistency: 'fresh'; staleReason: null; }; type QueryFresh = { data: T; error: null; loading: false; refreshing: false; stale: false; consistency: 'fresh'; staleReason: null; }; type QueryRefreshing = { data: T; error: null; loading: false; refreshing: true; stale: true; consistency: 'refreshing'; staleReason: null; }; type QueryPendingWrite = { data: T; error: null; loading: false; refreshing: true; stale: true; consistency: 'pending-write'; staleReason: null; }; type QueryStaleValue = { data: T; error: null; loading: false; refreshing: false; stale: true; consistency: 'stale'; staleReason: 'aborted' | 'inconsistent'; }; type QueryStaleErrorWithValue = { data: T; error: {}; loading: false; refreshing: false; stale: true; consistency: 'stale'; staleReason: 'error'; }; type QueryStaleError = { data: null; error: {}; loading: false; refreshing: false; stale: true; consistency: 'stale'; staleReason: 'error'; }; /** Reactive read state for a query cell: data, loading/refresh flags, and freshness. */ type Query = QueryControls & ( | QueryLoading | QueryFresh | QueryRefreshing | QueryPendingWrite | QueryStaleValue | QueryStaleErrorWithValue | QueryStaleError ); type MutationControls = { execute(input: TInput): Promise; abort(): void; reset(): void; }; type MutationIdle = { status: 'idle'; pending: false; error: null; result: null; }; type MutationPending = { status: 'pending'; pending: true; error: null; result: null; }; type MutationSuccess = { status: 'success'; pending: false; error: null; result: TResult; }; type MutationError = { status: 'error'; pending: false; error: {}; result: null; }; /** Reactive state for a mutation cell: status, error/result, and execute/abort/reset controls. */ type Mutation = MutationControls & (MutationIdle | MutationPending | MutationSuccess | MutationError); type QueryOptions = { key: string; fetch: (ctx: { signal: AbortSignal }) => Promise; isConsistent?: (data: T) => boolean; reconcile?: ( data: T, ctx: { key: string; } ) => Promise | boolean; runtime?: DataRuntime; initialData?: T; skipInitialFetch?: boolean; /** Cache lifetime in milliseconds. Defaults to 0 after component unmount and five minutes for ownerless client queries. */ gcTime?: number; }; /** Options for {@link createMutation}. */ type MutationOptions = { /** Stable identity used by runtime-scoped mutation test overrides. */ key?: string; action: ( input: TInput, ctx: { signal: AbortSignal; } ) => Promise; /** Apply a synchronous optimistic change. Return a rollback for failure or abort. */ optimistic?: ( input: TInput, ctx: { signal: AbortSignal } ) => void | (() => void); /** * Query prefixes to invalidate after success, matched by `:`-delimited * segment the same way as {@link invalidate}. */ affects?: (input: TInput, result: TResult) => string[]; afterSuccess?: 'invalidate'; runtime?: DataRuntime; }; /** * Create a reactive {@link Mutation} cell bound to the current component, * running `options.action` on `execute()` and optionally invalidating * affected query prefixes on success. */ declare function createMutation( options: MutationOptions ): Mutation; /** * Create a reactive {@link Query} cell bound to the current component, either * from inline `options` (key + fetch) or a reusable {@link QueryDefinition} * plus its input. */ declare function createQuery(options: QueryOptions): Query; declare function createQuery( definition: QueryDefinition, input: TInput, options?: Omit, 'key' | 'fetch'> ): Query; /** Create a new, isolated {@link DataRuntime} with its own query/mutation caches. */ declare function createDataRuntime(options?: DataRuntimeOptions): DataRuntime; /** Terminally retire an isolated runtime. The shared default cannot be disposed. */ declare function disposeDataRuntime(runtime: DataRuntime): void; /** Get the process-wide default {@link DataRuntime} used when none is provided explicitly. */ declare function getDefaultDataRuntime(): DataRuntime; /** * Mark all cached queries under `prefix` as stale, triggering a refresh. * Matching is by `:`-delimited segment: a key matches when it equals `prefix`, * when `prefix` ends in `:`, or when the key continues `prefix` at a `:` * (`'user:1'` matches `user:1:posts` but not `user:10`). Only `:` is a * segment boundary; the empty prefix matches every key. */ declare function invalidate(prefix: string, options?: InvalidateOptions): void; /** Create a {@link QueryScope} that namespaces keys and can bind invalidations to a runtime. */ declare function queryScope( namespace: string, options?: Pick ): QueryScope; /** * Periodically invalidate queries matching `prefix` on a fixed interval, * optionally gated by active route, document visibility, or window focus. * `prefix` matches key segments the same way as {@link invalidate}. */ declare function invalidateOnInterval( prefix: string, options: InvalidateOnIntervalOptions ): void; /** Refresh live queries on browser activity, with an explicit freshness age. */ declare function refreshOnActivity( prefix: string, options: RefreshOnActivityOptions ): void; /** * Create one lifecycle-owned collection of dynamically keyed readers for a * reusable query definition, with bounded collection-started fetches. */ declare function createQueryCollection< TInput, TResult extends {}, TKey extends QueryCollectionKey = string, >( options: QueryCollectionOptions ): QueryCollection; /** Lookup table of server handlers keyed by their {@link QueryDefinition}, built by {@link defineServerQueries}. */ interface ServerQueryRegistry { readonly entries: readonly ServerQueryEntry[]; get( query: QueryDefinition ): ServerQueryHandler | undefined; } /** A query paired with the server handler that resolves it, produced by {@link serveQuery}. */ interface ServerQueryEntry { readonly query: QueryDefinition; readonly handler: ServerQueryHandler; } /** Pair a {@link QueryDefinition} with the server-side handler that resolves it. */ declare function serveQuery( query: QueryDefinition, handler: ServerQueryHandler ): ServerQueryEntry; /** Build a {@link ServerQueryRegistry} from one or more {@link serveQuery} entries. */ declare function defineServerQueries( ...entries: readonly ServerQueryEntry[] ): ServerQueryRegistry; /** Freeze and return a reusable {@link QueryDefinition}. */ declare function defineQuery( definition: QueryDefinition ): QueryDefinition; /** * Create a {@link QueryPrefetchContext} for prefetching query data ahead of * render, e.g. during SSR route resolution. */ declare function createQueryPrefetchContext(options?: { runtime?: DataRuntime; registry?: ServerQueryRegistry; request?: Request; signal?: AbortSignal; mode?: 'ssr' | 'spa'; telemetry?: CoreTelemetry; }): QueryPrefetchContext; /** Prefetch `query` with `input` into a {@link QueryPrefetchContext}'s runtime. */ declare function prefetchQuery( context: QueryPrefetchContext, query: QueryDefinition, input: TInput ): Promise; /** * Extract a runtime's cached query data into a JSON-serializable snapshot. * Throws a `TypeError` naming the key and path of any value that would not * survive JSON transport unchanged (for example a `Date`, `Map`, or bigint). */ declare function dehydrateDataRuntime( runtime: DataRuntime ): Record; /** Load a {@link dehydrateDataRuntime} snapshot back into a runtime's query cache. */ declare function hydrateDataRuntime(runtime: DataRuntime, data: unknown): void; export { QueryConsistency, QueryStaleReason, DataRuntime, DataRuntimeOptions, QueryDefinition, QueryCollectionKey, QueryCollectionEntry, QueryCollectionOptions, QueryCollection, QueryPrefetchContext, ServerQueryHandler, InvalidateOptions, InvalidateOnIntervalOptions, RefreshOnActivityOptions, QueryKeyPart, QueryScope, QueryControls, QueryLoading, QueryFresh, QueryRefreshing, QueryPendingWrite, QueryStaleValue, QueryStaleErrorWithValue, QueryStaleError, Query, MutationControls, MutationIdle, MutationPending, MutationSuccess, MutationError, Mutation, QueryOptions, MutationOptions, createMutation, createQuery, createDataRuntime, disposeDataRuntime, getDefaultDataRuntime, invalidate, queryScope, invalidateOnInterval, refreshOnActivity, createQueryCollection, ServerQueryRegistry, ServerQueryEntry, serveQuery, defineServerQueries, defineQuery, createQueryPrefetchContext, prefetchQuery, dehydrateDataRuntime, hydrateDataRuntime, };