@raf-query/core 0.11.1 → 0.12.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.
Files changed (71) hide show
  1. package/CHANGELOG.md +11 -1
  2. package/README.md +28 -18
  3. package/dist/client.d.mts +132 -121
  4. package/dist/client.mjs +59 -162
  5. package/dist/entry.d.mts +67 -148
  6. package/dist/entry.mjs +303 -474
  7. package/dist/features/focus-refetch/focus-refetch.d.mts +15 -0
  8. package/dist/features/focus-refetch/focus-refetch.mjs +18 -0
  9. package/dist/features/polling/polling.d.mts +12 -0
  10. package/dist/features/polling/polling.mjs +35 -0
  11. package/dist/features/reconnect-refetch/reconnect-refetch.d.mts +15 -0
  12. package/dist/features/reconnect-refetch/reconnect-refetch.mjs +14 -0
  13. package/dist/features/shared.mjs +13 -0
  14. package/dist/guards.mjs +23 -0
  15. package/dist/hydration/hydration.d.mts +73 -0
  16. package/dist/hydration/hydration.mjs +128 -0
  17. package/dist/index.d.mts +18 -13
  18. package/dist/index.mjs +15 -13
  19. package/dist/infinite/infinite.d.mts +71 -0
  20. package/dist/infinite/infinite.mjs +88 -0
  21. package/dist/internal.d.mts +13 -0
  22. package/dist/internal.mjs +7 -0
  23. package/dist/keys/keys.d.mts +46 -0
  24. package/dist/keys/keys.mjs +53 -0
  25. package/dist/keys/targets.d.mts +56 -0
  26. package/dist/keys/targets.mjs +85 -0
  27. package/dist/links/retry/retry.d.mts +26 -0
  28. package/dist/links/retry/retry.mjs +51 -0
  29. package/dist/links/timeout/timeout.d.mts +9 -0
  30. package/dist/links/timeout/timeout.mjs +27 -0
  31. package/dist/load.d.mts +124 -0
  32. package/dist/load.mjs +165 -0
  33. package/dist/options.d.mts +112 -351
  34. package/dist/options.mjs +25 -41
  35. package/dist/presets.d.mts +29 -0
  36. package/dist/presets.mjs +25 -0
  37. package/dist/root.d.mts +82 -0
  38. package/dist/structural-sharing/structural-sharing.mjs +32 -0
  39. package/dist/subscribe.d.mts +15 -0
  40. package/dist/subscribe.mjs +29 -0
  41. package/dist/thenable.d.mts +13 -17
  42. package/dist/thenable.mjs +25 -6
  43. package/dist/verbs.d.mts +109 -0
  44. package/dist/verbs.mjs +87 -0
  45. package/package.json +13 -9
  46. package/dist/_virtual/_rolldown/runtime.mjs +0 -13
  47. package/dist/all-keyed.d.mts +0 -18
  48. package/dist/all-keyed.mjs +0 -19
  49. package/dist/binding.d.mts +0 -92
  50. package/dist/binding.mjs +0 -186
  51. package/dist/cache.d.mts +0 -164
  52. package/dist/cache.mjs +0 -184
  53. package/dist/controls.d.mts +0 -95
  54. package/dist/controls.mjs +0 -70
  55. package/dist/hydration.d.mts +0 -84
  56. package/dist/hydration.mjs +0 -148
  57. package/dist/infinite.d.mts +0 -5
  58. package/dist/infinite.mjs +0 -103
  59. package/dist/key.d.mts +0 -18
  60. package/dist/key.mjs +0 -36
  61. package/dist/listen.mjs +0 -19
  62. package/dist/notify.mjs +0 -21
  63. package/dist/observer.d.mts +0 -110
  64. package/dist/observer.mjs +0 -300
  65. package/dist/platform.d.mts +0 -27
  66. package/dist/platform.mjs +0 -44
  67. package/dist/query.d.mts +0 -137
  68. package/dist/query.mjs +0 -147
  69. package/dist/request.mjs +0 -47
  70. package/dist/retry.mjs +0 -25
  71. package/dist/share.mjs +0 -40
@@ -0,0 +1,15 @@
1
+ import { Feature } from "../../client.mjs";
2
+ //#region src/features/focus-refetch/focus-refetch.d.ts
3
+ /** What `focusRefetch()` reads from a query's `meta`. */
4
+ export interface FocusRefetchMeta {
5
+ /** `false`: don't refetch this query on focus. */
6
+ readonly refetchOnWindowFocus?: boolean;
7
+ }
8
+ /**
9
+ * Refetch read, stale queries when the window regains focus, except those
10
+ * with `meta: { refetchOnWindowFocus: false }`.
11
+ */
12
+ export declare function focusRefetch(): Feature<{
13
+ readonly meta: FocusRefetchMeta;
14
+ }>;
15
+ //#endregion
@@ -0,0 +1,18 @@
1
+ import { feature } from "../../client.mjs";
2
+ import { refetchStaleReads } from "../shared.mjs";
3
+ //#region src/features/focus-refetch/focus-refetch.ts
4
+ /**
5
+ * Refetch read, stale queries when the window regains focus, except those
6
+ * with `meta: { refetchOnWindowFocus: false }`.
7
+ */
8
+ function focusRefetch() {
9
+ return feature((client, signal) => {
10
+ const onFocus = () => {
11
+ if (document.visibilityState === "visible") refetchStaleReads(client, "refetchOnWindowFocus");
12
+ };
13
+ document.addEventListener("visibilitychange", onFocus, { signal });
14
+ window.addEventListener("focus", onFocus, { signal });
15
+ });
16
+ }
17
+ //#endregion
18
+ export { focusRefetch };
@@ -0,0 +1,12 @@
1
+ import { Feature } from "../../client.mjs";
2
+ //#region src/features/polling/polling.d.ts
3
+ /** What `polling()` reads from a query's `meta`. */
4
+ export interface PollingMeta {
5
+ /** Refetch every `n` ms while the query is read. */
6
+ readonly refetchInterval?: number | false;
7
+ }
8
+ /** Refetch read queries every `meta.refetchInterval` ms. */
9
+ export declare function polling(): Feature<{
10
+ readonly meta: PollingMeta;
11
+ }>;
12
+ //#endregion
@@ -0,0 +1,35 @@
1
+ import { feature } from "../../client.mjs";
2
+ import { isNumber } from "../../guards.mjs";
3
+ import { fetchEntry } from "../../entry.mjs";
4
+ import { metaOf } from "../shared.mjs";
5
+ //#region src/features/polling/polling.ts
6
+ /** Refetch read queries every `meta.refetchInterval` ms. */
7
+ function polling() {
8
+ return feature((client, signal) => {
9
+ const timers = /* @__PURE__ */ new Map();
10
+ const stop = (entry) => {
11
+ client.clock.clearTimeout(timers.get(entry));
12
+ timers.delete(entry);
13
+ };
14
+ const sync = (entry) => {
15
+ const interval = metaOf(entry, "refetchInterval");
16
+ if (!(entry.readers.size > 0 && isNumber(interval) && interval > 0 && client["~entries"].get(entry.hash) === entry)) stop(entry);
17
+ else if (!timers.has(entry)) {
18
+ const tick = () => {
19
+ timers.set(entry, client.clock.setTimeout(tick, interval));
20
+ fetchEntry(entry);
21
+ };
22
+ timers.set(entry, client.clock.setTimeout(tick, interval));
23
+ }
24
+ };
25
+ client.subscribe((event) => {
26
+ if (event.type === "readers" || event.type === "removed") sync(event.entry);
27
+ }, { signal });
28
+ for (const entry of client["~entries"].values()) sync(entry);
29
+ signal.addEventListener("abort", () => {
30
+ for (const entry of timers.keys()) stop(entry);
31
+ });
32
+ });
33
+ }
34
+ //#endregion
35
+ export { polling };
@@ -0,0 +1,15 @@
1
+ import { Feature } from "../../client.mjs";
2
+ //#region src/features/reconnect-refetch/reconnect-refetch.d.ts
3
+ /** What `reconnectRefetch()` reads from a query's `meta`. */
4
+ export interface ReconnectRefetchMeta {
5
+ /** `false`: don't refetch this query when the browser comes back online. */
6
+ readonly refetchOnReconnect?: boolean;
7
+ }
8
+ /**
9
+ * Refetch read, stale queries when the browser comes back online, except
10
+ * those with `meta: { refetchOnReconnect: false }`.
11
+ */
12
+ export declare function reconnectRefetch(): Feature<{
13
+ readonly meta: ReconnectRefetchMeta;
14
+ }>;
15
+ //#endregion
@@ -0,0 +1,14 @@
1
+ import { feature } from "../../client.mjs";
2
+ import { refetchStaleReads } from "../shared.mjs";
3
+ //#region src/features/reconnect-refetch/reconnect-refetch.ts
4
+ /**
5
+ * Refetch read, stale queries when the browser comes back online, except
6
+ * those with `meta: { refetchOnReconnect: false }`.
7
+ */
8
+ function reconnectRefetch() {
9
+ return feature((client, signal) => {
10
+ window.addEventListener("online", () => refetchStaleReads(client, "refetchOnReconnect"), { signal });
11
+ });
12
+ }
13
+ //#endregion
14
+ export { reconnectRefetch };
@@ -0,0 +1,13 @@
1
+ import { isObject } from "../guards.mjs";
2
+ import { fetchEntry, isStale } from "../entry.mjs";
3
+ //#region src/features/shared.ts
4
+ function metaOf(entry, field) {
5
+ const meta = entry.options?.meta;
6
+ if (!isObject(meta) || !(field in meta)) return;
7
+ return meta[field];
8
+ }
9
+ function refetchStaleReads(client, optOut) {
10
+ for (const entry of client["~entries"].values()) if (entry.readers.size > 0 && isStale(entry) && metaOf(entry, optOut) !== false) fetchEntry(entry);
11
+ }
12
+ //#endregion
13
+ export { metaOf, refetchStaleReads };
@@ -0,0 +1,23 @@
1
+ //#region src/guards.ts
2
+ function isFunction(value) {
3
+ return typeof value === "function";
4
+ }
5
+ /** `Array.isArray` that narrows readonly arrays and tuples too. */
6
+ function isArray(value) {
7
+ return Array.isArray(value);
8
+ }
9
+ function isNumber(value) {
10
+ return typeof value === "number";
11
+ }
12
+ function isObject(value) {
13
+ return typeof value === "object" && value !== null;
14
+ }
15
+ function isString(value) {
16
+ return typeof value === "string";
17
+ }
18
+ /** A `Response`, also one from another realm or polyfill. */
19
+ function isResponse(value) {
20
+ return Object.prototype.toString.call(value) === "[object Response]";
21
+ }
22
+ //#endregion
23
+ export { isArray, isFunction, isNumber, isObject, isResponse, isString };
@@ -0,0 +1,73 @@
1
+ import { QueryKey } from "../keys/keys.mjs";
2
+ import { Entry } from "../entry.mjs";
3
+ import { QueryClient } from "../client.mjs";
4
+ //#region src/hydration/hydration.d.ts
5
+ /** What a dehydrated pending entry's promise resolves to. */
6
+ export interface DehydratedResult {
7
+ readonly data?: unknown;
8
+ /** When the sender got the result (ms since epoch). */
9
+ readonly updatedAt: number;
10
+ }
11
+ /**
12
+ * One cache entry in transit. Settled entries carry `data` and
13
+ * `updatedAt > 0`; entries still loading carry their request's `promise`,
14
+ * so the receiver resumes it instead of fetching again.
15
+ */
16
+ export interface DehydratedEntry {
17
+ readonly data?: unknown;
18
+ readonly promise?: Promise<DehydratedResult>;
19
+ readonly queryKey: QueryKey;
20
+ /** When the data was fetched; `0` while pending. */
21
+ readonly updatedAt: number;
22
+ }
23
+ export interface DehydratedState {
24
+ readonly entries: ReadonlyArray<DehydratedEntry>;
25
+ }
26
+ export interface DehydrateOptions {
27
+ /**
28
+ * Which entries to send. Default: entries with data or a request in
29
+ * flight. An entry with neither has nothing to send and stays behind.
30
+ */
31
+ readonly filter?: (entry: Entry) => boolean;
32
+ /** Send a pending entry's error as is, instead of a `RedactedError`. */
33
+ readonly keepErrors?: boolean;
34
+ /**
35
+ * Hashes already sent in this transfer (one request). Those entries are
36
+ * skipped, and the ones sent are added.
37
+ */
38
+ readonly sent?: Set<string>;
39
+ }
40
+ /**
41
+ * What a streamed pending entry rejects with when its server request threw:
42
+ * the browser learns which query failed, not why.
43
+ */
44
+ export declare class RedactedError extends Error {
45
+ readonly name = "RedactedError";
46
+ readonly hash: string;
47
+ constructor(hash: string);
48
+ }
49
+ /** The default filter: entries with data or a request in flight. */
50
+ export declare function canDehydrate(entry: Entry): boolean;
51
+ /** Snapshot the client's entries for transfer. */
52
+ export declare function dehydrate(client: QueryClient, options?: DehydrateOptions): DehydratedState;
53
+ export interface DehydratedStream {
54
+ /** Stop: send what changed, then end `updates`. */
55
+ close(): void;
56
+ /** The entries to send first. */
57
+ readonly initial: DehydratedState;
58
+ /** Entries as they start or settle, batched per microtask. */
59
+ readonly updates: ReadableStream<DehydratedState>;
60
+ }
61
+ /**
62
+ * The cache now, then entries as they start, until `close()`. Snapshots and
63
+ * subscribes in one synchronous step, so no change falls between the two.
64
+ */
65
+ export declare function dehydrateStream(client: QueryClient, options?: DehydrateOptions): DehydratedStream;
66
+ /**
67
+ * Write dehydrated entries into a client. Existing entries only take newer
68
+ * data. A pending entry the client has nothing for resumes the sender's
69
+ * request; one that has data or a request of its own waits for the
70
+ * sender's, takes it if newer, and revalidates if the sender's failed.
71
+ */
72
+ export declare function hydrate(client: QueryClient, state: DehydratedState): void;
73
+ //#endregion
@@ -0,0 +1,128 @@
1
+ import { adopt, entryForKey, fetchEntry, isStale, write } from "../entry.mjs";
2
+ //#region src/hydration/hydration.ts
3
+ /**
4
+ * What a streamed pending entry rejects with when its server request threw:
5
+ * the browser learns which query failed, not why.
6
+ */
7
+ var RedactedError = class extends Error {
8
+ name = "RedactedError";
9
+ hash;
10
+ constructor(hash) {
11
+ super(`Query ${hash} failed on the server`);
12
+ this.hash = hash;
13
+ }
14
+ };
15
+ /** The default filter: entries with data or a request in flight. */
16
+ function canDehydrate(entry) {
17
+ const state = entry.state;
18
+ return state.hasData || state.isFetching;
19
+ }
20
+ function dehydrateEntry(entry, options) {
21
+ const state = entry.state;
22
+ const base = { queryKey: entry.key };
23
+ if (state.hasData) return {
24
+ ...base,
25
+ data: state.data,
26
+ updatedAt: state.updatedAt
27
+ };
28
+ const run = entry.run;
29
+ if (!run) return;
30
+ const promise = run.done.promise.then((outcome) => {
31
+ if (outcome.ok) return {
32
+ data: entry.state.data,
33
+ updatedAt: entry.state.updatedAt
34
+ };
35
+ throw options.keepErrors ? outcome.error : new RedactedError(entry.hash);
36
+ });
37
+ promise.catch(() => {});
38
+ return {
39
+ ...base,
40
+ promise,
41
+ updatedAt: 0
42
+ };
43
+ }
44
+ function dehydrateEntries(entries, options) {
45
+ const filter = options.filter ?? canDehydrate;
46
+ const sent = options.sent;
47
+ const dehydrated = [];
48
+ for (const entry of entries) {
49
+ const dehydratedEntry = !sent?.has(entry.hash) && filter(entry) ? dehydrateEntry(entry, options) : void 0;
50
+ if (dehydratedEntry) {
51
+ sent?.add(entry.hash);
52
+ dehydrated.push(dehydratedEntry);
53
+ }
54
+ }
55
+ return { entries: dehydrated };
56
+ }
57
+ /** Snapshot the client's entries for transfer. */
58
+ function dehydrate(client, options = {}) {
59
+ return dehydrateEntries(client["~entries"].values(), options);
60
+ }
61
+ /**
62
+ * The cache now, then entries as they start, until `close()`. Snapshots and
63
+ * subscribes in one synchronous step, so no change falls between the two.
64
+ */
65
+ function dehydrateStream(client, options = {}) {
66
+ const send = {
67
+ ...options,
68
+ sent: options.sent ?? /* @__PURE__ */ new Set()
69
+ };
70
+ const unsubscribe = new AbortController();
71
+ let controller;
72
+ const updates = new ReadableStream({ start(streamController) {
73
+ controller = streamController;
74
+ } });
75
+ let batch;
76
+ const flush = () => {
77
+ const changed = batch;
78
+ batch = void 0;
79
+ if (!changed) return;
80
+ const state = dehydrateEntries(changed, send);
81
+ if (state.entries.length > 0) controller?.enqueue(state);
82
+ };
83
+ client.subscribe((event) => {
84
+ if (event.type === "removed" || send.sent.has(event.entry.hash)) return;
85
+ if (!batch) {
86
+ batch = /* @__PURE__ */ new Set();
87
+ queueMicrotask(flush);
88
+ }
89
+ batch.add(event.entry);
90
+ }, { signal: unsubscribe.signal });
91
+ return {
92
+ close() {
93
+ if (unsubscribe.signal.aborted) return;
94
+ flush();
95
+ unsubscribe.abort();
96
+ controller?.close();
97
+ },
98
+ initial: dehydrate(client, send),
99
+ updates
100
+ };
101
+ }
102
+ function revalidate(entry) {
103
+ if (entry.options && entry.readers.size > 0 && isStale(entry)) fetchEntry(entry);
104
+ }
105
+ /** Take the sender's data if it's newer than the entry's. */
106
+ function takeNewer(entry, result) {
107
+ if (!entry.state.hasData || entry.state.updatedAt < result.updatedAt) write(entry, result.data, result.updatedAt, entry.client["~seq"]);
108
+ else revalidate(entry);
109
+ }
110
+ /**
111
+ * Write dehydrated entries into a client. Existing entries only take newer
112
+ * data. A pending entry the client has nothing for resumes the sender's
113
+ * request; one that has data or a request of its own waits for the
114
+ * sender's, takes it if newer, and revalidates if the sender's failed.
115
+ */
116
+ function hydrate(client, state) {
117
+ for (const sent of state.entries) {
118
+ const entry = entryForKey(client, sent.queryKey);
119
+ if (sent.promise === void 0) takeNewer(entry, sent);
120
+ else {
121
+ const result = Promise.resolve(sent.promise);
122
+ if (!entry.state.hasData && !entry.run) adopt(entry, result);
123
+ else result.then((settled) => takeNewer(entry, settled), () => revalidate(entry));
124
+ }
125
+ }
126
+ }
127
+ //#endregion
128
+ export { RedactedError, canDehydrate, dehydrate, dehydrateStream, hydrate };
package/dist/index.d.mts CHANGED
@@ -1,13 +1,18 @@
1
- import { Settled, allKeyed } from "./all-keyed.mjs";
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, ThrowOnErrorOf, infiniteQueryOptions, queryOptions } from "./options.mjs";
4
- import { platform_d_exports } from "./platform.mjs";
5
- import { Pending, Thenable, fulfilled, pending } from "./thenable.mjs";
6
- import { query_d_exports } from "./query.mjs";
7
- import { DehydrateOptions, DehydratedQuery, DehydratedResult, DehydratedState, DehydratedStream, HydrateOptions, RedactedError, canDehydrate, dehydrateQuery } from "./hydration.mjs";
8
- import { cache_d_exports } from "./cache.mjs";
9
- import { QueryClient, QueryClientConfig, dehydrate, hydrate } from "./client.mjs";
10
- import { observer_d_exports } from "./observer.mjs";
11
- import { HasTypedError, PagingControls, PromiseControls, QueryControls, ReadValue, ThrowsOnError, UseQueryControls, UseQueryOptions, UseQueryThrowOptions, promiseControls, resultThenable, throwsOnError } from "./controls.mjs";
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 ThrowOnErrorOf, type ThrowsOnError, type UseQueryControls, type UseQueryOptions, type UseQueryThrowOptions, allKeyed, canDehydrate, dehydrate, dehydrateQuery, fulfilled, hashKey, hydrate, infiniteQueryOptions, matchesKey, pending, promiseControls, queryOptions, resultThenable, throwsOnError };
1
+ import { Group, QueryKey, group } from "./keys/keys.mjs";
2
+ import { QueryMeta } from "./root.mjs";
3
+ import { QueryInfo, Target } from "./keys/targets.mjs";
4
+ import { DataOf, InfiniteQueryFactory, InputOf, QueryFactory, QueryFunctionContext, QueryOptions, QueryOptionsBuilder, SingleQueryFactory, StreamOptions, bindQueryOptions, queryOptions } from "./options.mjs";
5
+ import { Thenable } from "./thenable.mjs";
6
+ import { abortError } from "./entry.mjs";
7
+ import { Clock, Feature, Link, Operation, QueryClient, QueryClientConfig, createQueryClient, feature, link } from "./client.mjs";
8
+ import { focusRefetch } from "./features/focus-refetch/focus-refetch.mjs";
9
+ import { reconnectRefetch } from "./features/reconnect-refetch/reconnect-refetch.mjs";
10
+ import { polling } from "./features/polling/polling.mjs";
11
+ import { DehydrateOptions, DehydratedEntry, DehydratedResult, DehydratedState, DehydratedStream, RedactedError, canDehydrate, dehydrate, dehydrateStream, hydrate } from "./hydration/hydration.mjs";
12
+ import { InfiniteData, InfiniteQueryFunctionContext, InfiniteQueryOptions, InfiniteQueryOptionsBuilder, bindInfiniteQueryOptions, infiniteQueryOptions } from "./infinite/infinite.mjs";
13
+ import { RetryOptions, retry } from "./links/retry/retry.mjs";
14
+ import { QueryTimeoutError, timeout } from "./links/timeout/timeout.mjs";
15
+ import { LoadEntry, LoadEntryOptions, Loaded, QueryHandle, load, prefetch, revalidate, skipToken, swr, waterfallHandle } from "./load.mjs";
16
+ import { Recommended, recommended } from "./presets.mjs";
17
+ import { ClientFor, PartialInput, getData, invalidateAll, invalidateMany, invalidateOne, isFetching, removeAll, removeMany, removeOne, resetAll, resetMany, resetOne, setData } from "./verbs.mjs";
18
+ export { type ClientFor, type Clock, type DataOf, type DehydrateOptions, type DehydratedEntry, type DehydratedResult, type DehydratedState, type DehydratedStream, type Feature, type Group, type InfiniteData, type InfiniteQueryFactory, type InfiniteQueryFunctionContext, type InfiniteQueryOptions, type InfiniteQueryOptionsBuilder, type InputOf, type Link, type LoadEntry, type LoadEntryOptions, type Loaded, type Operation, type PartialInput, type QueryClient, type QueryClientConfig, type QueryFactory, type QueryFunctionContext, type QueryHandle, type QueryInfo, type QueryKey, type QueryMeta, type QueryOptions, type QueryOptionsBuilder, QueryTimeoutError, type Recommended, RedactedError, type RetryOptions, type SingleQueryFactory, type StreamOptions, type Target, type Thenable, abortError, bindInfiniteQueryOptions, bindQueryOptions, canDehydrate, createQueryClient, dehydrate, dehydrateStream, feature, focusRefetch, getData, group, hydrate, infiniteQueryOptions, invalidateAll, invalidateMany, invalidateOne, isFetching, link, load, polling, prefetch, queryOptions, recommended, reconnectRefetch, removeAll, removeMany, removeOne, resetAll, resetMany, resetOne, retry, revalidate, setData, skipToken, swr, timeout, waterfallHandle };
package/dist/index.mjs CHANGED
@@ -1,13 +1,15 @@
1
- import { allKeyed } from "./all-keyed.mjs";
2
- import { hashKey, matchesKey } from "./key.mjs";
3
- import { platform_exports } from "./platform.mjs";
4
- import { fulfilled, pending } from "./thenable.mjs";
5
- import { query_exports } from "./query.mjs";
6
- import { RedactedError, canDehydrate, dehydrateQuery } from "./hydration.mjs";
7
- import { infiniteQueryOptions, queryOptions } from "./options.mjs";
8
- import { cache_exports } from "./cache.mjs";
9
- import { QueryClient, dehydrate, hydrate } from "./client.mjs";
10
- import { promiseControls, resultThenable, throwsOnError } from "./controls.mjs";
11
- import { observer_exports } from "./observer.mjs";
12
- import { binding_exports } from "./binding.mjs";
13
- export { platform_exports as Platform, query_exports as Query, binding_exports as QueryBinding, cache_exports as QueryCache, QueryClient, observer_exports as QueryObserver, RedactedError, allKeyed, canDehydrate, dehydrate, dehydrateQuery, fulfilled, hashKey, hydrate, infiniteQueryOptions, matchesKey, pending, promiseControls, queryOptions, resultThenable, throwsOnError };
1
+ import { createQueryClient, feature, link } from "./client.mjs";
2
+ import { group } from "./keys/keys.mjs";
3
+ import { bindQueryOptions, queryOptions } from "./options.mjs";
4
+ import { abortError } from "./entry.mjs";
5
+ import { focusRefetch } from "./features/focus-refetch/focus-refetch.mjs";
6
+ import { reconnectRefetch } from "./features/reconnect-refetch/reconnect-refetch.mjs";
7
+ import { polling } from "./features/polling/polling.mjs";
8
+ import { RedactedError, canDehydrate, dehydrate, dehydrateStream, hydrate } from "./hydration/hydration.mjs";
9
+ import { bindInfiniteQueryOptions, infiniteQueryOptions } from "./infinite/infinite.mjs";
10
+ import { retry } from "./links/retry/retry.mjs";
11
+ import { QueryTimeoutError, timeout } from "./links/timeout/timeout.mjs";
12
+ import { load, prefetch, revalidate, skipToken, swr, waterfallHandle } from "./load.mjs";
13
+ import { recommended } from "./presets.mjs";
14
+ import { getData, invalidateAll, invalidateMany, invalidateOne, isFetching, removeAll, removeMany, removeOne, resetAll, resetMany, resetOne, setData } from "./verbs.mjs";
15
+ export { QueryTimeoutError, RedactedError, abortError, bindInfiniteQueryOptions, bindQueryOptions, canDehydrate, createQueryClient, dehydrate, dehydrateStream, feature, focusRefetch, getData, group, hydrate, infiniteQueryOptions, invalidateAll, invalidateMany, invalidateOne, isFetching, link, load, polling, prefetch, queryOptions, recommended, reconnectRefetch, removeAll, removeMany, removeOne, resetAll, resetMany, resetOne, retry, revalidate, setData, skipToken, swr, timeout, waterfallHandle };
@@ -0,0 +1,71 @@
1
+ import { QueryKey } from "../keys/keys.mjs";
2
+ import { DefaultTypes, RootOf, RootTypes } from "../root.mjs";
3
+ import { BaseOptions, FromQueryFn, QueryFunctionContext, QueryOptions } from "../options.mjs";
4
+ import { Operation } from "../client.mjs";
5
+ //#region src/infinite/infinite.d.ts
6
+ /** A paged query's data. */
7
+ export interface InfiniteData<TPage, TParam = unknown> {
8
+ readonly pageParams: ReadonlyArray<TParam>;
9
+ readonly pages: ReadonlyArray<TPage>;
10
+ }
11
+ export interface InfiniteQueryFunctionContext<TKey extends QueryKey, TParam> extends QueryFunctionContext<TKey> {
12
+ readonly direction: "backward" | "forward";
13
+ readonly pageParam: TParam;
14
+ }
15
+ type PageParamFn<TPage, TParam> = (page: TPage, pages: ReadonlyArray<TPage>, pageParam: TParam) => TParam | null | undefined;
16
+ interface InfiniteOptions<TKey extends QueryKey, TPage, TParam, TData, TTypes extends RootTypes = RootTypes> extends BaseOptions<TKey, TTypes> {
17
+ readonly getNextPageParam: PageParamFn<TPage, TParam>;
18
+ readonly getPreviousPageParam?: PageParamFn<TPage, TParam>;
19
+ readonly initialPageParam: TParam;
20
+ /** Keep at most this many pages, dropping from the other end. */
21
+ readonly maxPages?: number;
22
+ readonly select?: (data: InfiniteData<TPage, TParam>) => TData;
23
+ }
24
+ /** What `infiniteQueryOptions` returns. */
25
+ export type InfiniteQueryOptions<TKey extends QueryKey = QueryKey, TPage = unknown, TParam = unknown, TData = InfiniteData<TPage, TParam>, TTypes extends RootTypes = RootTypes> = QueryOptions<TKey, InfiniteData<TPage, TParam>, TData, TTypes> & Pick<InfiniteOptions<TKey, TPage, TParam, TData, TTypes>, "getNextPageParam" | "getPreviousPageParam" | "initialPageParam" | "maxPages"> & {
26
+ readonly "~run": (op: Operation) => Promise<unknown>;
27
+ };
28
+ /** `infiniteQueryOptions`, with `meta` checked against the root `TTypes`. */
29
+ export interface InfiniteQueryOptionsBuilder<TTypes extends RootTypes> {
30
+ <const TKey extends QueryKey, TPage, TParam, TData = InfiniteData<TPage, TParam>>(options: InfiniteOptions<TKey, FromQueryFn<TPage>, TParam, TData, TTypes> & {
31
+ readonly queryFn: (context: InfiniteQueryFunctionContext<TKey, TParam>) => PromiseLike<TPage> | TPage;
32
+ }): InfiniteQueryOptions<TKey, TPage, TParam, TData, TTypes>;
33
+ }
34
+ /**
35
+ * Typed options for a paged query factory. Readers get `{ pages, pageParams }`
36
+ * and, on their state, `fetchNextPage` and `fetchPreviousPage`:
37
+ *
38
+ * ```ts
39
+ * export const issueList = (input: { status: Status }) =>
40
+ * infiniteQueryOptions({
41
+ * queryKey: issues("list", input),
42
+ * queryFn: ({ pageParam, signal }) => listIssues({ ...input, cursor: pageParam }, { signal }),
43
+ * initialPageParam: 0,
44
+ * getNextPageParam: (lastPage) => lastPage.nextCursor,
45
+ * });
46
+ * ```
47
+ *
48
+ * Its `meta` is any record. To check `meta` against a client's links and
49
+ * features, use the builder {@link bindInfiniteQueryOptions} returns.
50
+ */
51
+ export declare const infiniteQueryOptions: InfiniteQueryOptionsBuilder<DefaultTypes>;
52
+ /**
53
+ * `infiniteQueryOptions` bound to a root, like `bindQueryOptions`. Bind it
54
+ * next to `queryOptions`, in apps that page:
55
+ *
56
+ * ```ts
57
+ * // raf.ts
58
+ * export const infiniteQueryOptions = bindInfiniteQueryOptions<typeof makeQueryClient>();
59
+ * ```
60
+ */
61
+ export declare function bindInfiniteQueryOptions<T>(): InfiniteQueryOptionsBuilder<RootOf<T>>;
62
+ interface PagedSource {
63
+ readonly getNextPageParam: PageParamFn<unknown, unknown>;
64
+ readonly getPreviousPageParam?: PageParamFn<unknown, unknown>;
65
+ readonly initialPageParam: unknown;
66
+ readonly maxPages?: number;
67
+ readonly queryFn: (context: InfiniteQueryFunctionContext<QueryKey, unknown>) => unknown;
68
+ }
69
+ /** The param of the page after (or before) `data`, or `undefined` at the end. */
70
+ export declare function pageParamAfter(options: Pick<PagedSource, "getNextPageParam" | "getPreviousPageParam">, data: InfiniteData<unknown>, direction: "next" | "previous"): unknown;
71
+ //#endregion
@@ -0,0 +1,88 @@
1
+ //#region src/infinite/infinite.ts
2
+ /**
3
+ * Typed options for a paged query factory. Readers get `{ pages, pageParams }`
4
+ * and, on their state, `fetchNextPage` and `fetchPreviousPage`:
5
+ *
6
+ * ```ts
7
+ * export const issueList = (input: { status: Status }) =>
8
+ * infiniteQueryOptions({
9
+ * queryKey: issues("list", input),
10
+ * queryFn: ({ pageParam, signal }) => listIssues({ ...input, cursor: pageParam }, { signal }),
11
+ * initialPageParam: 0,
12
+ * getNextPageParam: (lastPage) => lastPage.nextCursor,
13
+ * });
14
+ * ```
15
+ *
16
+ * Its `meta` is any record. To check `meta` against a client's links and
17
+ * features, use the builder {@link bindInfiniteQueryOptions} returns.
18
+ */
19
+ const infiniteQueryOptions = (options) => ({
20
+ ...options,
21
+ "~run": (op) => runPages(op, options)
22
+ });
23
+ /**
24
+ * `infiniteQueryOptions` bound to a root, like `bindQueryOptions`. Bind it
25
+ * next to `queryOptions`, in apps that page:
26
+ *
27
+ * ```ts
28
+ * // raf.ts
29
+ * export const infiniteQueryOptions = bindInfiniteQueryOptions<typeof makeQueryClient>();
30
+ * ```
31
+ */
32
+ function bindInfiniteQueryOptions() {
33
+ return infiniteQueryOptions;
34
+ }
35
+ /** The param of the page after (or before) `data`, or `undefined` at the end. */
36
+ function pageParamAfter(options, data, direction) {
37
+ const forward = direction === "next";
38
+ const index = forward ? data.pages.length - 1 : 0;
39
+ const page = data.pages[index];
40
+ const getParam = forward ? options.getNextPageParam : options.getPreviousPageParam;
41
+ if (page === void 0 || !getParam) return;
42
+ return getParam(page, data.pages, data.pageParams[index]) ?? void 0;
43
+ }
44
+ async function runPages(op, source) {
45
+ const fetchPage = (pageParam, direction) => Promise.resolve(source.queryFn({
46
+ direction,
47
+ meta: op.meta,
48
+ pageParam,
49
+ queryKey: op.queryKey,
50
+ signal: op.signal
51
+ }));
52
+ const previous = op.hasData ? op.data : void 0;
53
+ const direction = op.direction;
54
+ if (previous && direction) {
55
+ const pageParam = pageParamAfter(source, previous, direction);
56
+ if (pageParam === void 0) return previous;
57
+ const page = await fetchPage(pageParam, direction === "next" ? "forward" : "backward");
58
+ const max = source.maxPages ?? Infinity;
59
+ return direction === "next" ? {
60
+ pageParams: [...previous.pageParams, pageParam].slice(-max),
61
+ pages: [...previous.pages, page].slice(-max)
62
+ } : {
63
+ pageParams: [pageParam, ...previous.pageParams].slice(0, max),
64
+ pages: [page, ...previous.pages].slice(0, max)
65
+ };
66
+ }
67
+ const count = previous?.pages.length ?? op.pages ?? 1;
68
+ const pages = [];
69
+ const pageParams = [];
70
+ let pageParam = previous?.pageParams[0] ?? source.initialPageParam;
71
+ while (pages.length < count) {
72
+ const page = await fetchPage(pageParam, "forward");
73
+ pages.push(page);
74
+ pageParams.push(pageParam);
75
+ const next = pageParamAfter(source, {
76
+ pageParams,
77
+ pages
78
+ }, "next");
79
+ if (next === void 0) break;
80
+ pageParam = next;
81
+ }
82
+ return {
83
+ pageParams,
84
+ pages
85
+ };
86
+ }
87
+ //#endregion
88
+ export { bindInfiniteQueryOptions, infiniteQueryOptions, pageParamAfter };
@@ -0,0 +1,13 @@
1
+ import { AnyFactory, hashKey } from "./keys/keys.mjs";
2
+ import { Decl, DefaultTypes, MetaOf, RootOf, RootTypes } from "./root.mjs";
3
+ import { AnyTarget } from "./keys/targets.mjs";
4
+ import { fulfilled, mapThenable, pending, rejected } from "./thenable.mjs";
5
+ import { Entry, EntryState, entryOf, fetchEntry, isInvalidated, isStale, remove, reset, subscribeEntry } from "./entry.mjs";
6
+ import { AnyFeature, AnyLink, ClientEvent, mount, systemClock } from "./client.mjs";
7
+ import { FocusRefetchMeta } from "./features/focus-refetch/focus-refetch.mjs";
8
+ import { ReconnectRefetchMeta } from "./features/reconnect-refetch/reconnect-refetch.mjs";
9
+ import { PollingMeta } from "./features/polling/polling.mjs";
10
+ import { pageParamAfter } from "./infinite/infinite.mjs";
11
+ import { RetryMeta } from "./links/retry/retry.mjs";
12
+ import { LoadRecord, isWaterfallHandle, loadsOf, readData, startIfStale } from "./load.mjs";
13
+ export { type AnyFactory, type AnyFeature, type AnyLink, type AnyTarget, type ClientEvent, type Decl, type DefaultTypes, type Entry, type EntryState, type FocusRefetchMeta, type LoadRecord, type MetaOf, type PollingMeta, type ReconnectRefetchMeta, type RetryMeta, type RootOf, type RootTypes, entryOf, fetchEntry, fulfilled, hashKey, isInvalidated, isStale, isWaterfallHandle, loadsOf, mapThenable, mount, pageParamAfter, pending, readData, rejected, remove, reset, startIfStale, subscribeEntry, systemClock };
@@ -0,0 +1,7 @@
1
+ import { mount, systemClock } from "./client.mjs";
2
+ import { hashKey } from "./keys/keys.mjs";
3
+ import { fulfilled, mapThenable, pending, rejected } from "./thenable.mjs";
4
+ import { entryOf, fetchEntry, isInvalidated, isStale, remove, reset, subscribeEntry } from "./entry.mjs";
5
+ import { pageParamAfter } from "./infinite/infinite.mjs";
6
+ import { isWaterfallHandle, loadsOf, readData, startIfStale } from "./load.mjs";
7
+ export { entryOf, fetchEntry, fulfilled, hashKey, isInvalidated, isStale, isWaterfallHandle, loadsOf, mapThenable, mount, pageParamAfter, pending, readData, rejected, remove, reset, startIfStale, subscribeEntry, systemClock };