@raf-query/core 0.13.2 → 0.15.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.
package/CHANGELOG.md CHANGED
@@ -1,10 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.15.0](https://github.com/KATT/raf-query/compare/0.14.0...0.15.0) (2026-11-11)
4
+
5
+ ### ⚠ BREAKING CHANGES
6
+
7
+ * **core:** a part's link can give or change the queryFn context per request ([#251](https://github.com/KATT/raf-query/issues/251))
8
+
9
+ ### Features
10
+
11
+ * **core:** a part's link can give or change the queryFn context per request ([#251](https://github.com/KATT/raf-query/issues/251)) ([3358dde](https://github.com/KATT/raf-query/commit/3358ddeb1a0a19b0459af55d70b6e23a05a902d5))
12
+
13
+ ## [0.14.0](https://github.com/KATT/raf-query/compare/0.13.2...0.14.0) (2026-11-11)
14
+
15
+ ### ⚠ BREAKING CHANGES
16
+
17
+ - **core:** parts declare the options and queryFn context a client's queries get ([#250](https://github.com/KATT/raf-query/issues/250))
18
+
19
+ ### Features
20
+
21
+ - **core:** parts declare the options and queryFn context a client's queries get ([#250](https://github.com/KATT/raf-query/issues/250)) ([931b7ed](https://github.com/KATT/raf-query/commit/931b7ed83837576c607b63e2dfdd1c795129cd41))
22
+
3
23
  ## [0.13.2](https://github.com/KATT/raf-query/compare/0.13.1...0.13.2) (2026-11-10)
4
24
 
5
25
  ### Bug Fixes
6
26
 
7
- * **core:** a prefetch never drops pages keepPages turns down ([#249](https://github.com/KATT/raf-query/issues/249)) ([3c66020](https://github.com/KATT/raf-query/commit/3c66020ee7562c6e2592017a1b11af94bc89e340))
27
+ - **core:** a prefetch never drops pages keepPages turns down ([#249](https://github.com/KATT/raf-query/issues/249)) ([3c66020](https://github.com/KATT/raf-query/commit/3c66020ee7562c6e2592017a1b11af94bc89e340))
8
28
 
9
29
  ## [0.13.1](https://github.com/KATT/raf-query/compare/0.13.0...0.13.1) (2026-11-10)
10
30
 
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @raf-query/core
2
2
 
3
- The framework-agnostic query client behind [raf-query](https://raf-query.katt.dev): a small cache that dedupes requests, keeps entries fresh, and hands out serializable handles. Retries, timeouts, refetch on focus or reconnect, polling and hydration are opt-in links, features and exports, so a client bundles only what it turns on.
3
+ The framework-agnostic query client behind [raf-query](https://raf-query.katt.dev): a small cache that dedupes requests, keeps entries fresh, and hands out serializable handles. Retries, timeouts, refetch on focus or reconnect, polling and hydration are opt-in, as parts you give the client or exports you import, so a client bundles only what it turns on.
4
4
 
5
5
  **[Documentation](https://raf-query.katt.dev)** · [API reference](https://raf-query.katt.dev/docs/api-reference#raf-querycore) · [GitHub](https://github.com/KATT/raf-query)
6
6
 
@@ -37,7 +37,10 @@ export function issueQuery(input: { id: number }) {
37
37
  });
38
38
  }
39
39
 
40
- const queryClient = createQueryClient({ links: [retry()], staleTime: 5000 });
40
+ const queryClient = createQueryClient({
41
+ parts: [retry()],
42
+ defaults: { staleTime: 5000 },
43
+ });
41
44
 
42
45
  const [, data] = await load(queryClient, {
43
46
  issue: revalidate(issueQuery, { id: 1 }),
@@ -49,9 +52,9 @@ await invalidateOne(queryClient, issueQuery, { id: 1 });
49
52
 
50
53
  ## Entry points
51
54
 
52
- | Import | Use |
53
- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------- |
54
- | `@raf-query/core` | `createQueryClient`, query factories, `load`, the verbs, the built-in links and features, `group`, `dehydrate` and `hydrate` |
55
+ | Import | Use |
56
+ | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
57
+ | `@raf-query/core` | `createQueryClient`, query factories, `load`, the verbs, the built-in parts (`retry()`, `polling()` and so on), `group`, `dehydrate` and `hydrate` |
55
58
 
56
59
  ## License
57
60
 
package/dist/client.d.mts CHANGED
@@ -1,16 +1,10 @@
1
1
  import { QueryKey } from "./keys/keys.mjs";
2
- import { AnyPart, AnyRoot, Decl, Declares, MetaOf, MetaOfDecl, RootTypes } from "./root.mjs";
3
2
  import { Stamp } from "./keys/targets.mjs";
4
- import { QueryOptions } from "./options.mjs";
3
+ import { AnyDeclares, ContextOfDecl, Decl, Declares, NoDecl, NoParts, OptionsOfDecl, Root, RootOfParts, RootTypes } from "./root.mjs";
4
+ import { CoreOptions, QueryOptions } from "./options.mjs";
5
5
  import { Listeners, SubscribeOptions } from "./subscribe.mjs";
6
6
  import { Entry } from "./entry.mjs";
7
7
  //#region src/client.d.ts
8
- type LinkFunction = (op: Operation, next: (op: Operation) => Promise<unknown>) => Promise<unknown>;
9
- type FeatureFunction = (client: QueryClient, signal: AbortSignal) => void;
10
- /** Any link, whatever `meta` it reads. */
11
- export type AnyLink = LinkFunction & AnyPart;
12
- /** Any feature, whatever `meta` it reads. */
13
- export type AnyFeature = FeatureFunction & AnyPart;
14
8
  /**
15
9
  * Time and timers, injectable so tests control them without patching globals.
16
10
  *
@@ -23,12 +17,19 @@ export interface Clock {
23
17
  }
24
18
  export declare const systemClock: Clock;
25
19
  /**
26
- * One request, as links see it. `TMeta` is what the link declares.
20
+ * One request, as a part's link sees it. `TDecl` is what the part declares:
21
+ * `options` has the fields it reads.
27
22
  *
28
- * @see https://raf-query.katt.dev/docs/links-and-features#links-and-features
23
+ * @see https://raf-query.katt.dev/docs/links-and-features#parts
29
24
  */
30
- export interface Operation<TMeta extends object = object> {
25
+ export interface Operation<TDecl extends Decl = Decl> {
31
26
  readonly client: QueryClient;
27
+ /**
28
+ * What the `queryFn` gets beside the client, key and signal: the parts'
29
+ * context, as the links before this one left it. Pass `next` an
30
+ * operation with another `context` to change it for this request.
31
+ */
32
+ readonly context: Partial<ContextOfDecl<TDecl>>;
32
33
  /** The entry's data when the request started (paged queries extend it). */
33
34
  readonly data: unknown;
34
35
  /** For paged queries: which page to add. */
@@ -36,54 +37,119 @@ export interface Operation<TMeta extends object = object> {
36
37
  readonly hasData: boolean;
37
38
  readonly hash: string;
38
39
  readonly input: unknown;
39
- /** The query's `meta`, `{}` when it has none. */
40
- readonly meta: TMeta;
41
- readonly options: QueryOptions;
40
+ /** The query's options, over the client's `defaults`. */
41
+ readonly options: Partial<OptionsOfDecl<TDecl>> & QueryOptions;
42
42
  /** For paged queries: how many pages a first load fetches. */
43
43
  readonly pages: number | undefined;
44
44
  readonly queryKey: QueryKey;
45
45
  readonly signal: AbortSignal;
46
46
  }
47
+ type LinkFunction = (op: Operation, next: (op: Operation) => Promise<unknown>) => Promise<unknown>;
48
+ type SetupFunction = (client: QueryClient, signal: AbortSignal) => void;
47
49
  /**
48
- * Wraps every request, like a tRPC link. Call `next(op)` to run the rest of
49
- * the chain; the last link is the query's own `queryFn`. `TDecl` is the
50
- * `meta` it reads: see {@link link}.
51
- *
52
- * @see https://raf-query.katt.dev/docs/links-and-features#links-and-features
53
- */
54
- export type Link<TDecl extends Decl = Decl> = LinkFunction & Declares<TDecl>;
55
- /**
56
- * A cache-wide behavior, started when a provider mounts the client and
57
- * stopped by `signal`. `TDecl` is the `meta` it reads: see {@link feature}.
50
+ * One piece of a client's behavior: any of a link that wraps every request,
51
+ * a feature's `setup`, and values for every `queryFn`'s context. `TDecl` is
52
+ * what it declares: see {@link part}.
58
53
  *
59
- * @see https://raf-query.katt.dev/docs/links-and-features#links-and-features
54
+ * @see https://raf-query.katt.dev/docs/links-and-features#parts
60
55
  */
61
- export type Feature<TDecl extends Decl = Decl> = FeatureFunction & Declares<TDecl>;
56
+ export interface Part<TDecl extends Decl = NoDecl> extends Declares<TDecl> {
57
+ readonly context?: object;
58
+ readonly link?: LinkFunction;
59
+ readonly setup?: SetupFunction;
60
+ }
61
+ /** Any part, whatever it declares. */
62
+ export interface AnyPart extends AnyDeclares {
63
+ readonly context?: object;
64
+ readonly link?: LinkFunction;
65
+ readonly setup?: SetupFunction;
66
+ }
67
+ type LinkOf<TDecl extends Decl, TNext> = (op: Operation<TDecl>, next: (op: TNext) => Promise<unknown>) => Promise<unknown>;
68
+ interface PartSetup<TDecl extends Decl> {
69
+ /**
70
+ * A cache-wide behavior, started when a provider mounts the client and
71
+ * stopped by `signal`. The client is typed with this part, so it runs
72
+ * the factories of a builder bound to it.
73
+ */
74
+ readonly setup?: (client: QueryClient<Root<TDecl>>, signal: AbortSignal) => void;
75
+ }
76
+ /** The context a declaration says its part gives. */
77
+ type DeclaredContext<TDecl extends ContextDecl> = TDecl["context"];
78
+ /** A declaration with a `context`: its part gives it. */
79
+ interface ContextDecl extends Decl {
80
+ readonly context: object;
81
+ }
82
+ /** What {@link part} takes for a part that declares no `context`. */
83
+ interface PlainDefinition<TDecl extends Decl> extends PartSetup<TDecl> {
84
+ readonly context?: never;
85
+ /**
86
+ * Wraps every request, like a tRPC link. Call `next(op)` to run the
87
+ * rest of the chain; the last link is the query's own `queryFn`.
88
+ */
89
+ readonly link?: LinkOf<TDecl, Operation<TDecl>>;
90
+ }
91
+ /** What {@link part} takes for a part that gives its `context` for the client. */
92
+ interface ClientContextDefinition<TDecl extends ContextDecl> extends PartSetup<TDecl> {
93
+ /** Merged into the context of every `queryFn` the client runs. */
94
+ readonly context: DeclaredContext<TDecl>;
95
+ /**
96
+ * Wraps every request, like a tRPC link. Call `next(op)` to run the
97
+ * rest of the chain; the last link is the query's own `queryFn`. An
98
+ * operation with another `context` changes it for that request.
99
+ */
100
+ readonly link?: LinkOf<TDecl, Operation<TDecl>>;
101
+ }
102
+ /** What {@link part} takes for a part that gives its `context` per request. */
103
+ interface RequestContextDefinition<TDecl extends ContextDecl> extends PartSetup<TDecl> {
104
+ readonly context?: never;
105
+ /**
106
+ * Wraps every request, and gives each the context the part declares:
107
+ * `next` takes an operation whose `context` has it.
108
+ */
109
+ readonly link: LinkOf<TDecl, Operation<TDecl> & {
110
+ readonly context: DeclaredContext<TDecl>;
111
+ }>;
112
+ }
113
+ /** A declaration without a `context`: its part needs no definition. */
114
+ interface OptionsDecl {
115
+ readonly context?: never;
116
+ readonly options?: object;
117
+ }
62
118
  /**
63
- * A link that declares the `meta` fields it reads. A root's queries take
64
- * those fields only when the root has the link.
119
+ * A part of a client, with what it declares: the per-query `options` it
120
+ * reads and the `context` it gives every `queryFn`. A client's queries take
121
+ * those options, and get that context, only when the client has the part.
65
122
  *
66
123
  * ```ts
67
- * const traced = link<{ meta: { traceId?: string } }>((op, next) =>
68
- * withTrace(op.meta.traceId, () => next(op)),
69
- * );
124
+ * interface Traced {
125
+ * readonly options: { readonly traceId?: string };
126
+ * }
127
+ * const traced = part<Traced>({
128
+ * link: (op, next) => withTrace(op.options.traceId, () => next(op)),
129
+ * });
70
130
  * ```
71
131
  *
72
- * @see https://raf-query.katt.dev/docs/links-and-features#links-and-features
73
- */
74
- export declare function link<TDecl extends Decl = Decl>(run: (op: Operation<MetaOfDecl<TDecl> & object>, next: (op: Operation) => Promise<unknown>) => Promise<unknown>): Link<TDecl>;
75
- /**
76
- * A feature that declares the `meta` fields it reads. Without `setup`, it
77
- * only declares them: a root's own fields, such as an `owner` its targets
78
- * match on.
132
+ * A part without a link or `setup` only declares: an app's own options, such
133
+ * as an `owner` its targets match on.
134
+ *
135
+ * A part gives the `context` it declares for the client, as `context`, or
136
+ * per request, from its link:
79
137
  *
80
138
  * ```ts
81
- * const ownership = feature<{ meta: { owner?: "posts-team" | "users-team" } }>();
139
+ * interface Session {
140
+ * readonly context: { readonly token: string };
141
+ * }
142
+ * const session = part<Session>({
143
+ * link: async (op, next) =>
144
+ * next({ ...op, context: { ...op.context, token: await freshToken() } }),
145
+ * });
82
146
  * ```
83
147
  *
84
- * @see https://raf-query.katt.dev/docs/links-and-features#links-and-features
148
+ * @see https://raf-query.katt.dev/docs/links-and-features#parts
85
149
  */
86
- export declare function feature<TDecl extends Decl = Decl>(setup?: FeatureFunction): Feature<TDecl>;
150
+ export declare function part<TDecl extends OptionsDecl = NoDecl>(definition?: PlainDefinition<NoInfer<TDecl>>): Part<NoInfer<TDecl>>;
151
+ export declare function part<TDecl extends ContextDecl>(definition: ClientContextDefinition<NoInfer<TDecl>>): Part<NoInfer<TDecl>>;
152
+ export declare function part<TDecl extends ContextDecl>(definition: RequestContextDefinition<NoInfer<TDecl>>): Part<NoInfer<TDecl>>;
87
153
  export type ClientEvent = {
88
154
  readonly entry: Entry;
89
155
  readonly type: "added" | "removed" | "updated";
@@ -92,44 +158,47 @@ export type ClientEvent = {
92
158
  readonly type: "readers";
93
159
  };
94
160
  /**
95
- * What `createQueryClient` takes: links, features and the cache-wide defaults.
161
+ * What `createQueryClient` takes: its parts and the cache-wide defaults.
96
162
  *
97
163
  * @see https://raf-query.katt.dev/docs/important-defaults#changing-the-defaults
98
164
  */
99
165
  export interface QueryClientConfig {
100
166
  readonly clock?: Clock;
101
- /** Behaviors started while a provider has the client mounted. */
102
- readonly features?: ReadonlyArray<AnyFeature>;
103
- /** Default `gcTime`: 5 minutes. Server clients never gc. */
104
- readonly gcTime?: number;
167
+ /**
168
+ * Client-wide defaults for per-query options: the core's (`staleTime`,
169
+ * `gcTime`, `structuralSharing`) and those the parts declare. `ssr` is a
170
+ * query's own.
171
+ */
172
+ readonly defaults?: object;
105
173
  /** Default: no `window`. Server clients never gc and never revalidate cached data. */
106
174
  readonly isServer?: boolean;
107
- /** Wrap every request, outermost first. */
108
- readonly links?: ReadonlyArray<AnyLink>;
109
- /** Default `staleTime`: `0`. */
110
- readonly staleTime?: number;
111
- /** Default `structuralSharing`: `true`. */
112
- readonly structuralSharing?: boolean;
175
+ /**
176
+ * The client's behaviors. Links wrap every request, outermost first;
177
+ * features start while a provider has the client mounted.
178
+ */
179
+ readonly parts?: ReadonlyArray<AnyPart>;
113
180
  }
114
181
  /**
115
- * A query cache. `TTypes` is its root's types, which factories built with
116
- * `bindQueryOptions<typeof makeQueryClient>()` are checked against. The bare
117
- * `QueryClient` type takes a client of any root.
182
+ * A query cache. `TTypes` is its root's types: what its parts declare. It
183
+ * runs the factories of builders bound to those parts, or to fewer of them,
184
+ * so the bare `QueryClient` type takes any client.
118
185
  *
119
186
  * @see https://raf-query.katt.dev/docs/api-reference#the-client
120
187
  */
121
- export interface QueryClient<TTypes extends RootTypes = AnyRoot> {
188
+ export interface QueryClient<TTypes extends RootTypes = NoParts> {
122
189
  /** Entries changed since the last notification. */
123
190
  readonly "~changed": Set<Entry>;
191
+ /** What the parts give every `queryFn` for the client; links can change it per request. */
192
+ readonly "~context": object;
124
193
  readonly "~entries": Map<string, Entry>;
125
194
  readonly "~events": Listeners<ClientEvent>;
126
195
  /** Orders requests and invalidations. */
127
196
  "~seq": number;
128
197
  /** Invalidations not yet older than every entry's data. */
129
198
  "~stamps": Array<Stamp>;
130
- /** Phantom: the root's types, invariant. `undefined` at runtime. */
199
+ /** Phantom: the root's types. `undefined` at runtime. */
131
200
  readonly "~types"?: {
132
- readonly root: (types: TTypes) => TTypes;
201
+ readonly root: TTypes;
133
202
  };
134
203
  readonly clock: Clock;
135
204
  readonly config: QueryClientConfig;
@@ -145,13 +214,18 @@ export interface QueryClient<TTypes extends RootTypes = AnyRoot> {
145
214
  }): () => void;
146
215
  }
147
216
  /**
148
- * Create a query client. Behaviors are opt-in: pass `links` and `features`,
149
- * or spread `recommended()`. The client's `meta` type is what they declare.
217
+ * Create a query client. Behaviors are opt-in: pass `parts`, such as
218
+ * `recommended()`. The client's root is what they declare.
150
219
  *
151
220
  * ```ts
152
- * const ownership = feature<{ meta: { owner?: "posts-team" | "users-team" } }>();
221
+ * interface Ownership {
222
+ * readonly options: { readonly owner?: "posts-team" | "users-team" };
223
+ * }
153
224
  * export const makeQueryClient = () =>
154
- * createQueryClient({ links: [retry()], features: [ownership], staleTime: 30_000 });
225
+ * createQueryClient({
226
+ * parts: [retry(), part<Ownership>()],
227
+ * defaults: { staleTime: 30_000 },
228
+ * });
155
229
  * ```
156
230
  *
157
231
  * Make one per request on the server (in a loader or a request-scoped
@@ -159,14 +233,12 @@ export interface QueryClient<TTypes extends RootTypes = AnyRoot> {
159
233
  *
160
234
  * @see https://raf-query.katt.dev/docs/important-defaults
161
235
  */
162
- export declare function createQueryClient<const TLinks extends ReadonlyArray<AnyLink> = [], const TFeatures extends ReadonlyArray<AnyFeature> = []>(config?: QueryClientConfig & {
163
- readonly features?: TFeatures;
164
- readonly links?: TLinks;
165
- }): QueryClient<{
166
- readonly meta: MetaOf<[...TLinks, ...TFeatures]>;
167
- }>;
236
+ export declare function createQueryClient<const TParts extends ReadonlyArray<AnyPart> = []>(config?: Omit<QueryClientConfig, "defaults" | "parts"> & {
237
+ readonly defaults?: NoInfer<Omit<CoreOptions, "ssr"> & Partial<RootOfParts<TParts>["options"]>>;
238
+ readonly parts?: TParts;
239
+ }): QueryClient<RootOfParts<TParts>>;
168
240
  /**
169
- * Start the client's features. Providers call it while mounted; the
241
+ * Start the features of the client's parts. Providers call it while mounted; the
170
242
  * returned function stops them. Mounts are counted, so features start once
171
243
  * however many providers share the client, and stop with the last.
172
244
  */
package/dist/client.mjs CHANGED
@@ -7,44 +7,22 @@ const systemClock = {
7
7
  now: () => Date.now(),
8
8
  setTimeout: (callback, ms) => setTimeout(callback, ms)
9
9
  };
10
- /**
11
- * A link that declares the `meta` fields it reads. A root's queries take
12
- * those fields only when the root has the link.
13
- *
14
- * ```ts
15
- * const traced = link<{ meta: { traceId?: string } }>((op, next) =>
16
- * withTrace(op.meta.traceId, () => next(op)),
17
- * );
18
- * ```
19
- *
20
- * @see https://raf-query.katt.dev/docs/links-and-features#links-and-features
21
- */
22
- function link(run) {
23
- return run;
24
- }
25
- const noop = () => {};
26
- /**
27
- * A feature that declares the `meta` fields it reads. Without `setup`, it
28
- * only declares them: a root's own fields, such as an `owner` its targets
29
- * match on.
30
- *
31
- * ```ts
32
- * const ownership = feature<{ meta: { owner?: "posts-team" | "users-team" } }>();
33
- * ```
34
- *
35
- * @see https://raf-query.katt.dev/docs/links-and-features#links-and-features
36
- */
37
- function feature(setup = noop) {
38
- return setup;
10
+ function part(definition = {}) {
11
+ return definition;
39
12
  }
40
13
  /**
41
- * Create a query client. Behaviors are opt-in: pass `links` and `features`,
42
- * or spread `recommended()`. The client's `meta` type is what they declare.
14
+ * Create a query client. Behaviors are opt-in: pass `parts`, such as
15
+ * `recommended()`. The client's root is what they declare.
43
16
  *
44
17
  * ```ts
45
- * const ownership = feature<{ meta: { owner?: "posts-team" | "users-team" } }>();
18
+ * interface Ownership {
19
+ * readonly options: { readonly owner?: "posts-team" | "users-team" };
20
+ * }
46
21
  * export const makeQueryClient = () =>
47
- * createQueryClient({ links: [retry()], features: [ownership], staleTime: 30_000 });
22
+ * createQueryClient({
23
+ * parts: [retry(), part<Ownership>()],
24
+ * defaults: { staleTime: 30_000 },
25
+ * });
48
26
  * ```
49
27
  *
50
28
  * Make one per request on the server (in a loader or a request-scoped
@@ -57,6 +35,7 @@ function createQueryClient(config = {}) {
57
35
  const entries = /* @__PURE__ */ new Map();
58
36
  return {
59
37
  "~changed": /* @__PURE__ */ new Set(),
38
+ "~context": Object.assign({}, ...(config.parts ?? []).map((one) => one.context)),
60
39
  "~entries": entries,
61
40
  "~events": events,
62
41
  "~seq": 0,
@@ -74,9 +53,13 @@ function createQueryClient(config = {}) {
74
53
  }
75
54
  };
76
55
  }
56
+ /** The client's parts, as the kernel runs them. */
57
+ function partsOf(client) {
58
+ return client.config.parts ?? [];
59
+ }
77
60
  const mounted = /* @__PURE__ */ new WeakMap();
78
61
  /**
79
- * Start the client's features. Providers call it while mounted; the
62
+ * Start the features of the client's parts. Providers call it while mounted; the
80
63
  * returned function stops them. Mounts are counted, so features start once
81
64
  * however many providers share the client, and stop with the last.
82
65
  */
@@ -88,7 +71,7 @@ function mount(client) {
88
71
  count: 0
89
72
  };
90
73
  mounted.set(client, current);
91
- for (const start of client.config.features ?? []) start(client, current.controller.signal);
74
+ for (const one of partsOf(client)) one.setup?.(client, current.controller.signal);
92
75
  }
93
76
  const shared = current;
94
77
  shared.count += 1;
@@ -101,4 +84,4 @@ function mount(client) {
101
84
  };
102
85
  }
103
86
  //#endregion
104
- export { createQueryClient, feature, link, mount, systemClock };
87
+ export { createQueryClient, mount, part, partsOf, systemClock };
package/dist/entry.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { listeners } from "./subscribe.mjs";
2
+ import { partsOf } from "./client.mjs";
2
3
  import { isObject } from "./guards.mjs";
3
4
  import { hashKey } from "./keys/keys.mjs";
4
5
  import { matches } from "./keys/targets.mjs";
@@ -52,8 +53,13 @@ function newPending(entry) {
52
53
  entry.pendingThenable = next;
53
54
  entry.thenable = next.promise;
54
55
  }
56
+ /** One of the core's options for the entry: the query's, or else the client's default. */
57
+ function optionOf(entry, name) {
58
+ const defaults = entry.client.config.defaults;
59
+ return entry.options?.[name] ?? defaults?.[name];
60
+ }
55
61
  function gcTime(entry) {
56
- return entry.options?.gcTime ?? entry.client.config.gcTime ?? fiveMinutes;
62
+ return optionOf(entry, "gcTime") ?? fiveMinutes;
57
63
  }
58
64
  function scheduleGc(entry) {
59
65
  const client = entry.client;
@@ -136,13 +142,13 @@ function isBrowserOnly(entry) {
136
142
  function isStale(entry) {
137
143
  const state = entry.state;
138
144
  if (!state.hasData) return true;
139
- const staleTime = entry.options?.staleTime ?? entry.client.config.staleTime ?? 0;
145
+ const staleTime = optionOf(entry, "staleTime") ?? 0;
140
146
  return entry.client.clock.now() - state.updatedAt >= staleTime || isInvalidated(entry);
141
147
  }
142
148
  /** Write data. `startedAt` orders it against invalidations. */
143
149
  function write(entry, data, updatedAt, startedAt) {
144
150
  const previous = entry.state;
145
- const next = (entry.options?.structuralSharing ?? entry.client.config.structuralSharing ?? true) && previous.hasData ? replaceEqualDeep(previous.data, data) : data;
151
+ const next = (optionOf(entry, "structuralSharing") ?? true) && previous.hasData ? replaceEqualDeep(previous.data, data) : data;
146
152
  entry.requestedAt = Math.max(entry.requestedAt, startedAt);
147
153
  if (entry.pendingThenable) {
148
154
  entry.pendingThenable.resolve(next);
@@ -215,18 +221,19 @@ function terminal(op) {
215
221
  const options = op.options;
216
222
  const paged = options["~run"];
217
223
  resolve(paged ? paged(op) : options.queryFn({
224
+ ...op.context,
218
225
  client: op.client,
219
- meta: op.meta,
220
226
  queryKey: op.queryKey,
221
227
  signal: op.signal
222
228
  }));
223
229
  });
224
230
  }
225
231
  function chain(op) {
226
- const links = op.client.config.links ?? [];
232
+ const parts = partsOf(op.client);
227
233
  const call = (index, current) => {
228
- const link = links[index];
229
- return link ? link(current, (next) => call(index + 1, next)) : terminal(current);
234
+ const one = parts[index];
235
+ if (!one) return terminal(current);
236
+ return one.link ? one.link(current, (next) => call(index + 1, next)) : call(index + 1, current);
230
237
  };
231
238
  return call(0, op);
232
239
  }
@@ -257,13 +264,16 @@ function fetchEntry(entry, request = {}) {
257
264
  const state = entry.state;
258
265
  chain({
259
266
  client,
267
+ context: client["~context"],
260
268
  data: state.data,
261
269
  direction: request.direction,
262
270
  hasData: state.hasData,
263
271
  hash: entry.hash,
264
272
  input: entry.input,
265
- meta: options.meta ?? {},
266
- options,
273
+ options: {
274
+ ...client.config.defaults,
275
+ ...options
276
+ },
267
277
  pages: request.pages,
268
278
  queryKey: entry.key,
269
279
  signal: run.controller.signal
@@ -1,17 +1,21 @@
1
- import { Feature } from "../../client.mjs";
1
+ import { Part } from "../../client.mjs";
2
2
  //#region src/features/focus-refetch/focus-refetch.d.ts
3
- /** What `focusRefetch()` reads from a query's `meta`. */
4
- export interface FocusRefetchMeta {
5
- /** `false`: don't refetch this query on focus. */
6
- readonly refetchOnWindowFocus?: boolean;
3
+ /**
4
+ * What `focusRefetch()` declares.
5
+ *
6
+ * @see https://raf-query.katt.dev/docs/window-focus-refetching
7
+ */
8
+ export interface FocusRefetch {
9
+ readonly options: {
10
+ /** `false`: don't refetch this query on focus. */
11
+ readonly refetchOnWindowFocus?: boolean;
12
+ };
7
13
  }
8
14
  /**
9
15
  * Refetch read, stale queries when the window regains focus, except those
10
- * with `meta: { refetchOnWindowFocus: false }`.
16
+ * with `refetchOnWindowFocus: false`.
11
17
  *
12
18
  * @see https://raf-query.katt.dev/docs/window-focus-refetching
13
19
  */
14
- export declare function focusRefetch(): Feature<{
15
- readonly meta: FocusRefetchMeta;
16
- }>;
20
+ export declare function focusRefetch(): Part<FocusRefetch>;
17
21
  //#endregion
@@ -1,20 +1,20 @@
1
- import { feature } from "../../client.mjs";
1
+ import { part } from "../../client.mjs";
2
2
  import { refetchStaleReads } from "../shared.mjs";
3
3
  //#region src/features/focus-refetch/focus-refetch.ts
4
4
  /**
5
5
  * Refetch read, stale queries when the window regains focus, except those
6
- * with `meta: { refetchOnWindowFocus: false }`.
6
+ * with `refetchOnWindowFocus: false`.
7
7
  *
8
8
  * @see https://raf-query.katt.dev/docs/window-focus-refetching
9
9
  */
10
10
  function focusRefetch() {
11
- return feature((client, signal) => {
11
+ return part({ setup: (client, signal) => {
12
12
  const onFocus = () => {
13
13
  if (document.visibilityState === "visible") refetchStaleReads(client, "refetchOnWindowFocus");
14
14
  };
15
15
  document.addEventListener("visibilitychange", onFocus, { signal });
16
16
  window.addEventListener("focus", onFocus, { signal });
17
- });
17
+ } });
18
18
  }
19
19
  //#endregion
20
20
  export { focusRefetch };
@@ -1,16 +1,20 @@
1
- import { Feature } from "../../client.mjs";
1
+ import { Part } from "../../client.mjs";
2
2
  //#region src/features/polling/polling.d.ts
3
- /** What `polling()` reads from a query's `meta`. */
4
- export interface PollingMeta {
5
- /** Refetch every `n` ms while the query is read. */
6
- readonly refetchInterval?: number | false;
3
+ /**
4
+ * What `polling()` declares.
5
+ *
6
+ * @see https://raf-query.katt.dev/docs/polling
7
+ */
8
+ export interface Polling {
9
+ readonly options: {
10
+ /** Refetch every `n` ms while the query is read. */
11
+ readonly refetchInterval?: number | false;
12
+ };
7
13
  }
8
14
  /**
9
- * Refetch read queries every `meta.refetchInterval` ms.
15
+ * Refetch read queries every `refetchInterval` ms.
10
16
  *
11
17
  * @see https://raf-query.katt.dev/docs/polling
12
18
  */
13
- export declare function polling(): Feature<{
14
- readonly meta: PollingMeta;
15
- }>;
19
+ export declare function polling(): Part<Polling>;
16
20
  //#endregion