import type { Args, ArgsOrVoid, IResource, IResourceAgent, IResourceConfig, IResourceLiteState, Keyed, TPackedResource, TResourceFetchOptions, TResourcePrefetchOptions } from "../../../query/types/index.js"; import { type ReadonlySignal } from "../../../signals/index.js"; import { QueryCacheEntry } from "../cache/QueryCacheEntry.js"; /** * Data-fetching abstraction with caching and SWR. * * Each unique set of serialized arguments maps to a single {@link QueryCacheEntry}. * Entries are retained for `retentionTime` ms after the last subscriber unsubscribes. * * @template TArgs - Query argument type. * @template TData - Query return data type. */ export declare class Resource implements IResource { private readonly _cache; private readonly _queryFn; readonly _key: string | undefined; /** @internal Read by Snapshoter.getSnapshot to skip non-snapshotable resources. */ readonly _snapshotable: boolean; private readonly _retentionTime; private readonly _serializeArgs; private readonly _mapError; private readonly _onCacheEntryAdded; private readonly _onQueryStarted; private readonly _beforeQuery?; private readonly _allowStreamPatches; private _streamPatchWarned; constructor(config: IResourceConfig); /** * Execute a query with the given arguments. * * @deprecated Use {@link prefetch}: `trigger(args)` ≈ `prefetch(args)`, * `trigger(args, true)` ≈ `prefetch(args, { force: true })`. Not an exact * match on an `error`-state entry: `prefetch` retries it in both modes, * while `trigger` left it untouched (its force path went through * `refresh()`, which is a no-op from `error`). And unlike `trigger`, * every `prefetch` call — cache hits included — holds a keepalive * subscription until it settles and then restarts the entry's retention * countdown. Will be removed in a future release. * @param args - Query arguments. * @param doForce - When `true`, forces a refresh even if data is cached. */ trigger(args: Args, doForce?: boolean): void; /** * Mark the entry as stale and trigger a background SWR refresh. * * @param args - Query arguments identifying the cache entry. */ refresh(args: Args): void; /** * Synchronously return the cache entry for the given arguments. * * @param args - Query arguments (or `void` when `TArgs` is `void`). * @param doInitiate - When `true`, creates and starts the entry if absent, * so the result is never `null`. * @returns The cache entry, or `null` if not found and `doInitiate` is `false`. */ getEntry(args: ArgsOrVoid, doInitiate: true): QueryCacheEntry; getEntry(args: ArgsOrVoid, doInitiate?: boolean): QueryCacheEntry | null; getEntry(args: Keyed, doInitiate: true): QueryCacheEntry; /** * Synchronously return the cache entry for an already-serialized key. * * Unlike {@link getEntry}, the key is used for a direct cache lookup without * serialization. Needed where only the serialized key is available — e.g. * cross-tab sync, where raw args never leave the requesting tab. * * @param key - Serialized cache key (as produced by {@link serialize}). * @returns The cache entry, or `null` if not found. */ getEntryByKey(key: string): QueryCacheEntry | null; /** * Reactive variant of {@link getEntry} — establishes a signal dependency * so that `Signal.compute` / `Signal.effect` callers re-evaluate when the * cache map changes (entry added or removed). * * @param args - Query arguments (or `void` when `TArgs` is `void`). * @param doInitiate - When `false` (default) the signal is a pure observer: * reading it never mutates the cache and yields `null` while the entry is * absent. When `true`, reading the signal creates and starts the entry if it * is missing, so the signal always yields a non-null entry — re-creating it * on read even after it was removed. Creation is lazy: it happens on first * read (the underlying computed is lazy), not at call time, and that read * therefore has a side effect — it starts the query and fires the * `onCacheEntryAdded` / `onQueryStarted` hooks. Avoid `doInitiate: true` * where a read must stay pure (e.g. inside React render). * @returns The cache entry, or `null` if not found and `doInitiate` is `false`. */ getEntry$(args: ArgsOrVoid, doInitiate: true): ReadonlySignal>; getEntry$(args: ArgsOrVoid, doInitiate?: boolean): ReadonlySignal | null>; getEntry$(args: Keyed, doInitiate?: boolean): ReadonlySignal | null>; /** * Create a reactive {@link ResourceAgent} that observes this resource * and provides SWR-aware state transitions. */ createAgent(): IResourceAgent; /** * Serialize arguments into a cache key string. * * @param args - Query arguments. * @returns The serialized key used for cache lookup. */ serialize(args: Args): string; /** * Wrap arguments into a `{ value, key }` pair, avoiding repeated serialization. * * @param args - Query arguments. * @returns A {@link Keyed} wrapper containing the original args and their cache key. */ toKeyed(args: Args): Keyed; /** Iterate over all cache entries. */ getEntries(): IterableIterator>; /** * Bundle this resource with arguments into an inert {@link TPackedResource} * descriptor. Nothing is executed — the consumer hands the descriptor back to * the library, which can later read `resource`/`args` (e.g. `resource.prefetch(args)`). * * @param args - Query arguments (or a {@link Keyed} wrapper). * @returns A `{ kind: "resource", resource, args }` descriptor. */ pack(args: Args): TPackedResource; /** * Ensure data is available for the given arguments and resolve with it. * * If an entry already holds data (including stale data being refreshed) it * resolves immediately without a network round-trip. A cold entry is created * and its first load awaited; a failed entry is retried. Rejects if the * awaited query fails, the entry is removed, or `options.signal` aborts. * * Designed for router loaders (`ensureQueryData`-style): the consumer awaits * data, then a component mounts and subscribes within the retention window. * * @param args - Query arguments (or a {@link Keyed} wrapper). * @param options - See {@link TResourceFetchOptions}. */ ensure(args: Args, options?: TResourceFetchOptions): Promise; /** * Fetch fresh data for the given arguments and resolve with it. * * Unlike {@link ensure}, this always reflects the result of a fresh query: a * cached entry is refreshed (or retried) and the new result awaited; an * in-flight query is awaited rather than duplicated. Rejects if the query * fails, the entry is removed, or `options.signal` aborts. With cross-tab * sync enabled, a cold entry may be filled from another tab's cache * (`beforeQuery`) instead of this tab's own network round-trip. * * @param args - Query arguments (or a {@link Keyed} wrapper). * @param options - See {@link TResourceFetchOptions}. */ fetch(args: Args, options?: TResourceFetchOptions): Promise; /** * Warm the cache for the given arguments without surfacing the result. * * A fire-and-forget {@link ensure}: reuses cached data when present, creates * the entry synchronously, never rejects, and — unlike {@link ensure} — is * intentionally not abort-aware so speculative warm-ups survive navigation. * With `options.force` it warms with *fresh* data instead (a fire-and-forget * {@link fetch}): an existing entry is refreshed, or retried after an error. * * @param args - Query arguments (or a {@link Keyed} wrapper). * @param options - See {@link TResourcePrefetchOptions}. */ prefetch(args: Args, options?: TResourcePrefetchOptions): Promise; /** * Get a simplified state object for the given arguments. */ getState(args: ArgsOrVoid): IResourceLiteState; /** Clear all cache entries. */ reset(): void; /** * Run the user's queryFn, converting a synchronous throw (possible with a * non-async queryFn) into a rejected promise. Without this the throw would * escape the QueryCacheEntry constructor on the initial run — no entry * created, prefetch()/ensure()/fetch() throwing synchronously — and escape * `_execute` on refresh()/retry() after the machine had already moved to * refreshing/pending, stranding it there. As a rejection it flows through * the machine (→ error / refresh-error) like any other query failure. */ private _callQueryFn; /** * One-time warning for optimistic patches created while a query stream is * open (see `allowStreamPatches`). Wired into every entry as `onStreamPatch`. */ private _warnStreamPatch; /** Get an existing cache entry (refreshing it when `doForce`) or create a new one. */ private _getOrCreate; private _createEntry; /** Standard entry creation: queryFn auto-executes in constructor. */ private _createEntryDirect; /** Entry creation with beforeQuery intercept: starts in pending, asks other tabs first. */ private _createEntryWithBeforeQuery; private _hydrateEntry; private _fireOnCacheEntryAdded; private _fireOnQueryStarted; }