@raf-query/core 0.13.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,16 @@
1
- import { feature } from "../../client.mjs";
1
+ import { part } from "../../client.mjs";
2
2
  import { refetchStaleReads } from "../shared.mjs";
3
3
  //#region src/features/reconnect-refetch/reconnect-refetch.ts
4
4
  /**
5
5
  * Refetch read, stale queries when the browser comes back online, except
6
- * those with `meta: { refetchOnReconnect: false }`.
6
+ * those with `refetchOnReconnect: false`.
7
7
  *
8
8
  * @see https://raf-query.katt.dev/docs/testing#focus-and-the-network
9
9
  */
10
10
  function reconnectRefetch() {
11
- return feature((client, signal) => {
11
+ return part({ setup: (client, signal) => {
12
12
  window.addEventListener("online", () => refetchStaleReads(client, "refetchOnReconnect"), { signal });
13
- });
13
+ } });
14
14
  }
15
15
  //#endregion
16
16
  export { reconnectRefetch };
@@ -1,13 +1,15 @@
1
1
  import { isObject } from "../guards.mjs";
2
2
  import { fetchEntry, isStale } from "../entry.mjs";
3
3
  //#region src/features/shared.ts
4
- function metaOf(entry, field) {
5
- const meta = entry.options?.meta;
6
- if (!isObject(meta) || !(field in meta)) return;
7
- return meta[field];
4
+ /** An option a part declares, for the entry: the query's, or else the client's default. */
5
+ function optionOf(entry, name) {
6
+ for (const options of [entry.options, entry.client.config.defaults]) if (isObject(options) && name in options) {
7
+ const fields = options;
8
+ if (fields[name] !== void 0) return fields[name];
9
+ }
8
10
  }
9
11
  function refetchStaleReads(client, optOut) {
10
- for (const entry of client["~entries"].values()) if (entry.readers.size > 0 && isStale(entry) && metaOf(entry, optOut) !== false) fetchEntry(entry);
12
+ for (const entry of client["~entries"].values()) if (entry.readers.size > 0 && isStale(entry) && optionOf(entry, optOut) !== false) fetchEntry(entry);
11
13
  }
12
14
  //#endregion
13
- export { metaOf, refetchStaleReads };
15
+ export { optionOf, refetchStaleReads };
package/dist/index.d.mts CHANGED
@@ -1,19 +1,19 @@
1
1
  import { Group, QueryKey, group } from "./keys/keys.mjs";
2
- import { QueryMeta } from "./root.mjs";
3
2
  import { QueryInfo, Target } from "./keys/targets.mjs";
4
- import { DataOf, InfiniteQueryFactory, InputOf, QueryFactory, QueryFunctionContext, QueryOptions, QueryOptionsBuilder, SingleQueryFactory, StreamOptions, bindQueryOptions, queryOptions } from "./options.mjs";
3
+ import { Optional, RootOf } from "./root.mjs";
4
+ import { CoreOptions, DataOf, InfiniteQueryFactory, InputOf, OptionsOf, QueryFactory, QueryFunctionContext, QueryOptions, QueryOptionsBuilder, SingleQueryFactory, StreamOptions, bindQueryOptions, queryOptions } from "./options.mjs";
5
5
  import { Thenable } from "./thenable.mjs";
6
6
  import { abortError } from "./entry.mjs";
7
- import { Clock, Feature, Link, Operation, QueryClient, QueryClientConfig, createQueryClient, feature, link } from "./client.mjs";
8
- import { focusRefetch } from "./features/focus-refetch/focus-refetch.mjs";
9
- import { reconnectRefetch } from "./features/reconnect-refetch/reconnect-refetch.mjs";
10
- import { polling } from "./features/polling/polling.mjs";
7
+ import { Clock, Operation, Part, QueryClient, QueryClientConfig, createQueryClient, part } from "./client.mjs";
8
+ import { FocusRefetch, focusRefetch } from "./features/focus-refetch/focus-refetch.mjs";
9
+ import { ReconnectRefetch, reconnectRefetch } from "./features/reconnect-refetch/reconnect-refetch.mjs";
10
+ import { Polling, polling } from "./features/polling/polling.mjs";
11
11
  import { DehydrateOptions, DehydratedEntry, DehydratedResult, DehydratedState, DehydratedStream, RedactedError, canDehydrate, dehydrate, dehydrateStream, hydrate } from "./hydration/hydration.mjs";
12
12
  import { InfiniteData, InfiniteQueryFunctionContext, InfiniteQueryOptions, InfiniteQueryOptionsBuilder, bindInfiniteQueryOptions, infiniteQueryOptions } from "./infinite/infinite.mjs";
13
13
  import { ClientFor, PartialInput, getData, invalidateAll, invalidateMany, invalidateOne, isFetching, removeAll, removeMany, removeOne, resetAll, resetMany, resetOne, setData } from "./verbs.mjs";
14
14
  import { PageControls, PageDirection, PageState, fetchNextPage, fetchPreviousPage, hasNextPage, hasPreviousPage } from "./infinite/paging.mjs";
15
- import { RetryOptions, retry } from "./links/retry/retry.mjs";
15
+ import { Retry, RetryOptions, retry } from "./links/retry/retry.mjs";
16
16
  import { QueryTimeoutError, timeout } from "./links/timeout/timeout.mjs";
17
17
  import { LoadEntry, LoadEntryOptions, Loaded, QueryHandle, load, prefetch, revalidate, skipToken, swr, waterfallHandle } from "./load.mjs";
18
18
  import { Recommended, recommended } from "./presets.mjs";
19
- export { type ClientFor, type Clock, type DataOf, type DehydrateOptions, type DehydratedEntry, type DehydratedResult, type DehydratedState, type DehydratedStream, type Feature, type Group, type InfiniteData, type InfiniteQueryFactory, type InfiniteQueryFunctionContext, type InfiniteQueryOptions, type InfiniteQueryOptionsBuilder, type InputOf, type Link, type LoadEntry, type LoadEntryOptions, type Loaded, type Operation, type PageControls, type PageDirection, type PageState, type PartialInput, type QueryClient, type QueryClientConfig, type QueryFactory, type QueryFunctionContext, type QueryHandle, type QueryInfo, type QueryKey, type QueryMeta, type QueryOptions, type QueryOptionsBuilder, QueryTimeoutError, type Recommended, RedactedError, type RetryOptions, type SingleQueryFactory, type StreamOptions, type Target, type Thenable, abortError, bindInfiniteQueryOptions, bindQueryOptions, canDehydrate, createQueryClient, dehydrate, dehydrateStream, feature, fetchNextPage, fetchPreviousPage, focusRefetch, getData, group, hasNextPage, hasPreviousPage, hydrate, infiniteQueryOptions, invalidateAll, invalidateMany, invalidateOne, isFetching, link, load, polling, prefetch, queryOptions, recommended, reconnectRefetch, removeAll, removeMany, removeOne, resetAll, resetMany, resetOne, retry, revalidate, setData, skipToken, swr, timeout, waterfallHandle };
19
+ export { type ClientFor, type Clock, type CoreOptions, type DataOf, type DehydrateOptions, type DehydratedEntry, type DehydratedResult, type DehydratedState, type DehydratedStream, type FocusRefetch, type Group, type InfiniteData, type InfiniteQueryFactory, type InfiniteQueryFunctionContext, type InfiniteQueryOptions, type InfiniteQueryOptionsBuilder, type InputOf, type LoadEntry, type LoadEntryOptions, type Loaded, type Operation, type Optional, type OptionsOf, type PageControls, type PageDirection, type PageState, type Part, type PartialInput, type Polling, type QueryClient, type QueryClientConfig, type QueryFactory, type QueryFunctionContext, type QueryHandle, type QueryInfo, type QueryKey, type QueryOptions, type QueryOptionsBuilder, QueryTimeoutError, type Recommended, type ReconnectRefetch, RedactedError, type Retry, type RetryOptions, type RootOf, type SingleQueryFactory, type StreamOptions, type Target, type Thenable, abortError, bindInfiniteQueryOptions, bindQueryOptions, canDehydrate, createQueryClient, dehydrate, dehydrateStream, fetchNextPage, fetchPreviousPage, focusRefetch, getData, group, hasNextPage, hasPreviousPage, hydrate, infiniteQueryOptions, invalidateAll, invalidateMany, invalidateOne, isFetching, load, part, polling, prefetch, queryOptions, recommended, reconnectRefetch, removeAll, removeMany, removeOne, resetAll, resetMany, resetOne, retry, revalidate, setData, skipToken, swr, timeout, waterfallHandle };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { createQueryClient, feature, link } from "./client.mjs";
1
+ import { createQueryClient, part } from "./client.mjs";
2
2
  import { group } from "./keys/keys.mjs";
3
3
  import { bindQueryOptions, queryOptions } from "./options.mjs";
4
4
  import { abortError } from "./entry.mjs";
@@ -13,4 +13,4 @@ import { QueryTimeoutError, timeout } from "./links/timeout/timeout.mjs";
13
13
  import { load, prefetch, revalidate, skipToken, swr, waterfallHandle } from "./load.mjs";
14
14
  import { recommended } from "./presets.mjs";
15
15
  import { getData, invalidateAll, invalidateMany, invalidateOne, isFetching, removeAll, removeMany, removeOne, resetAll, resetMany, resetOne, setData } from "./verbs.mjs";
16
- export { QueryTimeoutError, RedactedError, abortError, bindInfiniteQueryOptions, bindQueryOptions, canDehydrate, createQueryClient, dehydrate, dehydrateStream, feature, fetchNextPage, fetchPreviousPage, focusRefetch, getData, group, hasNextPage, hasPreviousPage, hydrate, infiniteQueryOptions, invalidateAll, invalidateMany, invalidateOne, isFetching, link, load, polling, prefetch, queryOptions, recommended, reconnectRefetch, removeAll, removeMany, removeOne, resetAll, resetMany, resetOne, retry, revalidate, setData, skipToken, swr, timeout, waterfallHandle };
16
+ export { QueryTimeoutError, RedactedError, abortError, bindInfiniteQueryOptions, bindQueryOptions, canDehydrate, createQueryClient, dehydrate, dehydrateStream, fetchNextPage, fetchPreviousPage, focusRefetch, getData, group, hasNextPage, hasPreviousPage, hydrate, infiniteQueryOptions, invalidateAll, invalidateMany, invalidateOne, isFetching, load, part, polling, prefetch, queryOptions, recommended, reconnectRefetch, removeAll, removeMany, removeOne, resetAll, resetMany, resetOne, retry, revalidate, setData, skipToken, swr, timeout, waterfallHandle };
@@ -1,5 +1,5 @@
1
1
  import { QueryKey } from "../keys/keys.mjs";
2
- import { DefaultTypes, RootOf, RootTypes } from "../root.mjs";
2
+ import { NoParts, RootOf, RootTypes, SetsOf } from "../root.mjs";
3
3
  import { BaseOptions, FromQueryFn, QueryFunctionContext, QueryOptions } from "../options.mjs";
4
4
  import { Operation } from "../client.mjs";
5
5
  //#region src/infinite/infinite.d.ts
@@ -17,12 +17,12 @@ export interface InfiniteData<TPage, TParam = unknown> {
17
17
  *
18
18
  * @see https://raf-query.katt.dev/docs/infinite-queries
19
19
  */
20
- export interface InfiniteQueryFunctionContext<TKey extends QueryKey, TParam> extends QueryFunctionContext<TKey> {
20
+ export type InfiniteQueryFunctionContext<TKey extends QueryKey, TParam, TTypes extends RootTypes = NoParts> = QueryFunctionContext<TKey, TTypes> & {
21
21
  readonly direction: "backward" | "forward";
22
22
  readonly pageParam: TParam;
23
- }
23
+ };
24
24
  type PageParamFn<TPage, TParam> = (page: TPage, pages: ReadonlyArray<TPage>, pageParam: TParam) => TParam | null | undefined;
25
- interface InfiniteOptions<TKey extends QueryKey, TPage, TParam, TData, TTypes extends RootTypes = RootTypes> extends BaseOptions<TKey, TTypes> {
25
+ interface InfiniteOptions<TKey extends QueryKey, TPage, TParam, TData> extends BaseOptions<TKey> {
26
26
  readonly getNextPageParam: PageParamFn<TPage, TParam>;
27
27
  readonly getPreviousPageParam?: PageParamFn<TPage, TParam>;
28
28
  readonly initialPageParam: TParam;
@@ -45,17 +45,18 @@ interface InfiniteOptions<TKey extends QueryKey, TPage, TParam, TData, TTypes ex
45
45
  *
46
46
  * @see https://raf-query.katt.dev/docs/infinite-queries
47
47
  */
48
- export type InfiniteQueryOptions<TKey extends QueryKey = QueryKey, TPage = unknown, TParam = unknown, TData = InfiniteData<TPage, TParam>, TTypes extends RootTypes = RootTypes> = QueryOptions<TKey, InfiniteData<TPage, TParam>, TData, TTypes> & Pick<InfiniteOptions<TKey, TPage, TParam, TData, TTypes>, "getNextPageParam" | "getPreviousPageParam" | "initialPageParam" | "maxPages"> & {
48
+ export type InfiniteQueryOptions<TKey extends QueryKey = QueryKey, TPage = unknown, TParam = unknown, TData = InfiniteData<TPage, TParam>, TTypes extends RootTypes = RootTypes> = QueryOptions<TKey, InfiniteData<TPage, TParam>, TData, TTypes> & Pick<InfiniteOptions<TKey, TPage, TParam, TData>, "getNextPageParam" | "getPreviousPageParam" | "initialPageParam" | "maxPages"> & {
49
49
  readonly "~run": (op: Operation) => Promise<unknown>;
50
50
  };
51
51
  /**
52
- * `infiniteQueryOptions`, with `meta` checked against the root `TTypes`.
52
+ * `infiniteQueryOptions` for a root: `TTypes` is what the factories it
53
+ * builds need of a client, and `TSets` the options they can set.
53
54
  *
54
- * @see https://raf-query.katt.dev/docs/links-and-features#typing-meta-by-its-root
55
+ * @see https://raf-query.katt.dev/docs/links-and-features#typing-options-by-the-client
55
56
  */
56
- export interface InfiniteQueryOptionsBuilder<TTypes extends RootTypes> {
57
- <const TKey extends QueryKey, TPage, TParam, TData = InfiniteData<TPage, TParam>>(options: InfiniteOptions<TKey, FromQueryFn<TPage>, TParam, TData, TTypes> & {
58
- readonly queryFn: (context: InfiniteQueryFunctionContext<TKey, TParam>) => PromiseLike<TPage> | TPage;
57
+ export interface InfiniteQueryOptionsBuilder<TTypes extends RootTypes, TSets extends RootTypes = TTypes> {
58
+ <const TKey extends QueryKey, TPage, TParam, TData = InfiniteData<TPage, TParam>>(options: InfiniteOptions<TKey, FromQueryFn<TPage>, TParam, TData> & Partial<TSets["options"]> & {
59
+ readonly queryFn: (context: InfiniteQueryFunctionContext<TKey, TParam, TTypes>) => PromiseLike<TPage> | TPage;
59
60
  }): InfiniteQueryOptions<TKey, TPage, TParam, TData, TTypes>;
60
61
  }
61
62
  /**
@@ -72,12 +73,13 @@ export interface InfiniteQueryOptionsBuilder<TTypes extends RootTypes> {
72
73
  * });
73
74
  * ```
74
75
  *
75
- * Its `meta` is any record. To check `meta` against a client's links and
76
- * features, use the builder {@link bindInfiniteQueryOptions} returns.
76
+ * It takes the core's options only. For the options and the `queryFn`
77
+ * context a client's parts declare, use the builder
78
+ * {@link bindInfiniteQueryOptions} returns.
77
79
  *
78
80
  * @see https://raf-query.katt.dev/docs/infinite-queries
79
81
  */
80
- export declare const infiniteQueryOptions: InfiniteQueryOptionsBuilder<DefaultTypes>;
82
+ export declare const infiniteQueryOptions: InfiniteQueryOptionsBuilder<NoParts>;
81
83
  /**
82
84
  * `infiniteQueryOptions` bound to a root, like `bindQueryOptions`. Bind it
83
85
  * next to `queryOptions`, in apps that page:
@@ -87,7 +89,7 @@ export declare const infiniteQueryOptions: InfiniteQueryOptionsBuilder<DefaultTy
87
89
  * export const infiniteQueryOptions = bindInfiniteQueryOptions<typeof makeQueryClient>();
88
90
  * ```
89
91
  *
90
- * @see https://raf-query.katt.dev/docs/links-and-features#typing-meta-by-its-root
92
+ * @see https://raf-query.katt.dev/docs/links-and-features#typing-options-by-the-client
91
93
  */
92
- export declare function bindInfiniteQueryOptions<T>(): InfiniteQueryOptionsBuilder<RootOf<T>>;
94
+ export declare function bindInfiniteQueryOptions<T>(): InfiniteQueryOptionsBuilder<RootOf<T>, SetsOf<T>>;
93
95
  //#endregion
@@ -14,8 +14,9 @@ import { hashKey } from "../keys/keys.mjs";
14
14
  * });
15
15
  * ```
16
16
  *
17
- * Its `meta` is any record. To check `meta` against a client's links and
18
- * features, use the builder {@link bindInfiniteQueryOptions} returns.
17
+ * It takes the core's options only. For the options and the `queryFn`
18
+ * context a client's parts declare, use the builder
19
+ * {@link bindInfiniteQueryOptions} returns.
19
20
  *
20
21
  * @see https://raf-query.katt.dev/docs/infinite-queries
21
22
  */
@@ -33,7 +34,7 @@ const infiniteQueryOptions = (options) => ({
33
34
  * export const infiniteQueryOptions = bindInfiniteQueryOptions<typeof makeQueryClient>();
34
35
  * ```
35
36
  *
36
- * @see https://raf-query.katt.dev/docs/links-and-features#typing-meta-by-its-root
37
+ * @see https://raf-query.katt.dev/docs/links-and-features#typing-options-by-the-client
37
38
  */
38
39
  function bindInfiniteQueryOptions() {
39
40
  return infiniteQueryOptions;
@@ -65,9 +66,9 @@ function pageFor(data, pageParam) {
65
66
  }
66
67
  async function runPages(op, source) {
67
68
  const fetchPage = (pageParam, direction) => Promise.resolve(source.queryFn({
69
+ ...op.client.context,
68
70
  client: op.client,
69
71
  direction,
70
- meta: op.meta,
71
72
  pageParam,
72
73
  queryKey: op.queryKey,
73
74
  signal: op.signal
@@ -1,13 +1,9 @@
1
1
  import { AnyFactory, hashKey } from "./keys/keys.mjs";
2
- import { Decl, DefaultTypes, MetaOf, RootOf, RootTypes } from "./root.mjs";
3
2
  import { AnyTarget } from "./keys/targets.mjs";
3
+ import { Decl, NoParts, Root, RootOf, RootOfParts, RootTypes, SetsOf } from "./root.mjs";
4
4
  import { fulfilled, mapThenable, pending, rejected } from "./thenable.mjs";
5
5
  import { Entry, EntryState, entryOf, fetchEntry, isBrowserOnly, isInvalidated, isStale, remove, reset, subscribeEntry } from "./entry.mjs";
6
- import { AnyFeature, AnyLink, ClientEvent, mount, systemClock } from "./client.mjs";
7
- import { FocusRefetchMeta } from "./features/focus-refetch/focus-refetch.mjs";
8
- import { ReconnectRefetchMeta } from "./features/reconnect-refetch/reconnect-refetch.mjs";
9
- import { PollingMeta } from "./features/polling/polling.mjs";
6
+ import { AnyPart, ClientEvent, mount, systemClock } from "./client.mjs";
10
7
  import { fetchPage, pageState } from "./infinite/paging.mjs";
11
- import { RetryMeta } from "./links/retry/retry.mjs";
12
8
  import { LoadRecord, isWaterfallHandle, loadsOf, readData, startIfStale } from "./load.mjs";
13
- export { type AnyFactory, type AnyFeature, type AnyLink, type AnyTarget, type ClientEvent, type Decl, type DefaultTypes, type Entry, type EntryState, type FocusRefetchMeta, type LoadRecord, type MetaOf, type PollingMeta, type ReconnectRefetchMeta, type RetryMeta, type RootOf, type RootTypes, entryOf, fetchEntry, fetchPage, fulfilled, hashKey, isBrowserOnly, isInvalidated, isStale, isWaterfallHandle, loadsOf, mapThenable, mount, pageState, pending, readData, rejected, remove, reset, startIfStale, subscribeEntry, systemClock };
9
+ export { type AnyFactory, type AnyPart, type AnyTarget, type ClientEvent, type Decl, type Entry, type EntryState, type LoadRecord, type NoParts, type Root, type RootOf, type RootOfParts, type RootTypes, type SetsOf, entryOf, fetchEntry, fetchPage, fulfilled, hashKey, isBrowserOnly, isInvalidated, isStale, isWaterfallHandle, loadsOf, mapThenable, mount, pageState, pending, readData, rejected, remove, reset, startIfStale, subscribeEntry, systemClock };
@@ -1,17 +1,16 @@
1
1
  import { AnyFactory, Group, QueryKey } from "./keys.mjs";
2
- import { QueryMeta } from "../root.mjs";
3
2
  //#region src/keys/targets.d.ts
4
3
  /**
5
4
  * What a target's `where` sees of a query.
6
5
  *
7
6
  * @see https://raf-query.katt.dev/docs/query-invalidation#matching-with-where
8
7
  */
9
- export interface QueryInfo<TMeta = QueryMeta> {
8
+ export interface QueryInfo<TOptions = object> {
10
9
  /** The query's data, before `select`; `undefined` without data. */
11
10
  readonly data: unknown;
12
11
  readonly input: unknown;
13
- /** The `meta` its factory gave it. An entry only hydrated has `{}` until it's read. */
14
- readonly meta: TMeta;
12
+ /** The options its factory gave it. An entry only hydrated has `{}` until it's read. */
13
+ readonly options: TOptions;
15
14
  readonly queryKey: QueryKey;
16
15
  }
17
16
  /**
@@ -19,16 +18,16 @@ export interface QueryInfo<TMeta = QueryMeta> {
19
18
  * parameter the verb was called with.
20
19
  *
21
20
  * ```ts
22
- * const ownedBy: Target<AppMeta, Team> = { where: (query, team) => query.meta.owner === team };
21
+ * const ownedBy: Target<RootOf<Ownership>["options"], Team> = { where: (query, team) => query.options.owner === team };
23
22
  * await invalidateMany(client, ownedBy, "editorial");
24
23
  * ```
25
24
  *
26
25
  * @see https://raf-query.katt.dev/docs/query-invalidation#targets
27
26
  */
28
- export interface Target<TMeta = QueryMeta, TParam = never> {
29
- readonly where: (query: QueryInfo<TMeta>, param: TParam) => boolean;
27
+ export interface Target<TOptions = object, TParam = never> {
28
+ readonly where: (query: QueryInfo<TOptions>, param: TParam) => boolean;
30
29
  }
31
- /** A target of any meta and parameter. */
30
+ /** A target of any options and parameter. */
32
31
  export interface AnyTarget {
33
32
  readonly where: (query: never, param: never) => boolean;
34
33
  }
@@ -12,14 +12,15 @@ import { isPlainRecord } from "./keys.mjs";
12
12
  * path, `drafts("byId", input)` is `["posts", "drafts", "byId", input]`.
13
13
  * It matches every key that starts with its path, whoever built the key,
14
14
  * so it covers its subgroups and their queries.
15
- * - Any object with `where(query, param)`, typed by the client's root
16
- * `meta`: predicates over a query's key, input, `meta` or data. Tags
17
- * are one, written in user code over a `meta.tags` a feature declares.
15
+ * - Any object with `where(query, param)`, typed by the options the
16
+ * client's parts declare: predicates over a query's key, input, options
17
+ * or data. Tags are one, written in user code over a `tags` option a
18
+ * part declares.
18
19
  *
19
20
  * Invalidation records a stamp per target. An entry is invalidated when a
20
21
  * matching stamp is newer than the request its data came from. Entries with
21
22
  * readers refetch at once; the rest are checked when they are next read,
22
- * which always goes through their factory, so `where` sees their `meta`.
23
+ * which always goes through their factory, so `where` sees their options.
23
24
  *
24
25
  * An entry that was only hydrated has no factory or input until it's read.
25
26
  * A factory target covers it from that first read: invalidation through its
@@ -64,7 +65,7 @@ function infoOf(entry) {
64
65
  return {
65
66
  data: entry.state.data,
66
67
  input: entry.input,
67
- meta: entry.options?.meta ?? {},
68
+ options: entry.options ?? {},
68
69
  queryKey: entry.key
69
70
  };
70
71
  }
@@ -1,4 +1,4 @@
1
- import { Link } from "../../client.mjs";
1
+ import { Part } from "../../client.mjs";
2
2
  //#region src/links/retry/retry.d.ts
3
3
  /**
4
4
  * Options for {@link retry}.
@@ -6,28 +6,32 @@ import { Link } from "../../client.mjs";
6
6
  * @see https://raf-query.katt.dev/docs/retries#options
7
7
  */
8
8
  export interface RetryOptions {
9
- /** Retries after the first attempt. A query's `meta.retry` wins. Default 3. */
9
+ /** Retries after the first attempt. A query's `retry`, or the client's default for it, wins. Default 3. */
10
10
  readonly attempts?: number;
11
11
  /** Wait before retry `n` (0-based), in ms. Default: doubling from 1 s, at most 30 s. */
12
12
  readonly delay?: (attempt: number) => number;
13
13
  /** Whether an error is worth retrying. Default: every error but a thrown `Response`. */
14
14
  readonly when?: (error: unknown) => boolean;
15
15
  }
16
- /** What `retry()` reads from a query's `meta`. */
17
- export interface RetryMeta {
18
- /** Attempts for this query, or `false`. */
19
- readonly retry?: number | false;
16
+ /**
17
+ * What `retry()` declares.
18
+ *
19
+ * @see https://raf-query.katt.dev/docs/retries
20
+ */
21
+ export interface Retry {
22
+ readonly options: {
23
+ /** Attempts for this query, or `false`. */
24
+ readonly retry?: number | false;
25
+ };
20
26
  }
21
27
  /**
22
28
  * Retry failed requests. Thrown `Response`s (router redirects and
23
29
  * not-founds) and cancelled requests aren't retried,
24
30
  * server clients never retry, and a browser that is offline
25
31
  * waits until it's back online before retrying. A query sets its own
26
- * attempts with `meta: { retry }`.
32
+ * attempts with `retry`.
27
33
  *
28
34
  * @see https://raf-query.katt.dev/docs/retries
29
35
  */
30
- export declare function retry(options?: RetryOptions): Link<{
31
- readonly meta: RetryMeta;
32
- }>;
36
+ export declare function retry(options?: RetryOptions): Part<Retry>;
33
37
  //#endregion
@@ -1,4 +1,4 @@
1
- import { link } from "../../client.mjs";
1
+ import { part } from "../../client.mjs";
2
2
  import { isResponse } from "../../guards.mjs";
3
3
  //#region src/links/retry/retry.ts
4
4
  function wait(clock, ms, signal) {
@@ -31,13 +31,13 @@ const notThrownResponse = (error) => !isResponse(error);
31
31
  * not-founds) and cancelled requests aren't retried,
32
32
  * server clients never retry, and a browser that is offline
33
33
  * waits until it's back online before retrying. A query sets its own
34
- * attempts with `meta: { retry }`.
34
+ * attempts with `retry`.
35
35
  *
36
36
  * @see https://raf-query.katt.dev/docs/retries
37
37
  */
38
38
  function retry(options = {}) {
39
- return link(async (op, next) => {
40
- const configured = op.meta.retry;
39
+ return part({ link: async (op, next) => {
40
+ const configured = op.options.retry;
41
41
  const attempts = configured === false ? 0 : configured ?? options.attempts ?? 3;
42
42
  if (op.client.isServer || attempts === 0) return next(op);
43
43
  for (let attempt = 0;; attempt++) try {
@@ -47,7 +47,7 @@ function retry(options = {}) {
47
47
  await wait(op.client.clock, (options.delay ?? defaultDelay)(attempt), op.signal);
48
48
  await whenOnline(op.signal);
49
49
  }
50
- });
50
+ } });
51
51
  }
52
52
  //#endregion
53
53
  export { retry };
@@ -1,4 +1,4 @@
1
- import { Link } from "../../client.mjs";
1
+ import { Part } from "../../client.mjs";
2
2
  //#region src/links/timeout/timeout.d.ts
3
3
  /**
4
4
  * What a request that took too long fails with.
@@ -13,5 +13,5 @@ export declare class QueryTimeoutError extends Error {
13
13
  *
14
14
  * @see https://raf-query.katt.dev/docs/retries#timeouts
15
15
  */
16
- export declare function timeout(ms: number): Link;
16
+ export declare function timeout(ms: number): Part;
17
17
  //#endregion
@@ -1,3 +1,4 @@
1
+ import { part } from "../../client.mjs";
1
2
  //#region src/links/timeout/timeout.ts
2
3
  /**
3
4
  * What a request that took too long fails with.
@@ -13,7 +14,7 @@ var QueryTimeoutError = class extends Error {
13
14
  * @see https://raf-query.katt.dev/docs/retries#timeouts
14
15
  */
15
16
  function timeout(ms) {
16
- return (op, next) => {
17
+ return part({ link: (op, next) => {
17
18
  const controller = new AbortController();
18
19
  const signal = AbortSignal.any([op.signal, controller.signal]);
19
20
  return new Promise((resolve, reject) => {
@@ -29,7 +30,7 @@ function timeout(ms) {
29
30
  op.client.clock.clearTimeout(handle);
30
31
  });
31
32
  });
32
- };
33
+ } });
33
34
  }
34
35
  //#endregion
35
36
  export { QueryTimeoutError, timeout };
package/dist/load.d.mts CHANGED
@@ -1,4 +1,5 @@
1
- import { DataOf, InputArgs, InputOf, KeyOf, QueryFactory } from "./options.mjs";
1
+ import { RootTypes } from "./root.mjs";
2
+ import { DataOf, InputArgs, InputOf, KeyOf, QueryFactory, RootOfFactory } from "./options.mjs";
2
3
  import { Entry } from "./entry.mjs";
3
4
  import { QueryClient } from "./client.mjs";
4
5
  //#region src/load.d.ts
@@ -84,6 +85,12 @@ type LoadEntries = Record<string, LoadEntry | typeof skipToken>;
84
85
  type HandleOf<TEntry> = TEntry extends LoadEntry ? QueryHandle<TEntry["factory"]> : undefined;
85
86
  type DataOfEntry<TEntry> = TEntry extends LoadEntry ? DataOf<TEntry["factory"]> : never;
86
87
  type LoadedData<TEntries extends LoadEntries> = { [TName in keyof TEntries as TEntries[TName] extends LoadEntry<QueryFactory, "revalidate" | "swr"> ? TName : never]: DataOfEntry<TEntries[TName]>; };
88
+ /** In an error: the parts an entry's factory needs, which the client passed to `load` lacks. */
89
+ interface ClientLacksParts<TTypes extends RootTypes> {
90
+ readonly "~the client lacks parts this entry's factory needs": TTypes;
91
+ }
92
+ /** An entry, if the client has the parts its factory needs; else what it needs. */
93
+ type EntryFor<TTypes extends RootTypes, TEntry> = TEntry extends LoadEntry<infer TFactory> ? [TTypes] extends [RootOfFactory<TFactory>] ? TEntry : ClientLacksParts<RootOfFactory<TFactory>> : TEntry;
87
94
  /**
88
95
  * What `load` resolves to: a handle per entry (`undefined` for `skipToken`),
89
96
  * and the data of `swr` and `revalidate` entries.
@@ -124,7 +131,7 @@ export declare function startIfStale(entry: Entry): void;
124
131
  *
125
132
  * @see https://raf-query.katt.dev/docs/starting-queries
126
133
  */
127
- export declare function load<const TEntries extends LoadEntries>(client: QueryClient, entries: TEntries): Promise<Loaded<TEntries>>;
134
+ export declare function load<TTypes extends RootTypes, const TEntries extends LoadEntries>(client: QueryClient<TTypes>, entries: TEntries & { readonly [TName in keyof TEntries]: EntryFor<TTypes, TEntries[TName]>; }): Promise<Loaded<TEntries>>;
128
135
  /** Whether a handle came from `waterfallHandle()`: reading it is expected to fetch. */
129
136
  export declare function isWaterfallHandle(handle: Pick<QueryHandle, "queryKey">): boolean;
130
137
  /**
package/dist/load.mjs CHANGED
@@ -81,13 +81,10 @@ function startIfStale(entry) {
81
81
  function isFresh(entry) {
82
82
  return entry.client.isServer ? entry.state.hasData && !isInvalidated(entry) : !isStale(entry);
83
83
  }
84
- /**
85
- * Drop pages the entry's `keepPages` turns down for the input it was just
86
- * loaded with, so they load again from that input's `initialPageParam`.
87
- */
88
- function dropUnkeptPages(entry) {
84
+ /** Whether the entry's `keepPages` takes its cached pages for the input it was just loaded with. */
85
+ function keepsPages(entry) {
89
86
  const keep = entry.options?.["~keep"];
90
- if (keep && entry.state.hasData && !keep(entry.state.data)) reset(entry);
87
+ return !keep || !entry.state.hasData || keep(entry.state.data);
91
88
  }
92
89
  function waitFresh(entry, pages) {
93
90
  if (isFresh(entry)) return Promise.resolve({ ok: true });
@@ -123,14 +120,18 @@ async function load(client, entries) {
123
120
  }]).map((loaded) => {
124
121
  const item = loaded.item;
125
122
  const cached = entryOf(client, item.factory, item.input);
126
- dropUnkeptPages(cached);
123
+ const kept = keepsPages(cached);
127
124
  let wait;
128
- if (item.kind === "prefetch") startIfStale(cached);
129
- else if (isBrowserOnly(cached) && !cached.state.hasData) wait = Promise.resolve({
125
+ if (item.kind === "prefetch") {
126
+ if (kept) startIfStale(cached);
127
+ } else if (isBrowserOnly(cached) && !cached.state.hasData) wait = Promise.resolve({
130
128
  error: /* @__PURE__ */ new Error(`raf-query: ${cached.hash} has \`ssr: false\`, so the server can't wait for it. Load it with prefetch() instead of ${item.kind}().`),
131
129
  ok: false
132
130
  });
133
- else wait = (item.kind === "revalidate" ? waitFresh : waitAny)(cached, item.pages);
131
+ else {
132
+ if (!kept) reset(cached);
133
+ wait = (item.kind === "revalidate" ? waitFresh : waitAny)(cached, item.pages);
134
+ }
134
135
  return {
135
136
  entry: cached,
136
137
  item,