@@ -11,12 +11,15 @@ import { Command, CommandSignature, TypeMapping, CommanderConfig, RedisFunction,
11
11
import RedisClientMultiCommand , { RedisClientMultiCommandType } from './multi-command' ;
12
12
import { RedisMultiQueuedCommand } from '../multi-command' ;
13
13
import HELLO , { HelloOptions } from '../commands/HELLO' ;
14
+ import { AuthOptions } from '../commands/AUTH' ;
14
15
import { ScanOptions , ScanCommonOptions } from '../commands/SCAN' ;
15
16
import { RedisLegacyClient , RedisLegacyClientType } from './legacy-mode' ;
16
17
import { RedisPoolOptions , RedisClientPool } from './pool' ;
17
18
import { RedisVariadicArgument , parseArgs , pushVariadicArguments } from '../commands/generic-transformers' ;
18
19
import { BasicCommandParser , CommandParser } from './parser' ;
19
20
21
+ export type RedisCredentialSupplier = ( ) => Promise < AuthOptions | undefined > ;
22
+
20
23
export interface RedisClientOptions <
21
24
M extends RedisModules = RedisModules ,
22
25
F extends RedisFunctions = RedisFunctions ,
@@ -34,6 +37,10 @@ export interface RedisClientOptions<
34
37
* Socket connection properties
35
38
*/
36
39
socket ?: SocketOptions ;
40
+ /**
41
+ * Credential supplier callback function
42
+ */
43
+ credentialSupplier ?: RedisCredentialSupplier ;
37
44
/**
38
45
* ACL username ([see ACL guide](https://redis.io/topics/acl))
39
46
*/
@@ -276,6 +283,7 @@ export default class RedisClient<
276
283
readonly #options?: RedisClientOptions < M , F , S , RESP , TYPE_MAPPING > ;
277
284
readonly #socket: RedisSocket ;
278
285
readonly #queue: RedisCommandsQueue ;
286
+ #credentialSupplier: RedisCredentialSupplier ;
279
287
#selectedDB = 0 ;
280
288
#monitorCallback?: MonitorCallback < TYPE_MAPPING > ;
281
289
private _self = this ;
@@ -313,6 +321,8 @@ export default class RedisClient<
313
321
this . #options = this . #initiateOptions( options ) ;
314
322
this . #queue = this . #initiateQueue( ) ;
315
323
this . #socket = this . #initiateSocket( ) ;
324
+ this . #credentialSupplier = this . #initiateCredentialSupplier( ) ;
325
+
316
326
this . #epoch = 0 ;
317
327
}
318
328
@@ -345,16 +355,16 @@ export default class RedisClient<
345
355
) ;
346
356
}
347
357
348
- #handshake( selectedDB : number ) {
358
+ #handshake( selectedDB : number , credential ?: AuthOptions ) {
349
359
const commands = [ ] ;
350
360
351
361
if ( this . #options?. RESP ) {
352
362
const hello : HelloOptions = { } ;
353
363
354
- if ( this . #options . password ) {
364
+ if ( credential ? .password ) {
355
365
hello . AUTH = {
356
- username : this . #options . username ?? 'default' ,
357
- password : this . #options . password
366
+ username : credential ? .username ?? 'default' ,
367
+ password : credential ? .password
358
368
} ;
359
369
}
360
370
@@ -366,11 +376,11 @@ export default class RedisClient<
366
376
parseArgs ( HELLO , this . #options. RESP , hello )
367
377
) ;
368
378
} else {
369
- if ( this . #options ?. username || this . #options ?. password ) {
379
+ if ( credential ) {
370
380
commands . push (
371
381
parseArgs ( COMMANDS . AUTH , {
372
- username : this . #options . username ,
373
- password : this . #options . password ?? ''
382
+ username : credential . username ,
383
+ password : credential . password ?? ''
374
384
} )
375
385
) ;
376
386
}
@@ -396,7 +406,11 @@ export default class RedisClient<
396
406
}
397
407
398
408
#initiateSocket( ) : RedisSocket {
399
- const socketInitiator = ( ) => {
409
+ const socketInitiator = async ( ) => {
410
+ // we have to call the credential fetch before pushing any commands into the queue,
411
+ // so fetch the credentials before doing anything else.
412
+ const credential : AuthOptions | undefined = await this . #credentialSupplier( ) ;
413
+
400
414
const promises = [ ] ,
401
415
chainId = Symbol ( 'Socket Initiator' ) ;
402
416
@@ -418,7 +432,7 @@ export default class RedisClient<
418
432
) ;
419
433
}
420
434
421
- const commands = this . #handshake( this . #selectedDB) ;
435
+ const commands = this . #handshake( this . #selectedDB, credential ) ;
422
436
for ( let i = commands . length - 1 ; i >= 0 ; -- i ) {
423
437
promises . push (
424
438
this . #queue. addCommand ( commands [ i ] , {
@@ -463,6 +477,15 @@ export default class RedisClient<
463
477
. on ( 'end' , ( ) => this . emit ( 'end' ) ) ;
464
478
}
465
479
480
+ #initiateCredentialSupplier( ) : RedisCredentialSupplier {
481
+ // if a credential supplier has been provided, use it, otherwise create a provider from the
482
+ // supplier username and password (if provided)
483
+ return this . #options?. credentialSupplier ?? ( ( ) => Promise . resolve ( ( this . #options?. username || this . #options?. password ) ? {
484
+ username : this . #options?. username ,
485
+ password : this . #options?. password ?? '' ,
486
+ } : undefined ) ) ;
487
+ }
488
+
466
489
#pingTimer?: NodeJS . Timeout ;
467
490
468
491
#setPingTimer( ) : void {
@@ -997,10 +1020,11 @@ export default class RedisClient<
997
1020
* Reset the client to its default state (i.e. stop PubSub, stop monitoring, select default DB, etc.)
998
1021
*/
999
1022
async reset ( ) {
1023
+ const credential : AuthOptions | undefined = await this . #credentialSupplier?.( ) ;
1000
1024
const chainId = Symbol ( 'Reset Chain' ) ,
1001
1025
promises = [ this . _self . #queue. reset ( chainId ) ] ,
1002
1026
selectedDB = this . _self . #options?. database ?? 0 ;
1003
- for ( const command of this . _self . #handshake( selectedDB ) ) {
1027
+ for ( const command of this . _self . #handshake( selectedDB , credential ) ) {
1004
1028
promises . push (
1005
1029
this . _self . #queue. addCommand ( command , {
1006
1030
chainId
0 commit comments