@naturalcycles/js-lib 14.84.1 → 14.86.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.
Files changed (37) hide show
  1. package/dist/decorators/asyncMemo.decorator.d.ts +35 -9
  2. package/dist/decorators/asyncMemo.decorator.js +39 -34
  3. package/dist/decorators/decorator.util.d.ts +1 -1
  4. package/dist/decorators/decorator.util.js +2 -2
  5. package/dist/decorators/logMethod.decorator.d.ts +6 -4
  6. package/dist/decorators/logMethod.decorator.js +3 -3
  7. package/dist/decorators/memo.decorator.d.ts +29 -29
  8. package/dist/decorators/memo.decorator.js +42 -53
  9. package/dist/decorators/memo.util.d.ts +6 -6
  10. package/dist/decorators/memoFn.d.ts +5 -0
  11. package/dist/decorators/memoFn.js +32 -37
  12. package/dist/decorators/memoFnAsync.d.ts +10 -0
  13. package/dist/decorators/memoFnAsync.js +69 -0
  14. package/dist/decorators/memoSimple.decorator.d.ts +1 -1
  15. package/dist/decorators/memoSimple.decorator.js +3 -3
  16. package/dist/index.d.ts +3 -2
  17. package/dist/index.js +1 -0
  18. package/dist/types.d.ts +4 -0
  19. package/dist-esm/decorators/asyncMemo.decorator.js +40 -47
  20. package/dist-esm/decorators/decorator.util.js +2 -2
  21. package/dist-esm/decorators/logMethod.decorator.js +3 -3
  22. package/dist-esm/decorators/memo.decorator.js +41 -53
  23. package/dist-esm/decorators/memoFn.js +32 -37
  24. package/dist-esm/decorators/memoFnAsync.js +65 -0
  25. package/dist-esm/decorators/memoSimple.decorator.js +3 -3
  26. package/dist-esm/index.js +1 -0
  27. package/package.json +1 -1
  28. package/src/decorators/asyncMemo.decorator.ts +88 -61
  29. package/src/decorators/decorator.util.ts +2 -2
  30. package/src/decorators/logMethod.decorator.ts +16 -7
  31. package/src/decorators/memo.decorator.ts +66 -102
  32. package/src/decorators/memo.util.ts +7 -7
  33. package/src/decorators/memoFn.ts +33 -51
  34. package/src/decorators/memoFnAsync.ts +91 -0
  35. package/src/decorators/memoSimple.decorator.ts +4 -4
  36. package/src/index.ts +3 -0
  37. package/src/types.ts +5 -0
@@ -34,7 +34,7 @@ export const memoSimple = (opt = {}) => (target, key, descriptor) => {
34
34
  }
35
35
  */
36
36
  const cache = new MapMemoCache();
37
- const { logHit, logMiss, noLogArgs, logger = console } = opt;
37
+ const { logHit, logMiss, logArgs = true, logger = console } = opt;
38
38
  const keyStr = String(key);
39
39
  const methodSignature = _getTargetMethodSignature(target, keyStr);
40
40
  descriptor.value = function (...args) {
@@ -42,14 +42,14 @@ export const memoSimple = (opt = {}) => (target, key, descriptor) => {
42
42
  const cacheKey = jsonMemoSerializer(args);
43
43
  if (cache.has(cacheKey)) {
44
44
  if (logHit) {
45
- logger.log(`${methodSignature}(${_getArgsSignature(args, noLogArgs)}) @memo hit`);
45
+ logger.log(`${methodSignature}(${_getArgsSignature(args, logArgs)}) @memo hit`);
46
46
  }
47
47
  return cache.get(cacheKey);
48
48
  }
49
49
  const d = Date.now();
50
50
  const res = originalFn.apply(ctx, args);
51
51
  if (logMiss) {
52
- logger.log(`${methodSignature}(${_getArgsSignature(args, noLogArgs)}) @memo miss (${Date.now() - d} ms)`);
52
+ logger.log(`${methodSignature}(${_getArgsSignature(args, logArgs)}) @memo miss (${Date.now() - d} ms)`);
53
53
  }
54
54
  cache.set(cacheKey, res);
55
55
  return res;
package/dist-esm/index.js CHANGED
@@ -10,6 +10,7 @@ export * from './decorators/logMethod.decorator';
10
10
  export * from './decorators/memo.decorator';
11
11
  export * from './decorators/asyncMemo.decorator';
12
12
  export * from './decorators/memoFn';
13
+ export * from './decorators/memoFnAsync';
13
14
  export * from './decorators/retry.decorator';
14
15
  export * from './decorators/timeout.decorator';
15
16
  export * from './error/app.error';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
- "version": "14.84.1",
3
+ "version": "14.86.0",
4
4
  "scripts": {
5
5
  "prepare": "husky install",
6
6
  "build-prod": "build-prod-esm-cjs",
@@ -1,25 +1,54 @@
1
+ import { CommonLogger } from '../log/commonLogger'
1
2
  import { _since } from '../time/time.util'
2
- import { Merge } from '../typeFest'
3
3
  import { AnyObject } from '../types'
4
4
  import { _getArgsSignature, _getMethodSignature, _getTargetMethodSignature } from './decorator.util'
5
- import { CACHE_DROP, MemoOptions } from './memo.decorator'
6
- import { AsyncMemoCache, jsonMemoSerializer } from './memo.util'
7
-
8
- export type AsyncMemoOptions = Merge<
9
- MemoOptions,
10
- {
11
- /**
12
- * Provide a custom implementation of MemoCache.
13
- * Function that creates an instance of `MemoCache`.
14
- * e.g LRUMemoCache from `@naturalcycles/nodejs-lib`.
15
- *
16
- * It's an ARRAY of Caches, to allow multiple layers of Cache.
17
- * It will check it one by one, starting from the first.
18
- * HIT will be returned immediately, MISS will go one level deeper, or returned (if the end of the Cache stack is reached).
19
- */
20
- cacheFactory: () => AsyncMemoCache[]
21
- }
22
- >
5
+ import { AsyncMemoCache, jsonMemoSerializer, MapMemoCache } from './memo.util'
6
+
7
+ export interface AsyncMemoOptions {
8
+ /**
9
+ * Provide a custom implementation of MemoCache.
10
+ * Function that creates an instance of `MemoCache`.
11
+ * e.g LRUMemoCache from `@naturalcycles/nodejs-lib`.
12
+ */
13
+ cacheFactory?: () => AsyncMemoCache
14
+
15
+ /**
16
+ * Provide a custom implementation of CacheKey function.
17
+ */
18
+ cacheKeyFn?: (args: any[]) => any
19
+
20
+ /**
21
+ * Default true.
22
+ *
23
+ * Set to `false` to skip caching rejected promises (errors).
24
+ *
25
+ * True will ensure "max 1 execution", but will "remember" rejection.
26
+ * False will allow >1 execution in case of errors.
27
+ */
28
+ cacheRejections?: boolean
29
+
30
+ /**
31
+ * Default to false
32
+ */
33
+ logHit?: boolean
34
+
35
+ /**
36
+ * Default to false
37
+ */
38
+ logMiss?: boolean
39
+
40
+ /**
41
+ * Set to `false` to skip logging method arguments.
42
+ *
43
+ * Defaults to true.
44
+ */
45
+ logArgs?: boolean
46
+
47
+ /**
48
+ * Default to `console`
49
+ */
50
+ logger?: CommonLogger
51
+ }
23
52
 
24
53
  /**
25
54
  * Like @_Memo, but allowing async MemoCache implementation.
@@ -29,7 +58,7 @@ export type AsyncMemoOptions = Merge<
29
58
  */
30
59
  // eslint-disable-next-line @typescript-eslint/naming-convention
31
60
  export const _AsyncMemo =
32
- (opt: AsyncMemoOptions): MethodDecorator =>
61
+ (opt: AsyncMemoOptions = {}): MethodDecorator =>
33
62
  (target, key, descriptor) => {
34
63
  if (typeof descriptor.value !== 'function') {
35
64
  throw new TypeError('Memoization can be applied only to methods')
@@ -38,17 +67,16 @@ export const _AsyncMemo =
38
67
  const originalFn = descriptor.value
39
68
 
40
69
  // Map from "instance" of the Class where @_AsyncMemo is applied to AsyncMemoCache instance.
41
- const cache = new Map<AnyObject, AsyncMemoCache[]>()
70
+ const cache = new Map<AnyObject, AsyncMemoCache>()
42
71
 
43
72
  const {
44
73
  logHit = false,
45
74
  logMiss = false,
46
- noLogArgs = false,
75
+ logArgs = true,
47
76
  logger = console,
48
- cacheFactory,
77
+ cacheFactory = () => new MapMemoCache(),
49
78
  cacheKeyFn = jsonMemoSerializer,
50
- noCacheRejected = false,
51
- noCacheResolved = false,
79
+ cacheRejections = true,
52
80
  } = opt
53
81
 
54
82
  const keyStr = String(key)
@@ -65,29 +93,10 @@ export const _AsyncMemo =
65
93
  // UPD: no! AsyncMemo supports "persistent caches" (e.g Database-backed cache)
66
94
  }
67
95
 
68
- if (args.length === 1 && args[0] === CACHE_DROP) {
69
- // Special event - CACHE_DROP
70
- // Function will return undefined
71
- logger.log(`${methodSignature} @_AsyncMemo.dropCache()`)
72
- try {
73
- await Promise.all(cache.get(ctx)!.map(c => c.clear()))
74
- } catch (err) {
75
- logger.error(err)
76
- }
77
-
78
- return
79
- }
80
-
81
96
  let value: any
82
97
 
83
98
  try {
84
- for await (const cacheLayer of cache.get(ctx)!) {
85
- value = await cacheLayer.get(cacheKey)
86
- if (value !== undefined) {
87
- // it's a hit!
88
- break
89
- }
90
- }
99
+ value = await cache.get(ctx)!.get(cacheKey)
91
100
  } catch (err) {
92
101
  // log error, but don't throw, treat it as a "miss"
93
102
  logger.error(err)
@@ -99,12 +108,16 @@ export const _AsyncMemo =
99
108
  logger.log(
100
109
  `${_getMethodSignature(ctx, keyStr)}(${_getArgsSignature(
101
110
  args,
102
- noLogArgs,
111
+ logArgs,
103
112
  )}) @_AsyncMemo hit`,
104
113
  )
105
114
  }
106
115
 
107
- return value instanceof Error ? Promise.reject(value) : Promise.resolve(value)
116
+ if (value instanceof Error) {
117
+ throw value
118
+ }
119
+
120
+ return value
108
121
  }
109
122
 
110
123
  // Here we know it's a MISS, let's execute the real method
@@ -113,25 +126,30 @@ export const _AsyncMemo =
113
126
  try {
114
127
  value = await originalFn.apply(ctx, args)
115
128
 
116
- if (!noCacheResolved) {
117
- Promise.all(cache.get(ctx)!.map(cacheLayer => cacheLayer.set(cacheKey, value))).catch(
118
- err => {
119
- // log and ignore the error
120
- logger.error(err)
121
- },
122
- )
123
- }
129
+ // Save the value in the Cache, without awaiting it
130
+ // This is to support both sync and async functions
131
+ void (async () => {
132
+ try {
133
+ await cache.get(ctx)!.set(cacheKey, value)
134
+ } catch (err) {
135
+ // log and ignore the error
136
+ logger.error(err)
137
+ }
138
+ })()
124
139
 
125
140
  return value
126
141
  } catch (err) {
127
- if (!noCacheRejected) {
142
+ if (cacheRejections) {
128
143
  // We put it to cache as raw Error, not Promise.reject(err)
129
- Promise.all(cache.get(ctx)!.map(cacheLayer => cacheLayer.set(cacheKey, err))).catch(
130
- err => {
144
+ // This is to support both sync and async functions
145
+ void (async () => {
146
+ try {
147
+ await cache.get(ctx)!.set(cacheKey, err)
148
+ } catch (err) {
131
149
  // log and ignore the error
132
150
  logger.error(err)
133
- },
134
- )
151
+ }
152
+ })()
135
153
  }
136
154
 
137
155
  throw err
@@ -140,12 +158,21 @@ export const _AsyncMemo =
140
158
  logger.log(
141
159
  `${_getMethodSignature(ctx, keyStr)}(${_getArgsSignature(
142
160
  args,
143
- noLogArgs,
161
+ logArgs,
144
162
  )}) @_AsyncMemo miss (${_since(started)})`,
145
163
  )
146
164
  }
147
165
  }
148
166
  } as any
167
+ ;(descriptor.value as any).dropCache = async () => {
168
+ logger.log(`${methodSignature} @_AsyncMemo.dropCache()`)
169
+ try {
170
+ await Promise.all([...cache.values()].map(c => c.clear()))
171
+ cache.clear()
172
+ } catch (err) {
173
+ logger.error(err)
174
+ }
175
+ }
149
176
 
150
177
  return descriptor
151
178
  }
@@ -23,8 +23,8 @@ export function _getTargetMethodSignature(target: AnyObject, keyStr: string): st
23
23
  * returns:
24
24
  * a, b, c
25
25
  */
26
- export function _getArgsSignature(args: any[] = [], noLogArgs = false): string {
27
- if (noLogArgs) return ''
26
+ export function _getArgsSignature(args: any[] = [], logArgs = true): string {
27
+ if (!logArgs) return ''
28
28
 
29
29
  return args
30
30
  .map(arg => {
@@ -16,14 +16,16 @@ export interface LogMethodOptions {
16
16
  avg?: number
17
17
 
18
18
  /**
19
- * Skip logging method arguments
19
+ * Defaults to true.
20
+ * Set to false to skip logging method arguments
20
21
  */
21
- noLogArgs?: boolean
22
+ logArgs?: boolean
22
23
 
23
24
  /**
24
- * Skip logging result length when result is an array.
25
+ * Defaults to true.
26
+ * Set to false to skip logging result length when result is an array.
25
27
  */
26
- noLogResultLength?: boolean
28
+ logResultLength?: boolean
27
29
 
28
30
  /**
29
31
  * Also log on method start.
@@ -74,12 +76,19 @@ export function _LogMethod(opt: LogMethodOptions = {}): MethodDecorator {
74
76
  const originalFn = descriptor.value
75
77
  const keyStr = String(key)
76
78
 
77
- const { avg, noLogArgs, logStart, logResult, noLogResultLength, logger = console } = opt
79
+ const {
80
+ avg,
81
+ logArgs = true,
82
+ logStart,
83
+ logResult,
84
+ logResultLength = true,
85
+ logger = console,
86
+ } = opt
78
87
  let { logResultFn } = opt
79
88
  if (!logResultFn) {
80
89
  if (logResult) {
81
90
  logResultFn = r => ['result:', _stringifyAny(r)]
82
- } else if (!noLogResultLength) {
91
+ } else if (logResultLength) {
83
92
  logResultFn = r => (Array.isArray(r) ? [`result: ${r.length} items`] : [])
84
93
  }
85
94
  }
@@ -94,7 +103,7 @@ export function _LogMethod(opt: LogMethodOptions = {}): MethodDecorator {
94
103
  // e.g `NameOfYourClass.methodName`
95
104
  // or `NameOfYourClass(instanceId).methodName`
96
105
  const methodSignature = _getMethodSignature(ctx, keyStr)
97
- const argsStr = _getArgsSignature(args, noLogArgs)
106
+ const argsStr = _getArgsSignature(args, logArgs)
98
107
  const callSignature = `${methodSignature}(${argsStr}) #${++count}`
99
108
  if (logStart) logger.log(`>> ${callSignature}`)
100
109
 
@@ -1,67 +1,50 @@
1
- // Based on:
2
- // https://github.com/mgechev/memo-decorator/blob/master/index.ts
3
- // http://decodize.com/blog/2012/08/27/javascript-memoization-caching-results-for-better-performance/
4
- // http://inlehmansterms.net/2015/03/01/javascript-memoization/
5
- // https://community.risingstack.com/the-worlds-fastest-javascript-memoization-library/
6
-
7
1
  import { CommonLogger } from '../log/commonLogger'
8
2
  import { _since } from '../time/time.util'
9
3
  import { AnyObject } from '../types'
10
4
  import { _getArgsSignature, _getMethodSignature, _getTargetMethodSignature } from './decorator.util'
11
5
  import { jsonMemoSerializer, MapMemoCache, MemoCache } from './memo.util'
12
6
 
13
- /**
14
- * Symbol to indicate that the Cache should be dropped.
15
- */
16
- export const CACHE_DROP = Symbol('CACHE_DROP')
17
-
18
7
  export interface MemoOptions {
19
8
  /**
20
- * Default to false
21
- */
22
- logHit?: boolean
23
- /**
24
- * Default to false
9
+ * Provide a custom implementation of MemoCache.
10
+ * Function that creates an instance of `MemoCache`.
11
+ * e.g LRUMemoCache from `@naturalcycles/nodejs-lib`
25
12
  */
26
- logMiss?: boolean
13
+ cacheFactory?: () => MemoCache
27
14
 
28
15
  /**
29
- * Skip logging method arguments.
16
+ * Provide a custom implementation of CacheKey function.
30
17
  */
31
- noLogArgs?: boolean
18
+ cacheKeyFn?: (args: any[]) => any
32
19
 
33
20
  /**
34
- * Default to `console`
21
+ * Defaults to true.
22
+ * Set to false to skip caching errors.
23
+ *
24
+ * True will ensure "max 1 execution", but will "remember" errors.
25
+ * False will allow >1 execution in case of errors.
35
26
  */
36
- logger?: CommonLogger
27
+ cacheErrors?: boolean
37
28
 
38
29
  /**
39
- * Provide a custom implementation of MemoCache.
40
- * Function that creates an instance of `MemoCache`.
41
- * e.g LRUMemoCache from `@naturalcycles/nodejs-lib`
30
+ * Default to false
42
31
  */
43
- cacheFactory?: () => MemoCache
44
-
32
+ logHit?: boolean
45
33
  /**
46
- * Provide a custom implementation of CacheKey function.
34
+ * Default to false
47
35
  */
48
- cacheKeyFn?: (args: any[]) => any
36
+ logMiss?: boolean
49
37
 
50
38
  /**
51
- * Don't cache resolved promises.
52
- * Setting this to `true` will make the decorator to await the result.
53
- *
54
- * Default false.
39
+ * Defaults to true.
40
+ * Set to false to skip logging method arguments.
55
41
  */
56
- noCacheResolved?: boolean
42
+ logArgs?: boolean
57
43
 
58
44
  /**
59
- * Don't cache rejected promises.
60
- * Setting this to `true` will make the decorator to await the result.
61
- *
62
- * Default false.
45
+ * Default to `console`
63
46
  */
64
- noCacheRejected?: boolean
47
+ logger?: CommonLogger
65
48
  }
66
49
 
67
50
  /**
@@ -73,6 +56,15 @@ export interface MemoOptions {
73
56
  * If you don't want it that way - you can use a static method, then there will be only one "instance".
74
57
  *
75
58
  * Supports dropping it's cache by calling .dropCache() method of decorated function (useful in unit testing).
59
+ *
60
+ * Doesn't support Async functions, use @_AsyncMemo instead!
61
+ * (or, it will simply return the [unresolved] Promise further, without awaiting it)
62
+ *
63
+ * Based on:
64
+ * https://github.com/mgechev/memo-decorator/blob/master/index.ts
65
+ * http://decodize.com/blog/2012/08/27/javascript-memoization-caching-results-for-better-performance/
66
+ * http://inlehmansterms.net/2015/03/01/javascript-memoization/
67
+ * https://community.risingstack.com/the-worlds-fastest-javascript-memoization-library/
76
68
  */
77
69
  // eslint-disable-next-line @typescript-eslint/naming-convention
78
70
  export const _Memo =
@@ -96,105 +88,77 @@ export const _Memo =
96
88
  const {
97
89
  logHit = false,
98
90
  logMiss = false,
99
- noLogArgs = false,
91
+ logArgs = true,
100
92
  logger = console,
101
93
  cacheFactory = () => new MapMemoCache(),
102
94
  cacheKeyFn = jsonMemoSerializer,
103
- noCacheRejected = false,
104
- noCacheResolved = false,
95
+ cacheErrors = true,
105
96
  } = opt
106
97
 
107
- const awaitPromise = Boolean(noCacheRejected || noCacheResolved)
108
98
  const keyStr = String(key)
109
99
  const methodSignature = _getTargetMethodSignature(target, keyStr)
110
100
 
111
101
  descriptor.value = function (this: typeof target, ...args: any[]): any {
112
102
  const ctx = this
113
-
114
- if (args.length === 1 && args[0] === CACHE_DROP) {
115
- // Special event - CACHE_DROP
116
- // Function will return undefined
117
- logger.log(`${methodSignature} @_Memo.CACHE_DROP`)
118
- return cache.get(ctx)?.clear()
119
- }
120
-
121
103
  const cacheKey = cacheKeyFn(args)
104
+ let value: any
122
105
 
123
106
  if (!cache.has(ctx)) {
124
107
  cache.set(ctx, cacheFactory())
125
108
  } else if (cache.get(ctx)!.has(cacheKey)) {
126
109
  if (logHit) {
127
110
  logger.log(
128
- `${_getMethodSignature(ctx, keyStr)}(${_getArgsSignature(args, noLogArgs)}) @_Memo hit`,
111
+ `${_getMethodSignature(ctx, keyStr)}(${_getArgsSignature(args, logArgs)}) @_Memo hit`,
129
112
  )
130
113
  }
131
114
 
132
- const res = cache.get(ctx)!.get(cacheKey)
115
+ value = cache.get(ctx)!.get(cacheKey)
133
116
 
134
- if (awaitPromise) {
135
- return res instanceof Error ? Promise.reject(res) : Promise.resolve(res)
136
- } else {
137
- return res
117
+ if (value instanceof Error) {
118
+ throw value
138
119
  }
120
+
121
+ return value
139
122
  }
140
123
 
141
124
  const started = Date.now()
142
125
 
143
- const res: any = originalFn.apply(ctx, args)
144
-
145
- if (awaitPromise) {
146
- return (res as Promise<any>)
147
- .then(res => {
148
- // console.log('RESOLVED', res)
149
- if (logMiss) {
150
- logger.log(
151
- `${_getMethodSignature(ctx, keyStr)}(${_getArgsSignature(
152
- args,
153
- noLogArgs,
154
- )}) @_Memo miss resolved (${_since(started)})`,
155
- )
156
- }
157
-
158
- if (!noCacheResolved) {
159
- cache.get(ctx)!.set(cacheKey, res)
160
- }
161
-
162
- return res
163
- })
164
- .catch(err => {
165
- // console.log('REJECTED', err)
166
- if (logMiss) {
167
- logger.log(
168
- `${_getMethodSignature(ctx, keyStr)}(${_getArgsSignature(
169
- args,
170
- noLogArgs,
171
- )}) @_Memo miss rejected (${_since(started)})`,
172
- )
173
- }
174
-
175
- if (!noCacheRejected) {
176
- // We put it to cache as raw Error, not Promise.reject(err)
177
- // So, we'll need to check if it's instanceof Error to reject it or resolve
178
- // Wrap as Error if it's not Error
179
- cache.get(ctx)!.set(cacheKey, err instanceof Error ? err : new Error(err))
180
- }
181
-
182
- throw err
183
- })
184
- } else {
126
+ try {
127
+ value = originalFn.apply(ctx, args)
128
+
129
+ try {
130
+ cache.get(ctx)!.set(cacheKey, value)
131
+ } catch (err) {
132
+ logger.error(err)
133
+ }
134
+
135
+ return value
136
+ } catch (err) {
137
+ if (cacheErrors) {
138
+ try {
139
+ cache.get(ctx)!.set(cacheKey, err)
140
+ } catch (err) {
141
+ logger.error(err)
142
+ }
143
+ }
144
+
145
+ throw err
146
+ } finally {
185
147
  if (logMiss) {
186
148
  logger.log(
187
149
  `${_getMethodSignature(ctx, keyStr)}(${_getArgsSignature(
188
150
  args,
189
- noLogArgs,
151
+ logArgs,
190
152
  )}) @_Memo miss (${_since(started)})`,
191
153
  )
192
154
  }
193
-
194
- cache.get(ctx)!.set(cacheKey, res)
195
- return res
196
155
  }
197
156
  } as any
157
+ ;(descriptor.value as any).dropCache = () => {
158
+ logger.log(`${methodSignature} @_Memo.dropCache()`)
159
+ cache.forEach(memoCache => memoCache.clear())
160
+ cache.clear()
161
+ }
198
162
 
199
163
  return descriptor
200
164
  }
@@ -11,8 +11,8 @@ export const jsonMemoSerializer: MemoSerializer = args => {
11
11
 
12
12
  export interface MemoCache<KEY = any, VALUE = any> {
13
13
  has(k: KEY): boolean
14
- get(k: KEY): VALUE | undefined
15
- set(k: KEY, v: VALUE): void
14
+ get(k: KEY): VALUE | Error | undefined
15
+ set(k: KEY, v: VALUE | Error): void
16
16
 
17
17
  /**
18
18
  * Clear is only called when `.dropCache()` is called.
@@ -29,8 +29,8 @@ export interface AsyncMemoCache<KEY = any, VALUE = any> {
29
29
  * This also means that you CANNOT store `undefined` value in the Cache, as it'll be treated as a MISS.
30
30
  * You CAN store `null` value instead, it will be treated as a HIT.
31
31
  */
32
- get(k: KEY): Promisable<VALUE | undefined>
33
- set(k: KEY, v: VALUE): Promisable<void>
32
+ get(k: KEY): Promisable<VALUE | Error | undefined>
33
+ set(k: KEY, v: VALUE | Error): Promisable<void>
34
34
 
35
35
  /**
36
36
  * Clear is only called when `.dropCache()` is called.
@@ -88,17 +88,17 @@ export class ObjectMemoCache implements MemoCache {
88
88
  export class MapMemoCache<KEY = any, VALUE = any>
89
89
  implements MemoCache<KEY, VALUE>, AsyncMemoCache<KEY, VALUE>
90
90
  {
91
- private m = new Map<KEY, VALUE>()
91
+ private m = new Map<KEY, VALUE | Error>()
92
92
 
93
93
  has(k: KEY): boolean {
94
94
  return this.m.has(k)
95
95
  }
96
96
 
97
- get(k: KEY): VALUE | undefined {
97
+ get(k: KEY): VALUE | Error | undefined {
98
98
  return this.m.get(k)
99
99
  }
100
100
 
101
- set(k: KEY, v: VALUE): void {
101
+ set(k: KEY, v: VALUE | Error): void {
102
102
  this.m.set(k, v)
103
103
  }
104
104