From 861ec9d59ce63409f418b4408e00dbca713c8579 Mon Sep 17 00:00:00 2001 From: Nikolay Karadzhov Date: Wed, 21 May 2025 14:29:36 +0300 Subject: [PATCH] fix(cluster): replace native private with _ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Private class fields (e.g., #execute) cause runtime errors when accessed from contexts where `this` is not the exact instance, triggering “Receiver must be an instance of class RedisCluster”. fixes #2967 --- packages/client/lib/cluster/index.ts | 96 ++++++++++++++-------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/packages/client/lib/cluster/index.ts b/packages/client/lib/cluster/index.ts index f738562926..c2c251810e 100644 --- a/packages/client/lib/cluster/index.ts +++ b/packages/client/lib/cluster/index.ts @@ -188,7 +188,7 @@ export default class RedisCluster< const parser = new BasicCommandParser(); command.parseCommand(parser, ...args); - return this._self.#execute( + return this._self._execute( parser.firstKey, command.IS_READ_ONLY, this._commandOptions, @@ -204,7 +204,7 @@ export default class RedisCluster< const parser = new BasicCommandParser(); command.parseCommand(parser, ...args); - return this._self.#execute( + return this._self._execute( parser.firstKey, command.IS_READ_ONLY, this._self._commandOptions, @@ -222,7 +222,7 @@ export default class RedisCluster< parser.push(...prefix); fn.parseCommand(parser, ...args); - return this._self.#execute( + return this._self._execute( parser.firstKey, fn.IS_READ_ONLY, this._self._commandOptions, @@ -240,7 +240,7 @@ export default class RedisCluster< parser.push(...prefix); script.parseCommand(parser, ...args); - return this._self.#execute( + return this._self._execute( parser.firstKey, script.IS_READ_ONLY, this._commandOptions, @@ -293,9 +293,9 @@ export default class RedisCluster< return RedisCluster.factory(options)(options); } - readonly #options: RedisClusterOptions; + readonly _options: RedisClusterOptions; - readonly #slots: RedisClusterSlots; + readonly _slots: RedisClusterSlots; private _self = this; private _commandOptions?: ClusterCommandOptions; @@ -305,11 +305,11 @@ export default class RedisCluster< * Use with {@link RedisCluster.prototype.nodeClient} to get the client for a specific node (master or replica). */ get slots() { - return this._self.#slots.slots; + return this._self._slots.slots; } get clientSideCache() { - return this._self.#slots.clientSideCache; + return this._self._slots.clientSideCache; } /** @@ -317,7 +317,7 @@ export default class RedisCluster< * Use with {@link RedisCluster.prototype.nodeClient} to get the client for a specific master node. */ get masters() { - return this._self.#slots.masters; + return this._self._slots.masters; } /** @@ -325,7 +325,7 @@ export default class RedisCluster< * Use with {@link RedisCluster.prototype.nodeClient} to get the client for a specific replica node. */ get replicas() { - return this._self.#slots.replicas; + return this._self._slots.replicas; } /** @@ -333,25 +333,25 @@ export default class RedisCluster< * Use with {@link RedisCluster.prototype.nodeClient} to get the client for a specific node (master or replica). */ get nodeByAddress() { - return this._self.#slots.nodeByAddress; + return this._self._slots.nodeByAddress; } /** * The current pub/sub node. */ get pubSubNode() { - return this._self.#slots.pubSubNode; + return this._self._slots.pubSubNode; } get isOpen() { - return this._self.#slots.isOpen; + return this._self._slots.isOpen; } constructor(options: RedisClusterOptions) { super(); - this.#options = options; - this.#slots = new RedisClusterSlots(options, this.emit.bind(this)); + this._options = options; + this._slots = new RedisClusterSlots(options, this.emit.bind(this)); if (options?.commandOptions) { this._commandOptions = options.commandOptions; @@ -366,14 +366,14 @@ export default class RedisCluster< _TYPE_MAPPING extends TypeMapping = TYPE_MAPPING >(overrides?: Partial>) { return new (Object.getPrototypeOf(this).constructor)({ - ...this._self.#options, + ...this._self._options, commandOptions: this._commandOptions, ...overrides }) as RedisClusterType<_M, _F, _S, _RESP, _TYPE_MAPPING>; } async connect() { - await this._self.#slots.connect(); + await this._self._slots.connect(); return this as unknown as RedisClusterType; } @@ -429,7 +429,7 @@ export default class RedisCluster< // return this._commandOptionsProxy('policies', policies); // } - #handleAsk( + _handleAsk( fn: (client: RedisClientType, opts?: ClusterCommandOptions) => Promise ) { return async (client: RedisClientType, options?: ClusterCommandOptions) => { @@ -450,14 +450,14 @@ export default class RedisCluster< }; } - async #execute( + async _execute( firstKey: RedisArgument | undefined, isReadonly: boolean | undefined, options: ClusterCommandOptions | undefined, fn: (client: RedisClientType, opts?: ClusterCommandOptions) => Promise ): Promise { - const maxCommandRedirections = this.#options.maxCommandRedirections ?? 16; - let client = await this.#slots.getClient(firstKey, isReadonly); + const maxCommandRedirections = this._options.maxCommandRedirections ?? 16; + let client = await this._slots.getClient(firstKey, isReadonly); let i = 0; let myFn = fn; @@ -475,10 +475,10 @@ export default class RedisCluster< if (err.message.startsWith('ASK')) { const address = err.message.substring(err.message.lastIndexOf(' ') + 1); - let redirectTo = await this.#slots.getMasterByAddress(address); + let redirectTo = await this._slots.getMasterByAddress(address); if (!redirectTo) { - await this.#slots.rediscover(client); - redirectTo = await this.#slots.getMasterByAddress(address); + await this._slots.rediscover(client); + redirectTo = await this._slots.getMasterByAddress(address); } if (!redirectTo) { @@ -486,13 +486,13 @@ export default class RedisCluster< } client = redirectTo; - myFn = this.#handleAsk(fn); + myFn = this._handleAsk(fn); continue; } if (err.message.startsWith('MOVED')) { - await this.#slots.rediscover(client); - client = await this.#slots.getClient(firstKey, isReadonly); + await this._slots.rediscover(client); + client = await this._slots.getClient(firstKey, isReadonly); continue; } @@ -508,7 +508,7 @@ export default class RedisCluster< options?: ClusterCommandOptions, // defaultPolicies?: CommandPolicies ): Promise { - return this._self.#execute( + return this._self._execute( firstKey, isReadonly, options, @@ -520,11 +520,11 @@ export default class RedisCluster< type Multi = new (...args: ConstructorParameters) => RedisClusterMultiCommandType<[], M, F, S, RESP, TYPE_MAPPING>; return new ((this as any).Multi as Multi)( async (firstKey, isReadonly, commands) => { - const client = await this._self.#slots.getClient(firstKey, isReadonly); + const client = await this._self._slots.getClient(firstKey, isReadonly); return client._executeMulti(commands); }, async (firstKey, isReadonly, commands) => { - const client = await this._self.#slots.getClient(firstKey, isReadonly); + const client = await this._self._slots.getClient(firstKey, isReadonly); return client._executePipeline(commands); }, routing, @@ -539,7 +539,7 @@ export default class RedisCluster< listener: PubSubListener, bufferMode?: T ) { - return (await this._self.#slots.getPubSubClient()) + return (await this._self._slots.getPubSubClient()) .SUBSCRIBE(channels, listener, bufferMode); } @@ -550,7 +550,7 @@ export default class RedisCluster< listener?: PubSubListener, bufferMode?: T ) { - return this._self.#slots.executeUnsubscribeCommand(client => + return this._self._slots.executeUnsubscribeCommand(client => client.UNSUBSCRIBE(channels, listener, bufferMode) ); } @@ -562,7 +562,7 @@ export default class RedisCluster< listener: PubSubListener, bufferMode?: T ) { - return (await this._self.#slots.getPubSubClient()) + return (await this._self._slots.getPubSubClient()) .PSUBSCRIBE(patterns, listener, bufferMode); } @@ -573,7 +573,7 @@ export default class RedisCluster< listener?: PubSubListener, bufferMode?: T ) { - return this._self.#slots.executeUnsubscribeCommand(client => + return this._self._slots.executeUnsubscribeCommand(client => client.PUNSUBSCRIBE(patterns, listener, bufferMode) ); } @@ -585,9 +585,9 @@ export default class RedisCluster< listener: PubSubListener, bufferMode?: T ) { - const maxCommandRedirections = this._self.#options.maxCommandRedirections ?? 16, + const maxCommandRedirections = this._self._options.maxCommandRedirections ?? 16, firstChannel = Array.isArray(channels) ? channels[0] : channels; - let client = await this._self.#slots.getShardedPubSubClient(firstChannel); + let client = await this._self._slots.getShardedPubSubClient(firstChannel); for (let i = 0; ; i++) { try { return await client.SSUBSCRIBE(channels, listener, bufferMode); @@ -597,8 +597,8 @@ export default class RedisCluster< } if (err.message.startsWith('MOVED')) { - await this._self.#slots.rediscover(client); - client = await this._self.#slots.getShardedPubSubClient(firstChannel); + await this._self._slots.rediscover(client); + client = await this._self._slots.getShardedPubSubClient(firstChannel); continue; } @@ -614,7 +614,7 @@ export default class RedisCluster< listener?: PubSubListener, bufferMode?: T ) { - return this._self.#slots.executeShardedUnsubscribeCommand( + return this._self._slots.executeShardedUnsubscribeCommand( Array.isArray(channels) ? channels[0] : channels, client => client.SUNSUBSCRIBE(channels, listener, bufferMode) ); @@ -626,28 +626,28 @@ export default class RedisCluster< * @deprecated Use `close` instead. */ quit() { - return this._self.#slots.quit(); + return this._self._slots.quit(); } /** * @deprecated Use `destroy` instead. */ disconnect() { - return this._self.#slots.disconnect(); + return this._self._slots.disconnect(); } close() { - this._self.#slots.clientSideCache?.onPoolClose(); - return this._self.#slots.close(); + this._self._slots.clientSideCache?.onPoolClose(); + return this._self._slots.close(); } destroy() { - this._self.#slots.clientSideCache?.onPoolClose(); - return this._self.#slots.destroy(); + this._self._slots.clientSideCache?.onPoolClose(); + return this._self._slots.destroy(); } nodeClient(node: ShardNode) { - return this._self.#slots.nodeClient(node); + return this._self._slots.nodeClient(node); } /** @@ -655,7 +655,7 @@ export default class RedisCluster< * Userful for running "forward" commands (like PUBLISH) on a random node. */ getRandomNode() { - return this._self.#slots.getRandomNode(); + return this._self._slots.getRandomNode(); } /** @@ -663,7 +663,7 @@ export default class RedisCluster< * Useful for running readonly commands on a slot. */ getSlotRandomNode(slot: number) { - return this._self.#slots.getSlotRandomNode(slot); + return this._self._slots.getSlotRandomNode(slot); } /**