@metamask-previews/react-data-query 2.0.0-preview-f1c750c → 2.0.0-preview-9fd631f7d
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
CHANGED
|
@@ -24,7 +24,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
24
24
|
- Bump `@metamask/base-data-service` from `^2.0.0` to `^2.1.0` ([#10502](https://github.com/MetaMask/core/pull/10502))
|
|
25
25
|
- Bump `@tanstack/query-core` from `^5.89.0` to `^5.103.2` ([#10511](https://github.com/MetaMask/core/pull/10511))
|
|
26
26
|
- Bump `@tanstack/react-query` from `^5.89.0` to `^5.103.2` ([#10511](https://github.com/MetaMask/core/pull/10511))
|
|
27
|
-
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- UI queries now reflect `fetchStatus` and errors from fetches the data service starts in the background ([#11166](https://github.com/MetaMask/core/pull/11166))
|
|
31
|
+
- While the data service refetches a query, the UI query is now `fetching` instead of staying `idle`, unless the UI is running its own fetch for that query.
|
|
32
|
+
- When a background refetch fails, the UI query now moves to `error` with an `Error` built from the serialized error, keeping its existing data.
|
|
33
|
+
- A UI query that mirrors a background fetch goes back to `idle` when its last observer is removed or when the data service removes the query.
|
|
28
34
|
|
|
29
35
|
## [2.0.0]
|
|
30
36
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createUIQueryClient.d.ts","sourceRoot":"","sources":["../src/createUIQueryClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oCAAoC,EACpC,sCAAsC,
|
|
1
|
+
{"version":3,"file":"createUIQueryClient.d.ts","sourceRoot":"","sources":["../src/createUIQueryClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oCAAoC,EACpC,sCAAsC,EAEvC,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAGL,WAAW,EAIX,iBAAiB,EAKlB,MAAM,sBAAsB,CAAC;AAQ9B;;GAEG;AACH,KAAK,sCAAsC,GAAG,CAC5C,OAAO,EAAE,sCAAsC,KAC5C,IAAI,CAAC;AAiBV;;;GAGG;AACH,KAAK,gBAAgB,CAAC,eAAe,SAAS,MAAM,IAAI;IACtD;;;;;;;OAOG;IACH,IAAI,CACF,UAAU,EAAE,GAAG,eAAe,IAAI,MAAM,EAAE,EAC1C,GAAG,MAAM,EAAE,OAAO,EAAE,GACnB,OAAO,CAAC;IAEX;;;OAGG;IACH,SAAS,CACP,SAAS,EAAE,oCAAoC,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,EACxE,OAAO,EAAE,sCAAsC,GAC9C,IAAI,CAAC;IAER;;;OAGG;IACH,WAAW,CACT,SAAS,EAAE,oCAAoC,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,EACxE,OAAO,EAAE,sCAAsC,GAC9C,IAAI,CAAC;CACT,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,gBAAgB,SAAS,SAAS,MAAM,EAAE,EAC5E,YAAY,EAAE,gBAAgB,EAC9B,SAAS,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,EACrD,MAAM,GAAE,iBAAsB,GAC7B,WAAW,CAoZb"}
|
|
@@ -4,6 +4,20 @@ import { v4 as uuidV4 } from 'uuid';
|
|
|
4
4
|
import { hydrateMutations, readGlobalId } from './hydrateMutations.js';
|
|
5
5
|
import { createModuleLogger, projectLogger } from './loggers.js';
|
|
6
6
|
const log = createModuleLogger(projectLogger, 'createUIQueryClient');
|
|
7
|
+
/**
|
|
8
|
+
* Turn an error that came through a `:cacheUpdated` payload back into an
|
|
9
|
+
* `Error`, so UI code can treat it like any other query error.
|
|
10
|
+
*
|
|
11
|
+
* @param serializedError - The serialized error.
|
|
12
|
+
* @param serializedError.name - The name of the original error.
|
|
13
|
+
* @param serializedError.message - The message of the original error.
|
|
14
|
+
* @returns The error.
|
|
15
|
+
*/
|
|
16
|
+
function deserializeQueryError({ name, message }) {
|
|
17
|
+
const error = new Error(message);
|
|
18
|
+
error.name = name;
|
|
19
|
+
return error;
|
|
20
|
+
}
|
|
7
21
|
/**
|
|
8
22
|
* Create a QueryClient that enables data services to power queries and mutations via a messenger adapter.
|
|
9
23
|
*
|
|
@@ -107,6 +121,21 @@ export function createUIQueryClient(dataServices, messenger, config = {}) {
|
|
|
107
121
|
},
|
|
108
122
|
});
|
|
109
123
|
const queryCache = client.getQueryCache();
|
|
124
|
+
/**
|
|
125
|
+
* Set a UI query back to `idle` if it is marked as fetching only because it
|
|
126
|
+
* mirrors a fetch that the data service runs in the background. A fetch
|
|
127
|
+
* that the UI started itself (and so has a promise) is left alone.
|
|
128
|
+
*
|
|
129
|
+
* @param hash - The hash of the query.
|
|
130
|
+
*/
|
|
131
|
+
function resetBackgroundFetchStatus(hash) {
|
|
132
|
+
const uiQuery = queryCache.get(hash);
|
|
133
|
+
if (uiQuery &&
|
|
134
|
+
uiQuery.state.fetchStatus !== 'idle' &&
|
|
135
|
+
uiQuery.promise === undefined) {
|
|
136
|
+
uiQuery.setState({ fetchStatus: 'idle' });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
110
139
|
queryCache.subscribe((event) => {
|
|
111
140
|
const { query } = event;
|
|
112
141
|
const hash = query.queryHash;
|
|
@@ -121,10 +150,38 @@ export function createUIQueryClient(dataServices, messenger, config = {}) {
|
|
|
121
150
|
observerCount === 1) {
|
|
122
151
|
const cacheListener = (payload) => {
|
|
123
152
|
if (payload.type === 'removed') {
|
|
153
|
+
// No more updates will arrive for this query, so a background fetch
|
|
154
|
+
// we were mirroring will never be reported as finished.
|
|
155
|
+
resetBackgroundFetchStatus(hash);
|
|
124
156
|
return;
|
|
125
157
|
}
|
|
126
158
|
log('Hydrating with', payload.state);
|
|
127
159
|
hydrate(client, payload.state);
|
|
160
|
+
// `hydrate` leaves `fetchStatus` alone and only copies state when the
|
|
161
|
+
// data is newer, so fetches and errors the service runs on its own
|
|
162
|
+
// never show up. Mirror them here, unless the UI is running its own
|
|
163
|
+
// fetch, which always wins.
|
|
164
|
+
for (const { queryHash, state } of payload.state.queries) {
|
|
165
|
+
const uiQuery = queryCache.get(queryHash);
|
|
166
|
+
// `hydrate` builds any query that is missing, so this is a check
|
|
167
|
+
// to appease TypeScript.
|
|
168
|
+
// istanbul ignore next
|
|
169
|
+
if (!uiQuery) {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (uiQuery.promise !== undefined) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
uiQuery.setState({
|
|
176
|
+
fetchStatus: state.fetchStatus,
|
|
177
|
+
...(state.status === 'error' &&
|
|
178
|
+
state.error && {
|
|
179
|
+
status: 'error',
|
|
180
|
+
error: deserializeQueryError(state.error),
|
|
181
|
+
errorUpdatedAt: state.errorUpdatedAt,
|
|
182
|
+
}),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
128
185
|
};
|
|
129
186
|
subscriptions.set(hash, cacheListener);
|
|
130
187
|
messenger.subscribe(`${service}:cacheUpdated:${hash}`, cacheListener);
|
|
@@ -140,6 +197,9 @@ export function createUIQueryClient(dataServices, messenger, config = {}) {
|
|
|
140
197
|
messenger.unsubscribe(`${service}:cacheUpdated:${hash}`, subscriptionListener);
|
|
141
198
|
}
|
|
142
199
|
subscriptions.delete(hash);
|
|
200
|
+
// We stop listening here, so a background fetch we were mirroring would
|
|
201
|
+
// otherwise stay `fetching` forever.
|
|
202
|
+
resetBackgroundFetchStatus(hash);
|
|
143
203
|
}
|
|
144
204
|
});
|
|
145
205
|
const mutationCache = client.getMutationCache();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createUIQueryClient.js","sourceRoot":"","sources":["../src/createUIQueryClient.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DataServiceGranularCacheUpdatedEvent,\n DataServiceGranularCacheUpdatedPayload,\n} from '@metamask/base-data-service';\nimport { Json, assert } from '@metamask/utils';\nimport {\n hashKey,\n hydrate,\n QueryClient,\n InvalidateQueryFilters,\n InvalidateOptions,\n QueryKey,\n QueryClientConfig,\n Mutation,\n MutationOptions,\n MutationState,\n MutationFunction,\n} from '@tanstack/query-core';\nimport { v4 as uuidV4 } from 'uuid';\n\nimport { hydrateMutations, readGlobalId } from './hydrateMutations.js';\nimport { createModuleLogger, projectLogger } from './loggers.js';\n\nconst log = createModuleLogger(projectLogger, 'createUIQueryClient');\n\n/**\n * Handles granular cache update events emitted by data services.\n */\ntype DataServiceGranularCacheUpdatedHandler = (\n payload: DataServiceGranularCacheUpdatedPayload,\n) => void;\n\n/**\n * A narrower subset of the `Messenger` type, tailored to the messenger\n * that `createUIQueryClient` interacts with.\n */\ntype MessengerAdapter<DataServiceName extends string> = {\n /**\n * Call an action on one of the configured data services.\n *\n * Note: The parameters are typed as `unknown[]` rather than `Json[]`. For\n * concrete messengers, each action's parameters exist as fixed-length tuple,\n * and a variadic `Json[]` is not assignable to a fixed-length tuple, so using\n * `Json[]` here would reject otherwise valid messengers.\n */\n call(\n actionType: `${DataServiceName}:${string}`,\n ...params: unknown[]\n ): unknown;\n\n /**\n * Subscribe to a granular cache update event on one of the configured data\n * services.\n */\n subscribe(\n eventType: DataServiceGranularCacheUpdatedEvent<DataServiceName>['type'],\n handler: DataServiceGranularCacheUpdatedHandler,\n ): void;\n\n /**\n * Unsubscribe from a granular cache update event on one of the configured\n * data services.\n */\n unsubscribe(\n eventType: DataServiceGranularCacheUpdatedEvent<DataServiceName>['type'],\n handler: DataServiceGranularCacheUpdatedHandler,\n ): void;\n};\n\n/**\n * Create a QueryClient that enables data services to power queries and mutations via a messenger adapter.\n *\n * This returns a wrapped version of TanStack Query's QueryClient interface. Note that while some methods such as `invalidateQueries` have support for data services, some such as `setQueryData` do not.\n *\n * @param dataServices - A list of data services.\n * @param messenger - A messenger-like object with the following constraints: 1) the messenger must support the `call`, `subscribe` and `unsubscribe` methods; 2) all action handler arguments and event payloads must be JSON-compatible; 3) the messenger must minimally support actions that are scoped to the designated data services and must minimally support the `:cacheUpdated:${hash}` event scoped to the designated data services.\n * @param config - Optional query client configuration options.\n * @returns The created QueryClient.\n */\nexport function createUIQueryClient<DataServiceNames extends readonly string[]>(\n dataServices: DataServiceNames,\n messenger: MessengerAdapter<DataServiceNames[number]>,\n config: QueryClientConfig = {},\n): QueryClient {\n const subscriptions = new Map<\n string,\n DataServiceGranularCacheUpdatedHandler\n >();\n\n // Tracks how many mutation observers are currently relying on each mutation\n // key's cache subscription. Unlike queries, a `Mutation` does not expose its\n // observer count publicly, so we count observers ourselves and only tear down\n // the messenger subscription once the last observer for a key is removed.\n const mutationObserverCounts = new Map<string, number>();\n\n /**\n * Check whether a name is one of the provided data service names.\n *\n * @param service - The service name to check.\n * @returns Whether the service name is configured.\n */\n function isRecognizedDataService(\n service: string,\n ): service is DataServiceNames[number] {\n return dataServices.some((dataService) => dataService === service);\n }\n\n /**\n * Check whether an action belongs to one of the provided data services.\n *\n * @param action - The action name to check.\n * @returns Whether the action belongs to a configured data service.\n */\n function isRecognizedDataServiceAction(\n action: string,\n ): action is `${DataServiceNames[number]}:${string}` {\n return isRecognizedDataService(action.split(':')[0]);\n }\n\n /**\n * Parse a query key to detect a service name.\n *\n * @param queryKey - The query key.\n * @returns The service name if it parsing succeeded, otherwise null.\n */\n function parseQueryKey(queryKey: QueryKey): DataServiceNames[number] | null {\n const action = queryKey[0];\n\n if (typeof action !== 'string') {\n return null;\n }\n\n const service = action.split(':')[0];\n\n if (!isRecognizedDataService(service)) {\n return null;\n }\n\n return service;\n }\n\n /**\n * The default `mutationFn` for data-service mutations. It uses the\n * `mutationKey` to call an action on a data service through the messenger.\n *\n * This is a separate function so that we can use it to determine whether a\n * custom `mutationFn` was used when the mutation was executed.\n *\n * @param _variables - The variables with which the mutation is being\n * executed. Unused.\n * @param context - The context associated with the mutation. Holds the\n * `mutationKey`.\n * @returns The result of the data service action.\n */\n const defaultDataServiceMutationFn: MutationFunction = async (\n _variables,\n context,\n ): Promise<unknown> => {\n const { mutationKey } = context;\n\n assert(\n mutationKey !== undefined,\n \"You must pass a `mutationKey` that calls an action on the messenger provided to `createUIQueryClient`, e.g. `mutationKey: ['ExampleDataService:createOrder', ...]`.\",\n );\n\n const [action, ...params] = mutationKey;\n\n assert(\n typeof action === 'string' && isRecognizedDataServiceAction(action),\n \"You must pass a `mutationKey` that calls an action on the messenger provided to `createUIQueryClient`, e.g. `mutationKey: ['ExampleDataService:createOrder', ...]`.\",\n );\n\n log(`Detected mutation request, calling action: \"${action}\"`);\n\n // We assume that this mutation already has a global ID. (It was\n // added by our `MutationCache.build` override below.)\n const globalId = readGlobalId(context.meta);\n // We can't realistically test that it doesn't have a global ID, however,\n // since `MutationCache.build` always runs first.\n // istanbul ignore next\n assert(\n globalId !== undefined,\n 'Expected mutation to have a `globalId` in its `meta` by the time its `mutationFn` runs, but none was found. This is a bug in `createUIQueryClient`.',\n );\n\n return await messenger.call(action, ...(params as Json[]), globalId);\n };\n\n const client: QueryClient = new QueryClient({\n ...config,\n defaultOptions: {\n queries: {\n ...config.defaultOptions?.queries,\n queryFn: async (options): Promise<unknown> => {\n const { queryKey } = options;\n\n const action = queryKey[0];\n\n assert(\n typeof action === 'string' && isRecognizedDataServiceAction(action),\n \"You must pass a `queryKey` that calls an action on the messenger provided to `createUIQueryClient`, e.g. `queryKey: ['ExampleDataService:getAssets', ...]`.\",\n );\n\n const params = options.queryKey.slice(1);\n if (options.pageParam !== undefined) {\n params.push(options.pageParam);\n }\n\n return await messenger.call(action, ...params);\n },\n },\n mutations: {\n ...config.defaultOptions?.mutations,\n mutationFn: defaultDataServiceMutationFn,\n },\n },\n });\n\n const queryCache = client.getQueryCache();\n queryCache.subscribe((event) => {\n const { query } = event;\n\n const hash = query.queryHash;\n const hasSubscription = subscriptions.has(hash);\n const observerCount = query.getObserversCount();\n\n const service = parseQueryKey(query.queryKey);\n\n if (!service) {\n return;\n }\n\n if (\n !hasSubscription &&\n event.type === 'observerAdded' &&\n observerCount === 1\n ) {\n const cacheListener: DataServiceGranularCacheUpdatedHandler = (\n payload,\n ) => {\n if (payload.type === 'removed') {\n return;\n }\n\n log('Hydrating with', payload.state);\n hydrate(client, payload.state);\n };\n\n subscriptions.set(hash, cacheListener);\n messenger.subscribe(`${service}:cacheUpdated:${hash}`, cacheListener);\n } else if (\n event.type === 'observerRemoved' &&\n observerCount === 0 &&\n hasSubscription\n ) {\n const subscriptionListener = subscriptions.get(hash);\n\n // We can't write a test for this, as it's unrealistic\n // (we just need a check to appease TypeScript).\n // istanbul ignore next\n if (subscriptionListener) {\n messenger.unsubscribe(\n `${service}:cacheUpdated:${hash}`,\n subscriptionListener,\n );\n }\n subscriptions.delete(hash);\n }\n });\n\n const mutationCache = client.getMutationCache();\n mutationCache.subscribe((event) => {\n const { mutation } = event;\n\n if (!mutation?.options.mutationKey) {\n return;\n }\n\n const service = parseQueryKey(mutation.options.mutationKey);\n\n if (!service) {\n return;\n }\n\n const hash = hashKey(mutation.options.mutationKey);\n const hasSubscription = subscriptions.has(hash);\n\n log(\n `[mutationCache subscription] Received event \"${event.type}\". Details:`,\n event.mutation,\n );\n\n if (event.type === 'observerAdded') {\n mutationObserverCounts.set(\n hash,\n (mutationObserverCounts.get(hash) ?? 0) + 1,\n );\n\n log('[mutationCache subscription] hasSubscription =', hasSubscription);\n\n if (!hasSubscription) {\n const cacheListener = (\n payload: DataServiceGranularCacheUpdatedPayload,\n ): void => {\n log(\n `[mutationCache subscription] cacheUpdated:${hash} emitted`,\n payload,\n );\n\n // Only `updated` events have meaningful mutation state to sync.\n // When a mutation is first created, an `added` event is fired and the\n // state is `idle` with no result; hydrating that would clobber a UI\n // mutation that has already moved to `pending`, `success`, or\n // `error`. (And a `removed` event has no state at all.)\n if (payload.type !== 'updated') {\n return;\n }\n\n hydrateMutations(client, payload.state);\n };\n\n subscriptions.set(hash, cacheListener);\n messenger.subscribe(`${service}:cacheUpdated:${hash}`, cacheListener);\n }\n } else if (event.type === 'observerRemoved' && hasSubscription) {\n // We can assume that if an observed mutation is removed, it must have\n // first been added; and that when it was added, the observer count was\n // initialized. (There's no real way to test the alternative, anyway.)\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const remainingObservers = mutationObserverCounts.get(hash)! - 1;\n\n if (remainingObservers > 0) {\n mutationObserverCounts.set(hash, remainingObservers);\n return;\n }\n\n mutationObserverCounts.delete(hash);\n\n const subscriptionListener = subscriptions.get(hash);\n\n // A subscription always has a listener, since both are set together when\n // the first observer is added.\n // istanbul ignore next\n if (subscriptionListener) {\n messenger.unsubscribe(\n `${service}:cacheUpdated:${hash}`,\n subscriptionListener,\n );\n }\n subscriptions.delete(hash);\n }\n });\n\n // Override invalidateQueries to ensure the data service is invalidated as well.\n\n const originalInvalidate = client.invalidateQueries.bind(client);\n\n client.invalidateQueries = async (\n filters?: InvalidateQueryFilters,\n options?: InvalidateOptions,\n ): Promise<void> => {\n const queries = client.getQueryCache().findAll(filters);\n\n const services = [\n ...new Set(queries.map((query) => parseQueryKey(query.queryKey))),\n ];\n\n await Promise.all(\n services.map(async (service) => {\n if (!service) {\n return null;\n }\n\n return messenger.call(`${service}:invalidateQueries`, filters, options);\n }),\n );\n\n return originalInvalidate(filters, options);\n };\n\n // Override `build` to ensure that any data-service mutation created via\n // `executeMutation` or manually has a `globalId`.\n\n const originalBuildMutation = mutationCache.build.bind(mutationCache);\n\n mutationCache.build = function <TData, TError, TVariables, TOnMutateResult>(\n buildClient: QueryClient,\n options: MutationOptions<TData, TError, TVariables, TOnMutateResult>,\n state?: MutationState<TData, TError, TVariables, TOnMutateResult>,\n ): Mutation<TData, TError, TVariables, TOnMutateResult> {\n const mutation = originalBuildMutation(buildClient, options, state);\n const { mutationFn } = mutation.options;\n\n if (\n // We know that a custom `mutationFn` was provided because it\n // is not the default (which is defined above).\n mutationFn !== defaultDataServiceMutationFn ||\n // No need to add a global ID if there's already one.\n readGlobalId(mutation.options.meta) !== undefined\n ) {\n return mutation;\n }\n\n const globalId = uuidV4();\n\n // Give the mutation its own `options`/`meta` objects rather than mutating\n // in place. When options are already defaulted, TanStack returns the shared\n // observer options as-is, so mutating them would leak this mutation's\n // `globalId` back onto the observer and cause the next mutation built from\n // that observer to reuse the same id.\n const originalSetMutationOptions = mutation.setOptions.bind(mutation);\n originalSetMutationOptions({\n ...mutation.options,\n meta: { ...mutation.options.meta, globalId },\n });\n\n // `MutationObserver.setOptions` (triggered on every re-render) replaces a\n // pending mutation's options wholesale, which would otherwise strip the\n // `globalId` and stop the mutation from matching its service-side cache\n // updates. Preserve the established `globalId` across such updates.\n mutation.setOptions = (nextOptions): void => {\n originalSetMutationOptions({\n ...nextOptions,\n meta: { ...nextOptions.meta, globalId },\n });\n };\n\n return mutation;\n };\n\n return client;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"createUIQueryClient.js","sourceRoot":"","sources":["../src/createUIQueryClient.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DataServiceGranularCacheUpdatedEvent,\n DataServiceGranularCacheUpdatedPayload,\n SerializedQueryError,\n} from '@metamask/base-data-service';\nimport { Json, assert } from '@metamask/utils';\nimport {\n hashKey,\n hydrate,\n QueryClient,\n InvalidateQueryFilters,\n InvalidateOptions,\n QueryKey,\n QueryClientConfig,\n Mutation,\n MutationOptions,\n MutationState,\n MutationFunction,\n} from '@tanstack/query-core';\nimport { v4 as uuidV4 } from 'uuid';\n\nimport { hydrateMutations, readGlobalId } from './hydrateMutations.js';\nimport { createModuleLogger, projectLogger } from './loggers.js';\n\nconst log = createModuleLogger(projectLogger, 'createUIQueryClient');\n\n/**\n * Handles granular cache update events emitted by data services.\n */\ntype DataServiceGranularCacheUpdatedHandler = (\n payload: DataServiceGranularCacheUpdatedPayload,\n) => void;\n\n/**\n * Turn an error that came through a `:cacheUpdated` payload back into an\n * `Error`, so UI code can treat it like any other query error.\n *\n * @param serializedError - The serialized error.\n * @param serializedError.name - The name of the original error.\n * @param serializedError.message - The message of the original error.\n * @returns The error.\n */\nfunction deserializeQueryError({ name, message }: SerializedQueryError): Error {\n const error = new Error(message);\n error.name = name;\n return error;\n}\n\n/**\n * A narrower subset of the `Messenger` type, tailored to the messenger\n * that `createUIQueryClient` interacts with.\n */\ntype MessengerAdapter<DataServiceName extends string> = {\n /**\n * Call an action on one of the configured data services.\n *\n * Note: The parameters are typed as `unknown[]` rather than `Json[]`. For\n * concrete messengers, each action's parameters exist as fixed-length tuple,\n * and a variadic `Json[]` is not assignable to a fixed-length tuple, so using\n * `Json[]` here would reject otherwise valid messengers.\n */\n call(\n actionType: `${DataServiceName}:${string}`,\n ...params: unknown[]\n ): unknown;\n\n /**\n * Subscribe to a granular cache update event on one of the configured data\n * services.\n */\n subscribe(\n eventType: DataServiceGranularCacheUpdatedEvent<DataServiceName>['type'],\n handler: DataServiceGranularCacheUpdatedHandler,\n ): void;\n\n /**\n * Unsubscribe from a granular cache update event on one of the configured\n * data services.\n */\n unsubscribe(\n eventType: DataServiceGranularCacheUpdatedEvent<DataServiceName>['type'],\n handler: DataServiceGranularCacheUpdatedHandler,\n ): void;\n};\n\n/**\n * Create a QueryClient that enables data services to power queries and mutations via a messenger adapter.\n *\n * This returns a wrapped version of TanStack Query's QueryClient interface. Note that while some methods such as `invalidateQueries` have support for data services, some such as `setQueryData` do not.\n *\n * @param dataServices - A list of data services.\n * @param messenger - A messenger-like object with the following constraints: 1) the messenger must support the `call`, `subscribe` and `unsubscribe` methods; 2) all action handler arguments and event payloads must be JSON-compatible; 3) the messenger must minimally support actions that are scoped to the designated data services and must minimally support the `:cacheUpdated:${hash}` event scoped to the designated data services.\n * @param config - Optional query client configuration options.\n * @returns The created QueryClient.\n */\nexport function createUIQueryClient<DataServiceNames extends readonly string[]>(\n dataServices: DataServiceNames,\n messenger: MessengerAdapter<DataServiceNames[number]>,\n config: QueryClientConfig = {},\n): QueryClient {\n const subscriptions = new Map<\n string,\n DataServiceGranularCacheUpdatedHandler\n >();\n\n // Tracks how many mutation observers are currently relying on each mutation\n // key's cache subscription. Unlike queries, a `Mutation` does not expose its\n // observer count publicly, so we count observers ourselves and only tear down\n // the messenger subscription once the last observer for a key is removed.\n const mutationObserverCounts = new Map<string, number>();\n\n /**\n * Check whether a name is one of the provided data service names.\n *\n * @param service - The service name to check.\n * @returns Whether the service name is configured.\n */\n function isRecognizedDataService(\n service: string,\n ): service is DataServiceNames[number] {\n return dataServices.some((dataService) => dataService === service);\n }\n\n /**\n * Check whether an action belongs to one of the provided data services.\n *\n * @param action - The action name to check.\n * @returns Whether the action belongs to a configured data service.\n */\n function isRecognizedDataServiceAction(\n action: string,\n ): action is `${DataServiceNames[number]}:${string}` {\n return isRecognizedDataService(action.split(':')[0]);\n }\n\n /**\n * Parse a query key to detect a service name.\n *\n * @param queryKey - The query key.\n * @returns The service name if it parsing succeeded, otherwise null.\n */\n function parseQueryKey(queryKey: QueryKey): DataServiceNames[number] | null {\n const action = queryKey[0];\n\n if (typeof action !== 'string') {\n return null;\n }\n\n const service = action.split(':')[0];\n\n if (!isRecognizedDataService(service)) {\n return null;\n }\n\n return service;\n }\n\n /**\n * The default `mutationFn` for data-service mutations. It uses the\n * `mutationKey` to call an action on a data service through the messenger.\n *\n * This is a separate function so that we can use it to determine whether a\n * custom `mutationFn` was used when the mutation was executed.\n *\n * @param _variables - The variables with which the mutation is being\n * executed. Unused.\n * @param context - The context associated with the mutation. Holds the\n * `mutationKey`.\n * @returns The result of the data service action.\n */\n const defaultDataServiceMutationFn: MutationFunction = async (\n _variables,\n context,\n ): Promise<unknown> => {\n const { mutationKey } = context;\n\n assert(\n mutationKey !== undefined,\n \"You must pass a `mutationKey` that calls an action on the messenger provided to `createUIQueryClient`, e.g. `mutationKey: ['ExampleDataService:createOrder', ...]`.\",\n );\n\n const [action, ...params] = mutationKey;\n\n assert(\n typeof action === 'string' && isRecognizedDataServiceAction(action),\n \"You must pass a `mutationKey` that calls an action on the messenger provided to `createUIQueryClient`, e.g. `mutationKey: ['ExampleDataService:createOrder', ...]`.\",\n );\n\n log(`Detected mutation request, calling action: \"${action}\"`);\n\n // We assume that this mutation already has a global ID. (It was\n // added by our `MutationCache.build` override below.)\n const globalId = readGlobalId(context.meta);\n // We can't realistically test that it doesn't have a global ID, however,\n // since `MutationCache.build` always runs first.\n // istanbul ignore next\n assert(\n globalId !== undefined,\n 'Expected mutation to have a `globalId` in its `meta` by the time its `mutationFn` runs, but none was found. This is a bug in `createUIQueryClient`.',\n );\n\n return await messenger.call(action, ...(params as Json[]), globalId);\n };\n\n const client: QueryClient = new QueryClient({\n ...config,\n defaultOptions: {\n queries: {\n ...config.defaultOptions?.queries,\n queryFn: async (options): Promise<unknown> => {\n const { queryKey } = options;\n\n const action = queryKey[0];\n\n assert(\n typeof action === 'string' && isRecognizedDataServiceAction(action),\n \"You must pass a `queryKey` that calls an action on the messenger provided to `createUIQueryClient`, e.g. `queryKey: ['ExampleDataService:getAssets', ...]`.\",\n );\n\n const params = options.queryKey.slice(1);\n if (options.pageParam !== undefined) {\n params.push(options.pageParam);\n }\n\n return await messenger.call(action, ...params);\n },\n },\n mutations: {\n ...config.defaultOptions?.mutations,\n mutationFn: defaultDataServiceMutationFn,\n },\n },\n });\n\n const queryCache = client.getQueryCache();\n\n /**\n * Set a UI query back to `idle` if it is marked as fetching only because it\n * mirrors a fetch that the data service runs in the background. A fetch\n * that the UI started itself (and so has a promise) is left alone.\n *\n * @param hash - The hash of the query.\n */\n function resetBackgroundFetchStatus(hash: string): void {\n const uiQuery = queryCache.get(hash);\n\n if (\n uiQuery &&\n uiQuery.state.fetchStatus !== 'idle' &&\n uiQuery.promise === undefined\n ) {\n uiQuery.setState({ fetchStatus: 'idle' });\n }\n }\n\n queryCache.subscribe((event) => {\n const { query } = event;\n\n const hash = query.queryHash;\n const hasSubscription = subscriptions.has(hash);\n const observerCount = query.getObserversCount();\n\n const service = parseQueryKey(query.queryKey);\n\n if (!service) {\n return;\n }\n\n if (\n !hasSubscription &&\n event.type === 'observerAdded' &&\n observerCount === 1\n ) {\n const cacheListener: DataServiceGranularCacheUpdatedHandler = (\n payload,\n ) => {\n if (payload.type === 'removed') {\n // No more updates will arrive for this query, so a background fetch\n // we were mirroring will never be reported as finished.\n resetBackgroundFetchStatus(hash);\n return;\n }\n\n log('Hydrating with', payload.state);\n hydrate(client, payload.state);\n\n // `hydrate` leaves `fetchStatus` alone and only copies state when the\n // data is newer, so fetches and errors the service runs on its own\n // never show up. Mirror them here, unless the UI is running its own\n // fetch, which always wins.\n for (const { queryHash, state } of payload.state.queries) {\n const uiQuery = queryCache.get(queryHash);\n\n // `hydrate` builds any query that is missing, so this is a check\n // to appease TypeScript.\n // istanbul ignore next\n if (!uiQuery) {\n continue;\n }\n\n if (uiQuery.promise !== undefined) {\n continue;\n }\n\n uiQuery.setState({\n fetchStatus: state.fetchStatus,\n ...(state.status === 'error' &&\n state.error && {\n status: 'error',\n error: deserializeQueryError(state.error),\n errorUpdatedAt: state.errorUpdatedAt,\n }),\n });\n }\n };\n\n subscriptions.set(hash, cacheListener);\n messenger.subscribe(`${service}:cacheUpdated:${hash}`, cacheListener);\n } else if (\n event.type === 'observerRemoved' &&\n observerCount === 0 &&\n hasSubscription\n ) {\n const subscriptionListener = subscriptions.get(hash);\n\n // We can't write a test for this, as it's unrealistic\n // (we just need a check to appease TypeScript).\n // istanbul ignore next\n if (subscriptionListener) {\n messenger.unsubscribe(\n `${service}:cacheUpdated:${hash}`,\n subscriptionListener,\n );\n }\n subscriptions.delete(hash);\n\n // We stop listening here, so a background fetch we were mirroring would\n // otherwise stay `fetching` forever.\n resetBackgroundFetchStatus(hash);\n }\n });\n\n const mutationCache = client.getMutationCache();\n mutationCache.subscribe((event) => {\n const { mutation } = event;\n\n if (!mutation?.options.mutationKey) {\n return;\n }\n\n const service = parseQueryKey(mutation.options.mutationKey);\n\n if (!service) {\n return;\n }\n\n const hash = hashKey(mutation.options.mutationKey);\n const hasSubscription = subscriptions.has(hash);\n\n log(\n `[mutationCache subscription] Received event \"${event.type}\". Details:`,\n event.mutation,\n );\n\n if (event.type === 'observerAdded') {\n mutationObserverCounts.set(\n hash,\n (mutationObserverCounts.get(hash) ?? 0) + 1,\n );\n\n log('[mutationCache subscription] hasSubscription =', hasSubscription);\n\n if (!hasSubscription) {\n const cacheListener = (\n payload: DataServiceGranularCacheUpdatedPayload,\n ): void => {\n log(\n `[mutationCache subscription] cacheUpdated:${hash} emitted`,\n payload,\n );\n\n // Only `updated` events have meaningful mutation state to sync.\n // When a mutation is first created, an `added` event is fired and the\n // state is `idle` with no result; hydrating that would clobber a UI\n // mutation that has already moved to `pending`, `success`, or\n // `error`. (And a `removed` event has no state at all.)\n if (payload.type !== 'updated') {\n return;\n }\n\n hydrateMutations(client, payload.state);\n };\n\n subscriptions.set(hash, cacheListener);\n messenger.subscribe(`${service}:cacheUpdated:${hash}`, cacheListener);\n }\n } else if (event.type === 'observerRemoved' && hasSubscription) {\n // We can assume that if an observed mutation is removed, it must have\n // first been added; and that when it was added, the observer count was\n // initialized. (There's no real way to test the alternative, anyway.)\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const remainingObservers = mutationObserverCounts.get(hash)! - 1;\n\n if (remainingObservers > 0) {\n mutationObserverCounts.set(hash, remainingObservers);\n return;\n }\n\n mutationObserverCounts.delete(hash);\n\n const subscriptionListener = subscriptions.get(hash);\n\n // A subscription always has a listener, since both are set together when\n // the first observer is added.\n // istanbul ignore next\n if (subscriptionListener) {\n messenger.unsubscribe(\n `${service}:cacheUpdated:${hash}`,\n subscriptionListener,\n );\n }\n subscriptions.delete(hash);\n }\n });\n\n // Override invalidateQueries to ensure the data service is invalidated as well.\n\n const originalInvalidate = client.invalidateQueries.bind(client);\n\n client.invalidateQueries = async (\n filters?: InvalidateQueryFilters,\n options?: InvalidateOptions,\n ): Promise<void> => {\n const queries = client.getQueryCache().findAll(filters);\n\n const services = [\n ...new Set(queries.map((query) => parseQueryKey(query.queryKey))),\n ];\n\n await Promise.all(\n services.map(async (service) => {\n if (!service) {\n return null;\n }\n\n return messenger.call(`${service}:invalidateQueries`, filters, options);\n }),\n );\n\n return originalInvalidate(filters, options);\n };\n\n // Override `build` to ensure that any data-service mutation created via\n // `executeMutation` or manually has a `globalId`.\n\n const originalBuildMutation = mutationCache.build.bind(mutationCache);\n\n mutationCache.build = function <TData, TError, TVariables, TOnMutateResult>(\n buildClient: QueryClient,\n options: MutationOptions<TData, TError, TVariables, TOnMutateResult>,\n state?: MutationState<TData, TError, TVariables, TOnMutateResult>,\n ): Mutation<TData, TError, TVariables, TOnMutateResult> {\n const mutation = originalBuildMutation(buildClient, options, state);\n const { mutationFn } = mutation.options;\n\n if (\n // We know that a custom `mutationFn` was provided because it\n // is not the default (which is defined above).\n mutationFn !== defaultDataServiceMutationFn ||\n // No need to add a global ID if there's already one.\n readGlobalId(mutation.options.meta) !== undefined\n ) {\n return mutation;\n }\n\n const globalId = uuidV4();\n\n // Give the mutation its own `options`/`meta` objects rather than mutating\n // in place. When options are already defaulted, TanStack returns the shared\n // observer options as-is, so mutating them would leak this mutation's\n // `globalId` back onto the observer and cause the next mutation built from\n // that observer to reuse the same id.\n const originalSetMutationOptions = mutation.setOptions.bind(mutation);\n originalSetMutationOptions({\n ...mutation.options,\n meta: { ...mutation.options.meta, globalId },\n });\n\n // `MutationObserver.setOptions` (triggered on every re-render) replaces a\n // pending mutation's options wholesale, which would otherwise strip the\n // `globalId` and stop the mutation from matching its service-side cache\n // updates. Preserve the established `globalId` across such updates.\n mutation.setOptions = (nextOptions): void => {\n originalSetMutationOptions({\n ...nextOptions,\n meta: { ...nextOptions.meta, globalId },\n });\n };\n\n return mutation;\n };\n\n return client;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/react-data-query",
|
|
3
|
-
"version": "2.0.0-preview-
|
|
3
|
+
"version": "2.0.0-preview-9fd631f7d",
|
|
4
4
|
"description": "Provides React utilities for consuming data services",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ethereum",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@metamask/utils": "^12.0.1",
|
|
53
53
|
"@tanstack/query-core": "^5.103.2",
|
|
54
54
|
"@tanstack/react-query": "^5.103.2",
|
|
55
|
-
"uuid": "^
|
|
55
|
+
"uuid": "^11.1.1"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@metamask/auto-changelog": "^6.2.1",
|