diff --git a/.changeset/forty-hats-tickle.md b/.changeset/forty-hats-tickle.md new file mode 100644 index 000000000..0d5b1422e --- /dev/null +++ b/.changeset/forty-hats-tickle.md @@ -0,0 +1,6 @@ +--- +"apollo-client-devtools": minor +"@apollo/client-devtools-vscode": minor +--- + +Add a memory panel to monitor internal Apollo Client caches. diff --git a/package-lock.json b/package-lock.json index c178c4cea..0fa5703f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,6 +48,7 @@ "zen-observable": "^0.10.0" }, "devDependencies": { + "@0no-co/graphqlsp": "^1.12.13", "@changesets/changelog-github": "0.5.0", "@changesets/cli": "2.27.10", "@graphql-codegen/cli": "5.0.3", @@ -110,6 +111,34 @@ "ws": "^8.18.0" } }, + "node_modules/@0no-co/graphql.web": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.0.7.tgz", + "integrity": "sha512-E3Qku4mTzdrlwVWGPxklDnME5ANrEGetvYw4i2GCRlppWXXE4QD66j7pwb8HelZwS6LnqEChhrSOGCXpbiu6MQ==", + "dev": true, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" + }, + "peerDependenciesMeta": { + "graphql": { + "optional": true + } + } + }, + "node_modules/@0no-co/graphqlsp": { + "version": "1.12.13", + "resolved": "https://registry.npmjs.org/@0no-co/graphqlsp/-/graphqlsp-1.12.13.tgz", + "integrity": "sha512-/C9yXft+mq+VdoniBgWvA+iK5X6cB50KKThg1je4bFIhhBNccLJlNbWFxOglXseKuisq+h5oIY4ELTVKs6GhRQ==", + "dev": true, + "dependencies": { + "@gql.tada/internal": "^1.0.0", + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0" + }, + "peerDependencies": { + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", + "typescript": "^5.0.0" + } + }, "node_modules/@adobe/css-tools": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz", @@ -3135,70 +3164,6 @@ "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", "optional": true }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/darwin-arm64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", @@ -3215,294 +3180,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -3662,6 +3339,19 @@ "npm": ">=7.0.0" } }, + "node_modules/@gql.tada/internal": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@gql.tada/internal/-/internal-1.0.6.tgz", + "integrity": "sha512-K5dKMqqU0pcNWS+/i6EnoUGvA7lW2Agwl+nepZOEWbGpG80aJxXfL+yAvaHihP5VqGZFOygyc3NDBo1mm+Z4KQ==", + "dev": true, + "dependencies": { + "@0no-co/graphql.web": "^1.0.5" + }, + "peerDependencies": { + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", + "typescript": "^5.0.0" + } + }, "node_modules/@graphql-codegen/add": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/@graphql-codegen/add/-/add-5.0.3.tgz", @@ -6351,26 +6041,6 @@ "@parcel/watcher-win32-x64": "2.4.1" } }, - "node_modules/@parcel/watcher-android-arm64": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz", - "integrity": "sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "node_modules/@parcel/watcher-darwin-arm64": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz", @@ -6391,206 +6061,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz", - "integrity": "sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz", - "integrity": "sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz", - "integrity": "sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz", - "integrity": "sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz", - "integrity": "sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz", - "integrity": "sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz", - "integrity": "sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz", - "integrity": "sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz", - "integrity": "sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-x64": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz", - "integrity": "sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -28052,12 +27522,12 @@ } }, "packages/apollo-client-devtools": { - "version": "4.19.0", + "version": "4.19.2", "license": "MIT" }, "packages/client-devtools-vscode": { "name": "@apollo/client-devtools-vscode", - "version": "4.19.0", + "version": "4.19.2", "license": "MIT", "dependencies": { "zen-observable": "^0.8.0" diff --git a/package.json b/package.json index a2a0614ae..35ce6399f 100755 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "zen-observable": "^0.10.0" }, "devDependencies": { + "@0no-co/graphqlsp": "^1.12.13", "@changesets/changelog-github": "0.5.0", "@changesets/cli": "2.27.10", "@graphql-codegen/cli": "5.0.3", diff --git a/src/application/App.tsx b/src/application/App.tsx index 838b84236..3ebc23f76 100644 --- a/src/application/App.tsx +++ b/src/application/App.tsx @@ -41,6 +41,7 @@ import { removeClient } from "."; import { PageError } from "./components/PageError"; import { SidebarLayout } from "./components/Layouts/SidebarLayout"; import { ExternalLink } from "./components/ExternalLink"; +import { MemoryInternals } from "./components/MemoryInternals"; const APP_QUERY: TypedDocumentNode = gql` query AppQuery { @@ -168,6 +169,7 @@ export const App = () => { Mutations ({client?.mutations.total ?? 0}) Cache + Memory Explorer
@@ -273,6 +275,14 @@ export const App = () => { + + + + + ); diff --git a/src/application/components/CacheSize.tsx b/src/application/components/CacheSize.tsx new file mode 100644 index 000000000..47a4176b6 --- /dev/null +++ b/src/application/components/CacheSize.tsx @@ -0,0 +1,290 @@ +import type { ReactNode } from "react"; +import IconOutlink from "@apollo/icons/small/IconOutlink.svg"; +import IconInfo from "@apollo/icons/default/IconInfo.svg"; +import IconWarning from "@apollo/icons/large/IconWarning.svg"; +import { ExternalLink } from "./ExternalLink"; +import { Tooltip } from "./Tooltip"; +import type { CacheSizes } from "@apollo/client/utilities"; +import type { CacheSize as CacheSizeType } from "../types/gql"; +import clsx from "clsx"; + +const DESCRIPTIONS: Record = { + print: ( + <> +

+ Cache size for the{" "} + + print + {" "} + function. +

+

+ It is called with transformed DocumentNodes. +

+

+ This method is called to transform a GraphQL query AST parsed by{" "} + gql back into a GraphQL string. +

+ + ), + parser: ( + <> +

+ Cache size for the{" "} + + parser + {" "} + function. +

+

+ It is called with user-provided DocumentNodes. +

+ + ), + canonicalStringify: ( +

+ Cache used by{" "} + + canonicalStringify + +

+ ), + "PersistedQueryLink.persistedQueryHashes": ( + <> +

+ A cache inside of + + PersistedQueryLink + + . +

+

+ It is called with transformed DocumentNodes. +

+ + ), + "removeTypenameFromVariables.getVariableDefinitions": ( + <> +

+ Cache used in + + removeTypenameFromVariables + + . +

+

+ This function is called transformed DocumentNodes. +

+ + ), + "queryManager.getDocumentInfo": ( + <> +

+ A cache inside of{" "} + + QueryManager + + . +

+

+ It is called with transformed DocumentNodes. +

+ + ), + "documentTransform.cache": ( + <> +

+ Cache size for the cache of + + DocumentTransform + {" "} + instances with the cache option set to true. +

+

+ Can be called with user-defined or already-transformed{" "} + DocumentNodes. +

+ + ), + "fragmentRegistry.lookup": ( + <> +

+ A cache inside of + + FragmentRegistry + + . +

+

+ This function is called with fragment names in the form of a string. +

+ + ), + "fragmentRegistry.findFragmentSpreads": ( + <> +

+ Cache size for the findFragmentSpreads method of + + FragmentRegistry + + . +

+

+ This function is called with transformed DocumentNodes, as + well as recursively with every fragment spread referenced within that, + or a fragment referenced by a fragment spread. +

+ + ), + "fragmentRegistry.transform": ( + <> +

+ A cache inside of + + FragmentRegistry + + . +

+

+ Can be called with user-defined or already-transformed{" "} + DocumentNodes. +

+ + ), + "cache.fragmentQueryDocuments": ( + <> +

+ Cache size for the getFragmentDoc method of + + ApolloCache + + . +

+

This function is called with user-provided fragment definitions.

+ + ), + "inMemoryCache.executeSelectionSet": ( + <> +

+ Cache size for the executeSelectionSet method on{" "} + + StoreReader + + . +

+

+ Note: executeSelectionSet will be set to the{" "} + resultCacheMaxSize option and will fall back to this + configuration value if the option is not set. +

+ + ), + "inMemoryCache.executeSubSelectedArray": ( + <> +

+ Cache size for the executeSubSelectedArray method on{" "} + + StoreReader + + . +

+ +

+ Note: executeSubSelectedArray will be set to the{" "} + resultCacheMaxSize option and will fall back to this + configuration value if the option is not set. +

+ + ), + "inMemoryCache.maybeBroadcastWatch": ( + <> +

+ Cache size for the maybeBroadcastWatch method on{" "} + + InMemoryCache + + . +

+

+ Note: maybeBroadcastWatch will be set to the{" "} + resultCacheMaxSize option and will fall back to this + configuration value if the option is not set. +

+ + ), +}; + +export function CacheSize({ cacheSize }: { cacheSize: CacheSizeType }) { + if (cacheSize.size === null || cacheSize.limit === null) { + return null; + } + + const description = DESCRIPTIONS[cacheSize.key as keyof CacheSizes]; + const percentUsed = (cacheSize.size / cacheSize.limit) * 100; + + return ( +
+

+ {cacheSize.key} + {description && ( + {description}

} + > + + + + + )} + +
+
+ + Size + + {cacheSize.size} +
+
+ + Limit + + {cacheSize.limit} +
+
= 90, + "text-warning dark:text-warning-dark": + percentUsed >= 70 && percentUsed < 90, + } + )} + > + {percentUsed > 70 ? ( + + ) : null} + {percentUsed > 0 && percentUsed < 1 + ? percentUsed.toFixed(1) === "0.0" + ? "<0.1" + : percentUsed.toFixed(1) + : Math.floor(percentUsed)} + % +
+
+
+ ); +} + +function TooltipLink({ + children, + href, +}: { + children: ReactNode; + href: string; +}) { + return ( + + {children} + + + ); +} diff --git a/src/application/components/Layouts/Navigation.tsx b/src/application/components/Layouts/Navigation.tsx index 14b94a84a..9465d3c0f 100644 --- a/src/application/components/Layouts/Navigation.tsx +++ b/src/application/components/Layouts/Navigation.tsx @@ -5,6 +5,7 @@ export enum Screens { Queries = "queries", Mutations = "mutations", Explorer = "explorer", + Memory = "memory", } export const currentScreen = makeVar(Screens.Queries); diff --git a/src/application/components/MemoryInternals.tsx b/src/application/components/MemoryInternals.tsx new file mode 100644 index 000000000..15a2ee2ac --- /dev/null +++ b/src/application/components/MemoryInternals.tsx @@ -0,0 +1,292 @@ +import type { TypedDocumentNode } from "@apollo/client"; +import { gql, NetworkStatus, useQuery } from "@apollo/client"; +import IconOutlink from "@apollo/icons/default/IconOutlink.svg"; +import IconOperations from "@apollo/icons/default/IconOperations.svg"; +import IconObserve from "@apollo/icons/default/IconObserve.svg"; + +import { FullWidthLayout } from "./Layouts/FullWidthLayout"; +import { PageSpinner } from "./PageSpinner"; +import type { + MemoryInternalsQuery, + MemoryInternalsQueryVariables, +} from "../types/gql"; +import type { ReactNode } from "react"; +import { useState } from "react"; +import { ButtonGroup } from "./ButtonGroup"; +import { Button } from "./Button"; +import { Tooltip } from "./Tooltip"; +import { JSONTreeViewer } from "./JSONTreeViewer"; +import { CacheSize } from "./CacheSize"; +import { lt } from "semver"; +import { ExternalLink } from "./ExternalLink"; +import { PageError } from "./PageError"; + +interface MemoryInternalsProps { + clientId: string | undefined; +} + +const MEMORY_INTERNALS_QUERY: TypedDocumentNode< + MemoryInternalsQuery, + MemoryInternalsQueryVariables +> = gql` + query MemoryInternalsQuery($clientId: ID!) { + client(id: $clientId) { + id + version + memoryInternals { + raw + caches { + print { + ...CacheSizeFields + } + parser { + ...CacheSizeFields + } + canonicalStringify { + ...CacheSizeFields + } + links { + ... on PersistedQueryLinkCacheSizes { + persistedQueryHashes { + ...CacheSizeFields + } + } + ... on RemoveTypenameFromVariablesLinkCacheSizes { + getVariableDefinitions { + ...CacheSizeFields + } + } + } + queryManager { + getDocumentInfo { + ...CacheSizeFields + } + documentTransforms { + cache { + ...CacheSizeFields + } + } + } + fragmentRegistry { + lookup { + ...CacheSizeFields + } + findFragmentSpreads { + ...CacheSizeFields + } + transform { + ...CacheSizeFields + } + } + cache { + fragmentQueryDocuments { + ...CacheSizeFields + } + } + addTypenameDocumentTransform { + cache { + ...CacheSizeFields + } + } + inMemoryCache { + maybeBroadcastWatch { + ...CacheSizeFields + } + executeSelectionSet { + ...CacheSizeFields + } + executeSubSelectedArray { + ...CacheSizeFields + } + } + } + } + } + } + + fragment CacheSizeFields on CacheSize { + key + size + limit + } +`; + +export function MemoryInternals({ clientId }: MemoryInternalsProps) { + const [selectedView, setSelectedView] = useState<"raw" | "chart">("chart"); + + const { data, networkStatus, error } = useQuery(MEMORY_INTERNALS_QUERY, { + variables: { clientId: clientId as string }, + skip: !clientId, + pollInterval: 1000, + }); + + if (error) { + throw error; + } + + const memoryInternals = data?.client?.memoryInternals; + const caches = memoryInternals?.caches; + const version = data?.client?.version; + + if (networkStatus === NetworkStatus.loading) { + return ( + + + + ); + } + + if (version && lt(version, "3.9.0")) { + return ( + + + + Memory management not available + + Memory management is available in Apollo Client{" "} + + 3.9.0 + + {" "} + or greater. Please upgrade your Apollo Client version to use this + feature. + + + + + ); + } + + if (!caches) { + return ( + + + + Unable to get memory internals + + Could not get memory internals for the client. This could be a + result of running your application in production mode since access + to memory internals is only available in development builds. + + + + + ); + } + + return ( + +
+
+

+ Memory +

+

+ Learn how Apollo Client manages memory and how to set custom cache + size limits in the{" "} + + docs + + + . +

+
+ + + +
+ + {selectedView === "chart" ? ( +
+ + + + + + + + + + + + + {caches.queryManager.documentTransforms?.map(({ cache }, index) => ( + + ))} + {caches.links.map((link, index) => ( + + ))} +
+ ) : selectedView === "raw" ? ( + true} + /> + ) : null} +
+
+ ); +} + +function EmptyLayout({ children }: { children: ReactNode }) { + return ( + +
+

+ Memory +

+

+ Learn how Apollo Client manages memory and how to set custom cache + size limits in the{" "} + + docs + + + . +

+
+ + {children} + +
+ ); +} diff --git a/src/application/components/Select/Select.tsx b/src/application/components/Select/Select.tsx index d73c7f203..178e76d52 100644 --- a/src/application/components/Select/Select.tsx +++ b/src/application/components/Select/Select.tsx @@ -48,11 +48,12 @@ const scrollIndicator = cva( "items-center", "justify-center", "cursor-default", - "w-full", "py-2", "bg-primary", "dark:bg-primary-dark", "z-10", + "left-px", + "right-px", ], { variants: { @@ -99,7 +100,7 @@ export const Select = ({ align={align} sideOffset={6} position="popper" - className="border border-primary bg-primary dark:bg-primary-dark dark:border-primary-dark shadow-dropdown overflow-hidden rounded-lg w-80 max-h-[calc(100vh-8rem)]" + className="border border-primary bg-primary dark:bg-primary-dark dark:border-primary-dark shadow-dropdown overflow-hidden rounded-lg min-w-80 max-h-[--radix-select-content-available-height]" > {content} diff --git a/src/application/index.tsx b/src/application/index.tsx index 8ab408a58..7ce8568bb 100755 --- a/src/application/index.tsx +++ b/src/application/index.tsx @@ -58,6 +58,9 @@ const cache = new InMemoryCache({ cache: { merge: false, }, + memoryInternals: { + merge: false, + }, }, }, ClientQueries: { diff --git a/src/application/localSchema.graphql b/src/application/localSchema.graphql index 3d55a36bd..348d56446 100644 --- a/src/application/localSchema.graphql +++ b/src/application/localSchema.graphql @@ -18,6 +18,16 @@ type Query { client(id: ID!): Client } +type BaseCacheSizes { + fragmentQueryDocuments: CacheSize! +} + +type CacheSize { + key: String! + limit: Int + size: Int +} + type Client { id: String! name: String @@ -25,6 +35,7 @@ type Client { queries: ClientQueries! mutations: ClientMutations! cache: Cache! + memoryInternals: MemoryInternals } type ClientQueries { @@ -37,6 +48,56 @@ type ClientMutations { items: [WatchedMutation!]! } +type DocumentTransformCacheSizes { + cache: CacheSize! +} + +type FragmentRegistryCacheSizes { + lookup: CacheSize! + findFragmentSpreads: CacheSize! + transform: CacheSize! +} + +type InMemoryCacheSizes { + maybeBroadcastWatch: CacheSize! + executeSelectionSet: CacheSize! + executeSubSelectedArray: CacheSize! +} + +union LinkCacheSize = + | PersistedQueryLinkCacheSizes + | RemoveTypenameFromVariablesLinkCacheSizes + +type MemoryInternals { + raw: JSON + caches: MemoryInternalsCaches! +} + +type MemoryInternalsCaches { + print: CacheSize! + parser: CacheSize! + canonicalStringify: CacheSize! + links: [LinkCacheSize!]! + queryManager: QueryManagerCacheSizes! + fragmentRegistry: FragmentRegistryCacheSizes! + cache: BaseCacheSizes! + addTypenameDocumentTransform: [DocumentTransformCacheSizes!] + inMemoryCache: InMemoryCacheSizes! +} + +type QueryManagerCacheSizes { + getDocumentInfo: CacheSize! + documentTransforms: [DocumentTransformCacheSizes!] +} + +type PersistedQueryLinkCacheSizes { + persistedQueryHashes: CacheSize! +} + +type RemoveTypenameFromVariablesLinkCacheSizes { + getVariableDefinitions: CacheSize! +} + type WatchedMutation { id: ID! name: String diff --git a/src/application/schema.ts b/src/application/schema.ts index d58a662fc..1345db416 100644 --- a/src/application/schema.ts +++ b/src/application/schema.ts @@ -1,7 +1,11 @@ import type { RpcClient } from "../extension/rpc"; import typeDefs from "./localSchema.graphql"; import { makeExecutableSchema } from "@graphql-tools/schema"; -import type { Resolvers } from "./types/resolvers"; +import type { + Resolvers, + PersistedQueryLinkCacheSizes, + RemoveTypenameFromVariablesLinkCacheSizes, +} from "./types/resolvers"; import { getOperationName } from "@apollo/client/utilities"; import { print } from "graphql"; @@ -24,6 +28,93 @@ function createResolvers(client: RpcClient): Resolvers { queries: (client) => client, mutations: (client) => client, cache: (client) => rpcClient.request("getCache", client.id), + memoryInternals: async (client) => { + const memoryInternals = await rpcClient.request( + "getMemoryInternals", + client.id + ); + + if (!memoryInternals) { + return null; + } + + const sizes = memoryInternals.sizes; + const limits = memoryInternals.limits; + + return { + raw: memoryInternals, + caches: { + print: getCacheSize("print", sizes.print, limits), + parser: getCacheSize("parser", sizes.parser, limits), + canonicalStringify: getCacheSize( + "canonicalStringify", + sizes.canonicalStringify, + limits + ), + links: sizes.links + .map((linkCache) => getLinkCacheSize(linkCache, limits)) + .filter(Boolean), + queryManager: { + getDocumentInfo: getCacheSize( + "queryManager.getDocumentInfo", + sizes.queryManager.getDocumentInfo, + limits + ), + documentTransforms: getDocumentTransformCacheSizes( + sizes.queryManager.documentTransforms, + limits + ), + }, + fragmentRegistry: { + lookup: getCacheSize( + "fragmentRegistry.lookup", + sizes.fragmentRegistry?.lookup, + limits + ), + findFragmentSpreads: getCacheSize( + "fragmentRegistry.findFragmentSpreads", + sizes.fragmentRegistry?.findFragmentSpreads, + limits + ), + transform: getCacheSize( + "fragmentRegistry.transform", + sizes.fragmentRegistry?.transform, + limits + ), + }, + cache: { + fragmentQueryDocuments: getCacheSize( + "cache.fragmentQueryDocuments", + sizes.cache?.fragmentQueryDocuments, + limits + ), + }, + addTypenameDocumentTransform: sizes.addTypenameDocumentTransform + ? getDocumentTransformCacheSizes( + sizes.addTypenameDocumentTransform, + limits + ) + : null, + inMemoryCache: { + maybeBroadcastWatch: getCacheSize( + "inMemoryCache.maybeBroadcastWatch", + sizes.inMemoryCache?.maybeBroadcastWatch, + limits + ), + executeSelectionSet: getCacheSize( + "inMemoryCache.executeSelectionSet", + sizes.inMemoryCache?.executeSelectionSet, + limits + ), + executeSubSelectedArray: getCacheSize( + "inMemoryCache.executeSubSelectedArray", + sizes.inMemoryCache?.executeSubSelectedArray, + limits + ), + }, + }, + }; + }, }, ClientQueries: { total: (client) => client.queryCount, @@ -79,3 +170,84 @@ function createResolvers(client: RpcClient): Resolvers { }, }; } + +type MemoryLimits = Record; + +function getCacheSize( + key: string, + size: number | undefined, + limits: MemoryLimits +) { + return { key, size: size ?? null, limit: limits[key] ?? null }; +} + +function getDocumentTransformCacheSizes( + caches: Array<{ cache: number }>, + limits: MemoryLimits +) { + return caches.map(({ cache }) => ({ + cache: getCacheSize("documentTransform.cache", cache, limits), + })); +} + +interface PersistedQueryLinkCache { + PersistedQueryLink: { + persistedQueryHashes: number; + }; +} + +function isPersistedQueryLinkCache( + cache: unknown +): cache is PersistedQueryLinkCache { + return ( + typeof cache === "object" && cache !== null && "PersistedQueryLink" in cache + ); +} + +interface RemoveTypenameFromVariablesLinkCache { + removeTypenameFromVariables: { + getVariableDefinitions: number; + }; +} + +function isRemoveTypenameFromVariablesLinkCache( + cache: unknown +): cache is RemoveTypenameFromVariablesLinkCache { + return ( + typeof cache === "object" && + cache !== null && + "removeTypenameFromVariables" in cache + ); +} + +function getLinkCacheSize( + linkCache: unknown, + limits: MemoryLimits +): + | PersistedQueryLinkCacheSizes + | RemoveTypenameFromVariablesLinkCacheSizes + | null { + if (isPersistedQueryLinkCache(linkCache)) { + return { + __typename: "PersistedQueryLinkCacheSizes", + persistedQueryHashes: getCacheSize( + "PersistedQueryLink.persistedQueryHashes", + linkCache.PersistedQueryLink.persistedQueryHashes, + limits + ), + } satisfies PersistedQueryLinkCacheSizes; + } + + if (isRemoveTypenameFromVariablesLinkCache(linkCache)) { + return { + __typename: "RemoveTypenameFromVariablesLinkCacheSizes", + getVariableDefinitions: getCacheSize( + "removeTypenameFromVariables.getVariableDefinitions", + linkCache.removeTypenameFromVariables.getVariableDefinitions, + limits + ), + } satisfies RemoveTypenameFromVariablesLinkCacheSizes; + } + + return null; +} diff --git a/src/application/types/gql.ts b/src/application/types/gql.ts index 42a8e4788..f5561d2ca 100644 --- a/src/application/types/gql.ts +++ b/src/application/types/gql.ts @@ -43,10 +43,23 @@ export type Scalars = { Variables: { input: Variables; output: Variables }; }; +export type BaseCacheSizes = { + __typename: "BaseCacheSizes"; + fragmentQueryDocuments: CacheSize; +}; + +export type CacheSize = { + __typename: "CacheSize"; + key: Scalars["String"]["output"]; + limit: Maybe; + size: Maybe; +}; + export type Client = { __typename: "Client"; cache: Scalars["Cache"]["output"]; id: Scalars["String"]["output"]; + memoryInternals: Maybe; mutations: ClientMutations; name: Maybe; queries: ClientQueries; @@ -65,12 +78,59 @@ export type ClientQueries = { total: Scalars["Int"]["output"]; }; +export type DocumentTransformCacheSizes = { + __typename: "DocumentTransformCacheSizes"; + cache: CacheSize; +}; + +export type FragmentRegistryCacheSizes = { + __typename: "FragmentRegistryCacheSizes"; + findFragmentSpreads: CacheSize; + lookup: CacheSize; + transform: CacheSize; +}; + export type GraphQLErrorSourceLocation = { __typename: "GraphQLErrorSourceLocation"; column: Scalars["Int"]["output"]; line: Scalars["Int"]["output"]; }; +export type InMemoryCacheSizes = { + __typename: "InMemoryCacheSizes"; + executeSelectionSet: CacheSize; + executeSubSelectedArray: CacheSize; + maybeBroadcastWatch: CacheSize; +}; + +export type LinkCacheSize = + | PersistedQueryLinkCacheSizes + | RemoveTypenameFromVariablesLinkCacheSizes; + +export type MemoryInternals = { + __typename: "MemoryInternals"; + caches: MemoryInternalsCaches; + raw: Maybe; +}; + +export type MemoryInternalsCaches = { + __typename: "MemoryInternalsCaches"; + addTypenameDocumentTransform: Maybe>; + cache: BaseCacheSizes; + canonicalStringify: CacheSize; + fragmentRegistry: FragmentRegistryCacheSizes; + inMemoryCache: InMemoryCacheSizes; + links: Array; + parser: CacheSize; + print: CacheSize; + queryManager: QueryManagerCacheSizes; +}; + +export type PersistedQueryLinkCacheSizes = { + __typename: "PersistedQueryLinkCacheSizes"; + persistedQueryHashes: CacheSize; +}; + export type Query = { __typename: "Query"; client: Maybe; @@ -81,6 +141,17 @@ export type QueryclientArgs = { id: Scalars["ID"]["input"]; }; +export type QueryManagerCacheSizes = { + __typename: "QueryManagerCacheSizes"; + documentTransforms: Maybe>; + getDocumentInfo: CacheSize; +}; + +export type RemoveTypenameFromVariablesLinkCacheSizes = { + __typename: "RemoveTypenameFromVariablesLinkCacheSizes"; + getVariableDefinitions: CacheSize; +}; + export type SerializedApolloError = { __typename: "SerializedApolloError"; clientErrors: Array; @@ -183,6 +254,148 @@ export type GetCache = { client: { __typename: "Client"; id: string; cache: Cache } | null; }; +export type MemoryInternalsQueryVariables = Exact<{ + clientId: Scalars["ID"]["input"]; +}>; + +export type MemoryInternalsQuery = { + client: { + __typename: "Client"; + id: string; + version: string; + memoryInternals: { + __typename: "MemoryInternals"; + raw: JSON | null; + caches: { + __typename: "MemoryInternalsCaches"; + print: { + __typename: "CacheSize"; + key: string; + size: number | null; + limit: number | null; + }; + parser: { + __typename: "CacheSize"; + key: string; + size: number | null; + limit: number | null; + }; + canonicalStringify: { + __typename: "CacheSize"; + key: string; + size: number | null; + limit: number | null; + }; + links: Array< + | { + __typename: "PersistedQueryLinkCacheSizes"; + persistedQueryHashes: { + __typename: "CacheSize"; + key: string; + size: number | null; + limit: number | null; + }; + } + | { + __typename: "RemoveTypenameFromVariablesLinkCacheSizes"; + getVariableDefinitions: { + __typename: "CacheSize"; + key: string; + size: number | null; + limit: number | null; + }; + } + >; + queryManager: { + __typename: "QueryManagerCacheSizes"; + getDocumentInfo: { + __typename: "CacheSize"; + key: string; + size: number | null; + limit: number | null; + }; + documentTransforms: Array<{ + __typename: "DocumentTransformCacheSizes"; + cache: { + __typename: "CacheSize"; + key: string; + size: number | null; + limit: number | null; + }; + }> | null; + }; + fragmentRegistry: { + __typename: "FragmentRegistryCacheSizes"; + lookup: { + __typename: "CacheSize"; + key: string; + size: number | null; + limit: number | null; + }; + findFragmentSpreads: { + __typename: "CacheSize"; + key: string; + size: number | null; + limit: number | null; + }; + transform: { + __typename: "CacheSize"; + key: string; + size: number | null; + limit: number | null; + }; + }; + cache: { + __typename: "BaseCacheSizes"; + fragmentQueryDocuments: { + __typename: "CacheSize"; + key: string; + size: number | null; + limit: number | null; + }; + }; + addTypenameDocumentTransform: Array<{ + __typename: "DocumentTransformCacheSizes"; + cache: { + __typename: "CacheSize"; + key: string; + size: number | null; + limit: number | null; + }; + }> | null; + inMemoryCache: { + __typename: "InMemoryCacheSizes"; + maybeBroadcastWatch: { + __typename: "CacheSize"; + key: string; + size: number | null; + limit: number | null; + }; + executeSelectionSet: { + __typename: "CacheSize"; + key: string; + size: number | null; + limit: number | null; + }; + executeSubSelectedArray: { + __typename: "CacheSize"; + key: string; + size: number | null; + limit: number | null; + }; + }; + }; + } | null; + } | null; +}; + +export type CacheSizeFields = { + __typename: "CacheSize"; + key: string; + size: number | null; + limit: number | null; +}; + export type GetMutationsVariables = Exact<{ id: Scalars["ID"]["input"]; }>; diff --git a/src/application/types/resolvers.ts b/src/application/types/resolvers.ts index 5b0c412d8..774852f66 100644 --- a/src/application/types/resolvers.ts +++ b/src/application/types/resolvers.ts @@ -56,10 +56,23 @@ export type Scalars = { Variables: { input: Variables; output: Variables }; }; +export type BaseCacheSizes = { + __typename?: "BaseCacheSizes"; + fragmentQueryDocuments: CacheSize; +}; + +export type CacheSize = { + __typename?: "CacheSize"; + key: Scalars["String"]["output"]; + limit?: Maybe; + size?: Maybe; +}; + export type Client = { __typename?: "Client"; cache: Scalars["Cache"]["output"]; id: Scalars["String"]["output"]; + memoryInternals?: Maybe; mutations: ClientMutations; name?: Maybe; queries: ClientQueries; @@ -78,12 +91,59 @@ export type ClientQueries = { total: Scalars["Int"]["output"]; }; +export type DocumentTransformCacheSizes = { + __typename?: "DocumentTransformCacheSizes"; + cache: CacheSize; +}; + +export type FragmentRegistryCacheSizes = { + __typename?: "FragmentRegistryCacheSizes"; + findFragmentSpreads: CacheSize; + lookup: CacheSize; + transform: CacheSize; +}; + export type GraphQlErrorSourceLocation = { __typename?: "GraphQLErrorSourceLocation"; column: Scalars["Int"]["output"]; line: Scalars["Int"]["output"]; }; +export type InMemoryCacheSizes = { + __typename?: "InMemoryCacheSizes"; + executeSelectionSet: CacheSize; + executeSubSelectedArray: CacheSize; + maybeBroadcastWatch: CacheSize; +}; + +export type LinkCacheSize = + | PersistedQueryLinkCacheSizes + | RemoveTypenameFromVariablesLinkCacheSizes; + +export type MemoryInternals = { + __typename?: "MemoryInternals"; + caches: MemoryInternalsCaches; + raw?: Maybe; +}; + +export type MemoryInternalsCaches = { + __typename?: "MemoryInternalsCaches"; + addTypenameDocumentTransform?: Maybe>; + cache: BaseCacheSizes; + canonicalStringify: CacheSize; + fragmentRegistry: FragmentRegistryCacheSizes; + inMemoryCache: InMemoryCacheSizes; + links: Array; + parser: CacheSize; + print: CacheSize; + queryManager: QueryManagerCacheSizes; +}; + +export type PersistedQueryLinkCacheSizes = { + __typename?: "PersistedQueryLinkCacheSizes"; + persistedQueryHashes: CacheSize; +}; + export type Query = { __typename?: "Query"; client?: Maybe; @@ -94,6 +154,17 @@ export type QueryClientArgs = { id: Scalars["ID"]["input"]; }; +export type QueryManagerCacheSizes = { + __typename?: "QueryManagerCacheSizes"; + documentTransforms?: Maybe>; + getDocumentInfo: CacheSize; +}; + +export type RemoveTypenameFromVariablesLinkCacheSizes = { + __typename?: "RemoveTypenameFromVariablesLinkCacheSizes"; + getVariableDefinitions: CacheSize; +}; + export type SerializedApolloError = { __typename?: "SerializedApolloError"; clientErrors: Array; @@ -257,24 +328,44 @@ export type DirectiveResolverFn< /** Mapping of union types */ export type ResolversUnionTypes<_RefType extends Record> = { + LinkCacheSize: + | PersistedQueryLinkCacheSizes + | RemoveTypenameFromVariablesLinkCacheSizes; WatchedMutationError: RpcSerializedApolloError | RpcSerializedError; }; /** Mapping between all available schema types and the resolvers types */ export type ResolversTypes = { + BaseCacheSizes: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; Cache: ResolverTypeWrapper; + CacheSize: ResolverTypeWrapper; Client: ResolverTypeWrapper; ClientMutations: ResolverTypeWrapper; ClientQueries: ResolverTypeWrapper; + DocumentTransformCacheSizes: ResolverTypeWrapper; + FragmentRegistryCacheSizes: ResolverTypeWrapper; GraphQLErrorPath: ResolverTypeWrapper; GraphQLErrorSourceLocation: ResolverTypeWrapper; ID: ResolverTypeWrapper; + InMemoryCacheSizes: ResolverTypeWrapper; Int: ResolverTypeWrapper; JSON: ResolverTypeWrapper; + LinkCacheSize: ResolverTypeWrapper< + ResolversUnionTypes["LinkCacheSize"] + >; + MemoryInternals: ResolverTypeWrapper; + MemoryInternalsCaches: ResolverTypeWrapper< + Omit & { + links: Array; + } + >; + PersistedQueryLinkCacheSizes: ResolverTypeWrapper; Query: ResolverTypeWrapper; QueryData: ResolverTypeWrapper; + QueryManagerCacheSizes: ResolverTypeWrapper; QueryOptions: ResolverTypeWrapper; + RemoveTypenameFromVariablesLinkCacheSizes: ResolverTypeWrapper; SerializedApolloError: ResolverTypeWrapper; SerializedError: ResolverTypeWrapper; SerializedGraphQLError: ResolverTypeWrapper; @@ -302,19 +393,32 @@ export type ResolversTypes = { /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = { + BaseCacheSizes: BaseCacheSizes; Boolean: Scalars["Boolean"]["output"]; Cache: Scalars["Cache"]["output"]; + CacheSize: CacheSize; Client: ApolloClientInfo; ClientMutations: ApolloClientInfo; ClientQueries: ApolloClientInfo; + DocumentTransformCacheSizes: DocumentTransformCacheSizes; + FragmentRegistryCacheSizes: FragmentRegistryCacheSizes; GraphQLErrorPath: Scalars["GraphQLErrorPath"]["output"]; GraphQLErrorSourceLocation: GraphQlErrorSourceLocation; ID: Scalars["ID"]["output"]; + InMemoryCacheSizes: InMemoryCacheSizes; Int: Scalars["Int"]["output"]; JSON: Scalars["JSON"]["output"]; + LinkCacheSize: ResolversUnionTypes["LinkCacheSize"]; + MemoryInternals: MemoryInternals; + MemoryInternalsCaches: Omit & { + links: Array; + }; + PersistedQueryLinkCacheSizes: PersistedQueryLinkCacheSizes; Query: never; QueryData: Scalars["QueryData"]["output"]; + QueryManagerCacheSizes: QueryManagerCacheSizes; QueryOptions: Scalars["QueryOptions"]["output"]; + RemoveTypenameFromVariablesLinkCacheSizes: RemoveTypenameFromVariablesLinkCacheSizes; SerializedApolloError: RpcSerializedApolloError; SerializedError: RpcSerializedError; SerializedGraphQLError: GraphQLFormattedError; @@ -332,11 +436,35 @@ export type ResolversParentTypes = { }; }; +export type BaseCacheSizesResolvers< + ContextType = any, + ParentType extends + ResolversParentTypes["BaseCacheSizes"] = ResolversParentTypes["BaseCacheSizes"], +> = { + fragmentQueryDocuments?: Resolver< + ResolversTypes["CacheSize"], + ParentType, + ContextType + >; + __isTypeOf?: IsTypeOfResolverFn; +}; + export interface CacheScalarConfig extends GraphQLScalarTypeConfig { name: "Cache"; } +export type CacheSizeResolvers< + ContextType = any, + ParentType extends + ResolversParentTypes["CacheSize"] = ResolversParentTypes["CacheSize"], +> = { + key?: Resolver; + limit?: Resolver, ParentType, ContextType>; + size?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}; + export type ClientResolvers< ContextType = any, ParentType extends @@ -344,6 +472,11 @@ export type ClientResolvers< > = { cache?: Resolver; id?: Resolver; + memoryInternals?: Resolver< + Maybe, + ParentType, + ContextType + >; mutations?: Resolver< ResolversTypes["ClientMutations"], ParentType, @@ -383,6 +516,30 @@ export type ClientQueriesResolvers< __isTypeOf?: IsTypeOfResolverFn; }; +export type DocumentTransformCacheSizesResolvers< + ContextType = any, + ParentType extends + ResolversParentTypes["DocumentTransformCacheSizes"] = ResolversParentTypes["DocumentTransformCacheSizes"], +> = { + cache?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}; + +export type FragmentRegistryCacheSizesResolvers< + ContextType = any, + ParentType extends + ResolversParentTypes["FragmentRegistryCacheSizes"] = ResolversParentTypes["FragmentRegistryCacheSizes"], +> = { + findFragmentSpreads?: Resolver< + ResolversTypes["CacheSize"], + ParentType, + ContextType + >; + lookup?: Resolver; + transform?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}; + export interface GraphQlErrorPathScalarConfig extends GraphQLScalarTypeConfig { name: "GraphQLErrorPath"; @@ -398,11 +555,115 @@ export type GraphQlErrorSourceLocationResolvers< __isTypeOf?: IsTypeOfResolverFn; }; +export type InMemoryCacheSizesResolvers< + ContextType = any, + ParentType extends + ResolversParentTypes["InMemoryCacheSizes"] = ResolversParentTypes["InMemoryCacheSizes"], +> = { + executeSelectionSet?: Resolver< + ResolversTypes["CacheSize"], + ParentType, + ContextType + >; + executeSubSelectedArray?: Resolver< + ResolversTypes["CacheSize"], + ParentType, + ContextType + >; + maybeBroadcastWatch?: Resolver< + ResolversTypes["CacheSize"], + ParentType, + ContextType + >; + __isTypeOf?: IsTypeOfResolverFn; +}; + export interface JsonScalarConfig extends GraphQLScalarTypeConfig { name: "JSON"; } +export type LinkCacheSizeResolvers< + ContextType = any, + ParentType extends + ResolversParentTypes["LinkCacheSize"] = ResolversParentTypes["LinkCacheSize"], +> = { + __resolveType: TypeResolveFn< + | "PersistedQueryLinkCacheSizes" + | "RemoveTypenameFromVariablesLinkCacheSizes", + ParentType, + ContextType + >; +}; + +export type MemoryInternalsResolvers< + ContextType = any, + ParentType extends + ResolversParentTypes["MemoryInternals"] = ResolversParentTypes["MemoryInternals"], +> = { + caches?: Resolver< + ResolversTypes["MemoryInternalsCaches"], + ParentType, + ContextType + >; + raw?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}; + +export type MemoryInternalsCachesResolvers< + ContextType = any, + ParentType extends + ResolversParentTypes["MemoryInternalsCaches"] = ResolversParentTypes["MemoryInternalsCaches"], +> = { + addTypenameDocumentTransform?: Resolver< + Maybe>, + ParentType, + ContextType + >; + cache?: Resolver; + canonicalStringify?: Resolver< + ResolversTypes["CacheSize"], + ParentType, + ContextType + >; + fragmentRegistry?: Resolver< + ResolversTypes["FragmentRegistryCacheSizes"], + ParentType, + ContextType + >; + inMemoryCache?: Resolver< + ResolversTypes["InMemoryCacheSizes"], + ParentType, + ContextType + >; + links?: Resolver< + Array, + ParentType, + ContextType + >; + parser?: Resolver; + print?: Resolver; + queryManager?: Resolver< + ResolversTypes["QueryManagerCacheSizes"], + ParentType, + ContextType + >; + __isTypeOf?: IsTypeOfResolverFn; +}; + +export type PersistedQueryLinkCacheSizesResolvers< + ContextType = any, + ParentType extends + ResolversParentTypes["PersistedQueryLinkCacheSizes"] = ResolversParentTypes["PersistedQueryLinkCacheSizes"], +> = { + persistedQueryHashes?: Resolver< + ResolversTypes["CacheSize"], + ParentType, + ContextType + >; + __isTypeOf?: IsTypeOfResolverFn; +}; + export type QueryResolvers< ContextType = any, ParentType extends @@ -422,11 +683,42 @@ export interface QueryDataScalarConfig name: "QueryData"; } +export type QueryManagerCacheSizesResolvers< + ContextType = any, + ParentType extends + ResolversParentTypes["QueryManagerCacheSizes"] = ResolversParentTypes["QueryManagerCacheSizes"], +> = { + documentTransforms?: Resolver< + Maybe>, + ParentType, + ContextType + >; + getDocumentInfo?: Resolver< + ResolversTypes["CacheSize"], + ParentType, + ContextType + >; + __isTypeOf?: IsTypeOfResolverFn; +}; + export interface QueryOptionsScalarConfig extends GraphQLScalarTypeConfig { name: "QueryOptions"; } +export type RemoveTypenameFromVariablesLinkCacheSizesResolvers< + ContextType = any, + ParentType extends + ResolversParentTypes["RemoveTypenameFromVariablesLinkCacheSizes"] = ResolversParentTypes["RemoveTypenameFromVariablesLinkCacheSizes"], +> = { + getVariableDefinitions?: Resolver< + ResolversTypes["CacheSize"], + ParentType, + ContextType + >; + __isTypeOf?: IsTypeOfResolverFn; +}; + export type SerializedApolloErrorResolvers< ContextType = any, ParentType extends @@ -579,16 +871,27 @@ export type WatchedQueryResolvers< }; export type Resolvers = { + BaseCacheSizes?: BaseCacheSizesResolvers; Cache?: GraphQLScalarType; + CacheSize?: CacheSizeResolvers; Client?: ClientResolvers; ClientMutations?: ClientMutationsResolvers; ClientQueries?: ClientQueriesResolvers; + DocumentTransformCacheSizes?: DocumentTransformCacheSizesResolvers; + FragmentRegistryCacheSizes?: FragmentRegistryCacheSizesResolvers; GraphQLErrorPath?: GraphQLScalarType; GraphQLErrorSourceLocation?: GraphQlErrorSourceLocationResolvers; + InMemoryCacheSizes?: InMemoryCacheSizesResolvers; JSON?: GraphQLScalarType; + LinkCacheSize?: LinkCacheSizeResolvers; + MemoryInternals?: MemoryInternalsResolvers; + MemoryInternalsCaches?: MemoryInternalsCachesResolvers; + PersistedQueryLinkCacheSizes?: PersistedQueryLinkCacheSizesResolvers; Query?: QueryResolvers; QueryData?: GraphQLScalarType; + QueryManagerCacheSizes?: QueryManagerCacheSizesResolvers; QueryOptions?: GraphQLScalarType; + RemoveTypenameFromVariablesLinkCacheSizes?: RemoveTypenameFromVariablesLinkCacheSizesResolvers; SerializedApolloError?: SerializedApolloErrorResolvers; SerializedError?: SerializedErrorResolvers; SerializedGraphQLError?: SerializedGraphQlErrorResolvers; diff --git a/src/extension/rpc.ts b/src/extension/rpc.ts index d9596d369..0a0ea6637 100644 --- a/src/extension/rpc.ts +++ b/src/extension/rpc.ts @@ -1,6 +1,11 @@ import type { ErrorCodes } from "@apollo/client/invariantErrorCodes"; import type { JSONObject } from "../application/types/json"; -import type { ApolloClientInfo, NoInfer, SafeAny } from "../types"; +import type { + ApolloClientInfo, + MemoryInternals, + NoInfer, + SafeAny, +} from "../types"; import { createId } from "../utils/createId"; import { RPC_MESSAGE_TIMEOUT } from "./errorMessages"; import { deserializeError, serializeError } from "./errorSerialization"; @@ -15,6 +20,7 @@ export type RPCRequest = { getMutations(clientId: string): MutationDetails[]; getCache(clientId: string): JSONObject; getErrorCodes(version: string): Promise; + getMemoryInternals(clientId: string): MemoryInternals | undefined; }; export interface RpcClient { diff --git a/src/extension/tab/hook.ts b/src/extension/tab/hook.ts index d17d42f97..7fc00ae52 100755 --- a/src/extension/tab/hook.ts +++ b/src/extension/tab/hook.ts @@ -131,6 +131,10 @@ handleRpc("getCache", (clientId) => { return getClientById(clientId)?.cache.extract(true) ?? {}; }); +handleRpc("getMemoryInternals", (clientId) => { + return getClientById(clientId)?.getMemoryInternals?.(); +}); + function getClientById(clientId: string) { const [client] = [...knownClients.entries()].find(([, id]) => id === clientId) ?? []; diff --git a/src/extension/vscode/client.ts b/src/extension/vscode/client.ts index deee8fe9d..2017709ae 100644 --- a/src/extension/vscode/client.ts +++ b/src/extension/vscode/client.ts @@ -110,8 +110,12 @@ function registerClient( function getMutationsForClient() { return getMutations(getClient()?.queryManager.mutationStore ?? {}); } + function getMemoryInternalsForClient() { + return getClient()?.getMemoryInternals?.(); + } wsRpcHandler("getQueries", getQueriesForClient, { signal }); wsRpcHandler("getMutations", getMutationsForClient, { signal }); + wsRpcHandler("getMemoryInternals", getMemoryInternalsForClient, { signal }); wsRpcHandler("getCache", () => getClient()?.cache.extract(true) ?? {}, { signal, }); diff --git a/src/extension/vscode/server.ts b/src/extension/vscode/server.ts index d31c16df8..113d7c31e 100644 --- a/src/extension/vscode/server.ts +++ b/src/extension/vscode/server.ts @@ -45,6 +45,10 @@ export function runServer( clients.get(id)!.rpcClient.request("getCache", id) ); + handleRpc("getMemoryInternals", (id) => + clients.get(id)!.rpcClient.request("getMemoryInternals", id) + ); + server.on("connection", function connection(ws) { let id: string | undefined; const wsAdapter = createSocketMessageAdapter(ws); diff --git a/src/types.ts b/src/types.ts index f18c0bc4a..b06968bf1 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import type { ApolloQueryResult } from "@apollo/client"; +import type { ApolloClient, ApolloQueryResult } from "@apollo/client"; export type QueryResult = ApolloQueryResult; @@ -26,3 +26,7 @@ export interface ApolloClientInfo { queryCount: number; mutationCount: number; } + +export type MemoryInternals = ReturnType< + NonNullable["getMemoryInternals"]> +>; diff --git a/tsconfig.json b/tsconfig.json index c358c632c..fbb27a3d0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,7 +14,13 @@ "strict": true, "forceConsistentCasingInFileNames": true, "declaration": true, - "outDir": "dist" + "outDir": "dist", + "plugins": [ + { + "name": "@0no-co/graphqlsp", + "schema": "./src/application/localSchema.graphql" + } + ] }, "$schema": "https://json.schemastore.org/tsconfig", "compileOnSave": true,