@zudojs/cache 0.0.1 → 1.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 +90 -14
- package/dist/cache.d.ts +107 -18
- package/dist/cache.js +393 -33
- package/dist/constants.d.ts +46 -12
- package/dist/constants.js +47 -19
- package/dist/index.d.ts +10 -9
- package/dist/index.js +9 -8
- package/dist/invalidation.d.ts +23 -16
- package/dist/invalidation.js +43 -33
- package/dist/key-builder.d.ts +15 -0
- package/dist/key-builder.js +43 -3
- package/dist/lock.d.ts +36 -2
- package/dist/lock.js +160 -30
- package/dist/memory.d.ts +63 -7
- package/dist/memory.js +223 -39
- package/dist/metrics.d.ts +10 -0
- package/dist/metrics.js +49 -4
- package/dist/serializer.d.ts +19 -10
- package/dist/serializer.js +88 -21
- package/dist/store.d.ts +21 -11
- package/dist/store.js +125 -65
- package/dist/tags.d.ts +32 -12
- package/dist/tags.js +113 -33
- package/dist/types-adapter.d.ts +23 -9
- package/dist/types-config.d.ts +46 -9
- package/dist/types-health.d.ts +5 -2
- package/dist/types-keys.d.ts +8 -4
- package/dist/types-lock.d.ts +8 -0
- package/dist/types-operations.d.ts +13 -20
- package/dist/types-results.d.ts +7 -1
- package/dist/types-tags.d.ts +9 -0
- package/dist/types-utility.d.ts +6 -10
- package/dist/types-values.d.ts +9 -14
- package/dist/types.d.ts +6 -6
- package/dist/utils.d.ts +65 -0
- package/dist/utils.js +210 -0
- package/package.json +14 -7
- package/dist/.tsbuildinfo +0 -1
- package/dist/cache.d.ts.map +0 -1
- package/dist/cache.js.map +0 -1
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/invalidation.d.ts.map +0 -1
- package/dist/invalidation.js.map +0 -1
- package/dist/key-builder.d.ts.map +0 -1
- package/dist/key-builder.js.map +0 -1
- package/dist/lock.d.ts.map +0 -1
- package/dist/lock.js.map +0 -1
- package/dist/memory.d.ts.map +0 -1
- package/dist/memory.js.map +0 -1
- package/dist/metrics.d.ts.map +0 -1
- package/dist/metrics.js.map +0 -1
- package/dist/serializer.d.ts.map +0 -1
- package/dist/serializer.js.map +0 -1
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js.map +0 -1
- package/dist/tags.d.ts.map +0 -1
- package/dist/tags.js.map +0 -1
- package/dist/types-adapter.d.ts.map +0 -1
- package/dist/types-adapter.js.map +0 -1
- package/dist/types-config.d.ts.map +0 -1
- package/dist/types-config.js.map +0 -1
- package/dist/types-events.d.ts.map +0 -1
- package/dist/types-events.js.map +0 -1
- package/dist/types-health.d.ts.map +0 -1
- package/dist/types-health.js.map +0 -1
- package/dist/types-keys.d.ts.map +0 -1
- package/dist/types-keys.js.map +0 -1
- package/dist/types-lock.d.ts.map +0 -1
- package/dist/types-lock.js.map +0 -1
- package/dist/types-metrics.d.ts.map +0 -1
- package/dist/types-metrics.js.map +0 -1
- package/dist/types-operations.d.ts.map +0 -1
- package/dist/types-operations.js.map +0 -1
- package/dist/types-results.d.ts.map +0 -1
- package/dist/types-results.js.map +0 -1
- package/dist/types-tags.d.ts.map +0 -1
- package/dist/types-tags.js.map +0 -1
- package/dist/types-utility.d.ts.map +0 -1
- package/dist/types-utility.js.map +0 -1
- package/dist/types-values.d.ts.map +0 -1
- package/dist/types-values.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
package/dist/lock.js
CHANGED
|
@@ -1,52 +1,86 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @zudojs/cache — Lock Manager
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
|
+
* In-process lock manager with a pluggable `CacheLockStore`, for preventing
|
|
5
|
+
* concurrent cache operations. The bundled `InMemoryLockStore` holds leases
|
|
6
|
+
* in a single `Map` in a single process — it is NOT distributed. Pass a
|
|
7
|
+
* shared store (the exported `defaultLockStore` to share across services in
|
|
8
|
+
* one process, or a Redis-backed `CacheLockStore` to share across processes)
|
|
9
|
+
* via `CacheConfig.lockStore` when wider mutual exclusion is required.
|
|
10
|
+
*
|
|
11
|
+
* Leases are measured on a monotonic clock and are renewed by a heartbeat
|
|
12
|
+
* while the critical section runs, so a slow `fn()` does not silently lose
|
|
13
|
+
* its lock to expiry. If a lease is lost anyway, `withLock` aborts the
|
|
14
|
+
* signal it passed to `fn` and throws rather than reporting success.
|
|
4
15
|
*/
|
|
5
|
-
import {
|
|
6
|
-
import { DEFAULT_LOCK_RETRY_ATTEMPTS, DEFAULT_LOCK_RETRY_DELAY_MS, DEFAULT_LOCK_TTL_MS, } from "./constants.js";
|
|
16
|
+
import { randomUUID } from "node:crypto";
|
|
17
|
+
import { DEFAULT_LOCK_RETRY_ATTEMPTS, DEFAULT_LOCK_RETRY_DELAY_MS, DEFAULT_LOCK_TTL_MS, LOCK_HEARTBEAT_DIVISOR, } from "./constants.js";
|
|
7
18
|
import { CacheError, CacheOperation } from "./errors.js";
|
|
19
|
+
import { assertValidTtl, monotonicNow, wallClockFor } from "./utils.js";
|
|
8
20
|
function generateToken() {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
21
|
+
return randomUUID();
|
|
22
|
+
}
|
|
23
|
+
/** Separates the namespace from the lock name in the internal map key. */
|
|
24
|
+
const LOCK_SCOPE_SEPARATOR = "\u0000";
|
|
25
|
+
/**
|
|
26
|
+
* Composes the scoped lock name. Two callers holding the same lock name
|
|
27
|
+
* under different namespaces do not contend.
|
|
28
|
+
*/
|
|
29
|
+
function scopedLockKey(key, options) {
|
|
30
|
+
return options?.namespace !== undefined
|
|
31
|
+
? `${options.namespace}${LOCK_SCOPE_SEPARATOR}${key}`
|
|
32
|
+
: key;
|
|
13
33
|
}
|
|
14
34
|
export class InMemoryLockStore {
|
|
15
35
|
locks = new Map();
|
|
16
36
|
async acquire(key, options) {
|
|
17
|
-
const ttl = options?.ttl
|
|
37
|
+
const ttl = options?.ttl !== undefined ? options.ttl : DEFAULT_LOCK_TTL_MS;
|
|
38
|
+
// A negative or zero TTL would mint an already-expired lease that the
|
|
39
|
+
// next sweep drops, giving no exclusion at all while appearing to work.
|
|
40
|
+
assertValidTtl(ttl);
|
|
18
41
|
const token = generateToken();
|
|
19
|
-
const now =
|
|
20
|
-
const expiresAt = now + ttl;
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (this.locks.has(key))
|
|
42
|
+
const now = monotonicNow();
|
|
43
|
+
const expiresAt = ttl !== null ? now + ttl : null;
|
|
44
|
+
const scoped = scopedLockKey(key, options);
|
|
45
|
+
this.sweepExpired(now);
|
|
46
|
+
if (this.locks.has(scoped))
|
|
25
47
|
return null;
|
|
26
|
-
this.locks.set(
|
|
48
|
+
this.locks.set(scoped, { token, expiresAt });
|
|
27
49
|
return {
|
|
28
50
|
key,
|
|
29
51
|
token,
|
|
30
|
-
acquiredAt:
|
|
31
|
-
expiresAt:
|
|
52
|
+
acquiredAt: wallClockFor(now),
|
|
53
|
+
expiresAt: expiresAt !== null ? wallClockFor(expiresAt) : null,
|
|
32
54
|
release: async () => {
|
|
33
|
-
const current = this.locks.get(
|
|
55
|
+
const current = this.locks.get(scoped);
|
|
34
56
|
if (current && current.token === token) {
|
|
35
|
-
this.locks.delete(
|
|
57
|
+
this.locks.delete(scoped);
|
|
36
58
|
return true;
|
|
37
59
|
}
|
|
38
60
|
return false;
|
|
39
61
|
},
|
|
40
62
|
extend: async (newTtl) => {
|
|
41
|
-
|
|
63
|
+
assertValidTtl(newTtl);
|
|
64
|
+
const current = this.locks.get(scoped);
|
|
42
65
|
if (current && current.token === token) {
|
|
43
|
-
this.locks.set(
|
|
66
|
+
this.locks.set(scoped, {
|
|
67
|
+
...current,
|
|
68
|
+
expiresAt: newTtl !== null ? monotonicNow() + newTtl : null,
|
|
69
|
+
});
|
|
44
70
|
return true;
|
|
45
71
|
}
|
|
46
72
|
return false;
|
|
47
73
|
},
|
|
48
74
|
};
|
|
49
75
|
}
|
|
76
|
+
/** Removes all expired locks. Called opportunistically on each acquire. */
|
|
77
|
+
sweepExpired(now = monotonicNow()) {
|
|
78
|
+
for (const [key, lock] of [...this.locks]) {
|
|
79
|
+
if (lock.expiresAt !== null && now >= lock.expiresAt) {
|
|
80
|
+
this.locks.delete(key);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
50
84
|
get size() {
|
|
51
85
|
return this.locks.size;
|
|
52
86
|
}
|
|
@@ -63,34 +97,126 @@ export class CacheLockManager {
|
|
|
63
97
|
this.retryAttempts = options?.retryAttempts ?? DEFAULT_LOCK_RETRY_ATTEMPTS;
|
|
64
98
|
this.retryDelayMs = options?.retryDelayMs ?? DEFAULT_LOCK_RETRY_DELAY_MS;
|
|
65
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Acquires a lock, retrying on contention.
|
|
102
|
+
*
|
|
103
|
+
* Returns `null` for ordinary contention (someone else holds it) and
|
|
104
|
+
* throws only when the *last* attempt failed with a store error — the two
|
|
105
|
+
* outcomes decide differently (retry vs. fail the request), so they are
|
|
106
|
+
* never conflated.
|
|
107
|
+
*/
|
|
66
108
|
async acquire(key, options) {
|
|
109
|
+
// Per-call retry options take precedence over manager defaults.
|
|
110
|
+
// `attempts: 0` is honored (single attempt, no retries).
|
|
111
|
+
const attempts = options?.retry?.attempts ?? this.retryAttempts;
|
|
112
|
+
const delay = options?.retry?.delay ?? this.retryDelayMs;
|
|
67
113
|
let lastError;
|
|
68
|
-
for (let attempt = 0; attempt <=
|
|
114
|
+
for (let attempt = 0; attempt <= attempts; attempt++) {
|
|
69
115
|
try {
|
|
70
116
|
const lock = await this.store.acquire(key, options);
|
|
117
|
+
// An attempt that completed clears any earlier transient error:
|
|
118
|
+
// `lastError` must describe the final outcome, not a stale one.
|
|
119
|
+
lastError = undefined;
|
|
71
120
|
if (lock)
|
|
72
121
|
return lock;
|
|
73
122
|
}
|
|
74
123
|
catch (error) {
|
|
75
124
|
lastError = error;
|
|
76
125
|
}
|
|
77
|
-
if (attempt <
|
|
78
|
-
await sleep(
|
|
126
|
+
if (attempt < attempts)
|
|
127
|
+
await sleep(delay);
|
|
128
|
+
}
|
|
129
|
+
if (lastError) {
|
|
130
|
+
const code = "CACHE_LOCK_ACQUIRE_FAILED";
|
|
131
|
+
throw new CacheError(`Failed to acquire lock "${key}" after ${attempts} retries.`, {
|
|
132
|
+
code,
|
|
133
|
+
cause: lastError,
|
|
134
|
+
operation: CacheOperation.LOCK_ACQUIRE,
|
|
135
|
+
key,
|
|
136
|
+
});
|
|
79
137
|
}
|
|
80
|
-
if (lastError)
|
|
81
|
-
throw new CacheError(`Failed to acquire lock "${key}" after ${this.retryAttempts} retries.`, { cause: lastError, operation: CacheOperation.LOCK_ACQUIRE, key });
|
|
82
138
|
return null;
|
|
83
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* Runs `fn` while holding the lock.
|
|
142
|
+
*
|
|
143
|
+
* The lease is renewed on an interval of roughly `ttl / 3` for as long as
|
|
144
|
+
* `fn` runs, so a critical section longer than the TTL does not silently
|
|
145
|
+
* lose mutual exclusion. If renewal or release reports that the lease is
|
|
146
|
+
* no longer ours, the `AbortSignal` passed to `fn` fires and the call
|
|
147
|
+
* throws — losing a lease is never reported as success.
|
|
148
|
+
*/
|
|
84
149
|
async withLock(key, fn, options) {
|
|
85
150
|
const lock = await this.acquire(key, options);
|
|
86
|
-
if (!lock)
|
|
87
|
-
|
|
151
|
+
if (!lock) {
|
|
152
|
+
const code = "CACHE_LOCK_UNAVAILABLE";
|
|
153
|
+
throw new CacheError(`Could not acquire lock "${key}" for exclusive operation.`, {
|
|
154
|
+
code,
|
|
155
|
+
operation: CacheOperation.LOCK_ACQUIRE,
|
|
156
|
+
key,
|
|
157
|
+
statusCode: 409,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
const ttl = options?.ttl !== undefined ? options.ttl : DEFAULT_LOCK_TTL_MS;
|
|
161
|
+
const controller = new AbortController();
|
|
162
|
+
let leaseLost = false;
|
|
163
|
+
let heartbeat;
|
|
164
|
+
if (ttl !== null) {
|
|
165
|
+
const interval = Math.max(1, Math.floor(ttl / LOCK_HEARTBEAT_DIVISOR));
|
|
166
|
+
heartbeat = setInterval(() => {
|
|
167
|
+
void (async () => {
|
|
168
|
+
try {
|
|
169
|
+
const extended = await lock.extend(ttl);
|
|
170
|
+
if (extended)
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
/* fall through — treat a failed renewal as a lost lease */
|
|
175
|
+
}
|
|
176
|
+
leaseLost = true;
|
|
177
|
+
if (heartbeat !== undefined)
|
|
178
|
+
clearInterval(heartbeat);
|
|
179
|
+
controller.abort(new CacheError(`Lock "${key}" lease was lost during renewal.`, {
|
|
180
|
+
code: "CACHE_LOCK_LOST",
|
|
181
|
+
operation: CacheOperation.LOCK_ACQUIRE,
|
|
182
|
+
key,
|
|
183
|
+
}));
|
|
184
|
+
})();
|
|
185
|
+
}, interval);
|
|
186
|
+
// Never hold the event loop open on the cache's behalf.
|
|
187
|
+
heartbeat.unref?.();
|
|
188
|
+
}
|
|
189
|
+
let value;
|
|
190
|
+
let failure;
|
|
191
|
+
let failed = false;
|
|
88
192
|
try {
|
|
89
|
-
|
|
193
|
+
value = await fn(controller.signal);
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
failed = true;
|
|
197
|
+
failure = error;
|
|
90
198
|
}
|
|
91
199
|
finally {
|
|
92
|
-
|
|
200
|
+
if (heartbeat !== undefined)
|
|
201
|
+
clearInterval(heartbeat);
|
|
93
202
|
}
|
|
203
|
+
// `release()` returning false is the one signal that the lease expired or
|
|
204
|
+
// was taken over mid-critical-section. Surfacing it is the whole point of
|
|
205
|
+
// minting a fencing token. An error thrown by `fn` still wins, so the
|
|
206
|
+
// real cause is never masked.
|
|
207
|
+
const released = await lock.release();
|
|
208
|
+
if (failed)
|
|
209
|
+
throw failure;
|
|
210
|
+
if (!released || leaseLost) {
|
|
211
|
+
const code = "CACHE_LOCK_LOST";
|
|
212
|
+
throw new CacheError(`Lock "${key}" was lost before the critical section completed; its result cannot be trusted.`, {
|
|
213
|
+
code,
|
|
214
|
+
operation: CacheOperation.LOCK_RELEASE,
|
|
215
|
+
key,
|
|
216
|
+
statusCode: 409,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return value;
|
|
94
220
|
}
|
|
95
221
|
}
|
|
96
222
|
function sleep(ms) {
|
|
@@ -99,5 +225,9 @@ function sleep(ms) {
|
|
|
99
225
|
export function createLockManager(options) {
|
|
100
226
|
return new CacheLockManager(options);
|
|
101
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* Process-wide lock store. Pass it as `CacheConfig.lockStore` when several
|
|
230
|
+
* `CacheService` instances in one process must share locks.
|
|
231
|
+
*/
|
|
102
232
|
export const defaultLockStore = new InMemoryLockStore();
|
|
103
233
|
//# sourceMappingURL=lock.js.map
|
package/dist/memory.d.ts
CHANGED
|
@@ -1,16 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @zudojs/cache — Memory Adapter
|
|
3
3
|
* In-memory cache adapter using a Map. Suitable for development, testing, and single-process deployments.
|
|
4
|
+
*
|
|
5
|
+
* Receives fully-qualified keys; namespace resolution happens in CacheService.
|
|
6
|
+
*
|
|
7
|
+
* Bounds: the store is capped both by entry count (`maxEntries`) and by an
|
|
8
|
+
* approximate byte budget (`maxBytes`). Eviction is LRU — reads move an
|
|
9
|
+
* entry to the back of the queue, so the hottest keys survive.
|
|
10
|
+
*
|
|
11
|
+
* Expiry is measured on a monotonic clock, so an NTP step or a VM resume
|
|
12
|
+
* cannot extend (or collapse) an entry's lifetime. The wall-clock
|
|
13
|
+
* `expiresAt` returned to callers is derived from it for display only.
|
|
4
14
|
*/
|
|
5
|
-
import type {
|
|
15
|
+
import type { CacheClearOptions, CacheClearResult, CacheDeleteManyResult, CacheDeleteResult, CacheGetResult, CacheKeysOptions, CacheSetManyOptions, CacheSetOptions, CacheSetResult, CacheTTL } from "./types.js";
|
|
16
|
+
import type { CacheAdapter } from "./types.js";
|
|
17
|
+
/**
|
|
18
|
+
* Approximates the retained size of a value in bytes.
|
|
19
|
+
*
|
|
20
|
+
* Deliberately bounded: at most `SIZE_ESTIMATE_NODE_BUDGET` nodes are
|
|
21
|
+
* visited, so `set` stays cheap for large object graphs. Beyond the budget
|
|
22
|
+
* the remainder is charged a flat per-node estimate, which keeps the number
|
|
23
|
+
* monotone in value size without walking the whole graph.
|
|
24
|
+
*/
|
|
25
|
+
export declare function estimateValueBytes(value: unknown): number;
|
|
6
26
|
export declare class MemoryCacheAdapter implements CacheAdapter {
|
|
7
27
|
readonly name = "memory";
|
|
8
28
|
private readonly store;
|
|
9
29
|
private readonly maxEntries;
|
|
30
|
+
private readonly maxBytes;
|
|
10
31
|
private readonly defaultTtl;
|
|
32
|
+
private readonly separator;
|
|
33
|
+
private bytesUsed;
|
|
34
|
+
private lastPurgeAt;
|
|
11
35
|
constructor(options?: {
|
|
12
36
|
readonly maxEntries?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Approximate memory budget in bytes. Entries are evicted (LRU) until
|
|
39
|
+
* the estimated total fits. Defaults to `DEFAULT_MAX_MEMORY_BYTES`.
|
|
40
|
+
*/
|
|
41
|
+
readonly maxBytes?: number;
|
|
13
42
|
readonly defaultTtl?: CacheTTL;
|
|
43
|
+
/**
|
|
44
|
+
* Key separator used when matching glob patterns. `*` never crosses it.
|
|
45
|
+
* Defaults to `DEFAULT_SEPARATOR`; set it to match a custom key-builder
|
|
46
|
+
* separator.
|
|
47
|
+
*/
|
|
48
|
+
readonly separator?: string;
|
|
14
49
|
});
|
|
15
50
|
get<TValue = unknown>(key: string): Promise<CacheGetResult<TValue>>;
|
|
16
51
|
set<TValue = unknown>(key: string, value: TValue, options?: CacheSetOptions): Promise<CacheSetResult>;
|
|
@@ -18,20 +53,41 @@ export declare class MemoryCacheAdapter implements CacheAdapter {
|
|
|
18
53
|
has(key: string): Promise<boolean>;
|
|
19
54
|
clear(options?: CacheClearOptions): Promise<CacheClearResult>;
|
|
20
55
|
keys(options?: CacheKeysOptions): Promise<readonly string[]>;
|
|
56
|
+
/** Number of live entries currently held. */
|
|
57
|
+
size(): Promise<number>;
|
|
58
|
+
/** Estimated bytes currently retained by cached values. */
|
|
59
|
+
get estimatedBytes(): number;
|
|
21
60
|
getMany<TValue = unknown>(keys: readonly string[]): Promise<ReadonlyMap<string, CacheGetResult<TValue>>>;
|
|
22
61
|
setMany<TValue = unknown>(entries: ReadonlyMap<string, TValue>, options?: CacheSetManyOptions): Promise<readonly CacheSetResult[]>;
|
|
23
|
-
deleteMany(keys: readonly string[]): Promise<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
62
|
+
deleteMany(keys: readonly string[]): Promise<CacheDeleteManyResult>;
|
|
63
|
+
/**
|
|
64
|
+
* Remaining TTL for a key in milliseconds.
|
|
65
|
+
* - `undefined` — the key does not exist (expired entries are deleted)
|
|
66
|
+
* - `null` — the key exists and never expires
|
|
67
|
+
* - `number` — remaining milliseconds until expiry
|
|
68
|
+
*/
|
|
69
|
+
ttl(key: string): Promise<number | null | undefined>;
|
|
28
70
|
expire(key: string, ttl: CacheTTL): Promise<boolean>;
|
|
71
|
+
private toCacheEntry;
|
|
72
|
+
/**
|
|
73
|
+
* An entry is dead *at* its deadline, not one millisecond after it, so
|
|
74
|
+
* `ttl(key) === 0` and "present" are never both true.
|
|
75
|
+
*/
|
|
29
76
|
private isExpired;
|
|
77
|
+
private remove;
|
|
78
|
+
private purgeExpired;
|
|
79
|
+
private maybePurgeExpired;
|
|
80
|
+
/**
|
|
81
|
+
* Makes room for an incoming entry of `incomingBytes`, honouring both the
|
|
82
|
+
* entry-count cap and the memory budget. Expired entries are purged before
|
|
83
|
+
* live ones are evicted; live eviction is least-recently-used.
|
|
84
|
+
*/
|
|
30
85
|
private evictIfNeeded;
|
|
31
|
-
private patternToRegex;
|
|
32
86
|
}
|
|
33
87
|
export declare function createMemoryCacheAdapter(options?: {
|
|
34
88
|
readonly maxEntries?: number;
|
|
89
|
+
readonly maxBytes?: number;
|
|
35
90
|
readonly defaultTtl?: CacheTTL;
|
|
91
|
+
readonly separator?: string;
|
|
36
92
|
}): MemoryCacheAdapter;
|
|
37
93
|
//# sourceMappingURL=memory.d.ts.map
|