@raf-query/core 0.11.1 → 0.13.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 +39 -1
- package/README.md +28 -18
- package/dist/client.d.mts +163 -119
- package/dist/client.mjs +90 -162
- package/dist/entry.d.mts +73 -147
- package/dist/entry.mjs +314 -471
- package/dist/features/focus-refetch/focus-refetch.d.mts +17 -0
- package/dist/features/focus-refetch/focus-refetch.mjs +20 -0
- package/dist/features/polling/polling.d.mts +16 -0
- package/dist/features/polling/polling.mjs +39 -0
- package/dist/features/reconnect-refetch/reconnect-refetch.d.mts +17 -0
- package/dist/features/reconnect-refetch/reconnect-refetch.mjs +16 -0
- package/dist/features/shared.mjs +13 -0
- package/dist/guards.mjs +23 -0
- package/dist/hydration/hydration.d.mts +108 -0
- package/dist/hydration/hydration.mjs +142 -0
- package/dist/index.d.mts +19 -13
- package/dist/index.mjs +16 -13
- package/dist/infinite/infinite.d.mts +83 -0
- package/dist/infinite/infinite.mjs +120 -0
- package/dist/infinite/paging.d.mts +71 -0
- package/dist/infinite/paging.mjs +62 -0
- package/dist/internal.d.mts +13 -0
- package/dist/internal.mjs +7 -0
- package/dist/keys/keys.d.mts +54 -0
- package/dist/keys/keys.mjs +53 -0
- package/dist/keys/targets.d.mts +62 -0
- package/dist/keys/targets.mjs +85 -0
- package/dist/links/retry/retry.d.mts +33 -0
- package/dist/links/retry/retry.mjs +53 -0
- package/dist/links/timeout/timeout.d.mts +17 -0
- package/dist/links/timeout/timeout.mjs +35 -0
- package/dist/load.d.mts +149 -0
- package/dist/load.mjs +179 -0
- package/dist/options.d.mts +161 -332
- package/dist/options.mjs +28 -40
- package/dist/presets.d.mts +35 -0
- package/dist/presets.mjs +27 -0
- package/dist/root.d.mts +86 -0
- package/dist/structural-sharing/structural-sharing.mjs +32 -0
- package/dist/subscribe.d.mts +15 -0
- package/dist/subscribe.mjs +29 -0
- package/dist/thenable.d.mts +15 -17
- package/dist/thenable.mjs +25 -6
- package/dist/verbs.d.mts +150 -0
- package/dist/verbs.mjs +115 -0
- package/package.json +13 -9
- package/dist/_virtual/_rolldown/runtime.mjs +0 -13
- package/dist/all-keyed.d.mts +0 -18
- package/dist/all-keyed.mjs +0 -19
- package/dist/binding.d.mts +0 -92
- package/dist/binding.mjs +0 -186
- package/dist/cache.d.mts +0 -164
- package/dist/cache.mjs +0 -184
- package/dist/controls.d.mts +0 -95
- package/dist/controls.mjs +0 -70
- package/dist/hydration.d.mts +0 -84
- package/dist/hydration.mjs +0 -148
- package/dist/infinite.d.mts +0 -5
- package/dist/infinite.mjs +0 -103
- package/dist/key.d.mts +0 -18
- package/dist/key.mjs +0 -36
- package/dist/listen.mjs +0 -19
- package/dist/notify.mjs +0 -21
- package/dist/observer.d.mts +0 -110
- package/dist/observer.mjs +0 -300
- package/dist/platform.d.mts +0 -27
- package/dist/platform.mjs +0 -44
- package/dist/query.d.mts +0 -137
- package/dist/query.mjs +0 -147
- package/dist/request.mjs +0 -47
- package/dist/retry.mjs +0 -25
- package/dist/share.mjs +0 -40
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Feature, Link } from "./client.mjs";
|
|
2
|
+
import { FocusRefetchMeta } from "./features/focus-refetch/focus-refetch.mjs";
|
|
3
|
+
import { ReconnectRefetchMeta } from "./features/reconnect-refetch/reconnect-refetch.mjs";
|
|
4
|
+
import { PollingMeta } from "./features/polling/polling.mjs";
|
|
5
|
+
import { RetryMeta } from "./links/retry/retry.mjs";
|
|
6
|
+
//#region src/presets.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* What `recommended()` returns: its parts keep the `meta` they declare.
|
|
9
|
+
*
|
|
10
|
+
* @see https://raf-query.katt.dev/docs/important-defaults
|
|
11
|
+
*/
|
|
12
|
+
export interface Recommended {
|
|
13
|
+
readonly features: readonly [Feature<{
|
|
14
|
+
readonly meta: FocusRefetchMeta;
|
|
15
|
+
}>, Feature<{
|
|
16
|
+
readonly meta: ReconnectRefetchMeta;
|
|
17
|
+
}>, Feature<{
|
|
18
|
+
readonly meta: PollingMeta;
|
|
19
|
+
}>];
|
|
20
|
+
readonly links: readonly [Link<{
|
|
21
|
+
readonly meta: RetryMeta;
|
|
22
|
+
}>];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The behaviors most apps want: retries, refetching on focus and reconnect,
|
|
26
|
+
* and polling. Spread it into the config:
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* createQueryClient({ ...recommended(), staleTime: 30_000 });
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @see https://raf-query.katt.dev/docs/important-defaults
|
|
33
|
+
*/
|
|
34
|
+
export declare function recommended(): Recommended;
|
|
35
|
+
//#endregion
|
package/dist/presets.mjs
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { focusRefetch } from "./features/focus-refetch/focus-refetch.mjs";
|
|
2
|
+
import { reconnectRefetch } from "./features/reconnect-refetch/reconnect-refetch.mjs";
|
|
3
|
+
import { polling } from "./features/polling/polling.mjs";
|
|
4
|
+
import { retry } from "./links/retry/retry.mjs";
|
|
5
|
+
//#region src/presets.ts
|
|
6
|
+
/**
|
|
7
|
+
* The behaviors most apps want: retries, refetching on focus and reconnect,
|
|
8
|
+
* and polling. Spread it into the config:
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* createQueryClient({ ...recommended(), staleTime: 30_000 });
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* @see https://raf-query.katt.dev/docs/important-defaults
|
|
15
|
+
*/
|
|
16
|
+
function recommended() {
|
|
17
|
+
return {
|
|
18
|
+
features: [
|
|
19
|
+
focusRefetch(),
|
|
20
|
+
reconnectRefetch(),
|
|
21
|
+
polling()
|
|
22
|
+
],
|
|
23
|
+
links: [retry()]
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { recommended };
|
package/dist/root.d.mts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
//#region src/root.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Root types, the way tRPC v12 types a client from its links: each link and
|
|
4
|
+
* feature declares the `meta` fields it reads, a client's `meta` is what its
|
|
5
|
+
* parts declare, and builders bound to a root (`bindQueryOptions`) carry it
|
|
6
|
+
* as a phantom on the options they build.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* A query's `meta` when its builder isn't bound to a root.
|
|
10
|
+
*
|
|
11
|
+
* @see https://raf-query.katt.dev/docs/links-and-features
|
|
12
|
+
*/
|
|
13
|
+
export type QueryMeta = Readonly<Record<string, unknown>>;
|
|
14
|
+
/** What a link or feature declares: the `meta` fields it reads. */
|
|
15
|
+
export interface Decl {
|
|
16
|
+
readonly meta?: object;
|
|
17
|
+
}
|
|
18
|
+
/** A root's types. */
|
|
19
|
+
export interface RootTypes {
|
|
20
|
+
readonly meta: object;
|
|
21
|
+
}
|
|
22
|
+
/** The root of the unbound builders. A type only, never a value. */
|
|
23
|
+
export interface DefaultTypes {
|
|
24
|
+
readonly "~default": true;
|
|
25
|
+
readonly meta: QueryMeta;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The root of a client typed only as `QueryClient`: any root. The one way
|
|
29
|
+
* an invariant phantom takes every root.
|
|
30
|
+
*/
|
|
31
|
+
export type AnyRoot = any;
|
|
32
|
+
/** Whether `TTypes` is {@link AnyRoot}. */
|
|
33
|
+
export type IsAnyRoot<TTypes> = 0 extends 1 & TTypes ? true : false;
|
|
34
|
+
/**
|
|
35
|
+
* Phantom carrier of a part's declaration, `undefined` at runtime.
|
|
36
|
+
* Invariant, so a part that declares nothing doesn't absorb the
|
|
37
|
+
* declarations of the others in an array.
|
|
38
|
+
*/
|
|
39
|
+
export interface Declares<TDecl extends Decl> {
|
|
40
|
+
readonly "~decl"?: {
|
|
41
|
+
readonly in: (decl: TDecl) => void;
|
|
42
|
+
readonly out: TDecl;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** Any link or feature, whatever it declares. */
|
|
46
|
+
export interface AnyPart {
|
|
47
|
+
readonly "~decl"?: {
|
|
48
|
+
readonly in: (decl: never) => void;
|
|
49
|
+
readonly out: unknown;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The `meta` a declaration adds to its root. Every declared key is present
|
|
54
|
+
* and may be `undefined`: roots of all-optional metas would be assignable to
|
|
55
|
+
* one another. Queries pass a `Partial` of it.
|
|
56
|
+
*/
|
|
57
|
+
export type MetaOfDecl<TDecl> = TDecl extends {
|
|
58
|
+
readonly meta?: infer TMeta extends object;
|
|
59
|
+
} ? Present<TMeta> : unknown;
|
|
60
|
+
/**
|
|
61
|
+
* Every key of `T` required, its value possibly `undefined`. Mapping over
|
|
62
|
+
* `Exclude<keyof T, never>` rather than `keyof T` drops the modifiers
|
|
63
|
+
* without dropping `undefined`, which `-?` would.
|
|
64
|
+
*/
|
|
65
|
+
type Present<T> = { readonly [K in Exclude<keyof T, never>]: T[K] | undefined; };
|
|
66
|
+
type DeclOf<TPart> = TPart extends {
|
|
67
|
+
readonly "~decl"?: {
|
|
68
|
+
readonly out: infer TDecl;
|
|
69
|
+
};
|
|
70
|
+
} ? TDecl : never;
|
|
71
|
+
type Intersect<TUnion> = (TUnion extends unknown ? (value: TUnion) => void : never) extends ((value: infer TIntersection) => void) ? TIntersection : never;
|
|
72
|
+
type Flat<T> = { readonly [K in keyof T]: T[K]; };
|
|
73
|
+
/** A root's `meta`: what its links and features declare. */
|
|
74
|
+
export type MetaOf<TParts extends ReadonlyArray<AnyPart>> = [DeclOf<TParts[number]>] extends [never] ? Flat<unknown> : Flat<Intersect<MetaOfDecl<DeclOf<TParts[number]>>>>;
|
|
75
|
+
declare const rootBrand: unique symbol;
|
|
76
|
+
/** Phantom carrier of the root a factory's builder is bound to. Never set at runtime. */
|
|
77
|
+
export interface RootTag<TTypes extends RootTypes> {
|
|
78
|
+
readonly [rootBrand]: TTypes;
|
|
79
|
+
}
|
|
80
|
+
/** A root's types, from a client or from a function that makes one. */
|
|
81
|
+
export type RootOf<T> = T extends ((...args: never) => infer TClient) ? RootOf<TClient> : T extends {
|
|
82
|
+
readonly "~types"?: {
|
|
83
|
+
readonly root: (types: infer TTypes extends RootTypes) => unknown;
|
|
84
|
+
};
|
|
85
|
+
} ? TTypes : never;
|
|
86
|
+
//#endregion
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/structural-sharing/structural-sharing.ts
|
|
2
|
+
function isPlainArray(value) {
|
|
3
|
+
return Array.isArray(value) && value.length === Object.keys(value).length;
|
|
4
|
+
}
|
|
5
|
+
function isPlainObject(value) {
|
|
6
|
+
if (typeof value !== "object" || value === null) return false;
|
|
7
|
+
const prototype = Object.getPrototypeOf(value);
|
|
8
|
+
return prototype === Object.prototype || prototype === null;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* `next`, reusing every part of `previous` that is deeply equal to it, so
|
|
12
|
+
* unchanged objects keep their identity and memoized readers skip work.
|
|
13
|
+
*/
|
|
14
|
+
function replaceEqualDeep(previous, next) {
|
|
15
|
+
if (Object.is(previous, next)) return previous;
|
|
16
|
+
const arrays = isPlainArray(previous) && isPlainArray(next);
|
|
17
|
+
if (!arrays && !(isPlainObject(previous) && isPlainObject(next))) return next;
|
|
18
|
+
const before = previous;
|
|
19
|
+
const after = next;
|
|
20
|
+
const names = Object.keys(after);
|
|
21
|
+
let same = names.length === Object.keys(before).length;
|
|
22
|
+
const values = names.map((name) => {
|
|
23
|
+
const own = Object.hasOwn(before, name);
|
|
24
|
+
const value = replaceEqualDeep(own ? before[name] : void 0, after[name]);
|
|
25
|
+
if (!own || value !== before[name]) same = false;
|
|
26
|
+
return value;
|
|
27
|
+
});
|
|
28
|
+
if (same) return previous;
|
|
29
|
+
return arrays ? values : Object.fromEntries(names.map((name, index) => [name, values[index]]));
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { replaceEqualDeep };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/subscribe.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The kernel's one subscription primitive: `subscribe(listener, { signal })`.
|
|
4
|
+
* Unsubscribe by aborting the signal, or by calling what it returns. There
|
|
5
|
+
* is no error channel: errors live in entry state.
|
|
6
|
+
*/
|
|
7
|
+
export interface SubscribeOptions {
|
|
8
|
+
readonly signal?: AbortSignal;
|
|
9
|
+
}
|
|
10
|
+
export interface Listeners<TEvent> {
|
|
11
|
+
emit(event: TEvent): void;
|
|
12
|
+
readonly size: number;
|
|
13
|
+
subscribe(listener: (event: TEvent) => void, options?: SubscribeOptions): () => void;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/subscribe.ts
|
|
2
|
+
function listeners(onSizeChange) {
|
|
3
|
+
const set = /* @__PURE__ */ new Set();
|
|
4
|
+
return {
|
|
5
|
+
emit(event) {
|
|
6
|
+
for (const item of set) item.listener(event);
|
|
7
|
+
},
|
|
8
|
+
get size() {
|
|
9
|
+
return set.size;
|
|
10
|
+
},
|
|
11
|
+
subscribe(listener, options) {
|
|
12
|
+
const signal = options?.signal;
|
|
13
|
+
if (signal?.aborted) return () => {};
|
|
14
|
+
const item = { listener };
|
|
15
|
+
set.add(item);
|
|
16
|
+
onSizeChange?.(set.size);
|
|
17
|
+
const unsubscribe = () => {
|
|
18
|
+
if (set.delete(item)) {
|
|
19
|
+
signal?.removeEventListener("abort", unsubscribe);
|
|
20
|
+
onSizeChange?.(set.size);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
signal?.addEventListener("abort", unsubscribe, { once: true });
|
|
24
|
+
return unsubscribe;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
export { listeners };
|
package/dist/thenable.d.mts
CHANGED
|
@@ -1,31 +1,29 @@
|
|
|
1
1
|
//#region src/thenable.d.ts
|
|
2
2
|
/**
|
|
3
|
-
* Promises that carry their own result
|
|
4
|
-
* before suspending (`status`, `value`, `reason`). A settled one
|
|
3
|
+
* Promises that carry their own result in the fields React's `use()` reads
|
|
4
|
+
* before suspending (`status`, `value`, `reason`). A settled one is read
|
|
5
5
|
* synchronously, so React renders it without a fallback.
|
|
6
|
+
*
|
|
7
|
+
* @see https://raf-query.katt.dev/docs/reading-queries
|
|
6
8
|
*/
|
|
7
|
-
|
|
8
|
-
readonly status: "pending";
|
|
9
|
-
}
|
|
10
|
-
interface FulfilledStatus<T> {
|
|
11
|
-
readonly status: "fulfilled";
|
|
12
|
-
readonly value: T;
|
|
13
|
-
}
|
|
14
|
-
interface RejectedStatus {
|
|
9
|
+
export type Thenable<T> = Promise<T> & ({
|
|
15
10
|
readonly reason: unknown;
|
|
16
11
|
readonly status: "rejected";
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
export type Thenable<T> = Promise<T> & (FulfilledStatus<T> | PendingStatus | RejectedStatus);
|
|
12
|
+
} | {
|
|
13
|
+
readonly status: "fulfilled";
|
|
14
|
+
readonly value: T;
|
|
15
|
+
} | {
|
|
16
|
+
readonly status: "pending";
|
|
17
|
+
});
|
|
24
18
|
export declare function fulfilled<T>(value: T): Thenable<T>;
|
|
19
|
+
export declare function rejected<T>(reason: unknown): Thenable<T>;
|
|
25
20
|
export interface Pending<T> {
|
|
26
21
|
readonly promise: Thenable<T>;
|
|
27
22
|
reject(reason: unknown): void;
|
|
28
23
|
resolve(value: T): void;
|
|
29
24
|
}
|
|
25
|
+
/** A pending thenable that settles in place, so `use()` resumes on it. */
|
|
30
26
|
export declare function pending<T>(): Pending<T>;
|
|
27
|
+
/** `thenable` with `map` applied to its value, cached per source thenable. */
|
|
28
|
+
export declare function mapThenable<T, U>(cache: WeakMap<Thenable<unknown>, Thenable<unknown>>, thenable: Thenable<T>, map: (value: T) => U): Thenable<U>;
|
|
31
29
|
//#endregion
|
package/dist/thenable.mjs
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
//#region src/thenable.ts
|
|
2
|
-
/**
|
|
3
|
-
* Promises that carry their own result, in the fields React's `use()` reads
|
|
4
|
-
* before suspending (`status`, `value`, `reason`). A settled one can be read
|
|
5
|
-
* synchronously, so React renders it without a fallback.
|
|
6
|
-
*/
|
|
7
2
|
const noop = () => {};
|
|
8
3
|
function fulfilled(value) {
|
|
9
4
|
return Object.assign(Promise.resolve(value), {
|
|
@@ -11,6 +6,15 @@ function fulfilled(value) {
|
|
|
11
6
|
value
|
|
12
7
|
});
|
|
13
8
|
}
|
|
9
|
+
function rejected(reason) {
|
|
10
|
+
const promise = Promise.reject(reason);
|
|
11
|
+
promise.catch(noop);
|
|
12
|
+
return Object.assign(promise, {
|
|
13
|
+
reason,
|
|
14
|
+
status: "rejected"
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
/** A pending thenable that settles in place, so `use()` resumes on it. */
|
|
14
18
|
function pending() {
|
|
15
19
|
const deferred = Promise.withResolvers();
|
|
16
20
|
const promise = Object.assign(deferred.promise, { status: "pending" });
|
|
@@ -33,5 +37,20 @@ function pending() {
|
|
|
33
37
|
}
|
|
34
38
|
};
|
|
35
39
|
}
|
|
40
|
+
/** `thenable` with `map` applied to its value, cached per source thenable. */
|
|
41
|
+
function mapThenable(cache, thenable, map) {
|
|
42
|
+
const cached = cache.get(thenable);
|
|
43
|
+
if (cached) return cached;
|
|
44
|
+
let mapped;
|
|
45
|
+
if (thenable.status === "fulfilled") mapped = fulfilled(map(thenable.value));
|
|
46
|
+
else if (thenable.status === "rejected") mapped = rejected(thenable.reason);
|
|
47
|
+
else {
|
|
48
|
+
const next = pending();
|
|
49
|
+
thenable.then((value) => next.resolve(map(value)), (error) => next.reject(error));
|
|
50
|
+
mapped = next.promise;
|
|
51
|
+
}
|
|
52
|
+
cache.set(thenable, mapped);
|
|
53
|
+
return mapped;
|
|
54
|
+
}
|
|
36
55
|
//#endregion
|
|
37
|
-
export { fulfilled, pending };
|
|
56
|
+
export { fulfilled, mapThenable, pending, rejected };
|
package/dist/verbs.d.mts
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { Group } from "./keys/keys.mjs";
|
|
2
|
+
import { IsAnyRoot, RootTypes } from "./root.mjs";
|
|
3
|
+
import { AnyInvalidation, AnyTarget, ParamArgs, Target } from "./keys/targets.mjs";
|
|
4
|
+
import { InputArgs, InputOf, QueryFactory, QueryFnDataOf, RootOfFactory } from "./options.mjs";
|
|
5
|
+
import { QueryClient } from "./client.mjs";
|
|
6
|
+
//#region src/verbs.d.ts
|
|
7
|
+
type DeepPartial<T> = T extends object ? { readonly [TName in keyof T]?: DeepPartial<T[TName]>; } : T;
|
|
8
|
+
/**
|
|
9
|
+
* What `invalidateMany(factory, partial)` takes: part of the factory's
|
|
10
|
+
* input, whatever its key looks like.
|
|
11
|
+
*
|
|
12
|
+
* @see https://raf-query.katt.dev/docs/query-invalidation
|
|
13
|
+
*/
|
|
14
|
+
export type PartialInput<TFactory extends QueryFactory> = DeepPartial<InputOf<TFactory>>;
|
|
15
|
+
/**
|
|
16
|
+
* The clients a factory's verbs take: its root's, or any client for a
|
|
17
|
+
* factory from an unbound builder.
|
|
18
|
+
*
|
|
19
|
+
* @see https://raf-query.katt.dev/docs/links-and-features#typing-meta-by-its-root
|
|
20
|
+
*/
|
|
21
|
+
export type ClientFor<TFactory extends QueryFactory> = QueryClient<RootOfFactory<TFactory>>;
|
|
22
|
+
/**
|
|
23
|
+
* A target a client's root can match: its `where` reads that root's `meta`.
|
|
24
|
+
* A client typed only as `QueryClient` (from `useQueryClient()`, say) may
|
|
25
|
+
* be of any root, so it takes any target.
|
|
26
|
+
*/
|
|
27
|
+
export type TargetFor<TTypes extends RootTypes, TParam> = IsAnyRoot<TTypes> extends true ? Target<never, TParam> : Target<NoInfer<TTypes["meta"]>, TParam>;
|
|
28
|
+
type ParamOf<TTarget> = TTarget extends {
|
|
29
|
+
readonly where: (query: never, param: infer TParam) => boolean;
|
|
30
|
+
} ? TParam : never;
|
|
31
|
+
/** A factory, if the client's root is its root; else nothing fits. */
|
|
32
|
+
type FactoryFor<TTypes extends RootTypes, TFactory extends QueryFactory> = [QueryClient<TTypes>] extends [ClientFor<TFactory>] ? TFactory : never;
|
|
33
|
+
/** A target on its own, if it needs no parameter; else with its parameter. */
|
|
34
|
+
type BareTarget<TTypes extends RootTypes, TParam> = [] extends ParamArgs<TParam> ? TargetFor<TTypes, TParam> : readonly [TargetFor<TTypes, TParam>, TParam];
|
|
35
|
+
type AnyItem = AnyTarget | Group | QueryFactory | readonly [AnyTarget | QueryFactory, unknown];
|
|
36
|
+
/**
|
|
37
|
+
* What one element of a target list must be, given what was passed: a
|
|
38
|
+
* group, a factory of the client's root, a factory with a partial input, a
|
|
39
|
+
* target, or a target with its parameter.
|
|
40
|
+
*/
|
|
41
|
+
type Item<TTypes extends RootTypes, TItem> = TItem extends Group ? Group : TItem extends QueryFactory ? FactoryFor<TTypes, TItem> : TItem extends AnyTarget ? BareTarget<TTypes, ParamOf<TItem>> : TItem extends readonly [infer TFirst, unknown] ? TFirst extends QueryFactory ? readonly [FactoryFor<TTypes, TFirst>, PartialInput<TFirst>] : TFirst extends AnyTarget ? readonly [TargetFor<TTypes, ParamOf<TFirst>>, ParamOf<TFirst>] : AnyItem : AnyItem;
|
|
42
|
+
/**
|
|
43
|
+
* Several targets for one verb call, each checked on its own: a group, a
|
|
44
|
+
* factory, `[factory, partial]`, a target, or `[target, param]`.
|
|
45
|
+
*/
|
|
46
|
+
export type TargetList<TTypes extends RootTypes, TItems extends ReadonlyArray<unknown>> = { readonly [TIndex in keyof TItems]: Item<TTypes, TItems[TIndex]>; };
|
|
47
|
+
/** The data `setData` writes: plain for a query, paged for an infinite one. */
|
|
48
|
+
type WritableData<TFactory extends QueryFactory> = QueryFnDataOf<TFactory>;
|
|
49
|
+
/**
|
|
50
|
+
* Mark one query stale: a factory and its full input. If it's read, it
|
|
51
|
+
* refetches; resolves when that settles.
|
|
52
|
+
*
|
|
53
|
+
* @see https://raf-query.katt.dev/docs/query-invalidation
|
|
54
|
+
*/
|
|
55
|
+
export declare function invalidateOne<TFactory extends QueryFactory>(client: ClientFor<TFactory>, factory: TFactory, ...input: InputArgs<TFactory>): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Mark queries stale: a factory's (optionally only those whose input
|
|
58
|
+
* matches `partial`), a group's (keys that start with its path, whether
|
|
59
|
+
* the group built them or not), or those a target's `where` picks. Read
|
|
60
|
+
* queries refetch now; the rest when next read. Resolves when the
|
|
61
|
+
* refetches settle.
|
|
62
|
+
*
|
|
63
|
+
* Pass a list to invalidate several targets in one call: each query they
|
|
64
|
+
* cover refetches once, and the refetches run side by side. Awaiting one
|
|
65
|
+
* call after another runs them one after another instead.
|
|
66
|
+
*
|
|
67
|
+
* ```ts
|
|
68
|
+
* await invalidateMany(client, [authors, [commentsQuery, { slug }], [ownedBy, "editorial"]]);
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @see https://raf-query.katt.dev/docs/query-invalidation#several-targets
|
|
72
|
+
*/
|
|
73
|
+
export declare function invalidateMany<TFactory extends QueryFactory>(client: ClientFor<TFactory>, factory: TFactory, partial?: PartialInput<TFactory>): Promise<void>;
|
|
74
|
+
export declare function invalidateMany(client: QueryClient, group: Group): Promise<void>;
|
|
75
|
+
export declare function invalidateMany<TTypes extends RootTypes, TParam = never>(client: QueryClient<TTypes>, target: TargetFor<TTypes, TParam>, ...param: ParamArgs<NoInfer<TParam>>): Promise<void>;
|
|
76
|
+
export declare function invalidateMany<TTypes extends RootTypes, const TItems extends ReadonlyArray<unknown>>(client: QueryClient<TTypes>, targets: TargetList<TTypes, TItems>): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Mark every query stale; read ones refetch. For sign-out, or after any write.
|
|
79
|
+
*
|
|
80
|
+
* @see https://raf-query.katt.dev/docs/query-invalidation
|
|
81
|
+
*/
|
|
82
|
+
export declare function invalidateAll(client: QueryClient): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Drop one query's data and error. If it's read, it suspends and refetches;
|
|
85
|
+
* resolves when that settles.
|
|
86
|
+
*
|
|
87
|
+
* @see https://raf-query.katt.dev/docs/query-invalidation#invalidate-reset-or-remove
|
|
88
|
+
*/
|
|
89
|
+
export declare function resetOne<TFactory extends QueryFactory>(client: ClientFor<TFactory>, factory: TFactory, ...input: InputArgs<TFactory>): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* {@link resetOne} for every query a target, or a list of them, covers.
|
|
92
|
+
*
|
|
93
|
+
* @see https://raf-query.katt.dev/docs/query-invalidation#invalidate-reset-or-remove
|
|
94
|
+
*/
|
|
95
|
+
export declare function resetMany<TFactory extends QueryFactory>(client: ClientFor<TFactory>, factory: TFactory, partial?: PartialInput<TFactory>): Promise<void>;
|
|
96
|
+
export declare function resetMany(client: QueryClient, group: Group): Promise<void>;
|
|
97
|
+
export declare function resetMany<TTypes extends RootTypes, TParam = never>(client: QueryClient<TTypes>, target: TargetFor<TTypes, TParam>, ...param: ParamArgs<NoInfer<TParam>>): Promise<void>;
|
|
98
|
+
export declare function resetMany<TTypes extends RootTypes, const TItems extends ReadonlyArray<unknown>>(client: QueryClient<TTypes>, targets: TargetList<TTypes, TItems>): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* {@link resetOne} for every query.
|
|
101
|
+
*
|
|
102
|
+
* @see https://raf-query.katt.dev/docs/query-invalidation#invalidate-reset-or-remove
|
|
103
|
+
*/
|
|
104
|
+
export declare function resetAll(client: QueryClient): Promise<void>;
|
|
105
|
+
/**
|
|
106
|
+
* Remove one query from the cache, aborting its request.
|
|
107
|
+
*
|
|
108
|
+
* @see https://raf-query.katt.dev/docs/query-invalidation#invalidate-reset-or-remove
|
|
109
|
+
*/
|
|
110
|
+
export declare function removeOne<TFactory extends QueryFactory>(client: ClientFor<TFactory>, factory: TFactory, ...input: InputArgs<TFactory>): void;
|
|
111
|
+
/**
|
|
112
|
+
* {@link removeOne} for every query a target, or a list of them, covers.
|
|
113
|
+
*
|
|
114
|
+
* @see https://raf-query.katt.dev/docs/query-invalidation#invalidate-reset-or-remove
|
|
115
|
+
*/
|
|
116
|
+
export declare function removeMany<TFactory extends QueryFactory>(client: ClientFor<TFactory>, factory: TFactory, partial?: PartialInput<TFactory>): void;
|
|
117
|
+
export declare function removeMany(client: QueryClient, group: Group): void;
|
|
118
|
+
export declare function removeMany<TTypes extends RootTypes, TParam = never>(client: QueryClient<TTypes>, target: TargetFor<TTypes, TParam>, ...param: ParamArgs<NoInfer<TParam>>): void;
|
|
119
|
+
export declare function removeMany<TTypes extends RootTypes, const TItems extends ReadonlyArray<unknown>>(client: QueryClient<TTypes>, targets: TargetList<TTypes, TItems>): void;
|
|
120
|
+
/**
|
|
121
|
+
* Remove every query, aborting their requests.
|
|
122
|
+
*
|
|
123
|
+
* @see https://raf-query.katt.dev/docs/query-invalidation#invalidate-reset-or-remove
|
|
124
|
+
*/
|
|
125
|
+
export declare function removeAll(client: QueryClient): void;
|
|
126
|
+
/** New data for `setData`, or a function from the current data to it. */
|
|
127
|
+
type Updater<TFactory extends QueryFactory> = ((previous: WritableData<TFactory> | undefined) => WritableData<TFactory>) | WritableData<TFactory>;
|
|
128
|
+
/**
|
|
129
|
+
* Write a query's data, as if a request had just returned it. `updater`
|
|
130
|
+
* gets the current data, or `undefined` if there is none. A factory that
|
|
131
|
+
* takes no input (or an optional one) skips the input:
|
|
132
|
+
* `setData(client, feedQuery, updater)`.
|
|
133
|
+
*
|
|
134
|
+
* @see https://raf-query.katt.dev/docs/mutations#updates-from-mutation-responses
|
|
135
|
+
*/
|
|
136
|
+
export declare function setData<TFactory extends QueryFactory>(client: ClientFor<TFactory>, factory: TFactory, ...updater: [] extends Parameters<TFactory> ? [updater: Updater<TFactory>] : never): void;
|
|
137
|
+
export declare function setData<TFactory extends QueryFactory>(client: ClientFor<TFactory>, factory: TFactory, input: Parameters<TFactory> extends [] ? never : Parameters<TFactory>[0], updater: Updater<TFactory>): void;
|
|
138
|
+
/**
|
|
139
|
+
* A query's cached data (before `select`), or `undefined`.
|
|
140
|
+
*
|
|
141
|
+
* @see https://raf-query.katt.dev/docs/api-reference#changing-the-cache
|
|
142
|
+
*/
|
|
143
|
+
export declare function getData<TFactory extends QueryFactory>(client: ClientFor<TFactory>, factory: TFactory, ...input: InputArgs<TFactory>): WritableData<TFactory> | undefined;
|
|
144
|
+
/**
|
|
145
|
+
* How many queries have a request in flight, optionally only a factory's, a group's or a target's.
|
|
146
|
+
*
|
|
147
|
+
* @see https://raf-query.katt.dev/docs/background-fetching-indicators
|
|
148
|
+
*/
|
|
149
|
+
export declare function isFetching(client: QueryClient, target?: AnyInvalidation): number;
|
|
150
|
+
//#endregion
|
package/dist/verbs.mjs
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { isArray, isFunction } from "./guards.mjs";
|
|
2
|
+
import { hashKey } from "./keys/keys.mjs";
|
|
3
|
+
import { entryStamp, matches, stampFor } from "./keys/targets.mjs";
|
|
4
|
+
import { optionsOf } from "./options.mjs";
|
|
5
|
+
import { entryOf, invalidate, remove, reset, write } from "./entry.mjs";
|
|
6
|
+
//#region src/verbs.ts
|
|
7
|
+
function hashOf(factory, input) {
|
|
8
|
+
return hashKey(optionsOf(factory, input).queryKey);
|
|
9
|
+
}
|
|
10
|
+
/** A stamp per target: one target and its argument, or each of a list. */
|
|
11
|
+
function stampsOf(targets, arg, at) {
|
|
12
|
+
return (isArray(targets) ? targets : [[targets, arg]]).map((item) => isArray(item) ? stampFor(item[0], item[1], at) : stampFor(item, void 0, at));
|
|
13
|
+
}
|
|
14
|
+
function entriesMatching(client, stamps) {
|
|
15
|
+
return [...client["~entries"].values()].filter((entry) => stamps.some((stamp) => matches(entry, stamp)));
|
|
16
|
+
}
|
|
17
|
+
function settle(outcomes) {
|
|
18
|
+
return Promise.all(outcomes).then(() => {});
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Mark one query stale: a factory and its full input. If it's read, it
|
|
22
|
+
* refetches; resolves when that settles.
|
|
23
|
+
*
|
|
24
|
+
* @see https://raf-query.katt.dev/docs/query-invalidation
|
|
25
|
+
*/
|
|
26
|
+
function invalidateOne(client, factory, ...input) {
|
|
27
|
+
return invalidate(client, (at) => [entryStamp(hashOf(factory, input[0]), at)]);
|
|
28
|
+
}
|
|
29
|
+
function invalidateMany(client, target, partial) {
|
|
30
|
+
return invalidate(client, (at) => stampsOf(target, partial, at));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Mark every query stale; read ones refetch. For sign-out, or after any write.
|
|
34
|
+
*
|
|
35
|
+
* @see https://raf-query.katt.dev/docs/query-invalidation
|
|
36
|
+
*/
|
|
37
|
+
function invalidateAll(client) {
|
|
38
|
+
return invalidate(client, (at) => [{
|
|
39
|
+
at,
|
|
40
|
+
kind: "all"
|
|
41
|
+
}]);
|
|
42
|
+
}
|
|
43
|
+
function oneEntry(client, factory, input) {
|
|
44
|
+
return client["~entries"].get(hashOf(factory, input));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Drop one query's data and error. If it's read, it suspends and refetches;
|
|
48
|
+
* resolves when that settles.
|
|
49
|
+
*
|
|
50
|
+
* @see https://raf-query.katt.dev/docs/query-invalidation#invalidate-reset-or-remove
|
|
51
|
+
*/
|
|
52
|
+
function resetOne(client, factory, ...input) {
|
|
53
|
+
const entry = oneEntry(client, factory, input[0]);
|
|
54
|
+
return settle(entry ? [reset(entry)] : []);
|
|
55
|
+
}
|
|
56
|
+
function resetMany(client, target, partial) {
|
|
57
|
+
return settle(entriesMatching(client, stampsOf(target, partial, 0)).map(reset));
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* {@link resetOne} for every query.
|
|
61
|
+
*
|
|
62
|
+
* @see https://raf-query.katt.dev/docs/query-invalidation#invalidate-reset-or-remove
|
|
63
|
+
*/
|
|
64
|
+
function resetAll(client) {
|
|
65
|
+
return settle([...client["~entries"].values()].map(reset));
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Remove one query from the cache, aborting its request.
|
|
69
|
+
*
|
|
70
|
+
* @see https://raf-query.katt.dev/docs/query-invalidation#invalidate-reset-or-remove
|
|
71
|
+
*/
|
|
72
|
+
function removeOne(client, factory, ...input) {
|
|
73
|
+
const entry = oneEntry(client, factory, input[0]);
|
|
74
|
+
if (entry) remove(entry);
|
|
75
|
+
}
|
|
76
|
+
function removeMany(client, target, partial) {
|
|
77
|
+
for (const entry of entriesMatching(client, stampsOf(target, partial, 0))) remove(entry);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Remove every query, aborting their requests.
|
|
81
|
+
*
|
|
82
|
+
* @see https://raf-query.katt.dev/docs/query-invalidation#invalidate-reset-or-remove
|
|
83
|
+
*/
|
|
84
|
+
function removeAll(client) {
|
|
85
|
+
for (const entry of client["~entries"].values()) remove(entry);
|
|
86
|
+
}
|
|
87
|
+
function setData(client, factory, ...args) {
|
|
88
|
+
const [input, updater] = args.length < 2 ? [void 0, args[0]] : args;
|
|
89
|
+
const entry = entryOf(client, factory, input);
|
|
90
|
+
const previous = entry.state.hasData ? entry.state.data : void 0;
|
|
91
|
+
const data = isFunction(updater) ? updater(previous) : updater;
|
|
92
|
+
write(entry, data, client.clock.now(), ++client["~seq"]);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* A query's cached data (before `select`), or `undefined`.
|
|
96
|
+
*
|
|
97
|
+
* @see https://raf-query.katt.dev/docs/api-reference#changing-the-cache
|
|
98
|
+
*/
|
|
99
|
+
function getData(client, factory, ...input) {
|
|
100
|
+
const entry = oneEntry(client, factory, input[0]);
|
|
101
|
+
return entry?.state.hasData ? entry.state.data : void 0;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* How many queries have a request in flight, optionally only a factory's, a group's or a target's.
|
|
105
|
+
*
|
|
106
|
+
* @see https://raf-query.katt.dev/docs/background-fetching-indicators
|
|
107
|
+
*/
|
|
108
|
+
function isFetching(client, target) {
|
|
109
|
+
return entriesMatching(client, [target === void 0 ? {
|
|
110
|
+
at: 0,
|
|
111
|
+
kind: "all"
|
|
112
|
+
} : stampFor(target, void 0, 0)]).filter((entry) => entry.state.isFetching).length;
|
|
113
|
+
}
|
|
114
|
+
//#endregion
|
|
115
|
+
export { getData, invalidateAll, invalidateMany, invalidateOne, isFetching, removeAll, removeMany, removeOne, resetAll, resetMany, resetOne, setData };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raf-query/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Framework-agnostic core of raf-query, a render-as-you-fetch query library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"query",
|
|
@@ -31,18 +31,22 @@
|
|
|
31
31
|
"type": "module",
|
|
32
32
|
"sideEffects": false,
|
|
33
33
|
"exports": {
|
|
34
|
-
".": "./dist/index.mjs"
|
|
35
|
-
|
|
36
|
-
"peerDependencies": {
|
|
37
|
-
"effect": "^4.0.0"
|
|
34
|
+
".": "./dist/index.mjs",
|
|
35
|
+
"./internal": "./dist/internal.mjs"
|
|
38
36
|
},
|
|
39
37
|
"devDependencies": {
|
|
40
|
-
"@
|
|
38
|
+
"@testing-library/react": "16.3.3",
|
|
41
39
|
"@types/node": "26.6.4",
|
|
40
|
+
"@types/react": "19.3.0",
|
|
41
|
+
"@types/react-dom": "19.3.0",
|
|
42
42
|
"@vitest/coverage-v8": "5.0.1",
|
|
43
|
-
"
|
|
43
|
+
"fast-check": "4.10.2",
|
|
44
|
+
"happy-dom": "21.0.1",
|
|
45
|
+
"react": "19.3.0",
|
|
46
|
+
"react-dom": "19.3.0",
|
|
44
47
|
"typescript": "7.0.2",
|
|
45
|
-
"vite-plus": "1.0.0"
|
|
48
|
+
"vite-plus": "1.0.0",
|
|
49
|
+
"vitest": "5.0.1"
|
|
46
50
|
},
|
|
47
51
|
"publishConfig": {
|
|
48
52
|
"access": "public",
|
|
@@ -54,7 +58,7 @@
|
|
|
54
58
|
"scripts": {
|
|
55
59
|
"build": "vp pack",
|
|
56
60
|
"test": "vp test",
|
|
57
|
-
"typecheck": "tsc",
|
|
61
|
+
"typecheck": "tsc && tsc -p tsconfig.no-node.json",
|
|
58
62
|
"publish:npm": "pnpm pack --out package.tgz && npm publish package.tgz --access public && rm package.tgz"
|
|
59
63
|
}
|
|
60
64
|
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
//#region \0rolldown/runtime.js
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __exportAll = (all, no_symbols) => {
|
|
4
|
-
let target = {};
|
|
5
|
-
for (var name in all) __defProp(target, name, {
|
|
6
|
-
get: all[name],
|
|
7
|
-
enumerable: true
|
|
8
|
-
});
|
|
9
|
-
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
10
|
-
return target;
|
|
11
|
-
};
|
|
12
|
-
//#endregion
|
|
13
|
-
export { __exportAll };
|
package/dist/all-keyed.d.mts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
//#region src/all-keyed.d.ts
|
|
2
|
-
/** The resolved form of a record passed to {@link allKeyed}. */
|
|
3
|
-
export type Settled<TRecord> = { -readonly [TKey in keyof TRecord]: Awaited<TRecord[TKey]>; };
|
|
4
|
-
/**
|
|
5
|
-
* Ponyfill of the TC39 `Promise.allKeyed` proposal: a record of promises in,
|
|
6
|
-
* a promise of the same record out, rejecting on the first failure.
|
|
7
|
-
*
|
|
8
|
-
* ```ts
|
|
9
|
-
* const data = await allKeyed({
|
|
10
|
-
* post: qc.ensure(postQuery, { slug }),
|
|
11
|
-
* author: qc.ensure(authorQuery, { slug }),
|
|
12
|
-
* });
|
|
13
|
-
* ```
|
|
14
|
-
*/
|
|
15
|
-
export declare function allKeyed<TRecord extends {
|
|
16
|
-
readonly [key: string]: unknown;
|
|
17
|
-
}>(record: TRecord): Promise<Settled<TRecord>>;
|
|
18
|
-
//#endregion
|