@raf-query/core 0.7.12 → 0.9.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,15 +1,44 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.0](https://github.com/KATT/raf-query/compare/0.8.0...0.9.0) (2026-10-15)
4
+
5
+ ### ⚠ BREAKING CHANGES
6
+
7
+ * useQuery returns the data for a handle from ensure or fetch ([#144](https://github.com/KATT/raf-query/issues/144))
8
+
9
+ ### Features
10
+
11
+ * useQuery returns the data for a handle from ensure or fetch ([#144](https://github.com/KATT/raf-query/issues/144)) ([1845244](https://github.com/KATT/raf-query/commit/18452443ba61c205a53c4f71d60ec99a9b8620a7)), references [#142](https://github.com/KATT/raf-query/issues/142)
12
+
13
+ ### Documentation
14
+
15
+ * call the early API a note about minor releases ([#143](https://github.com/KATT/raf-query/issues/143)) ([2d79eed](https://github.com/KATT/raf-query/commit/2d79eed7b107b6d16898ebb203a9bdfcfb3856c4))
16
+ * show prefetch and ensure, and make list queries infinite ([#140](https://github.com/KATT/raf-query/issues/140)) ([25cfaa0](https://github.com/KATT/raf-query/commit/25cfaa08f9f192af7efded1269f4ae8a9e5f1026))
17
+
18
+ ## [0.8.0](https://github.com/KATT/raf-query/compare/0.7.12...0.8.0) (2026-10-15)
19
+
20
+ ### ⚠ BREAKING CHANGES
21
+
22
+ - ensure and fetch return a QueryHandleWithData ([#142](https://github.com/KATT/raf-query/issues/142))
23
+
24
+ ### Features
25
+
26
+ - ensure and fetch return a QueryHandleWithData ([#142](https://github.com/KATT/raf-query/issues/142)) ([504cd2a](https://github.com/KATT/raf-query/commit/504cd2a19e04b614eb648f02b256128c4eb31d38))
27
+
28
+ ### Miscellaneous Chores
29
+
30
+ - group experiments under `.experimental/<topic>/` ([#137](https://github.com/KATT/raf-query/issues/137)) ([52ce752](https://github.com/KATT/raf-query/commit/52ce7522223346e82687338d6ac6d34f793b6fcf))
31
+
3
32
  ## [0.7.12](https://github.com/KATT/raf-query/compare/0.7.11...0.7.12) (2026-10-15)
4
33
 
5
- * add knip with every issue type as an error ([#129](https://github.com/KATT/raf-query/issues/129)) ([603719d](https://github.com/KATT/raf-query/commit/603719dcb834312d4a813ecae865df7d56faf8c5))
6
- * cache Next.js Turbopack builds ([#128](https://github.com/KATT/raf-query/issues/128)) ([667b38f](https://github.com/KATT/raf-query/commit/667b38ff5728dad3fdad6d90445aea480cfbd063))
7
- * explain how a route loads its data on the homepage ([#121](https://github.com/KATT/raf-query/issues/121)) ([ec1d6ef](https://github.com/KATT/raf-query/commit/ec1d6efdad75ea2d05dd56790e5e980756afea13))
8
- * frame the cache as async data, not server-state-only ([#126](https://github.com/KATT/raf-query/issues/126)) ([db9ba02](https://github.com/KATT/raf-query/commit/db9ba02995aa01cadacb2739fd258de3c920d440))
34
+ - add knip with every issue type as an error ([#129](https://github.com/KATT/raf-query/issues/129)) ([603719d](https://github.com/KATT/raf-query/commit/603719dcb834312d4a813ecae865df7d56faf8c5))
35
+ - cache Next.js Turbopack builds ([#128](https://github.com/KATT/raf-query/issues/128)) ([667b38f](https://github.com/KATT/raf-query/commit/667b38ff5728dad3fdad6d90445aea480cfbd063))
36
+ - explain how a route loads its data on the homepage ([#121](https://github.com/KATT/raf-query/issues/121)) ([ec1d6ef](https://github.com/KATT/raf-query/commit/ec1d6efdad75ea2d05dd56790e5e980756afea13))
37
+ - frame the cache as async data, not server-state-only ([#126](https://github.com/KATT/raf-query/issues/126)) ([db9ba02](https://github.com/KATT/raf-query/commit/db9ba02995aa01cadacb2739fd258de3c920d440))
9
38
 
10
39
  ### Features
11
40
 
12
- * **examples:** reinstall shadcn on Base UI without Radix ([#125](https://github.com/KATT/raf-query/issues/125)) ([7c13ef3](https://github.com/KATT/raf-query/commit/7c13ef379dc297edbbe160516b26916d465a48d1))
41
+ - **examples:** reinstall shadcn on Base UI without Radix ([#125](https://github.com/KATT/raf-query/issues/125)) ([7c13ef3](https://github.com/KATT/raf-query/commit/7c13ef379dc297edbbe160516b26916d465a48d1))
13
42
 
14
43
  ## [0.7.11](https://github.com/KATT/raf-query/compare/0.7.10...0.7.11) (2026-10-14)
15
44
 
package/README.md CHANGED
@@ -4,8 +4,8 @@ The framework-agnostic cache behind [raf-query](https://raf-query.katt.dev), wri
4
4
 
5
5
  **[Documentation](https://raf-query.katt.dev/docs/effect)** · [API reference](https://raf-query.katt.dev/docs/api-reference#raf-querycore) · [GitHub](https://github.com/KATT/raf-query)
6
6
 
7
- > [!WARNING]
8
- > raf-query is early. The API can still change between patch releases, and you use it at your own risk.
7
+ > [!NOTE]
8
+ > raf-query is early. The API can still change between minor releases, and you use it at your own risk.
9
9
 
10
10
  React apps install [`@raf-query/react`](https://www.npmjs.com/package/@raf-query/react) instead: it re-exports this package, so you never import core directly. Install core on its own for Effect programs and for bindings to other frameworks.
11
11
 
@@ -31,7 +31,7 @@ export function issueQuery(input: { id: number }) {
31
31
 
32
32
  const program = Effect.gen(function* () {
33
33
  const cache = yield* QueryCache.QueryCache;
34
- const issue = yield* cache.fetch(issueQuery, { id: 1 }); // fails with IssueNotFound
34
+ yield* cache.fetch(issueQuery, { id: 1 }); // fails with IssueNotFound
35
35
  yield* cache.watch(issueQuery, { id: 1 }).pipe(
36
36
  Stream.map((state) => state.data?.title),
37
37
  Stream.runForEach((title) => Effect.log(title)),
package/dist/cache.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { QueryKey } from "./key.mjs";
2
- import { DataOf, EnsuredQueryHandle, ErrorOf, InputArgs, InputOf, LoadOptions, PagedQueryFactory, QueryBehavior, QueryFactory, QueryHandle, ServicesOf } from "./options.mjs";
2
+ import { DataOf, ErrorOf, InputArgs, InputOf, LoadOptions, PagedQueryFactory, QueryBehavior, QueryFactory, QueryHandle, QueryHandleWithData, ServicesOf } from "./options.mjs";
3
3
  import { DehydrateOptions, DehydratedState, DehydratedStream, HydrateOptions } from "./hydration.mjs";
4
4
  import { CancelledError, Query, State, query_d_exports } from "./query.mjs";
5
5
  import { Context, Effect, Layer, Option, Scope, Stream } from "effect";
@@ -53,8 +53,7 @@ export type Target<TFactory extends QueryFactory> = [factory: TFactory, ...args:
53
53
  * both with no data and with `undefined` data.
54
54
  */
55
55
  export type Updater<TData> = TData | ((previous: TData | undefined) => TData);
56
- type Ensured<TFactory extends QueryFactory> = Effect.Effect<EnsuredQueryHandle<TFactory>, ErrorOf<TFactory> | CancelledError, ServicesOf<TFactory>>;
57
- type Fetched<TFactory extends QueryFactory> = Effect.Effect<DataOf<TFactory>, ErrorOf<TFactory> | CancelledError, ServicesOf<TFactory>>;
56
+ type Loaded<TFactory extends QueryFactory> = Effect.Effect<QueryHandleWithData<TFactory>, ErrorOf<TFactory> | CancelledError, ServicesOf<TFactory>>;
58
57
  export interface QueryCache {
59
58
  /** Every entry. */
60
59
  readonly all: Effect.Effect<ReadonlyArray<Query>>;
@@ -70,24 +69,23 @@ export interface QueryCache {
70
69
  */
71
70
  dehydrateStream(options?: DehydrateOptions): Effect.Effect<DehydratedStream, never, Scope.Scope>;
72
71
  /**
73
- * Start a query and wait for it on a cache miss. Fails if that request
74
- * fails. Stale cached data succeeds immediately and revalidates in the
75
- * browser. The handle is marked `ensured`, so `useQuery` returns its data
76
- * directly.
72
+ * {@link fetch} without waiting on stale data: start a query and wait for
73
+ * it on a cache miss. Stale cached data succeeds immediately and
74
+ * revalidates in the browser. Fails if that request fails.
77
75
  */
78
- ensure<TFactory extends QueryFactory>(factory: TFactory, ...args: InputArgs<TFactory>): Ensured<TFactory>;
76
+ ensure<TFactory extends QueryFactory>(factory: TFactory, ...args: InputArgs<TFactory>): Loaded<TFactory>;
79
77
  /** {@link ensure}, loading `options.pages` pages of a paged query. */
80
- ensure<TFactory extends PagedQueryFactory>(factory: TFactory, input: InputOf<TFactory>, options: LoadOptions): Ensured<TFactory>;
78
+ ensure<TFactory extends PagedQueryFactory>(factory: TFactory, input: InputOf<TFactory>, options: LoadOptions): Loaded<TFactory>;
81
79
  /** Cache events from the moment the stream starts. */
82
80
  readonly events: Stream.Stream<Event>;
83
81
  /**
84
- * Start a query and succeed with its data. Waits on a cache miss and on
85
- * stale data (on the server, only invalidated data), so the data is fresh.
86
- * Fails if that request fails.
82
+ * Start a query and succeed with a handle holding its data. Waits on a
83
+ * cache miss and on stale data (on the server, only invalidated data), so
84
+ * the data is fresh. Fails if that request fails.
87
85
  */
88
- fetch<TFactory extends QueryFactory>(factory: TFactory, ...args: InputArgs<TFactory>): Fetched<TFactory>;
86
+ fetch<TFactory extends QueryFactory>(factory: TFactory, ...args: InputArgs<TFactory>): Loaded<TFactory>;
89
87
  /** {@link fetch}, loading `options.pages` pages of a paged query. */
90
- fetch<TFactory extends PagedQueryFactory>(factory: TFactory, input: InputOf<TFactory>, options: LoadOptions): Fetched<TFactory>;
88
+ fetch<TFactory extends PagedQueryFactory>(factory: TFactory, input: InputOf<TFactory>, options: LoadOptions): Loaded<TFactory>;
91
89
  /**
92
90
  * Cached data for a factory call. `Some(undefined)` when the data itself
93
91
  * is `undefined`.
package/dist/cache.mjs CHANGED
@@ -63,6 +63,14 @@ function load(entry, pages, fresh) {
63
63
  revalidate(entry);
64
64
  return Effect.succeed(dataOf(entry));
65
65
  }
66
+ /** The entry's handle as of this call, with the data `loaded` succeeds with. */
67
+ function withData(entry, loaded) {
68
+ const handle = handleOf(entry);
69
+ return Effect.map(loaded, (data) => ({
70
+ ...handle,
71
+ data
72
+ }));
73
+ }
66
74
  /** Settles every effect, started together. */
67
75
  function settleAll(effects) {
68
76
  return Effect.all(effects, {
@@ -134,12 +142,9 @@ const make = /*#__PURE__*/ Effect.fnUntraced(function* (config = {}) {
134
142
  }),
135
143
  dehydrate: (options = {}) => Effect.sync(() => dehydrateEntries(state.entries.values(), options)),
136
144
  dehydrateStream: (options = {}) => dehydrateStream(() => state.entries.values(), subscribeUnsafe, options),
137
- ensure: (factory, input, options) => Effect.flatMap(buildFor(factory, input), (entry) => load(entry, options?.pages, false).pipe(Effect.as({
138
- ...handleOf(entry),
139
- ensured: true
140
- }))),
145
+ ensure: (factory, input, options) => Effect.flatMap(buildFor(factory, input), (entry) => withData(entry, load(entry, options?.pages, false))),
141
146
  events: listen(subscribeUnsafe),
142
- fetch: (factory, input, options) => Effect.flatMap(buildFor(factory, input), (entry) => load(entry, options?.pages, true)),
147
+ fetch: (factory, input, options) => Effect.flatMap(buildFor(factory, input), (entry) => withData(entry, load(entry, options?.pages, true))),
143
148
  getData: (factory, ...args) => Effect.sync(() => {
144
149
  const options = optionsFor(factory, args[0]);
145
150
  const entry = state.entries.get(hashKey(options.queryKey));
package/dist/index.d.mts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { platform_d_exports } from "./platform.mjs";
2
2
  import { QueryKey, hashKey, matchesKey } from "./key.mjs";
3
- import { AnyQueryOptions, DataOf, EnsuredQueryHandle, ErrorOf, InfiniteData, InfiniteQueryOptions, InfiniteQueryTypes, InputArgs, InputOf, IsPaged, LoadOptions, PageFunctionContext, PageOf, PagedQueryFactory, QueryBehavior, QueryFactory, QueryFnResult, QueryFunctionContext, QueryHandle, QueryMeta, QueryOptions, QueryTypes, Register, RetryPolicy, ServicesOf, infiniteQueryOptions, queryOptions } from "./options.mjs";
3
+ import { AnyQueryOptions, DataOf, ErrorOf, InfiniteData, InfiniteQueryOptions, InfiniteQueryTypes, InputArgs, InputOf, IsPaged, LoadOptions, PageFunctionContext, PageOf, PagedQueryFactory, QueryBehavior, QueryFactory, QueryFnResult, QueryFunctionContext, QueryHandle, QueryHandleWithData, QueryMeta, QueryOptions, QueryTypes, Register, RetryPolicy, ServicesOf, infiniteQueryOptions, queryOptions } from "./options.mjs";
4
4
  import { DehydrateOptions, DehydratedQuery, DehydratedResult, DehydratedState, DehydratedStream, HydrateOptions, RedactedError, canDehydrate, dehydrateQuery } from "./hydration.mjs";
5
5
  import { cache_d_exports } from "./cache.mjs";
6
6
  import { Pending, Thenable, fulfilled, pending } from "./thenable.mjs";
7
7
  import { query_d_exports } from "./query.mjs";
8
8
  import { observer_d_exports } from "./observer.mjs";
9
- export { type AnyQueryOptions, type DataOf, type DehydrateOptions, type DehydratedQuery, type DehydratedResult, type DehydratedState, type DehydratedStream, type EnsuredQueryHandle, type ErrorOf, type HydrateOptions, type InfiniteData, type InfiniteQueryOptions, type InfiniteQueryTypes, type InputArgs, type InputOf, type IsPaged, type LoadOptions, type PageFunctionContext, type PageOf, type PagedQueryFactory, type Pending, platform_d_exports as Platform, query_d_exports as Query, type QueryBehavior, cache_d_exports as QueryCache, type QueryFactory, type QueryFnResult, type QueryFunctionContext, type QueryHandle, type QueryKey, type QueryMeta, observer_d_exports as QueryObserver, type QueryOptions, type QueryTypes, RedactedError, type Register, type RetryPolicy, type ServicesOf, type Thenable, canDehydrate, dehydrateQuery, fulfilled, hashKey, infiniteQueryOptions, matchesKey, pending, queryOptions };
9
+ export { type AnyQueryOptions, type DataOf, type DehydrateOptions, type DehydratedQuery, type DehydratedResult, type DehydratedState, type DehydratedStream, type ErrorOf, type HydrateOptions, type InfiniteData, type InfiniteQueryOptions, type InfiniteQueryTypes, type InputArgs, type InputOf, type IsPaged, type LoadOptions, type PageFunctionContext, type PageOf, type PagedQueryFactory, type Pending, platform_d_exports as Platform, query_d_exports as Query, type QueryBehavior, cache_d_exports as QueryCache, type QueryFactory, type QueryFnResult, type QueryFunctionContext, type QueryHandle, type QueryHandleWithData, type QueryKey, type QueryMeta, observer_d_exports as QueryObserver, type QueryOptions, type QueryTypes, RedactedError, type Register, type RetryPolicy, type ServicesOf, type Thenable, canDehydrate, dehydrateQuery, fulfilled, hashKey, infiniteQueryOptions, matchesKey, pending, queryOptions };
@@ -311,27 +311,23 @@ export interface LoadOptions {
311
311
  readonly pages?: number;
312
312
  }
313
313
  declare const factoryType: unique symbol;
314
- interface HandleFields<TFactory extends QueryFactory> {
314
+ /**
315
+ * The serializable reference a loader or server component hands to the
316
+ * component that reads the query. It holds no functions.
317
+ */
318
+ export interface QueryHandle<TFactory extends QueryFactory = QueryFactory> {
315
319
  /** Type-only: ties the handle to its factory. Never present at runtime. */
316
320
  readonly [factoryType]?: TFactory;
317
321
  /** The factory's input; `unknown` on a handle of no particular factory. */
318
- readonly input: QueryFactory extends TFactory ? unknown : InputOf<TFactory>;
322
+ readonly input: InputOf<TFactory>;
319
323
  readonly key: QueryKey;
320
324
  }
321
325
  /**
322
- * The serializable reference a loader or server component hands to the
323
- * component that reads the query. It holds no data and no functions.
324
- */
325
- export interface QueryHandle<TFactory extends QueryFactory = QueryFactory> extends HandleFields<TFactory> {
326
- readonly ensured?: false;
327
- }
328
- /**
329
- * A handle from `ensure`: its data was loaded before the handle was
330
- * returned, so `useQuery` returns the data rather than a promise. Not
331
- * assignable to {@link QueryHandle}, so a prop typed for one can't receive
332
- * the other.
326
+ * A handle from `ensure` or `fetch`, with the data they waited for. `data`
327
+ * is a snapshot from when the handle was returned; components read the live
328
+ * entry with `useQuery`.
333
329
  */
334
- export interface EnsuredQueryHandle<TFactory extends QueryFactory = QueryFactory> extends HandleFields<TFactory> {
335
- readonly ensured: true;
330
+ export interface QueryHandleWithData<TFactory extends QueryFactory = QueryFactory> extends QueryHandle<TFactory> {
331
+ readonly data: DataOf<TFactory>;
336
332
  }
337
333
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raf-query/core",
3
- "version": "0.7.12",
3
+ "version": "0.9.0",
4
4
  "description": "Framework-agnostic core of raf-query, a render-as-you-fetch query library",
5
5
  "keywords": [
6
6
  "query",