@@ -11,11 +11,14 @@ 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 , pushVariadicArguments } from '../commands/generic-transformers' ;
18
19
20
+ export type RedisCredentialSupplier = ( ) => Promise < AuthOptions > ;
21
+
19
22
export interface RedisClientOptions <
20
23
M extends RedisModules = RedisModules ,
21
24
F extends RedisFunctions = RedisFunctions ,
@@ -33,6 +36,10 @@ export interface RedisClientOptions<
33
36
* Socket connection properties
34
37
*/
35
38
socket ?: SocketOptions ;
39
+ /**
40
+ * Credential supplier callback function
41
+ */
42
+ credentialSupplier ?: RedisCredentialSupplier ;
36
43
/**
37
44
* ACL username ([see ACL guide](https://redis.io/topics/acl))
38
45
*/
@@ -289,6 +296,7 @@ export default class RedisClient<
289
296
readonly #options?: RedisClientOptions < M , F , S , RESP , TYPE_MAPPING > ;
290
297
readonly #socket: RedisSocket ;
291
298
readonly #queue: RedisCommandsQueue ;
299
+ #credentialSupplier?: RedisCredentialSupplier ;
292
300
#selectedDB = 0 ;
293
301
#monitorCallback?: MonitorCallback < TYPE_MAPPING > ;
294
302
private _self = this ;
@@ -347,6 +355,13 @@ export default class RedisClient<
347
355
this . _commandOptions = options . commandOptions ;
348
356
}
349
357
358
+ // if a credential supplier has been provided, use it, otherwise create a provider from the
359
+ // supplier username and password (if provided), otherwise leave it undefined
360
+ this . #credentialSupplier = options ?. credentialSupplier ?? ( ( options ?. username || options ?. password ) ? ( ) => Promise . resolve ( {
361
+ username : options ?. username ,
362
+ password : options ?. password ?? '' ,
363
+ } ) : undefined ) ;
364
+
350
365
return options ;
351
366
}
352
367
@@ -358,16 +373,16 @@ export default class RedisClient<
358
373
) ;
359
374
}
360
375
361
- #handshake( selectedDB : number ) {
376
+ #handshake( selectedDB : number , credential ?: AuthOptions ) {
362
377
const commands = [ ] ;
363
378
364
379
if ( this . #options?. RESP ) {
365
380
const hello : HelloOptions = { } ;
366
381
367
- if ( this . #options . password ) {
382
+ if ( credential ? .password ) {
368
383
hello . AUTH = {
369
- username : this . #options . username ?? 'default' ,
370
- password : this . #options . password
384
+ username : credential ? .username ?? 'default' ,
385
+ password : credential ? .password
371
386
} ;
372
387
}
373
388
@@ -379,11 +394,11 @@ export default class RedisClient<
379
394
HELLO . transformArguments ( this . #options. RESP , hello )
380
395
) ;
381
396
} else {
382
- if ( this . #options ?. username || this . #options ?. password ) {
397
+ if ( credential ) {
383
398
commands . push (
384
399
COMMANDS . AUTH . transformArguments ( {
385
- username : this . #options . username ,
386
- password : this . #options . password ?? ''
400
+ username : credential . username ,
401
+ password : credential . password ?? ''
387
402
} )
388
403
) ;
389
404
}
@@ -409,7 +424,11 @@ export default class RedisClient<
409
424
}
410
425
411
426
#initiateSocket( ) : RedisSocket {
412
- const socketInitiator = ( ) => {
427
+ const socketInitiator = async ( ) => {
428
+ // we have to call the credential fetch before pushing any commands into the queue,
429
+ // so fetch the credentials before doing anything else.
430
+ const credential : AuthOptions | undefined = await this . #credentialSupplier?.( ) ;
431
+
413
432
const promises = [ ] ,
414
433
chainId = Symbol ( 'Socket Initiator' ) ;
415
434
@@ -431,7 +450,7 @@ export default class RedisClient<
431
450
) ;
432
451
}
433
452
434
- const commands = this . #handshake( this . #selectedDB) ;
453
+ const commands = this . #handshake( this . #selectedDB, credential ) ;
435
454
for ( let i = commands . length - 1 ; i >= 0 ; -- i ) {
436
455
promises . push (
437
456
this . #queue. addCommand ( commands [ i ] , {
@@ -981,10 +1000,11 @@ export default class RedisClient<
981
1000
* Reset the client to its default state (i.e. stop PubSub, stop monitoring, select default DB, etc.)
982
1001
*/
983
1002
async reset ( ) {
1003
+ const credential : AuthOptions | undefined = await this . #credentialSupplier?.( ) ;
984
1004
const chainId = Symbol ( 'Reset Chain' ) ,
985
1005
promises = [ this . _self . #queue. reset ( chainId ) ] ,
986
1006
selectedDB = this . _self . #options?. database ?? 0 ;
987
- for ( const command of this . _self . #handshake( selectedDB ) ) {
1007
+ for ( const command of this . _self . #handshake( selectedDB , credential ) ) {
988
1008
promises . push (
989
1009
this . _self . #queue. addCommand ( command , {
990
1010
chainId
0 commit comments