@raf-query/core 0.13.2 → 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
  /**
@@ -1,40 +1,35 @@
1
1
  import { QueryKey } from "./keys/keys.mjs";
2
- import { AnyRoot, DefaultTypes, RootOf, RootTag, RootTypes } from "./root.mjs";
2
+ import { NoParts, RootOf, RootTag, RootTypes, SetsOf } from "./root.mjs";
3
3
  import { QueryClient } from "./client.mjs";
4
4
  //#region src/options.d.ts
5
5
  /**
6
- * What a `queryFn` gets: the client making the request, the query's key,
7
- * `meta` and abort `signal`.
6
+ * What a `queryFn` gets: the client making the request, the query's key and
7
+ * abort `signal`, and what the client's parts give every `queryFn`.
8
8
  *
9
9
  * @see https://raf-query.katt.dev/docs/query-functions#the-query-function-context
10
10
  */
11
- export interface QueryFunctionContext<TKey extends QueryKey = QueryKey> {
11
+ export type QueryFunctionContext<TKey extends QueryKey = QueryKey, TTypes extends RootTypes = NoParts> = TTypes["context"] & {
12
12
  /**
13
- * The client making the request. A server makes one per request, so it
14
- * keys per-request services, such as an API client with the request's
15
- * cookies.
13
+ * The client making the request. A server makes one per request, so
14
+ * what its parts give the context belongs to that request, such as an
15
+ * API client with the request's cookies.
16
16
  */
17
- readonly client: QueryClient;
18
- /** The query's `meta`, typed by its root where the query is defined. */
19
- readonly meta: object;
17
+ readonly client: QueryClient<TTypes>;
20
18
  readonly queryKey: TKey;
21
19
  /** Aborted when the request is restarted or its entry is removed. */
22
20
  readonly signal: AbortSignal;
23
- }
21
+ };
24
22
  declare const dataTag: unique symbol;
25
23
  declare const queryFnDataTag: unique symbol;
26
- /** Options every query takes. */
27
- export interface BaseOptions<TKey extends QueryKey, TTypes extends RootTypes = RootTypes> {
24
+ /**
25
+ * The per-query options the core reads, whatever parts the client has. A
26
+ * client's `defaults` set them for every query.
27
+ *
28
+ * @see https://raf-query.katt.dev/docs/important-defaults#changing-the-defaults
29
+ */
30
+ export interface CoreOptions {
28
31
  /** How long an entry with no reader stays cached. Default 5 minutes; never on the server. */
29
32
  readonly gcTime?: number;
30
- /**
31
- * Settings for the root's links and features, and data for targets: the
32
- * fields the root's parts declare, such as `retry` with the `retry()`
33
- * link.
34
- */
35
- readonly meta?: NoInfer<Partial<TTypes["meta"]>>;
36
- /** A plain array, usually built by a `group()`. Handles keep its literal type. */
37
- readonly queryKey: TKey;
38
33
  /**
39
34
  * `false` for a query only a browser can run (a permission, the service
40
35
  * worker, `localStorage`): a server client never starts it, never sends
@@ -49,12 +44,29 @@ export interface BaseOptions<TKey extends QueryKey, TTypes extends RootTypes = R
49
44
  /** Keep the deeply equal parts of new data, so they keep their identity. Default `true`. */
50
45
  readonly structuralSharing?: boolean;
51
46
  }
47
+ /** Options every query takes. */
48
+ export interface BaseOptions<TKey extends QueryKey> extends CoreOptions {
49
+ /** A plain array, usually built by a `group()`. Handles keep its literal type. */
50
+ readonly queryKey: TKey;
51
+ }
52
+ /**
53
+ * The options a builder bound to `T` lets a query set, beside its key and
54
+ * `queryFn`: the core's, and those `T`'s parts declare. For a fragment
55
+ * several factories share:
56
+ *
57
+ * ```ts
58
+ * const pinned = { retry: false, staleTime: Infinity } satisfies OptionsOf<typeof makeQueryClient>;
59
+ * ```
60
+ *
61
+ * @see https://raf-query.katt.dev/docs/links-and-features#typing-options-by-the-client
62
+ */
63
+ export type OptionsOf<T> = CoreOptions & Partial<SetsOf<T>["options"]>;
52
64
  /**
53
65
  * What `queryOptions` and `infiniteQueryOptions` return.
54
66
  *
55
67
  * @see https://raf-query.katt.dev/docs/api-reference#query-factories
56
68
  */
57
- export interface QueryOptions<TKey extends QueryKey = QueryKey, TQueryFnData = unknown, TData = TQueryFnData, TTypes extends RootTypes = RootTypes> extends BaseOptions<TKey, TTypes> {
69
+ export interface QueryOptions<TKey extends QueryKey = QueryKey, TQueryFnData = unknown, TData = TQueryFnData, TTypes extends RootTypes = RootTypes> extends BaseOptions<TKey> {
58
70
  /** Set by `infiniteQueryOptions` from `keepPages`: whether `load` keeps the cached pages. */
59
71
  readonly "~keep"?: (data: never) => boolean;
60
72
  /** Phantom: the root the builder is bound to. Never set at runtime. */
@@ -91,17 +103,18 @@ type Awaitable<T> = PromiseLike<T> | T;
91
103
  */
92
104
  export type FromQueryFn<T> = T extends unknown ? T : never;
93
105
  /**
94
- * `queryOptions`, with `meta` checked against the root `TTypes`.
106
+ * `queryOptions` for a root: `TTypes` is what the factories it builds need
107
+ * of a client, and `TSets` the options they can set.
95
108
  *
96
- * @see https://raf-query.katt.dev/docs/links-and-features#typing-meta-by-its-root
109
+ * @see https://raf-query.katt.dev/docs/links-and-features#typing-options-by-the-client
97
110
  */
98
- export interface QueryOptionsBuilder<TTypes extends RootTypes> {
99
- <const TKey extends QueryKey, TChunk, TData>(options: BaseOptions<TKey, TTypes> & {
100
- readonly queryFn: (context: QueryFunctionContext<TKey>) => AsyncIterable<TChunk>;
111
+ export interface QueryOptionsBuilder<TTypes extends RootTypes, TSets extends RootTypes = TTypes> {
112
+ <const TKey extends QueryKey, TChunk, TData>(options: BaseOptions<TKey> & Partial<TSets["options"]> & {
113
+ readonly queryFn: (context: QueryFunctionContext<TKey, TTypes>) => AsyncIterable<TChunk>;
101
114
  readonly stream: StreamOptions<TData, TChunk>;
102
115
  }): QueryOptions<TKey, TData, TData, TTypes>;
103
- <const TKey extends QueryKey, TQueryFnData, TData = TQueryFnData>(options: BaseOptions<TKey, TTypes> & {
104
- readonly queryFn: (context: QueryFunctionContext<TKey>) => Awaitable<TQueryFnData>;
116
+ <const TKey extends QueryKey, TQueryFnData, TData = TQueryFnData>(options: BaseOptions<TKey> & Partial<TSets["options"]> & {
117
+ readonly queryFn: (context: QueryFunctionContext<TKey, TTypes>) => Awaitable<TQueryFnData>;
105
118
  readonly select?: (data: FromQueryFn<TQueryFnData>) => TData;
106
119
  }): QueryOptions<TKey, TQueryFnData, TData, TTypes>;
107
120
  }
@@ -120,27 +133,36 @@ export interface QueryOptionsBuilder<TTypes extends RootTypes> {
120
133
  * fold its chunks into the data. Readers get the data after the first chunk,
121
134
  * and every later chunk updates it in place.
122
135
  *
123
- * Its `meta` is any record. To check `meta` against a client's links and
124
- * features, use the builder {@link bindQueryOptions} returns.
136
+ * It takes the core's options only, and its factories run on any client.
137
+ * For the options and the `queryFn` context a client's parts declare, use
138
+ * the builder {@link bindQueryOptions} returns.
125
139
  *
126
140
  * @see https://raf-query.katt.dev/docs/query-factories
127
141
  */
128
- export declare const queryOptions: QueryOptionsBuilder<DefaultTypes>;
142
+ export declare const queryOptions: QueryOptionsBuilder<NoParts>;
129
143
  /**
130
- * `queryOptions` bound to a root: `meta` takes the fields the root's links
131
- * and features declare, and verbs take only that root's clients. `T` is the
132
- * client's type, or the type of a function that makes it. Bind once per app:
144
+ * `queryOptions` bound to a root: it takes the options the root's parts
145
+ * declare, its `queryFn`s get their context, and its factories run on the
146
+ * clients that have those parts. `T` is the client's type, or the type of a
147
+ * function that makes it. Bind once per client:
133
148
  *
134
149
  * ```ts
135
150
  * // raf.ts
136
151
  * export const queryOptions = bindQueryOptions<typeof makeQueryClient>();
137
152
  * ```
138
153
  *
154
+ * A library names the parts its factories need by their declarations, and
155
+ * as `Optional` the ones whose options it sets where the client has them:
156
+ *
157
+ * ```ts
158
+ * const queryOptions = bindQueryOptions<Convex & Optional<Retry>>();
159
+ * ```
160
+ *
139
161
  * It returns `queryOptions` itself; only the types change.
140
162
  *
141
- * @see https://raf-query.katt.dev/docs/links-and-features#typing-meta-by-its-root
163
+ * @see https://raf-query.katt.dev/docs/links-and-features#typing-options-by-the-client
142
164
  */
143
- export declare function bindQueryOptions<T>(): QueryOptionsBuilder<RootOf<T>>;
165
+ export declare function bindQueryOptions<T>(): QueryOptionsBuilder<RootOf<T>, SetsOf<T>>;
144
166
  /**
145
167
  * A function of the query's input that returns its options. The input is a
146
168
  * method parameter typed `unknown`, which TypeScript checks bivariantly:
@@ -198,8 +220,8 @@ export type InputOf<TFactory extends QueryFactory> = Parameters<TFactory> extend
198
220
  export type InputArgs<TFactory extends QueryFactory> = Parameters<TFactory> extends [] ? [] : Parameters<TFactory> extends [infer TInput, ...Array<unknown>] ? [input: TInput] : [input?: Parameters<TFactory>[0]];
199
221
  /** A factory's key type, the way handles carry it. */
200
222
  export type KeyOf<TFactory extends QueryFactory> = ReturnType<TFactory>["queryKey"];
201
- /** The root a factory's builder is bound to; any root for an unbound one. */
223
+ /** The root a factory's builder is bound to: what the factory needs of a client. */
202
224
  export type RootOfFactory<TFactory extends QueryFactory> = ReturnType<TFactory> extends {
203
225
  readonly "~root"?: RootTag<infer TTypes>;
204
- } ? TTypes extends DefaultTypes ? AnyRoot : TTypes : AnyRoot;
226
+ } ? TTypes : NoParts;
205
227
  //#endregion