@darco2903/expiry-cache 2.0.2 → 3.0.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/README.md +133 -25
- package/dist/ExpiryCache.d.ts +9 -22
- package/dist/ExpiryCache.js +8 -29
- package/dist/ExpiryCacheAsync.d.ts +11 -24
- package/dist/ExpiryCacheAsync.js +10 -34
- package/dist/ExpiryCacheSafe.d.ts +18 -0
- package/dist/ExpiryCacheSafe.js +31 -0
- package/dist/ExpiryCacheSafeAsync.d.ts +20 -0
- package/dist/ExpiryCacheSafeAsync.js +40 -0
- package/dist/ReturnOptions.d.ts +15 -0
- package/dist/ReturnOptions.js +24 -0
- package/dist/base/ExpiryCacheAsyncBase.d.ts +13 -0
- package/dist/base/ExpiryCacheAsyncBase.js +11 -0
- package/dist/base/ExpiryCacheBase.d.ts +112 -0
- package/dist/base/ExpiryCacheBase.js +177 -0
- package/dist/base/ExpiryCacheSyncBase.d.ts +5 -0
- package/dist/base/ExpiryCacheSyncBase.js +3 -0
- package/dist/base/index.d.ts +2 -0
- package/dist/base/index.js +2 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/interface/ExpiryCacheAsync.d.ts +6 -0
- package/dist/interface/ExpiryCacheAsync.js +2 -0
- package/dist/interface/ExpiryCacheSafe.d.ts +6 -0
- package/dist/interface/ExpiryCacheSafe.js +2 -0
- package/dist/interface/ExpiryCacheSync.d.ts +6 -0
- package/dist/interface/ExpiryCacheSync.js +2 -0
- package/dist/interface/ExpiryCacheUnsafe.d.ts +6 -0
- package/dist/interface/ExpiryCacheUnsafe.js +2 -0
- package/dist/interface/index.d.ts +4 -0
- package/dist/types/RefreshFunction.d.ts +11 -0
- package/dist/types/RefreshFunction.js +1 -0
- package/dist/types/ReturnType.d.ts +10 -0
- package/dist/types/ReturnType.js +1 -0
- package/dist/types/events.d.ts +8 -0
- package/dist/types/events.js +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +1 -0
- package/dist/utils.d.ts +10 -0
- package/dist/utils.js +17 -0
- package/package.json +8 -5
- package/dist/ExpiryCacheBase.d.ts +0 -95
- package/dist/ExpiryCacheBase.js +0 -115
- package/dist/types.d.ts +0 -2
- /package/dist/{types.js → interface/index.js} +0 -0
package/README.md
CHANGED
|
@@ -12,8 +12,11 @@ A simple in-memory cache with expiry functionality. It allows you to store data
|
|
|
12
12
|
- **Automatic Expiry**: Cache entries automatically expire after a specified duration.
|
|
13
13
|
- **Manual Expiry**: Manually expire cache entries when needed.
|
|
14
14
|
- **Synchronous and Asynchronous Fetching**: Support for both synchronous and asynchronous data fetching.
|
|
15
|
-
- **
|
|
15
|
+
- **Safe Fetching**: Safe cache fetching that returns a `Result` type, allowing for error handling without throwing exceptions.
|
|
16
|
+
- **Stale Data Access**: Option to access stale data even after it has expired.
|
|
16
17
|
- **Parameterized Fetching**: Support for fetcher functions that require parameters.
|
|
18
|
+
- **Return Options**: Allow to set expiry time when refreshing the cache. For exemple API tokens that return their expiry time.
|
|
19
|
+
- **Event Emission**: Emit events on cache refresh and expiry for better integration with other parts of your application.
|
|
17
20
|
|
|
18
21
|
## Installation
|
|
19
22
|
|
|
@@ -28,31 +31,46 @@ npm install @darco2903/expiry-cache
|
|
|
28
31
|
```ts
|
|
29
32
|
import { ExpiryCache } from "@darco2903/expiry-cache";
|
|
30
33
|
|
|
31
|
-
const cache = new ExpiryCache("initial", () => "refreshed", 1000); //
|
|
32
|
-
console.log(cache.getData()); //
|
|
34
|
+
const cache = new ExpiryCache("initial", () => "refreshed", 1000); // ExpiryCache<string, () => string>
|
|
35
|
+
console.log(cache.getData()); // initial
|
|
33
36
|
|
|
34
37
|
await new Promise((resolve) => setTimeout(resolve, 1100)); // wait for cache to expire
|
|
35
|
-
console.log(cache.isExpired); //
|
|
36
|
-
console.log(cache.getData()); //
|
|
37
|
-
console.log(cache.getRawData()); //
|
|
38
|
+
console.log(cache.isExpired); // true
|
|
39
|
+
console.log(cache.getData()); // null
|
|
40
|
+
console.log(cache.getRawData()); // initial (returns the raw data even if expired)
|
|
38
41
|
|
|
39
42
|
cache.refresh();
|
|
40
|
-
console.log(cache.getData()); //
|
|
43
|
+
console.log(cache.getData()); // refreshed
|
|
41
44
|
|
|
42
45
|
await new Promise((resolve) => setTimeout(resolve, 1100)); // wait for cache to expire
|
|
43
|
-
console.log(cache.isExpired); //
|
|
44
|
-
console.log(cache.getDataOrRefresh()); //
|
|
46
|
+
console.log(cache.isExpired); // true
|
|
47
|
+
console.log(cache.getDataOrRefresh()); // refreshed (refreshes the cache and returns the new value)
|
|
45
48
|
|
|
46
|
-
console.log(cache.expirationTime); //
|
|
47
|
-
console.log(cache.expiresAt); //
|
|
48
|
-
console.log(cache.timeToLive); //
|
|
49
|
+
console.log(cache.expirationTime); // 1000
|
|
50
|
+
console.log(cache.expiresAt); // current timestamp + 1000 milliseconds
|
|
51
|
+
console.log(cache.timeToLive); // time remaining until expiration in milliseconds
|
|
49
52
|
|
|
50
|
-
|
|
51
|
-
console.log(cache.isExpired); //
|
|
53
|
+
cache.expire(); // Manually expire the cache
|
|
54
|
+
console.log(cache.isExpired); // true
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### With Parameters
|
|
58
|
+
|
|
59
|
+
You can also use the cache with a fetcher function that requires parameters. In this case, the `refresh` method accepts the necessary parameters to fetch the new data.
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { ExpiryCache } from "@darco2903/expiry-cache";
|
|
63
|
+
|
|
64
|
+
const cache = new ExpiryCache(10, (a: number, b: number) => a + b, 200); // ExpiryCache<number, (a: number, b: number) => number>
|
|
65
|
+
|
|
66
|
+
cache.refresh(5, 7); // typed: refresh(a: number, b: number)
|
|
67
|
+
console.log(cache.getData()); // 12
|
|
52
68
|
```
|
|
53
69
|
|
|
54
70
|
### With Async Fetcher
|
|
55
71
|
|
|
72
|
+
Same as the ExpiryCache, but with an asynchronous fetcher function. The `refresh` method will return a promise that resolves when the cache has been updated.
|
|
73
|
+
|
|
56
74
|
```ts
|
|
57
75
|
import { ExpiryCacheAsync } from "@darco2903/expiry-cache";
|
|
58
76
|
|
|
@@ -68,37 +86,127 @@ async function getApiData(): Promise<string> {
|
|
|
68
86
|
const cache = new ExpiryCacheAsync("initial data", getApiData, 5000);
|
|
69
87
|
|
|
70
88
|
await cache.refresh();
|
|
71
|
-
console.log(cache.getData()); //
|
|
89
|
+
console.log(cache.getData()); // fetched data from API
|
|
72
90
|
```
|
|
73
91
|
|
|
74
|
-
### With
|
|
92
|
+
### With Result
|
|
93
|
+
|
|
94
|
+
Allows to handle errors without throwing exceptions, returning a `Result` type instead. The cache will be updated only if the result is `Ok`, otherwise nothing is changed and the cache is not refreshed when the result is `Err`.
|
|
95
|
+
|
|
96
|
+
In this example, we have a fetcher function that performs a division operation. If the divisor is zero, it returns an error instead of throwing an exception.
|
|
75
97
|
|
|
76
98
|
```ts
|
|
77
|
-
import {
|
|
99
|
+
import { ExpiryCacheSafe } from "@darco2903/expiry-cache";
|
|
100
|
+
import { err, ok } from "neverthrow";
|
|
78
101
|
|
|
79
|
-
const cache = new
|
|
102
|
+
const cache = new ExpiryCacheSafe(1, (a: number, b: number) => (b === 0 ? err("Division by zero") : ok(a / b)), 100);
|
|
103
|
+
console.log(cache.getData()); // 1
|
|
104
|
+
console.log(cache.timeToLiveAsTime?.toStringWithUnit()); // ~100ms
|
|
80
105
|
|
|
81
|
-
|
|
82
|
-
console.log(cache.
|
|
106
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
107
|
+
console.log(cache.isExpired); // true
|
|
108
|
+
|
|
109
|
+
cache.refresh(4, 2); // ok(2)
|
|
110
|
+
console.log(cache.getData()); // 2
|
|
111
|
+
console.log(cache.timeToLiveAsTime?.toStringWithUnit()); // ~100ms
|
|
112
|
+
|
|
113
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
114
|
+
console.log(cache.isExpired); // true
|
|
115
|
+
|
|
116
|
+
cache.refresh(4, 0); // err("Division by zero")
|
|
117
|
+
console.log(cache.getData()); // null
|
|
118
|
+
console.log(cache.isExpired); // true
|
|
83
119
|
```
|
|
84
120
|
|
|
85
|
-
###
|
|
121
|
+
### Event Emission
|
|
86
122
|
|
|
87
123
|
```ts
|
|
88
124
|
import { ExpiryCache } from "@darco2903/expiry-cache";
|
|
89
125
|
|
|
90
|
-
const cache = new ExpiryCache(0, () =>
|
|
126
|
+
const cache = new ExpiryCache(0, () => 10, 1000);
|
|
127
|
+
cache.on("expired", () => {
|
|
128
|
+
console.log("Cache expired");
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
cache.on("refreshed", (value) => {
|
|
132
|
+
console.log("Cache refreshed with value:", value);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
cache.expire(); // trigger the expired event
|
|
136
|
+
|
|
137
|
+
cache.refresh(); // trigger the refreshed event
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Setting expiry time when refreshing
|
|
141
|
+
|
|
142
|
+
#### ExpiresIn
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import { ExpiryCache, ReturnOptions } from "@darco2903/expiry-cache";
|
|
146
|
+
|
|
147
|
+
const cache = new ExpiryCache(0, () => ReturnOptions.ExpiresIn(0, 200), 1000);
|
|
148
|
+
console.log(cache.expirationTime); // 1000
|
|
91
149
|
|
|
92
150
|
cache.refresh();
|
|
93
|
-
|
|
94
|
-
|
|
151
|
+
console.log(cache.expirationTime); // 200
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
#### ExpiresAt
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
import { ExpiryCache, ReturnOptions } from "@darco2903/expiry-cache";
|
|
158
|
+
|
|
159
|
+
const cache = new ExpiryCache(0, () => ReturnOptions.ExpiresAt(0, Date.now() + 200), 1000);
|
|
160
|
+
console.log(cache.expiresAt - Date.now()); // ~1000
|
|
161
|
+
|
|
162
|
+
cache.refresh();
|
|
163
|
+
console.log(cache.expiresAt - Date.now()); // ~200
|
|
95
164
|
```
|
|
96
165
|
|
|
97
166
|
### SecondThought Integration
|
|
98
167
|
|
|
99
168
|
```ts
|
|
100
169
|
import { ExpiryCache } from "@darco2903/expiry-cache";
|
|
101
|
-
import { Minute } from "@darco2903/secondthought";
|
|
170
|
+
import { Millisecond, Second, Minute, Hour } from "@darco2903/secondthought";
|
|
102
171
|
|
|
103
172
|
const cache = new ExpiryCache("data", () => "data", new Minute(5)); // Cache expires in 5 minutes
|
|
173
|
+
|
|
174
|
+
cache.setExpiresIn(new Hour(1)); // Update the cache to expire in 1 hour
|
|
175
|
+
cache.setExpiresAt(Millisecond.now().add(new Second(2))); // Set the cache to expire in 2 seconds
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Full Example with Async Fetcher, Result and ReturnOptions
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { ExpiryCacheSafeAsync, ReturnOptions } from "@darco2903/expiry-cache";
|
|
182
|
+
import { Second } from "@darco2903/secondthought";
|
|
183
|
+
import { ResultAsync, okAsync } from "neverthrow";
|
|
184
|
+
|
|
185
|
+
type TokenData = {
|
|
186
|
+
token: string;
|
|
187
|
+
expiresIn: number;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
function fetchApiToken(): ResultAsync<TokenData, string> {
|
|
191
|
+
return ResultAsync.fromPromise(
|
|
192
|
+
fetch("https://example.com/api/token").then((res) => res.json()),
|
|
193
|
+
(err) => String(err),
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const cache = new ExpiryCacheSafeAsync("", () => {
|
|
198
|
+
return fetchApiToken().andThen((res) => {
|
|
199
|
+
return okAsync(ReturnOptions.ExpiresIn(res.token, new Second(res.expiresIn)));
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
cache.expire(); // expire the cache immediately to force a refresh on the first call
|
|
203
|
+
|
|
204
|
+
await cache.refresh().match(
|
|
205
|
+
(token) => {
|
|
206
|
+
console.log("Fetched API token:", token);
|
|
207
|
+
},
|
|
208
|
+
(err) => {
|
|
209
|
+
console.error("Error fetching API token:", err);
|
|
210
|
+
},
|
|
211
|
+
);
|
|
104
212
|
```
|
package/dist/ExpiryCache.d.ts
CHANGED
|
@@ -1,27 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import type {
|
|
4
|
-
|
|
1
|
+
import { ExpiryCacheSyncBase } from "./base/index.js";
|
|
2
|
+
import type { RefreshFunctionUnsafeSync } from "./types/index.js";
|
|
3
|
+
import type { IExpiryCacheSync, IExpiryCacheUnsafe } from "./interface/index.js";
|
|
4
|
+
import type { CacheEventsUnsafe } from "./types/events.js";
|
|
5
|
+
export declare class ExpiryCache<T, F extends RefreshFunctionUnsafeSync<T>> extends ExpiryCacheSyncBase<T, F, CacheEventsUnsafe<T>> implements IExpiryCacheSync<T, F>, IExpiryCacheUnsafe<T, F> {
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
-
* @param data The initial data to be cached.
|
|
8
|
-
* @param callback The function to refresh the cached data.
|
|
9
|
-
* @param expirationTime The time in milliseconds after which the cache expires. Defaults to 60_000 (1 minute). If set to 0, the cache will never expire.
|
|
7
|
+
* Refreshes the cache by calling the refresh function with the provided arguments and updates the cache data. Returns the updated cache data.
|
|
10
8
|
*/
|
|
11
|
-
|
|
9
|
+
refresh(...args: Parameters<F>): T;
|
|
12
10
|
/**
|
|
13
|
-
*
|
|
11
|
+
* Returns the cached data if it is not expired. If the cache is expired, it refreshes the cache by calling the refresh function with the provided arguments and returns the updated cache data.
|
|
14
12
|
*/
|
|
15
|
-
|
|
16
|
-
getDataOrRefresh(...args: Parameters<U>): T;
|
|
17
|
-
/**
|
|
18
|
-
* Refreshes the cached data and sets a new expiration timestamp.
|
|
19
|
-
* @param expiresAt The new expiration timestamp in milliseconds.
|
|
20
|
-
*/
|
|
21
|
-
refreshExpiresAt(expiresAt: number | Time, ...args: Parameters<U>): void;
|
|
22
|
-
/**
|
|
23
|
-
* Refreshes the cached data and sets a new expiration time.
|
|
24
|
-
* @param expirationTime The new expiration time in milliseconds.
|
|
25
|
-
*/
|
|
26
|
-
refreshExpiresIn(expirationTime: number | Time, ...args: Parameters<U>): void;
|
|
13
|
+
getDataOrRefresh(...args: Parameters<F>): T;
|
|
27
14
|
}
|
package/dist/ExpiryCache.js
CHANGED
|
@@ -1,41 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
export class ExpiryCache extends ExpiryCacheBase {
|
|
1
|
+
import { ExpiryCacheSyncBase } from "./base/index.js";
|
|
2
|
+
export class ExpiryCache extends ExpiryCacheSyncBase {
|
|
4
3
|
/**
|
|
5
|
-
*
|
|
6
|
-
* @param data The initial data to be cached.
|
|
7
|
-
* @param callback The function to refresh the cached data.
|
|
8
|
-
* @param expirationTime The time in milliseconds after which the cache expires. Defaults to 60_000 (1 minute). If set to 0, the cache will never expire.
|
|
4
|
+
* Refreshes the cache by calling the refresh function with the provided arguments and updates the cache data. Returns the updated cache data.
|
|
9
5
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
refresh(...args) {
|
|
7
|
+
this.setData(this.refreshFn(...args));
|
|
8
|
+
this._emit("refreshed", this.data);
|
|
9
|
+
return this.data;
|
|
12
10
|
}
|
|
13
11
|
/**
|
|
14
|
-
*
|
|
12
|
+
* Returns the cached data if it is not expired. If the cache is expired, it refreshes the cache by calling the refresh function with the provided arguments and returns the updated cache data.
|
|
15
13
|
*/
|
|
16
|
-
refresh(...args) {
|
|
17
|
-
this.setData(this.callback(...args));
|
|
18
|
-
}
|
|
19
14
|
getDataOrRefresh(...args) {
|
|
20
15
|
if (this.isExpired) {
|
|
21
16
|
this.refresh(...args);
|
|
22
17
|
}
|
|
23
18
|
return this.data;
|
|
24
19
|
}
|
|
25
|
-
/**
|
|
26
|
-
* Refreshes the cached data and sets a new expiration timestamp.
|
|
27
|
-
* @param expiresAt The new expiration timestamp in milliseconds.
|
|
28
|
-
*/
|
|
29
|
-
refreshExpiresAt(expiresAt, ...args) {
|
|
30
|
-
const expAt = this.argToMs(expiresAt);
|
|
31
|
-
this.setDataExpiresAt(this.callback(...args), expAt);
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Refreshes the cached data and sets a new expiration time.
|
|
35
|
-
* @param expirationTime The new expiration time in milliseconds.
|
|
36
|
-
*/
|
|
37
|
-
refreshExpiresIn(expirationTime, ...args) {
|
|
38
|
-
const expTime = this.argToMs(expirationTime);
|
|
39
|
-
this.setDataExpiresIn(this.callback(...args), expTime);
|
|
40
|
-
}
|
|
41
20
|
}
|
|
@@ -1,29 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { ExpiryCacheAsyncBase } from "./base/index.js";
|
|
2
|
+
import type { ReturnOptions } from "./ReturnOptions.js";
|
|
3
|
+
import type { RefreshFunctionUnsafeAsync, ReturnTypeUnsafeAsync } from "./types/index.js";
|
|
4
|
+
import type { IExpiryCacheAsync, IExpiryCacheUnsafe } from "./interface/index.js";
|
|
5
|
+
import type { CacheEventsUnsafe } from "./types/events.js";
|
|
6
|
+
export declare class ExpiryCacheAsync<T, F extends RefreshFunctionUnsafeAsync<T>> extends ExpiryCacheAsyncBase<T, F, ReturnTypeUnsafeAsync<T | ReturnOptions<T>>, CacheEventsUnsafe<T>> implements IExpiryCacheAsync<T, F>, IExpiryCacheUnsafe<T, F> {
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* @param callback The function to refresh the cached data.
|
|
11
|
-
* @param expirationTime The time in milliseconds after which the cache expires. Defaults to 60_000 (1 minute). If set to 0, the cache will never expire.
|
|
8
|
+
* Refreshes the cache by calling the refresh function with the provided arguments and updates the cache data. Returns the updated cache data.
|
|
9
|
+
* If a refresh is already in progress, it returns the existing refresh promise instead of calling the callback again.
|
|
12
10
|
*/
|
|
13
|
-
|
|
11
|
+
refresh(...args: Parameters<F>): Promise<T>;
|
|
14
12
|
/**
|
|
15
|
-
*
|
|
13
|
+
* Returns the cached data if it is not expired. If the cache is expired, it refreshes the cache by calling the refresh function with the provided arguments and returns the updated cache data.
|
|
16
14
|
*/
|
|
17
|
-
|
|
18
|
-
getDataOrRefresh(...args: Parameters<U>): Promise<T>;
|
|
19
|
-
/**
|
|
20
|
-
* Refreshes the cached data and sets a new expiration timestamp.
|
|
21
|
-
* @param expiresAt The new expiration timestamp in milliseconds.
|
|
22
|
-
*/
|
|
23
|
-
refreshExpiresAt(expiresAt: number | Time, ...args: Parameters<U>): Promise<void>;
|
|
24
|
-
/**
|
|
25
|
-
* Refreshes the cached data and sets a new expiration time.
|
|
26
|
-
* @param expirationTime The new expiration time in milliseconds.
|
|
27
|
-
*/
|
|
28
|
-
refreshExpiresIn(expirationTime: number | Time, ...args: Parameters<U>): Promise<void>;
|
|
15
|
+
getDataOrRefresh(...args: Parameters<F>): Promise<T>;
|
|
29
16
|
}
|
package/dist/ExpiryCacheAsync.js
CHANGED
|
@@ -1,52 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
export class ExpiryCacheAsync extends ExpiryCacheBase {
|
|
4
|
-
get refreshing() {
|
|
5
|
-
return this._refreshCb !== null;
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Creates an instance of ExpiryCache.
|
|
9
|
-
* @param data The initial data to be cached.
|
|
10
|
-
* @param callback The function to refresh the cached data.
|
|
11
|
-
* @param expirationTime The time in milliseconds after which the cache expires. Defaults to 60_000 (1 minute). If set to 0, the cache will never expire.
|
|
12
|
-
*/
|
|
13
|
-
constructor(data, callback, expirationTime = new Minute(1)) {
|
|
14
|
-
super(data, callback, expirationTime);
|
|
15
|
-
this._refreshCb = null;
|
|
16
|
-
}
|
|
1
|
+
import { ExpiryCacheAsyncBase } from "./base/index.js";
|
|
2
|
+
export class ExpiryCacheAsync extends ExpiryCacheAsyncBase {
|
|
17
3
|
/**
|
|
18
|
-
* Refreshes the
|
|
4
|
+
* Refreshes the cache by calling the refresh function with the provided arguments and updates the cache data. Returns the updated cache data.
|
|
5
|
+
* If a refresh is already in progress, it returns the existing refresh promise instead of calling the callback again.
|
|
19
6
|
*/
|
|
20
7
|
async refresh(...args) {
|
|
21
8
|
if (this.refreshing) {
|
|
22
9
|
await this._refreshCb;
|
|
23
10
|
}
|
|
24
11
|
else {
|
|
25
|
-
this._refreshCb = this.
|
|
12
|
+
this._refreshCb = this.refreshFn(...args);
|
|
26
13
|
this.setData(await this._refreshCb);
|
|
14
|
+
this._emit("refreshed", this.data);
|
|
27
15
|
this._refreshCb = null;
|
|
28
16
|
}
|
|
17
|
+
return this.data;
|
|
29
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Returns the cached data if it is not expired. If the cache is expired, it refreshes the cache by calling the refresh function with the provided arguments and returns the updated cache data.
|
|
21
|
+
*/
|
|
30
22
|
async getDataOrRefresh(...args) {
|
|
31
23
|
if (this.isExpired) {
|
|
32
24
|
await this.refresh(...args);
|
|
33
25
|
}
|
|
34
26
|
return this.data;
|
|
35
27
|
}
|
|
36
|
-
/**
|
|
37
|
-
* Refreshes the cached data and sets a new expiration timestamp.
|
|
38
|
-
* @param expiresAt The new expiration timestamp in milliseconds.
|
|
39
|
-
*/
|
|
40
|
-
async refreshExpiresAt(expiresAt, ...args) {
|
|
41
|
-
const expAt = this.argToMs(expiresAt);
|
|
42
|
-
this.setDataExpiresAt(await this.callback(...args), expAt);
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Refreshes the cached data and sets a new expiration time.
|
|
46
|
-
* @param expirationTime The new expiration time in milliseconds.
|
|
47
|
-
*/
|
|
48
|
-
async refreshExpiresIn(expirationTime, ...args) {
|
|
49
|
-
const expTime = this.argToMs(expirationTime);
|
|
50
|
-
this.setDataExpiresIn(await this.callback(...args), expTime);
|
|
51
|
-
}
|
|
52
28
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Result } from "neverthrow";
|
|
2
|
+
import { ExpiryCacheSyncBase } from "./base/index.js";
|
|
3
|
+
import type { RefreshFunctionSafeSync } from "./types/index.js";
|
|
4
|
+
import type { IExpiryCacheSafe, IExpiryCacheSync } from "./interface/index.js";
|
|
5
|
+
import type { CacheEventsSafe } from "./types/events.js";
|
|
6
|
+
export declare class ExpiryCacheSafe<T, E, F extends RefreshFunctionSafeSync<T, E>> extends ExpiryCacheSyncBase<T, F, CacheEventsSafe<T, E>, E> implements IExpiryCacheSync<T, F, E>, IExpiryCacheSafe<T, F, E> {
|
|
7
|
+
/**
|
|
8
|
+
* Refreshes the cache by calling the refresh function with the provided arguments and updates the cache data if the result is Ok, otherwise it does not update the cache data.
|
|
9
|
+
* Returns the refresh function result.
|
|
10
|
+
*/
|
|
11
|
+
refresh(...args: Parameters<F>): Result<T, E>;
|
|
12
|
+
/**
|
|
13
|
+
* Returns the cached data if it is not expired.
|
|
14
|
+
* If the cache is expired, it refreshes the cache by calling the refresh function with the provided arguments and returns the refresh function result.
|
|
15
|
+
* It behaves the same as the refresh method if the cache is expired, otherwise it returns the cached data wrapped in an Ok result.
|
|
16
|
+
*/
|
|
17
|
+
getDataOrRefresh(...args: Parameters<F>): Result<T, E>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ok } from "neverthrow";
|
|
2
|
+
import { ExpiryCacheSyncBase } from "./base/index.js";
|
|
3
|
+
import { mapRefreshReturn } from "./utils.js";
|
|
4
|
+
export class ExpiryCacheSafe extends ExpiryCacheSyncBase {
|
|
5
|
+
/**
|
|
6
|
+
* Refreshes the cache by calling the refresh function with the provided arguments and updates the cache data if the result is Ok, otherwise it does not update the cache data.
|
|
7
|
+
* Returns the refresh function result.
|
|
8
|
+
*/
|
|
9
|
+
refresh(...args) {
|
|
10
|
+
return this.refreshFn(...args)
|
|
11
|
+
.andTee((data) => this.setData(data))
|
|
12
|
+
.map((mapRefreshReturn))
|
|
13
|
+
.andTee((data) => {
|
|
14
|
+
this._emit("refreshed", data);
|
|
15
|
+
})
|
|
16
|
+
.orTee((err) => {
|
|
17
|
+
this._emit("error", err);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Returns the cached data if it is not expired.
|
|
22
|
+
* If the cache is expired, it refreshes the cache by calling the refresh function with the provided arguments and returns the refresh function result.
|
|
23
|
+
* It behaves the same as the refresh method if the cache is expired, otherwise it returns the cached data wrapped in an Ok result.
|
|
24
|
+
*/
|
|
25
|
+
getDataOrRefresh(...args) {
|
|
26
|
+
if (this.isExpired) {
|
|
27
|
+
return this.refresh(...args);
|
|
28
|
+
}
|
|
29
|
+
return ok(this.data);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type ResultAsync } from "neverthrow";
|
|
2
|
+
import { ExpiryCacheAsyncBase } from "./base/index.js";
|
|
3
|
+
import type { ReturnOptions } from "./ReturnOptions.js";
|
|
4
|
+
import type { RefreshFunctionSafeAsync, ReturnTypeSafeAsync } from "./types/index.js";
|
|
5
|
+
import type { IExpiryCacheAsync, IExpiryCacheSafe } from "./interface/index.js";
|
|
6
|
+
import type { CacheEventsSafe } from "./types/events.js";
|
|
7
|
+
export declare class ExpiryCacheSafeAsync<T, E, F extends RefreshFunctionSafeAsync<T, E>> extends ExpiryCacheAsyncBase<T, F, ReturnTypeSafeAsync<T | ReturnOptions<T>, E>, CacheEventsSafe<T, E>, E> implements IExpiryCacheAsync<T, F, E>, IExpiryCacheSafe<T, F, E> {
|
|
8
|
+
/**
|
|
9
|
+
* Refreshes the cache by calling the refresh function with the provided arguments and updates the cache data if the result is Ok, otherwise it does not update the cache data.
|
|
10
|
+
* Returns the refresh function result.
|
|
11
|
+
* If a refresh is already in progress, it returns the existing refresh promise instead of calling the callback again.
|
|
12
|
+
*/
|
|
13
|
+
refresh(...args: Parameters<F>): ResultAsync<T, E>;
|
|
14
|
+
/**
|
|
15
|
+
* Returns the cached data if it is not expired.
|
|
16
|
+
* If the cache is expired, it refreshes the cache by calling the refresh function with the provided arguments and returns the refresh function result.
|
|
17
|
+
* It behaves the same as the refresh method if the cache is expired, otherwise it returns the cached data wrapped in an Ok result.
|
|
18
|
+
*/
|
|
19
|
+
getDataOrRefresh(...args: Parameters<F>): ResultAsync<T, E>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { okAsync } from "neverthrow";
|
|
2
|
+
import { ExpiryCacheAsyncBase } from "./base/index.js";
|
|
3
|
+
import { mapRefreshReturn } from "./utils.js";
|
|
4
|
+
export class ExpiryCacheSafeAsync extends ExpiryCacheAsyncBase {
|
|
5
|
+
/**
|
|
6
|
+
* Refreshes the cache by calling the refresh function with the provided arguments and updates the cache data if the result is Ok, otherwise it does not update the cache data.
|
|
7
|
+
* Returns the refresh function result.
|
|
8
|
+
* If a refresh is already in progress, it returns the existing refresh promise instead of calling the callback again.
|
|
9
|
+
*/
|
|
10
|
+
refresh(...args) {
|
|
11
|
+
if (this._refreshCb !== null) {
|
|
12
|
+
return this._refreshCb.map((mapRefreshReturn));
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
this._refreshCb = this.refreshFn(...args);
|
|
16
|
+
return this._refreshCb
|
|
17
|
+
.andTee((res) => this.setData(res))
|
|
18
|
+
.map((mapRefreshReturn))
|
|
19
|
+
.andTee((data) => {
|
|
20
|
+
this._refreshCb = null;
|
|
21
|
+
this._emit("refreshed", data);
|
|
22
|
+
})
|
|
23
|
+
.orTee((err) => {
|
|
24
|
+
this._refreshCb = null;
|
|
25
|
+
this._emit("error", err);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Returns the cached data if it is not expired.
|
|
31
|
+
* If the cache is expired, it refreshes the cache by calling the refresh function with the provided arguments and returns the refresh function result.
|
|
32
|
+
* It behaves the same as the refresh method if the cache is expired, otherwise it returns the cached data wrapped in an Ok result.
|
|
33
|
+
*/
|
|
34
|
+
getDataOrRefresh(...args) {
|
|
35
|
+
if (this.isExpired) {
|
|
36
|
+
return this.refresh(...args);
|
|
37
|
+
}
|
|
38
|
+
return okAsync(this.data);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Millisecond, type Time } from "@darco2903/secondthought";
|
|
2
|
+
export declare abstract class ReturnOptions<T> {
|
|
3
|
+
readonly data: T;
|
|
4
|
+
constructor(data: T);
|
|
5
|
+
static ExpiresAt<T>(data: T, expiresAt: number | Time): ReturnOptionsExpiresAtClass<T>;
|
|
6
|
+
static ExpiresIn<T>(data: T, expiresIn: number | Time): ReturnOptionsExpiresInClass<T>;
|
|
7
|
+
}
|
|
8
|
+
export declare class ReturnOptionsExpiresInClass<T> extends ReturnOptions<T> {
|
|
9
|
+
readonly expiresIn: Millisecond;
|
|
10
|
+
constructor(data: T, expiresIn: number | Time);
|
|
11
|
+
}
|
|
12
|
+
export declare class ReturnOptionsExpiresAtClass<T> extends ReturnOptions<T> {
|
|
13
|
+
readonly expiresAt: Millisecond;
|
|
14
|
+
constructor(data: T, expiresAt: number | Time);
|
|
15
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { argToMs } from "./utils.js";
|
|
2
|
+
export class ReturnOptions {
|
|
3
|
+
constructor(data) {
|
|
4
|
+
this.data = data;
|
|
5
|
+
}
|
|
6
|
+
static ExpiresAt(data, expiresAt) {
|
|
7
|
+
return new ReturnOptionsExpiresAtClass(data, expiresAt);
|
|
8
|
+
}
|
|
9
|
+
static ExpiresIn(data, expiresIn) {
|
|
10
|
+
return new ReturnOptionsExpiresInClass(data, expiresIn);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class ReturnOptionsExpiresInClass extends ReturnOptions {
|
|
14
|
+
constructor(data, expiresIn) {
|
|
15
|
+
super(data);
|
|
16
|
+
this.expiresIn = argToMs(expiresIn);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export class ReturnOptionsExpiresAtClass extends ReturnOptions {
|
|
20
|
+
constructor(data, expiresAt) {
|
|
21
|
+
super(data);
|
|
22
|
+
this.expiresAt = argToMs(expiresAt);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Time } from "@darco2903/secondthought";
|
|
2
|
+
import { ExpiryCacheBase } from "./ExpiryCacheBase.js";
|
|
3
|
+
import type { ReturnOptions } from "../ReturnOptions.js";
|
|
4
|
+
import type { RefreshFunctionAsync } from "../types/RefreshFunction.js";
|
|
5
|
+
import type { ReturnTypeAsync } from "../types/ReturnType.js";
|
|
6
|
+
import type { CacheEvents } from "../types/events.js";
|
|
7
|
+
export declare abstract class ExpiryCacheAsyncBase<T, F extends RefreshFunctionAsync<T, E>, V extends ReturnTypeAsync<T | ReturnOptions<T>, E>, M extends CacheEvents<T, E>, E = any> extends ExpiryCacheBase<T, F, M, E> {
|
|
8
|
+
/** The promise of the current refresh operation, or null if no refresh is in progress. */
|
|
9
|
+
protected _refreshCb: V | null;
|
|
10
|
+
/** Indicates whether the cache is currently being refreshed. */
|
|
11
|
+
get refreshing(): boolean;
|
|
12
|
+
constructor(data: T, callback: F, expirationTime?: number | Time);
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ExpiryCacheBase } from "./ExpiryCacheBase.js";
|
|
2
|
+
export class ExpiryCacheAsyncBase extends ExpiryCacheBase {
|
|
3
|
+
/** Indicates whether the cache is currently being refreshed. */
|
|
4
|
+
get refreshing() {
|
|
5
|
+
return this._refreshCb !== null;
|
|
6
|
+
}
|
|
7
|
+
constructor(data, callback, expirationTime) {
|
|
8
|
+
super(data, callback, expirationTime);
|
|
9
|
+
this._refreshCb = null;
|
|
10
|
+
}
|
|
11
|
+
}
|