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/LICENSE +21 -0
- package/README.md +558 -0
- package/dist/cli.js +17420 -0
- package/dist/cli.js.map +1 -0
- package/dist/core.d.mts +651 -0
- package/dist/core.d.ts +651 -0
- package/dist/core.js +17929 -0
- package/dist/core.js.map +1 -0
- package/dist/core.mjs +17691 -0
- package/dist/core.mjs.map +1 -0
- package/dist/index.d.mts +502 -0
- package/dist/index.d.ts +502 -0
- package/dist/index.js +18845 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +18749 -0
- package/dist/index.mjs.map +1 -0
- package/dist/redis-error-C96iHLJ-.d.mts +1392 -0
- package/dist/redis-error-C96iHLJ-.d.ts +1392 -0
- package/package.json +119 -0
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 };
|