@shaferllc/keel 0.59.0 → 0.68.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/AGENTS.md +167 -0
- package/README.md +30 -1
- package/bin/keel-mcp.mjs +9 -0
- package/dist/core/application.d.ts +5 -5
- package/dist/core/application.js +14 -2
- package/dist/core/auth.d.ts +47 -0
- package/dist/core/auth.js +77 -0
- package/dist/core/authorization.d.ts +9 -1
- package/dist/core/authorization.js +22 -2
- package/dist/core/cache.d.ts +82 -5
- package/dist/core/cache.js +181 -23
- package/dist/core/cli/stubs.d.ts +12 -0
- package/dist/core/cli/stubs.js +120 -0
- package/dist/core/container.d.ts +20 -0
- package/dist/core/container.js +52 -0
- package/dist/core/cors.d.ts +29 -0
- package/dist/core/cors.js +72 -0
- package/dist/core/crypto.d.ts +40 -4
- package/dist/core/crypto.js +66 -6
- package/dist/core/csrf.d.ts +25 -0
- package/dist/core/csrf.js +78 -0
- package/dist/core/database.d.ts +49 -4
- package/dist/core/database.js +89 -21
- package/dist/core/events.d.ts +129 -5
- package/dist/core/events.js +165 -7
- package/dist/core/health.d.ts +141 -0
- package/dist/core/health.js +226 -0
- package/dist/core/helpers.d.ts +15 -3
- package/dist/core/helpers.js +23 -3
- package/dist/core/index.d.ts +33 -18
- package/dist/core/index.js +16 -8
- package/dist/core/lock.d.ts +139 -0
- package/dist/core/lock.js +215 -0
- package/dist/core/logger.d.ts +82 -4
- package/dist/core/logger.js +141 -23
- package/dist/core/mail.d.ts +128 -7
- package/dist/core/mail.js +264 -16
- package/dist/core/model.d.ts +2 -0
- package/dist/core/model.js +16 -14
- package/dist/core/provider.d.ts +7 -0
- package/dist/core/provider.js +7 -0
- package/dist/core/queue.d.ts +134 -9
- package/dist/core/queue.js +304 -14
- package/dist/core/rate-limit.js +3 -0
- package/dist/core/relations.js +13 -13
- package/dist/core/request.d.ts +26 -0
- package/dist/core/request.js +77 -0
- package/dist/core/shield.d.ts +39 -0
- package/dist/core/shield.js +60 -0
- package/dist/core/social.d.ts +173 -0
- package/dist/core/social.js +337 -0
- package/dist/core/storage.d.ts +159 -6
- package/dist/core/storage.js +287 -7
- package/dist/core/tokens.d.ts +74 -0
- package/dist/core/tokens.js +155 -0
- package/dist/db/d1.d.ts +32 -0
- package/dist/db/d1.js +26 -0
- package/dist/db/libsql.d.ts +29 -0
- package/dist/db/libsql.js +32 -0
- package/dist/db/pg.d.ts +29 -0
- package/dist/db/pg.js +33 -0
- package/dist/mcp/server.d.ts +19 -0
- package/dist/mcp/server.js +355 -0
- package/docs/ai-manifest.json +2472 -0
- package/docs/ai.md +128 -0
- package/docs/architecture.md +331 -0
- package/docs/authentication.md +453 -0
- package/docs/authorization.md +167 -0
- package/docs/broadcasting.md +137 -0
- package/docs/broker.md +500 -0
- package/docs/cache.md +558 -0
- package/docs/configuration.md +311 -0
- package/docs/console.md +356 -0
- package/docs/container.md +467 -0
- package/docs/controllers.md +265 -0
- package/docs/cors.md +51 -0
- package/docs/database.md +530 -0
- package/docs/debugging.md +129 -0
- package/docs/decorators.md +127 -0
- package/docs/errors.md +395 -0
- package/docs/events.md +496 -0
- package/docs/examples/architecture-app.ts +27 -0
- package/docs/examples/authentication.ts +61 -0
- package/docs/examples/authorization.ts +79 -0
- package/docs/examples/broadcasting.ts +60 -0
- package/docs/examples/broker-cache-validate.ts +34 -0
- package/docs/examples/broker-fault-tolerance.ts +29 -0
- package/docs/examples/broker-middleware.ts +27 -0
- package/docs/examples/broker.ts +203 -0
- package/docs/examples/cache.ts +222 -0
- package/docs/examples/configuration.ts +81 -0
- package/docs/examples/container.ts +134 -0
- package/docs/examples/controllers.ts +86 -0
- package/docs/examples/database.ts +118 -0
- package/docs/examples/debugging.ts +41 -0
- package/docs/examples/decorators.ts +40 -0
- package/docs/examples/errors.ts +121 -0
- package/docs/examples/events.ts +204 -0
- package/docs/examples/factories.ts +84 -0
- package/docs/examples/hashing.ts +71 -0
- package/docs/examples/health.ts +94 -0
- package/docs/examples/helpers.ts +171 -0
- package/docs/examples/hooks.ts +54 -0
- package/docs/examples/inertia.ts +81 -0
- package/docs/examples/locks.ts +120 -0
- package/docs/examples/logger.ts +92 -0
- package/docs/examples/mail.ts +160 -0
- package/docs/examples/middleware.ts +119 -0
- package/docs/examples/migrations.ts +126 -0
- package/docs/examples/models.ts +239 -0
- package/docs/examples/notification.ts +124 -0
- package/docs/examples/providers.ts +123 -0
- package/docs/examples/queues.ts +254 -0
- package/docs/examples/rate-limiting.ts +42 -0
- package/docs/examples/redis.ts +99 -0
- package/docs/examples/request-response.ts +197 -0
- package/docs/examples/routing.ts +186 -0
- package/docs/examples/scheduling.ts +62 -0
- package/docs/examples/sessions.ts +102 -0
- package/docs/examples/static-files.ts +63 -0
- package/docs/examples/storage.ts +132 -0
- package/docs/examples/templates.ts +58 -0
- package/docs/examples/testing.ts +66 -0
- package/docs/examples/transformer.ts +141 -0
- package/docs/examples/transformers.ts +49 -0
- package/docs/examples/url-builder.ts +86 -0
- package/docs/examples/validation.ts +102 -0
- package/docs/examples/views.tsx +62 -0
- package/docs/examples/vite.ts +106 -0
- package/docs/factories.md +166 -0
- package/docs/getting-started.md +290 -0
- package/docs/hashing.md +259 -0
- package/docs/health.md +225 -0
- package/docs/helpers.md +347 -0
- package/docs/hono.md +186 -0
- package/docs/hooks.md +118 -0
- package/docs/inertia.md +241 -0
- package/docs/locks.md +323 -0
- package/docs/logger.md +290 -0
- package/docs/mail.md +678 -0
- package/docs/middleware.md +425 -0
- package/docs/migrations.md +476 -0
- package/docs/models.md +810 -0
- package/docs/notifications.md +474 -0
- package/docs/providers.md +363 -0
- package/docs/queues.md +679 -0
- package/docs/rate-limiting.md +155 -0
- package/docs/redis.md +178 -0
- package/docs/request-response.md +953 -0
- package/docs/routing.md +804 -0
- package/docs/scheduling.md +110 -0
- package/docs/security.md +85 -0
- package/docs/sessions.md +354 -0
- package/docs/social-auth.md +174 -0
- package/docs/static-files.md +211 -0
- package/docs/storage.md +450 -0
- package/docs/templates.md +315 -0
- package/docs/testing.md +125 -0
- package/docs/transformers.md +381 -0
- package/docs/url-builder.md +295 -0
- package/docs/validation.md +288 -0
- package/docs/views.md +267 -0
- package/docs/vite.md +434 -0
- package/llms-full.txt +17694 -0
- package/llms.txt +116 -0
- package/package.json +38 -7
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Rate Limiting
|
|
2
|
+
|
|
3
|
+
`rateLimiter()` is a middleware that caps how many requests a client can make in
|
|
4
|
+
a window. It sets the standard `X-RateLimit-*` and `Retry-After` headers, and
|
|
5
|
+
returns `429 Too Many Requests` when the limit is exceeded.
|
|
6
|
+
|
|
7
|
+
It's a **fixed-window** limiter: each key gets a bucket that counts requests
|
|
8
|
+
until a fixed reset time, then starts over. Simple, cheap, and edge-safe — the
|
|
9
|
+
default store is a plain in-memory `Map`, so nothing is imported that can't run
|
|
10
|
+
on a Worker.
|
|
11
|
+
|
|
12
|
+
## Global or per-route
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { rateLimiter } from "@shaferllc/keel/core";
|
|
16
|
+
|
|
17
|
+
// every request: 60 per minute per IP
|
|
18
|
+
export class Kernel extends HttpKernel {
|
|
19
|
+
constructor(app: Application) {
|
|
20
|
+
super(app);
|
|
21
|
+
this.use(rateLimiter({ max: 60, window: 60 }));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// a stricter limit on a sensitive route
|
|
26
|
+
router.post("/login", [AuthController, "login"]).use(rateLimiter({ max: 5, window: 60 }));
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Each call to `rateLimiter()` owns its own bucket store, so a global limiter and a
|
|
30
|
+
per-route limiter count independently — a request to `/login` ticks both, but in
|
|
31
|
+
separate buckets. Stack as many as you like.
|
|
32
|
+
|
|
33
|
+
## Options
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
rateLimiter({
|
|
37
|
+
max: 60, // requests per window (default 60)
|
|
38
|
+
window: 60, // window seconds (default 60)
|
|
39
|
+
key: (c) => c.req.header("x-api-key") ?? "anon", // bucket key (default: IP)
|
|
40
|
+
message: "Slow down!", // 429 body message
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The `key` function decides what to limit by — per IP (default), per API key, per
|
|
45
|
+
user id, etc. Different keys get independent buckets. Return the same string to
|
|
46
|
+
share a bucket; return `"global"` (or any constant) to limit everyone together.
|
|
47
|
+
|
|
48
|
+
### The default key
|
|
49
|
+
|
|
50
|
+
With no `key`, the bucket is derived from the client IP, tried in this order:
|
|
51
|
+
|
|
52
|
+
1. the first entry of `X-Forwarded-For` (trimmed),
|
|
53
|
+
2. `X-Real-IP`,
|
|
54
|
+
3. the literal `"global"` if neither header is present.
|
|
55
|
+
|
|
56
|
+
That fallback means that behind a proxy that strips those headers, *every* client
|
|
57
|
+
shares the `"global"` bucket — so set an explicit `key` if your platform doesn't
|
|
58
|
+
surface the client IP.
|
|
59
|
+
|
|
60
|
+
## Response headers
|
|
61
|
+
|
|
62
|
+
Every response carries:
|
|
63
|
+
|
|
64
|
+
| Header | Meaning |
|
|
65
|
+
|--------|---------|
|
|
66
|
+
| `X-RateLimit-Limit` | the ceiling for the window |
|
|
67
|
+
| `X-RateLimit-Remaining` | requests left in the window |
|
|
68
|
+
| `Retry-After` | (on 429) seconds until the window resets |
|
|
69
|
+
|
|
70
|
+
On an allowed request the two `X-RateLimit-*` headers are written *after* the
|
|
71
|
+
handler runs. On a rejected request all three are set on the `429` itself.
|
|
72
|
+
|
|
73
|
+
## What happens at the limit
|
|
74
|
+
|
|
75
|
+
The counter increments on every request. The request that pushes the count
|
|
76
|
+
*past* `max` is the one that's rejected — so `max: 5` lets five requests through
|
|
77
|
+
and blocks the sixth within the window. The `429` body is:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{ "error": "Too Many Requests", "status": 429 }
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`error` is your `message` if you passed one. `Retry-After` reports the whole
|
|
84
|
+
seconds until the bucket resets. Once the window elapses the next request starts
|
|
85
|
+
a fresh bucket at count 1.
|
|
86
|
+
|
|
87
|
+
## Storage
|
|
88
|
+
|
|
89
|
+
The default store is **in-memory** — per process, and per isolate on the edge.
|
|
90
|
+
That's fine for a single instance, but limits aren't shared across instances.
|
|
91
|
+
The store self-prunes: once it holds more than 10,000 keys it sweeps expired
|
|
92
|
+
buckets on the next request, so a large key space (e.g. per-IP) won't grow
|
|
93
|
+
unbounded.
|
|
94
|
+
|
|
95
|
+
For distributed limiting, wrap your own middleware that counts in Redis/KV and
|
|
96
|
+
returns `429` the same way.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## API reference
|
|
101
|
+
|
|
102
|
+
### `rateLimiter(options?)`
|
|
103
|
+
|
|
104
|
+
`rateLimiter(options?: RateLimiterOptions): MiddlewareHandler`
|
|
105
|
+
|
|
106
|
+
Builds a fixed-window rate-limiting middleware. Each returned handler keeps its
|
|
107
|
+
own private bucket store, counts requests per key within the window, sets the
|
|
108
|
+
`X-RateLimit-*` headers, and short-circuits with `429` past the limit.
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { rateLimiter } from "@shaferllc/keel/core";
|
|
112
|
+
|
|
113
|
+
const limit = rateLimiter({ max: 100, window: 60 });
|
|
114
|
+
// register it: this.use(limit) globally, or .use(limit) on a route
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Notes:** all options are optional — `rateLimiter()` with no arguments is 60
|
|
118
|
+
requests per 60 seconds, keyed by client IP. The returned handler is a Hono
|
|
119
|
+
`MiddlewareHandler`, so it works anywhere middleware is accepted (`use`, per
|
|
120
|
+
route, per group). Buckets live in a closure over the single call, so reusing the
|
|
121
|
+
*same* handler shares state while a second `rateLimiter(...)` call does not.
|
|
122
|
+
The `429` is returned before `next()`, so downstream handlers never run for a
|
|
123
|
+
throttled request.
|
|
124
|
+
|
|
125
|
+
### Interfaces & types
|
|
126
|
+
|
|
127
|
+
#### `RateLimiterOptions`
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
interface RateLimiterOptions {
|
|
131
|
+
max?: number; // requests per window; default 60
|
|
132
|
+
window?: number; // window length in seconds; default 60
|
|
133
|
+
key?: (c: Context) => string; // bucket key; default: client IP
|
|
134
|
+
message?: string; // 429 body message; default "Too Many Requests"
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The shape you pass to `rateLimiter()`. Every field is optional; `key` receives the
|
|
139
|
+
Hono `Context` and returns the string that identifies the bucket.
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import { rateLimiter, type RateLimiterOptions } from "@shaferllc/keel/core";
|
|
143
|
+
|
|
144
|
+
const perUser: RateLimiterOptions = {
|
|
145
|
+
max: 30,
|
|
146
|
+
window: 60,
|
|
147
|
+
key: (c) => c.req.header("authorization") ?? "anon",
|
|
148
|
+
message: "Easy there — try again shortly.",
|
|
149
|
+
};
|
|
150
|
+
rateLimiter(perUser);
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Notes:** `window` is **seconds**, not milliseconds (it's multiplied by 1000
|
|
154
|
+
internally). `key` is called on every request, so keep it cheap and pure. Returning
|
|
155
|
+
a constant string collapses all clients into one shared bucket.
|
package/docs/redis.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Redis
|
|
2
|
+
|
|
3
|
+
A Redis integration built on a small pluggable driver — like the database and
|
|
4
|
+
mail layers, the core imports no client, so it runs on Node and on the edge.
|
|
5
|
+
Point it at Upstash (HTTP/`fetch`), ioredis, node-redis, or the built-in
|
|
6
|
+
`MemoryRedis` for tests and local dev.
|
|
7
|
+
|
|
8
|
+
## Using it
|
|
9
|
+
|
|
10
|
+
Register a driver once (in a service provider), then reach Redis anywhere with
|
|
11
|
+
`redis()`:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { redis, setRedis, MemoryRedis } from "@shaferllc/keel/core";
|
|
15
|
+
|
|
16
|
+
setRedis(new MemoryRedis()); // swap for an Upstash / ioredis adapter in production
|
|
17
|
+
|
|
18
|
+
await redis().set("views", "1");
|
|
19
|
+
await redis().incr("views"); // 2
|
|
20
|
+
await redis().get("views"); // "2"
|
|
21
|
+
await redis().set("token", "abc", { ex: 60 }); // expire in 60s
|
|
22
|
+
await redis().del("token");
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The default client is a `MemoryRedis`, so `redis()` works out of the box in
|
|
26
|
+
tests without any setup.
|
|
27
|
+
|
|
28
|
+
## Commands
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
const r = redis();
|
|
32
|
+
|
|
33
|
+
await r.get(key); // string | null
|
|
34
|
+
await r.set(key, value, { ex }); // { ex: seconds } or { px: ms }
|
|
35
|
+
await r.del(...keys); // number removed
|
|
36
|
+
await r.exists(...keys); // number present
|
|
37
|
+
await r.has(key); // boolean
|
|
38
|
+
|
|
39
|
+
await r.incr(key); // +1
|
|
40
|
+
await r.decr(key); // -1
|
|
41
|
+
await r.incrBy(key, 5);
|
|
42
|
+
|
|
43
|
+
await r.expire(key, 60); // set a TTL (seconds)
|
|
44
|
+
await r.ttl(key); // seconds left, -1 (no expiry), -2 (no key)
|
|
45
|
+
await r.keys("user:*"); // glob match
|
|
46
|
+
await r.flushAll(); // clear everything
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### JSON & remember
|
|
50
|
+
|
|
51
|
+
`getJson` / `setJson` handle serialization, and `remember` is the read-through
|
|
52
|
+
cache pattern:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
await redis().setJson("user:1", { id: 1, name: "Ada" });
|
|
56
|
+
const user = await redis().getJson<{ id: number; name: string }>("user:1");
|
|
57
|
+
|
|
58
|
+
// Compute once, cache for 300s, serve from cache after:
|
|
59
|
+
const stats = await redis().remember("stats", 300, () => computeStats());
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## As a cache store
|
|
63
|
+
|
|
64
|
+
`redisStore()` adapts the Redis client into a [`CacheStore`](./cache.md), so the
|
|
65
|
+
cache can be Redis-backed — shared across instances instead of per-process:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { Cache, redisStore, redis } from "@shaferllc/keel/core";
|
|
69
|
+
|
|
70
|
+
const cache = new Cache(redisStore(redis()));
|
|
71
|
+
await cache.remember("home", 60, () => renderHome());
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Writing a driver
|
|
75
|
+
|
|
76
|
+
A driver is the `RedisConnection` interface. Here's the shape for an Upstash
|
|
77
|
+
REST client over `fetch` (edge-safe):
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import type { RedisConnection } from "@shaferllc/keel/core";
|
|
81
|
+
|
|
82
|
+
const upstash = (url: string, token: string): RedisConnection => {
|
|
83
|
+
const call = (...args: (string | number)[]) =>
|
|
84
|
+
fetch(url, {
|
|
85
|
+
method: "POST",
|
|
86
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
87
|
+
body: JSON.stringify(args),
|
|
88
|
+
}).then((r) => r.json());
|
|
89
|
+
return {
|
|
90
|
+
async get(key) { return (await call("GET", key)).result ?? null; },
|
|
91
|
+
async set(key, value, o) {
|
|
92
|
+
await (o?.ex ? call("SET", key, value, "EX", o.ex) : call("SET", key, value));
|
|
93
|
+
},
|
|
94
|
+
async del(...keys) { return (await call("DEL", ...keys)).result; },
|
|
95
|
+
async exists(...keys) { return (await call("EXISTS", ...keys)).result; },
|
|
96
|
+
async incrBy(key, n) { return (await call("INCRBY", key, n)).result; },
|
|
97
|
+
async expire(key, s) { return (await call("EXPIRE", key, s)).result === 1; },
|
|
98
|
+
async ttl(key) { return (await call("TTL", key)).result; },
|
|
99
|
+
async keys(pattern) { return (await call("KEYS", pattern)).result; },
|
|
100
|
+
async flushAll() { await call("FLUSHALL"); },
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
setRedis(upstash(env("UPSTASH_URL"), env("UPSTASH_TOKEN")));
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## In tests
|
|
107
|
+
|
|
108
|
+
`MemoryRedis` is a full in-memory implementation with TTL support — no server:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { setRedis, MemoryRedis, redis } from "@shaferllc/keel/core";
|
|
112
|
+
|
|
113
|
+
setRedis(new MemoryRedis());
|
|
114
|
+
await redis().incr("signups");
|
|
115
|
+
assert.equal(await redis().get("signups"), "1");
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## API reference
|
|
119
|
+
|
|
120
|
+
### `redis()`
|
|
121
|
+
|
|
122
|
+
`redis(): Redis`
|
|
123
|
+
|
|
124
|
+
The default client. Register a driver with `setRedis` first; defaults to a
|
|
125
|
+
`MemoryRedis`.
|
|
126
|
+
|
|
127
|
+
### `setRedis(conn)`
|
|
128
|
+
|
|
129
|
+
`setRedis(conn: RedisConnection): Redis`
|
|
130
|
+
|
|
131
|
+
Registers the driver behind `redis()` and returns the wrapping client. Last call
|
|
132
|
+
wins.
|
|
133
|
+
|
|
134
|
+
### `Redis`
|
|
135
|
+
|
|
136
|
+
Wraps a `RedisConnection` with conveniences.
|
|
137
|
+
|
|
138
|
+
| Method | Signature | Notes |
|
|
139
|
+
|--------|-----------|-------|
|
|
140
|
+
| `get` | `(key) => Promise<string \| null>` | raw string value |
|
|
141
|
+
| `set` | `(key, value, options?) => Promise<void>` | `{ ex: seconds }` / `{ px: ms }` |
|
|
142
|
+
| `del` / `exists` | `(...keys) => Promise<number>` | count removed / present |
|
|
143
|
+
| `has` | `(key) => Promise<boolean>` | `exists(key) > 0` |
|
|
144
|
+
| `incr` / `decr` | `(key) => Promise<number>` | ±1 |
|
|
145
|
+
| `incrBy` | `(key, amount) => Promise<number>` | atomic add |
|
|
146
|
+
| `expire` | `(key, seconds) => Promise<boolean>` | false if the key is gone |
|
|
147
|
+
| `ttl` | `(key) => Promise<number>` | seconds, `-1` no expiry, `-2` no key |
|
|
148
|
+
| `keys` | `(pattern?) => Promise<string[]>` | glob; default `"*"` |
|
|
149
|
+
| `flushAll` | `() => Promise<void>` | clear all |
|
|
150
|
+
| `getJson` / `setJson` | JSON convenience over `get`/`set` | |
|
|
151
|
+
| `remember` | `(key, seconds, factory) => Promise<T>` | read-through cache |
|
|
152
|
+
|
|
153
|
+
### `MemoryRedis`
|
|
154
|
+
|
|
155
|
+
`class MemoryRedis implements RedisConnection`
|
|
156
|
+
|
|
157
|
+
An in-memory driver with TTL support — the default and ideal for tests. Not
|
|
158
|
+
shared across processes.
|
|
159
|
+
|
|
160
|
+
### `redisStore(client?)`
|
|
161
|
+
|
|
162
|
+
`redisStore(client?: Redis): CacheStore`
|
|
163
|
+
|
|
164
|
+
Adapts a `Redis` client into a `CacheStore` for the cache layer. Defaults to the
|
|
165
|
+
global `redis()`.
|
|
166
|
+
|
|
167
|
+
### Interfaces & types
|
|
168
|
+
|
|
169
|
+
#### `RedisConnection`
|
|
170
|
+
|
|
171
|
+
The driver seam — implement it to back Redis with any client. Methods: `get`,
|
|
172
|
+
`set`, `del`, `exists`, `incrBy`, `expire`, `ttl`, `keys`, `flushAll`.
|
|
173
|
+
|
|
174
|
+
#### `SetOptions`
|
|
175
|
+
|
|
176
|
+
`interface SetOptions { ex?: number; px?: number }`
|
|
177
|
+
|
|
178
|
+
Expiry for `set` — `ex` in seconds, `px` in milliseconds.
|