@raf-query/core 0.10.4 → 0.11.1

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,11 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.11.1](https://github.com/KATT/raf-query/compare/0.11.0...0.11.1) (2026-10-17)
4
+
5
+ ### Features
6
+
7
+ * **core:** take throwOnError from the query's options (2/2) ([#214](https://github.com/KATT/raf-query/issues/214)) ([ef1f0fd](https://github.com/KATT/raf-query/commit/ef1f0fd8eda2a73f4c4c268e8a3a5cf91a0ba0d8)), references [#448](https://github.com/KATT/raf-query/issues/448)
8
+
9
+ ## [0.11.0](https://github.com/KATT/raf-query/compare/0.10.4...0.11.0) (2026-10-16)
10
+
11
+ ### ⚠ BREAKING CHANGES
12
+
13
+ - **core:** enabled replaces ssr, as a boolean like TanStack Query's ([#204](https://github.com/KATT/raf-query/issues/204))
14
+
15
+ ### Features
16
+
17
+ - **core:** enabled replaces ssr, as a boolean like TanStack Query's ([#204](https://github.com/KATT/raf-query/issues/204)) ([b7e543b](https://github.com/KATT/raf-query/commit/b7e543b9d1d34e02061740f749f2ddabcdee2ad2))
18
+
3
19
  ## [0.10.4](https://github.com/KATT/raf-query/compare/0.10.3...0.10.4) (2026-10-16)
4
20
 
5
21
  ### Bug Fixes
6
22
 
7
- * **core:** keep pages written during a paged refetch ([#215](https://github.com/KATT/raf-query/issues/215)) ([b6a5946](https://github.com/KATT/raf-query/commit/b6a5946e806e12e9b7df40e80ef0e532c0871b25)), references [#75](https://github.com/KATT/raf-query/issues/75)
8
- * **react:** read promise queryFns as plain data on a client with a layer (1/2) ([#205](https://github.com/KATT/raf-query/issues/205)) ([a9b156e](https://github.com/KATT/raf-query/commit/a9b156edfa18b1e41e9ea929afc412252a61b83c))
23
+ - **core:** keep pages written during a paged refetch ([#215](https://github.com/KATT/raf-query/issues/215)) ([b6a5946](https://github.com/KATT/raf-query/commit/b6a5946e806e12e9b7df40e80ef0e532c0871b25)), references [#75](https://github.com/KATT/raf-query/issues/75)
24
+ - **react:** read promise queryFns as plain data on a client with a layer (1/2) ([#205](https://github.com/KATT/raf-query/issues/205)) ([a9b156e](https://github.com/KATT/raf-query/commit/a9b156edfa18b1e41e9ea929afc412252a61b83c))
9
25
 
10
26
  ## [0.10.3](https://github.com/KATT/raf-query/compare/0.10.2...0.10.3) (2026-10-16)
11
27
 
package/dist/binding.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { __exportAll } from "./_virtual/_rolldown/runtime.mjs";
2
2
  import { hashKey } from "./key.mjs";
3
3
  import { readUnsafe } from "./query.mjs";
4
- import { promiseControls, resultThenable } from "./controls.mjs";
4
+ import { promiseControls, resultThenable, throwsOnError } from "./controls.mjs";
5
5
  import { getOptimisticResultUnsafe, getUnsafe, makeUnsafe as makeUnsafe$1, setOptionsUnsafe, subscribeUnsafe as subscribeUnsafe$1, trackProp } from "./observer.mjs";
6
6
  import { Result } from "effect";
7
7
  //#region src/binding.ts
@@ -113,7 +113,7 @@ function resultOf(impl) {
113
113
  return impl.client.isServer ? getOptimisticResultUnsafe(observer, impl.query, impl.options) : getUnsafe(observer);
114
114
  }
115
115
  function throwOnError() {
116
- return impl.source.options().throwOnError ?? impl.client.throwOnError;
116
+ return throwsOnError(impl.query, impl.source.options().throwOnError, impl.client.throwOnError);
117
117
  }
118
118
  function shown() {
119
119
  const promise = read("promise").promise;
package/dist/client.d.mts CHANGED
@@ -17,8 +17,10 @@ export interface QueryClientConfig<TServices = never> extends Config {
17
17
  * When `false`, `useQuery` for an Effect `queryFn` (a typed `ErrorOf`)
18
18
  * returns a `Result` in the first tuple slot instead of a promise that
19
19
  * rejects. Defaults to `false` when `layer` is set, `true` otherwise.
20
- * Promise `queryFn`s always throw, whatever this flag says: reads tell
21
- * them apart by what the `queryFn` returned ({@link Query.returnsEffectUnsafe}).
20
+ * A query's own `throwOnError` (in `queryOptions`) and a read's win over
21
+ * it; types only see those two. Promise `queryFn`s always throw, whatever
22
+ * the flags say: reads tell them apart by what the `queryFn` returned
23
+ * ({@link Query.returnsEffectUnsafe}).
22
24
  */
23
25
  readonly throwOnError?: boolean;
24
26
  }
@@ -1,5 +1,5 @@
1
1
  import { QueryKey } from "./key.mjs";
2
- import { DataOf, ErrorOf, InputOf, IsPaged, QueryFactory } from "./options.mjs";
2
+ import { DataOf, ErrorOf, InputOf, IsPaged, QueryFactory, ThrowOnErrorOf } from "./options.mjs";
3
3
  import { Thenable } from "./thenable.mjs";
4
4
  import { Query, query_d_exports } from "./query.mjs";
5
5
  import { Options, Result as Result$1, observer_d_exports } from "./observer.mjs";
@@ -14,8 +14,8 @@ export type UseQueryOptions = Options;
14
14
  export type UseQueryThrowOptions<TFactory extends QueryFactory> = HasTypedError<TFactory> extends true ? {
15
15
  /**
16
16
  * When `false`, the data is a `Result` instead of a rejecting
17
- * promise. Omit to use the client's default (`false` with a
18
- * `layer`, `true` without).
17
+ * promise. Omit to use the query's `throwOnError`, else the
18
+ * client's default (`false` with a `layer`, `true` without).
19
19
  */
20
20
  readonly throwOnError?: boolean;
21
21
  } : {
@@ -61,18 +61,20 @@ export type UseQueryControls<TFactory extends QueryFactory> = IsPaged<TFactory>
61
61
  export type HasTypedError<TFactory extends QueryFactory> = unknown extends ErrorOf<TFactory> ? false : true;
62
62
  /**
63
63
  * Whether this read throws on failure. Untyped errors always throw. Typed
64
- * errors follow `options.throwOnError`, else the client's default (`false`
65
- * with a `layer`, `true` without). Types treat an omitted flag as `false`
66
- * (Result), matching a client with a `layer`.
64
+ * errors follow the read's `throwOnError`, else the query's
65
+ * ({@link ThrowOnErrorOf}), else the client's default (`false` with a
66
+ * `layer`, `true` without). Types can't see the client's, so they treat it
67
+ * as `false` (Result), matching a client with a `layer`.
67
68
  */
68
- export type ThrowsOnError<TFactory extends QueryFactory, TThrow extends boolean | undefined> = HasTypedError<TFactory> extends false ? true : TThrow extends boolean ? TThrow : false;
69
+ export type ThrowsOnError<TFactory extends QueryFactory, TThrow extends boolean | undefined> = HasTypedError<TFactory> extends false ? true : TThrow extends boolean ? TThrow : ThrowOnErrorOf<TFactory> extends boolean ? ThrowOnErrorOf<TFactory> : false;
69
70
  /**
70
71
  * {@link ThrowsOnError} at runtime, for bindings: a read of `query` throws
71
- * when `throwOnError` (the call's, else the client's) is `true`, or when its
72
- * `queryFn` returns a promise or plain value, whose error isn't typed. A
73
- * query whose `queryFn` hasn't run yet follows `throwOnError`.
72
+ * when its `queryFn` returns a promise or plain value, whose error isn't
73
+ * typed. Otherwise it follows the read's `throwOnError`, else the query's
74
+ * options', else `clientDefault` (pass the client's `throwOnError`). A query
75
+ * whose `queryFn` hasn't run yet follows the flags.
74
76
  */
75
- export declare function throwsOnError<TFactory extends QueryFactory>(query: Query<TFactory>, throwOnError: boolean): boolean;
77
+ export declare function throwsOnError<TFactory extends QueryFactory>(query: Query<TFactory>, throwOnError: boolean | undefined, clientDefault?: boolean): boolean;
76
78
  /** What a read settles with: the data, or a `Result` when it doesn't throw. */
77
79
  export type ReadValue<TFactory extends QueryFactory, TThrow extends boolean | undefined = undefined> = ThrowsOnError<TFactory, TThrow> extends true ? DataOf<TFactory> : Result.Result<DataOf<TFactory>, ErrorOf<TFactory>>;
78
80
  type Command = "fetchNextPage" | "fetchPreviousPage" | "refetch";
package/dist/controls.mjs CHANGED
@@ -9,12 +9,13 @@ import { Effect, Result } from "effect";
9
9
  */
10
10
  /**
11
11
  * {@link ThrowsOnError} at runtime, for bindings: a read of `query` throws
12
- * when `throwOnError` (the call's, else the client's) is `true`, or when its
13
- * `queryFn` returns a promise or plain value, whose error isn't typed. A
14
- * query whose `queryFn` hasn't run yet follows `throwOnError`.
12
+ * when its `queryFn` returns a promise or plain value, whose error isn't
13
+ * typed. Otherwise it follows the read's `throwOnError`, else the query's
14
+ * options', else `clientDefault` (pass the client's `throwOnError`). A query
15
+ * whose `queryFn` hasn't run yet follows the flags.
15
16
  */
16
- function throwsOnError(query, throwOnError) {
17
- return throwOnError || returnsEffectUnsafe(query) === false;
17
+ function throwsOnError(query, throwOnError, clientDefault = false) {
18
+ return returnsEffectUnsafe(query) === false || (throwOnError ?? query.options?.throwOnError ?? clientDefault);
18
19
  }
19
20
  const commands = /* @__PURE__ */ new WeakMap();
20
21
  /** One stable Promise function per command Effect, so identities track the query's. */
package/dist/entry.d.mts CHANGED
@@ -6,7 +6,7 @@ import { FetchRequest, Query, State, SubscribeOptions } from "./query.mjs";
6
6
  import { Event } from "./cache.mjs";
7
7
  import { Cause, Clock, Context, Deferred, Effect, Scope, Stream } from "effect";
8
8
  declare namespace entry_d_exports {
9
- export { BrowserOnlyError, CacheState, CancelledError, Entry, TypeId, changes, emit, entryOf, fetch, hasNextPageUnsafe, hasPreviousPageUnsafe, invalidate, isBrowserOnly, isObserved, isQuery, isStaleUnsafe, make, metaOf, needsRefetch, onPlatformEvent, provide, readUnsafe, remove, reset, resume, revalidate, setData, setOptions, start, subscribeUnsafe };
9
+ export { CacheState, CancelledError, DisabledError, Entry, TypeId, changes, emit, entryOf, fetch, hasNextPageUnsafe, hasPreviousPageUnsafe, invalidate, isDisabled, isObserved, isQuery, isStaleUnsafe, make, metaOf, needsRefetch, onPlatformEvent, provide, readUnsafe, remove, reset, resume, revalidate, setData, setOptions, start, subscribeUnsafe };
10
10
  }
11
11
  export declare const TypeId = "~@raf-query/core/Query";
12
12
  declare const CancelledError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => Cause.YieldableError & {
@@ -19,14 +19,14 @@ declare const CancelledError_base: new <A extends Record<string, any> = {}>(args
19
19
  export declare class CancelledError extends CancelledError_base {
20
20
  readonly message = "The query was cancelled";
21
21
  }
22
- declare const BrowserOnlyError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => Cause.YieldableError & {
23
- readonly _tag: "BrowserOnlyError";
22
+ declare const DisabledError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => Cause.YieldableError & {
23
+ readonly _tag: "DisabledError";
24
24
  } & Readonly<A>;
25
25
  /**
26
- * Why a query with `ssr: false` has no data on the server: its promise
27
- * there rejects with this, and `ensure` / `fetch` die with it.
26
+ * Why a query with `enabled: false` has no data: `ensure` / `fetch` die
27
+ * with it, and on a server its promise rejects with it.
28
28
  */
29
- export declare class BrowserOnlyError extends BrowserOnlyError_base<{
29
+ export declare class DisabledError extends DisabledError_base<{
30
30
  readonly hash: string;
31
31
  }> {
32
32
  get message(): string;
@@ -106,8 +106,8 @@ export declare function emit(cache: CacheState, event: Event): void;
106
106
  export declare function make(cache: CacheState, key: QueryKey, hash: string): Entry;
107
107
  /** Readers are subscribed; `invalidate` and focus refetch only what is read. */
108
108
  export declare function isObserved(entry: Entry): boolean;
109
- /** A server cache's entry for an `ssr: false` query: it never runs here. */
110
- export declare function isBrowserOnly(entry: Entry): boolean;
109
+ /** The entry's latest factory call returned `enabled: false`: it doesn't run. */
110
+ export declare function isDisabled(entry: Entry): boolean;
111
111
  /** Until a factory call attaches options, `meta` comes from hydration. */
112
112
  export declare function metaOf(entry: Entry): QueryMeta | undefined;
113
113
  export declare function isStaleUnsafe(entry: Entry): boolean;
package/dist/entry.mjs CHANGED
@@ -17,12 +17,12 @@ var CancelledError = class extends Data.TaggedError("CancelledError") {
17
17
  message = "The query was cancelled";
18
18
  };
19
19
  /**
20
- * Why a query with `ssr: false` has no data on the server: its promise
21
- * there rejects with this, and `ensure` / `fetch` die with it.
20
+ * Why a query with `enabled: false` has no data: `ensure` / `fetch` die
21
+ * with it, and on a server its promise rejects with it.
22
22
  */
23
- var BrowserOnlyError = class extends Data.TaggedError("BrowserOnlyError") {
23
+ var DisabledError = class extends Data.TaggedError("DisabledError") {
24
24
  get message() {
25
- return `Query ${this.hash} runs in the browser only (ssr: false)`;
25
+ return `Query ${this.hash} is disabled (enabled: false)`;
26
26
  }
27
27
  };
28
28
  const Proto = {
@@ -95,7 +95,7 @@ function make(cache, key, hash) {
95
95
  },
96
96
  tasks: makeTasks(cache, scope)
97
97
  });
98
- const command = (request) => Effect.suspend(() => isBrowserOnly(entry) ? Effect.void : Effect.ignore(fetch(entry, request)));
98
+ const command = (request) => Effect.suspend(() => isDisabled(entry) ? Effect.void : Effect.ignore(fetch(entry, request)));
99
99
  const commands = {
100
100
  fetchNextPage: command({ direction: "forward" }),
101
101
  fetchPreviousPage: command({ direction: "backward" }),
@@ -115,9 +115,9 @@ function isObserved(entry) {
115
115
  function behavior(entry, name) {
116
116
  return entry.options?.[name] ?? entry.cache.defaults[name];
117
117
  }
118
- /** A server cache's entry for an `ssr: false` query: it never runs here. */
119
- function isBrowserOnly(entry) {
120
- return entry.cache.isServer && behavior(entry, "ssr") === false;
118
+ /** The entry's latest factory call returned `enabled: false`: it doesn't run. */
119
+ function isDisabled(entry) {
120
+ return behavior(entry, "enabled") === false;
121
121
  }
122
122
  /** Until a factory call attaches options, `meta` comes from hydration. */
123
123
  function metaOf(entry) {
@@ -225,7 +225,7 @@ function fetch(entry, request = {}) {
225
225
  function invalidate(entry) {
226
226
  return Effect.suspend(() => {
227
227
  set(entry, { isInvalidated: true });
228
- if (!isObserved(entry) || !entry.options || isBrowserOnly(entry)) return Effect.void;
228
+ if (!isObserved(entry) || !entry.options || isDisabled(entry)) return Effect.void;
229
229
  return Effect.ignore(begin(entry, { restart: true }));
230
230
  });
231
231
  }
@@ -244,7 +244,7 @@ function reset(entry) {
244
244
  status: "pending",
245
245
  updatedAt: 0
246
246
  });
247
- if (!entry.options || isBrowserOnly(entry) || !isObserved(entry) && !entry.inFlight) return Effect.void;
247
+ if (!entry.options || isDisabled(entry) || !isObserved(entry) && !entry.inFlight) return Effect.void;
248
248
  return Effect.ignore(begin(entry, { restart: true }));
249
249
  });
250
250
  }
@@ -291,11 +291,13 @@ function remove(entry) {
291
291
  */
292
292
  function begin(entry, request) {
293
293
  if (Predicate.isTagged(entry.scope.state, "Closed")) return Effect.fail(new CancelledError());
294
- if (isBrowserOnly(entry)) {
295
- const error = new BrowserOnlyError({ hash: entry.hash });
296
- const firstLoad = entry.pending;
297
- entry.pending = void 0;
298
- firstLoad?.reject(error);
294
+ if (isDisabled(entry)) {
295
+ const error = new DisabledError({ hash: entry.hash });
296
+ if (entry.cache.isServer) {
297
+ const firstLoad = entry.pending;
298
+ entry.pending = void 0;
299
+ firstLoad?.reject(error);
300
+ }
299
301
  return Effect.die(error);
300
302
  }
301
303
  const options = entry.options;
@@ -332,7 +334,7 @@ function startRequest(entry, request, direction, updatedAt) {
332
334
  entry.retriesStopped = false;
333
335
  entry.signalRead = false;
334
336
  entry.tasks.cancel("gc");
335
- if (!entry.state.hasData && entry.state.status === "error") {
337
+ if (!entry.state.hasData && !entry.pending) {
336
338
  entry.pending = pending();
337
339
  set(entry, {
338
340
  error: null,
@@ -521,4 +523,4 @@ function scheduleStale(entry) {
521
523
  entry.tasks.fork("stale", Effect.sleep(Math.max(remaining, 0) + 1).pipe(Effect.andThen(Effect.sync(() => set(entry, {})))));
522
524
  }
523
525
  //#endregion
524
- export { BrowserOnlyError, CancelledError, TypeId, changes, emit, entryOf, fetch, hasNextPageUnsafe, hasPreviousPageUnsafe, invalidate, isBrowserOnly, isObserved, isQuery, isStaleUnsafe, make, metaOf, needsRefetch, onPlatformEvent, provide, readUnsafe, remove, reset, resume, revalidate, setData, setOptions, start, subscribeUnsafe };
526
+ export { CancelledError, DisabledError, TypeId, changes, emit, entryOf, fetch, hasNextPageUnsafe, hasPreviousPageUnsafe, invalidate, isDisabled, isObserved, isQuery, isStaleUnsafe, make, metaOf, needsRefetch, onPlatformEvent, provide, readUnsafe, remove, reset, resume, revalidate, setData, setOptions, start, subscribeUnsafe };
@@ -1,4 +1,4 @@
1
- import { entryOf, isBrowserOnly, resume, revalidate, setData } from "./entry.mjs";
1
+ import { entryOf, isDisabled, resume, revalidate, setData } from "./entry.mjs";
2
2
  import { getUnsafe, metaUnsafe, returnsEffectUnsafe } from "./query.mjs";
3
3
  import { Data, Effect, Queue, Stream } from "effect";
4
4
  //#region src/hydration.ts
@@ -62,7 +62,7 @@ function dehydrateEntries(queries, options) {
62
62
  const filter = options.filter ?? canDehydrate;
63
63
  const sent = options.sent;
64
64
  const dehydrated = [];
65
- for (const query of queries) if (!sent?.has(query.hash) && !isBrowserOnly(entryOf(query)) && filter(query)) {
65
+ for (const query of queries) if (!sent?.has(query.hash) && !isDisabled(entryOf(query)) && filter(query)) {
66
66
  sent?.add(query.hash);
67
67
  dehydrated.push(dehydrateUnsafe(query, options));
68
68
  }
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Settled, allKeyed } from "./all-keyed.mjs";
2
2
  import { QueryKey, hashKey, matchesKey } from "./key.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";
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, ThrowOnErrorOf, infiniteQueryOptions, queryOptions } from "./options.mjs";
4
4
  import { platform_d_exports } from "./platform.mjs";
5
5
  import { Pending, Thenable, fulfilled, pending } from "./thenable.mjs";
6
6
  import { query_d_exports } from "./query.mjs";
@@ -10,4 +10,4 @@ import { QueryClient, QueryClientConfig, dehydrate, hydrate } from "./client.mjs
10
10
  import { observer_d_exports } from "./observer.mjs";
11
11
  import { HasTypedError, PagingControls, PromiseControls, QueryControls, ReadValue, ThrowsOnError, UseQueryControls, UseQueryOptions, UseQueryThrowOptions, promiseControls, resultThenable, throwsOnError } from "./controls.mjs";
12
12
  import { binding_d_exports } from "./binding.mjs";
13
- export { type AnyQueryOptions, type DataOf, type DehydrateOptions, type DehydratedQuery, type DehydratedResult, type DehydratedState, type DehydratedStream, type ErrorOf, type HasTypedError, type HydrateOptions, type InfiniteData, type InfiniteQueryOptions, type InfiniteQueryTypes, type InputArgs, type InputOf, type IsPaged, type LoadOptions, type PageFunctionContext, type PageOf, type PagedQueryFactory, type PagingControls, type Pending, platform_d_exports as Platform, type PromiseControls, query_d_exports as Query, type QueryBehavior, binding_d_exports as QueryBinding, cache_d_exports as QueryCache, QueryClient, type QueryClientConfig, type QueryControls, type QueryFactory, type QueryFnResult, type QueryFunctionContext, type QueryHandle, type QueryHandleWithData, type QueryKey, type QueryMeta, observer_d_exports as QueryObserver, type QueryOptions, type QueryTypes, type ReadValue, RedactedError, type Register, type RetryPolicy, type ServicesOf, type Settled, type Thenable, type ThrowsOnError, type UseQueryControls, type UseQueryOptions, type UseQueryThrowOptions, allKeyed, canDehydrate, dehydrate, dehydrateQuery, fulfilled, hashKey, hydrate, infiniteQueryOptions, matchesKey, pending, promiseControls, queryOptions, resultThenable, throwsOnError };
13
+ export { type AnyQueryOptions, type DataOf, type DehydrateOptions, type DehydratedQuery, type DehydratedResult, type DehydratedState, type DehydratedStream, type ErrorOf, type HasTypedError, type HydrateOptions, type InfiniteData, type InfiniteQueryOptions, type InfiniteQueryTypes, type InputArgs, type InputOf, type IsPaged, type LoadOptions, type PageFunctionContext, type PageOf, type PagedQueryFactory, type PagingControls, type Pending, platform_d_exports as Platform, type PromiseControls, query_d_exports as Query, type QueryBehavior, binding_d_exports as QueryBinding, cache_d_exports as QueryCache, QueryClient, type QueryClientConfig, type QueryControls, type QueryFactory, type QueryFnResult, type QueryFunctionContext, type QueryHandle, type QueryHandleWithData, type QueryKey, type QueryMeta, observer_d_exports as QueryObserver, type QueryOptions, type QueryTypes, type ReadValue, RedactedError, type Register, type RetryPolicy, type ServicesOf, type Settled, type Thenable, type ThrowOnErrorOf, type ThrowsOnError, type UseQueryControls, type UseQueryOptions, type UseQueryThrowOptions, allKeyed, canDehydrate, dehydrate, dehydrateQuery, fulfilled, hashKey, hydrate, infiniteQueryOptions, matchesKey, pending, promiseControls, queryOptions, resultThenable, throwsOnError };
@@ -6,7 +6,8 @@ import { Effect, Schedule } from "effect";
6
6
  * `queryFn` its error and the services it needs, and the shape of its key.
7
7
  * Leave `error` out and it is `unknown` (promises reject with anything);
8
8
  * leave `services` out and it is `never`; leave `key` out and it is any
9
- * {@link QueryKey}.
9
+ * {@link QueryKey}. `throwOnError` is the query's `throwOnError` option;
10
+ * leave it out when the query doesn't set one.
10
11
  *
11
12
  * ```ts
12
13
  * type PostOptions = QueryOptions<{ data: Post }>;
@@ -17,10 +18,12 @@ export interface QueryTypes {
17
18
  readonly error?: unknown;
18
19
  readonly key?: QueryKey;
19
20
  readonly services?: unknown;
21
+ readonly throwOnError?: boolean;
20
22
  }
21
23
  /**
22
24
  * The types of a paged query: one page, the param that loads it, and as in
23
- * {@link QueryTypes}, an Effect `queryFn`'s error and services and the key.
25
+ * {@link QueryTypes}, an Effect `queryFn`'s error and services, the key and
26
+ * `throwOnError`.
24
27
  */
25
28
  export interface InfiniteQueryTypes {
26
29
  readonly error?: unknown;
@@ -28,6 +31,7 @@ export interface InfiniteQueryTypes {
28
31
  readonly page: unknown;
29
32
  readonly pageParam: unknown;
30
33
  readonly services?: unknown;
34
+ readonly throwOnError?: boolean;
31
35
  }
32
36
  /** `error` of a types bag, `unknown` when it has none. */
33
37
  type ErrorIn<TTypes> = TTypes extends {
@@ -41,52 +45,39 @@ type ServicesIn<TTypes> = TTypes extends {
41
45
  type KeyIn<TTypes> = TTypes extends {
42
46
  readonly key: infer TKey extends QueryKey;
43
47
  } ? TKey : QueryKey;
48
+ /** `throwOnError` of a types bag, `undefined` when it has none. */
49
+ type ThrowIn<TTypes> = TTypes extends {
50
+ readonly throwOnError: infer TThrow extends boolean;
51
+ } ? TThrow : undefined;
52
+ /** One object type for an intersection, so bags read as written. */
53
+ type Flat<T> = { [K in keyof T]: T[K]; };
54
+ type ErrorPart<TError> = unknown extends TError ? unknown : {
55
+ error: TError;
56
+ };
57
+ type ServicesPart<TServices> = [TServices] extends [never] ? unknown : {
58
+ services: TServices;
59
+ };
60
+ type ThrowPart<TThrow> = [TThrow] extends [boolean] ? {
61
+ throwOnError: TThrow;
62
+ } : unknown;
44
63
  /**
45
64
  * The bag `queryOptions` returns. `error` is left out when the `queryFn`
46
65
  * doesn't name one (`unknown`: a promise or a plain value). `services` is
47
66
  * left out when the `queryFn` needs none (`never`). An Effect's error,
48
67
  * including `never` when it can't fail, stays. `key` is always there, so two
49
- * factories with different key shapes have different types.
68
+ * factories with different key shapes have different types. `throwOnError`
69
+ * is there when the options set it.
50
70
  */
51
- type QueryTypesOf<TData, TError, TServices, TKey> = unknown extends TError ? [TServices] extends [never] ? {
52
- data: TData;
53
- key: TKey;
54
- } : {
55
- data: TData;
56
- key: TKey;
57
- services: TServices;
58
- } : [TServices] extends [never] ? {
59
- data: TData;
60
- error: TError;
61
- key: TKey;
62
- } : {
71
+ type QueryTypesOf<TData, TError, TServices, TKey, TThrow> = Flat<{
63
72
  data: TData;
64
- error: TError;
65
73
  key: TKey;
66
- services: TServices;
67
- };
74
+ } & ErrorPart<TError> & ServicesPart<TServices> & ThrowPart<TThrow>>;
68
75
  /** As {@link QueryTypesOf}, for a paged query. */
69
- type InfiniteQueryTypesOf<TPage, TPageParam, TError, TServices, TKey> = unknown extends TError ? [TServices] extends [never] ? {
76
+ type InfiniteQueryTypesOf<TPage, TPageParam, TError, TServices, TKey, TThrow> = Flat<{
70
77
  key: TKey;
71
78
  page: TPage;
72
79
  pageParam: TPageParam;
73
- } : {
74
- key: TKey;
75
- page: TPage;
76
- pageParam: TPageParam;
77
- services: TServices;
78
- } : [TServices] extends [never] ? {
79
- error: TError;
80
- key: TKey;
81
- page: TPage;
82
- pageParam: TPageParam;
83
- } : {
84
- error: TError;
85
- key: TKey;
86
- page: TPage;
87
- pageParam: TPageParam;
88
- services: TServices;
89
- };
80
+ } & ErrorPart<TError> & ServicesPart<TServices> & ThrowPart<TThrow>>;
90
81
  /**
91
82
  * What a `queryFn` may return: a value, a promise, or an `Effect`. An
92
83
  * Effect's error type becomes the query's (promises reject with `unknown`),
@@ -135,6 +126,20 @@ export interface PageFunctionContext<TPageParam> extends QueryFunctionContext {
135
126
  export type RetryPolicy = boolean | number | Schedule.Schedule<unknown, unknown> | ((failureCount: number, error: unknown) => boolean);
136
127
  /** Options every query accepts. `QueryCache` defaults fill in the rest. */
137
128
  export interface QueryBehavior {
129
+ /**
130
+ * `false` keeps the query from running. Default `true`. The factory
131
+ * decides per call, so `enabled: typeof window !== "undefined"` runs a
132
+ * query only in the browser, for data only a browser has (permissions,
133
+ * device APIs, `localStorage`).
134
+ *
135
+ * While disabled, readers see `isPending`, `ensure` and `fetch` fail with
136
+ * `Query.DisabledError`, and `invalidate`, `reset` and `refetch` do
137
+ * nothing. In the browser, its promise stays pending until a factory
138
+ * call returns `true` and runs it. A server cache never sends it, and its
139
+ * promise rejects with `Query.DisabledError`: under Suspense, React
140
+ * renders the fallback on the server and the component in the browser.
141
+ */
142
+ readonly enabled?: boolean;
138
143
  /** How long an unread entry stays cached, in ms. `Infinity` keeps it. */
139
144
  readonly gcTime?: number;
140
145
  /**
@@ -151,15 +156,6 @@ export interface QueryBehavior {
151
156
  readonly retry?: RetryPolicy;
152
157
  /** Delay before retry number `failureCount` (1-based), in ms. */
153
158
  readonly retryDelay?: number | ((failureCount: number, error: unknown) => number);
154
- /**
155
- * `false`: only the browser runs the query, for data only a browser has
156
- * (permissions, device APIs). A server cache never starts it or sends it.
157
- * Readers there see `isPending`, and a promise that rejects with
158
- * `Query.BrowserOnlyError`: under Suspense, React renders the fallback on
159
- * the server and the query in the browser. `ensure` and `fetch` on the
160
- * server fail with that error. Default `true`.
161
- */
162
- readonly ssr?: boolean;
163
159
  /** How long data counts as fresh, in ms. Fresh data is never refetched. */
164
160
  readonly staleTime?: number;
165
161
  /**
@@ -178,7 +174,17 @@ interface ServicesField<TServices> {
178
174
  */
179
175
  readonly [servicesType]?: () => TServices;
180
176
  }
181
- export interface QueryOptions<TTypes extends QueryTypes> extends QueryBehavior, ServicesField<ServicesIn<TTypes>> {
177
+ interface ThrowOnErrorField<TThrow> {
178
+ /**
179
+ * How reads of this query settle on failure when they don't set
180
+ * `throwOnError` themselves: `true` rejects (to an error boundary),
181
+ * `false` settles with a `Result`. Omit it for the client's default.
182
+ * Only an Effect `queryFn`'s typed error reads as a `Result`; a promise
183
+ * `queryFn` always rejects.
184
+ */
185
+ readonly throwOnError?: TThrow;
186
+ }
187
+ export interface QueryOptions<TTypes extends QueryTypes> extends QueryBehavior, ServicesField<ServicesIn<TTypes>>, ThrowOnErrorField<ThrowIn<TTypes>> {
182
188
  readonly kind: "query";
183
189
  queryFn(context: QueryFunctionContext): QueryFnResult<TTypes>;
184
190
  readonly queryKey: KeyIn<TTypes>;
@@ -200,7 +206,7 @@ export interface InfiniteQueryOptions<TTypes extends InfiniteQueryTypes> extends
200
206
  data: TTypes["page"];
201
207
  error: ErrorIn<TTypes>;
202
208
  services: ServicesIn<TTypes>;
203
- }>>, QueryBehavior, ServicesField<ServicesIn<TTypes>> {
209
+ }>>, QueryBehavior, ServicesField<ServicesIn<TTypes>>, ThrowOnErrorField<ThrowIn<TTypes>> {
204
210
  readonly initialPageParam: TTypes["pageParam"];
205
211
  readonly kind: "infinite";
206
212
  /** Keep at most this many pages; the far end is dropped when paging. */
@@ -216,11 +222,13 @@ export type AnyQueryOptions = QueryOptions<{
216
222
  data: unknown;
217
223
  error: unknown;
218
224
  services: unknown;
225
+ throwOnError: boolean;
219
226
  }> | InfiniteQueryOptions<{
220
227
  error: unknown;
221
228
  page: unknown;
222
229
  pageParam: unknown;
223
230
  services: unknown;
231
+ throwOnError: boolean;
224
232
  }>;
225
233
  /**
226
234
  * Typed options for a query factory:
@@ -243,28 +251,33 @@ export type AnyQueryOptions = QueryOptions<{
243
251
  * factories with the same input and data but different keys have different
244
252
  * types, and a handle of one doesn't type-check where the other's goes.
245
253
  *
254
+ * `throwOnError: true` or `false` is kept as a literal too, so reads that
255
+ * don't set their own follow it in their types.
256
+ *
246
257
  * The type parameters are only there for TypeScript to infer the types bag
247
- * from `queryFn` and `queryKey`; it can't infer a bag's members.
258
+ * from `queryFn`, `queryKey` and `throwOnError`; it can't infer a bag's
259
+ * members. Passing them explicitly, pass `TThrow` too when setting
260
+ * `throwOnError`.
248
261
  */
249
- export declare function queryOptions<TData, TError = unknown, TServices = never, const TKey extends QueryKey = QueryKey>(options: Omit<QueryOptions<{
262
+ export declare function queryOptions<TData, TError = unknown, TServices = never, const TKey extends QueryKey = QueryKey, TThrow extends boolean | undefined = undefined>(options: Omit<QueryOptions<{
250
263
  data: TData;
251
264
  error: TError;
252
265
  key: TKey;
253
266
  services: TServices;
254
- }>, "kind">): QueryOptions<QueryTypesOf<TData, TError, TServices, TKey>>;
267
+ }>, "kind" | "throwOnError"> & ThrowOnErrorField<TThrow>): QueryOptions<QueryTypesOf<TData, TError, TServices, TKey, TThrow>>;
255
268
  /**
256
269
  * Typed options for a paged query factory. The page type is inferred from
257
270
  * `queryFn`, as in {@link queryOptions}. So is an Effect `queryFn`'s error;
258
271
  * a promise or a plain value leaves `error` out. The key's literal type is
259
272
  * kept, as in {@link queryOptions}.
260
273
  */
261
- export declare function infiniteQueryOptions<TPage, TPageParam, TError = unknown, TServices = never, const TKey extends QueryKey = QueryKey>(options: Omit<InfiniteQueryOptions<{
274
+ export declare function infiniteQueryOptions<TPage, TPageParam, TError = unknown, TServices = never, const TKey extends QueryKey = QueryKey, TThrow extends boolean | undefined = undefined>(options: Omit<InfiniteQueryOptions<{
262
275
  error: TError;
263
276
  key: TKey;
264
277
  page: TPage;
265
278
  pageParam: TPageParam;
266
279
  services: TServices;
267
- }>, "kind">): InfiniteQueryOptions<InfiniteQueryTypesOf<TPage, TPageParam, TError, TServices, TKey>>;
280
+ }>, "kind" | "throwOnError"> & ThrowOnErrorField<TThrow>): InfiniteQueryOptions<InfiniteQueryTypesOf<TPage, TPageParam, TError, TServices, TKey, TThrow>>;
268
281
  interface FactoryResult {
269
282
  readonly kind: "infinite" | "query";
270
283
  readonly queryKey: QueryKey;
@@ -322,6 +335,11 @@ export type ErrorOf<TFactory extends QueryFactory> = ReturnType<TFactory> extend
322
335
  * values, and for a factory of no particular query.
323
336
  */
324
337
  export type ServicesOf<TFactory extends QueryFactory> = ReturnType<TFactory> extends InfiniteQueryOptions<infer TTypes> ? ServicesIn<TTypes> : ReturnType<TFactory> extends QueryOptions<infer TTypes> ? ServicesIn<TTypes> : never;
338
+ /**
339
+ * The `throwOnError` a factory's options set, `undefined` when they set
340
+ * none (or for a factory of no particular query).
341
+ */
342
+ export type ThrowOnErrorOf<TFactory extends QueryFactory> = ReturnType<TFactory> extends InfiniteQueryOptions<infer TTypes> ? ThrowIn<TTypes> : ReturnType<TFactory> extends QueryOptions<infer TTypes> ? ThrowIn<TTypes> : undefined;
325
343
  /** Page type of a paged factory. */
326
344
  export type PageOf<TFactory extends QueryFactory> = ReturnType<TFactory> extends InfiniteQueryOptions<infer TTypes> ? TTypes["page"] : never;
327
345
  /**
package/dist/options.mjs CHANGED
@@ -20,8 +20,13 @@
20
20
  * factories with the same input and data but different keys have different
21
21
  * types, and a handle of one doesn't type-check where the other's goes.
22
22
  *
23
+ * `throwOnError: true` or `false` is kept as a literal too, so reads that
24
+ * don't set their own follow it in their types.
25
+ *
23
26
  * The type parameters are only there for TypeScript to infer the types bag
24
- * from `queryFn` and `queryKey`; it can't infer a bag's members.
27
+ * from `queryFn`, `queryKey` and `throwOnError`; it can't infer a bag's
28
+ * members. Passing them explicitly, pass `TThrow` too when setting
29
+ * `throwOnError`.
25
30
  */
26
31
  function queryOptions(options) {
27
32
  return {
package/dist/query.d.mts CHANGED
@@ -2,10 +2,10 @@ import { QueryKey } from "./key.mjs";
2
2
  import { AnyQueryOptions, DataOf, ErrorOf, QueryFactory, QueryHandle, QueryMeta, ServicesOf } from "./options.mjs";
3
3
  import { Direction } from "./infinite.mjs";
4
4
  import { Thenable } from "./thenable.mjs";
5
- import { BrowserOnlyError as BrowserOnlyError$1, CancelledError as CancelledError$1, TypeId as TypeId$1, entry_d_exports } from "./entry.mjs";
5
+ import { CancelledError as CancelledError$1, DisabledError as DisabledError$1, TypeId as TypeId$1, entry_d_exports } from "./entry.mjs";
6
6
  import { Effect, Pipeable, Stream } from "effect";
7
7
  declare namespace query_d_exports {
8
- export { BrowserOnlyError, CancelledError, FetchRequest, Query, State, SubscribeOptions, TypeId, changes, fetch, fetchNextPage, fetchPreviousPage, get, getUnsafe, hasNextPageUnsafe, hasPreviousPageUnsafe, invalidate, isQuery, isStaleUnsafe, metaUnsafe, observerCountUnsafe, readUnsafe, refetch, reset, returnsEffectUnsafe, revalidateUnsafe, subscribeUnsafe };
8
+ export { CancelledError, DisabledError, FetchRequest, Query, State, SubscribeOptions, TypeId, changes, fetch, fetchNextPage, fetchPreviousPage, get, getUnsafe, hasNextPageUnsafe, hasPreviousPageUnsafe, invalidate, isQuery, isStaleUnsafe, metaUnsafe, observerCountUnsafe, readUnsafe, refetch, reset, returnsEffectUnsafe, revalidateUnsafe, subscribeUnsafe };
9
9
  }
10
10
  export declare const TypeId: typeof TypeId$1;
11
11
  export type TypeId = typeof TypeId;
@@ -67,8 +67,8 @@ export interface FetchRequest {
67
67
  }
68
68
  export declare const CancelledError: typeof CancelledError$1;
69
69
  export type CancelledError = CancelledError$1;
70
- export declare const BrowserOnlyError: typeof BrowserOnlyError$1;
71
- export type BrowserOnlyError = BrowserOnlyError$1;
70
+ export declare const DisabledError: typeof DisabledError$1;
71
+ export type DisabledError = DisabledError$1;
72
72
  export declare const isQuery: (value: unknown) => value is Query;
73
73
  /**
74
74
  * Start a request, or join the one in flight. Fails with the request's
package/dist/query.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { __exportAll } from "./_virtual/_rolldown/runtime.mjs";
2
- import { BrowserOnlyError as BrowserOnlyError$1, CancelledError as CancelledError$1, TypeId as TypeId$1, changes as changes$1, entryOf, fetch as fetch$1, hasNextPageUnsafe as hasNextPageUnsafe$1, hasPreviousPageUnsafe as hasPreviousPageUnsafe$1, invalidate as invalidate$1, isQuery as isQuery$1, isStaleUnsafe as isStaleUnsafe$1, metaOf, provide, readUnsafe as readUnsafe$1, reset as reset$1, revalidate, subscribeUnsafe as subscribeUnsafe$1 } from "./entry.mjs";
2
+ import { CancelledError as CancelledError$1, DisabledError as DisabledError$1, TypeId as TypeId$1, changes as changes$1, entryOf, fetch as fetch$1, hasNextPageUnsafe as hasNextPageUnsafe$1, hasPreviousPageUnsafe as hasPreviousPageUnsafe$1, invalidate as invalidate$1, isQuery as isQuery$1, isStaleUnsafe as isStaleUnsafe$1, metaOf, provide, readUnsafe as readUnsafe$1, reset as reset$1, revalidate, subscribeUnsafe as subscribeUnsafe$1 } from "./entry.mjs";
3
3
  import { Effect } from "effect";
4
4
  import { dual } from "effect/Function";
5
5
  //#region src/query.ts
@@ -12,8 +12,8 @@ import { dual } from "effect/Function";
12
12
  * synchronously, for renders and external stores that can't run an Effect.
13
13
  */
14
14
  var query_exports = /* @__PURE__ */ __exportAll({
15
- BrowserOnlyError: () => BrowserOnlyError,
16
15
  CancelledError: () => CancelledError,
16
+ DisabledError: () => DisabledError,
17
17
  TypeId: () => TypeId,
18
18
  changes: () => changes,
19
19
  fetch: () => fetch,
@@ -37,7 +37,7 @@ var query_exports = /* @__PURE__ */ __exportAll({
37
37
  });
38
38
  const TypeId = TypeId$1;
39
39
  const CancelledError = CancelledError$1;
40
- const BrowserOnlyError = BrowserOnlyError$1;
40
+ const DisabledError = DisabledError$1;
41
41
  const isQuery = isQuery$1;
42
42
  function typed(effect) {
43
43
  return effect;
@@ -144,4 +144,4 @@ function observerCountUnsafe(self) {
144
144
  return entryOf(self).listeners.size;
145
145
  }
146
146
  //#endregion
147
- export { BrowserOnlyError, CancelledError, TypeId, changes, fetch, fetchNextPage, fetchPreviousPage, get, getUnsafe, hasNextPageUnsafe, hasPreviousPageUnsafe, invalidate, isQuery, isStaleUnsafe, metaUnsafe, observerCountUnsafe, query_exports, readUnsafe, refetch, reset, returnsEffectUnsafe, revalidateUnsafe, subscribeUnsafe };
147
+ export { CancelledError, DisabledError, TypeId, changes, fetch, fetchNextPage, fetchPreviousPage, get, getUnsafe, hasNextPageUnsafe, hasPreviousPageUnsafe, invalidate, isQuery, isStaleUnsafe, metaUnsafe, observerCountUnsafe, query_exports, readUnsafe, refetch, reset, returnsEffectUnsafe, revalidateUnsafe, subscribeUnsafe };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raf-query/core",
3
- "version": "0.10.4",
3
+ "version": "0.11.1",
4
4
  "description": "Framework-agnostic core of raf-query, a render-as-you-fetch query library",
5
5
  "keywords": [
6
6
  "query",