@envelop/response-cache 3.0.0-alpha-d0d0776.0 → 3.0.0-alpha-6a4e0e2.0

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.
Files changed (4) hide show
  1. package/index.js +111 -106
  2. package/index.mjs +107 -99
  3. package/package.json +6 -18
  4. package/plugin.d.ts +10 -13
package/index.js CHANGED
@@ -2,21 +2,19 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- const LRU = require('lru-cache');
5
+ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
+
7
+ const LRU = _interopDefault(require('lru-cache'));
6
8
  const core = require('@envelop/core');
7
9
  const utils = require('@graphql-tools/utils');
8
10
  const graphql = require('graphql');
9
- const jsonStableStringify = require('fast-json-stable-stringify');
10
-
11
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
12
-
13
- const LRU__default = /*#__PURE__*/_interopDefaultLegacy(LRU);
14
- const jsonStableStringify__default = /*#__PURE__*/_interopDefaultLegacy(jsonStableStringify);
11
+ const jsonStableStringify = _interopDefault(require('fast-json-stable-stringify'));
15
12
 
16
13
  const createInMemoryCache = (params) => {
17
- const buildEntityId = params?.buildEntityId ?? defaultBuildEntityId;
18
- const cachedResponses = new LRU__default["default"]({
19
- max: params?.max,
14
+ var _a;
15
+ const buildEntityId = (_a = params === null || params === void 0 ? void 0 : params.buildEntityId) !== null && _a !== void 0 ? _a : defaultBuildEntityId;
16
+ const cachedResponses = new LRU({
17
+ max: params === null || params === void 0 ? void 0 : params.max,
20
18
  stale: false,
21
19
  noDisposeOnSet: true,
22
20
  dispose(responseId) {
@@ -26,12 +24,13 @@ const createInMemoryCache = (params) => {
26
24
  const entityToResponseIds = new Map();
27
25
  const responseIdToEntityIds = new Map();
28
26
  function purgeResponse(responseId, shouldRemove = true) {
27
+ var _a;
29
28
  const entityIds = responseIdToEntityIds.get(responseId);
30
29
  // get entities related to the response
31
30
  if (entityIds !== undefined) {
32
31
  for (const entityId of entityIds) {
33
32
  // remove the response mapping from the entity
34
- entityToResponseIds.get(entityId)?.delete(responseId);
33
+ (_a = entityToResponseIds.get(entityId)) === null || _a === void 0 ? void 0 : _a.delete(responseId);
35
34
  }
36
35
  // remove all the entity mappings from the response
37
36
  responseIdToEntityIds.delete(responseId);
@@ -79,7 +78,8 @@ const createInMemoryCache = (params) => {
79
78
  }
80
79
  },
81
80
  get(responseId) {
82
- return cachedResponses.get(responseId) ?? null;
81
+ var _a;
82
+ return (_a = cachedResponses.get(responseId)) !== null && _a !== void 0 ? _a : null;
83
83
  },
84
84
  invalidate(entitiesToRemove) {
85
85
  for (const { typename, id } of entitiesToRemove) {
@@ -154,17 +154,19 @@ const hashSHA256 = async (text) => {
154
154
  };
155
155
 
156
156
  const contextSymbol = Symbol('responseCache');
157
- const rawDocumentStringSymbol = Symbol('rawDocumentString');
158
157
  /**
159
158
  * Default function used for building the response cache key.
160
159
  * It is exported here for advanced use-cases. E.g. if you want to short circuit and serve responses from the cache on a global level in order to completely by-pass the GraphQL flow.
161
160
  */
162
- const defaultBuildResponseCacheKey = params => hashSHA256([
163
- params.documentString,
164
- params.operationName ?? '',
165
- jsonStableStringify__default["default"](params.variableValues ?? {}),
166
- params.sessionId ?? '',
167
- ].join('|'));
161
+ const defaultBuildResponseCacheKey = params => {
162
+ var _a, _b, _c;
163
+ return hashSHA256([
164
+ params.documentString,
165
+ (_a = params.operationName) !== null && _a !== void 0 ? _a : '',
166
+ jsonStableStringify((_b = params.variableValues) !== null && _b !== void 0 ? _b : {}),
167
+ (_c = params.sessionId) !== null && _c !== void 0 ? _c : '',
168
+ ].join('|'));
169
+ };
168
170
  /**
169
171
  * Default function used to check if the result should be cached.
170
172
  *
@@ -181,8 +183,16 @@ const defaultShouldCacheResult = (params) => {
181
183
  }
182
184
  return true;
183
185
  };
184
- const defaultGetDocumentStringFromContext = context => context[rawDocumentStringSymbol];
185
- function useResponseCache({ cache = createInMemoryCache(), ttl: globalTtl = Infinity, session = () => null, enabled, ignoredTypes = [], ttlPerType = {}, ttlPerSchemaCoordinate = {}, idFields = ['id'], invalidateViaMutation = true, buildResponseCacheKey = defaultBuildResponseCacheKey, getDocumentStringFromContext = defaultGetDocumentStringFromContext, shouldCacheResult = defaultShouldCacheResult,
186
+ const documentStringByDocument = new WeakMap();
187
+ function defaultGetDocumentString(executionArgs) {
188
+ let documentString = documentStringByDocument.get(executionArgs.document);
189
+ if (!documentString) {
190
+ documentString = graphql.print(executionArgs.document);
191
+ documentStringByDocument.set(executionArgs.document, documentString);
192
+ }
193
+ return documentString;
194
+ }
195
+ function useResponseCache({ cache = createInMemoryCache(), ttl: globalTtl = Infinity, session = () => null, enabled, ignoredTypes = [], ttlPerType = {}, ttlPerSchemaCoordinate = {}, idFields = ['id'], invalidateViaMutation = true, buildResponseCacheKey = defaultBuildResponseCacheKey, getDocumentString = defaultGetDocumentString, shouldCacheResult = defaultShouldCacheResult,
186
196
  // eslint-disable-next-line dot-notation
187
197
  includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_ENV'] === 'development' : false, } = {}) {
188
198
  const appliedTransform = Symbol('responseCache.appliedTransform');
@@ -191,8 +201,9 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
191
201
  ttlPerSchemaCoordinate = { 'Query.__schema': 0, ...ttlPerSchemaCoordinate };
192
202
  return {
193
203
  onSchemaChange({ schema, replaceSchema }) {
204
+ var _a;
194
205
  // @ts-expect-error See https://github.com/graphql/graphql-js/pull/3511 - remove this comments once merged
195
- if (schema.extensions?.[appliedTransform] === true) {
206
+ if (((_a = schema.extensions) === null || _a === void 0 ? void 0 : _a[appliedTransform]) === true) {
196
207
  return;
197
208
  }
198
209
  const patchedSchema = applyResponseCacheLogic(schema, idFields);
@@ -202,18 +213,15 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
202
213
  };
203
214
  replaceSchema(patchedSchema);
204
215
  },
205
- onParse(parseCtx) {
206
- return function onParseEnd(ctx) {
207
- if (ctx.result && 'kind' in ctx.result) {
208
- const source = parseCtx.params.source;
209
- const rawDocumentString = typeof source === 'string' ? source : source.body;
210
- ctx.extendContext({
211
- [rawDocumentStringSymbol]: rawDocumentString,
212
- });
216
+ onParse({ params: { source } }) {
217
+ return function onParseEnd({ result }) {
218
+ if (result != null && !(result instanceof Error)) {
219
+ documentStringByDocument.set(result, source.toString());
213
220
  }
214
221
  };
215
222
  },
216
223
  async onExecute(ctx) {
224
+ var _a;
217
225
  const identifier = new Map();
218
226
  const types = new Set();
219
227
  const context = {
@@ -253,99 +261,95 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
253
261
  },
254
262
  };
255
263
  }
256
- const documentString = getDocumentStringFromContext(ctx.args.contextValue);
257
- if (documentString != null) {
258
- const operationId = await buildResponseCacheKey({
259
- documentString,
260
- variableValues: ctx.args.variableValues,
261
- operationName: ctx.args.operationName,
262
- sessionId: session(ctx.args.contextValue),
263
- });
264
- if ((enabled?.(ctx.args.contextValue) ?? true) === true) {
265
- const cachedResponse = await cache.get(operationId);
266
- if (cachedResponse != null) {
267
- if (includeExtensionMetadata) {
268
- ctx.setResultAndStopExecution({
269
- ...cachedResponse,
270
- extensions: {
271
- responseCache: {
272
- hit: true,
273
- },
264
+ const operationId = await buildResponseCacheKey({
265
+ documentString: getDocumentString(ctx.args),
266
+ sessionId: session(ctx.args.contextValue),
267
+ ...ctx.args,
268
+ });
269
+ if (((_a = enabled === null || enabled === void 0 ? void 0 : enabled(ctx.args.contextValue)) !== null && _a !== void 0 ? _a : true) === true) {
270
+ const cachedResponse = await cache.get(operationId);
271
+ if (cachedResponse != null) {
272
+ if (includeExtensionMetadata) {
273
+ ctx.setResultAndStopExecution({
274
+ ...cachedResponse,
275
+ extensions: {
276
+ responseCache: {
277
+ hit: true,
274
278
  },
275
- });
276
- }
277
- else {
278
- ctx.setResultAndStopExecution(cachedResponse);
279
- }
280
- return;
279
+ },
280
+ });
281
281
  }
282
+ else {
283
+ ctx.setResultAndStopExecution(cachedResponse);
284
+ }
285
+ return;
282
286
  }
283
- if (ttlPerSchemaCoordinate) {
284
- const typeInfo = new graphql.TypeInfo(ctx.args.schema);
285
- graphql.visit(ctx.args.document, graphql.visitWithTypeInfo(typeInfo, {
286
- Field(fieldNode) {
287
- const parentType = typeInfo.getParentType();
288
- if (parentType) {
289
- const schemaCoordinate = `${parentType.name}.${fieldNode.name.value}`;
290
- const maybeTtl = ttlPerSchemaCoordinate[schemaCoordinate];
291
- if (maybeTtl !== undefined) {
292
- context.currentTtl = calculateTtl(maybeTtl, context.currentTtl);
293
- }
294
- }
295
- },
296
- }));
297
- }
298
- return {
299
- onExecuteDone({ result, setResult }) {
300
- if (core.isAsyncIterable(result)) {
301
- // eslint-disable-next-line no-console
302
- console.warn('[useResponseCache] AsyncIterable returned from execute is currently unsupported.');
303
- return;
304
- }
305
- if (!shouldCacheResult({ result })) {
306
- return;
307
- }
308
- // we only use the global ttl if no currentTtl has been determined.
309
- const finalTtl = context.currentTtl ?? globalTtl;
310
- if (finalTtl === 0) {
311
- if (includeExtensionMetadata) {
312
- setResult({
313
- ...result,
314
- extensions: {
315
- responseCache: {
316
- hit: false,
317
- didCache: false,
318
- },
319
- },
320
- });
287
+ }
288
+ if (ttlPerSchemaCoordinate) {
289
+ const typeInfo = new graphql.TypeInfo(ctx.args.schema);
290
+ graphql.visit(ctx.args.document, graphql.visitWithTypeInfo(typeInfo, {
291
+ Field(fieldNode) {
292
+ const parentType = typeInfo.getParentType();
293
+ if (parentType) {
294
+ const schemaCoordinate = `${parentType.name}.${fieldNode.name.value}`;
295
+ const maybeTtl = ttlPerSchemaCoordinate[schemaCoordinate];
296
+ if (maybeTtl !== undefined) {
297
+ context.currentTtl = calculateTtl(maybeTtl, context.currentTtl);
321
298
  }
322
- return;
323
299
  }
324
- cache.set(operationId, result, identifier.values(), finalTtl);
300
+ },
301
+ }));
302
+ }
303
+ return {
304
+ onExecuteDone({ result, setResult }) {
305
+ var _a;
306
+ if (core.isAsyncIterable(result)) {
307
+ // eslint-disable-next-line no-console
308
+ console.warn('[useResponseCache] AsyncIterable returned from execute is currently unsupported.');
309
+ return;
310
+ }
311
+ if (context.skip) {
312
+ return;
313
+ }
314
+ if (!shouldCacheResult({ result })) {
315
+ return;
316
+ }
317
+ // we only use the global ttl if no currentTtl has been determined.
318
+ const finalTtl = (_a = context.currentTtl) !== null && _a !== void 0 ? _a : globalTtl;
319
+ if (finalTtl === 0) {
325
320
  if (includeExtensionMetadata) {
326
321
  setResult({
327
322
  ...result,
328
323
  extensions: {
329
324
  responseCache: {
330
325
  hit: false,
331
- didCache: true,
332
- ttl: finalTtl,
326
+ didCache: false,
333
327
  },
334
328
  },
335
329
  });
336
330
  }
337
- },
338
- };
339
- }
340
- // eslint-disable-next-line no-console
341
- console.warn(`[useResponseCache] Failed extracting document string from the context. The response will not be cached or served from the cache. ` +
342
- `If you are overriding the 'parse' behavior make sure to pass a custom 'getDocumentStringFromContext' function for getting the document string, which is required for building the response cache key.`);
343
- return undefined;
331
+ return;
332
+ }
333
+ cache.set(operationId, result, identifier.values(), finalTtl);
334
+ if (includeExtensionMetadata) {
335
+ setResult({
336
+ ...result,
337
+ extensions: {
338
+ responseCache: {
339
+ hit: false,
340
+ didCache: true,
341
+ ttl: finalTtl,
342
+ },
343
+ },
344
+ });
345
+ }
346
+ },
347
+ };
344
348
  },
345
349
  };
346
350
  }
347
351
  function isOperationDefinition(node) {
348
- return node?.kind === 'OperationDefinition';
352
+ return (node === null || node === void 0 ? void 0 : node.kind) === 'OperationDefinition';
349
353
  }
350
354
  function calculateTtl(typeTtl, currentTtl) {
351
355
  if (typeof currentTtl === 'number') {
@@ -371,7 +375,8 @@ function applyResponseCacheLogic(schema, idFieldNames) {
371
375
  return {
372
376
  ...fieldConfig,
373
377
  resolve(src, args, context, info) {
374
- const result = (fieldConfig.resolve ?? graphql.defaultFieldResolver)(src, args, context, info);
378
+ var _a;
379
+ const result = ((_a = fieldConfig.resolve) !== null && _a !== void 0 ? _a : graphql.defaultFieldResolver)(src, args, context, info);
375
380
  runWith(result, (id) => {
376
381
  const ctx = context[contextSymbol];
377
382
  if (ctx !== undefined) {
@@ -403,6 +408,6 @@ function applyResponseCacheLogic(schema, idFieldNames) {
403
408
  exports.createInMemoryCache = createInMemoryCache;
404
409
  exports.defaultBuildEntityId = defaultBuildEntityId;
405
410
  exports.defaultBuildResponseCacheKey = defaultBuildResponseCacheKey;
406
- exports.defaultGetDocumentStringFromContext = defaultGetDocumentStringFromContext;
411
+ exports.defaultGetDocumentString = defaultGetDocumentString;
407
412
  exports.defaultShouldCacheResult = defaultShouldCacheResult;
408
413
  exports.useResponseCache = useResponseCache;
package/index.mjs CHANGED
@@ -1,13 +1,14 @@
1
1
  import LRU from 'lru-cache';
2
2
  import { isAsyncIterable } from '@envelop/core';
3
3
  import { mapSchema, MapperKind } from '@graphql-tools/utils';
4
- import { defaultFieldResolver, TypeInfo, visit, visitWithTypeInfo } from 'graphql';
4
+ import { print, defaultFieldResolver, TypeInfo, visit, visitWithTypeInfo } from 'graphql';
5
5
  import jsonStableStringify from 'fast-json-stable-stringify';
6
6
 
7
7
  const createInMemoryCache = (params) => {
8
- const buildEntityId = params?.buildEntityId ?? defaultBuildEntityId;
8
+ var _a;
9
+ const buildEntityId = (_a = params === null || params === void 0 ? void 0 : params.buildEntityId) !== null && _a !== void 0 ? _a : defaultBuildEntityId;
9
10
  const cachedResponses = new LRU({
10
- max: params?.max,
11
+ max: params === null || params === void 0 ? void 0 : params.max,
11
12
  stale: false,
12
13
  noDisposeOnSet: true,
13
14
  dispose(responseId) {
@@ -17,12 +18,13 @@ const createInMemoryCache = (params) => {
17
18
  const entityToResponseIds = new Map();
18
19
  const responseIdToEntityIds = new Map();
19
20
  function purgeResponse(responseId, shouldRemove = true) {
21
+ var _a;
20
22
  const entityIds = responseIdToEntityIds.get(responseId);
21
23
  // get entities related to the response
22
24
  if (entityIds !== undefined) {
23
25
  for (const entityId of entityIds) {
24
26
  // remove the response mapping from the entity
25
- entityToResponseIds.get(entityId)?.delete(responseId);
27
+ (_a = entityToResponseIds.get(entityId)) === null || _a === void 0 ? void 0 : _a.delete(responseId);
26
28
  }
27
29
  // remove all the entity mappings from the response
28
30
  responseIdToEntityIds.delete(responseId);
@@ -70,7 +72,8 @@ const createInMemoryCache = (params) => {
70
72
  }
71
73
  },
72
74
  get(responseId) {
73
- return cachedResponses.get(responseId) ?? null;
75
+ var _a;
76
+ return (_a = cachedResponses.get(responseId)) !== null && _a !== void 0 ? _a : null;
74
77
  },
75
78
  invalidate(entitiesToRemove) {
76
79
  for (const { typename, id } of entitiesToRemove) {
@@ -145,17 +148,19 @@ const hashSHA256 = async (text) => {
145
148
  };
146
149
 
147
150
  const contextSymbol = Symbol('responseCache');
148
- const rawDocumentStringSymbol = Symbol('rawDocumentString');
149
151
  /**
150
152
  * Default function used for building the response cache key.
151
153
  * It is exported here for advanced use-cases. E.g. if you want to short circuit and serve responses from the cache on a global level in order to completely by-pass the GraphQL flow.
152
154
  */
153
- const defaultBuildResponseCacheKey = params => hashSHA256([
154
- params.documentString,
155
- params.operationName ?? '',
156
- jsonStableStringify(params.variableValues ?? {}),
157
- params.sessionId ?? '',
158
- ].join('|'));
155
+ const defaultBuildResponseCacheKey = params => {
156
+ var _a, _b, _c;
157
+ return hashSHA256([
158
+ params.documentString,
159
+ (_a = params.operationName) !== null && _a !== void 0 ? _a : '',
160
+ jsonStableStringify((_b = params.variableValues) !== null && _b !== void 0 ? _b : {}),
161
+ (_c = params.sessionId) !== null && _c !== void 0 ? _c : '',
162
+ ].join('|'));
163
+ };
159
164
  /**
160
165
  * Default function used to check if the result should be cached.
161
166
  *
@@ -172,8 +177,16 @@ const defaultShouldCacheResult = (params) => {
172
177
  }
173
178
  return true;
174
179
  };
175
- const defaultGetDocumentStringFromContext = context => context[rawDocumentStringSymbol];
176
- function useResponseCache({ cache = createInMemoryCache(), ttl: globalTtl = Infinity, session = () => null, enabled, ignoredTypes = [], ttlPerType = {}, ttlPerSchemaCoordinate = {}, idFields = ['id'], invalidateViaMutation = true, buildResponseCacheKey = defaultBuildResponseCacheKey, getDocumentStringFromContext = defaultGetDocumentStringFromContext, shouldCacheResult = defaultShouldCacheResult,
180
+ const documentStringByDocument = new WeakMap();
181
+ function defaultGetDocumentString(executionArgs) {
182
+ let documentString = documentStringByDocument.get(executionArgs.document);
183
+ if (!documentString) {
184
+ documentString = print(executionArgs.document);
185
+ documentStringByDocument.set(executionArgs.document, documentString);
186
+ }
187
+ return documentString;
188
+ }
189
+ function useResponseCache({ cache = createInMemoryCache(), ttl: globalTtl = Infinity, session = () => null, enabled, ignoredTypes = [], ttlPerType = {}, ttlPerSchemaCoordinate = {}, idFields = ['id'], invalidateViaMutation = true, buildResponseCacheKey = defaultBuildResponseCacheKey, getDocumentString = defaultGetDocumentString, shouldCacheResult = defaultShouldCacheResult,
177
190
  // eslint-disable-next-line dot-notation
178
191
  includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_ENV'] === 'development' : false, } = {}) {
179
192
  const appliedTransform = Symbol('responseCache.appliedTransform');
@@ -182,8 +195,9 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
182
195
  ttlPerSchemaCoordinate = { 'Query.__schema': 0, ...ttlPerSchemaCoordinate };
183
196
  return {
184
197
  onSchemaChange({ schema, replaceSchema }) {
198
+ var _a;
185
199
  // @ts-expect-error See https://github.com/graphql/graphql-js/pull/3511 - remove this comments once merged
186
- if (schema.extensions?.[appliedTransform] === true) {
200
+ if (((_a = schema.extensions) === null || _a === void 0 ? void 0 : _a[appliedTransform]) === true) {
187
201
  return;
188
202
  }
189
203
  const patchedSchema = applyResponseCacheLogic(schema, idFields);
@@ -193,18 +207,15 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
193
207
  };
194
208
  replaceSchema(patchedSchema);
195
209
  },
196
- onParse(parseCtx) {
197
- return function onParseEnd(ctx) {
198
- if (ctx.result && 'kind' in ctx.result) {
199
- const source = parseCtx.params.source;
200
- const rawDocumentString = typeof source === 'string' ? source : source.body;
201
- ctx.extendContext({
202
- [rawDocumentStringSymbol]: rawDocumentString,
203
- });
210
+ onParse({ params: { source } }) {
211
+ return function onParseEnd({ result }) {
212
+ if (result != null && !(result instanceof Error)) {
213
+ documentStringByDocument.set(result, source.toString());
204
214
  }
205
215
  };
206
216
  },
207
217
  async onExecute(ctx) {
218
+ var _a;
208
219
  const identifier = new Map();
209
220
  const types = new Set();
210
221
  const context = {
@@ -244,99 +255,95 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
244
255
  },
245
256
  };
246
257
  }
247
- const documentString = getDocumentStringFromContext(ctx.args.contextValue);
248
- if (documentString != null) {
249
- const operationId = await buildResponseCacheKey({
250
- documentString,
251
- variableValues: ctx.args.variableValues,
252
- operationName: ctx.args.operationName,
253
- sessionId: session(ctx.args.contextValue),
254
- });
255
- if ((enabled?.(ctx.args.contextValue) ?? true) === true) {
256
- const cachedResponse = await cache.get(operationId);
257
- if (cachedResponse != null) {
258
- if (includeExtensionMetadata) {
259
- ctx.setResultAndStopExecution({
260
- ...cachedResponse,
261
- extensions: {
262
- responseCache: {
263
- hit: true,
264
- },
258
+ const operationId = await buildResponseCacheKey({
259
+ documentString: getDocumentString(ctx.args),
260
+ sessionId: session(ctx.args.contextValue),
261
+ ...ctx.args,
262
+ });
263
+ if (((_a = enabled === null || enabled === void 0 ? void 0 : enabled(ctx.args.contextValue)) !== null && _a !== void 0 ? _a : true) === true) {
264
+ const cachedResponse = await cache.get(operationId);
265
+ if (cachedResponse != null) {
266
+ if (includeExtensionMetadata) {
267
+ ctx.setResultAndStopExecution({
268
+ ...cachedResponse,
269
+ extensions: {
270
+ responseCache: {
271
+ hit: true,
265
272
  },
266
- });
267
- }
268
- else {
269
- ctx.setResultAndStopExecution(cachedResponse);
270
- }
271
- return;
273
+ },
274
+ });
272
275
  }
276
+ else {
277
+ ctx.setResultAndStopExecution(cachedResponse);
278
+ }
279
+ return;
273
280
  }
274
- if (ttlPerSchemaCoordinate) {
275
- const typeInfo = new TypeInfo(ctx.args.schema);
276
- visit(ctx.args.document, visitWithTypeInfo(typeInfo, {
277
- Field(fieldNode) {
278
- const parentType = typeInfo.getParentType();
279
- if (parentType) {
280
- const schemaCoordinate = `${parentType.name}.${fieldNode.name.value}`;
281
- const maybeTtl = ttlPerSchemaCoordinate[schemaCoordinate];
282
- if (maybeTtl !== undefined) {
283
- context.currentTtl = calculateTtl(maybeTtl, context.currentTtl);
284
- }
285
- }
286
- },
287
- }));
288
- }
289
- return {
290
- onExecuteDone({ result, setResult }) {
291
- if (isAsyncIterable(result)) {
292
- // eslint-disable-next-line no-console
293
- console.warn('[useResponseCache] AsyncIterable returned from execute is currently unsupported.');
294
- return;
295
- }
296
- if (!shouldCacheResult({ result })) {
297
- return;
298
- }
299
- // we only use the global ttl if no currentTtl has been determined.
300
- const finalTtl = context.currentTtl ?? globalTtl;
301
- if (finalTtl === 0) {
302
- if (includeExtensionMetadata) {
303
- setResult({
304
- ...result,
305
- extensions: {
306
- responseCache: {
307
- hit: false,
308
- didCache: false,
309
- },
310
- },
311
- });
281
+ }
282
+ if (ttlPerSchemaCoordinate) {
283
+ const typeInfo = new TypeInfo(ctx.args.schema);
284
+ visit(ctx.args.document, visitWithTypeInfo(typeInfo, {
285
+ Field(fieldNode) {
286
+ const parentType = typeInfo.getParentType();
287
+ if (parentType) {
288
+ const schemaCoordinate = `${parentType.name}.${fieldNode.name.value}`;
289
+ const maybeTtl = ttlPerSchemaCoordinate[schemaCoordinate];
290
+ if (maybeTtl !== undefined) {
291
+ context.currentTtl = calculateTtl(maybeTtl, context.currentTtl);
312
292
  }
313
- return;
314
293
  }
315
- cache.set(operationId, result, identifier.values(), finalTtl);
294
+ },
295
+ }));
296
+ }
297
+ return {
298
+ onExecuteDone({ result, setResult }) {
299
+ var _a;
300
+ if (isAsyncIterable(result)) {
301
+ // eslint-disable-next-line no-console
302
+ console.warn('[useResponseCache] AsyncIterable returned from execute is currently unsupported.');
303
+ return;
304
+ }
305
+ if (context.skip) {
306
+ return;
307
+ }
308
+ if (!shouldCacheResult({ result })) {
309
+ return;
310
+ }
311
+ // we only use the global ttl if no currentTtl has been determined.
312
+ const finalTtl = (_a = context.currentTtl) !== null && _a !== void 0 ? _a : globalTtl;
313
+ if (finalTtl === 0) {
316
314
  if (includeExtensionMetadata) {
317
315
  setResult({
318
316
  ...result,
319
317
  extensions: {
320
318
  responseCache: {
321
319
  hit: false,
322
- didCache: true,
323
- ttl: finalTtl,
320
+ didCache: false,
324
321
  },
325
322
  },
326
323
  });
327
324
  }
328
- },
329
- };
330
- }
331
- // eslint-disable-next-line no-console
332
- console.warn(`[useResponseCache] Failed extracting document string from the context. The response will not be cached or served from the cache. ` +
333
- `If you are overriding the 'parse' behavior make sure to pass a custom 'getDocumentStringFromContext' function for getting the document string, which is required for building the response cache key.`);
334
- return undefined;
325
+ return;
326
+ }
327
+ cache.set(operationId, result, identifier.values(), finalTtl);
328
+ if (includeExtensionMetadata) {
329
+ setResult({
330
+ ...result,
331
+ extensions: {
332
+ responseCache: {
333
+ hit: false,
334
+ didCache: true,
335
+ ttl: finalTtl,
336
+ },
337
+ },
338
+ });
339
+ }
340
+ },
341
+ };
335
342
  },
336
343
  };
337
344
  }
338
345
  function isOperationDefinition(node) {
339
- return node?.kind === 'OperationDefinition';
346
+ return (node === null || node === void 0 ? void 0 : node.kind) === 'OperationDefinition';
340
347
  }
341
348
  function calculateTtl(typeTtl, currentTtl) {
342
349
  if (typeof currentTtl === 'number') {
@@ -362,7 +369,8 @@ function applyResponseCacheLogic(schema, idFieldNames) {
362
369
  return {
363
370
  ...fieldConfig,
364
371
  resolve(src, args, context, info) {
365
- const result = (fieldConfig.resolve ?? defaultFieldResolver)(src, args, context, info);
372
+ var _a;
373
+ const result = ((_a = fieldConfig.resolve) !== null && _a !== void 0 ? _a : defaultFieldResolver)(src, args, context, info);
366
374
  runWith(result, (id) => {
367
375
  const ctx = context[contextSymbol];
368
376
  if (ctx !== undefined) {
@@ -391,4 +399,4 @@ function applyResponseCacheLogic(schema, idFieldNames) {
391
399
  });
392
400
  }
393
401
 
394
- export { createInMemoryCache, defaultBuildEntityId, defaultBuildResponseCacheKey, defaultGetDocumentStringFromContext, defaultShouldCacheResult, useResponseCache };
402
+ export { createInMemoryCache, defaultBuildEntityId, defaultBuildResponseCacheKey, defaultGetDocumentString, defaultShouldCacheResult, useResponseCache };
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@envelop/response-cache",
3
- "version": "3.0.0-alpha-d0d0776.0",
3
+ "version": "3.0.0-alpha-6a4e0e2.0",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
- "@envelop/core": "3.0.0-alpha-d0d0776.0",
6
+ "@envelop/core": "^2.3.3",
7
7
  "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"
8
8
  },
9
9
  "dependencies": {
@@ -26,24 +26,12 @@
26
26
  },
27
27
  "exports": {
28
28
  ".": {
29
- "require": {
30
- "default": "./index.js",
31
- "types": "./index.d.ts"
32
- },
33
- "import": {
34
- "default": "./index.mjs",
35
- "types": "./index.d.ts"
36
- }
29
+ "require": "./index.js",
30
+ "import": "./index.mjs"
37
31
  },
38
32
  "./*": {
39
- "require": {
40
- "default": "./*.js",
41
- "types": "./*.d.ts"
42
- },
43
- "import": {
44
- "default": "./*.mjs",
45
- "types": "./*.d.ts"
46
- }
33
+ "require": "./*.js",
34
+ "import": "./*.mjs"
47
35
  },
48
36
  "./package.json": "./package.json"
49
37
  }
package/plugin.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Plugin, Maybe, DefaultContext } from '@envelop/core';
1
+ import { Plugin, Maybe } from '@envelop/core';
2
2
  import { ExecutionArgs, ExecutionResult } from 'graphql';
3
3
  import type { Cache } from './cache';
4
4
  /**
@@ -7,14 +7,10 @@ import type { Cache } from './cache';
7
7
  export declare type BuildResponseCacheKeyFunction = (params: {
8
8
  /** Raw document string as sent from the client. */
9
9
  documentString: string;
10
- /** Variable values as sent form the client. */
11
- variableValues: ExecutionArgs['variableValues'];
12
- /** The name of the GraphQL operation that should be executed from within the document. */
13
- operationName?: Maybe<string>;
14
10
  /** optional sessionId for make unique cache keys based on the session. */
15
11
  sessionId?: Maybe<string>;
16
- }) => Promise<string>;
17
- export declare type GetDocumentStringFromContextFunction = (params: DefaultContext) => Maybe<string>;
12
+ } & ExecutionArgs) => Promise<string>;
13
+ export declare type GetDocumentStringFunction = (executionArgs: ExecutionArgs) => string;
18
14
  export declare type ShouldCacheResultFunction = (params: {
19
15
  result: ExecutionResult;
20
16
  }) => Boolean;
@@ -72,12 +68,13 @@ export declare type UseResponseCacheParameter<C = any> = {
72
68
  */
73
69
  buildResponseCacheKey?: BuildResponseCacheKeyFunction;
74
70
  /**
75
- * Function used for reading the document string that is used for building the response cache key from the context object.
76
- * By default, the useResponseCache plugin hooks into onParse and writes the original operation string to the context.
71
+ * Function used for reading the document string that is used for building the response cache key from the execution arguments.
72
+ * By default, the useResponseCache plugin hooks into onParse and caches the original operation string in a WeakMap.
77
73
  * If you are hard overriding parse you need to set this function, otherwise responses will not be cached or served from the cache.
78
- * Defaults to `defaultGetDocumentStringFromContext`
74
+ * Defaults to `defaultGetDocumentString`
75
+ *
79
76
  */
80
- getDocumentStringFromContext?: GetDocumentStringFromContextFunction;
77
+ getDocumentString?: GetDocumentStringFunction;
81
78
  /**
82
79
  * Include extension values that provide useful information, such as whether the cache was hit or which resources a mutation invalidated.
83
80
  * Defaults to `true` if `process.env["NODE_ENV"]` is set to `"development"`, otherwise `false`.
@@ -104,5 +101,5 @@ export declare const defaultBuildResponseCacheKey: BuildResponseCacheKeyFunction
104
101
  * By default, results with errors (unexpected, EnvelopError, or GraphQLError) are not cached.
105
102
  */
106
103
  export declare const defaultShouldCacheResult: ShouldCacheResultFunction;
107
- export declare const defaultGetDocumentStringFromContext: GetDocumentStringFromContextFunction;
108
- export declare function useResponseCache({ cache, ttl: globalTtl, session, enabled, ignoredTypes, ttlPerType, ttlPerSchemaCoordinate, idFields, invalidateViaMutation, buildResponseCacheKey, getDocumentStringFromContext, shouldCacheResult, includeExtensionMetadata, }?: UseResponseCacheParameter): Plugin;
104
+ export declare function defaultGetDocumentString(executionArgs: ExecutionArgs): string;
105
+ export declare function useResponseCache({ cache, ttl: globalTtl, session, enabled, ignoredTypes, ttlPerType, ttlPerSchemaCoordinate, idFields, invalidateViaMutation, buildResponseCacheKey, getDocumentString, shouldCacheResult, includeExtensionMetadata, }?: UseResponseCacheParameter): Plugin;