@beignet/provider-redis 0.0.2 → 0.0.4
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 +48 -0
- package/README.md +58 -16
- package/dist/index.d.ts +93 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +307 -223
- package/dist/index.js.map +1 -1
- package/package.json +38 -3
- package/src/index.ts +396 -245
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
# @beignet/provider-redis
|
|
2
2
|
|
|
3
|
+
## 0.0.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8bcb31f: Mark package READMEs with Beignet's experimental alpha status and 0.0.x stability expectations.
|
|
8
|
+
- d137044: Declare `@beignet/core` as a peer dependency with a lockstep version range in
|
|
9
|
+
every integration and provider package instead of a regular `"*"` dependency.
|
|
10
|
+
Installs now always resolve a single shared copy of core, so `instanceof`
|
|
11
|
+
checks such as `isContractError` and upload error identity keep working, and
|
|
12
|
+
mixed Beignet versions fail loudly at install time instead of at runtime.
|
|
13
|
+
|
|
14
|
+
If your package manager does not install peer dependencies automatically, add
|
|
15
|
+
`@beignet/core` to your app alongside these packages. `@beignet/nuqs` now also
|
|
16
|
+
declares `@beignet/react-query` as a peer dependency, and
|
|
17
|
+
`@beignet/provider-storage-s3` now expects you to install
|
|
18
|
+
`@aws-sdk/client-s3` and `@aws-sdk/s3-request-presigner` yourself, matching
|
|
19
|
+
how other providers treat their SDKs.
|
|
20
|
+
|
|
21
|
+
- 603478f: Align package documentation with the canonical route registry and AppContext conventions.
|
|
22
|
+
- 1a79090: Emit Node-compatible ESM: all relative imports in published packages now carry explicit .js extensions, fixing ERR_MODULE_NOT_FOUND when running the CLI or importing package dist files under plain Node.
|
|
23
|
+
- 44f1192: Move first-party provider diagnostics to package-owned `beignet.provider`
|
|
24
|
+
manifest metadata and have doctor read installed provider package manifests.
|
|
25
|
+
- 2aa77ca: Add static provider metadata and provider wiring diagnostics for generated apps.
|
|
26
|
+
- 89390fe: Add `createRedisProvider(options)` factory with connection robustness controls
|
|
27
|
+
and move the raw client escape hatch to a separate port.
|
|
28
|
+
|
|
29
|
+
- New config: `REDIS_CONNECT_TIMEOUT_MS` (default 5000),
|
|
30
|
+
`REDIS_MAX_RETRIES_PER_REQUEST` (default 2), and
|
|
31
|
+
`REDIS_CONNECT_MAX_ATTEMPTS` (default 3), with matching factory options
|
|
32
|
+
`connectTimeoutMs`, `maxRetriesPerRequest`, `retryStrategy`, and `db`.
|
|
33
|
+
- Startup now fails fast with a clear error when Redis is unreachable instead
|
|
34
|
+
of retrying forever. After a successful connection, reconnects use capped
|
|
35
|
+
exponential backoff (max 2s).
|
|
36
|
+
- The provider now contributes `{ cache: CachePort, redis: { client } }`.
|
|
37
|
+
`RedisCachePort` is replaced by the exported `RedisProviderPorts` interface;
|
|
38
|
+
access the raw ioredis client through `ctx.ports.redis.client` instead of
|
|
39
|
+
casting `ctx.ports.cache`.
|
|
40
|
+
|
|
41
|
+
## 0.0.3
|
|
42
|
+
|
|
43
|
+
### Patch Changes
|
|
44
|
+
|
|
45
|
+
- Updated dependencies [3160184]
|
|
46
|
+
- Updated dependencies [254ef6d]
|
|
47
|
+
- Updated dependencies [4cb1784]
|
|
48
|
+
- Updated dependencies [8bd9085]
|
|
49
|
+
- @beignet/core@0.0.3
|
|
50
|
+
|
|
3
51
|
## 0.0.2
|
|
4
52
|
|
|
5
53
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
# @beignet/provider-redis
|
|
2
2
|
|
|
3
|
+
> [!CAUTION]
|
|
4
|
+
> Beignet is experimental alpha software. The `0.0.x` package line is for early
|
|
5
|
+
> evaluation, and APIs may change between releases while the framework settles.
|
|
6
|
+
|
|
3
7
|
Redis-backed `CachePort` provider for Beignet applications.
|
|
4
8
|
|
|
5
9
|
The provider installs `ctx.ports.cache` using
|
|
6
|
-
[ioredis](https://github.com/redis/ioredis) and exposes the Redis client
|
|
7
|
-
as
|
|
10
|
+
[ioredis](https://github.com/redis/ioredis) and exposes the raw Redis client
|
|
11
|
+
separately as `ctx.ports.redis` for Redis-specific features.
|
|
8
12
|
|
|
9
13
|
## Install
|
|
10
14
|
|
|
11
15
|
```bash
|
|
12
|
-
bun add @beignet/provider-redis ioredis
|
|
16
|
+
bun add @beignet/provider-redis @beignet/core ioredis
|
|
13
17
|
```
|
|
14
18
|
|
|
15
19
|
## Setup
|
|
@@ -29,7 +33,7 @@ const appPorts = definePorts({});
|
|
|
29
33
|
export const server = await createNextServer({
|
|
30
34
|
ports: appPorts,
|
|
31
35
|
providers: [redisProvider],
|
|
32
|
-
|
|
36
|
+
context: ({ ports }) => ({
|
|
33
37
|
ports,
|
|
34
38
|
}),
|
|
35
39
|
routes,
|
|
@@ -42,7 +46,7 @@ Once the provider is registered, your ports will include a `cache` property:
|
|
|
42
46
|
|
|
43
47
|
```typescript
|
|
44
48
|
// In your use case
|
|
45
|
-
async function getUserProfile(ctx:
|
|
49
|
+
async function getUserProfile(ctx: AppContext) {
|
|
46
50
|
const userId = ctx.actor.type === "user" ? ctx.actor.id : undefined;
|
|
47
51
|
if (!userId) throw new Error("User actor required.");
|
|
48
52
|
|
|
@@ -76,6 +80,38 @@ The Redis provider reads configuration from environment variables with the `REDI
|
|
|
76
80
|
|----------|----------|-------------|---------|
|
|
77
81
|
| `REDIS_URL` | Yes | Redis connection URL | `redis://localhost:6379` |
|
|
78
82
|
| `REDIS_DB` | No | Redis database number (default: 0) | `0` |
|
|
83
|
+
| `REDIS_CONNECT_TIMEOUT_MS` | No | Initial connection timeout in milliseconds (default: 5000) | `2000` |
|
|
84
|
+
| `REDIS_MAX_RETRIES_PER_REQUEST` | No | Per-command retry limit before the command rejects (default: 2) | `1` |
|
|
85
|
+
| `REDIS_CONNECT_MAX_ATTEMPTS` | No | Connection attempts before startup fails (default: 3) | `5` |
|
|
86
|
+
|
|
87
|
+
### Factory options
|
|
88
|
+
|
|
89
|
+
Use `createRedisProvider(options)` when the app should own connection
|
|
90
|
+
defaults. Matching `REDIS_*` environment variables still win when both are
|
|
91
|
+
set:
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { createRedisProvider } from "@beignet/provider-redis";
|
|
95
|
+
|
|
96
|
+
const redisProvider = createRedisProvider({
|
|
97
|
+
connectTimeoutMs: 2000,
|
|
98
|
+
maxRetriesPerRequest: 1,
|
|
99
|
+
db: 1,
|
|
100
|
+
// Optional: replace the default retry strategy entirely.
|
|
101
|
+
retryStrategy: (times) => Math.min(times * 100, 1000),
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The default `redisProvider` export is `createRedisProvider()` with no options.
|
|
106
|
+
|
|
107
|
+
### Connection behavior
|
|
108
|
+
|
|
109
|
+
During startup the provider connects eagerly and fails fast: the initial
|
|
110
|
+
`connect()` stops retrying after `REDIS_CONNECT_MAX_ATTEMPTS` attempts (or
|
|
111
|
+
after `REDIS_CONNECT_TIMEOUT_MS` per attempt) and throws a clear error instead
|
|
112
|
+
of hanging against an unreachable host. After a successful connection, lost
|
|
113
|
+
connections are retried forever with capped exponential backoff (maximum 2
|
|
114
|
+
seconds between attempts).
|
|
79
115
|
|
|
80
116
|
## Cache port API
|
|
81
117
|
|
|
@@ -130,16 +166,20 @@ const value = await ctx.ports.cache.remember(
|
|
|
130
166
|
);
|
|
131
167
|
```
|
|
132
168
|
|
|
133
|
-
|
|
169
|
+
## Escape hatch
|
|
134
170
|
|
|
135
|
-
|
|
171
|
+
The provider also contributes `ctx.ports.redis` with the raw ioredis client
|
|
172
|
+
for operations the stable cache port does not model:
|
|
136
173
|
|
|
137
174
|
```typescript
|
|
138
175
|
// Use ioredis methods directly
|
|
139
|
-
await ctx.ports.
|
|
140
|
-
await ctx.ports.
|
|
176
|
+
await ctx.ports.redis.client.expire("key", 300);
|
|
177
|
+
await ctx.ports.redis.client.incr("counter");
|
|
141
178
|
```
|
|
142
179
|
|
|
180
|
+
Use the stable `CachePort` for normal application behavior. Use the raw client
|
|
181
|
+
only when the Redis-specific operation is intentional.
|
|
182
|
+
|
|
143
183
|
## Devtools
|
|
144
184
|
|
|
145
185
|
When `@beignet/devtools` is installed before this provider, Redis cache
|
|
@@ -151,25 +191,26 @@ duration. Cached values are not recorded.
|
|
|
151
191
|
|
|
152
192
|
## TypeScript support
|
|
153
193
|
|
|
154
|
-
To get proper type inference for the
|
|
194
|
+
To get proper type inference for the contributed ports, extend your ports
|
|
195
|
+
type with `RedisProviderPorts`:
|
|
155
196
|
|
|
156
197
|
```typescript
|
|
157
|
-
import type {
|
|
198
|
+
import type { RedisProviderPorts } from "@beignet/provider-redis";
|
|
158
199
|
|
|
159
200
|
// Your base ports, if any
|
|
160
201
|
const basePorts = definePorts({});
|
|
161
202
|
|
|
162
203
|
// After using redisProvider, your ports will have this shape:
|
|
163
|
-
type AppPorts = typeof basePorts &
|
|
164
|
-
|
|
165
|
-
};
|
|
204
|
+
type AppPorts = typeof basePorts & RedisProviderPorts;
|
|
205
|
+
// { cache: CachePort; redis: { client: Redis } }
|
|
166
206
|
```
|
|
167
207
|
|
|
168
208
|
## Lifecycle
|
|
169
209
|
|
|
170
210
|
The Redis provider:
|
|
171
211
|
|
|
172
|
-
1. **During `setup`**: Connects to Redis and returns the `cache`
|
|
212
|
+
1. **During `setup`**: Connects to Redis and returns the `cache` and `redis`
|
|
213
|
+
ports
|
|
173
214
|
2. **During `stop`**: Gracefully closes the Redis connection
|
|
174
215
|
|
|
175
216
|
## Error handling
|
|
@@ -177,7 +218,8 @@ The Redis provider:
|
|
|
177
218
|
The provider will throw errors in these cases:
|
|
178
219
|
|
|
179
220
|
- Missing `REDIS_URL` environment variable
|
|
180
|
-
- Failed connection to Redis server
|
|
221
|
+
- Failed connection to Redis server after `REDIS_CONNECT_MAX_ATTEMPTS`
|
|
222
|
+
attempts
|
|
181
223
|
|
|
182
224
|
Make sure to handle these during application startup.
|
|
183
225
|
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
* Configuration:
|
|
7
7
|
* - REDIS_URL: Redis connection URL (required)
|
|
8
8
|
* - REDIS_DB: Redis database number (optional, default: 0)
|
|
9
|
+
* - REDIS_CONNECT_TIMEOUT_MS: Initial connection timeout in milliseconds (optional, default: 5000)
|
|
10
|
+
* - REDIS_MAX_RETRIES_PER_REQUEST: Per-command retry limit (optional, default: 2)
|
|
11
|
+
* - REDIS_CONNECT_MAX_ATTEMPTS: Connection attempts before startup fails (optional, default: 3)
|
|
9
12
|
*
|
|
10
13
|
* @example
|
|
11
14
|
* ```ts
|
|
@@ -29,7 +32,7 @@
|
|
|
29
32
|
* ```
|
|
30
33
|
*/
|
|
31
34
|
import type { CachePort } from "@beignet/core/ports";
|
|
32
|
-
import Redis from "ioredis";
|
|
35
|
+
import { Redis } from "ioredis";
|
|
33
36
|
import { z } from "zod";
|
|
34
37
|
/**
|
|
35
38
|
* Configuration schema for the Redis provider.
|
|
@@ -37,29 +40,102 @@ import { z } from "zod";
|
|
|
37
40
|
*/
|
|
38
41
|
declare const RedisConfigSchema: z.ZodObject<{
|
|
39
42
|
URL: z.ZodString;
|
|
40
|
-
DB: z.ZodOptional<z.
|
|
43
|
+
DB: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<number, string>>>;
|
|
44
|
+
CONNECT_TIMEOUT_MS: z.ZodDefault<z.ZodPipe<z.ZodString, z.ZodTransform<number, string>>>;
|
|
45
|
+
MAX_RETRIES_PER_REQUEST: z.ZodDefault<z.ZodPipe<z.ZodString, z.ZodTransform<number, string>>>;
|
|
46
|
+
CONNECT_MAX_ATTEMPTS: z.ZodDefault<z.ZodPipe<z.ZodString, z.ZodTransform<number, string>>>;
|
|
41
47
|
}, z.core.$strip>;
|
|
42
48
|
/**
|
|
43
49
|
* Inferred configuration type for Redis provider.
|
|
44
50
|
*/
|
|
45
51
|
export type RedisConfig = z.infer<typeof RedisConfigSchema>;
|
|
46
52
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
53
|
+
* Options for {@link createRedisProvider}.
|
|
54
|
+
*
|
|
55
|
+
* Numeric options become schema defaults, so matching `REDIS_*` environment
|
|
56
|
+
* variables still win when both are set.
|
|
57
|
+
*/
|
|
58
|
+
export interface RedisProviderOptions {
|
|
59
|
+
/**
|
|
60
|
+
* Timeout for the initial connection attempt, in milliseconds.
|
|
61
|
+
*
|
|
62
|
+
* @default 5000
|
|
63
|
+
*/
|
|
64
|
+
connectTimeoutMs?: number;
|
|
65
|
+
/**
|
|
66
|
+
* How many times a single command is retried before its promise rejects.
|
|
67
|
+
*
|
|
68
|
+
* @default 2
|
|
69
|
+
*/
|
|
70
|
+
maxRetriesPerRequest?: number;
|
|
71
|
+
/**
|
|
72
|
+
* Custom ioredis retry strategy. Replaces the default strategy, which stops
|
|
73
|
+
* retrying after `REDIS_CONNECT_MAX_ATTEMPTS` during the initial connect and
|
|
74
|
+
* reconnects with capped exponential backoff afterwards.
|
|
75
|
+
*/
|
|
76
|
+
retryStrategy?: (times: number) => number | null;
|
|
77
|
+
/**
|
|
78
|
+
* Redis database number.
|
|
79
|
+
*
|
|
80
|
+
* @default 0
|
|
81
|
+
*/
|
|
82
|
+
db?: number;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Escape hatch for apps that need the raw ioredis client.
|
|
49
86
|
*/
|
|
50
|
-
export interface
|
|
87
|
+
export interface RedisEscapeHatch {
|
|
51
88
|
/**
|
|
52
|
-
*
|
|
53
|
-
* Use this for
|
|
89
|
+
* Raw ioredis client.
|
|
90
|
+
* Use this for Redis operations the stable cache port does not model.
|
|
54
91
|
*/
|
|
55
92
|
client: Redis;
|
|
56
93
|
}
|
|
57
94
|
/**
|
|
58
|
-
*
|
|
95
|
+
* Ports contributed by the Redis provider.
|
|
96
|
+
*/
|
|
97
|
+
export interface RedisProviderPorts {
|
|
98
|
+
/**
|
|
99
|
+
* Beignet cache port backed by Redis.
|
|
100
|
+
*/
|
|
101
|
+
cache: CachePort;
|
|
102
|
+
/**
|
|
103
|
+
* Raw ioredis client escape hatch.
|
|
104
|
+
*/
|
|
105
|
+
redis: RedisEscapeHatch;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Create an env-backed Redis cache provider.
|
|
109
|
+
*
|
|
110
|
+
* Reads `REDIS_*` env vars, contributes `ports.cache`, and exposes
|
|
111
|
+
* `ports.redis` for raw ioredis client access.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* const provider = createRedisProvider({ connectTimeoutMs: 2000 });
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
export declare function createRedisProvider(options?: RedisProviderOptions): import("@beignet/core/providers").ServiceProvider<unknown, z.ZodObject<{
|
|
119
|
+
URL: z.ZodString;
|
|
120
|
+
CONNECT_MAX_ATTEMPTS: z.ZodDefault<z.ZodPipe<z.ZodString, z.ZodTransform<number, string>>>;
|
|
121
|
+
DB: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<number, string>>> | z.ZodDefault<z.ZodPipe<z.ZodString, z.ZodTransform<number, string>>>;
|
|
122
|
+
CONNECT_TIMEOUT_MS: z.ZodDefault<z.ZodPipe<z.ZodString, z.ZodTransform<number, string>>>;
|
|
123
|
+
MAX_RETRIES_PER_REQUEST: z.ZodDefault<z.ZodPipe<z.ZodString, z.ZodTransform<number, string>>>;
|
|
124
|
+
}, z.core.$strip>, {
|
|
125
|
+
cache: CachePort;
|
|
126
|
+
redis: {
|
|
127
|
+
client: Redis;
|
|
128
|
+
};
|
|
129
|
+
}, unknown, void>;
|
|
130
|
+
/**
|
|
131
|
+
* Default env-backed Redis provider.
|
|
59
132
|
*
|
|
60
133
|
* Configuration via environment variables:
|
|
61
134
|
* - REDIS_URL: Redis connection URL (required)
|
|
62
135
|
* - REDIS_DB: Redis database number (optional)
|
|
136
|
+
* - REDIS_CONNECT_TIMEOUT_MS: Initial connection timeout in ms (optional)
|
|
137
|
+
* - REDIS_MAX_RETRIES_PER_REQUEST: Per-command retry limit (optional)
|
|
138
|
+
* - REDIS_CONNECT_MAX_ATTEMPTS: Connection attempts before startup fails (optional)
|
|
63
139
|
*
|
|
64
140
|
* @example
|
|
65
141
|
* ```ts
|
|
@@ -72,9 +148,15 @@ export interface RedisCachePort extends CachePort {
|
|
|
72
148
|
*/
|
|
73
149
|
export declare const redisProvider: import("@beignet/core/providers").ServiceProvider<unknown, z.ZodObject<{
|
|
74
150
|
URL: z.ZodString;
|
|
75
|
-
|
|
151
|
+
CONNECT_MAX_ATTEMPTS: z.ZodDefault<z.ZodPipe<z.ZodString, z.ZodTransform<number, string>>>;
|
|
152
|
+
DB: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<number, string>>> | z.ZodDefault<z.ZodPipe<z.ZodString, z.ZodTransform<number, string>>>;
|
|
153
|
+
CONNECT_TIMEOUT_MS: z.ZodDefault<z.ZodPipe<z.ZodString, z.ZodTransform<number, string>>>;
|
|
154
|
+
MAX_RETRIES_PER_REQUEST: z.ZodDefault<z.ZodPipe<z.ZodString, z.ZodTransform<number, string>>>;
|
|
76
155
|
}, z.core.$strip>, {
|
|
77
|
-
cache:
|
|
78
|
-
|
|
156
|
+
cache: CachePort;
|
|
157
|
+
redis: {
|
|
158
|
+
client: Redis;
|
|
159
|
+
};
|
|
160
|
+
}, unknown, void>;
|
|
79
161
|
export {};
|
|
80
162
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAKrD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB;;;GAGG;AACH,QAAA,MAAM,iBAAiB;;;;;;iBAgCrB,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAEjD;;;;OAIG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,MAAM,EAAE,KAAK,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IACjB;;OAEG;IACH,KAAK,EAAE,gBAAgB,CAAC;CACzB;AAUD;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB;;;;;;;;;;;kBAoSrE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;iBAAwB,CAAC"}
|