@@ -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 > ;
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 ;
@@ -334,6 +342,13 @@ export default class RedisClient<
334
342
this . _commandOptions = options . commandOptions ;
335
343
}
336
344
345
+ // if a credential supplier has been provided, use it, otherwise create a provider from the
346
+ // supplier username and password (if provided), otherwise leave it undefined
347
+ this . #credentialSupplier = options ?. credentialSupplier ?? ( ( options ?. username || options ?. password ) ? ( ) => Promise . resolve ( {
348
+ username : options ?. username ,
349
+ password : options ?. password ?? '' ,
350
+ } ) : undefined ) ;
351
+
337
352
return options ;
338
353
}
339
354
@@ -345,16 +360,16 @@ export default class RedisClient<
345
360
) ;
346
361
}
347
362
348
- #handshake( selectedDB : number ) {
363
+ #handshake( selectedDB : number , credential ?: AuthOptions ) {
349
364
const commands = [ ] ;
350
365
351
366
if ( this . #options?. RESP ) {
352
367
const hello : HelloOptions = { } ;
353
368
354
- if ( this . #options . password ) {
369
+ if ( credential ? .password ) {
355
370
hello . AUTH = {
356
- username : this . #options . username ?? 'default' ,
357
- password : this . #options . password
371
+ username : credential ? .username ?? 'default' ,
372
+ password : credential ? .password
358
373
} ;
359
374
}
360
375
@@ -366,11 +381,11 @@ export default class RedisClient<
366
381
parseArgs ( HELLO , this . #options. RESP , hello )
367
382
) ;
368
383
} else {
369
- if ( this . #options ?. username || this . #options ?. password ) {
384
+ if ( credential ) {
370
385
commands . push (
371
386
parseArgs ( COMMANDS . AUTH , {
372
- username : this . #options . username ,
373
- password : this . #options . password ?? ''
387
+ username : credential . username ,
388
+ password : credential . password ?? ''
374
389
} )
375
390
) ;
376
391
}
@@ -396,7 +411,11 @@ export default class RedisClient<
396
411
}
397
412
398
413
#initiateSocket( ) : RedisSocket {
399
- const socketInitiator = ( ) => {
414
+ const socketInitiator = async ( ) => {
415
+ // we have to call the credential fetch before pushing any commands into the queue,
416
+ // so fetch the credentials before doing anything else.
417
+ const credential : AuthOptions | undefined = await this . #credentialSupplier?.( ) ;
418
+
400
419
const promises = [ ] ,
401
420
chainId = Symbol ( 'Socket Initiator' ) ;
402
421
@@ -418,7 +437,7 @@ export default class RedisClient<
418
437
) ;
419
438
}
420
439
421
- const commands = this . #handshake( this . #selectedDB) ;
440
+ const commands = this . #handshake( this . #selectedDB, credential ) ;
422
441
for ( let i = commands . length - 1 ; i >= 0 ; -- i ) {
423
442
promises . push (
424
443
this . #queue. addCommand ( commands [ i ] , {
@@ -997,10 +1016,11 @@ export default class RedisClient<
997
1016
* Reset the client to its default state (i.e. stop PubSub, stop monitoring, select default DB, etc.)
998
1017
*/
999
1018
async reset ( ) {
1019
+ const credential : AuthOptions | undefined = await this . #credentialSupplier?.( ) ;
1000
1020
const chainId = Symbol ( 'Reset Chain' ) ,
1001
1021
promises = [ this . _self . #queue. reset ( chainId ) ] ,
1002
1022
selectedDB = this . _self . #options?. database ?? 0 ;
1003
- for ( const command of this . _self . #handshake( selectedDB ) ) {
1023
+ for ( const command of this . _self . #handshake( selectedDB , credential ) ) {
1004
1024
promises . push (
1005
1025
this . _self . #queue. addCommand ( command , {
1006
1026
chainId
0 commit comments