apollographql / apollo-utils Goto Github PK
View Code? Open in Web Editor NEWMonorepo of common utilities related to Apollo and GraphQL
License: MIT License
Monorepo of common utilities related to Apollo and GraphQL
License: MIT License
Introduce READMEs for each package
Update directory in package.json files, maybe that fixes the reference / homepage link on npmjs website.
Hi,
in the last version of @apollo/utils.keyvaluecache
package there is this line return prefixesAreUnnecessaryForIsolationSymbol in c;
which breaks our apollo server instance (tested on node v16 and v18).
It throws this error:
TypeError: Cannot use 'in' operator to search for 'Symbol(prefixesAreUnnecessaryForIsolation)' in bounded
at Function.prefixesAreUnnecessaryForIsolation (/app/node_modules/@apollo/server/node_modules/@apollo/utils.keyvaluecache/dist/PrefixingKeyValueCache.js:27:57)
at new PrefixingKeyValueCache (/app/node_modules/@apollo/server/node_modules/@apollo/utils.keyvaluecache/dist/PrefixingKeyValueCache.js:9:36)
at new ApolloServer (/app/node_modules/@apollo/server/dist/cjs/ApolloServer.js:110:28)
I was testing it on @apollo/server
version 4.2.1
which creates object PrefixingKeyValueCache
like this:
new utils_keyvaluecache_1.PrefixingKeyValueCache(config.persistedQueries?.cache ?? this.cache, requestPipeline_js_1.APQ_CACHE_PREFIX),
With these params:
console.log(
config.persistedQueries?.cache, // undefined
this.cache, // bounded
requestPipeline_js_1.APQ_CACHE_PREFIX // apq:
);
Where constructor on line 22:
if (PrefixingKeyValueCache.prefixesAreUnnecessaryForIsolation(wrapped)) {
Uses mentioned function prefixesAreUnnecessaryForIsolation
called with "bounded" string in params which turns into faulty code Symbol(prefixesAreUnnecessaryForIsolation) in "bounded"
.
Is it a problem of @apollo/server
or of @apollo/utils.keyvaluecache
? With previous version of utils.keyvaluecache
(v2.0.1) everything worked fine.
This repo expects graphql@14+
support for all packages. This isn't intentional, just a matter of simplicity in implementation. At some point, we'll likely want to allow packages to specify whether or not they should be tested for graphql backcompat and against which versions.
When using the Redis Keyv and if the Redis client is unable to connect to the Redis cluster, the keyv.get()
function will returned undefined
.
This in turn would cause the DataLoader used by the KeyvAdapter to throw the following error since returning undefined
violates the DataLoader contract:
DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did not return a Promise of an Array: undefined.
Would suggest changing the following KeyvAdapter code to better handle this error scenario:
this.dataLoader = options?.disableBatchReads
? undefined
: new DataLoader(
(keys) => this.keyv.get([...keys]),
// We're not actually using `DataLoader` for its caching
// capabilities, we're only interested in batching functionality
{ cache: false },
);
For example, to something like this:
this.dataLoader = options?.disableBatchReads
? undefined
: new DataLoader(
async (keys) => (await this.keyv.get([...keys])) ?? keys.map(() => null),
// We're not actually using `DataLoader` for its caching
// capabilities, we're only interested in batching functionality
{ cache: false },
);
I haven't tested this with other Keyv implementations so this issue exist with other caches besides Redis. I've also only noticed this issue occurring when Redis can't connect to the cluster, but could possible occur for other type of Redis errors as well.
With more and more build tools (vite, nuxt, etc) going towards an esm-first build, it would be nice if a proper esm interface could be provided, i.e. transpile and distribute esm version, including correct export declaration in package.json
.
I am using @apollo/utils.keyvadapter
to implement redis cache backend. The adapter makes redis or other cache backend a hard dependency. This means when the apollo server lost connection to redis server, any incoming requests will fail. It would be good to allow the redis client to retry connection. At the same time, any queries with cache control should still function by bypassing cache.
Meanwhile, I use the following code to achieve the goal.
class BetterKeyvAdapter extends KeyvAdapter {
// this will allow the query to bypass the cache if cache backend is not available
async get(key) {
try {
return await super.get(key);
} catch (e) {
return undefined;
}
}
}
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These problems occurred while renovating this repository. View logs.
These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
@apollo/client
, @types/node
, @types/node-fetch
, @typescript-eslint/eslint-plugin
, @typescript-eslint/parser
, prettier
, ts-jest
)package.json
@apollo/client 3.8.9
@changesets/changelog-github 0.5.0
@changesets/cli 2.27.1
@jest/types 29.6.3
@types/bunyan 1.8.11
@types/glob 8.1.0
@types/jest 29.5.11
@types/lodash.sortby 4.7.9
@types/make-fetch-happen 10.0.4
@types/node 16.18.70
@types/node-fetch 2.6.10
@typescript-eslint/eslint-plugin 6.18.1
@typescript-eslint/parser 6.18.1
bunyan 1.8.15
crypto-hash 1.3.0
eslint 8.56.0
graphql 16.8.1
graphql-tag 2.12.6
jest 29.7.0
jest-junit 16.0.0
log4js 6.9.1
loglevel 1.8.1
make-fetch-happen 13.0.0
node-fetch 2.7.0
prettier 3.2.2
prettier-2 2.8.8
ts-expect 1.3.0
ts-jest 29.1.1
ts-node 10.9.2
typescript 5.3.3
undici 5.28.2
winston 3.11.0
winston-transport 4.6.0
node >=16
npm >=8
node 20.11.0
npm 10.3.0
packages/createHash/package.json
sha.js ^2.4.11
node >=16
packages/dropUnusedDefinitions/package.json
graphql 14.x || 15.x || 16.x
node >=16
packages/fetcher/package.json
node >=16
packages/generate-persisted-query-manifest/package.json
@graphql-tools/graphql-tag-pluck ^8.0.0
chalk ^4.1.2
commander ^11.0.0
cosmiconfig ^8.1.3
cosmiconfig-typescript-loader ^5.0.0
globby ^11.1.0
lodash ^4.17.21
vfile ^4.2.1
vfile-reporter ^6.0.2
@gmrchk/cli-testing-library 0.1.2
@wry/equality 0.5.7
@apollo/client ^3.7.0 || ^3.8.0-alpha
graphql 14.x || 15.x || 16.x
node >=16
packages/isNodeLike/package.json
node >=16
packages/jestGraphQLASTSerializer/package.json
graphql 14.x || 15.x || 16.x
node >=16
packages/keyValueCache/package.json
lru-cache ^10.0.0
node >=16.14
packages/keyvAdapter/package.json
dataloader ^2.1.0
keyv ^4.4.0
node >=16
packages/logger/package.json
node >=16
packages/operationRegistrySignature/package.json
node >=16
packages/persisted-query-lists/package.json
@apollo/client ^3.2.0 || ^3.8.0-alpha
graphql 14.x || 15.x || 16.x
node >=16
packages/printWithReducedWhitespace/package.json
graphql 14.x || 15.x || 16.x
node >=16
packages/removeAliases/package.json
graphql 14.x || 15.x || 16.x
node >=16
packages/sortAST/package.json
lodash.sortby ^4.7.0
graphql 14.x || 15.x || 16.x
node >=16
packages/stripSensitiveLiterals/package.json
graphql 14.x || 15.x || 16.x
node >=16
packages/usageReporting/package.json
@apollo/usage-reporting-protobuf ^4.1.0
graphql 14.x || 15.x || 16.x
node >=16
packages/withRequired/package.json
node >=16
Trying to build a project using utils.withrequired
with rollup fails:
Error building /workspaces/apollo-server-integration-h3: SyntaxError: Unexpected token (1:7) in /workspaces/apollo-server-integration-h3/node_modules/.pnpm/@[email protected]/node_modules/@apollo/utils.withrequired/dist/index.d.ts
SyntaxError: Unexpected token (1:7) in /workspaces/apollo-server-integration-h3/node_modules/.pnpm/@[email protected]/node_modules/@apollo/utils.withrequired/dist/index.d.ts
at pp$4.raise (file:///workspaces/apollo-server-integration-h3/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:19420:13)
at pp$9.unexpected (file:///workspaces/apollo-server-integration-h3/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:16714:8)
at pp$9.expect (file:///workspaces/apollo-server-integration-h3/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:16708:26)
at pp$8.parseExportSpecifiers (file:///workspaces/apollo-server-integration-h3/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:17729:8)
at pp$8.parseExport (file:///workspaces/apollo-server-integration-h3/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:17644:28)
at pp$8.parseStatement (file:///workspaces/apollo-server-integration-h3/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:16890:74)
at pp$8.parseTopLevel (file:///workspaces/apollo-server-integration-h3/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:16771:21)
at Parser.parse (file:///workspaces/apollo-server-integration-h3/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:16543:15)
at Function.parse (file:///workspaces/apollo-server-integration-h3/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:16593:35)
at Graph.contextParse (file:///workspaces/apollo-server-integration-h3/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/rollup.js:22959:38) {
pos: 7,
loc: {
column: 7,
file: '/workspaces/apollo-server-integration-h3/node_modules/.pnpm/@[email protected]/node_modules/@apollo/utils.withrequired/dist/index.d.ts',
line: 1
},
raisedAt: 14,
frame: '1: export declare type WithRequired<T, K extends keyof T> = T & Required<Pick<T, K>>;\n' +
' ^\n' +
'2: //# sourceMappingURL=index.d.ts.map',
id: '/workspaces/apollo-server-integration-h3/node_modules/.pnpm/@[email protected]/node_modules/@apollo/utils.withrequired/dist/index.d.ts',
hook: 'resolveId',
code: 'PLUGIN_ERROR',
plugin: 'commonjs--resolver',
watchFiles: [
'/workspaces/apollo-server-integration-h3/src/index.ts',
'/workspaces/apollo-server-integration-h3/node_modules/.pnpm/@[email protected]/node_modules/@apollo/utils.withrequired/dist/index.d.ts'
]
}
I think the issue is that the package doesn't specify a) the type and b) its exports (which should be empty mjs and cjs files).
The official RequestInit
supports a signal?: AbortSignal
property to allow aborting a request https://fetch.spec.whatwg.org/#requestinit. I tried a few options to add it to our custom FetcherRequestInit
, but ran into snags (details below).
Any suggestions on any of these attempts (I think the errors can be worked around, but each has tradeoffs), or other ways we might solve this?
DOM
to tsconfig.base.json
's lib
node-fetch@2
doesn't support the interface completely
packages/fetcher/src/__tests__/index.test.ts:10:14 - error TS2345: Argument of type 'typeof fetch' is not assignable to parameter of type 'Fetcher'.
Types of parameters 'init' and 'init' are incompatible.
Type 'FetcherRequestInit | undefined' is not assignable to type 'RequestInit | undefined'.
Type 'FetcherRequestInit' is not assignable to type 'RequestInit'.
The types of 'signal.addEventListener' are incompatible between these types.
Type '{ <K extends "abort">(type: K, listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any, options?: boolean | AddEventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | ... 1 more ... | undefined): void; }' is not assignable to type '(type: "abort", listener: (this: AbortSignal, event: any) => any, options?: boolean | { capture?: boolean | undefined; once?: boolean | undefined; passive?: boolean | undefined; } | undefined) => void'.
Types of parameters 'options' and 'options' are incompatible.
Type 'boolean | { capture?: boolean | undefined; once?: boolean | undefined; passive?: boolean | undefined; } | undefined' is not assignable to type 'boolean | AddEventListenerOptions | undefined'.
Type '{ capture?: boolean | undefined; once?: boolean | undefined; passive?: boolean | undefined; }' is not assignable to type 'boolean | AddEventListenerOptions | undefined'.
Type '{ capture?: boolean | undefined; once?: boolean | undefined; passive?: boolean | undefined; }' is not assignable to type 'AddEventListenerOptions' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
Types of property 'once' are incompatible.
Type 'boolean | undefined' is not assignable to type 'boolean'.
Type 'undefined' is not assignable to type 'boolean'.
10 isAFetcher(nodeFetch);
node-fetch@3
Attempting to update to node-fetch@3
causes the make-fetch-happen
test to fail
packages/fetcher/src/__tests__/index.test.ts:14:14 - error TS2345: Argument of type 'FetchInterface' is not assignable to parameter of type 'Fetcher'.
Types of parameters 'opts' and 'init' are incompatible.
Type 'FetcherRequestInit | undefined' is not assignable to type 'FetchOptions | undefined'.
Type 'FetcherRequestInit' is not assignable to type 'FetchOptions' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
Property 'timeout' is missing in type 'FetcherRequestInit' but required in type 'NodeFetchOptions'.
14 isAFetcher(makeFetchHappen);
AbortSignal
I also tried copy-pasta'ing AbortSignal
from the typescript defs but that's a whole lotta extra stuff we have to bring along (also need to make modifications to support aforementioned node-fetch
error). Using the node-fetch
type defs doesn't work (incompatibility with undici
). the undici
type defs assume a DOM-compatible global.
We have this error when the queries are not yet cached: DataLoader must be constructed with a function which accepts Array<key> and returns Promise<Array<value>>, but the function did not return a Promise of an Array of the same length as the Array of keys.
const server = new ApolloServer({
...,
cache: new KeyvAdapter(new Keyv(process.env.CACHE_REDIS_URL)),
}
See https://github.com/apollographql/apollo-utils/blob/main/packages/keyvAdapter/src/index.ts#L27
As mentioned in the DataLoader documentation, the Array of values must be the same length as the Array of keys. And it seems this.keyv.get does not ensure that. We should probably ensure that in the KeyvAdapter.
Workaround: set disableBatchReads
to true
I have a load balanced redis sentinels running in kuberenetes, however every hour I get this error below and this "warning" is causing my application to crash. I am still investigating, why this code thinks they are unavailable (which they aren't), but is there a way to catch this application as it looks like ioredis
wants to retry in 10ms.
const redis = new Redis({
sentinels: [{ host: process.env.REDIS_HOST, port: 26379 }],
name: 'mymaster',
});
const keyvRedis = new KeyvRedis(redis);
cache = new KeyvAdapter(new Keyv({ store: keyvRedis }));
/node_modules/standard-as-callback/built/index.js:6
throw e;
Error: All sentinels are unreachable. Retrying from scratch after 10ms.
at SentinelConnector.<anonymous> (/node_modules/ioredis/built/connectors/SentinelConnector/index.js:73:31)
at Generator.next (<anonymous>)
at /node_modules/ioredis/built/connectors/SentinelConnector/index.js:8:71
at new Promise (<anonymous>)
at __awaiter (/node_modules/ioredis/built/connectors/SentinelConnector/index.js:4:12)
at connectToNext (/node_modules/ioredis/built/connectors/SentinelConnector/index.js:59:37)
at SentinelConnector.connect (/node_modules/ioredis/built/connectors/SentinelConnector/index.js:128:16)
at /node_modules/ioredis/built/redis/index.js:292:55
at new Promise (<anonymous>)
at Redis.connect (/node_modules/ioredis/built/redis/index.js:265:21)
Emitted 'error' event on Keyv instance at:
at KeyvRedis.<anonymous> (/node_modules/keyv/src/index.js:61:46)
at KeyvRedis.emit (node:events:390:28)
at Redis.<anonymous> (/node_modules/@keyv/redis/src/index.js:18:40)
at Redis.emit (node:events:390:28)
at Redis.silentEmit (/node_modules/ioredis/built/redis/index.js:553:26)
at /node_modules/ioredis/built/redis/index.js:297:23
at tryCatcher (/node_modules/standard-as-callback/built/utils.js:12:23)
at /node_modules/standard-as-callback/built/index.js:33:51
at runMicrotasks (<anonymous>)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
```
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.