From 9251cb508010d37050581f86d4d45edb1a8382ec Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Oct 2023 19:57:28 -0400 Subject: [PATCH 01/17] chore(deps): update cimg/node docker tag to v20.7.0 (#11246) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .circleci/config.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4743a55f95e..8ab65c744a1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,7 +12,7 @@ jobs: Lint: docker: - - image: cimg/node:20.6.1 + - image: cimg/node:20.7.0 steps: - checkout - run: npm version @@ -21,7 +21,7 @@ jobs: Formatting: docker: - - image: cimg/node:20.6.1 + - image: cimg/node:20.7.0 steps: - checkout - run: npm ci @@ -29,7 +29,7 @@ jobs: Tests: docker: - - image: cimg/node:20.6.1 + - image: cimg/node:20.7.0 steps: - checkout - run: npm run ci:precheck @@ -47,7 +47,7 @@ jobs: BuildTarball: docker: - - image: cimg/node:20.6.1 + - image: cimg/node:20.7.0 steps: - checkout - run: npm run ci:precheck @@ -64,7 +64,7 @@ jobs: framework: type: string docker: - - image: cimg/node:20.6.1 + - image: cimg/node:20.7.0 steps: - checkout - attach_workspace: From 3e881f1cb8351fb6c7add4c345dc01ed0ec5df6b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Oct 2023 19:58:45 -0400 Subject: [PATCH 02/17] chore(deps): update dependency @microsoft/api-extractor to v7.38.0 (#11263) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 42 +++++++++++++++++++++--------------------- package.json | 2 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/package-lock.json b/package-lock.json index a0e81551b27..387d3923ac2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,7 @@ "@changesets/changelog-github": "0.4.8", "@changesets/cli": "2.26.2", "@graphql-tools/schema": "10.0.0", - "@microsoft/api-extractor": "7.37.0", + "@microsoft/api-extractor": "7.38.0", "@rollup/plugin-node-resolve": "11.2.1", "@size-limit/esbuild-why": "8.2.6", "@size-limit/preset-small-lib": "8.2.6", @@ -2111,17 +2111,17 @@ } }, "node_modules/@microsoft/api-extractor": { - "version": "7.37.0", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.37.0.tgz", - "integrity": "sha512-df/wffWpDhYRw7kzdxeHGsCpim+dC8aFiZlsJb4uFvVPWhBZpDzOhQxSUTFx3Df1ORY+/JjuPR3fDE9Hq+PHzQ==", + "version": "7.38.0", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.38.0.tgz", + "integrity": "sha512-e1LhZYnfw+JEebuY2bzhw0imDCl1nwjSThTrQqBXl40hrVo6xm3j/1EpUr89QyzgjqmAwek2ZkIVZbrhaR+cqg==", "dev": true, "dependencies": { - "@microsoft/api-extractor-model": "7.28.0", + "@microsoft/api-extractor-model": "7.28.2", "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.60.0", - "@rushstack/rig-package": "0.5.0", - "@rushstack/ts-command-line": "4.16.0", + "@rushstack/node-core-library": "3.61.0", + "@rushstack/rig-package": "0.5.1", + "@rushstack/ts-command-line": "4.16.1", "colors": "~1.2.1", "lodash": "~4.17.15", "resolve": "~1.22.1", @@ -2134,14 +2134,14 @@ } }, "node_modules/@microsoft/api-extractor-model": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.0.tgz", - "integrity": "sha512-QIMtUVm1tqiKG+M6ciFgRShcDoovyltaeg+CbyOnyr7SMrp6gg0ojK5/nToMqR9kAvsTS4QVgW4Twl50EoAjcw==", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.2.tgz", + "integrity": "sha512-vkojrM2fo3q4n4oPh4uUZdjJ2DxQ2+RnDQL/xhTWSRUNPF6P4QyrvY357HBxbnltKcYu+nNNolVqc6TIGQ73Ig==", "dev": true, "dependencies": { "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.60.0" + "@rushstack/node-core-library": "3.61.0" } }, "node_modules/@microsoft/api-extractor/node_modules/semver": { @@ -2292,9 +2292,9 @@ "dev": true }, "node_modules/@rushstack/node-core-library": { - "version": "3.60.0", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.60.0.tgz", - "integrity": "sha512-PcyrqhILvzU+65wMFybQ2VeGNnU5JzhDq2OvUi3j6jPUxyllM7b2hrRUwCuVaYboewYzIbpzXFzgxe2K7ii1nw==", + "version": "3.61.0", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.61.0.tgz", + "integrity": "sha512-tdOjdErme+/YOu4gPed3sFS72GhtWCgNV9oDsHDnoLY5oDfwjKUc9Z+JOZZ37uAxcm/OCahDHfuu2ugqrfWAVQ==", "dev": true, "dependencies": { "colors": "~1.2.1", @@ -2330,9 +2330,9 @@ } }, "node_modules/@rushstack/rig-package": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.0.tgz", - "integrity": "sha512-bGnOW4DWHOePDiABKy6qyqYJl9i7fKn4bRucExRVt5QzyPxuVHMl8CMmCabtoNSpXzgG3qymWOrMoa/W2PpJrw==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.1.tgz", + "integrity": "sha512-pXRYSe29TjRw7rqxD4WS3HN/sRSbfr+tJs4a9uuaSIBAITbUggygdhuG0VrO0EO+QqH91GhYMN4S6KRtOEmGVA==", "dev": true, "dependencies": { "resolve": "~1.22.1", @@ -2340,9 +2340,9 @@ } }, "node_modules/@rushstack/ts-command-line": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.16.0.tgz", - "integrity": "sha512-WJKhdR9ThK9Iy7t78O3at7I3X4Ssp5RRZay/IQa8NywqkFy/DQbT3iLouodMMdUwLZD9n8n++xLubVd3dkmpkg==", + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.16.1.tgz", + "integrity": "sha512-+OCsD553GYVLEmz12yiFjMOzuPeCiZ3f8wTiFHL30ZVXexTyPmgjwXEhg2K2P0a2lVf+8YBy7WtPoflB2Fp8/A==", "dev": true, "dependencies": { "@types/argparse": "1.0.38", diff --git a/package.json b/package.json index 25c630b8ec4..1b44347fd69 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,7 @@ "@changesets/changelog-github": "0.4.8", "@changesets/cli": "2.26.2", "@graphql-tools/schema": "10.0.0", - "@microsoft/api-extractor": "7.37.0", + "@microsoft/api-extractor": "7.38.0", "@rollup/plugin-node-resolve": "11.2.1", "@size-limit/esbuild-why": "8.2.6", "@size-limit/preset-small-lib": "8.2.6", From 1d4ba6211ca6e4acb490cff747dfd30f15274560 Mon Sep 17 00:00:00 2001 From: Thet Naing Tun Date: Mon, 9 Oct 2023 16:48:54 +0700 Subject: [PATCH 03/17] add `onQueryUpdated` to `useMutation` execution option docs --- docs/shared/mutation-result.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/shared/mutation-result.mdx b/docs/shared/mutation-result.mdx index 3feb6b1cc50..21e4e858137 100644 --- a/docs/shared/mutation-result.mdx +++ b/docs/shared/mutation-result.mdx @@ -27,6 +27,7 @@ A function to trigger the mutation from your UI. You can optionally pass this fu * `onError` * `optimisticResponse` * `refetchQueries` +* `onQueryUpdated` * `update` * `variables` * `client` From b29f000f36f281e256809b5454eaeca2ec4450bf Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Mon, 9 Oct 2023 14:55:00 -0700 Subject: [PATCH 04/17] Fix auto dispose timeout that could cause components to suspend indefinitely (#11274) The `autoDisposeTimeoutMs` configurable value for Suspense hooks was created to ensure components that suspend but never remount would get properly cleaned up after the timeout duration. This works well to cleanup after components that never mount again after initially suspending (such as a user interaction that hides the element while suspended). This timer started when the query ref was initialized and disposed of regardless of whether the initial promise had settled or not. This meant that when the request finished after the configured timeout, the component would suspend indefinitely since nothing was around to resolve/reject the promise leaving it in a pending state forever. This change adjusts the start of the dispose timer to wait until the initial promise is settled. This ensures React will try rendering again regardless of how long the request takes, and only after `autoDisposeTimeoutMs` will the query ref try and clean itself up if a component doesn't come along and retain it. --- .changeset/lemon-tigers-promise.md | 5 ++ .size-limit.cjs | 2 +- src/react/cache/QueryReference.ts | 17 ++++- .../hooks/__tests__/useSuspenseQuery.test.tsx | 75 ++++++++++++++++--- 4 files changed, 82 insertions(+), 17 deletions(-) create mode 100644 .changeset/lemon-tigers-promise.md diff --git a/.changeset/lemon-tigers-promise.md b/.changeset/lemon-tigers-promise.md new file mode 100644 index 00000000000..7c397bae3ad --- /dev/null +++ b/.changeset/lemon-tigers-promise.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +Start the query ref auto dispose timeout after the initial promise has settled. This prevents requests that run longer than the timeout duration from keeping the component suspended indefinitely. diff --git a/.size-limit.cjs b/.size-limit.cjs index d8da5ff2578..223a3dce7ae 100644 --- a/.size-limit.cjs +++ b/.size-limit.cjs @@ -1,7 +1,7 @@ const checks = [ { path: "dist/apollo-client.min.cjs", - limit: "37940", + limit: "37960", }, { path: "dist/main.cjs", diff --git a/src/react/cache/QueryReference.ts b/src/react/cache/QueryReference.ts index 7a03ea10d37..f1ad5732bac 100644 --- a/src/react/cache/QueryReference.ts +++ b/src/react/cache/QueryReference.ts @@ -123,10 +123,19 @@ export class InternalQueryReference { // suspended resource does not use this queryRef in the given time. This // helps prevent memory leaks when a component has unmounted before the // query has finished loading. - this.autoDisposeTimeoutId = setTimeout( - this.dispose, - options.autoDisposeTimeoutMs ?? 30_000 - ); + const startDisposeTimer = () => { + if (!this.references) { + this.autoDisposeTimeoutId = setTimeout( + this.dispose, + options.autoDisposeTimeoutMs ?? 30_000 + ); + } + }; + + // We wait until the request has settled to ensure we don't dispose of the + // query ref before the request finishes, otherwise we would leave the + // promise in a pending state rendering the suspense boundary indefinitely. + this.promise.then(startDisposeTimer, startDisposeTimer); } get watchQueryOptions() { diff --git a/src/react/hooks/__tests__/useSuspenseQuery.test.tsx b/src/react/hooks/__tests__/useSuspenseQuery.test.tsx index 08b4abb3f64..468fe8f4fc5 100644 --- a/src/react/hooks/__tests__/useSuspenseQuery.test.tsx +++ b/src/react/hooks/__tests__/useSuspenseQuery.test.tsx @@ -805,8 +805,12 @@ describe("useSuspenseQuery", () => { expect(screen.queryByText("Loading greeting...")).not.toBeInTheDocument(); - link.simulateResult({ result: { data: { greeting: "Hello" } } }); - link.simulateComplete(); + await act(() => { + link.simulateResult({ result: { data: { greeting: "Hello" } } }, true); + // Ensure simulateResult will deliver the result since its wrapped with + // setTimeout + jest.advanceTimersByTime(10); + }); expect(client.getObservableQueries().size).toBe(1); expect(client).toHaveSuspenseCacheEntryUsing(query); @@ -817,10 +821,6 @@ describe("useSuspenseQuery", () => { expect(client).not.toHaveSuspenseCacheEntryUsing(query); jest.useRealTimers(); - - // Avoid act warnings for a suspended resource - // eslint-disable-next-line testing-library/no-unnecessary-act - await act(() => wait(0)); }); it("has configurable auto dispose timer if the component never renders again after suspending", async () => { @@ -871,8 +871,12 @@ describe("useSuspenseQuery", () => { expect(screen.queryByText("Loading greeting...")).not.toBeInTheDocument(); - link.simulateResult({ result: { data: { greeting: "Hello" } } }); - link.simulateComplete(); + await act(() => { + link.simulateResult({ result: { data: { greeting: "Hello" } } }, true); + // Ensure simulateResult will deliver the result since its wrapped with + // setTimeout + jest.advanceTimersByTime(10); + }); expect(client.getObservableQueries().size).toBe(1); expect(client).toHaveSuspenseCacheEntryUsing(query); @@ -883,10 +887,6 @@ describe("useSuspenseQuery", () => { expect(client).not.toHaveSuspenseCacheEntryUsing(query); jest.useRealTimers(); - - // Avoid act warnings for a suspended resource - // eslint-disable-next-line testing-library/no-unnecessary-act - await act(() => wait(0)); }); it("cancels auto dispose if the component renders before timer finishes", async () => { @@ -940,6 +940,57 @@ describe("useSuspenseQuery", () => { jest.useRealTimers(); }); + // https://github.com/apollographql/apollo-client/issues/11270 + it("does not leave component suspended if query completes if request takes longer than auto dispose timeout", async () => { + jest.useFakeTimers(); + const { query } = useSimpleQueryCase(); + const link = new MockSubscriptionLink(); + const client = new ApolloClient({ + link, + cache: new InMemoryCache(), + defaultOptions: { + react: { + suspense: { + autoDisposeTimeoutMs: 10, + }, + }, + }, + }); + + function App() { + return ( + + + + + + ); + } + + function Greeting() { + const { data } = useSuspenseQuery(query); + + return {data.greeting}; + } + + render(); + + // Ensure suspends immediately + expect(screen.getByText("Loading greeting...")).toBeInTheDocument(); + + jest.advanceTimersByTime(20); + + link.simulateResult({ result: { data: { greeting: "Hello" } } }, true); + + await waitFor(() => { + expect(screen.queryByText("Loading greeting...")).not.toBeInTheDocument(); + }); + + expect(screen.getByText("Hello")).toBeInTheDocument(); + + jest.useRealTimers(); + }); + it("allows the client to be overridden", async () => { const { query } = useSimpleQueryCase(); From 8a405c2ac0e1a7d49fbec90b6dfda032df17168c Mon Sep 17 00:00:00 2001 From: Matt Peake <7741049+peakematt@users.noreply.github.com> Date: Tue, 10 Oct 2023 04:29:27 -0400 Subject: [PATCH 05/17] SECOPS-2268: Add Gitleaks to CI (#11282) Co-authored-by: Lenz Weber-Tronic --- .circleci/config.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8ab65c744a1..eb17342c272 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,5 +1,8 @@ version: 2.1 +orbs: + secops: apollo/circleci-secops-orb@2.0.0 + jobs: # Filesize: # docker: @@ -109,3 +112,12 @@ workflows: - vite - vite-swc # -browser-esm would need a package publish to npm/CDNs + security-scans: + jobs: + - secops/gitleaks: + context: + - platform-docker-ro + - github-orb + - secops-oidc + git-base-revision: <<#pipeline.git.base_revision>><><> + git-revision: << pipeline.git.revision >> From 09b23351ebe0b2bbffbe4d17db788938e6a62973 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 10 Oct 2023 11:26:25 -0400 Subject: [PATCH 06/17] chore(deps): update all devdependencies (#11278) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 54 +++++++++++++++++++++++------------------------ package.json | 8 +++---- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/package-lock.json b/package-lock.json index 387d3923ac2..f18298e0876 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,7 @@ "zen-observable-ts": "^1.2.5" }, "devDependencies": { - "@arethetypeswrong/cli": "0.11.0", + "@arethetypeswrong/cli": "0.12.1", "@babel/parser": "7.23.0", "@changesets/changelog-github": "0.4.8", "@changesets/cli": "2.26.2", @@ -59,12 +59,12 @@ "blob-polyfill": "7.0.20220408", "bytes": "3.1.2", "cross-fetch": "3.1.8", - "eslint": "8.50.0", + "eslint": "8.51.0", "eslint-import-resolver-typescript": "3.6.0", "eslint-plugin-import": "npm:@phryneas/eslint-plugin-import@2.27.5-pr.2813.2817.199971c", "eslint-plugin-local-rules": "2.0.0", "eslint-plugin-testing-library": "5.11.1", - "expect-type": "0.16.0", + "expect-type": "0.17.3", "fetch-mock": "9.11.0", "glob": "8.1.0", "graphql": "16.8.1", @@ -88,7 +88,7 @@ "rxjs": "7.8.1", "size-limit": "8.2.6", "subscriptions-transport-ws": "0.11.0", - "terser": "5.20.0", + "terser": "5.21.0", "ts-api-utils": "1.0.3", "ts-jest": "29.1.1", "ts-jest-resolver": "2.0.1", @@ -146,12 +146,12 @@ "dev": true }, "node_modules/@arethetypeswrong/cli": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@arethetypeswrong/cli/-/cli-0.11.0.tgz", - "integrity": "sha512-0GxlV58x8DaiWRUx0JWc3glr8iGsjK+KATuubH8qRqjw4aIGB8BBQ8Bv2Bvs9DfGuojBgbVWhOTe8+3BepYZ6Q==", + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@arethetypeswrong/cli/-/cli-0.12.1.tgz", + "integrity": "sha512-5nA91oqi8GPv9NkxgcjdpyKSMJ0WCcX8YYcxlZS5XBqY6cau0pMt5S0CXU3QGgl9qDryrok1QaM1xtUUhBKTAA==", "dev": true, "dependencies": { - "@arethetypeswrong/core": "0.10.2", + "@arethetypeswrong/core": "0.12.1", "chalk": "^4.1.2", "cli-table3": "^0.6.3", "commander": "^10.0.1", @@ -201,9 +201,9 @@ } }, "node_modules/@arethetypeswrong/core": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@arethetypeswrong/core/-/core-0.10.2.tgz", - "integrity": "sha512-jL1MPpZKuMkm0EbZn1OLgdTO5hci7g79EUSELEnATdFyTgbPUxJwTXi1Kdont/BG05BZCcxZnOQgYO/whVmwdA==", + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@arethetypeswrong/core/-/core-0.12.1.tgz", + "integrity": "sha512-1XCwz+IRSptRu1Y48D462vu3de8sLFrtXaXkgthIZ8+iRhEBIZtu+q7MwrfR3hWbYIgUsBj2WugtIgaPAdX9FA==", "dev": true, "dependencies": { "@andrewbranch/untar.js": "^1.0.0", @@ -1400,9 +1400,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz", - "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", + "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -4901,15 +4901,15 @@ } }, "node_modules/eslint": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", - "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", + "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.50.0", + "@eslint/js": "8.51.0", "@humanwhocodes/config-array": "^0.11.11", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -5312,9 +5312,9 @@ } }, "node_modules/eslint/node_modules/globals": { - "version": "13.22.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.22.0.tgz", - "integrity": "sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==", + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -5579,9 +5579,9 @@ } }, "node_modules/expect-type": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-0.16.0.tgz", - "integrity": "sha512-wCpFeVBiAPGiYkQZzaqvGuuBnNCHbtnowMOBpBGY8a27XbG8VAit3lklWph1r8VmgsH61mOZqI3NuGm8bZnUlw==", + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-0.17.3.tgz", + "integrity": "sha512-K0ZdZJ97jiAtaOwhEHHz/f0N6Xbj5reRz5g6+5BO7+OvqQ7PMQz0/c8bFSJs1zPotNJL5HJaC6t6lGPEAtGyOw==", "dev": true, "engines": { "node": ">=12.0.0" @@ -10695,9 +10695,9 @@ } }, "node_modules/terser": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.20.0.tgz", - "integrity": "sha512-e56ETryaQDyebBwJIWYB2TT6f2EZ0fL0sW/JRXNMN26zZdKi2u/E/5my5lG6jNxym6qsrVXfFRmOdV42zlAgLQ==", + "version": "5.21.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.21.0.tgz", + "integrity": "sha512-WtnFKrxu9kaoXuiZFSGrcAvvBqAdmKx0SFNmVNYdJamMu9yyN3I/QF0FbH4QcqJQ+y1CJnzxGIKH0cSj+FGYRw==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", diff --git a/package.json b/package.json index 1b44347fd69..2b0837566fb 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "zen-observable-ts": "^1.2.5" }, "devDependencies": { - "@arethetypeswrong/cli": "0.11.0", + "@arethetypeswrong/cli": "0.12.1", "@babel/parser": "7.23.0", "@changesets/changelog-github": "0.4.8", "@changesets/cli": "2.26.2", @@ -137,12 +137,12 @@ "blob-polyfill": "7.0.20220408", "bytes": "3.1.2", "cross-fetch": "3.1.8", - "eslint": "8.50.0", + "eslint": "8.51.0", "eslint-import-resolver-typescript": "3.6.0", "eslint-plugin-import": "npm:@phryneas/eslint-plugin-import@2.27.5-pr.2813.2817.199971c", "eslint-plugin-local-rules": "2.0.0", "eslint-plugin-testing-library": "5.11.1", - "expect-type": "0.16.0", + "expect-type": "0.17.3", "fetch-mock": "9.11.0", "glob": "8.1.0", "graphql": "16.8.1", @@ -166,7 +166,7 @@ "rxjs": "7.8.1", "size-limit": "8.2.6", "subscriptions-transport-ws": "0.11.0", - "terser": "5.20.0", + "terser": "5.21.0", "ts-api-utils": "1.0.3", "ts-jest": "29.1.1", "ts-jest-resolver": "2.0.1", From a9aa95fe2b28670420892e56228eb6606671f615 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 10 Oct 2023 11:27:10 -0400 Subject: [PATCH 07/17] chore(deps): update cimg/node docker tag to v20.8.0 (#11279) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .circleci/config.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index eb17342c272..84e1015d438 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,7 +15,7 @@ jobs: Lint: docker: - - image: cimg/node:20.7.0 + - image: cimg/node:20.8.0 steps: - checkout - run: npm version @@ -24,7 +24,7 @@ jobs: Formatting: docker: - - image: cimg/node:20.7.0 + - image: cimg/node:20.8.0 steps: - checkout - run: npm ci @@ -32,7 +32,7 @@ jobs: Tests: docker: - - image: cimg/node:20.7.0 + - image: cimg/node:20.8.0 steps: - checkout - run: npm run ci:precheck @@ -50,7 +50,7 @@ jobs: BuildTarball: docker: - - image: cimg/node:20.7.0 + - image: cimg/node:20.8.0 steps: - checkout - run: npm run ci:precheck @@ -67,7 +67,7 @@ jobs: framework: type: string docker: - - image: cimg/node:20.7.0 + - image: cimg/node:20.8.0 steps: - checkout - attach_workspace: From 2c62273f4eb741cb15c81785789134c77739b8a2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 10 Oct 2023 11:36:36 -0400 Subject: [PATCH 08/17] chore(deps): update stefanzweifel/git-auto-commit-action action to v5 (#11280) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/exit-prerelease.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/exit-prerelease.yml b/.github/workflows/exit-prerelease.yml index 8d350e43252..67f6c41bb43 100644 --- a/.github/workflows/exit-prerelease.yml +++ b/.github/workflows/exit-prerelease.yml @@ -52,7 +52,7 @@ jobs: - name: Remove pre.json run: npx rimraf .changeset/pre.json - - uses: stefanzweifel/git-auto-commit-action@v4 + - uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: Exit prerelease mode # Commit these changes to the branch workflow is running against From 2e6a6e25aaa18309223732bd5e529cbb73c04c0a Mon Sep 17 00:00:00 2001 From: Jeff Auriemma Date: Thu, 12 Oct 2023 12:32:12 -0400 Subject: [PATCH 09/17] Update bug template instructions --- .github/ISSUE_TEMPLATE/bug.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 1f0e8939cc2..d2e1bc647dc 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -13,7 +13,7 @@ body: - type: input attributes: label: Link to Reproduction - description: "A link with runnable reproduction. For web projects, you can fork our `react-apollo-error-template` to create one via [GitHub repository](https://github.com/apollographql/react-apollo-error-template) or [CodeSandbox](https://codesandbox.io/s/github/apollographql/react-apollo-error-template). For React Native projects, you can fork our `rn-apollo-client-testbed` via [GitHub respository](https://github.com/apollographql/rn-apollo-client-testbed). Make sure this includes everything necessary (`package.json`, `tsconfig.json`, etc.) so we don't have to guess anything! If a minimal reproduction can't be created, please share a [Replay](https://docs.replay.io/workflows/recording-bug-reports) of the bug (note: you don't have to grant Replay access to a private repo to create a recording, but it will contain source maps for your JavaScript code)." + description: "A link with runnable reproduction. For web projects, you can fork our `react-apollo-error-template` to create one via [GitHub repository](https://github.com/apollographql/react-apollo-error-template) or [CodeSandbox](https://codesandbox.io/s/github/apollographql/react-apollo-error-template). For React Native projects, you can fork our `rn-apollo-client-testbed` via [GitHub respository](https://github.com/apollographql/rn-apollo-client-testbed). Make sure this includes everything necessary (`package.json`, `tsconfig.json`, etc.) so we don't have to guess anything! If a minimal reproduction can't be created, please share a [Replay](https://docs.replay.io/workflows/recording-bug-reports) of the bug (note: you don't have to grant Replay access to a private repo to create a recording, but it will contain source maps for your JavaScript code). Feel free to ask for an email address to send Replays to if they contain sensitive information." validations: required: true - type: textarea From 78c00b968dee664b49b46b1271e3007052653b9f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Oct 2023 09:36:44 -0400 Subject: [PATCH 10/17] chore(deps): update all dependencies - patch updates (#11244) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 261 ++++++++++++++++++++++++---------------------- package.json | 32 +++--- 2 files changed, 151 insertions(+), 142 deletions(-) diff --git a/package-lock.json b/package-lock.json index f18298e0876..43e648d575c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,7 @@ "zen-observable-ts": "^1.2.5" }, "devDependencies": { - "@arethetypeswrong/cli": "0.12.1", + "@arethetypeswrong/cli": "0.12.2", "@babel/parser": "7.23.0", "@changesets/changelog-github": "0.4.8", "@changesets/cli": "2.26.2", @@ -42,25 +42,25 @@ "@types/bytes": "3.1.2", "@types/fetch-mock": "7.3.6", "@types/glob": "8.1.0", - "@types/hoist-non-react-statics": "3.3.2", + "@types/hoist-non-react-statics": "3.3.3", "@types/jest": "29.5.5", - "@types/lodash": "4.14.198", - "@types/node": "20.8.0", - "@types/node-fetch": "2.6.5", - "@types/react": "18.2.22", - "@types/react-dom": "18.2.7", + "@types/lodash": "4.14.199", + "@types/node": "20.8.6", + "@types/node-fetch": "2.6.6", + "@types/react": "18.2.28", + "@types/react-dom": "18.2.13", "@types/use-sync-external-store": "0.0.4", - "@typescript-eslint/eslint-plugin": "6.7.2", - "@typescript-eslint/parser": "6.7.2", - "@typescript-eslint/rule-tester": "6.7.2", - "@typescript-eslint/types": "6.7.2", - "@typescript-eslint/utils": "6.7.2", + "@typescript-eslint/eslint-plugin": "6.7.5", + "@typescript-eslint/parser": "6.7.5", + "@typescript-eslint/rule-tester": "6.7.5", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/utils": "6.7.5", "acorn": "8.10.0", "blob-polyfill": "7.0.20220408", "bytes": "3.1.2", "cross-fetch": "3.1.8", "eslint": "8.51.0", - "eslint-import-resolver-typescript": "3.6.0", + "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.0", "eslint-plugin-testing-library": "5.11.1", @@ -68,7 +68,7 @@ "fetch-mock": "9.11.0", "glob": "8.1.0", "graphql": "16.8.1", - "graphql-ws": "5.14.0", + "graphql-ws": "5.14.1", "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", "jest-junit": "16.0.0", @@ -81,8 +81,8 @@ "react-dom-17": "npm:react-dom@^17", "react-error-boundary": "3.1.4", "recast": "0.23.4", - "resolve": "1.22.6", - "rimraf": "5.0.1", + "resolve": "1.22.8", + "rimraf": "5.0.5", "rollup": "2.79.1", "rollup-plugin-terser": "7.0.2", "rxjs": "7.8.1", @@ -140,18 +140,18 @@ "dev": true }, "node_modules/@andrewbranch/untar.js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@andrewbranch/untar.js/-/untar.js-1.0.2.tgz", - "integrity": "sha512-hL80MHK3b++pEp6K23+Nl5r5D1F19DRagp2ruCBIv4McyCiLKq67vUNvEQY1aGCAKNZ8GxV23n5MhOm7RwO8Pg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@andrewbranch/untar.js/-/untar.js-1.0.3.tgz", + "integrity": "sha512-Jh15/qVmrLGhkKJBdXlK1+9tY4lZruYjsgkDFj08ZmDiWVBLJcqkok7Z0/R0In+i1rScBpJlSvrTS2Lm41Pbnw==", "dev": true }, "node_modules/@arethetypeswrong/cli": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@arethetypeswrong/cli/-/cli-0.12.1.tgz", - "integrity": "sha512-5nA91oqi8GPv9NkxgcjdpyKSMJ0WCcX8YYcxlZS5XBqY6cau0pMt5S0CXU3QGgl9qDryrok1QaM1xtUUhBKTAA==", + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@arethetypeswrong/cli/-/cli-0.12.2.tgz", + "integrity": "sha512-SE4Rqy8LM8zgRLeVXZqFIOg4w4TCDG2AMguuZDDRcrUmVQj7phW0tWJnKwsZtyJ6SdqXTIzWvGYiUJiHg2hb9w==", "dev": true, "dependencies": { - "@arethetypeswrong/core": "0.12.1", + "@arethetypeswrong/core": "0.12.2", "chalk": "^4.1.2", "cli-table3": "^0.6.3", "commander": "^10.0.1", @@ -201,12 +201,12 @@ } }, "node_modules/@arethetypeswrong/core": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@arethetypeswrong/core/-/core-0.12.1.tgz", - "integrity": "sha512-1XCwz+IRSptRu1Y48D462vu3de8sLFrtXaXkgthIZ8+iRhEBIZtu+q7MwrfR3hWbYIgUsBj2WugtIgaPAdX9FA==", + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@arethetypeswrong/core/-/core-0.12.2.tgz", + "integrity": "sha512-ez/quGfC6RVg7VrwCgMVreJ01jbkfJQRNxOG7Bpl4YGcPRs45ZE1AzpHiIdzqfwFg9EBVSaewaffrsK5MVbALw==", "dev": true, "dependencies": { - "@andrewbranch/untar.js": "^1.0.0", + "@andrewbranch/untar.js": "^1.0.3", "fetch-ponyfill": "^7.1.0", "fflate": "^0.7.4", "semver": "^7.5.4", @@ -2774,9 +2774,9 @@ } }, "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-YIQtIg4PKr7ZyqNPZObpxfHsHEmuB8dXCxd6qVcGuQVDK2bpsF7bYNnBJ4Nn7giuACZg+WewExgrtAJ3XnA4Xw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.3.tgz", + "integrity": "sha512-Wny3a2UXn5FEA1l7gc6BbpoV5mD1XijZqgkp4TRgDCDL5r3B5ieOFGUX5h3n78Tr1MEG7BfvoM8qeztdvNU0fw==", "dev": true, "dependencies": { "@types/react": "*", @@ -2882,9 +2882,9 @@ "dev": true }, "node_modules/@types/lodash": { - "version": "4.14.198", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.198.tgz", - "integrity": "sha512-trNJ/vtMZYMLhfN45uLq4ShQSw0/S7xCTLLVM+WM1rmFpba/VS42jVUgaO3w/NOLiWR/09lnYk0yMaA/atdIsg==", + "version": "4.14.199", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.199.tgz", + "integrity": "sha512-Vrjz5N5Ia4SEzWWgIVwnHNEnb1UE1XMkvY5DGXrAeOGE9imk0hgTHh5GyDjLDJi9OTCn9oo9dXH1uToK1VRfrg==", "dev": true }, "node_modules/@types/minimatch": { @@ -2900,15 +2900,18 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.8.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.0.tgz", - "integrity": "sha512-LzcWltT83s1bthcvjBmiBvGJiiUe84NWRHkw+ZV6Fr41z2FbIzvc815dk2nQ3RAKMuN2fkenM/z3Xv2QzEpYxQ==", - "dev": true + "version": "20.8.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.6.tgz", + "integrity": "sha512-eWO4K2Ji70QzKUqRy6oyJWUeB7+g2cRagT3T/nxYibYcT4y2BDL8lqolRXjTHmkZCdJfIPaY73KbJAZmcryxTQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.25.1" + } }, "node_modules/@types/node-fetch": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.5.tgz", - "integrity": "sha512-OZsUlr2nxvkqUFLSaY2ZbA+P1q22q+KrlxWOn/38RX+u5kTkYL2mTujEpzUhGkS+K/QCYp9oagfXG39XOzyySg==", + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.6.tgz", + "integrity": "sha512-95X8guJYhfqiuVVhRFxVQcf4hW/2bCuoPwDasMf/531STFoNoWTT7YDnWdXHEZKqAGUigmpG31r2FE70LwnzJw==", "dev": true, "dependencies": { "@types/node": "*", @@ -2928,9 +2931,9 @@ "dev": true }, "node_modules/@types/react": { - "version": "18.2.22", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.22.tgz", - "integrity": "sha512-60fLTOLqzarLED2O3UQImc/lsNRgG0jE/a1mPW9KjMemY0LMITWEsbS4VvZ4p6rorEHd5YKxxmMKSDK505GHpA==", + "version": "18.2.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.28.tgz", + "integrity": "sha512-ad4aa/RaaJS3hyGz0BGegdnSRXQBkd1CCYDCdNjBPg90UUpLgo+WlJqb9fMYUxtehmzF3PJaTWqRZjko6BRzBg==", "dev": true, "dependencies": { "@types/prop-types": "*", @@ -2939,9 +2942,9 @@ } }, "node_modules/@types/react-dom": { - "version": "18.2.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz", - "integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==", + "version": "18.2.13", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.13.tgz", + "integrity": "sha512-eJIUv7rPP+EC45uNYp/ThhSpE16k22VJUknt5OLoH9tbXoi8bMhwLf5xRuWMywamNbWzhrSmU7IBJfPup1+3fw==", "dev": true, "dependencies": { "@types/react": "*" @@ -3011,16 +3014,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.2.tgz", - "integrity": "sha512-ooaHxlmSgZTM6CHYAFRlifqh1OAr3PAQEwi7lhYhaegbnXrnh7CDcHmc3+ihhbQC7H0i4JF0psI5ehzkF6Yl6Q==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.5.tgz", + "integrity": "sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.7.2", - "@typescript-eslint/type-utils": "6.7.2", - "@typescript-eslint/utils": "6.7.2", - "@typescript-eslint/visitor-keys": "6.7.2", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/type-utils": "6.7.5", + "@typescript-eslint/utils": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -3061,15 +3064,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.2.tgz", - "integrity": "sha512-KA3E4ox0ws+SPyxQf9iSI25R6b4Ne78ORhNHeVKrPQnoYsb9UhieoiRoJgrzgEeKGOXhcY1i8YtOeCHHTDa6Fw==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.5.tgz", + "integrity": "sha512-bIZVSGx2UME/lmhLcjdVc7ePBwn7CLqKarUBL4me1C5feOd663liTGjMBGVcGr+BhnSLeP4SgwdvNnnkbIdkCw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.7.2", - "@typescript-eslint/types": "6.7.2", - "@typescript-eslint/typescript-estree": "6.7.2", - "@typescript-eslint/visitor-keys": "6.7.2", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4" }, "engines": { @@ -3089,13 +3092,13 @@ } }, "node_modules/@typescript-eslint/rule-tester": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/rule-tester/-/rule-tester-6.7.2.tgz", - "integrity": "sha512-jhnGel3v8annJcmubTA0rzNw5xwDhQDXGqRp57OJ8uUXYcfdrom/326R0lNLWLBvBp+UXrcsZBi6ybj+jlp7Vw==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/rule-tester/-/rule-tester-6.7.5.tgz", + "integrity": "sha512-rDUQDkMg577jA7U+2NFlgLv3S43epbjruLZ4MQaELhH+WZLmmGylFbcCWeonRmtFjF2Xd/lfYsjqQ+p61XZDkw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.7.2", - "@typescript-eslint/utils": "6.7.2", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/utils": "6.7.5", "ajv": "^6.10.0", "lodash.merge": "4.6.2", "semver": "^7.5.4" @@ -3128,13 +3131,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.2.tgz", - "integrity": "sha512-bgi6plgyZjEqapr7u2mhxGR6E8WCzKNUFWNh6fkpVe9+yzRZeYtDTbsIBzKbcxI+r1qVWt6VIoMSNZ4r2A+6Yw==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz", + "integrity": "sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.2", - "@typescript-eslint/visitor-keys": "6.7.2" + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3145,13 +3148,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.2.tgz", - "integrity": "sha512-36F4fOYIROYRl0qj95dYKx6kybddLtsbmPIYNK0OBeXv2j9L5nZ17j9jmfy+bIDHKQgn2EZX+cofsqi8NPATBQ==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.5.tgz", + "integrity": "sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.7.2", - "@typescript-eslint/utils": "6.7.2", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/utils": "6.7.5", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -3172,9 +3175,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.2.tgz", - "integrity": "sha512-flJYwMYgnUNDAN9/GAI3l8+wTmvTYdv64fcH8aoJK76Y+1FCZ08RtI5zDerM/FYT5DMkAc+19E4aLmd5KqdFyg==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz", + "integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3185,13 +3188,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.2.tgz", - "integrity": "sha512-kiJKVMLkoSciGyFU0TOY0fRxnp9qq1AzVOHNeN1+B9erKFCJ4Z8WdjAkKQPP+b1pWStGFqezMLltxO+308dJTQ==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz", + "integrity": "sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.2", - "@typescript-eslint/visitor-keys": "6.7.2", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3227,17 +3230,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.2.tgz", - "integrity": "sha512-ZCcBJug/TS6fXRTsoTkgnsvyWSiXwMNiPzBUani7hDidBdj1779qwM1FIAmpH4lvlOZNF3EScsxxuGifjpLSWQ==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.5.tgz", + "integrity": "sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.7.2", - "@typescript-eslint/types": "6.7.2", - "@typescript-eslint/typescript-estree": "6.7.2", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/typescript-estree": "6.7.5", "semver": "^7.5.4" }, "engines": { @@ -3267,12 +3270,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.2.tgz", - "integrity": "sha512-uVw9VIMFBUTz8rIeaUT3fFe8xIUx8r4ywAdlQv1ifH+6acn/XF8Y6rwJ7XNmkNMDrTW+7+vxFFPIF40nJCVsMQ==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz", + "integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.2", + "@typescript-eslint/types": "6.7.5", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -4975,9 +4978,9 @@ } }, "node_modules/eslint-import-resolver-typescript": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.0.tgz", - "integrity": "sha512-QTHR9ddNnn35RTxlaEnx2gCxqFlF2SEN0SE2d17SqwyM7YOSI2GHWRYp5BiRkObTUNYPupC/3Fq2a0PpT+EKpg==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", "dev": true, "dependencies": { "debug": "^4.3.4", @@ -6169,9 +6172,9 @@ } }, "node_modules/graphql-ws": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.14.0.tgz", - "integrity": "sha512-itrUTQZP/TgswR4GSSYuwWUzrE/w5GhbwM2GX3ic2U7aw33jgEsayfIlvaj7/GcIvZgNMzsPTrE5hqPuFUiE5g==", + "version": "5.14.1", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.14.1.tgz", + "integrity": "sha512-aqkls1espsygP1PfkAuuLIV96IbztQ6EaADse97pw8wRIMT3+AL/OYfS8V2iCRkc0gzckitoDRGCQEdnySggiA==", "dev": true, "engines": { "node": ">=10" @@ -6952,9 +6955,9 @@ "dev": true }, "node_modules/jackspeak": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.0.tgz", - "integrity": "sha512-r5XBrqIJfwRIjRt/Xr5fv9Wh09qyhHfKnYddDlpM+ibRR20qrYActpCAgU6U+d53EOEjzkvxPMVHSlgR7leXrQ==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -9216,13 +9219,13 @@ "dev": true }, "node_modules/path-scurry": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.9.2.tgz", - "integrity": "sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", "dev": true, "dependencies": { - "lru-cache": "^9.1.1", - "minipass": "^5.0.0 || ^6.0.2" + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -9803,9 +9806,9 @@ "dev": true }, "node_modules/resolve": { - "version": "1.22.6", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", - "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { "is-core-module": "^2.13.0", @@ -9877,15 +9880,15 @@ } }, "node_modules/rimraf": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.1.tgz", - "integrity": "sha512-OfFZdwtd3lZ+XZzYP/6gTACubwFcHdLRqS9UX3UwpU2dnGQYkPFISRwvM3w9IiB2w7bW5qGo/uAwE4SmXXSKvg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", "dev": true, "dependencies": { - "glob": "^10.2.5" + "glob": "^10.3.7" }, "bin": { - "rimraf": "dist/cjs/src/bin.js" + "rimraf": "dist/esm/bin.mjs" }, "engines": { "node": ">=14" @@ -9904,19 +9907,19 @@ } }, "node_modules/rimraf/node_modules/glob": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.5.tgz", - "integrity": "sha512-Gj+dFYPZ5hc5dazjXzB0iHg2jKWJZYMjITXYPBRQ/xc2Buw7H0BINknRTwURJ6IC6MEFpYbLvtgVb3qD+DwyuA==", + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.0", - "minipass": "^5.0.0 || ^6.0.2", - "path-scurry": "^1.7.0" + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" }, "bin": { - "glob": "dist/cjs/src/bin.js" + "glob": "dist/esm/bin.mjs" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -9926,9 +9929,9 @@ } }, "node_modules/rimraf/node_modules/minimatch": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", - "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -11170,6 +11173,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "5.25.3", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", + "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", + "dev": true + }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", diff --git a/package.json b/package.json index 2b0837566fb..d782f1b8dbe 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "zen-observable-ts": "^1.2.5" }, "devDependencies": { - "@arethetypeswrong/cli": "0.12.1", + "@arethetypeswrong/cli": "0.12.2", "@babel/parser": "7.23.0", "@changesets/changelog-github": "0.4.8", "@changesets/cli": "2.26.2", @@ -120,25 +120,25 @@ "@types/bytes": "3.1.2", "@types/fetch-mock": "7.3.6", "@types/glob": "8.1.0", - "@types/hoist-non-react-statics": "3.3.2", + "@types/hoist-non-react-statics": "3.3.3", "@types/jest": "29.5.5", - "@types/lodash": "4.14.198", - "@types/node": "20.8.0", - "@types/node-fetch": "2.6.5", - "@types/react": "18.2.22", - "@types/react-dom": "18.2.7", + "@types/lodash": "4.14.199", + "@types/node": "20.8.6", + "@types/node-fetch": "2.6.6", + "@types/react": "18.2.28", + "@types/react-dom": "18.2.13", "@types/use-sync-external-store": "0.0.4", - "@typescript-eslint/eslint-plugin": "6.7.2", - "@typescript-eslint/parser": "6.7.2", - "@typescript-eslint/rule-tester": "6.7.2", - "@typescript-eslint/types": "6.7.2", - "@typescript-eslint/utils": "6.7.2", + "@typescript-eslint/eslint-plugin": "6.7.5", + "@typescript-eslint/parser": "6.7.5", + "@typescript-eslint/rule-tester": "6.7.5", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/utils": "6.7.5", "acorn": "8.10.0", "blob-polyfill": "7.0.20220408", "bytes": "3.1.2", "cross-fetch": "3.1.8", "eslint": "8.51.0", - "eslint-import-resolver-typescript": "3.6.0", + "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.0", "eslint-plugin-testing-library": "5.11.1", @@ -146,7 +146,7 @@ "fetch-mock": "9.11.0", "glob": "8.1.0", "graphql": "16.8.1", - "graphql-ws": "5.14.0", + "graphql-ws": "5.14.1", "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", "jest-junit": "16.0.0", @@ -159,8 +159,8 @@ "react-dom-17": "npm:react-dom@^17", "react-error-boundary": "3.1.4", "recast": "0.23.4", - "resolve": "1.22.6", - "rimraf": "5.0.1", + "resolve": "1.22.8", + "rimraf": "5.0.5", "rollup": "2.79.1", "rollup-plugin-terser": "7.0.2", "rxjs": "7.8.1", From 2be7eafe3c115d56d993dbda64d320550712df1f Mon Sep 17 00:00:00 2001 From: ArioA Date: Mon, 16 Oct 2023 16:01:28 +0100 Subject: [PATCH 11/17] Don't crash if some (but not all) Error Codes are loaded (#11291) Co-authored-by: Lenz Weber-Tronic --- .changeset/heavy-camels-double.md | 5 +++++ src/dev/loadErrorMessageHandler.ts | 2 +- .../__tests__/invariantWrappers.test.ts | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 .changeset/heavy-camels-double.md diff --git a/.changeset/heavy-camels-double.md b/.changeset/heavy-camels-double.md new file mode 100644 index 00000000000..d236122b255 --- /dev/null +++ b/.changeset/heavy-camels-double.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +Fix a bug that allows to only call `loadErrorMessages` without also calling `loadDevErrorMessages`. diff --git a/src/dev/loadErrorMessageHandler.ts b/src/dev/loadErrorMessageHandler.ts index 199a6477b5c..ad18c159ed5 100644 --- a/src/dev/loadErrorMessageHandler.ts +++ b/src/dev/loadErrorMessageHandler.ts @@ -16,7 +16,7 @@ export function loadErrorMessageHandler(...errorCodes: ErrorCodes[]) { function handler(message: string | number, args: unknown[]) { if (typeof message === "number") { const definition = global[ApolloErrorMessageHandler]![message]; - if (!message || !definition.message) return; + if (!message || !definition?.message) return; message = definition.message; } return args.reduce( diff --git a/src/utilities/globals/__tests__/invariantWrappers.test.ts b/src/utilities/globals/__tests__/invariantWrappers.test.ts index f9255c170c8..2b750c534ed 100644 --- a/src/utilities/globals/__tests__/invariantWrappers.test.ts +++ b/src/utilities/globals/__tests__/invariantWrappers.test.ts @@ -99,3 +99,21 @@ test("invariant.log(5, ...), with handlers", () => { { a: 1 } ); }); + +test("base invariant(false, 6, ...), raises fallback", () => { + using _ = mockErrorMessageHandler(); + expect(() => { + invariant(false, 6, "hello"); + }).toThrow( + new InvariantError( + "An error occurred! For more details, see the full error text at https://go.apollo.dev/c/err#" + + encodeURIComponent( + JSON.stringify({ + version: "local", + message: 6, + args: ["hello"], + }) + ) + ) + ); +}); From b5894dbf0fd5ea5ef1ff20dd896a658ef78c69dc Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Mon, 16 Oct 2023 17:11:02 +0200 Subject: [PATCH 12/17] MockedProvider: default `connectToDevTools: false` (#11289) --- .api-reports/api-report-testing.md | 2 ++ .changeset/lucky-coats-march.md | 7 +++++++ src/testing/react/MockedProvider.tsx | 7 +++++++ 3 files changed, 16 insertions(+) create mode 100644 .changeset/lucky-coats-march.md diff --git a/.api-reports/api-report-testing.md b/.api-reports/api-report-testing.md index 90a4c964b6f..003206bda70 100644 --- a/.api-reports/api-report-testing.md +++ b/.api-reports/api-report-testing.md @@ -861,6 +861,8 @@ export interface MockedProviderProps { childProps?: object; // (undocumented) children?: any; + // (undocumented) + connectToDevTools?: boolean; // Warning: (ae-forgotten-export) The symbol "DefaultOptions" needs to be exported by the entry point index.d.ts // // (undocumented) diff --git a/.changeset/lucky-coats-march.md b/.changeset/lucky-coats-march.md new file mode 100644 index 00000000000..e26c21c6cee --- /dev/null +++ b/.changeset/lucky-coats-march.md @@ -0,0 +1,7 @@ +--- +"@apollo/client": patch +--- + +`MockedProvider`: default `connectToDevTools` to `false` in created `ApolloClient` instance. + +This will prevent the mocked `ApolloClient` instance from trying to connect to the DevTools, which would start a `setTimeout` that might keep running after a test has finished. diff --git a/src/testing/react/MockedProvider.tsx b/src/testing/react/MockedProvider.tsx index fcc3dfdb217..b7afb9d416c 100644 --- a/src/testing/react/MockedProvider.tsx +++ b/src/testing/react/MockedProvider.tsx @@ -20,6 +20,11 @@ export interface MockedProviderProps { children?: any; link?: ApolloLink; showWarnings?: boolean; + /** + * If set to true, the MockedProvider will try to connect to the Apollo DevTools. + * Defaults to false. + */ + connectToDevTools?: boolean; } export interface MockedProviderState { @@ -45,10 +50,12 @@ export class MockedProvider extends React.Component< resolvers, link, showWarnings, + connectToDevTools = false, } = this.props; const client = new ApolloClient({ cache: cache || new Cache({ addTypename }), defaultOptions, + connectToDevTools, link: link || new MockLink(mocks || [], addTypename, { showWarnings }), resolvers, }); From dd2ce7687ae9afa399e950a523fc7330284c25fe Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Mon, 16 Oct 2023 17:35:19 +0200 Subject: [PATCH 13/17] `cache.modify`: less strict types & dev runtime warnings (#11206) --- .api-reports/api-report-cache.md | 11 +- .api-reports/api-report-core.md | 11 +- .api-reports/api-report-react.md | 21 +- .api-reports/api-report-react_components.md | 21 +- .api-reports/api-report-react_context.md | 21 +- .api-reports/api-report-react_hoc.md | 21 +- .api-reports/api-report-react_hooks.md | 21 +- .api-reports/api-report-react_ssr.md | 21 +- .api-reports/api-report-testing.md | 21 +- .api-reports/api-report-testing_core.md | 21 +- .api-reports/api-report-utilities.md | 11 +- .api-reports/api-report.md | 11 +- .changeset/weak-worms-fetch.md | 5 + .size-limit.cjs | 4 +- src/cache/core/__tests__/cache.ts | 6 +- src/cache/core/types/common.ts | 12 +- src/cache/inmemory/__tests__/cache.ts | 220 ++++++++++++++++++++ src/cache/inmemory/entityStore.ts | 45 ++++ src/utilities/graphql/storeUtils.ts | 18 ++ src/utilities/index.ts | 1 + 20 files changed, 459 insertions(+), 64 deletions(-) create mode 100644 .changeset/weak-worms-fetch.md diff --git a/.api-reports/api-report-cache.md b/.api-reports/api-report-cache.md index e2135907143..34278f0c522 100644 --- a/.api-reports/api-report-cache.md +++ b/.api-reports/api-report-cache.md @@ -75,6 +75,13 @@ export type ApolloReducerConfig = { addTypename?: boolean; }; +// @public (undocumented) +type AsStoreObject = { + [K in keyof T]: T[K]; +}; + // @public (undocumented) type BroadcastOptions = Pick, "optimistic" | "onWatchUpdated">; @@ -875,8 +882,10 @@ export interface StoreObject { __typename?: string; } +// Warning: (ae-forgotten-export) The symbol "AsStoreObject" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type StoreObjectValueMaybeReference = StoreVal extends Record[] ? Readonly | readonly Reference[] : StoreVal extends Record ? StoreVal | Reference : StoreVal; +type StoreObjectValueMaybeReference = StoreVal extends Array> ? ReadonlyArray | Reference> : StoreVal extends Record ? AsStoreObject | Reference : StoreVal; // @public (undocumented) export type StoreValue = number | string | string[] | Reference | Reference[] | null | undefined | void | Object; diff --git a/.api-reports/api-report-core.md b/.api-reports/api-report-core.md index c5a2b4ae963..bd0acbce3df 100644 --- a/.api-reports/api-report-core.md +++ b/.api-reports/api-report-core.md @@ -271,6 +271,13 @@ export type ApolloReducerConfig = { addTypename?: boolean; }; +// @public (undocumented) +type AsStoreObject = { + [K in keyof T]: T[K]; +}; + // @public (undocumented) interface Body_2 { // (undocumented) @@ -2005,8 +2012,10 @@ export interface StoreObject { __typename?: string; } +// Warning: (ae-forgotten-export) The symbol "AsStoreObject" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type StoreObjectValueMaybeReference = StoreVal extends Record[] ? Readonly | readonly Reference[] : StoreVal extends Record ? StoreVal | Reference : StoreVal; +type StoreObjectValueMaybeReference = StoreVal extends Array> ? ReadonlyArray | Reference> : StoreVal extends Record ? AsStoreObject | Reference : StoreVal; // @public (undocumented) export type StoreValue = number | string | string[] | Reference | Reference[] | null | undefined | void | Object; diff --git a/.api-reports/api-report-react.md b/.api-reports/api-report-react.md index 1a92b739f41..8a6f21665bd 100644 --- a/.api-reports/api-report-react.md +++ b/.api-reports/api-report-react.md @@ -337,6 +337,13 @@ type ApolloQueryResult = { partial?: boolean; }; +// @public (undocumented) +type AsStoreObject = { + [K in keyof T]: T[K]; +}; + // Warning: (ae-forgotten-export) The symbol "WatchQueryFetchPolicy" needs to be exported by the entry point index.d.ts // // @public (undocumented) @@ -1849,8 +1856,10 @@ interface StoreObject { __typename?: string; } +// Warning: (ae-forgotten-export) The symbol "AsStoreObject" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type StoreObjectValueMaybeReference = StoreVal extends Record[] ? Readonly | readonly Reference[] : StoreVal extends Record ? StoreVal | Reference : StoreVal; +type StoreObjectValueMaybeReference = StoreVal extends Array> ? ReadonlyArray | Reference> : StoreVal extends Record ? AsStoreObject | Reference : StoreVal; // @public (undocumented) type StoreValue = number | string | string[] | Reference | Reference[] | null | undefined | void | Object; @@ -2184,11 +2193,11 @@ interface WatchQueryOptions = { partial?: boolean; }; +// @public (undocumented) +type AsStoreObject = { + [K in keyof T]: T[K]; +}; + // @public (undocumented) interface BaseMutationOptions = ApolloCache> extends Omit, "mutation"> { // Warning: (ae-forgotten-export) The symbol "ApolloClient" needs to be exported by the entry point index.d.ts @@ -1584,8 +1591,10 @@ interface StoreObject { __typename?: string; } +// Warning: (ae-forgotten-export) The symbol "AsStoreObject" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type StoreObjectValueMaybeReference = StoreVal extends Record[] ? Readonly | readonly Reference[] : StoreVal extends Record ? StoreVal | Reference : StoreVal; +type StoreObjectValueMaybeReference = StoreVal extends Array> ? ReadonlyArray | Reference> : StoreVal extends Record ? AsStoreObject | Reference : StoreVal; // @public (undocumented) type StoreValue = number | string | string[] | Reference | Reference[] | null | undefined | void | Object; @@ -1722,11 +1731,11 @@ interface WatchQueryOptions = { partial?: boolean; }; +// @public (undocumented) +type AsStoreObject = { + [K in keyof T]: T[K]; +}; + // @public (undocumented) interface BaseQueryOptions extends Omit, "query"> { // (undocumented) @@ -1519,8 +1526,10 @@ interface StoreObject { __typename?: string; } +// Warning: (ae-forgotten-export) The symbol "AsStoreObject" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type StoreObjectValueMaybeReference = StoreVal extends Record[] ? Readonly | readonly Reference[] : StoreVal extends Record ? StoreVal | Reference : StoreVal; +type StoreObjectValueMaybeReference = StoreVal extends Array> ? ReadonlyArray | Reference> : StoreVal extends Record ? AsStoreObject | Reference : StoreVal; // @public (undocumented) type StoreValue = number | string | string[] | Reference | Reference[] | null | undefined | void | Object; @@ -1620,11 +1629,11 @@ interface WatchQueryOptions = { partial?: boolean; }; +// @public (undocumented) +type AsStoreObject = { + [K in keyof T]: T[K]; +}; + // @public (undocumented) interface BaseMutationOptions = ApolloCache> extends Omit, "mutation"> { // Warning: (ae-forgotten-export) The symbol "ApolloClient" needs to be exported by the entry point index.d.ts @@ -1540,8 +1547,10 @@ interface StoreObject { __typename?: string; } +// Warning: (ae-forgotten-export) The symbol "AsStoreObject" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type StoreObjectValueMaybeReference = StoreVal extends Record[] ? Readonly | readonly Reference[] : StoreVal extends Record ? StoreVal | Reference : StoreVal; +type StoreObjectValueMaybeReference = StoreVal extends Array> ? ReadonlyArray | Reference> : StoreVal extends Record ? AsStoreObject | Reference : StoreVal; // @public (undocumented) type StoreValue = number | string | string[] | Reference | Reference[] | null | undefined | void | Object; @@ -1664,11 +1673,11 @@ export function withSubscription = { partial?: boolean; }; +// @public (undocumented) +type AsStoreObject = { + [K in keyof T]: T[K]; +}; + // Warning: (ae-forgotten-export) The symbol "WatchQueryFetchPolicy" needs to be exported by the entry point index.d.ts // // @public (undocumented) @@ -1742,8 +1749,10 @@ interface StoreObject { __typename?: string; } +// Warning: (ae-forgotten-export) The symbol "AsStoreObject" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type StoreObjectValueMaybeReference = StoreVal extends Record[] ? Readonly | readonly Reference[] : StoreVal extends Record ? StoreVal | Reference : StoreVal; +type StoreObjectValueMaybeReference = StoreVal extends Array> ? ReadonlyArray | Reference> : StoreVal extends Record ? AsStoreObject | Reference : StoreVal; // @public (undocumented) type StoreValue = number | string | string[] | Reference | Reference[] | null | undefined | void | Object; @@ -2075,11 +2084,11 @@ interface WatchQueryOptions = { partial?: boolean; }; +// @public (undocumented) +type AsStoreObject = { + [K in keyof T]: T[K]; +}; + // @public (undocumented) interface BaseQueryOptions extends Omit, "query"> { // Warning: (ae-forgotten-export) The symbol "ApolloClient" needs to be exported by the entry point index.d.ts @@ -1506,8 +1513,10 @@ interface StoreObject { __typename?: string; } +// Warning: (ae-forgotten-export) The symbol "AsStoreObject" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type StoreObjectValueMaybeReference = StoreVal extends Record[] ? Readonly | readonly Reference[] : StoreVal extends Record ? StoreVal | Reference : StoreVal; +type StoreObjectValueMaybeReference = StoreVal extends Array> ? ReadonlyArray | Reference> : StoreVal extends Record ? AsStoreObject | Reference : StoreVal; // @public (undocumented) type StoreValue = number | string | string[] | Reference | Reference[] | null | undefined | void | Object; @@ -1607,11 +1616,11 @@ interface WatchQueryOptions = { partial?: boolean; }; +// @public (undocumented) +type AsStoreObject = { + [K in keyof T]: T[K]; +}; + // @public (undocumented) namespace Cache_2 { // (undocumented) @@ -1538,8 +1545,10 @@ interface StoreObject { __typename?: string; } +// Warning: (ae-forgotten-export) The symbol "AsStoreObject" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type StoreObjectValueMaybeReference = StoreVal extends Record[] ? Readonly | readonly Reference[] : StoreVal extends Record ? StoreVal | Reference : StoreVal; +type StoreObjectValueMaybeReference = StoreVal extends Array> ? ReadonlyArray | Reference> : StoreVal extends Record ? AsStoreObject | Reference : StoreVal; // @public (undocumented) type StoreValue = number | string | string[] | Reference | Reference[] | null | undefined | void | Object; @@ -1657,11 +1666,11 @@ export function withWarningSpy(it: (...args: TArgs // Warnings were encountered during analysis: // // src/cache/core/types/DataProxy.ts:141:5 - (ae-forgotten-export) The symbol "MissingFieldError" needs to be exported by the entry point index.d.ts -// src/cache/core/types/common.ts:95:3 - (ae-forgotten-export) The symbol "ReadFieldFunction" needs to be exported by the entry point index.d.ts -// src/cache/core/types/common.ts:96:3 - (ae-forgotten-export) The symbol "CanReadFunction" needs to be exported by the entry point index.d.ts -// src/cache/core/types/common.ts:97:3 - (ae-forgotten-export) The symbol "isReference" needs to be exported by the entry point index.d.ts -// src/cache/core/types/common.ts:98:3 - (ae-forgotten-export) The symbol "ToReferenceFunction" needs to be exported by the entry point index.d.ts -// src/cache/core/types/common.ts:99:3 - (ae-forgotten-export) The symbol "StorageType" needs to be exported by the entry point index.d.ts +// src/cache/core/types/common.ts:96:3 - (ae-forgotten-export) The symbol "ReadFieldFunction" needs to be exported by the entry point index.d.ts +// src/cache/core/types/common.ts:97:3 - (ae-forgotten-export) The symbol "CanReadFunction" needs to be exported by the entry point index.d.ts +// src/cache/core/types/common.ts:98:3 - (ae-forgotten-export) The symbol "isReference" needs to be exported by the entry point index.d.ts +// src/cache/core/types/common.ts:99:3 - (ae-forgotten-export) The symbol "ToReferenceFunction" needs to be exported by the entry point index.d.ts +// src/cache/core/types/common.ts:100:3 - (ae-forgotten-export) The symbol "StorageType" needs to be exported by the entry point index.d.ts // src/core/ApolloClient.ts:47:3 - (ae-forgotten-export) The symbol "UriFunction" needs to be exported by the entry point index.d.ts // src/core/LocalState.ts:46:5 - (ae-forgotten-export) The symbol "FragmentMap" needs to be exported by the entry point index.d.ts // src/core/ObservableQuery.ts:112:5 - (ae-forgotten-export) The symbol "QueryManager" needs to be exported by the entry point index.d.ts diff --git a/.api-reports/api-report-testing_core.md b/.api-reports/api-report-testing_core.md index 6dd0aaf3bae..f5de976f0c6 100644 --- a/.api-reports/api-report-testing_core.md +++ b/.api-reports/api-report-testing_core.md @@ -297,6 +297,13 @@ type ApolloQueryResult = { partial?: boolean; }; +// @public (undocumented) +type AsStoreObject = { + [K in keyof T]: T[K]; +}; + // @public (undocumented) namespace Cache_2 { // (undocumented) @@ -1494,8 +1501,10 @@ interface StoreObject { __typename?: string; } +// Warning: (ae-forgotten-export) The symbol "AsStoreObject" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type StoreObjectValueMaybeReference = StoreVal extends Record[] ? Readonly | readonly Reference[] : StoreVal extends Record ? StoreVal | Reference : StoreVal; +type StoreObjectValueMaybeReference = StoreVal extends Array> ? ReadonlyArray | Reference> : StoreVal extends Record ? AsStoreObject | Reference : StoreVal; // @public (undocumented) type StoreValue = number | string | string[] | Reference | Reference[] | null | undefined | void | Object; @@ -1613,11 +1622,11 @@ export function withWarningSpy(it: (...args: TArgs // Warnings were encountered during analysis: // // src/cache/core/types/DataProxy.ts:141:5 - (ae-forgotten-export) The symbol "MissingFieldError" needs to be exported by the entry point index.d.ts -// src/cache/core/types/common.ts:95:3 - (ae-forgotten-export) The symbol "ReadFieldFunction" needs to be exported by the entry point index.d.ts -// src/cache/core/types/common.ts:96:3 - (ae-forgotten-export) The symbol "CanReadFunction" needs to be exported by the entry point index.d.ts -// src/cache/core/types/common.ts:97:3 - (ae-forgotten-export) The symbol "isReference" needs to be exported by the entry point index.d.ts -// src/cache/core/types/common.ts:98:3 - (ae-forgotten-export) The symbol "ToReferenceFunction" needs to be exported by the entry point index.d.ts -// src/cache/core/types/common.ts:99:3 - (ae-forgotten-export) The symbol "StorageType" needs to be exported by the entry point index.d.ts +// src/cache/core/types/common.ts:96:3 - (ae-forgotten-export) The symbol "ReadFieldFunction" needs to be exported by the entry point index.d.ts +// src/cache/core/types/common.ts:97:3 - (ae-forgotten-export) The symbol "CanReadFunction" needs to be exported by the entry point index.d.ts +// src/cache/core/types/common.ts:98:3 - (ae-forgotten-export) The symbol "isReference" needs to be exported by the entry point index.d.ts +// src/cache/core/types/common.ts:99:3 - (ae-forgotten-export) The symbol "ToReferenceFunction" needs to be exported by the entry point index.d.ts +// src/cache/core/types/common.ts:100:3 - (ae-forgotten-export) The symbol "StorageType" needs to be exported by the entry point index.d.ts // src/core/ApolloClient.ts:47:3 - (ae-forgotten-export) The symbol "UriFunction" needs to be exported by the entry point index.d.ts // src/core/LocalState.ts:46:5 - (ae-forgotten-export) The symbol "FragmentMap" needs to be exported by the entry point index.d.ts // src/core/ObservableQuery.ts:112:5 - (ae-forgotten-export) The symbol "QueryManager" needs to be exported by the entry point index.d.ts diff --git a/.api-reports/api-report-utilities.md b/.api-reports/api-report-utilities.md index f10def0a20a..742cf060348 100644 --- a/.api-reports/api-report-utilities.md +++ b/.api-reports/api-report-utilities.md @@ -329,6 +329,13 @@ type ApolloReducerConfig = { // @public (undocumented) export function argumentsObjectFromField(field: FieldNode | DirectiveNode, variables?: Record): Object | null; +// @public (undocumented) +export type AsStoreObject = { + [K in keyof T]: T[K]; +}; + // @public (undocumented) export function asyncMap(observable: Observable, mapFn: (value: V) => R | PromiseLike, catchFn?: (error: any) => R | PromiseLike): Observable; @@ -2291,7 +2298,7 @@ export interface StoreObject { } // @public (undocumented) -type StoreObjectValueMaybeReference = StoreVal extends Record[] ? Readonly | readonly Reference[] : StoreVal extends Record ? StoreVal | Reference : StoreVal; +type StoreObjectValueMaybeReference = StoreVal extends Array> ? ReadonlyArray | Reference> : StoreVal extends Record ? AsStoreObject | Reference : StoreVal; // @public (undocumented) export type StoreValue = number | string | string[] | Reference | Reference[] | null | undefined | void | Object; @@ -2515,7 +2522,7 @@ interface WriteContext extends ReadMergeModifyContext { // src/core/types.ts:178:3 - (ae-forgotten-export) The symbol "MutationQueryReducer" needs to be exported by the entry point index.d.ts // src/core/types.ts:205:5 - (ae-forgotten-export) The symbol "Resolver" needs to be exported by the entry point index.d.ts // src/core/watchQueryOptions.ts:191:3 - (ae-forgotten-export) The symbol "UpdateQueryFn" needs to be exported by the entry point index.d.ts -// src/utilities/graphql/storeUtils.ts:202:12 - (ae-forgotten-export) The symbol "stringify" needs to be exported by the entry point index.d.ts +// src/utilities/graphql/storeUtils.ts:220:12 - (ae-forgotten-export) The symbol "stringify" needs to be exported by the entry point index.d.ts // src/utilities/policies/pagination.ts:76:3 - (ae-forgotten-export) The symbol "TRelayEdge" needs to be exported by the entry point index.d.ts // src/utilities/policies/pagination.ts:77:3 - (ae-forgotten-export) The symbol "TRelayPageInfo" needs to be exported by the entry point index.d.ts diff --git a/.api-reports/api-report.md b/.api-reports/api-report.md index f30c67954a9..e3f49b900c0 100644 --- a/.api-reports/api-report.md +++ b/.api-reports/api-report.md @@ -310,6 +310,13 @@ export type ApolloReducerConfig = { addTypename?: boolean; }; +// @public (undocumented) +type AsStoreObject = { + [K in keyof T]: T[K]; +}; + // @public (undocumented) export type BackgroundQueryHookFetchPolicy = Extract; @@ -2452,8 +2459,10 @@ export interface StoreObject { __typename?: string; } +// Warning: (ae-forgotten-export) The symbol "AsStoreObject" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type StoreObjectValueMaybeReference = StoreVal extends Record[] ? Readonly | readonly Reference[] : StoreVal extends Record ? StoreVal | Reference : StoreVal; +type StoreObjectValueMaybeReference = StoreVal extends Array> ? ReadonlyArray | Reference> : StoreVal extends Record ? AsStoreObject | Reference : StoreVal; // @public (undocumented) export type StoreValue = number | string | string[] | Reference | Reference[] | null | undefined | void | Object; diff --git a/.changeset/weak-worms-fetch.md b/.changeset/weak-worms-fetch.md new file mode 100644 index 00000000000..ac65f76dd98 --- /dev/null +++ b/.changeset/weak-worms-fetch.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +`cache.modify`: Less strict types & new dev runtime warnings. diff --git a/.size-limit.cjs b/.size-limit.cjs index 223a3dce7ae..d63784ccf10 100644 --- a/.size-limit.cjs +++ b/.size-limit.cjs @@ -1,7 +1,7 @@ const checks = [ { path: "dist/apollo-client.min.cjs", - limit: "37960", + limit: "37956", }, { path: "dist/main.cjs", @@ -10,7 +10,7 @@ const checks = [ { path: "dist/index.js", import: "{ ApolloClient, InMemoryCache, HttpLink }", - limit: "31970", + limit: "32017", }, ...[ "ApolloProvider", diff --git a/src/cache/core/__tests__/cache.ts b/src/cache/core/__tests__/cache.ts index f456695c7b5..6ca7e77e8b6 100644 --- a/src/cache/core/__tests__/cache.ts +++ b/src/cache/core/__tests__/cache.ts @@ -374,7 +374,7 @@ describe.skip("Cache type tests", () => { }, children(field) { expectTypeOf(field).toEqualTypeOf< - ReadonlyArray<{ anotherObject: false }> | ReadonlyArray + ReadonlyArray<{ anotherObject: false } | Reference> >(); return field; }, @@ -440,7 +440,7 @@ describe.skip("Cache type tests", () => { id: "foo", fields(field) { expectTypeOf(field).toEqualTypeOf< - boolean | symbol | readonly OtherChildEntry[] | readonly Reference[] + boolean | symbol | ReadonlyArray >(); return field; }, @@ -477,7 +477,7 @@ describe.skip("Cache type tests", () => { id: "foo", fields(field) { expectTypeOf(field).toEqualTypeOf< - boolean | symbol | readonly OtherChildEntry[] | readonly Reference[] + boolean | symbol | ReadonlyArray >(); return field; }, diff --git a/src/cache/core/types/common.ts b/src/cache/core/types/common.ts index 052844014a0..19200d4845e 100644 --- a/src/cache/core/types/common.ts +++ b/src/cache/core/types/common.ts @@ -5,6 +5,7 @@ import type { StoreObject, StoreValue, isReference, + AsStoreObject, } from "../../../utilities/index.js"; import type { StorageType } from "../../inmemory/policies.js"; @@ -104,13 +105,12 @@ export type Modifier = ( details: ModifierDetails ) => T | DeleteModifier | InvalidateModifier; -type StoreObjectValueMaybeReference = StoreVal extends Record< - string, - any ->[] - ? Readonly | readonly Reference[] +type StoreObjectValueMaybeReference = StoreVal extends Array< + infer Item extends Record +> + ? ReadonlyArray | Reference> : StoreVal extends Record - ? StoreVal | Reference + ? AsStoreObject | Reference : StoreVal; export type AllFieldsModifier> = Modifier< diff --git a/src/cache/inmemory/__tests__/cache.ts b/src/cache/inmemory/__tests__/cache.ts index 498936c1e31..a7289cd2c64 100644 --- a/src/cache/inmemory/__tests__/cache.ts +++ b/src/cache/inmemory/__tests__/cache.ts @@ -18,6 +18,7 @@ import { StoreReader } from "../readFromStore"; import { StoreWriter } from "../writeToStore"; import { ObjectCanon } from "../object-canon"; import { TypePolicies } from "../policies"; +import { spyOnConsole } from "../../../testing/internal"; disableFragmentWarnings(); @@ -3454,6 +3455,225 @@ describe("InMemoryCache#modify", () => { expect(cache.extract()).toEqual(snapshot); }); + + it("warns if `modify` returns a mixed array of objects and references", () => { + const cache = new InMemoryCache(); + const query = gql` + query { + me { + id + books { + id + title + } + } + } + `; + + interface Book { + __typename: "Book"; + id: string; + title: string; + } + + const book1: Book = { __typename: "Book", id: "1", title: "1984" }; + const book2: Book = { __typename: "Book", id: "2", title: "The Odyssey" }; + const book3: Book = { __typename: "Book", id: "3", title: "The Hobbit" }; + const book4: Book = { __typename: "Book", id: "4", title: "The Swarm" }; + + cache.writeQuery({ + query, + data: { + me: { + __typename: "User", + id: "42", + books: [book1, book2, book3], + }, + }, + }); + + expect(cache.readQuery({ query })).toEqual({ + me: { + __typename: "User", + books: [book1, book2, book3], + id: "42", + }, + }); + + { + using consoleSpy = spyOnConsole("warn"); + cache.modify<{ books: Book[] }>({ + id: cache.identify({ __typename: "User", id: "42" }), + fields: { + books(existingBooks, { toReference }) { + return [toReference(existingBooks[2])!, book4]; + }, + }, + }); + expect(consoleSpy.warn).toHaveBeenLastCalledWith( + "cache.modify: Writing an array with a mix of both References and Objects will not result in the Objects being normalized correctly.\n" + + "Please convert the object instance %o to a Reference before writing it to the cache by calling `toReference(object, true)`.", + book4 + ); + } + }); + + it("warns if `modify` returns a Reference that is not part of the store as part of an array", () => { + const cache = new InMemoryCache(); + const query = gql` + query { + me { + id + books { + id + title + } + } + } + `; + + type Book = { + __typename: "Book"; + id: string; + title: string; + }; + + const book1: Book = { __typename: "Book", id: "1", title: "1984" }; + const book2: Book = { __typename: "Book", id: "2", title: "The Odyssey" }; + const book3: Book = { __typename: "Book", id: "3", title: "The Hobbit" }; + const book4: Book = { __typename: "Book", id: "4", title: "The Swarm" }; + + cache.writeQuery({ + query, + data: { + me: { + __typename: "User", + id: "42", + books: [book1, book2, book3], + }, + }, + }); + + expect(cache.readQuery({ query })).toEqual({ + me: { + __typename: "User", + books: [book1, book2, book3], + id: "42", + }, + }); + + { + using consoleSpy = spyOnConsole("warn"); + cache.modify<{ books: Book[] }>({ + id: cache.identify({ __typename: "User", id: "42" }), + fields: { + books(existingBooks, { toReference }) { + return [...existingBooks, toReference(book4)!]; + }, + }, + }); + expect(consoleSpy.warn).toHaveBeenLastCalledWith( + "cache.modify: You are trying to write a Reference that is not part of the store: %o\n" + + "Please make sure to set the `mergeIntoStore` parameter to `true` when creating a Reference that is not part of the store yet:\n" + + "`toReference(object, true)`", + { __ref: "Book:4" } + ); + } + + // reading the cache *looks* good to the user + expect(cache.readQuery({ query })).toEqual({ + me: { + __typename: "User", + // this is what we're warning about - book 4 is not in the store + books: [book1, book2, book3], + id: "42", + }, + }); + expect(cache.extract()).toEqual({ + ROOT_QUERY: { __typename: "Query", me: { __ref: "User:42" } }, + "Book:1": book1, + "Book:2": book2, + "Book:3": book3, + // no Book:4 + "User:42": { + __typename: "User", + id: "42", + // Book:4 here is a dead ref + books: [ + { __ref: "Book:1" }, + { __ref: "Book:2" }, + { __ref: "Book:3" }, + { __ref: "Book:4" }, + ], + }, + }); + }); + + it("warns if `modify` returns a Reference that is not part of the store", () => { + const cache = new InMemoryCache(); + const query = gql` + query { + me { + id + } + } + `; + + type User = { + __typename: string; + id: string; + }; + + cache.writeQuery({ + query, + data: { + me: { + __typename: "User", + id: "42", + }, + }, + }); + + expect(cache.readQuery({ query })).toEqual({ + me: { + __typename: "User", + id: "42", + }, + }); + + { + using consoleSpy = spyOnConsole("warn"); + cache.modify<{ me: User }>({ + id: "ROOT_QUERY", + fields: { + me(existingUser, { toReference }) { + return toReference({ + __typename: "User", + id: "43", + })!; + }, + }, + }); + expect(consoleSpy.warn).toHaveBeenLastCalledWith( + "cache.modify: You are trying to write a Reference that is not part of the store: %o\n" + + "Please make sure to set the `mergeIntoStore` parameter to `true` when creating a Reference that is not part of the store yet:\n" + + "`toReference(object, true)`", + { __ref: "User:43" } + ); + } + + // reading the cache returns `null` + expect(cache.readQuery({ query })).toEqual(null); + expect(cache.extract()).toEqual({ + // User:43 is a dead ref + ROOT_QUERY: { __typename: "Query", me: { __ref: "User:43" } }, + "User:42": { + __typename: "User", + id: "42", + }, + // no User:43 + }); + }); }); describe("ReactiveVar and makeVar", () => { diff --git a/src/cache/inmemory/entityStore.ts b/src/cache/inmemory/entityStore.ts index 024e694b220..ddb03b274da 100644 --- a/src/cache/inmemory/entityStore.ts +++ b/src/cache/inmemory/entityStore.ts @@ -257,6 +257,51 @@ export abstract class EntityStore implements NormalizedCache { changedFields[storeFieldName] = newValue; needToMerge = true; fieldValue = newValue; + + if (__DEV__) { + const checkReference = (ref: Reference) => { + if (this.lookup(ref.__ref) === undefined) { + invariant.warn( + "cache.modify: You are trying to write a Reference that is not part of the store: %o\n" + + "Please make sure to set the `mergeIntoStore` parameter to `true` when creating a Reference that is not part of the store yet:\n" + + "`toReference(object, true)`", + ref + ); + return true; + } + }; + if (isReference(newValue)) { + checkReference(newValue); + } else if (Array.isArray(newValue)) { + // Warn about writing "mixed" arrays of Reference and non-Reference objects + let seenReference: boolean = false; + let someNonReference: unknown; + for (const value of newValue) { + if (isReference(value)) { + seenReference = true; + if (checkReference(value)) break; + } else { + // Do not warn on primitive values, since those could never be represented + // by a reference. This is a valid (albeit uncommon) use case. + if (typeof value === "object" && !!value) { + const [id] = this.policies.identify(value); + // check if object could even be referenced, otherwise we are not interested in it for this warning + if (id) { + someNonReference = value; + } + } + } + if (seenReference && someNonReference !== undefined) { + invariant.warn( + "cache.modify: Writing an array with a mix of both References and Objects will not result in the Objects being normalized correctly.\n" + + "Please convert the object instance %o to a Reference before writing it to the cache by calling `toReference(object, true)`.", + someNonReference + ); + break; + } + } + } + } } } } diff --git a/src/utilities/graphql/storeUtils.ts b/src/utilities/graphql/storeUtils.ts index 606c3667f00..439a47359ea 100644 --- a/src/utilities/graphql/storeUtils.ts +++ b/src/utilities/graphql/storeUtils.ts @@ -55,6 +55,24 @@ export interface StoreObject { [storeFieldName: string]: StoreValue; } +/** + * Workaround for a TypeScript quirk: + * types per default have an implicit index signature that makes them + * assignable to `StoreObject`. + * interfaces do not have that implicit index signature, so they cannot + * be assigned to `StoreObject`. + * This type just maps over a type or interface that is passed in, + * implicitly adding the index signature. + * That way, the result can be assigned to `StoreObject`. + * + * This is important if some user-defined interface is used e.g. + * in cache.modify, where the `toReference` method expects a + * `StoreObject` as input. + */ +export type AsStoreObject = { + [K in keyof T]: T[K]; +}; + export function isDocumentNode(value: any): value is DocumentNode { return ( isNonNullObject(value) && diff --git a/src/utilities/index.ts b/src/utilities/index.ts index 6462f639fea..5f120fd4290 100644 --- a/src/utilities/index.ts +++ b/src/utilities/index.ts @@ -39,6 +39,7 @@ export { print } from "./graphql/print.js"; export type { StoreObject, + AsStoreObject, Reference, StoreValue, Directives, From 1cdaea21eff4aae260b116f4d7abe4d6df22a359 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 16 Oct 2023 09:45:16 -0600 Subject: [PATCH 14/17] Version Packages (#11283) Co-authored-by: github-actions[bot] --- .changeset/heavy-camels-double.md | 5 ----- .changeset/lemon-tigers-promise.md | 5 ----- .changeset/lucky-coats-march.md | 7 ------- .changeset/weak-worms-fetch.md | 5 ----- CHANGELOG.md | 14 ++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 7 files changed, 17 insertions(+), 25 deletions(-) delete mode 100644 .changeset/heavy-camels-double.md delete mode 100644 .changeset/lemon-tigers-promise.md delete mode 100644 .changeset/lucky-coats-march.md delete mode 100644 .changeset/weak-worms-fetch.md diff --git a/.changeset/heavy-camels-double.md b/.changeset/heavy-camels-double.md deleted file mode 100644 index d236122b255..00000000000 --- a/.changeset/heavy-camels-double.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@apollo/client": patch ---- - -Fix a bug that allows to only call `loadErrorMessages` without also calling `loadDevErrorMessages`. diff --git a/.changeset/lemon-tigers-promise.md b/.changeset/lemon-tigers-promise.md deleted file mode 100644 index 7c397bae3ad..00000000000 --- a/.changeset/lemon-tigers-promise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@apollo/client": patch ---- - -Start the query ref auto dispose timeout after the initial promise has settled. This prevents requests that run longer than the timeout duration from keeping the component suspended indefinitely. diff --git a/.changeset/lucky-coats-march.md b/.changeset/lucky-coats-march.md deleted file mode 100644 index e26c21c6cee..00000000000 --- a/.changeset/lucky-coats-march.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@apollo/client": patch ---- - -`MockedProvider`: default `connectToDevTools` to `false` in created `ApolloClient` instance. - -This will prevent the mocked `ApolloClient` instance from trying to connect to the DevTools, which would start a `setTimeout` that might keep running after a test has finished. diff --git a/.changeset/weak-worms-fetch.md b/.changeset/weak-worms-fetch.md deleted file mode 100644 index ac65f76dd98..00000000000 --- a/.changeset/weak-worms-fetch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@apollo/client": patch ---- - -`cache.modify`: Less strict types & new dev runtime warnings. diff --git a/CHANGELOG.md b/CHANGELOG.md index 22d3ee42b53..fa43468947b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # @apollo/client +## 3.8.6 + +### Patch Changes + +- [#11291](https://github.com/apollographql/apollo-client/pull/11291) [`2be7eafe3`](https://github.com/apollographql/apollo-client/commit/2be7eafe3c115d56d993dbda64d320550712df1f) Thanks [@ArioA](https://github.com/ArioA)! - Fix a bug that allows to only call `loadErrorMessages` without also calling `loadDevErrorMessages`. + +- [#11274](https://github.com/apollographql/apollo-client/pull/11274) [`b29f000f3`](https://github.com/apollographql/apollo-client/commit/b29f000f36f281e256809b5454eaeca2ec4450bf) Thanks [@jerelmiller](https://github.com/jerelmiller)! - Start the query ref auto dispose timeout after the initial promise has settled. This prevents requests that run longer than the timeout duration from keeping the component suspended indefinitely. + +- [#11289](https://github.com/apollographql/apollo-client/pull/11289) [`b5894dbf0`](https://github.com/apollographql/apollo-client/commit/b5894dbf0fd5ea5ef1ff20dd896a658ef78c69dc) Thanks [@phryneas](https://github.com/phryneas)! - `MockedProvider`: default `connectToDevTools` to `false` in created `ApolloClient` instance. + + This will prevent the mocked `ApolloClient` instance from trying to connect to the DevTools, which would start a `setTimeout` that might keep running after a test has finished. + +- [#11206](https://github.com/apollographql/apollo-client/pull/11206) [`dd2ce7687`](https://github.com/apollographql/apollo-client/commit/dd2ce7687ae9afa399e950a523fc7330284c25fe) Thanks [@phryneas](https://github.com/phryneas)! - `cache.modify`: Less strict types & new dev runtime warnings. + ## 3.8.5 ### Patch Changes diff --git a/package-lock.json b/package-lock.json index 43e648d575c..0e2dbb4c6ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@apollo/client", - "version": "3.8.5", + "version": "3.8.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@apollo/client", - "version": "3.8.5", + "version": "3.8.6", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index d782f1b8dbe..5261a172811 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@apollo/client", - "version": "3.8.5", + "version": "3.8.6", "description": "A fully-featured caching GraphQL client.", "private": true, "keywords": [ From 7d3cac9236163eb68cfbf00ac2cc1b4cafefc41f Mon Sep 17 00:00:00 2001 From: Alessia Bellisario Date: Mon, 16 Oct 2023 10:37:05 -0700 Subject: [PATCH 15/17] Update renovate.json to ignore glob (#11293) --- renovate.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index 9264bc08977..ac7f81ee4b8 100644 --- a/renovate.json +++ b/renovate.json @@ -33,6 +33,7 @@ "react-dom-17", "@testing-library/react-12", "@rollup/plugin-node-resolve", - "rollup" + "rollup", + "glob" ] } From 89374ca2c1cfe4da96bb7c7b0f8f9ce222a68909 Mon Sep 17 00:00:00 2001 From: Tobias Schlatter Date: Tue, 17 Oct 2023 10:11:07 +0200 Subject: [PATCH 16/17] Add delay in docs for loading state testing (#11287) --- docs/source/development-testing/testing.mdx | 3 + .../react/__tests__/MockedProvider.test.tsx | 66 ++++++++++++++++++- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/docs/source/development-testing/testing.mdx b/docs/source/development-testing/testing.mdx index 06a69d5db25..9821626749c 100644 --- a/docs/source/development-testing/testing.mdx +++ b/docs/source/development-testing/testing.mdx @@ -169,6 +169,9 @@ We can use the asynchronous `screen.findByText` method to query the DOM elements ```jsx it("should render dog", async () => { const dogMock = { + delay: 30 // to prevent React from batching the loading state away + // delay: Infinity // if you only want to test the loading state + request: { query: GET_DOG_QUERY, variables: { name: "Buck" } diff --git a/src/testing/react/__tests__/MockedProvider.test.tsx b/src/testing/react/__tests__/MockedProvider.test.tsx index 8dd2b3be043..eb18f3b3a9f 100644 --- a/src/testing/react/__tests__/MockedProvider.test.tsx +++ b/src/testing/react/__tests__/MockedProvider.test.tsx @@ -1,6 +1,6 @@ import React from "react"; import { DocumentNode } from "graphql"; -import { render, waitFor } from "@testing-library/react"; +import { render, screen, waitFor } from "@testing-library/react"; import gql from "graphql-tag"; import { itAsync, MockedResponse, MockLink } from "../../core"; @@ -708,6 +708,70 @@ describe("General use", () => { }).then(resolve, reject); } ); + + it("should support loading state testing with delay", async () => { + function Component({ username }: Variables) { + const { loading, data } = useQuery(query, { variables }); + + if (loading || data === undefined) return

Loading the user ID...

; + + return

The user ID is '{data.user.id}'

; + } + + const mocks: ReadonlyArray = [ + { + delay: 30, // prevent React from batching the loading state away + request: { + query, + variables, + }, + result: { data: { user } }, + }, + ]; + + render( + + + + ); + + expect( + await screen.findByText("Loading the user ID...") + ).toBeInTheDocument(); + expect( + await screen.findByText("The user ID is 'user_id'") + ).toBeInTheDocument(); + }); + + it("should support loading state testing with infinite delay", async () => { + function Component({ username }: Variables) { + const { loading, data } = useQuery(query, { variables }); + + if (loading || data === undefined) return

Loading the user ID...

; + + return

The user ID is '{data.user.id}'

; + } + + const mocks: ReadonlyArray = [ + { + delay: Infinity, // keep loading forever. + request: { + query, + variables, + }, + }, + ]; + + render( + + + + ); + + expect( + await screen.findByText("Loading the user ID...") + ).toBeInTheDocument(); + }); }); describe("@client testing", () => { From c8c76a522e593de0d06cff73fde2d9e88152bed6 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 17 Oct 2023 09:53:16 -0600 Subject: [PATCH 17/17] Add an explicit return type for `useReadQuery` (#11297) --- .api-reports/api-report-react.md | 12 +++++++--- .api-reports/api-report-react_hooks.md | 12 +++++++--- .api-reports/api-report.md | 12 +++++++--- .changeset/good-experts-repair.md | 5 +++++ src/react/hooks/index.ts | 1 + src/react/hooks/useReadQuery.ts | 31 +++++++++++++++++++++++++- 6 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 .changeset/good-experts-repair.md diff --git a/.api-reports/api-report-react.md b/.api-reports/api-report-react.md index 8a6f21665bd..267adc1a330 100644 --- a/.api-reports/api-report-react.md +++ b/.api-reports/api-report-react.md @@ -2101,11 +2101,17 @@ export function useQuery(rv: ReactiveVar): T; // @public (undocumented) -export function useReadQuery(queryRef: QueryReference): { +export function useReadQuery(queryRef: QueryReference): UseReadQueryResult; + +// @public (undocumented) +export interface UseReadQueryResult { + // (undocumented) data: TData; - networkStatus: NetworkStatus; + // (undocumented) error: ApolloError | undefined; -}; + // (undocumented) + networkStatus: NetworkStatus; +} // @public (undocumented) export function useSubscription(subscription: DocumentNode | TypedDocumentNode, options?: SubscriptionHookOptions, NoInfer>): SubscriptionResult; diff --git a/.api-reports/api-report-react_hooks.md b/.api-reports/api-report-react_hooks.md index cf0f649ed18..110739c8df9 100644 --- a/.api-reports/api-report-react_hooks.md +++ b/.api-reports/api-report-react_hooks.md @@ -1988,11 +1988,17 @@ export function useQuery(rv: ReactiveVar): T; // @public (undocumented) -export function useReadQuery(queryRef: QueryReference): { +export function useReadQuery(queryRef: QueryReference): UseReadQueryResult; + +// @public (undocumented) +export interface UseReadQueryResult { + // (undocumented) data: TData; - networkStatus: NetworkStatus; + // (undocumented) error: ApolloError | undefined; -}; + // (undocumented) + networkStatus: NetworkStatus; +} // Warning: (ae-forgotten-export) The symbol "SubscriptionHookOptions" needs to be exported by the entry point index.d.ts // diff --git a/.api-reports/api-report.md b/.api-reports/api-report.md index e3f49b900c0..3004669da51 100644 --- a/.api-reports/api-report.md +++ b/.api-reports/api-report.md @@ -2742,11 +2742,17 @@ export function useQuery(rv: ReactiveVar): T; // @public (undocumented) -export function useReadQuery(queryRef: QueryReference): { +export function useReadQuery(queryRef: QueryReference): UseReadQueryResult; + +// @public (undocumented) +export interface UseReadQueryResult { + // (undocumented) data: TData; - networkStatus: NetworkStatus; + // (undocumented) error: ApolloError | undefined; -}; + // (undocumented) + networkStatus: NetworkStatus; +} // @public (undocumented) export function useSubscription(subscription: DocumentNode | TypedDocumentNode, options?: SubscriptionHookOptions, NoInfer>): SubscriptionResult; diff --git a/.changeset/good-experts-repair.md b/.changeset/good-experts-repair.md new file mode 100644 index 00000000000..37aef92f934 --- /dev/null +++ b/.changeset/good-experts-repair.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +Add an explicit return type for the `useReadQuery` hook called `UseReadQueryResult`. Previously the return type of this hook was inferred from the return value. diff --git a/src/react/hooks/index.ts b/src/react/hooks/index.ts index 3aace0d3e9d..61d50665cac 100644 --- a/src/react/hooks/index.ts +++ b/src/react/hooks/index.ts @@ -11,6 +11,7 @@ export type { UseSuspenseQueryResult } from "./useSuspenseQuery.js"; export { useSuspenseQuery } from "./useSuspenseQuery.js"; export type { UseBackgroundQueryResult } from "./useBackgroundQuery.js"; export { useBackgroundQuery } from "./useBackgroundQuery.js"; +export type { UseReadQueryResult } from "./useReadQuery.js"; export { useReadQuery } from "./useReadQuery.js"; export { skipToken } from "./constants.js"; export type { SkipToken } from "./constants.js"; diff --git a/src/react/hooks/useReadQuery.ts b/src/react/hooks/useReadQuery.ts index 85d4b3026f1..e6a97e1446f 100644 --- a/src/react/hooks/useReadQuery.ts +++ b/src/react/hooks/useReadQuery.ts @@ -5,8 +5,37 @@ import { __use } from "./internal/index.js"; import { toApolloError } from "./useSuspenseQuery.js"; import { invariant } from "../../utilities/globals/index.js"; import { useSyncExternalStore } from "./useSyncExternalStore.js"; +import type { ApolloError } from "../../errors/index.js"; +import type { NetworkStatus } from "../../core/index.js"; -export function useReadQuery(queryRef: QueryReference) { +export interface UseReadQueryResult { + /** + * An object containing the result of your GraphQL query after it completes. + * + * This value might be `undefined` if a query results in one or more errors + * (depending on the query's `errorPolicy`). + */ + data: TData; + /** + * If the query produces one or more errors, this object contains either an + * array of `graphQLErrors` or a single `networkError`. Otherwise, this value + * is `undefined`. + * + * This property can be ignored when using the default `errorPolicy` or an + * `errorPolicy` of `none`. The hook will throw the error instead of setting + * this property. + */ + error: ApolloError | undefined; + /** + * A number indicating the current network state of the query's associated + * request. {@link https://github.com/apollographql/apollo-client/blob/d96f4578f89b933c281bb775a39503f6cdb59ee8/src/core/networkStatus.ts#L4 | See possible values}. + */ + networkStatus: NetworkStatus; +} + +export function useReadQuery( + queryRef: QueryReference +): UseReadQueryResult { const internalQueryRef = unwrapQueryRef(queryRef); invariant( internalQueryRef.promiseCache,