@veams/status-quo-query 0.11.0 → 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/.turbo/turbo-build.log +3 -3
- package/README.md +166 -34
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/mutation.d.ts +8 -8
- package/dist/mutation.js +9 -9
- package/dist/mutation.js.map +1 -1
- package/dist/provider.d.ts +3 -2
- package/dist/provider.js +2 -0
- package/dist/provider.js.map +1 -1
- package/dist/query.d.ts +26 -15
- package/dist/query.js +40 -31
- package/dist/query.js.map +1 -1
- package/dist/react/hooks/index.d.ts +2 -1
- package/dist/react/hooks/index.js +2 -1
- package/dist/react/hooks/index.js.map +1 -1
- package/dist/react/hooks/use-mutation-handle.d.ts +2 -0
- package/dist/react/hooks/use-mutation-handle.js +71 -0
- package/dist/react/hooks/use-mutation-handle.js.map +1 -0
- package/dist/react/hooks/use-query-handle.d.ts +2 -0
- package/dist/react/hooks/use-query-handle.js +71 -0
- package/dist/react/hooks/use-query-handle.js.map +1 -0
- package/dist/react/hooks/use-query-subscription.d.ts +1 -2
- package/dist/react/hooks/use-query-subscription.js +1 -72
- package/dist/react/hooks/use-query-subscription.js.map +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +1 -1
- package/dist/react/index.js.map +1 -1
- package/package.json +1 -8
- package/src/__tests__/provider.spec.ts +8 -0
- package/src/index.ts +0 -2
- package/src/mutation.ts +27 -27
- package/src/provider.ts +13 -9
- package/src/query.ts +84 -64
- package/src/react/__tests__/use-mutation-handle.spec.tsx +107 -0
- package/src/react/__tests__/{query-subscription.spec.tsx → use-query-handle.spec.tsx} +7 -7
- package/src/react/hooks/index.ts +2 -1
- package/src/react/hooks/use-mutation-handle.ts +98 -0
- package/src/react/hooks/{use-query-subscription.ts → use-query-handle.ts} +19 -21
- package/src/react/index.ts +1 -1
- package/dist/query-registry.d.ts +0 -9
- package/dist/query-registry.js +0 -28
- package/dist/query-registry.js.map +0 -1
- package/src/__tests__/query-registry.spec.ts +0 -101
- package/src/query-registry.ts +0 -52
package/dist/query.d.ts
CHANGED
|
@@ -3,9 +3,9 @@ import { type TrackedDependencyRecord, type TrackingRegistry, type TrackedQueryK
|
|
|
3
3
|
export type QueryFetchStatus = FetchStatus;
|
|
4
4
|
export type QueryStatus = TanstackQueryStatus;
|
|
5
5
|
/**
|
|
6
|
-
* Represents a stable snapshot of
|
|
6
|
+
* Represents a stable snapshot of one query handle's state.
|
|
7
7
|
*/
|
|
8
|
-
export interface
|
|
8
|
+
export interface QueryHandleSnapshot<TData, TError> {
|
|
9
9
|
data: TData | undefined;
|
|
10
10
|
error: TError | null;
|
|
11
11
|
fetchStatus: QueryFetchStatus;
|
|
@@ -15,6 +15,13 @@ export interface QueryServiceSnapshot<TData, TError> {
|
|
|
15
15
|
isPending: boolean;
|
|
16
16
|
isSuccess: boolean;
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Represents the lightweight data/error read model for one query handle.
|
|
20
|
+
*/
|
|
21
|
+
export interface QueryHandleData<TData, TError> {
|
|
22
|
+
data: TData | undefined;
|
|
23
|
+
error: TError | null;
|
|
24
|
+
}
|
|
18
25
|
/**
|
|
19
26
|
* Defines a subset of query state containing only the status and fetch status.
|
|
20
27
|
*/
|
|
@@ -23,12 +30,12 @@ export interface QueryMetaState {
|
|
|
23
30
|
status: QueryStatus;
|
|
24
31
|
}
|
|
25
32
|
/**
|
|
26
|
-
* Defines the public API for a query
|
|
33
|
+
* Defines the public API for a query handle.
|
|
27
34
|
*/
|
|
28
|
-
export interface
|
|
29
|
-
getSnapshot: () =>
|
|
30
|
-
subscribe: (listener: (snapshot:
|
|
31
|
-
refetch: (options?: RefetchOptions) => Promise<
|
|
35
|
+
export interface QueryHandle<TData, TError> {
|
|
36
|
+
getSnapshot: () => QueryHandleSnapshot<TData, TError>;
|
|
37
|
+
subscribe: (listener: (snapshot: QueryHandleSnapshot<TData, TError>) => void) => () => void;
|
|
38
|
+
refetch: (options?: RefetchOptions) => Promise<QueryHandleSnapshot<TData, TError>>;
|
|
32
39
|
invalidate: (options?: QueryInvalidateOptions) => Promise<void>;
|
|
33
40
|
unsafe_getResult: () => QueryObserverResult<TData, TError>;
|
|
34
41
|
}
|
|
@@ -43,38 +50,42 @@ type QueryDependencyDerivedOptions<TQueryKey extends QueryKey = QueryKey> = {
|
|
|
43
50
|
};
|
|
44
51
|
export type QueryDependencyTuple<TSources extends readonly unknown[], TQueryKey extends QueryKey = QueryKey> = readonly [
|
|
45
52
|
sources: {
|
|
46
|
-
readonly [K in keyof TSources]:
|
|
53
|
+
readonly [K in keyof TSources]: QueryHandle<TSources[K], Error>;
|
|
47
54
|
},
|
|
48
55
|
deriveOptions: (sourceSnapshots: {
|
|
49
|
-
readonly [K in keyof TSources]:
|
|
56
|
+
readonly [K in keyof TSources]: QueryHandleSnapshot<TSources[K], Error>;
|
|
50
57
|
}) => QueryDependencyDerivedOptions<TQueryKey>
|
|
51
58
|
];
|
|
52
59
|
/**
|
|
53
60
|
* Function signature for the untracked query factory.
|
|
54
61
|
*/
|
|
55
62
|
export interface CreateUntrackedQuery {
|
|
56
|
-
<TSources extends readonly unknown[] = [], TQueryFnData = unknown, TError = Error, TData = TQueryFnData, TQueryData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(queryKey: TQueryKey, queryFn: QueryFunction<TQueryFnData, TQueryKey>, options?:
|
|
63
|
+
<TSources extends readonly unknown[] = [], TQueryFnData = unknown, TError = Error, TData = TQueryFnData, TQueryData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(queryKey: TQueryKey, queryFn: QueryFunction<TQueryFnData, TQueryKey>, options?: QueryHandleOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey, TSources>): QueryHandle<TData, TError>;
|
|
57
64
|
}
|
|
58
65
|
/**
|
|
59
66
|
* Function signature for the default query factory that derives dependencies from the final
|
|
60
67
|
* query-key segment.
|
|
61
68
|
*
|
|
62
|
-
* The tracked query handle deliberately stays API-compatible with the normal query
|
|
69
|
+
* The tracked query handle deliberately stays API-compatible with the normal query handle.
|
|
63
70
|
* The only extra behavior is invisible: dependency registration and on-demand re-registration.
|
|
64
71
|
*/
|
|
65
72
|
export interface CreateQuery {
|
|
66
|
-
<TDeps extends TrackedDependencyRecord, TSources extends readonly unknown[] = [], TQueryFnData = unknown, TError = Error, TData = TQueryFnData, TQueryData = TQueryFnData, TQueryKey extends TrackedQueryKey<TDeps> = TrackedQueryKey<TDeps>>(queryKey: TQueryKey, queryFn: QueryFunction<TQueryFnData, TQueryKey>, options?:
|
|
73
|
+
<TDeps extends TrackedDependencyRecord, TSources extends readonly unknown[] = [], TQueryFnData = unknown, TError = Error, TData = TQueryFnData, TQueryData = TQueryFnData, TQueryKey extends TrackedQueryKey<TDeps> = TrackedQueryKey<TDeps>>(queryKey: TQueryKey, queryFn: QueryFunction<TQueryFnData, TQueryKey>, options?: QueryHandleOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey, TSources>): QueryHandle<TData, TError>;
|
|
67
74
|
}
|
|
68
75
|
/**
|
|
69
|
-
* Configuration options for creating a query
|
|
76
|
+
* Configuration options for creating a query handle, excluding function and key.
|
|
70
77
|
*/
|
|
71
|
-
export type
|
|
78
|
+
export type QueryHandleOptions<TQueryFnData = unknown, TError = Error, TData = TQueryFnData, TQueryData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, TSources extends readonly unknown[] = []> = Omit<QueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>, 'queryFn' | 'queryKey'> & {
|
|
72
79
|
dependsOn?: QueryDependencyTuple<TSources, TQueryKey>;
|
|
73
80
|
};
|
|
74
81
|
/**
|
|
75
82
|
* Extracts and maps status and fetchStatus to our QueryMetaState interface.
|
|
76
83
|
*/
|
|
77
|
-
export declare function toQueryMetaState<TData, TError>(snapshot: Pick<
|
|
84
|
+
export declare function toQueryMetaState<TData, TError>(snapshot: Pick<QueryHandleSnapshot<TData, TError>, 'fetchStatus' | 'status'>): QueryMetaState;
|
|
85
|
+
/**
|
|
86
|
+
* Extracts only data and error from a query snapshot.
|
|
87
|
+
*/
|
|
88
|
+
export declare function toQueryHandleData<TData, TError>(snapshot: Pick<QueryHandleSnapshot<TData, TError>, 'data' | 'error'>): QueryHandleData<TData, TError>;
|
|
78
89
|
/**
|
|
79
90
|
* Helper function to check if the query is in its initial loading state.
|
|
80
91
|
*/
|
package/dist/query.js
CHANGED
|
@@ -12,6 +12,15 @@ export function toQueryMetaState(snapshot) {
|
|
|
12
12
|
status: snapshot.status,
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Extracts only data and error from a query snapshot.
|
|
17
|
+
*/
|
|
18
|
+
export function toQueryHandleData(snapshot) {
|
|
19
|
+
return {
|
|
20
|
+
data: snapshot.data,
|
|
21
|
+
error: snapshot.error,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
15
24
|
/**
|
|
16
25
|
* Helper function to check if the query is in its initial loading state.
|
|
17
26
|
*/
|
|
@@ -23,14 +32,14 @@ export function isQueryLoading(query) {
|
|
|
23
32
|
* Prepares the query factory by binding it to a specific QueryClient instance.
|
|
24
33
|
*/
|
|
25
34
|
export function setupQuery(queryClient) {
|
|
26
|
-
// Returns the actual factory function for creating individual query
|
|
35
|
+
// Returns the actual factory function for creating individual query handles.
|
|
27
36
|
return function createQuery(queryKey, queryFn, options) {
|
|
28
|
-
const { dependsOn, runtimeOptions } =
|
|
29
|
-
const
|
|
37
|
+
const { dependsOn, runtimeOptions } = splitQueryHandleOptions(options);
|
|
38
|
+
const handle = createQueryHandle(queryClient, queryKey, queryFn, runtimeOptions);
|
|
30
39
|
if (!dependsOn) {
|
|
31
|
-
return
|
|
40
|
+
return handle.handle;
|
|
32
41
|
}
|
|
33
|
-
return bindQueryDependencies(
|
|
42
|
+
return bindQueryDependencies(handle, queryKey, dependsOn);
|
|
34
43
|
};
|
|
35
44
|
}
|
|
36
45
|
/**
|
|
@@ -45,22 +54,22 @@ export function setupQuery(queryClient) {
|
|
|
45
54
|
*/
|
|
46
55
|
export function setupTrackedQuery(queryClient, trackingRegistry) {
|
|
47
56
|
return function createQuery(queryKey, queryFn, options) {
|
|
48
|
-
const { dependsOn, runtimeOptions } =
|
|
49
|
-
// Reuse the same core query
|
|
50
|
-
const
|
|
57
|
+
const { dependsOn, runtimeOptions } = splitQueryHandleOptions(options);
|
|
58
|
+
// Reuse the same core query-handle implementation as the untracked API.
|
|
59
|
+
const handle = createQueryHandle(queryClient, queryKey, queryFn, runtimeOptions);
|
|
51
60
|
// We only need re-registration on the transition from zero to one subscribers.
|
|
52
61
|
let subscriberCount = 0;
|
|
53
62
|
// Register the current query hash immediately so future tracked mutations can find it.
|
|
54
|
-
trackingRegistry.register(
|
|
63
|
+
trackingRegistry.register(handle.observer.getCurrentQuery().queryHash, extractTrackedDependencies(handle.getCurrentQueryKey()));
|
|
55
64
|
const applyTrackedDerivedState = (derivedOptions) => {
|
|
56
|
-
const previousQueryHash =
|
|
57
|
-
|
|
58
|
-
const nextQueryHash =
|
|
65
|
+
const previousQueryHash = handle.observer.getCurrentQuery().queryHash;
|
|
66
|
+
handle.setDerivedState(derivedOptions);
|
|
67
|
+
const nextQueryHash = handle.observer.getCurrentQuery().queryHash;
|
|
59
68
|
if (nextQueryHash === previousQueryHash) {
|
|
60
69
|
return;
|
|
61
70
|
}
|
|
62
71
|
trackingRegistry.unregister(previousQueryHash);
|
|
63
|
-
trackingRegistry.register(nextQueryHash, extractTrackedDependencies(
|
|
72
|
+
trackingRegistry.register(nextQueryHash, extractTrackedDependencies(handle.getCurrentQueryKey()));
|
|
64
73
|
};
|
|
65
74
|
const dependencyController = dependsOn
|
|
66
75
|
? createDependencyController(queryKey, applyTrackedDerivedState, dependsOn)
|
|
@@ -68,8 +77,8 @@ export function setupTrackedQuery(queryClient, trackingRegistry) {
|
|
|
68
77
|
const ensureRegistered = () => {
|
|
69
78
|
// Build resolves the current live TanStack query for the stored observer options. This is
|
|
70
79
|
// the same mechanism TanStack uses internally when a query gets recreated after GC.
|
|
71
|
-
const liveQuery = queryClient.getQueryCache().build(queryClient,
|
|
72
|
-
const liveDependencies = extractTrackedDependencies(
|
|
80
|
+
const liveQuery = queryClient.getQueryCache().build(queryClient, handle.getCurrentObserverOptions());
|
|
81
|
+
const liveDependencies = extractTrackedDependencies(handle.getCurrentQueryKey());
|
|
73
82
|
// Re-register only when TanStack has recreated the query and the registry has already
|
|
74
83
|
// cleaned up the previous hash. This keeps the edge-case handling cheap in the common case.
|
|
75
84
|
if (!trackingRegistry.has(liveQuery.queryHash)) {
|
|
@@ -77,12 +86,12 @@ export function setupTrackedQuery(queryClient, trackingRegistry) {
|
|
|
77
86
|
}
|
|
78
87
|
};
|
|
79
88
|
return {
|
|
80
|
-
...
|
|
89
|
+
...handle.handle,
|
|
81
90
|
refetch: async (refetchOptions) => {
|
|
82
91
|
await dependencyController?.evaluateForRefetch();
|
|
83
92
|
// Refetch is one of the two explicit reactivation paths agreed on in the design.
|
|
84
93
|
ensureRegistered();
|
|
85
|
-
return
|
|
94
|
+
return handle.handle.refetch(refetchOptions);
|
|
86
95
|
},
|
|
87
96
|
subscribe: (listener) => {
|
|
88
97
|
// The first active subscriber is the other reactivation path. Re-running registration
|
|
@@ -92,7 +101,7 @@ export function setupTrackedQuery(queryClient, trackingRegistry) {
|
|
|
92
101
|
ensureRegistered();
|
|
93
102
|
}
|
|
94
103
|
subscriberCount += 1;
|
|
95
|
-
const unsubscribe =
|
|
104
|
+
const unsubscribe = handle.handle.subscribe(listener);
|
|
96
105
|
return () => {
|
|
97
106
|
// Keep the counter bounded so accidental double-unsubscribe cannot push it negative.
|
|
98
107
|
subscriberCount = Math.max(0, subscriberCount - 1);
|
|
@@ -108,8 +117,8 @@ export function setupTrackedQuery(queryClient, trackingRegistry) {
|
|
|
108
117
|
/**
|
|
109
118
|
* Internal helper to transform a raw Tanstack query result into our public snapshot format.
|
|
110
119
|
*/
|
|
111
|
-
function
|
|
112
|
-
// Extract and return the relevant fields for the UI or other
|
|
120
|
+
function toQueryHandleSnapshot(result) {
|
|
121
|
+
// Extract and return the relevant fields for the UI or other handle consumers.
|
|
113
122
|
return {
|
|
114
123
|
data: result.data,
|
|
115
124
|
error: result.error,
|
|
@@ -121,7 +130,7 @@ function toQueryServiceSnapshot(result) {
|
|
|
121
130
|
isSuccess: result.isSuccess,
|
|
122
131
|
};
|
|
123
132
|
}
|
|
124
|
-
function
|
|
133
|
+
function createQueryHandle(queryClient, queryKey, queryFn, options) {
|
|
125
134
|
const baseQueryKey = queryKey;
|
|
126
135
|
const baseOptions = options;
|
|
127
136
|
let resolvedQueryKey = baseQueryKey;
|
|
@@ -141,12 +150,12 @@ function createQueryService(queryClient, queryKey, queryFn, options) {
|
|
|
141
150
|
getCurrentObserverOptions,
|
|
142
151
|
getCurrentQueryKey: () => resolvedQueryKey,
|
|
143
152
|
setDerivedState,
|
|
144
|
-
|
|
145
|
-
getSnapshot: () =>
|
|
153
|
+
handle: {
|
|
154
|
+
getSnapshot: () => toQueryHandleSnapshot(observer.getCurrentResult()),
|
|
146
155
|
subscribe: (listener) => observer.subscribe((result) => {
|
|
147
|
-
listener(
|
|
156
|
+
listener(toQueryHandleSnapshot(result));
|
|
148
157
|
}),
|
|
149
|
-
refetch: async (refetchOptions) =>
|
|
158
|
+
refetch: async (refetchOptions) => toQueryHandleSnapshot(await observer.refetch(refetchOptions)),
|
|
150
159
|
invalidate: (invalidateOptions) => queryClient.invalidateQueries({
|
|
151
160
|
exact: true,
|
|
152
161
|
queryKey: resolvedQueryKey,
|
|
@@ -158,21 +167,21 @@ function createQueryService(queryClient, queryKey, queryFn, options) {
|
|
|
158
167
|
},
|
|
159
168
|
};
|
|
160
169
|
}
|
|
161
|
-
function bindQueryDependencies(
|
|
162
|
-
const dependencyController = createDependencyController(queryKey,
|
|
170
|
+
function bindQueryDependencies(queryHandle, queryKey, dependsOn) {
|
|
171
|
+
const dependencyController = createDependencyController(queryKey, queryHandle.setDerivedState, dependsOn);
|
|
163
172
|
let subscriberCount = 0;
|
|
164
173
|
return {
|
|
165
|
-
...
|
|
174
|
+
...queryHandle.handle,
|
|
166
175
|
refetch: async (refetchOptions) => {
|
|
167
176
|
await dependencyController.evaluateForRefetch();
|
|
168
|
-
return
|
|
177
|
+
return queryHandle.handle.refetch(refetchOptions);
|
|
169
178
|
},
|
|
170
179
|
subscribe: (listener) => {
|
|
171
180
|
if (subscriberCount === 0) {
|
|
172
181
|
dependencyController.activate();
|
|
173
182
|
}
|
|
174
183
|
subscriberCount += 1;
|
|
175
|
-
const unsubscribe =
|
|
184
|
+
const unsubscribe = queryHandle.handle.subscribe(listener);
|
|
176
185
|
return () => {
|
|
177
186
|
subscriberCount = Math.max(0, subscriberCount - 1);
|
|
178
187
|
if (subscriberCount === 0) {
|
|
@@ -239,7 +248,7 @@ function createDependencyController(baseQueryKey, setDerivedState, dependsOn) {
|
|
|
239
248
|
},
|
|
240
249
|
};
|
|
241
250
|
}
|
|
242
|
-
function
|
|
251
|
+
function splitQueryHandleOptions(options) {
|
|
243
252
|
if (options === undefined) {
|
|
244
253
|
return {
|
|
245
254
|
dependsOn: undefined,
|
package/dist/query.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO;AAaL,iEAAiE;AACjE,aAAa,GAUd,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAIL,0BAA0B,GAC3B,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { useQueryHandle } from './use-query-handle.js';
|
|
2
|
+
export { useMutationHandle } from './use-mutation-handle.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/react/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/react/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Import the React hooks needed to memoize callbacks, hold mutable cache state,
|
|
2
|
+
// and connect an external store to React rendering.
|
|
3
|
+
import { useCallback, useRef, useSyncExternalStore } from 'react';
|
|
4
|
+
// Subscribe a React component to a MutationHandle and return its latest snapshot.
|
|
5
|
+
export function useMutationHandle(
|
|
6
|
+
// Receive the external mutation handle instance to subscribe to.
|
|
7
|
+
mutationHandle) {
|
|
8
|
+
// Count store notifications so we can tell when our cached snapshot is stale.
|
|
9
|
+
const snapshotVersionRef = useRef(0);
|
|
10
|
+
// Cache one client-side snapshot per observed version to keep getSnapshot stable.
|
|
11
|
+
const snapshotCacheRef = useRef(null);
|
|
12
|
+
// Cache the server snapshot separately for the useSyncExternalStore SSR fallback.
|
|
13
|
+
const serverSnapshotCacheRef = useRef(null);
|
|
14
|
+
// Create the subscribe function expected by useSyncExternalStore.
|
|
15
|
+
const subscribe = useCallback(
|
|
16
|
+
// React passes a listener that must run whenever the external store changes.
|
|
17
|
+
(listener) =>
|
|
18
|
+
// Forward the subscription to the mutation handle.
|
|
19
|
+
mutationHandle.subscribe(() => {
|
|
20
|
+
// Bump the version so later reads know the previous cache is outdated.
|
|
21
|
+
snapshotVersionRef.current += 1;
|
|
22
|
+
// Drop the cached client snapshot because the store just changed.
|
|
23
|
+
snapshotCacheRef.current = null;
|
|
24
|
+
// Drop the cached server snapshot for the same reason.
|
|
25
|
+
serverSnapshotCacheRef.current = null;
|
|
26
|
+
// Notify React that it should read a fresh snapshot.
|
|
27
|
+
listener();
|
|
28
|
+
}),
|
|
29
|
+
// Recreate the subscription function only when the handle instance changes.
|
|
30
|
+
[mutationHandle]);
|
|
31
|
+
// Read the current client snapshot in a referentially stable way for React.
|
|
32
|
+
const getSnapshot = useCallback(() => {
|
|
33
|
+
// Read the latest store version number.
|
|
34
|
+
const version = snapshotVersionRef.current;
|
|
35
|
+
// Read the last cached client snapshot, if there is one.
|
|
36
|
+
const cachedSnapshot = snapshotCacheRef.current;
|
|
37
|
+
// Reuse the cached snapshot when it was produced for the current version.
|
|
38
|
+
if (cachedSnapshot && cachedSnapshot.version === version) {
|
|
39
|
+
// Return the cached snapshot so repeated reads in the same render stay stable.
|
|
40
|
+
return cachedSnapshot.snapshot;
|
|
41
|
+
}
|
|
42
|
+
// Ask the mutation handle for the latest snapshot because the cache is empty or stale.
|
|
43
|
+
const snapshot = mutationHandle.getSnapshot();
|
|
44
|
+
// Store the new snapshot together with the version it belongs to.
|
|
45
|
+
snapshotCacheRef.current = {
|
|
46
|
+
snapshot,
|
|
47
|
+
version,
|
|
48
|
+
};
|
|
49
|
+
// Return the freshly read snapshot to React.
|
|
50
|
+
return snapshot;
|
|
51
|
+
}, [mutationHandle]);
|
|
52
|
+
// Read the server snapshot used by React during SSR or hydration fallback paths.
|
|
53
|
+
const getServerSnapshot = useCallback(() => {
|
|
54
|
+
// Read the cached server snapshot, if one was stored earlier.
|
|
55
|
+
const cachedSnapshot = serverSnapshotCacheRef.current;
|
|
56
|
+
// Reuse the cached server snapshot to keep server reads stable.
|
|
57
|
+
if (cachedSnapshot) {
|
|
58
|
+
// Return the cached server snapshot directly.
|
|
59
|
+
return cachedSnapshot;
|
|
60
|
+
}
|
|
61
|
+
// Ask the mutation handle for a snapshot because no server cache exists yet.
|
|
62
|
+
const snapshot = mutationHandle.getSnapshot();
|
|
63
|
+
// Cache that snapshot for the next server read.
|
|
64
|
+
serverSnapshotCacheRef.current = snapshot;
|
|
65
|
+
// Return the freshly read server snapshot.
|
|
66
|
+
return snapshot;
|
|
67
|
+
}, [mutationHandle]);
|
|
68
|
+
// Let React subscribe to the external store and read snapshots through the callbacks above.
|
|
69
|
+
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=use-mutation-handle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-mutation-handle.js","sourceRoot":"","sources":["../../../src/react/hooks/use-mutation-handle.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,oDAAoD;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAelE,kFAAkF;AAClF,MAAM,UAAU,iBAAiB;AAC/B,iEAAiE;AACjE,cAAyD;IAEzD,8EAA8E;IAC9E,MAAM,kBAAkB,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACrC,kFAAkF;IAClF,MAAM,gBAAgB,GAAG,MAAM,CAAuD,IAAI,CAAC,CAAC;IAC5F,kFAAkF;IAClF,MAAM,sBAAsB,GAAG,MAAM,CACnC,IAAI,CACL,CAAC;IAEF,kEAAkE;IAClE,MAAM,SAAS,GAAG,WAAW;IAC3B,6EAA6E;IAC7E,CAAC,QAAkB,EAAE,EAAE;IACrB,mDAAmD;IACnD,cAAc,CAAC,SAAS,CAAC,GAAG,EAAE;QAC5B,uEAAuE;QACvE,kBAAkB,CAAC,OAAO,IAAI,CAAC,CAAC;QAChC,kEAAkE;QAClE,gBAAgB,CAAC,OAAO,GAAG,IAAI,CAAC;QAChC,uDAAuD;QACvD,sBAAsB,CAAC,OAAO,GAAG,IAAI,CAAC;QACtC,qDAAqD;QACrD,QAAQ,EAAE,CAAC;IACb,CAAC,CAAC;IACJ,4EAA4E;IAC5E,CAAC,cAAc,CAAC,CACjB,CAAC;IAEF,4EAA4E;IAC5E,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE;QACnC,wCAAwC;QACxC,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,CAAC;QAC3C,yDAAyD;QACzD,MAAM,cAAc,GAAG,gBAAgB,CAAC,OAAO,CAAC;QAEhD,0EAA0E;QAC1E,IAAI,cAAc,IAAI,cAAc,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;YACzD,+EAA+E;YAC/E,OAAO,cAAc,CAAC,QAAQ,CAAC;QACjC,CAAC;QAED,uFAAuF;QACvF,MAAM,QAAQ,GAAG,cAAc,CAAC,WAAW,EAAE,CAAC;QAC9C,kEAAkE;QAClE,gBAAgB,CAAC,OAAO,GAAG;YACzB,QAAQ;YACR,OAAO;SACR,CAAC;QAEF,6CAA6C;QAC7C,OAAO,QAAQ,CAAC;IAClB,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC;IAErB,iFAAiF;IACjF,MAAM,iBAAiB,GAAG,WAAW,CAAC,GAAG,EAAE;QACzC,8DAA8D;QAC9D,MAAM,cAAc,GAAG,sBAAsB,CAAC,OAAO,CAAC;QAEtD,gEAAgE;QAChE,IAAI,cAAc,EAAE,CAAC;YACnB,8CAA8C;YAC9C,OAAO,cAAc,CAAC;QACxB,CAAC;QAED,6EAA6E;QAC7E,MAAM,QAAQ,GAAG,cAAc,CAAC,WAAW,EAAE,CAAC;QAC9C,gDAAgD;QAChD,sBAAsB,CAAC,OAAO,GAAG,QAAQ,CAAC;QAE1C,2CAA2C;QAC3C,OAAO,QAAQ,CAAC;IAClB,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC;IAErB,4FAA4F;IAC5F,OAAO,oBAAoB,CAAC,SAAS,EAAE,WAAW,EAAE,iBAAiB,CAAC,CAAC;AACzE,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Import the React hooks needed to memoize callbacks, hold mutable cache state,
|
|
2
|
+
// and connect an external store to React rendering.
|
|
3
|
+
import { useCallback, useRef, useSyncExternalStore } from 'react';
|
|
4
|
+
// Subscribe a React component to a QueryHandle and return its latest snapshot.
|
|
5
|
+
export function useQueryHandle(
|
|
6
|
+
// Receive the external query handle instance to subscribe to.
|
|
7
|
+
queryHandle) {
|
|
8
|
+
// Count store notifications so we can tell when our cached snapshot is stale.
|
|
9
|
+
const snapshotVersionRef = useRef(0);
|
|
10
|
+
// Cache one client-side snapshot per observed version to keep getSnapshot stable.
|
|
11
|
+
const snapshotCacheRef = useRef(null);
|
|
12
|
+
// Cache the server snapshot separately for the useSyncExternalStore SSR fallback.
|
|
13
|
+
const serverSnapshotCacheRef = useRef(null);
|
|
14
|
+
// Create the subscribe function expected by useSyncExternalStore.
|
|
15
|
+
const subscribe = useCallback(
|
|
16
|
+
// React passes a listener that must run whenever the external store changes.
|
|
17
|
+
(listener) =>
|
|
18
|
+
// Forward the subscription to the query handle.
|
|
19
|
+
queryHandle.subscribe(() => {
|
|
20
|
+
// Bump the version so later reads know the previous cache is outdated.
|
|
21
|
+
snapshotVersionRef.current += 1;
|
|
22
|
+
// Drop the cached client snapshot because the store just changed.
|
|
23
|
+
snapshotCacheRef.current = null;
|
|
24
|
+
// Drop the cached server snapshot for the same reason.
|
|
25
|
+
serverSnapshotCacheRef.current = null;
|
|
26
|
+
// Notify React that it should read a fresh snapshot.
|
|
27
|
+
listener();
|
|
28
|
+
}),
|
|
29
|
+
// Recreate the subscription function only when the handle instance changes.
|
|
30
|
+
[queryHandle]);
|
|
31
|
+
// Read the current client snapshot in a referentially stable way for React.
|
|
32
|
+
const getSnapshot = useCallback(() => {
|
|
33
|
+
// Read the latest store version number.
|
|
34
|
+
const version = snapshotVersionRef.current;
|
|
35
|
+
// Read the last cached client snapshot, if there is one.
|
|
36
|
+
const cachedSnapshot = snapshotCacheRef.current;
|
|
37
|
+
// Reuse the cached snapshot when it was produced for the current version.
|
|
38
|
+
if (cachedSnapshot && cachedSnapshot.version === version) {
|
|
39
|
+
// Return the cached snapshot so repeated reads in the same render stay stable.
|
|
40
|
+
return cachedSnapshot.snapshot;
|
|
41
|
+
}
|
|
42
|
+
// Ask the query handle for the latest snapshot because the cache is empty or stale.
|
|
43
|
+
const snapshot = queryHandle.getSnapshot();
|
|
44
|
+
// Store the new snapshot together with the version it belongs to.
|
|
45
|
+
snapshotCacheRef.current = {
|
|
46
|
+
snapshot,
|
|
47
|
+
version,
|
|
48
|
+
};
|
|
49
|
+
// Return the freshly read snapshot to React.
|
|
50
|
+
return snapshot;
|
|
51
|
+
}, [queryHandle]);
|
|
52
|
+
// Read the server snapshot used by React during SSR or hydration fallback paths.
|
|
53
|
+
const getServerSnapshot = useCallback(() => {
|
|
54
|
+
// Read the cached server snapshot, if one was stored earlier.
|
|
55
|
+
const cachedSnapshot = serverSnapshotCacheRef.current;
|
|
56
|
+
// Reuse the cached server snapshot to keep server reads stable.
|
|
57
|
+
if (cachedSnapshot) {
|
|
58
|
+
// Return the cached server snapshot directly.
|
|
59
|
+
return cachedSnapshot;
|
|
60
|
+
}
|
|
61
|
+
// Ask the query handle for a snapshot because no server cache exists yet.
|
|
62
|
+
const snapshot = queryHandle.getSnapshot();
|
|
63
|
+
// Cache that snapshot for the next server read.
|
|
64
|
+
serverSnapshotCacheRef.current = snapshot;
|
|
65
|
+
// Return the freshly read server snapshot.
|
|
66
|
+
return snapshot;
|
|
67
|
+
}, [queryHandle]);
|
|
68
|
+
// Let React subscribe to the external store and read snapshots through the callbacks above.
|
|
69
|
+
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=use-query-handle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-query-handle.js","sourceRoot":"","sources":["../../../src/react/hooks/use-query-handle.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,oDAAoD;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAelE,+EAA+E;AAC/E,MAAM,UAAU,cAAc;AAC5B,8DAA8D;AAC9D,WAAuC;IAEvC,8EAA8E;IAC9E,MAAM,kBAAkB,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACrC,kFAAkF;IAClF,MAAM,gBAAgB,GAAG,MAAM,CAA2C,IAAI,CAAC,CAAC;IAChF,kFAAkF;IAClF,MAAM,sBAAsB,GAAG,MAAM,CAA4C,IAAI,CAAC,CAAC;IAEvF,kEAAkE;IAClE,MAAM,SAAS,GAAG,WAAW;IAC3B,6EAA6E;IAC7E,CAAC,QAAkB,EAAE,EAAE;IACrB,gDAAgD;IAChD,WAAW,CAAC,SAAS,CAAC,GAAG,EAAE;QACzB,uEAAuE;QACvE,kBAAkB,CAAC,OAAO,IAAI,CAAC,CAAC;QAChC,kEAAkE;QAClE,gBAAgB,CAAC,OAAO,GAAG,IAAI,CAAC;QAChC,uDAAuD;QACvD,sBAAsB,CAAC,OAAO,GAAG,IAAI,CAAC;QACtC,qDAAqD;QACrD,QAAQ,EAAE,CAAC;IACb,CAAC,CAAC;IACJ,4EAA4E;IAC5E,CAAC,WAAW,CAAC,CACd,CAAC;IAEF,4EAA4E;IAC5E,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE;QACnC,wCAAwC;QACxC,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,CAAC;QAC3C,yDAAyD;QACzD,MAAM,cAAc,GAAG,gBAAgB,CAAC,OAAO,CAAC;QAEhD,0EAA0E;QAC1E,IAAI,cAAc,IAAI,cAAc,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;YACzD,+EAA+E;YAC/E,OAAO,cAAc,CAAC,QAAQ,CAAC;QACjC,CAAC;QAED,oFAAoF;QACpF,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC;QAC3C,kEAAkE;QAClE,gBAAgB,CAAC,OAAO,GAAG;YACzB,QAAQ;YACR,OAAO;SACR,CAAC;QAEF,6CAA6C;QAC7C,OAAO,QAAQ,CAAC;IAClB,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAElB,iFAAiF;IACjF,MAAM,iBAAiB,GAAG,WAAW,CAAC,GAAG,EAAE;QACzC,8DAA8D;QAC9D,MAAM,cAAc,GAAG,sBAAsB,CAAC,OAAO,CAAC;QAEtD,gEAAgE;QAChE,IAAI,cAAc,EAAE,CAAC;YACnB,8CAA8C;YAC9C,OAAO,cAAc,CAAC;QACxB,CAAC;QAED,0EAA0E;QAC1E,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC;QAC3C,gDAAgD;QAChD,sBAAsB,CAAC,OAAO,GAAG,QAAQ,CAAC;QAE1C,2CAA2C;QAC3C,OAAO,QAAQ,CAAC;IAClB,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAElB,4FAA4F;IAC5F,OAAO,oBAAoB,CAAC,SAAS,EAAE,WAAW,EAAE,iBAAiB,CAAC,CAAC;AACzE,CAAC"}
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export declare function useQuerySubscription<TData, TError>(queryService: QueryService<TData, TError>): QueryServiceSnapshot<TData, TError>;
|
|
1
|
+
export { useQueryHandle, useQuerySubscription } from './use-query-handle.js';
|
|
@@ -1,73 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
// and connect an external store to React rendering.
|
|
3
|
-
import { useCallback, useRef, useSyncExternalStore } from 'react';
|
|
4
|
-
// Subscribe a React component to a QueryService and return its latest snapshot.
|
|
5
|
-
export function useQuerySubscription(
|
|
6
|
-
// Receive the external query service instance to subscribe to.
|
|
7
|
-
queryService) {
|
|
8
|
-
// Count store notifications so we can tell when our cached snapshot is stale.
|
|
9
|
-
const snapshotVersionRef = useRef(0);
|
|
10
|
-
// Cache one client-side snapshot per observed version to keep getSnapshot stable.
|
|
11
|
-
const snapshotCacheRef = useRef(null);
|
|
12
|
-
// Cache the server snapshot separately for the useSyncExternalStore SSR fallback.
|
|
13
|
-
const serverSnapshotCacheRef = useRef(null);
|
|
14
|
-
// Create the subscribe function expected by useSyncExternalStore.
|
|
15
|
-
const subscribe = useCallback(
|
|
16
|
-
// React passes a listener that must run whenever the external store changes.
|
|
17
|
-
(listener) =>
|
|
18
|
-
// Forward the subscription to the query service.
|
|
19
|
-
queryService.subscribe(() => {
|
|
20
|
-
// Bump the version so later reads know the previous cache is outdated.
|
|
21
|
-
snapshotVersionRef.current += 1;
|
|
22
|
-
// Drop the cached client snapshot because the store just changed.
|
|
23
|
-
snapshotCacheRef.current = null;
|
|
24
|
-
// Drop the cached server snapshot for the same reason.
|
|
25
|
-
serverSnapshotCacheRef.current = null;
|
|
26
|
-
// Notify React that it should read a fresh snapshot.
|
|
27
|
-
listener();
|
|
28
|
-
}),
|
|
29
|
-
// Recreate the subscription function only when the service instance changes.
|
|
30
|
-
[queryService]);
|
|
31
|
-
// Read the current client snapshot in a referentially stable way for React.
|
|
32
|
-
const getSnapshot = useCallback(() => {
|
|
33
|
-
// Read the latest store version number.
|
|
34
|
-
const version = snapshotVersionRef.current;
|
|
35
|
-
// Read the last cached client snapshot, if there is one.
|
|
36
|
-
const cachedSnapshot = snapshotCacheRef.current;
|
|
37
|
-
// Reuse the cached snapshot when it was produced for the current version.
|
|
38
|
-
if (cachedSnapshot && cachedSnapshot.version === version) {
|
|
39
|
-
// Return the cached snapshot so repeated reads in the same render stay stable.
|
|
40
|
-
return cachedSnapshot.snapshot;
|
|
41
|
-
}
|
|
42
|
-
// Ask the query service for the latest snapshot because the cache is empty or stale.
|
|
43
|
-
const snapshot = queryService.getSnapshot();
|
|
44
|
-
// Store the new snapshot together with the version it belongs to.
|
|
45
|
-
snapshotCacheRef.current = {
|
|
46
|
-
snapshot,
|
|
47
|
-
version,
|
|
48
|
-
};
|
|
49
|
-
// Return the freshly read snapshot to React.
|
|
50
|
-
return snapshot;
|
|
51
|
-
// Recreate this getter only when the service instance changes.
|
|
52
|
-
}, [queryService]);
|
|
53
|
-
// Read the server snapshot used by React during SSR or hydration fallback paths.
|
|
54
|
-
const getServerSnapshot = useCallback(() => {
|
|
55
|
-
// Read the cached server snapshot, if one was stored earlier.
|
|
56
|
-
const cachedSnapshot = serverSnapshotCacheRef.current;
|
|
57
|
-
// Reuse the cached server snapshot to keep server reads stable.
|
|
58
|
-
if (cachedSnapshot) {
|
|
59
|
-
// Return the cached server snapshot directly.
|
|
60
|
-
return cachedSnapshot;
|
|
61
|
-
}
|
|
62
|
-
// Ask the query service for a snapshot because no server cache exists yet.
|
|
63
|
-
const snapshot = queryService.getSnapshot();
|
|
64
|
-
// Cache that snapshot for the next server read.
|
|
65
|
-
serverSnapshotCacheRef.current = snapshot;
|
|
66
|
-
// Return the freshly read server snapshot.
|
|
67
|
-
return snapshot;
|
|
68
|
-
// Recreate this getter only when the service instance changes.
|
|
69
|
-
}, [queryService]);
|
|
70
|
-
// Let React subscribe to the external store and read snapshots through the callbacks above.
|
|
71
|
-
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
72
|
-
}
|
|
1
|
+
export { useQueryHandle, useQuerySubscription } from './use-query-handle.js';
|
|
73
2
|
//# sourceMappingURL=use-query-subscription.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-query-subscription.js","sourceRoot":"","sources":["../../../src/react/hooks/use-query-subscription.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"use-query-subscription.js","sourceRoot":"","sources":["../../../src/react/hooks/use-query-subscription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { useQueryHandle, useMutationHandle } from './hooks/index.js';
|
package/dist/react/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { useQueryHandle, useMutationHandle } from './hooks/index.js';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/react/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veams/status-quo-query",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "TanStack Query service layer for the VEAMS StatusQuo ecosystem.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -39,13 +39,6 @@
|
|
|
39
39
|
"default": "./dist/provider.js"
|
|
40
40
|
},
|
|
41
41
|
"require": "./dist/provider.js"
|
|
42
|
-
},
|
|
43
|
-
"./query-registry": {
|
|
44
|
-
"import": {
|
|
45
|
-
"types": "./dist/query-registry.d.ts",
|
|
46
|
-
"default": "./dist/query-registry.js"
|
|
47
|
-
},
|
|
48
|
-
"require": "./dist/query-registry.js"
|
|
49
42
|
}
|
|
50
43
|
},
|
|
51
44
|
"types": "dist/index.d.ts",
|