@raf-query/core 0.0.18 → 0.0.19

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,16 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.19](https://github.com/KATT/raf-query/compare/0.0.18...0.0.19) (2026-10-12)
4
+
5
+ ### Features
6
+
7
+ * **core:** type the cache's promises as Thenable ([#21](https://github.com/KATT/raf-query/issues/21)) ([c0541b0](https://github.com/KATT/raf-query/commit/c0541b0c14e687f25d47f25fe457e49b135d8c06))
8
+
3
9
  ## [0.0.18](https://github.com/KATT/raf-query/compare/0.0.17...0.0.18) (2026-10-12)
4
10
 
5
11
  ### Bug Fixes
6
12
 
7
- * **core:** allow undefined query data ([#22](https://github.com/KATT/raf-query/issues/22)) ([9b85e57](https://github.com/KATT/raf-query/commit/9b85e57bf2fed4413cdbc1b49f925cc60dad695f)), references [#20](https://github.com/KATT/raf-query/issues/20)
13
+ - **core:** allow undefined query data ([#22](https://github.com/KATT/raf-query/issues/22)) ([9b85e57](https://github.com/KATT/raf-query/commit/9b85e57bf2fed4413cdbc1b49f925cc60dad695f)), references [#20](https://github.com/KATT/raf-query/issues/20)
8
14
 
9
15
  ## [0.0.17](https://github.com/KATT/raf-query/compare/0.0.16...0.0.17) (2026-10-12)
10
16
 
package/README.md CHANGED
@@ -574,16 +574,17 @@ In the browser, retries pause while `navigator.onLine` is `false`: after the ret
574
574
  | `CancelledError` | Rejection of a request cancelled by `clear()` or a restart |
575
575
  | `QueryHandle<TFactory>` | Handle type for props |
576
576
  | `EnsuredQueryHandle<TFactory>` | Handle type for props fed by `ensure` |
577
+ | `Thenable<T>` | Promise with `status` / `value` / `reason`, read by `use()` |
577
578
  | `DataOf<TFactory>`, `InputOf<TFactory>` | A factory's data and input types |
578
579
 
579
580
  `@raf-query/react` (plus all of the above):
580
581
 
581
- | Export | Use |
582
- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
583
- | `QueryClientProvider` | Provides a client to the tree |
584
- | `useQueryClient()` | Read the client |
585
- | `useQuery(factory, handle, options?)` | `[Promise<Data>, controls]`; for paged factories `Data` is `{ pages, pageParams }` and controls include paging |
586
- | `useWaterfall(factory, input)` | Start a query during render and return its handle |
582
+ | Export | Use |
583
+ | ------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
584
+ | `QueryClientProvider` | Provides a client to the tree |
585
+ | `useQueryClient()` | Read the client |
586
+ | `useQuery(factory, handle, options?)` | `[Thenable<Data>, controls]`; for paged factories `Data` is `{ pages, pageParams }` and controls include paging |
587
+ | `useWaterfall(factory, input)` | Start a query during render and return its handle |
587
588
 
588
589
  ## Development
589
590
 
package/dist/client.mjs CHANGED
@@ -113,11 +113,8 @@ var QueryClient = class {
113
113
  }
114
114
  /** Like `ensure`, but resolves to the data. */
115
115
  async fetch(factory, ...args) {
116
- const entry = this.#build(factory, args[0]);
117
- await this.#load(entry, args[1]?.pages);
118
- const state = entry.getState();
119
- if (!state.hasData) throw new Error(`Query ${entry.hash} has no data`);
120
- return unsafeCast(state.data);
116
+ const entry = typed(this.#build(factory, args[0]));
117
+ return this.#load(entry, args[1]?.pages);
121
118
  }
122
119
  async invalidate(target, input) {
123
120
  await Promise.all(this.#match(target, input).map((entry) => entry.invalidate()));
@@ -201,11 +198,12 @@ var QueryClient = class {
201
198
  entry.setOptions(options, input);
202
199
  return entry;
203
200
  }
201
+ /** Resolves to the entry's data: the cached thenable, or the first fetch. */
204
202
  #load(entry, pages) {
205
203
  const state = entry.getState();
206
204
  if (!state.hasData) return entry.fetch({ pages });
207
205
  this.#revalidate(entry);
208
- return Promise.resolve(state.data);
206
+ return state.promise;
209
207
  }
210
208
  /**
211
209
  * Background refetch of cached data a verb reuses. A server client renders
package/dist/index.d.mts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { Settled, allKeyed } from "./all-keyed.mjs";
2
2
  import { QueryKey, hashKey, matchesKey } from "./key.mjs";
3
3
  import { AnyQueryOptions, DataOf, EnsuredQueryHandle, InfiniteData, InfiniteQueryOptions, InputArgs, InputOf, IsPaged, LoadOptions, PageFunctionContext, PageOf, QueryBehavior, QueryFactory, QueryFnResult, QueryFunctionContext, QueryHandle, QueryOptions, RetryPolicy, infiniteQueryOptions, queryOptions } from "./options.mjs";
4
+ import { Thenable } from "./thenable.mjs";
4
5
  import { CancelledError, FetchRequest, Query, QueryState, SubscribeOptions } from "./query.mjs";
5
6
  import { CacheEvent, LoadArgs, QueryClient, QueryClientConfig, QueryClientEffect, QueryFilter, Updater } from "./client.mjs";
6
7
  import { DehydrateOptions, DehydratedQuery, DehydratedState, HydrateOptions, canDehydrate, dehydrate, dehydrateQuery, hydrate } from "./hydration.mjs";
7
8
  import { QueryObserver, QueryObserverOptions, QueryObserverResult } from "./observer.mjs";
8
- export { type AnyQueryOptions, type CacheEvent, CancelledError, type DataOf, type DehydrateOptions, type DehydratedQuery, type DehydratedState, type EnsuredQueryHandle, type FetchRequest, type HydrateOptions, type InfiniteData, type InfiniteQueryOptions, type InputArgs, type InputOf, type IsPaged, type LoadArgs, type LoadOptions, type PageFunctionContext, type PageOf, type Query, type QueryBehavior, QueryClient, type QueryClientConfig, type QueryClientEffect, type QueryFactory, type QueryFilter, type QueryFnResult, type QueryFunctionContext, type QueryHandle, type QueryKey, QueryObserver, type QueryObserverOptions, type QueryObserverResult, type QueryOptions, type QueryState, type RetryPolicy, type Settled, type SubscribeOptions, type Updater, allKeyed, canDehydrate, dehydrate, dehydrateQuery, hashKey, hydrate, infiniteQueryOptions, matchesKey, queryOptions };
9
+ export { type AnyQueryOptions, type CacheEvent, CancelledError, type DataOf, type DehydrateOptions, type DehydratedQuery, type DehydratedState, type EnsuredQueryHandle, type FetchRequest, type HydrateOptions, type InfiniteData, type InfiniteQueryOptions, type InputArgs, type InputOf, type IsPaged, type LoadArgs, type LoadOptions, type PageFunctionContext, type PageOf, type Query, type QueryBehavior, QueryClient, type QueryClientConfig, type QueryClientEffect, type QueryFactory, type QueryFilter, type QueryFnResult, type QueryFunctionContext, type QueryHandle, type QueryKey, QueryObserver, type QueryObserverOptions, type QueryObserverResult, type QueryOptions, type QueryState, type RetryPolicy, type Settled, type SubscribeOptions, type Thenable, type Updater, allKeyed, canDehydrate, dehydrate, dehydrateQuery, hashKey, hydrate, infiniteQueryOptions, matchesKey, queryOptions };
@@ -1,5 +1,6 @@
1
1
  import { QueryKey } from "./key.mjs";
2
2
  import { QueryFactory } from "./options.mjs";
3
+ import { Thenable } from "./thenable.mjs";
3
4
  import { Query } from "./query.mjs";
4
5
  //#region src/observer.d.ts
5
6
  /** How one reader observes its query. */
@@ -42,7 +43,7 @@ export interface QueryObserverResult<TData = unknown> {
42
43
  /** Key of the data in `promise`; differs from the query's while `isPrevious`. */
43
44
  readonly key: QueryKey;
44
45
  /** Settles with the data to show; see `QueryState.promise`. */
45
- readonly promise: Promise<TData>;
46
+ readonly promise: Thenable<TData>;
46
47
  refetch(): Promise<void>;
47
48
  /** When the data in `promise` was fetched (ms since epoch); `0` before that. */
48
49
  readonly updatedAt: number;
package/dist/query.d.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { QueryKey } from "./key.mjs";
2
2
  import { AnyQueryOptions, QueryFactory, QueryHandle } from "./options.mjs";
3
+ import { Thenable } from "./thenable.mjs";
3
4
  //#region src/query.d.ts
4
5
  /** A snapshot of one cache entry. Replaced, never mutated, on every change. */
5
6
  export interface QueryState<TData> {
@@ -20,9 +21,9 @@ export interface QueryState<TData> {
20
21
  readonly isStale: boolean;
21
22
  /**
22
23
  * Settles with `data`. A new promise is created per data version, already
23
- * fulfilled once data exists, so React's `use()` reads it synchronously.
24
+ * fulfilled once data exists, so it can be read synchronously.
24
25
  */
25
- readonly promise: Promise<TData>;
26
+ readonly promise: Thenable<TData>;
26
27
  readonly status: "error" | "pending" | "success";
27
28
  /** When `data` was fetched (ms since epoch); `0` without data. */
28
29
  readonly updatedAt: number;
@@ -0,0 +1,24 @@
1
+ //#region src/thenable.d.ts
2
+ /**
3
+ * Promises that carry their own result, in the fields React's `use()` reads
4
+ * before suspending (`status`, `value`, `reason`). A settled one can be read
5
+ * synchronously, so React renders it without a fallback.
6
+ */
7
+ interface PendingStatus {
8
+ readonly status: "pending";
9
+ }
10
+ interface FulfilledStatus<T> {
11
+ readonly status: "fulfilled";
12
+ readonly value: T;
13
+ }
14
+ interface RejectedStatus {
15
+ readonly reason: unknown;
16
+ readonly status: "rejected";
17
+ }
18
+ /**
19
+ * A promise that says whether it has settled, and with what. `status` moves
20
+ * from `"pending"` to `"fulfilled"` (with `value`) or `"rejected"` (with
21
+ * `reason`) once, when the promise settles.
22
+ */
23
+ export type Thenable<T> = Promise<T> & (FulfilledStatus<T> | PendingStatus | RejectedStatus);
24
+ //#endregion
package/dist/thenable.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  //#region src/thenable.ts
2
2
  /**
3
- * Promises that React's `use()` can read synchronously. React checks
4
- * `status` / `value` / `reason` on a thenable before suspending, so a
5
- * settled one renders without a fallback.
3
+ * Promises that carry their own result, in the fields React's `use()` reads
4
+ * before suspending (`status`, `value`, `reason`). A settled one can be read
5
+ * synchronously, so React renders it without a fallback.
6
6
  */
7
7
  const noop = () => {};
8
8
  function fulfilled(value) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raf-query/core",
3
- "version": "0.0.18",
3
+ "version": "0.0.19",
4
4
  "description": "Framework-agnostic core of raf-query, a render-as-you-fetch query library",
5
5
  "keywords": [
6
6
  "query",