@@ -8,7 +8,7 @@ import { ClientClosedError, ClientOfflineError, DisconnectsClientError, SimpleEr
88import { URL } from 'node:url' ;
99import { TcpSocketConnectOpts } from 'node:net' ;
1010import { PUBSUB_TYPE , PubSubType , PubSubListener , PubSubTypeListeners , ChannelListeners } from './pub-sub' ;
11- import { Command , CommandSignature , TypeMapping , CommanderConfig , RedisFunction , RedisFunctions , RedisModules , RedisScript , RedisScripts , ReplyUnion , RespVersions , RedisArgument , ReplyWithTypeMapping , SimpleStringReply , TransformReply } from '../RESP/types' ;
11+ import { Command , CommandSignature , TypeMapping , CommanderConfig , RedisFunction , RedisFunctions , RedisModules , RedisScript , RedisScripts , ReplyUnion , RespVersions , RedisArgument , ReplyWithTypeMapping , SimpleStringReply , TransformReply , CommandArguments } from '../RESP/types' ;
1212import RedisClientMultiCommand , { RedisClientMultiCommandType } from './multi-command' ;
1313import { RedisMultiQueuedCommand } from '../multi-command' ;
1414import HELLO , { HelloOptions } from '../commands/HELLO' ;
@@ -446,7 +446,30 @@ export default class RedisClient<
446446 } ) ;
447447 }
448448
449- async #handshake( selectedDB : number ) {
449+ async #handshake( chainId : symbol , asap : boolean ) {
450+ const promises = [ ] ;
451+ const commandsWithErrorHandlers = await this . #getHandshakeCommands( this . #selectedDB ?? 0 ) ;
452+
453+ if ( asap ) commandsWithErrorHandlers . reverse ( )
454+
455+ for ( const { cmd, errorHandler } of commandsWithErrorHandlers ) {
456+ promises . push (
457+ this . #queue
458+ . addCommand ( cmd , {
459+ chainId,
460+ asap
461+ } )
462+ . catch ( errorHandler )
463+ ) ;
464+ }
465+ return promises ;
466+ }
467+
468+ async #getHandshakeCommands(
469+ selectedDB : number
470+ ) : Promise <
471+ Array < { cmd : CommandArguments } & { errorHandler ?: ( err : Error ) => void } >
472+ > {
450473 const commands = [ ] ;
451474 const cp = this . #options?. credentialsProvider ;
452475
@@ -464,8 +487,8 @@ export default class RedisClient<
464487 }
465488
466489 if ( cp && cp . type === 'streaming-credentials-provider' ) {
467-
468- const [ credentials , disposable ] = await this . #subscribeForStreamingCredentials( cp )
490+ const [ credentials , disposable ] =
491+ await this . #subscribeForStreamingCredentials( cp ) ;
469492 this . #credentialsSubscription = disposable ;
470493
471494 if ( credentials . password ) {
@@ -480,55 +503,84 @@ export default class RedisClient<
480503 hello . SETNAME = this . #options. name ;
481504 }
482505
483- commands . push (
484- parseArgs ( HELLO , this . #options. RESP , hello )
485- ) ;
506+ commands . push ( { cmd : parseArgs ( HELLO , this . #options. RESP , hello ) } ) ;
486507 } else {
487-
488508 if ( cp && cp . type === 'async-credentials-provider' ) {
489-
490509 const credentials = await cp . credentials ( ) ;
491510
492511 if ( credentials . username || credentials . password ) {
493- commands . push (
494- parseArgs ( COMMANDS . AUTH , {
512+ commands . push ( {
513+ cmd : parseArgs ( COMMANDS . AUTH , {
495514 username : credentials . username ,
496515 password : credentials . password ?? ''
497516 } )
498- ) ;
517+ } ) ;
499518 }
500519 }
501520
502521 if ( cp && cp . type === 'streaming-credentials-provider' ) {
503-
504- const [ credentials , disposable ] = await this . #subscribeForStreamingCredentials( cp )
522+ const [ credentials , disposable ] =
523+ await this . #subscribeForStreamingCredentials( cp ) ;
505524 this . #credentialsSubscription = disposable ;
506525
507526 if ( credentials . username || credentials . password ) {
508- commands . push (
509- parseArgs ( COMMANDS . AUTH , {
527+ commands . push ( {
528+ cmd : parseArgs ( COMMANDS . AUTH , {
510529 username : credentials . username ,
511530 password : credentials . password ?? ''
512531 } )
513- ) ;
532+ } ) ;
514533 }
515534 }
516535
517536 if ( this . #options?. name ) {
518- commands . push (
519- parseArgs ( COMMANDS . CLIENT_SETNAME , this . #options. name )
520- ) ;
537+ commands . push ( {
538+ cmd : parseArgs ( COMMANDS . CLIENT_SETNAME , this . #options. name )
539+ } ) ;
521540 }
522541 }
523542
524543 if ( selectedDB !== 0 ) {
525- commands . push ( [ 'SELECT' , this . #selectedDB. toString ( ) ] ) ;
544+ commands . push ( { cmd : [ 'SELECT' , this . #selectedDB. toString ( ) ] } ) ;
526545 }
527546
528547 if ( this . #options?. readonly ) {
529- commands . push (
530- parseArgs ( COMMANDS . READONLY )
531- ) ;
548+ commands . push ( { cmd : parseArgs ( COMMANDS . READONLY ) } ) ;
549+ }
550+
551+ if ( ! this . #options?. disableClientInfo ) {
552+ commands . push ( {
553+ cmd : [ 'CLIENT' , 'SETINFO' , 'LIB-VER' , version ] ,
554+ errorHandler : ( err : Error ) => {
555+ // Only throw if not a SimpleError - unknown subcommand
556+ // Client libraries are expected to ignore failures
557+ // of type SimpleError - unknown subcommand, which are
558+ // expected from older servers ( < v7 )
559+ if ( ! ( err instanceof SimpleError ) || ! err . isUnknownSubcommand ( ) ) {
560+ throw err ;
561+ }
562+ }
563+ } ) ;
564+
565+ commands . push ( {
566+ cmd : [
567+ 'CLIENT' ,
568+ 'SETINFO' ,
569+ 'LIB-NAME' ,
570+ this . #options?. clientInfoTag
571+ ? `node-redis(${ this . #options. clientInfoTag } )`
572+ : 'node-redis'
573+ ] ,
574+ errorHandler : ( err : Error ) => {
575+ // Only throw if not a SimpleError - unknown subcommand
576+ // Client libraries are expected to ignore failures
577+ // of type SimpleError - unknown subcommand, which are
578+ // expected from older servers ( < v7 )
579+ if ( ! ( err instanceof SimpleError ) || ! err . isUnknownSubcommand ( ) ) {
580+ throw err ;
581+ }
582+ }
583+ } ) ;
532584 }
533585
534586 return commands ;
@@ -557,52 +609,7 @@ export default class RedisClient<
557609 ) ;
558610 }
559611
560- if ( ! this . #options?. disableClientInfo ) {
561- promises . push (
562- this . #queue. addCommand ( [
563- 'CLIENT' ,
564- 'SETINFO' ,
565- 'LIB-NAME' ,
566- this . #options?. clientInfoTag
567- ? `node-redis(${ this . #options. clientInfoTag } )` : 'node-redis'
568- ] , {
569- chainId,
570- asap : true
571- } ) . catch ( err => {
572- // Only throw if not a SimpleError - unknown subcommand
573- // Client libraries are expected to ignore failures
574- // of type SimpleError - unknown subcommand, which are
575- // expected from older servers ( < v7 )
576- if ( ! ( err instanceof SimpleError ) || ! err . isUnknownSubcommand ( ) ) {
577- throw err ;
578- }
579- } )
580- ) ;
581- promises . push (
582- this . #queue. addCommand ( [ 'CLIENT' , 'SETINFO' , 'LIB-VER' , version ] , {
583- chainId,
584- asap : true
585- } ) . catch ( err => {
586- // Only throw if not a SimpleError - unknown subcommand
587- // Client libraries are expected to ignore failures
588- // of type SimpleError - unknown subcommand, which are
589- // expected from older servers ( < v7 )
590- if ( ! ( err instanceof SimpleError ) || ! err . isUnknownSubcommand ( ) ) {
591- throw err ;
592- }
593- } )
594- ) ;
595- }
596-
597- const commands = await this . #handshake( this . #selectedDB) ;
598- for ( let i = commands . length - 1 ; i >= 0 ; -- i ) {
599- promises . push (
600- this . #queue. addCommand ( commands [ i ] , {
601- chainId,
602- asap : true
603- } )
604- ) ;
605- }
612+ promises . push ( ...( await this . #handshake( chainId , true ) ) ) ;
606613
607614 if ( promises . length ) {
608615 this . #write( ) ;
@@ -1179,13 +1186,7 @@ export default class RedisClient<
11791186 selectedDB = this . _self . #options?. database ?? 0 ;
11801187 this . _self . #credentialsSubscription?. dispose ( ) ;
11811188 this . _self . #credentialsSubscription = null ;
1182- for ( const command of ( await this . _self . #handshake( selectedDB ) ) ) {
1183- promises . push (
1184- this . _self . #queue. addCommand ( command , {
1185- chainId
1186- } )
1187- ) ;
1188- }
1189+ promises . push ( ...( await this . _self . #handshake( chainId , false ) ) ) ;
11891190 this . _self . #scheduleWrite( ) ;
11901191 await Promise . all ( promises ) ;
11911192 this . _self . #selectedDB = selectedDB ;
0 commit comments