@sebspark/promise-cache 4.0.3 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +136 -132
- package/dist/index.d.mts +2 -5
- package/dist/index.d.ts +2 -5
- package/dist/index.js +43 -30
- package/dist/index.mjs +31 -28
- package/package.json +18 -7
package/README.md
CHANGED
|
@@ -18,7 +18,139 @@ yarn install @sebspark/promise-cache
|
|
|
18
18
|
```
|
|
19
19
|
## **Usage**
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
# Cache implementation
|
|
22
|
+
|
|
23
|
+
The basic functionality of this new implementation is:
|
|
24
|
+
|
|
25
|
+
1. You create a persistor to store your cached data. This can be the built in `InMemoryPersistor` or a `Redis` client
|
|
26
|
+
2. You create a cache by calling `createCache(persistor, 'optional-prefix')`
|
|
27
|
+
3. You call the cache's wrap function to wrap your original function(s)
|
|
28
|
+
4. You call the wrapped function(s) instead of the originals
|
|
29
|
+
|
|
30
|
+
**Why the change?**
|
|
31
|
+
|
|
32
|
+
When trying to add support for caching _to_ a specified time in addition to _for_ a specified time, it tuyrned out to be hard given the original implementation. Changing the implementation proved hard without breaking changes. So a new implementation is is.
|
|
33
|
+
|
|
34
|
+
## How to use it
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { createClient } from 'redis'
|
|
38
|
+
import { createCache } from '@sebspark/promise-cache'
|
|
39
|
+
import { myFunction } from './some_function'
|
|
40
|
+
|
|
41
|
+
const run = async () => {
|
|
42
|
+
// Create your persistor
|
|
43
|
+
const persistor = createClient({ url: 'redis' })
|
|
44
|
+
await persistor.connect() // This is not handled by the cache
|
|
45
|
+
|
|
46
|
+
// Create your cache and give it a prefix
|
|
47
|
+
const cache = createCache(persistor, 'my-prefix')
|
|
48
|
+
|
|
49
|
+
// wrap your function
|
|
50
|
+
const myCachedFunction = cache.wrap(myFunction, {
|
|
51
|
+
key: 'my-function', // cached data will be stored with the key 'my-prefix:my-function'
|
|
52
|
+
expiry: 100, // ttl will be 100 ms
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
// call the wrapped function
|
|
56
|
+
const response = await myCachedFunction() // the wrapped function will have the same signature as the original
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
run()
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Keys
|
|
63
|
+
|
|
64
|
+
Keys can be constructed in two ways: as a fixed string or as a function that generates a string. The generator will accept the arguments of the wrapped function.
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
const cache = createCache(persistor, 'api')
|
|
68
|
+
|
|
69
|
+
const getById = async (id: string): Promise<Data> => {
|
|
70
|
+
// Something gets called
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const cachedGetById = cache.wrap(myApiCall, {
|
|
74
|
+
key: (id) => `getById:${id}`
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
const result = await cachedGetById('foo')
|
|
78
|
+
|
|
79
|
+
// key will be 'api:getById:foo'
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Expiry
|
|
83
|
+
|
|
84
|
+
Expiration can be set as either a number (number of milliseconds from now) or a Date (exact expiry time). It can be set either as a value (`number | Date`) or as a function that generates a value (`number | Date`). The generator will accept the arguments _and_ the response of the wrapped function.
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
const cache = createCache(persistor, 'api')
|
|
88
|
+
|
|
89
|
+
type Data = {
|
|
90
|
+
value: number
|
|
91
|
+
expires: string // ISO6501 date time string
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const getById = async (id: string): Promise<Data> => {
|
|
95
|
+
// Something gets called
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const cachedGetById = cache.wrap(myApiCall, {
|
|
99
|
+
key: (id) => `getById:${id}`,
|
|
100
|
+
expires: ([id], data) => new Date(data.expires),
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
const result = await cachedGetById('foo')
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
There are also helpers for setting time or manipulating dates
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import { createCache, time } from '@sebspark/promise-cache'
|
|
110
|
+
|
|
111
|
+
const cache = createCache(persistor, 'api')
|
|
112
|
+
|
|
113
|
+
type Data = {
|
|
114
|
+
value: number
|
|
115
|
+
lastUpdated: string // ISO6501 date time string. Data is updated every 30 minutes.
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const getById = async (id: string): Promise<Data> => {
|
|
119
|
+
// Something gets called
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Computed from response
|
|
123
|
+
const cachedGetById = cache.wrap(myApiCall, {
|
|
124
|
+
key: (id) => `getById:${id}`,
|
|
125
|
+
expires: ([id], data) => time.add(new Date(data.lastUpdated), { minutes: 30 })
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
// Fixed at 20 seconds
|
|
129
|
+
const cachedGetById = cache.wrap(myApiCall, {
|
|
130
|
+
key: (id) => `getById:${id}`,
|
|
131
|
+
expires: time.seconds(100),
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
// Fixed at today 20:00:00 UTC
|
|
135
|
+
const cachedGetById = cache.wrap(myApiCall, {
|
|
136
|
+
key: (id) => `getById:${id}`,
|
|
137
|
+
expires: time.today(20),
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
// Fixed at tomorrow 00:00:00
|
|
141
|
+
const cachedGetById = cache.wrap(myApiCall, {
|
|
142
|
+
key: (id) => `getById:${id}`,
|
|
143
|
+
expires: time.tomorrow(),
|
|
144
|
+
})
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
If expiry is not set or yields an unusable value, it will default to 1 sec.
|
|
148
|
+
|
|
149
|
+
# Old implementation
|
|
150
|
+
|
|
151
|
+
** Deprecated - do not use **
|
|
152
|
+
|
|
153
|
+
## **PromiseCache Class**
|
|
22
154
|
|
|
23
155
|
| Params | Type | Default | Description |
|
|
24
156
|
|--------------------|---------------------|-----------|--------------------------------------------------|
|
|
@@ -47,7 +179,7 @@ const cacheLocalMemory = new PromiseCache<T>({
|
|
|
47
179
|
})
|
|
48
180
|
```
|
|
49
181
|
|
|
50
|
-
|
|
182
|
+
### **PromiseCache Methods**
|
|
51
183
|
|
|
52
184
|
```typescript
|
|
53
185
|
// Wrap
|
|
@@ -94,7 +226,7 @@ const cached = cacheInRedis.find('Key')
|
|
|
94
226
|
expect(cached).toBe(234)
|
|
95
227
|
```
|
|
96
228
|
|
|
97
|
-
|
|
229
|
+
## **Persistor Class**
|
|
98
230
|
|
|
99
231
|
| Params | Type | Default |Description |
|
|
100
232
|
|---------------|----------|---------|---------------------------------------------|
|
|
@@ -116,7 +248,7 @@ const store = new Persistor<T>({
|
|
|
116
248
|
const store = new Persistor<T>()
|
|
117
249
|
```
|
|
118
250
|
|
|
119
|
-
|
|
251
|
+
### **Persistor Methods**
|
|
120
252
|
|
|
121
253
|
```typescript
|
|
122
254
|
|
|
@@ -164,131 +296,3 @@ expect(cached).toBe({
|
|
|
164
296
|
await store.delete('MyKey')
|
|
165
297
|
expect(await store.get('MyKey').toBe(null)
|
|
166
298
|
```
|
|
167
|
-
|
|
168
|
-
# Cache implementation
|
|
169
|
-
|
|
170
|
-
The basic functionality of this new implementation is:
|
|
171
|
-
|
|
172
|
-
1. You create a persistor to store your cached data. This can be the built in `InMemoryPersistor` or a `Redis` client
|
|
173
|
-
2. You create a cache by calling `createCache(persistor, 'optional-prefix')`
|
|
174
|
-
3. You call the cache's wrap function to wrap your original function(s)
|
|
175
|
-
4. You call the wrapped function(s) instead of the originals
|
|
176
|
-
|
|
177
|
-
**Why the change?**
|
|
178
|
-
|
|
179
|
-
When trying to add support for caching _to_ a specified time in addition to _for_ a specified time, it tuyrned out to be hard given the original implementation. Changing the implementation proved hard without breaking changes. So a new implementation is is.
|
|
180
|
-
|
|
181
|
-
## How to use it
|
|
182
|
-
|
|
183
|
-
```typescript
|
|
184
|
-
import { createClient } from 'redis'
|
|
185
|
-
import { createCache } from '@sebspark/promise-cache'
|
|
186
|
-
import { myFunction } from './some_function'
|
|
187
|
-
|
|
188
|
-
const run = async () => {
|
|
189
|
-
// Create your persistor
|
|
190
|
-
const persistor = createClient({ url: 'redis' })
|
|
191
|
-
await persistor.connect() // This is not handled by the cache
|
|
192
|
-
|
|
193
|
-
// Create your cache and give it a prefix
|
|
194
|
-
const cache = createCache(persistor, 'my-prefix')
|
|
195
|
-
|
|
196
|
-
// wrap your function
|
|
197
|
-
const myCachedFunction = cache.wrap(myFunction, {
|
|
198
|
-
key: 'my-function', // cached data will be stored with the key 'my-prefix:my-function'
|
|
199
|
-
expiry: 100, // ttl will be 100 ms
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
// call the wrapped function
|
|
203
|
-
const response = await myCachedFunction() // the wrapped function will have the same signature as the original
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
run()
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### Keys
|
|
210
|
-
|
|
211
|
-
Keys can be constructed in two ways: as a fixed string or as a function that generates a string. The generator will accept the arguments of the wrapped function.
|
|
212
|
-
|
|
213
|
-
```typescript
|
|
214
|
-
const cache = createCache(persistor, 'api')
|
|
215
|
-
|
|
216
|
-
const getById = async (id: string): Promise<Data> => {
|
|
217
|
-
// Something gets called
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
const cachedGetById = cache.wrap(myApiCall, {
|
|
221
|
-
key: (id) => `getById:${id}`
|
|
222
|
-
})
|
|
223
|
-
|
|
224
|
-
const result = await cachedGetById('foo')
|
|
225
|
-
|
|
226
|
-
// key will be 'api:getById:foo'
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
### Expiry
|
|
230
|
-
|
|
231
|
-
Expiration can be set as either a number (number of milliseconds from now) or a Date (exact expiry time). It can be set either as a value (`number | Date`) or as a function that generates a value (`number | Date`). The generator will accept the arguments _and_ the response of the wrapped function.
|
|
232
|
-
|
|
233
|
-
```typescript
|
|
234
|
-
const cache = createCache(persistor, 'api')
|
|
235
|
-
|
|
236
|
-
type Data = {
|
|
237
|
-
value: number
|
|
238
|
-
expires: string // ISO6501 date time string
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
const getById = async (id: string): Promise<Data> => {
|
|
242
|
-
// Something gets called
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const cachedGetById = cache.wrap(myApiCall, {
|
|
246
|
-
key: (id) => `getById:${id}`,
|
|
247
|
-
expires: ([id], data) => new Date(data.expires),
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
const result = await cachedGetById('foo')
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
There are also helpers for setting time or manipulating dates
|
|
254
|
-
|
|
255
|
-
```typescript
|
|
256
|
-
import { createCache, time } from '@sebspark/promise-cache'
|
|
257
|
-
|
|
258
|
-
const cache = createCache(persistor, 'api')
|
|
259
|
-
|
|
260
|
-
type Data = {
|
|
261
|
-
value: number
|
|
262
|
-
lastUpdated: string // ISO6501 date time string. Data is updated every 30 minutes.
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const getById = async (id: string): Promise<Data> => {
|
|
266
|
-
// Something gets called
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Computed from response
|
|
270
|
-
const cachedGetById = cache.wrap(myApiCall, {
|
|
271
|
-
key: (id) => `getById:${id}`,
|
|
272
|
-
expires: ([id], data) => time.add(new Date(data.lastUpdated), { minutes: 30 })
|
|
273
|
-
})
|
|
274
|
-
|
|
275
|
-
// Fixed at 20 seconds
|
|
276
|
-
const cachedGetById = cache.wrap(myApiCall, {
|
|
277
|
-
key: (id) => `getById:${id}`,
|
|
278
|
-
expires: time.seconds(100),
|
|
279
|
-
})
|
|
280
|
-
|
|
281
|
-
// Fixed at today 20:00:00 UTC
|
|
282
|
-
const cachedGetById = cache.wrap(myApiCall, {
|
|
283
|
-
key: (id) => `getById:${id}`,
|
|
284
|
-
expires: time.today(20),
|
|
285
|
-
})
|
|
286
|
-
|
|
287
|
-
// Fixed at tomorrow 00:00:00
|
|
288
|
-
const cachedGetById = cache.wrap(myApiCall, {
|
|
289
|
-
key: (id) => `getById:${id}`,
|
|
290
|
-
expires: time.tomorrow(),
|
|
291
|
-
})
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
If expiry is not set or yields an unusable value, it will default to 1 sec.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { SetOptions, RedisClientOptions, createClient } from 'redis';
|
|
2
2
|
export { RedisClientOptions } from 'redis';
|
|
3
3
|
import { UUID } from 'node:crypto';
|
|
4
|
-
import { Logger } from 'winston';
|
|
5
4
|
import { add, sub } from 'date-fns';
|
|
6
5
|
|
|
7
6
|
type MultiExecReturnTypes = string[] | string | number | boolean | null | undefined;
|
|
@@ -768,7 +767,6 @@ type PersistorConstructorType = {
|
|
|
768
767
|
clientId?: UUID;
|
|
769
768
|
onError?: (error: string) => void;
|
|
770
769
|
onSuccess?: () => void;
|
|
771
|
-
logger?: Logger;
|
|
772
770
|
};
|
|
773
771
|
declare class Persistor {
|
|
774
772
|
client: ReturnType<typeof createClient> | null;
|
|
@@ -777,7 +775,7 @@ declare class Persistor {
|
|
|
777
775
|
private readonly onSuccess;
|
|
778
776
|
private readonly logger;
|
|
779
777
|
private readonly redis?;
|
|
780
|
-
constructor({ redis, clientId, onSuccess, onError,
|
|
778
|
+
constructor({ redis, clientId, onSuccess, onError, }: PersistorConstructorType);
|
|
781
779
|
startConnection(): Promise<void>;
|
|
782
780
|
size(): Promise<number>;
|
|
783
781
|
getClientId(): UUID | undefined;
|
|
@@ -811,7 +809,6 @@ type PromiseCacheOptions = {
|
|
|
811
809
|
fallbackToFunction?: boolean;
|
|
812
810
|
onError?: (error: string) => void;
|
|
813
811
|
onSuccess?: () => void;
|
|
814
|
-
logger?: Logger;
|
|
815
812
|
};
|
|
816
813
|
declare class PromiseCache<U> {
|
|
817
814
|
persistor: Persistor;
|
|
@@ -825,7 +822,7 @@ declare class PromiseCache<U> {
|
|
|
825
822
|
* @param ttlInSeconds Default cache TTL.
|
|
826
823
|
* @param caseSensitive Set to true if you want to differentiate between keys with different casing.
|
|
827
824
|
*/
|
|
828
|
-
constructor({ ttlInSeconds, caseSensitive, redis, fallbackToFunction, onSuccess, onError,
|
|
825
|
+
constructor({ ttlInSeconds, caseSensitive, redis, fallbackToFunction, onSuccess, onError, }: PromiseCacheOptions);
|
|
829
826
|
/**
|
|
830
827
|
* Cache size.
|
|
831
828
|
* @returns The number of entries in the cache.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { SetOptions, RedisClientOptions, createClient } from 'redis';
|
|
2
2
|
export { RedisClientOptions } from 'redis';
|
|
3
3
|
import { UUID } from 'node:crypto';
|
|
4
|
-
import { Logger } from 'winston';
|
|
5
4
|
import { add, sub } from 'date-fns';
|
|
6
5
|
|
|
7
6
|
type MultiExecReturnTypes = string[] | string | number | boolean | null | undefined;
|
|
@@ -768,7 +767,6 @@ type PersistorConstructorType = {
|
|
|
768
767
|
clientId?: UUID;
|
|
769
768
|
onError?: (error: string) => void;
|
|
770
769
|
onSuccess?: () => void;
|
|
771
|
-
logger?: Logger;
|
|
772
770
|
};
|
|
773
771
|
declare class Persistor {
|
|
774
772
|
client: ReturnType<typeof createClient> | null;
|
|
@@ -777,7 +775,7 @@ declare class Persistor {
|
|
|
777
775
|
private readonly onSuccess;
|
|
778
776
|
private readonly logger;
|
|
779
777
|
private readonly redis?;
|
|
780
|
-
constructor({ redis, clientId, onSuccess, onError,
|
|
778
|
+
constructor({ redis, clientId, onSuccess, onError, }: PersistorConstructorType);
|
|
781
779
|
startConnection(): Promise<void>;
|
|
782
780
|
size(): Promise<number>;
|
|
783
781
|
getClientId(): UUID | undefined;
|
|
@@ -811,7 +809,6 @@ type PromiseCacheOptions = {
|
|
|
811
809
|
fallbackToFunction?: boolean;
|
|
812
810
|
onError?: (error: string) => void;
|
|
813
811
|
onSuccess?: () => void;
|
|
814
|
-
logger?: Logger;
|
|
815
812
|
};
|
|
816
813
|
declare class PromiseCache<U> {
|
|
817
814
|
persistor: Persistor;
|
|
@@ -825,7 +822,7 @@ declare class PromiseCache<U> {
|
|
|
825
822
|
* @param ttlInSeconds Default cache TTL.
|
|
826
823
|
* @param caseSensitive Set to true if you want to differentiate between keys with different casing.
|
|
827
824
|
*/
|
|
828
|
-
constructor({ ttlInSeconds, caseSensitive, redis, fallbackToFunction, onSuccess, onError,
|
|
825
|
+
constructor({ ttlInSeconds, caseSensitive, redis, fallbackToFunction, onSuccess, onError, }: PromiseCacheOptions);
|
|
829
826
|
/**
|
|
830
827
|
* Cache size.
|
|
831
828
|
* @returns The number of entries in the cache.
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -35,14 +45,13 @@ __export(serializer_exports, {
|
|
|
35
45
|
deserialize: () => deserialize,
|
|
36
46
|
serialize: () => serialize
|
|
37
47
|
});
|
|
38
|
-
var
|
|
39
|
-
var superjson = fixESM.require("superjson");
|
|
48
|
+
var import_superjson = __toESM(require("superjson"));
|
|
40
49
|
var serialize = (data) => {
|
|
41
|
-
return
|
|
50
|
+
return import_superjson.default.stringify(data);
|
|
42
51
|
};
|
|
43
52
|
var deserialize = (serialized) => {
|
|
44
53
|
if (serialized === void 0 || serialized === null) return serialized;
|
|
45
|
-
return
|
|
54
|
+
return import_superjson.default.parse(serialized);
|
|
46
55
|
};
|
|
47
56
|
|
|
48
57
|
// src/setOptions.ts
|
|
@@ -988,8 +997,9 @@ var createLocalMemoryClient = () => {
|
|
|
988
997
|
};
|
|
989
998
|
|
|
990
999
|
// src/persistor.ts
|
|
991
|
-
var
|
|
992
|
-
var
|
|
1000
|
+
var import_otel = require("@sebspark/otel");
|
|
1001
|
+
var fixESM = require("fix-esm");
|
|
1002
|
+
var superjson2 = fixESM.require("superjson");
|
|
993
1003
|
var CACHE_CLIENT = import_redis.createClient;
|
|
994
1004
|
var isTestRunning = process.env.NODE_ENV === "test";
|
|
995
1005
|
function toMillis(seconds2) {
|
|
@@ -1006,15 +1016,17 @@ var Persistor = class {
|
|
|
1006
1016
|
redis,
|
|
1007
1017
|
clientId,
|
|
1008
1018
|
onSuccess,
|
|
1009
|
-
onError
|
|
1010
|
-
logger
|
|
1019
|
+
onError
|
|
1011
1020
|
}) {
|
|
1021
|
+
this.logger = (0, import_otel.getLogger)("Persistor");
|
|
1022
|
+
this.logger.warn(
|
|
1023
|
+
"Persistor class is deprecated. Use InMemoryPersistor or redis: createClient instead"
|
|
1024
|
+
);
|
|
1012
1025
|
this.onError = onError || (() => {
|
|
1013
1026
|
});
|
|
1014
1027
|
this.onSuccess = onSuccess || (() => {
|
|
1015
1028
|
});
|
|
1016
1029
|
this.clientId = clientId;
|
|
1017
|
-
this.logger = logger;
|
|
1018
1030
|
if (redis && !isTestRunning) {
|
|
1019
1031
|
this.redis = redis;
|
|
1020
1032
|
} else {
|
|
@@ -1035,7 +1047,7 @@ var Persistor = class {
|
|
|
1035
1047
|
socket: {
|
|
1036
1048
|
...this.redis?.socket,
|
|
1037
1049
|
reconnectStrategy: (retries, cause) => {
|
|
1038
|
-
this.logger
|
|
1050
|
+
this.logger.error(cause);
|
|
1039
1051
|
return 1e3 * 2 ** retries;
|
|
1040
1052
|
}
|
|
1041
1053
|
}
|
|
@@ -1046,15 +1058,15 @@ var Persistor = class {
|
|
|
1046
1058
|
this.onSuccess();
|
|
1047
1059
|
resolve(true);
|
|
1048
1060
|
}).on("reconnecting", () => {
|
|
1049
|
-
this.logger
|
|
1061
|
+
this.logger.info(`reconnecting... ${this.clientId}`);
|
|
1050
1062
|
}).on("end", () => {
|
|
1051
|
-
this.logger
|
|
1063
|
+
this.logger.info(`end... ${this.clientId}`);
|
|
1052
1064
|
});
|
|
1053
1065
|
this.client.connect();
|
|
1054
1066
|
});
|
|
1055
|
-
} catch (
|
|
1056
|
-
this.onError(`${
|
|
1057
|
-
this.logger
|
|
1067
|
+
} catch (err) {
|
|
1068
|
+
this.onError(`${err}`);
|
|
1069
|
+
this.logger.error(err);
|
|
1058
1070
|
}
|
|
1059
1071
|
}
|
|
1060
1072
|
async size() {
|
|
@@ -1084,7 +1096,7 @@ var Persistor = class {
|
|
|
1084
1096
|
*/
|
|
1085
1097
|
async set(key, { value, timestamp = Date.now(), ttl }) {
|
|
1086
1098
|
if (!this.client || !this.client.isReady) {
|
|
1087
|
-
this.logger
|
|
1099
|
+
this.logger.error("Client not ready");
|
|
1088
1100
|
return;
|
|
1089
1101
|
}
|
|
1090
1102
|
try {
|
|
@@ -1096,7 +1108,7 @@ var Persistor = class {
|
|
|
1096
1108
|
const options = this.createOptions(ttl);
|
|
1097
1109
|
await this.client.set(key, serializedData, options);
|
|
1098
1110
|
} catch (error) {
|
|
1099
|
-
this.logger
|
|
1111
|
+
this.logger.error("Error setting data in redis", error);
|
|
1100
1112
|
throw new Error(`Error setting data in redis: ${error}`);
|
|
1101
1113
|
}
|
|
1102
1114
|
}
|
|
@@ -1107,7 +1119,7 @@ var Persistor = class {
|
|
|
1107
1119
|
*/
|
|
1108
1120
|
async get(key) {
|
|
1109
1121
|
if (!this.client) {
|
|
1110
|
-
this.logger
|
|
1122
|
+
this.logger.error("Client not ready");
|
|
1111
1123
|
return null;
|
|
1112
1124
|
}
|
|
1113
1125
|
try {
|
|
@@ -1117,7 +1129,7 @@ var Persistor = class {
|
|
|
1117
1129
|
}
|
|
1118
1130
|
return superjson2.parse(data);
|
|
1119
1131
|
} catch (error) {
|
|
1120
|
-
this.logger
|
|
1132
|
+
this.logger.error(`Error getting data in redis: ${error}`);
|
|
1121
1133
|
throw new Error(`Error getting data from redis: ${error}`);
|
|
1122
1134
|
}
|
|
1123
1135
|
}
|
|
@@ -1127,13 +1139,13 @@ var Persistor = class {
|
|
|
1127
1139
|
*/
|
|
1128
1140
|
async delete(key) {
|
|
1129
1141
|
if (!this.client || !this.client.isReady) {
|
|
1130
|
-
this.logger
|
|
1142
|
+
this.logger.error("Client not ready");
|
|
1131
1143
|
return;
|
|
1132
1144
|
}
|
|
1133
1145
|
try {
|
|
1134
1146
|
await this.client.del(key);
|
|
1135
1147
|
} catch (error) {
|
|
1136
|
-
this.logger
|
|
1148
|
+
this.logger.error(`Error deleting data from redis: ${error}`);
|
|
1137
1149
|
throw new Error(`Error deleting data from redis: ${error}`);
|
|
1138
1150
|
}
|
|
1139
1151
|
}
|
|
@@ -1141,14 +1153,15 @@ var Persistor = class {
|
|
|
1141
1153
|
|
|
1142
1154
|
// src/promiseCache.ts
|
|
1143
1155
|
var import_node_crypto = require("crypto");
|
|
1156
|
+
var import_otel2 = require("@sebspark/otel");
|
|
1144
1157
|
var persistors = {};
|
|
1145
1158
|
var getPersistor = ({
|
|
1146
1159
|
redis,
|
|
1147
|
-
logger,
|
|
1148
1160
|
onError,
|
|
1149
1161
|
onSuccess,
|
|
1150
1162
|
clientId
|
|
1151
1163
|
}) => {
|
|
1164
|
+
const logger = (0, import_otel2.getLogger)("PromiseCache persistor");
|
|
1152
1165
|
const connectionName = redis ? redis?.name || "default" : "local";
|
|
1153
1166
|
if (!persistors[connectionName]) {
|
|
1154
1167
|
persistors[connectionName] = new Persistor({
|
|
@@ -1165,8 +1178,7 @@ var getPersistor = ({
|
|
|
1165
1178
|
`\u{1F4E6} REDIS | Connection Ready | ${connectionName} | ${redis?.url}`
|
|
1166
1179
|
);
|
|
1167
1180
|
},
|
|
1168
|
-
clientId
|
|
1169
|
-
logger
|
|
1181
|
+
clientId
|
|
1170
1182
|
});
|
|
1171
1183
|
}
|
|
1172
1184
|
return persistors[connectionName];
|
|
@@ -1191,16 +1203,17 @@ var PromiseCache = class {
|
|
|
1191
1203
|
redis,
|
|
1192
1204
|
fallbackToFunction = false,
|
|
1193
1205
|
onSuccess,
|
|
1194
|
-
onError
|
|
1195
|
-
logger
|
|
1206
|
+
onError
|
|
1196
1207
|
}) {
|
|
1197
|
-
this.logger =
|
|
1208
|
+
this.logger = (0, import_otel2.getLogger)("PromiseCache");
|
|
1209
|
+
this.logger.warn(
|
|
1210
|
+
"PromiseCache class is deprecated. Use createCache instead"
|
|
1211
|
+
);
|
|
1198
1212
|
this.persistor = getPersistor({
|
|
1199
1213
|
redis,
|
|
1200
1214
|
onError,
|
|
1201
1215
|
onSuccess,
|
|
1202
|
-
clientId: this.clientId
|
|
1203
|
-
logger: this.logger
|
|
1216
|
+
clientId: this.clientId
|
|
1204
1217
|
});
|
|
1205
1218
|
this.caseSensitive = caseSensitive;
|
|
1206
1219
|
this.fallbackToFunction = fallbackToFunction;
|
|
@@ -1267,7 +1280,7 @@ var PromiseCache = class {
|
|
|
1267
1280
|
}
|
|
1268
1281
|
this.logger?.error(
|
|
1269
1282
|
"redis error, falling back to function execution",
|
|
1270
|
-
error
|
|
1283
|
+
error
|
|
1271
1284
|
);
|
|
1272
1285
|
}
|
|
1273
1286
|
const response = await delegate();
|
package/dist/index.mjs
CHANGED
|
@@ -16,8 +16,7 @@ __export(serializer_exports, {
|
|
|
16
16
|
deserialize: () => deserialize,
|
|
17
17
|
serialize: () => serialize
|
|
18
18
|
});
|
|
19
|
-
|
|
20
|
-
var superjson = fixESM.require("superjson");
|
|
19
|
+
import superjson from "superjson";
|
|
21
20
|
var serialize = (data) => {
|
|
22
21
|
return superjson.stringify(data);
|
|
23
22
|
};
|
|
@@ -969,8 +968,9 @@ var createLocalMemoryClient = () => {
|
|
|
969
968
|
};
|
|
970
969
|
|
|
971
970
|
// src/persistor.ts
|
|
972
|
-
|
|
973
|
-
var
|
|
971
|
+
import { getLogger } from "@sebspark/otel";
|
|
972
|
+
var fixESM = __require("fix-esm");
|
|
973
|
+
var superjson2 = fixESM.require("superjson");
|
|
974
974
|
var CACHE_CLIENT = createClient;
|
|
975
975
|
var isTestRunning = process.env.NODE_ENV === "test";
|
|
976
976
|
function toMillis(seconds2) {
|
|
@@ -987,15 +987,17 @@ var Persistor = class {
|
|
|
987
987
|
redis,
|
|
988
988
|
clientId,
|
|
989
989
|
onSuccess,
|
|
990
|
-
onError
|
|
991
|
-
logger
|
|
990
|
+
onError
|
|
992
991
|
}) {
|
|
992
|
+
this.logger = getLogger("Persistor");
|
|
993
|
+
this.logger.warn(
|
|
994
|
+
"Persistor class is deprecated. Use InMemoryPersistor or redis: createClient instead"
|
|
995
|
+
);
|
|
993
996
|
this.onError = onError || (() => {
|
|
994
997
|
});
|
|
995
998
|
this.onSuccess = onSuccess || (() => {
|
|
996
999
|
});
|
|
997
1000
|
this.clientId = clientId;
|
|
998
|
-
this.logger = logger;
|
|
999
1001
|
if (redis && !isTestRunning) {
|
|
1000
1002
|
this.redis = redis;
|
|
1001
1003
|
} else {
|
|
@@ -1016,7 +1018,7 @@ var Persistor = class {
|
|
|
1016
1018
|
socket: {
|
|
1017
1019
|
...this.redis?.socket,
|
|
1018
1020
|
reconnectStrategy: (retries, cause) => {
|
|
1019
|
-
this.logger
|
|
1021
|
+
this.logger.error(cause);
|
|
1020
1022
|
return 1e3 * 2 ** retries;
|
|
1021
1023
|
}
|
|
1022
1024
|
}
|
|
@@ -1027,15 +1029,15 @@ var Persistor = class {
|
|
|
1027
1029
|
this.onSuccess();
|
|
1028
1030
|
resolve(true);
|
|
1029
1031
|
}).on("reconnecting", () => {
|
|
1030
|
-
this.logger
|
|
1032
|
+
this.logger.info(`reconnecting... ${this.clientId}`);
|
|
1031
1033
|
}).on("end", () => {
|
|
1032
|
-
this.logger
|
|
1034
|
+
this.logger.info(`end... ${this.clientId}`);
|
|
1033
1035
|
});
|
|
1034
1036
|
this.client.connect();
|
|
1035
1037
|
});
|
|
1036
|
-
} catch (
|
|
1037
|
-
this.onError(`${
|
|
1038
|
-
this.logger
|
|
1038
|
+
} catch (err) {
|
|
1039
|
+
this.onError(`${err}`);
|
|
1040
|
+
this.logger.error(err);
|
|
1039
1041
|
}
|
|
1040
1042
|
}
|
|
1041
1043
|
async size() {
|
|
@@ -1065,7 +1067,7 @@ var Persistor = class {
|
|
|
1065
1067
|
*/
|
|
1066
1068
|
async set(key, { value, timestamp = Date.now(), ttl }) {
|
|
1067
1069
|
if (!this.client || !this.client.isReady) {
|
|
1068
|
-
this.logger
|
|
1070
|
+
this.logger.error("Client not ready");
|
|
1069
1071
|
return;
|
|
1070
1072
|
}
|
|
1071
1073
|
try {
|
|
@@ -1077,7 +1079,7 @@ var Persistor = class {
|
|
|
1077
1079
|
const options = this.createOptions(ttl);
|
|
1078
1080
|
await this.client.set(key, serializedData, options);
|
|
1079
1081
|
} catch (error) {
|
|
1080
|
-
this.logger
|
|
1082
|
+
this.logger.error("Error setting data in redis", error);
|
|
1081
1083
|
throw new Error(`Error setting data in redis: ${error}`);
|
|
1082
1084
|
}
|
|
1083
1085
|
}
|
|
@@ -1088,7 +1090,7 @@ var Persistor = class {
|
|
|
1088
1090
|
*/
|
|
1089
1091
|
async get(key) {
|
|
1090
1092
|
if (!this.client) {
|
|
1091
|
-
this.logger
|
|
1093
|
+
this.logger.error("Client not ready");
|
|
1092
1094
|
return null;
|
|
1093
1095
|
}
|
|
1094
1096
|
try {
|
|
@@ -1098,7 +1100,7 @@ var Persistor = class {
|
|
|
1098
1100
|
}
|
|
1099
1101
|
return superjson2.parse(data);
|
|
1100
1102
|
} catch (error) {
|
|
1101
|
-
this.logger
|
|
1103
|
+
this.logger.error(`Error getting data in redis: ${error}`);
|
|
1102
1104
|
throw new Error(`Error getting data from redis: ${error}`);
|
|
1103
1105
|
}
|
|
1104
1106
|
}
|
|
@@ -1108,13 +1110,13 @@ var Persistor = class {
|
|
|
1108
1110
|
*/
|
|
1109
1111
|
async delete(key) {
|
|
1110
1112
|
if (!this.client || !this.client.isReady) {
|
|
1111
|
-
this.logger
|
|
1113
|
+
this.logger.error("Client not ready");
|
|
1112
1114
|
return;
|
|
1113
1115
|
}
|
|
1114
1116
|
try {
|
|
1115
1117
|
await this.client.del(key);
|
|
1116
1118
|
} catch (error) {
|
|
1117
|
-
this.logger
|
|
1119
|
+
this.logger.error(`Error deleting data from redis: ${error}`);
|
|
1118
1120
|
throw new Error(`Error deleting data from redis: ${error}`);
|
|
1119
1121
|
}
|
|
1120
1122
|
}
|
|
@@ -1122,14 +1124,15 @@ var Persistor = class {
|
|
|
1122
1124
|
|
|
1123
1125
|
// src/promiseCache.ts
|
|
1124
1126
|
import { randomUUID } from "crypto";
|
|
1127
|
+
import { getLogger as getLogger2 } from "@sebspark/otel";
|
|
1125
1128
|
var persistors = {};
|
|
1126
1129
|
var getPersistor = ({
|
|
1127
1130
|
redis,
|
|
1128
|
-
logger,
|
|
1129
1131
|
onError,
|
|
1130
1132
|
onSuccess,
|
|
1131
1133
|
clientId
|
|
1132
1134
|
}) => {
|
|
1135
|
+
const logger = getLogger2("PromiseCache persistor");
|
|
1133
1136
|
const connectionName = redis ? redis?.name || "default" : "local";
|
|
1134
1137
|
if (!persistors[connectionName]) {
|
|
1135
1138
|
persistors[connectionName] = new Persistor({
|
|
@@ -1146,8 +1149,7 @@ var getPersistor = ({
|
|
|
1146
1149
|
`\u{1F4E6} REDIS | Connection Ready | ${connectionName} | ${redis?.url}`
|
|
1147
1150
|
);
|
|
1148
1151
|
},
|
|
1149
|
-
clientId
|
|
1150
|
-
logger
|
|
1152
|
+
clientId
|
|
1151
1153
|
});
|
|
1152
1154
|
}
|
|
1153
1155
|
return persistors[connectionName];
|
|
@@ -1172,16 +1174,17 @@ var PromiseCache = class {
|
|
|
1172
1174
|
redis,
|
|
1173
1175
|
fallbackToFunction = false,
|
|
1174
1176
|
onSuccess,
|
|
1175
|
-
onError
|
|
1176
|
-
logger
|
|
1177
|
+
onError
|
|
1177
1178
|
}) {
|
|
1178
|
-
this.logger =
|
|
1179
|
+
this.logger = getLogger2("PromiseCache");
|
|
1180
|
+
this.logger.warn(
|
|
1181
|
+
"PromiseCache class is deprecated. Use createCache instead"
|
|
1182
|
+
);
|
|
1179
1183
|
this.persistor = getPersistor({
|
|
1180
1184
|
redis,
|
|
1181
1185
|
onError,
|
|
1182
1186
|
onSuccess,
|
|
1183
|
-
clientId: this.clientId
|
|
1184
|
-
logger: this.logger
|
|
1187
|
+
clientId: this.clientId
|
|
1185
1188
|
});
|
|
1186
1189
|
this.caseSensitive = caseSensitive;
|
|
1187
1190
|
this.fallbackToFunction = fallbackToFunction;
|
|
@@ -1248,7 +1251,7 @@ var PromiseCache = class {
|
|
|
1248
1251
|
}
|
|
1249
1252
|
this.logger?.error(
|
|
1250
1253
|
"redis error, falling back to function execution",
|
|
1251
|
-
error
|
|
1254
|
+
error
|
|
1252
1255
|
);
|
|
1253
1256
|
}
|
|
1254
1257
|
const response = await delegate();
|
package/package.json
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sebspark/promise-cache",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"require": "./dist/index.js",
|
|
12
|
+
"import": "./dist/index.mjs"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
8
15
|
"files": [
|
|
9
16
|
"dist"
|
|
10
17
|
],
|
|
@@ -17,14 +24,18 @@
|
|
|
17
24
|
"typecheck": "vitest --typecheck.only --passWithNoTests"
|
|
18
25
|
},
|
|
19
26
|
"devDependencies": {
|
|
20
|
-
"@
|
|
21
|
-
"
|
|
22
|
-
"
|
|
27
|
+
"@sebspark/otel": "*",
|
|
28
|
+
"@sebspark/tsconfig": "*",
|
|
29
|
+
"@testcontainers/redis": "11.7.2",
|
|
30
|
+
"testcontainers": "11.7.2"
|
|
23
31
|
},
|
|
24
32
|
"dependencies": {
|
|
25
|
-
"date-
|
|
33
|
+
"date-fns": "4.1.0",
|
|
26
34
|
"fix-esm": "1.0.1",
|
|
27
|
-
"redis": "5.
|
|
28
|
-
"superjson": "2.2.
|
|
35
|
+
"redis": "5.9.0",
|
|
36
|
+
"superjson": "2.2.3"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@sebspark/otel": ">=1.1.4"
|
|
29
40
|
}
|
|
30
41
|
}
|