diff --git a/packages/base-data-service/CHANGELOG.md b/packages/base-data-service/CHANGELOG.md index 87aa5230ac5..65c473ee126 100644 --- a/packages/base-data-service/CHANGELOG.md +++ b/packages/base-data-service/CHANGELOG.md @@ -38,6 +38,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **BREAKING:** Remove `TPageData` type parameter from `invalidateQueries` method ([#9526](https://github.com/MetaMask/core/pull/9526)) - This is technically a breaking change, but this was not used in any of our codebases +- **BREAKING:** Bump `@tanstack/query-core` from `^4.43.0` to `^5.62.16` ([#9712](https://github.com/MetaMask/core/pull/9712)) + - The option types accepted by `fetchQuery`, `fetchInfiniteQuery`, and `invalidateQueries` now follow the query-core v5 API. Subclasses may need to rename `cacheTime` to `gcTime`, and infinite queries no longer accept an explicit page param through the `fetchMore` meta. - Bump `@metamask/utils` from `^11.9.0` to `^11.11.0` ([#9074](https://github.com/MetaMask/core/pull/9074)) - Bump `@metamask/controller-utils` from `^12.1.0` to `^12.3.0` ([#9058](https://github.com/MetaMask/core/pull/9058), [#9083](https://github.com/MetaMask/core/pull/9083), [#9218](https://github.com/MetaMask/core/pull/9218)) - Bump `@metamask/messenger` from `^1.2.0` to `^2.0.0` ([#9392](https://github.com/MetaMask/core/pull/9392)) diff --git a/packages/base-data-service/package.json b/packages/base-data-service/package.json index 32a4ca2d3a7..0ba3f0fb40c 100644 --- a/packages/base-data-service/package.json +++ b/packages/base-data-service/package.json @@ -59,7 +59,7 @@ "@metamask/messenger": "^2.0.0", "@metamask/storage-service": "^1.0.2", "@metamask/utils": "^11.11.0", - "@tanstack/query-core": "^4.43.0", + "@tanstack/query-core": "^5.62.16", "cockatiel": "^3.1.2", "fast-deep-equal": "^3.1.3", "lodash": "^4.17.21" diff --git a/packages/base-data-service/src/BaseDataService.test.ts b/packages/base-data-service/src/BaseDataService.test.ts index df6ed594d36..3c82a53cd15 100644 --- a/packages/base-data-service/src/BaseDataService.test.ts +++ b/packages/base-data-service/src/BaseDataService.test.ts @@ -1,6 +1,6 @@ import { MOCK_ANY_NAMESPACE, Messenger } from '@metamask/messenger'; -import { hashQueryKey } from '@tanstack/query-core'; -import { BrokenCircuitError } from 'cockatiel'; +import { hashKey } from '@tanstack/query-core'; +import { BrokenCircuitError, ConstantBackoff } from 'cockatiel'; import { cleanAll } from 'nock'; import { @@ -15,7 +15,13 @@ import { TRANSACTIONS_PAGE_2_CURSOR, TRANSACTIONS_PAGE_3_CURSOR, } from '../tests/mocks.js'; -import { STORAGE_SERVICE_KEY } from './BaseDataService.js'; +import { + BaseDataService, + DataServiceCacheUpdatedEvent, + DataServiceGranularCacheUpdatedEvent, + DataServiceInvalidateQueriesAction, + STORAGE_SERVICE_KEY, +} from './BaseDataService.js'; const TEST_ADDRESS = '0x4bbeEB066eD09B7AEd07bF39EEe0460DFa261520'; @@ -25,6 +31,209 @@ const MOCK_ASSETS = [ 'eip155:1/erc20:0x6b175474e89094c44da98b954eedeac495271d0f', ]; +// --- `fetchInfiniteQuery` test harness ------------------------------------- +// An in-memory paginator plus a service that exposes `fetchInfiniteQuery` both +// with and without page-param callbacks, used to pin down the pagination +// behaviour that must stay identical to query-core v4. + +const paginatedServiceName = 'PaginatedService'; + +// A cursor encodes the offset of a page's first item. +type Cursor = string; +type PageParam = { after?: Cursor; before?: Cursor }; + +type Page = { + data: string[]; + pageInfo: { + hasNextPage: boolean; + hasPreviousPage: boolean; + startCursor: Cursor | null; + endCursor: Cursor | null; + }; +}; + +const PAGE_SIZE = 3; +// 9 items => three pages: [item-0..2], [item-3..5], [item-6..8]. +const DATASET = Array.from({ length: 9 }, (_, index) => `item-${index}`); + +/** + * Serve a single page from the in-memory dataset. + * + * @param pageParam - The requested page. `undefined` or an `after`/`before` + * cursor. `after` fetches the page starting at the cursor offset; `before` + * fetches the page ending just before the cursor offset. + * @returns The requested page with cursor metadata. + */ +function fetchPage(pageParam?: PageParam): Page { + let offset = 0; + if (pageParam?.after !== undefined) { + offset = Number(pageParam.after); + } else if (pageParam?.before !== undefined) { + offset = Number(pageParam.before) - PAGE_SIZE; + } + + const data = DATASET.slice(offset, offset + PAGE_SIZE); + const hasNextPage = offset + PAGE_SIZE < DATASET.length; + const hasPreviousPage = offset > 0; + + return { + data, + pageInfo: { + hasNextPage, + hasPreviousPage, + startCursor: hasPreviousPage ? String(offset) : null, + endCursor: hasNextPage ? String(offset + PAGE_SIZE) : null, + }, + }; +} + +type PaginatedServiceActions = DataServiceInvalidateQueriesAction< + typeof paginatedServiceName +>; +type PaginatedServiceEvents = + | DataServiceCacheUpdatedEvent + | DataServiceGranularCacheUpdatedEvent; +type PaginatedServiceMessenger = Messenger< + typeof paginatedServiceName, + PaginatedServiceActions, + PaginatedServiceEvents +>; + +class PaginatedService extends BaseDataService< + typeof paginatedServiceName, + PaginatedServiceMessenger +> { + // Records every page param the query function is actually invoked with. + readonly queryFnCalls: (PageParam | null | undefined)[] = []; + + constructor( + messenger: PaginatedServiceMessenger, + { staleTime = Infinity }: { staleTime?: number } = {}, + ) { + super({ + name: paginatedServiceName, + messenger, + policyOptions: { maxRetries: 0, backoff: new ConstantBackoff(0) }, + }); + this.#staleTime = staleTime; + } + + readonly #staleTime: number; + + /** + * Paginate using page-param callbacks, the way a well-behaved consumer would. + * + * @param pageParam - The page to fetch. + * @returns The requested page. + */ + async withCallbacks(pageParam?: PageParam): Promise { + return this.fetchInfiniteQuery( + { + queryKey: [`${this.name}:withCallbacks`], + queryFn: async ({ pageParam: param }) => { + this.queryFnCalls.push(param); + return fetchPage(param); + }, + getNextPageParam: (lastPage) => + lastPage.pageInfo.hasNextPage && lastPage.pageInfo.endCursor + ? { after: lastPage.pageInfo.endCursor } + : undefined, + getPreviousPageParam: (firstPage) => + firstPage.pageInfo.hasPreviousPage && firstPage.pageInfo.startCursor + ? { before: firstPage.pageInfo.startCursor } + : undefined, + staleTime: this.#staleTime, + }, + pageParam, + ); + } + + /** + * Paginate without any page-param callbacks, relying purely on the explicit + * page param passed to the base method (the `MoneyAccountApiDataService` + * shape). + * + * @param pageParam - The page to fetch. + * @returns The requested page. + */ + async withoutCallbacks(pageParam?: PageParam): Promise { + return this.fetchInfiniteQuery( + { + queryKey: [`${this.name}:withoutCallbacks`], + queryFn: async ({ pageParam: param }) => { + this.queryFnCalls.push(param); + return fetchPage(param); + }, + staleTime: this.#staleTime, + }, + pageParam, + ); + } + + /** + * Paginate with a consumer-provided `initialPageParam`, used to check that a + * `null` initial param (a valid `Json` first-page sentinel) is preserved. + * + * @param initialPageParam - The initial page param to configure. + * @returns The first page. + */ + async withInitialPageParam( + initialPageParam: PageParam | null, + ): Promise { + return this.fetchInfiniteQuery< + Page, + unknown, + Page, + [string], + PageParam | null + >({ + queryKey: [`${this.name}:withInitialPageParam`], + queryFn: async ({ pageParam: param }) => { + this.queryFnCalls.push(param); + return fetchPage(param ?? undefined); + }, + initialPageParam, + }); + } +} + +/** + * The options bag that `withService` takes. + */ +type WithServiceOptions = { + staleTime?: number; +}; + +type WithServiceCallback = (payload: { + service: PaginatedService; + messenger: PaginatedServiceMessenger; +}) => Promise | ReturnValue; + +/** + * Construct a `PaginatedService`, pass it to the given function, and tear it + * down afterward. + * + * @param args - Either a function, or an options bag + a function. The options + * bag configures the service (currently just `staleTime`). The function is + * called with the new service and its messenger. + * @returns The same return value as the given function. + */ +async function withService( + ...args: + | [WithServiceCallback] + | [WithServiceOptions, WithServiceCallback] +): Promise { + const [{ staleTime }, testFunction] = + args.length === 2 ? args : [{}, args[0]]; + const messenger = new Messenger({ namespace: paginatedServiceName }); + const service = new PaginatedService(messenger, { staleTime }); + try { + return await testFunction({ service, messenger }); + } finally { + service.destroy(); + } +} + describe('BaseDataService', () => { beforeAll(() => { jest.useFakeTimers({ doNotFake: ['nextTick', 'setImmediate'] }); @@ -131,7 +340,7 @@ describe('BaseDataService', () => { const queryKey = ['ExampleDataService:getAssets', MOCK_ASSETS]; - const hash = hashQueryKey(queryKey); + const hash = hashKey(queryKey); expect(publishSpy).toHaveBeenNthCalledWith( 6, @@ -186,7 +395,7 @@ describe('BaseDataService', () => { const queryKey = ['ExampleDataService:getAssets', MOCK_ASSETS]; - const hash = hashQueryKey(queryKey); + const hash = hashKey(queryKey); expect(publishSpy).toHaveBeenNthCalledWith( 8, @@ -333,6 +542,7 @@ describe('BaseDataService', () => { state: { queries: [ { + dehydratedAt: expect.any(Number), queryHash: '["ExampleDataService:getAssets",["eip155:1/slip44:60","bip122:000000000019d6689c085ae165831e93/slip44:0","eip155:1/erc20:0x6b175474e89094c44da98b954eedeac495271d0f"]]', queryKey: [ @@ -627,4 +837,151 @@ describe('BaseDataService', () => { expect(publishSpy).not.toHaveBeenCalled(); }); }); + + describe('fetchInfiniteQuery', () => { + beforeAll(() => { + jest.useRealTimers(); + }); + + afterAll(() => { + jest.useFakeTimers({ doNotFake: ['nextTick', 'setImmediate'] }); + }); + + describe('with page-param callbacks', () => { + it('returns the first page on a cold fetch', async () => { + await withService(async ({ service }) => { + const page = await service.withCallbacks(); + + expect(page.data).toStrictEqual(['item-0', 'item-1', 'item-2']); + expect(page.pageInfo.hasPreviousPage).toBe(false); + }); + }); + + it('jumps directly to a page by cursor on a cold cache', async () => { + await withService(async ({ service }) => { + const page = await service.withCallbacks({ after: '6' }); + + expect(page.data).toStrictEqual(['item-6', 'item-7', 'item-8']); + }); + }); + + it('paginates forward across every page', async () => { + await withService(async ({ service }) => { + const page1 = await service.withCallbacks(); + const page2 = await service.withCallbacks({ + after: page1.pageInfo.endCursor as string, + }); + const page3 = await service.withCallbacks({ + after: page2.pageInfo.endCursor as string, + }); + + expect(page1.data).toStrictEqual(['item-0', 'item-1', 'item-2']); + expect(page2.data).toStrictEqual(['item-3', 'item-4', 'item-5']); + expect(page3.data).toStrictEqual(['item-6', 'item-7', 'item-8']); + }); + }); + + it('paginates backward to the previous page', async () => { + await withService(async ({ service }) => { + // Start in the middle so there is a previous page to go back to. + const middle = await service.withCallbacks({ after: '3' }); + expect(middle.data).toStrictEqual(['item-3', 'item-4', 'item-5']); + + const previous = await service.withCallbacks({ + before: middle.pageInfo.startCursor as string, + }); + + expect(previous.data).toStrictEqual(['item-0', 'item-1', 'item-2']); + }); + }); + + it('returns only the requested page, not the accumulated data', async () => { + await withService(async ({ service }) => { + await service.withCallbacks(); + await service.withCallbacks({ after: '3' }); + const page3 = await service.withCallbacks({ after: '6' }); + + expect(page3.data).toHaveLength(PAGE_SIZE); + expect(page3.data).toStrictEqual(['item-6', 'item-7', 'item-8']); + }); + }); + + it('does not refetch a fresh cached page', async () => { + await withService({ staleTime: Infinity }, async ({ service }) => { + await service.withCallbacks(); + await service.withCallbacks(); + + expect(service.queryFnCalls).toHaveLength(1); + }); + }); + + it('keeps navigation correct after refetching stale pages', async () => { + await withService({ staleTime: 0 }, async ({ service }) => { + await service.withCallbacks(); + await service.withCallbacks({ after: '3' }); + await service.withCallbacks({ after: '6' }); + + // A param-less call is stale, so query-core rebuilds all cached pages. + // This exercises the full-rebuild path, which must use the consumer's + // page-param callbacks and not any resolvers injected while paging. + const rebuilt = await service.withCallbacks(); + expect(rebuilt.data).toStrictEqual(['item-0', 'item-1', 'item-2']); + + const page2Again = await service.withCallbacks({ after: '3' }); + expect(page2Again.data).toStrictEqual(['item-3', 'item-4', 'item-5']); + }); + }); + }); + + describe('without page-param callbacks', () => { + it('fetches an arbitrary page by explicit cursor (forward)', async () => { + await withService(async ({ service }) => { + const page1 = await service.withoutCallbacks(); + expect(page1.data).toStrictEqual(['item-0', 'item-1', 'item-2']); + + const page2 = await service.withoutCallbacks({ after: '3' }); + expect(page2.data).toStrictEqual(['item-3', 'item-4', 'item-5']); + }); + }); + + it('fetches the correct page content for a `before` cursor', async () => { + await withService(async ({ service }) => { + // Cold jump into the middle, then ask for the page before it. + const middle = await service.withoutCallbacks({ after: '3' }); + expect(middle.data).toStrictEqual(['item-3', 'item-4', 'item-5']); + + const previous = await service.withoutCallbacks({ before: '3' }); + expect(previous.data).toStrictEqual(['item-0', 'item-1', 'item-2']); + }); + }); + + it('refetches stale multi-page state without page-param callbacks', async () => { + await withService({ staleTime: 0 }, async ({ service }) => { + await service.withoutCallbacks(); + await service.withoutCallbacks({ after: '3' }); + await service.withoutCallbacks({ after: '6' }); + + // Stale, so query-core rebuilds every cached page by walking forward + // from the first one. With no consumer `getNextPageParam`, that walk + // must not throw (the base service supplies a no-op resolver). + const rebuilt = await service.withoutCallbacks(); + expect(rebuilt.data).toStrictEqual(['item-0', 'item-1', 'item-2']); + + // Navigation still works after the rebuild. + const page2Again = await service.withoutCallbacks({ after: '3' }); + expect(page2Again.data).toStrictEqual(['item-3', 'item-4', 'item-5']); + }); + }); + + it('preserves a `null` consumer `initialPageParam`', async () => { + await withService(async ({ service }) => { + await service.withInitialPageParam(null); + + // `null` is a valid page param, so it must reach the query function + // rather than being coerced to `undefined`. + expect(service.queryFnCalls).toStrictEqual([null]); + }); + }); + }); + }); }); diff --git a/packages/base-data-service/src/BaseDataService.ts b/packages/base-data-service/src/BaseDataService.ts index 6c9b1146e19..e8446b3f6d3 100644 --- a/packages/base-data-service/src/BaseDataService.ts +++ b/packages/base-data-service/src/BaseDataService.ts @@ -13,14 +13,16 @@ import type { Json } from '@metamask/utils'; import { DefaultOptions, DehydratedState, - FetchInfiniteQueryOptions, FetchQueryOptions, + GetNextPageParamFunction, + GetPreviousPageParamFunction, InfiniteData, InvalidateOptions, InvalidateQueryFilters, OmitKeyof, QueryClient, QueryClientConfig, + QueryFunction, WithRequired, dehydrate, hydrate, @@ -54,7 +56,7 @@ type CacheUpdatedType = DataServiceCacheUpdatedPayload['type']; export type DataServiceInvalidateQueriesAction = { type: `${ServiceName}:invalidateQueries`; handler: ( - filters?: InvalidateQueryFilters, + filters?: InvalidateQueryFilters, options?: InvalidateOptions, ) => Promise; }; @@ -251,10 +253,14 @@ export class BaseDataService< options: WithRequired< OmitKeyof< FetchQueryOptions, - 'retry' | 'retryDelay' + 'retry' | 'retryDelay' | 'queryFn' >, - 'queryKey' | 'queryFn' - >, + 'queryKey' + > & { + // Data services always provide a concrete query function; the `skipToken` + // sentinel added in query-core v5 is not supported here. + queryFn: QueryFunction; + }, ): Promise { return this.#queryClient.fetchQuery({ ...options, @@ -280,47 +286,107 @@ export class BaseDataService< >( options: WithRequired< OmitKeyof< - FetchInfiniteQueryOptions, - 'retry' | 'retryDelay' + FetchQueryOptions< + TQueryFnData, + TError, + InfiniteData, + TQueryKey, + TPageParam + >, + 'retry' | 'retryDelay' | 'queryFn' | 'initialPageParam' >, - 'queryKey' | 'queryFn' - >, + 'queryKey' + > & { + // Data services always provide a concrete query function; the `skipToken` + // sentinel added in query-core v5 is not supported here. + queryFn: QueryFunction; + // These are required by query-core v5 for infinite queries but remain + // optional here: consumers may drive pagination purely by passing an + // explicit `pageParam` (see below). + initialPageParam?: TPageParam; + getNextPageParam?: GetNextPageParamFunction; + getPreviousPageParam?: GetPreviousPageParamFunction< + TPageParam, + TQueryFnData + >; + }, pageParam?: TPageParam, ): Promise { const cache = this.#queryClient.getQueryCache(); - const query = cache.find>({ + const query = cache.find< + TQueryFnData, + TError, + InfiniteData + >({ queryKey: options.queryKey, }); if (!query?.state.data || pageParam === undefined) { - const result = await this.#queryClient.fetchInfiniteQuery({ + // query-core v5 requires an `initialPageParam`, which becomes the param of + // the first (and only) page this fetches. Prefer an explicit per-call + // `pageParam` (a cold jump to a specific page); otherwise use the + // consumer's `initialPageParam`. Branching on a strict `undefined` check + // (rather than `??`) preserves `null`, which is a valid `Json` page param + // and query-core's usual first-page sentinel. + let initialPageParam: TPageParam; + if (pageParam === undefined) { + initialPageParam = options.initialPageParam as TPageParam; + } else { + initialPageParam = pageParam; + } + + const result = await this.#queryClient.fetchInfiniteQuery< + TQueryFnData, + TError, + TData, + TQueryKey, + TPageParam + >({ ...options, + initialPageParam, + // Provide a no-op `getNextPageParam` when the consumer omits one. + // query-core v5 walks `getNextPageParam` when it refetches a multi-page + // infinite query, so a missing resolver would throw once more than one + // page has been cached. The no-op rebuilds the cache down to the first + // page; the consumer repopulates it by re-navigating with explicit + // page params. + getNextPageParam: options.getNextPageParam ?? ((): null => null), queryFn: (context) => - this.#policy.execute(() => - options.queryFn({ - ...context, - pageParam: context.pageParam ?? pageParam, - }), - ), + this.#policy.execute(() => options.queryFn(context)), }); return result.pages[0]; } - const { pages } = query.state.data; - const previous = options.getPreviousPageParam?.(pages[0], pages); + const { pages, pageParams } = query.state.data; + const previous = options.getPreviousPageParam?.( + pages[0], + pages, + pageParams[0], + pageParams, + ); const direction = deepEqual(pageParam, previous) ? 'backward' : 'forward'; - const result = await query.fetch(undefined, { - meta: { - fetchMore: { - direction, - pageParam, + // query-core v5 no longer accepts an explicit page param via the `fetchMore` + // meta; it derives the next/previous param from these callbacks instead. + // Override them to return exactly the requested page so pagination works + // even when the consumer did not provide page-param callbacks. + const result = await query.fetch( + { + ...query.options, + getNextPageParam: () => pageParam, + getPreviousPageParam: () => pageParam, + } as typeof query.options, + { + meta: { + fetchMore: { + direction, + }, }, }, - }); + ); const pageIndex = result.pageParams.findIndex((param) => deepEqual(param, pageParam), @@ -337,7 +403,7 @@ export class BaseDataService< * @returns Nothing. */ async invalidateQueries( - filters?: InvalidateQueryFilters, + filters?: InvalidateQueryFilters, options?: InvalidateOptions, ): Promise { return this.#queryClient.invalidateQueries(filters, options); diff --git a/packages/base-data-service/tests/ExampleDataService.ts b/packages/base-data-service/tests/ExampleDataService.ts index d84e9edf5d1..3f0b2a16ff3 100644 --- a/packages/base-data-service/tests/ExampleDataService.ts +++ b/packages/base-data-service/tests/ExampleDataService.ts @@ -101,7 +101,7 @@ export class ExampleDataService extends BaseDataService< return response.json(); }, staleTime: inMilliseconds(1, Duration.Day), - cacheTime: inMilliseconds(1, Duration.Day), + gcTime: inMilliseconds(1, Duration.Day), }); } @@ -109,7 +109,13 @@ export class ExampleDataService extends BaseDataService< address: string, page?: PageParam, ): Promise { - return this.fetchInfiniteQuery( + return this.fetchInfiniteQuery< + GetActivityResponse, + unknown, + GetActivityResponse, + [string, string], + PageParam + >( { queryKey: [`${this.name}:getActivity`, address], queryFn: async ({ pageParam }) => { diff --git a/packages/chomp-api-service/CHANGELOG.md b/packages/chomp-api-service/CHANGELOG.md index b1a57a81648..527d342f4cc 100644 --- a/packages/chomp-api-service/CHANGELOG.md +++ b/packages/chomp-api-service/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- Bump `@tanstack/query-core` from `^4.43.0` to `^5.62.16` ([#9712](https://github.com/MetaMask/core/pull/9712)) + ## [4.0.0] ### Added diff --git a/packages/chomp-api-service/package.json b/packages/chomp-api-service/package.json index b5d79e415ba..cb3a0f15e8a 100644 --- a/packages/chomp-api-service/package.json +++ b/packages/chomp-api-service/package.json @@ -58,7 +58,7 @@ "@metamask/messenger": "^2.0.0", "@metamask/superstruct": "^3.1.0", "@metamask/utils": "^11.11.0", - "@tanstack/query-core": "^4.43.0" + "@tanstack/query-core": "^5.62.16" }, "devDependencies": { "@metamask/auto-changelog": "^6.1.0", diff --git a/packages/chomp-api-service/src/chomp-api-service.ts b/packages/chomp-api-service/src/chomp-api-service.ts index a8d400c1bc5..d3348fd7a6a 100644 --- a/packages/chomp-api-service/src/chomp-api-service.ts +++ b/packages/chomp-api-service/src/chomp-api-service.ts @@ -404,7 +404,7 @@ export class ChompApiService extends BaseDataService< * The result is scoped to the authenticated profile and consumers use it * to decide whether an association already exists, so it is always fetched * fresh (`staleTime: 0`) and evicted as soon as the call settles - * (`cacheTime: 0`). The query key carries a SHA-256 digest of the bearer + * (`gcTime: 0`). The query key carries a SHA-256 digest of the bearer * token — the same token the request is made with — so concurrent calls * only share an in-flight request when they are for the same profile. The * digest, not the token, is used because query keys leave the service via @@ -422,7 +422,7 @@ export class ChompApiService extends BaseDataService< const jsonResponse = await this.fetchQuery({ queryKey: [`${this.name}:getAssociatedAddresses`, profileKey], staleTime: 0, - cacheTime: 0, + gcTime: 0, queryFn: async () => { const response = await fetch( new URL('/v1/auth/address', this.#baseUrl), diff --git a/packages/money-account-api-data-service/CHANGELOG.md b/packages/money-account-api-data-service/CHANGELOG.md index 1c20eb5f817..459ca3e6fcc 100644 --- a/packages/money-account-api-data-service/CHANGELOG.md +++ b/packages/money-account-api-data-service/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- Bump `@tanstack/query-core` from `^4.43.0` to `^5.62.16` ([#9712](https://github.com/MetaMask/core/pull/9712)) + ## [0.4.0] ### Changed diff --git a/packages/money-account-api-data-service/package.json b/packages/money-account-api-data-service/package.json index ed792384533..2ff826dce82 100644 --- a/packages/money-account-api-data-service/package.json +++ b/packages/money-account-api-data-service/package.json @@ -60,7 +60,7 @@ "@metamask/messenger": "^2.0.0", "@metamask/superstruct": "^3.1.0", "@metamask/utils": "^11.11.0", - "@tanstack/query-core": "^4.43.0" + "@tanstack/query-core": "^5.62.16" }, "devDependencies": { "@metamask/auto-changelog": "^6.1.0", diff --git a/packages/sample-controllers/CHANGELOG.md b/packages/sample-controllers/CHANGELOG.md index 4b6d5957be5..ab146f19620 100644 --- a/packages/sample-controllers/CHANGELOG.md +++ b/packages/sample-controllers/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Bump `@tanstack/query-core` from `^4.43.0` to `^5.62.16` ([#9712](https://github.com/MetaMask/core/pull/9712)) - Bump `@metamask/network-controller` from `^35.0.0` to `^35.0.1` ([#9758](https://github.com/MetaMask/core/pull/9758)) ## [5.0.4] diff --git a/packages/sample-controllers/package.json b/packages/sample-controllers/package.json index 25f00dd4560..339af99d42b 100644 --- a/packages/sample-controllers/package.json +++ b/packages/sample-controllers/package.json @@ -61,7 +61,7 @@ "@metamask/network-controller": "^35.0.1", "@metamask/superstruct": "^3.1.0", "@metamask/utils": "^11.11.0", - "@tanstack/query-core": "^4.43.0" + "@tanstack/query-core": "^5.62.16" }, "devDependencies": { "@metamask/auto-changelog": "^6.1.0", diff --git a/packages/sentinel-api-service/CHANGELOG.md b/packages/sentinel-api-service/CHANGELOG.md index ecef2d16016..171c3e96c56 100644 --- a/packages/sentinel-api-service/CHANGELOG.md +++ b/packages/sentinel-api-service/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- Bump `@tanstack/query-core` from `^4.43.0` to `^5.62.16` ([#9712](https://github.com/MetaMask/core/pull/9712)) + ## [1.0.0] ### Added diff --git a/packages/sentinel-api-service/package.json b/packages/sentinel-api-service/package.json index b41f3d14fcb..a5370148807 100644 --- a/packages/sentinel-api-service/package.json +++ b/packages/sentinel-api-service/package.json @@ -60,7 +60,7 @@ "@metamask/messenger": "^2.0.0", "@metamask/superstruct": "^3.1.0", "@metamask/utils": "^11.11.0", - "@tanstack/query-core": "^4.43.0" + "@tanstack/query-core": "^5.62.16" }, "devDependencies": { "@metamask/auto-changelog": "^6.1.0", diff --git a/packages/wallet-framework-docs/package.json b/packages/wallet-framework-docs/package.json index 777d122ea05..1db2dc874d7 100644 --- a/packages/wallet-framework-docs/package.json +++ b/packages/wallet-framework-docs/package.json @@ -42,7 +42,7 @@ "@metamask/messenger": "^2.0.0", "@metamask/superstruct": "^3.1.0", "@metamask/utils": "^11.11.0", - "@tanstack/query-core": "^4.43.0" + "@tanstack/query-core": "^5.62.16" }, "devDependencies": { "@docusaurus/core": "^3.10.1", diff --git a/yarn.config.cjs b/yarn.config.cjs index 1e1dc0fbf90..2b55c2fd360 100644 --- a/yarn.config.cjs +++ b/yarn.config.cjs @@ -23,9 +23,7 @@ const { inspect } = require('util'); * Only intended as temporary measures to faciliate upgrades and releases. * This should trend towards empty. */ -const ALLOWED_INCONSISTENT_DEPENDENCIES = { - '@tanstack/query-core': ['^4.43.0'], -}; +const ALLOWED_INCONSISTENT_DEPENDENCIES = {}; /** * These packages are allowed as peer dependencies without requiring installation as diff --git a/yarn.lock b/yarn.lock index a5561d619e9..f2303d444b3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6212,7 +6212,7 @@ __metadata: "@metamask/messenger": "npm:^2.0.0" "@metamask/storage-service": "npm:^1.0.2" "@metamask/utils": "npm:^11.11.0" - "@tanstack/query-core": "npm:^4.43.0" + "@tanstack/query-core": "npm:^5.62.16" "@ts-bridge/cli": "npm:^0.6.4" "@types/jest": "npm:^30.0.0" "@types/lodash": "npm:^4.14.191" @@ -6395,7 +6395,7 @@ __metadata: "@metamask/messenger": "npm:^2.0.0" "@metamask/superstruct": "npm:^3.1.0" "@metamask/utils": "npm:^11.11.0" - "@tanstack/query-core": "npm:^4.43.0" + "@tanstack/query-core": "npm:^5.62.16" "@ts-bridge/cli": "npm:^0.6.4" "@types/jest": "npm:^30.0.0" deepmerge: "npm:^4.2.2" @@ -7836,7 +7836,7 @@ __metadata: "@metamask/messenger": "npm:^2.0.0" "@metamask/superstruct": "npm:^3.1.0" "@metamask/utils": "npm:^11.11.0" - "@tanstack/query-core": "npm:^4.43.0" + "@tanstack/query-core": "npm:^5.62.16" "@ts-bridge/cli": "npm:^0.6.4" "@types/jest": "npm:^30.0.0" deepmerge: "npm:^4.2.2" @@ -8782,7 +8782,7 @@ __metadata: "@metamask/network-controller": "npm:^35.0.1" "@metamask/superstruct": "npm:^3.1.0" "@metamask/utils": "npm:^11.11.0" - "@tanstack/query-core": "npm:^4.43.0" + "@tanstack/query-core": "npm:^5.62.16" "@ts-bridge/cli": "npm:^0.6.4" "@types/jest": "npm:^30.0.0" deepmerge: "npm:^4.2.2" @@ -8878,7 +8878,7 @@ __metadata: "@metamask/messenger": "npm:^2.0.0" "@metamask/superstruct": "npm:^3.1.0" "@metamask/utils": "npm:^11.11.0" - "@tanstack/query-core": "npm:^4.43.0" + "@tanstack/query-core": "npm:^5.62.16" "@ts-bridge/cli": "npm:^0.6.4" "@types/jest": "npm:^30.0.0" deepmerge: "npm:^4.2.2" @@ -9516,7 +9516,7 @@ __metadata: "@metamask/messenger": "npm:^2.0.0" "@metamask/superstruct": "npm:^3.1.0" "@metamask/utils": "npm:^11.11.0" - "@tanstack/query-core": "npm:^4.43.0" + "@tanstack/query-core": "npm:^5.62.16" "@types/jest": "npm:^30.0.0" "@types/react": "npm:^19.0.0" deepmerge: "npm:^4.2.2" @@ -11510,13 +11510,6 @@ __metadata: languageName: node linkType: hard -"@tanstack/query-core@npm:^4.43.0": - version: 4.43.0 - resolution: "@tanstack/query-core@npm:4.43.0" - checksum: 10/c2a5a151c7adaea8311e01a643255f31946ae3164a71567ba80048242821ae14043f13f5516b695baebe5ea7e4b2cf717fd60908a929d18a5c5125fee925ff67 - languageName: node - linkType: hard - "@tanstack/react-query@npm:^5.62.16": version: 5.101.2 resolution: "@tanstack/react-query@npm:5.101.2"