@envelop/response-cache 6.2.2 → 6.2.3
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/plugin.js +70 -41
- package/esm/plugin.js +71 -42
- package/package.json +1 -1
package/cjs/plugin.js
CHANGED
|
@@ -184,45 +184,34 @@ function useResponseCache({ cache = (0, in_memory_cache_js_1.createInMemoryCache
|
|
|
184
184
|
},
|
|
185
185
|
};
|
|
186
186
|
}
|
|
187
|
-
function
|
|
188
|
-
if (data == null || typeof data !== 'object') {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
if (Array.isArray(data)) {
|
|
192
|
-
for (const item of data) {
|
|
193
|
-
processResult(item);
|
|
194
|
-
}
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
const typename = data.__responseCacheTypeName ?? data.__typename;
|
|
198
|
-
delete data.__responseCacheTypeName;
|
|
199
|
-
const idField = typename && idFieldByTypeName.get(typename);
|
|
200
|
-
const entityId = data.__responseCacheId ?? (idField && data[idField]);
|
|
201
|
-
delete data.__responseCacheId;
|
|
202
|
-
// Always process nested objects, even if we are skipping cache, to ensure the result is cleaned up
|
|
203
|
-
// of metadata fields added to the query document.
|
|
204
|
-
for (const fieldName in data) {
|
|
205
|
-
processResult(data[fieldName]);
|
|
206
|
-
}
|
|
187
|
+
function onEntity(entity, data) {
|
|
207
188
|
if (skip) {
|
|
208
189
|
return;
|
|
209
190
|
}
|
|
210
|
-
if (ignoredTypesMap.has(typename) ||
|
|
191
|
+
if (ignoredTypesMap.has(entity.typename) ||
|
|
192
|
+
(!sessionId && isPrivate(entity.typename, data))) {
|
|
211
193
|
skip = true;
|
|
212
194
|
return;
|
|
213
195
|
}
|
|
214
|
-
|
|
215
|
-
if (
|
|
216
|
-
const
|
|
196
|
+
// in case the entity has no id, we attempt to extract it from the data
|
|
197
|
+
if (!entity.id) {
|
|
198
|
+
const idField = idFieldByTypeName.get(entity.typename);
|
|
199
|
+
if (idField) {
|
|
200
|
+
entity.id = data[idField];
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
types.add(entity.typename);
|
|
204
|
+
if (entity.typename in ttlPerType) {
|
|
205
|
+
const maybeTtl = ttlPerType[entity.typename];
|
|
217
206
|
currentTtl = calculateTtl(maybeTtl, currentTtl);
|
|
218
207
|
}
|
|
219
|
-
if (
|
|
220
|
-
identifier.set(`${typename}:${
|
|
208
|
+
if (entity.id != null) {
|
|
209
|
+
identifier.set(`${entity.typename}:${entity.id}`, entity);
|
|
221
210
|
}
|
|
222
211
|
for (const fieldName in data) {
|
|
223
212
|
const fieldData = data[fieldName];
|
|
224
213
|
if (fieldData == null || (Array.isArray(fieldData) && fieldData.length === 0)) {
|
|
225
|
-
const inferredTypes = typePerSchemaCoordinateMap.get(`${typename}.${fieldName}`);
|
|
214
|
+
const inferredTypes = typePerSchemaCoordinateMap.get(`${entity.typename}.${fieldName}`);
|
|
226
215
|
inferredTypes?.forEach(inferredType => {
|
|
227
216
|
if (inferredType in ttlPerType) {
|
|
228
217
|
const maybeTtl = ttlPerType[inferredType];
|
|
@@ -234,7 +223,10 @@ function useResponseCache({ cache = (0, in_memory_cache_js_1.createInMemoryCache
|
|
|
234
223
|
}
|
|
235
224
|
}
|
|
236
225
|
function invalidateCache(result, setResult) {
|
|
237
|
-
|
|
226
|
+
result = { ...result };
|
|
227
|
+
if (result.data) {
|
|
228
|
+
result.data = removeMetadataFieldsFromResult(result.data, onEntity);
|
|
229
|
+
}
|
|
238
230
|
const cacheInstance = cacheFactory(onExecuteParams.args.contextValue);
|
|
239
231
|
if (cacheInstance == null) {
|
|
240
232
|
// eslint-disable-next-line no-console
|
|
@@ -286,7 +278,9 @@ function useResponseCache({ cache = (0, in_memory_cache_js_1.createInMemoryCache
|
|
|
286
278
|
});
|
|
287
279
|
}
|
|
288
280
|
function maybeCacheResult(result, setResult) {
|
|
289
|
-
|
|
281
|
+
if (result.data) {
|
|
282
|
+
result.data = removeMetadataFieldsFromResult(result.data, onEntity);
|
|
283
|
+
}
|
|
290
284
|
// we only use the global ttl if no currentTtl has been determined.
|
|
291
285
|
const finalTtl = currentTtl ?? globalTtl;
|
|
292
286
|
if (skip || !shouldCacheResult({ cacheKey, result }) || finalTtl === 0) {
|
|
@@ -347,9 +341,28 @@ function handleAsyncIterableResult(handler) {
|
|
|
347
341
|
}
|
|
348
342
|
}
|
|
349
343
|
const newResult = { ...payload.result };
|
|
344
|
+
// Handle initial/single result
|
|
350
345
|
if (newResult.data) {
|
|
351
346
|
newResult.data = removeMetadataFieldsFromResult(newResult.data);
|
|
352
347
|
}
|
|
348
|
+
// Handle Incremental results
|
|
349
|
+
if ('hasNext' in newResult && newResult.incremental) {
|
|
350
|
+
newResult.incremental = newResult.incremental.map(value => {
|
|
351
|
+
if ('items' in value && value.items) {
|
|
352
|
+
return {
|
|
353
|
+
...value,
|
|
354
|
+
items: removeMetadataFieldsFromResult(value.items),
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
if ('data' in value && value.data) {
|
|
358
|
+
return {
|
|
359
|
+
...value,
|
|
360
|
+
data: removeMetadataFieldsFromResult(value.data),
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
return value;
|
|
364
|
+
});
|
|
365
|
+
}
|
|
353
366
|
payload.setResult(newResult);
|
|
354
367
|
},
|
|
355
368
|
};
|
|
@@ -376,14 +389,17 @@ function calculateTtl(typeTtl, currentTtl) {
|
|
|
376
389
|
}
|
|
377
390
|
return currentTtl;
|
|
378
391
|
}
|
|
379
|
-
function unwrapTypenames(
|
|
380
|
-
if (
|
|
381
|
-
return unwrapTypenames(
|
|
392
|
+
function unwrapTypenames(ttype) {
|
|
393
|
+
if ((0, graphql_1.isListType)(ttype) || (0, graphql_1.isNonNullType)(ttype)) {
|
|
394
|
+
return unwrapTypenames(ttype.ofType);
|
|
382
395
|
}
|
|
383
|
-
if (
|
|
384
|
-
return
|
|
396
|
+
if ((0, graphql_1.isUnionType)(ttype)) {
|
|
397
|
+
return ttype
|
|
398
|
+
.getTypes()
|
|
399
|
+
.map(ttype => unwrapTypenames(ttype))
|
|
400
|
+
.flat();
|
|
385
401
|
}
|
|
386
|
-
return [
|
|
402
|
+
return [ttype.name];
|
|
387
403
|
}
|
|
388
404
|
exports.cacheControlDirective = `
|
|
389
405
|
enum CacheControlScope {
|
|
@@ -393,17 +409,30 @@ exports.cacheControlDirective = `
|
|
|
393
409
|
|
|
394
410
|
directive @cacheControl(maxAge: Int, scope: CacheControlScope) on FIELD_DEFINITION | OBJECT
|
|
395
411
|
`;
|
|
396
|
-
function removeMetadataFieldsFromResult(data) {
|
|
412
|
+
function removeMetadataFieldsFromResult(data, onEntity) {
|
|
397
413
|
if (Array.isArray(data)) {
|
|
398
|
-
return data.map(removeMetadataFieldsFromResult);
|
|
414
|
+
return data.map(record => removeMetadataFieldsFromResult(record, onEntity));
|
|
399
415
|
}
|
|
400
416
|
// clone the data to avoid mutation
|
|
401
417
|
data = { ...data };
|
|
402
|
-
|
|
403
|
-
|
|
418
|
+
const typename = data.__responseCacheTypeName ?? data.__typename;
|
|
419
|
+
if (typeof typename === 'string') {
|
|
420
|
+
const entity = { typename };
|
|
421
|
+
delete data.__responseCacheTypeName;
|
|
422
|
+
if (data.__responseCacheId &&
|
|
423
|
+
(typeof data.__responseCacheId === 'string' || typeof data.__responseCacheId === 'number')) {
|
|
424
|
+
entity.id = data.__responseCacheId;
|
|
425
|
+
delete data.__responseCacheId;
|
|
426
|
+
}
|
|
427
|
+
onEntity?.(entity, data);
|
|
428
|
+
}
|
|
404
429
|
for (const key in data) {
|
|
405
|
-
|
|
406
|
-
|
|
430
|
+
const value = data[key];
|
|
431
|
+
if (Array.isArray(value)) {
|
|
432
|
+
data[key] = removeMetadataFieldsFromResult(value, onEntity);
|
|
433
|
+
}
|
|
434
|
+
if (value !== null && typeof value === 'object') {
|
|
435
|
+
data[key] = removeMetadataFieldsFromResult(value, onEntity);
|
|
407
436
|
}
|
|
408
437
|
}
|
|
409
438
|
return data;
|
package/esm/plugin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import jsonStableStringify from 'fast-json-stable-stringify';
|
|
2
|
-
import { getOperationAST, Kind, print, TypeInfo, visit, visitWithTypeInfo, } from 'graphql';
|
|
2
|
+
import { getOperationAST, isListType, isNonNullType, isUnionType, Kind, print, TypeInfo, visit, visitWithTypeInfo, } from 'graphql';
|
|
3
3
|
import { getDocumentString, isAsyncIterable, } from '@envelop/core';
|
|
4
4
|
import { getDirective, MapperKind, mapSchema, memoize1, memoize4, mergeIncrementalResult, } from '@graphql-tools/utils';
|
|
5
5
|
import { hashSHA256 } from './hash-sha256.js';
|
|
@@ -177,45 +177,34 @@ export function useResponseCache({ cache = createInMemoryCache(), ttl: globalTtl
|
|
|
177
177
|
},
|
|
178
178
|
};
|
|
179
179
|
}
|
|
180
|
-
function
|
|
181
|
-
if (data == null || typeof data !== 'object') {
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
if (Array.isArray(data)) {
|
|
185
|
-
for (const item of data) {
|
|
186
|
-
processResult(item);
|
|
187
|
-
}
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
const typename = data.__responseCacheTypeName ?? data.__typename;
|
|
191
|
-
delete data.__responseCacheTypeName;
|
|
192
|
-
const idField = typename && idFieldByTypeName.get(typename);
|
|
193
|
-
const entityId = data.__responseCacheId ?? (idField && data[idField]);
|
|
194
|
-
delete data.__responseCacheId;
|
|
195
|
-
// Always process nested objects, even if we are skipping cache, to ensure the result is cleaned up
|
|
196
|
-
// of metadata fields added to the query document.
|
|
197
|
-
for (const fieldName in data) {
|
|
198
|
-
processResult(data[fieldName]);
|
|
199
|
-
}
|
|
180
|
+
function onEntity(entity, data) {
|
|
200
181
|
if (skip) {
|
|
201
182
|
return;
|
|
202
183
|
}
|
|
203
|
-
if (ignoredTypesMap.has(typename) ||
|
|
184
|
+
if (ignoredTypesMap.has(entity.typename) ||
|
|
185
|
+
(!sessionId && isPrivate(entity.typename, data))) {
|
|
204
186
|
skip = true;
|
|
205
187
|
return;
|
|
206
188
|
}
|
|
207
|
-
|
|
208
|
-
if (
|
|
209
|
-
const
|
|
189
|
+
// in case the entity has no id, we attempt to extract it from the data
|
|
190
|
+
if (!entity.id) {
|
|
191
|
+
const idField = idFieldByTypeName.get(entity.typename);
|
|
192
|
+
if (idField) {
|
|
193
|
+
entity.id = data[idField];
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
types.add(entity.typename);
|
|
197
|
+
if (entity.typename in ttlPerType) {
|
|
198
|
+
const maybeTtl = ttlPerType[entity.typename];
|
|
210
199
|
currentTtl = calculateTtl(maybeTtl, currentTtl);
|
|
211
200
|
}
|
|
212
|
-
if (
|
|
213
|
-
identifier.set(`${typename}:${
|
|
201
|
+
if (entity.id != null) {
|
|
202
|
+
identifier.set(`${entity.typename}:${entity.id}`, entity);
|
|
214
203
|
}
|
|
215
204
|
for (const fieldName in data) {
|
|
216
205
|
const fieldData = data[fieldName];
|
|
217
206
|
if (fieldData == null || (Array.isArray(fieldData) && fieldData.length === 0)) {
|
|
218
|
-
const inferredTypes = typePerSchemaCoordinateMap.get(`${typename}.${fieldName}`);
|
|
207
|
+
const inferredTypes = typePerSchemaCoordinateMap.get(`${entity.typename}.${fieldName}`);
|
|
219
208
|
inferredTypes?.forEach(inferredType => {
|
|
220
209
|
if (inferredType in ttlPerType) {
|
|
221
210
|
const maybeTtl = ttlPerType[inferredType];
|
|
@@ -227,7 +216,10 @@ export function useResponseCache({ cache = createInMemoryCache(), ttl: globalTtl
|
|
|
227
216
|
}
|
|
228
217
|
}
|
|
229
218
|
function invalidateCache(result, setResult) {
|
|
230
|
-
|
|
219
|
+
result = { ...result };
|
|
220
|
+
if (result.data) {
|
|
221
|
+
result.data = removeMetadataFieldsFromResult(result.data, onEntity);
|
|
222
|
+
}
|
|
231
223
|
const cacheInstance = cacheFactory(onExecuteParams.args.contextValue);
|
|
232
224
|
if (cacheInstance == null) {
|
|
233
225
|
// eslint-disable-next-line no-console
|
|
@@ -279,7 +271,9 @@ export function useResponseCache({ cache = createInMemoryCache(), ttl: globalTtl
|
|
|
279
271
|
});
|
|
280
272
|
}
|
|
281
273
|
function maybeCacheResult(result, setResult) {
|
|
282
|
-
|
|
274
|
+
if (result.data) {
|
|
275
|
+
result.data = removeMetadataFieldsFromResult(result.data, onEntity);
|
|
276
|
+
}
|
|
283
277
|
// we only use the global ttl if no currentTtl has been determined.
|
|
284
278
|
const finalTtl = currentTtl ?? globalTtl;
|
|
285
279
|
if (skip || !shouldCacheResult({ cacheKey, result }) || finalTtl === 0) {
|
|
@@ -339,9 +333,28 @@ function handleAsyncIterableResult(handler) {
|
|
|
339
333
|
}
|
|
340
334
|
}
|
|
341
335
|
const newResult = { ...payload.result };
|
|
336
|
+
// Handle initial/single result
|
|
342
337
|
if (newResult.data) {
|
|
343
338
|
newResult.data = removeMetadataFieldsFromResult(newResult.data);
|
|
344
339
|
}
|
|
340
|
+
// Handle Incremental results
|
|
341
|
+
if ('hasNext' in newResult && newResult.incremental) {
|
|
342
|
+
newResult.incremental = newResult.incremental.map(value => {
|
|
343
|
+
if ('items' in value && value.items) {
|
|
344
|
+
return {
|
|
345
|
+
...value,
|
|
346
|
+
items: removeMetadataFieldsFromResult(value.items),
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
if ('data' in value && value.data) {
|
|
350
|
+
return {
|
|
351
|
+
...value,
|
|
352
|
+
data: removeMetadataFieldsFromResult(value.data),
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
return value;
|
|
356
|
+
});
|
|
357
|
+
}
|
|
345
358
|
payload.setResult(newResult);
|
|
346
359
|
},
|
|
347
360
|
};
|
|
@@ -367,14 +380,17 @@ function calculateTtl(typeTtl, currentTtl) {
|
|
|
367
380
|
}
|
|
368
381
|
return currentTtl;
|
|
369
382
|
}
|
|
370
|
-
function unwrapTypenames(
|
|
371
|
-
if (
|
|
372
|
-
return unwrapTypenames(
|
|
383
|
+
function unwrapTypenames(ttype) {
|
|
384
|
+
if (isListType(ttype) || isNonNullType(ttype)) {
|
|
385
|
+
return unwrapTypenames(ttype.ofType);
|
|
373
386
|
}
|
|
374
|
-
if (
|
|
375
|
-
return
|
|
387
|
+
if (isUnionType(ttype)) {
|
|
388
|
+
return ttype
|
|
389
|
+
.getTypes()
|
|
390
|
+
.map(ttype => unwrapTypenames(ttype))
|
|
391
|
+
.flat();
|
|
376
392
|
}
|
|
377
|
-
return [
|
|
393
|
+
return [ttype.name];
|
|
378
394
|
}
|
|
379
395
|
export const cacheControlDirective = /* GraphQL */ `
|
|
380
396
|
enum CacheControlScope {
|
|
@@ -384,17 +400,30 @@ export const cacheControlDirective = /* GraphQL */ `
|
|
|
384
400
|
|
|
385
401
|
directive @cacheControl(maxAge: Int, scope: CacheControlScope) on FIELD_DEFINITION | OBJECT
|
|
386
402
|
`;
|
|
387
|
-
function removeMetadataFieldsFromResult(data) {
|
|
403
|
+
function removeMetadataFieldsFromResult(data, onEntity) {
|
|
388
404
|
if (Array.isArray(data)) {
|
|
389
|
-
return data.map(removeMetadataFieldsFromResult);
|
|
405
|
+
return data.map(record => removeMetadataFieldsFromResult(record, onEntity));
|
|
390
406
|
}
|
|
391
407
|
// clone the data to avoid mutation
|
|
392
408
|
data = { ...data };
|
|
393
|
-
|
|
394
|
-
|
|
409
|
+
const typename = data.__responseCacheTypeName ?? data.__typename;
|
|
410
|
+
if (typeof typename === 'string') {
|
|
411
|
+
const entity = { typename };
|
|
412
|
+
delete data.__responseCacheTypeName;
|
|
413
|
+
if (data.__responseCacheId &&
|
|
414
|
+
(typeof data.__responseCacheId === 'string' || typeof data.__responseCacheId === 'number')) {
|
|
415
|
+
entity.id = data.__responseCacheId;
|
|
416
|
+
delete data.__responseCacheId;
|
|
417
|
+
}
|
|
418
|
+
onEntity?.(entity, data);
|
|
419
|
+
}
|
|
395
420
|
for (const key in data) {
|
|
396
|
-
|
|
397
|
-
|
|
421
|
+
const value = data[key];
|
|
422
|
+
if (Array.isArray(value)) {
|
|
423
|
+
data[key] = removeMetadataFieldsFromResult(value, onEntity);
|
|
424
|
+
}
|
|
425
|
+
if (value !== null && typeof value === 'object') {
|
|
426
|
+
data[key] = removeMetadataFieldsFromResult(value, onEntity);
|
|
398
427
|
}
|
|
399
428
|
}
|
|
400
429
|
return data;
|