@envelop/response-cache 3.2.0 → 3.2.1-alpha-20220901205925-b1fd44a9
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/README.md +87 -0
- package/cjs/in-memory-cache.js +4 -7
- package/cjs/plugin.js +63 -70
- package/esm/in-memory-cache.js +4 -7
- package/esm/plugin.js +63 -70
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -38,10 +38,15 @@ When configuring the `useResponseCache`, you can choose the type of cache:
|
|
|
38
38
|
The in-memory LRU cache is used by default.
|
|
39
39
|
|
|
40
40
|
```ts
|
|
41
|
+
import { parse, validate, execute, subscribe } from 'graphql'
|
|
41
42
|
import { envelop } from '@envelop/core'
|
|
42
43
|
import { useResponseCache } from '@envelop/response-cache'
|
|
43
44
|
|
|
44
45
|
const getEnveloped = envelop({
|
|
46
|
+
parse,
|
|
47
|
+
validate,
|
|
48
|
+
execute,
|
|
49
|
+
subscribe,
|
|
45
50
|
plugins: [
|
|
46
51
|
// ... other plugins ...
|
|
47
52
|
useResponseCache({
|
|
@@ -55,12 +60,17 @@ const getEnveloped = envelop({
|
|
|
55
60
|
Or, you may create the in-memory LRU cache explicitly.
|
|
56
61
|
|
|
57
62
|
```ts
|
|
63
|
+
import { parse, validate, execute, subscribe } from 'graphql'
|
|
58
64
|
import { envelop } from '@envelop/core'
|
|
59
65
|
import { useResponseCache, createInMemoryCache } from '@envelop/response-cache'
|
|
60
66
|
|
|
61
67
|
const cache = createInMemoryCache()
|
|
62
68
|
|
|
63
69
|
const getEnveloped = envelop({
|
|
70
|
+
parse,
|
|
71
|
+
validate,
|
|
72
|
+
execute,
|
|
73
|
+
subscribe,
|
|
64
74
|
plugins: [
|
|
65
75
|
// ... other plugins ...
|
|
66
76
|
useResponseCache({
|
|
@@ -76,10 +86,15 @@ const getEnveloped = envelop({
|
|
|
76
86
|
### Cache based on session/user
|
|
77
87
|
|
|
78
88
|
```ts
|
|
89
|
+
import { parse, validate, execute, subscribe } from 'graphql'
|
|
79
90
|
import { envelop } from '@envelop/core'
|
|
80
91
|
import { useResponseCache } from '@envelop/response-cache'
|
|
81
92
|
|
|
82
93
|
const getEnveloped = envelop({
|
|
94
|
+
parse,
|
|
95
|
+
validate,
|
|
96
|
+
execute,
|
|
97
|
+
subscribe,
|
|
83
98
|
plugins: [
|
|
84
99
|
// ... other plugins ...
|
|
85
100
|
useResponseCache({
|
|
@@ -105,6 +120,7 @@ In order to use the Redis cache, you need to:
|
|
|
105
120
|
- Create an instance of the Redis Cache and set to the `useResponseCache` plugin options
|
|
106
121
|
|
|
107
122
|
```ts
|
|
123
|
+
import { parse, validate, execute, subscribe } from 'graphql'
|
|
108
124
|
import { envelop } from '@envelop/core'
|
|
109
125
|
import { useResponseCache } from '@envelop/response-cache'
|
|
110
126
|
import { createRedisCache } from '@envelop/response-cache-redis'
|
|
@@ -122,6 +138,10 @@ const redis = new Redis('rediss://:1234567890@my-redis-db.example.com:30652')
|
|
|
122
138
|
const cache = createRedisCache({ redis })
|
|
123
139
|
|
|
124
140
|
const getEnveloped = envelop({
|
|
141
|
+
parse,
|
|
142
|
+
validate,
|
|
143
|
+
execute,
|
|
144
|
+
subscribe,
|
|
125
145
|
plugins: [
|
|
126
146
|
// ... other plugins ...
|
|
127
147
|
useResponseCache({
|
|
@@ -139,10 +159,15 @@ const getEnveloped = envelop({
|
|
|
139
159
|
### Cache with maximum TTL
|
|
140
160
|
|
|
141
161
|
```ts
|
|
162
|
+
import { parse, validate, execute, subscribe } from 'graphql'
|
|
142
163
|
import { envelop } from '@envelop/core'
|
|
143
164
|
import { useResponseCache } from '@envelop/response-cache'
|
|
144
165
|
|
|
145
166
|
const getEnveloped = envelop({
|
|
167
|
+
parse,
|
|
168
|
+
validate,
|
|
169
|
+
execute,
|
|
170
|
+
subscribe,
|
|
146
171
|
plugins: [
|
|
147
172
|
// ... other plugins ...
|
|
148
173
|
useResponseCache({
|
|
@@ -158,10 +183,15 @@ const getEnveloped = envelop({
|
|
|
158
183
|
### Cache with custom TTL per object type
|
|
159
184
|
|
|
160
185
|
```ts
|
|
186
|
+
import { parse, validate, execute, subscribe } from 'graphql'
|
|
161
187
|
import { envelop } from '@envelop/core'
|
|
162
188
|
import { useResponseCache } from '@envelop/response-cache'
|
|
163
189
|
|
|
164
190
|
const getEnveloped = envelop({
|
|
191
|
+
parse,
|
|
192
|
+
validate,
|
|
193
|
+
execute,
|
|
194
|
+
subscribe,
|
|
165
195
|
plugins: [
|
|
166
196
|
// ... other plugins ...
|
|
167
197
|
useResponseCache({
|
|
@@ -178,10 +208,15 @@ const getEnveloped = envelop({
|
|
|
178
208
|
### Cache with custom TTL per schema coordinate
|
|
179
209
|
|
|
180
210
|
```ts
|
|
211
|
+
import { parse, validate, execute, subscribe } from 'graphql'
|
|
181
212
|
import { envelop } from '@envelop/core'
|
|
182
213
|
import { useResponseCache } from '@envelop/response-cache'
|
|
183
214
|
|
|
184
215
|
const getEnveloped = envelop({
|
|
216
|
+
parse,
|
|
217
|
+
validate,
|
|
218
|
+
execute,
|
|
219
|
+
subscribe,
|
|
185
220
|
plugins: [
|
|
186
221
|
// ... other plugins ...
|
|
187
222
|
useResponseCache({
|
|
@@ -198,10 +233,15 @@ const getEnveloped = envelop({
|
|
|
198
233
|
### Disable cache based on session/user
|
|
199
234
|
|
|
200
235
|
```ts
|
|
236
|
+
import { parse, validate, execute, subscribe } from 'graphql'
|
|
201
237
|
import { envelop } from '@envelop/core'
|
|
202
238
|
import { useResponseCache } from '@envelop/response-cache'
|
|
203
239
|
|
|
204
240
|
const getEnveloped = envelop({
|
|
241
|
+
parse,
|
|
242
|
+
validate,
|
|
243
|
+
execute,
|
|
244
|
+
subscribe,
|
|
205
245
|
plugins: [
|
|
206
246
|
// ... other plugins ...
|
|
207
247
|
useResponseCache({
|
|
@@ -228,6 +268,7 @@ cache results with certain error types.
|
|
|
228
268
|
By default, the `defaultShouldCacheResult` function is used which never caches any query operation execution results that includes any errors (unexpected, EnvelopError, or GraphQLError).
|
|
229
269
|
|
|
230
270
|
```ts
|
|
271
|
+
import { parse, validate, execute, subscribe } from 'graphql'
|
|
231
272
|
import { envelop } from '@envelop/core'
|
|
232
273
|
import { useResponseCache, ShouldCacheResultFunction } from '@envelop/response-cache'
|
|
233
274
|
|
|
@@ -238,6 +279,10 @@ export const defaultShouldCacheResult: ShouldCacheResultFunction = (params): Boo
|
|
|
238
279
|
}
|
|
239
280
|
|
|
240
281
|
const getEnveloped = envelop({
|
|
282
|
+
parse,
|
|
283
|
+
validate,
|
|
284
|
+
execute,
|
|
285
|
+
subscribe,
|
|
241
286
|
plugins: [
|
|
242
287
|
// ... other plugins ...
|
|
243
288
|
useResponseCache({
|
|
@@ -255,10 +300,15 @@ By default introspection query operations are not cached. In case you want to ca
|
|
|
255
300
|
**Infinite caching**
|
|
256
301
|
|
|
257
302
|
```ts
|
|
303
|
+
import { parse, validate, execute, subscribe } from 'graphql'
|
|
258
304
|
import { envelop } from '@envelop/core'
|
|
259
305
|
import { useResponseCache } from '@envelop/response-cache'
|
|
260
306
|
|
|
261
307
|
const getEnveloped = envelop({
|
|
308
|
+
parse,
|
|
309
|
+
validate,
|
|
310
|
+
execute,
|
|
311
|
+
subscribe,
|
|
262
312
|
plugins: [
|
|
263
313
|
// ... other plugins ...
|
|
264
314
|
useResponseCache({
|
|
@@ -274,10 +324,15 @@ const getEnveloped = envelop({
|
|
|
274
324
|
**TTL caching**
|
|
275
325
|
|
|
276
326
|
```ts
|
|
327
|
+
import { parse, validate, execute, subscribe } from 'graphql'
|
|
277
328
|
import { envelop } from '@envelop/core'
|
|
278
329
|
import { useResponseCache } from '@envelop/response-cache'
|
|
279
330
|
|
|
280
331
|
const getEnveloped = envelop({
|
|
332
|
+
parse,
|
|
333
|
+
validate,
|
|
334
|
+
execute,
|
|
335
|
+
subscribe,
|
|
281
336
|
plugins: [
|
|
282
337
|
// ... other plugins ...
|
|
283
338
|
useResponseCache({
|
|
@@ -293,10 +348,15 @@ const getEnveloped = envelop({
|
|
|
293
348
|
### Cache with maximum TTL
|
|
294
349
|
|
|
295
350
|
```ts
|
|
351
|
+
import { parse, validate, execute, subscribe } from 'graphql'
|
|
296
352
|
import { envelop } from '@envelop/core'
|
|
297
353
|
import { useResponseCache } from '@envelop/response-cache'
|
|
298
354
|
|
|
299
355
|
const getEnveloped = envelop({
|
|
356
|
+
parse,
|
|
357
|
+
validate,
|
|
358
|
+
execute,
|
|
359
|
+
subscribe,
|
|
300
360
|
plugins: [
|
|
301
361
|
// ... other plugins ...
|
|
302
362
|
useResponseCache({
|
|
@@ -310,10 +370,15 @@ const getEnveloped = envelop({
|
|
|
310
370
|
### Customize the fields that are used for building the cache ID
|
|
311
371
|
|
|
312
372
|
```ts
|
|
373
|
+
import { parse, validate, execute, subscribe } from 'graphql'
|
|
313
374
|
import { envelop } from '@envelop/core'
|
|
314
375
|
import { useResponseCache } from '@envelop/response-cache'
|
|
315
376
|
|
|
316
377
|
const getEnveloped = envelop({
|
|
378
|
+
parse,
|
|
379
|
+
validate,
|
|
380
|
+
execute,
|
|
381
|
+
subscribe,
|
|
317
382
|
plugins: [
|
|
318
383
|
// ... other plugins ...
|
|
319
384
|
useResponseCache({
|
|
@@ -329,10 +394,15 @@ const getEnveloped = envelop({
|
|
|
329
394
|
### Disable automatic cache invalidation via mutations
|
|
330
395
|
|
|
331
396
|
```ts
|
|
397
|
+
import { parse, validate, execute, subscribe } from 'graphql'
|
|
332
398
|
import { envelop } from '@envelop/core'
|
|
333
399
|
import { useResponseCache } from '@envelop/response-cache'
|
|
334
400
|
|
|
335
401
|
const getEnveloped = envelop({
|
|
402
|
+
parse,
|
|
403
|
+
validate,
|
|
404
|
+
execute,
|
|
405
|
+
subscribe,
|
|
336
406
|
plugins: [
|
|
337
407
|
// ... other plugins ...
|
|
338
408
|
useResponseCache({
|
|
@@ -348,6 +418,7 @@ const getEnveloped = envelop({
|
|
|
348
418
|
### Invalidate Cache based on custom logic
|
|
349
419
|
|
|
350
420
|
```ts
|
|
421
|
+
import { parse, validate, execute, subscribe } from 'graphql'
|
|
351
422
|
import { envelop } from '@envelop/core'
|
|
352
423
|
import { useResponseCache, createInMemoryCache } from '@envelop/response-cache'
|
|
353
424
|
import { emitter } from './eventEmitter'
|
|
@@ -356,6 +427,10 @@ import { emitter } from './eventEmitter'
|
|
|
356
427
|
const cache = createInMemoryCache()
|
|
357
428
|
|
|
358
429
|
const getEnveloped = envelop({
|
|
430
|
+
parse,
|
|
431
|
+
validate,
|
|
432
|
+
execute,
|
|
433
|
+
subscribe,
|
|
359
434
|
plugins: [
|
|
360
435
|
// ... other plugins ...
|
|
361
436
|
useResponseCache({
|
|
@@ -380,6 +455,7 @@ emitter.on('invalidate', resource => {
|
|
|
380
455
|
### Customize how cache ids are built
|
|
381
456
|
|
|
382
457
|
```ts
|
|
458
|
+
import { parse, validate, execute, subscribe } from 'graphql'
|
|
383
459
|
import { envelop } from '@envelop/core'
|
|
384
460
|
import { useResponseCache, createInMemoryCache } from '@envelop/response-cache'
|
|
385
461
|
import { emitter } from './eventEmitter'
|
|
@@ -391,6 +467,10 @@ const cache = createInMemoryCache({
|
|
|
391
467
|
})
|
|
392
468
|
|
|
393
469
|
const getEnveloped = envelop({
|
|
470
|
+
parse,
|
|
471
|
+
validate,
|
|
472
|
+
execute,
|
|
473
|
+
subscribe,
|
|
394
474
|
plugins: [
|
|
395
475
|
// ... other plugins ...
|
|
396
476
|
useResponseCache({
|
|
@@ -408,7 +488,14 @@ const getEnveloped = envelop({
|
|
|
408
488
|
For debugging or monitoring it might be useful to know whether a response got served from the cache or not.
|
|
409
489
|
|
|
410
490
|
```ts
|
|
491
|
+
import { parse, validate, execute, subscribe } from 'graphql'
|
|
492
|
+
import { envelop } from '@envelop/core'
|
|
493
|
+
|
|
411
494
|
const getEnveloped = envelop({
|
|
495
|
+
parse,
|
|
496
|
+
validate,
|
|
497
|
+
execute,
|
|
498
|
+
subscribe,
|
|
412
499
|
plugins: [
|
|
413
500
|
// ... other plugins ...
|
|
414
501
|
useResponseCache({
|
package/cjs/in-memory-cache.js
CHANGED
|
@@ -4,10 +4,9 @@ exports.defaultBuildEntityId = exports.createInMemoryCache = void 0;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const lru_cache_1 = tslib_1.__importDefault(require("lru-cache"));
|
|
6
6
|
const createInMemoryCache = (params) => {
|
|
7
|
-
|
|
8
|
-
const buildEntityId = (_a = params === null || params === void 0 ? void 0 : params.buildEntityId) !== null && _a !== void 0 ? _a : exports.defaultBuildEntityId;
|
|
7
|
+
const buildEntityId = params?.buildEntityId ?? exports.defaultBuildEntityId;
|
|
9
8
|
const cachedResponses = new lru_cache_1.default({
|
|
10
|
-
max: params
|
|
9
|
+
max: params?.max,
|
|
11
10
|
stale: false,
|
|
12
11
|
noDisposeOnSet: true,
|
|
13
12
|
dispose(responseId) {
|
|
@@ -17,13 +16,12 @@ const createInMemoryCache = (params) => {
|
|
|
17
16
|
const entityToResponseIds = new Map();
|
|
18
17
|
const responseIdToEntityIds = new Map();
|
|
19
18
|
function purgeResponse(responseId, shouldRemove = true) {
|
|
20
|
-
var _a;
|
|
21
19
|
const entityIds = responseIdToEntityIds.get(responseId);
|
|
22
20
|
// get entities related to the response
|
|
23
21
|
if (entityIds !== undefined) {
|
|
24
22
|
for (const entityId of entityIds) {
|
|
25
23
|
// remove the response mapping from the entity
|
|
26
|
-
|
|
24
|
+
entityToResponseIds.get(entityId)?.delete(responseId);
|
|
27
25
|
}
|
|
28
26
|
// remove all the entity mappings from the response
|
|
29
27
|
responseIdToEntityIds.delete(responseId);
|
|
@@ -71,8 +69,7 @@ const createInMemoryCache = (params) => {
|
|
|
71
69
|
}
|
|
72
70
|
},
|
|
73
71
|
get(responseId) {
|
|
74
|
-
|
|
75
|
-
return (_a = cachedResponses.get(responseId)) !== null && _a !== void 0 ? _a : null;
|
|
72
|
+
return cachedResponses.get(responseId) ?? null;
|
|
76
73
|
},
|
|
77
74
|
invalidate(entitiesToRemove) {
|
|
78
75
|
for (const { typename, id } of entitiesToRemove) {
|
package/cjs/plugin.js
CHANGED
|
@@ -13,15 +13,12 @@ const cache_document_str_js_1 = require("./cache-document-str.js");
|
|
|
13
13
|
* Default function used for building the response cache key.
|
|
14
14
|
* 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.
|
|
15
15
|
*/
|
|
16
|
-
const defaultBuildResponseCacheKey = params =>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
(_c = params.sessionId) !== null && _c !== void 0 ? _c : '',
|
|
23
|
-
].join('|'));
|
|
24
|
-
};
|
|
16
|
+
const defaultBuildResponseCacheKey = params => (0, hash_sha256_js_1.hashSHA256)([
|
|
17
|
+
params.documentString,
|
|
18
|
+
params.operationName ?? '',
|
|
19
|
+
(0, fast_json_stable_stringify_1.default)(params.variableValues ?? {}),
|
|
20
|
+
params.sessionId ?? '',
|
|
21
|
+
].join('|'));
|
|
25
22
|
exports.defaultBuildResponseCacheKey = defaultBuildResponseCacheKey;
|
|
26
23
|
/**
|
|
27
24
|
* Default function used to check if the result should be cached.
|
|
@@ -53,7 +50,6 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
|
|
|
53
50
|
}
|
|
54
51
|
},
|
|
55
52
|
async onExecute(onExecuteParams) {
|
|
56
|
-
var _a;
|
|
57
53
|
let documentChanged = false;
|
|
58
54
|
const newDocument = (0, graphql_1.visit)(onExecuteParams.args.document, {
|
|
59
55
|
SelectionSet(node) {
|
|
@@ -88,68 +84,65 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
|
|
|
88
84
|
const types = new Set();
|
|
89
85
|
let currentTtl;
|
|
90
86
|
let skip = false;
|
|
91
|
-
const processResult = (result) => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (fieldName === '__typename') {
|
|
111
|
-
typenameCalled++;
|
|
112
|
-
}
|
|
113
|
-
if (fieldName === '__leave' &&
|
|
114
|
-
/**
|
|
115
|
-
* The visitResult function is called for each field in the selection set.
|
|
116
|
-
* But visitResult function looks for __typename field visitor even if it is not there in the document
|
|
117
|
-
* So it calls __typename field visitor twice if it is also in the selection set.
|
|
118
|
-
* That's why we need to count the number of times it is called.
|
|
119
|
-
*
|
|
120
|
-
* Default call of __typename https://github.com/ardatan/graphql-tools/blob/master/packages/utils/src/visitResult.ts#L277
|
|
121
|
-
* Call for the field node https://github.com/ardatan/graphql-tools/blob/master/packages/utils/src/visitResult.ts#L272
|
|
122
|
-
*/ typenameCalled < 2) {
|
|
123
|
-
return (root) => {
|
|
124
|
-
delete root.__typename;
|
|
125
|
-
return root;
|
|
126
|
-
};
|
|
127
|
-
}
|
|
87
|
+
const processResult = (result) => (0, utils_1.visitResult)(result, {
|
|
88
|
+
document: onExecuteParams.args.document,
|
|
89
|
+
variables: onExecuteParams.args.variableValues,
|
|
90
|
+
operationName: onExecuteParams.args.operationName ?? undefined,
|
|
91
|
+
rootValue: onExecuteParams.args.rootValue,
|
|
92
|
+
context: onExecuteParams.args.contextValue,
|
|
93
|
+
}, onExecuteParams.args.schema, new Proxy({}, {
|
|
94
|
+
get(_, typename) {
|
|
95
|
+
let typenameCalled = 0;
|
|
96
|
+
return new Proxy((val) => val, {
|
|
97
|
+
// Needed for leaf values such as scalars, enums etc
|
|
98
|
+
// They don't have fields so visitResult expects functions for those
|
|
99
|
+
apply(_, __, [val]) {
|
|
100
|
+
return val;
|
|
101
|
+
},
|
|
102
|
+
get(_, fieldName) {
|
|
103
|
+
if (documentChanged) {
|
|
104
|
+
if (fieldName === '__typename') {
|
|
105
|
+
typenameCalled++;
|
|
128
106
|
}
|
|
129
|
-
if (
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return id;
|
|
107
|
+
if (fieldName === '__leave' &&
|
|
108
|
+
/**
|
|
109
|
+
* The visitResult function is called for each field in the selection set.
|
|
110
|
+
* But visitResult function looks for __typename field visitor even if it is not there in the document
|
|
111
|
+
* So it calls __typename field visitor twice if it is also in the selection set.
|
|
112
|
+
* That's why we need to count the number of times it is called.
|
|
113
|
+
*
|
|
114
|
+
* Default call of __typename https://github.com/ardatan/graphql-tools/blob/master/packages/utils/src/visitResult.ts#L277
|
|
115
|
+
* Call for the field node https://github.com/ardatan/graphql-tools/blob/master/packages/utils/src/visitResult.ts#L272
|
|
116
|
+
*/ typenameCalled < 2) {
|
|
117
|
+
return (root) => {
|
|
118
|
+
delete root.__typename;
|
|
119
|
+
return root;
|
|
143
120
|
};
|
|
144
121
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
122
|
+
}
|
|
123
|
+
if (idFields.includes(fieldName)) {
|
|
124
|
+
if (ignoredTypesMap.has(typename)) {
|
|
125
|
+
skip = true;
|
|
126
|
+
}
|
|
127
|
+
if (skip === true) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
return (id) => {
|
|
131
|
+
identifier.set(`${typename}:${id}`, { typename, id });
|
|
132
|
+
types.add(typename);
|
|
133
|
+
if (typename in ttlPerType) {
|
|
134
|
+
currentTtl = calculateTtl(ttlPerType[typename], currentTtl);
|
|
135
|
+
}
|
|
136
|
+
return id;
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
return undefined;
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
},
|
|
143
|
+
}));
|
|
151
144
|
const operationAST = (0, graphql_1.getOperationAST)(onExecuteParams.args.document, onExecuteParams.args.operationName);
|
|
152
|
-
if (invalidateViaMutation !== false &&
|
|
145
|
+
if (invalidateViaMutation !== false && operationAST?.operation === 'mutation') {
|
|
153
146
|
return {
|
|
154
147
|
onExecuteDone({ result, setResult }) {
|
|
155
148
|
if ((0, core_1.isAsyncIterable)(result)) {
|
|
@@ -179,7 +172,7 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
|
|
|
179
172
|
operationName: onExecuteParams.args.operationName,
|
|
180
173
|
sessionId: session(onExecuteParams.args.contextValue),
|
|
181
174
|
});
|
|
182
|
-
if ((
|
|
175
|
+
if ((enabled?.(onExecuteParams.args.contextValue) ?? true) === true) {
|
|
183
176
|
const cachedResponse = await cache.get(operationId);
|
|
184
177
|
if (cachedResponse != null) {
|
|
185
178
|
if (includeExtensionMetadata) {
|
|
@@ -228,7 +221,7 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
|
|
|
228
221
|
return;
|
|
229
222
|
}
|
|
230
223
|
// we only use the global ttl if no currentTtl has been determined.
|
|
231
|
-
const finalTtl = currentTtl
|
|
224
|
+
const finalTtl = currentTtl ?? globalTtl;
|
|
232
225
|
if (finalTtl === 0) {
|
|
233
226
|
if (includeExtensionMetadata) {
|
|
234
227
|
setResult({
|
package/esm/in-memory-cache.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import LRU from 'lru-cache';
|
|
2
2
|
export const createInMemoryCache = (params) => {
|
|
3
|
-
|
|
4
|
-
const buildEntityId = (_a = params === null || params === void 0 ? void 0 : params.buildEntityId) !== null && _a !== void 0 ? _a : defaultBuildEntityId;
|
|
3
|
+
const buildEntityId = params?.buildEntityId ?? defaultBuildEntityId;
|
|
5
4
|
const cachedResponses = new LRU({
|
|
6
|
-
max: params
|
|
5
|
+
max: params?.max,
|
|
7
6
|
stale: false,
|
|
8
7
|
noDisposeOnSet: true,
|
|
9
8
|
dispose(responseId) {
|
|
@@ -13,13 +12,12 @@ export const createInMemoryCache = (params) => {
|
|
|
13
12
|
const entityToResponseIds = new Map();
|
|
14
13
|
const responseIdToEntityIds = new Map();
|
|
15
14
|
function purgeResponse(responseId, shouldRemove = true) {
|
|
16
|
-
var _a;
|
|
17
15
|
const entityIds = responseIdToEntityIds.get(responseId);
|
|
18
16
|
// get entities related to the response
|
|
19
17
|
if (entityIds !== undefined) {
|
|
20
18
|
for (const entityId of entityIds) {
|
|
21
19
|
// remove the response mapping from the entity
|
|
22
|
-
|
|
20
|
+
entityToResponseIds.get(entityId)?.delete(responseId);
|
|
23
21
|
}
|
|
24
22
|
// remove all the entity mappings from the response
|
|
25
23
|
responseIdToEntityIds.delete(responseId);
|
|
@@ -67,8 +65,7 @@ export const createInMemoryCache = (params) => {
|
|
|
67
65
|
}
|
|
68
66
|
},
|
|
69
67
|
get(responseId) {
|
|
70
|
-
|
|
71
|
-
return (_a = cachedResponses.get(responseId)) !== null && _a !== void 0 ? _a : null;
|
|
68
|
+
return cachedResponses.get(responseId) ?? null;
|
|
72
69
|
},
|
|
73
70
|
invalidate(entitiesToRemove) {
|
|
74
71
|
for (const { typename, id } of entitiesToRemove) {
|
package/esm/plugin.js
CHANGED
|
@@ -9,15 +9,12 @@ import { defaultGetDocumentString, useCacheDocumentString } from './cache-docume
|
|
|
9
9
|
* Default function used for building the response cache key.
|
|
10
10
|
* 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.
|
|
11
11
|
*/
|
|
12
|
-
export const defaultBuildResponseCacheKey = params =>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
(_c = params.sessionId) !== null && _c !== void 0 ? _c : '',
|
|
19
|
-
].join('|'));
|
|
20
|
-
};
|
|
12
|
+
export const defaultBuildResponseCacheKey = params => hashSHA256([
|
|
13
|
+
params.documentString,
|
|
14
|
+
params.operationName ?? '',
|
|
15
|
+
jsonStableStringify(params.variableValues ?? {}),
|
|
16
|
+
params.sessionId ?? '',
|
|
17
|
+
].join('|'));
|
|
21
18
|
/**
|
|
22
19
|
* Default function used to check if the result should be cached.
|
|
23
20
|
*
|
|
@@ -47,7 +44,6 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
|
|
|
47
44
|
}
|
|
48
45
|
},
|
|
49
46
|
async onExecute(onExecuteParams) {
|
|
50
|
-
var _a;
|
|
51
47
|
let documentChanged = false;
|
|
52
48
|
const newDocument = visit(onExecuteParams.args.document, {
|
|
53
49
|
SelectionSet(node) {
|
|
@@ -82,68 +78,65 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
|
|
|
82
78
|
const types = new Set();
|
|
83
79
|
let currentTtl;
|
|
84
80
|
let skip = false;
|
|
85
|
-
const processResult = (result) => {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (fieldName === '__typename') {
|
|
105
|
-
typenameCalled++;
|
|
106
|
-
}
|
|
107
|
-
if (fieldName === '__leave' &&
|
|
108
|
-
/**
|
|
109
|
-
* The visitResult function is called for each field in the selection set.
|
|
110
|
-
* But visitResult function looks for __typename field visitor even if it is not there in the document
|
|
111
|
-
* So it calls __typename field visitor twice if it is also in the selection set.
|
|
112
|
-
* That's why we need to count the number of times it is called.
|
|
113
|
-
*
|
|
114
|
-
* Default call of __typename https://github.com/ardatan/graphql-tools/blob/master/packages/utils/src/visitResult.ts#L277
|
|
115
|
-
* Call for the field node https://github.com/ardatan/graphql-tools/blob/master/packages/utils/src/visitResult.ts#L272
|
|
116
|
-
*/ typenameCalled < 2) {
|
|
117
|
-
return (root) => {
|
|
118
|
-
delete root.__typename;
|
|
119
|
-
return root;
|
|
120
|
-
};
|
|
121
|
-
}
|
|
81
|
+
const processResult = (result) => visitResult(result, {
|
|
82
|
+
document: onExecuteParams.args.document,
|
|
83
|
+
variables: onExecuteParams.args.variableValues,
|
|
84
|
+
operationName: onExecuteParams.args.operationName ?? undefined,
|
|
85
|
+
rootValue: onExecuteParams.args.rootValue,
|
|
86
|
+
context: onExecuteParams.args.contextValue,
|
|
87
|
+
}, onExecuteParams.args.schema, new Proxy({}, {
|
|
88
|
+
get(_, typename) {
|
|
89
|
+
let typenameCalled = 0;
|
|
90
|
+
return new Proxy((val) => val, {
|
|
91
|
+
// Needed for leaf values such as scalars, enums etc
|
|
92
|
+
// They don't have fields so visitResult expects functions for those
|
|
93
|
+
apply(_, __, [val]) {
|
|
94
|
+
return val;
|
|
95
|
+
},
|
|
96
|
+
get(_, fieldName) {
|
|
97
|
+
if (documentChanged) {
|
|
98
|
+
if (fieldName === '__typename') {
|
|
99
|
+
typenameCalled++;
|
|
122
100
|
}
|
|
123
|
-
if (
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
return id;
|
|
101
|
+
if (fieldName === '__leave' &&
|
|
102
|
+
/**
|
|
103
|
+
* The visitResult function is called for each field in the selection set.
|
|
104
|
+
* But visitResult function looks for __typename field visitor even if it is not there in the document
|
|
105
|
+
* So it calls __typename field visitor twice if it is also in the selection set.
|
|
106
|
+
* That's why we need to count the number of times it is called.
|
|
107
|
+
*
|
|
108
|
+
* Default call of __typename https://github.com/ardatan/graphql-tools/blob/master/packages/utils/src/visitResult.ts#L277
|
|
109
|
+
* Call for the field node https://github.com/ardatan/graphql-tools/blob/master/packages/utils/src/visitResult.ts#L272
|
|
110
|
+
*/ typenameCalled < 2) {
|
|
111
|
+
return (root) => {
|
|
112
|
+
delete root.__typename;
|
|
113
|
+
return root;
|
|
137
114
|
};
|
|
138
115
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
116
|
+
}
|
|
117
|
+
if (idFields.includes(fieldName)) {
|
|
118
|
+
if (ignoredTypesMap.has(typename)) {
|
|
119
|
+
skip = true;
|
|
120
|
+
}
|
|
121
|
+
if (skip === true) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
return (id) => {
|
|
125
|
+
identifier.set(`${typename}:${id}`, { typename, id });
|
|
126
|
+
types.add(typename);
|
|
127
|
+
if (typename in ttlPerType) {
|
|
128
|
+
currentTtl = calculateTtl(ttlPerType[typename], currentTtl);
|
|
129
|
+
}
|
|
130
|
+
return id;
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
return undefined;
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
},
|
|
137
|
+
}));
|
|
145
138
|
const operationAST = getOperationAST(onExecuteParams.args.document, onExecuteParams.args.operationName);
|
|
146
|
-
if (invalidateViaMutation !== false &&
|
|
139
|
+
if (invalidateViaMutation !== false && operationAST?.operation === 'mutation') {
|
|
147
140
|
return {
|
|
148
141
|
onExecuteDone({ result, setResult }) {
|
|
149
142
|
if (isAsyncIterable(result)) {
|
|
@@ -173,7 +166,7 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
|
|
|
173
166
|
operationName: onExecuteParams.args.operationName,
|
|
174
167
|
sessionId: session(onExecuteParams.args.contextValue),
|
|
175
168
|
});
|
|
176
|
-
if ((
|
|
169
|
+
if ((enabled?.(onExecuteParams.args.contextValue) ?? true) === true) {
|
|
177
170
|
const cachedResponse = await cache.get(operationId);
|
|
178
171
|
if (cachedResponse != null) {
|
|
179
172
|
if (includeExtensionMetadata) {
|
|
@@ -222,7 +215,7 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
|
|
|
222
215
|
return;
|
|
223
216
|
}
|
|
224
217
|
// we only use the global ttl if no currentTtl has been determined.
|
|
225
|
-
const finalTtl = currentTtl
|
|
218
|
+
const finalTtl = currentTtl ?? globalTtl;
|
|
226
219
|
if (finalTtl === 0) {
|
|
227
220
|
if (includeExtensionMetadata) {
|
|
228
221
|
setResult({
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@envelop/response-cache",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.1-alpha-20220901205925-b1fd44a9",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"peerDependencies": {
|
|
6
|
-
"@envelop/core": "
|
|
6
|
+
"@envelop/core": "2.6.1-alpha-20220901205925-b1fd44a9",
|
|
7
7
|
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|