@fozy-labs/rx-toolkit 0.5.3-rc.1 → 0.5.3
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/LICENSE +21 -21
- package/README.md +143 -137
- package/dist/common/devtools/combineDevtools.js +3 -3
- package/dist/common/devtools/index.d.ts +3 -3
- package/dist/common/devtools/index.js +3 -3
- package/dist/common/devtools/reduxDevtools.d.ts +1 -1
- package/dist/common/devtools/reduxDevtools.js +17 -17
- package/dist/common/devtools/types.d.ts +0 -6
- package/dist/common/options/DefaultOptions.d.ts +1 -1
- package/dist/common/options/SharedOptions.d.ts +3 -2
- package/dist/common/options/SharedOptions.js +6 -0
- package/dist/common/options/index.d.ts +1 -1
- package/dist/common/options/index.js +1 -1
- package/dist/common/react/index.d.ts +2 -2
- package/dist/common/react/index.js +2 -2
- package/dist/common/react/useConstant.js +1 -1
- package/dist/common/utils/deepEqual.js +1 -1
- package/dist/common/utils/index.d.ts +3 -3
- package/dist/common/utils/index.js +3 -3
- package/dist/common/utils/shallowEqual.js +1 -1
- package/dist/index.d.ts +8 -7
- package/dist/index.js +8 -7
- package/dist/query/SKIP_TOKEN.js +1 -1
- package/dist/query/api/createCommand.d.ts +21 -0
- package/dist/query/api/createCommand.js +20 -0
- package/dist/query/api/createOperation.d.ts +5 -3
- package/dist/query/api/createOperation.js +6 -2
- package/dist/query/api/createResource.d.ts +2 -2
- package/dist/query/api/createResourceDuplicator.d.ts +2 -2
- package/dist/query/core/Command/Command.d.ts +35 -0
- package/dist/query/core/{Opertation/Operation.js → Command/Command.js} +13 -14
- package/dist/query/core/Command/CommandAgent.d.ts +19 -0
- package/dist/query/core/{Opertation/OperationAgent.js → Command/CommandAgent.js} +13 -13
- package/dist/query/core/Command/index.d.ts +2 -0
- package/dist/query/core/Command/index.js +2 -0
- package/dist/query/core/Operation/Operation.d.ts +8 -0
- package/dist/query/core/Operation/Operation.js +4 -0
- package/dist/query/core/Operation/OperationAgent.d.ts +4 -0
- package/dist/query/core/Operation/OperationAgent.js +4 -0
- package/dist/query/core/QueriesCache.d.ts +2 -2
- package/dist/query/core/QueriesCache.js +1 -1
- package/dist/query/core/QueriesLifetimeHooks.d.ts +1 -1
- package/dist/query/core/QueriesLifetimeHooks.js +7 -7
- package/dist/query/core/Resource/Resource.d.ts +16 -16
- package/dist/query/core/Resource/Resource.js +7 -7
- package/dist/query/core/Resource/ResourceAgent.d.ts +2 -2
- package/dist/query/core/Resource/ResourceAgent.js +3 -3
- package/dist/query/core/Resource/ResourceDuplicator.d.ts +17 -17
- package/dist/query/core/Resource/ResourceDuplicator.js +18 -20
- package/dist/query/core/Resource/ResourceDuplicatorAgent.d.ts +6 -6
- package/dist/query/core/Resource/ResourceDuplicatorAgent.js +3 -3
- package/dist/query/core/Resource/ResourceRef.d.ts +2 -2
- package/dist/query/core/Resource/ResourceRef.js +12 -12
- package/dist/query/index.d.ts +11 -8
- package/dist/query/index.js +14 -8
- package/dist/query/lib/IndirectMap.js +4 -4
- package/dist/query/lib/ReactiveCache.d.ts +1 -1
- package/dist/query/react/useCommandAgent.d.ts +24 -0
- package/dist/query/react/useCommandAgent.js +39 -0
- package/dist/query/react/useOperationAgent.d.ts +6 -8
- package/dist/query/react/useOperationAgent.js +6 -23
- package/dist/query/react/useResourceAgent.d.ts +4 -4
- package/dist/query/react/useResourceAgent.js +1 -1
- package/dist/query/react/useResourceRef.d.ts +3 -3
- package/dist/query/react/useResourceRef.js +7 -2
- package/dist/query/types/Command.types.d.ts +154 -0
- package/dist/query/types/Command.types.js +1 -0
- package/dist/query/types/Operation.types.d.ts +13 -154
- package/dist/query/types/Resource.types.d.ts +7 -5
- package/dist/query/types/index.d.ts +4 -3
- package/dist/query/types/index.js +5 -3
- package/dist/query-v2/api/createApi.d.ts +10 -0
- package/dist/query-v2/api/createApi.js +83 -0
- package/dist/query-v2/core/common/CacheEntry.d.ts +29 -0
- package/dist/query-v2/core/common/CacheEntry.js +71 -0
- package/dist/query-v2/core/common/CacheMap.d.ts +38 -0
- package/dist/query-v2/core/common/CacheMap.js +127 -0
- package/dist/query-v2/core/common/LifecycleHooks.d.ts +22 -0
- package/dist/query-v2/core/common/LifecycleHooks.js +104 -0
- package/dist/query-v2/core/common/index.d.ts +3 -0
- package/dist/query-v2/core/common/index.js +3 -0
- package/dist/query-v2/core/index.d.ts +3 -0
- package/dist/query-v2/core/index.js +3 -0
- package/dist/query-v2/core/machines/Machine.d.ts +14 -0
- package/dist/query-v2/core/machines/Machine.js +33 -0
- package/dist/query-v2/core/machines/MachineError.d.ts +11 -0
- package/dist/query-v2/core/machines/MachineError.js +26 -0
- package/dist/query-v2/core/machines/MachineIdle.d.ts +8 -0
- package/dist/query-v2/core/machines/MachineIdle.js +19 -0
- package/dist/query-v2/core/machines/MachinePending.d.ts +12 -0
- package/dist/query-v2/core/machines/MachinePending.js +29 -0
- package/dist/query-v2/core/machines/MachineRefreshing.d.ts +14 -0
- package/dist/query-v2/core/machines/MachineRefreshing.js +46 -0
- package/dist/query-v2/core/machines/MachineSuccess.d.ts +16 -0
- package/dist/query-v2/core/machines/MachineSuccess.js +42 -0
- package/dist/query-v2/core/machines/MachineWithData.d.ts +18 -0
- package/dist/query-v2/core/machines/MachineWithData.js +40 -0
- package/dist/query-v2/core/machines/Patcher.d.ts +20 -0
- package/dist/query-v2/core/machines/Patcher.js +104 -0
- package/dist/query-v2/core/machines/index.d.ts +8 -0
- package/dist/query-v2/core/machines/index.js +8 -0
- package/dist/query-v2/core/resource/ResourceV2.d.ts +120 -0
- package/dist/query-v2/core/resource/ResourceV2.js +464 -0
- package/dist/query-v2/core/resource/ResourceV2Agent.d.ts +26 -0
- package/dist/query-v2/core/resource/ResourceV2Agent.js +132 -0
- package/dist/query-v2/core/resource/index.d.ts +2 -0
- package/dist/query-v2/core/resource/index.js +2 -0
- package/dist/query-v2/index.d.ts +11 -0
- package/dist/query-v2/index.js +17 -0
- package/dist/query-v2/lib/NO_VALUE.d.ts +2 -0
- package/dist/query-v2/lib/NO_VALUE.js +1 -0
- package/dist/query-v2/lib/SKIP_TOKEN.d.ts +2 -0
- package/dist/query-v2/lib/SKIP_TOKEN.js +1 -0
- package/dist/query-v2/lib/index.d.ts +4 -0
- package/dist/query-v2/lib/index.js +3 -0
- package/dist/query-v2/lib/stableStringify.d.ts +8 -0
- package/dist/query-v2/lib/stableStringify.js +23 -0
- package/dist/query-v2/plugins/ReactHooksPlugin.d.ts +25 -0
- package/dist/query-v2/plugins/ReactHooksPlugin.js +19 -0
- package/dist/query-v2/plugins/types.d.ts +1 -0
- package/dist/query-v2/plugins/types.js +1 -0
- package/dist/query-v2/react/__tests__/helpers.d.ts +12 -0
- package/dist/query-v2/react/__tests__/helpers.js +33 -0
- package/dist/query-v2/react/index.d.ts +2 -0
- package/dist/query-v2/react/index.js +2 -0
- package/dist/query-v2/react/useResourceV2Agent.d.ts +12 -0
- package/dist/query-v2/react/useResourceV2Agent.js +36 -0
- package/dist/query-v2/react/useResourceV2Ref.d.ts +12 -0
- package/dist/query-v2/react/useResourceV2Ref.js +57 -0
- package/dist/query-v2/snapshot/Snapshot.d.ts +13 -0
- package/dist/query-v2/snapshot/Snapshot.js +76 -0
- package/dist/query-v2/types/agent.types.d.ts +54 -0
- package/dist/query-v2/types/agent.types.js +1 -0
- package/dist/query-v2/types/api.types.d.ts +22 -0
- package/dist/query-v2/types/api.types.js +1 -0
- package/dist/query-v2/types/cache.types.d.ts +37 -0
- package/dist/query-v2/types/cache.types.js +1 -0
- package/dist/query-v2/types/index.d.ts +9 -0
- package/dist/query-v2/types/index.js +9 -0
- package/dist/query-v2/types/lifecycle.types.d.ts +25 -0
- package/dist/query-v2/types/lifecycle.types.js +1 -0
- package/dist/query-v2/types/machine.types.d.ts +67 -0
- package/dist/query-v2/types/machine.types.js +1 -0
- package/dist/query-v2/types/plugin.types.d.ts +38 -0
- package/dist/query-v2/types/plugin.types.js +1 -0
- package/dist/query-v2/types/resource.types.d.ts +35 -0
- package/dist/query-v2/types/resource.types.js +1 -0
- package/dist/query-v2/types/shared.types.d.ts +20 -0
- package/dist/query-v2/types/shared.types.js +1 -0
- package/dist/query-v2/types/snapshot.types.d.ts +21 -0
- package/dist/query-v2/types/snapshot.types.js +1 -0
- package/dist/signals/base/Batcher.js +9 -5
- package/dist/signals/base/ComputeCache.js +3 -3
- package/dist/signals/base/DependencyTracker.js +1 -1
- package/dist/signals/base/Devtools.d.ts +3 -2
- package/dist/signals/base/Devtools.js +54 -27
- package/dist/signals/base/Indexer.js +1 -1
- package/dist/signals/base/ReadonlySignal.js +1 -1
- package/dist/signals/base/SyncObservable.d.ts +1 -2
- package/dist/signals/base/SyncObservable.js +2 -5
- package/dist/signals/base/index.d.ts +6 -6
- package/dist/signals/base/index.js +6 -6
- package/dist/signals/index.d.ts +5 -4
- package/dist/signals/index.js +5 -4
- package/dist/signals/operators/index.d.ts +1 -1
- package/dist/signals/operators/index.js +1 -1
- package/dist/signals/operators/signalize.d.ts +1 -1
- package/dist/signals/react/index.d.ts +1 -1
- package/dist/signals/react/index.js +1 -1
- package/dist/signals/signals/Computed.d.ts +3 -4
- package/dist/signals/signals/Computed.js +18 -10
- package/dist/signals/signals/Effect.js +2 -1
- package/dist/signals/signals/LocalState.d.ts +44 -0
- package/dist/signals/signals/{LocalSignal.js → LocalState.js} +62 -28
- package/dist/signals/signals/Signal.d.ts +8 -7
- package/dist/signals/signals/Signal.js +4 -1
- package/dist/signals/signals/State.d.ts +4 -5
- package/dist/signals/signals/State.js +23 -9
- package/dist/signals/signals/index.d.ts +5 -5
- package/dist/signals/signals/index.js +5 -6
- package/dist/signals/types/SignalOptions.d.ts +16 -0
- package/dist/signals/types/SignalOptions.js +1 -0
- package/dist/signals/types/index.d.ts +3 -1
- package/dist/signals/types/index.js +3 -1
- package/dist/signals/types/normalizeSignalOptions.d.ts +2 -0
- package/dist/signals/types/normalizeSignalOptions.js +10 -0
- package/dist/signals/types/signals.types.d.ts +6 -2
- package/docs/CHANGELOG.md +111 -32
- package/docs/CONTRIBUTING.md +230 -0
- package/docs/contributing/ai-assisted-development.md +47 -0
- package/docs/contributing/query-v2/README.md +379 -0
- package/docs/{release → contributing/release}/README.md +59 -59
- package/docs/devtools/README.md +228 -228
- package/docs/migrations/0.5.0.md +58 -58
- package/docs/migrations/query-v2.md +171 -0
- package/docs/options/README.md +92 -90
- package/docs/query/README.md +575 -571
- package/docs/query-v2/README.md +280 -0
- package/docs/query-v2/api-reference.md +235 -0
- package/docs/query-v2/optimistic-updates.md +148 -0
- package/docs/query-v2/ssr.md +130 -0
- package/docs/signals/README.md +300 -295
- package/docs/usage/react/README.md +309 -307
- package/package.json +86 -63
- package/dist/query/core/Opertation/Operation.d.ts +0 -35
- package/dist/query/core/Opertation/OperationAgent.d.ts +0 -19
- package/dist/signals/signals/LocalSignal.d.ts +0 -32
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { SKIP } from "../../../query-v2/lib/SKIP_TOKEN";
|
|
2
|
+
import { Signal } from "../../../signals";
|
|
3
|
+
/**
|
|
4
|
+
* Agent that tracks a single cache entry with reactive state, designed for React hook consumption.
|
|
5
|
+
* Provides SWR (stale-while-revalidate) semantics by keeping previous data while new data loads.
|
|
6
|
+
*/
|
|
7
|
+
export class ResourceV2Agent {
|
|
8
|
+
_resource;
|
|
9
|
+
_tracking$;
|
|
10
|
+
_refreshError$;
|
|
11
|
+
_state$;
|
|
12
|
+
_unsubRefreshError;
|
|
13
|
+
_currentArgs = null;
|
|
14
|
+
constructor(resource) {
|
|
15
|
+
this._resource = resource;
|
|
16
|
+
// Agent signals are internal derived state for React hooks — only CacheEntry signals belong in devtools
|
|
17
|
+
this._tracking$ = Signal.state({ previous: null, current: null }, { isDisabled: true });
|
|
18
|
+
// Agent signal — excluded from devtools; only CacheEntry signals represent canonical cache state
|
|
19
|
+
this._refreshError$ = Signal.state(null, { isDisabled: true });
|
|
20
|
+
// Subscribe to refresh errors from the resource
|
|
21
|
+
this._unsubRefreshError = this._resource.onRefreshError((args, error) => {
|
|
22
|
+
if (this._currentArgs !== null && this._resource.compareArgs(this._currentArgs, args)) {
|
|
23
|
+
this._refreshError$.set(error);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
// Agent signal — excluded from devtools; only CacheEntry signals represent canonical cache state
|
|
27
|
+
this._state$ = Signal.compute(() => {
|
|
28
|
+
const { previous, current } = this._tracking$();
|
|
29
|
+
if (!current) {
|
|
30
|
+
return {
|
|
31
|
+
status: "idle",
|
|
32
|
+
data: null,
|
|
33
|
+
error: null,
|
|
34
|
+
args: null,
|
|
35
|
+
isLoading: false,
|
|
36
|
+
isInitialLoading: false,
|
|
37
|
+
isRefreshing: false,
|
|
38
|
+
isSuccess: false,
|
|
39
|
+
isError: false,
|
|
40
|
+
refreshError: this._refreshError$(),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// Read machine$ reactively — this is the key reactive subscription
|
|
44
|
+
const machine = current.machine$();
|
|
45
|
+
const machineState = machine.state;
|
|
46
|
+
const status = machineState.status;
|
|
47
|
+
// Determine previous data for SWR
|
|
48
|
+
let previousData = null;
|
|
49
|
+
if (previous) {
|
|
50
|
+
const prevMachine = previous.machine$();
|
|
51
|
+
const prevState = prevMachine.state;
|
|
52
|
+
if (prevState.data != null) {
|
|
53
|
+
previousData = prevState.data;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const currentData = machineState.data;
|
|
57
|
+
const isLoading = status === "pending" || status === "refreshing";
|
|
58
|
+
const isRefreshing = status === "refreshing";
|
|
59
|
+
// SWR: use previous data if current is loading and has no data yet
|
|
60
|
+
const data = currentData ?? (isLoading ? previousData : null);
|
|
61
|
+
const hasPreviousData = previousData !== null;
|
|
62
|
+
const isInitialLoading = isLoading && !hasPreviousData && currentData === null;
|
|
63
|
+
const isSuccess = data !== null;
|
|
64
|
+
const isError = status === "error";
|
|
65
|
+
const error = isError ? machineState.error : null;
|
|
66
|
+
return {
|
|
67
|
+
status,
|
|
68
|
+
data,
|
|
69
|
+
error,
|
|
70
|
+
args: machineState.args ?? null,
|
|
71
|
+
isLoading,
|
|
72
|
+
isInitialLoading,
|
|
73
|
+
isRefreshing,
|
|
74
|
+
isSuccess,
|
|
75
|
+
isError,
|
|
76
|
+
refreshError: this._refreshError$(),
|
|
77
|
+
};
|
|
78
|
+
}, { isDisabled: true });
|
|
79
|
+
}
|
|
80
|
+
/** Computed reactive state signal — projects CacheEntry machine state into a flat agent state object. */
|
|
81
|
+
get state$() {
|
|
82
|
+
return this._state$;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Start (or re-start) the agent with new args. Skips if args are unchanged.
|
|
86
|
+
*
|
|
87
|
+
* @param args - Query arguments, or `SKIP_TOKEN` to do nothing.
|
|
88
|
+
*/
|
|
89
|
+
async start(args) {
|
|
90
|
+
// SKIP: no-op
|
|
91
|
+
if (args === SKIP) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const typedArgs = args;
|
|
95
|
+
// Same args check — skip if unchanged
|
|
96
|
+
if (this._currentArgs !== null && this._resource.compareArgs(this._currentArgs, typedArgs)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
this._currentArgs = typedArgs;
|
|
100
|
+
// Query the resource — get a cache entry
|
|
101
|
+
const entryPromise = this._resource.query(typedArgs);
|
|
102
|
+
// Get the entry synchronously from the resource
|
|
103
|
+
const entry = this._resource.entry(typedArgs);
|
|
104
|
+
// Swap previous/current
|
|
105
|
+
const oldTracking = this._tracking$.peek();
|
|
106
|
+
this._tracking$.set({
|
|
107
|
+
previous: oldTracking.current,
|
|
108
|
+
current: entry,
|
|
109
|
+
});
|
|
110
|
+
// Wait for the query to resolve and then clear previous
|
|
111
|
+
try {
|
|
112
|
+
await entryPromise;
|
|
113
|
+
// Clear refreshError on successful query completion
|
|
114
|
+
this._refreshError$.set(null);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// query() shouldn't reject, but handle gracefully
|
|
118
|
+
}
|
|
119
|
+
// Clear previous after current resolves (success or error)
|
|
120
|
+
// Only if current hasn't changed (latest-wins)
|
|
121
|
+
const currentTracking = this._tracking$.peek();
|
|
122
|
+
if (currentTracking.current === entry) {
|
|
123
|
+
this._tracking$.set({
|
|
124
|
+
previous: null,
|
|
125
|
+
current: entry,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
compareArgs(a, b) {
|
|
130
|
+
return this._resource.compareArgs(a, b);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { SKIP, type SKIP_TOKEN } from "./lib/SKIP_TOKEN";
|
|
2
|
+
export { NO_VALUE } from "./lib/NO_VALUE";
|
|
3
|
+
export type { NO_VALUE as NO_VALUE_TYPE } from "./lib/NO_VALUE";
|
|
4
|
+
export { stableStringify } from "./lib/stableStringify";
|
|
5
|
+
export { Machine, type TMachineInstance, MachineIdle, MachinePending, MachineSuccess, MachineError, MachineRefreshing, MachineWithData, Patcher, CacheEntry, type CacheEntryOptions, CacheMap, type TCacheMapInstance, LifecycleHooks, ResourceV2, type ResourceV2Config, ResourceV2Agent, } from "./core";
|
|
6
|
+
export { createApi } from "./api/createApi";
|
|
7
|
+
export { ReactHooksPlugin } from "./plugins/ReactHooksPlugin";
|
|
8
|
+
export type { IReactHooksPluginContributions } from "./plugins/ReactHooksPlugin";
|
|
9
|
+
export { useResourceV2Agent, useResourceV2Ref } from "./react";
|
|
10
|
+
export { getSnapshot, hydrateSnapshot, CURRENT_SNAPSHOT_VERSION } from "./snapshot/Snapshot";
|
|
11
|
+
export * from "./types";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Sentinel tokens
|
|
2
|
+
export { SKIP } from "./lib/SKIP_TOKEN";
|
|
3
|
+
export { NO_VALUE } from "./lib/NO_VALUE";
|
|
4
|
+
// Utilities
|
|
5
|
+
export { stableStringify } from "./lib/stableStringify";
|
|
6
|
+
// Core — Machine classes
|
|
7
|
+
export { Machine, MachineIdle, MachinePending, MachineSuccess, MachineError, MachineRefreshing, MachineWithData, Patcher, CacheEntry, CacheMap, LifecycleHooks, ResourceV2, ResourceV2Agent, } from "./core";
|
|
8
|
+
// API factory
|
|
9
|
+
export { createApi } from "./api/createApi";
|
|
10
|
+
// Plugins
|
|
11
|
+
export { ReactHooksPlugin } from "./plugins/ReactHooksPlugin";
|
|
12
|
+
// React hooks (standalone)
|
|
13
|
+
export { useResourceV2Agent, useResourceV2Ref } from "./react";
|
|
14
|
+
// Snapshot
|
|
15
|
+
export { getSnapshot, hydrateSnapshot, CURRENT_SNAPSHOT_VERSION } from "./snapshot/Snapshot";
|
|
16
|
+
// Types
|
|
17
|
+
export * from "./types";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const NO_VALUE = Symbol("NO_VALUE");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const SKIP = Symbol("SKIP");
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic JSON.stringify with sorted object keys.
|
|
3
|
+
* Used as the default serializeArgs for the 'serialize' key strategy.
|
|
4
|
+
*
|
|
5
|
+
* Handles: plain objects, arrays, primitives, null, undefined, nested structures.
|
|
6
|
+
* Does NOT handle: Date, Map, Set, RegExp (documented limitation).
|
|
7
|
+
*/
|
|
8
|
+
export declare function stableStringify(value: unknown): string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
function isPlainObject(value) {
|
|
2
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Deterministic JSON.stringify with sorted object keys.
|
|
6
|
+
* Used as the default serializeArgs for the 'serialize' key strategy.
|
|
7
|
+
*
|
|
8
|
+
* Handles: plain objects, arrays, primitives, null, undefined, nested structures.
|
|
9
|
+
* Does NOT handle: Date, Map, Set, RegExp (documented limitation).
|
|
10
|
+
*/
|
|
11
|
+
export function stableStringify(value) {
|
|
12
|
+
return JSON.stringify(value, (_, val) => {
|
|
13
|
+
if (isPlainObject(val)) {
|
|
14
|
+
return Object.keys(val)
|
|
15
|
+
.sort()
|
|
16
|
+
.reduce((acc, key) => {
|
|
17
|
+
acc[key] = val[key];
|
|
18
|
+
return acc;
|
|
19
|
+
}, {});
|
|
20
|
+
}
|
|
21
|
+
return val;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ResourceV2 } from "../../query-v2/core/resource/ResourceV2";
|
|
2
|
+
import type { SKIP_TOKEN } from "../../query-v2/lib/SKIP_TOKEN";
|
|
3
|
+
import type { IResourceV2AgentState, IResourceV2Ref } from "../../query-v2/types/agent.types";
|
|
4
|
+
import type { IPlugin, IPluginContext } from "../../query-v2/types/plugin.types";
|
|
5
|
+
import type { IResourceV2Options } from "../../query-v2/types/resource.types";
|
|
6
|
+
/** Contributions added by ReactHooksPlugin to resources */
|
|
7
|
+
export interface IReactHooksPluginContributions<TArgs, TData, TError = Error> {
|
|
8
|
+
useResourceV2Agent(args: TArgs | SKIP_TOKEN): IResourceV2AgentState<TArgs, TData, TError>;
|
|
9
|
+
useResourceV2Ref(args: TArgs | SKIP_TOKEN): IResourceV2Ref<TArgs, TData, TError>;
|
|
10
|
+
}
|
|
11
|
+
declare module "../../query-v2/types/plugin.types" {
|
|
12
|
+
interface PluginContributionMap<TArgs, TData, TError> {
|
|
13
|
+
ReactHooksPlugin: IReactHooksPluginContributions<TArgs, TData, TError>;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Plugin that attaches `useResourceV2Agent` and `useResourceV2Ref` as methods on resources via `augmentResource`.
|
|
18
|
+
* Standalone imports from `@/query-v2/react/` are available as an alternative without requiring this plugin.
|
|
19
|
+
*/
|
|
20
|
+
export declare class ReactHooksPlugin implements IPlugin {
|
|
21
|
+
readonly name: "ReactHooksPlugin";
|
|
22
|
+
private _context;
|
|
23
|
+
install(context: IPluginContext): void;
|
|
24
|
+
augmentResource<TArgs, TData, TError>(res: ResourceV2<TArgs, TData, TError>, _options: IResourceV2Options<TArgs, TData, TError>): Record<string, unknown>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useResourceV2Agent } from "../../query-v2/react/useResourceV2Agent";
|
|
2
|
+
import { useResourceV2Ref } from "../../query-v2/react/useResourceV2Ref";
|
|
3
|
+
/**
|
|
4
|
+
* Plugin that attaches `useResourceV2Agent` and `useResourceV2Ref` as methods on resources via `augmentResource`.
|
|
5
|
+
* Standalone imports from `@/query-v2/react/` are available as an alternative without requiring this plugin.
|
|
6
|
+
*/
|
|
7
|
+
export class ReactHooksPlugin {
|
|
8
|
+
name = "ReactHooksPlugin";
|
|
9
|
+
_context = null;
|
|
10
|
+
install(context) {
|
|
11
|
+
this._context = context;
|
|
12
|
+
}
|
|
13
|
+
augmentResource(res, _options) {
|
|
14
|
+
return {
|
|
15
|
+
useResourceV2Agent: (args) => useResourceV2Agent(res, args),
|
|
16
|
+
useResourceV2Ref: (args) => useResourceV2Ref(res, args),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { IPlugin, IPluginContext, ExtractPluginContributions, PluginAugmentations, } from "../../query-v2/types/plugin.types";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ResourceV2, type ResourceV2Config } from "../../../query-v2/core/resource/ResourceV2";
|
|
2
|
+
export declare function controllableQueryFn<TArgs = unknown, TData = unknown>(): {
|
|
3
|
+
fn: import("vitest").Mock<(args: TArgs, { abortSignal }: {
|
|
4
|
+
abortSignal: AbortSignal;
|
|
5
|
+
}) => Promise<TData>>;
|
|
6
|
+
calls: {
|
|
7
|
+
args: TArgs;
|
|
8
|
+
resolve: (data: TData) => void;
|
|
9
|
+
reject: (error: Error) => void;
|
|
10
|
+
}[];
|
|
11
|
+
};
|
|
12
|
+
export declare function createTestResource<TArgs = unknown, TData = unknown, TError = Error>(config: Partial<ResourceV2Config<TArgs, TData, TError>> & Pick<ResourceV2Config<TArgs, TData, TError>, "queryFn">): ResourceV2<TArgs, TData, TError>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { vi } from "vitest";
|
|
2
|
+
import { ResourceV2 } from "../../../query-v2/core/resource/ResourceV2";
|
|
3
|
+
export function controllableQueryFn() {
|
|
4
|
+
const calls = [];
|
|
5
|
+
const fn = vi.fn((args, { abortSignal }) => {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
let settled = false;
|
|
8
|
+
const wrappedResolve = (data) => {
|
|
9
|
+
if (!settled) {
|
|
10
|
+
settled = true;
|
|
11
|
+
resolve(data);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const wrappedReject = (error) => {
|
|
15
|
+
if (!settled) {
|
|
16
|
+
settled = true;
|
|
17
|
+
reject(error);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
calls.push({ args, resolve: wrappedResolve, reject: wrappedReject });
|
|
21
|
+
abortSignal.addEventListener("abort", () => {
|
|
22
|
+
wrappedReject(new DOMException("Aborted", "AbortError"));
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
return { fn, calls };
|
|
27
|
+
}
|
|
28
|
+
export function createTestResource(config) {
|
|
29
|
+
return new ResourceV2({
|
|
30
|
+
key: "test-resource",
|
|
31
|
+
...config,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ResourceV2 } from "../../query-v2/core/resource/ResourceV2";
|
|
2
|
+
import { type SKIP_TOKEN } from "../../query-v2/lib/SKIP_TOKEN";
|
|
3
|
+
import type { IResourceV2AgentState } from "../../query-v2/types/agent.types";
|
|
4
|
+
/**
|
|
5
|
+
* React hook that creates a ResourceV2Agent and returns its reactive state (SWR).
|
|
6
|
+
*
|
|
7
|
+
* @param resource - The resource to observe.
|
|
8
|
+
* @param args - Query arguments, or `SKIP_TOKEN` to skip the query.
|
|
9
|
+
* @returns Reactive agent state with `data`, `error`, status flags, etc.
|
|
10
|
+
* @see docs/query-v2/README.md
|
|
11
|
+
*/
|
|
12
|
+
export declare function useResourceV2Agent<TArgs, TData, TError>(resource: ResourceV2<TArgs, TData, TError>, args: TArgs | SKIP_TOKEN): IResourceV2AgentState<TArgs, TData, TError>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useConstant } from "../../common/react/useConstant";
|
|
3
|
+
import { SKIP } from "../../query-v2/lib/SKIP_TOKEN";
|
|
4
|
+
import { useSignal } from "../../signals/react/useSignal";
|
|
5
|
+
/**
|
|
6
|
+
* React hook that creates a ResourceV2Agent and returns its reactive state (SWR).
|
|
7
|
+
*
|
|
8
|
+
* @param resource - The resource to observe.
|
|
9
|
+
* @param args - Query arguments, or `SKIP_TOKEN` to skip the query.
|
|
10
|
+
* @returns Reactive agent state with `data`, `error`, status flags, etc.
|
|
11
|
+
* @see docs/query-v2/README.md
|
|
12
|
+
*/
|
|
13
|
+
export function useResourceV2Agent(resource, args) {
|
|
14
|
+
const prevArgsRef = React.useRef(SKIP);
|
|
15
|
+
const agent = useConstant(() => {
|
|
16
|
+
const agent = resource.createAgent();
|
|
17
|
+
if (args !== SKIP) {
|
|
18
|
+
agent.start(args);
|
|
19
|
+
}
|
|
20
|
+
return agent;
|
|
21
|
+
});
|
|
22
|
+
if (!compareArgs(args, prevArgsRef.current, resource)) {
|
|
23
|
+
prevArgsRef.current = args;
|
|
24
|
+
if (args !== SKIP) {
|
|
25
|
+
agent.start(args);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return useSignal(agent.state$);
|
|
29
|
+
}
|
|
30
|
+
function compareArgs(args, prevArgs, resource) {
|
|
31
|
+
if (args === SKIP && prevArgs === SKIP)
|
|
32
|
+
return true;
|
|
33
|
+
if (args === SKIP || prevArgs === SKIP)
|
|
34
|
+
return false;
|
|
35
|
+
return resource.compareArgs(args, prevArgs);
|
|
36
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ResourceV2 } from "../../query-v2/core/resource/ResourceV2";
|
|
2
|
+
import { type SKIP_TOKEN } from "../../query-v2/lib/SKIP_TOKEN";
|
|
3
|
+
import type { IResourceV2Ref } from "../../query-v2/types/agent.types";
|
|
4
|
+
/**
|
|
5
|
+
* React hook that provides an imperative ref handle for a cache entry (lock, invalidate, patch, create).
|
|
6
|
+
*
|
|
7
|
+
* @param resource - The resource to access.
|
|
8
|
+
* @param args - Query arguments, or `SKIP_TOKEN` to return a no-op ref.
|
|
9
|
+
* @returns Imperative ref with `has`, `lock`, `invalidate`, `createPatch`, `create`.
|
|
10
|
+
* @see docs/query-v2/optimistic-updates.md
|
|
11
|
+
*/
|
|
12
|
+
export declare function useResourceV2Ref<TArgs, TData, TError>(resource: ResourceV2<TArgs, TData, TError>, args: TArgs | SKIP_TOKEN): IResourceV2Ref<TArgs, TData, TError>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { shallowEqual } from "../../common/utils/shallowEqual";
|
|
3
|
+
import { SKIP } from "../../query-v2/lib/SKIP_TOKEN";
|
|
4
|
+
/**
|
|
5
|
+
* React hook that provides an imperative ref handle for a cache entry (lock, invalidate, patch, create).
|
|
6
|
+
*
|
|
7
|
+
* @param resource - The resource to access.
|
|
8
|
+
* @param args - Query arguments, or `SKIP_TOKEN` to return a no-op ref.
|
|
9
|
+
* @returns Imperative ref with `has`, `lock`, `invalidate`, `createPatch`, `create`.
|
|
10
|
+
* @see docs/query-v2/optimistic-updates.md
|
|
11
|
+
*/
|
|
12
|
+
export function useResourceV2Ref(resource, args) {
|
|
13
|
+
const stableArgsRef = React.useRef(args);
|
|
14
|
+
if (!shallowEqual(stableArgsRef.current, args)) {
|
|
15
|
+
stableArgsRef.current = args;
|
|
16
|
+
}
|
|
17
|
+
return React.useMemo(() => {
|
|
18
|
+
if (stableArgsRef.current === SKIP) {
|
|
19
|
+
return createSkippedRef();
|
|
20
|
+
}
|
|
21
|
+
return createRefHandle(resource, stableArgsRef.current);
|
|
22
|
+
}, [stableArgsRef.current]);
|
|
23
|
+
}
|
|
24
|
+
function createRefHandle(resource, args) {
|
|
25
|
+
return {
|
|
26
|
+
get has() {
|
|
27
|
+
return resource.hasEntry(args);
|
|
28
|
+
},
|
|
29
|
+
lock() {
|
|
30
|
+
return resource.lockEntry(args);
|
|
31
|
+
},
|
|
32
|
+
invalidate() {
|
|
33
|
+
resource.invalidate(args);
|
|
34
|
+
},
|
|
35
|
+
createPatch(patchFn) {
|
|
36
|
+
return resource.createEntryPatch(args, patchFn);
|
|
37
|
+
},
|
|
38
|
+
create(data) {
|
|
39
|
+
resource.populateEntry(args, data);
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function createSkippedRef() {
|
|
44
|
+
return {
|
|
45
|
+
get has() {
|
|
46
|
+
return false;
|
|
47
|
+
},
|
|
48
|
+
lock() {
|
|
49
|
+
return { unlock: () => { } };
|
|
50
|
+
},
|
|
51
|
+
invalidate() { },
|
|
52
|
+
createPatch() {
|
|
53
|
+
return null;
|
|
54
|
+
},
|
|
55
|
+
create() { },
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ResourceV2 } from "../../query-v2/core/resource/ResourceV2";
|
|
2
|
+
import type { TApiSnapshot } from "../../query-v2/types/snapshot.types";
|
|
3
|
+
export declare const CURRENT_SNAPSHOT_VERSION = 1;
|
|
4
|
+
/**
|
|
5
|
+
* Capture snapshot from all registered resources.
|
|
6
|
+
* Only `MachineSuccess` entries are included (per design §5).
|
|
7
|
+
*/
|
|
8
|
+
export declare function getSnapshot(resources: Map<string, ResourceV2<any, any, any>>, keyPrefix: string | null, keyStrategy: "serialize" | "compare"): TApiSnapshot;
|
|
9
|
+
/**
|
|
10
|
+
* Hydrate resources from a snapshot.
|
|
11
|
+
* Validates version and keyPrefix before applying.
|
|
12
|
+
*/
|
|
13
|
+
export declare function hydrateSnapshot(snapshot: TApiSnapshot, resources: Map<string, ResourceV2<any, any, any>>, apiKeyPrefix: string | null, maxSnapshotDataAge: number): void;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Machine } from "../../query-v2/core/machines/Machine";
|
|
2
|
+
import { MachineSuccess } from "../../query-v2/core/machines/MachineSuccess";
|
|
3
|
+
export const CURRENT_SNAPSHOT_VERSION = 1;
|
|
4
|
+
/**
|
|
5
|
+
* Capture snapshot from all registered resources.
|
|
6
|
+
* Only `MachineSuccess` entries are included (per design §5).
|
|
7
|
+
*/
|
|
8
|
+
export function getSnapshot(resources, keyPrefix, keyStrategy) {
|
|
9
|
+
if (keyStrategy === "compare") {
|
|
10
|
+
throw new Error('getSnapshot() is not supported with keyStrategy "compare". ' +
|
|
11
|
+
'SSR snapshots require keyStrategy "serialize" so that cache keys are serializable strings.');
|
|
12
|
+
}
|
|
13
|
+
const resourceSnapshots = {};
|
|
14
|
+
for (const [resourceKey, resource] of resources) {
|
|
15
|
+
const entries = {};
|
|
16
|
+
let hasEntries = false;
|
|
17
|
+
for (const [key, cacheEntry] of resource.cacheEntries()) {
|
|
18
|
+
const machine = cacheEntry.peek();
|
|
19
|
+
if (!(machine instanceof MachineSuccess))
|
|
20
|
+
continue;
|
|
21
|
+
const state = machine.state;
|
|
22
|
+
entries[key] = {
|
|
23
|
+
status: "success",
|
|
24
|
+
args: state.args,
|
|
25
|
+
data: state.data,
|
|
26
|
+
updatedAt: state.updatedAt,
|
|
27
|
+
};
|
|
28
|
+
hasEntries = true;
|
|
29
|
+
}
|
|
30
|
+
if (hasEntries) {
|
|
31
|
+
resourceSnapshots[resourceKey] = { entries };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
version: CURRENT_SNAPSHOT_VERSION,
|
|
36
|
+
keyPrefix,
|
|
37
|
+
resources: resourceSnapshots,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Hydrate resources from a snapshot.
|
|
42
|
+
* Validates version and keyPrefix before applying.
|
|
43
|
+
*/
|
|
44
|
+
export function hydrateSnapshot(snapshot, resources, apiKeyPrefix, maxSnapshotDataAge) {
|
|
45
|
+
// Fatal: snapshot format incompatibility — the serialization schema has changed between versions.
|
|
46
|
+
// This cannot be recovered from; the snapshot must be regenerated.
|
|
47
|
+
if (snapshot.version !== CURRENT_SNAPSHOT_VERSION) {
|
|
48
|
+
throw new Error(`Snapshot version mismatch: expected ${CURRENT_SNAPSHOT_VERSION}, got ${snapshot.version}. ` +
|
|
49
|
+
`The snapshot format is incompatible with the current version of query-v2.`);
|
|
50
|
+
}
|
|
51
|
+
// Fatal: wrong API instance — the snapshot was created by a different keyPrefix configuration.
|
|
52
|
+
// Applying it would pollute the cache with data from an unrelated API.
|
|
53
|
+
if (snapshot.keyPrefix !== apiKeyPrefix) {
|
|
54
|
+
throw new Error(`Snapshot keyPrefix mismatch: expected "${apiKeyPrefix}", got "${snapshot.keyPrefix}". ` +
|
|
55
|
+
`Ensure the snapshot was created by the same API instance configuration.`);
|
|
56
|
+
}
|
|
57
|
+
const now = Date.now();
|
|
58
|
+
for (const [resourceKey, resourceSnapshot] of Object.entries(snapshot.resources)) {
|
|
59
|
+
const resource = resources.get(resourceKey);
|
|
60
|
+
if (!resource) {
|
|
61
|
+
// Non-fatal: a resource may have been removed between versions — skip gracefully.
|
|
62
|
+
console.warn(`[rx-toolkit] hydrateSnapshot: unknown resource key "${resourceKey}", skipping.`);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
for (const [, slice] of Object.entries(resourceSnapshot.entries)) {
|
|
66
|
+
const machine = Machine.fromSnapshot(slice);
|
|
67
|
+
// Reconstruct args from the slice
|
|
68
|
+
const args = slice.args;
|
|
69
|
+
resource.hydrateEntry(args, machine);
|
|
70
|
+
// S3: stale entries trigger invalidation
|
|
71
|
+
if (now - slice.updatedAt > maxSnapshotDataAge) {
|
|
72
|
+
resource.invalidate(args);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { TMachineStatus, TPatchFn } from "./machine.types";
|
|
2
|
+
/** SKIP_TOKEN type alias for agent args */
|
|
3
|
+
type SKIP_TOKEN = typeof import("../lib/SKIP_TOKEN").SKIP;
|
|
4
|
+
/** Agent — observer with stale-while-revalidate */
|
|
5
|
+
export interface IResourceV2Agent<TArgs, TData, TError = Error> {
|
|
6
|
+
/** Reactive state (computed signal) */
|
|
7
|
+
readonly state$: () => IResourceV2AgentState<TArgs, TData, TError>;
|
|
8
|
+
/** Start query with new args (returns promise) */
|
|
9
|
+
start(args: TArgs | SKIP_TOKEN): Promise<void>;
|
|
10
|
+
/** Compare previous and new args */
|
|
11
|
+
compareArgs(a: TArgs, b: TArgs): boolean;
|
|
12
|
+
}
|
|
13
|
+
/** Agent's computed state shape */
|
|
14
|
+
export interface IResourceV2AgentState<TArgs, TData, TError = Error> {
|
|
15
|
+
/** Current machine status */
|
|
16
|
+
status: TMachineStatus;
|
|
17
|
+
/** Current data (may be stale during loading) */
|
|
18
|
+
data: TData | null;
|
|
19
|
+
/** Current error */
|
|
20
|
+
error: TError | null;
|
|
21
|
+
/** Current args (fresh) */
|
|
22
|
+
args: TArgs | null;
|
|
23
|
+
/** Loading indicator */
|
|
24
|
+
isLoading: boolean;
|
|
25
|
+
/** True only on first load (no previous data) */
|
|
26
|
+
isInitialLoading: boolean;
|
|
27
|
+
/** True when refreshing existing data */
|
|
28
|
+
isRefreshing: boolean;
|
|
29
|
+
/** True when data is available */
|
|
30
|
+
isSuccess: boolean;
|
|
31
|
+
/** True when in error state */
|
|
32
|
+
isError: boolean;
|
|
33
|
+
/** Error from a failed background refresh (stale data preserved) */
|
|
34
|
+
refreshError: TError | null;
|
|
35
|
+
}
|
|
36
|
+
/** Ref — imperative access to a specific cache entry by args */
|
|
37
|
+
export interface IResourceV2Ref<_TArgs, TData, _TError = Error> {
|
|
38
|
+
/** Check if cache entry exists */
|
|
39
|
+
readonly has: boolean;
|
|
40
|
+
/** Lock cache entry (prevent eviction) */
|
|
41
|
+
lock(): {
|
|
42
|
+
unlock: () => void;
|
|
43
|
+
};
|
|
44
|
+
/** Invalidate (force re-fetch) */
|
|
45
|
+
invalidate(): void;
|
|
46
|
+
/** Create optimistic patch */
|
|
47
|
+
createPatch(patchFn: TPatchFn<TData>): {
|
|
48
|
+
commit: () => void;
|
|
49
|
+
abort: () => void;
|
|
50
|
+
} | null;
|
|
51
|
+
/** Pre-populate cache with data */
|
|
52
|
+
create(data: TData): void;
|
|
53
|
+
}
|
|
54
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { IPlugin, PluginAugmentations } from "./plugin.types";
|
|
2
|
+
import type { IResourceV2, IResourceV2Options } from "./resource.types";
|
|
3
|
+
import type { TCompareArgsFn, TSerializeArgsFn } from "./shared.types";
|
|
4
|
+
import type { TApiSnapshot } from "./snapshot.types";
|
|
5
|
+
/** Options for createApi factory */
|
|
6
|
+
export interface ICreateApiOptions<TPlugins extends IPlugin[] = []> {
|
|
7
|
+
keyPrefix?: string | null;
|
|
8
|
+
keyStrategy?: "serialize" | "compare";
|
|
9
|
+
serializeArgs?: TSerializeArgsFn;
|
|
10
|
+
compareArg?: TCompareArgsFn;
|
|
11
|
+
initialSnapshot?: TApiSnapshot | null;
|
|
12
|
+
cacheLifetime?: number;
|
|
13
|
+
plugins?: TPlugins;
|
|
14
|
+
maxSnapshotDataAge?: number;
|
|
15
|
+
doCacheArgs?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** API instance returned by createApi */
|
|
18
|
+
export interface IApi<TPlugins extends IPlugin[] = []> {
|
|
19
|
+
createResource<TArgs, TData, TError = Error>(options: IResourceV2Options<TArgs, TData, TError>): IResourceV2<TArgs, TData, TError> & PluginAugmentations<TPlugins, TArgs, TData, TError>;
|
|
20
|
+
resetAll(): void;
|
|
21
|
+
getSnapshot(): TApiSnapshot;
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|