express-memorize 1.3.0 → 2.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/CHANGELOG.md +12 -0
- package/README.md +204 -66
- package/dist/MemorizeStore.d.ts +29 -7
- package/dist/MemorizeStore.d.ts.map +1 -1
- package/dist/MemorizeStore.js +78 -7
- package/dist/MemorizeStore.js.map +1 -1
- package/dist/adapters/express.d.ts +25 -0
- package/dist/adapters/express.d.ts.map +1 -0
- package/dist/adapters/express.js +62 -0
- package/dist/adapters/express.js.map +1 -0
- package/dist/adapters/fetch.d.ts +45 -0
- package/dist/adapters/fetch.d.ts.map +1 -0
- package/dist/adapters/fetch.js +72 -0
- package/dist/adapters/fetch.js.map +1 -0
- package/dist/adapters/hono.d.ts +34 -0
- package/dist/adapters/hono.d.ts.map +1 -0
- package/dist/adapters/hono.js +63 -0
- package/dist/adapters/hono.js.map +1 -0
- package/dist/adapters/nestjs.d.ts +84 -0
- package/dist/adapters/nestjs.d.ts.map +1 -0
- package/dist/adapters/nestjs.js +194 -0
- package/dist/adapters/nestjs.js.map +1 -0
- package/dist/domain/CacheEntry.d.ts +4 -0
- package/dist/domain/CacheEntry.d.ts.map +1 -1
- package/dist/domain/Memorize.d.ts +99 -4
- package/dist/domain/Memorize.d.ts.map +1 -1
- package/dist/domain/MemorizeCallOptions.d.ts +2 -2
- package/dist/domain/MemorizeEvent.d.ts +2 -1
- package/dist/domain/MemorizeEvent.d.ts.map +1 -1
- package/dist/domain/MemorizeEventType.d.ts +3 -1
- package/dist/domain/MemorizeEventType.d.ts.map +1 -1
- package/dist/domain/MemorizeEventType.js +2 -0
- package/dist/domain/MemorizeEventType.js.map +1 -1
- package/dist/domain/MemorizeEvictEvent.d.ts +18 -0
- package/dist/domain/MemorizeEvictEvent.d.ts.map +1 -0
- package/dist/domain/MemorizeEvictEvent.js +3 -0
- package/dist/domain/MemorizeEvictEvent.js.map +1 -0
- package/dist/domain/MemorizeOptions.d.ts +12 -0
- package/dist/domain/MemorizeOptions.d.ts.map +1 -1
- package/dist/domain/MemorizeSetEvent.d.ts +2 -0
- package/dist/domain/MemorizeSetEvent.d.ts.map +1 -1
- package/dist/domain/MemorizeStats.d.ts +12 -0
- package/dist/domain/MemorizeStats.d.ts.map +1 -0
- package/dist/domain/MemorizeStats.js +3 -0
- package/dist/domain/MemorizeStats.js.map +1 -0
- package/dist/domain/index.d.ts +2 -0
- package/dist/domain/index.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/memorize.d.ts +19 -16
- package/dist/memorize.d.ts.map +1 -1
- package/dist/memorize.js +51 -45
- package/dist/memorize.js.map +1 -1
- package/package.json +46 -12
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
This file is automatically updated by [release-please](https://github.com/googleapis/release-please) based on [Conventional Commits](https://www.conventionalcommits.org/).
|
|
6
6
|
|
|
7
|
+
## [1.4.0](https://github.com/ElJijuna/express-memorize/compare/v1.3.0...v1.4.0) (2026-03-31)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* add hits counter to track cache key consumption ([8104029](https://github.com/ElJijuna/express-memorize/commit/81040296354c8a6de78542d6cc6c3fdc18e21e04))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* add header X-Cache: BYPASS value when set noCache: true in middleware config to override. ([cab3c85](https://github.com/ElJijuna/express-memorize/commit/cab3c85f53885ff287e569248a402632363f31fd))
|
|
18
|
+
|
|
7
19
|
## [1.3.0](https://github.com/ElJijuna/express-memorize/compare/v1.2.0...v1.3.0) (2026-03-26)
|
|
8
20
|
|
|
9
21
|
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
In-memory cache
|
|
12
|
+
In-memory HTTP cache for <strong>Express, NestJS, Hono, Fetch API</strong>, and more.<br/>
|
|
13
13
|
Caches <code>GET</code> responses with optional TTL — zero dependencies, fully typed.
|
|
14
14
|
</p>
|
|
15
15
|
|
|
@@ -18,12 +18,16 @@
|
|
|
18
18
|
## Features
|
|
19
19
|
|
|
20
20
|
- Caches `GET` responses automatically when status code is `2xx`
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
21
|
+
- Works with **Express**, **NestJS**, **Hono**, **Fetch API / serverless**, and direct service-level usage
|
|
22
|
+
- Per-route TTL override and `noCache` bypass
|
|
23
|
+
- **`maxEntries` cap with LRU eviction** to bound memory usage
|
|
24
|
+
- **Size metrics**: `size()`, `byteSize()`, `getStats()`
|
|
25
|
+
- **Service-level cache**: `remember()`, `set()`, `getValue()`
|
|
26
|
+
- Event hooks: `set`, `delete`, `expire`, `evict`
|
|
27
|
+
- Cache inspection and invalidation API (`get`, `getAll`, `delete`, `deleteMatching`, `clear`)
|
|
28
|
+
- Hit counter per cache entry
|
|
29
|
+
- `X-Cache: HIT | MISS | BYPASS` response header
|
|
30
|
+
- Zero runtime dependencies, fully typed
|
|
27
31
|
|
|
28
32
|
## Installation
|
|
29
33
|
|
|
@@ -31,14 +35,23 @@
|
|
|
31
35
|
npm install express-memorize
|
|
32
36
|
```
|
|
33
37
|
|
|
38
|
+
Adapters for non-Express runtimes are optional — install only what you need:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install hono # only if using the Hono adapter
|
|
42
|
+
npm install @nestjs/common @nestjs/core rxjs # only if using the NestJS adapter
|
|
43
|
+
```
|
|
44
|
+
|
|
34
45
|
## Quick Start
|
|
35
46
|
|
|
47
|
+
### Express
|
|
48
|
+
|
|
36
49
|
```typescript
|
|
37
50
|
import express from 'express';
|
|
38
51
|
import { memorize } from 'express-memorize';
|
|
39
52
|
|
|
40
53
|
const app = express();
|
|
41
|
-
const cache = memorize({ ttl: 30_000 });
|
|
54
|
+
const cache = memorize({ ttl: 30_000 });
|
|
42
55
|
|
|
43
56
|
app.get('/users', cache(), async (req, res) => {
|
|
44
57
|
const users = await db.getUsers();
|
|
@@ -48,32 +61,92 @@ app.get('/users', cache(), async (req, res) => {
|
|
|
48
61
|
app.listen(3000);
|
|
49
62
|
```
|
|
50
63
|
|
|
51
|
-
|
|
64
|
+
### Hono
|
|
52
65
|
|
|
53
|
-
|
|
66
|
+
```typescript
|
|
67
|
+
import { Hono } from 'hono';
|
|
68
|
+
import { memorize } from 'express-memorize';
|
|
69
|
+
import { createHonoMiddleware } from 'express-memorize/hono';
|
|
70
|
+
|
|
71
|
+
const app = new Hono();
|
|
72
|
+
const cache = memorize({ ttl: 30_000 });
|
|
73
|
+
|
|
74
|
+
app.get('/users', createHonoMiddleware(cache), async (c) => {
|
|
75
|
+
return c.json(await usersService.findAll());
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### NestJS
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { Module } from '@nestjs/common';
|
|
83
|
+
import { APP_INTERCEPTOR } from '@nestjs/core';
|
|
84
|
+
import {
|
|
85
|
+
MemorizeCacheKey,
|
|
86
|
+
MemorizeInterceptor,
|
|
87
|
+
MemorizeModule,
|
|
88
|
+
MemorizeTtl,
|
|
89
|
+
} from 'express-memorize/nestjs';
|
|
90
|
+
|
|
91
|
+
@Module({
|
|
92
|
+
imports: [MemorizeModule.forRoot({ ttl: 30_000 })],
|
|
93
|
+
providers: [
|
|
94
|
+
{
|
|
95
|
+
provide: APP_INTERCEPTOR,
|
|
96
|
+
useExisting: MemorizeInterceptor,
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
})
|
|
100
|
+
export class AppModule {}
|
|
101
|
+
|
|
102
|
+
export class UsersController {
|
|
103
|
+
@MemorizeCacheKey('users:list')
|
|
104
|
+
@MemorizeTtl(10_000)
|
|
105
|
+
findAll() {
|
|
106
|
+
return usersService.findAll();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Fetch API / Serverless
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import { memorize } from 'express-memorize';
|
|
115
|
+
import { cacheFetchHandler } from 'express-memorize/fetch';
|
|
116
|
+
|
|
117
|
+
const cache = memorize({ ttl: 30_000 });
|
|
118
|
+
|
|
119
|
+
export default cacheFetchHandler(cache, async (request) => {
|
|
120
|
+
const users = await usersService.findAll();
|
|
121
|
+
return Response.json(users);
|
|
122
|
+
});
|
|
123
|
+
```
|
|
54
124
|
|
|
55
|
-
###
|
|
125
|
+
### Service-level caching
|
|
56
126
|
|
|
57
|
-
|
|
127
|
+
Cache arbitrary values directly — no HTTP layer required.
|
|
58
128
|
|
|
59
129
|
```typescript
|
|
60
130
|
const cache = memorize({ ttl: 60_000 });
|
|
61
131
|
|
|
62
|
-
|
|
132
|
+
// Compute-and-cache pattern
|
|
133
|
+
const users = await cache.remember('users:list', () => usersService.findAll());
|
|
63
134
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
135
|
+
// Explicit set/get
|
|
136
|
+
cache.set('config', appConfig);
|
|
137
|
+
const config = cache.getValue<AppConfig>('config');
|
|
67
138
|
```
|
|
68
139
|
|
|
69
|
-
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Usage
|
|
143
|
+
|
|
144
|
+
### Global middleware (Express)
|
|
70
145
|
|
|
71
146
|
```typescript
|
|
72
147
|
const cache = memorize({ ttl: 60_000 });
|
|
73
148
|
|
|
74
|
-
app.
|
|
75
|
-
res.json({ data: products });
|
|
76
|
-
});
|
|
149
|
+
app.use(cache()); // applies to all GET routes
|
|
77
150
|
```
|
|
78
151
|
|
|
79
152
|
### Per-route TTL override
|
|
@@ -82,39 +155,69 @@ app.get('/products', cache(), (req, res) => {
|
|
|
82
155
|
const cache = memorize({ ttl: 60_000 }); // global: 60s
|
|
83
156
|
|
|
84
157
|
app.get('/users', cache(), handler); // 60s
|
|
85
|
-
app.get('/products', cache({ ttl: 10_000 }), handler); //
|
|
158
|
+
app.get('/products', cache({ ttl: 10_000 }), handler); // 10s
|
|
86
159
|
app.get('/config', cache({ ttl: 0 }), handler); // no expiry
|
|
87
160
|
```
|
|
88
161
|
|
|
89
|
-
###
|
|
162
|
+
### noCache bypass
|
|
90
163
|
|
|
91
164
|
```typescript
|
|
92
|
-
|
|
165
|
+
app.get('/live-feed', cache({ noCache: true }), handler);
|
|
166
|
+
// Sets X-Cache: BYPASS, never reads or writes the cache
|
|
167
|
+
```
|
|
93
168
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
169
|
+
### NestJS decorators
|
|
170
|
+
|
|
171
|
+
Use `MemorizeInterceptor` on a controller or globally, then configure caching at the controller or method level.
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import { Controller, Get, UseInterceptors } from '@nestjs/common';
|
|
175
|
+
import {
|
|
176
|
+
MemorizeCacheKey,
|
|
177
|
+
MemorizeInterceptor,
|
|
178
|
+
MemorizeNoCache,
|
|
179
|
+
MemorizeTtl,
|
|
180
|
+
} from 'express-memorize/nestjs';
|
|
181
|
+
|
|
182
|
+
@Controller('users')
|
|
183
|
+
@UseInterceptors(MemorizeInterceptor)
|
|
184
|
+
@MemorizeTtl(30_000)
|
|
185
|
+
export class UsersController {
|
|
186
|
+
@Get()
|
|
187
|
+
@MemorizeCacheKey('users:list')
|
|
188
|
+
findAll() {
|
|
189
|
+
return usersService.findAll();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
@Get('live')
|
|
193
|
+
@MemorizeNoCache()
|
|
194
|
+
live() {
|
|
195
|
+
return usersService.live();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
97
199
|
|
|
200
|
+
For global usage, import `MemorizeModule.forRoot()` and register `APP_INTERCEPTOR` with `useExisting: MemorizeInterceptor` so the interceptor receives the module's shared cache instance.
|
|
201
|
+
|
|
202
|
+
### Cache invalidation
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
98
205
|
app.post('/users', (req, res) => {
|
|
99
206
|
users.push(req.body);
|
|
100
|
-
cache.delete('/users');
|
|
101
|
-
res.status(201).json(
|
|
207
|
+
cache.delete('/users');
|
|
208
|
+
res.status(201).json(req.body);
|
|
102
209
|
});
|
|
103
210
|
```
|
|
104
211
|
|
|
105
212
|
### Pattern-based invalidation
|
|
106
213
|
|
|
107
|
-
Use `cache.deleteMatching(pattern)` to remove
|
|
214
|
+
Use `cache.deleteMatching(pattern)` to remove entries by glob pattern.
|
|
108
215
|
|
|
109
216
|
```typescript
|
|
110
|
-
// Cached keys: /api/users/abc123, /api/users/abc123?lang=es, /api/users/abc123?page=1
|
|
111
217
|
app.put('/users/:id', (req, res) => {
|
|
112
218
|
users.update(req.params.id, req.body);
|
|
113
|
-
|
|
114
|
-
// Remove all cached variants of this user, regardless of query params
|
|
115
219
|
const deleted = cache.deleteMatching(`**/users/${req.params.id}*`);
|
|
116
|
-
console.log(`${deleted}
|
|
117
|
-
|
|
220
|
+
console.log(`${deleted} entries removed`);
|
|
118
221
|
res.json({ ok: true });
|
|
119
222
|
});
|
|
120
223
|
```
|
|
@@ -123,35 +226,33 @@ app.put('/users/:id', (req, res) => {
|
|
|
123
226
|
|
|
124
227
|
| Pattern | Behaviour |
|
|
125
228
|
|---------|-----------|
|
|
126
|
-
| `*` | Matches any sequence
|
|
127
|
-
| `**` | Matches any sequence
|
|
229
|
+
| `*` | Matches any sequence within a single path segment (does not cross `/`) |
|
|
230
|
+
| `**` | Matches any sequence across path segments (crosses `/`) |
|
|
128
231
|
| `?` | Matches any single character except `/` |
|
|
129
232
|
|
|
130
|
-
|
|
233
|
+
### Bounding memory with `maxEntries`
|
|
131
234
|
|
|
132
|
-
|
|
235
|
+
Prevent unbounded growth by setting a maximum number of entries. When the limit is reached, the **least-recently-used (LRU)** entry is evicted before the new one is stored.
|
|
133
236
|
|
|
134
237
|
```typescript
|
|
135
|
-
const cache = memorize({ ttl: 30_000 });
|
|
136
|
-
|
|
137
|
-
cache.on('set', (e) => {
|
|
138
|
-
console.log(`[cache] stored ${e.key} — expires in ${e.expiresAt ? e.expiresAt - Date.now() : '∞'}ms`);
|
|
139
|
-
});
|
|
238
|
+
const cache = memorize({ ttl: 30_000, maxEntries: 1_000 });
|
|
239
|
+
```
|
|
140
240
|
|
|
141
|
-
|
|
142
|
-
console.log(`[cache] deleted ${e.key}`);
|
|
143
|
-
});
|
|
241
|
+
### Size metrics
|
|
144
242
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
243
|
+
```typescript
|
|
244
|
+
cache.size(); // number of active entries
|
|
245
|
+
cache.byteSize(); // approximate total body size in bytes
|
|
246
|
+
cache.getStats(); // { entries, maxEntries, byteSize }
|
|
148
247
|
```
|
|
149
248
|
|
|
249
|
+
> `byteSize()` is an estimate based on UTF-8 encoding for strings and `byteLength` for buffers. It may not reflect actual VM memory usage.
|
|
250
|
+
|
|
150
251
|
### Inspect the cache
|
|
151
252
|
|
|
152
253
|
```typescript
|
|
153
|
-
cache.get('/users'); // CacheInfo | null
|
|
154
|
-
cache.getAll(); // Record<string, CacheInfo>
|
|
254
|
+
cache.get('/users'); // CacheInfo | null
|
|
255
|
+
cache.getAll(); // Record<string, CacheInfo>
|
|
155
256
|
```
|
|
156
257
|
|
|
157
258
|
`CacheInfo` shape:
|
|
@@ -164,17 +265,27 @@ cache.getAll(); // Record<string, CacheInfo> — all active entries
|
|
|
164
265
|
contentType: string;
|
|
165
266
|
expiresAt: number | null;
|
|
166
267
|
remainingTtl: number | null; // ms until expiry, null if no TTL
|
|
268
|
+
hits: number; // times this key was served from cache
|
|
269
|
+
size: number; // approximate body size in bytes
|
|
167
270
|
}
|
|
168
271
|
```
|
|
169
272
|
|
|
170
|
-
|
|
273
|
+
`hits` starts at `1` on the initial cache miss and increments on every hit. It resets to `1` if the entry is evicted and re-cached.
|
|
274
|
+
|
|
275
|
+
### Event hooks
|
|
171
276
|
|
|
172
277
|
```typescript
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
cache.
|
|
278
|
+
import { MemorizeEventType } from 'express-memorize';
|
|
279
|
+
|
|
280
|
+
cache.on(MemorizeEventType.Set, (e) => console.log('stored', e.key));
|
|
281
|
+
cache.on(MemorizeEventType.Delete, (e) => console.log('deleted', e.key));
|
|
282
|
+
cache.on(MemorizeEventType.Expire, (e) => console.log('expired', e.key));
|
|
283
|
+
cache.on(MemorizeEventType.Evict, (e) => console.log('evicted', e.key)); // maxEntries LRU
|
|
284
|
+
cache.on(MemorizeEventType.Empty, () => console.log('cache is empty'));
|
|
176
285
|
```
|
|
177
286
|
|
|
287
|
+
---
|
|
288
|
+
|
|
178
289
|
## API Reference
|
|
179
290
|
|
|
180
291
|
### `memorize(options?)`
|
|
@@ -184,32 +295,57 @@ Creates a cache instance. Returns a `Memorize` object.
|
|
|
184
295
|
| Option | Type | Default | Description |
|
|
185
296
|
|--------|------|---------|-------------|
|
|
186
297
|
| `ttl` | `number` | `undefined` | Time-to-live in milliseconds. Omit for no expiry. |
|
|
298
|
+
| `maxEntries` | `number` | `undefined` | Maximum number of entries. LRU eviction when reached. |
|
|
187
299
|
|
|
188
|
-
### `cache(options?)`
|
|
300
|
+
### `cache(options?)` / `cache.express(options?)`
|
|
189
301
|
|
|
190
|
-
Returns an Express `RequestHandler`
|
|
302
|
+
Returns an Express `RequestHandler`. `cache()` is a backwards-compatible alias for `cache.express()`.
|
|
191
303
|
|
|
192
304
|
| Option | Type | Default | Description |
|
|
193
305
|
|--------|------|---------|-------------|
|
|
194
|
-
| `ttl` | `number` | global `ttl` | TTL override for this
|
|
306
|
+
| `ttl` | `number` | global `ttl` | TTL override for this route. |
|
|
307
|
+
| `noCache` | `boolean` | `false` | Skip cache entirely. Sets `X-Cache: BYPASS`. |
|
|
308
|
+
|
|
309
|
+
### Service-level cache methods
|
|
310
|
+
|
|
311
|
+
| Method | Signature | Description |
|
|
312
|
+
|--------|-----------|-------------|
|
|
313
|
+
| `remember` | `(key, factory, ttl?) => Promise<T>` | Return cached value or call factory and cache the result. |
|
|
314
|
+
| `set` | `(key, value, ttl?) => void` | Store an arbitrary value. |
|
|
315
|
+
| `getValue` | `(key) => T \| undefined` | Retrieve a value stored via `set` or `remember`. |
|
|
195
316
|
|
|
196
317
|
### Cache management
|
|
197
318
|
|
|
198
319
|
| Method | Signature | Description |
|
|
199
320
|
|--------|-----------|-------------|
|
|
200
|
-
| `get` | `(key
|
|
201
|
-
| `getAll` | `() => Record<string, CacheInfo>` | Returns all active
|
|
202
|
-
| `delete` | `(key
|
|
203
|
-
| `deleteMatching` | `(pattern
|
|
321
|
+
| `get` | `(key) => CacheInfo \| null` | Returns info for a cached key. |
|
|
322
|
+
| `getAll` | `() => Record<string, CacheInfo>` | Returns all active entries. |
|
|
323
|
+
| `delete` | `(key) => boolean` | Removes a single entry. |
|
|
324
|
+
| `deleteMatching` | `(pattern) => number` | Removes entries matching a glob pattern. |
|
|
204
325
|
| `clear` | `() => void` | Removes all entries. |
|
|
326
|
+
| `size` | `() => number` | Number of active entries. |
|
|
327
|
+
| `byteSize` | `() => number` | Approximate total body size in bytes. |
|
|
328
|
+
| `getStats` | `() => MemorizeStats` | Aggregate stats: `{ entries, maxEntries, byteSize }`. |
|
|
329
|
+
|
|
330
|
+
### Adapters
|
|
331
|
+
|
|
332
|
+
| Import path | Export | Framework |
|
|
333
|
+
|-------------|--------|-----------|
|
|
334
|
+
| `express-memorize` | `memorize` | Core factory |
|
|
335
|
+
| `express-memorize/express` | `createExpressAdapter(cache, options?)` | Express |
|
|
336
|
+
| `express-memorize/nestjs` | `MemorizeModule`, `MemorizeInterceptor`, decorators | NestJS |
|
|
337
|
+
| `express-memorize/hono` | `createHonoMiddleware(cache, options?)` | Hono |
|
|
338
|
+
| `express-memorize/fetch` | `cacheFetchHandler(cache, handler, options?)` | Fetch API / Serverless |
|
|
205
339
|
|
|
206
340
|
### Events
|
|
207
341
|
|
|
208
342
|
| Event | Payload | When |
|
|
209
343
|
|-------|---------|------|
|
|
210
|
-
| `set` | `{ type, key, body, statusCode, contentType, expiresAt }` | A response is stored |
|
|
211
|
-
| `delete` | `{ type, key }` | `
|
|
344
|
+
| `set` | `{ type, key, body, statusCode, contentType, expiresAt, size }` | A response is stored |
|
|
345
|
+
| `delete` | `{ type, key }` | Manual removal via `delete`, `deleteMatching`, or `clear` |
|
|
212
346
|
| `expire` | `{ type, key }` | TTL timer fires or lazy expiry is detected |
|
|
347
|
+
| `evict` | `{ type, key }` | LRU eviction due to `maxEntries` limit |
|
|
348
|
+
| `empty` | `{ type }` | Last entry removed, cache is now empty |
|
|
213
349
|
|
|
214
350
|
## Response Headers
|
|
215
351
|
|
|
@@ -217,13 +353,15 @@ Returns an Express `RequestHandler` middleware. Can override the global TTL.
|
|
|
217
353
|
|--------|-------|-------------|
|
|
218
354
|
| `X-Cache` | `HIT` | Response served from cache |
|
|
219
355
|
| `X-Cache` | `MISS` | Response computed and stored |
|
|
356
|
+
| `X-Cache` | `BYPASS` | Cache skipped — `noCache: true` |
|
|
220
357
|
|
|
221
358
|
## Behavior
|
|
222
359
|
|
|
223
|
-
- Only `GET` requests are cached. All other methods bypass the
|
|
360
|
+
- Only `GET` requests are cached. All other methods bypass the cache entirely.
|
|
224
361
|
- Only responses with a `2xx` status code are stored.
|
|
225
|
-
-
|
|
362
|
+
- All middleware and adapter instances created from the same `memorize()` call **share the same store**.
|
|
226
363
|
- Two separate `memorize()` calls produce **independent stores**.
|
|
364
|
+
- Byte size is an approximation — strings use UTF-8 encoding, objects use `JSON.stringify` length.
|
|
227
365
|
|
|
228
366
|
## License
|
|
229
367
|
|
package/dist/MemorizeStore.d.ts
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
import { CacheEntry } from './domain/CacheEntry';
|
|
2
2
|
import { CacheInfo } from './domain/CacheInfo';
|
|
3
|
+
import { MemorizeStats } from './domain/MemorizeStats';
|
|
3
4
|
import { MemorizeEventType } from './domain/MemorizeEventType';
|
|
4
5
|
import { MemorizeEvent } from './domain/MemorizeEvent';
|
|
5
6
|
import { MemorizeSetEvent } from './domain/MemorizeSetEvent';
|
|
6
7
|
import { MemorizeDeleteEvent } from './domain/MemorizeDeleteEvent';
|
|
7
8
|
import { MemorizeExpireEvent } from './domain/MemorizeExpireEvent';
|
|
8
9
|
import { MemorizeEmptyEvent } from './domain/MemorizeEmptyEvent';
|
|
9
|
-
|
|
10
|
+
import { MemorizeEvictEvent } from './domain/MemorizeEvictEvent';
|
|
11
|
+
export type { CacheEntry, CacheInfo, MemorizeStats, MemorizeEvent, MemorizeSetEvent, MemorizeDeleteEvent, MemorizeExpireEvent, MemorizeEmptyEvent, MemorizeEvictEvent, };
|
|
10
12
|
export { MemorizeEventType };
|
|
11
13
|
/**
|
|
12
|
-
* Low-level in-memory key-value store with optional TTL and event emission.
|
|
14
|
+
* Low-level in-memory key-value store with optional TTL, LRU eviction, and event emission.
|
|
13
15
|
*
|
|
14
16
|
* You do not usually interact with this class directly — use the {@link memorize} factory
|
|
15
17
|
* instead, which wraps this store in an Express middleware.
|
|
16
18
|
*/
|
|
17
19
|
export declare class MemorizeStore {
|
|
20
|
+
private readonly _maxEntries?;
|
|
18
21
|
private _store;
|
|
19
22
|
private _timers;
|
|
23
|
+
private _totalByteSize;
|
|
20
24
|
private _listeners;
|
|
25
|
+
constructor(_maxEntries?: number | undefined);
|
|
21
26
|
/**
|
|
22
27
|
* Registers an event listener.
|
|
23
28
|
*
|
|
@@ -26,25 +31,27 @@ export declare class MemorizeStore {
|
|
|
26
31
|
*
|
|
27
32
|
* @example
|
|
28
33
|
* ```ts
|
|
29
|
-
* store.on(MemorizeEventType.Set,
|
|
30
|
-
* store.on(MemorizeEventType.
|
|
34
|
+
* store.on(MemorizeEventType.Set, (e) => console.log('cached', e.key));
|
|
35
|
+
* store.on(MemorizeEventType.Evict, (e) => console.log('evicted', e.key));
|
|
31
36
|
* ```
|
|
32
37
|
*/
|
|
33
38
|
on(event: MemorizeEventType.Set, handler: (e: MemorizeSetEvent) => void): void;
|
|
34
39
|
on(event: MemorizeEventType.Delete, handler: (e: MemorizeDeleteEvent) => void): void;
|
|
35
40
|
on(event: MemorizeEventType.Expire, handler: (e: MemorizeExpireEvent) => void): void;
|
|
36
41
|
on(event: MemorizeEventType.Empty, handler: (e: MemorizeEmptyEvent) => void): void;
|
|
42
|
+
on(event: MemorizeEventType.Evict, handler: (e: MemorizeEvictEvent) => void): void;
|
|
37
43
|
/**
|
|
38
44
|
* Stores an entry in the cache.
|
|
39
45
|
*
|
|
40
46
|
* If an entry already exists for the given key its TTL timer is reset and the
|
|
41
|
-
* value is overwritten.
|
|
47
|
+
* value is overwritten. If `maxEntries` is configured and the store is full,
|
|
48
|
+
* the least-recently-used entry is evicted first. Emits a {@link MemorizeEventType.Set} event.
|
|
42
49
|
*
|
|
43
50
|
* @param key - The cache key (typically `req.originalUrl`).
|
|
44
51
|
* @param entry - The response data to store.
|
|
45
52
|
* @param ttl - Time-to-live in milliseconds. Omit or pass `null` for no expiry.
|
|
46
53
|
*/
|
|
47
|
-
set(key: string, entry: Omit<CacheEntry, 'expiresAt'>, ttl?: number | null): void;
|
|
54
|
+
set(key: string, entry: Omit<CacheEntry, 'expiresAt' | 'hits' | 'size'>, ttl?: number | null): void;
|
|
48
55
|
/**
|
|
49
56
|
* Returns the formatted {@link CacheInfo} for the given key, or `null` if the
|
|
50
57
|
* key does not exist or its TTL has elapsed.
|
|
@@ -82,15 +89,30 @@ export declare class MemorizeStore {
|
|
|
82
89
|
* for each entry.
|
|
83
90
|
*/
|
|
84
91
|
clear(): void;
|
|
92
|
+
/**
|
|
93
|
+
* Returns the number of active cache entries.
|
|
94
|
+
*/
|
|
95
|
+
size(): number;
|
|
96
|
+
/**
|
|
97
|
+
* Returns the approximate total byte size of all cached bodies.
|
|
98
|
+
*
|
|
99
|
+
* The value is an estimate and may not reflect actual memory usage.
|
|
100
|
+
*/
|
|
101
|
+
byteSize(): number;
|
|
102
|
+
/**
|
|
103
|
+
* Returns aggregate cache statistics.
|
|
104
|
+
*/
|
|
105
|
+
getStats(): MemorizeStats;
|
|
85
106
|
/**
|
|
86
107
|
* Returns the raw {@link CacheEntry} for the given key without formatting metadata,
|
|
87
108
|
* or `null` if the entry is missing or expired. Used internally by the middleware
|
|
88
|
-
* to serve cached responses.
|
|
109
|
+
* to serve cached responses. Updates LRU order and increments the hit counter.
|
|
89
110
|
*
|
|
90
111
|
* @param key - The cache key to look up.
|
|
91
112
|
* @internal
|
|
92
113
|
*/
|
|
93
114
|
getRaw(key: string): CacheEntry | null;
|
|
115
|
+
private _evictLRU;
|
|
94
116
|
private _evict;
|
|
95
117
|
private _emit;
|
|
96
118
|
private _format;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MemorizeStore.d.ts","sourceRoot":"","sources":["../src/MemorizeStore.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEjE,YAAY,EACV,UAAU,EACV,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,GACnB,CAAC;AACF,OAAO,EAAE,iBAAiB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"MemorizeStore.d.ts","sourceRoot":"","sources":["../src/MemorizeStore.ts"],"names":[],"mappings":"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"}
|