diff --git a/.changeset/quiet-moles-nail.md b/.changeset/quiet-moles-nail.md new file mode 100644 index 0000000000..46b4de1059 --- /dev/null +++ b/.changeset/quiet-moles-nail.md @@ -0,0 +1,5 @@ +--- +'graphql-yoga': minor +--- + +Now `onParams` hook's payload has `serverContext` diff --git a/.changeset/twenty-birds-sin.md b/.changeset/twenty-birds-sin.md new file mode 100644 index 0000000000..3b0c4ebf8c --- /dev/null +++ b/.changeset/twenty-birds-sin.md @@ -0,0 +1,5 @@ +--- +'@graphql-yoga/plugin-response-cache': patch +--- + +Now `enabled` and `session` factory functions take a second parameter `ServerContext` that includes the server specific context object. But this object is not the one provided by the user. [Learn more about the difference between the server context and the user context](https://the-guild.dev/graphql/yoga-server/docs/features/context#advanced-context-life-cycle) diff --git a/examples/bun-yoga-ws/package.json b/examples/bun-yoga-ws/package.json index 75adfe9935..b6174dd0df 100644 --- a/examples/bun-yoga-ws/package.json +++ b/examples/bun-yoga-ws/package.json @@ -10,7 +10,7 @@ "bun-types": "^1.0.0", "graphql": "^16.6.0", "graphql-ws": "^5.14.1", - "graphql-yoga": "^4.0.5" + "graphql-yoga": "5.3.1" }, "devDependencies": { "@whatwg-node/fetch": "^0.9.0" diff --git a/packages/graphql-yoga/src/plugins/types.ts b/packages/graphql-yoga/src/plugins/types.ts index 79aac461c7..ee7c9d827b 100644 --- a/packages/graphql-yoga/src/plugins/types.ts +++ b/packages/graphql-yoga/src/plugins/types.ts @@ -49,7 +49,7 @@ export type Plugin< * Use this hook with your own risk. It is still experimental and may change in the future. * @internal */ - onParams?: OnParamsHook; + onParams?: OnParamsHook; /** * Use this hook with your own risk. It is still experimental and may change in the future. * @internal @@ -106,11 +106,14 @@ export interface OnRequestParseDoneEventPayload { setRequestParserResult: (params: GraphQLParams | GraphQLParams[]) => void; } -export type OnParamsHook = (payload: OnParamsEventPayload) => PromiseOrValue; +export type OnParamsHook = ( + payload: OnParamsEventPayload, +) => PromiseOrValue; -export interface OnParamsEventPayload { +export interface OnParamsEventPayload { params: GraphQLParams; request: Request; + serverContext?: TServerContext; setParams: (params: GraphQLParams) => void; setResult: (result: ExecutionResult | AsyncIterable) => void; fetchAPI: FetchAPI; diff --git a/packages/graphql-yoga/src/server.ts b/packages/graphql-yoga/src/server.ts index eadd1eaf5b..f9013d26f4 100644 --- a/packages/graphql-yoga/src/server.ts +++ b/packages/graphql-yoga/src/server.ts @@ -197,7 +197,7 @@ export class YogaServer< Plugin >; private onRequestParseHooks: OnRequestParseHook[]; - private onParamsHooks: OnParamsHook[]; + private onParamsHooks: OnParamsHook[]; private onResultProcessHooks: OnResultProcess[]; private maskedErrorsOpts: YogaMaskedErrorOpts | null; private id: string; @@ -446,12 +446,14 @@ export class YogaServer< : [serverContext: TServerContext] ) { try { + const serverContext = args[0]; let result: ExecutionResult | AsyncIterable | undefined; for (const onParamsHook of this.onParamsHooks) { await onParamsHook({ params, request, + serverContext, setParams(newParams) { params = newParams; }, @@ -464,7 +466,7 @@ export class YogaServer< if (result == null) { const additionalContext = - args[0]?.request === request + serverContext?.request === request ? { params, } @@ -473,8 +475,8 @@ export class YogaServer< params, }; - const initialContext = args[0] - ? Object.assign(batched ? Object.create(args[0]) : args[0], additionalContext) + const initialContext = serverContext + ? Object.assign(batched ? Object.create(serverContext) : serverContext, additionalContext) : additionalContext; const enveloped = this.getEnveloped(initialContext); diff --git a/packages/plugins/response-cache/src/index.ts b/packages/plugins/response-cache/src/index.ts index 2c7975cc3c..2bdf624a2e 100644 --- a/packages/plugins/response-cache/src/index.ts +++ b/packages/plugins/response-cache/src/index.ts @@ -20,13 +20,13 @@ export type BuildResponseCacheKeyFunction = ( }, ) => ReturnType; -export type UseResponseCacheParameter = Omit< +export type UseResponseCacheParameter = Omit< UseEnvelopResponseCacheParameter, 'getDocumentString' | 'session' | 'cache' | 'enabled' | 'buildResponseCacheKey' > & { cache?: Cache; - session: (request: Request) => PromiseOrValue>; - enabled?: (request: Request) => boolean; + session: (request: Request, serverContext?: TServerContext) => PromiseOrValue>; + enabled?: (request: Request, serverContext?: TServerContext) => boolean; buildResponseCacheKey?: BuildResponseCacheKeyFunction; }; @@ -82,7 +82,9 @@ export interface Cache extends EnvelopCache { >; } -export function useResponseCache(options: UseResponseCacheParameter): Plugin { +export function useResponseCache>( + options: UseResponseCacheParameter, +): Plugin { const buildResponseCacheKey: BuildResponseCacheKeyFunction = options?.buildResponseCacheKey || defaultBuildResponseCacheKey; const cache = options.cache ?? createInMemoryCache(); @@ -94,10 +96,10 @@ export function useResponseCache(options: UseResponseCacheParameter): Plugin { }, onPluginInit({ addPlugin }) { addPlugin( - useEnvelopResponseCache({ + useEnvelopResponseCache({ ...options, - enabled({ request }) { - return enabled(request); + enabled(ctx: YogaInitialContext & TServerContext) { + return enabled(ctx.request, ctx); }, cache, getDocumentString: getDocumentStringForEnvelop, @@ -129,8 +131,8 @@ export function useResponseCache(options: UseResponseCacheParameter): Plugin { }), ); }, - async onRequest({ request, fetchAPI, endResponse }) { - if (enabled(request)) { + async onRequest({ request, serverContext, fetchAPI, endResponse }) { + if (enabled(request, serverContext)) { const operationId = request.headers.get('If-None-Match'); if (operationId) { const cachedResponse = await cache.get(operationId); @@ -158,8 +160,8 @@ export function useResponseCache(options: UseResponseCacheParameter): Plugin { } } }, - async onParams({ params, request, setResult }) { - const sessionId = await options.session(request); + async onParams({ params, request, serverContext, setResult }) { + const sessionId = await options.session(request, serverContext); const operationId = await buildResponseCacheKey({ documentString: params.query || '', variableValues: params.variables, @@ -169,7 +171,7 @@ export function useResponseCache(options: UseResponseCacheParameter): Plugin { }); operationIdByRequest.set(request, operationId); sessionByRequest.set(request, sessionId); - if (enabled(request)) { + if (enabled(request, serverContext)) { const cachedResponse = await cache.get(operationId); if (cachedResponse) { const responseWithSymbol = { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 70bc4f3137..b1792225dc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -350,8 +350,8 @@ importers: specifier: ^5.14.1 version: 5.14.1(graphql@16.8.1) graphql-yoga: - specifier: ^4.0.5 - version: 4.0.5(graphql@16.8.1) + specifier: 5.3.1 + version: link:../../packages/graphql-yoga/dist devDependencies: '@whatwg-node/fetch': specifier: ^0.9.0 @@ -7752,31 +7752,6 @@ packages: dependencies: graphql: 16.8.1 - /@graphql-yoga/logger@1.0.0: - resolution: {integrity: sha512-JYoxwnPggH2BfO+dWlWZkDeFhyFZqaTRGLvFhy+Pjp2UxitEW6nDrw+pEDw/K9tJwMjIFMmTT9VfTqrnESmBHg==} - engines: {node: '>=16.0.0'} - dependencies: - tslib: 2.6.2 - dev: false - - /@graphql-yoga/subscription@4.0.0: - resolution: {integrity: sha512-0qsN/BPPZNMoC2CZ8i+P6PgiJyHh1H35aKDt37qARBDaIOKDQuvEOq7+4txUKElcmXi7DYFo109FkhSQoEajrg==} - engines: {node: '>=16.0.0'} - dependencies: - '@graphql-yoga/typed-event-target': 2.0.0 - '@repeaterjs/repeater': 3.0.4 - '@whatwg-node/events': 0.1.0 - tslib: 2.6.2 - dev: false - - /@graphql-yoga/typed-event-target@2.0.0: - resolution: {integrity: sha512-oA/VGxGmaSDym1glOHrltw43qZsFwLLjBwvh57B79UKX/vo3+UQcRgOyE44c5RP7DCYjkrC2tuArZmb6jCzysw==} - engines: {node: '>=16.0.0'} - dependencies: - '@repeaterjs/repeater': 3.0.4 - tslib: 2.6.2 - dev: false - /@grpc/grpc-js@1.8.11: resolution: {integrity: sha512-f/xC+6Z2QKsRJ+VSSFlt4hA5KSRm+PKvMWV8kMPkMgGlFidR6PeIkXrOasIY2roe+WROM6GFQLlgDKfeEZo2YQ==} engines: {node: ^8.13.0 || >=10.10.0} @@ -21530,26 +21505,6 @@ packages: dependencies: graphql: 16.8.1 - /graphql-yoga@4.0.5(graphql@16.8.1): - resolution: {integrity: sha512-vIbJU9QX5RP4PoxbMCHcfOlt/3EsC/0uLdAOlKaiUvlwJDTFCaIHo2X10vL4i/27Gw8g90ECIwm2YbmeLDwcqg==} - engines: {node: '>=16.0.0'} - peerDependencies: - graphql: ^15.2.0 || ^16.0.0 - dependencies: - '@envelop/core': 4.0.0 - '@graphql-tools/executor': 1.2.5(graphql@16.8.1) - '@graphql-tools/schema': 10.0.3(graphql@16.8.1) - '@graphql-tools/utils': 10.1.1(graphql@16.8.1) - '@graphql-yoga/logger': 1.0.0 - '@graphql-yoga/subscription': 4.0.0 - '@whatwg-node/fetch': 0.9.17 - '@whatwg-node/server': 0.9.33 - dset: 3.1.2 - graphql: 16.8.1 - lru-cache: 10.0.0 - tslib: 2.6.2 - dev: false - /graphql@16.6.0: resolution: {integrity: sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} @@ -32216,7 +32171,7 @@ packages: uglify-js: optional: true dependencies: - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.18 esbuild: 0.17.19 jest-worker: 27.5.1 schema-utils: 3.3.0