@metamask-previews/react-data-query 1.0.0-preview-8bfa290fb → 1.0.0-preview-24ff6e049

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 (40) hide show
  1. package/CHANGELOG.md +0 -12
  2. package/dist/createUIQueryClient.cjs +3 -90
  3. package/dist/createUIQueryClient.cjs.map +1 -1
  4. package/dist/createUIQueryClient.d.cts.map +1 -1
  5. package/dist/createUIQueryClient.d.mts.map +1 -1
  6. package/dist/createUIQueryClient.mjs +4 -91
  7. package/dist/createUIQueryClient.mjs.map +1 -1
  8. package/dist/hooks.cjs +3 -21
  9. package/dist/hooks.cjs.map +1 -1
  10. package/dist/hooks.d.cts +2 -17
  11. package/dist/hooks.d.cts.map +1 -1
  12. package/dist/hooks.d.mts +2 -17
  13. package/dist/hooks.d.mts.map +1 -1
  14. package/dist/hooks.mjs +3 -20
  15. package/dist/hooks.mjs.map +1 -1
  16. package/dist/index.cjs +1 -2
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +1 -1
  19. package/dist/index.d.cts.map +1 -1
  20. package/dist/index.d.mts +1 -1
  21. package/dist/index.d.mts.map +1 -1
  22. package/dist/index.mjs +1 -1
  23. package/dist/index.mjs.map +1 -1
  24. package/package.json +11 -8
  25. package/dist/hydrateMutations.cjs +0 -100
  26. package/dist/hydrateMutations.cjs.map +0 -1
  27. package/dist/hydrateMutations.d.cts +0 -35
  28. package/dist/hydrateMutations.d.cts.map +0 -1
  29. package/dist/hydrateMutations.d.mts +0 -35
  30. package/dist/hydrateMutations.d.mts.map +0 -1
  31. package/dist/hydrateMutations.mjs +0 -95
  32. package/dist/hydrateMutations.mjs.map +0 -1
  33. package/dist/loggers.cjs +0 -7
  34. package/dist/loggers.cjs.map +0 -1
  35. package/dist/loggers.d.cts +0 -5
  36. package/dist/loggers.d.cts.map +0 -1
  37. package/dist/loggers.d.mts +0 -5
  38. package/dist/loggers.d.mts.map +0 -1
  39. package/dist/loggers.mjs +0 -4
  40. package/dist/loggers.mjs.map +0 -1
package/CHANGELOG.md CHANGED
@@ -7,18 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ### Added
11
-
12
- - Add support for executing mutations by updating `createUIQueryClient` and adding `useMutation` wrapper ([#9324](https://github.com/MetaMask/core/pull/9324))
13
- - Provided an action in your data service uses `BaseDataService.executeMutation` to make the request instead of `fetchQuery`, you can now use `useMutation` in your UI files via the UI query client and pass a reference to the action as the mutation key.
14
- - Like `fetchQuery` and `fetchInfiniteQuery`, the `useMutation` wrapper disables retries by default and enforces that `mutationKey` matches the same thing that `executeMutation` takes.
15
- - `createUIQueryClient` now tags each mutation it creates with a unique `globalId` (stored on the mutation's `meta`) and passes it to the data service action as the trailing argument. It uses this `globalId` to update the exact UI mutation that a `:cacheUpdated` event corresponds to, so mutations sharing a `mutationKey` no longer clobber one another, and mutations that use a custom `mutationFn` are left untouched.
16
-
17
- ### Changed
18
-
19
- - Add `uuid` `^8.3.2` as a dependency ([#9324](https://github.com/MetaMask/core/pull/9324))
20
- - Bump `@metamask/utils` from `^11.11.0` to `^11.12.0` ([#10076](https://github.com/MetaMask/core/pull/10076))
21
-
22
10
  ## [1.0.0]
23
11
 
24
12
  ### Changed
@@ -3,10 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createUIQueryClient = void 0;
4
4
  const utils_1 = require("@metamask/utils");
5
5
  const query_core_1 = require("@tanstack/query-core");
6
- const uuid_1 = require("uuid");
7
- const hydrateMutations_js_1 = require("./hydrateMutations.cjs");
8
- const loggers_js_1 = require("./loggers.cjs");
9
- const log = (0, loggers_js_1.createModuleLogger)(loggers_js_1.projectLogger, 'createUIQueryClient');
10
6
  /**
11
7
  * Create a QueryClient that queries and subscribes to data services using a
12
8
  * messenger adapter. This is a messenger-like object that carries some
@@ -26,11 +22,6 @@ const log = (0, loggers_js_1.createModuleLogger)(loggers_js_1.projectLogger, 'cr
26
22
  */
27
23
  function createUIQueryClient(dataServices, messenger, config = {}) {
28
24
  const subscriptions = new Map();
29
- // Tracks how many mutation observers are currently relying on each mutation
30
- // key's cache subscription. Unlike queries, a `Mutation` does not expose its
31
- // observer count publicly, so we count observers ourselves and only tear down
32
- // the messenger subscription once the last observer for a key is removed.
33
- const mutationObserverCounts = new Map();
34
25
  /**
35
26
  * Check whether a name is one of the provided data service names.
36
27
  *
@@ -74,7 +65,7 @@ function createUIQueryClient(dataServices, messenger, config = {}) {
74
65
  queryFn: async (options) => {
75
66
  const { queryKey } = options;
76
67
  const action = queryKey[0];
77
- (0, utils_1.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', ...]`.");
68
+ (0, utils_1.assert)(typeof action === 'string' && isRecognizedDataServiceAction(action), "Queries must call actions on the messenger provided to createUIQueryClient, e.g. `queryKey: ['ExampleDataService:getAssets', ...]`.");
78
69
  const params = options.queryKey.slice(1);
79
70
  if (options.pageParam !== undefined) {
80
71
  params.push(options.pageParam);
@@ -85,8 +76,8 @@ function createUIQueryClient(dataServices, messenger, config = {}) {
85
76
  mutations: config.defaultOptions?.mutations,
86
77
  },
87
78
  });
88
- const queryCache = client.getQueryCache();
89
- queryCache.subscribe((event) => {
79
+ const cache = client.getQueryCache();
80
+ cache.subscribe((event) => {
90
81
  const { query } = event;
91
82
  const hash = query.queryHash;
92
83
  const hasSubscription = subscriptions.has(hash);
@@ -102,7 +93,6 @@ function createUIQueryClient(dataServices, messenger, config = {}) {
102
93
  if (payload.type === 'removed') {
103
94
  return;
104
95
  }
105
- log('Hydrating with', payload.state);
106
96
  (0, query_core_1.hydrate)(client, payload.state);
107
97
  };
108
98
  subscriptions.set(hash, cacheListener);
@@ -121,55 +111,6 @@ function createUIQueryClient(dataServices, messenger, config = {}) {
121
111
  subscriptions.delete(hash);
122
112
  }
123
113
  });
124
- const mutationCache = client.getMutationCache();
125
- mutationCache.subscribe((event) => {
126
- const { mutation } = event;
127
- if (!mutation?.options.mutationKey) {
128
- return;
129
- }
130
- const hash = (0, query_core_1.hashKey)(mutation.options.mutationKey);
131
- const hasSubscription = subscriptions.has(hash);
132
- const service = parseQueryKey(mutation.options.mutationKey);
133
- if (!service) {
134
- return;
135
- }
136
- log(`[mutationCache subscription] Received event "${event.type}". Details:`, event.mutation);
137
- if (event.type === 'observerAdded') {
138
- mutationObserverCounts.set(hash, (mutationObserverCounts.get(hash) ?? 0) + 1);
139
- log('[mutationCache subscription] hasSubscription =', hasSubscription);
140
- if (!hasSubscription) {
141
- const cacheListener = (payload) => {
142
- log(`[mutationCache subscription] cacheUpdated:${hash} emitted`, payload);
143
- if (payload.type === 'removed') {
144
- return;
145
- }
146
- (0, hydrateMutations_js_1.hydrateMutations)(client, payload.state);
147
- };
148
- subscriptions.set(hash, cacheListener);
149
- messenger.subscribe(`${service}:cacheUpdated:${hash}`, cacheListener);
150
- }
151
- }
152
- else if (event.type === 'observerRemoved' && hasSubscription) {
153
- // We can assume that if an observed mutation is removed, it must have
154
- // first been added; and that when it was added, the observer count was
155
- // initialized. (There's no real way to test the alternative, anyway.)
156
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
157
- const remainingObservers = mutationObserverCounts.get(hash) - 1;
158
- if (remainingObservers > 0) {
159
- mutationObserverCounts.set(hash, remainingObservers);
160
- return;
161
- }
162
- mutationObserverCounts.delete(hash);
163
- const subscriptionListener = subscriptions.get(hash);
164
- // A subscription always has a listener, since both are set together when
165
- // the first observer is added.
166
- // istanbul ignore next
167
- if (subscriptionListener) {
168
- messenger.unsubscribe(`${service}:cacheUpdated:${hash}`, subscriptionListener);
169
- }
170
- subscriptions.delete(hash);
171
- }
172
- });
173
114
  // Override invalidateQueries to ensure the data service is invalidated as well.
174
115
  const originalInvalidate = client.invalidateQueries.bind(client);
175
116
  client.invalidateQueries = async (filters, options) => {
@@ -185,34 +126,6 @@ function createUIQueryClient(dataServices, messenger, config = {}) {
185
126
  }));
186
127
  return originalInvalidate(filters, options);
187
128
  };
188
- // Override defaultMutationOptions to check for mutationKey if mutationFn is
189
- // not provided.
190
- const originalDefaultMutationOptions = client.defaultMutationOptions.bind(client);
191
- client.defaultMutationOptions = (options) => {
192
- const defaultedOptions = originalDefaultMutationOptions(options);
193
- // Only mutations that fall back to the data-service default `mutationFn`
194
- // need a `globalId` to correlate the UI and service caches. A mutation with
195
- // a custom `mutationFn` never reaches a data service, so we leave it alone.
196
- if (defaultedOptions.mutationFn === undefined) {
197
- // Generate the `globalId` once and memoize it on `meta` so it stays
198
- // stable across the mutation's lifetime and can be matched against
199
- // incoming cache updates.
200
- const globalId = (0, hydrateMutations_js_1.readGlobalId)(defaultedOptions.meta) ?? (0, uuid_1.v4)();
201
- defaultedOptions.meta = { ...defaultedOptions.meta, globalId };
202
- defaultedOptions.mutationFn = async () => {
203
- const { mutationKey } = defaultedOptions;
204
- (0, utils_1.assert)(mutationKey !== undefined, "You must pass a `mutationKey` that calls an action on the messenger provided to `createUIQueryClient`, e.g. `mutationKey: ['ExampleDataService:createOrder', ...]`.");
205
- const [action, ...params] = mutationKey;
206
- (0, utils_1.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', ...]`.");
207
- log(`Detected mutation request, calling action: "${action}"`);
208
- // The `globalId` is passed as the trailing action argument. Each data
209
- // service mutation method forwards it into `executeMutation`, which
210
- // echoes it back on the service-side mutation's `meta`.
211
- return await messenger.call(action, ...params, globalId);
212
- };
213
- }
214
- return defaultedOptions;
215
- };
216
129
  return client;
217
130
  }
218
131
  exports.createUIQueryClient = createUIQueryClient;
@@ -1 +1 @@
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
+ {"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 { assert } from '@metamask/utils';\nimport {\n hydrate,\n QueryClient,\n InvalidateQueryFilters,\n InvalidateOptions,\n QueryKey,\n QueryClientConfig,\n} from '@tanstack/query-core';\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 /**\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 \"Queries must call actions 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 cache = client.getQueryCache();\n\n cache.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 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 // 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 return client;\n}\n"]}
@@ -1 +1 @@
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
+ {"version":3,"file":"createUIQueryClient.d.cts","sourceRoot":"","sources":["../src/createUIQueryClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oCAAoC,EACpC,sCAAsC,EACvC,oCAAoC;AAErC,OAAO,EAEL,WAAW,EAIX,iBAAiB,EAClB,6BAA6B;AAE9B;;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,CA8Jb"}
@@ -1 +1 @@
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
+ {"version":3,"file":"createUIQueryClient.d.mts","sourceRoot":"","sources":["../src/createUIQueryClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oCAAoC,EACpC,sCAAsC,EACvC,oCAAoC;AAErC,OAAO,EAEL,WAAW,EAIX,iBAAiB,EAClB,6BAA6B;AAE9B;;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,CA8Jb"}
@@ -1,9 +1,5 @@
1
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');
2
+ import { hydrate, QueryClient } from "@tanstack/query-core";
7
3
  /**
8
4
  * Create a QueryClient that queries and subscribes to data services using a
9
5
  * messenger adapter. This is a messenger-like object that carries some
@@ -23,11 +19,6 @@ const log = createModuleLogger(projectLogger, 'createUIQueryClient');
23
19
  */
24
20
  export function createUIQueryClient(dataServices, messenger, config = {}) {
25
21
  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
22
  /**
32
23
  * Check whether a name is one of the provided data service names.
33
24
  *
@@ -71,7 +62,7 @@ export function createUIQueryClient(dataServices, messenger, config = {}) {
71
62
  queryFn: async (options) => {
72
63
  const { queryKey } = options;
73
64
  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', ...]`.");
65
+ assert(typeof action === 'string' && isRecognizedDataServiceAction(action), "Queries must call actions on the messenger provided to createUIQueryClient, e.g. `queryKey: ['ExampleDataService:getAssets', ...]`.");
75
66
  const params = options.queryKey.slice(1);
76
67
  if (options.pageParam !== undefined) {
77
68
  params.push(options.pageParam);
@@ -82,8 +73,8 @@ export function createUIQueryClient(dataServices, messenger, config = {}) {
82
73
  mutations: config.defaultOptions?.mutations,
83
74
  },
84
75
  });
85
- const queryCache = client.getQueryCache();
86
- queryCache.subscribe((event) => {
76
+ const cache = client.getQueryCache();
77
+ cache.subscribe((event) => {
87
78
  const { query } = event;
88
79
  const hash = query.queryHash;
89
80
  const hasSubscription = subscriptions.has(hash);
@@ -99,7 +90,6 @@ export function createUIQueryClient(dataServices, messenger, config = {}) {
99
90
  if (payload.type === 'removed') {
100
91
  return;
101
92
  }
102
- log('Hydrating with', payload.state);
103
93
  hydrate(client, payload.state);
104
94
  };
105
95
  subscriptions.set(hash, cacheListener);
@@ -118,55 +108,6 @@ export function createUIQueryClient(dataServices, messenger, config = {}) {
118
108
  subscriptions.delete(hash);
119
109
  }
120
110
  });
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
111
  // Override invalidateQueries to ensure the data service is invalidated as well.
171
112
  const originalInvalidate = client.invalidateQueries.bind(client);
172
113
  client.invalidateQueries = async (filters, options) => {
@@ -182,34 +123,6 @@ export function createUIQueryClient(dataServices, messenger, config = {}) {
182
123
  }));
183
124
  return originalInvalidate(filters, options);
184
125
  };
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
126
  return client;
214
127
  }
215
128
  //# sourceMappingURL=createUIQueryClient.mjs.map
@@ -1 +1 @@
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"]}
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 { assert } from '@metamask/utils';\nimport {\n hydrate,\n QueryClient,\n InvalidateQueryFilters,\n InvalidateOptions,\n QueryKey,\n QueryClientConfig,\n} from '@tanstack/query-core';\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 /**\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 \"Queries must call actions 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 cache = client.getQueryCache();\n\n cache.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 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 // 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 return client;\n}\n"]}
package/dist/hooks.cjs CHANGED
@@ -1,19 +1,15 @@
1
1
  "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useInfiniteQuery = exports.useQuery = void 0;
4
+ const react_query_1 = require("@tanstack/react-query");
2
5
  /**
3
- * @file
4
6
  * We provide re-exports of the underlying TanStack Query hooks with narrower types,
5
7
  * removing `staleTime` and `queryFn` which aren't useful when using data services.
6
8
  */
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
9
  const DATA_SERVICE_QUERY_DEFAULTS = {
11
10
  staleTime: 0,
12
11
  retry: false,
13
12
  };
14
- const DATA_SERVICE_MUTATION_DEFAULTS = {
15
- retry: false,
16
- };
17
13
  /**
18
14
  * Consume a query from a data service.
19
15
  *
@@ -39,18 +35,4 @@ function useInfiniteQuery(options) {
39
35
  });
40
36
  }
41
37
  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
38
  //# sourceMappingURL=hooks.cjs.map
@@ -1 +1 @@
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"]}
1
+ {"version":3,"file":"hooks.cjs","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":";;;AACA,uDAY+B;AAE/B;;;GAGG;AAEH,MAAM,2BAA2B,GAAG;IAClC,SAAS,EAAE,CAAC;IACZ,KAAK,EAAE,KAAK;CACb,CAAC;AAEF;;;;;;GAMG;AACH,SAAgB,QAAQ,CAMtB,OAQC;IAED,OAAO,IAAA,sBAAgB,EAAC,EAAE,GAAG,2BAA2B,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;AAC1E,CAAC;AAjBD,4BAiBC;AAED;;;;;;GAMG;AACH,SAAgB,gBAAgB,CAO9B,OAGC;IAED,OAAO,IAAA,8BAAwB,EAAC;QAC9B,GAAG,2BAA2B;QAC9B,GAAG,OAAO;KACX,CAAC,CAAC;AACL,CAAC;AAhBD,4CAgBC","sourcesContent":["import { QueryKey } from '@metamask/base-data-service';\nimport {\n useQuery as useQueryTanStack,\n useInfiniteQuery as useInfiniteQueryTanStack,\n OmitKeyof,\n UseQueryOptions,\n InitialDataFunction,\n NonUndefinedGuard,\n UseInfiniteQueryOptions,\n UseQueryResult,\n UseInfiniteQueryResult,\n DefaultError,\n InfiniteData,\n} from '@tanstack/react-query';\n\n/**\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\nconst DATA_SERVICE_QUERY_DEFAULTS = {\n staleTime: 0,\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 useQueryTanStack({ ...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 useInfiniteQueryTanStack({\n ...DATA_SERVICE_QUERY_DEFAULTS,\n ...options,\n });\n}\n"]}
package/dist/hooks.d.cts CHANGED
@@ -1,10 +1,5 @@
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";
1
+ import { QueryKey } from "@metamask/base-data-service";
2
+ import { OmitKeyof, UseQueryOptions, InitialDataFunction, NonUndefinedGuard, UseInfiniteQueryOptions, UseQueryResult, UseInfiniteQueryResult, DefaultError, InfiniteData } from "@tanstack/react-query";
8
3
  /**
9
4
  * Consume a query from a data service.
10
5
  *
@@ -23,14 +18,4 @@ export declare function useQuery<TQueryFnData = unknown, TError = DefaultError,
23
18
  * @returns The paginated query results.
24
19
  */
25
20
  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
21
  //# sourceMappingURL=hooks.d.cts.map
@@ -1 +1 @@
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
+ {"version":3,"file":"hooks.d.cts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,oCAAoC;AACvD,OAAO,EAGL,SAAS,EACT,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,cAAc,EACd,sBAAsB,EACtB,YAAY,EACZ,YAAY,EACb,8BAA8B;AAY/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"}
package/dist/hooks.d.mts CHANGED
@@ -1,10 +1,5 @@
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";
1
+ import { QueryKey } from "@metamask/base-data-service";
2
+ import { OmitKeyof, UseQueryOptions, InitialDataFunction, NonUndefinedGuard, UseInfiniteQueryOptions, UseQueryResult, UseInfiniteQueryResult, DefaultError, InfiniteData } from "@tanstack/react-query";
8
3
  /**
9
4
  * Consume a query from a data service.
10
5
  *
@@ -23,14 +18,4 @@ export declare function useQuery<TQueryFnData = unknown, TError = DefaultError,
23
18
  * @returns The paginated query results.
24
19
  */
25
20
  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
21
  //# sourceMappingURL=hooks.d.mts.map
@@ -1 +1 @@
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
+ {"version":3,"file":"hooks.d.mts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,oCAAoC;AACvD,OAAO,EAGL,SAAS,EACT,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,cAAc,EACd,sBAAsB,EACtB,YAAY,EACZ,YAAY,EACb,8BAA8B;AAY/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"}
package/dist/hooks.mjs CHANGED
@@ -1,16 +1,12 @@
1
+ import { useQuery as useQueryTanStack, useInfiniteQuery as useInfiniteQueryTanStack } from "@tanstack/react-query";
1
2
  /**
2
- * @file
3
3
  * We provide re-exports of the underlying TanStack Query hooks with narrower types,
4
4
  * removing `staleTime` and `queryFn` which aren't useful when using data services.
5
5
  */
6
- import { useQuery as useQueryFromTanStack, useInfiniteQuery as useInfiniteQueryFromTanStack, useMutation as useMutationFromTanStack } from "@tanstack/react-query";
7
6
  const DATA_SERVICE_QUERY_DEFAULTS = {
8
7
  staleTime: 0,
9
8
  retry: false,
10
9
  };
11
- const DATA_SERVICE_MUTATION_DEFAULTS = {
12
- retry: false,
13
- };
14
10
  /**
15
11
  * Consume a query from a data service.
16
12
  *
@@ -19,7 +15,7 @@ const DATA_SERVICE_MUTATION_DEFAULTS = {
19
15
  * @returns The query results.
20
16
  */
21
17
  export function useQuery(options) {
22
- return useQueryFromTanStack({ ...DATA_SERVICE_QUERY_DEFAULTS, ...options });
18
+ return useQueryTanStack({ ...DATA_SERVICE_QUERY_DEFAULTS, ...options });
23
19
  }
24
20
  /**
25
21
  * Consume a paginated query from a data service.
@@ -29,22 +25,9 @@ export function useQuery(options) {
29
25
  * @returns The paginated query results.
30
26
  */
31
27
  export function useInfiniteQuery(options) {
32
- return useInfiniteQueryFromTanStack({
28
+ return useInfiniteQueryTanStack({
33
29
  ...DATA_SERVICE_QUERY_DEFAULTS,
34
30
  ...options,
35
31
  });
36
32
  }
37
- /**
38
- * Execute a mutation through a data service.
39
- *
40
- * @param options - The mutation options. Keep in mind that `mutationFn` is not supported
41
- * when executing mutations through data services.
42
- * @returns The result of the mutation.
43
- */
44
- export function useMutation(options) {
45
- return useMutationFromTanStack({
46
- ...DATA_SERVICE_MUTATION_DEFAULTS,
47
- ...options,
48
- });
49
- }
50
33
  //# sourceMappingURL=hooks.mjs.map
@@ -1 +1 @@
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
+ {"version":3,"file":"hooks.mjs","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AACA,OAAO,EACL,QAAQ,IAAI,gBAAgB,EAC5B,gBAAgB,IAAI,wBAAwB,EAU7C,8BAA8B;AAE/B;;;GAGG;AAEH,MAAM,2BAA2B,GAAG;IAClC,SAAS,EAAE,CAAC;IACZ,KAAK,EAAE,KAAK;CACb,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAMtB,OAQC;IAED,OAAO,gBAAgB,CAAC,EAAE,GAAG,2BAA2B,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAO9B,OAGC;IAED,OAAO,wBAAwB,CAAC;QAC9B,GAAG,2BAA2B;QAC9B,GAAG,OAAO;KACX,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { QueryKey } from '@metamask/base-data-service';\nimport {\n useQuery as useQueryTanStack,\n useInfiniteQuery as useInfiniteQueryTanStack,\n OmitKeyof,\n UseQueryOptions,\n InitialDataFunction,\n NonUndefinedGuard,\n UseInfiniteQueryOptions,\n UseQueryResult,\n UseInfiniteQueryResult,\n DefaultError,\n InfiniteData,\n} from '@tanstack/react-query';\n\n/**\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\nconst DATA_SERVICE_QUERY_DEFAULTS = {\n staleTime: 0,\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 useQueryTanStack({ ...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 useInfiniteQueryTanStack({\n ...DATA_SERVICE_QUERY_DEFAULTS,\n ...options,\n });\n}\n"]}
package/dist/index.cjs CHANGED
@@ -1,10 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useMutation = exports.useInfiniteQuery = exports.useQuery = exports.createUIQueryClient = void 0;
3
+ exports.useInfiniteQuery = exports.useQuery = exports.createUIQueryClient = void 0;
4
4
  var createUIQueryClient_js_1 = require("./createUIQueryClient.cjs");
5
5
  Object.defineProperty(exports, "createUIQueryClient", { enumerable: true, get: function () { return createUIQueryClient_js_1.createUIQueryClient; } });
6
6
  var hooks_js_1 = require("./hooks.cjs");
7
7
  Object.defineProperty(exports, "useQuery", { enumerable: true, get: function () { return hooks_js_1.useQuery; } });
8
8
  Object.defineProperty(exports, "useInfiniteQuery", { enumerable: true, get: function () { return hooks_js_1.useInfiniteQuery; } });
9
- Object.defineProperty(exports, "useMutation", { enumerable: true, get: function () { return hooks_js_1.useMutation; } });
10
9
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,oEAA+D;AAAtD,6HAAA,mBAAmB,OAAA;AAC5B,wCAAqE;AAA5D,oGAAA,QAAQ,OAAA;AAAE,4GAAA,gBAAgB,OAAA;AAAE,uGAAA,WAAW,OAAA","sourcesContent":["export { createUIQueryClient } from './createUIQueryClient.js';\nexport { useQuery, useInfiniteQuery, useMutation } from './hooks.js';\n"]}
1
+ {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,oEAA+D;AAAtD,6HAAA,mBAAmB,OAAA;AAC5B,wCAAwD;AAA/C,oGAAA,QAAQ,OAAA;AAAE,4GAAA,gBAAgB,OAAA","sourcesContent":["export { createUIQueryClient } from './createUIQueryClient.js';\nexport { useQuery, useInfiniteQuery } from './hooks.js';\n"]}
package/dist/index.d.cts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { createUIQueryClient } from "./createUIQueryClient.cjs";
2
- export { useQuery, useInfiniteQuery, useMutation } from "./hooks.cjs";
2
+ export { useQuery, useInfiniteQuery } from "./hooks.cjs";
3
3
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,kCAAiC;AAC/D,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,oBAAmB"}
1
+ {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,kCAAiC;AAC/D,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,oBAAmB"}
package/dist/index.d.mts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { createUIQueryClient } from "./createUIQueryClient.mjs";
2
- export { useQuery, useInfiniteQuery, useMutation } from "./hooks.mjs";
2
+ export { useQuery, useInfiniteQuery } from "./hooks.mjs";
3
3
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,kCAAiC;AAC/D,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,oBAAmB"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,kCAAiC;AAC/D,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,oBAAmB"}
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  export { createUIQueryClient } from "./createUIQueryClient.mjs";
2
- export { useQuery, useInfiniteQuery, useMutation } from "./hooks.mjs";
2
+ export { useQuery, useInfiniteQuery } from "./hooks.mjs";
3
3
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,kCAAiC;AAC/D,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,oBAAmB","sourcesContent":["export { createUIQueryClient } from './createUIQueryClient.js';\nexport { useQuery, useInfiniteQuery, useMutation } from './hooks.js';\n"]}
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,kCAAiC;AAC/D,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,oBAAmB","sourcesContent":["export { createUIQueryClient } from './createUIQueryClient.js';\nexport { useQuery, useInfiniteQuery } from './hooks.js';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/react-data-query",
3
- "version": "1.0.0-preview-8bfa290fb",
3
+ "version": "1.0.0-preview-24ff6e049",
4
4
  "description": "Provides React utilities for consuming data services",
5
5
  "keywords": [
6
6
  "Ethereum",
@@ -47,17 +47,20 @@
47
47
  "lint:tsconfigs": "tsx ../../scripts/lint-tsconfigs/lint-tsconfigs.mts",
48
48
  "lint:tsconfigs:fix": "tsx ../../scripts/lint-tsconfigs/lint-tsconfigs.mts --fix",
49
49
  "since-latest-release": "../../scripts/since-latest-release.sh",
50
- "test": "NODE_OPTIONS=--experimental-vm-modules jest --reporters=jest-silent-reporter",
51
- "test:clean": "NODE_OPTIONS=--experimental-vm-modules jest --clearCache",
52
- "test:verbose": "NODE_OPTIONS=--experimental-vm-modules jest --verbose",
50
+ "test": "yarn test:unit && yarn test:types",
51
+ "test:clean": "yarn test:unit:clean && yarn test:types",
52
+ "test:types": "tstyche",
53
+ "test:unit": "NODE_OPTIONS=--experimental-vm-modules jest --reporters=jest-silent-reporter",
54
+ "test:unit:clean": "NODE_OPTIONS=--experimental-vm-modules jest --clearCache",
55
+ "test:unit:verbose": "NODE_OPTIONS=--experimental-vm-modules jest --verbose",
56
+ "test:verbose": "yarn test:unit:verbose && yarn test:types",
53
57
  "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch"
54
58
  },
55
59
  "dependencies": {
56
60
  "@metamask/base-data-service": "^1.0.0",
57
- "@metamask/utils": "^11.12.0",
61
+ "@metamask/utils": "^11.11.0",
58
62
  "@tanstack/query-core": "^5.62.16",
59
- "@tanstack/react-query": "^5.62.16",
60
- "uuid": "^8.3.2"
63
+ "@tanstack/react-query": "^5.62.16"
61
64
  },
62
65
  "devDependencies": {
63
66
  "@metamask/auto-changelog": "^6.1.0",
@@ -66,8 +69,8 @@
66
69
  "@types/jest": "^30.0.0",
67
70
  "deepmerge": "^4.2.2",
68
71
  "jest": "^30.4.2",
69
- "nock": "^13.3.1",
70
72
  "ts-jest": "^29.4.11",
73
+ "tstyche": "^5.0.2",
71
74
  "tsx": "^4.20.5",
72
75
  "typedoc": "^0.25.13",
73
76
  "typedoc-plugin-missing-exports": "^2.0.0",
@@ -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"]}
@@ -1,35 +0,0 @@
1
- import { QueryClient, DehydratedState } from "@tanstack/query-core";
2
- /**
3
- * Get the `globalId` of a mutation by reading its `meta` data.
4
- *
5
- * Each mutation that is routed from the UI query client to a data service is
6
- * assigned a `globalId` through the mutation's `meta` property. However, the
7
- * `meta` property is optional and untyped, so reading this property back
8
- * requires some validation.
9
- *
10
- * @param meta - The mutation `meta`, if any.
11
- * @returns The `globalId` if present and a string, otherwise undefined.
12
- */
13
- export declare function readGlobalId(meta: Record<string, unknown> | undefined): string | undefined;
14
- /**
15
- * Load dehydrated mutations into the given query client.
16
- *
17
- * TanStack Query's `hydrate` function works well for queries: it ensures that
18
- * incoming queries remain deduplicated as it hydrates them (using the query key
19
- * hash as a filter). But mutations don't need to be deduplicated, and so
20
- * `hydrate` follows a different process, opting to load incoming mutations as
21
- * new entries each time it is called.
22
- *
23
- * This does not well for what we want to achieve, which is to be able to
24
- * synchronize queries and mutations between a data service query client service
25
- * and a UI query client. To accomplish this, we assume that mutations which
26
- * originated on the UI side have been tagged with a custom UUID (stored as
27
- * `globalId` in its `meta`). This allows us to keep mutations with the same
28
- * UUID on both sides and thus sychronize them effectively.
29
- *
30
- * @param client - The UI query client whose mutation cache should be hydrated.
31
- * @param dehydratedState - The dehydrated state emitted by a data service's
32
- * `:cacheUpdated` event.
33
- */
34
- export declare function hydrateMutations(client: QueryClient, dehydratedState: DehydratedState): void;
35
- //# sourceMappingURL=hydrateMutations.d.cts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hydrateMutations.d.cts","sourceRoot":"","sources":["../src/hydrateMutations.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,eAAe,EAEhB,6BAA6B;AAE9B;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GACxC,MAAM,GAAG,SAAS,CAGpB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,WAAW,EACnB,eAAe,EAAE,eAAe,GAC/B,IAAI,CAkCN"}
@@ -1,35 +0,0 @@
1
- import { QueryClient, DehydratedState } from "@tanstack/query-core";
2
- /**
3
- * Get the `globalId` of a mutation by reading its `meta` data.
4
- *
5
- * Each mutation that is routed from the UI query client to a data service is
6
- * assigned a `globalId` through the mutation's `meta` property. However, the
7
- * `meta` property is optional and untyped, so reading this property back
8
- * requires some validation.
9
- *
10
- * @param meta - The mutation `meta`, if any.
11
- * @returns The `globalId` if present and a string, otherwise undefined.
12
- */
13
- export declare function readGlobalId(meta: Record<string, unknown> | undefined): string | undefined;
14
- /**
15
- * Load dehydrated mutations into the given query client.
16
- *
17
- * TanStack Query's `hydrate` function works well for queries: it ensures that
18
- * incoming queries remain deduplicated as it hydrates them (using the query key
19
- * hash as a filter). But mutations don't need to be deduplicated, and so
20
- * `hydrate` follows a different process, opting to load incoming mutations as
21
- * new entries each time it is called.
22
- *
23
- * This does not well for what we want to achieve, which is to be able to
24
- * synchronize queries and mutations between a data service query client service
25
- * and a UI query client. To accomplish this, we assume that mutations which
26
- * originated on the UI side have been tagged with a custom UUID (stored as
27
- * `globalId` in its `meta`). This allows us to keep mutations with the same
28
- * UUID on both sides and thus sychronize them effectively.
29
- *
30
- * @param client - The UI query client whose mutation cache should be hydrated.
31
- * @param dehydratedState - The dehydrated state emitted by a data service's
32
- * `:cacheUpdated` event.
33
- */
34
- export declare function hydrateMutations(client: QueryClient, dehydratedState: DehydratedState): void;
35
- //# sourceMappingURL=hydrateMutations.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hydrateMutations.d.mts","sourceRoot":"","sources":["../src/hydrateMutations.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,eAAe,EAEhB,6BAA6B;AAE9B;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GACxC,MAAM,GAAG,SAAS,CAGpB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,WAAW,EACnB,eAAe,EAAE,eAAe,GAC/B,IAAI,CAkCN"}
@@ -1,95 +0,0 @@
1
- import { QueryClient } from "@tanstack/query-core";
2
- /**
3
- * Get the `globalId` of a mutation by reading its `meta` data.
4
- *
5
- * Each mutation that is routed from the UI query client to a data service is
6
- * assigned a `globalId` through the mutation's `meta` property. However, the
7
- * `meta` property is optional and untyped, so reading this property back
8
- * requires some validation.
9
- *
10
- * @param meta - The mutation `meta`, if any.
11
- * @returns The `globalId` if present and a string, otherwise undefined.
12
- */
13
- export function readGlobalId(meta) {
14
- const globalId = meta?.globalId;
15
- return typeof globalId === 'string' ? globalId : undefined;
16
- }
17
- /**
18
- * Load dehydrated mutations into the given query client.
19
- *
20
- * TanStack Query's `hydrate` function works well for queries: it ensures that
21
- * incoming queries remain deduplicated as it hydrates them (using the query key
22
- * hash as a filter). But mutations don't need to be deduplicated, and so
23
- * `hydrate` follows a different process, opting to load incoming mutations as
24
- * new entries each time it is called.
25
- *
26
- * This does not well for what we want to achieve, which is to be able to
27
- * synchronize queries and mutations between a data service query client service
28
- * and a UI query client. To accomplish this, we assume that mutations which
29
- * originated on the UI side have been tagged with a custom UUID (stored as
30
- * `globalId` in its `meta`). This allows us to keep mutations with the same
31
- * UUID on both sides and thus sychronize them effectively.
32
- *
33
- * @param client - The UI query client whose mutation cache should be hydrated.
34
- * @param dehydratedState - The dehydrated state emitted by a data service's
35
- * `:cacheUpdated` event.
36
- */
37
- export function hydrateMutations(client, dehydratedState) {
38
- const mutationCache = client.getMutationCache();
39
- for (const dehydratedMutation of dehydratedState.mutations) {
40
- const { mutationKey, state, meta } = dehydratedMutation;
41
- const globalId = readGlobalId(meta);
42
- // Although TanStack Query does not require mutations to have mutation keys,
43
- // all mutations created through data services or the UI query client *must*
44
- // have one. They must also have a global ID.
45
- if (!mutationKey || !globalId) {
46
- continue;
47
- }
48
- const existingMutation = mutationCache.find({
49
- mutationKey,
50
- predicate: (mutation) => readGlobalId(mutation.meta) === globalId,
51
- });
52
- // A UI query client only subscribes to a mutation key's cache updates after
53
- // it has built a mutation for that key, so there is always a matching
54
- // mutation to update in place, and we can disregard the case in which there
55
- // is not.
56
- // istanbul ignore else
57
- if (existingMutation) {
58
- existingMutation.state = state;
59
- mutationCache.notify({
60
- type: 'updated',
61
- mutation: existingMutation,
62
- action: deriveMutationAction(state),
63
- });
64
- }
65
- }
66
- }
67
- /**
68
- * When publishing an `update` event through the mutation cache we must supply
69
- * an action. This function derives an appropriate action from a dehydrated
70
- * mutation's state.
71
- *
72
- * @param state - The state of a dehydrated mutation.
73
- * @returns The mutation cache action describing the state.
74
- */
75
- function deriveMutationAction(state) {
76
- switch (state.status) {
77
- case 'success':
78
- return { type: 'success', data: state.data };
79
- case 'error':
80
- // A mutation in the `error` state always carries a non-null `error`.
81
- return { type: 'error', error: state.error };
82
- case 'pending':
83
- return {
84
- type: 'pending',
85
- variables: state.variables,
86
- context: state.context,
87
- isPaused: state.isPaused,
88
- };
89
- // The `idle` status carries no data, error, or variables, so a neutral
90
- // `continue` action refreshes subscribers without implying a result.
91
- default:
92
- return { type: 'continue' };
93
- }
94
- }
95
- //# sourceMappingURL=hydrateMutations.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hydrateMutations.mjs","sourceRoot":"","sources":["../src/hydrateMutations.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EAGZ,6BAA6B;AAE9B;;;;;;;;;;GAUG;AACH,MAAM,UAAU,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;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,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;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"]}
package/dist/loggers.cjs DELETED
@@ -1,7 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createModuleLogger = exports.projectLogger = void 0;
4
- const utils_1 = require("@metamask/utils");
5
- Object.defineProperty(exports, "createModuleLogger", { enumerable: true, get: function () { return utils_1.createModuleLogger; } });
6
- exports.projectLogger = (0, utils_1.createProjectLogger)('react-data-query');
7
- //# sourceMappingURL=loggers.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"loggers.cjs","sourceRoot":"","sources":["../src/loggers.ts"],"names":[],"mappings":";;;AAAA,2CAA0E;AAIjE,mGAJqB,0BAAkB,OAIrB;AAFd,QAAA,aAAa,GAAG,IAAA,2BAAmB,EAAC,kBAAkB,CAAC,CAAC","sourcesContent":["import { createProjectLogger, createModuleLogger } from '@metamask/utils';\n\nexport const projectLogger = createProjectLogger('react-data-query');\n\nexport { createModuleLogger };\n"]}
@@ -1,5 +0,0 @@
1
- /// <reference types="debug" />
2
- import { createModuleLogger } from "@metamask/utils";
3
- export declare const projectLogger: import("debug").Debugger;
4
- export { createModuleLogger };
5
- //# sourceMappingURL=loggers.d.cts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"loggers.d.cts","sourceRoot":"","sources":["../src/loggers.ts"],"names":[],"mappings":";AAAA,OAAO,EAAuB,kBAAkB,EAAE,wBAAwB;AAE1E,eAAO,MAAM,aAAa,0BAA0C,CAAC;AAErE,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -1,5 +0,0 @@
1
- /// <reference types="debug" />
2
- import { createModuleLogger } from "@metamask/utils";
3
- export declare const projectLogger: import("debug").Debugger;
4
- export { createModuleLogger };
5
- //# sourceMappingURL=loggers.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"loggers.d.mts","sourceRoot":"","sources":["../src/loggers.ts"],"names":[],"mappings":";AAAA,OAAO,EAAuB,kBAAkB,EAAE,wBAAwB;AAE1E,eAAO,MAAM,aAAa,0BAA0C,CAAC;AAErE,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
package/dist/loggers.mjs DELETED
@@ -1,4 +0,0 @@
1
- import { createProjectLogger, createModuleLogger } from "@metamask/utils";
2
- export const projectLogger = createProjectLogger('react-data-query');
3
- export { createModuleLogger };
4
- //# sourceMappingURL=loggers.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"loggers.mjs","sourceRoot":"","sources":["../src/loggers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,wBAAwB;AAE1E,MAAM,CAAC,MAAM,aAAa,GAAG,mBAAmB,CAAC,kBAAkB,CAAC,CAAC;AAErE,OAAO,EAAE,kBAAkB,EAAE,CAAC","sourcesContent":["import { createProjectLogger, createModuleLogger } from '@metamask/utils';\n\nexport const projectLogger = createProjectLogger('react-data-query');\n\nexport { createModuleLogger };\n"]}