@raf-query/core 0.11.0 → 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 +18 -2
  2. package/README.md +28 -18
  3. package/dist/client.d.mts +132 -119
  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 -338
  34. package/dist/options.mjs +25 -36
  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 -93
  54. package/dist/controls.mjs +0 -69
  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
package/dist/controls.mjs DELETED
@@ -1,69 +0,0 @@
1
- import { fulfilled, pending } from "./thenable.mjs";
2
- import { returnsEffectUnsafe } from "./query.mjs";
3
- import { Effect, Result } from "effect";
4
- //#region src/controls.ts
5
- /**
6
- * What a framework binding's `useQuery` returns next to the data: the
7
- * observer's result with Promise commands, and the types every binding
8
- * shares. The React, Svelte and Vue packages build their reads on this.
9
- */
10
- /**
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`.
15
- */
16
- function throwsOnError(query, throwOnError) {
17
- return throwOnError || returnsEffectUnsafe(query) === false;
18
- }
19
- const commands = /* @__PURE__ */ new WeakMap();
20
- /** One stable Promise function per command Effect, so identities track the query's. */
21
- function commandFor(effect) {
22
- let command = commands.get(effect);
23
- if (!command) {
24
- command = () => Effect.runPromise(effect);
25
- commands.set(effect, command);
26
- }
27
- return command;
28
- }
29
- /**
30
- * `result`, with the observer's command Effects as Promise functions. Reads
31
- * of every other property go through to `result`, so a tracked result
32
- * (`QueryObserver.trackResult`) stays tracked. For bindings.
33
- */
34
- function promiseControls(result) {
35
- return new Proxy(result, { get: (target, name, receiver) => {
36
- if (name === "fetchNextPage" || name === "fetchPreviousPage" || name === "refetch") return commandFor(target[name]);
37
- return Reflect.get(target, name, receiver);
38
- } });
39
- }
40
- /**
41
- * One `Result` thenable per data thenable, so readers see a stable identity
42
- * across re-renders the same way they do for the data promise.
43
- */
44
- const resultThenables = /* @__PURE__ */ new WeakMap();
45
- /**
46
- * A thenable that fulfills with a `Result` when `promise` settles, for reads
47
- * that don't throw (`throwOnError: false`). Settled already when `promise`
48
- * is, and the same thenable for the same `promise`. For bindings.
49
- */
50
- function resultThenable(promise) {
51
- const cached = resultThenables.get(promise);
52
- if (cached) return cached;
53
- let next;
54
- if (promise.status === "fulfilled") next = fulfilled(Result.succeed(promise.value));
55
- else if (promise.status === "rejected") next = fulfilled(Result.fail(promise.reason));
56
- else {
57
- const deferred = pending();
58
- promise.then((value) => {
59
- deferred.resolve(Result.succeed(value));
60
- }, (error) => {
61
- deferred.resolve(Result.fail(error));
62
- });
63
- next = deferred.promise;
64
- }
65
- resultThenables.set(promise, next);
66
- return next;
67
- }
68
- //#endregion
69
- export { promiseControls, resultThenable, throwsOnError };
@@ -1,84 +0,0 @@
1
- import { QueryKey } from "./key.mjs";
2
- import { QueryFactory, QueryMeta } from "./options.mjs";
3
- import { Query, query_d_exports } from "./query.mjs";
4
- import "./entry.mjs";
5
- import "./cache.mjs";
6
- import { Cause, Effect, Scope, Stream } from "effect";
7
- //#region src/hydration.d.ts
8
- /** What a dehydrated pending query's promise resolves to. */
9
- export interface DehydratedResult {
10
- readonly data?: unknown;
11
- /** When the sender got `data` (ms since epoch). */
12
- readonly updatedAt: number;
13
- }
14
- /**
15
- * One cache entry in transit. Settled entries carry `data`; entries still
16
- * loading their first data carry the request's `promise`, so the receiving
17
- * cache resumes it instead of fetching again.
18
- */
19
- export interface DehydratedQuery {
20
- readonly data?: unknown;
21
- /** Whether the sender's `queryFn` returned an Effect, when it ran there. */
22
- readonly effect?: boolean;
23
- readonly key: QueryKey;
24
- /** The query's `meta`, for receivers that haven't called its factory. */
25
- readonly meta?: QueryMeta;
26
- readonly promise?: Promise<DehydratedResult>;
27
- /** When `data` was fetched; `0` while pending. */
28
- readonly updatedAt: number;
29
- }
30
- export interface DehydratedState {
31
- readonly queries: ReadonlyArray<DehydratedQuery>;
32
- }
33
- /** The cache now, then entries as they start or settle. */
34
- export interface DehydratedStream {
35
- /** The entries to send first. */
36
- readonly initial: DehydratedState;
37
- /**
38
- * Later entries, in batches. Ends once the scope `dehydrateStream` ran in
39
- * closes, after a last batch of what changed before. One consumer only.
40
- */
41
- readonly updates: Stream.Stream<DehydratedState>;
42
- }
43
- export interface DehydrateOptions {
44
- /**
45
- * Which entries to send. Default: entries with data or a request in
46
- * flight ({@link canDehydrate}).
47
- */
48
- readonly filter?: (query: Query) => boolean;
49
- /**
50
- * Send a pending query's rejection as-is. By default the receiving side
51
- * gets a {@link RedactedError}, so server errors don't leak into the page;
52
- * its error boundary can still retry on the client.
53
- */
54
- readonly keepErrors?: boolean;
55
- /**
56
- * Hashes of entries sent already, shared by every dehydration of one
57
- * transfer (e.g. one request). Those entries are skipped, and the ones
58
- * sent are added.
59
- */
60
- readonly sent?: Set<string>;
61
- /** Transform data before it is serialized. */
62
- readonly serializeData?: (data: unknown) => unknown;
63
- }
64
- export interface HydrateOptions {
65
- /** Reverse `serializeData`. */
66
- readonly deserializeData?: (data: unknown) => unknown;
67
- }
68
- declare const RedactedError_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 & {
69
- readonly _tag: "RedactedError";
70
- } & Readonly<A>;
71
- /**
72
- * What a dehydrated pending query rejects with when its request failed and
73
- * `keepErrors` is off: the receiving side learns which query failed, not why.
74
- */
75
- export declare class RedactedError extends RedactedError_base<{
76
- readonly hash: string;
77
- }> {
78
- get message(): string;
79
- }
80
- /** The default dehydrate filter: entries with data or a request in flight. */
81
- export declare function canDehydrate<TFactory extends QueryFactory>(query: Query<TFactory>): boolean;
82
- /** Snapshot one entry for transfer. */
83
- export declare function dehydrateQuery<TFactory extends QueryFactory>(query: Query<TFactory>, options?: DehydrateOptions): Effect.Effect<DehydratedQuery>;
84
- //#endregion
@@ -1,148 +0,0 @@
1
- import { entryOf, isDisabled, resume, revalidate, setData } from "./entry.mjs";
2
- import { getUnsafe, metaUnsafe, returnsEffectUnsafe } from "./query.mjs";
3
- import { Data, Effect, Queue, Stream } from "effect";
4
- //#region src/hydration.ts
5
- /**
6
- * What a dehydrated pending query rejects with when its request failed and
7
- * `keepErrors` is off: the receiving side learns which query failed, not why.
8
- */
9
- var RedactedError = class extends Data.TaggedError("RedactedError") {
10
- get message() {
11
- return `Query ${this.hash} failed`;
12
- }
13
- };
14
- const noop = () => {};
15
- const identity = (value) => value;
16
- /** The default dehydrate filter: entries with data or a request in flight. */
17
- function canDehydrate(query) {
18
- const state = getUnsafe(query);
19
- return state.hasData || state.isFetching;
20
- }
21
- function dehydrateUnsafe(query, options) {
22
- const sent = dehydrateState(query, options);
23
- const effect = returnsEffectUnsafe(query);
24
- return effect === void 0 ? sent : {
25
- ...sent,
26
- effect
27
- };
28
- }
29
- /** {@link dehydrateUnsafe} without `effect`. */
30
- function dehydrateState(query, options) {
31
- const state = getUnsafe(query);
32
- const serialize = options.serializeData ?? identity;
33
- const meta = metaUnsafe(query);
34
- const sent = meta === void 0 ? { key: query.key } : {
35
- key: query.key,
36
- meta
37
- };
38
- if (state.hasData) return {
39
- ...sent,
40
- data: serialize(state.data),
41
- updatedAt: state.updatedAt
42
- };
43
- const promise = state.promise.then((data) => ({
44
- data: serialize(data),
45
- updatedAt: getUnsafe(query).updatedAt
46
- }), (error) => {
47
- throw options.keepErrors ? error : new RedactedError({ hash: query.hash });
48
- });
49
- promise.catch(noop);
50
- return {
51
- ...sent,
52
- promise,
53
- updatedAt: 0
54
- };
55
- }
56
- /** Snapshot one entry for transfer. */
57
- function dehydrateQuery(query, options = {}) {
58
- return Effect.sync(() => dehydrateUnsafe(query, options));
59
- }
60
- /** Dehydrate the entries `options` selects, recording them in `options.sent`. */
61
- function dehydrateEntries(queries, options) {
62
- const filter = options.filter ?? canDehydrate;
63
- const sent = options.sent;
64
- const dehydrated = [];
65
- for (const query of queries) if (!sent?.has(query.hash) && !isDisabled(entryOf(query)) && filter(query)) {
66
- sent?.add(query.hash);
67
- dehydrated.push(dehydrateUnsafe(query, options));
68
- }
69
- return { queries: dehydrated };
70
- }
71
- /**
72
- * Snapshots `queries()` and subscribes in the same synchronous step, so no
73
- * change falls between the two. Changed entries are collected for a
74
- * microtask, so entries that settle together share a batch, and the batch is
75
- * handed to the reader before that microtask ends: ahead of the Suspense
76
- * boundaries React resumes for those entries.
77
- */
78
- const dehydrateStream = /*#__PURE__*/ Effect.fnUntraced(function* (queries, subscribe, options) {
79
- const sent = options.sent ?? /* @__PURE__ */ new Set();
80
- const send = {
81
- ...options,
82
- sent
83
- };
84
- const queue = yield* Queue.unbounded();
85
- let batch;
86
- const flush = () => {
87
- const changed = batch;
88
- batch = void 0;
89
- if (!changed) return;
90
- const state = dehydrateEntries(changed.values(), send);
91
- if (state.queries.length > 0) {
92
- Queue.offerUnsafe(queue, state);
93
- Queue.flushUnsafe(queue);
94
- }
95
- };
96
- yield* Effect.acquireRelease(Effect.sync(() => subscribe((event) => {
97
- if (event.type === "removed" || sent.has(event.query.hash)) return;
98
- if (!batch) {
99
- batch = /* @__PURE__ */ new Map();
100
- queueMicrotask(flush);
101
- }
102
- batch.set(event.query.hash, event.query);
103
- })), (unsubscribe) => Effect.sync(() => {
104
- flush();
105
- unsubscribe();
106
- Queue.endUnsafe(queue);
107
- }));
108
- return {
109
- initial: dehydrateEntries(queries(), send),
110
- updates: Stream.fromQueue(queue)
111
- };
112
- });
113
- /**
114
- * Take the sender's data if it's newer than the entry's. An entry that keeps
115
- * its own (the sender's is older, as in a router's cached payload) was asked
116
- * for again, so it revalidates if stale, as `prefetch` would.
117
- */
118
- function takeNewer(entry, data, updatedAt) {
119
- const current = entry.state;
120
- if (!current.hasData || current.updatedAt < updatedAt) setData(entry, data, updatedAt);
121
- else revalidate(entry);
122
- }
123
- /**
124
- * Write dehydrated entries into a cache. Existing entries only take newer
125
- * data. A pending entry the cache has nothing for resumes the sender's
126
- * request. One that has data, or a request of its own, waits for the
127
- * sender's instead of fetching again, and then takes whichever is newer;
128
- * if the sender's failed, it revalidates.
129
- */
130
- function hydrateEntries(entryFor, state, options) {
131
- const deserialize = options.deserializeData ?? identity;
132
- for (const query of state.queries) {
133
- const entry = entryFor(query.key);
134
- if (!entry.options && query.meta !== void 0) entry.hydratedMeta = query.meta;
135
- entry.returnsEffect ??= query.effect;
136
- if (query.updatedAt > 0) takeNewer(entry, deserialize(query.data), query.updatedAt);
137
- else if (query.promise) {
138
- const result = Promise.resolve(query.promise).then((sent) => ({
139
- data: deserialize(sent.data),
140
- updatedAt: sent.updatedAt
141
- }));
142
- if (!entry.state.hasData && !entry.inFlight) resume(entry, result);
143
- else result.then((sent) => takeNewer(entry, sent.data, sent.updatedAt), () => revalidate(entry));
144
- } else revalidate(entry);
145
- }
146
- }
147
- //#endregion
148
- export { RedactedError, canDehydrate, dehydrateEntries, dehydrateQuery, dehydrateStream, hydrateEntries };
@@ -1,5 +0,0 @@
1
- import "./options.mjs";
2
- import { Effect } from "effect";
3
- //#region src/infinite.d.ts
4
- export type Direction = "backward" | "forward";
5
- //#endregion
package/dist/infinite.mjs DELETED
@@ -1,103 +0,0 @@
1
- import { replaceEqualDeep } from "./share.mjs";
2
- import { Effect, Option, Predicate } from "effect";
3
- //#region src/infinite.ts
4
- function isInfiniteData(data) {
5
- return Predicate.hasProperty(data, "pages") && Predicate.hasProperty(data, "pageParams") && Array.isArray(data.pages) && Array.isArray(data.pageParams);
6
- }
7
- function nextPageParam(options, data) {
8
- if (data.pages.length === 0) return;
9
- return options.getNextPageParam(data.pages.at(-1), data.pages, data.pageParams.at(-1), data.pageParams);
10
- }
11
- function previousPageParam(options, data) {
12
- if (data.pages.length === 0 || !options.getPreviousPageParam) return;
13
- return options.getPreviousPageParam(data.pages[0], data.pages, data.pageParams[0], data.pageParams);
14
- }
15
- function addPage(data, page, pageParam, direction, maxPages) {
16
- const forward = direction === "forward";
17
- const pages = forward ? [...data.pages, page] : [page, ...data.pages];
18
- const pageParams = forward ? [...data.pageParams, pageParam] : [pageParam, ...data.pageParams];
19
- if (maxPages === void 0 || pages.length <= maxPages) return {
20
- pageParams,
21
- pages
22
- };
23
- return forward ? {
24
- pageParams: pageParams.slice(-maxPages),
25
- pages: pages.slice(-maxPages)
26
- } : {
27
- pageParams: pageParams.slice(0, maxPages),
28
- pages: pages.slice(0, maxPages)
29
- };
30
- }
31
- function edgeParam(data, direction) {
32
- return direction === "forward" ? data.pageParams.at(-1) : data.pageParams[0];
33
- }
34
- /** The page `data` holds for `pageParam`, compared deeply. */
35
- function pageFor(data, pageParam) {
36
- const index = data?.pageParams.findIndex((param) => replaceEqualDeep(param, pageParam) === param) ?? -1;
37
- return index === -1 ? Option.none() : Option.some(data?.pages[index]);
38
- }
39
- /**
40
- * `data`, a full refetch's pages, with each page that `latest` replaced
41
- * after the refetch started reading it: that write is newer than the read.
42
- * A page written before its read started is read again, and the read wins.
43
- */
44
- function keepWrites(data, readFrom, latest) {
45
- let changed = false;
46
- const pages = data.pages.map((page, index) => {
47
- const pageParam = data.pageParams[index];
48
- const read = readFrom.find((entry) => replaceEqualDeep(entry.pageParam, pageParam) === entry.pageParam);
49
- const now = pageFor(latest, pageParam);
50
- if (!read || Option.isNone(now) || Option.isSome(read.seen) && read.seen.value === now.value) return page;
51
- changed = true;
52
- return now.value;
53
- });
54
- return changed ? {
55
- pageParams: data.pageParams,
56
- pages
57
- } : data;
58
- }
59
- /**
60
- * A paged query's request. With a `direction`, adds one page at that end of
61
- * the entry's data, read again with `latest` once the page loads, so data
62
- * written meanwhile (`setData`, a live subscription) stays. If that data no
63
- * longer ends at the page param the request started from, the write
64
- * replaced the list, and the page is dropped. Without a `direction`, loads
65
- * from the first page param again: as many pages as `current` has, or
66
- * `pages` if that's more, stopping at the last page. A page written while
67
- * the refetch was reading it, or after, stays as written ({@link keepWrites}).
68
- */
69
- const fetchPages = /*#__PURE__*/ Effect.fnUntraced(function* (options, current, request, fetchPage, latest) {
70
- const direction = request.direction;
71
- if (direction && current) {
72
- const pageParam = direction === "forward" ? nextPageParam(options, current) : previousPageParam(options, current);
73
- if (pageParam == null) return current;
74
- const page = yield* fetchPage(pageParam, direction);
75
- const now = latest() ?? current;
76
- const startedFrom = edgeParam(current, direction);
77
- if (replaceEqualDeep(startedFrom, edgeParam(now, direction)) !== startedFrom) return now;
78
- return addPage(now, page, pageParam, direction, options.maxPages);
79
- }
80
- const count = Math.max(request.pages ?? 1, current?.pages.length ?? 0);
81
- let data = {
82
- pageParams: [],
83
- pages: []
84
- };
85
- const readFrom = [];
86
- let pageParam = current && current.pageParams.length > 0 ? current.pageParams[0] : options.initialPageParam;
87
- for (let index = 0; index < count; index++) {
88
- if (index > 0) {
89
- const next = nextPageParam(options, data);
90
- if (next == null) break;
91
- pageParam = next;
92
- }
93
- readFrom.push({
94
- pageParam,
95
- seen: pageFor(latest(), pageParam)
96
- });
97
- const page = yield* fetchPage(pageParam, "forward");
98
- data = addPage(data, page, pageParam, "forward", options.maxPages);
99
- }
100
- return keepWrites(data, readFrom, latest());
101
- });
102
- //#endregion
103
- export { fetchPages, isInfiniteData, nextPageParam, previousPageParam };
package/dist/key.d.mts DELETED
@@ -1,18 +0,0 @@
1
- //#region src/key.d.ts
2
- /**
3
- * A query's cache key. Must be JSON-serializable (plain objects, arrays and
4
- * primitives): it travels inside handles.
5
- */
6
- export type QueryKey = ReadonlyArray<unknown>;
7
- /**
8
- * Stable string form of a key. Object keys are sorted, so `{ a, b }` and
9
- * `{ b, a }` hash the same.
10
- */
11
- export declare function hashKey(key: QueryKey): string;
12
- /**
13
- * Whether `key` starts with `prefix`. Object segments match when every field
14
- * in the prefix's segment matches, so `["posts", { sort: "new" }]` matches
15
- * `["posts", { sort: "new", page: 2 }]`.
16
- */
17
- export declare function matchesKey(key: QueryKey, prefix: QueryKey): boolean;
18
- //#endregion
package/dist/key.mjs DELETED
@@ -1,36 +0,0 @@
1
- import { Predicate } from "effect";
2
- //#region src/key.ts
3
- function isPlainRecord(value) {
4
- if (!Predicate.isObject(value) || Array.isArray(value)) return false;
5
- const prototype = Object.getPrototypeOf(value);
6
- return prototype === Object.prototype || prototype === null;
7
- }
8
- function sortKeys(_name, value) {
9
- if (!isPlainRecord(value)) return value;
10
- const sorted = {};
11
- for (const name of Object.keys(value).toSorted()) sorted[name] = value[name];
12
- return sorted;
13
- }
14
- /**
15
- * Stable string form of a key. Object keys are sorted, so `{ a, b }` and
16
- * `{ b, a }` hash the same.
17
- */
18
- function hashKey(key) {
19
- return JSON.stringify(key, sortKeys);
20
- }
21
- function partialMatch(actual, expected) {
22
- if (actual === expected) return true;
23
- if (Array.isArray(actual) && Array.isArray(expected)) return actual.length === expected.length && expected.every((part, index) => partialMatch(actual[index], part));
24
- if (isPlainRecord(actual) && isPlainRecord(expected)) return Object.keys(expected).every((name) => partialMatch(actual[name], expected[name]));
25
- return false;
26
- }
27
- /**
28
- * Whether `key` starts with `prefix`. Object segments match when every field
29
- * in the prefix's segment matches, so `["posts", { sort: "new" }]` matches
30
- * `["posts", { sort: "new", page: 2 }]`.
31
- */
32
- function matchesKey(key, prefix) {
33
- return prefix.length <= key.length && prefix.every((part, index) => partialMatch(key[index], part));
34
- }
35
- //#endregion
36
- export { hashKey, isPlainRecord, matchesKey };
package/dist/listen.mjs DELETED
@@ -1,19 +0,0 @@
1
- import { Effect, Queue, Stream } from "effect";
2
- //#region src/listen.ts
3
- /**
4
- * A stream of what `subscribe` emits. Subscribes in the consuming fiber as
5
- * soon as the stream starts, so nothing emitted after that is missed
6
- * (`Stream.callback` subscribes on a forked fiber, a scheduler tick later),
7
- * and unsubscribes when the stream ends.
8
- */
9
- function listen(subscribe) {
10
- return Stream.unwrap(Effect.gen(function* () {
11
- const queue = yield* Queue.unbounded();
12
- yield* Effect.acquireRelease(Effect.sync(() => subscribe((value) => {
13
- Queue.offerUnsafe(queue, value);
14
- })), (unsubscribe) => Effect.sync(unsubscribe));
15
- return Stream.fromQueue(queue);
16
- }));
17
- }
18
- //#endregion
19
- export { listen };
package/dist/notify.mjs DELETED
@@ -1,21 +0,0 @@
1
- //#region src/notify.ts
2
- let queued;
3
- /**
4
- * Calls `listener` in a microtask, once per batch. State changes made while
5
- * React renders (a fetch started by a read) must not notify subscribers
6
- * synchronously, and several changes in one turn should re-render once.
7
- */
8
- function scheduleNotify(listener) {
9
- if (queued) {
10
- queued.add(listener);
11
- return;
12
- }
13
- const batch = /* @__PURE__ */ new Set([listener]);
14
- queued = batch;
15
- queueMicrotask(() => {
16
- queued = void 0;
17
- for (const queuedListener of batch) queuedListener();
18
- });
19
- }
20
- //#endregion
21
- export { scheduleNotify };
@@ -1,110 +0,0 @@
1
- import { QueryKey } from "./key.mjs";
2
- import { DataOf, QueryFactory } from "./options.mjs";
3
- import { Thenable } from "./thenable.mjs";
4
- import { Query, query_d_exports } from "./query.mjs";
5
- import { Effect, Pipeable, Stream } from "effect";
6
- declare namespace observer_d_exports {
7
- export { Options, QueryObserver, Result$1 as Result, ResultKey, TypeId, changes, get, getOptimisticResultUnsafe, getUnsafe, isQueryObserver, make, makeUnsafe, setOptionsUnsafe, subscribeUnsafe, trackProp, trackResult, trackThenable };
8
- }
9
- export declare const TypeId = "~@raf-query/core/QueryObserver";
10
- export type TypeId = typeof TypeId;
11
- /** How one reader observes its query. */
12
- export interface Options {
13
- /** Refetch on this interval (ms) while subscribed and the page is visible. */
14
- readonly refetchInterval?: number;
15
- /** Refetch on reconnect while stale. Default: the query's option, else `true`. */
16
- readonly refetchOnReconnect?: boolean;
17
- /** Refetch on window focus while stale. Default: the query's option, else `true`. */
18
- readonly refetchOnWindowFocus?: boolean;
19
- /**
20
- * What to show while the query has no data yet:
21
- * - `"suspend"` (default): the result's promise is the query's pending one.
22
- * - `"previous"`: keep the last observed query's data, with `isPrevious`.
23
- */
24
- readonly whilePending?: "previous" | "suspend";
25
- }
26
- /** What a reader sees of its query. Replaced, never mutated, on every change. */
27
- interface Result$1<TData = unknown> {
28
- /** Error of the last failed request. Existing data stays readable. */
29
- readonly error: unknown;
30
- /** The query's `fetchNextPage`. */
31
- readonly fetchNextPage: Effect.Effect<void>;
32
- /** The query's `fetchPreviousPage`. */
33
- readonly fetchPreviousPage: Effect.Effect<void>;
34
- /** Stable string form of the observed query's key. */
35
- readonly hash: string;
36
- readonly hasNextPage: boolean;
37
- readonly hasPreviousPage: boolean;
38
- /** Input of the data in `promise`; differs from the query's while `isPrevious`. */
39
- readonly input: unknown;
40
- /** A request is in flight: first load, new input, or background refetch. */
41
- readonly isFetching: boolean;
42
- readonly isFetchingNextPage: boolean;
43
- readonly isFetchingPreviousPage: boolean;
44
- /** No data yet for the observed query. */
45
- readonly isPending: boolean;
46
- /** `promise` holds a previous query's data (`whilePending: "previous"`). */
47
- readonly isPrevious: boolean;
48
- /** The data is older than `staleTime`, or was invalidated. */
49
- readonly isStale: boolean;
50
- /** Key of the data in `promise`; differs from the query's while `isPrevious`. */
51
- readonly key: QueryKey;
52
- /** Settles with the data to show; see `Query.State.promise`. */
53
- readonly promise: Thenable<TData>;
54
- /** The query's `refetch`. */
55
- readonly refetch: Effect.Effect<void>;
56
- /** When the data in `promise` was fetched (ms since epoch); `0` before that. */
57
- readonly updatedAt: number;
58
- }
59
- export type ResultKey = keyof Result$1;
60
- /** An observer of a factory's queries; its results hold the factory's {@link DataOf}. */
61
- export interface QueryObserver<TFactory extends QueryFactory = QueryFactory> extends Pipeable.Pipeable {
62
- /** The options set by the latest `make` or {@link setOptionsUnsafe}. */
63
- readonly options: Options;
64
- /** The observed query. */
65
- readonly query: Query<TFactory>;
66
- readonly [TypeId]: {
67
- readonly _A: (_: never) => DataOf<TFactory>;
68
- };
69
- }
70
- export declare function isQueryObserver(value: unknown): value is QueryObserver;
71
- /** Observe `query`. Doesn't subscribe to it until the observer has a listener. */
72
- export declare function makeUnsafe<TFactory extends QueryFactory>(query: Query<TFactory>, options?: Options): QueryObserver<TFactory>;
73
- /** {@link makeUnsafe}, as an Effect. */
74
- export declare function make<TFactory extends QueryFactory>(query: Query<TFactory>, options?: Options): Effect.Effect<QueryObserver<TFactory>>;
75
- /** The current result. */
76
- export declare function getUnsafe<TFactory extends QueryFactory>(self: QueryObserver<TFactory>): Result$1<DataOf<TFactory>>;
77
- /** {@link getUnsafe}, as an Effect. */
78
- export declare function get<TFactory extends QueryFactory>(self: QueryObserver<TFactory>): Effect.Effect<Result$1<DataOf<TFactory>>>;
79
- /**
80
- * The result for `query` with `options` right now, without switching to
81
- * them. Bindings call this during render, before `setOptionsUnsafe` commits.
82
- */
83
- export declare function getOptimisticResultUnsafe<TFactory extends QueryFactory>(self: QueryObserver<TFactory>, query: Query<TFactory>, options: Options): Result$1<DataOf<TFactory>>;
84
- /** Observe `query` with `options` from now on. */
85
- export declare function setOptionsUnsafe<TFactory extends QueryFactory>(self: QueryObserver<TFactory>, query: Query<TFactory>, options: Options): void;
86
- /** Listen for result changes. The first listener subscribes to the query. */
87
- export declare function subscribeUnsafe<TFactory extends QueryFactory>(self: QueryObserver<TFactory>, listener: () => void): () => void;
88
- /**
89
- * The current result, then every change listeners are notified of. Counts
90
- * as a listener while the stream runs, so the query counts as read.
91
- */
92
- export declare function changes<TFactory extends QueryFactory>(self: QueryObserver<TFactory>): Stream.Stream<Result$1<DataOf<TFactory>>>;
93
- /**
94
- * Wrap `result` so that reading a property marks it tracked. Once any
95
- * property is tracked, listeners are only notified when a tracked one
96
- * changes.
97
- */
98
- export declare function trackResult<TFactory extends QueryFactory, TResult extends Result$1<DataOf<TFactory>>>(self: QueryObserver<TFactory>, result: TResult): TResult;
99
- /**
100
- * Wrap `promise`, the result's or one derived from it, so that reading its
101
- * `status`, `value` or `reason` marks its settling as tracked. A first load
102
- * settles its promise in place, without a new promise, so only readers of
103
- * those fields need to hear about it. The mark is the wrapper's, shared by
104
- * the observers that hand it out.
105
- */
106
- export declare function trackThenable<TFactory extends QueryFactory, TThenable extends Thenable<unknown>>(self: QueryObserver<TFactory>, promise: TThenable): TThenable;
107
- /** Mark `name` as read, for bindings that track access themselves. */
108
- export declare function trackProp<TFactory extends QueryFactory>(self: QueryObserver<TFactory>, name: ResultKey): void;
109
- //#endregion
110
- export { Result$1 as Result, observer_d_exports };