From 45c47be26d4e020cfcff359a5af19ccfc39b930e Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Tue, 21 May 2024 11:05:48 +0200 Subject: [PATCH 01/15] useLazyQuery: fix rules of React violations (#11851) * useLazyQuery: fix rules of React violations * size-limits * Clean up Prettier, Size-limit, and Api-Extractor --------- Co-authored-by: phryneas --- .changeset/shaggy-mirrors-judge.md | 5 ++++ .changeset/stupid-planes-nail.md | 5 ++++ .size-limits.json | 2 +- src/react/hooks/useLazyQuery.ts | 26 ++++++++++++--------- src/react/hooks/useQuery.ts | 37 ++++++++++++++++++------------ 5 files changed, 48 insertions(+), 27 deletions(-) create mode 100644 .changeset/shaggy-mirrors-judge.md create mode 100644 .changeset/stupid-planes-nail.md diff --git a/.changeset/shaggy-mirrors-judge.md b/.changeset/shaggy-mirrors-judge.md new file mode 100644 index 00000000000..f5e599284ab --- /dev/null +++ b/.changeset/shaggy-mirrors-judge.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +Avoid usage of useRef in useInternalState to prevent ref access in render. diff --git a/.changeset/stupid-planes-nail.md b/.changeset/stupid-planes-nail.md new file mode 100644 index 00000000000..200a00ac26b --- /dev/null +++ b/.changeset/stupid-planes-nail.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +Fix a bug where `useLazyQuery` would not pick up a client change. diff --git a/.size-limits.json b/.size-limits.json index 6dce9510b90..d082ee9265e 100644 --- a/.size-limits.json +++ b/.size-limits.json @@ -1,4 +1,4 @@ { - "dist/apollo-client.min.cjs": 39574, + "dist/apollo-client.min.cjs": 39607, "import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 32821 } diff --git a/src/react/hooks/useLazyQuery.ts b/src/react/hooks/useLazyQuery.ts index 909bf8a24da..a8d6eb00a67 100644 --- a/src/react/hooks/useLazyQuery.ts +++ b/src/react/hooks/useLazyQuery.ts @@ -9,7 +9,6 @@ import type { LazyQueryHookOptions, LazyQueryResultTuple, NoInfer, - QueryResult, } from "../types/types.js"; import { useInternalState } from "./useQuery.js"; import { useApolloClient } from "./useApolloClient.js"; @@ -95,20 +94,17 @@ export function useLazyQuery< useQueryResult.observable.options.initialFetchPolicy || internalState.getDefaultFetchPolicy(); - const result: QueryResult = Object.assign(useQueryResult, { - called: !!execOptionsRef.current, - }); - + const { forceUpdateState, obsQueryFields } = internalState; // We use useMemo here to make sure the eager methods have a stable identity. const eagerMethods = React.useMemo(() => { const eagerMethods: Record = {}; for (const key of EAGER_METHODS) { - const method = result[key]; + const method = obsQueryFields[key]; eagerMethods[key] = function () { if (!execOptionsRef.current) { execOptionsRef.current = Object.create(null); // Only the first time populating execOptionsRef.current matters here. - internalState.forceUpdateState(); + forceUpdateState(); } // @ts-expect-error this is just too generic to type return method.apply(this, arguments); @@ -116,9 +112,17 @@ export function useLazyQuery< } return eagerMethods; - }, []); - - Object.assign(result, eagerMethods); + }, [forceUpdateState, obsQueryFields]); + + const called = !!execOptionsRef.current; + const result = React.useMemo( + () => ({ + ...useQueryResult, + ...eagerMethods, + called, + }), + [useQueryResult, eagerMethods, called] + ); const execute = React.useCallback[0]>( (executeOptions) => { @@ -147,7 +151,7 @@ export function useLazyQuery< return promise; }, - [] + [eagerMethods, initialFetchPolicy, internalState] ); return [execute, result]; diff --git a/src/react/hooks/useQuery.ts b/src/react/hooks/useQuery.ts index 225577521b4..c4ed41193e2 100644 --- a/src/react/hooks/useQuery.ts +++ b/src/react/hooks/useQuery.ts @@ -109,23 +109,30 @@ export function useInternalState( client: ApolloClient, query: DocumentNode | TypedDocumentNode ): InternalState { - const stateRef = React.useRef>(); - if ( - !stateRef.current || - client !== stateRef.current.client || - query !== stateRef.current.query - ) { - stateRef.current = new InternalState(client, query, stateRef.current); - } - const state = stateRef.current; - // By default, InternalState.prototype.forceUpdate is an empty function, but // we replace it here (before anyone has had a chance to see this state yet) // with a function that unconditionally forces an update, using the latest - // setTick function. Updating this state by calling state.forceUpdate is the - // only way we trigger React component updates (no other useState calls within - // the InternalState class). - state.forceUpdateState = React.useReducer((tick) => tick + 1, 0)[1]; + // setTick function. Updating this state by calling state.forceUpdate or the + // uSES notification callback are the only way we trigger React component updates. + const forceUpdateState = React.useReducer((tick) => tick + 1, 0)[1]; + + function createInternalState(previous?: InternalState) { + return Object.assign(new InternalState(client, query, previous), { + forceUpdateState, + }); + } + + let [state, updateState] = React.useState(createInternalState); + + if (client !== state.client || query !== state.query) { + // If the client or query have changed, we need to create a new InternalState. + // This will trigger a re-render with the new state, but it will also continue + // to run the current render function to completion. + // Since we sometimes trigger some side-effects in the render function, we + // re-assign `state` to the new state to ensure that those side-effects are + // triggered with the new state. + updateState((state = createInternalState(state))); + } return state; } @@ -511,7 +518,7 @@ class InternalState { private onError(error: ApolloError) {} private observable!: ObservableQuery; - private obsQueryFields!: Omit< + public obsQueryFields!: Omit< ObservableQueryFields, "variables" >; From d502a69654d8ffa31e09467da028304a934a9874 Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Tue, 21 May 2024 11:33:34 +0200 Subject: [PATCH 02/15] useMutation: fix rules of React violations (#11852) * useMutation: fix rules of React violations * size-limits * Clean up Prettier, Size-limit, and Api-Extractor --------- Co-authored-by: phryneas --- .changeset/loud-hairs-think.md | 5 +++++ .changeset/mighty-monkeys-explain.md | 6 ++++++ .size-limits.json | 2 +- .../__tests__/client/Mutation.test.tsx | 4 ++-- .../hoc/__tests__/mutations/lifecycle.test.tsx | 4 +++- src/react/hooks/useMutation.ts | 17 ++++++++++------- 6 files changed, 27 insertions(+), 11 deletions(-) create mode 100644 .changeset/loud-hairs-think.md create mode 100644 .changeset/mighty-monkeys-explain.md diff --git a/.changeset/loud-hairs-think.md b/.changeset/loud-hairs-think.md new file mode 100644 index 00000000000..7e29ffae5ec --- /dev/null +++ b/.changeset/loud-hairs-think.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +Fix a bug where calling the `useMutation` `reset` function would point the hook to an outdated `client` reference. diff --git a/.changeset/mighty-monkeys-explain.md b/.changeset/mighty-monkeys-explain.md new file mode 100644 index 00000000000..4629cd11273 --- /dev/null +++ b/.changeset/mighty-monkeys-explain.md @@ -0,0 +1,6 @@ +--- +"@apollo/client": patch +--- + +Prevent writing to a ref in render in `useMutation`. +As a result, you might encounter problems in the future if you call the mutation's `execute` function during render. Please note that this was never supported behavior, and we strongly recommend against it. diff --git a/.size-limits.json b/.size-limits.json index d082ee9265e..4176d307cbb 100644 --- a/.size-limits.json +++ b/.size-limits.json @@ -1,4 +1,4 @@ { - "dist/apollo-client.min.cjs": 39607, + "dist/apollo-client.min.cjs": 39620, "import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 32821 } diff --git a/src/react/components/__tests__/client/Mutation.test.tsx b/src/react/components/__tests__/client/Mutation.test.tsx index 80c75f99506..b71ba82f7cc 100644 --- a/src/react/components/__tests__/client/Mutation.test.tsx +++ b/src/react/components/__tests__/client/Mutation.test.tsx @@ -1348,7 +1348,7 @@ describe("General Mutation testing", () => { if (count === 0) { expect(result.called).toEqual(false); expect(result.loading).toEqual(false); - createTodo(); + setTimeout(createTodo, 10); } else if (count === 2 && result) { expect(result.data).toEqual(data); setTimeout(() => { @@ -1358,7 +1358,7 @@ describe("General Mutation testing", () => { }); } else if (count === 3) { expect(result.loading).toEqual(false); - createTodo(); + setTimeout(createTodo, 10); } else if (count === 5) { expect(result.data).toEqual(data3); } diff --git a/src/react/hoc/__tests__/mutations/lifecycle.test.tsx b/src/react/hoc/__tests__/mutations/lifecycle.test.tsx index f74895780a3..f6ff711e48d 100644 --- a/src/react/hoc/__tests__/mutations/lifecycle.test.tsx +++ b/src/react/hoc/__tests__/mutations/lifecycle.test.tsx @@ -92,7 +92,9 @@ describe("graphql(mutation) lifecycle", () => { class Container extends React.Component> { render() { if (this.props.listId !== 2) return null; - this.props.mutate!().then(() => resolve()); + setTimeout(() => { + this.props.mutate!().then(() => resolve()); + }); return null; } } diff --git a/src/react/hooks/useMutation.ts b/src/react/hooks/useMutation.ts index 79825f91524..65f0820e015 100644 --- a/src/react/hooks/useMutation.ts +++ b/src/react/hooks/useMutation.ts @@ -99,11 +99,9 @@ export function useMutation< options, }); - // TODO: Trying to assign these in a useEffect or useLayoutEffect breaks - // higher-order components. - { + React.useLayoutEffect(() => { Object.assign(ref.current, { client, options, mutation }); - } + }); const execute = React.useCallback( ( @@ -221,17 +219,22 @@ export function useMutation< const reset = React.useCallback(() => { if (ref.current.isMounted) { - const result = { called: false, loading: false, client }; + const result = { + called: false, + loading: false, + client: ref.current.client, + }; Object.assign(ref.current, { mutationId: 0, result }); setResult(result); } }, []); React.useEffect(() => { - ref.current.isMounted = true; + const current = ref.current; + current.isMounted = true; return () => { - ref.current.isMounted = false; + current.isMounted = false; }; }, []); From 45055d0c96ae44414a50e5ba9e46768029c4537c Mon Sep 17 00:00:00 2001 From: Jeff Auriemma Date: Mon, 3 Jun 2024 11:08:10 -0400 Subject: [PATCH 03/15] 2024-06-03 Roadmap update --- ROADMAP.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 0c81ce26893..575e97eb231 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,6 +1,6 @@ # 🔮 Apollo Client Roadmap -**Last updated: 2024-04-29** +**Last updated: 2024-06-03** For up to date release notes, refer to the project's [Changelog](https://github.com/apollographql/apollo-client/blob/main/CHANGELOG.md). @@ -16,11 +16,13 @@ For up to date release notes, refer to the project's [Changelog](https://github. ## [3.11.0](https://github.com/apollographql/apollo-client/milestone/40) - July 9th, 2024 _Release candidate - July 2nd, 2024_ +- Rewriting `useQuery` and `useSubscription` for better React Compiler support + ## Upcoming features - Data masking - Introduce a suspenseful `useFragment` that will suspend when the data is not yet loaded -- leaner client (under alternate entry point) +- Leaner client (under alternate entry point) - Better types for `useQuery`/`useMutation`/`useSubscription` ## 4.0 From 634d91aeb10ab308b05d5ffb918678806046af09 Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Fri, 7 Jun 2024 11:21:21 +0200 Subject: [PATCH 04/15] Add missing name to tuple member (fix TS5084) (#11877) * Add missing name to tuple member (fix TS5084) * Update src/react/hooks/useLoadableQuery.ts * Clean up Prettier, Size-limit, and Api-Extractor --------- Co-authored-by: phryneas --- .api-reports/api-report-react.md | 2 +- .api-reports/api-report-react_hooks.md | 2 +- .api-reports/api-report.md | 2 +- .changeset/sharp-cats-taste.md | 5 +++++ src/react/hooks/useLoadableQuery.ts | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 .changeset/sharp-cats-taste.md diff --git a/.api-reports/api-report-react.md b/.api-reports/api-report-react.md index 00a986ce9ec..dd2e4bee702 100644 --- a/.api-reports/api-report-react.md +++ b/.api-reports/api-report-react.md @@ -2145,7 +2145,7 @@ export function useLoadableQuery = [ loadQuery: LoadQueryFunction, queryRef: QueryRef | null, - { +handlers: { fetchMore: FetchMoreFunction; refetch: RefetchFunction; reset: ResetFunction; diff --git a/.api-reports/api-report-react_hooks.md b/.api-reports/api-report-react_hooks.md index d530450d98b..22d2d73624c 100644 --- a/.api-reports/api-report-react_hooks.md +++ b/.api-reports/api-report-react_hooks.md @@ -1973,7 +1973,7 @@ export function useLoadableQuery = [ loadQuery: LoadQueryFunction, queryRef: QueryRef | null, - { +handlers: { fetchMore: FetchMoreFunction; refetch: RefetchFunction; reset: ResetFunction; diff --git a/.api-reports/api-report.md b/.api-reports/api-report.md index 632f1f0976d..b3eb3f71625 100644 --- a/.api-reports/api-report.md +++ b/.api-reports/api-report.md @@ -2808,7 +2808,7 @@ export function useLoadableQuery = [ loadQuery: LoadQueryFunction, queryRef: QueryRef | null, - { +handlers: { fetchMore: FetchMoreFunction; refetch: RefetchFunction; reset: ResetFunction; diff --git a/.changeset/sharp-cats-taste.md b/.changeset/sharp-cats-taste.md new file mode 100644 index 00000000000..6d2946fe28d --- /dev/null +++ b/.changeset/sharp-cats-taste.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +Add missing name to tuple member (fix TS5084) diff --git a/src/react/hooks/useLoadableQuery.ts b/src/react/hooks/useLoadableQuery.ts index 00249b08e76..01a95a630ec 100644 --- a/src/react/hooks/useLoadableQuery.ts +++ b/src/react/hooks/useLoadableQuery.ts @@ -44,7 +44,7 @@ export type UseLoadableQueryResult< > = [ loadQuery: LoadQueryFunction, queryRef: QueryRef | null, - { + handlers: { /** {@inheritDoc @apollo/client!QueryResultDocumentation#fetchMore:member} */ fetchMore: FetchMoreFunction; /** {@inheritDoc @apollo/client!QueryResultDocumentation#refetch:member} */ From 486613c365bc18c31e11bc741768332bdd74aacb Mon Sep 17 00:00:00 2001 From: Liz Hennessy <95302380+lizhennessy@users.noreply.github.com> Date: Mon, 10 Jun 2024 14:58:37 -0600 Subject: [PATCH 05/15] Update advanced-topics.mdx --- docs/source/caching/advanced-topics.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/caching/advanced-topics.mdx b/docs/source/caching/advanced-topics.mdx index 9d00bbf9014..4be10cd6a5f 100644 --- a/docs/source/caching/advanced-topics.mdx +++ b/docs/source/caching/advanced-topics.mdx @@ -116,7 +116,7 @@ function Foo (){ export default Foo; ``` -## TypePolicy inheritence +## TypePolicy inheritance JavaScript developers will be familiar with the idea of [inheritance](https://en.m.wikipedia.org/wiki/Inheritance_(object-oriented_programming)) from the `extends` clause of `class` declarations, or possibly from dealing with prototype chains created by `Object.create`. From 6ca5ef4981085caf326bcfc984757078648c709e Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Tue, 11 Jun 2024 11:17:56 +0200 Subject: [PATCH 06/15] start testing with React 19 (#11883) * start testing with React 19 --------- Co-authored-by: phryneas --- .circleci/config.yml | 16 ++++++--- config/jest.config.js | 28 ++++++++++++++- package-lock.json | 31 +++++++++++++++++ package.json | 4 ++- .../hooks/__tests__/useFragment.test.tsx | 2 +- .../hooks/__tests__/useLoadableQuery.test.tsx | 6 ++++ .../hooks/__tests__/useMutation.test.tsx | 2 +- src/react/hooks/__tests__/useQuery.test.tsx | 34 +++++++++++++++++-- .../hooks/__tests__/useReactiveVar.test.tsx | 3 +- .../hooks/__tests__/useSuspenseQuery.test.tsx | 13 ++++--- .../__tests__/useRenderGuard.test.tsx | 3 ++ src/testing/internal/profile/profile.tsx | 11 ++++-- .../__tests__/mockSubscriptionLink.test.tsx | 3 +- 13 files changed, 137 insertions(+), 19 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index fdb5be1a7ca..ff7ac58f270 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -33,16 +33,20 @@ jobs: Tests: docker: - image: cimg/node:22.2.0 + parameters: + project: + type: string steps: - checkout - run: npm run ci:precheck - run: npm version - run: npm ci + - run: if test "<< parameters.project >>" = "Core Tests"; then npm run test:memory; fi - run: name: Jest suite with coverage - command: npm run test:ci + command: npm run test:ci -- --selectProjects "<< parameters.project >>" environment: - JEST_JUNIT_OUTPUT_FILE: "reports/junit/js-test-results.xml" + JEST_JUNIT_OUTPUT_FILE: "reports/junit/js-test-results-<< parameters.project >>.xml" - store_test_results: path: reports/junit - store_artifacts: @@ -124,7 +128,11 @@ workflows: Build and Test: jobs: # - Filesize - - Tests + - Tests: + matrix: + parameters: + project: + ["Core Tests", "ReactDOM 17", "ReactDOM 18", "ReactDOM 19"] - Formatting - Lint - BuildTarball @@ -165,7 +173,7 @@ workflows: - "@types/react@16.8 @types/react-dom@16.8" - "@types/react@17 @types/react-dom@17" - "@types/react@18 @types/react-dom@18" - - "@types/react@npm:types-react@19.0.0-alpha.3 @types/react-dom@npm:types-react-dom@19.0.0-alpha.3" + - "@types/react@npm:types-react@19.0.0-rc.0 @types/react-dom@npm:types-react-dom@19.0.0-rc.0" - "typescript@next" security-scans: jobs: diff --git a/config/jest.config.js b/config/jest.config.js index 646185e63da..33e7aba59df 100644 --- a/config/jest.config.js +++ b/config/jest.config.js @@ -29,6 +29,16 @@ const defaults = { const ignoreTSFiles = ".ts$"; const ignoreTSXFiles = ".tsx$"; +const react19TestFileIgnoreList = [ + ignoreTSFiles, + // The HOCs and Render Prop Components have been deprecated since March 2020, + // and to test them we would need to rewrite a lot of our test suites. + // We will not support them any more for React 19. + // They will probably work, but we make no more guarantees. + "src/react/hoc/.*", + "src/react/components/.*", +]; + const react17TestFileIgnoreList = [ ignoreTSFiles, // We only support Suspense with React 18, so don't test suspense hooks with @@ -49,6 +59,17 @@ const tsStandardConfig = { // For both React (Jest) "projects", ignore core tests (.ts files) as they // do not import React, to avoid running them twice. +const standardReact19Config = { + ...defaults, + displayName: "ReactDOM 19", + testPathIgnorePatterns: react19TestFileIgnoreList, + moduleNameMapper: { + "^react$": "react-19", + "^react-dom$": "react-dom-19", + "^react-dom/(.*)$": "react-dom-19/$1", + }, +}; + const standardReact18Config = { ...defaults, displayName: "ReactDOM 18", @@ -69,5 +90,10 @@ const standardReact17Config = { }; module.exports = { - projects: [tsStandardConfig, standardReact17Config, standardReact18Config], + projects: [ + tsStandardConfig, + standardReact17Config, + standardReact18Config, + standardReact19Config, + ], }; diff --git a/package-lock.json b/package-lock.json index df5d9cf9714..9e67a4ec4fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -81,8 +81,10 @@ "prettier": "3.1.1", "react": "18.3.1", "react-17": "npm:react@^17", + "react-19": "npm:react@19.0.0-rc-cc1ec60d0d-20240607", "react-dom": "18.3.1", "react-dom-17": "npm:react-dom@^17", + "react-dom-19": "npm:react-dom@19.0.0-rc-cc1ec60d0d-20240607", "react-error-boundary": "4.0.13", "recast": "0.23.6", "resolve": "1.22.8", @@ -10301,6 +10303,16 @@ "node": ">=0.10.0" } }, + "node_modules/react-19": { + "name": "react", + "version": "19.0.0-rc-cc1ec60d0d-20240607", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0-rc-cc1ec60d0d-20240607.tgz", + "integrity": "sha512-q8A0/IdJ2wdHsjDNO1igFcSSFIMqSKmO7oJZtAjxIA9g0klK45Lxt15NQJ7z7cBvgD1r3xRTtQ/MAqnmwYHs1Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -10339,6 +10351,25 @@ "object-assign": "^4.1.1" } }, + "node_modules/react-dom-19": { + "name": "react-dom", + "version": "19.0.0-rc-cc1ec60d0d-20240607", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0-rc-cc1ec60d0d-20240607.tgz", + "integrity": "sha512-paspD9kAfKKuURVwKWJ0/g3qYw1DGi9h1k9xQV2iQN9cSVZ4JAOD727yjVLyp1zdzsoygjFfLMtSBdZ+oERYvA==", + "dev": true, + "dependencies": { + "scheduler": "0.25.0-rc-cc1ec60d0d-20240607" + }, + "peerDependencies": { + "react": "19.0.0-rc-cc1ec60d0d-20240607" + } + }, + "node_modules/react-dom-19/node_modules/scheduler": { + "version": "0.25.0-rc-cc1ec60d0d-20240607", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0-rc-cc1ec60d0d-20240607.tgz", + "integrity": "sha512-yFVKy6SDJkN2bOJSeH6gNo4+1MTygTZXnLRY5IHvEB6P9+O6WYRWz9PkELLjnl64lQwRgiigwzWQRSMNEboOGQ==", + "dev": true + }, "node_modules/react-error-boundary": { "version": "4.0.13", "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.13.tgz", diff --git a/package.json b/package.json index d8620f4b238..cb6168914be 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "inline-inherit-doc": "ts-node-script config/inlineInheritDoc.ts", "test": "node --expose-gc ./node_modules/jest/bin/jest.js --config ./config/jest.config.js", "test:debug": "node --inspect-brk node_modules/.bin/jest --config ./config/jest.config.js --runInBand --testTimeout 99999 --logHeapUsage", - "test:ci": "TEST_ENV=ci npm run test:coverage -- --logHeapUsage && npm run test:memory", + "test:ci": "TEST_ENV=ci npm run test:coverage -- --logHeapUsage", "test:watch": "jest --config ./config/jest.config.js --watch", "test:memory": "npm i && npm run build && cd scripts/memory && npm i && npm test", "test:coverage": "npm run coverage -- --ci --runInBand --reporters=default --reporters=jest-junit", @@ -162,8 +162,10 @@ "prettier": "3.1.1", "react": "18.3.1", "react-17": "npm:react@^17", + "react-19": "npm:react@19.0.0-rc-cc1ec60d0d-20240607", "react-dom": "18.3.1", "react-dom-17": "npm:react-dom@^17", + "react-dom-19": "npm:react-dom@19.0.0-rc-cc1ec60d0d-20240607", "react-error-boundary": "4.0.13", "recast": "0.23.6", "resolve": "1.22.8", diff --git a/src/react/hooks/__tests__/useFragment.test.tsx b/src/react/hooks/__tests__/useFragment.test.tsx index 0af4a3a1d37..f58ef9aaa6d 100644 --- a/src/react/hooks/__tests__/useFragment.test.tsx +++ b/src/react/hooks/__tests__/useFragment.test.tsx @@ -7,7 +7,7 @@ import { within, } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { act } from "react-dom/test-utils"; +import { act } from "@testing-library/react"; import { UseFragmentOptions, useFragment } from "../useFragment"; import { MockedProvider } from "../../../testing"; diff --git a/src/react/hooks/__tests__/useLoadableQuery.test.tsx b/src/react/hooks/__tests__/useLoadableQuery.test.tsx index 520ec1edf98..a5e97ca52e8 100644 --- a/src/react/hooks/__tests__/useLoadableQuery.test.tsx +++ b/src/react/hooks/__tests__/useLoadableQuery.test.tsx @@ -55,6 +55,8 @@ import { useTrackRenders, } from "../../../testing/internal"; +const IS_REACT_19 = React.version.startsWith("19"); + afterEach(() => { jest.useRealTimers(); }); @@ -4594,6 +4596,8 @@ it('does not suspend deferred queries with partial data in the cache and using a }); it("throws when calling loadQuery on first render", async () => { + // We don't provide this functionality with React 19 anymore since it requires internals access + if (IS_REACT_19) return; using _consoleSpy = spyOnConsole("error"); const { query, mocks } = useSimpleQueryCase(); @@ -4613,6 +4617,8 @@ it("throws when calling loadQuery on first render", async () => { }); it("throws when calling loadQuery on subsequent render", async () => { + // We don't provide this functionality with React 19 anymore since it requires internals access + if (React.version.startsWith("19")) return; using _consoleSpy = spyOnConsole("error"); const { query, mocks } = useSimpleQueryCase(); diff --git a/src/react/hooks/__tests__/useMutation.test.tsx b/src/react/hooks/__tests__/useMutation.test.tsx index cbabe673071..452b1ad77de 100644 --- a/src/react/hooks/__tests__/useMutation.test.tsx +++ b/src/react/hooks/__tests__/useMutation.test.tsx @@ -1,7 +1,7 @@ import React, { useEffect } from "react"; import { GraphQLError } from "graphql"; import gql from "graphql-tag"; -import { act } from "react-dom/test-utils"; +import { act } from "@testing-library/react"; import { render, waitFor, screen, renderHook } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import fetchMock from "fetch-mock"; diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 457a6fb6fed..f900f61bbda 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -1,7 +1,7 @@ import React, { Fragment, ReactNode, useEffect, useRef, useState } from "react"; import { DocumentNode, GraphQLError } from "graphql"; import gql from "graphql-tag"; -import { act } from "react-dom/test-utils"; +import { act } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { render, screen, waitFor, renderHook } from "@testing-library/react"; import { @@ -35,6 +35,8 @@ import { import { useApolloClient } from "../useApolloClient"; import { useLazyQuery } from "../useLazyQuery"; +const IS_REACT_19 = React.version.startsWith("19"); + describe("useQuery Hook", () => { describe("General use", () => { it("should handle a simple query", async () => { @@ -1557,7 +1559,33 @@ describe("useQuery Hook", () => { function checkObservableQueries(expectedLinkCount: number) { const obsQueries = client.getObservableQueries("all"); - expect(obsQueries.size).toBe(2); + /* +This is due to a timing change in React 19 + +In React 18, you observe this pattern: + + 1. render + 2. useState initializer + 3. component continues to render with first state + 4. strictMode: render again + 5. strictMode: call useState initializer again + 6. component continues to render with second state + +now, in React 19 it looks like this: + + 1. render + 2. useState initializer + 3. strictMode: call useState initializer again + 4. component continues to render with one of these two states + 5. strictMode: render again + 6. component continues to render with the same state as during the first render + +Since useQuery breaks the rules of React and mutably creates an ObservableQuery on the state during render if none is present, React 18 did create two, while React 19 only creates one. + +This is pure coincidence though, and the useQuery rewrite that doesn't break the rules of hooks as much and creates the ObservableQuery as part of the state initializer will end up with behaviour closer to the old React 18 behaviour again. + +*/ + expect(obsQueries.size).toBe(IS_REACT_19 ? 1 : 2); const activeSet = new Set(); const inactiveSet = new Set(); @@ -1578,7 +1606,7 @@ describe("useQuery Hook", () => { } }); expect(activeSet.size).toBe(1); - expect(inactiveSet.size).toBe(1); + expect(inactiveSet.size).toBe(obsQueries.size - activeSet.size); } checkObservableQueries(1); diff --git a/src/react/hooks/__tests__/useReactiveVar.test.tsx b/src/react/hooks/__tests__/useReactiveVar.test.tsx index 3c5e8afdbf3..8979f9bbd32 100644 --- a/src/react/hooks/__tests__/useReactiveVar.test.tsx +++ b/src/react/hooks/__tests__/useReactiveVar.test.tsx @@ -6,6 +6,7 @@ import { makeVar } from "../../../core"; import { useReactiveVar } from "../useReactiveVar"; const IS_REACT_18 = React.version.startsWith("18"); +const IS_REACT_19 = React.version.startsWith("19"); describe("useReactiveVar Hook", () => { it("works with one component", async () => { @@ -277,7 +278,7 @@ describe("useReactiveVar Hook", () => { ); await waitFor(() => { - if (IS_REACT_18) { + if (IS_REACT_18 || IS_REACT_19) { expect(mock).toHaveBeenCalledTimes(3); expect(mock).toHaveBeenNthCalledWith(1, 0); expect(mock).toHaveBeenNthCalledWith(2, 0); diff --git a/src/react/hooks/__tests__/useSuspenseQuery.test.tsx b/src/react/hooks/__tests__/useSuspenseQuery.test.tsx index 121ae749493..31855bf83a4 100644 --- a/src/react/hooks/__tests__/useSuspenseQuery.test.tsx +++ b/src/react/hooks/__tests__/useSuspenseQuery.test.tsx @@ -9591,9 +9591,14 @@ describe("useSuspenseQuery", () => { await act(() => user.type(input, "ab")); - await waitFor(() => { - expect(screen.getByTestId("result")).toHaveTextContent("ab"); - }); + await waitFor( + () => { + expect(screen.getByTestId("result")).toHaveTextContent("ab"); + }, + { + timeout: 10000, + } + ); await act(() => user.type(input, "c")); @@ -9612,7 +9617,7 @@ describe("useSuspenseQuery", () => { await waitFor(() => { expect(screen.getByTestId("result")).toHaveTextContent("abc"); }); - }); + }, 10000); it("works with startTransition to change variables", async () => { type Variables = { diff --git a/src/react/hooks/internal/__tests__/useRenderGuard.test.tsx b/src/react/hooks/internal/__tests__/useRenderGuard.test.tsx index 0bf53ed8ab5..ff27fb82a3c 100644 --- a/src/react/hooks/internal/__tests__/useRenderGuard.test.tsx +++ b/src/react/hooks/internal/__tests__/useRenderGuard.test.tsx @@ -5,8 +5,11 @@ import { render, waitFor } from "@testing-library/react"; import { withCleanup } from "../../../../testing/internal"; const UNDEF = {}; +const IS_REACT_19 = React.version.startsWith("19"); it("returns a function that returns `true` if called during render", () => { + // We don't provide this functionality with React 19 anymore since it requires internals access + if (IS_REACT_19) return; let result: boolean | typeof UNDEF = UNDEF; function TestComponent() { const calledDuringRender = useRenderGuard(); diff --git a/src/testing/internal/profile/profile.tsx b/src/testing/internal/profile/profile.tsx index b9e82619534..d1c7731ec2a 100644 --- a/src/testing/internal/profile/profile.tsx +++ b/src/testing/internal/profile/profile.tsx @@ -434,13 +434,20 @@ export function profileHook( ); } -function resolveHookOwner(): React.ComponentType | undefined { +function resolveR18HookOwner(): React.ComponentType | undefined { return (React as any).__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED ?.ReactCurrentOwner?.current?.elementType; } +function resolveR19HookOwner(): React.ComponentType | undefined { + return ( + React as any + ).__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE?.A?.getOwner() + .elementType; +} + export function useTrackRenders({ name }: { name?: string } = {}) { - const component = name || resolveHookOwner(); + const component = name || resolveR18HookOwner() || resolveR19HookOwner(); if (!component) { throw new Error( diff --git a/src/testing/react/__tests__/mockSubscriptionLink.test.tsx b/src/testing/react/__tests__/mockSubscriptionLink.test.tsx index 0515e45cb0a..8b26aea0dd3 100644 --- a/src/testing/react/__tests__/mockSubscriptionLink.test.tsx +++ b/src/testing/react/__tests__/mockSubscriptionLink.test.tsx @@ -9,6 +9,7 @@ import { ApolloProvider } from "../../../react/context"; import { useSubscription } from "../../../react/hooks"; const IS_REACT_18 = React.version.startsWith("18"); +const IS_REACT_19 = React.version.startsWith("19"); describe("mockSubscriptionLink", () => { it("should work with multiple subscribers to the same mock websocket", async () => { @@ -64,7 +65,7 @@ describe("mockSubscriptionLink", () => { ); - const numRenders = IS_REACT_18 ? 2 : results.length + 1; + const numRenders = IS_REACT_18 || IS_REACT_19 ? 2 : results.length + 1; // automatic batching in React 18 means we only see 2 renders vs. 5 in v17 await waitFor( From 08dbc02c3f3ad76954f02af7354dc4cb715c5c13 Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Wed, 12 Jun 2024 10:43:23 +0200 Subject: [PATCH 07/15] use circleci `-browsers` image to save some install time (#11889) --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ff7ac58f270..f1aa7d88d82 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -73,7 +73,7 @@ jobs: react: type: string docker: - - image: cimg/node:22.2.0 + - image: cimg/node:22.2.0-browsers steps: - checkout - attach_workspace: From 6536369cf213469d20d15b779c344268d70fecd5 Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Wed, 12 Jun 2024 11:42:37 +0200 Subject: [PATCH 08/15] enable `react-hooks` lint rules (#11511) * enable `react-hooks` lint rules * Clean up Prettier, Size-limit, and Api-Extractor * update eslint rule * different type casting to not break lint rule parsing * fix up useMutation + lifecycle test * Clean up Prettier, Size-limit, and Api-Extractor * avoid reading/writing ref in render * fix up useLazyQuery * Clean up Prettier, Size-limit, and Api-Extractor * fix up another test doing a mutation in render * more useQuery cleanup * Clean up Prettier, Size-limit, and Api-Extractor * ignore rule of hook for context access * undo changes that were moved into separate PRs * Clean up Prettier, Size-limit, and Api-Extractor * almost full rewrite of the `useSubscription` hook * Clean up Prettier, Size-limit, and Api-Extractor * ignore any rule violation lint warnings in useSubscription and useQuery * changeset * rename patch * also add "eslint-plugin-react-compiler" rules --------- Co-authored-by: phryneas --- .changeset/famous-camels-rescue.md | 5 + .eslintrc | 3 + package-lock.json | 875 +++++++++++++----- package.json | 2 + patches/eslint-plugin-react-hooks+4.6.2.patch | 28 + src/react/hooks/internal/useRenderGuard.ts | 1 + src/react/hooks/useLoadableQuery.ts | 11 +- src/react/hooks/useQuery.ts | 6 + src/react/hooks/useQueryRefHandlers.ts | 4 + src/react/hooks/useReadQuery.ts | 6 +- src/react/hooks/useSubscription.ts | 4 + src/react/hooks/useSuspenseQuery.ts | 14 +- src/react/hooks/useSyncExternalStore.ts | 4 + 13 files changed, 738 insertions(+), 225 deletions(-) create mode 100644 .changeset/famous-camels-rescue.md create mode 100644 patches/eslint-plugin-react-hooks+4.6.2.patch diff --git a/.changeset/famous-camels-rescue.md b/.changeset/famous-camels-rescue.md new file mode 100644 index 00000000000..fbf8b08722b --- /dev/null +++ b/.changeset/famous-camels-rescue.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +`useLoadableQuery`: ensure that `loadQuery` is updated if the ApolloClient instance changes diff --git a/.eslintrc b/.eslintrc index dccf775414b..b4d6d6f5363 100644 --- a/.eslintrc +++ b/.eslintrc @@ -23,10 +23,13 @@ { "files": ["**/*.ts", "**/*.tsx"], "excludedFiles": ["**/__tests__/**/*.*", "*.d.ts"], + "extends": ["plugin:react-hooks/recommended"], "parserOptions": { "project": "./tsconfig.json" }, + "plugins": ["eslint-plugin-react-compiler"], "rules": { + "react-compiler/react-compiler": "error", "@typescript-eslint/consistent-type-imports": [ "error", { diff --git a/package-lock.json b/package-lock.json index 9e67a4ec4fb..5e8c0ddd816 100644 --- a/package-lock.json +++ b/package-lock.json @@ -67,6 +67,8 @@ "eslint-import-resolver-typescript": "3.6.1", "eslint-plugin-import": "npm:@phryneas/eslint-plugin-import@2.27.5-pr.2813.2817.199971c", "eslint-plugin-local-rules": "2.0.1", + "eslint-plugin-react-compiler": "^0.0.0-experimental-c8b3f72-20240517", + "eslint-plugin-react-hooks": "4.6.2", "eslint-plugin-testing-library": "6.2.2", "expect-type": "0.19.0", "fetch-mock": "9.11.0", @@ -269,78 +271,43 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.6.tgz", + "integrity": "sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.6", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.6.tgz", + "integrity": "sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", - "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.6.tgz", + "integrity": "sha512-qAHSfAdVyFmIvl0VHELib8xar7ONuSHrE2hLnsaWkYNTI68dmi1x8GYDhJjMI/e7XWal9QBlZkwbOnkcw7Z8gQ==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.7", - "@babel/parser": "^7.23.6", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6", + "@babel/code-frame": "^7.24.6", + "@babel/generator": "^7.24.6", + "@babel/helper-compilation-targets": "^7.24.6", + "@babel/helper-module-transforms": "^7.24.6", + "@babel/helpers": "^7.24.6", + "@babel/parser": "^7.24.6", + "@babel/template": "^7.24.6", + "@babel/traverse": "^7.24.6", + "@babel/types": "^7.24.6", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -355,6 +322,18 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/@babel/parser": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.6.tgz", + "integrity": "sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/core/node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -362,14 +341,14 @@ "dev": true }, "node_modules/@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.6.tgz", + "integrity": "sha512-S7m4eNa6YAPJRHmKsLHIDJhNAGNKoWNiWefz1MBbpnt8g9lvMDl1hir4P9bo/57bQEmuwEhnRU/AMWsD0G/Fbg==", "dev": true, "dependencies": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.24.6", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -377,23 +356,35 @@ } }, "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", + "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", - "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.6.tgz", + "integrity": "sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-validator-option": "^7.23.5", + "@babel/compat-data": "^7.24.6", + "@babel/helper-validator-option": "^7.24.6", "browserslist": "^4.22.2", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -417,63 +408,98 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.6.tgz", + "integrity": "sha512-djsosdPJVZE6Vsw3kk7IPRWethP94WHGOhQTc67SNXE0ZzMhHgALw8iGmYS0TD1bbMM0VDROy43od7/hN6WYcA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.6", + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-function-name": "^7.24.6", + "@babel/helper-member-expression-to-functions": "^7.24.6", + "@babel/helper-optimise-call-expression": "^7.24.6", + "@babel/helper-replace-supers": "^7.24.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6", + "@babel/helper-split-export-declaration": "^7.24.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz", + "integrity": "sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.6.tgz", + "integrity": "sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==", "dev": true, "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" + "@babel/template": "^7.24.6", + "@babel/types": "^7.24.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.6.tgz", + "integrity": "sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.6.tgz", + "integrity": "sha512-OTsCufZTxDUsv2/eDXanw/mUZHWOxSbEmC3pP8cgjcy5rgeVPWWMStnv274DV60JtHxTk0adT0QrCzC4M9NWGg==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.6.tgz", + "integrity": "sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==", "dev": true, "dependencies": { - "@babel/types": "^7.22.15" + "@babel/types": "^7.24.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.6.tgz", + "integrity": "sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-module-imports": "^7.24.6", + "@babel/helper-simple-access": "^7.24.6", + "@babel/helper-split-export-declaration": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.6" }, "engines": { "node": ">=6.9.0" @@ -482,6 +508,18 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.6.tgz", + "integrity": "sha512-3SFDJRbx7KuPRl8XDUr8O7GAEB8iGyWPjLKJh/ywP/Iy9WOmEfMrsWbaZpvBu2HSYn4KQygIsz0O7m8y10ncMA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-plugin-utils": { "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", @@ -491,80 +529,109 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.6.tgz", + "integrity": "sha512-mRhfPwDqDpba8o1F8ESxsEkJMQkUF8ZIWrAc0FtWhxnjfextxMWxr22RtFizxxSYLjVHDeMgVsRq8BBZR2ikJQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-member-expression-to-functions": "^7.24.6", + "@babel/helper-optimise-call-expression": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.6.tgz", + "integrity": "sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.6.tgz", + "integrity": "sha512-jhbbkK3IUKc4T43WadP96a27oYti9gEf1LdyGSP2rHGH77kwLwfhO7TgwnWvxxQVmke0ImmCSS47vcuxEMGD3Q==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", + "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.6.tgz", + "integrity": "sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.6.tgz", + "integrity": "sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.6.tgz", + "integrity": "sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.7.tgz", - "integrity": "sha512-6AMnjCoC8wjqBzDHkuqpa7jAKwvMo4dC+lr/TFBz+ucfulO1XMpDnwWPGBNwClOKZ8h6xn5N81W/R5OrcKtCbQ==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.6.tgz", + "integrity": "sha512-V2PI+NqnyFu1i0GyTd/O/cTpxzQCYioSkUIRmgo7gFEHKKCg5w46+r/A6WeUR1+P3TeQ49dspGPNd/E3n9AnnA==", "dev": true, "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6" + "@babel/template": "^7.24.6", + "@babel/types": "^7.24.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.6.tgz", + "integrity": "sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.6", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -617,6 +684,23 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", @@ -807,33 +891,45 @@ } }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.6.tgz", + "integrity": "sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.24.6", + "@babel/parser": "^7.24.6", + "@babel/types": "^7.24.6" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/template/node_modules/@babel/parser": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.6.tgz", + "integrity": "sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/traverse": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", - "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.6", - "@babel/types": "^7.23.6", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.6.tgz", + "integrity": "sha512-OsNjaJwT9Zn8ozxcfoBc+RaHdj3gFmCmYoQLUII1o6ZrUwku0BMg80FoOTPx+Gi6XhcQxAYE4xyjPTo4SxEQqw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.6", + "@babel/generator": "^7.24.6", + "@babel/helper-environment-visitor": "^7.24.6", + "@babel/helper-function-name": "^7.24.6", + "@babel/helper-hoist-variables": "^7.24.6", + "@babel/helper-split-export-declaration": "^7.24.6", + "@babel/parser": "^7.24.6", + "@babel/types": "^7.24.6", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -841,14 +937,26 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/traverse/node_modules/@babel/parser": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.6.tgz", + "integrity": "sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/types": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", - "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz", + "integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.6", "to-fast-properties": "^2.0.0" }, "engines": { @@ -2411,19 +2519,29 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, + "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", @@ -2434,9 +2552,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", - "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "engines": { "node": ">=6.0.0" @@ -4083,6 +4201,19 @@ "dequal": "^2.0.3" } }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-includes": { "version": "3.1.6", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", @@ -4166,6 +4297,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", @@ -4202,6 +4354,21 @@ "node": ">= 4.0.0" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -4386,9 +4553,9 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", - "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "dev": true, "funding": [ { @@ -4405,8 +4572,8 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001565", - "electron-to-chromium": "^1.4.601", + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" }, @@ -4563,9 +4730,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001576", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz", - "integrity": "sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==", + "version": "1.0.30001623", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001623.tgz", + "integrity": "sha512-X/XhAVKlpIxWPpgRTnlgZssJrF0m6YtRA0QDWgsBNT12uZM6LPRydR7ip405Y3t1LamD8cP2TZFEDZFBf5ApcA==", "dev": true, "funding": [ { @@ -5313,9 +5480,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.623", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.623.tgz", - "integrity": "sha512-lKoz10iCYlP1WtRYdh5MvocQPWVRoI7ysp6qf18bmeBgR8abE6+I2CsfyNKztRDZvhdWc+krKT6wS7Neg8sw3A==", + "version": "1.4.783", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.783.tgz", + "integrity": "sha512-bT0jEz/Xz1fahQpbZ1D7LgmPYZ3iHVY39NcWWro1+hA2IvjiPeaXtfSqrQ+nXjApMvQRE2ASt1itSLRrebHMRQ==", "dev": true }, "node_modules/emittery": { @@ -5389,35 +5556,50 @@ } }, "node_modules/es-abstract": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", - "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", "get-symbol-description": "^1.0.0", - "has": "^1.0.3", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", + "hasown": "^2.0.0", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", + "object-inspect": "^1.13.1", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -5426,6 +5608,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-set-tostringtag": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-shim-unscopables": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", @@ -5534,9 +5730,9 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, "engines": { "node": ">=6" @@ -5758,6 +5954,38 @@ "integrity": "sha512-AJhGd+GcI5r2dbjiGPixM8jnBl0XFxqoVbqzwKbYz+nTk+Cj5dNE3+OlhC176bl5r25KsGsIthLi1VqIW5Ga+A==", "dev": true }, + "node_modules/eslint-plugin-react-compiler": { + "version": "0.0.0-experimental-c8b3f72-20240517", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-compiler/-/eslint-plugin-react-compiler-0.0.0-experimental-c8b3f72-20240517.tgz", + "integrity": "sha512-cxUTFNMEKiLX6uFaRfrr2GHnB7KUHDMYLjEGzDec82ka6WyBCHg906nGSf3JvVnQKHaBDfUk7Mmv/JMvdgQB8Q==", + "dev": true, + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "hermes-parser": "^0.20.1", + "zod": "^3.22.4", + "zod-validation-error": "^3.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.0.0 || >= 18.0.0" + }, + "peerDependencies": { + "eslint": ">=7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, "node_modules/eslint-plugin-testing-library": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-6.2.2.tgz", @@ -6494,6 +6722,15 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/foreground-child": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", @@ -6580,15 +6817,15 @@ } }, "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" }, "engines": { "node": ">= 0.4" @@ -6755,6 +6992,21 @@ "node": ">=4" } }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -6945,6 +7197,21 @@ "node": ">= 0.4" } }, + "node_modules/hermes-estree": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.20.1.tgz", + "integrity": "sha512-SQpZK4BzR48kuOg0v4pb3EAGNclzIlqMj3Opu/mu7bbAoFw6oig6cEt/RAi0zTFW/iW6Iz9X9ggGuZTAZ/yZHg==", + "dev": true + }, + "node_modules/hermes-parser": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.20.1.tgz", + "integrity": "sha512-BL5P83cwCogI8D7rrDCgsFY0tdYUtmFP9XaXtl2IQjC+2Xo+4okjfXintlTxcIwl4qeGddEl28Z11kbVIw0aNA==", + "dev": true, + "dependencies": { + "hermes-estree": "0.20.1" + } + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -7141,6 +7408,20 @@ "node": ">= 0.4" } }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -7467,6 +7748,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -9511,9 +9807,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9984,9 +10280,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", "dev": true }, "node_modules/picomatch": { @@ -10031,6 +10327,15 @@ "node": ">=8" } }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/preferred-pm": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/preferred-pm/-/preferred-pm-3.0.3.tgz", @@ -10177,13 +10482,13 @@ } }, "node_modules/prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", - "react-is": "^16.8.1" + "react-is": "^16.13.1" } }, "node_modules/pseudomap": { @@ -10383,9 +10688,9 @@ } }, "node_modules/react-is": { - "version": "16.13.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.0.tgz", - "integrity": "sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA==" + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/read-pkg": { "version": "5.2.0", @@ -10829,6 +11134,24 @@ "tslib": "^2.1.0" } }, + "node_modules/safe-array-concat": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", + "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -11417,29 +11740,46 @@ "node": ">=8" } }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -12034,6 +12374,71 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typedoc": { "version": "0.25.0", "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.0.tgz", @@ -12144,9 +12549,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", + "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", "dev": true, "funding": [ { @@ -12163,8 +12568,8 @@ } ], "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.1.2", + "picocolors": "^1.0.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -12440,6 +12845,25 @@ "node": ">=8.15" } }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -12725,6 +13149,27 @@ "dependencies": { "zen-observable": "0.8.15" } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.3.0.tgz", + "integrity": "sha512-Syib9oumw1NTqEv4LT0e6U83Td9aVRk9iTXPUQr1otyV1PuXQKOvOwhMNqZIq5hluzHP2pMgnOmHEo7kPdI2mw==", + "dev": true, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.18.0" + } } } } diff --git a/package.json b/package.json index cb6168914be..a36db028e60 100644 --- a/package.json +++ b/package.json @@ -148,6 +148,8 @@ "eslint-import-resolver-typescript": "3.6.1", "eslint-plugin-import": "npm:@phryneas/eslint-plugin-import@2.27.5-pr.2813.2817.199971c", "eslint-plugin-local-rules": "2.0.1", + "eslint-plugin-react-compiler": "0.0.0-experimental-c8b3f72-20240517", + "eslint-plugin-react-hooks": "4.6.2", "eslint-plugin-testing-library": "6.2.2", "expect-type": "0.19.0", "fetch-mock": "9.11.0", diff --git a/patches/eslint-plugin-react-hooks+4.6.2.patch b/patches/eslint-plugin-react-hooks+4.6.2.patch new file mode 100644 index 00000000000..a8356f0f3df --- /dev/null +++ b/patches/eslint-plugin-react-hooks+4.6.2.patch @@ -0,0 +1,28 @@ +diff --git a/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js b/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js +index 441442f..d1ec5dc 100644 +--- a/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js ++++ b/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js +@@ -905,7 +905,7 @@ var ExhaustiveDeps = { + var _callee = callee, + name = _callee.name; + +- if (name === 'useRef' && id.type === 'Identifier') { ++ if ((name === 'useRef' || name === "useLazyRef") && id.type === 'Identifier') { + // useRef() return value is stable. + return true; + } else if (name === 'useState' || name === 'useReducer') { +diff --git a/node_modules/eslint-plugin-react-hooks/index.js b/node_modules/eslint-plugin-react-hooks/index.js +index 0e91baf..7e86d46 100644 +--- a/node_modules/eslint-plugin-react-hooks/index.js ++++ b/node_modules/eslint-plugin-react-hooks/index.js +@@ -1,9 +1,3 @@ + 'use strict'; + +-// TODO: this doesn't make sense for an ESLint rule. +-// We need to fix our build process to not create bundles for "raw" packages like this. +-if (process.env.NODE_ENV === 'production') { +- module.exports = require('./cjs/eslint-plugin-react-hooks.production.min.js'); +-} else { +- module.exports = require('./cjs/eslint-plugin-react-hooks.development.js'); +-} ++module.exports = require('./cjs/eslint-plugin-react-hooks.development.js'); diff --git a/src/react/hooks/internal/useRenderGuard.ts b/src/react/hooks/internal/useRenderGuard.ts index fbe341d56a9..2d5a798fc3c 100644 --- a/src/react/hooks/internal/useRenderGuard.ts +++ b/src/react/hooks/internal/useRenderGuard.ts @@ -12,6 +12,7 @@ Relay does this too, so we hope this is safe. https://github.com/facebook/relay/blob/8651fbca19adbfbb79af7a3bc40834d105fd7747/packages/react-relay/relay-hooks/loadQuery.js#L90-L98 */ export function useRenderGuard() { + // eslint-disable-next-line react-compiler/react-compiler RenderDispatcher = getRenderDispatcher(); return React.useCallback(() => { diff --git a/src/react/hooks/useLoadableQuery.ts b/src/react/hooks/useLoadableQuery.ts index 01a95a630ec..15d1e2a7e56 100644 --- a/src/react/hooks/useLoadableQuery.ts +++ b/src/react/hooks/useLoadableQuery.ts @@ -245,12 +245,19 @@ export function useLoadableQuery< setQueryRef(wrapQueryRef(queryRef)); }, - [query, queryKey, suspenseCache, watchQueryOptions, calledDuringRender] + [ + query, + queryKey, + suspenseCache, + watchQueryOptions, + calledDuringRender, + client, + ] ); const reset: ResetFunction = React.useCallback(() => { setQueryRef(null); - }, [queryRef]); + }, []); return [loadQuery, queryRef, { fetchMore, refetch, reset }]; } diff --git a/src/react/hooks/useQuery.ts b/src/react/hooks/useQuery.ts index c4ed41193e2..61ca66527b6 100644 --- a/src/react/hooks/useQuery.ts +++ b/src/react/hooks/useQuery.ts @@ -230,13 +230,16 @@ class InternalState { // initialization, this.renderPromises is usually undefined (unless SSR is // happening), but that's fine as long as it has been initialized that way, // rather than left uninitialized. + // eslint-disable-next-line react-hooks/rules-of-hooks this.renderPromises = React.useContext(getApolloContext()).renderPromises; this.useOptions(options); const obsQuery = this.useObservableQuery(); + // eslint-disable-next-line react-hooks/rules-of-hooks const result = useSyncExternalStore( + // eslint-disable-next-line react-hooks/rules-of-hooks React.useCallback( (handleStoreChange) => { if (this.renderPromises) { @@ -307,7 +310,9 @@ class InternalState { // effectively passing this dependency array to that useEffect buried // inside useSyncExternalStore, as desired. obsQuery, + // eslint-disable-next-line react-hooks/exhaustive-deps this.renderPromises, + // eslint-disable-next-line react-hooks/exhaustive-deps this.client.disableNetworkFetches, ] ), @@ -533,6 +538,7 @@ class InternalState { this.observable || // Reuse this.observable if possible (and not SSR) this.client.watchQuery(this.getObsQueryOptions())); + // eslint-disable-next-line react-hooks/rules-of-hooks this.obsQueryFields = React.useMemo( () => ({ refetch: obsQuery.refetch.bind(obsQuery), diff --git a/src/react/hooks/useQueryRefHandlers.ts b/src/react/hooks/useQueryRefHandlers.ts index a62149360aa..95036eafcf3 100644 --- a/src/react/hooks/useQueryRefHandlers.ts +++ b/src/react/hooks/useQueryRefHandlers.ts @@ -59,6 +59,10 @@ export function useQueryRefHandlers< // client that's available to us at the current position in the React tree // that ApolloClient will then have the job to recreate a real queryRef from // the transported object + // This is just a context read - it's fine to do this conditionally. + // This hook wrapper also shouldn't be optimized by React Compiler. + // eslint-disable-next-line react-compiler/react-compiler + // eslint-disable-next-line react-hooks/rules-of-hooks : useApolloClient() )(queryRef); } diff --git a/src/react/hooks/useReadQuery.ts b/src/react/hooks/useReadQuery.ts index e3a9836b0b5..3d6ae811df6 100644 --- a/src/react/hooks/useReadQuery.ts +++ b/src/react/hooks/useReadQuery.ts @@ -52,6 +52,10 @@ export function useReadQuery( // client that's available to us at the current position in the React tree // that ApolloClient will then have the job to recreate a real queryRef from // the transported object + // This is just a context read - it's fine to do this conditionally. + // This hook wrapper also shouldn't be optimized by React Compiler. + // eslint-disable-next-line react-compiler/react-compiler + // eslint-disable-next-line react-hooks/rules-of-hooks : useApolloClient() )(queryRef); } @@ -85,7 +89,7 @@ function _useReadQuery( forceUpdate(); }); }, - [internalQueryRef] + [internalQueryRef, queryRef] ), getPromise, getPromise diff --git a/src/react/hooks/useSubscription.ts b/src/react/hooks/useSubscription.ts index 366ebfe97f4..0ba57c64346 100644 --- a/src/react/hooks/useSubscription.ts +++ b/src/react/hooks/useSubscription.ts @@ -204,6 +204,8 @@ export function useSubscription< } Object.assign(ref.current, { client, subscription, options }); + // eslint-disable-next-line react-compiler/react-compiler + // eslint-disable-next-line react-hooks/exhaustive-deps }, [client, subscription, options, canResetObservableRef.current]); React.useEffect(() => { @@ -271,6 +273,8 @@ export function useSubscription< subscription.unsubscribe(); }); }; + // eslint-disable-next-line react-compiler/react-compiler + // eslint-disable-next-line react-hooks/exhaustive-deps }, [observable]); return result; diff --git a/src/react/hooks/useSuspenseQuery.ts b/src/react/hooks/useSuspenseQuery.ts index 77159eb31f2..fe438ab6240 100644 --- a/src/react/hooks/useSuspenseQuery.ts +++ b/src/react/hooks/useSuspenseQuery.ts @@ -251,18 +251,18 @@ function _useSuspenseQuery< }, [queryRef.result]); const result = fetchPolicy === "standby" ? skipResult : __use(promise); - const fetchMore = React.useCallback( - ((options) => { + + const fetchMore = React.useCallback< + FetchMoreFunction + >( + (options) => { const promise = queryRef.fetchMore(options); setPromise([queryRef.key, queryRef.promise]); return promise; - }) satisfies FetchMoreFunction< - unknown, - OperationVariables - > as FetchMoreFunction, + }, [queryRef] - ); + ) as FetchMoreFunction; const refetch: RefetchFunction = React.useCallback( (variables) => { diff --git a/src/react/hooks/useSyncExternalStore.ts b/src/react/hooks/useSyncExternalStore.ts index adf4d059f7f..1cecbe90eac 100644 --- a/src/react/hooks/useSyncExternalStore.ts +++ b/src/react/hooks/useSyncExternalStore.ts @@ -81,6 +81,8 @@ export const useSyncExternalStore: RealUseSESHookType = // Force a re-render. forceUpdate({ inst }); } + // React Hook React.useLayoutEffect has a missing dependency: 'inst'. Either include it or remove the dependency array. + // eslint-disable-next-line react-hooks/exhaustive-deps }, [subscribe, value, getSnapshot]); } else { Object.assign(inst, { value, getSnapshot }); @@ -108,6 +110,8 @@ export const useSyncExternalStore: RealUseSESHookType = forceUpdate({ inst }); } }); + // React Hook React.useEffect has a missing dependency: 'inst'. Either include it or remove the dependency array. + // eslint-disable-next-line react-hooks/exhaustive-deps }, [subscribe]); return value; From 7fb7939edb7ca8f4273b75554f96ea9936731458 Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Wed, 12 Jun 2024 13:14:10 +0200 Subject: [PATCH 09/15] switch `useRenderGuard` to an approach not accessing React's internals (#11888) --- .changeset/brown-bikes-divide.md | 5 ++ .size-limits.json | 2 +- .../__tests__/useRenderGuard.test.tsx | 43 -------------- src/react/hooks/internal/useRenderGuard.ts | 56 +++++++++++++------ 4 files changed, 45 insertions(+), 61 deletions(-) create mode 100644 .changeset/brown-bikes-divide.md diff --git a/.changeset/brown-bikes-divide.md b/.changeset/brown-bikes-divide.md new file mode 100644 index 00000000000..8701c21eae9 --- /dev/null +++ b/.changeset/brown-bikes-divide.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +switch `useRenderGuard` to an approach not accessing React's internals diff --git a/.size-limits.json b/.size-limits.json index 4176d307cbb..5c28672b1f7 100644 --- a/.size-limits.json +++ b/.size-limits.json @@ -1,4 +1,4 @@ { - "dist/apollo-client.min.cjs": 39620, + "dist/apollo-client.min.cjs": 39561, "import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 32821 } diff --git a/src/react/hooks/internal/__tests__/useRenderGuard.test.tsx b/src/react/hooks/internal/__tests__/useRenderGuard.test.tsx index ff27fb82a3c..0f60cb58892 100644 --- a/src/react/hooks/internal/__tests__/useRenderGuard.test.tsx +++ b/src/react/hooks/internal/__tests__/useRenderGuard.test.tsx @@ -2,7 +2,6 @@ import React, { useEffect } from "rehackt"; import { useRenderGuard } from "../useRenderGuard"; import { render, waitFor } from "@testing-library/react"; -import { withCleanup } from "../../../../testing/internal"; const UNDEF = {}; const IS_REACT_19 = React.version.startsWith("19"); @@ -35,45 +34,3 @@ it("returns a function that returns `false` if called after render", async () => }); expect(result).toBe(false); }); - -function breakReactInternalsTemporarily() { - const R = React as unknown as { - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: any; - }; - const orig = R.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; - - R.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = {}; - return withCleanup({}, () => { - R.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = orig; - }); -} - -it("results in false negatives if React internals change", () => { - let result: boolean | typeof UNDEF = UNDEF; - function TestComponent() { - using _ = breakReactInternalsTemporarily(); - const calledDuringRender = useRenderGuard(); - result = calledDuringRender(); - return <>Test; - } - render(); - expect(result).toBe(false); -}); - -it("does not result in false positives if React internals change", async () => { - let result: boolean | typeof UNDEF = UNDEF; - function TestComponent() { - using _ = breakReactInternalsTemporarily(); - const calledDuringRender = useRenderGuard(); - useEffect(() => { - using _ = breakReactInternalsTemporarily(); - result = calledDuringRender(); - }); - return <>Test; - } - render(); - await waitFor(() => { - expect(result).not.toBe(UNDEF); - }); - expect(result).toBe(false); -}); diff --git a/src/react/hooks/internal/useRenderGuard.ts b/src/react/hooks/internal/useRenderGuard.ts index 2d5a798fc3c..ba101f109b7 100644 --- a/src/react/hooks/internal/useRenderGuard.ts +++ b/src/react/hooks/internal/useRenderGuard.ts @@ -1,23 +1,45 @@ import * as React from "rehackt"; -function getRenderDispatcher() { - return (React as any).__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED - ?.ReactCurrentDispatcher?.current; -} - -let RenderDispatcher: unknown = null; +let Ctx: React.Context; -/* -Relay does this too, so we hope this is safe. -https://github.com/facebook/relay/blob/8651fbca19adbfbb79af7a3bc40834d105fd7747/packages/react-relay/relay-hooks/loadQuery.js#L90-L98 -*/ +function noop() {} export function useRenderGuard() { - // eslint-disable-next-line react-compiler/react-compiler - RenderDispatcher = getRenderDispatcher(); + if (!Ctx) { + // we want the intialization to be lazy because `createContext` would error on import in a RSC + Ctx = React.createContext(null); + } + + return React.useCallback( + /** + * @returns true if the hook was called during render + */ () => { + const orig = console.error; + try { + console.error = noop; - return React.useCallback(() => { - return ( - RenderDispatcher != null && RenderDispatcher === getRenderDispatcher() - ); - }, []); + /** + * `useContext` can be called conditionally during render, so this is safe. + * (Also, during render we would want to throw as a reaction to this anyways, so it + * wouldn't even matter if we got the order of hooks mixed up...) + * + * They cannot however be called outside of Render, and that's what we're testing here. + * + * Different versions of React have different behaviour on an invalid hook call: + * + * React 16.8 - 17: throws an error + * https://github.com/facebook/react/blob/2b93d686e359c7afa299e2ec5cf63160a32a1155/packages/react/src/ReactHooks.js#L18-L26 + * + * React 18 & 19: `console.error` in development, then `resolveDispatcher` returns `null` and a member access on `null` throws. + * https://github.com/facebook/react/blob/58e8304483ebfadd02a295339b5e9a989ac98c6e/packages/react/src/ReactHooks.js#L28-L35 + */ + React["useContext" /* hide this from the linter */](Ctx); + return true; + } catch (e) { + return false; + } finally { + console.error = orig; + } + }, + [] + ); } From 3e5e7701adaa09d0aa629aeb1c04beb7572fb5bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Jun 2024 11:47:11 -0600 Subject: [PATCH 10/15] chore(deps-dev): bump braces from 3.0.2 to 3.0.3 (#11887) Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3. - [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3) --- updated-dependencies: - dependency-name: braces dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5e8c0ddd816..0684be839e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -67,7 +67,7 @@ "eslint-import-resolver-typescript": "3.6.1", "eslint-plugin-import": "npm:@phryneas/eslint-plugin-import@2.27.5-pr.2813.2817.199971c", "eslint-plugin-local-rules": "2.0.1", - "eslint-plugin-react-compiler": "^0.0.0-experimental-c8b3f72-20240517", + "eslint-plugin-react-compiler": "0.0.0-experimental-c8b3f72-20240517", "eslint-plugin-react-hooks": "4.6.2", "eslint-plugin-testing-library": "6.2.2", "expect-type": "0.19.0", @@ -4526,12 +4526,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -6625,9 +6625,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" From 1aca223b8da3fe02bbd38379d6a211844e0b40bb Mon Sep 17 00:00:00 2001 From: Maria Elisabeth Schreiber Date: Wed, 12 Jun 2024 11:48:12 -0600 Subject: [PATCH 11/15] Update router terminology (#11885) --- docs/source/api/link/persisted-queries.mdx | 10 +++++----- docs/source/data/defer.mdx | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/api/link/persisted-queries.mdx b/docs/source/api/link/persisted-queries.mdx index e2b4a35da86..4d71bfbf25d 100644 --- a/docs/source/api/link/persisted-queries.mdx +++ b/docs/source/api/link/persisted-queries.mdx @@ -31,21 +31,21 @@ Using persisted queries for safelisting has the following requirements: - Apollo Client Web (v3.7.0+) - The [`@apollo/generate-persisted-query-manifest` package](https://www.npmjs.com/package/@apollo/generate-persisted-query-manifest) - The [`@apollo/persisted-query-lists` package](https://www.npmjs.com/package/@apollo/persisted-query-lists) -- [Apollo Router](/router) (v1.25.0+) +- [GraphOS Router](/router) (v1.25.0+) - [GraphOS Enterprise plan](/graphos/enterprise/) -You can use APQ with the following versions of Apollo Client Web, Apollo Server, and Apollo Router: +You can use APQ with the following versions of Apollo Client Web, Apollo Server, and Apollo Router Core: - Apollo Client Web (v3.2.0+) - [Apollo Server](/apollo-server/) (v1.0.0+) -- [Apollo Router](/router) (v0.1.0+) +- [Apollo Router Core](/router) (v0.1.0+) -> **Note:** You can use _either_ Apollo Server _or_ Apollo Router for APQs. They don't need to be used together. +> **Note:** You can use _either_ Apollo Server _or_ Apollo Router Core for APQs. They don't need to be used together. ## 1. Generate operation manifests > **This step is only required for persisted queries, not APQ.** -An operation manifest acts as a safelist the [Apollo Router](/router/) can check incoming requests against. +An operation manifest acts as a safelist the [GraphOS Router](/router/) can check incoming requests against. You can generate the manifest using the [`@apollo/generate-persisted-query-manifest`](https://www.npmjs.com/package/@apollo/generate-persisted-query-manifest) package: 1. Install the [`@apollo/generate-persisted-query-manifest`](https://www.npmjs.com/package/@apollo/generate-persisted-query-manifest) package as a dev dependency: diff --git a/docs/source/data/defer.mdx b/docs/source/data/defer.mdx index 908ada61c6b..6b43736590b 100644 --- a/docs/source/data/defer.mdx +++ b/docs/source/data/defer.mdx @@ -7,7 +7,7 @@ description: Receive query response data incrementally Beginning with version `3.7.0`, Apollo Client provides preview support for [the `@defer` directive](https://github.com/graphql/graphql-wg/blob/main/rfcs/DeferStream.md). This directive enables your queries to receive data for specific fields _incrementally_, instead of receiving all field data at the same time. This is helpful whenever some fields in a query take much longer to resolve than others. -> For a query to defer fields successfully, the queried endpoint must _also_ support the `@defer` directive. Entity-based `@defer` support is also at the General Availability stage in [Apollo Router](/router/executing-operations/defer-support/) and is compatible with all [federation-compatible subgraph libraries](/federation/building-supergraphs/supported-subgraphs/). +> For a query to defer fields successfully, the queried endpoint must _also_ support the `@defer` directive. Entity-based `@defer` support is also at the General Availability stage in [GraphOS Router](/router/executing-operations/defer-support/) and is compatible with all [federation-compatible subgraph libraries](/federation/building-supergraphs/supported-subgraphs/). ## Example From 3d164ea16c17d271f6fa9e5ad8f013623eec23a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavol=20Luk=C4=8Da?= Date: Wed, 12 Jun 2024 20:08:48 +0200 Subject: [PATCH 12/15] fix: graphQLErrors in Error Link if networkError.result is an empty string (#11329) --- .changeset/loud-hounds-heal.md | 5 +++++ src/link/error/__tests__/index.ts | 34 +++++++++++++++++++++++++++++++ src/link/error/index.ts | 7 ++++--- 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 .changeset/loud-hounds-heal.md diff --git a/.changeset/loud-hounds-heal.md b/.changeset/loud-hounds-heal.md new file mode 100644 index 00000000000..f80a0a34105 --- /dev/null +++ b/.changeset/loud-hounds-heal.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +Fix graphQLErrors in Error Link if networkError.result is an empty string diff --git a/src/link/error/__tests__/index.ts b/src/link/error/__tests__/index.ts index a6189ee3b87..5e886ff58d3 100644 --- a/src/link/error/__tests__/index.ts +++ b/src/link/error/__tests__/index.ts @@ -145,6 +145,40 @@ describe("error handling", () => { }); } ); + itAsync( + "sets graphQLErrors to undefined if networkError.result is an empty string", + (resolve, reject) => { + const query = gql` + query Foo { + foo { + bar + } + } + `; + + let called: boolean; + const errorLink = onError(({ graphQLErrors }) => { + expect(graphQLErrors).toBeUndefined(); + called = true; + }); + + const mockLink = new ApolloLink((operation) => { + return new Observable((obs) => { + const response = { status: 500, ok: false } as Response; + throwServerError(response, "", "app is crashing"); + }); + }); + + const link = errorLink.concat(mockLink); + + execute(link, { query }).subscribe({ + error: (e) => { + expect(called).toBe(true); + resolve(); + }, + }); + } + ); itAsync("completes if no errors", (resolve, reject) => { const query = gql` { diff --git a/src/link/error/index.ts b/src/link/error/index.ts index 7122ff792e8..00b0701ab6f 100644 --- a/src/link/error/index.ts +++ b/src/link/error/index.ts @@ -60,9 +60,10 @@ export function onError(errorHandler: ErrorHandler): ApolloLink { networkError, //Network errors can return GraphQL errors on for example a 403 graphQLErrors: - networkError && - networkError.result && - networkError.result.errors, + (networkError && + networkError.result && + networkError.result.errors) || + void 0, forward, }); if (retriedResult) { From 5f5326bb629fd855e6c1dbfc6c8cc9c6dd9492ee Mon Sep 17 00:00:00 2001 From: Rishabh Chawla Date: Wed, 12 Jun 2024 23:43:58 +0530 Subject: [PATCH 13/15] docs: add graphql-tag-swc-plugin to performance docs (#11884) --- docs/source/performance/babel.md | 44 +++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/docs/source/performance/babel.md b/docs/source/performance/babel.md index 3fa6cde18d1..ba25ee62896 100644 --- a/docs/source/performance/babel.md +++ b/docs/source/performance/babel.md @@ -1,14 +1,15 @@ --- -title: Compiling queries with Babel +title: Compiling queries with Transpilers --- If you prefer co-locating your GraphQL queries in your Javascript files, you typically use the [graphql-tag](https://github.com/apollographql/graphql-tag) library to write them. That requires to process the query strings into a GraphQL AST, which will add to the startup time of your application, especially if you have many queries. -To avoid this runtime overhead, you can precompile your queries created with `graphql-tag` using [Babel](http://babeljs.io/). Here are two ways you can do this: +To avoid this runtime overhead, you can precompile your queries created with `graphql-tag` using transpilers like [Babel](http://babeljs.io/) and [SWC](https://swc.rs). Here are possible ways you can do this: 1. Using [babel-plugin-graphql-tag](#using-babel-plugin-graphql-tag) -2. Using [graphql-tag.macro](#using-graphql-tagmacro) -1. Using [ts-transform-graphql-tag](#using-ts-transform-graphql-tag) for TypeScript +2. Using [graphql-tag-swc-plugin](#using-graphql-tag-swc-plugin) +3. Using [graphql-tag.macro](#using-graphql-tagmacro) +4. Using [ts-transform-graphql-tag](#using-ts-transform-graphql-tag) for TypeScript If you prefer to keep your GraphQL code in separate files (`.graphql` or `.gql`) you can use [babel-plugin-import-graphql](https://github.com/detrohutt/babel-plugin-import-graphql). This plugin still uses `graphql-tag` under the hood, but transparently. You simply `import` your operations/fragments as if each were an export from your GraphQL file. This carries the same precompilation benefits as the above approaches. @@ -38,6 +39,41 @@ Then add the plugin in your `.babelrc` configuration file: And that's it! All the usages of `import gql from 'graphql-tag'` will be removed, and the calls to `gql` will be replaced by the compiled version. +## Using graphql-tag-swc-plugin + +This plugin is the same as [babel-plugin-graphql-tag](#using-babel-plugin-graphql-tag) but for [swc](https://swc.rs/), a fast rust based babel alternative. + +Install the plugin in your dev dependencies: + +``` +# with npm +npm install --save-dev graphql-tag-swc-plugin + +# or with yarn +yarn add --dev graphql-tag-swc-plugin +``` + +Then add the plugin in your `.swcrc` configuration file: + +``` +{ + jsc: { + experimental: { + plugins: [ + ["graphql-tag-swc-plugin", + { + importSources: ["@apollo/client", "graphql-tag"], + gqlTagIdentifiers: ["gql"] + }, + ], + ], + }, + }, +} +``` + +For more information on configuration and features, please checkout the [`graphql-tag-swc-plugin`](https://github.com/rishabh3112/graphql-tag-swc-plugin) documentation. + ## Using graphql-tag.macro This approach is a bit more explicit, since you change all your usages of `graphql-tag` for `graphql-tag.macro`, which exports a `gql` function that you can use the same way as the original one. This macro requires the [babel-macros](https://github.com/kentcdodds/babel-macros) plugin, which will do the same as the previous approach but only on the calls that come from the macro import, leaving regular calls to the `graphql-tag` library untouched. From e41580b590ffdc5ac11f31966852ad6fcfebad07 Mon Sep 17 00:00:00 2001 From: Maria Elisabeth Schreiber Date: Wed, 12 Jun 2024 12:16:27 -0600 Subject: [PATCH 14/15] Revert "Update router terminology (#11885)" (#11892) This reverts commit 1aca223b8da3fe02bbd38379d6a211844e0b40bb. --- docs/source/api/link/persisted-queries.mdx | 10 +++++----- docs/source/data/defer.mdx | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/api/link/persisted-queries.mdx b/docs/source/api/link/persisted-queries.mdx index 4d71bfbf25d..e2b4a35da86 100644 --- a/docs/source/api/link/persisted-queries.mdx +++ b/docs/source/api/link/persisted-queries.mdx @@ -31,21 +31,21 @@ Using persisted queries for safelisting has the following requirements: - Apollo Client Web (v3.7.0+) - The [`@apollo/generate-persisted-query-manifest` package](https://www.npmjs.com/package/@apollo/generate-persisted-query-manifest) - The [`@apollo/persisted-query-lists` package](https://www.npmjs.com/package/@apollo/persisted-query-lists) -- [GraphOS Router](/router) (v1.25.0+) +- [Apollo Router](/router) (v1.25.0+) - [GraphOS Enterprise plan](/graphos/enterprise/) -You can use APQ with the following versions of Apollo Client Web, Apollo Server, and Apollo Router Core: +You can use APQ with the following versions of Apollo Client Web, Apollo Server, and Apollo Router: - Apollo Client Web (v3.2.0+) - [Apollo Server](/apollo-server/) (v1.0.0+) -- [Apollo Router Core](/router) (v0.1.0+) +- [Apollo Router](/router) (v0.1.0+) -> **Note:** You can use _either_ Apollo Server _or_ Apollo Router Core for APQs. They don't need to be used together. +> **Note:** You can use _either_ Apollo Server _or_ Apollo Router for APQs. They don't need to be used together. ## 1. Generate operation manifests > **This step is only required for persisted queries, not APQ.** -An operation manifest acts as a safelist the [GraphOS Router](/router/) can check incoming requests against. +An operation manifest acts as a safelist the [Apollo Router](/router/) can check incoming requests against. You can generate the manifest using the [`@apollo/generate-persisted-query-manifest`](https://www.npmjs.com/package/@apollo/generate-persisted-query-manifest) package: 1. Install the [`@apollo/generate-persisted-query-manifest`](https://www.npmjs.com/package/@apollo/generate-persisted-query-manifest) package as a dev dependency: diff --git a/docs/source/data/defer.mdx b/docs/source/data/defer.mdx index 6b43736590b..908ada61c6b 100644 --- a/docs/source/data/defer.mdx +++ b/docs/source/data/defer.mdx @@ -7,7 +7,7 @@ description: Receive query response data incrementally Beginning with version `3.7.0`, Apollo Client provides preview support for [the `@defer` directive](https://github.com/graphql/graphql-wg/blob/main/rfcs/DeferStream.md). This directive enables your queries to receive data for specific fields _incrementally_, instead of receiving all field data at the same time. This is helpful whenever some fields in a query take much longer to resolve than others. -> For a query to defer fields successfully, the queried endpoint must _also_ support the `@defer` directive. Entity-based `@defer` support is also at the General Availability stage in [GraphOS Router](/router/executing-operations/defer-support/) and is compatible with all [federation-compatible subgraph libraries](/federation/building-supergraphs/supported-subgraphs/). +> For a query to defer fields successfully, the queried endpoint must _also_ support the `@defer` directive. Entity-based `@defer` support is also at the General Availability stage in [Apollo Router](/router/executing-operations/defer-support/) and is compatible with all [federation-compatible subgraph libraries](/federation/building-supergraphs/supported-subgraphs/). ## Example From a739dfd2847d002405bb6c8b637ead9e54d5d012 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:31:53 -0600 Subject: [PATCH 15/15] Version Packages (#11855) Co-authored-by: github-actions[bot] --- .changeset/brown-bikes-divide.md | 5 ----- .changeset/famous-camels-rescue.md | 5 ----- .changeset/late-days-give.md | 5 ----- .changeset/loud-hairs-think.md | 5 ----- .changeset/loud-hounds-heal.md | 5 ----- .changeset/mighty-monkeys-explain.md | 6 ------ .changeset/nasty-pens-dress.md | 5 ----- .changeset/shaggy-mirrors-judge.md | 5 ----- .changeset/sharp-cats-taste.md | 5 ----- .changeset/stupid-planes-nail.md | 5 ----- CHANGELOG.md | 25 +++++++++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 13 files changed, 28 insertions(+), 54 deletions(-) delete mode 100644 .changeset/brown-bikes-divide.md delete mode 100644 .changeset/famous-camels-rescue.md delete mode 100644 .changeset/late-days-give.md delete mode 100644 .changeset/loud-hairs-think.md delete mode 100644 .changeset/loud-hounds-heal.md delete mode 100644 .changeset/mighty-monkeys-explain.md delete mode 100644 .changeset/nasty-pens-dress.md delete mode 100644 .changeset/shaggy-mirrors-judge.md delete mode 100644 .changeset/sharp-cats-taste.md delete mode 100644 .changeset/stupid-planes-nail.md diff --git a/.changeset/brown-bikes-divide.md b/.changeset/brown-bikes-divide.md deleted file mode 100644 index 8701c21eae9..00000000000 --- a/.changeset/brown-bikes-divide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@apollo/client": patch ---- - -switch `useRenderGuard` to an approach not accessing React's internals diff --git a/.changeset/famous-camels-rescue.md b/.changeset/famous-camels-rescue.md deleted file mode 100644 index fbf8b08722b..00000000000 --- a/.changeset/famous-camels-rescue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@apollo/client": patch ---- - -`useLoadableQuery`: ensure that `loadQuery` is updated if the ApolloClient instance changes diff --git a/.changeset/late-days-give.md b/.changeset/late-days-give.md deleted file mode 100644 index 4fe36c2d495..00000000000 --- a/.changeset/late-days-give.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@apollo/client": patch ---- - -Fixes [#11849](https://github.com/apollographql/apollo-client/issues/11849) by reevaluating `window.fetch` each time `BatchHttpLink` uses it, if not configured via `options.fetch`. Takes the same approach as PR [#8603](https://github.com/apollographql/apollo-client/pull/8603) which fixed the same issue in `HttpLink`. diff --git a/.changeset/loud-hairs-think.md b/.changeset/loud-hairs-think.md deleted file mode 100644 index 7e29ffae5ec..00000000000 --- a/.changeset/loud-hairs-think.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@apollo/client": patch ---- - -Fix a bug where calling the `useMutation` `reset` function would point the hook to an outdated `client` reference. diff --git a/.changeset/loud-hounds-heal.md b/.changeset/loud-hounds-heal.md deleted file mode 100644 index f80a0a34105..00000000000 --- a/.changeset/loud-hounds-heal.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@apollo/client": patch ---- - -Fix graphQLErrors in Error Link if networkError.result is an empty string diff --git a/.changeset/mighty-monkeys-explain.md b/.changeset/mighty-monkeys-explain.md deleted file mode 100644 index 4629cd11273..00000000000 --- a/.changeset/mighty-monkeys-explain.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@apollo/client": patch ---- - -Prevent writing to a ref in render in `useMutation`. -As a result, you might encounter problems in the future if you call the mutation's `execute` function during render. Please note that this was never supported behavior, and we strongly recommend against it. diff --git a/.changeset/nasty-pens-dress.md b/.changeset/nasty-pens-dress.md deleted file mode 100644 index 7eb2f16b3c6..00000000000 --- a/.changeset/nasty-pens-dress.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@apollo/client": patch ---- - -Ensure covariant behavior: `MockedResponse` should be assignable to `MockedResponse` diff --git a/.changeset/shaggy-mirrors-judge.md b/.changeset/shaggy-mirrors-judge.md deleted file mode 100644 index f5e599284ab..00000000000 --- a/.changeset/shaggy-mirrors-judge.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@apollo/client": patch ---- - -Avoid usage of useRef in useInternalState to prevent ref access in render. diff --git a/.changeset/sharp-cats-taste.md b/.changeset/sharp-cats-taste.md deleted file mode 100644 index 6d2946fe28d..00000000000 --- a/.changeset/sharp-cats-taste.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@apollo/client": patch ---- - -Add missing name to tuple member (fix TS5084) diff --git a/.changeset/stupid-planes-nail.md b/.changeset/stupid-planes-nail.md deleted file mode 100644 index 200a00ac26b..00000000000 --- a/.changeset/stupid-planes-nail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@apollo/client": patch ---- - -Fix a bug where `useLazyQuery` would not pick up a client change. diff --git a/CHANGELOG.md b/CHANGELOG.md index e4473180110..1791cbeafe8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ # @apollo/client +## 3.10.5 + +### Patch Changes + +- [#11888](https://github.com/apollographql/apollo-client/pull/11888) [`7fb7939`](https://github.com/apollographql/apollo-client/commit/7fb7939edb7ca8f4273b75554f96ea9936731458) Thanks [@phryneas](https://github.com/phryneas)! - switch `useRenderGuard` to an approach not accessing React's internals + +- [#11511](https://github.com/apollographql/apollo-client/pull/11511) [`6536369`](https://github.com/apollographql/apollo-client/commit/6536369cf213469d20d15b779c344268d70fecd5) Thanks [@phryneas](https://github.com/phryneas)! - `useLoadableQuery`: ensure that `loadQuery` is updated if the ApolloClient instance changes + +- [#11860](https://github.com/apollographql/apollo-client/pull/11860) [`8740f19`](https://github.com/apollographql/apollo-client/commit/8740f198805a99e01136617c4055d611b92cc231) Thanks [@alessbell](https://github.com/alessbell)! - Fixes [#11849](https://github.com/apollographql/apollo-client/issues/11849) by reevaluating `window.fetch` each time `BatchHttpLink` uses it, if not configured via `options.fetch`. Takes the same approach as PR [#8603](https://github.com/apollographql/apollo-client/pull/8603) which fixed the same issue in `HttpLink`. + +- [#11852](https://github.com/apollographql/apollo-client/pull/11852) [`d502a69`](https://github.com/apollographql/apollo-client/commit/d502a69654d8ffa31e09467da028304a934a9874) Thanks [@phryneas](https://github.com/phryneas)! - Fix a bug where calling the `useMutation` `reset` function would point the hook to an outdated `client` reference. + +- [#11329](https://github.com/apollographql/apollo-client/pull/11329) [`3d164ea`](https://github.com/apollographql/apollo-client/commit/3d164ea16c17d271f6fa9e5ad8f013623eec23a0) Thanks [@PaLy](https://github.com/PaLy)! - Fix graphQLErrors in Error Link if networkError.result is an empty string + +- [#11852](https://github.com/apollographql/apollo-client/pull/11852) [`d502a69`](https://github.com/apollographql/apollo-client/commit/d502a69654d8ffa31e09467da028304a934a9874) Thanks [@phryneas](https://github.com/phryneas)! - Prevent writing to a ref in render in `useMutation`. + As a result, you might encounter problems in the future if you call the mutation's `execute` function during render. Please note that this was never supported behavior, and we strongly recommend against it. + +- [#11848](https://github.com/apollographql/apollo-client/pull/11848) [`ad63924`](https://github.com/apollographql/apollo-client/commit/ad6392424ddbeb6f91b165c806251490e1cdd69e) Thanks [@phryneas](https://github.com/phryneas)! - Ensure covariant behavior: `MockedResponse` should be assignable to `MockedResponse` + +- [#11851](https://github.com/apollographql/apollo-client/pull/11851) [`45c47be`](https://github.com/apollographql/apollo-client/commit/45c47be26d4e020cfcff359a5af19ccfc39b930e) Thanks [@phryneas](https://github.com/phryneas)! - Avoid usage of useRef in useInternalState to prevent ref access in render. + +- [#11877](https://github.com/apollographql/apollo-client/pull/11877) [`634d91a`](https://github.com/apollographql/apollo-client/commit/634d91aeb10ab308b05d5ffb918678806046af09) Thanks [@phryneas](https://github.com/phryneas)! - Add missing name to tuple member (fix TS5084) + +- [#11851](https://github.com/apollographql/apollo-client/pull/11851) [`45c47be`](https://github.com/apollographql/apollo-client/commit/45c47be26d4e020cfcff359a5af19ccfc39b930e) Thanks [@phryneas](https://github.com/phryneas)! - Fix a bug where `useLazyQuery` would not pick up a client change. + ## 3.10.4 ### Patch Changes diff --git a/package-lock.json b/package-lock.json index 0684be839e5..ec5a1503faa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@apollo/client", - "version": "3.10.4", + "version": "3.10.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@apollo/client", - "version": "3.10.4", + "version": "3.10.5", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index a36db028e60..b88727f93ed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@apollo/client", - "version": "3.10.4", + "version": "3.10.5", "description": "A fully-featured caching GraphQL client.", "private": true, "keywords": [