ioredis-toolkit 0.0.3 → 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/dist/cache.d.ts +2 -2
- package/dist/client.d.ts +9 -7
- package/dist/client.js +79 -28
- package/dist/index.d.ts +1 -1
- package/dist/lock.d.ts +1 -22
- package/dist/lock.js +22 -0
- package/dist/ratelimiter.d.ts +2 -1
- package/dist/session/revocation-store.d.ts +6 -1
- package/dist/session/revocation-store.js +9 -1
- package/dist/session/session-config.d.ts +4 -4
- package/dist/session/session-scripts.d.ts +1 -1
- package/dist/types.d.ts +282 -157
- package/dist/types.js +20 -8
- package/dist/utils/deepmerge.d.ts +9 -0
- package/dist/utils/deepmerge.js +61 -0
- package/package.json +5 -4
package/dist/cache.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RedisClientWrapper } from './client.js';
|
|
2
|
-
import {
|
|
2
|
+
import { CacheOptions, CacheInputConfig } from './types.js';
|
|
3
3
|
import { LoggerLike } from './logger.js';
|
|
4
4
|
/**
|
|
5
5
|
* Cache layer on top of {@link RedisClientWrapper} with JSON serialization,
|
|
@@ -33,7 +33,7 @@ export declare class Cache {
|
|
|
33
33
|
* const cache = new Cache(client, { defaultTTL: 600, compressionThreshold: 2048 });
|
|
34
34
|
* ```
|
|
35
35
|
*/
|
|
36
|
-
constructor(client: RedisClientWrapper, config:
|
|
36
|
+
constructor(client: RedisClientWrapper, config: CacheInputConfig, logger?: LoggerLike);
|
|
37
37
|
private serialize;
|
|
38
38
|
private deserialize;
|
|
39
39
|
private getKey;
|
package/dist/client.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Cluster, Redis as RedisClient } from "ioredis";
|
|
2
|
-
import { type ClusterInfo, type ClusterSlotRange, type ConnectionStatus, type RedisConfigInput, type RedisMode } from "./types.js";
|
|
2
|
+
import { RateLimitOptionsInput, type ClusterInfo, type ClusterSlotRange, type ConnectionStatus, type RedisConfigInput, type RedisMode, DistributedLockInputOptions, CacheInputConfig } from "./types.js";
|
|
3
3
|
import { type LoggerLike } from "./logger.js";
|
|
4
4
|
import { Cache } from "./cache.js";
|
|
5
5
|
import { PubSub } from "./pubsub.js";
|
|
6
6
|
import { DistributedLock } from "./lock.js";
|
|
7
7
|
import { RateLimiter } from "./ratelimiter.js";
|
|
8
|
-
import { SessionManager } from "./session/session-manager.js";
|
|
8
|
+
import { SessionManager, SessionManagerOptions } from "./session/session-manager.js";
|
|
9
|
+
import { RedisRevocationStore } from "./session/revocation-store.js";
|
|
9
10
|
export interface RedisClientOptions {
|
|
10
11
|
config: RedisConfigInput;
|
|
11
12
|
logger?: LoggerLike;
|
|
@@ -69,21 +70,22 @@ export declare class RedisClientWrapper {
|
|
|
69
70
|
private _lock?;
|
|
70
71
|
private _rateLimiter?;
|
|
71
72
|
private _session?;
|
|
73
|
+
private _revocationStore?;
|
|
72
74
|
private readonly config;
|
|
73
75
|
private readonly logger;
|
|
74
76
|
private isReady;
|
|
75
77
|
constructor(config: RedisConfigInput, logger?: LoggerLike);
|
|
76
78
|
get mode(): RedisMode;
|
|
77
79
|
get cache(): Cache;
|
|
78
|
-
|
|
80
|
+
withCache(value: CacheInputConfig): RedisClientWrapper;
|
|
79
81
|
get pubsub(): PubSub;
|
|
80
|
-
set pubsub(value: PubSub);
|
|
81
82
|
get lock(): DistributedLock;
|
|
82
|
-
|
|
83
|
+
withLock(value: DistributedLockInputOptions): RedisClientWrapper;
|
|
83
84
|
get rateLimiter(): RateLimiter;
|
|
84
|
-
|
|
85
|
+
withRateLimiter(value: RateLimitOptionsInput): RedisClientWrapper;
|
|
86
|
+
get revocationStore(): RedisRevocationStore;
|
|
85
87
|
get session(): SessionManager;
|
|
86
|
-
|
|
88
|
+
withSession(value: Omit<SessionManagerOptions, "client">): RedisClientWrapper;
|
|
87
89
|
private createClient;
|
|
88
90
|
private createClusterClient;
|
|
89
91
|
private createSentinelClient;
|
package/dist/client.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Cluster, Redis as RedisClient, } from "ioredis";
|
|
2
2
|
import { ConfigurationError, RedisError } from "./errors.js";
|
|
3
|
-
import { RedisConfigSchema, } from "./types.js";
|
|
3
|
+
import { RateLimitOptionsSchema, RedisConfigSchema, DistributedLockOptionsSchema, CacheOptionsSchema, } from "./types.js";
|
|
4
4
|
import { defaultLogger } from "./logger.js";
|
|
5
5
|
import { executeBySlot } from "./cluster.js";
|
|
6
6
|
import { calculateRedisClusterSlot } from "./cluster-slot.js";
|
|
@@ -10,6 +10,8 @@ import { DistributedLock } from "./lock.js";
|
|
|
10
10
|
import { RateLimiter } from "./ratelimiter.js";
|
|
11
11
|
import { createSessionManager, } from "./session/session-manager.js";
|
|
12
12
|
import { prettifyError } from "zod";
|
|
13
|
+
import { RedisRevocationStore } from "./session/revocation-store.js";
|
|
14
|
+
import { deepMerge } from "./utils/deepmerge.js";
|
|
13
15
|
// ============================================================================
|
|
14
16
|
// Type Guards
|
|
15
17
|
// ============================================================================
|
|
@@ -47,6 +49,7 @@ export class RedisClientWrapper {
|
|
|
47
49
|
_lock;
|
|
48
50
|
_rateLimiter;
|
|
49
51
|
_session;
|
|
52
|
+
_revocationStore;
|
|
50
53
|
config;
|
|
51
54
|
logger;
|
|
52
55
|
isReady = false;
|
|
@@ -89,12 +92,24 @@ export class RedisClientWrapper {
|
|
|
89
92
|
// ========================================================================
|
|
90
93
|
get cache() {
|
|
91
94
|
if (!this._cache) {
|
|
92
|
-
this._cache = new Cache(this, this.config, this.logger);
|
|
95
|
+
this._cache = new Cache(this, this.config.cacheOptions ?? {}, this.logger);
|
|
93
96
|
}
|
|
94
97
|
return this._cache;
|
|
95
98
|
}
|
|
96
|
-
|
|
97
|
-
|
|
99
|
+
withCache(value) {
|
|
100
|
+
const parsed = CacheOptionsSchema.safeParse(value);
|
|
101
|
+
if (parsed.success) {
|
|
102
|
+
const data = { ...this.config.cacheOptions, ...parsed.data };
|
|
103
|
+
this.config.cacheOptions = data;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
this.logger.error("Invalid cache options", { error: parsed.error });
|
|
107
|
+
throw new ConfigurationError(`Invalid cache options: ${parsed.error.message}`, {
|
|
108
|
+
message: prettifyError(parsed.error),
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
this._cache = undefined;
|
|
112
|
+
return this;
|
|
98
113
|
}
|
|
99
114
|
// ========================================================================
|
|
100
115
|
// Pub/Sub
|
|
@@ -105,56 +120,92 @@ export class RedisClientWrapper {
|
|
|
105
120
|
}
|
|
106
121
|
return this._pubsub;
|
|
107
122
|
}
|
|
108
|
-
set pubsub(value) {
|
|
109
|
-
this._pubsub = value;
|
|
110
|
-
}
|
|
111
123
|
// ========================================================================
|
|
112
124
|
// Distributed Lock
|
|
113
125
|
// ========================================================================
|
|
114
126
|
get lock() {
|
|
115
127
|
if (!this._lock) {
|
|
116
|
-
this._lock = new DistributedLock(this, this.logger);
|
|
128
|
+
this._lock = new DistributedLock(this, this.logger, this.config.lockOptions);
|
|
117
129
|
}
|
|
118
130
|
return this._lock;
|
|
119
131
|
}
|
|
120
|
-
|
|
121
|
-
|
|
132
|
+
withLock(value) {
|
|
133
|
+
const parseResult = DistributedLockOptionsSchema.safeParse(value);
|
|
134
|
+
if (parseResult.success) {
|
|
135
|
+
const data = { ...this.config.lockOptions, ...parseResult.data };
|
|
136
|
+
this.config.lockOptions = data;
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
this.logger.error("Invalid lock options", { error: parseResult.error });
|
|
140
|
+
throw new ConfigurationError(`Invalid lock options: ${parseResult.error.message}`, {
|
|
141
|
+
message: prettifyError(parseResult.error),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
this._lock = undefined;
|
|
145
|
+
return this;
|
|
122
146
|
}
|
|
123
147
|
// ========================================================================
|
|
124
148
|
// Rate Limiter
|
|
125
149
|
// ========================================================================
|
|
126
150
|
get rateLimiter() {
|
|
127
151
|
if (!this._rateLimiter) {
|
|
128
|
-
this._rateLimiter = new RateLimiter(this);
|
|
152
|
+
this._rateLimiter = new RateLimiter(this, this.config.rateLimit);
|
|
129
153
|
}
|
|
130
154
|
return this._rateLimiter;
|
|
131
155
|
}
|
|
132
|
-
|
|
133
|
-
|
|
156
|
+
withRateLimiter(value) {
|
|
157
|
+
const parseResult = RateLimitOptionsSchema.safeParse(value);
|
|
158
|
+
if (parseResult.success) {
|
|
159
|
+
const data = { ...this.config.rateLimit, ...parseResult.data };
|
|
160
|
+
this.config.rateLimit = data;
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
this.logger.error("Invalid rate limit options", { error: parseResult.error });
|
|
164
|
+
throw new ConfigurationError(`Invalid rate limit options: ${parseResult.error.message}`, {
|
|
165
|
+
message: prettifyError(parseResult.error),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
this._rateLimiter = undefined;
|
|
169
|
+
return this;
|
|
170
|
+
}
|
|
171
|
+
get revocationStore() {
|
|
172
|
+
if (!this._revocationStore) {
|
|
173
|
+
this._revocationStore = new RedisRevocationStore({
|
|
174
|
+
client: this
|
|
175
|
+
});
|
|
176
|
+
this.config.sessionOptions = { ...(this.config.sessionOptions ?? {}), revocationStore: this._revocationStore };
|
|
177
|
+
}
|
|
178
|
+
;
|
|
179
|
+
return this._revocationStore;
|
|
134
180
|
}
|
|
135
181
|
// ========================================================================
|
|
136
182
|
// Session
|
|
137
183
|
// ========================================================================
|
|
138
184
|
get session() {
|
|
139
185
|
if (!this._session) {
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
this
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
else {
|
|
149
|
-
this._session = createSessionManager({
|
|
150
|
-
client: this,
|
|
151
|
-
});
|
|
152
|
-
}
|
|
186
|
+
const options = this.config.sessionOptions ?? {};
|
|
187
|
+
const params = {
|
|
188
|
+
...options,
|
|
189
|
+
client: this,
|
|
190
|
+
revocationStore: options.revocationStore ?? this.revocationStore,
|
|
191
|
+
};
|
|
192
|
+
this._session = createSessionManager(params);
|
|
193
|
+
this.config.sessionOptions = params;
|
|
153
194
|
}
|
|
154
195
|
return this._session;
|
|
155
196
|
}
|
|
156
|
-
|
|
157
|
-
|
|
197
|
+
withSession(value) {
|
|
198
|
+
const revocationRedisStore = this.revocationStore;
|
|
199
|
+
const config = deepMerge(this.config.sessionOptions ?? {}, value);
|
|
200
|
+
const { revocationStore = revocationRedisStore, ...rest } = config ?? {};
|
|
201
|
+
const newConfig = {
|
|
202
|
+
...rest,
|
|
203
|
+
client: this,
|
|
204
|
+
revocationStore,
|
|
205
|
+
};
|
|
206
|
+
this.config.sessionOptions = newConfig;
|
|
207
|
+
this._session = undefined;
|
|
208
|
+
return this;
|
|
158
209
|
}
|
|
159
210
|
// ========================================================================
|
|
160
211
|
// Client Creation
|
package/dist/index.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export { StaticSessionKeyProvider, createRandomSessionKeyProvider, toKeyBuffer,
|
|
|
29
29
|
export type { SessionKeyProvider } from './session/session-encryption.js';
|
|
30
30
|
export type { SessionRecord, SessionCreateInput, SessionUpdatePatch, CreatedSession, RotatedSession, SessionValidationResult, SessionInvalidReason, TouchOutcome, SessionEnvelope, EncryptedSessionEnvelope, PlainSessionEnvelope, ListOptions, RotateOptions, TouchOptions, UpdateOptions, ValidateOptions, BindingMismatch, } from './session/session-types.js';
|
|
31
31
|
export { RedisError } from './errors.js';
|
|
32
|
-
export type { RedisConfig, RedisConfigInput, RedisCommonConfigInput, RedisMode, RedisNode, StandaloneRedisConfig, SentinelRedisConfig, ClusterRedisConfig, RedisConfigForMode, CacheOptions,
|
|
32
|
+
export type { RedisConfig, RedisConfigInput, RedisCommonConfigInput, RedisMode, RedisNode, StandaloneRedisConfig, SentinelRedisConfig, ClusterRedisConfig, RedisConfigForMode, CacheOptions, LockInfo, DistributedLockOptions, HealthStatus, PubSubStats, PubSubMessage, ClusterInfo, ClusterSlotRange, ConnectionStatus, Redis } from './types.js';
|
|
33
33
|
export { RedisConfigSchema } from './types.js';
|
|
34
34
|
export { calculateRedisClusterSlot, hashTag } from './cluster-slot.js';
|
|
35
35
|
export type { RedisConfig as RedisConfiguration } from './types.js';
|
package/dist/lock.d.ts
CHANGED
|
@@ -1,27 +1,6 @@
|
|
|
1
1
|
import { RedisClientWrapper } from './client.js';
|
|
2
2
|
import { LoggerLike } from './logger.js';
|
|
3
|
-
|
|
4
|
-
* Information about a distributed lock.
|
|
5
|
-
*/
|
|
6
|
-
export interface LockInfo {
|
|
7
|
-
/** Whether the lock is currently held. */
|
|
8
|
-
locked: boolean;
|
|
9
|
-
/** Remaining TTL in seconds (when held and TTL set). */
|
|
10
|
-
ttl?: number;
|
|
11
|
-
/** Unique owner id of the lock. */
|
|
12
|
-
lockId?: string;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Options for the distributed lock.
|
|
16
|
-
*/
|
|
17
|
-
export interface DistributedLockOptions {
|
|
18
|
-
/** Lock TTL in milliseconds. Default: `30000`. */
|
|
19
|
-
ttl?: number;
|
|
20
|
-
/** Number of acquisition attempts. Default: `3`. */
|
|
21
|
-
retryCount?: number;
|
|
22
|
-
/** Base delay between retries in ms (grows exponentially). Default: `200`. */
|
|
23
|
-
retryDelay?: number;
|
|
24
|
-
}
|
|
3
|
+
import { DistributedLockOptions, LockInfo } from './types.js';
|
|
25
4
|
/**
|
|
26
5
|
* Distributed mutual-exclusion lock backed by Redis.
|
|
27
6
|
*
|
package/dist/lock.js
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import { RedisError } from './errors.js';
|
|
2
2
|
import { randomBytes } from 'node:crypto';
|
|
3
3
|
import { defaultLogger } from './logger.js';
|
|
4
|
+
// /**
|
|
5
|
+
// * Information about a distributed lock.
|
|
6
|
+
// */
|
|
7
|
+
// export interface LockInfo {
|
|
8
|
+
// /** Whether the lock is currently held. */
|
|
9
|
+
// locked: boolean;
|
|
10
|
+
// /** Remaining TTL in seconds (when held and TTL set). */
|
|
11
|
+
// ttl?: number;
|
|
12
|
+
// /** Unique owner id of the lock. */
|
|
13
|
+
// lockId?: string;
|
|
14
|
+
// }
|
|
15
|
+
// /**
|
|
16
|
+
// * Options for the distributed lock.
|
|
17
|
+
// */
|
|
18
|
+
// export interface DistributedLockOptions {
|
|
19
|
+
// /** Lock TTL in milliseconds. Default: `30000`. */
|
|
20
|
+
// ttl?: number;
|
|
21
|
+
// /** Number of acquisition attempts. Default: `3`. */
|
|
22
|
+
// retryCount?: number;
|
|
23
|
+
// /** Base delay between retries in ms (grows exponentially). Default: `200`. */
|
|
24
|
+
// retryDelay?: number;
|
|
25
|
+
// }
|
|
4
26
|
/**
|
|
5
27
|
* Distributed mutual-exclusion lock backed by Redis.
|
|
6
28
|
*
|
package/dist/ratelimiter.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RedisClientWrapper } from './client.js';
|
|
2
2
|
import { LoggerLike } from './logger.js';
|
|
3
|
+
import { RateLimitOptionsInput } from './types.js';
|
|
3
4
|
/**
|
|
4
5
|
* Window algorithm used by the rate limiter.
|
|
5
6
|
* - `fixed` - fixed window via `INCR`/`EXPIRE` (simple, cheapest)
|
|
@@ -76,7 +77,7 @@ export declare class RateLimiter {
|
|
|
76
77
|
* const limiter = new RateLimiter(client, { limit: 10, duration: 1, algorithm: 'fixed' });
|
|
77
78
|
* ```
|
|
78
79
|
*/
|
|
79
|
-
constructor(client: RedisClientWrapper, options?:
|
|
80
|
+
constructor(client: RedisClientWrapper, options?: RateLimitOptionsInput, logger?: LoggerLike);
|
|
80
81
|
/**
|
|
81
82
|
* Builds the Redis key for a resource + identifier combination.
|
|
82
83
|
*
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { RevocationRecord, RevocationStore } from './session-types.js';
|
|
2
2
|
import type { RedisClientWrapper } from '../client.js';
|
|
3
|
+
import z from 'zod';
|
|
3
4
|
export interface RedisRevocationStoreOptions {
|
|
4
5
|
/**
|
|
5
6
|
* Redis client.
|
|
@@ -19,8 +20,12 @@ export interface RedisRevocationStoreOptions {
|
|
|
19
20
|
* new RedisRevocationStore({ client, keyPrefix: 'auth:revoked:' });
|
|
20
21
|
* ```
|
|
21
22
|
*/
|
|
22
|
-
keyPrefix?: string;
|
|
23
|
+
keyPrefix?: string | undefined;
|
|
23
24
|
}
|
|
25
|
+
export declare const RedisRevocationStoreOptionsSchema: z.ZodObject<{
|
|
26
|
+
keyPrefix: z.ZodOptional<z.ZodString>;
|
|
27
|
+
}, z.z.core.$strip>;
|
|
28
|
+
export type RedisRevocationStoreOptionsInput = z.input<typeof RedisRevocationStoreOptionsSchema>;
|
|
24
29
|
/**
|
|
25
30
|
* Redis-backed revocation store. Each revoked jti is stored as
|
|
26
31
|
* `{prefix}{jti} -> reason`, with the Redis key TTL itself set to the
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { RevocationError, RevocationBatchError, redactIdentifier } from './session-errors.js';
|
|
2
|
+
import z from 'zod';
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Redis Revocations config
|
|
5
|
+
// ============================================================================
|
|
6
|
+
//
|
|
7
|
+
export const RedisRevocationStoreOptionsSchema = z.object({
|
|
8
|
+
keyPrefix: z.string().optional(),
|
|
9
|
+
});
|
|
2
10
|
/**
|
|
3
11
|
* Redis-backed revocation store. Each revoked jti is stored as
|
|
4
12
|
* `{prefix}{jti} -> reason`, with the Redis key TTL itself set to the
|
|
@@ -53,7 +61,7 @@ export class RedisRevocationStore {
|
|
|
53
61
|
*/
|
|
54
62
|
constructor(options) {
|
|
55
63
|
this.client = options.client;
|
|
56
|
-
this.keyPrefix = options.keyPrefix ?? '
|
|
64
|
+
this.keyPrefix = options.keyPrefix ?? 'cache:revoked:';
|
|
57
65
|
}
|
|
58
66
|
/* ------------------------------------------------------------------------ */
|
|
59
67
|
/* Revoke */
|
|
@@ -12,8 +12,8 @@ export declare const SessionStatusSchema: z.ZodEnum<{
|
|
|
12
12
|
}>;
|
|
13
13
|
/** How strictly session binding metadata (IP/UA/device) is enforced. */
|
|
14
14
|
export declare const SessionBindingPolicySchema: z.ZodEnum<{
|
|
15
|
-
advisory: "advisory";
|
|
16
15
|
disabled: "disabled";
|
|
16
|
+
advisory: "advisory";
|
|
17
17
|
strict: "strict";
|
|
18
18
|
}>;
|
|
19
19
|
/** Optional fail-closed circuit breaker around session operations. */
|
|
@@ -103,9 +103,9 @@ export declare const SessionCookieConfigSchema: z.ZodObject<{
|
|
|
103
103
|
httpOnly: z.ZodDefault<z.ZodBoolean>;
|
|
104
104
|
secure: z.ZodDefault<z.ZodBoolean>;
|
|
105
105
|
sameSite: z.ZodDefault<z.ZodEnum<{
|
|
106
|
-
lax: "lax";
|
|
107
106
|
none: "none";
|
|
108
107
|
strict: "strict";
|
|
108
|
+
lax: "lax";
|
|
109
109
|
}>>;
|
|
110
110
|
maxAge: z.ZodOptional<z.ZodNumber>;
|
|
111
111
|
}, z.core.$strip>;
|
|
@@ -260,8 +260,8 @@ export declare const SessionConfigSchema: z.ZodObject<{
|
|
|
260
260
|
storeIpAddress: z.ZodDefault<z.ZodBoolean>;
|
|
261
261
|
storeUserAgent: z.ZodDefault<z.ZodBoolean>;
|
|
262
262
|
bindingPolicy: z.ZodDefault<z.ZodEnum<{
|
|
263
|
-
advisory: "advisory";
|
|
264
263
|
disabled: "disabled";
|
|
264
|
+
advisory: "advisory";
|
|
265
265
|
strict: "strict";
|
|
266
266
|
}>>;
|
|
267
267
|
securityVersion: z.ZodPrefault<z.ZodObject<{
|
|
@@ -296,9 +296,9 @@ export declare const SessionConfigSchema: z.ZodObject<{
|
|
|
296
296
|
httpOnly: z.ZodDefault<z.ZodBoolean>;
|
|
297
297
|
secure: z.ZodDefault<z.ZodBoolean>;
|
|
298
298
|
sameSite: z.ZodDefault<z.ZodEnum<{
|
|
299
|
-
lax: "lax";
|
|
300
299
|
none: "none";
|
|
301
300
|
strict: "strict";
|
|
301
|
+
lax: "lax";
|
|
302
302
|
}>>;
|
|
303
303
|
maxAge: z.ZodOptional<z.ZodNumber>;
|
|
304
304
|
}, z.core.$strip>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RedisClientWrapper } from '../client.js';
|
|
2
|
-
export declare const SCRIPT_NAMES: readonly [
|
|
2
|
+
export declare const SCRIPT_NAMES: readonly ["create", "touch", "touchEncrypted", "rotate", "rotateEncrypted", "delete", "revoke", "conditionalUpdate", "conditionalUpdateEncrypted", "deleteByUser", "cleanupIndex", "enforceLimit", "validate"];
|
|
3
3
|
export type ScriptName = (typeof SCRIPT_NAMES)[number];
|
|
4
4
|
/** Loads a script source from disk relative to this module. */
|
|
5
5
|
export declare function loadScriptSource(name: ScriptName): string;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,61 @@
|
|
|
1
1
|
import type { Redis as RedisType } from "ioredis";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import type { SessionManagerOptions } from "./session/session-manager.js";
|
|
4
|
+
/**
|
|
5
|
+
* Information about a distributed lock.
|
|
6
|
+
*/
|
|
7
|
+
export type LockInfo = {
|
|
8
|
+
/** Whether the lock is currently held. */
|
|
9
|
+
locked: boolean;
|
|
10
|
+
/** Remaining TTL in seconds (when held and TTL set). */
|
|
11
|
+
ttl?: number;
|
|
12
|
+
/** Unique owner id of the lock. */
|
|
13
|
+
lockId?: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Options for the distributed lock.
|
|
17
|
+
*/
|
|
18
|
+
export type DistributedLockOptions = {
|
|
19
|
+
/** Lock TTL in milliseconds. Default: `30000`. */
|
|
20
|
+
ttl?: number;
|
|
21
|
+
/** Number of acquisition attempts. Default: `3`. */
|
|
22
|
+
retryCount?: number;
|
|
23
|
+
/** Base delay between retries in ms (grows exponentially). Default: `200`. */
|
|
24
|
+
retryDelay?: number;
|
|
25
|
+
};
|
|
26
|
+
export declare const DistributedLockOptionsSchema: z.ZodObject<{
|
|
27
|
+
ttl: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
28
|
+
retryCount: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
29
|
+
retryDelay: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
30
|
+
}, z.core.$strip>;
|
|
31
|
+
export type DistributedLockInputOptions = z.input<typeof DistributedLockOptionsSchema>;
|
|
32
|
+
export type CacheOptions = {
|
|
33
|
+
/**
|
|
34
|
+
* TTL in seconds.
|
|
35
|
+
*
|
|
36
|
+
* Falls back to the cache's `defaultTTL`.
|
|
37
|
+
*/
|
|
38
|
+
ttl?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Enable/disable compression.
|
|
41
|
+
*
|
|
42
|
+
* Default: true.
|
|
43
|
+
*/
|
|
44
|
+
compress?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Namespace prefix.
|
|
47
|
+
*/
|
|
48
|
+
namespace?: string;
|
|
49
|
+
};
|
|
50
|
+
export declare const CacheOptionsSchema: z.ZodObject<{
|
|
51
|
+
defaultTTL: z.ZodDefault<z.ZodNumber>;
|
|
52
|
+
compressionThreshold: z.ZodDefault<z.ZodNumber>;
|
|
53
|
+
}, z.core.$strip>;
|
|
54
|
+
export type CacheInputConfig = z.input<typeof CacheOptionsSchema>;
|
|
55
|
+
export type CacheStats = {
|
|
56
|
+
namespace: string;
|
|
57
|
+
connectionStatus: ConnectionStatus;
|
|
58
|
+
};
|
|
4
59
|
export declare const RateLimitAlgorithmSchema: z.ZodEnum<{
|
|
5
60
|
fixed: "fixed";
|
|
6
61
|
sliding: "sliding";
|
|
@@ -27,9 +82,9 @@ export type RateLimitOptionsInput = z.input<typeof RateLimitOptionsSchema>;
|
|
|
27
82
|
*/
|
|
28
83
|
export type RateLimitOptions = z.output<typeof RateLimitOptionsSchema>;
|
|
29
84
|
export declare const RedisModeSchema: z.ZodEnum<{
|
|
30
|
-
cluster: "cluster";
|
|
31
|
-
sentinel: "sentinel";
|
|
32
85
|
standalone: "standalone";
|
|
86
|
+
sentinel: "sentinel";
|
|
87
|
+
cluster: "cluster";
|
|
33
88
|
}>;
|
|
34
89
|
export type RedisMode = z.infer<typeof RedisModeSchema>;
|
|
35
90
|
export declare const RedisNodeSchema: z.ZodObject<{
|
|
@@ -72,10 +127,17 @@ export declare const BaseRedisConfigSchema: z.ZodObject<{
|
|
|
72
127
|
connectionTimeout: z.ZodDefault<z.ZodNumber>;
|
|
73
128
|
maxFanOutConcurrency: z.ZodDefault<z.ZodNumber>;
|
|
74
129
|
maxBatchSize: z.ZodDefault<z.ZodNumber>;
|
|
75
|
-
|
|
76
|
-
|
|
130
|
+
lockOptions: z.ZodOptional<z.ZodObject<{
|
|
131
|
+
ttl: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
132
|
+
retryCount: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
133
|
+
retryDelay: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
134
|
+
}, z.core.$strip>>;
|
|
135
|
+
cacheOptions: z.ZodOptional<z.ZodObject<{
|
|
136
|
+
defaultTTL: z.ZodDefault<z.ZodNumber>;
|
|
137
|
+
compressionThreshold: z.ZodDefault<z.ZodNumber>;
|
|
138
|
+
}, z.core.$strip>>;
|
|
77
139
|
slowCommandThreshold: z.ZodDefault<z.ZodNumber>;
|
|
78
|
-
rateLimit: z.
|
|
140
|
+
rateLimit: z.ZodOptional<z.ZodObject<{
|
|
79
141
|
limit: z.ZodDefault<z.ZodNumber>;
|
|
80
142
|
duration: z.ZodDefault<z.ZodNumber>;
|
|
81
143
|
algorithm: z.ZodDefault<z.ZodEnum<{
|
|
@@ -109,10 +171,17 @@ export declare const StandaloneRedisConfigSchema: z.ZodObject<{
|
|
|
109
171
|
connectionTimeout: z.ZodDefault<z.ZodNumber>;
|
|
110
172
|
maxFanOutConcurrency: z.ZodDefault<z.ZodNumber>;
|
|
111
173
|
maxBatchSize: z.ZodDefault<z.ZodNumber>;
|
|
112
|
-
|
|
113
|
-
|
|
174
|
+
lockOptions: z.ZodOptional<z.ZodObject<{
|
|
175
|
+
ttl: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
176
|
+
retryCount: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
177
|
+
retryDelay: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
178
|
+
}, z.core.$strip>>;
|
|
179
|
+
cacheOptions: z.ZodOptional<z.ZodObject<{
|
|
180
|
+
defaultTTL: z.ZodDefault<z.ZodNumber>;
|
|
181
|
+
compressionThreshold: z.ZodDefault<z.ZodNumber>;
|
|
182
|
+
}, z.core.$strip>>;
|
|
114
183
|
slowCommandThreshold: z.ZodDefault<z.ZodNumber>;
|
|
115
|
-
rateLimit: z.
|
|
184
|
+
rateLimit: z.ZodOptional<z.ZodObject<{
|
|
116
185
|
limit: z.ZodDefault<z.ZodNumber>;
|
|
117
186
|
duration: z.ZodDefault<z.ZodNumber>;
|
|
118
187
|
algorithm: z.ZodDefault<z.ZodEnum<{
|
|
@@ -147,10 +216,17 @@ export declare const SentinelRedisConfigSchema: z.ZodObject<{
|
|
|
147
216
|
connectionTimeout: z.ZodDefault<z.ZodNumber>;
|
|
148
217
|
maxFanOutConcurrency: z.ZodDefault<z.ZodNumber>;
|
|
149
218
|
maxBatchSize: z.ZodDefault<z.ZodNumber>;
|
|
150
|
-
|
|
151
|
-
|
|
219
|
+
lockOptions: z.ZodOptional<z.ZodObject<{
|
|
220
|
+
ttl: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
221
|
+
retryCount: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
222
|
+
retryDelay: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
223
|
+
}, z.core.$strip>>;
|
|
224
|
+
cacheOptions: z.ZodOptional<z.ZodObject<{
|
|
225
|
+
defaultTTL: z.ZodDefault<z.ZodNumber>;
|
|
226
|
+
compressionThreshold: z.ZodDefault<z.ZodNumber>;
|
|
227
|
+
}, z.core.$strip>>;
|
|
152
228
|
slowCommandThreshold: z.ZodDefault<z.ZodNumber>;
|
|
153
|
-
rateLimit: z.
|
|
229
|
+
rateLimit: z.ZodOptional<z.ZodObject<{
|
|
154
230
|
limit: z.ZodDefault<z.ZodNumber>;
|
|
155
231
|
duration: z.ZodDefault<z.ZodNumber>;
|
|
156
232
|
algorithm: z.ZodDefault<z.ZodEnum<{
|
|
@@ -187,10 +263,17 @@ export declare const ClusterRedisConfigSchema: z.ZodObject<{
|
|
|
187
263
|
connectionTimeout: z.ZodDefault<z.ZodNumber>;
|
|
188
264
|
maxFanOutConcurrency: z.ZodDefault<z.ZodNumber>;
|
|
189
265
|
maxBatchSize: z.ZodDefault<z.ZodNumber>;
|
|
190
|
-
|
|
191
|
-
|
|
266
|
+
lockOptions: z.ZodOptional<z.ZodObject<{
|
|
267
|
+
ttl: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
268
|
+
retryCount: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
269
|
+
retryDelay: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
270
|
+
}, z.core.$strip>>;
|
|
271
|
+
cacheOptions: z.ZodOptional<z.ZodObject<{
|
|
272
|
+
defaultTTL: z.ZodDefault<z.ZodNumber>;
|
|
273
|
+
compressionThreshold: z.ZodDefault<z.ZodNumber>;
|
|
274
|
+
}, z.core.$strip>>;
|
|
192
275
|
slowCommandThreshold: z.ZodDefault<z.ZodNumber>;
|
|
193
|
-
rateLimit: z.
|
|
276
|
+
rateLimit: z.ZodOptional<z.ZodObject<{
|
|
194
277
|
limit: z.ZodDefault<z.ZodNumber>;
|
|
195
278
|
duration: z.ZodDefault<z.ZodNumber>;
|
|
196
279
|
algorithm: z.ZodDefault<z.ZodEnum<{
|
|
@@ -231,10 +314,17 @@ export declare const RedisConfigInputSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
231
314
|
connectionTimeout: z.ZodDefault<z.ZodNumber>;
|
|
232
315
|
maxFanOutConcurrency: z.ZodDefault<z.ZodNumber>;
|
|
233
316
|
maxBatchSize: z.ZodDefault<z.ZodNumber>;
|
|
234
|
-
|
|
235
|
-
|
|
317
|
+
lockOptions: z.ZodOptional<z.ZodObject<{
|
|
318
|
+
ttl: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
319
|
+
retryCount: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
320
|
+
retryDelay: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
321
|
+
}, z.core.$strip>>;
|
|
322
|
+
cacheOptions: z.ZodOptional<z.ZodObject<{
|
|
323
|
+
defaultTTL: z.ZodDefault<z.ZodNumber>;
|
|
324
|
+
compressionThreshold: z.ZodDefault<z.ZodNumber>;
|
|
325
|
+
}, z.core.$strip>>;
|
|
236
326
|
slowCommandThreshold: z.ZodDefault<z.ZodNumber>;
|
|
237
|
-
rateLimit: z.
|
|
327
|
+
rateLimit: z.ZodOptional<z.ZodObject<{
|
|
238
328
|
limit: z.ZodDefault<z.ZodNumber>;
|
|
239
329
|
duration: z.ZodDefault<z.ZodNumber>;
|
|
240
330
|
algorithm: z.ZodDefault<z.ZodEnum<{
|
|
@@ -264,10 +354,17 @@ export declare const RedisConfigInputSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
264
354
|
connectionTimeout: z.ZodDefault<z.ZodNumber>;
|
|
265
355
|
maxFanOutConcurrency: z.ZodDefault<z.ZodNumber>;
|
|
266
356
|
maxBatchSize: z.ZodDefault<z.ZodNumber>;
|
|
267
|
-
|
|
268
|
-
|
|
357
|
+
lockOptions: z.ZodOptional<z.ZodObject<{
|
|
358
|
+
ttl: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
359
|
+
retryCount: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
360
|
+
retryDelay: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
361
|
+
}, z.core.$strip>>;
|
|
362
|
+
cacheOptions: z.ZodOptional<z.ZodObject<{
|
|
363
|
+
defaultTTL: z.ZodDefault<z.ZodNumber>;
|
|
364
|
+
compressionThreshold: z.ZodDefault<z.ZodNumber>;
|
|
365
|
+
}, z.core.$strip>>;
|
|
269
366
|
slowCommandThreshold: z.ZodDefault<z.ZodNumber>;
|
|
270
|
-
rateLimit: z.
|
|
367
|
+
rateLimit: z.ZodOptional<z.ZodObject<{
|
|
271
368
|
limit: z.ZodDefault<z.ZodNumber>;
|
|
272
369
|
duration: z.ZodDefault<z.ZodNumber>;
|
|
273
370
|
algorithm: z.ZodDefault<z.ZodEnum<{
|
|
@@ -298,10 +395,17 @@ export declare const RedisConfigInputSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
298
395
|
connectionTimeout: z.ZodDefault<z.ZodNumber>;
|
|
299
396
|
maxFanOutConcurrency: z.ZodDefault<z.ZodNumber>;
|
|
300
397
|
maxBatchSize: z.ZodDefault<z.ZodNumber>;
|
|
301
|
-
|
|
302
|
-
|
|
398
|
+
lockOptions: z.ZodOptional<z.ZodObject<{
|
|
399
|
+
ttl: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
400
|
+
retryCount: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
401
|
+
retryDelay: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
402
|
+
}, z.core.$strip>>;
|
|
403
|
+
cacheOptions: z.ZodOptional<z.ZodObject<{
|
|
404
|
+
defaultTTL: z.ZodDefault<z.ZodNumber>;
|
|
405
|
+
compressionThreshold: z.ZodDefault<z.ZodNumber>;
|
|
406
|
+
}, z.core.$strip>>;
|
|
303
407
|
slowCommandThreshold: z.ZodDefault<z.ZodNumber>;
|
|
304
|
-
rateLimit: z.
|
|
408
|
+
rateLimit: z.ZodOptional<z.ZodObject<{
|
|
305
409
|
limit: z.ZodDefault<z.ZodNumber>;
|
|
306
410
|
duration: z.ZodDefault<z.ZodNumber>;
|
|
307
411
|
algorithm: z.ZodDefault<z.ZodEnum<{
|
|
@@ -350,10 +454,17 @@ export declare const RedisConfigSchema: z.ZodPipe<z.ZodUnion<readonly [z.ZodObje
|
|
|
350
454
|
connectionTimeout: z.ZodDefault<z.ZodNumber>;
|
|
351
455
|
maxFanOutConcurrency: z.ZodDefault<z.ZodNumber>;
|
|
352
456
|
maxBatchSize: z.ZodDefault<z.ZodNumber>;
|
|
353
|
-
|
|
354
|
-
|
|
457
|
+
lockOptions: z.ZodOptional<z.ZodObject<{
|
|
458
|
+
ttl: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
459
|
+
retryCount: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
460
|
+
retryDelay: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
461
|
+
}, z.core.$strip>>;
|
|
462
|
+
cacheOptions: z.ZodOptional<z.ZodObject<{
|
|
463
|
+
defaultTTL: z.ZodDefault<z.ZodNumber>;
|
|
464
|
+
compressionThreshold: z.ZodDefault<z.ZodNumber>;
|
|
465
|
+
}, z.core.$strip>>;
|
|
355
466
|
slowCommandThreshold: z.ZodDefault<z.ZodNumber>;
|
|
356
|
-
rateLimit: z.
|
|
467
|
+
rateLimit: z.ZodOptional<z.ZodObject<{
|
|
357
468
|
limit: z.ZodDefault<z.ZodNumber>;
|
|
358
469
|
duration: z.ZodDefault<z.ZodNumber>;
|
|
359
470
|
algorithm: z.ZodDefault<z.ZodEnum<{
|
|
@@ -383,10 +494,17 @@ export declare const RedisConfigSchema: z.ZodPipe<z.ZodUnion<readonly [z.ZodObje
|
|
|
383
494
|
connectionTimeout: z.ZodDefault<z.ZodNumber>;
|
|
384
495
|
maxFanOutConcurrency: z.ZodDefault<z.ZodNumber>;
|
|
385
496
|
maxBatchSize: z.ZodDefault<z.ZodNumber>;
|
|
386
|
-
|
|
387
|
-
|
|
497
|
+
lockOptions: z.ZodOptional<z.ZodObject<{
|
|
498
|
+
ttl: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
499
|
+
retryCount: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
500
|
+
retryDelay: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
501
|
+
}, z.core.$strip>>;
|
|
502
|
+
cacheOptions: z.ZodOptional<z.ZodObject<{
|
|
503
|
+
defaultTTL: z.ZodDefault<z.ZodNumber>;
|
|
504
|
+
compressionThreshold: z.ZodDefault<z.ZodNumber>;
|
|
505
|
+
}, z.core.$strip>>;
|
|
388
506
|
slowCommandThreshold: z.ZodDefault<z.ZodNumber>;
|
|
389
|
-
rateLimit: z.
|
|
507
|
+
rateLimit: z.ZodOptional<z.ZodObject<{
|
|
390
508
|
limit: z.ZodDefault<z.ZodNumber>;
|
|
391
509
|
duration: z.ZodDefault<z.ZodNumber>;
|
|
392
510
|
algorithm: z.ZodDefault<z.ZodEnum<{
|
|
@@ -417,10 +535,17 @@ export declare const RedisConfigSchema: z.ZodPipe<z.ZodUnion<readonly [z.ZodObje
|
|
|
417
535
|
connectionTimeout: z.ZodDefault<z.ZodNumber>;
|
|
418
536
|
maxFanOutConcurrency: z.ZodDefault<z.ZodNumber>;
|
|
419
537
|
maxBatchSize: z.ZodDefault<z.ZodNumber>;
|
|
420
|
-
|
|
421
|
-
|
|
538
|
+
lockOptions: z.ZodOptional<z.ZodObject<{
|
|
539
|
+
ttl: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
540
|
+
retryCount: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
541
|
+
retryDelay: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
542
|
+
}, z.core.$strip>>;
|
|
543
|
+
cacheOptions: z.ZodOptional<z.ZodObject<{
|
|
544
|
+
defaultTTL: z.ZodDefault<z.ZodNumber>;
|
|
545
|
+
compressionThreshold: z.ZodDefault<z.ZodNumber>;
|
|
546
|
+
}, z.core.$strip>>;
|
|
422
547
|
slowCommandThreshold: z.ZodDefault<z.ZodNumber>;
|
|
423
|
-
rateLimit: z.
|
|
548
|
+
rateLimit: z.ZodOptional<z.ZodObject<{
|
|
424
549
|
limit: z.ZodDefault<z.ZodNumber>;
|
|
425
550
|
duration: z.ZodDefault<z.ZodNumber>;
|
|
426
551
|
algorithm: z.ZodDefault<z.ZodEnum<{
|
|
@@ -437,236 +562,236 @@ export declare const RedisConfigSchema: z.ZodPipe<z.ZodUnion<readonly [z.ZodObje
|
|
|
437
562
|
}, z.core.$strict>>;
|
|
438
563
|
database: z.ZodDefault<z.ZodLiteral<0>>;
|
|
439
564
|
}, z.core.$strict>]>, z.ZodTransform<{
|
|
440
|
-
password?: string | undefined;
|
|
441
|
-
username?: string | undefined;
|
|
442
565
|
database: number;
|
|
443
566
|
tls: boolean;
|
|
444
|
-
tlsOptions?: {
|
|
445
|
-
ca?: string | undefined;
|
|
446
|
-
cert?: string | undefined;
|
|
447
|
-
key?: string | undefined;
|
|
448
|
-
rejectUnauthorized: boolean;
|
|
449
|
-
} | undefined;
|
|
450
567
|
maxRetries: number;
|
|
451
568
|
retryDelay: number;
|
|
452
569
|
connectionTimeout: number;
|
|
453
570
|
maxFanOutConcurrency: number;
|
|
454
571
|
maxBatchSize: number;
|
|
455
|
-
defaultTTL: number;
|
|
456
|
-
compressionThreshold: number;
|
|
457
572
|
slowCommandThreshold: number;
|
|
458
|
-
rateLimit: {
|
|
459
|
-
limit: number;
|
|
460
|
-
duration: number;
|
|
461
|
-
algorithm: "fixed" | "sliding";
|
|
462
|
-
namespace: string;
|
|
463
|
-
};
|
|
464
|
-
sessionOptions?: Partial<SessionManagerOptions> | undefined;
|
|
465
573
|
mode: "sentinel";
|
|
466
574
|
sentinelNodes: {
|
|
467
575
|
host: string;
|
|
468
576
|
port: number;
|
|
469
577
|
}[];
|
|
470
578
|
sentinelMasterName: string;
|
|
471
|
-
} | {
|
|
472
579
|
password?: string | undefined;
|
|
473
580
|
username?: string | undefined;
|
|
474
|
-
tls: boolean;
|
|
475
581
|
tlsOptions?: {
|
|
582
|
+
rejectUnauthorized: boolean;
|
|
476
583
|
ca?: string | undefined;
|
|
477
584
|
cert?: string | undefined;
|
|
478
585
|
key?: string | undefined;
|
|
479
|
-
rejectUnauthorized: boolean;
|
|
480
586
|
} | undefined;
|
|
587
|
+
lockOptions?: {
|
|
588
|
+
ttl: number;
|
|
589
|
+
retryCount: number;
|
|
590
|
+
retryDelay: number;
|
|
591
|
+
} | undefined;
|
|
592
|
+
cacheOptions?: {
|
|
593
|
+
defaultTTL: number;
|
|
594
|
+
compressionThreshold: number;
|
|
595
|
+
} | undefined;
|
|
596
|
+
rateLimit?: {
|
|
597
|
+
limit: number;
|
|
598
|
+
duration: number;
|
|
599
|
+
algorithm: "fixed" | "sliding";
|
|
600
|
+
namespace: string;
|
|
601
|
+
} | undefined;
|
|
602
|
+
sessionOptions?: Partial<SessionManagerOptions> | undefined;
|
|
603
|
+
} | {
|
|
604
|
+
tls: boolean;
|
|
481
605
|
maxRetries: number;
|
|
482
606
|
retryDelay: number;
|
|
483
607
|
connectionTimeout: number;
|
|
484
608
|
maxFanOutConcurrency: number;
|
|
485
609
|
maxBatchSize: number;
|
|
486
|
-
defaultTTL: number;
|
|
487
|
-
compressionThreshold: number;
|
|
488
610
|
slowCommandThreshold: number;
|
|
489
|
-
rateLimit: {
|
|
490
|
-
limit: number;
|
|
491
|
-
duration: number;
|
|
492
|
-
algorithm: "fixed" | "sliding";
|
|
493
|
-
namespace: string;
|
|
494
|
-
};
|
|
495
|
-
sessionOptions?: Partial<SessionManagerOptions> | undefined;
|
|
496
611
|
mode: "cluster";
|
|
497
612
|
clusterNodes: {
|
|
498
613
|
host: string;
|
|
499
614
|
port: number;
|
|
500
615
|
}[];
|
|
501
616
|
database: 0;
|
|
502
|
-
} | {
|
|
503
617
|
password?: string | undefined;
|
|
504
618
|
username?: string | undefined;
|
|
505
|
-
database: number;
|
|
506
|
-
tls: boolean;
|
|
507
619
|
tlsOptions?: {
|
|
620
|
+
rejectUnauthorized: boolean;
|
|
508
621
|
ca?: string | undefined;
|
|
509
622
|
cert?: string | undefined;
|
|
510
623
|
key?: string | undefined;
|
|
511
|
-
rejectUnauthorized: boolean;
|
|
512
624
|
} | undefined;
|
|
625
|
+
lockOptions?: {
|
|
626
|
+
ttl: number;
|
|
627
|
+
retryCount: number;
|
|
628
|
+
retryDelay: number;
|
|
629
|
+
} | undefined;
|
|
630
|
+
cacheOptions?: {
|
|
631
|
+
defaultTTL: number;
|
|
632
|
+
compressionThreshold: number;
|
|
633
|
+
} | undefined;
|
|
634
|
+
rateLimit?: {
|
|
635
|
+
limit: number;
|
|
636
|
+
duration: number;
|
|
637
|
+
algorithm: "fixed" | "sliding";
|
|
638
|
+
namespace: string;
|
|
639
|
+
} | undefined;
|
|
640
|
+
sessionOptions?: Partial<SessionManagerOptions> | undefined;
|
|
641
|
+
} | {
|
|
642
|
+
mode: "standalone";
|
|
643
|
+
database: number;
|
|
644
|
+
tls: boolean;
|
|
513
645
|
maxRetries: number;
|
|
514
646
|
retryDelay: number;
|
|
515
647
|
connectionTimeout: number;
|
|
516
648
|
maxFanOutConcurrency: number;
|
|
517
649
|
maxBatchSize: number;
|
|
518
|
-
defaultTTL: number;
|
|
519
|
-
compressionThreshold: number;
|
|
520
650
|
slowCommandThreshold: number;
|
|
521
|
-
rateLimit: {
|
|
522
|
-
limit: number;
|
|
523
|
-
duration: number;
|
|
524
|
-
algorithm: "fixed" | "sliding";
|
|
525
|
-
namespace: string;
|
|
526
|
-
};
|
|
527
|
-
sessionOptions?: Partial<SessionManagerOptions> | undefined;
|
|
528
651
|
host: string;
|
|
529
652
|
port: number;
|
|
530
|
-
url?: string | undefined;
|
|
531
|
-
mode: "standalone";
|
|
532
|
-
}, {
|
|
533
653
|
password?: string | undefined;
|
|
534
654
|
username?: string | undefined;
|
|
535
|
-
database: number;
|
|
536
|
-
tls: boolean;
|
|
537
655
|
tlsOptions?: {
|
|
656
|
+
rejectUnauthorized: boolean;
|
|
538
657
|
ca?: string | undefined;
|
|
539
658
|
cert?: string | undefined;
|
|
540
659
|
key?: string | undefined;
|
|
541
|
-
rejectUnauthorized: boolean;
|
|
542
660
|
} | undefined;
|
|
661
|
+
lockOptions?: {
|
|
662
|
+
ttl: number;
|
|
663
|
+
retryCount: number;
|
|
664
|
+
retryDelay: number;
|
|
665
|
+
} | undefined;
|
|
666
|
+
cacheOptions?: {
|
|
667
|
+
defaultTTL: number;
|
|
668
|
+
compressionThreshold: number;
|
|
669
|
+
} | undefined;
|
|
670
|
+
rateLimit?: {
|
|
671
|
+
limit: number;
|
|
672
|
+
duration: number;
|
|
673
|
+
algorithm: "fixed" | "sliding";
|
|
674
|
+
namespace: string;
|
|
675
|
+
} | undefined;
|
|
676
|
+
sessionOptions?: Partial<SessionManagerOptions> | undefined;
|
|
677
|
+
url?: string | undefined;
|
|
678
|
+
}, {
|
|
679
|
+
database: number;
|
|
680
|
+
tls: boolean;
|
|
543
681
|
maxRetries: number;
|
|
544
682
|
retryDelay: number;
|
|
545
683
|
connectionTimeout: number;
|
|
546
684
|
maxFanOutConcurrency: number;
|
|
547
685
|
maxBatchSize: number;
|
|
548
|
-
defaultTTL: number;
|
|
549
|
-
compressionThreshold: number;
|
|
550
686
|
slowCommandThreshold: number;
|
|
551
|
-
|
|
687
|
+
host: string;
|
|
688
|
+
port: number;
|
|
689
|
+
password?: string | undefined;
|
|
690
|
+
username?: string | undefined;
|
|
691
|
+
tlsOptions?: {
|
|
692
|
+
rejectUnauthorized: boolean;
|
|
693
|
+
ca?: string | undefined;
|
|
694
|
+
cert?: string | undefined;
|
|
695
|
+
key?: string | undefined;
|
|
696
|
+
} | undefined;
|
|
697
|
+
lockOptions?: {
|
|
698
|
+
ttl: number;
|
|
699
|
+
retryCount: number;
|
|
700
|
+
retryDelay: number;
|
|
701
|
+
} | undefined;
|
|
702
|
+
cacheOptions?: {
|
|
703
|
+
defaultTTL: number;
|
|
704
|
+
compressionThreshold: number;
|
|
705
|
+
} | undefined;
|
|
706
|
+
rateLimit?: {
|
|
552
707
|
limit: number;
|
|
553
708
|
duration: number;
|
|
554
709
|
algorithm: "fixed" | "sliding";
|
|
555
710
|
namespace: string;
|
|
556
|
-
};
|
|
711
|
+
} | undefined;
|
|
557
712
|
sessionOptions?: Partial<SessionManagerOptions> | undefined;
|
|
558
713
|
mode?: "standalone" | undefined;
|
|
559
|
-
host: string;
|
|
560
|
-
port: number;
|
|
561
714
|
url?: string | undefined;
|
|
562
715
|
} | {
|
|
563
|
-
password?: string | undefined;
|
|
564
|
-
username?: string | undefined;
|
|
565
716
|
database: number;
|
|
566
717
|
tls: boolean;
|
|
567
|
-
tlsOptions?: {
|
|
568
|
-
ca?: string | undefined;
|
|
569
|
-
cert?: string | undefined;
|
|
570
|
-
key?: string | undefined;
|
|
571
|
-
rejectUnauthorized: boolean;
|
|
572
|
-
} | undefined;
|
|
573
718
|
maxRetries: number;
|
|
574
719
|
retryDelay: number;
|
|
575
720
|
connectionTimeout: number;
|
|
576
721
|
maxFanOutConcurrency: number;
|
|
577
722
|
maxBatchSize: number;
|
|
578
|
-
defaultTTL: number;
|
|
579
|
-
compressionThreshold: number;
|
|
580
723
|
slowCommandThreshold: number;
|
|
581
|
-
rateLimit: {
|
|
582
|
-
limit: number;
|
|
583
|
-
duration: number;
|
|
584
|
-
algorithm: "fixed" | "sliding";
|
|
585
|
-
namespace: string;
|
|
586
|
-
};
|
|
587
|
-
sessionOptions?: Partial<SessionManagerOptions> | undefined;
|
|
588
724
|
mode: "sentinel";
|
|
589
725
|
sentinelNodes: {
|
|
590
726
|
host: string;
|
|
591
727
|
port: number;
|
|
592
728
|
}[];
|
|
593
729
|
sentinelMasterName: string;
|
|
594
|
-
} | {
|
|
595
730
|
password?: string | undefined;
|
|
596
731
|
username?: string | undefined;
|
|
597
|
-
tls: boolean;
|
|
598
732
|
tlsOptions?: {
|
|
733
|
+
rejectUnauthorized: boolean;
|
|
599
734
|
ca?: string | undefined;
|
|
600
735
|
cert?: string | undefined;
|
|
601
736
|
key?: string | undefined;
|
|
602
|
-
rejectUnauthorized: boolean;
|
|
603
737
|
} | undefined;
|
|
738
|
+
lockOptions?: {
|
|
739
|
+
ttl: number;
|
|
740
|
+
retryCount: number;
|
|
741
|
+
retryDelay: number;
|
|
742
|
+
} | undefined;
|
|
743
|
+
cacheOptions?: {
|
|
744
|
+
defaultTTL: number;
|
|
745
|
+
compressionThreshold: number;
|
|
746
|
+
} | undefined;
|
|
747
|
+
rateLimit?: {
|
|
748
|
+
limit: number;
|
|
749
|
+
duration: number;
|
|
750
|
+
algorithm: "fixed" | "sliding";
|
|
751
|
+
namespace: string;
|
|
752
|
+
} | undefined;
|
|
753
|
+
sessionOptions?: Partial<SessionManagerOptions> | undefined;
|
|
754
|
+
} | {
|
|
755
|
+
tls: boolean;
|
|
604
756
|
maxRetries: number;
|
|
605
757
|
retryDelay: number;
|
|
606
758
|
connectionTimeout: number;
|
|
607
759
|
maxFanOutConcurrency: number;
|
|
608
760
|
maxBatchSize: number;
|
|
609
|
-
defaultTTL: number;
|
|
610
|
-
compressionThreshold: number;
|
|
611
761
|
slowCommandThreshold: number;
|
|
612
|
-
rateLimit: {
|
|
613
|
-
limit: number;
|
|
614
|
-
duration: number;
|
|
615
|
-
algorithm: "fixed" | "sliding";
|
|
616
|
-
namespace: string;
|
|
617
|
-
};
|
|
618
|
-
sessionOptions?: Partial<SessionManagerOptions> | undefined;
|
|
619
762
|
mode: "cluster";
|
|
620
763
|
clusterNodes: {
|
|
621
764
|
host: string;
|
|
622
765
|
port: number;
|
|
623
766
|
}[];
|
|
624
767
|
database: 0;
|
|
768
|
+
password?: string | undefined;
|
|
769
|
+
username?: string | undefined;
|
|
770
|
+
tlsOptions?: {
|
|
771
|
+
rejectUnauthorized: boolean;
|
|
772
|
+
ca?: string | undefined;
|
|
773
|
+
cert?: string | undefined;
|
|
774
|
+
key?: string | undefined;
|
|
775
|
+
} | undefined;
|
|
776
|
+
lockOptions?: {
|
|
777
|
+
ttl: number;
|
|
778
|
+
retryCount: number;
|
|
779
|
+
retryDelay: number;
|
|
780
|
+
} | undefined;
|
|
781
|
+
cacheOptions?: {
|
|
782
|
+
defaultTTL: number;
|
|
783
|
+
compressionThreshold: number;
|
|
784
|
+
} | undefined;
|
|
785
|
+
rateLimit?: {
|
|
786
|
+
limit: number;
|
|
787
|
+
duration: number;
|
|
788
|
+
algorithm: "fixed" | "sliding";
|
|
789
|
+
namespace: string;
|
|
790
|
+
} | undefined;
|
|
791
|
+
sessionOptions?: Partial<SessionManagerOptions> | undefined;
|
|
625
792
|
}>>;
|
|
626
793
|
export type RedisConfig = z.output<typeof RedisConfigSchema>;
|
|
627
794
|
export type RedisConfigForMode<M extends RedisMode> = M extends "cluster" ? ClusterRedisConfig : M extends "sentinel" ? SentinelRedisConfig : StandaloneRedisConfig;
|
|
628
|
-
export type CacheOptions = {
|
|
629
|
-
/**
|
|
630
|
-
* TTL in seconds.
|
|
631
|
-
*
|
|
632
|
-
* Falls back to the cache's `defaultTTL`.
|
|
633
|
-
*/
|
|
634
|
-
ttl?: number;
|
|
635
|
-
/**
|
|
636
|
-
* Enable/disable compression.
|
|
637
|
-
*
|
|
638
|
-
* Default: true.
|
|
639
|
-
*/
|
|
640
|
-
compress?: boolean;
|
|
641
|
-
/**
|
|
642
|
-
* Namespace prefix.
|
|
643
|
-
*/
|
|
644
|
-
namespace?: string;
|
|
645
|
-
};
|
|
646
|
-
export type CacheStats = {
|
|
647
|
-
namespace: string;
|
|
648
|
-
connectionStatus: ConnectionStatus;
|
|
649
|
-
};
|
|
650
|
-
export type LockOptions = {
|
|
651
|
-
/**
|
|
652
|
-
* Lock TTL in milliseconds.
|
|
653
|
-
*/
|
|
654
|
-
ttl?: number;
|
|
655
|
-
/**
|
|
656
|
-
* Number of acquisition attempts.
|
|
657
|
-
*/
|
|
658
|
-
retryCount?: number;
|
|
659
|
-
/**
|
|
660
|
-
* Base retry delay in milliseconds.
|
|
661
|
-
*/
|
|
662
|
-
retryDelay?: number;
|
|
663
|
-
};
|
|
664
|
-
export type DistributedLockOptions = LockOptions;
|
|
665
|
-
export type LockInfo = {
|
|
666
|
-
locked: boolean;
|
|
667
|
-
ttl?: number;
|
|
668
|
-
lockId?: string;
|
|
669
|
-
};
|
|
670
795
|
export type HealthStatus = {
|
|
671
796
|
healthy: boolean;
|
|
672
797
|
status: "healthy" | "degraded" | "unhealthy";
|
package/dist/types.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
export const DistributedLockOptionsSchema = z.object({
|
|
3
|
+
ttl: z.coerce.number().int().positive().default(30000),
|
|
4
|
+
retryCount: z.coerce.number().int().positive().default(3),
|
|
5
|
+
retryDelay: z.coerce.number().int().positive().default(200)
|
|
6
|
+
});
|
|
7
|
+
export const CacheOptionsSchema = z.object({
|
|
8
|
+
defaultTTL: z.number().int().min(0).default(3_600),
|
|
9
|
+
compressionThreshold: z.number().int().min(1).default(1_024),
|
|
10
|
+
});
|
|
2
11
|
// ============================================================================
|
|
3
12
|
// Rate Limiting
|
|
4
13
|
// ============================================================================
|
|
@@ -57,15 +66,18 @@ export const BaseRedisConfigSchema = z
|
|
|
57
66
|
connectionTimeout: z.number().int().min(100).default(5_000),
|
|
58
67
|
maxFanOutConcurrency: z.number().int().min(1).max(128).default(8),
|
|
59
68
|
maxBatchSize: z.number().int().min(1).max(10_000).default(500),
|
|
60
|
-
|
|
61
|
-
|
|
69
|
+
lockOptions: DistributedLockOptionsSchema.optional(),
|
|
70
|
+
// defaultTTL: z.number().int().min(0).default(3_600),
|
|
71
|
+
// compressionThreshold: z.number().int().min(1).default(1_024),
|
|
72
|
+
cacheOptions: CacheOptionsSchema.optional(),
|
|
62
73
|
slowCommandThreshold: z.number().int().min(0).default(1_000),
|
|
63
|
-
rateLimit: RateLimitOptionsSchema.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
74
|
+
rateLimit: RateLimitOptionsSchema.optional(),
|
|
75
|
+
// rateLimit: RateLimitOptionsSchema.default({
|
|
76
|
+
// algorithm: "sliding",
|
|
77
|
+
// duration: 60,
|
|
78
|
+
// limit: 100,
|
|
79
|
+
// namespace: "ratelimit",
|
|
80
|
+
// }),
|
|
69
81
|
sessionOptions: z.custom().optional(),
|
|
70
82
|
})
|
|
71
83
|
.strict();
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type Builtin = Date | RegExp | Map<unknown, unknown> | Set<unknown> | WeakMap<object, unknown> | WeakSet<object> | Promise<unknown> | Error;
|
|
2
|
+
type DeepMerge<T, U> = T extends Builtin ? U : U extends Builtin ? U : T extends readonly unknown[] ? U : U extends readonly unknown[] ? U : T extends object ? U extends object ? {
|
|
3
|
+
[K in keyof T | keyof U]: K extends keyof U ? K extends keyof T ? DeepMerge<T[K], U[K]> : U[K] : K extends keyof T ? T[K] : never;
|
|
4
|
+
} : U : U;
|
|
5
|
+
export declare function deepMerge<T extends object>(target: T): T;
|
|
6
|
+
export declare function deepMerge<T extends object, U extends object>(target: T, source: U): DeepMerge<T, U>;
|
|
7
|
+
export declare function deepMerge<T extends object, U extends object, V extends object>(target: T, source: U, source2: V): DeepMerge<DeepMerge<T, U>, V>;
|
|
8
|
+
export declare function deepMerge<T extends object, U extends object, V extends object, W extends object>(target: T, source: U, source2: V, source3: W): DeepMerge<DeepMerge<DeepMerge<T, U>, V>, W>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const BLOCKED_KEYS = new Set(["__proto__", "prototype", "constructor"]);
|
|
2
|
+
function isBlockedKey(key) {
|
|
3
|
+
return typeof key === "string" && BLOCKED_KEYS.has(key);
|
|
4
|
+
}
|
|
5
|
+
function isPlainObject(value) {
|
|
6
|
+
if (value === null || typeof value !== "object") {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
const prototype = Object.getPrototypeOf(value);
|
|
10
|
+
return prototype === Object.prototype || prototype === null;
|
|
11
|
+
}
|
|
12
|
+
function deepMergeTwo(target, source) {
|
|
13
|
+
// Non-objects and special objects are replaced.
|
|
14
|
+
if (!isPlainObject(target) || !isPlainObject(source)) {
|
|
15
|
+
return source;
|
|
16
|
+
}
|
|
17
|
+
const result = Object.create(Object.getPrototypeOf(target));
|
|
18
|
+
// Copy target.
|
|
19
|
+
for (const key of Reflect.ownKeys(target)) {
|
|
20
|
+
if (isBlockedKey(key)) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const descriptor = Object.getOwnPropertyDescriptor(target, key);
|
|
24
|
+
if (descriptor) {
|
|
25
|
+
Object.defineProperty(result, key, descriptor);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Merge source.
|
|
29
|
+
for (const key of Reflect.ownKeys(source)) {
|
|
30
|
+
if (isBlockedKey(key)) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const sourceDescriptor = Object.getOwnPropertyDescriptor(source, key);
|
|
34
|
+
if (!sourceDescriptor) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const sourceValue = sourceDescriptor.value;
|
|
38
|
+
const targetDescriptor = Object.getOwnPropertyDescriptor(target, key);
|
|
39
|
+
const targetValue = targetDescriptor?.value;
|
|
40
|
+
if (targetDescriptor &&
|
|
41
|
+
"value" in targetDescriptor &&
|
|
42
|
+
isPlainObject(targetValue) &&
|
|
43
|
+
isPlainObject(sourceValue)) {
|
|
44
|
+
Object.defineProperty(result, key, {
|
|
45
|
+
...sourceDescriptor,
|
|
46
|
+
value: deepMergeTwo(targetValue, sourceValue),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
Object.defineProperty(result, key, sourceDescriptor);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
export function deepMerge(target, ...sources) {
|
|
56
|
+
let result = target;
|
|
57
|
+
for (const source of sources) {
|
|
58
|
+
result = deepMergeTwo(result, source);
|
|
59
|
+
}
|
|
60
|
+
return result;
|
|
61
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ioredis-toolkit",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Production-grade, type-safe Redis infrastructure for standalone, Sentinel, and Cluster deployments",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -70,8 +70,8 @@
|
|
|
70
70
|
"changeset": "changeset",
|
|
71
71
|
"version": "changeset version",
|
|
72
72
|
"publish": "changeset publish",
|
|
73
|
-
"release": "
|
|
74
|
-
"prebuild": "
|
|
73
|
+
"release": "bun build && changeset publish",
|
|
74
|
+
"prebuild": "bun typecheck",
|
|
75
75
|
"test:unit": "vitest run test/cluster-slot.test.ts test/config.test.ts test/client.test.ts test/cache.test.ts test/ratelimiter.test.ts"
|
|
76
76
|
},
|
|
77
77
|
"keywords": [
|
|
@@ -99,7 +99,8 @@
|
|
|
99
99
|
"@changesets/changelog-github": "^0.7.0",
|
|
100
100
|
"@changesets/cli": "^2.31.1",
|
|
101
101
|
"@types/node": "^26.2.0",
|
|
102
|
-
"
|
|
102
|
+
"ioredis-mock": "^8.13.1",
|
|
103
|
+
"typescript": "^6.0.3",
|
|
103
104
|
"vitest": "^4.1.10"
|
|
104
105
|
}
|
|
105
106
|
}
|