@envelop/response-cache 5.4.0 → 5.5.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.
- package/cjs/plugin.js +44 -29
- package/esm/plugin.js +45 -30
- package/package.json +1 -1
package/cjs/plugin.js
CHANGED
|
@@ -41,8 +41,9 @@ function defaultGetDocumentString(executionArgs) {
|
|
|
41
41
|
}
|
|
42
42
|
exports.defaultGetDocumentString = defaultGetDocumentString;
|
|
43
43
|
const originalDocumentMap = new WeakMap();
|
|
44
|
-
const
|
|
45
|
-
const
|
|
44
|
+
const addEntityInfosToDocument = (0, utils_1.memoize4)(function addTypeNameToDocument(document, addTypeNameToDocumentOpts, schema, idFieldByTypeName) {
|
|
45
|
+
const typeInfo = new graphql_1.TypeInfo(schema);
|
|
46
|
+
const newDocument = (0, graphql_1.visit)(document, (0, graphql_1.visitWithTypeInfo)(typeInfo, {
|
|
46
47
|
OperationDefinition: {
|
|
47
48
|
enter(node) {
|
|
48
49
|
if (!addTypeNameToDocumentOpts.invalidateViaMutation && node.operation === 'mutation') {
|
|
@@ -53,7 +54,9 @@ const addTypeNameToDocument = (0, utils_1.memoize2)(function addTypeNameToDocume
|
|
|
53
54
|
}
|
|
54
55
|
},
|
|
55
56
|
},
|
|
56
|
-
SelectionSet(node, _key
|
|
57
|
+
SelectionSet(node, _key) {
|
|
58
|
+
const parentType = typeInfo.getParentType();
|
|
59
|
+
const idField = parentType && idFieldByTypeName.get(parentType.name);
|
|
57
60
|
return {
|
|
58
61
|
...node,
|
|
59
62
|
selections: [
|
|
@@ -68,11 +71,20 @@ const addTypeNameToDocument = (0, utils_1.memoize2)(function addTypeNameToDocume
|
|
|
68
71
|
value: '__responseCacheTypeName',
|
|
69
72
|
},
|
|
70
73
|
},
|
|
74
|
+
...(idField
|
|
75
|
+
? [
|
|
76
|
+
{
|
|
77
|
+
kind: graphql_1.Kind.FIELD,
|
|
78
|
+
name: { kind: graphql_1.Kind.NAME, value: idField },
|
|
79
|
+
alias: { kind: graphql_1.Kind.NAME, value: '__responseCacheId' },
|
|
80
|
+
},
|
|
81
|
+
]
|
|
82
|
+
: []),
|
|
71
83
|
...node.selections,
|
|
72
84
|
],
|
|
73
85
|
};
|
|
74
86
|
},
|
|
75
|
-
});
|
|
87
|
+
}));
|
|
76
88
|
originalDocumentMap.set(newDocument, document);
|
|
77
89
|
return newDocument;
|
|
78
90
|
});
|
|
@@ -81,24 +93,32 @@ function useResponseCache({ cache = (0, in_memory_cache_js_1.createInMemoryCache
|
|
|
81
93
|
process.env['NODE_ENV'] === 'development' || !!process.env['DEBUG']
|
|
82
94
|
: false, }) {
|
|
83
95
|
const ignoredTypesMap = new Set(ignoredTypes);
|
|
84
|
-
const processedSchemas = new WeakSet();
|
|
85
96
|
const typePerSchemaCoordinateMap = new Map();
|
|
86
97
|
// never cache Introspections
|
|
87
98
|
ttlPerSchemaCoordinate = { 'Query.__schema': 0, ...ttlPerSchemaCoordinate };
|
|
88
99
|
const addTypeNameToDocumentOpts = { invalidateViaMutation };
|
|
100
|
+
const idFieldByTypeName = new Map();
|
|
101
|
+
let schema;
|
|
102
|
+
function isPrivate(typeName, data) {
|
|
103
|
+
if (scopePerSchemaCoordinate[typeName] === 'PRIVATE') {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
return Object.keys(data).some(fieldName => scopePerSchemaCoordinate[`${typeName}.${fieldName}`] === 'PRIVATE');
|
|
107
|
+
}
|
|
89
108
|
return {
|
|
90
109
|
onParse() {
|
|
91
110
|
return ({ result, replaceParseResult }) => {
|
|
92
111
|
if (!originalDocumentMap.has(result) && result.kind === graphql_1.Kind.DOCUMENT) {
|
|
93
|
-
const newDocument =
|
|
112
|
+
const newDocument = addEntityInfosToDocument(result, addTypeNameToDocumentOpts, schema, idFieldByTypeName);
|
|
94
113
|
replaceParseResult(newDocument);
|
|
95
114
|
}
|
|
96
115
|
};
|
|
97
116
|
},
|
|
98
|
-
onSchemaChange({ schema }) {
|
|
99
|
-
if (
|
|
117
|
+
onSchemaChange({ schema: newSchema }) {
|
|
118
|
+
if (schema === newSchema) {
|
|
100
119
|
return;
|
|
101
120
|
}
|
|
121
|
+
schema = newSchema;
|
|
102
122
|
const cacheControlDirective = schema.getDirective('cacheControl');
|
|
103
123
|
(0, utils_1.mapSchema)(schema, {
|
|
104
124
|
...(cacheControlDirective && {
|
|
@@ -120,22 +140,24 @@ function useResponseCache({ cache = (0, in_memory_cache_js_1.createInMemoryCache
|
|
|
120
140
|
const schemaCoordinates = `${typeName}.${fieldName}`;
|
|
121
141
|
const resultTypeNames = unwrapTypenames(fieldConfig.type);
|
|
122
142
|
typePerSchemaCoordinateMap.set(schemaCoordinates, resultTypeNames);
|
|
143
|
+
if (idFields.includes(fieldName) && !idFieldByTypeName.has(typeName)) {
|
|
144
|
+
idFieldByTypeName.set(typeName, fieldName);
|
|
145
|
+
}
|
|
123
146
|
if (cacheControlDirective) {
|
|
124
147
|
const cacheControlAnnotations = (0, utils_1.getDirective)(schema, fieldConfig, 'cacheControl');
|
|
125
148
|
cacheControlAnnotations?.forEach(cacheControl => {
|
|
126
149
|
const ttl = cacheControl.maxAge * 1000;
|
|
127
150
|
if (ttl != null) {
|
|
128
|
-
ttlPerSchemaCoordinate[
|
|
151
|
+
ttlPerSchemaCoordinate[schemaCoordinates] = ttl;
|
|
129
152
|
}
|
|
130
153
|
if (cacheControl.scope) {
|
|
131
|
-
scopePerSchemaCoordinate[
|
|
154
|
+
scopePerSchemaCoordinate[schemaCoordinates] = cacheControl.scope;
|
|
132
155
|
}
|
|
133
156
|
});
|
|
134
157
|
}
|
|
135
158
|
return fieldConfig;
|
|
136
159
|
},
|
|
137
160
|
});
|
|
138
|
-
processedSchemas.add(schema);
|
|
139
161
|
},
|
|
140
162
|
async onExecute(onExecuteParams) {
|
|
141
163
|
const identifier = new Map();
|
|
@@ -155,9 +177,10 @@ function useResponseCache({ cache = (0, in_memory_cache_js_1.createInMemoryCache
|
|
|
155
177
|
}
|
|
156
178
|
const typename = data.__responseCacheTypeName;
|
|
157
179
|
delete data.__responseCacheTypeName;
|
|
180
|
+
const entityId = data.__responseCacheId;
|
|
181
|
+
delete data.__responseCacheId;
|
|
158
182
|
if (!skip) {
|
|
159
|
-
if (ignoredTypesMap.has(typename) ||
|
|
160
|
-
(scopePerSchemaCoordinate[typename] === 'PRIVATE' && !sessionId)) {
|
|
183
|
+
if (ignoredTypesMap.has(typename) || (!sessionId && isPrivate(typename, data))) {
|
|
161
184
|
skip = true;
|
|
162
185
|
return;
|
|
163
186
|
}
|
|
@@ -165,24 +188,16 @@ function useResponseCache({ cache = (0, in_memory_cache_js_1.createInMemoryCache
|
|
|
165
188
|
if (typename in ttlPerType) {
|
|
166
189
|
currentTtl = calculateTtl(ttlPerType[typename], currentTtl);
|
|
167
190
|
}
|
|
191
|
+
if (entityId != null) {
|
|
192
|
+
identifier.set(`${typename}:${entityId}`, { typename, id: entityId });
|
|
193
|
+
}
|
|
168
194
|
for (const fieldName in data) {
|
|
169
195
|
const fieldData = data[fieldName];
|
|
170
|
-
if (
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
else if (idFields.includes(fieldName)) {
|
|
176
|
-
const id = fieldData;
|
|
177
|
-
identifier.set(`${typename}:${id}`, { typename, id });
|
|
178
|
-
}
|
|
179
|
-
else if (fieldData == null ||
|
|
180
|
-
(Array.isArray(fieldData) && fieldData.length === 0)) {
|
|
181
|
-
const inferredTypes = typePerSchemaCoordinateMap.get(`${typename}.${fieldName}`);
|
|
182
|
-
inferredTypes?.forEach(inferredType => {
|
|
183
|
-
identifier.set(inferredType, { typename: inferredType });
|
|
184
|
-
});
|
|
185
|
-
}
|
|
196
|
+
if (fieldData == null || (Array.isArray(fieldData) && fieldData.length === 0)) {
|
|
197
|
+
const inferredTypes = typePerSchemaCoordinateMap.get(`${typename}.${fieldName}`);
|
|
198
|
+
inferredTypes?.forEach(inferredType => {
|
|
199
|
+
identifier.set(inferredType, { typename: inferredType });
|
|
200
|
+
});
|
|
186
201
|
}
|
|
187
202
|
processResult(fieldData);
|
|
188
203
|
}
|
package/esm/plugin.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import jsonStableStringify from 'fast-json-stable-stringify';
|
|
2
2
|
import { getOperationAST, Kind, print, TypeInfo, visit, visitWithTypeInfo, } from 'graphql';
|
|
3
3
|
import { getDocumentString, isAsyncIterable, } from '@envelop/core';
|
|
4
|
-
import { getDirective, MapperKind, mapSchema,
|
|
4
|
+
import { getDirective, MapperKind, mapSchema, memoize4, mergeIncrementalResult, } from '@graphql-tools/utils';
|
|
5
5
|
import { hashSHA256 } from './hash-sha256.js';
|
|
6
6
|
import { createInMemoryCache } from './in-memory-cache.js';
|
|
7
7
|
/**
|
|
@@ -34,8 +34,9 @@ export function defaultGetDocumentString(executionArgs) {
|
|
|
34
34
|
return getDocumentString(executionArgs.document, print);
|
|
35
35
|
}
|
|
36
36
|
const originalDocumentMap = new WeakMap();
|
|
37
|
-
const
|
|
38
|
-
const
|
|
37
|
+
const addEntityInfosToDocument = memoize4(function addTypeNameToDocument(document, addTypeNameToDocumentOpts, schema, idFieldByTypeName) {
|
|
38
|
+
const typeInfo = new TypeInfo(schema);
|
|
39
|
+
const newDocument = visit(document, visitWithTypeInfo(typeInfo, {
|
|
39
40
|
OperationDefinition: {
|
|
40
41
|
enter(node) {
|
|
41
42
|
if (!addTypeNameToDocumentOpts.invalidateViaMutation && node.operation === 'mutation') {
|
|
@@ -46,7 +47,9 @@ const addTypeNameToDocument = memoize2(function addTypeNameToDocument(document,
|
|
|
46
47
|
}
|
|
47
48
|
},
|
|
48
49
|
},
|
|
49
|
-
SelectionSet(node, _key
|
|
50
|
+
SelectionSet(node, _key) {
|
|
51
|
+
const parentType = typeInfo.getParentType();
|
|
52
|
+
const idField = parentType && idFieldByTypeName.get(parentType.name);
|
|
50
53
|
return {
|
|
51
54
|
...node,
|
|
52
55
|
selections: [
|
|
@@ -61,11 +64,20 @@ const addTypeNameToDocument = memoize2(function addTypeNameToDocument(document,
|
|
|
61
64
|
value: '__responseCacheTypeName',
|
|
62
65
|
},
|
|
63
66
|
},
|
|
67
|
+
...(idField
|
|
68
|
+
? [
|
|
69
|
+
{
|
|
70
|
+
kind: Kind.FIELD,
|
|
71
|
+
name: { kind: Kind.NAME, value: idField },
|
|
72
|
+
alias: { kind: Kind.NAME, value: '__responseCacheId' },
|
|
73
|
+
},
|
|
74
|
+
]
|
|
75
|
+
: []),
|
|
64
76
|
...node.selections,
|
|
65
77
|
],
|
|
66
78
|
};
|
|
67
79
|
},
|
|
68
|
-
});
|
|
80
|
+
}));
|
|
69
81
|
originalDocumentMap.set(newDocument, document);
|
|
70
82
|
return newDocument;
|
|
71
83
|
});
|
|
@@ -74,24 +86,32 @@ export function useResponseCache({ cache = createInMemoryCache(), ttl: globalTtl
|
|
|
74
86
|
process.env['NODE_ENV'] === 'development' || !!process.env['DEBUG']
|
|
75
87
|
: false, }) {
|
|
76
88
|
const ignoredTypesMap = new Set(ignoredTypes);
|
|
77
|
-
const processedSchemas = new WeakSet();
|
|
78
89
|
const typePerSchemaCoordinateMap = new Map();
|
|
79
90
|
// never cache Introspections
|
|
80
91
|
ttlPerSchemaCoordinate = { 'Query.__schema': 0, ...ttlPerSchemaCoordinate };
|
|
81
92
|
const addTypeNameToDocumentOpts = { invalidateViaMutation };
|
|
93
|
+
const idFieldByTypeName = new Map();
|
|
94
|
+
let schema;
|
|
95
|
+
function isPrivate(typeName, data) {
|
|
96
|
+
if (scopePerSchemaCoordinate[typeName] === 'PRIVATE') {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
return Object.keys(data).some(fieldName => scopePerSchemaCoordinate[`${typeName}.${fieldName}`] === 'PRIVATE');
|
|
100
|
+
}
|
|
82
101
|
return {
|
|
83
102
|
onParse() {
|
|
84
103
|
return ({ result, replaceParseResult }) => {
|
|
85
104
|
if (!originalDocumentMap.has(result) && result.kind === Kind.DOCUMENT) {
|
|
86
|
-
const newDocument =
|
|
105
|
+
const newDocument = addEntityInfosToDocument(result, addTypeNameToDocumentOpts, schema, idFieldByTypeName);
|
|
87
106
|
replaceParseResult(newDocument);
|
|
88
107
|
}
|
|
89
108
|
};
|
|
90
109
|
},
|
|
91
|
-
onSchemaChange({ schema }) {
|
|
92
|
-
if (
|
|
110
|
+
onSchemaChange({ schema: newSchema }) {
|
|
111
|
+
if (schema === newSchema) {
|
|
93
112
|
return;
|
|
94
113
|
}
|
|
114
|
+
schema = newSchema;
|
|
95
115
|
const cacheControlDirective = schema.getDirective('cacheControl');
|
|
96
116
|
mapSchema(schema, {
|
|
97
117
|
...(cacheControlDirective && {
|
|
@@ -113,22 +133,24 @@ export function useResponseCache({ cache = createInMemoryCache(), ttl: globalTtl
|
|
|
113
133
|
const schemaCoordinates = `${typeName}.${fieldName}`;
|
|
114
134
|
const resultTypeNames = unwrapTypenames(fieldConfig.type);
|
|
115
135
|
typePerSchemaCoordinateMap.set(schemaCoordinates, resultTypeNames);
|
|
136
|
+
if (idFields.includes(fieldName) && !idFieldByTypeName.has(typeName)) {
|
|
137
|
+
idFieldByTypeName.set(typeName, fieldName);
|
|
138
|
+
}
|
|
116
139
|
if (cacheControlDirective) {
|
|
117
140
|
const cacheControlAnnotations = getDirective(schema, fieldConfig, 'cacheControl');
|
|
118
141
|
cacheControlAnnotations?.forEach(cacheControl => {
|
|
119
142
|
const ttl = cacheControl.maxAge * 1000;
|
|
120
143
|
if (ttl != null) {
|
|
121
|
-
ttlPerSchemaCoordinate[
|
|
144
|
+
ttlPerSchemaCoordinate[schemaCoordinates] = ttl;
|
|
122
145
|
}
|
|
123
146
|
if (cacheControl.scope) {
|
|
124
|
-
scopePerSchemaCoordinate[
|
|
147
|
+
scopePerSchemaCoordinate[schemaCoordinates] = cacheControl.scope;
|
|
125
148
|
}
|
|
126
149
|
});
|
|
127
150
|
}
|
|
128
151
|
return fieldConfig;
|
|
129
152
|
},
|
|
130
153
|
});
|
|
131
|
-
processedSchemas.add(schema);
|
|
132
154
|
},
|
|
133
155
|
async onExecute(onExecuteParams) {
|
|
134
156
|
const identifier = new Map();
|
|
@@ -148,9 +170,10 @@ export function useResponseCache({ cache = createInMemoryCache(), ttl: globalTtl
|
|
|
148
170
|
}
|
|
149
171
|
const typename = data.__responseCacheTypeName;
|
|
150
172
|
delete data.__responseCacheTypeName;
|
|
173
|
+
const entityId = data.__responseCacheId;
|
|
174
|
+
delete data.__responseCacheId;
|
|
151
175
|
if (!skip) {
|
|
152
|
-
if (ignoredTypesMap.has(typename) ||
|
|
153
|
-
(scopePerSchemaCoordinate[typename] === 'PRIVATE' && !sessionId)) {
|
|
176
|
+
if (ignoredTypesMap.has(typename) || (!sessionId && isPrivate(typename, data))) {
|
|
154
177
|
skip = true;
|
|
155
178
|
return;
|
|
156
179
|
}
|
|
@@ -158,24 +181,16 @@ export function useResponseCache({ cache = createInMemoryCache(), ttl: globalTtl
|
|
|
158
181
|
if (typename in ttlPerType) {
|
|
159
182
|
currentTtl = calculateTtl(ttlPerType[typename], currentTtl);
|
|
160
183
|
}
|
|
184
|
+
if (entityId != null) {
|
|
185
|
+
identifier.set(`${typename}:${entityId}`, { typename, id: entityId });
|
|
186
|
+
}
|
|
161
187
|
for (const fieldName in data) {
|
|
162
188
|
const fieldData = data[fieldName];
|
|
163
|
-
if (
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
else if (idFields.includes(fieldName)) {
|
|
169
|
-
const id = fieldData;
|
|
170
|
-
identifier.set(`${typename}:${id}`, { typename, id });
|
|
171
|
-
}
|
|
172
|
-
else if (fieldData == null ||
|
|
173
|
-
(Array.isArray(fieldData) && fieldData.length === 0)) {
|
|
174
|
-
const inferredTypes = typePerSchemaCoordinateMap.get(`${typename}.${fieldName}`);
|
|
175
|
-
inferredTypes?.forEach(inferredType => {
|
|
176
|
-
identifier.set(inferredType, { typename: inferredType });
|
|
177
|
-
});
|
|
178
|
-
}
|
|
189
|
+
if (fieldData == null || (Array.isArray(fieldData) && fieldData.length === 0)) {
|
|
190
|
+
const inferredTypes = typePerSchemaCoordinateMap.get(`${typename}.${fieldName}`);
|
|
191
|
+
inferredTypes?.forEach(inferredType => {
|
|
192
|
+
identifier.set(inferredType, { typename: inferredType });
|
|
193
|
+
});
|
|
179
194
|
}
|
|
180
195
|
processResult(fieldData);
|
|
181
196
|
}
|