js-valkey-server 0.3.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/dist/core.d.ts ADDED
@@ -0,0 +1,651 @@
1
+ import { F as FeatureId, V as VersionGate, a6 as ExecutionPolicy, a7 as RedisClusterTopology, a8 as RedisClientSession, a as RedisServerState, d as CommandExecutor, a9 as RedisClusterNodeRole, aa as ParkHandler, ab as RedisTurnQueue, ac as ClientSessionMode, ad as RespVersion, ae as RedisDatabase, af as CommandPlan, ag as RedisResult, ah as Unsubscribe, ai as ExecutorResult, aj as RedisTurnHandle, ak as RedisMonitorContext, al as RedisExecutionContext, L as Logger, am as RespEncodeOptions, an as CommandDefinition, C as CompatibilitySpec, f as CompatibilityProfile, ao as CommandRegistry } from './redis-error-C96iHLJ-.js';
2
+ export { ap as AtLeastOneInputKeyError, aq as BitOffsetError, ar as BitOpNotSingleKeyError, as as BitPosBitError, at as BitValueError, au as BitfieldOverflowTypeError, av as BitfieldRoGetOnlyError, aw as BitfieldTypeError, ax as CommandCapabilities, ay as CommandExecutionResult, az as CommandFlag, aA as CommandSchema, g as CountGreaterThanZeroError, aB as DbIndexOutOfRangeError, D as DiscardWithoutMultiError, aC as ExecCommandAbortError, E as ExecWithoutMultiError, h as ExpectedFloatError, i as ExpectedIntegerError, aD as ExpirationState, aE as ExpireGtLtConflictError, aF as ExpireNxXxGtLtConflictError, aG as GeoAnyRequiresCountError, aH as GeoBoxNegativeError, aI as GeoCountNotPositiveError, aJ as GeoHeightNotNumericError, aK as GeoMissingMemberError, aL as GeoRadiusNegativeError, aM as GeoRadiusNotNumericError, aN as GeoRadiusStoreWithOptionsError, aO as GeoSearchStoreWithOptionsError, aP as GeoUnsupportedUnitError, aQ as GeoWidthNotNumericError, H as HashValueNotFloatError, j as HashValueNotIntegerError, aR as HelloProtocolNotIntegerError, aS as IncrByFloatNanOrInfinityError, aT as IncrDecrOverflowError, I as IndexOutOfRangeError, aU as InferSchema, k as InvalidExpireTimeError, aV as InvalidHllError, aW as InvalidLexRangeError, aX as InvalidLongitudeLatitudeError, aY as InvalidStreamIdError, aZ as KeyspaceEntry, l as LimitCantBeNegativeError, a_ as LposCountNegativeError, a$ as LposMaxlenNegativeError, b0 as LposRankZeroError, b1 as LuaReplyValue, M as MinMaxNotFloatError, N as NoAuthError, m as NoPasswordConfiguredError, b2 as NoProtoError, n as NoScriptError, o as NoSuchKeyError, p as NumKeysGreaterThanZeroError, O as OffsetOutOfRangeError, b3 as ParkRequest, b4 as ParseContext, b5 as ParseNodeResult, P as PositiveCountError, b6 as REDIS_CLUSTER_SLOT_COUNT, R as RedisCluster, q as RedisClusterDownError, b7 as RedisClusterNode, b as RedisClusterNodeHandle, r as RedisClusterOptions, s as RedisCommandError, t as RedisCrossSlotError, b8 as RedisDataTypeName, b9 as RedisDataValue, u as RedisFlavor, ba as RedisFunctionRegistry, bb as RedisHashData, bc as RedisHashField, bd as RedisKeyspace, be as RedisListData, bf as RedisLuaRuntime, bg as RedisMonitorCommandEvent, bh as RedisMonitorCommandListener, bi as RedisMonitorFeed, v as RedisMovedError, bj as RedisMutationBus, bk as RedisMutationEvent, bl as RedisMutationListener, bm as RedisPubSubBroker, bn as RedisResultOptions, bo as RedisScriptCache, bp as RedisServerStateOptions, bq as RedisSetData, br as RedisSortedSetData, bs as RedisSortedSetMember, bt as RedisStreamData, bu as RedisStringData, w as RedisSyntaxError, e as RedisValue, c as Resp2Server, bv as Resp2ServerOptions, bw as ResponseStream, x as ResultingScoreNaNError, bx as SameObjectError, S as ScriptCallNoCommandError, y as ScriptDebugModeError, z as ScriptFlushOptionError, by as ScriptNotAllowedCommandError, A as ScriptUnknownCommandError, bz as SerialTurnQueue, bA as SetOptions, bB as SortScoreNotDoubleError, B as StreamElementTooLargeError, bC as StreamIdEqualOrSmallerError, G as StreamIdExhaustedError, bD as StreamIdNotGreaterThanZeroError, bE as StreamLimitNegativeError, bF as StreamLimitRequiresApproxError, bG as TimeoutNegativeError, bH as TimeoutNotFloatError, T as TransactionDiscardedError, U as UnknownClusterSubcommandError, J as UnknownRedisCommandError, K as UnknownScriptSubcommandError, bI as UnsupportedOptionError, W as WatchInsideMultiError, bJ as WeightNotFloatError, Q as WrongNumberOfArgumentsError, X as WrongNumberOfKeysError, Y as WrongPassError, bK as WrongRedisTypeError, Z as WrongTypeRedisError, _ as ZaddGtLtNxConflictError, $ as ZaddIncrPairError, a0 as ZaddNxXxConflictError, bL as ZrangeLimitWithoutByError, bM as ZrangeWithScoresByLexError, a1 as buildRedisCluster, bN as cloneRedisDataValue, a2 as computeSlotRange, bO as createDefaultParkHandler, bP as createHashData, bQ as createListData, bR as createNonBlockingParkHandler, bS as createNoopParkHandler, a3 as createRedisCluster, bT as createRedisLuaRuntime, bU as createSetData, bV as createSortedSetData, bW as createStringData, bX as defineCommand, bY as encodeRedisResult, bZ as encodeRedisValue, a4 as gateSatisfied, b_ as isResponseStream, b$ as luaReplyToRedisValue, c0 as parseCommandArgs, c1 as parseVersion, a5 as resolveCompatibilityProfile, c2 as setLuaWasmLoadOptions, c3 as t } from './redis-error-C96iHLJ-.js';
3
+ import { Socket } from 'net';
4
+ import { Duplex } from 'node:stream';
5
+ import 'lua-redis-wasm';
6
+
7
+ declare const FEATURE_GATES: Record<FeatureId, VersionGate>;
8
+
9
+ declare function createTransactionPolicy(): ExecutionPolicy;
10
+
11
+ /**
12
+ * Enforces `requirepass`: when the server is password-protected and the session
13
+ * has not yet authenticated, every command outside {@link NO_AUTH_COMMANDS} is
14
+ * short-circuited with `-NOAUTH Authentication required.`. When no password is
15
+ * configured the policy is a no-op, so the default `nopass` user can run
16
+ * anything.
17
+ */
18
+ declare function createAuthPolicy(): ExecutionPolicy;
19
+
20
+ type ClusterPolicyOptions = {
21
+ localNodeId: string;
22
+ topology?: RedisClusterTopology;
23
+ };
24
+ declare function createClusterPolicy(options: ClusterPolicyOptions): ExecutionPolicy;
25
+
26
+ type ClientSessionOptions = {
27
+ id?: string;
28
+ clientAddress?: string;
29
+ server: RedisServerState;
30
+ executor: CommandExecutor;
31
+ database?: number;
32
+ nodeRole?: RedisClusterNodeRole;
33
+ signal?: AbortSignal;
34
+ park?: ParkHandler;
35
+ turnQueue?: RedisTurnQueue;
36
+ closeConnection?: (reason?: string) => void;
37
+ };
38
+ /**
39
+ * Mutable view of the turn currently held by an in-flight command. A blocking
40
+ * command suspends its turn while parked and is later resumed on a *new* handle,
41
+ * so the holder must be able to both read the current turn and swap it.
42
+ */
43
+ type TurnAccess = {
44
+ get(): RedisTurnHandle | undefined;
45
+ set(turn: RedisTurnHandle | undefined): void;
46
+ };
47
+ /**
48
+ * Per-connection server state and the concrete {@link RedisClientSession}.
49
+ *
50
+ * One instance exists per connected client and owns everything that is scoped
51
+ * to that connection rather than to the shared server:
52
+ * - the selected database index and the resolved {@link RedisDatabase};
53
+ * - the session {@link ClientSessionMode} (normal / transaction / subscribed);
54
+ * - the negotiated RESP protocol version (HELLO);
55
+ * - the cluster READONLY flag (replica reads via READONLY/READWRITE);
56
+ * - the MULTI command queue and its dirty bit;
57
+ * - WATCH key registrations for optimistic locking.
58
+ *
59
+ * Commands are serialized through a per-database turn queue so that, even though
60
+ * execution is async, only one command mutates a given database at a time. This
61
+ * is also what makes blocking commands (BLPOP, ...) cooperate instead of
62
+ * deadlock — see {@link createTurnAwareParkHandler}.
63
+ */
64
+ declare class ClientSession implements RedisClientSession {
65
+ private static nextId;
66
+ readonly id: string;
67
+ readonly clientAddress?: string;
68
+ readonly connectedAtMs: number;
69
+ readonly server: RedisServerState;
70
+ /** Aborted when the connection closes; threaded into every command's ctx. */
71
+ readonly signal: AbortSignal;
72
+ private readonly executor;
73
+ private readonly signalSource?;
74
+ private readonly nodeRole?;
75
+ private readonly parkHandler;
76
+ private readonly turnQueueOverride?;
77
+ private readonly closeConnection?;
78
+ /**
79
+ * The turn handle of the command currently executing on this session,
80
+ * exposed so {@link executeTransaction} can hand the turn off to another
81
+ * database's queue when a queued SELECT switches databases mid-EXEC.
82
+ */
83
+ private activeTurnAccess?;
84
+ private selectedDatabaseId;
85
+ private sessionMode;
86
+ private respVersion;
87
+ private authenticated;
88
+ /** Set by READONLY, cleared by READWRITE/RESET; lets a replica serve reads. */
89
+ private clusterReadOnlyMode;
90
+ /** Commands buffered between MULTI and EXEC, in submission order. */
91
+ private transactionPlans;
92
+ /** True once a queued command errored — forces EXEC to abort with EXECABORT. */
93
+ private transactionDirty;
94
+ /** Active WATCH registrations, keyed by `db:keyHex`. */
95
+ private readonly watches;
96
+ /** Subset of watched keys mutated since WATCH — non-empty fails the next EXEC. */
97
+ private readonly dirtyWatches;
98
+ private readonly pubsubChannels;
99
+ private readonly pubsubShardChannels;
100
+ private readonly pubsubPatterns;
101
+ private readonly pushQueue;
102
+ private readonly pushWaiters;
103
+ private deferredPushes;
104
+ private pushQueueClosed;
105
+ private readonly responseStreamCleanups;
106
+ private unregisterClientSession?;
107
+ constructor(options: ClientSessionOptions);
108
+ get selectedDatabase(): number;
109
+ get mode(): ClientSessionMode;
110
+ get protocolVersion(): RespVersion;
111
+ get usesSubscribedReplyMode(): boolean;
112
+ get clusterReadOnly(): boolean;
113
+ get isAuthenticated(): boolean;
114
+ get pubsubChannelCount(): number;
115
+ get pubsubShardChannelCount(): number;
116
+ get pubsubPatternCount(): number;
117
+ get pubsubRegularSubscriptionCount(): number;
118
+ get pubsubSubscriptionCount(): number;
119
+ setAuthenticated(value: boolean): void;
120
+ /** The live database object for the currently selected index. */
121
+ get db(): RedisDatabase;
122
+ setProtocolVersion(version: RespVersion): void;
123
+ /** Toggle replica read mode for this connection (READONLY / READWRITE). */
124
+ setClusterReadOnly(value: boolean): void;
125
+ selectDatabase(database: number): void;
126
+ /** MULTI: enter transaction mode. Redis forbids nesting. */
127
+ beginTransaction(): void;
128
+ /** Buffer one command while in MULTI; replies "+QUEUED" to the client. */
129
+ queueTransaction(plan: CommandPlan): void;
130
+ /**
131
+ * EXEC step 1: hand back the queued plans and atomically reset the session to
132
+ * normal mode (clearing the queue, dirty bit, and WATCHes). The caller is
133
+ * responsible for actually running the returned plans via
134
+ * {@link executeTransaction}. Returns an empty list if not in MULTI.
135
+ */
136
+ drainTransaction(): CommandPlan[];
137
+ /** DISCARD: drop the queued commands and leave transaction mode. */
138
+ discardTransaction(): void;
139
+ /** Flag the transaction as poisoned (a queued command failed). No-op outside MULTI. */
140
+ markTransactionDirty(): void;
141
+ isTransactionDirty(): boolean;
142
+ /**
143
+ * EXEC step 2: run the drained plans in order and collect their replies into a
144
+ * single array reply. Each command runs in its own fresh execution context.
145
+ * Streaming commands (SUBSCRIBE/MONITOR) are not permitted inside a
146
+ * transaction: the stream is closed immediately and replaced with an error
147
+ * entry so the array stays positionally aligned with the queued commands.
148
+ */
149
+ executeTransaction(plans: readonly CommandPlan[]): Promise<RedisResult>;
150
+ private appendTransactionValue;
151
+ /**
152
+ * Release the currently held serialization turn and acquire a fresh one on
153
+ * the selected database's queue. Called when a queued SELECT switches
154
+ * databases mid-EXEC so subsequent commands run under the correct
155
+ * per-database turn (see {@link executeTransaction}).
156
+ *
157
+ * No-op when a fixed turn-queue override is in force (a single queue already
158
+ * serializes every database) or when no managed turn is active.
159
+ */
160
+ private handoffTurnToSelectedDb;
161
+ /**
162
+ * WATCH the given keys for optimistic locking. Each key is subscribed in the
163
+ * keyspace; any mutation flips its entry into {@link dirtyWatches}, which a
164
+ * subsequent EXEC checks via {@link isWatchDirty}. Already-watched keys are
165
+ * skipped so re-WATCHing is idempotent.
166
+ */
167
+ watch(keys: readonly Buffer[]): void;
168
+ /** UNWATCH / cleanup: drop every keyspace subscription and clear dirty state. */
169
+ unwatch(): void;
170
+ /** True if any watched key was mutated since WATCH — EXEC must return nil. */
171
+ isWatchDirty(): boolean;
172
+ subscribePubSubChannels(channels: readonly Buffer[]): RedisResult[];
173
+ unsubscribePubSubChannels(channels: readonly Buffer[]): RedisResult[];
174
+ subscribePubSubShardChannels(channels: readonly Buffer[]): RedisResult[];
175
+ unsubscribePubSubShardChannels(channels: readonly Buffer[]): RedisResult[];
176
+ subscribePubSubPatterns(patterns: readonly Buffer[]): RedisResult[];
177
+ unsubscribePubSubPatterns(patterns: readonly Buffer[]): RedisResult[];
178
+ resetPubSub(): void;
179
+ deferPushesUntilAfterReply(): () => void;
180
+ registerResponseStreamCleanup(cleanup: () => void): Unsubscribe;
181
+ resetResponseStreams(): void;
182
+ enqueuePush(result: RedisResult): void;
183
+ readPushes(signal: AbortSignal): AsyncIterable<RedisResult>;
184
+ /**
185
+ * Public entry point for executing one client command.
186
+ *
187
+ * Acquires a turn on the database's turn queue before running, guaranteeing
188
+ * serialized access to the keyspace, and always releases it afterward. The
189
+ * acquired turn is exposed to the command via a turn-aware park handler so a
190
+ * blocking command can yield the turn while parked (see
191
+ * {@link createTurnAwareParkHandler}); `turn` is reassigned through the
192
+ * {@link TurnAccess} closure because suspending returns a *new* handle.
193
+ */
194
+ execute(rawCommand: Buffer | string, rawArgs: readonly Buffer[]): Promise<ExecutorResult>;
195
+ /**
196
+ * Build the {@link RedisExecutionContext} passed to a command's `execute`.
197
+ * When a turn is supplied (the normal client path) the context gets a
198
+ * turn-aware park handler so blocking commands release their turn while
199
+ * waiting; without one (e.g. nested transaction execution) the plain park
200
+ * handler is used.
201
+ */
202
+ createExecutionContext(turnAccess?: TurnAccess, parkOverride?: ParkHandler, monitor?: RedisMonitorContext, transactionReplay?: boolean): RedisExecutionContext;
203
+ /** Tear down the session: abort in-flight work and reset all per-connection state. */
204
+ close(): void;
205
+ disconnect(reason?: string): void;
206
+ /**
207
+ * Wrap the base park handler so that parking also yields the command's turn.
208
+ *
209
+ * Blocking commands (BLPOP, BRPOP, ...) must not hold the database turn while
210
+ * they wait, or no other client could ever produce the value that unblocks
211
+ * them — a deadlock. The flow:
212
+ * 1. Start the underlying park, capturing its eventual value.
213
+ * 2. Clear the local turn and call `turn.suspend(parked)`, which releases the
214
+ * turn back to the queue and resolves with a fresh turn once the park
215
+ * settles and this session is scheduled again.
216
+ * 3. Store the new turn (so `finally`/subsequent parks see it) and return the
217
+ * parked value.
218
+ *
219
+ * If there is no current turn, fall back to plain parking.
220
+ */
221
+ private createTurnAwareParkHandler;
222
+ private refreshPubSubMode;
223
+ private waitForPush;
224
+ private closePushQueue;
225
+ private wakePushWaiters;
226
+ }
227
+
228
+ type ConnectionTransportEvent = 'close' | 'drain' | 'error';
229
+ type ConnectionTransportListener = (error?: Error) => void;
230
+ type ConnectionTransportUnsubscribe = () => void;
231
+ interface ConnectionTransport {
232
+ readonly id: string;
233
+ readonly signal: AbortSignal;
234
+ read(): AsyncIterable<Buffer>;
235
+ write(chunk: Buffer): void | Promise<void>;
236
+ close(reason?: string): void;
237
+ on(event: ConnectionTransportEvent, listener: ConnectionTransportListener): ConnectionTransportUnsubscribe;
238
+ }
239
+
240
+ type SocketConnectionTransportOptions = {
241
+ id?: string;
242
+ };
243
+ declare class SocketConnectionTransport implements ConnectionTransport {
244
+ private readonly socket;
245
+ private static nextId;
246
+ readonly id: string;
247
+ readonly signal: AbortSignal;
248
+ private readonly controller;
249
+ private closed;
250
+ constructor(socket: Socket, options?: SocketConnectionTransportOptions);
251
+ read(): AsyncIterable<Buffer>;
252
+ write(chunk: Buffer): Promise<void>;
253
+ close(_reason?: string): void;
254
+ on(event: ConnectionTransportEvent, listener: ConnectionTransportListener): ConnectionTransportUnsubscribe;
255
+ private abort;
256
+ }
257
+
258
+ type Resp2CommandFrame = {
259
+ command: Buffer;
260
+ args: Buffer[];
261
+ };
262
+ type Resp2DecodeResult = {
263
+ frames: Resp2CommandFrame[];
264
+ error?: Resp2ParseError;
265
+ };
266
+ declare class Resp2ParseError extends Error {
267
+ constructor(message: string);
268
+ }
269
+ declare class Resp2CommandDecoder {
270
+ private buffered;
271
+ push(chunk: Buffer): Resp2DecodeResult;
272
+ private parseFrame;
273
+ private parseArrayFrame;
274
+ private parseInlineFrame;
275
+ }
276
+
277
+ type Resp2SessionAdapterOptions = {
278
+ transport: ConnectionTransport;
279
+ session: ClientSession;
280
+ logger?: Pick<Logger, 'error'>;
281
+ encoder?: RespEncodeOptions;
282
+ };
283
+ declare class Resp2SessionAdapter {
284
+ private readonly decoder;
285
+ private readonly transport;
286
+ private readonly session;
287
+ private readonly logger?;
288
+ private readonly encoder?;
289
+ private writeChain;
290
+ private readonly activeStreams;
291
+ constructor(options: Resp2SessionAdapterOptions);
292
+ run(): Promise<void>;
293
+ private handleFrame;
294
+ private writeExecutorResult;
295
+ private spawnStreamDrain;
296
+ private drainStream;
297
+ private writeRedisResult;
298
+ private writeSessionPushes;
299
+ private writeError;
300
+ }
301
+
302
+ declare const pingCommand: CommandDefinition<{
303
+ message: Buffer<ArrayBufferLike> | undefined;
304
+ }>;
305
+ declare const quitCommand: CommandDefinition<{}>;
306
+ declare const selectCommand: CommandDefinition<{
307
+ database: number;
308
+ }>;
309
+ declare const clientCommand: CommandDefinition<{
310
+ subcommand: string;
311
+ args: Buffer<ArrayBufferLike>[];
312
+ }>;
313
+ declare const aclCommand: CommandDefinition<{
314
+ subcommand: string;
315
+ args: Buffer<ArrayBufferLike>[];
316
+ }>;
317
+ declare const slowlogCommand: CommandDefinition<{
318
+ subcommand: string;
319
+ args: Buffer<ArrayBufferLike>[];
320
+ }>;
321
+ declare const shutdownCommand: CommandDefinition<{
322
+ args: Buffer<ArrayBufferLike>[];
323
+ }>;
324
+ declare const connectionCommands: CommandDefinition<{}>[];
325
+
326
+ declare const monitorCommand: CommandDefinition<{}>;
327
+ declare const monitorCommands: CommandDefinition<{}>[];
328
+
329
+ declare function createClusterCommands(localNodeId: string): readonly CommandDefinition[];
330
+ declare const readonlyCommand: CommandDefinition<{}>;
331
+ declare const readwriteCommand: CommandDefinition<{}>;
332
+
333
+ declare const commandCommand: CommandDefinition<{
334
+ subcommand: string | undefined;
335
+ args: Buffer<ArrayBufferLike>[];
336
+ }>;
337
+
338
+ type SetCondition = 'NX' | 'XX';
339
+ type SetArgs = {
340
+ key: Buffer;
341
+ value: Buffer;
342
+ condition?: SetCondition;
343
+ expiresAt?: number;
344
+ keepTtl?: boolean;
345
+ get?: boolean;
346
+ };
347
+ declare const getCommand: CommandDefinition<{
348
+ key: Buffer<ArrayBufferLike>;
349
+ }>;
350
+ declare const setCommand: CommandDefinition<SetArgs>;
351
+ declare const mgetCommand: CommandDefinition<{
352
+ keys: Buffer<ArrayBufferLike>[];
353
+ }>;
354
+ declare const stringsCommands: (CommandDefinition<{
355
+ key: Buffer<ArrayBufferLike>;
356
+ }> | CommandDefinition<{
357
+ keys: Buffer<ArrayBufferLike>[];
358
+ }> | CommandDefinition<KeyValuePair[]>)[];
359
+ type KeyValuePair = {
360
+ key: Buffer;
361
+ value: Buffer;
362
+ };
363
+
364
+ declare const multiCommand: CommandDefinition<{}>;
365
+ declare const execCommand: CommandDefinition<{}>;
366
+ declare const discardCommand: CommandDefinition<{}>;
367
+ declare const watchCommand: CommandDefinition<{
368
+ keys: Buffer<ArrayBufferLike>[];
369
+ }>;
370
+ declare const unwatchCommand: CommandDefinition<{}>;
371
+ declare const transactionCommands: CommandDefinition<{}>[];
372
+
373
+ declare const delCommand: CommandDefinition<{
374
+ keys: Buffer<ArrayBufferLike>[];
375
+ }>;
376
+ declare const existsCommand: CommandDefinition<{
377
+ keys: Buffer<ArrayBufferLike>[];
378
+ }>;
379
+ declare const typeCommand: CommandDefinition<{
380
+ key: Buffer<ArrayBufferLike>;
381
+ }>;
382
+ declare const dbsizeCommand: CommandDefinition<{}>;
383
+ declare const randomkeyCommand: CommandDefinition<{}>;
384
+ declare const ttlCommand: CommandDefinition<{
385
+ key: Buffer<ArrayBufferLike>;
386
+ }>;
387
+ declare const pttlCommand: CommandDefinition<{
388
+ key: Buffer<ArrayBufferLike>;
389
+ }>;
390
+ declare const expiretimeCommand: CommandDefinition<{
391
+ key: Buffer<ArrayBufferLike>;
392
+ }>;
393
+ declare const pexpiretimeCommand: CommandDefinition<{
394
+ key: Buffer<ArrayBufferLike>;
395
+ }>;
396
+ type ExpireCondition = 'NX' | 'XX';
397
+ type ExpireComparison = 'GT' | 'LT';
398
+ type ExpireOptions = {
399
+ condition?: ExpireCondition;
400
+ comparison?: ExpireComparison;
401
+ };
402
+ declare const expireCommand: CommandDefinition<{
403
+ key: Buffer<ArrayBufferLike>;
404
+ seconds: number;
405
+ options: ExpireOptions;
406
+ }>;
407
+ declare const pexpireCommand: CommandDefinition<{
408
+ key: Buffer<ArrayBufferLike>;
409
+ milliseconds: number;
410
+ options: ExpireOptions;
411
+ }>;
412
+ declare const persistCommand: CommandDefinition<{
413
+ key: Buffer<ArrayBufferLike>;
414
+ }>;
415
+ declare const flushdbCommand: CommandDefinition<{
416
+ mode: "async" | "sync" | undefined;
417
+ }>;
418
+ declare const flushallCommand: CommandDefinition<{
419
+ mode: "async" | "sync" | undefined;
420
+ }>;
421
+ type CopyOptions = {
422
+ db?: number;
423
+ replace: boolean;
424
+ };
425
+ declare const copyCommand: CommandDefinition<{
426
+ source: Buffer<ArrayBufferLike>;
427
+ destination: Buffer<ArrayBufferLike>;
428
+ options: CopyOptions;
429
+ }>;
430
+ declare const keysCommands: CommandDefinition<{}>[];
431
+
432
+ type ScanOptions = {
433
+ cursor: bigint;
434
+ match?: Buffer;
435
+ count?: number;
436
+ type?: string;
437
+ noValues?: boolean;
438
+ };
439
+ type KeyedScanOptions = {
440
+ key: Buffer;
441
+ cursor: bigint;
442
+ match?: Buffer;
443
+ count?: number;
444
+ noValues?: boolean;
445
+ };
446
+ declare const keysCommand: CommandDefinition<{
447
+ pattern: Buffer<ArrayBufferLike>;
448
+ }>;
449
+ declare const scanCommand: CommandDefinition<ScanOptions>;
450
+ declare const hscanCommand: CommandDefinition<KeyedScanOptions>;
451
+ declare const sscanCommand: CommandDefinition<KeyedScanOptions>;
452
+ declare const zscanCommand: CommandDefinition<KeyedScanOptions>;
453
+ declare const scanCommands: (CommandDefinition<{
454
+ pattern: Buffer<ArrayBufferLike>;
455
+ }> | CommandDefinition<ScanOptions> | CommandDefinition<KeyedScanOptions>)[];
456
+
457
+ type EvalArgs = {
458
+ script: Buffer;
459
+ numKeys: number;
460
+ rest: Buffer[];
461
+ };
462
+ type EvalShaArgs = {
463
+ sha: string;
464
+ numKeys: number;
465
+ rest: Buffer[];
466
+ };
467
+ type FunctionArgs = {
468
+ subcommand: string;
469
+ rest: Buffer[];
470
+ };
471
+ type FcallArgs = {
472
+ functionName: string;
473
+ numKeys: number;
474
+ rest: Buffer[];
475
+ };
476
+ declare const scriptCommand: CommandDefinition<{
477
+ subcommand: string;
478
+ rest: Buffer<ArrayBufferLike>[];
479
+ }>;
480
+ declare const evalCommand: CommandDefinition<EvalArgs>;
481
+ declare const evalshaCommand: CommandDefinition<EvalShaArgs>;
482
+ declare const evalRoCommand: CommandDefinition<EvalArgs>;
483
+ declare const evalshaRoCommand: CommandDefinition<EvalShaArgs>;
484
+ declare const functionCommand: CommandDefinition<FunctionArgs>;
485
+ declare const fcallCommand: CommandDefinition<FcallArgs>;
486
+ declare const fcallRoCommand: CommandDefinition<FcallArgs>;
487
+ declare const scriptsCommands: (CommandDefinition<{
488
+ subcommand: string;
489
+ rest: Buffer<ArrayBufferLike>[];
490
+ }> | CommandDefinition<EvalArgs> | CommandDefinition<EvalShaArgs> | CommandDefinition<FcallArgs>)[];
491
+
492
+ declare const redisCommandDefinitions: readonly CommandDefinition[];
493
+ declare function createRedisCommandRegistry(extraCommands?: readonly CommandDefinition[], profile?: CompatibilityProfile): CommandRegistry;
494
+ declare function createRedisCommandExecutor(options?: {
495
+ extraCommands?: readonly CommandDefinition[];
496
+ policies?: readonly ExecutionPolicy[];
497
+ compatibility?: CompatibilitySpec;
498
+ }): CommandExecutor;
499
+
500
+ declare class InMemoryConnectionTransport implements ConnectionTransport {
501
+ private static nextId;
502
+ readonly id: string;
503
+ readonly signal: AbortSignal;
504
+ private readonly controller;
505
+ private readonly incoming;
506
+ private readonly written;
507
+ private readonly listeners;
508
+ private readonly waiters;
509
+ private inputEnded;
510
+ private readerActive;
511
+ private closed;
512
+ constructor(id?: string);
513
+ feed(chunk: Buffer): void;
514
+ endRead(): void;
515
+ read(): AsyncIterable<Buffer>;
516
+ write(chunk: Buffer): void;
517
+ getWritten(): Buffer[];
518
+ getWrittenBuffer(): Buffer;
519
+ clearWritten(): void;
520
+ close(_reason?: string): void;
521
+ on(event: ConnectionTransportEvent, listener: ConnectionTransportListener): ConnectionTransportUnsubscribe;
522
+ private waitForInput;
523
+ private wakeReaders;
524
+ private emit;
525
+ }
526
+
527
+ type AttachSessionOptions = {
528
+ state: RedisServerState;
529
+ executor: CommandExecutor;
530
+ nodeRole?: RedisClusterNodeRole;
531
+ logger?: Pick<Logger, 'error'>;
532
+ encoder?: RespEncodeOptions;
533
+ clientAddress?: string;
534
+ };
535
+ type AttachedSession = {
536
+ session: ClientSession;
537
+ adapter: Resp2SessionAdapter;
538
+ /** Resolves once the adapter's read/write loop finishes (transport closed). */
539
+ done: Promise<void>;
540
+ /** Tear down the transport (which aborts the adapter and closes the session). */
541
+ close(): void;
542
+ };
543
+ /**
544
+ * Wire a {@link ConnectionTransport} to a fresh {@link ClientSession} driven by
545
+ * a {@link Resp2SessionAdapter}, kicking off the adapter's run loop.
546
+ *
547
+ * This is the transport-agnostic core extracted from `Resp2Server.handleConnection`:
548
+ * the socket-backed server and the in-memory virtual connection share it, so the
549
+ * RESP framing / session lifecycle never diverges between them. The returned
550
+ * `done` promise settles when the adapter loop ends; `close()` closes the
551
+ * transport, which aborts the adapter and (via the adapter's `finally`) the
552
+ * session.
553
+ */
554
+ declare function attachSession(transport: ConnectionTransport, opts: AttachSessionOptions): AttachedSession;
555
+
556
+ type CreateVirtualConnectionOptions = {
557
+ state: RedisServerState;
558
+ executor: CommandExecutor;
559
+ nodeRole?: RedisClusterNodeRole;
560
+ logger?: Pick<Logger, 'error'>;
561
+ encoder?: RespEncodeOptions;
562
+ /** Synthetic remote address reported to the client lib. Default 127.0.0.1. */
563
+ remoteAddress?: string;
564
+ /** Synthetic remote port reported to the client lib. Default 6379. */
565
+ remotePort?: number;
566
+ };
567
+ type VirtualConnection = {
568
+ /** The fake `net.Socket`-shaped stream handed to the client library. */
569
+ clientSocket: VirtualClientSocket;
570
+ /** Resolves once the server-side adapter loop ends and the session is closed. */
571
+ done: Promise<void>;
572
+ /** Tear down both ends of the wire and the server-side session. */
573
+ close(): void;
574
+ };
575
+ /**
576
+ * A `net.Socket`-compatible {@link Duplex} handed to a client library (ioredis)
577
+ * as its connection stream. Only the surface the client touches is implemented:
578
+ * duplex read/write, the no-op socket tuning methods, the `remoteAddress` /
579
+ * `remotePort` getters, and the `'connect'` event (emitted on `nextTick`, like
580
+ * ioredis' `StandaloneConnector`). Bytes written by the client are forwarded to
581
+ * the server side via {@link feedServer}; bytes from the server are pushed back
582
+ * out as `'data'`.
583
+ */
584
+ declare class VirtualClientSocket extends Duplex {
585
+ readonly remoteAddress: string;
586
+ readonly remotePort: number;
587
+ readonly localAddress = "127.0.0.1";
588
+ readonly localPort = 0;
589
+ /** Called with each chunk the client writes; set by the wiring below. */
590
+ private onClientWrite?;
591
+ /** Called once when the client side initiates teardown. */
592
+ private onClientDestroy?;
593
+ constructor(remoteAddress: string, remotePort: number);
594
+ /** @internal Wire the server-bound write + destroy hooks. */
595
+ bindServer(hooks: {
596
+ onClientWrite: (chunk: Buffer) => void;
597
+ onClientDestroy: () => void;
598
+ }): void;
599
+ /** @internal Push a chunk produced by the server out to the client reader. */
600
+ feedClient(chunk: Buffer): void;
601
+ /** @internal Signal the client reader that the server closed the wire. */
602
+ endClient(): void;
603
+ _read(): void;
604
+ _write(chunk: Buffer | string, encoding: BufferEncoding, callback: (error?: Error | null) => void): void;
605
+ _destroy(error: Error | null, callback: (error: Error | null) => void): void;
606
+ setNoDelay(): this;
607
+ setKeepAlive(): this;
608
+ setTimeout(): this;
609
+ ref(): this;
610
+ unref(): this;
611
+ }
612
+ /**
613
+ * Build an in-process virtual connection: a fake client-facing `net.Socket`
614
+ * already wired to a fresh server-side {@link ClientSession}. The reusable
615
+ * primitive behind {@link createIoredisMock} — no TCP socket, no port bind.
616
+ *
617
+ * Bytes the client writes flow into a {@link DuplexConnectionTransport} that
618
+ * {@link attachSession} drives exactly like a real socket connection; the
619
+ * server's replies are pushed back out as `'data'` on the client socket. Tearing
620
+ * down either end (client `destroy()` or {@link VirtualConnection.close}) closes
621
+ * the transport, which aborts the adapter and the session.
622
+ */
623
+ declare function createVirtualConnection(opts: CreateVirtualConnectionOptions): VirtualConnection;
624
+
625
+ /**
626
+ * The in-memory pipeline behind one synthetic `host:port`: the node's keyspace
627
+ * state, its command executor (cluster-aware for cluster nodes), and its role.
628
+ */
629
+ type NodePipeline = {
630
+ state: RedisServerState;
631
+ executor: CommandExecutor;
632
+ nodeRole?: RedisClusterNodeRole;
633
+ };
634
+ type RegisteredNode = NodePipeline & {
635
+ host: string;
636
+ port: number;
637
+ };
638
+ /**
639
+ * Maps a synthetic `host:port` to its in-memory {@link NodePipeline} so a client
640
+ * library's per-node connections resolve to the right state/executor without any
641
+ * TCP socket. A standalone mock registers a single entry; a cluster mock
642
+ * registers one entry per node (the synthetic ports advertised by CLUSTER SLOTS).
643
+ */
644
+ declare class InMemoryNodeRegistry {
645
+ private readonly nodesByAddress;
646
+ register(host: string, port: number, pipeline: NodePipeline): void;
647
+ resolve(host: string, port: number): NodePipeline | undefined;
648
+ nodes(): readonly RegisteredNode[];
649
+ }
650
+
651
+ export { type AttachSessionOptions, type AttachedSession, ClientSession, ClientSessionMode, type ClientSessionOptions, CommandDefinition, CommandExecutor, CommandPlan, CommandRegistry, CompatibilityProfile, CompatibilitySpec, type ConnectionTransport, type ConnectionTransportEvent, type ConnectionTransportListener, type ConnectionTransportUnsubscribe, type CreateVirtualConnectionOptions, ExecutorResult, FEATURE_GATES, FeatureId, InMemoryConnectionTransport, InMemoryNodeRegistry, type NodePipeline, ParkHandler, RedisClientSession, RedisClusterNodeRole, RedisClusterTopology, RedisDatabase, RedisExecutionContext, RedisResult, RedisServerState, RedisTurnHandle, RedisTurnQueue, type RegisteredNode, Resp2CommandDecoder, type Resp2CommandFrame, Resp2ParseError, Resp2SessionAdapter, type Resp2SessionAdapterOptions, RespEncodeOptions, RespVersion, SocketConnectionTransport, type SocketConnectionTransportOptions, Unsubscribe, VersionGate, VirtualClientSocket, type VirtualConnection, aclCommand, attachSession, clientCommand, commandCommand, connectionCommands, copyCommand, createAuthPolicy, createClusterCommands, createClusterPolicy, createRedisCommandExecutor, createRedisCommandRegistry, createTransactionPolicy, createVirtualConnection, dbsizeCommand, delCommand, discardCommand, evalCommand, evalRoCommand, evalshaCommand, evalshaRoCommand, execCommand, existsCommand, expireCommand, expiretimeCommand, fcallCommand, fcallRoCommand, flushallCommand, flushdbCommand, functionCommand, getCommand, hscanCommand, keysCommand, keysCommands, mgetCommand, monitorCommand, monitorCommands, multiCommand, persistCommand, pexpireCommand, pexpiretimeCommand, pingCommand, pttlCommand, quitCommand, randomkeyCommand, readonlyCommand, readwriteCommand, redisCommandDefinitions, scanCommand, scanCommands, scriptCommand, scriptsCommands, selectCommand, setCommand, shutdownCommand, slowlogCommand, sscanCommand, stringsCommands, transactionCommands, ttlCommand, typeCommand, unwatchCommand, watchCommand, zscanCommand };