diff --git a/.prettierignore b/.prettierignore index 75c879f900e..667548ca807 100644 --- a/.prettierignore +++ b/.prettierignore @@ -10,3 +10,5 @@ docs/.cache/ # Don't format generated files! **/generated/** + +.volta diff --git a/CHANGELOG.md b/CHANGELOG.md index ad909c31bfb..e8be3244870 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,11 @@ The version headers in this history reflect the versions of Apollo Server itself - [`@apollo/gateway`](https://github.com/apollographql/federation/blob/HEAD/gateway-js/CHANGELOG.md) - [`@apollo/federation`](https://github.com/apollographql/federation/blob/HEAD/federation-js/CHANGELOG.md) + ## vNEXT +- Remove internal dependency on `apollo-server-caching`, switch over to `@apollo/utils.keyvaluecache`. This PR specifically also introduces Keyv as an unbounded cache solution, but will replace with our own simple implementation in a follow-up PR targeting this minor version release. [PR #6522](https://github.com/apollographql/apollo-server/pull/6522) + ## v3.8.2 - `apollo-server-core`: Fix usage reporting plugin "willResolveField called after stopTiming!" error caused by a race condition related to null bubbling. [Issue #4472](https://github.com/apollographql/apollo-server/issues/4472) [PR #6398](https://github.com/apollographql/apollo-server/pull/6398) @@ -92,7 +95,7 @@ The version headers in this history reflect the versions of Apollo Server itself new ApolloServer({ documentStore: new InMemoryLRUCache({ maxSize: Math.pow(2, 20) * approximateDocumentStoreMiB, - sizeCalculator: InMemoryLRUCache.jsonBytesSizeCalculator, + sizeCalculator: InMemoryLRUCache.sizeCalculator, }), ...moreOptions, }) diff --git a/cspell-dict.txt b/cspell-dict.txt index f7d02e67caa..8bc102f3b5d 100644 --- a/cspell-dict.txt +++ b/cspell-dict.txt @@ -79,6 +79,8 @@ iteratees josephg jsdelivr keyv +keyvadapter +keyvaluecache KHTML Kubernetes linearizability diff --git a/docs/source/api/apollo-server.mdx b/docs/source/api/apollo-server.mdx index 076fddfe2d1..544f313176f 100644 --- a/docs/source/api/apollo-server.mdx +++ b/docs/source/api/apollo-server.mdx @@ -209,12 +209,12 @@ To use `InMemoryLRUCache` but change its size to an amount `approximateDocumentS
```typescript -import { InMemoryLRUCache } from 'apollo-server-caching'; +import { InMemoryLRUCache } from '@apollo/utils.keyvaluecache'; import type { DocumentNode } from 'graphql'; new ApolloServer({ documentStore: new InMemoryLRUCache({ maxSize: Math.pow(2, 20) * approximateDocumentStoreMiB, - sizeCalculator: InMemoryLRUCache.jsonBytesSizeCalculator, + sizeCalculation: InMemoryLRUCache.sizeCalculation, }), // ... }) diff --git a/package-lock.json b/package-lock.json index 204b19c7c89..12018934990 100644 --- a/package-lock.json +++ b/package-lock.json @@ -209,6 +209,46 @@ "graphql": "14.x || 15.x || 16.x" } }, + "node_modules/@apollo/utils.keyvadapter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@apollo/utils.keyvadapter/-/utils.keyvadapter-1.0.1.tgz", + "integrity": "sha512-o8u9w33txkxRzEAdvkZ3myGp0D9ShZqJZOB2bCQMcKs+IlXyedxAV1dlPirijFW0UiLYJ6V82vJNacrTejT38A==", + "dependencies": { + "@apollo/utils.keyvaluecache": "^1.0.1", + "keyv": "^4.2.8" + } + }, + "node_modules/@apollo/utils.keyvadapter/node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "node_modules/@apollo/utils.keyvadapter/node_modules/keyv": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.3.0.tgz", + "integrity": "sha512-C30Un9+63J0CsR7Wka5quXKqYZsT6dcRQ2aOwGcSc3RiQ4HGWpTAHlCA+puNfw2jA/s11EsxA1nCXgZRuRKMQQ==", + "dependencies": { + "compress-brotli": "^1.3.8", + "json-buffer": "3.0.1" + } + }, + "node_modules/@apollo/utils.keyvaluecache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@apollo/utils.keyvaluecache/-/utils.keyvaluecache-1.0.1.tgz", + "integrity": "sha512-nLgYLomqjVimEzQ4cdvVQkcryi970NDvcRVPfd0OPeXhBfda38WjBq+WhQFk+czSHrmrSp34YHBxpat0EtiowA==", + "dependencies": { + "@apollo/utils.logger": "^1.0.0", + "lru-cache": "^7.10.1" + } + }, + "node_modules/@apollo/utils.keyvaluecache/node_modules/lru-cache": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.10.1.tgz", + "integrity": "sha512-BQuhQxPuRl79J5zSXRP+uNzPOyZw2oFI9JLRQ80XswSvg21KMKNtQza9eF42rfI/3Z40RvzBdXgziEkudzjo8A==", + "engines": { + "node": ">=12" + } + }, "node_modules/@apollo/utils.logger": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@apollo/utils.logger/-/utils.logger-1.0.0.tgz", @@ -6508,6 +6548,11 @@ "integrity": "sha512-KbeHS/Y4R+k+5sWXEYzAZKuB1yQlZtEghuhRxrVRLaqhtoG5+26JwQsa4HyS3AWX8v1Uwukma5HheduUDskasA==", "dev": true }, + "node_modules/@types/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-3YP80IxxFJB4b5tYC2SUPwkg0XQLiu0nWvhRgEatgjf+29IcWO9X1k8xRv5DGssJ/lCrjYTjQPcobJr2yWIVuQ==" + }, "node_modules/@types/json-stable-stringify": { "version": "1.0.33", "resolved": "https://registry.npmjs.org/@types/json-stable-stringify/-/json-stable-stringify-1.0.33.tgz", @@ -8574,6 +8619,23 @@ "dev": true, "license": "MIT" }, + "node_modules/compress-brotli": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/compress-brotli/-/compress-brotli-1.3.8.tgz", + "integrity": "sha512-lVcQsjhxhIXsuupfy9fmZUFtAIdBmXA7EGY6GBdgZ++qkM9zG4YFT8iU7FoBxzryNDMOpD1HIFHUSX4D87oqhQ==", + "dependencies": { + "@types/json-buffer": "~3.0.0", + "json-buffer": "~3.0.1" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/compress-brotli/node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, "node_modules/concat-map": { "version": "0.0.1", "dev": true, @@ -21249,7 +21311,7 @@ "version": "3.3.1", "license": "MIT", "dependencies": { - "apollo-server-caching": "file:../apollo-server-caching", + "@apollo/utils.keyvaluecache": "^1.0.1", "apollo-server-env": "file:../apollo-server-env" }, "engines": { @@ -21260,8 +21322,8 @@ "version": "3.6.0", "license": "MIT", "dependencies": { + "@apollo/utils.keyvaluecache": "^1.0.1", "apollo-datasource": "file:../apollo-datasource", - "apollo-server-caching": "file:../apollo-server-caching", "apollo-server-env": "file:../apollo-server-env", "apollo-server-errors": "file:../apollo-server-errors", "http-cache-semantics": "^4.1.0" @@ -21319,6 +21381,7 @@ "version": "3.3.1", "license": "MIT", "dependencies": { + "@apollo/utils.keyvaluecache": "^1.0.1", "apollo-server-caching": "file:../apollo-server-caching", "apollo-server-env": "file:../apollo-server-env", "memcached": "^2.2.2" @@ -21331,7 +21394,7 @@ "version": "3.3.1", "license": "MIT", "dependencies": { - "apollo-server-caching": "file:../apollo-server-caching", + "@apollo/utils.keyvaluecache": "^1.0.1", "apollo-server-env": "file:../apollo-server-env", "dataloader": "^2.0.0", "ioredis": "^4.17.3" @@ -21383,6 +21446,8 @@ "version": "3.8.2", "license": "MIT", "dependencies": { + "@apollo/utils.keyvadapter": "^1.0.1", + "@apollo/utils.keyvaluecache": "^1.0.1", "@apollo/utils.logger": "^1.0.0", "@apollo/utils.usagereporting": "^1.0.0", "@apollographql/apollo-tools": "^0.5.3", @@ -21392,7 +21457,6 @@ "@josephg/resolvable": "^1.0.0", "apollo-datasource": "file:../apollo-datasource", "apollo-reporting-protobuf": "file:../apollo-reporting-protobuf", - "apollo-server-caching": "file:../apollo-server-caching", "apollo-server-env": "file:../apollo-server-env", "apollo-server-errors": "file:../apollo-server-errors", "apollo-server-plugin-base": "file:../apollo-server-plugin-base", @@ -21400,6 +21464,7 @@ "async-retry": "^1.2.1", "fast-json-stable-stringify": "^2.1.0", "graphql-tag": "^2.11.0", + "keyv": "^4.3.0", "loglevel": "^1.6.8", "lru-cache": "^6.0.0", "sha.js": "^2.4.11", @@ -21413,6 +21478,20 @@ "graphql": "^15.3.0 || ^16.0.0" } }, + "packages/apollo-server-core/node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "packages/apollo-server-core/node_modules/keyv": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.3.0.tgz", + "integrity": "sha512-C30Un9+63J0CsR7Wka5quXKqYZsT6dcRQ2aOwGcSc3RiQ4HGWpTAHlCA+puNfw2jA/s11EsxA1nCXgZRuRKMQQ==", + "dependencies": { + "compress-brotli": "^1.3.8", + "json-buffer": "3.0.1" + } + }, "packages/apollo-server-core/node_modules/uuid": { "version": "8.3.2", "license": "MIT", @@ -21634,7 +21713,7 @@ "version": "3.6.0", "license": "MIT", "dependencies": { - "apollo-server-caching": "file:../apollo-server-caching", + "@apollo/utils.keyvaluecache": "^1.0.1", "apollo-server-plugin-base": "file:../apollo-server-plugin-base", "apollo-server-types": "file:../apollo-server-types" }, @@ -21649,9 +21728,9 @@ "version": "3.6.0", "license": "MIT", "dependencies": { + "@apollo/utils.keyvaluecache": "^1.0.1", "@apollo/utils.logger": "^1.0.0", "apollo-reporting-protobuf": "file:../apollo-reporting-protobuf", - "apollo-server-caching": "file:../apollo-server-caching", "apollo-server-env": "file:../apollo-server-env" }, "engines": { @@ -21726,6 +21805,47 @@ "integrity": "sha512-R2iZgXB+vTEx+B+N2mME0SP61+iEt+5fM26bYBvubyZflKed1VH2YiPLIl44nrahIph5JsTIvi/CeUsveJRZkg==", "requires": {} }, + "@apollo/utils.keyvadapter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@apollo/utils.keyvadapter/-/utils.keyvadapter-1.0.1.tgz", + "integrity": "sha512-o8u9w33txkxRzEAdvkZ3myGp0D9ShZqJZOB2bCQMcKs+IlXyedxAV1dlPirijFW0UiLYJ6V82vJNacrTejT38A==", + "requires": { + "@apollo/utils.keyvaluecache": "^1.0.1", + "keyv": "^4.2.8" + }, + "dependencies": { + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "keyv": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.3.0.tgz", + "integrity": "sha512-C30Un9+63J0CsR7Wka5quXKqYZsT6dcRQ2aOwGcSc3RiQ4HGWpTAHlCA+puNfw2jA/s11EsxA1nCXgZRuRKMQQ==", + "requires": { + "compress-brotli": "^1.3.8", + "json-buffer": "3.0.1" + } + } + } + }, + "@apollo/utils.keyvaluecache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@apollo/utils.keyvaluecache/-/utils.keyvaluecache-1.0.1.tgz", + "integrity": "sha512-nLgYLomqjVimEzQ4cdvVQkcryi970NDvcRVPfd0OPeXhBfda38WjBq+WhQFk+czSHrmrSp34YHBxpat0EtiowA==", + "requires": { + "@apollo/utils.logger": "^1.0.0", + "lru-cache": "^7.10.1" + }, + "dependencies": { + "lru-cache": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.10.1.tgz", + "integrity": "sha512-BQuhQxPuRl79J5zSXRP+uNzPOyZw2oFI9JLRQ80XswSvg21KMKNtQza9eF42rfI/3Z40RvzBdXgziEkudzjo8A==" + } + } + }, "@apollo/utils.logger": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@apollo/utils.logger/-/utils.logger-1.0.0.tgz", @@ -26577,6 +26697,11 @@ "integrity": "sha512-KbeHS/Y4R+k+5sWXEYzAZKuB1yQlZtEghuhRxrVRLaqhtoG5+26JwQsa4HyS3AWX8v1Uwukma5HheduUDskasA==", "dev": true }, + "@types/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-3YP80IxxFJB4b5tYC2SUPwkg0XQLiu0nWvhRgEatgjf+29IcWO9X1k8xRv5DGssJ/lCrjYTjQPcobJr2yWIVuQ==" + }, "@types/json-stable-stringify": { "version": "1.0.33", "resolved": "https://registry.npmjs.org/@types/json-stable-stringify/-/json-stable-stringify-1.0.33.tgz", @@ -27078,15 +27203,15 @@ "apollo-datasource": { "version": "file:packages/apollo-datasource", "requires": { - "apollo-server-caching": "file:../apollo-server-caching", + "@apollo/utils.keyvaluecache": "^1.0.1", "apollo-server-env": "file:../apollo-server-env" } }, "apollo-datasource-rest": { "version": "file:packages/apollo-datasource-rest", "requires": { + "@apollo/utils.keyvaluecache": "^1.0.1", "apollo-datasource": "file:../apollo-datasource", - "apollo-server-caching": "file:../apollo-server-caching", "apollo-server-env": "file:../apollo-server-env", "apollo-server-errors": "file:../apollo-server-errors", "http-cache-semantics": "^4.1.0" @@ -27121,6 +27246,7 @@ "apollo-server-cache-memcached": { "version": "file:packages/apollo-server-cache-memcached", "requires": { + "@apollo/utils.keyvaluecache": "^1.0.1", "apollo-server-caching": "file:../apollo-server-caching", "apollo-server-env": "file:../apollo-server-env", "memcached": "^2.2.2" @@ -27129,7 +27255,7 @@ "apollo-server-cache-redis": { "version": "file:packages/apollo-server-cache-redis", "requires": { - "apollo-server-caching": "file:../apollo-server-caching", + "@apollo/utils.keyvaluecache": "^1.0.1", "apollo-server-env": "file:../apollo-server-env", "dataloader": "^2.0.0", "ioredis": "^4.17.3" @@ -27160,6 +27286,8 @@ "apollo-server-core": { "version": "file:packages/apollo-server-core", "requires": { + "@apollo/utils.keyvadapter": "^1.0.1", + "@apollo/utils.keyvaluecache": "^1.0.1", "@apollo/utils.logger": "^1.0.0", "@apollo/utils.usagereporting": "^1.0.0", "@apollographql/apollo-tools": "^0.5.3", @@ -27169,7 +27297,6 @@ "@josephg/resolvable": "^1.0.0", "apollo-datasource": "file:../apollo-datasource", "apollo-reporting-protobuf": "file:../apollo-reporting-protobuf", - "apollo-server-caching": "file:../apollo-server-caching", "apollo-server-env": "file:../apollo-server-env", "apollo-server-errors": "file:../apollo-server-errors", "apollo-server-plugin-base": "file:../apollo-server-plugin-base", @@ -27177,6 +27304,7 @@ "async-retry": "^1.2.1", "fast-json-stable-stringify": "^2.1.0", "graphql-tag": "^2.11.0", + "keyv": "^4.3.0", "loglevel": "^1.6.8", "lru-cache": "^6.0.0", "sha.js": "^2.4.11", @@ -27184,6 +27312,20 @@ "whatwg-mimetype": "^3.0.0" }, "dependencies": { + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "keyv": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.3.0.tgz", + "integrity": "sha512-C30Un9+63J0CsR7Wka5quXKqYZsT6dcRQ2aOwGcSc3RiQ4HGWpTAHlCA+puNfw2jA/s11EsxA1nCXgZRuRKMQQ==", + "requires": { + "compress-brotli": "^1.3.8", + "json-buffer": "3.0.1" + } + }, "uuid": { "version": "8.3.2" }, @@ -27316,7 +27458,7 @@ "apollo-server-plugin-response-cache": { "version": "file:packages/apollo-server-plugin-response-cache", "requires": { - "apollo-server-caching": "file:../apollo-server-caching", + "@apollo/utils.keyvaluecache": "^1.0.1", "apollo-server-plugin-base": "file:../apollo-server-plugin-base", "apollo-server-types": "file:../apollo-server-types" } @@ -27324,9 +27466,9 @@ "apollo-server-types": { "version": "file:packages/apollo-server-types", "requires": { + "@apollo/utils.keyvaluecache": "^1.0.1", "@apollo/utils.logger": "^1.0.0", "apollo-reporting-protobuf": "file:../apollo-reporting-protobuf", - "apollo-server-caching": "file:../apollo-server-caching", "apollo-server-env": "file:../apollo-server-env" } }, @@ -28350,6 +28492,22 @@ "version": "1.3.0", "dev": true }, + "compress-brotli": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/compress-brotli/-/compress-brotli-1.3.8.tgz", + "integrity": "sha512-lVcQsjhxhIXsuupfy9fmZUFtAIdBmXA7EGY6GBdgZ++qkM9zG4YFT8iU7FoBxzryNDMOpD1HIFHUSX4D87oqhQ==", + "requires": { + "@types/json-buffer": "~3.0.0", + "json-buffer": "~3.0.1" + }, + "dependencies": { + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + } + } + }, "concat-map": { "version": "0.0.1", "dev": true diff --git a/packages/apollo-datasource-rest/package.json b/packages/apollo-datasource-rest/package.json index e6d0bc08eaf..4abe67ca4d4 100644 --- a/packages/apollo-datasource-rest/package.json +++ b/packages/apollo-datasource-rest/package.json @@ -18,8 +18,8 @@ "node": ">=12.0" }, "dependencies": { + "@apollo/utils.keyvaluecache": "^1.0.1", "apollo-datasource": "file:../apollo-datasource", - "apollo-server-caching": "file:../apollo-server-caching", "apollo-server-env": "file:../apollo-server-env", "apollo-server-errors": "file:../apollo-server-errors", "http-cache-semantics": "^4.1.0" diff --git a/packages/apollo-datasource-rest/src/HTTPCache.ts b/packages/apollo-datasource-rest/src/HTTPCache.ts index d04cb37a0ec..a16e7513cfb 100644 --- a/packages/apollo-datasource-rest/src/HTTPCache.ts +++ b/packages/apollo-datasource-rest/src/HTTPCache.ts @@ -6,7 +6,7 @@ import { KeyValueCache, InMemoryLRUCache, PrefixingKeyValueCache, -} from 'apollo-server-caching'; +} from '@apollo/utils.keyvaluecache'; import type { CacheOptions } from './RESTDataSource'; export class HTTPCache { diff --git a/packages/apollo-datasource-rest/src/__tests__/HTTPCache.test.ts b/packages/apollo-datasource-rest/src/__tests__/HTTPCache.test.ts index aa20192c32f..7a8677dd0bd 100644 --- a/packages/apollo-datasource-rest/src/__tests__/HTTPCache.test.ts +++ b/packages/apollo-datasource-rest/src/__tests__/HTTPCache.test.ts @@ -352,8 +352,11 @@ describe('HTTPCache', () => { await httpCache.fetch(new Request('https://api.example.com/people/1')); - expect(storeSet.mock.calls[0][2]).toEqual({ ttl: 30 }); - + expect(storeSet).toHaveBeenCalledWith( + expect.any(String), + expect.any(String), + { ttl: 30 }, + ); storeSet.mockRestore(); }); @@ -367,7 +370,11 @@ describe('HTTPCache', () => { await httpCache.fetch(new Request('https://api.example.com/people/1')); - expect(storeSet.mock.calls[0][2]).toEqual({ ttl: 60 }); + expect(storeSet).toHaveBeenCalledWith( + expect.any(String), + expect.any(String), + { ttl: 60 }, + ); storeSet.mockRestore(); }); diff --git a/packages/apollo-datasource-rest/src/__tests__/MapKeyValueCache.ts b/packages/apollo-datasource-rest/src/__tests__/MapKeyValueCache.ts index 9e88a2fa48d..96b96e2605e 100644 --- a/packages/apollo-datasource-rest/src/__tests__/MapKeyValueCache.ts +++ b/packages/apollo-datasource-rest/src/__tests__/MapKeyValueCache.ts @@ -1,14 +1,11 @@ -import type { - KeyValueCache, - KeyValueCacheSetOptions, -} from 'apollo-server-caching'; +import type { KeyValueCache } from '@apollo/utils.keyvaluecache'; export class MapKeyValueCache implements KeyValueCache { store = new Map(); async get(key: string) { return this.store.get(key); } - async set(key: string, value: V, _?: KeyValueCacheSetOptions) { + async set(key: string, value: V) { this.store.set(key, value); } async delete(key: string) { diff --git a/packages/apollo-datasource-rest/tsconfig.json b/packages/apollo-datasource-rest/tsconfig.json index 83c0c7fe9c3..e53836dcde3 100644 --- a/packages/apollo-datasource-rest/tsconfig.json +++ b/packages/apollo-datasource-rest/tsconfig.json @@ -8,7 +8,6 @@ "exclude": ["**/__tests__"], "references": [ { "path": "../apollo-datasource" }, - { "path": "../apollo-server-caching" }, { "path": "../apollo-server-errors" }, ] } diff --git a/packages/apollo-datasource/package.json b/packages/apollo-datasource/package.json index 224f7036da9..cbd9cd0f7d4 100644 --- a/packages/apollo-datasource/package.json +++ b/packages/apollo-datasource/package.json @@ -18,7 +18,7 @@ "node": ">=12.0" }, "dependencies": { - "apollo-server-caching": "file:../apollo-server-caching", + "@apollo/utils.keyvaluecache": "^1.0.1", "apollo-server-env": "file:../apollo-server-env" } } diff --git a/packages/apollo-datasource/src/index.ts b/packages/apollo-datasource/src/index.ts index 424dbd4402f..e11c6370b69 100644 --- a/packages/apollo-datasource/src/index.ts +++ b/packages/apollo-datasource/src/index.ts @@ -1,4 +1,4 @@ -import type { KeyValueCache } from 'apollo-server-caching'; +import type { KeyValueCache } from '@apollo/utils.keyvaluecache'; export interface DataSourceConfig { context: TContext; diff --git a/packages/apollo-datasource/tsconfig.json b/packages/apollo-datasource/tsconfig.json index dab7afbdc99..98e3dc7fa93 100644 --- a/packages/apollo-datasource/tsconfig.json +++ b/packages/apollo-datasource/tsconfig.json @@ -6,7 +6,5 @@ }, "include": ["src/**/*"], "exclude": ["**/__tests__"], - "references": [ - { "path": "../apollo-server-caching" }, - ] + "references": [] } diff --git a/packages/apollo-server-cache-memcached/package.json b/packages/apollo-server-cache-memcached/package.json index 98b9470c015..29302cc4caa 100644 --- a/packages/apollo-server-cache-memcached/package.json +++ b/packages/apollo-server-cache-memcached/package.json @@ -18,6 +18,7 @@ "node": ">=12.0" }, "dependencies": { + "@apollo/utils.keyvaluecache": "^1.0.1", "apollo-server-caching": "file:../apollo-server-caching", "apollo-server-env": "file:../apollo-server-env", "memcached": "^2.2.2" diff --git a/packages/apollo-server-cache-memcached/src/index.ts b/packages/apollo-server-cache-memcached/src/index.ts index cf66cdb82fa..cec2d9899c3 100644 --- a/packages/apollo-server-cache-memcached/src/index.ts +++ b/packages/apollo-server-cache-memcached/src/index.ts @@ -1,7 +1,7 @@ import type { KeyValueCache, KeyValueCacheSetOptions, -} from 'apollo-server-caching'; +} from '@apollo/utils.keyvaluecache'; import Memcached from 'memcached'; import { promisify } from 'util'; diff --git a/packages/apollo-server-cache-memcached/tsconfig.json b/packages/apollo-server-cache-memcached/tsconfig.json index dab7afbdc99..98e3dc7fa93 100644 --- a/packages/apollo-server-cache-memcached/tsconfig.json +++ b/packages/apollo-server-cache-memcached/tsconfig.json @@ -6,7 +6,5 @@ }, "include": ["src/**/*"], "exclude": ["**/__tests__"], - "references": [ - { "path": "../apollo-server-caching" }, - ] + "references": [] } diff --git a/packages/apollo-server-cache-redis/package.json b/packages/apollo-server-cache-redis/package.json index 87682ae3262..647241d458e 100644 --- a/packages/apollo-server-cache-redis/package.json +++ b/packages/apollo-server-cache-redis/package.json @@ -18,7 +18,7 @@ "node": ">=12.0" }, "dependencies": { - "apollo-server-caching": "file:../apollo-server-caching", + "@apollo/utils.keyvaluecache": "^1.0.1", "apollo-server-env": "file:../apollo-server-env", "dataloader": "^2.0.0", "ioredis": "^4.17.3" diff --git a/packages/apollo-server-cache-redis/src/BaseRedisCache.ts b/packages/apollo-server-cache-redis/src/BaseRedisCache.ts index bd66e9ca1d8..9b375894cbd 100644 --- a/packages/apollo-server-cache-redis/src/BaseRedisCache.ts +++ b/packages/apollo-server-cache-redis/src/BaseRedisCache.ts @@ -1,7 +1,7 @@ import type { KeyValueCache, KeyValueCacheSetOptions, -} from 'apollo-server-caching'; +} from '@apollo/utils.keyvaluecache'; import DataLoader from 'dataloader'; interface BaseRedisClient { diff --git a/packages/apollo-server-cache-redis/tsconfig.json b/packages/apollo-server-cache-redis/tsconfig.json index dab7afbdc99..98e3dc7fa93 100644 --- a/packages/apollo-server-cache-redis/tsconfig.json +++ b/packages/apollo-server-cache-redis/tsconfig.json @@ -6,7 +6,5 @@ }, "include": ["src/**/*"], "exclude": ["**/__tests__"], - "references": [ - { "path": "../apollo-server-caching" }, - ] + "references": [] } diff --git a/packages/apollo-server-core/package.json b/packages/apollo-server-core/package.json index 998ab523171..c3704e5c397 100644 --- a/packages/apollo-server-core/package.json +++ b/packages/apollo-server-core/package.json @@ -25,6 +25,8 @@ "node": ">=12.0" }, "dependencies": { + "@apollo/utils.keyvadapter": "^1.0.1", + "@apollo/utils.keyvaluecache": "^1.0.1", "@apollo/utils.logger": "^1.0.0", "@apollo/utils.usagereporting": "^1.0.0", "@apollographql/apollo-tools": "^0.5.3", @@ -34,7 +36,6 @@ "@josephg/resolvable": "^1.0.0", "apollo-datasource": "file:../apollo-datasource", "apollo-reporting-protobuf": "file:../apollo-reporting-protobuf", - "apollo-server-caching": "file:../apollo-server-caching", "apollo-server-env": "file:../apollo-server-env", "apollo-server-errors": "file:../apollo-server-errors", "apollo-server-plugin-base": "file:../apollo-server-plugin-base", @@ -42,6 +43,7 @@ "async-retry": "^1.2.1", "fast-json-stable-stringify": "^2.1.0", "graphql-tag": "^2.11.0", + "keyv": "^4.3.0", "loglevel": "^1.6.8", "lru-cache": "^6.0.0", "sha.js": "^2.4.11", diff --git a/packages/apollo-server-core/src/ApolloServer.ts b/packages/apollo-server-core/src/ApolloServer.ts index 18ae8a1bd9f..bc7a0c9e025 100644 --- a/packages/apollo-server-core/src/ApolloServer.ts +++ b/packages/apollo-server-core/src/ApolloServer.ts @@ -14,7 +14,7 @@ import resolvable, { Resolvable } from '@josephg/resolvable'; import { InMemoryLRUCache, PrefixingKeyValueCache, -} from 'apollo-server-caching'; +} from '@apollo/utils.keyvaluecache'; import type { ApolloServerPlugin, GraphQLServiceContext, @@ -60,6 +60,8 @@ import { InternalPluginId, pluginIsInternal } from './internalPlugin'; import { newCachePolicy } from './cachePolicy'; import { GatewayIsTooOldError, SchemaManager } from './utils/schemaManager'; import * as uuid from 'uuid'; +import { KeyvAdapter } from '@apollo/utils.keyvadapter'; +import Keyv from 'keyv'; const NoIntrospection = (context: ValidationContext) => ({ Field(node: FieldDefinitionNode) { @@ -709,7 +711,7 @@ export class ApolloServerBase< // random prefix each time we get a new schema. documentStore: this.config.documentStore === undefined - ? this.initializeDocumentStore() + ? new KeyvAdapter(new Keyv()) : this.config.documentStore === null ? null : new PrefixingKeyValueCache( @@ -906,20 +908,6 @@ export class ApolloServerBase< } } - private initializeDocumentStore(): InMemoryLRUCache { - return new InMemoryLRUCache({ - // Create ~about~ a 30MiB InMemoryLRUCache. This is less than precise - // since the technique to calculate the size of a DocumentNode is - // only using JSON.stringify on the DocumentNode (and thus doesn't account - // for unicode characters, etc.), but it should do a reasonable job at - // providing a caching document store for most operations. - // - // If you want to tweak the max size, pass in your own documentStore. - maxSize: Math.pow(2, 20) * 30, - sizeCalculator: InMemoryLRUCache.jsonBytesSizeCalculator, - }); - } - // This function is used by the integrations to generate the graphQLOptions // from an object containing the request and other integration specific // options diff --git a/packages/apollo-server-core/src/__tests__/documentStore.test.ts b/packages/apollo-server-core/src/__tests__/documentStore.test.ts index 319b6775393..4f3f76cdc53 100644 --- a/packages/apollo-server-core/src/__tests__/documentStore.test.ts +++ b/packages/apollo-server-core/src/__tests__/documentStore.test.ts @@ -2,7 +2,8 @@ import gql from 'graphql-tag'; import type { DocumentNode } from 'graphql'; import { ApolloServerBase } from '../ApolloServer'; -import { InMemoryLRUCache } from 'apollo-server-caching'; +import { KeyvAdapter } from '@apollo/utils.keyvadapter'; +import assert from 'assert'; const typeDefs = gql` type Query { @@ -51,12 +52,12 @@ describe('ApolloServerBase documentStore', () => { await server.start(); const options = await server.graphQLServerOptions(); - const embeddedStore = options.documentStore as any; - expect(embeddedStore).toBeInstanceOf(InMemoryLRUCache); + const embeddedStore = options.documentStore; + assert(embeddedStore); + expect(embeddedStore).toBeInstanceOf(KeyvAdapter); await server.executeOperation(operations.simple.op); - expect(await embeddedStore.getTotalSize()).toBe(403); expect(await embeddedStore.get(operations.simple.hash)).toMatchObject( documentNodeMatcher, ); diff --git a/packages/apollo-server-core/src/__tests__/runQuery.test.ts b/packages/apollo-server-core/src/__tests__/runQuery.test.ts index ee6595cb5d8..7336d64fc92 100644 --- a/packages/apollo-server-core/src/__tests__/runQuery.test.ts +++ b/packages/apollo-server-core/src/__tests__/runQuery.test.ts @@ -28,7 +28,7 @@ import type { GraphQLRequestListenerValidationDidEnd, GraphQLRequestContext, } from 'apollo-server-plugin-base'; -import { InMemoryLRUCache } from 'apollo-server-caching'; +import { InMemoryLRUCache } from '@apollo/utils.keyvaluecache'; import { newCachePolicy } from '../cachePolicy'; // This is a temporary kludge to ensure we preserve runQuery behavior with the @@ -1157,12 +1157,12 @@ describe('runQuery', () => { // size of the two smaller queries. All three of these queries will never // fit into this cache, so we'll roll through them all. const maxSize = - InMemoryLRUCache.jsonBytesSizeCalculator(parse(querySmall1)) + - InMemoryLRUCache.jsonBytesSizeCalculator(parse(querySmall2)); + InMemoryLRUCache.sizeCalculation(parse(querySmall1)) + + InMemoryLRUCache.sizeCalculation(parse(querySmall2)); const documentStore = new InMemoryLRUCache({ maxSize, - sizeCalculator: InMemoryLRUCache.jsonBytesSizeCalculator, + sizeCalculation: InMemoryLRUCache.sizeCalculation, }); await runRequest({ plugins, documentStore, queryString: querySmall1 }); diff --git a/packages/apollo-server-core/src/graphqlOptions.ts b/packages/apollo-server-core/src/graphqlOptions.ts index 499c6d63c75..039b51ed710 100644 --- a/packages/apollo-server-core/src/graphqlOptions.ts +++ b/packages/apollo-server-core/src/graphqlOptions.ts @@ -7,7 +7,7 @@ import type { GraphQLFormattedError, ParseOptions, } from 'graphql'; -import type { KeyValueCache } from 'apollo-server-caching'; +import type { KeyValueCache } from '@apollo/utils.keyvaluecache'; import type { DataSource } from 'apollo-datasource'; import type { ApolloServerPlugin } from 'apollo-server-plugin-base'; import type { diff --git a/packages/apollo-server-core/src/requestPipeline.ts b/packages/apollo-server-core/src/requestPipeline.ts index 21120f0e307..efe3c395760 100644 --- a/packages/apollo-server-core/src/requestPipeline.ts +++ b/packages/apollo-server-core/src/requestPipeline.ts @@ -53,7 +53,10 @@ import type { } from 'apollo-server-plugin-base'; import { Dispatcher } from './utils/dispatcher'; -import { KeyValueCache, PrefixingKeyValueCache } from 'apollo-server-caching'; +import { + KeyValueCache, + PrefixingKeyValueCache, +} from '@apollo/utils.keyvaluecache'; export { GraphQLRequest, GraphQLResponse, GraphQLRequestContext }; diff --git a/packages/apollo-server-core/src/types.ts b/packages/apollo-server-core/src/types.ts index 16228ac6de3..db3fa2244b2 100644 --- a/packages/apollo-server-core/src/types.ts +++ b/packages/apollo-server-core/src/types.ts @@ -18,7 +18,7 @@ import type { GraphQLSchemaModule } from '@apollographql/apollo-tools'; export type { GraphQLSchemaModule }; -import type { KeyValueCache } from 'apollo-server-caching'; +import type { KeyValueCache } from '@apollo/utils.keyvaluecache'; export type { KeyValueCache }; export type Context = T; diff --git a/packages/apollo-server-core/src/utils/pluginTestHarness.ts b/packages/apollo-server-core/src/utils/pluginTestHarness.ts index d44203ce785..24b0ea90060 100644 --- a/packages/apollo-server-core/src/utils/pluginTestHarness.ts +++ b/packages/apollo-server-core/src/utils/pluginTestHarness.ts @@ -23,7 +23,7 @@ import type { GraphQLRequestExecutionListener, GraphQLServerListener, } from 'apollo-server-plugin-base'; -import { InMemoryLRUCache } from 'apollo-server-caching'; +import { InMemoryLRUCache } from '@apollo/utils.keyvaluecache'; import { Dispatcher } from './dispatcher'; import { getOperationAST, parse, validate as graphqlValidate } from 'graphql'; import { newCachePolicy } from '../cachePolicy'; diff --git a/packages/apollo-server-core/tsconfig.json b/packages/apollo-server-core/tsconfig.json index 6f7f9635a2a..0f7c94862f0 100644 --- a/packages/apollo-server-core/tsconfig.json +++ b/packages/apollo-server-core/tsconfig.json @@ -8,7 +8,6 @@ "exclude": ["**/__tests__"], "references": [ { "path": "../apollo-datasource" }, - { "path": "../apollo-server-caching" }, { "path": "../apollo-server-errors" }, { "path": "../apollo-server-plugin-base" }, { "path": "../apollo-server-types" }, diff --git a/packages/apollo-server-integration-testsuite/src/ApolloServer.ts b/packages/apollo-server-integration-testsuite/src/ApolloServer.ts index f210f08b4c6..6ba585f4bb9 100644 --- a/packages/apollo-server-integration-testsuite/src/ApolloServer.ts +++ b/packages/apollo-server-integration-testsuite/src/ApolloServer.ts @@ -58,7 +58,10 @@ import resolvable, { Resolvable } from '@josephg/resolvable'; import FakeTimers from '@sinonjs/fake-timers'; import type { AddressInfo } from 'net'; import request, { Response } from 'supertest'; -import { InMemoryLRUCache } from 'apollo-server-caching'; +import { + type KeyValueCache, + InMemoryLRUCache, +} from '@apollo/utils.keyvaluecache'; const quietLogger = loglevel.getLogger('quiet'); quietLogger.setLevel(loglevel.levels.WARN); @@ -2251,11 +2254,10 @@ export function testApolloServer( describe('Response caching', () => { let clock: FakeTimers.InstalledClock; beforeAll(() => { - // These tests use the default InMemoryLRUCache, which is backed by the - // lru-cache npm module, whose maxAge feature is based on `Date.now()` - // (no setTimeout or anything like that). So we want to use fake timers - // just for Date. (Faking all the timer methods messes up things like a - // setImmediate in ApolloServerPluginDrainHttpServer.) + // The ApolloServerPluginResponseCache uses Date.now() to derive the + // "age" header, so we want to use fake timers just for Date. (Faking + // all the timer methods messes up things like a setImmediate in + // ApolloServerPluginDrainHttpServer.) clock = FakeTimers.install({ toFake: ['Date'] }); }); @@ -2264,6 +2266,44 @@ export function testApolloServer( }); it('basic caching', async () => { + class TTLTestingCache implements KeyValueCache { + private fakeTime = 0; + constructor( + private cache: Map< + string, + { value: string; deadline: number | null } + > = new Map(), + ) {} + + async get(key: string) { + const entry = this.cache.get(key); + if (!entry) return undefined; + if (entry.deadline && entry.deadline <= this.fakeTime) { + await this.delete(key); + return undefined; + } + return entry.value; + } + + async set( + key: string, + value: string, + { ttl }: { ttl: number | null } = { ttl: null }, + ) { + this.cache.set(key, { + value, + deadline: ttl ? this.fakeTime + ttl * 1000 : null, + }); + } + + async delete(key: string) { + this.cache.delete(key); + } + + advanceTime(ms: number) { + this.fakeTime += ms; + } + } const typeDefs = gql` type Query { cached: String @cacheControl(maxAge: 10) @@ -2319,9 +2359,12 @@ export function testApolloServer( }; }); + const fakeTTLCache = new TTLTestingCache(); + const { url: uri } = await createApolloServer({ typeDefs, resolvers, + cache: fakeTTLCache, plugins: [ ApolloServerPluginResponseCache({ sessionId: (requestContext: GraphQLRequestContext) => { @@ -2445,6 +2488,7 @@ export function testApolloServer( } // Cache hit partway to ttl. + fakeTTLCache.advanceTime(5 * 1000); clock.tick(5 * 1000); { const result = await fetch(); @@ -2456,6 +2500,7 @@ export function testApolloServer( } // Cache miss after ttl. + fakeTTLCache.advanceTime(6 * 1000); clock.tick(6 * 1000); { const result = await fetch(); @@ -2733,6 +2778,7 @@ export function testApolloServer( } // Let's expire the cache, and run again, not writing to the cache. + fakeTTLCache.advanceTime(15 * 1000); clock.tick(15 * 1000); { const result = await doFetch({ diff --git a/packages/apollo-server-plugin-response-cache/package.json b/packages/apollo-server-plugin-response-cache/package.json index 6b431a59d4a..ddb20941c3f 100644 --- a/packages/apollo-server-plugin-response-cache/package.json +++ b/packages/apollo-server-plugin-response-cache/package.json @@ -20,7 +20,7 @@ "node": ">=12.0" }, "dependencies": { - "apollo-server-caching": "file:../apollo-server-caching", + "@apollo/utils.keyvaluecache": "^1.0.1", "apollo-server-plugin-base": "file:../apollo-server-plugin-base", "apollo-server-types": "file:../apollo-server-types" }, diff --git a/packages/apollo-server-plugin-response-cache/src/ApolloServerPluginResponseCache.ts b/packages/apollo-server-plugin-response-cache/src/ApolloServerPluginResponseCache.ts index 71da54b6fc4..45009f88c65 100644 --- a/packages/apollo-server-plugin-response-cache/src/ApolloServerPluginResponseCache.ts +++ b/packages/apollo-server-plugin-response-cache/src/ApolloServerPluginResponseCache.ts @@ -8,7 +8,10 @@ import type { CacheHint, ValueOrPromise, } from 'apollo-server-types'; -import { KeyValueCache, PrefixingKeyValueCache } from 'apollo-server-caching'; +import { + KeyValueCache, + PrefixingKeyValueCache, +} from '@apollo/utils.keyvaluecache'; import { CacheScope } from 'apollo-server-types'; // XXX This should use createSHA from apollo-server-core in order to work on diff --git a/packages/apollo-server-plugin-response-cache/tsconfig.json b/packages/apollo-server-plugin-response-cache/tsconfig.json index 5c4502fa2c5..f6504a7fb5c 100644 --- a/packages/apollo-server-plugin-response-cache/tsconfig.json +++ b/packages/apollo-server-plugin-response-cache/tsconfig.json @@ -8,7 +8,6 @@ "exclude": ["**/__tests__"], "references": [ { "path": "../apollo-server-plugin-base" }, - { "path": "../apollo-server-caching" }, { "path": "../apollo-server-types" }, ] } diff --git a/packages/apollo-server-types/package.json b/packages/apollo-server-types/package.json index 38572f2ac18..796fc207f5b 100644 --- a/packages/apollo-server-types/package.json +++ b/packages/apollo-server-types/package.json @@ -11,9 +11,9 @@ "node": ">=12.0" }, "dependencies": { + "@apollo/utils.keyvaluecache": "^1.0.1", "@apollo/utils.logger": "^1.0.0", "apollo-reporting-protobuf": "file:../apollo-reporting-protobuf", - "apollo-server-caching": "file:../apollo-server-caching", "apollo-server-env": "file:../apollo-server-env" }, "peerDependencies": { diff --git a/packages/apollo-server-types/src/index.ts b/packages/apollo-server-types/src/index.ts index 48f0745de8f..cea8ab2d08c 100644 --- a/packages/apollo-server-types/src/index.ts +++ b/packages/apollo-server-types/src/index.ts @@ -12,7 +12,7 @@ import type { } from 'graphql'; // This seems like it could live in this package too. -import type { KeyValueCache } from 'apollo-server-caching'; +import type { KeyValueCache } from '@apollo/utils.keyvaluecache'; import type { Trace } from 'apollo-reporting-protobuf'; import type { Logger } from '@apollo/utils.logger'; diff --git a/packages/apollo-server-types/tsconfig.json b/packages/apollo-server-types/tsconfig.json index 4adeddc00e9..98e3dc7fa93 100644 --- a/packages/apollo-server-types/tsconfig.json +++ b/packages/apollo-server-types/tsconfig.json @@ -6,7 +6,5 @@ }, "include": ["src/**/*"], "exclude": ["**/__tests__"], - "references": [ - { "path": "../apollo-server-caching/" }, - ] + "references": [] }