@raf-query/core 0.0.15 → 0.0.16

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,8 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.16](https://github.com/KATT/raf-query/compare/0.0.15...0.0.16) (2026-10-12)
4
+
5
+ ### Bug Fixes
6
+
7
+ * **core:** don't revalidate cached data in server verbs ([#19](https://github.com/KATT/raf-query/issues/19)) ([0ed7d9f](https://github.com/KATT/raf-query/commit/0ed7d9fefd0b70a8aa9a85c8d2c309a9fed42903))
8
+
3
9
  ## [0.0.15](https://github.com/KATT/raf-query/compare/0.0.14...0.0.15) (2026-10-12)
4
10
 
5
- * **agent-docs:** replace local ~/dev path with upstream React link ([#17](https://github.com/KATT/raf-query/issues/17)) ([79c0314](https://github.com/KATT/raf-query/commit/79c031475c3ed62ce5a07fb91d68733534e452b3))
11
+ - **agent-docs:** replace local ~/dev path with upstream React link ([#17](https://github.com/KATT/raf-query/issues/17)) ([79c0314](https://github.com/KATT/raf-query/commit/79c031475c3ed62ce5a07fb91d68733534e452b3))
6
12
 
7
13
  ## [0.0.14](https://github.com/KATT/raf-query/compare/0.0.13...0.0.14) (2026-10-12)
8
14
 
package/README.md CHANGED
@@ -113,6 +113,7 @@ Behavior:
113
113
 
114
114
  - Every verb dedupes against the cache. A fresh entry is reused; a stale entry is refetched in the background.
115
115
  - `ensure` and `fetch` wait only on a cache miss. With stale cached data they resolve immediately and revalidate in the background.
116
+ - On the server, cached data is always reused, whatever `staleTime` says. A server client renders once, so a background refetch could only repeat a request whose result is never shown. Entries marked by `invalidate` still refetch.
116
117
  - A failed `prefetch` never throws out of the loader. The error surfaces where the data is read, and is reported to the client's `onError`.
117
118
  - A failed `ensure` or `fetch` rejects, so it reaches the route's error boundary.
118
119
 
@@ -445,7 +446,7 @@ export default async function Page(props: {
445
446
  - `getQueryClient` is scoped to one request by React's `cache()`.
446
447
  - `HydrationBoundary` sends the request client's entries to the browser cache; pending ones stream as promises. Render one in each server component that starts queries for client components. Entries already sent in this request are skipped.
447
448
  - `QueryProvider` creates the browser client, and streams queries that client components start during SSR (`useWaterfall`) into the HTML. Pass `config` for the client's options; it must be serializable.
448
- - Server components that only render data can `await qc.fetch(...)` anywhere; the per-request client dedupes them.
449
+ - Server components that only render data can `await qc.fetch(...)` anywhere; the per-request client makes one request per query, whatever its `staleTime`.
449
450
  - `fetch` returns data, not a handle. When a server component renders the data and also hands the query to a client component, pass `await qc.ensure(...)`: after the `fetch` it resolves from the cache, and the client component gets the data from `useQuery` without a promise.
450
451
  - Factories can call server actions: server components call them directly, and the browser calls them on refetch. Validate their arguments, since anyone can call them.
451
452
 
@@ -540,7 +541,7 @@ Both render nothing on the server, since the server's cache isn't the browser's.
540
541
  | `getAll()`, `getQuery(factory, input?)` | Cache entries, for devtools and integrations |
541
542
  | `clear()` | Drop every entry and abort in-flight requests |
542
543
  | `mount()` | Start window-focus and reconnect refetching. The providers call it |
543
- | `isServer` | Detected from `window`. Server clients don't retry, never gc, skip stale timers |
544
+ | `isServer` | Detected from `window`. Server clients don't retry, never gc, skip stale timers, and never revalidate cached data |
544
545
 
545
546
  Query options, accepted by `queryOptions`, `infiniteQueryOptions` and `config.defaults`:
546
547
 
package/dist/client.d.mts CHANGED
@@ -8,7 +8,9 @@ export interface QueryClientConfig {
8
8
  readonly defaults?: QueryBehavior;
9
9
  /**
10
10
  * Whether this client runs on the server. Detected from `window`. Server
11
- * clients don't retry, never garbage-collect, and skip stale timers.
11
+ * clients don't retry, never garbage-collect, skip stale timers, and reuse
12
+ * cached data in `prefetch` / `ensure` / `fetch` instead of revalidating
13
+ * it, unless `invalidate` marked it.
12
14
  */
13
15
  readonly isServer?: boolean;
14
16
  /** Called with every failed request, including failed prefetches. */
@@ -63,14 +65,16 @@ export declare class QueryClient {
63
65
  getQuery<TFactory extends QueryFactory>(factory: TFactory, ...args: InputArgs<TFactory>): Query<DataOf<TFactory>, TFactory>;
64
66
  /**
65
67
  * Start a query without waiting and return its handle. Fresh data is
66
- * reused; stale data refetches in the background. Errors surface where the
67
- * data is read, never here.
68
+ * reused; stale data refetches in the background (in the browser only, see
69
+ * {@link QueryClientConfig.isServer}). Errors surface where the data is
70
+ * read, never here.
68
71
  */
69
72
  prefetch<TFactory extends QueryFactory>(factory: TFactory, ...args: InputArgs<TFactory>): QueryHandle<TFactory>;
70
73
  /**
71
74
  * Start a query and wait for it on a cache miss. Rejects if that request
72
- * fails. Stale cached data resolves immediately and revalidates. The
73
- * handle is marked `ensured`, so `useQuery` returns its data directly.
75
+ * fails. Stale cached data resolves immediately and revalidates in the
76
+ * browser. The handle is marked `ensured`, so `useQuery` returns its data
77
+ * directly.
74
78
  */
75
79
  ensure<TFactory extends QueryFactory>(factory: TFactory, ...args: LoadArgs<TFactory>): Promise<EnsuredQueryHandle<TFactory>>;
76
80
  /** Like `ensure`, but resolves to the data. */
package/dist/client.mjs CHANGED
@@ -90,19 +90,21 @@ var QueryClient = class {
90
90
  }
91
91
  /**
92
92
  * Start a query without waiting and return its handle. Fresh data is
93
- * reused; stale data refetches in the background. Errors surface where the
94
- * data is read, never here.
93
+ * reused; stale data refetches in the background (in the browser only, see
94
+ * {@link QueryClientConfig.isServer}). Errors surface where the data is
95
+ * read, never here.
95
96
  */
96
97
  prefetch(factory, ...args) {
97
98
  const entry = this.#build(factory, args[0]);
98
- const state = entry.getState();
99
- if (!state.isFetching && (!state.hasData || entry.isStaleNow())) entry.fetch().catch(noop);
99
+ if (entry.getState().hasData) this.#revalidate(entry);
100
+ else entry.fetch().catch(noop);
100
101
  return handleOf(entry);
101
102
  }
102
103
  /**
103
104
  * Start a query and wait for it on a cache miss. Rejects if that request
104
- * fails. Stale cached data resolves immediately and revalidates. The
105
- * handle is marked `ensured`, so `useQuery` returns its data directly.
105
+ * fails. Stale cached data resolves immediately and revalidates in the
106
+ * browser. The handle is marked `ensured`, so `useQuery` returns its data
107
+ * directly.
106
108
  */
107
109
  async ensure(factory, ...args) {
108
110
  const entry = this.#build(factory, args[0]);
@@ -199,9 +201,19 @@ var QueryClient = class {
199
201
  #load(entry, pages) {
200
202
  const state = entry.getState();
201
203
  if (!state.hasData) return entry.fetch({ pages });
202
- if (!state.isFetching && entry.isStaleNow()) entry.fetch().catch(noop);
204
+ this.#revalidate(entry);
203
205
  return Promise.resolve(state.data);
204
206
  }
207
+ /**
208
+ * Background refetch of cached data a verb reuses. A server client renders
209
+ * once, so a refetch there could only duplicate a request whose result is
210
+ * never shown; it refetches only what `invalidate` marked.
211
+ */
212
+ #revalidate(entry) {
213
+ const state = entry.getState();
214
+ const wanted = this.isServer ? state.isInvalidated : entry.isStaleNow();
215
+ if (!state.isFetching && wanted) entry.fetch().catch(noop);
216
+ }
205
217
  #match(target, input) {
206
218
  if (Predicate.isFunction(target)) {
207
219
  const entry = this.#cache.get(hashKey(optionsFor(target, input).queryKey));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raf-query/core",
3
- "version": "0.0.15",
3
+ "version": "0.0.16",
4
4
  "description": "Framework-agnostic core of raf-query, a render-as-you-fetch query library",
5
5
  "keywords": [
6
6
  "query",