@metamask-previews/react-data-query 1.0.0-preview-8bfa290fb → 2.0.0-preview-97d6b86c0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +9 -8
  2. package/dist/{createUIQueryClient.d.mts → createUIQueryClient.d.ts} +3 -3
  3. package/dist/createUIQueryClient.d.ts.map +1 -0
  4. package/dist/createUIQueryClient.js +128 -0
  5. package/dist/createUIQueryClient.js.map +1 -0
  6. package/dist/{hooks.d.mts → hooks.d.ts} +3 -18
  7. package/dist/hooks.d.ts.map +1 -0
  8. package/dist/{hooks.mjs → hooks.js} +4 -21
  9. package/dist/hooks.js.map +1 -0
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +3 -0
  13. package/dist/index.js.map +1 -0
  14. package/package.json +15 -21
  15. package/dist/createUIQueryClient.cjs +0 -219
  16. package/dist/createUIQueryClient.cjs.map +0 -1
  17. package/dist/createUIQueryClient.d.cts +0 -51
  18. package/dist/createUIQueryClient.d.cts.map +0 -1
  19. package/dist/createUIQueryClient.d.mts.map +0 -1
  20. package/dist/createUIQueryClient.mjs +0 -215
  21. package/dist/createUIQueryClient.mjs.map +0 -1
  22. package/dist/hooks.cjs +0 -56
  23. package/dist/hooks.cjs.map +0 -1
  24. package/dist/hooks.d.cts +0 -36
  25. package/dist/hooks.d.cts.map +0 -1
  26. package/dist/hooks.d.mts.map +0 -1
  27. package/dist/hooks.mjs.map +0 -1
  28. package/dist/hydrateMutations.cjs +0 -100
  29. package/dist/hydrateMutations.cjs.map +0 -1
  30. package/dist/hydrateMutations.d.cts +0 -35
  31. package/dist/hydrateMutations.d.cts.map +0 -1
  32. package/dist/hydrateMutations.d.mts +0 -35
  33. package/dist/hydrateMutations.d.mts.map +0 -1
  34. package/dist/hydrateMutations.mjs +0 -95
  35. package/dist/hydrateMutations.mjs.map +0 -1
  36. package/dist/index.cjs +0 -10
  37. package/dist/index.cjs.map +0 -1
  38. package/dist/index.d.cts +0 -3
  39. package/dist/index.d.cts.map +0 -1
  40. package/dist/index.d.mts +0 -3
  41. package/dist/index.d.mts.map +0 -1
  42. package/dist/index.mjs +0 -3
  43. package/dist/index.mjs.map +0 -1
  44. package/dist/loggers.cjs +0 -7
  45. package/dist/loggers.cjs.map +0 -1
  46. package/dist/loggers.d.cts +0 -5
  47. package/dist/loggers.d.cts.map +0 -1
  48. package/dist/loggers.d.mts +0 -5
  49. package/dist/loggers.d.mts.map +0 -1
  50. package/dist/loggers.mjs +0 -4
  51. package/dist/loggers.mjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"createUIQueryClient.cjs","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 MutationOptions,\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 queries and subscribes to data services using a\n * messenger adapter. This is a messenger-like object that carries some\n * constraints:\n *\n * 1. The messenger must support the `call`, `subscribe` and\n * `unsubscribe` methods.\n * 2. All action handler arguments and event payloads must be JSON-compatible.\n * 3. The messenger must minimally support actions that are scoped to the\n * designated data services and must minimally support the\n * `:cacheUpdated:${hash}` event scoped to the designated data services.\n *\n * @param dataServices - A list of data services.\n * @param messenger - A messenger adapter.\n * @param config - Optional query client configuration options.\n * @returns The 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 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: config.defaultOptions?.mutations,\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 hash = hashKey(mutation.options.mutationKey);\n const hasSubscription = subscriptions.has(hash);\n\n const service = parseQueryKey(mutation.options.mutationKey);\n\n if (!service) {\n return;\n }\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 if (payload.type === 'removed') {\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 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 defaultMutationOptions to check for mutationKey if mutationFn is\n // not provided.\n const originalDefaultMutationOptions =\n client.defaultMutationOptions.bind(client);\n\n client.defaultMutationOptions = <\n // We are overriding a type in @tanstack/query-core.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Options extends MutationOptions<any, any, any, any>,\n >(\n options?: Options,\n ): Options => {\n const defaultedOptions = originalDefaultMutationOptions(options);\n\n // Only mutations that fall back to the data-service default `mutationFn`\n // need a `globalId` to correlate the UI and service caches. A mutation with\n // a custom `mutationFn` never reaches a data service, so we leave it alone.\n if (defaultedOptions.mutationFn === undefined) {\n // Generate the `globalId` once and memoize it on `meta` so it stays\n // stable across the mutation's lifetime and can be matched against\n // incoming cache updates.\n const globalId = readGlobalId(defaultedOptions.meta) ?? uuidV4();\n defaultedOptions.meta = { ...defaultedOptions.meta, globalId };\n\n defaultedOptions.mutationFn = async (): Promise<unknown> => {\n const { mutationKey } = defaultedOptions;\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 // The `globalId` is passed as the trailing action argument. Each data\n // service mutation method forwards it into `executeMutation`, which\n // echoes it back on the service-side mutation's `meta`.\n return await messenger.call(action, ...(params as Json[]), globalId);\n };\n }\n\n return defaultedOptions;\n };\n\n return client;\n}\n"]}
@@ -1,51 +0,0 @@
1
- import type { DataServiceGranularCacheUpdatedEvent, DataServiceGranularCacheUpdatedPayload } from "@metamask/base-data-service";
2
- import { QueryClient, QueryClientConfig } from "@tanstack/query-core";
3
- /**
4
- * Handles granular cache update events emitted by data services.
5
- */
6
- type DataServiceGranularCacheUpdatedHandler = (payload: DataServiceGranularCacheUpdatedPayload) => void;
7
- /**
8
- * A narrower subset of the `Messenger` type, tailored to the messenger
9
- * that `createUIQueryClient` interacts with.
10
- */
11
- type MessengerAdapter<DataServiceName extends string> = {
12
- /**
13
- * Call an action on one of the configured data services.
14
- *
15
- * Note: The parameters are typed as `unknown[]` rather than `Json[]`. For
16
- * concrete messengers, each action's parameters exist as fixed-length tuple,
17
- * and a variadic `Json[]` is not assignable to a fixed-length tuple, so using
18
- * `Json[]` here would reject otherwise valid messengers.
19
- */
20
- call(actionType: `${DataServiceName}:${string}`, ...params: unknown[]): unknown;
21
- /**
22
- * Subscribe to a granular cache update event on one of the configured data
23
- * services.
24
- */
25
- subscribe(eventType: DataServiceGranularCacheUpdatedEvent<DataServiceName>['type'], handler: DataServiceGranularCacheUpdatedHandler): void;
26
- /**
27
- * Unsubscribe from a granular cache update event on one of the configured
28
- * data services.
29
- */
30
- unsubscribe(eventType: DataServiceGranularCacheUpdatedEvent<DataServiceName>['type'], handler: DataServiceGranularCacheUpdatedHandler): void;
31
- };
32
- /**
33
- * Create a QueryClient that queries and subscribes to data services using a
34
- * messenger adapter. This is a messenger-like object that carries some
35
- * constraints:
36
- *
37
- * 1. The messenger must support the `call`, `subscribe` and
38
- * `unsubscribe` methods.
39
- * 2. All action handler arguments and event payloads must be JSON-compatible.
40
- * 3. The messenger must minimally support actions that are scoped to the
41
- * designated data services and must minimally support the
42
- * `:cacheUpdated:${hash}` event scoped to the designated data services.
43
- *
44
- * @param dataServices - A list of data services.
45
- * @param messenger - A messenger adapter.
46
- * @param config - Optional query client configuration options.
47
- * @returns The QueryClient.
48
- */
49
- export declare function createUIQueryClient<DataServiceNames extends readonly string[]>(dataServices: DataServiceNames, messenger: MessengerAdapter<DataServiceNames[number]>, config?: QueryClientConfig): QueryClient;
50
- export {};
51
- //# sourceMappingURL=createUIQueryClient.d.cts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createUIQueryClient.d.cts","sourceRoot":"","sources":["../src/createUIQueryClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oCAAoC,EACpC,sCAAsC,EACvC,oCAAoC;AAErC,OAAO,EAGL,WAAW,EAIX,iBAAiB,EAElB,6BAA6B;AAQ9B;;GAEG;AACH,KAAK,sCAAsC,GAAG,CAC5C,OAAO,EAAE,sCAAsC,KAC5C,IAAI,CAAC;AAEV;;;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;;;;;;;;;;;;;;;;GAgBG;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,CAqSb"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"createUIQueryClient.d.mts","sourceRoot":"","sources":["../src/createUIQueryClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oCAAoC,EACpC,sCAAsC,EACvC,oCAAoC;AAErC,OAAO,EAGL,WAAW,EAIX,iBAAiB,EAElB,6BAA6B;AAQ9B;;GAEG;AACH,KAAK,sCAAsC,GAAG,CAC5C,OAAO,EAAE,sCAAsC,KAC5C,IAAI,CAAC;AAEV;;;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;;;;;;;;;;;;;;;;GAgBG;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,CAqSb"}
@@ -1,215 +0,0 @@
1
- import { assert } from "@metamask/utils";
2
- import { hashKey, hydrate, QueryClient } from "@tanstack/query-core";
3
- import { v4 as uuidV4 } from "uuid";
4
- import { hydrateMutations, readGlobalId } from "./hydrateMutations.mjs";
5
- import { createModuleLogger, projectLogger } from "./loggers.mjs";
6
- const log = createModuleLogger(projectLogger, 'createUIQueryClient');
7
- /**
8
- * Create a QueryClient that queries and subscribes to data services using a
9
- * messenger adapter. This is a messenger-like object that carries some
10
- * constraints:
11
- *
12
- * 1. The messenger must support the `call`, `subscribe` and
13
- * `unsubscribe` methods.
14
- * 2. All action handler arguments and event payloads must be JSON-compatible.
15
- * 3. The messenger must minimally support actions that are scoped to the
16
- * designated data services and must minimally support the
17
- * `:cacheUpdated:${hash}` event scoped to the designated data services.
18
- *
19
- * @param dataServices - A list of data services.
20
- * @param messenger - A messenger adapter.
21
- * @param config - Optional query client configuration options.
22
- * @returns The QueryClient.
23
- */
24
- export function createUIQueryClient(dataServices, messenger, config = {}) {
25
- const subscriptions = new Map();
26
- // Tracks how many mutation observers are currently relying on each mutation
27
- // key's cache subscription. Unlike queries, a `Mutation` does not expose its
28
- // observer count publicly, so we count observers ourselves and only tear down
29
- // the messenger subscription once the last observer for a key is removed.
30
- const mutationObserverCounts = new Map();
31
- /**
32
- * Check whether a name is one of the provided data service names.
33
- *
34
- * @param service - The service name to check.
35
- * @returns Whether the service name is configured.
36
- */
37
- function isRecognizedDataService(service) {
38
- return dataServices.some((dataService) => dataService === service);
39
- }
40
- /**
41
- * Check whether an action belongs to one of the provided data services.
42
- *
43
- * @param action - The action name to check.
44
- * @returns Whether the action belongs to a configured data service.
45
- */
46
- function isRecognizedDataServiceAction(action) {
47
- return isRecognizedDataService(action.split(':')[0]);
48
- }
49
- /**
50
- * Parse a query key to detect a service name.
51
- *
52
- * @param queryKey - The query key.
53
- * @returns The service name if it parsing succeeded, otherwise null.
54
- */
55
- function parseQueryKey(queryKey) {
56
- const action = queryKey[0];
57
- if (typeof action !== 'string') {
58
- return null;
59
- }
60
- const service = action.split(':')[0];
61
- if (!isRecognizedDataService(service)) {
62
- return null;
63
- }
64
- return service;
65
- }
66
- const client = new QueryClient({
67
- ...config,
68
- defaultOptions: {
69
- queries: {
70
- ...config.defaultOptions?.queries,
71
- queryFn: async (options) => {
72
- const { queryKey } = options;
73
- const action = queryKey[0];
74
- assert(typeof action === 'string' && isRecognizedDataServiceAction(action), "You must pass a `queryKey` that calls an action on the messenger provided to `createUIQueryClient`, e.g. `queryKey: ['ExampleDataService:getAssets', ...]`.");
75
- const params = options.queryKey.slice(1);
76
- if (options.pageParam !== undefined) {
77
- params.push(options.pageParam);
78
- }
79
- return await messenger.call(action, ...params);
80
- },
81
- },
82
- mutations: config.defaultOptions?.mutations,
83
- },
84
- });
85
- const queryCache = client.getQueryCache();
86
- queryCache.subscribe((event) => {
87
- const { query } = event;
88
- const hash = query.queryHash;
89
- const hasSubscription = subscriptions.has(hash);
90
- const observerCount = query.getObserversCount();
91
- const service = parseQueryKey(query.queryKey);
92
- if (!service) {
93
- return;
94
- }
95
- if (!hasSubscription &&
96
- event.type === 'observerAdded' &&
97
- observerCount === 1) {
98
- const cacheListener = (payload) => {
99
- if (payload.type === 'removed') {
100
- return;
101
- }
102
- log('Hydrating with', payload.state);
103
- hydrate(client, payload.state);
104
- };
105
- subscriptions.set(hash, cacheListener);
106
- messenger.subscribe(`${service}:cacheUpdated:${hash}`, cacheListener);
107
- }
108
- else if (event.type === 'observerRemoved' &&
109
- observerCount === 0 &&
110
- hasSubscription) {
111
- const subscriptionListener = subscriptions.get(hash);
112
- // We can't write a test for this, as it's unrealistic
113
- // (we just need a check to appease TypeScript).
114
- // istanbul ignore next
115
- if (subscriptionListener) {
116
- messenger.unsubscribe(`${service}:cacheUpdated:${hash}`, subscriptionListener);
117
- }
118
- subscriptions.delete(hash);
119
- }
120
- });
121
- const mutationCache = client.getMutationCache();
122
- mutationCache.subscribe((event) => {
123
- const { mutation } = event;
124
- if (!mutation?.options.mutationKey) {
125
- return;
126
- }
127
- const hash = hashKey(mutation.options.mutationKey);
128
- const hasSubscription = subscriptions.has(hash);
129
- const service = parseQueryKey(mutation.options.mutationKey);
130
- if (!service) {
131
- return;
132
- }
133
- log(`[mutationCache subscription] Received event "${event.type}". Details:`, event.mutation);
134
- if (event.type === 'observerAdded') {
135
- mutationObserverCounts.set(hash, (mutationObserverCounts.get(hash) ?? 0) + 1);
136
- log('[mutationCache subscription] hasSubscription =', hasSubscription);
137
- if (!hasSubscription) {
138
- const cacheListener = (payload) => {
139
- log(`[mutationCache subscription] cacheUpdated:${hash} emitted`, payload);
140
- if (payload.type === 'removed') {
141
- return;
142
- }
143
- hydrateMutations(client, payload.state);
144
- };
145
- subscriptions.set(hash, cacheListener);
146
- messenger.subscribe(`${service}:cacheUpdated:${hash}`, cacheListener);
147
- }
148
- }
149
- else if (event.type === 'observerRemoved' && hasSubscription) {
150
- // We can assume that if an observed mutation is removed, it must have
151
- // first been added; and that when it was added, the observer count was
152
- // initialized. (There's no real way to test the alternative, anyway.)
153
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
154
- const remainingObservers = mutationObserverCounts.get(hash) - 1;
155
- if (remainingObservers > 0) {
156
- mutationObserverCounts.set(hash, remainingObservers);
157
- return;
158
- }
159
- mutationObserverCounts.delete(hash);
160
- const subscriptionListener = subscriptions.get(hash);
161
- // A subscription always has a listener, since both are set together when
162
- // the first observer is added.
163
- // istanbul ignore next
164
- if (subscriptionListener) {
165
- messenger.unsubscribe(`${service}:cacheUpdated:${hash}`, subscriptionListener);
166
- }
167
- subscriptions.delete(hash);
168
- }
169
- });
170
- // Override invalidateQueries to ensure the data service is invalidated as well.
171
- const originalInvalidate = client.invalidateQueries.bind(client);
172
- client.invalidateQueries = async (filters, options) => {
173
- const queries = client.getQueryCache().findAll(filters);
174
- const services = [
175
- ...new Set(queries.map((query) => parseQueryKey(query.queryKey))),
176
- ];
177
- await Promise.all(services.map(async (service) => {
178
- if (!service) {
179
- return null;
180
- }
181
- return messenger.call(`${service}:invalidateQueries`, filters, options);
182
- }));
183
- return originalInvalidate(filters, options);
184
- };
185
- // Override defaultMutationOptions to check for mutationKey if mutationFn is
186
- // not provided.
187
- const originalDefaultMutationOptions = client.defaultMutationOptions.bind(client);
188
- client.defaultMutationOptions = (options) => {
189
- const defaultedOptions = originalDefaultMutationOptions(options);
190
- // Only mutations that fall back to the data-service default `mutationFn`
191
- // need a `globalId` to correlate the UI and service caches. A mutation with
192
- // a custom `mutationFn` never reaches a data service, so we leave it alone.
193
- if (defaultedOptions.mutationFn === undefined) {
194
- // Generate the `globalId` once and memoize it on `meta` so it stays
195
- // stable across the mutation's lifetime and can be matched against
196
- // incoming cache updates.
197
- const globalId = readGlobalId(defaultedOptions.meta) ?? uuidV4();
198
- defaultedOptions.meta = { ...defaultedOptions.meta, globalId };
199
- defaultedOptions.mutationFn = async () => {
200
- const { mutationKey } = defaultedOptions;
201
- assert(mutationKey !== undefined, "You must pass a `mutationKey` that calls an action on the messenger provided to `createUIQueryClient`, e.g. `mutationKey: ['ExampleDataService:createOrder', ...]`.");
202
- const [action, ...params] = mutationKey;
203
- assert(typeof action === 'string' && isRecognizedDataServiceAction(action), "You must pass a `mutationKey` that calls an action on the messenger provided to `createUIQueryClient`, e.g. `mutationKey: ['ExampleDataService:createOrder', ...]`.");
204
- log(`Detected mutation request, calling action: "${action}"`);
205
- // The `globalId` is passed as the trailing action argument. Each data
206
- // service mutation method forwards it into `executeMutation`, which
207
- // echoes it back on the service-side mutation's `meta`.
208
- return await messenger.call(action, ...params, globalId);
209
- };
210
- }
211
- return defaultedOptions;
212
- };
213
- return client;
214
- }
215
- //# sourceMappingURL=createUIQueryClient.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createUIQueryClient.mjs","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 MutationOptions,\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 queries and subscribes to data services using a\n * messenger adapter. This is a messenger-like object that carries some\n * constraints:\n *\n * 1. The messenger must support the `call`, `subscribe` and\n * `unsubscribe` methods.\n * 2. All action handler arguments and event payloads must be JSON-compatible.\n * 3. The messenger must minimally support actions that are scoped to the\n * designated data services and must minimally support the\n * `:cacheUpdated:${hash}` event scoped to the designated data services.\n *\n * @param dataServices - A list of data services.\n * @param messenger - A messenger adapter.\n * @param config - Optional query client configuration options.\n * @returns The 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 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: config.defaultOptions?.mutations,\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 hash = hashKey(mutation.options.mutationKey);\n const hasSubscription = subscriptions.has(hash);\n\n const service = parseQueryKey(mutation.options.mutationKey);\n\n if (!service) {\n return;\n }\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 if (payload.type === 'removed') {\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 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 defaultMutationOptions to check for mutationKey if mutationFn is\n // not provided.\n const originalDefaultMutationOptions =\n client.defaultMutationOptions.bind(client);\n\n client.defaultMutationOptions = <\n // We are overriding a type in @tanstack/query-core.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Options extends MutationOptions<any, any, any, any>,\n >(\n options?: Options,\n ): Options => {\n const defaultedOptions = originalDefaultMutationOptions(options);\n\n // Only mutations that fall back to the data-service default `mutationFn`\n // need a `globalId` to correlate the UI and service caches. A mutation with\n // a custom `mutationFn` never reaches a data service, so we leave it alone.\n if (defaultedOptions.mutationFn === undefined) {\n // Generate the `globalId` once and memoize it on `meta` so it stays\n // stable across the mutation's lifetime and can be matched against\n // incoming cache updates.\n const globalId = readGlobalId(defaultedOptions.meta) ?? uuidV4();\n defaultedOptions.meta = { ...defaultedOptions.meta, globalId };\n\n defaultedOptions.mutationFn = async (): Promise<unknown> => {\n const { mutationKey } = defaultedOptions;\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 // The `globalId` is passed as the trailing action argument. Each data\n // service mutation method forwards it into `executeMutation`, which\n // echoes it back on the service-side mutation's `meta`.\n return await messenger.call(action, ...(params as Json[]), globalId);\n };\n }\n\n return defaultedOptions;\n };\n\n return client;\n}\n"]}
package/dist/hooks.cjs DELETED
@@ -1,56 +0,0 @@
1
- "use strict";
2
- /**
3
- * @file
4
- * We provide re-exports of the underlying TanStack Query hooks with narrower types,
5
- * removing `staleTime` and `queryFn` which aren't useful when using data services.
6
- */
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.useMutation = exports.useInfiniteQuery = exports.useQuery = void 0;
9
- const react_query_1 = require("@tanstack/react-query");
10
- const DATA_SERVICE_QUERY_DEFAULTS = {
11
- staleTime: 0,
12
- retry: false,
13
- };
14
- const DATA_SERVICE_MUTATION_DEFAULTS = {
15
- retry: false,
16
- };
17
- /**
18
- * Consume a query from a data service.
19
- *
20
- * @param options - The query options. Keep in mind that `staleTime` and `queryFn` are not supported
21
- * when querying data services.
22
- * @returns The query results.
23
- */
24
- function useQuery(options) {
25
- return (0, react_query_1.useQuery)({ ...DATA_SERVICE_QUERY_DEFAULTS, ...options });
26
- }
27
- exports.useQuery = useQuery;
28
- /**
29
- * Consume a paginated query from a data service.
30
- *
31
- * @param options - The query options. Keep in mind that `staleTime` and `queryFn` are not supported
32
- * when querying data services.
33
- * @returns The paginated query results.
34
- */
35
- function useInfiniteQuery(options) {
36
- return (0, react_query_1.useInfiniteQuery)({
37
- ...DATA_SERVICE_QUERY_DEFAULTS,
38
- ...options,
39
- });
40
- }
41
- exports.useInfiniteQuery = useInfiniteQuery;
42
- /**
43
- * Execute a mutation through a data service.
44
- *
45
- * @param options - The mutation options. Keep in mind that `mutationFn` is not supported
46
- * when executing mutations through data services.
47
- * @returns The result of the mutation.
48
- */
49
- function useMutation(options) {
50
- return (0, react_query_1.useMutation)({
51
- ...DATA_SERVICE_MUTATION_DEFAULTS,
52
- ...options,
53
- });
54
- }
55
- exports.useMutation = useMutation;
56
- //# sourceMappingURL=hooks.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hooks.cjs","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAGH,uDAe+B;AAE/B,MAAM,2BAA2B,GAAG;IAClC,SAAS,EAAE,CAAC;IACZ,KAAK,EAAE,KAAK;CACb,CAAC;AAEF,MAAM,8BAA8B,GAAG;IACrC,KAAK,EAAE,KAAK;CACb,CAAC;AAEF;;;;;;GAMG;AACH,SAAgB,QAAQ,CAMtB,OAQC;IAED,OAAO,IAAA,sBAAoB,EAAC,EAAE,GAAG,2BAA2B,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;AAC9E,CAAC;AAjBD,4BAiBC;AAED;;;;;;GAMG;AACH,SAAgB,gBAAgB,CAO9B,OAGC;IAED,OAAO,IAAA,8BAA4B,EAAC;QAClC,GAAG,2BAA2B;QAC9B,GAAG,OAAO;KACX,CAAC,CAAC;AACL,CAAC;AAhBD,4CAgBC;AAED;;;;;;GAMG;AACH,SAAgB,WAAW,CAOzB,OAKC;IAED,OAAO,IAAA,yBAAuB,EAAC;QAC7B,GAAG,8BAA8B;QACjC,GAAG,OAAO;KACX,CAAC,CAAC;AACL,CAAC;AAlBD,kCAkBC","sourcesContent":["/**\n * @file\n * We provide re-exports of the underlying TanStack Query hooks with narrower types,\n * removing `staleTime` and `queryFn` which aren't useful when using data services.\n */\n\nimport { QueryKey, MutationKey } from '@metamask/base-data-service';\nimport {\n useQuery as useQueryFromTanStack,\n useInfiniteQuery as useInfiniteQueryFromTanStack,\n useMutation as useMutationFromTanStack,\n OmitKeyof,\n UseQueryOptions,\n InitialDataFunction,\n NonUndefinedGuard,\n UseInfiniteQueryOptions,\n UseQueryResult,\n UseInfiniteQueryResult,\n DefaultError,\n InfiniteData,\n UseMutationOptions,\n UseMutationResult,\n} from '@tanstack/react-query';\n\nconst DATA_SERVICE_QUERY_DEFAULTS = {\n staleTime: 0,\n retry: false,\n};\n\nconst DATA_SERVICE_MUTATION_DEFAULTS = {\n retry: false,\n};\n\n/**\n * Consume a query from a data service.\n *\n * @param options - The query options. Keep in mind that `staleTime` and `queryFn` are not supported\n * when querying data services.\n * @returns The query results.\n */\nexport function useQuery<\n TQueryFnData = unknown,\n TError = DefaultError,\n TData = TQueryFnData,\n TQueryKey extends QueryKey = QueryKey,\n>(\n options: OmitKeyof<\n UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,\n 'initialData' | 'staleTime' | 'queryFn'\n > & {\n initialData?:\n | undefined\n | InitialDataFunction<NonUndefinedGuard<TQueryFnData>>\n | NonUndefinedGuard<TQueryFnData>;\n },\n): UseQueryResult<TData, TError> {\n return useQueryFromTanStack({ ...DATA_SERVICE_QUERY_DEFAULTS, ...options });\n}\n\n/**\n * Consume a paginated query from a data service.\n *\n * @param options - The query options. Keep in mind that `staleTime` and `queryFn` are not supported\n * when querying data services.\n * @returns The paginated query results.\n */\nexport function useInfiniteQuery<\n TQueryFnData = unknown,\n TError = DefaultError,\n TData = InfiniteData<TQueryFnData>,\n TQueryKey extends QueryKey = QueryKey,\n TPageParam = unknown,\n>(\n options: OmitKeyof<\n UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>,\n 'staleTime' | 'queryFn'\n >,\n): UseInfiniteQueryResult<TData, TError> {\n return useInfiniteQueryFromTanStack({\n ...DATA_SERVICE_QUERY_DEFAULTS,\n ...options,\n });\n}\n\n/**\n * Execute a mutation through a data service.\n *\n * @param options - The mutation options. Keep in mind that `mutationFn` is not supported\n * when executing mutations through data services.\n * @returns The result of the mutation.\n */\nexport function useMutation<\n TData = unknown,\n TError = DefaultError,\n TVariables = void,\n TOnMutateResult = unknown,\n TMutationKey extends MutationKey = MutationKey,\n>(\n options: OmitKeyof<\n UseMutationOptions<TData, TError, TVariables, TOnMutateResult>,\n 'mutationKey' | 'mutationFn'\n > & {\n mutationKey: TMutationKey;\n },\n): UseMutationResult<TData, TError, TVariables, TOnMutateResult> {\n return useMutationFromTanStack({\n ...DATA_SERVICE_MUTATION_DEFAULTS,\n ...options,\n });\n}\n"]}
package/dist/hooks.d.cts DELETED
@@ -1,36 +0,0 @@
1
- /**
2
- * @file
3
- * We provide re-exports of the underlying TanStack Query hooks with narrower types,
4
- * removing `staleTime` and `queryFn` which aren't useful when using data services.
5
- */
6
- import { QueryKey, MutationKey } from "@metamask/base-data-service";
7
- import { OmitKeyof, UseQueryOptions, InitialDataFunction, NonUndefinedGuard, UseInfiniteQueryOptions, UseQueryResult, UseInfiniteQueryResult, DefaultError, InfiniteData, UseMutationOptions, UseMutationResult } from "@tanstack/react-query";
8
- /**
9
- * Consume a query from a data service.
10
- *
11
- * @param options - The query options. Keep in mind that `staleTime` and `queryFn` are not supported
12
- * when querying data services.
13
- * @returns The query results.
14
- */
15
- export declare function useQuery<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(options: OmitKeyof<UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>, 'initialData' | 'staleTime' | 'queryFn'> & {
16
- initialData?: undefined | InitialDataFunction<NonUndefinedGuard<TQueryFnData>> | NonUndefinedGuard<TQueryFnData>;
17
- }): UseQueryResult<TData, TError>;
18
- /**
19
- * Consume a paginated query from a data service.
20
- *
21
- * @param options - The query options. Keep in mind that `staleTime` and `queryFn` are not supported
22
- * when querying data services.
23
- * @returns The paginated query results.
24
- */
25
- export declare function useInfiniteQuery<TQueryFnData = unknown, TError = DefaultError, TData = InfiniteData<TQueryFnData>, TQueryKey extends QueryKey = QueryKey, TPageParam = unknown>(options: OmitKeyof<UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>, 'staleTime' | 'queryFn'>): UseInfiniteQueryResult<TData, TError>;
26
- /**
27
- * Execute a mutation through a data service.
28
- *
29
- * @param options - The mutation options. Keep in mind that `mutationFn` is not supported
30
- * when executing mutations through data services.
31
- * @returns The result of the mutation.
32
- */
33
- export declare function useMutation<TData = unknown, TError = DefaultError, TVariables = void, TOnMutateResult = unknown, TMutationKey extends MutationKey = MutationKey>(options: OmitKeyof<UseMutationOptions<TData, TError, TVariables, TOnMutateResult>, 'mutationKey' | 'mutationFn'> & {
34
- mutationKey: TMutationKey;
35
- }): UseMutationResult<TData, TError, TVariables, TOnMutateResult>;
36
- //# sourceMappingURL=hooks.d.cts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hooks.d.cts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,oCAAoC;AACpE,OAAO,EAIL,SAAS,EACT,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,cAAc,EACd,sBAAsB,EACtB,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EAClB,8BAA8B;AAW/B;;;;;;GAMG;AACH,wBAAgB,QAAQ,CACtB,YAAY,GAAG,OAAO,EACtB,MAAM,GAAG,YAAY,EACrB,KAAK,GAAG,YAAY,EACpB,SAAS,SAAS,QAAQ,GAAG,QAAQ,EAErC,OAAO,EAAE,SAAS,CAChB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,EACvD,aAAa,GAAG,WAAW,GAAG,SAAS,CACxC,GAAG;IACF,WAAW,CAAC,EACR,SAAS,GACT,mBAAmB,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC,GACpD,iBAAiB,CAAC,YAAY,CAAC,CAAC;CACrC,GACA,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,CAE/B;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,GAAG,OAAO,EACtB,MAAM,GAAG,YAAY,EACrB,KAAK,GAAG,YAAY,CAAC,YAAY,CAAC,EAClC,SAAS,SAAS,QAAQ,GAAG,QAAQ,EACrC,UAAU,GAAG,OAAO,EAEpB,OAAO,EAAE,SAAS,CAChB,uBAAuB,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC,EAC3E,WAAW,GAAG,SAAS,CACxB,GACA,sBAAsB,CAAC,KAAK,EAAE,MAAM,CAAC,CAKvC;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,KAAK,GAAG,OAAO,EACf,MAAM,GAAG,YAAY,EACrB,UAAU,GAAG,IAAI,EACjB,eAAe,GAAG,OAAO,EACzB,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,OAAO,EAAE,SAAS,CAChB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,CAAC,EAC9D,aAAa,GAAG,YAAY,CAC7B,GAAG;IACF,WAAW,EAAE,YAAY,CAAC;CAC3B,GACA,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,CAAC,CAK/D"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"hooks.d.mts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,oCAAoC;AACpE,OAAO,EAIL,SAAS,EACT,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,cAAc,EACd,sBAAsB,EACtB,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EAClB,8BAA8B;AAW/B;;;;;;GAMG;AACH,wBAAgB,QAAQ,CACtB,YAAY,GAAG,OAAO,EACtB,MAAM,GAAG,YAAY,EACrB,KAAK,GAAG,YAAY,EACpB,SAAS,SAAS,QAAQ,GAAG,QAAQ,EAErC,OAAO,EAAE,SAAS,CAChB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,EACvD,aAAa,GAAG,WAAW,GAAG,SAAS,CACxC,GAAG;IACF,WAAW,CAAC,EACR,SAAS,GACT,mBAAmB,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC,GACpD,iBAAiB,CAAC,YAAY,CAAC,CAAC;CACrC,GACA,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,CAE/B;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,GAAG,OAAO,EACtB,MAAM,GAAG,YAAY,EACrB,KAAK,GAAG,YAAY,CAAC,YAAY,CAAC,EAClC,SAAS,SAAS,QAAQ,GAAG,QAAQ,EACrC,UAAU,GAAG,OAAO,EAEpB,OAAO,EAAE,SAAS,CAChB,uBAAuB,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC,EAC3E,WAAW,GAAG,SAAS,CACxB,GACA,sBAAsB,CAAC,KAAK,EAAE,MAAM,CAAC,CAKvC;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,KAAK,GAAG,OAAO,EACf,MAAM,GAAG,YAAY,EACrB,UAAU,GAAG,IAAI,EACjB,eAAe,GAAG,OAAO,EACzB,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,OAAO,EAAE,SAAS,CAChB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,CAAC,EAC9D,aAAa,GAAG,YAAY,CAC7B,GAAG;IACF,WAAW,EAAE,YAAY,CAAC;CAC3B,GACA,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,CAAC,CAK/D"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"hooks.mjs","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,QAAQ,IAAI,oBAAoB,EAChC,gBAAgB,IAAI,4BAA4B,EAChD,WAAW,IAAI,uBAAuB,EAYvC,8BAA8B;AAE/B,MAAM,2BAA2B,GAAG;IAClC,SAAS,EAAE,CAAC;IACZ,KAAK,EAAE,KAAK;CACb,CAAC;AAEF,MAAM,8BAA8B,GAAG;IACrC,KAAK,EAAE,KAAK;CACb,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAMtB,OAQC;IAED,OAAO,oBAAoB,CAAC,EAAE,GAAG,2BAA2B,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;AAC9E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAO9B,OAGC;IAED,OAAO,4BAA4B,CAAC;QAClC,GAAG,2BAA2B;QAC9B,GAAG,OAAO;KACX,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAOzB,OAKC;IAED,OAAO,uBAAuB,CAAC;QAC7B,GAAG,8BAA8B;QACjC,GAAG,OAAO;KACX,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * @file\n * We provide re-exports of the underlying TanStack Query hooks with narrower types,\n * removing `staleTime` and `queryFn` which aren't useful when using data services.\n */\n\nimport { QueryKey, MutationKey } from '@metamask/base-data-service';\nimport {\n useQuery as useQueryFromTanStack,\n useInfiniteQuery as useInfiniteQueryFromTanStack,\n useMutation as useMutationFromTanStack,\n OmitKeyof,\n UseQueryOptions,\n InitialDataFunction,\n NonUndefinedGuard,\n UseInfiniteQueryOptions,\n UseQueryResult,\n UseInfiniteQueryResult,\n DefaultError,\n InfiniteData,\n UseMutationOptions,\n UseMutationResult,\n} from '@tanstack/react-query';\n\nconst DATA_SERVICE_QUERY_DEFAULTS = {\n staleTime: 0,\n retry: false,\n};\n\nconst DATA_SERVICE_MUTATION_DEFAULTS = {\n retry: false,\n};\n\n/**\n * Consume a query from a data service.\n *\n * @param options - The query options. Keep in mind that `staleTime` and `queryFn` are not supported\n * when querying data services.\n * @returns The query results.\n */\nexport function useQuery<\n TQueryFnData = unknown,\n TError = DefaultError,\n TData = TQueryFnData,\n TQueryKey extends QueryKey = QueryKey,\n>(\n options: OmitKeyof<\n UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,\n 'initialData' | 'staleTime' | 'queryFn'\n > & {\n initialData?:\n | undefined\n | InitialDataFunction<NonUndefinedGuard<TQueryFnData>>\n | NonUndefinedGuard<TQueryFnData>;\n },\n): UseQueryResult<TData, TError> {\n return useQueryFromTanStack({ ...DATA_SERVICE_QUERY_DEFAULTS, ...options });\n}\n\n/**\n * Consume a paginated query from a data service.\n *\n * @param options - The query options. Keep in mind that `staleTime` and `queryFn` are not supported\n * when querying data services.\n * @returns The paginated query results.\n */\nexport function useInfiniteQuery<\n TQueryFnData = unknown,\n TError = DefaultError,\n TData = InfiniteData<TQueryFnData>,\n TQueryKey extends QueryKey = QueryKey,\n TPageParam = unknown,\n>(\n options: OmitKeyof<\n UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>,\n 'staleTime' | 'queryFn'\n >,\n): UseInfiniteQueryResult<TData, TError> {\n return useInfiniteQueryFromTanStack({\n ...DATA_SERVICE_QUERY_DEFAULTS,\n ...options,\n });\n}\n\n/**\n * Execute a mutation through a data service.\n *\n * @param options - The mutation options. Keep in mind that `mutationFn` is not supported\n * when executing mutations through data services.\n * @returns The result of the mutation.\n */\nexport function useMutation<\n TData = unknown,\n TError = DefaultError,\n TVariables = void,\n TOnMutateResult = unknown,\n TMutationKey extends MutationKey = MutationKey,\n>(\n options: OmitKeyof<\n UseMutationOptions<TData, TError, TVariables, TOnMutateResult>,\n 'mutationKey' | 'mutationFn'\n > & {\n mutationKey: TMutationKey;\n },\n): UseMutationResult<TData, TError, TVariables, TOnMutateResult> {\n return useMutationFromTanStack({\n ...DATA_SERVICE_MUTATION_DEFAULTS,\n ...options,\n });\n}\n"]}
@@ -1,100 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hydrateMutations = exports.readGlobalId = void 0;
4
- const query_core_1 = require("@tanstack/query-core");
5
- /**
6
- * Get the `globalId` of a mutation by reading its `meta` data.
7
- *
8
- * Each mutation that is routed from the UI query client to a data service is
9
- * assigned a `globalId` through the mutation's `meta` property. However, the
10
- * `meta` property is optional and untyped, so reading this property back
11
- * requires some validation.
12
- *
13
- * @param meta - The mutation `meta`, if any.
14
- * @returns The `globalId` if present and a string, otherwise undefined.
15
- */
16
- function readGlobalId(meta) {
17
- const globalId = meta?.globalId;
18
- return typeof globalId === 'string' ? globalId : undefined;
19
- }
20
- exports.readGlobalId = readGlobalId;
21
- /**
22
- * Load dehydrated mutations into the given query client.
23
- *
24
- * TanStack Query's `hydrate` function works well for queries: it ensures that
25
- * incoming queries remain deduplicated as it hydrates them (using the query key
26
- * hash as a filter). But mutations don't need to be deduplicated, and so
27
- * `hydrate` follows a different process, opting to load incoming mutations as
28
- * new entries each time it is called.
29
- *
30
- * This does not well for what we want to achieve, which is to be able to
31
- * synchronize queries and mutations between a data service query client service
32
- * and a UI query client. To accomplish this, we assume that mutations which
33
- * originated on the UI side have been tagged with a custom UUID (stored as
34
- * `globalId` in its `meta`). This allows us to keep mutations with the same
35
- * UUID on both sides and thus sychronize them effectively.
36
- *
37
- * @param client - The UI query client whose mutation cache should be hydrated.
38
- * @param dehydratedState - The dehydrated state emitted by a data service's
39
- * `:cacheUpdated` event.
40
- */
41
- function hydrateMutations(client, dehydratedState) {
42
- const mutationCache = client.getMutationCache();
43
- for (const dehydratedMutation of dehydratedState.mutations) {
44
- const { mutationKey, state, meta } = dehydratedMutation;
45
- const globalId = readGlobalId(meta);
46
- // Although TanStack Query does not require mutations to have mutation keys,
47
- // all mutations created through data services or the UI query client *must*
48
- // have one. They must also have a global ID.
49
- if (!mutationKey || !globalId) {
50
- continue;
51
- }
52
- const existingMutation = mutationCache.find({
53
- mutationKey,
54
- predicate: (mutation) => readGlobalId(mutation.meta) === globalId,
55
- });
56
- // A UI query client only subscribes to a mutation key's cache updates after
57
- // it has built a mutation for that key, so there is always a matching
58
- // mutation to update in place, and we can disregard the case in which there
59
- // is not.
60
- // istanbul ignore else
61
- if (existingMutation) {
62
- existingMutation.state = state;
63
- mutationCache.notify({
64
- type: 'updated',
65
- mutation: existingMutation,
66
- action: deriveMutationAction(state),
67
- });
68
- }
69
- }
70
- }
71
- exports.hydrateMutations = hydrateMutations;
72
- /**
73
- * When publishing an `update` event through the mutation cache we must supply
74
- * an action. This function derives an appropriate action from a dehydrated
75
- * mutation's state.
76
- *
77
- * @param state - The state of a dehydrated mutation.
78
- * @returns The mutation cache action describing the state.
79
- */
80
- function deriveMutationAction(state) {
81
- switch (state.status) {
82
- case 'success':
83
- return { type: 'success', data: state.data };
84
- case 'error':
85
- // A mutation in the `error` state always carries a non-null `error`.
86
- return { type: 'error', error: state.error };
87
- case 'pending':
88
- return {
89
- type: 'pending',
90
- variables: state.variables,
91
- context: state.context,
92
- isPaused: state.isPaused,
93
- };
94
- // The `idle` status carries no data, error, or variables, so a neutral
95
- // `continue` action refreshes subscribers without implying a result.
96
- default:
97
- return { type: 'continue' };
98
- }
99
- }
100
- //# sourceMappingURL=hydrateMutations.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hydrateMutations.cjs","sourceRoot":"","sources":["../src/hydrateMutations.ts"],"names":[],"mappings":";;;AAAA,qDAI8B;AAE9B;;;;;;;;;;GAUG;AACH,SAAgB,YAAY,CAC1B,IAAyC;IAEzC,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ,CAAC;IAChC,OAAO,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7D,CAAC;AALD,oCAKC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,SAAgB,gBAAgB,CAC9B,MAAmB,EACnB,eAAgC;IAEhC,MAAM,aAAa,GAAG,MAAM,CAAC,gBAAgB,EAAE,CAAC;IAEhD,KAAK,MAAM,kBAAkB,IAAI,eAAe,CAAC,SAAS,EAAE,CAAC;QAC3D,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,kBAAkB,CAAC;QAExD,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QAEpC,4EAA4E;QAC5E,4EAA4E;QAC5E,6CAA6C;QAC7C,IAAI,CAAC,WAAW,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC9B,SAAS;QACX,CAAC;QAED,MAAM,gBAAgB,GAAG,aAAa,CAAC,IAAI,CAAC;YAC1C,WAAW;YACX,SAAS,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,QAAQ;SAClE,CAAC,CAAC;QAEH,4EAA4E;QAC5E,sEAAsE;QACtE,4EAA4E;QAC5E,UAAU;QACV,uBAAuB;QACvB,IAAI,gBAAgB,EAAE,CAAC;YACrB,gBAAgB,CAAC,KAAK,GAAG,KAAK,CAAC;YAC/B,aAAa,CAAC,MAAM,CAAC;gBACnB,IAAI,EAAE,SAAS;gBACf,QAAQ,EAAE,gBAAgB;gBAC1B,MAAM,EAAE,oBAAoB,CAAC,KAAK,CAAC;aACpC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;AArCD,4CAqCC;AAED;;;;;;;GAOG;AACH,SAAS,oBAAoB,CAC3B,KAAoB;IAMpB,QAAQ,KAAK,CAAC,MAAM,EAAE,CAAC;QACrB,KAAK,SAAS;YACZ,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;QAC/C,KAAK,OAAO;YACV,qEAAqE;YACrE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;QAC/C,KAAK,SAAS;YACZ,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;aACzB,CAAC;QACJ,uEAAuE;QACvE,qEAAqE;QACrE;YACE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IAChC,CAAC;AACH,CAAC","sourcesContent":["import {\n QueryClient,\n DehydratedState,\n MutationState,\n} from '@tanstack/query-core';\n\n/**\n * Get the `globalId` of a mutation by reading its `meta` data.\n *\n * Each mutation that is routed from the UI query client to a data service is\n * assigned a `globalId` through the mutation's `meta` property. However, the\n * `meta` property is optional and untyped, so reading this property back\n * requires some validation.\n *\n * @param meta - The mutation `meta`, if any.\n * @returns The `globalId` if present and a string, otherwise undefined.\n */\nexport function readGlobalId(\n meta: Record<string, unknown> | undefined,\n): string | undefined {\n const globalId = meta?.globalId;\n return typeof globalId === 'string' ? globalId : undefined;\n}\n\n/**\n * Load dehydrated mutations into the given query client.\n *\n * TanStack Query's `hydrate` function works well for queries: it ensures that\n * incoming queries remain deduplicated as it hydrates them (using the query key\n * hash as a filter). But mutations don't need to be deduplicated, and so\n * `hydrate` follows a different process, opting to load incoming mutations as\n * new entries each time it is called.\n *\n * This does not well for what we want to achieve, which is to be able to\n * synchronize queries and mutations between a data service query client service\n * and a UI query client. To accomplish this, we assume that mutations which\n * originated on the UI side have been tagged with a custom UUID (stored as\n * `globalId` in its `meta`). This allows us to keep mutations with the same\n * UUID on both sides and thus sychronize them effectively.\n *\n * @param client - The UI query client whose mutation cache should be hydrated.\n * @param dehydratedState - The dehydrated state emitted by a data service's\n * `:cacheUpdated` event.\n */\nexport function hydrateMutations(\n client: QueryClient,\n dehydratedState: DehydratedState,\n): void {\n const mutationCache = client.getMutationCache();\n\n for (const dehydratedMutation of dehydratedState.mutations) {\n const { mutationKey, state, meta } = dehydratedMutation;\n\n const globalId = readGlobalId(meta);\n\n // Although TanStack Query does not require mutations to have mutation keys,\n // all mutations created through data services or the UI query client *must*\n // have one. They must also have a global ID.\n if (!mutationKey || !globalId) {\n continue;\n }\n\n const existingMutation = mutationCache.find({\n mutationKey,\n predicate: (mutation) => readGlobalId(mutation.meta) === globalId,\n });\n\n // A UI query client only subscribes to a mutation key's cache updates after\n // it has built a mutation for that key, so there is always a matching\n // mutation to update in place, and we can disregard the case in which there\n // is not.\n // istanbul ignore else\n if (existingMutation) {\n existingMutation.state = state;\n mutationCache.notify({\n type: 'updated',\n mutation: existingMutation,\n action: deriveMutationAction(state),\n });\n }\n }\n}\n\n/**\n * When publishing an `update` event through the mutation cache we must supply\n * an action. This function derives an appropriate action from a dehydrated\n * mutation's state.\n *\n * @param state - The state of a dehydrated mutation.\n * @returns The mutation cache action describing the state.\n */\nfunction deriveMutationAction(\n state: MutationState,\n):\n | { type: 'success'; data: unknown }\n | { type: 'error'; error: unknown }\n | { type: 'pending'; variables: unknown; context: unknown; isPaused: boolean }\n | { type: 'continue' } {\n switch (state.status) {\n case 'success':\n return { type: 'success', data: state.data };\n case 'error':\n // A mutation in the `error` state always carries a non-null `error`.\n return { type: 'error', error: state.error };\n case 'pending':\n return {\n type: 'pending',\n variables: state.variables,\n context: state.context,\n isPaused: state.isPaused,\n };\n // The `idle` status carries no data, error, or variables, so a neutral\n // `continue` action refreshes subscribers without implying a result.\n default:\n return { type: 'continue' };\n }\n}\n"]}