@envelop/response-cache 3.0.0-alpha-2869053.0 → 3.0.0-alpha-7c8ceda.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/cache.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hashSHA256 = void 0;
4
+ const webCrypto = globalThis.crypto;
5
+ const sha256Browser = (bytes) => {
6
+ const hash = webCrypto.subtle.digest({ name: 'SHA-256' }, bytes);
7
+ return new Promise((resolve, reject) => {
8
+ Promise.resolve(hash)
9
+ .then(function (result) {
10
+ resolve(new Uint8Array(result));
11
+ })
12
+ .catch(function (error) {
13
+ reject(error);
14
+ });
15
+ });
16
+ };
17
+ let nodeCrypto;
18
+ if (typeof window === 'undefined' && !webCrypto) {
19
+ // Indirect eval'd require/import to guarantee no side-effects in module scope
20
+ // (optimization for minifier)
21
+ try {
22
+ // eslint-disable-next-line no-new-func
23
+ nodeCrypto = Promise.resolve(new Function('require', 'return require("crypto")')(require));
24
+ }
25
+ catch (_error) {
26
+ try {
27
+ // eslint-disable-next-line no-new-func
28
+ nodeCrypto = new Function('return import("crypto")')();
29
+ }
30
+ catch (_error) { }
31
+ }
32
+ }
33
+ const hashSHA256 = async (text) => {
34
+ // Node.js support
35
+ if (nodeCrypto) {
36
+ return nodeCrypto.then(crypto => crypto.createHash('sha256').update(text).digest('hex'));
37
+ }
38
+ if (webCrypto) {
39
+ let buf;
40
+ if (typeof TextEncoder !== 'undefined') {
41
+ buf = new TextEncoder().encode(text);
42
+ }
43
+ else {
44
+ buf = new Uint8Array(text.length);
45
+ for (let i = 0, l = text.length; i < l; i++) {
46
+ // NOTE: We assume that the input GraphQL Query only uses UTF-8 at most
47
+ // since GraphQL mostly consists of ASCII, this is completely fine
48
+ buf[i] = text.charCodeAt(i);
49
+ }
50
+ }
51
+ const out = await sha256Browser(buf);
52
+ let hash = '';
53
+ for (let i = 0, l = out.length; i < l; i++) {
54
+ const hex = out[i].toString(16);
55
+ hash += '00'.slice(0, Math.max(0, 2 - hex.length)) + hex;
56
+ }
57
+ return hash;
58
+ }
59
+ if (process.env.NODE_ENV !== 'production') {
60
+ // eslint-disable-next-line no-console
61
+ console.warn('[@envelop/response-cache]: The Node Crypto and Web Crypto APIs are not available.\n' +
62
+ 'This is an unexpected error. Please report it by filing a GitHub Issue.');
63
+ }
64
+ return Promise.resolve('');
65
+ };
66
+ exports.hashSHA256 = hashSHA256;
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultBuildEntityId = exports.createInMemoryCache = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const lru_cache_1 = tslib_1.__importDefault(require("lru-cache"));
6
+ const createInMemoryCache = (params) => {
7
+ var _a;
8
+ const buildEntityId = (_a = params === null || params === void 0 ? void 0 : params.buildEntityId) !== null && _a !== void 0 ? _a : exports.defaultBuildEntityId;
9
+ const cachedResponses = new lru_cache_1.default({
10
+ max: params === null || params === void 0 ? void 0 : params.max,
11
+ stale: false,
12
+ noDisposeOnSet: true,
13
+ dispose(responseId) {
14
+ purgeResponse(responseId, false);
15
+ },
16
+ });
17
+ const entityToResponseIds = new Map();
18
+ const responseIdToEntityIds = new Map();
19
+ function purgeResponse(responseId, shouldRemove = true) {
20
+ var _a;
21
+ const entityIds = responseIdToEntityIds.get(responseId);
22
+ // get entities related to the response
23
+ if (entityIds !== undefined) {
24
+ for (const entityId of entityIds) {
25
+ // remove the response mapping from the entity
26
+ (_a = entityToResponseIds.get(entityId)) === null || _a === void 0 ? void 0 : _a.delete(responseId);
27
+ }
28
+ // remove all the entity mappings from the response
29
+ responseIdToEntityIds.delete(responseId);
30
+ }
31
+ if (shouldRemove) {
32
+ // remove the response from the cache
33
+ cachedResponses.del(responseId);
34
+ }
35
+ }
36
+ function purgeEntity(entity) {
37
+ const responseIds = entityToResponseIds.get(entity);
38
+ if (responseIds !== undefined) {
39
+ for (const responseId of responseIds) {
40
+ purgeResponse(responseId);
41
+ }
42
+ }
43
+ }
44
+ return {
45
+ set(responseId, result, collectedEntities, ttl) {
46
+ cachedResponses.set(responseId, result, ttl);
47
+ const entityIds = new Set();
48
+ responseIdToEntityIds.set(responseId, entityIds);
49
+ for (const { typename, id } of collectedEntities) {
50
+ let operationIds = entityToResponseIds.get(typename);
51
+ if (operationIds == null) {
52
+ operationIds = new Set();
53
+ entityToResponseIds.set(typename, operationIds);
54
+ }
55
+ // typename => operation
56
+ operationIds.add(responseId);
57
+ // operation => typename
58
+ entityIds.add(typename);
59
+ if (id !== undefined) {
60
+ const entityId = buildEntityId(typename, id);
61
+ let responseIds = entityToResponseIds.get(entityId);
62
+ if (responseIds == null) {
63
+ responseIds = new Set();
64
+ entityToResponseIds.set(entityId, responseIds);
65
+ }
66
+ // typename:id => operation
67
+ responseIds.add(responseId);
68
+ // operation => typename:id
69
+ entityIds.add(entityId);
70
+ }
71
+ }
72
+ },
73
+ get(responseId) {
74
+ var _a;
75
+ return (_a = cachedResponses.get(responseId)) !== null && _a !== void 0 ? _a : null;
76
+ },
77
+ invalidate(entitiesToRemove) {
78
+ for (const { typename, id } of entitiesToRemove) {
79
+ purgeEntity(id != null ? buildEntityId(typename, id) : typename);
80
+ }
81
+ },
82
+ };
83
+ };
84
+ exports.createInMemoryCache = createInMemoryCache;
85
+ const defaultBuildEntityId = (typename, id) => `${typename}:${id}`;
86
+ exports.defaultBuildEntityId = defaultBuildEntityId;
package/cjs/index.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./in-memory-cache.js"), exports);
5
+ tslib_1.__exportStar(require("./plugin.js"), exports);
6
+ tslib_1.__exportStar(require("./cache.js"), exports);
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -1,158 +1,13 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
-
7
- const LRU = _interopDefault(require('lru-cache'));
8
- const core = require('@envelop/core');
9
- const utils = require('@graphql-tools/utils');
10
- const graphql = require('graphql');
11
- const jsonStableStringify = _interopDefault(require('fast-json-stable-stringify'));
12
-
13
- const createInMemoryCache = (params) => {
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,
18
- stale: false,
19
- noDisposeOnSet: true,
20
- dispose(responseId) {
21
- purgeResponse(responseId, false);
22
- },
23
- });
24
- const entityToResponseIds = new Map();
25
- const responseIdToEntityIds = new Map();
26
- function purgeResponse(responseId, shouldRemove = true) {
27
- var _a;
28
- const entityIds = responseIdToEntityIds.get(responseId);
29
- // get entities related to the response
30
- if (entityIds !== undefined) {
31
- for (const entityId of entityIds) {
32
- // remove the response mapping from the entity
33
- (_a = entityToResponseIds.get(entityId)) === null || _a === void 0 ? void 0 : _a.delete(responseId);
34
- }
35
- // remove all the entity mappings from the response
36
- responseIdToEntityIds.delete(responseId);
37
- }
38
- if (shouldRemove) {
39
- // remove the response from the cache
40
- cachedResponses.del(responseId);
41
- }
42
- }
43
- function purgeEntity(entity) {
44
- const responseIds = entityToResponseIds.get(entity);
45
- if (responseIds !== undefined) {
46
- for (const responseId of responseIds) {
47
- purgeResponse(responseId);
48
- }
49
- }
50
- }
51
- return {
52
- set(responseId, result, collectedEntities, ttl) {
53
- cachedResponses.set(responseId, result, ttl);
54
- const entityIds = new Set();
55
- responseIdToEntityIds.set(responseId, entityIds);
56
- for (const { typename, id } of collectedEntities) {
57
- let operationIds = entityToResponseIds.get(typename);
58
- if (operationIds == null) {
59
- operationIds = new Set();
60
- entityToResponseIds.set(typename, operationIds);
61
- }
62
- // typename => operation
63
- operationIds.add(responseId);
64
- // operation => typename
65
- entityIds.add(typename);
66
- if (id !== undefined) {
67
- const entityId = buildEntityId(typename, id);
68
- let responseIds = entityToResponseIds.get(entityId);
69
- if (responseIds == null) {
70
- responseIds = new Set();
71
- entityToResponseIds.set(entityId, responseIds);
72
- }
73
- // typename:id => operation
74
- responseIds.add(responseId);
75
- // operation => typename:id
76
- entityIds.add(entityId);
77
- }
78
- }
79
- },
80
- get(responseId) {
81
- var _a;
82
- return (_a = cachedResponses.get(responseId)) !== null && _a !== void 0 ? _a : null;
83
- },
84
- invalidate(entitiesToRemove) {
85
- for (const { typename, id } of entitiesToRemove) {
86
- purgeEntity(id != null ? buildEntityId(typename, id) : typename);
87
- }
88
- },
89
- };
90
- };
91
- const defaultBuildEntityId = (typename, id) => `${typename}:${id}`;
92
-
93
- const webCrypto = globalThis.crypto;
94
- const sha256Browser = (bytes) => {
95
- const hash = webCrypto.subtle.digest({ name: 'SHA-256' }, bytes);
96
- return new Promise((resolve, reject) => {
97
- Promise.resolve(hash)
98
- .then(function (result) {
99
- resolve(new Uint8Array(result));
100
- })
101
- .catch(function (error) {
102
- reject(error);
103
- });
104
- });
105
- };
106
- let nodeCrypto;
107
- if (typeof window === 'undefined' && !webCrypto) {
108
- // Indirect eval'd require/import to guarantee no side-effects in module scope
109
- // (optimization for minifier)
110
- try {
111
- // eslint-disable-next-line no-new-func
112
- nodeCrypto = Promise.resolve(new Function('require', 'return require("crypto")')(require));
113
- }
114
- catch (_error) {
115
- try {
116
- // eslint-disable-next-line no-new-func
117
- nodeCrypto = new Function('return import("crypto")')();
118
- }
119
- catch (_error) { }
120
- }
121
- }
122
- const hashSHA256 = async (text) => {
123
- // Node.js support
124
- if (nodeCrypto) {
125
- return nodeCrypto.then(crypto => crypto.createHash('sha256').update(text).digest('hex'));
126
- }
127
- if (webCrypto) {
128
- let buf;
129
- if (typeof TextEncoder !== 'undefined') {
130
- buf = new TextEncoder().encode(text);
131
- }
132
- else {
133
- buf = new Uint8Array(text.length);
134
- for (let i = 0, l = text.length; i < l; i++) {
135
- // NOTE: We assume that the input GraphQL Query only uses UTF-8 at most
136
- // since GraphQL mostly consists of ASCII, this is completely fine
137
- buf[i] = text.charCodeAt(i);
138
- }
139
- }
140
- const out = await sha256Browser(buf);
141
- let hash = '';
142
- for (let i = 0, l = out.length; i < l; i++) {
143
- const hex = out[i].toString(16);
144
- hash += '00'.slice(0, Math.max(0, 2 - hex.length)) + hex;
145
- }
146
- return hash;
147
- }
148
- if (process.env.NODE_ENV !== 'production') {
149
- // eslint-disable-next-line no-console
150
- console.warn('[@envelop/response-cache]: The Node Crypto and Web Crypto APIs are not available.\n' +
151
- 'This is an unexpected error. Please report it by filing a GitHub Issue.');
152
- }
153
- return Promise.resolve('');
154
- };
155
-
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useResponseCache = exports.defaultGetDocumentString = exports.defaultShouldCacheResult = exports.defaultBuildResponseCacheKey = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const core_1 = require("@envelop/core");
6
+ const utils_1 = require("@graphql-tools/utils");
7
+ const graphql_1 = require("graphql");
8
+ const fast_json_stable_stringify_1 = tslib_1.__importDefault(require("fast-json-stable-stringify"));
9
+ const in_memory_cache_js_1 = require("./in-memory-cache.js");
10
+ const hashSHA256_js_1 = require("./hashSHA256.js");
156
11
  const contextSymbol = Symbol('responseCache');
157
12
  /**
158
13
  * Default function used for building the response cache key.
@@ -160,13 +15,14 @@ const contextSymbol = Symbol('responseCache');
160
15
  */
161
16
  const defaultBuildResponseCacheKey = params => {
162
17
  var _a, _b, _c;
163
- return hashSHA256([
18
+ return (0, hashSHA256_js_1.hashSHA256)([
164
19
  params.documentString,
165
20
  (_a = params.operationName) !== null && _a !== void 0 ? _a : '',
166
- jsonStableStringify((_b = params.variableValues) !== null && _b !== void 0 ? _b : {}),
21
+ (0, fast_json_stable_stringify_1.default)((_b = params.variableValues) !== null && _b !== void 0 ? _b : {}),
167
22
  (_c = params.sessionId) !== null && _c !== void 0 ? _c : '',
168
23
  ].join('|'));
169
24
  };
25
+ exports.defaultBuildResponseCacheKey = defaultBuildResponseCacheKey;
170
26
  /**
171
27
  * Default function used to check if the result should be cached.
172
28
  *
@@ -183,16 +39,18 @@ const defaultShouldCacheResult = (params) => {
183
39
  }
184
40
  return true;
185
41
  };
42
+ exports.defaultShouldCacheResult = defaultShouldCacheResult;
186
43
  const documentStringByDocument = new WeakMap();
187
44
  function defaultGetDocumentString(executionArgs) {
188
45
  let documentString = documentStringByDocument.get(executionArgs.document);
189
46
  if (!documentString) {
190
- documentString = graphql.print(executionArgs.document);
47
+ documentString = (0, graphql_1.print)(executionArgs.document);
191
48
  documentStringByDocument.set(executionArgs.document, documentString);
192
49
  }
193
50
  return documentString;
194
51
  }
195
- function useResponseCache({ cache = createInMemoryCache(), ttl: globalTtl = Infinity, session = () => null, enabled, ignoredTypes = [], ttlPerType = {}, ttlPerSchemaCoordinate = {}, idFields = ['id'], invalidateViaMutation = true, buildResponseCacheKey = defaultBuildResponseCacheKey, getDocumentString = defaultGetDocumentString, shouldCacheResult = defaultShouldCacheResult,
52
+ exports.defaultGetDocumentString = defaultGetDocumentString;
53
+ function useResponseCache({ cache = (0, in_memory_cache_js_1.createInMemoryCache)(), ttl: globalTtl = Infinity, session = () => null, enabled, ignoredTypes = [], ttlPerType = {}, ttlPerSchemaCoordinate = {}, idFields = ['id'], invalidateViaMutation = true, buildResponseCacheKey = exports.defaultBuildResponseCacheKey, getDocumentString = defaultGetDocumentString, shouldCacheResult = exports.defaultShouldCacheResult,
196
54
  // eslint-disable-next-line dot-notation
197
55
  includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_ENV'] === 'development' : false, } = {}) {
198
56
  const appliedTransform = Symbol('responseCache.appliedTransform');
@@ -241,7 +99,7 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
241
99
  }
242
100
  return {
243
101
  onExecuteDone({ result, setResult }) {
244
- if (core.isAsyncIterable(result)) {
102
+ if ((0, core_1.isAsyncIterable)(result)) {
245
103
  // eslint-disable-next-line no-console
246
104
  console.warn('[useResponseCache] AsyncIterable returned from execute is currently unsupported.');
247
105
  return;
@@ -261,12 +119,10 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
261
119
  },
262
120
  };
263
121
  }
264
- const documentString = getDocumentString(ctx.args);
265
122
  const operationId = await buildResponseCacheKey({
266
- documentString,
267
- variableValues: ctx.args.variableValues,
268
- operationName: ctx.args.operationName,
123
+ documentString: getDocumentString(ctx.args),
269
124
  sessionId: session(ctx.args.contextValue),
125
+ ...ctx.args,
270
126
  });
271
127
  if (((_a = enabled === null || enabled === void 0 ? void 0 : enabled(ctx.args.contextValue)) !== null && _a !== void 0 ? _a : true) === true) {
272
128
  const cachedResponse = await cache.get(operationId);
@@ -288,8 +144,8 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
288
144
  }
289
145
  }
290
146
  if (ttlPerSchemaCoordinate) {
291
- const typeInfo = new graphql.TypeInfo(ctx.args.schema);
292
- graphql.visit(ctx.args.document, graphql.visitWithTypeInfo(typeInfo, {
147
+ const typeInfo = new graphql_1.TypeInfo(ctx.args.schema);
148
+ (0, graphql_1.visit)(ctx.args.document, (0, graphql_1.visitWithTypeInfo)(typeInfo, {
293
149
  Field(fieldNode) {
294
150
  const parentType = typeInfo.getParentType();
295
151
  if (parentType) {
@@ -305,7 +161,7 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
305
161
  return {
306
162
  onExecuteDone({ result, setResult }) {
307
163
  var _a;
308
- if (core.isAsyncIterable(result)) {
164
+ if ((0, core_1.isAsyncIterable)(result)) {
309
165
  // eslint-disable-next-line no-console
310
166
  console.warn('[useResponseCache] AsyncIterable returned from execute is currently unsupported.');
311
167
  return;
@@ -350,6 +206,7 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
350
206
  },
351
207
  };
352
208
  }
209
+ exports.useResponseCache = useResponseCache;
353
210
  function isOperationDefinition(node) {
354
211
  return (node === null || node === void 0 ? void 0 : node.kind) === 'OperationDefinition';
355
212
  }
@@ -371,14 +228,14 @@ function runWith(input, callback) {
371
228
  }
372
229
  }
373
230
  function applyResponseCacheLogic(schema, idFieldNames) {
374
- return utils.mapSchema(schema, {
375
- [utils.MapperKind.OBJECT_FIELD](fieldConfig, fieldName, typename) {
231
+ return (0, utils_1.mapSchema)(schema, {
232
+ [utils_1.MapperKind.OBJECT_FIELD](fieldConfig, fieldName, typename) {
376
233
  if (idFieldNames.includes(fieldName)) {
377
234
  return {
378
235
  ...fieldConfig,
379
236
  resolve(src, args, context, info) {
380
237
  var _a;
381
- const result = ((_a = fieldConfig.resolve) !== null && _a !== void 0 ? _a : graphql.defaultFieldResolver)(src, args, context, info);
238
+ const result = ((_a = fieldConfig.resolve) !== null && _a !== void 0 ? _a : graphql_1.defaultFieldResolver)(src, args, context, info);
382
239
  runWith(result, (id) => {
383
240
  const ctx = context[contextSymbol];
384
241
  if (ctx !== undefined) {
@@ -406,10 +263,3 @@ function applyResponseCacheLogic(schema, idFieldNames) {
406
263
  },
407
264
  });
408
265
  }
409
-
410
- exports.createInMemoryCache = createInMemoryCache;
411
- exports.defaultBuildEntityId = defaultBuildEntityId;
412
- exports.defaultBuildResponseCacheKey = defaultBuildResponseCacheKey;
413
- exports.defaultGetDocumentString = defaultGetDocumentString;
414
- exports.defaultShouldCacheResult = defaultShouldCacheResult;
415
- exports.useResponseCache = useResponseCache;
package/esm/cache.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,62 @@
1
+ const webCrypto = globalThis.crypto;
2
+ const sha256Browser = (bytes) => {
3
+ const hash = webCrypto.subtle.digest({ name: 'SHA-256' }, bytes);
4
+ return new Promise((resolve, reject) => {
5
+ Promise.resolve(hash)
6
+ .then(function (result) {
7
+ resolve(new Uint8Array(result));
8
+ })
9
+ .catch(function (error) {
10
+ reject(error);
11
+ });
12
+ });
13
+ };
14
+ let nodeCrypto;
15
+ if (typeof window === 'undefined' && !webCrypto) {
16
+ // Indirect eval'd require/import to guarantee no side-effects in module scope
17
+ // (optimization for minifier)
18
+ try {
19
+ // eslint-disable-next-line no-new-func
20
+ nodeCrypto = Promise.resolve(new Function('require', 'return require("crypto")')(require));
21
+ }
22
+ catch (_error) {
23
+ try {
24
+ // eslint-disable-next-line no-new-func
25
+ nodeCrypto = new Function('return import("crypto")')();
26
+ }
27
+ catch (_error) { }
28
+ }
29
+ }
30
+ export const hashSHA256 = async (text) => {
31
+ // Node.js support
32
+ if (nodeCrypto) {
33
+ return nodeCrypto.then(crypto => crypto.createHash('sha256').update(text).digest('hex'));
34
+ }
35
+ if (webCrypto) {
36
+ let buf;
37
+ if (typeof TextEncoder !== 'undefined') {
38
+ buf = new TextEncoder().encode(text);
39
+ }
40
+ else {
41
+ buf = new Uint8Array(text.length);
42
+ for (let i = 0, l = text.length; i < l; i++) {
43
+ // NOTE: We assume that the input GraphQL Query only uses UTF-8 at most
44
+ // since GraphQL mostly consists of ASCII, this is completely fine
45
+ buf[i] = text.charCodeAt(i);
46
+ }
47
+ }
48
+ const out = await sha256Browser(buf);
49
+ let hash = '';
50
+ for (let i = 0, l = out.length; i < l; i++) {
51
+ const hex = out[i].toString(16);
52
+ hash += '00'.slice(0, Math.max(0, 2 - hex.length)) + hex;
53
+ }
54
+ return hash;
55
+ }
56
+ if (process.env.NODE_ENV !== 'production') {
57
+ // eslint-disable-next-line no-console
58
+ console.warn('[@envelop/response-cache]: The Node Crypto and Web Crypto APIs are not available.\n' +
59
+ 'This is an unexpected error. Please report it by filing a GitHub Issue.');
60
+ }
61
+ return Promise.resolve('');
62
+ };
@@ -0,0 +1,80 @@
1
+ import LRU from 'lru-cache';
2
+ export const createInMemoryCache = (params) => {
3
+ var _a;
4
+ const buildEntityId = (_a = params === null || params === void 0 ? void 0 : params.buildEntityId) !== null && _a !== void 0 ? _a : defaultBuildEntityId;
5
+ const cachedResponses = new LRU({
6
+ max: params === null || params === void 0 ? void 0 : params.max,
7
+ stale: false,
8
+ noDisposeOnSet: true,
9
+ dispose(responseId) {
10
+ purgeResponse(responseId, false);
11
+ },
12
+ });
13
+ const entityToResponseIds = new Map();
14
+ const responseIdToEntityIds = new Map();
15
+ function purgeResponse(responseId, shouldRemove = true) {
16
+ var _a;
17
+ const entityIds = responseIdToEntityIds.get(responseId);
18
+ // get entities related to the response
19
+ if (entityIds !== undefined) {
20
+ for (const entityId of entityIds) {
21
+ // remove the response mapping from the entity
22
+ (_a = entityToResponseIds.get(entityId)) === null || _a === void 0 ? void 0 : _a.delete(responseId);
23
+ }
24
+ // remove all the entity mappings from the response
25
+ responseIdToEntityIds.delete(responseId);
26
+ }
27
+ if (shouldRemove) {
28
+ // remove the response from the cache
29
+ cachedResponses.del(responseId);
30
+ }
31
+ }
32
+ function purgeEntity(entity) {
33
+ const responseIds = entityToResponseIds.get(entity);
34
+ if (responseIds !== undefined) {
35
+ for (const responseId of responseIds) {
36
+ purgeResponse(responseId);
37
+ }
38
+ }
39
+ }
40
+ return {
41
+ set(responseId, result, collectedEntities, ttl) {
42
+ cachedResponses.set(responseId, result, ttl);
43
+ const entityIds = new Set();
44
+ responseIdToEntityIds.set(responseId, entityIds);
45
+ for (const { typename, id } of collectedEntities) {
46
+ let operationIds = entityToResponseIds.get(typename);
47
+ if (operationIds == null) {
48
+ operationIds = new Set();
49
+ entityToResponseIds.set(typename, operationIds);
50
+ }
51
+ // typename => operation
52
+ operationIds.add(responseId);
53
+ // operation => typename
54
+ entityIds.add(typename);
55
+ if (id !== undefined) {
56
+ const entityId = buildEntityId(typename, id);
57
+ let responseIds = entityToResponseIds.get(entityId);
58
+ if (responseIds == null) {
59
+ responseIds = new Set();
60
+ entityToResponseIds.set(entityId, responseIds);
61
+ }
62
+ // typename:id => operation
63
+ responseIds.add(responseId);
64
+ // operation => typename:id
65
+ entityIds.add(entityId);
66
+ }
67
+ }
68
+ },
69
+ get(responseId) {
70
+ var _a;
71
+ return (_a = cachedResponses.get(responseId)) !== null && _a !== void 0 ? _a : null;
72
+ },
73
+ invalidate(entitiesToRemove) {
74
+ for (const { typename, id } of entitiesToRemove) {
75
+ purgeEntity(id != null ? buildEntityId(typename, id) : typename);
76
+ }
77
+ },
78
+ };
79
+ };
80
+ export const defaultBuildEntityId = (typename, id) => `${typename}:${id}`;
package/esm/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './in-memory-cache.js';
2
+ export * from './plugin.js';
3
+ export * from './cache.js';
@@ -1,158 +1,15 @@
1
- import LRU from 'lru-cache';
2
1
  import { isAsyncIterable } from '@envelop/core';
3
- import { mapSchema, MapperKind } from '@graphql-tools/utils';
4
- import { print, defaultFieldResolver, TypeInfo, visit, visitWithTypeInfo } from 'graphql';
2
+ import { MapperKind, mapSchema } from '@graphql-tools/utils';
3
+ import { visit, TypeInfo, visitWithTypeInfo, defaultFieldResolver, print, } from 'graphql';
5
4
  import jsonStableStringify from 'fast-json-stable-stringify';
6
-
7
- const createInMemoryCache = (params) => {
8
- var _a;
9
- const buildEntityId = (_a = params === null || params === void 0 ? void 0 : params.buildEntityId) !== null && _a !== void 0 ? _a : defaultBuildEntityId;
10
- const cachedResponses = new LRU({
11
- max: params === null || params === void 0 ? void 0 : params.max,
12
- stale: false,
13
- noDisposeOnSet: true,
14
- dispose(responseId) {
15
- purgeResponse(responseId, false);
16
- },
17
- });
18
- const entityToResponseIds = new Map();
19
- const responseIdToEntityIds = new Map();
20
- function purgeResponse(responseId, shouldRemove = true) {
21
- var _a;
22
- const entityIds = responseIdToEntityIds.get(responseId);
23
- // get entities related to the response
24
- if (entityIds !== undefined) {
25
- for (const entityId of entityIds) {
26
- // remove the response mapping from the entity
27
- (_a = entityToResponseIds.get(entityId)) === null || _a === void 0 ? void 0 : _a.delete(responseId);
28
- }
29
- // remove all the entity mappings from the response
30
- responseIdToEntityIds.delete(responseId);
31
- }
32
- if (shouldRemove) {
33
- // remove the response from the cache
34
- cachedResponses.del(responseId);
35
- }
36
- }
37
- function purgeEntity(entity) {
38
- const responseIds = entityToResponseIds.get(entity);
39
- if (responseIds !== undefined) {
40
- for (const responseId of responseIds) {
41
- purgeResponse(responseId);
42
- }
43
- }
44
- }
45
- return {
46
- set(responseId, result, collectedEntities, ttl) {
47
- cachedResponses.set(responseId, result, ttl);
48
- const entityIds = new Set();
49
- responseIdToEntityIds.set(responseId, entityIds);
50
- for (const { typename, id } of collectedEntities) {
51
- let operationIds = entityToResponseIds.get(typename);
52
- if (operationIds == null) {
53
- operationIds = new Set();
54
- entityToResponseIds.set(typename, operationIds);
55
- }
56
- // typename => operation
57
- operationIds.add(responseId);
58
- // operation => typename
59
- entityIds.add(typename);
60
- if (id !== undefined) {
61
- const entityId = buildEntityId(typename, id);
62
- let responseIds = entityToResponseIds.get(entityId);
63
- if (responseIds == null) {
64
- responseIds = new Set();
65
- entityToResponseIds.set(entityId, responseIds);
66
- }
67
- // typename:id => operation
68
- responseIds.add(responseId);
69
- // operation => typename:id
70
- entityIds.add(entityId);
71
- }
72
- }
73
- },
74
- get(responseId) {
75
- var _a;
76
- return (_a = cachedResponses.get(responseId)) !== null && _a !== void 0 ? _a : null;
77
- },
78
- invalidate(entitiesToRemove) {
79
- for (const { typename, id } of entitiesToRemove) {
80
- purgeEntity(id != null ? buildEntityId(typename, id) : typename);
81
- }
82
- },
83
- };
84
- };
85
- const defaultBuildEntityId = (typename, id) => `${typename}:${id}`;
86
-
87
- const webCrypto = globalThis.crypto;
88
- const sha256Browser = (bytes) => {
89
- const hash = webCrypto.subtle.digest({ name: 'SHA-256' }, bytes);
90
- return new Promise((resolve, reject) => {
91
- Promise.resolve(hash)
92
- .then(function (result) {
93
- resolve(new Uint8Array(result));
94
- })
95
- .catch(function (error) {
96
- reject(error);
97
- });
98
- });
99
- };
100
- let nodeCrypto;
101
- if (typeof window === 'undefined' && !webCrypto) {
102
- // Indirect eval'd require/import to guarantee no side-effects in module scope
103
- // (optimization for minifier)
104
- try {
105
- // eslint-disable-next-line no-new-func
106
- nodeCrypto = Promise.resolve(new Function('require', 'return require("crypto")')(require));
107
- }
108
- catch (_error) {
109
- try {
110
- // eslint-disable-next-line no-new-func
111
- nodeCrypto = new Function('return import("crypto")')();
112
- }
113
- catch (_error) { }
114
- }
115
- }
116
- const hashSHA256 = async (text) => {
117
- // Node.js support
118
- if (nodeCrypto) {
119
- return nodeCrypto.then(crypto => crypto.createHash('sha256').update(text).digest('hex'));
120
- }
121
- if (webCrypto) {
122
- let buf;
123
- if (typeof TextEncoder !== 'undefined') {
124
- buf = new TextEncoder().encode(text);
125
- }
126
- else {
127
- buf = new Uint8Array(text.length);
128
- for (let i = 0, l = text.length; i < l; i++) {
129
- // NOTE: We assume that the input GraphQL Query only uses UTF-8 at most
130
- // since GraphQL mostly consists of ASCII, this is completely fine
131
- buf[i] = text.charCodeAt(i);
132
- }
133
- }
134
- const out = await sha256Browser(buf);
135
- let hash = '';
136
- for (let i = 0, l = out.length; i < l; i++) {
137
- const hex = out[i].toString(16);
138
- hash += '00'.slice(0, Math.max(0, 2 - hex.length)) + hex;
139
- }
140
- return hash;
141
- }
142
- if (process.env.NODE_ENV !== 'production') {
143
- // eslint-disable-next-line no-console
144
- console.warn('[@envelop/response-cache]: The Node Crypto and Web Crypto APIs are not available.\n' +
145
- 'This is an unexpected error. Please report it by filing a GitHub Issue.');
146
- }
147
- return Promise.resolve('');
148
- };
149
-
5
+ import { createInMemoryCache } from './in-memory-cache.js';
6
+ import { hashSHA256 } from './hashSHA256.js';
150
7
  const contextSymbol = Symbol('responseCache');
151
8
  /**
152
9
  * Default function used for building the response cache key.
153
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.
154
11
  */
155
- const defaultBuildResponseCacheKey = params => {
12
+ export const defaultBuildResponseCacheKey = params => {
156
13
  var _a, _b, _c;
157
14
  return hashSHA256([
158
15
  params.documentString,
@@ -169,7 +26,7 @@ const defaultBuildResponseCacheKey = params => {
169
26
  *
170
27
  * By default, results with errors (unexpected, EnvelopError, or GraphQLError) are not cached.
171
28
  */
172
- const defaultShouldCacheResult = (params) => {
29
+ export const defaultShouldCacheResult = (params) => {
173
30
  if (params.result.errors) {
174
31
  // eslint-disable-next-line no-console
175
32
  console.warn('[useResponseCache] Failed to cache due to errors');
@@ -178,7 +35,7 @@ const defaultShouldCacheResult = (params) => {
178
35
  return true;
179
36
  };
180
37
  const documentStringByDocument = new WeakMap();
181
- function defaultGetDocumentString(executionArgs) {
38
+ export function defaultGetDocumentString(executionArgs) {
182
39
  let documentString = documentStringByDocument.get(executionArgs.document);
183
40
  if (!documentString) {
184
41
  documentString = print(executionArgs.document);
@@ -186,7 +43,7 @@ function defaultGetDocumentString(executionArgs) {
186
43
  }
187
44
  return documentString;
188
45
  }
189
- function useResponseCache({ cache = createInMemoryCache(), ttl: globalTtl = Infinity, session = () => null, enabled, ignoredTypes = [], ttlPerType = {}, ttlPerSchemaCoordinate = {}, idFields = ['id'], invalidateViaMutation = true, buildResponseCacheKey = defaultBuildResponseCacheKey, getDocumentString = defaultGetDocumentString, shouldCacheResult = defaultShouldCacheResult,
46
+ export function useResponseCache({ cache = createInMemoryCache(), ttl: globalTtl = Infinity, session = () => null, enabled, ignoredTypes = [], ttlPerType = {}, ttlPerSchemaCoordinate = {}, idFields = ['id'], invalidateViaMutation = true, buildResponseCacheKey = defaultBuildResponseCacheKey, getDocumentString = defaultGetDocumentString, shouldCacheResult = defaultShouldCacheResult,
190
47
  // eslint-disable-next-line dot-notation
191
48
  includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_ENV'] === 'development' : false, } = {}) {
192
49
  const appliedTransform = Symbol('responseCache.appliedTransform');
@@ -255,12 +112,10 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
255
112
  },
256
113
  };
257
114
  }
258
- const documentString = getDocumentString(ctx.args);
259
115
  const operationId = await buildResponseCacheKey({
260
- documentString,
261
- variableValues: ctx.args.variableValues,
262
- operationName: ctx.args.operationName,
116
+ documentString: getDocumentString(ctx.args),
263
117
  sessionId: session(ctx.args.contextValue),
118
+ ...ctx.args,
264
119
  });
265
120
  if (((_a = enabled === null || enabled === void 0 ? void 0 : enabled(ctx.args.contextValue)) !== null && _a !== void 0 ? _a : true) === true) {
266
121
  const cachedResponse = await cache.get(operationId);
@@ -400,5 +255,3 @@ function applyResponseCacheLogic(schema, idFieldNames) {
400
255
  },
401
256
  });
402
257
  }
403
-
404
- export { createInMemoryCache, defaultBuildEntityId, defaultBuildResponseCacheKey, defaultGetDocumentString, defaultShouldCacheResult, useResponseCache };
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@envelop/response-cache",
3
- "version": "3.0.0-alpha-2869053.0",
3
+ "version": "3.0.0-alpha-7c8ceda.0",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
- "@envelop/core": "^2.3.3",
6
+ "@envelop/core": "^2.4.0",
7
7
  "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"
8
8
  },
9
9
  "dependencies": {
10
- "@graphql-tools/utils": "^8.6.1",
11
- "fast-json-stable-stringify": "^2.1.0",
12
- "lru-cache": "^6.0.0"
10
+ "@graphql-tools/utils": "^8.8.0",
11
+ "lru-cache": "^6.0.0",
12
+ "fast-json-stable-stringify": "^2.1.0"
13
13
  },
14
14
  "repository": {
15
15
  "type": "git",
@@ -18,21 +18,42 @@
18
18
  },
19
19
  "author": "Kamil Kisiela <kamilkisiela@gmail.com>",
20
20
  "license": "MIT",
21
- "main": "index.js",
22
- "module": "index.mjs",
23
- "typings": "index.d.ts",
21
+ "main": "cjs/index.js",
22
+ "module": "esm/index.js",
23
+ "typings": "typings/index.d.ts",
24
24
  "typescript": {
25
- "definition": "index.d.ts"
25
+ "definition": "typings/index.d.ts"
26
26
  },
27
+ "type": "module",
27
28
  "exports": {
28
29
  ".": {
29
- "require": "./index.js",
30
- "import": "./index.mjs"
30
+ "require": {
31
+ "types": "./typings/index.d.ts",
32
+ "default": "./cjs/index.js"
33
+ },
34
+ "import": {
35
+ "types": "./typings/index.d.ts",
36
+ "default": "./esm/index.js"
37
+ },
38
+ "default": {
39
+ "types": "./typings/index.d.ts",
40
+ "default": "./esm/index.js"
41
+ }
31
42
  },
32
43
  "./*": {
33
- "require": "./*.js",
34
- "import": "./*.mjs"
44
+ "require": {
45
+ "types": "./typings/*.d.ts",
46
+ "default": "./cjs/*.js"
47
+ },
48
+ "import": {
49
+ "types": "./typings/*.d.ts",
50
+ "default": "./esm/*.js"
51
+ },
52
+ "default": {
53
+ "types": "./typings/*.d.ts",
54
+ "default": "./esm/*.js"
55
+ }
35
56
  },
36
57
  "./package.json": "./package.json"
37
58
  }
38
- }
59
+ }
File without changes
File without changes
@@ -1,4 +1,4 @@
1
- import type { Cache } from './cache';
1
+ import type { Cache } from './cache.js';
2
2
  export declare type BuildEntityId = (typename: string, id: number | string) => string;
3
3
  export declare type InMemoryCacheParameter = {
4
4
  /**
@@ -11,5 +11,5 @@ export declare type InMemoryCacheParameter = {
11
11
  */
12
12
  buildEntityId?: BuildEntityId;
13
13
  };
14
- export declare const createInMemoryCache: (params?: InMemoryCacheParameter | undefined) => Cache;
14
+ export declare const createInMemoryCache: (params?: InMemoryCacheParameter) => Cache;
15
15
  export declare const defaultBuildEntityId: BuildEntityId;
@@ -0,0 +1,3 @@
1
+ export * from './in-memory-cache.js';
2
+ export * from './plugin.js';
3
+ export * from './cache.js';
@@ -1,19 +1,15 @@
1
1
  import { Plugin, Maybe } from '@envelop/core';
2
2
  import { ExecutionArgs, ExecutionResult } from 'graphql';
3
- import type { Cache } from './cache';
3
+ import type { Cache } from './cache.js';
4
4
  /**
5
5
  * Function for building the response cache key based on the input parameters
6
6
  */
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>;
12
+ } & ExecutionArgs) => Promise<string>;
17
13
  export declare type GetDocumentStringFunction = (executionArgs: ExecutionArgs) => string;
18
14
  export declare type ShouldCacheResultFunction = (params: {
19
15
  result: ExecutionResult;
package/index.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export * from './in-memory-cache';
2
- export * from './plugin';
3
- export * from './cache';