@envelop/response-cache 3.0.0-alpha-6a4e0e2.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;
@@ -286,8 +144,8 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
286
144
  }
287
145
  }
288
146
  if (ttlPerSchemaCoordinate) {
289
- const typeInfo = new graphql.TypeInfo(ctx.args.schema);
290
- 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, {
291
149
  Field(fieldNode) {
292
150
  const parentType = typeInfo.getParentType();
293
151
  if (parentType) {
@@ -303,7 +161,7 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
303
161
  return {
304
162
  onExecuteDone({ result, setResult }) {
305
163
  var _a;
306
- if (core.isAsyncIterable(result)) {
164
+ if ((0, core_1.isAsyncIterable)(result)) {
307
165
  // eslint-disable-next-line no-console
308
166
  console.warn('[useResponseCache] AsyncIterable returned from execute is currently unsupported.');
309
167
  return;
@@ -348,6 +206,7 @@ includeExtensionMetadata = typeof process !== 'undefined' ? process.env['NODE_EN
348
206
  },
349
207
  };
350
208
  }
209
+ exports.useResponseCache = useResponseCache;
351
210
  function isOperationDefinition(node) {
352
211
  return (node === null || node === void 0 ? void 0 : node.kind) === 'OperationDefinition';
353
212
  }
@@ -369,14 +228,14 @@ function runWith(input, callback) {
369
228
  }
370
229
  }
371
230
  function applyResponseCacheLogic(schema, idFieldNames) {
372
- return utils.mapSchema(schema, {
373
- [utils.MapperKind.OBJECT_FIELD](fieldConfig, fieldName, typename) {
231
+ return (0, utils_1.mapSchema)(schema, {
232
+ [utils_1.MapperKind.OBJECT_FIELD](fieldConfig, fieldName, typename) {
374
233
  if (idFieldNames.includes(fieldName)) {
375
234
  return {
376
235
  ...fieldConfig,
377
236
  resolve(src, args, context, info) {
378
237
  var _a;
379
- 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);
380
239
  runWith(result, (id) => {
381
240
  const ctx = context[contextSymbol];
382
241
  if (ctx !== undefined) {
@@ -404,10 +263,3 @@ function applyResponseCacheLogic(schema, idFieldNames) {
404
263
  },
405
264
  });
406
265
  }
407
-
408
- exports.createInMemoryCache = createInMemoryCache;
409
- exports.defaultBuildEntityId = defaultBuildEntityId;
410
- exports.defaultBuildResponseCacheKey = defaultBuildResponseCacheKey;
411
- exports.defaultGetDocumentString = defaultGetDocumentString;
412
- exports.defaultShouldCacheResult = defaultShouldCacheResult;
413
- 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');
@@ -398,5 +255,3 @@ function applyResponseCacheLogic(schema, idFieldNames) {
398
255
  },
399
256
  });
400
257
  }
401
-
402
- 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-6a4e0e2.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,6 +1,6 @@
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
  */
package/index.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export * from './in-memory-cache';
2
- export * from './plugin';
3
- export * from './cache';