@graphql-mesh/plugin-response-cache 0.104.0-alpha-20250124181238-87366ee8e2a95025d881bdaba556f04d337e8331 → 0.104.0-alpha-20250303152151-d99794163758395e3b9780a2cfdef2a5a39433df

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cjs/index.js CHANGED
@@ -1,11 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = useMeshResponseCache;
4
+ const tslib_1 = require("tslib");
5
+ const cache_control_parser_1 = tslib_1.__importDefault(require("cache-control-parser"));
4
6
  const response_cache_1 = require("@envelop/response-cache");
5
7
  const cross_helpers_1 = require("@graphql-mesh/cross-helpers");
6
8
  const string_interpolation_1 = require("@graphql-mesh/string-interpolation");
7
9
  const utils_1 = require("@graphql-tools/utils");
8
10
  const plugin_response_cache_1 = require("@graphql-yoga/plugin-response-cache");
11
+ const promise_helpers_1 = require("@whatwg-node/promise-helpers");
9
12
  function generateSessionIdFactory(sessionIdDef) {
10
13
  if (sessionIdDef == null) {
11
14
  return function voidSession() {
@@ -79,7 +82,7 @@ function getCacheForResponseCache(meshCache) {
79
82
  const entitiesToRemoveJobs = [];
80
83
  for (const { typename, id } of entitiesToRemove) {
81
84
  const entryId = `${typename}.${id}`;
82
- const job = (0, utils_1.mapMaybePromise)(meshCache.getKeysByPrefix(`response-cache:${entryId}:`), cacheEntriesToDelete => {
85
+ const job = (0, promise_helpers_1.handleMaybePromise)(() => meshCache.getKeysByPrefix(`response-cache:${entryId}:`), cacheEntriesToDelete => {
83
86
  const jobs = [];
84
87
  for (const cacheEntryName of cacheEntriesToDelete) {
85
88
  const [, , responseId] = cacheEntryName.split(':');
@@ -108,10 +111,10 @@ function getCacheForResponseCache(meshCache) {
108
111
  else if (entitiesToRemoveJobs.length > 0) {
109
112
  promiseAllJob = Promise.all(entitiesToRemoveJobs);
110
113
  }
111
- return (0, utils_1.mapMaybePromise)(promiseAllJob, () => {
114
+ return (0, promise_helpers_1.handleMaybePromise)(() => promiseAllJob, () => {
112
115
  const responseIdsToCheckJobs = [];
113
116
  for (const responseId of responseIdsToCheck) {
114
- const job = (0, utils_1.mapMaybePromise)(meshCache.getKeysByPrefix(`response-cache:${responseId}:`), cacheEntries => {
117
+ const job = (0, promise_helpers_1.handleMaybePromise)(() => meshCache.getKeysByPrefix(`response-cache:${responseId}:`), cacheEntries => {
115
118
  if (cacheEntries.length !== 0) {
116
119
  return meshCache.delete(`response-cache:${responseId}`);
117
120
  }
@@ -143,7 +146,11 @@ function useMeshResponseCache(options) {
143
146
  ttlPerSchemaCoordinate[ttlConfig.coordinate] = ttlConfig.ttl;
144
147
  }
145
148
  }
146
- return (0, plugin_response_cache_1.useResponseCache)({
149
+ // Stored TTL by the context
150
+ // To be compared with the calculated one later in `onTtl`
151
+ const ttlByContext = new WeakMap();
152
+ // @ts-expect-error - GatewayPlugin types
153
+ const plugin = (0, plugin_response_cache_1.useResponseCache)({
147
154
  includeExtensionMetadata: options.includeExtensionMetadata != null
148
155
  ? options.includeExtensionMetadata
149
156
  : cross_helpers_1.process.env.DEBUG === '1',
@@ -157,5 +164,45 @@ function useMeshResponseCache(options) {
157
164
  cache: getCacheForResponseCache(options.cache),
158
165
  ttlPerType,
159
166
  ttlPerSchemaCoordinate,
167
+ // Checks the TTL stored in the context
168
+ // Compares it to the calculated one
169
+ // Then it takes the lowest value
170
+ onTtl({ ttl, context }) {
171
+ const ttlForThisContext = ttlByContext.get(context);
172
+ if (ttlForThisContext != null && ttlForThisContext < ttl) {
173
+ return ttlForThisContext;
174
+ }
175
+ return ttl;
176
+ },
160
177
  });
178
+ // Checks the TTL stored in the context
179
+ // Takes the lowest value
180
+ function checkTtl(context, ttl) {
181
+ const ttlForThisContext = ttlByContext.get(context);
182
+ if (ttlForThisContext == null || ttl < ttlForThisContext) {
183
+ ttlByContext.set(context, ttl);
184
+ }
185
+ }
186
+ plugin.onFetch = function ({ executionRequest, context }) {
187
+ // Only if it is a subgraph request
188
+ if (executionRequest && context) {
189
+ return function onFetchDone({ response }) {
190
+ const cacheControlHeader = response.headers.get('cache-control');
191
+ if (cacheControlHeader != null) {
192
+ const parsedCacheControl = cache_control_parser_1.default.parse(cacheControlHeader);
193
+ if (parsedCacheControl['max-age'] != null) {
194
+ const maxAgeInSeconds = parsedCacheControl['max-age'];
195
+ const maxAgeInMs = maxAgeInSeconds * 1000;
196
+ checkTtl(context, maxAgeInMs);
197
+ }
198
+ if (parsedCacheControl['s-maxage'] != null) {
199
+ const sMaxAgeInSeconds = parsedCacheControl['s-maxage'];
200
+ const sMaxAgeInMs = sMaxAgeInSeconds * 1000;
201
+ checkTtl(context, sMaxAgeInMs);
202
+ }
203
+ }
204
+ };
205
+ }
206
+ };
207
+ return plugin;
161
208
  }
package/esm/index.js CHANGED
@@ -1,8 +1,10 @@
1
+ import CacheControlParser from 'cache-control-parser';
1
2
  import { defaultBuildResponseCacheKey } from '@envelop/response-cache';
2
3
  import { process } from '@graphql-mesh/cross-helpers';
3
4
  import { stringInterpolator } from '@graphql-mesh/string-interpolation';
4
- import { isPromise, mapMaybePromise } from '@graphql-tools/utils';
5
+ import { isPromise } from '@graphql-tools/utils';
5
6
  import { useResponseCache } from '@graphql-yoga/plugin-response-cache';
7
+ import { handleMaybePromise } from '@whatwg-node/promise-helpers';
6
8
  function generateSessionIdFactory(sessionIdDef) {
7
9
  if (sessionIdDef == null) {
8
10
  return function voidSession() {
@@ -76,7 +78,7 @@ function getCacheForResponseCache(meshCache) {
76
78
  const entitiesToRemoveJobs = [];
77
79
  for (const { typename, id } of entitiesToRemove) {
78
80
  const entryId = `${typename}.${id}`;
79
- const job = mapMaybePromise(meshCache.getKeysByPrefix(`response-cache:${entryId}:`), cacheEntriesToDelete => {
81
+ const job = handleMaybePromise(() => meshCache.getKeysByPrefix(`response-cache:${entryId}:`), cacheEntriesToDelete => {
80
82
  const jobs = [];
81
83
  for (const cacheEntryName of cacheEntriesToDelete) {
82
84
  const [, , responseId] = cacheEntryName.split(':');
@@ -105,10 +107,10 @@ function getCacheForResponseCache(meshCache) {
105
107
  else if (entitiesToRemoveJobs.length > 0) {
106
108
  promiseAllJob = Promise.all(entitiesToRemoveJobs);
107
109
  }
108
- return mapMaybePromise(promiseAllJob, () => {
110
+ return handleMaybePromise(() => promiseAllJob, () => {
109
111
  const responseIdsToCheckJobs = [];
110
112
  for (const responseId of responseIdsToCheck) {
111
- const job = mapMaybePromise(meshCache.getKeysByPrefix(`response-cache:${responseId}:`), cacheEntries => {
113
+ const job = handleMaybePromise(() => meshCache.getKeysByPrefix(`response-cache:${responseId}:`), cacheEntries => {
112
114
  if (cacheEntries.length !== 0) {
113
115
  return meshCache.delete(`response-cache:${responseId}`);
114
116
  }
@@ -140,7 +142,11 @@ export default function useMeshResponseCache(options) {
140
142
  ttlPerSchemaCoordinate[ttlConfig.coordinate] = ttlConfig.ttl;
141
143
  }
142
144
  }
143
- return useResponseCache({
145
+ // Stored TTL by the context
146
+ // To be compared with the calculated one later in `onTtl`
147
+ const ttlByContext = new WeakMap();
148
+ // @ts-expect-error - GatewayPlugin types
149
+ const plugin = useResponseCache({
144
150
  includeExtensionMetadata: options.includeExtensionMetadata != null
145
151
  ? options.includeExtensionMetadata
146
152
  : process.env.DEBUG === '1',
@@ -154,5 +160,45 @@ export default function useMeshResponseCache(options) {
154
160
  cache: getCacheForResponseCache(options.cache),
155
161
  ttlPerType,
156
162
  ttlPerSchemaCoordinate,
163
+ // Checks the TTL stored in the context
164
+ // Compares it to the calculated one
165
+ // Then it takes the lowest value
166
+ onTtl({ ttl, context }) {
167
+ const ttlForThisContext = ttlByContext.get(context);
168
+ if (ttlForThisContext != null && ttlForThisContext < ttl) {
169
+ return ttlForThisContext;
170
+ }
171
+ return ttl;
172
+ },
157
173
  });
174
+ // Checks the TTL stored in the context
175
+ // Takes the lowest value
176
+ function checkTtl(context, ttl) {
177
+ const ttlForThisContext = ttlByContext.get(context);
178
+ if (ttlForThisContext == null || ttl < ttlForThisContext) {
179
+ ttlByContext.set(context, ttl);
180
+ }
181
+ }
182
+ plugin.onFetch = function ({ executionRequest, context }) {
183
+ // Only if it is a subgraph request
184
+ if (executionRequest && context) {
185
+ return function onFetchDone({ response }) {
186
+ const cacheControlHeader = response.headers.get('cache-control');
187
+ if (cacheControlHeader != null) {
188
+ const parsedCacheControl = CacheControlParser.parse(cacheControlHeader);
189
+ if (parsedCacheControl['max-age'] != null) {
190
+ const maxAgeInSeconds = parsedCacheControl['max-age'];
191
+ const maxAgeInMs = maxAgeInSeconds * 1000;
192
+ checkTtl(context, maxAgeInMs);
193
+ }
194
+ if (parsedCacheControl['s-maxage'] != null) {
195
+ const sMaxAgeInSeconds = parsedCacheControl['s-maxage'];
196
+ const sMaxAgeInMs = sMaxAgeInSeconds * 1000;
197
+ checkTtl(context, sMaxAgeInMs);
198
+ }
199
+ }
200
+ };
201
+ }
202
+ };
203
+ return plugin;
158
204
  }
package/package.json CHANGED
@@ -1,20 +1,22 @@
1
1
  {
2
2
  "name": "@graphql-mesh/plugin-response-cache",
3
- "version": "0.104.0-alpha-20250124181238-87366ee8e2a95025d881bdaba556f04d337e8331",
3
+ "version": "0.104.0-alpha-20250303152151-d99794163758395e3b9780a2cfdef2a5a39433df",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
6
  "graphql": "*"
7
7
  },
8
8
  "dependencies": {
9
- "@envelop/core": "^5.0.0",
10
- "@envelop/response-cache": "^6.1.1",
11
- "@graphql-mesh/cross-helpers": "^0.4.9",
9
+ "@envelop/core": "^5.1.0",
10
+ "@envelop/response-cache": "^7.0.0",
11
+ "@graphql-mesh/cross-helpers": "^0.4.10",
12
12
  "@graphql-mesh/string-interpolation": "0.5.8",
13
- "@graphql-mesh/types": "0.104.0-alpha-20250124181238-87366ee8e2a95025d881bdaba556f04d337e8331",
14
- "@graphql-mesh/utils": "0.104.0-alpha-20250124181238-87366ee8e2a95025d881bdaba556f04d337e8331",
13
+ "@graphql-mesh/types": "0.104.0-alpha-20250303152151-d99794163758395e3b9780a2cfdef2a5a39433df",
14
+ "@graphql-mesh/utils": "0.104.0-alpha-20250303152151-d99794163758395e3b9780a2cfdef2a5a39433df",
15
15
  "@graphql-tools/utils": "^10.6.2",
16
- "@graphql-yoga/plugin-response-cache": "^3.1.1",
17
- "graphql-yoga": "^5.7.0",
16
+ "@graphql-yoga/plugin-response-cache": "^3.13.1",
17
+ "@whatwg-node/promise-helpers": "^1.0.0",
18
+ "cache-control-parser": "^2.0.6",
19
+ "graphql-yoga": "^5.12.0",
18
20
  "tslib": "^2.4.0"
19
21
  },
20
22
  "repository": {
@@ -1,4 +1,4 @@
1
- import type { Plugin } from 'graphql-yoga';
1
+ import type { GatewayPlugin } from '@graphql-hive/gateway-runtime';
2
2
  import type { KeyValueCache, YamlConfig } from '@graphql-mesh/types';
3
3
  import type { UseResponseCacheParameter } from '@graphql-yoga/plugin-response-cache';
4
4
  export type ResponseCacheConfig = Omit<UseResponseCacheParameter, 'cache'> & {
@@ -20,11 +20,11 @@ export type ResponseCacheConfig = Omit<UseResponseCacheParameter, 'cache'> & {
20
20
  * Response cache plugin for GraphQL Mesh
21
21
  * @param options
22
22
  */
23
- export default function useMeshResponseCache(options: ResponseCacheConfig): Plugin;
23
+ export default function useMeshResponseCache(options: ResponseCacheConfig): GatewayPlugin;
24
24
  /**
25
25
  * @deprecated Use new configuration format `ResponseCacheConfig`
26
26
  * @param options
27
27
  */
28
28
  export default function useMeshResponseCache(options: YamlConfig.ResponseCacheConfig & {
29
29
  cache: KeyValueCache;
30
- }): Plugin;
30
+ }): GatewayPlugin;
@@ -1,4 +1,4 @@
1
- import type { Plugin } from 'graphql-yoga';
1
+ import type { GatewayPlugin } from '@graphql-hive/gateway-runtime';
2
2
  import type { KeyValueCache, YamlConfig } from '@graphql-mesh/types';
3
3
  import type { UseResponseCacheParameter } from '@graphql-yoga/plugin-response-cache';
4
4
  export type ResponseCacheConfig = Omit<UseResponseCacheParameter, 'cache'> & {
@@ -20,11 +20,11 @@ export type ResponseCacheConfig = Omit<UseResponseCacheParameter, 'cache'> & {
20
20
  * Response cache plugin for GraphQL Mesh
21
21
  * @param options
22
22
  */
23
- export default function useMeshResponseCache(options: ResponseCacheConfig): Plugin;
23
+ export default function useMeshResponseCache(options: ResponseCacheConfig): GatewayPlugin;
24
24
  /**
25
25
  * @deprecated Use new configuration format `ResponseCacheConfig`
26
26
  * @param options
27
27
  */
28
28
  export default function useMeshResponseCache(options: YamlConfig.ResponseCacheConfig & {
29
29
  cache: KeyValueCache;
30
- }): Plugin;
30
+ }): GatewayPlugin;