ioredis-toolkit 0.0.10 → 0.5.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 +67 -0
- package/LICENSE +1 -1
- package/README.md +68 -1613
- package/dist/cache/cache.d.ts +30 -0
- package/dist/cache/cache.d.ts.map +1 -0
- package/dist/cache/cache.js +59 -0
- package/dist/cache/cache.js.map +1 -0
- package/dist/cache/config.d.ts +12 -0
- package/dist/cache/config.d.ts.map +1 -0
- package/dist/cache/config.js +13 -0
- package/dist/cache/config.js.map +1 -0
- package/dist/cache/types.d.ts +32 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +5 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/index.d.ts +43 -51
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -44
- package/dist/index.js.map +1 -0
- package/dist/lock/config.d.ts +12 -0
- package/dist/lock/config.d.ts.map +1 -0
- package/dist/lock/config.js +8 -0
- package/dist/lock/config.js.map +1 -0
- package/dist/lock/lock.d.ts +20 -0
- package/dist/lock/lock.d.ts.map +1 -0
- package/dist/lock/lock.js +44 -0
- package/dist/lock/lock.js.map +1 -0
- package/dist/lock/types.d.ts +19 -0
- package/dist/lock/types.d.ts.map +1 -0
- package/dist/lock/types.js +2 -0
- package/dist/lock/types.js.map +1 -0
- package/dist/modules-config.d.ts +3 -0
- package/dist/modules-config.d.ts.map +1 -0
- package/dist/modules-config.js +2 -0
- package/dist/modules-config.js.map +1 -0
- package/dist/pubsub/config.d.ts +11 -0
- package/dist/pubsub/config.d.ts.map +1 -0
- package/dist/pubsub/config.js +6 -0
- package/dist/pubsub/config.js.map +1 -0
- package/dist/pubsub/pubsub.d.ts +20 -0
- package/dist/pubsub/pubsub.d.ts.map +1 -0
- package/dist/pubsub/pubsub.js +54 -0
- package/dist/pubsub/pubsub.js.map +1 -0
- package/dist/pubsub/types.d.ts +24 -0
- package/dist/pubsub/types.d.ts.map +1 -0
- package/dist/pubsub/types.js +2 -0
- package/dist/pubsub/types.js.map +1 -0
- package/dist/rate-limit/config.d.ts +12 -0
- package/dist/rate-limit/config.d.ts.map +1 -0
- package/dist/rate-limit/config.js +6 -0
- package/dist/rate-limit/config.js.map +1 -0
- package/dist/rate-limit/rate-limiter.d.ts +18 -0
- package/dist/rate-limit/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limit/rate-limiter.js +37 -0
- package/dist/rate-limit/rate-limiter.js.map +1 -0
- package/dist/rate-limit/types.d.ts +27 -0
- package/dist/rate-limit/types.d.ts.map +1 -0
- package/dist/rate-limit/types.js +2 -0
- package/dist/rate-limit/types.js.map +1 -0
- package/dist/redis/client-facade.d.ts +77 -0
- package/dist/redis/client-facade.d.ts.map +1 -0
- package/dist/redis/client-facade.js +102 -0
- package/dist/redis/client-facade.js.map +1 -0
- package/dist/redis/client.d.ts +10 -0
- package/dist/redis/client.d.ts.map +1 -0
- package/dist/redis/client.js +29 -0
- package/dist/redis/client.js.map +1 -0
- package/dist/redis/cluster.d.ts +7 -0
- package/dist/redis/cluster.d.ts.map +1 -0
- package/dist/redis/cluster.js +47 -0
- package/dist/redis/cluster.js.map +1 -0
- package/dist/redis/config.d.ts +39 -0
- package/dist/redis/config.d.ts.map +1 -0
- package/dist/redis/config.js +52 -0
- package/dist/redis/config.js.map +1 -0
- package/dist/redis/errors.d.ts +5 -0
- package/dist/redis/errors.d.ts.map +1 -0
- package/dist/redis/errors.js +5 -0
- package/dist/redis/errors.js.map +1 -0
- package/dist/redis/types.d.ts +135 -0
- package/dist/redis/types.d.ts.map +1 -0
- package/dist/redis/types.js +2 -0
- package/dist/redis/types.js.map +1 -0
- package/dist/redis/wrapper.d.ts +88 -0
- package/dist/redis/wrapper.d.ts.map +1 -0
- package/dist/redis/wrapper.js +206 -0
- package/dist/redis/wrapper.js.map +1 -0
- package/dist/session/config.d.ts +47 -0
- package/dist/session/config.d.ts.map +1 -0
- package/dist/session/config.js +101 -0
- package/dist/session/config.js.map +1 -0
- package/dist/session/cookie.d.ts +16 -0
- package/dist/session/cookie.d.ts.map +1 -0
- package/dist/session/cookie.js +28 -0
- package/dist/session/cookie.js.map +1 -0
- package/dist/session/errors.d.ts +56 -0
- package/dist/session/errors.d.ts.map +1 -0
- package/dist/session/errors.js +58 -0
- package/dist/session/errors.js.map +1 -0
- package/dist/session/factory.d.ts +21 -0
- package/dist/session/factory.d.ts.map +1 -0
- package/dist/session/factory.js +30 -0
- package/dist/session/factory.js.map +1 -0
- package/dist/session/health.d.ts +12 -0
- package/dist/session/health.d.ts.map +1 -0
- package/dist/session/health.js +23 -0
- package/dist/session/health.js.map +1 -0
- package/dist/session/keys.d.ts +23 -0
- package/dist/session/keys.d.ts.map +1 -0
- package/dist/session/keys.js +27 -0
- package/dist/session/keys.js.map +1 -0
- package/dist/session/manager.d.ts +34 -0
- package/dist/session/manager.d.ts.map +1 -0
- package/dist/session/manager.js +31 -0
- package/dist/session/manager.js.map +1 -0
- package/dist/session/metrics.d.ts +11 -0
- package/dist/session/metrics.d.ts.map +1 -0
- package/dist/session/metrics.js +10 -0
- package/dist/session/metrics.js.map +1 -0
- package/dist/session/repository.d.ts +49 -0
- package/dist/session/repository.d.ts.map +1 -0
- package/dist/session/repository.js +203 -0
- package/dist/session/repository.js.map +1 -0
- package/dist/session/revocation.d.ts +22 -0
- package/dist/session/revocation.d.ts.map +1 -0
- package/dist/session/revocation.js +41 -0
- package/dist/session/revocation.js.map +1 -0
- package/dist/session/script-sources.d.ts +11 -0
- package/dist/session/script-sources.d.ts.map +1 -0
- package/dist/session/script-sources.js +140 -0
- package/dist/session/script-sources.js.map +1 -0
- package/dist/session/scripts.d.ts +15 -0
- package/dist/session/scripts.d.ts.map +1 -0
- package/dist/session/scripts.js +41 -0
- package/dist/session/scripts.js.map +1 -0
- package/dist/session/serializer.d.ts +12 -0
- package/dist/session/serializer.d.ts.map +1 -0
- package/dist/session/serializer.js +77 -0
- package/dist/session/serializer.js.map +1 -0
- package/dist/session/service.d.ts +48 -0
- package/dist/session/service.d.ts.map +1 -0
- package/dist/session/service.js +235 -0
- package/dist/session/service.js.map +1 -0
- package/dist/session/token.d.ts +16 -0
- package/dist/session/token.d.ts.map +1 -0
- package/dist/session/token.js +32 -0
- package/dist/session/token.js.map +1 -0
- package/dist/session/types.d.ts +134 -0
- package/dist/session/types.d.ts.map +1 -0
- package/dist/session/types.js +2 -0
- package/dist/session/types.js.map +1 -0
- package/dist/streams/config.d.ts +12 -0
- package/dist/streams/config.d.ts.map +1 -0
- package/dist/streams/config.js +6 -0
- package/dist/streams/config.js.map +1 -0
- package/dist/streams/streams.d.ts +24 -0
- package/dist/streams/streams.d.ts.map +1 -0
- package/dist/streams/streams.js +55 -0
- package/dist/streams/streams.js.map +1 -0
- package/dist/streams/types.d.ts +32 -0
- package/dist/streams/types.d.ts.map +1 -0
- package/dist/streams/types.js +2 -0
- package/dist/streams/types.js.map +1 -0
- package/docs/ACCEPTANCE-REPORT.md +70 -0
- package/docs/ARCHITECTURE.md +61 -0
- package/docs/CAPACITY.md +33 -0
- package/docs/DEPLOYMENT.md +22 -0
- package/docs/README-API.md +15 -0
- package/docs/STATE-MACHINE.md +38 -0
- package/docs/TESTING.md +37 -0
- package/docs/THREAT-MODEL.md +23 -0
- package/docs/TYPE-SAFETY.md +34 -0
- package/docs/modules/cache/README.md +7 -0
- package/docs/modules/cache/usage.md +156 -0
- package/docs/modules/lock/README.md +7 -0
- package/docs/modules/lock/usage.md +105 -0
- package/docs/modules/pubsub/README.md +7 -0
- package/docs/modules/pubsub/usage.md +106 -0
- package/docs/modules/rate-limit/README.md +7 -0
- package/docs/modules/rate-limit/usage.md +100 -0
- package/docs/modules/sessions/README.md +7 -0
- package/docs/modules/sessions/usage.md +262 -0
- package/docs/modules/streams/README.md +7 -0
- package/docs/modules/streams/usage.md +141 -0
- package/package.json +50 -60
- package/src/scripts/cleanup-index.lua +4 -0
- package/src/scripts/conditional-update.lua +21 -0
- package/src/scripts/consume-session.lua +21 -0
- package/src/scripts/create-session.lua +28 -0
- package/src/scripts/delete.lua +2 -0
- package/src/scripts/destroy-user.lua +13 -0
- package/src/scripts/enforce-limit.lua +17 -0
- package/src/scripts/revoke-session.lua +13 -0
- package/src/scripts/rotate.lua +24 -0
- package/src/scripts/touch-session.lua +28 -0
- package/src/scripts/update-session.lua +18 -0
- package/dist/cache.d.ts +0 -797
- package/dist/cache.js +0 -1115
- package/dist/client.d.ts +0 -287
- package/dist/client.js +0 -1113
- package/dist/cluster-slot.d.ts +0 -4
- package/dist/cluster-slot.js +0 -31
- package/dist/cluster.d.ts +0 -79
- package/dist/cluster.js +0 -156
- package/dist/errors.d.ts +0 -30
- package/dist/errors.js +0 -63
- package/dist/health.d.ts +0 -180
- package/dist/health.js +0 -239
- package/dist/lock.d.ts +0 -233
- package/dist/lock.js +0 -440
- package/dist/logger.d.ts +0 -12
- package/dist/logger.js +0 -40
- package/dist/pubsub.d.ts +0 -423
- package/dist/pubsub.js +0 -537
- package/dist/ratelimiter.d.ts +0 -441
- package/dist/ratelimiter.js +0 -539
- package/dist/session/index.d.ts +0 -23
- package/dist/session/index.js +0 -16
- package/dist/session/revocation-store.d.ts +0 -176
- package/dist/session/revocation-store.js +0 -318
- package/dist/session/scripts/cleanup-index.lua +0 -21
- package/dist/session/scripts/conditional-update-encrypted.lua +0 -60
- package/dist/session/scripts/conditional-update.lua +0 -63
- package/dist/session/scripts/create.lua +0 -83
- package/dist/session/scripts/delete-by-user.lua +0 -29
- package/dist/session/scripts/delete.lua +0 -15
- package/dist/session/scripts/enforce-limit.lua +0 -38
- package/dist/session/scripts/revoke.lua +0 -61
- package/dist/session/scripts/rotate-encrypted.lua +0 -149
- package/dist/session/scripts/rotate.lua +0 -167
- package/dist/session/scripts/touch-encrypted.lua +0 -89
- package/dist/session/scripts/touch.lua +0 -72
- package/dist/session/scripts/validate.lua +0 -90
- package/dist/session/session-circuit-breaker.d.ts +0 -42
- package/dist/session/session-circuit-breaker.js +0 -129
- package/dist/session/session-config.d.ts +0 -355
- package/dist/session/session-config.js +0 -171
- package/dist/session/session-cookie.d.ts +0 -72
- package/dist/session/session-cookie.js +0 -101
- package/dist/session/session-encryption.d.ts +0 -87
- package/dist/session/session-encryption.js +0 -139
- package/dist/session/session-errors.d.ts +0 -85
- package/dist/session/session-errors.js +0 -145
- package/dist/session/session-health.d.ts +0 -38
- package/dist/session/session-health.js +0 -60
- package/dist/session/session-keys.d.ts +0 -64
- package/dist/session/session-keys.js +0 -128
- package/dist/session/session-manager.d.ts +0 -73
- package/dist/session/session-manager.js +0 -94
- package/dist/session/session-metrics.d.ts +0 -41
- package/dist/session/session-metrics.js +0 -135
- package/dist/session/session-repository.d.ts +0 -184
- package/dist/session/session-repository.js +0 -763
- package/dist/session/session-scripts.d.ts +0 -36
- package/dist/session/session-scripts.js +0 -130
- package/dist/session/session-serializer.d.ts +0 -42
- package/dist/session/session-serializer.js +0 -267
- package/dist/session/session-service.d.ts +0 -123
- package/dist/session/session-service.js +0 -670
- package/dist/session/session-token.d.ts +0 -38
- package/dist/session/session-token.js +0 -86
- package/dist/session/session-types.d.ts +0 -281
- package/dist/session/session-types.js +0 -16
- package/dist/types.d.ts +0 -924
- package/dist/types.js +0 -151
- package/dist/utils/deepmerge.d.ts +0 -9
- package/dist/utils/deepmerge.js +0 -61
package/dist/cluster-slot.d.ts
DELETED
package/dist/cluster-slot.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/** Redis Cluster uses CRC16-CCITT/XMODEM over the hash-tagged key bytes. */
|
|
2
|
-
const CRC16_TABLE = (() => {
|
|
3
|
-
const table = new Uint16Array(256);
|
|
4
|
-
for (let i = 0; i < 256; i++) {
|
|
5
|
-
let crc = i << 8;
|
|
6
|
-
for (let bit = 0; bit < 8; bit++) {
|
|
7
|
-
crc = (crc & 0x8000) !== 0
|
|
8
|
-
? ((crc << 1) ^ 0x1021) & 0xffff
|
|
9
|
-
: (crc << 1) & 0xffff;
|
|
10
|
-
}
|
|
11
|
-
table[i] = crc;
|
|
12
|
-
}
|
|
13
|
-
return table;
|
|
14
|
-
})();
|
|
15
|
-
/** Extracts the Redis Cluster hash tag from a key. */
|
|
16
|
-
export function hashTag(key) {
|
|
17
|
-
const start = key.indexOf("{");
|
|
18
|
-
if (start < 0)
|
|
19
|
-
return key;
|
|
20
|
-
const end = key.indexOf("}", start + 1);
|
|
21
|
-
return end > start + 1 ? key.slice(start + 1, end) : key;
|
|
22
|
-
}
|
|
23
|
-
/** Returns the Redis Cluster hash slot for a key (0..16383). */
|
|
24
|
-
export function calculateRedisClusterSlot(key) {
|
|
25
|
-
const bytes = Buffer.from(hashTag(key), "utf8");
|
|
26
|
-
let crc = 0;
|
|
27
|
-
for (const byte of bytes) {
|
|
28
|
-
crc = ((crc << 8) ^ CRC16_TABLE[((crc >>> 8) ^ byte) & 0xff]) & 0xffff;
|
|
29
|
-
}
|
|
30
|
-
return crc % 16384;
|
|
31
|
-
}
|
package/dist/cluster.d.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import type { RedisClientWrapper } from './client.js';
|
|
2
|
-
/** A single queued pipeline command. */
|
|
3
|
-
export interface PipelineCommand {
|
|
4
|
-
/** ioredis command name, e.g. `'get'`, `'del'`. */
|
|
5
|
-
command: string;
|
|
6
|
-
/** Arguments for the command (key first for routed commands). */
|
|
7
|
-
args: unknown[];
|
|
8
|
-
/** Slot for the key this command targets (computed by the caller). */
|
|
9
|
-
slot: number;
|
|
10
|
-
}
|
|
11
|
-
/** Result of one pipelined command: `[error, value]` like ioredis. */
|
|
12
|
-
export type PipelineCommandResult = [Error | null, unknown];
|
|
13
|
-
/** Options for {@link executeBySlot}. */
|
|
14
|
-
export interface ExecuteBySlotOptions {
|
|
15
|
-
/**
|
|
16
|
-
* Maximum number of slot pipelines to run concurrently.
|
|
17
|
-
* Default: 8.
|
|
18
|
-
*/
|
|
19
|
-
concurrency?: number;
|
|
20
|
-
/**
|
|
21
|
-
* When a whole slot pipeline fails at the network level (rejected promise,
|
|
22
|
-
* e.g. connection loss), how many times it may be retried before the error
|
|
23
|
-
* is reported per command. Command-level errors are never retried.
|
|
24
|
-
* Default: 1. Pass `false` to disable retries.
|
|
25
|
-
*
|
|
26
|
-
* Only safe for idempotent command batches; the caller decides.
|
|
27
|
-
*/
|
|
28
|
-
retry?: number | false;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Executes a batch of commands grouped by Redis hash slot.
|
|
32
|
-
*
|
|
33
|
-
* For every distinct slot the commands are collected into one pipeline and
|
|
34
|
-
* executed on the node owning that slot. Pipelines run with bounded
|
|
35
|
-
* concurrency (default 8 slots at a time) so a fan-out over many slots cannot
|
|
36
|
-
* exhaust sockets or event-loop resources.
|
|
37
|
-
*
|
|
38
|
-
* Result ordering is preserved: the returned array mirrors the input array.
|
|
39
|
-
* Command-level failures do NOT reject the whole call; each entry is reported
|
|
40
|
-
* as `[error, null]` so callers can implement partial-failure handling.
|
|
41
|
-
* Network-level pipeline failures are retried once per slot pipeline before
|
|
42
|
-
* being reported per command.
|
|
43
|
-
*
|
|
44
|
-
* @param client - The Redis client wrapper.
|
|
45
|
-
* @param commands - Commands to run, each with a resolved slot.
|
|
46
|
-
* @param options - Concurrency and retry tuning.
|
|
47
|
-
* @returns One result per input command, in input order.
|
|
48
|
-
*/
|
|
49
|
-
export declare function executeBySlot(client: RedisClientWrapper, commands: PipelineCommand[], options?: ExecuteBySlotOptions): Promise<PipelineCommandResult[]>;
|
|
50
|
-
/**
|
|
51
|
-
* Inspects ioredis pipeline results and throws a structured error if any
|
|
52
|
-
* command failed. Returns the values (without errors) on success.
|
|
53
|
-
*
|
|
54
|
-
* Pipeline `exec()` resolves with `[error, value][]` per command; a resolved
|
|
55
|
-
* promise does NOT mean every command succeeded. Use this helper to enforce
|
|
56
|
-
* command-level error handling.
|
|
57
|
-
*
|
|
58
|
-
* @param results - The `exec()` result array.
|
|
59
|
-
* @param describe - Optional per-index description used in the error message
|
|
60
|
-
* (must not contain sensitive data).
|
|
61
|
-
* @throws {Error} Listing the failed command indexes.
|
|
62
|
-
*/
|
|
63
|
-
export declare function assertPipelineOk(results: PipelineCommandResult[] | null, describe?: (index: number) => string): unknown[];
|
|
64
|
-
/**
|
|
65
|
-
* Runs an async map over a list with bounded concurrency.
|
|
66
|
-
*
|
|
67
|
-
* Do NOT use `Promise.all(list.map(fn))` for cross-slot fan-out; use this to
|
|
68
|
-
* keep the number of in-flight Redis operations bounded.
|
|
69
|
-
*
|
|
70
|
-
* @param items - Input list.
|
|
71
|
-
* @param limit - Maximum concurrent workers.
|
|
72
|
-
* @param fn - Async mapper.
|
|
73
|
-
* @returns Results in input order.
|
|
74
|
-
*/
|
|
75
|
-
export declare function mapWithConcurrency<T, R>(items: readonly T[], limit: number, fn: (item: T, index: number) => Promise<R>): Promise<R[]>;
|
|
76
|
-
/**
|
|
77
|
-
* Chunks an array into bounded batches. Yields nothing for an empty array.
|
|
78
|
-
*/
|
|
79
|
-
export declare function chunk<T>(items: readonly T[], size: number): Generator<T[]>;
|
package/dist/cluster.js
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Executes a batch of commands grouped by Redis hash slot.
|
|
3
|
-
*
|
|
4
|
-
* For every distinct slot the commands are collected into one pipeline and
|
|
5
|
-
* executed on the node owning that slot. Pipelines run with bounded
|
|
6
|
-
* concurrency (default 8 slots at a time) so a fan-out over many slots cannot
|
|
7
|
-
* exhaust sockets or event-loop resources.
|
|
8
|
-
*
|
|
9
|
-
* Result ordering is preserved: the returned array mirrors the input array.
|
|
10
|
-
* Command-level failures do NOT reject the whole call; each entry is reported
|
|
11
|
-
* as `[error, null]` so callers can implement partial-failure handling.
|
|
12
|
-
* Network-level pipeline failures are retried once per slot pipeline before
|
|
13
|
-
* being reported per command.
|
|
14
|
-
*
|
|
15
|
-
* @param client - The Redis client wrapper.
|
|
16
|
-
* @param commands - Commands to run, each with a resolved slot.
|
|
17
|
-
* @param options - Concurrency and retry tuning.
|
|
18
|
-
* @returns One result per input command, in input order.
|
|
19
|
-
*/
|
|
20
|
-
export async function executeBySlot(client, commands, options = {}) {
|
|
21
|
-
if (commands.length === 0)
|
|
22
|
-
return [];
|
|
23
|
-
const concurrency = Math.max(1, options.concurrency ?? 8);
|
|
24
|
-
const results = new Array(commands.length);
|
|
25
|
-
const missing = new Array(commands.length).fill(false);
|
|
26
|
-
// Group by slot, remembering the original indexes so ordering is preserved.
|
|
27
|
-
const groups = new Map();
|
|
28
|
-
for (let i = 0; i < commands.length; i++) {
|
|
29
|
-
const command = commands[i];
|
|
30
|
-
const group = groups.get(command.slot);
|
|
31
|
-
if (group) {
|
|
32
|
-
group.push({ index: i, command });
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
groups.set(command.slot, [{ index: i, command }]);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
const entries = Array.from(groups.entries());
|
|
39
|
-
// Bounded concurrency: run at most `concurrency` slot pipelines at once.
|
|
40
|
-
let cursor = 0;
|
|
41
|
-
const workers = Array.from({ length: Math.min(concurrency, entries.length) }, async () => {
|
|
42
|
-
while (cursor < entries.length) {
|
|
43
|
-
const [slot, group] = entries[cursor++];
|
|
44
|
-
await runSlotPipeline(client, slot, group, results, missing, options);
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
await Promise.all(workers);
|
|
48
|
-
for (let i = 0; i < missing.length; i++) {
|
|
49
|
-
if (missing[i]) {
|
|
50
|
-
results[i] = [new Error('Command did not produce a pipeline result'), null];
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return results;
|
|
54
|
-
}
|
|
55
|
-
async function runSlotPipeline(client, slot, group, results, missing, options) {
|
|
56
|
-
const retries = options.retry === false ? 0 : Math.max(0, options.retry ?? 1);
|
|
57
|
-
let lastError = null;
|
|
58
|
-
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
59
|
-
try {
|
|
60
|
-
const pipeline = client.pipeline();
|
|
61
|
-
for (const { command } of group) {
|
|
62
|
-
// `args` are formatted for the ioredis pipeline method signature.
|
|
63
|
-
const fn = pipeline[command.command];
|
|
64
|
-
fn.call(pipeline, ...command.args);
|
|
65
|
-
}
|
|
66
|
-
const raw = await pipeline.exec();
|
|
67
|
-
const resultsArray = Array.isArray(raw) ? raw : [];
|
|
68
|
-
for (let i = 0; i < group.length; i++) {
|
|
69
|
-
const item = group[i];
|
|
70
|
-
const result = resultsArray[i];
|
|
71
|
-
if (Array.isArray(result) && result.length === 2) {
|
|
72
|
-
results[item.index] = result;
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
missing[item.index] = true;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
catch (error) {
|
|
81
|
-
lastError = error instanceof Error ? error : new Error(String(error));
|
|
82
|
-
// Network-level failure: retry the whole slot pipeline.
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
// All retries exhausted: report the network error on every command.
|
|
86
|
-
for (const item of group) {
|
|
87
|
-
results[item.index] = [lastError, null];
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Inspects ioredis pipeline results and throws a structured error if any
|
|
92
|
-
* command failed. Returns the values (without errors) on success.
|
|
93
|
-
*
|
|
94
|
-
* Pipeline `exec()` resolves with `[error, value][]` per command; a resolved
|
|
95
|
-
* promise does NOT mean every command succeeded. Use this helper to enforce
|
|
96
|
-
* command-level error handling.
|
|
97
|
-
*
|
|
98
|
-
* @param results - The `exec()` result array.
|
|
99
|
-
* @param describe - Optional per-index description used in the error message
|
|
100
|
-
* (must not contain sensitive data).
|
|
101
|
-
* @throws {Error} Listing the failed command indexes.
|
|
102
|
-
*/
|
|
103
|
-
export function assertPipelineOk(results, describe) {
|
|
104
|
-
if (!results) {
|
|
105
|
-
throw new Error('Pipeline returned no results (connection likely lost).');
|
|
106
|
-
}
|
|
107
|
-
const failures = [];
|
|
108
|
-
for (let i = 0; i < results.length; i++) {
|
|
109
|
-
const result = results[i];
|
|
110
|
-
const error = Array.isArray(result) ? result[0] : undefined;
|
|
111
|
-
if (error) {
|
|
112
|
-
const label = describe ? `"${describe(i)}"` : `index ${i}`;
|
|
113
|
-
failures.push(`${label}: ${error.message}`);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
if (failures.length > 0) {
|
|
117
|
-
throw new Error(`Pipeline failed for ${failures.length} command(s): ${failures.join('; ')}`);
|
|
118
|
-
}
|
|
119
|
-
return results.map((r) => (Array.isArray(r) ? r[1] : undefined));
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Runs an async map over a list with bounded concurrency.
|
|
123
|
-
*
|
|
124
|
-
* Do NOT use `Promise.all(list.map(fn))` for cross-slot fan-out; use this to
|
|
125
|
-
* keep the number of in-flight Redis operations bounded.
|
|
126
|
-
*
|
|
127
|
-
* @param items - Input list.
|
|
128
|
-
* @param limit - Maximum concurrent workers.
|
|
129
|
-
* @param fn - Async mapper.
|
|
130
|
-
* @returns Results in input order.
|
|
131
|
-
*/
|
|
132
|
-
export async function mapWithConcurrency(items, limit, fn) {
|
|
133
|
-
if (items.length === 0)
|
|
134
|
-
return [];
|
|
135
|
-
const concurrency = Math.max(1, limit);
|
|
136
|
-
const results = new Array(items.length);
|
|
137
|
-
let cursor = 0;
|
|
138
|
-
const workers = Array.from({ length: Math.min(concurrency, items.length) }, async () => {
|
|
139
|
-
while (cursor < items.length) {
|
|
140
|
-
const index = cursor++;
|
|
141
|
-
results[index] = await fn(items[index], index);
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
await Promise.all(workers);
|
|
145
|
-
return results;
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Chunks an array into bounded batches. Yields nothing for an empty array.
|
|
149
|
-
*/
|
|
150
|
-
export function chunk(items, size) {
|
|
151
|
-
return (function* () {
|
|
152
|
-
for (let i = 0; i < items.length; i += size) {
|
|
153
|
-
yield items.slice(i, i + size);
|
|
154
|
-
}
|
|
155
|
-
})();
|
|
156
|
-
}
|
package/dist/errors.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
export declare class RedisError extends Error {
|
|
2
|
-
code: string;
|
|
3
|
-
details?: Record<string, any>;
|
|
4
|
-
constructor(message: string, code?: string, details?: Record<string, any>);
|
|
5
|
-
}
|
|
6
|
-
export declare class ConnectionError extends RedisError {
|
|
7
|
-
constructor(message: string, details?: Record<string, any>);
|
|
8
|
-
}
|
|
9
|
-
export declare class TimeoutError extends RedisError {
|
|
10
|
-
constructor(message: string, details?: Record<string, any>);
|
|
11
|
-
}
|
|
12
|
-
/** Session referenced by a token no longer exists or has expired. */
|
|
13
|
-
export declare class SessionExpiredError extends RedisError {
|
|
14
|
-
constructor(message: string, details?: Record<string, any>);
|
|
15
|
-
}
|
|
16
|
-
export declare class LockError extends RedisError {
|
|
17
|
-
constructor(message: string, details?: Record<string, any>);
|
|
18
|
-
}
|
|
19
|
-
export declare class SerializationError extends RedisError {
|
|
20
|
-
constructor(message: string, details?: Record<string, any>);
|
|
21
|
-
}
|
|
22
|
-
export declare class CompressionError extends RedisError {
|
|
23
|
-
constructor(message: string, details?: Record<string, any>);
|
|
24
|
-
}
|
|
25
|
-
export declare class ConfigurationError extends RedisError {
|
|
26
|
-
constructor(message: string, details?: Record<string, any>);
|
|
27
|
-
}
|
|
28
|
-
export declare class ClusterError extends RedisError {
|
|
29
|
-
constructor(message: string, details?: Record<string, any>);
|
|
30
|
-
}
|
package/dist/errors.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
export class RedisError extends Error {
|
|
2
|
-
code;
|
|
3
|
-
details;
|
|
4
|
-
constructor(message, code = 'UNKNOWN_ERROR', details) {
|
|
5
|
-
super(message);
|
|
6
|
-
this.name = 'RedisError';
|
|
7
|
-
this.code = code;
|
|
8
|
-
this.details = details;
|
|
9
|
-
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
10
|
-
if (Error.captureStackTrace) {
|
|
11
|
-
Error.captureStackTrace(this, RedisError);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
export class ConnectionError extends RedisError {
|
|
16
|
-
constructor(message, details) {
|
|
17
|
-
super(message, 'CONNECTION_ERROR', details);
|
|
18
|
-
this.name = 'ConnectionError';
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
export class TimeoutError extends RedisError {
|
|
22
|
-
constructor(message, details) {
|
|
23
|
-
super(message, 'TIMEOUT_ERROR', details);
|
|
24
|
-
this.name = 'TimeoutError';
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
/** Session referenced by a token no longer exists or has expired. */
|
|
28
|
-
export class SessionExpiredError extends RedisError {
|
|
29
|
-
constructor(message, details) {
|
|
30
|
-
super(message, 'AUTH_SESSION_EXPIRED', details);
|
|
31
|
-
this.name = 'SessionExpiredError';
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
export class LockError extends RedisError {
|
|
35
|
-
constructor(message, details) {
|
|
36
|
-
super(message, 'LOCK_ERROR', details);
|
|
37
|
-
this.name = 'LockError';
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
export class SerializationError extends RedisError {
|
|
41
|
-
constructor(message, details) {
|
|
42
|
-
super(message, 'SERIALIZATION_ERROR', details);
|
|
43
|
-
this.name = 'SerializationError';
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
export class CompressionError extends RedisError {
|
|
47
|
-
constructor(message, details) {
|
|
48
|
-
super(message, 'COMPRESSION_ERROR', details);
|
|
49
|
-
this.name = 'CompressionError';
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
export class ConfigurationError extends RedisError {
|
|
53
|
-
constructor(message, details) {
|
|
54
|
-
super(message, 'CONFIGURATION_ERROR', details);
|
|
55
|
-
this.name = 'ConfigurationError';
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
export class ClusterError extends RedisError {
|
|
59
|
-
constructor(message, details) {
|
|
60
|
-
super(message, 'CLUSTER_ERROR', details);
|
|
61
|
-
this.name = 'ClusterError';
|
|
62
|
-
}
|
|
63
|
-
}
|
package/dist/health.d.ts
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import { RedisClientWrapper } from './client.js';
|
|
2
|
-
import { LoggerLike } from './logger.js';
|
|
3
|
-
export interface HealthStatus {
|
|
4
|
-
/** Whether the system is healthy. */
|
|
5
|
-
healthy: boolean;
|
|
6
|
-
/** Current status label. */
|
|
7
|
-
status: 'healthy' | 'degraded' | 'unhealthy';
|
|
8
|
-
/** Latency of the last ping check in milliseconds. */
|
|
9
|
-
latency: number;
|
|
10
|
-
/** Timestamp of when the status was recorded. */
|
|
11
|
-
timestamp: Date;
|
|
12
|
-
/** Additional details about the health check. */
|
|
13
|
-
details: {
|
|
14
|
-
/** Whether a PING command succeeded. */
|
|
15
|
-
ping: boolean;
|
|
16
|
-
/** Number of connected clients (when available). */
|
|
17
|
-
connections?: number;
|
|
18
|
-
/** Memory usage information (when available). */
|
|
19
|
-
memory?: string;
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
export declare class HealthChecker {
|
|
23
|
-
private client;
|
|
24
|
-
private logger;
|
|
25
|
-
private timer;
|
|
26
|
-
private callbacks;
|
|
27
|
-
private lastStatus;
|
|
28
|
-
/**
|
|
29
|
-
* Creates a health checker instance.
|
|
30
|
-
*
|
|
31
|
-
* @param client - The underlying {@link RedisClientWrapper}.
|
|
32
|
-
* @param logger - Optional pino-compatible logger; defaults to `console`.
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* ```ts
|
|
36
|
-
* const health = new HealthChecker(client);
|
|
37
|
-
* ```
|
|
38
|
-
*/
|
|
39
|
-
constructor(client: RedisClientWrapper, logger?: LoggerLike);
|
|
40
|
-
/**
|
|
41
|
-
* Starts periodic health checks.
|
|
42
|
-
*
|
|
43
|
-
* **Behavior:**
|
|
44
|
-
* - If a timer is already running, it is cleared and replaced with the new interval.
|
|
45
|
-
* - Health checks run at the specified `interval` in milliseconds.
|
|
46
|
-
* - Each check runs asynchronously; errors are logged but do not stop the interval.
|
|
47
|
-
* - The first check runs immediately when `start()` is called (depending on setInterval timing).
|
|
48
|
-
*
|
|
49
|
-
* **Parameters:**
|
|
50
|
-
* - `interval` - Check interval in milliseconds. Default: `10000` (10 seconds).
|
|
51
|
-
*
|
|
52
|
-
* @example
|
|
53
|
-
* ```ts
|
|
54
|
-
* // Check every 5 seconds
|
|
55
|
-
* health.start(5000);
|
|
56
|
-
*
|
|
57
|
-
* // Check every 30 seconds (default)
|
|
58
|
-
* health.start();
|
|
59
|
-
* ```
|
|
60
|
-
*
|
|
61
|
-
* @returns `void`
|
|
62
|
-
*/
|
|
63
|
-
start(interval?: number): void;
|
|
64
|
-
/**
|
|
65
|
-
* Stops the health checker.
|
|
66
|
-
*
|
|
67
|
-
* **Behavior:**
|
|
68
|
-
* - Clears the internal timer, stopping further health checks.
|
|
69
|
-
* - Logs a warning if no timer was active.
|
|
70
|
-
*
|
|
71
|
-
* @example
|
|
72
|
-
* ```ts
|
|
73
|
-
* health.stop();
|
|
74
|
-
* ```
|
|
75
|
-
*
|
|
76
|
-
* @returns `void`
|
|
77
|
-
*/
|
|
78
|
-
stop(): void;
|
|
79
|
-
/**
|
|
80
|
-
* Runs a single health check.
|
|
81
|
-
*
|
|
82
|
-
* **Behavior:**
|
|
83
|
-
* - Performs a PING command to verify Redis connectivity.
|
|
84
|
-
* - Attempts to fetch Redis INFO for additional details (connections, memory).
|
|
85
|
-
* In cluster mode, INFO may not be available and is silently ignored.
|
|
86
|
-
* - Measures latency of the PING command.
|
|
87
|
-
* - Updates the internal `lastStatus` and notifies all registered callbacks.
|
|
88
|
-
*
|
|
89
|
-
* **Returns:**
|
|
90
|
-
* - A {@link HealthStatus} object with the current health state.
|
|
91
|
-
*
|
|
92
|
-
* **Example:**
|
|
93
|
-
* ```ts
|
|
94
|
-
* const status = await health.check();
|
|
95
|
-
* console.log(status.healthy, status.latency);
|
|
96
|
-
* // healthy === true, latency === 1.2 (ms)
|
|
97
|
-
* ```
|
|
98
|
-
*
|
|
99
|
-
* **Parameters:**
|
|
100
|
-
* - None
|
|
101
|
-
*
|
|
102
|
-
* @returns Current health status.
|
|
103
|
-
*/
|
|
104
|
-
check(): Promise<HealthStatus>;
|
|
105
|
-
/**
|
|
106
|
-
* Returns the most recent health check result.
|
|
107
|
-
*
|
|
108
|
-
* @returns The last {@link HealthStatus}, or `null` before the first check.
|
|
109
|
-
*
|
|
110
|
-
* @example
|
|
111
|
-
* ```ts
|
|
112
|
-
* const status = health.getStatus();
|
|
113
|
-
* console.log(status?.healthy, status?.latency);
|
|
114
|
-
* ```
|
|
115
|
-
*/
|
|
116
|
-
/**
|
|
117
|
-
* Returns the most recent health check result.
|
|
118
|
-
*
|
|
119
|
-
* **Returns:**
|
|
120
|
-
* - The last {@link HealthStatus}, or `null` before the first check.
|
|
121
|
-
*
|
|
122
|
-
* **Example:**
|
|
123
|
-
* ```ts
|
|
124
|
-
* const status = health.getStatus();
|
|
125
|
-
* console.log(status?.healthy, status?.latency);
|
|
126
|
-
* ```
|
|
127
|
-
*
|
|
128
|
-
* **Parameters:**
|
|
129
|
-
* - None
|
|
130
|
-
*
|
|
131
|
-
* @returns The last result, or `null`.
|
|
132
|
-
*/
|
|
133
|
-
getStatus(): HealthStatus | null;
|
|
134
|
-
/**
|
|
135
|
-
* Registers a callback for health status changes.
|
|
136
|
-
*
|
|
137
|
-
* **Behavior:**
|
|
138
|
-
* - The callback is invoked whenever a health check runs and the status changes.
|
|
139
|
-
* - Callbacks are invoked synchronously within the `check()` method.
|
|
140
|
-
* - Multiple callbacks can be registered; they are invoked in registration order.
|
|
141
|
-
*
|
|
142
|
-
* **Parameters:**
|
|
143
|
-
* - `callback` - A function receiving a {@link HealthStatus} object.
|
|
144
|
-
*
|
|
145
|
-
* @example
|
|
146
|
-
* ```ts
|
|
147
|
-
* health.onChange((status) => {
|
|
148
|
-
* console.log(`Health status: ${status.status}, latency: ${status.latency}ms`);
|
|
149
|
-
* });
|
|
150
|
-
* ```
|
|
151
|
-
*
|
|
152
|
-
* @returns `void`
|
|
153
|
-
*/
|
|
154
|
-
onChange(callback: (status: HealthStatus) => void): void;
|
|
155
|
-
private notifyCallbacks;
|
|
156
|
-
/**
|
|
157
|
-
* Waits until the Redis connection is healthy.
|
|
158
|
-
*
|
|
159
|
-
* **Behavior:**
|
|
160
|
-
* - Polls {@link check} at 1-second intervals.
|
|
161
|
-
* - Returns `true` as soon as `status.healthy` is `true`.
|
|
162
|
-
* - Returns `false` if the timeout is reached without becoming healthy.
|
|
163
|
-
*
|
|
164
|
-
* **Parameters:**
|
|
165
|
-
* - `timeout` - Maximum time to wait in milliseconds. Default: `30000` (30 seconds).
|
|
166
|
-
*
|
|
167
|
-
* **Returns:**
|
|
168
|
-
* - `true` if the connection became healthy within the timeout.
|
|
169
|
-
* - `false` if the timeout was reached without the connection becoming healthy.
|
|
170
|
-
*
|
|
171
|
-
* **Example:**
|
|
172
|
-
* ```ts
|
|
173
|
-
* const healthy = await health.waitForHealthy(10000);
|
|
174
|
-
* // healthy === true if Redis became healthy within 10 seconds
|
|
175
|
-
* ```
|
|
176
|
-
*
|
|
177
|
-
* @returns `true` if became healthy within timeout.
|
|
178
|
-
*/
|
|
179
|
-
waitForHealthy(timeout?: number): Promise<boolean>;
|
|
180
|
-
}
|