@raf-query/core 0.5.3 → 0.6.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 +19 -1
- package/dist/cache.d.mts +10 -6
- package/dist/cache.mjs +3 -3
- package/dist/entry.d.mts +15 -1
- package/dist/entry.mjs +31 -10
- package/dist/hydration.mjs +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/infinite.mjs +19 -6
- package/dist/options.d.mts +32 -4
- package/dist/query.d.mts +4 -2
- package/dist/query.mjs +4 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.6.0](https://github.com/KATT/raf-query/compare/0.5.3...0.6.0) (2026-10-14)
|
|
4
|
+
|
|
5
|
+
### ⚠ BREAKING CHANGES
|
|
6
|
+
|
|
7
|
+
* **core:** LoadOptions takes no type argument, and QueryCache.LoadArgs is gone.
|
|
8
|
+
|
|
9
|
+
* **testing:** render in an async act so suspended trees resume ([#78](https://github.com/KATT/raf-query/issues/78)) ([c706b9d](https://github.com/KATT/raf-query/commit/c706b9db0d3ba3ea2d5b3fd1e21dc8e1fe315b82))
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **core:** ssr: false runs a query in the browser only ([#77](https://github.com/KATT/raf-query/issues/77)) ([22c47bd](https://github.com/KATT/raf-query/commit/22c47bdad9da2e9e84728017db3dde636c5d4113))
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* **core:** infer generic factory makers passed inline to a verb ([#76](https://github.com/KATT/raf-query/issues/76)) ([f0616f7](https://github.com/KATT/raf-query/commit/f0616f7cd4288fb4a00e784f6d94dc3880d19a39))
|
|
18
|
+
* **core:** keep data written while a page loads ([#75](https://github.com/KATT/raf-query/issues/75)) ([d1b8ae5](https://github.com/KATT/raf-query/commit/d1b8ae560540cea345dad1008f8b4d8a467f48aa))
|
|
19
|
+
* **react:** let beforeLoad return handles in TanStack Start route context ([#74](https://github.com/KATT/raf-query/issues/74)) ([70c2121](https://github.com/KATT/raf-query/commit/70c2121a1926b4045049e6d9bfe56778262be42f))
|
|
20
|
+
|
|
3
21
|
## [0.5.3](https://github.com/KATT/raf-query/compare/0.5.2...0.5.3) (2026-10-14)
|
|
4
22
|
|
|
5
|
-
|
|
23
|
+
- compare prefetch, ensure and fetch in the starting queries demo ([#73](https://github.com/KATT/raf-query/issues/73)) ([b26a65e](https://github.com/KATT/raf-query/commit/b26a65e3e003f18308ce456646eba1d3f50c1357))
|
|
6
24
|
|
|
7
25
|
## [0.5.2](https://github.com/KATT/raf-query/compare/0.5.1...0.5.2) (2026-10-14)
|
|
8
26
|
|
package/dist/cache.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { QueryKey } from "./key.mjs";
|
|
2
|
-
import { DataOf, EnsuredQueryHandle, ErrorOf, InputArgs, InputOf, LoadOptions, QueryBehavior, QueryFactory, QueryHandle, ServicesOf } from "./options.mjs";
|
|
2
|
+
import { DataOf, EnsuredQueryHandle, ErrorOf, InputArgs, InputOf, LoadOptions, PagedQueryFactory, QueryBehavior, QueryFactory, QueryHandle, 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";
|
|
6
6
|
declare namespace cache_d_exports {
|
|
7
|
-
export { Config, Event, Filter,
|
|
7
|
+
export { Config, Event, Filter, QueryCache, Target, TypeId, Updater, isQueryCache, layer, make };
|
|
8
8
|
}
|
|
9
9
|
export declare const TypeId = "~@raf-query/core/QueryCache";
|
|
10
10
|
export type TypeId = typeof TypeId;
|
|
@@ -46,8 +46,6 @@ export interface Filter {
|
|
|
46
46
|
readonly predicate?: (query: Query) => boolean;
|
|
47
47
|
readonly queryKey?: QueryKey;
|
|
48
48
|
}
|
|
49
|
-
/** `ensure` / `fetch` arguments: the input, then load options for paged factories. */
|
|
50
|
-
export type LoadArgs<TFactory extends QueryFactory> = InputArgs<TFactory> | [input: InputOf<TFactory>, options: LoadOptions<TFactory>];
|
|
51
49
|
/** The entries `invalidate`, `reset` and `remove` act on: one factory call, or a filter. */
|
|
52
50
|
export type Target<TFactory extends QueryFactory> = [factory: TFactory, ...args: InputArgs<TFactory>] | [filter: Filter];
|
|
53
51
|
/**
|
|
@@ -55,6 +53,8 @@ export type Target<TFactory extends QueryFactory> = [factory: TFactory, ...args:
|
|
|
55
53
|
* both with no data and with `undefined` data.
|
|
56
54
|
*/
|
|
57
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>>;
|
|
58
58
|
export interface QueryCache {
|
|
59
59
|
/** Every entry. */
|
|
60
60
|
readonly all: Effect.Effect<ReadonlyArray<Query>>;
|
|
@@ -75,7 +75,9 @@ export interface QueryCache {
|
|
|
75
75
|
* browser. The handle is marked `ensured`, so `useQuery` returns its data
|
|
76
76
|
* directly.
|
|
77
77
|
*/
|
|
78
|
-
ensure<TFactory extends QueryFactory>(factory: TFactory, ...args:
|
|
78
|
+
ensure<TFactory extends QueryFactory>(factory: TFactory, ...args: InputArgs<TFactory>): Ensured<TFactory>;
|
|
79
|
+
/** {@link ensure}, loading `options.pages` pages of a paged query. */
|
|
80
|
+
ensure<TFactory extends PagedQueryFactory>(factory: TFactory, input: InputOf<TFactory>, options: LoadOptions): Ensured<TFactory>;
|
|
79
81
|
/** Cache events from the moment the stream starts. */
|
|
80
82
|
readonly events: Stream.Stream<Event>;
|
|
81
83
|
/**
|
|
@@ -83,7 +85,9 @@ export interface QueryCache {
|
|
|
83
85
|
* stale data (on the server, only invalidated data), so the data is fresh.
|
|
84
86
|
* Fails if that request fails.
|
|
85
87
|
*/
|
|
86
|
-
fetch<TFactory extends QueryFactory>(factory: TFactory, ...args:
|
|
88
|
+
fetch<TFactory extends QueryFactory>(factory: TFactory, ...args: InputArgs<TFactory>): Fetched<TFactory>;
|
|
89
|
+
/** {@link fetch}, loading `options.pages` pages of a paged query. */
|
|
90
|
+
fetch<TFactory extends PagedQueryFactory>(factory: TFactory, input: InputOf<TFactory>, options: LoadOptions): Fetched<TFactory>;
|
|
87
91
|
/**
|
|
88
92
|
* Cached data for a factory call. `Some(undefined)` when the data itself
|
|
89
93
|
* is `undefined`.
|
package/dist/cache.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { __exportAll } from "./_virtual/_rolldown/runtime.mjs";
|
|
2
2
|
import { Platform } from "./platform.mjs";
|
|
3
3
|
import { unsafeCast } from "./cast.mjs";
|
|
4
|
-
import { listen } from "./listen.mjs";
|
|
5
4
|
import { hashKey, matchesKey } from "./key.mjs";
|
|
5
|
+
import { listen } from "./listen.mjs";
|
|
6
6
|
import { changes, emit, fetch, invalidate, isObserved, make as make$1, needsRefetch, onPlatformEvent, provide, remove, reset, revalidate, setData, setOptions, start } from "./entry.mjs";
|
|
7
7
|
import { dehydrateEntries, dehydrateStream, hydrateEntries } from "./hydration.mjs";
|
|
8
8
|
import { optionsFor } from "./options.mjs";
|
|
@@ -135,12 +135,12 @@ const make = /*#__PURE__*/ Effect.fnUntraced(function* (config = {}) {
|
|
|
135
135
|
}),
|
|
136
136
|
dehydrate: (options = {}) => Effect.sync(() => dehydrateEntries(state.entries.values(), options)),
|
|
137
137
|
dehydrateStream: (options = {}) => dehydrateStream(() => state.entries.values(), subscribeUnsafe, options),
|
|
138
|
-
ensure: (factory,
|
|
138
|
+
ensure: (factory, input, options) => Effect.flatMap(buildFor(factory, input), (entry) => load(entry, options?.pages, false).pipe(Effect.as({
|
|
139
139
|
...handleOf(entry),
|
|
140
140
|
ensured: true
|
|
141
141
|
}))),
|
|
142
142
|
events: listen(subscribeUnsafe),
|
|
143
|
-
fetch: (factory,
|
|
143
|
+
fetch: (factory, input, options) => Effect.flatMap(buildFor(factory, input), (entry) => load(entry, options?.pages, true)),
|
|
144
144
|
getData: (factory, ...args) => Effect.sync(() => {
|
|
145
145
|
const options = optionsFor(factory, args[0]);
|
|
146
146
|
const entry = state.entries.get(hashKey(options.queryKey));
|
package/dist/entry.d.mts
CHANGED
|
@@ -6,7 +6,7 @@ import { Pending, Thenable } from "./thenable.mjs";
|
|
|
6
6
|
import { FetchRequest, Query, State, SubscribeOptions } from "./query.mjs";
|
|
7
7
|
import { Cause, Clock, Context, Deferred, Effect, Scope, Stream } from "effect";
|
|
8
8
|
declare namespace entry_d_exports {
|
|
9
|
-
export { CacheState, CancelledError, Entry, TypeId, changes, emit, entryOf, fetch, hasNextPageUnsafe, hasPreviousPageUnsafe, invalidate, isObserved, isQuery, isStaleUnsafe, make, metaOf, needsRefetch, now, onPlatformEvent, provide, readUnsafe, remove, reset, resume, revalidate, setData, setOptions, start, subscribeUnsafe };
|
|
9
|
+
export { BrowserOnlyError, CacheState, CancelledError, Entry, TypeId, changes, emit, entryOf, fetch, hasNextPageUnsafe, hasPreviousPageUnsafe, invalidate, isBrowserOnly, isObserved, isQuery, isStaleUnsafe, make, metaOf, needsRefetch, now, 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,6 +19,18 @@ 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";
|
|
24
|
+
} & Readonly<A>;
|
|
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.
|
|
28
|
+
*/
|
|
29
|
+
export declare class BrowserOnlyError extends BrowserOnlyError_base<{
|
|
30
|
+
readonly hash: string;
|
|
31
|
+
}> {
|
|
32
|
+
get message(): string;
|
|
33
|
+
}
|
|
22
34
|
/**
|
|
23
35
|
* The state a cache shares with its entries. Entries are created
|
|
24
36
|
* synchronously (a render reads one), so they fork their fibers with the
|
|
@@ -89,6 +101,8 @@ export declare function make(cache: CacheState, key: QueryKey, hash: string): En
|
|
|
89
101
|
export declare function now(entry: Entry): number;
|
|
90
102
|
/** Readers are subscribed; `invalidate` and focus refetch only what is read. */
|
|
91
103
|
export declare function isObserved(entry: Entry): boolean;
|
|
104
|
+
/** A server cache's entry for an `ssr: false` query: it never runs here. */
|
|
105
|
+
export declare function isBrowserOnly(entry: Entry): boolean;
|
|
92
106
|
/** Until a factory call attaches options, `meta` comes from hydration. */
|
|
93
107
|
export declare function metaOf(entry: Entry): QueryMeta | undefined;
|
|
94
108
|
export declare function isStaleUnsafe(entry: Entry): boolean;
|
package/dist/entry.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { whenOnline } from "./platform.mjs";
|
|
2
2
|
import { unsafeCast } from "./cast.mjs";
|
|
3
|
+
import { replaceEqualDeep } from "./share.mjs";
|
|
3
4
|
import { fetchPages, isInfiniteData, nextPageParam, previousPageParam } from "./infinite.mjs";
|
|
4
5
|
import { listen } from "./listen.mjs";
|
|
5
6
|
import { scheduleNotify } from "./notify.mjs";
|
|
6
7
|
import { fromQueryFn, requestServices, runRequest } from "./request.mjs";
|
|
7
8
|
import { retrySchedule } from "./retry.mjs";
|
|
8
|
-
import { replaceEqualDeep } from "./share.mjs";
|
|
9
9
|
import { fulfilled, pending } from "./thenable.mjs";
|
|
10
10
|
import { Cause, Data, Deferred, Effect, Exit, FiberMap, Pipeable, Predicate, Schedule, Scope } from "effect";
|
|
11
11
|
//#region src/entry.ts
|
|
@@ -17,6 +17,15 @@ const TypeId = "~@raf-query/core/Query";
|
|
|
17
17
|
var CancelledError = class extends Data.TaggedError("CancelledError") {
|
|
18
18
|
message = "The query was cancelled";
|
|
19
19
|
};
|
|
20
|
+
/**
|
|
21
|
+
* Why a query with `ssr: false` has no data on the server: its promise
|
|
22
|
+
* there rejects with this, and `ensure` / `fetch` die with it.
|
|
23
|
+
*/
|
|
24
|
+
var BrowserOnlyError = class extends Data.TaggedError("BrowserOnlyError") {
|
|
25
|
+
get message() {
|
|
26
|
+
return `Query ${this.hash} runs in the browser only (ssr: false)`;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
20
29
|
const Proto = {
|
|
21
30
|
...Pipeable.Prototype,
|
|
22
31
|
[TypeId]: {
|
|
@@ -86,10 +95,11 @@ function make(cache, key, hash) {
|
|
|
86
95
|
},
|
|
87
96
|
tasks: makeTasks(cache, scope)
|
|
88
97
|
});
|
|
98
|
+
const command = (request) => Effect.suspend(() => isBrowserOnly(entry) ? Effect.void : Effect.ignore(fetch(entry, request)));
|
|
89
99
|
const commands = {
|
|
90
|
-
fetchNextPage:
|
|
91
|
-
fetchPreviousPage:
|
|
92
|
-
refetch:
|
|
100
|
+
fetchNextPage: command({ direction: "forward" }),
|
|
101
|
+
fetchPreviousPage: command({ direction: "backward" }),
|
|
102
|
+
refetch: command()
|
|
93
103
|
};
|
|
94
104
|
Object.assign(entry, { commands });
|
|
95
105
|
scheduleGc(entry);
|
|
@@ -105,6 +115,10 @@ function isObserved(entry) {
|
|
|
105
115
|
function behavior(entry, name) {
|
|
106
116
|
return entry.options?.[name] ?? entry.cache.defaults[name];
|
|
107
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;
|
|
121
|
+
}
|
|
108
122
|
/** Until a factory call attaches options, `meta` comes from hydration. */
|
|
109
123
|
function metaOf(entry) {
|
|
110
124
|
return entry.options ? behavior(entry, "meta") : entry.hydratedMeta ?? entry.cache.defaults.meta;
|
|
@@ -211,7 +225,7 @@ function fetch(entry, request = {}) {
|
|
|
211
225
|
function invalidate(entry) {
|
|
212
226
|
return Effect.suspend(() => {
|
|
213
227
|
set(entry, { isInvalidated: true });
|
|
214
|
-
if (!isObserved(entry) || !entry.options) return Effect.void;
|
|
228
|
+
if (!isObserved(entry) || !entry.options || isBrowserOnly(entry)) return Effect.void;
|
|
215
229
|
return Effect.ignore(begin(entry, { restart: true }));
|
|
216
230
|
});
|
|
217
231
|
}
|
|
@@ -230,7 +244,7 @@ function reset(entry) {
|
|
|
230
244
|
status: "pending",
|
|
231
245
|
updatedAt: 0
|
|
232
246
|
});
|
|
233
|
-
if (!entry.options || !isObserved(entry) && !entry.inFlight) return Effect.void;
|
|
247
|
+
if (!entry.options || isBrowserOnly(entry) || !isObserved(entry) && !entry.inFlight) return Effect.void;
|
|
234
248
|
return Effect.ignore(begin(entry, { restart: true }));
|
|
235
249
|
});
|
|
236
250
|
}
|
|
@@ -277,6 +291,13 @@ function remove(entry) {
|
|
|
277
291
|
*/
|
|
278
292
|
function begin(entry, request) {
|
|
279
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);
|
|
299
|
+
return Effect.die(error);
|
|
300
|
+
}
|
|
280
301
|
const options = entry.options;
|
|
281
302
|
const inFlight = entry.inFlight;
|
|
282
303
|
if (inFlight && !(request.restart && options)) return Deferred.await(inFlight);
|
|
@@ -432,8 +453,8 @@ function requestEffect(entry, options, request) {
|
|
|
432
453
|
return readSignal();
|
|
433
454
|
}
|
|
434
455
|
}));
|
|
435
|
-
const
|
|
436
|
-
return fetchPages(options,
|
|
456
|
+
const pagesOf = () => isInfiniteData(entry.state.data) ? entry.state.data : void 0;
|
|
457
|
+
return fetchPages(options, pagesOf(), request, (pageParam, direction) => attempt(entry, (readSignal) => options.queryFn({
|
|
437
458
|
direction,
|
|
438
459
|
meta,
|
|
439
460
|
pageParam,
|
|
@@ -441,7 +462,7 @@ function requestEffect(entry, options, request) {
|
|
|
441
462
|
get signal() {
|
|
442
463
|
return readSignal();
|
|
443
464
|
}
|
|
444
|
-
})));
|
|
465
|
+
})), pagesOf);
|
|
445
466
|
}
|
|
446
467
|
/**
|
|
447
468
|
* One `queryFn` call, retried per the query's policy. Every failure counts.
|
|
@@ -499,4 +520,4 @@ function scheduleStale(entry) {
|
|
|
499
520
|
entry.tasks.fork("stale", Effect.sleep(Math.max(remaining, 0) + 1).pipe(Effect.andThen(Effect.sync(() => set(entry, {})))));
|
|
500
521
|
}
|
|
501
522
|
//#endregion
|
|
502
|
-
export { CancelledError, TypeId, changes, emit, entryOf, fetch, hasNextPageUnsafe, hasPreviousPageUnsafe, invalidate, isObserved, isQuery, isStaleUnsafe, make, metaOf, needsRefetch, now, onPlatformEvent, provide, readUnsafe, remove, reset, resume, revalidate, setData, setOptions, start, subscribeUnsafe };
|
|
523
|
+
export { BrowserOnlyError, CancelledError, TypeId, changes, emit, entryOf, fetch, hasNextPageUnsafe, hasPreviousPageUnsafe, invalidate, isBrowserOnly, isObserved, isQuery, isStaleUnsafe, make, metaOf, needsRefetch, now, onPlatformEvent, provide, readUnsafe, remove, reset, resume, revalidate, setData, setOptions, start, subscribeUnsafe };
|
package/dist/hydration.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resume, revalidate, setData } from "./entry.mjs";
|
|
1
|
+
import { entryOf, isBrowserOnly, resume, revalidate, setData } from "./entry.mjs";
|
|
2
2
|
import { getUnsafe, metaUnsafe } from "./query.mjs";
|
|
3
3
|
import { Data, Effect, Queue, Stream } from "effect";
|
|
4
4
|
//#region src/hydration.ts
|
|
@@ -53,7 +53,7 @@ function dehydrateEntries(queries, options) {
|
|
|
53
53
|
const filter = options.filter ?? canDehydrate;
|
|
54
54
|
const sent = options.sent;
|
|
55
55
|
const dehydrated = [];
|
|
56
|
-
for (const query of queries) if (!sent?.has(query.hash) && filter(query)) {
|
|
56
|
+
for (const query of queries) if (!sent?.has(query.hash) && !isBrowserOnly(entryOf(query)) && filter(query)) {
|
|
57
57
|
sent?.add(query.hash);
|
|
58
58
|
dehydrated.push(dehydrateUnsafe(query, options));
|
|
59
59
|
}
|
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, QueryBehavior, QueryFactory, QueryFnResult, QueryFunctionContext, QueryHandle, QueryMeta, QueryOptions, QueryTypes, Register, RetryPolicy, ServicesOf, infiniteQueryOptions, queryOptions } from "./options.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";
|
|
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 { Thenable } 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, 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, hashKey, infiniteQueryOptions, matchesKey, queryOptions };
|
|
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, 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, hashKey, infiniteQueryOptions, matchesKey, queryOptions };
|
package/dist/infinite.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { replaceEqualDeep } from "./share.mjs";
|
|
1
2
|
import { Effect, Predicate } from "effect";
|
|
2
3
|
//#region src/infinite.ts
|
|
3
4
|
function isInfiniteData(data) {
|
|
@@ -27,16 +28,28 @@ function addPage(data, page, pageParam, direction, maxPages) {
|
|
|
27
28
|
pages: pages.slice(0, maxPages)
|
|
28
29
|
};
|
|
29
30
|
}
|
|
31
|
+
function edgeParam(data, direction) {
|
|
32
|
+
return direction === "forward" ? data.pageParams.at(-1) : data.pageParams[0];
|
|
33
|
+
}
|
|
30
34
|
/**
|
|
31
35
|
* A paged query's request. With a `direction`, adds one page at that end of
|
|
32
|
-
*
|
|
33
|
-
*
|
|
36
|
+
* the entry's data, read again with `latest` once the page loads, so data
|
|
37
|
+
* written meanwhile (`setData`, a live subscription) stays. If that data no
|
|
38
|
+
* longer ends at the page param the request started from, the write
|
|
39
|
+
* replaced the list, and the page is dropped. Without a `direction`, loads
|
|
40
|
+
* from the first page param again: as many pages as `current` has, or
|
|
41
|
+
* `pages` if that's more, stopping at the last page.
|
|
34
42
|
*/
|
|
35
|
-
const fetchPages = /*#__PURE__*/ Effect.fnUntraced(function* (options, current, request, fetchPage) {
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
const fetchPages = /*#__PURE__*/ Effect.fnUntraced(function* (options, current, request, fetchPage, latest) {
|
|
44
|
+
const direction = request.direction;
|
|
45
|
+
if (direction && current) {
|
|
46
|
+
const pageParam = direction === "forward" ? nextPageParam(options, current) : previousPageParam(options, current);
|
|
38
47
|
if (pageParam == null) return current;
|
|
39
|
-
|
|
48
|
+
const page = yield* fetchPage(pageParam, direction);
|
|
49
|
+
const now = latest() ?? current;
|
|
50
|
+
const startedFrom = edgeParam(current, direction);
|
|
51
|
+
if (replaceEqualDeep(startedFrom, edgeParam(now, direction)) !== startedFrom) return now;
|
|
52
|
+
return addPage(now, page, pageParam, direction, options.maxPages);
|
|
40
53
|
}
|
|
41
54
|
const count = Math.max(request.pages ?? 1, current?.pages.length ?? 0);
|
|
42
55
|
let data = {
|
package/dist/options.d.mts
CHANGED
|
@@ -97,6 +97,15 @@ export interface QueryBehavior {
|
|
|
97
97
|
readonly retry?: RetryPolicy;
|
|
98
98
|
/** Delay before retry number `failureCount` (1-based), in ms. */
|
|
99
99
|
readonly retryDelay?: number | ((failureCount: number, error: unknown) => number);
|
|
100
|
+
/**
|
|
101
|
+
* `false`: only the browser runs the query, for data only a browser has
|
|
102
|
+
* (permissions, device APIs). A server cache never starts it or sends it.
|
|
103
|
+
* Readers there see `isPending`, and a promise that rejects with
|
|
104
|
+
* `Query.BrowserOnlyError`: under Suspense, React renders the fallback on
|
|
105
|
+
* the server and the query in the browser. `ensure` and `fetch` on the
|
|
106
|
+
* server fail with that error. Default `true`.
|
|
107
|
+
*/
|
|
108
|
+
readonly ssr?: boolean;
|
|
100
109
|
/** How long data counts as fresh, in ms. Fresh data is never refetched. */
|
|
101
110
|
readonly staleTime?: number;
|
|
102
111
|
/**
|
|
@@ -215,7 +224,22 @@ interface FactoryResult {
|
|
|
215
224
|
* TypeScript infers an inline factory's `queryOptions` type arguments from
|
|
216
225
|
* it, and an `unknown` there would infer `unknown` services.
|
|
217
226
|
*/
|
|
218
|
-
export type QueryFactory<TServices = unknown> =
|
|
227
|
+
export type QueryFactory<TServices = unknown> = FactorySignature<unknown extends TServices ? FactoryResult : FactoryResult & ServicesField<TServices>>["call"];
|
|
228
|
+
/** A {@link QueryFactory} returning `infiniteQueryOptions(...)`. */
|
|
229
|
+
export type PagedQueryFactory<TServices = unknown> = FactorySignature<unknown extends TServices ? PagedFactoryResult : PagedFactoryResult & ServicesField<TServices>>["call"];
|
|
230
|
+
interface PagedFactoryResult extends FactoryResult {
|
|
231
|
+
readonly kind: "infinite";
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* A method, so its `input` is checked bivariantly: a factory of any input
|
|
235
|
+
* type is assignable. A verb's factory parameter is contextually typed by
|
|
236
|
+
* this, and a generic factory maker called inline
|
|
237
|
+
* (`qc.ensure(makeFactory(x), input)`) infers its own type parameters
|
|
238
|
+
* against it. An `input: never` there would infer `never` for them.
|
|
239
|
+
*/
|
|
240
|
+
interface FactorySignature<TResult> {
|
|
241
|
+
call(input: unknown): TResult;
|
|
242
|
+
}
|
|
219
243
|
/** The factory's input type; `undefined` for factories without one. */
|
|
220
244
|
export type InputOf<TFactory extends QueryFactory> = Parameters<TFactory> extends [] ? undefined : Parameters<TFactory>[0];
|
|
221
245
|
/** Arguments after the factory: the input, optional when the factory's is. */
|
|
@@ -245,11 +269,15 @@ export type ErrorOf<TFactory extends QueryFactory> = ReturnType<TFactory> extend
|
|
|
245
269
|
export type ServicesOf<TFactory extends QueryFactory> = ReturnType<TFactory> extends InfiniteQueryOptions<infer TTypes> ? ServicesIn<TTypes> : ReturnType<TFactory> extends QueryOptions<infer TTypes> ? ServicesIn<TTypes> : never;
|
|
246
270
|
/** Page type of a paged factory. */
|
|
247
271
|
export type PageOf<TFactory extends QueryFactory> = ReturnType<TFactory> extends InfiniteQueryOptions<infer TTypes> ? TTypes["page"] : never;
|
|
248
|
-
/**
|
|
249
|
-
|
|
272
|
+
/**
|
|
273
|
+
* `ensure` / `fetch` options, for {@link PagedQueryFactory paged factories}
|
|
274
|
+
* only. Not generic: an options type that depends on the factory's type stops
|
|
275
|
+
* a generic factory maker called inline from inferring.
|
|
276
|
+
*/
|
|
277
|
+
export interface LoadOptions {
|
|
250
278
|
/** Load this many pages up front (default 1). */
|
|
251
279
|
readonly pages?: number;
|
|
252
|
-
}
|
|
280
|
+
}
|
|
253
281
|
declare const factoryType: unique symbol;
|
|
254
282
|
interface HandleFields<TFactory extends QueryFactory> {
|
|
255
283
|
/** Type-only: ties the handle to its factory. Never present at runtime. */
|
package/dist/query.d.mts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { QueryKey } from "./key.mjs";
|
|
2
2
|
import { AnyQueryOptions, DataOf, ErrorOf, QueryFactory, QueryHandle, QueryMeta, ServicesOf } from "./options.mjs";
|
|
3
3
|
import { Thenable } from "./thenable.mjs";
|
|
4
|
-
import { CancelledError as CancelledError$1, TypeId as TypeId$1, entry_d_exports } from "./entry.mjs";
|
|
4
|
+
import { BrowserOnlyError as BrowserOnlyError$1, CancelledError as CancelledError$1, TypeId as TypeId$1, entry_d_exports } from "./entry.mjs";
|
|
5
5
|
import { Direction } from "./infinite.mjs";
|
|
6
6
|
import { Effect, Pipeable, Stream } from "effect";
|
|
7
7
|
declare namespace query_d_exports {
|
|
8
|
-
export { CancelledError, FetchRequest, Query, State, SubscribeOptions, TypeId, changes, fetch, fetchNextPage, fetchPreviousPage, get, getUnsafe, hasNextPageUnsafe, hasPreviousPageUnsafe, invalidate, isQuery, isStaleUnsafe, metaUnsafe, observerCountUnsafe, readUnsafe, refetch, reset, revalidateUnsafe, subscribeUnsafe };
|
|
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, revalidateUnsafe, subscribeUnsafe };
|
|
9
9
|
}
|
|
10
10
|
export declare const TypeId: typeof TypeId$1;
|
|
11
11
|
export type TypeId = typeof TypeId;
|
|
@@ -67,6 +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
72
|
export declare const isQuery: (value: unknown) => value is Query;
|
|
71
73
|
/**
|
|
72
74
|
* Start a request, or join the one in flight. Fails with the request's
|
package/dist/query.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __exportAll } from "./_virtual/_rolldown/runtime.mjs";
|
|
2
2
|
import { unsafeCast } from "./cast.mjs";
|
|
3
|
-
import { 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";
|
|
3
|
+
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";
|
|
4
4
|
import { Effect } from "effect";
|
|
5
5
|
import { dual } from "effect/Function";
|
|
6
6
|
//#region src/query.ts
|
|
@@ -13,6 +13,7 @@ import { dual } from "effect/Function";
|
|
|
13
13
|
* synchronously, for renders and external stores that can't run an Effect.
|
|
14
14
|
*/
|
|
15
15
|
var query_exports = /* @__PURE__ */ __exportAll({
|
|
16
|
+
BrowserOnlyError: () => BrowserOnlyError,
|
|
16
17
|
CancelledError: () => CancelledError,
|
|
17
18
|
TypeId: () => TypeId,
|
|
18
19
|
changes: () => changes,
|
|
@@ -36,6 +37,7 @@ var query_exports = /* @__PURE__ */ __exportAll({
|
|
|
36
37
|
});
|
|
37
38
|
const TypeId = TypeId$1;
|
|
38
39
|
const CancelledError = CancelledError$1;
|
|
40
|
+
const BrowserOnlyError = BrowserOnlyError$1;
|
|
39
41
|
const isQuery = isQuery$1;
|
|
40
42
|
function typed(effect) {
|
|
41
43
|
return unsafeCast(effect);
|
|
@@ -133,4 +135,4 @@ function observerCountUnsafe(self) {
|
|
|
133
135
|
return entryOf(self).listeners.size;
|
|
134
136
|
}
|
|
135
137
|
//#endregion
|
|
136
|
-
export { CancelledError, TypeId, changes, fetch, fetchNextPage, fetchPreviousPage, get, getUnsafe, hasNextPageUnsafe, hasPreviousPageUnsafe, invalidate, isQuery, isStaleUnsafe, metaUnsafe, observerCountUnsafe, query_exports, readUnsafe, refetch, reset, revalidateUnsafe, subscribeUnsafe };
|
|
138
|
+
export { BrowserOnlyError, CancelledError, TypeId, changes, fetch, fetchNextPage, fetchPreviousPage, get, getUnsafe, hasNextPageUnsafe, hasPreviousPageUnsafe, invalidate, isQuery, isStaleUnsafe, metaUnsafe, observerCountUnsafe, query_exports, readUnsafe, refetch, reset, revalidateUnsafe, subscribeUnsafe };
|