-first commit

This commit is contained in:
2025-11-11 12:36:06 +07:00
commit b99c214434
5683 changed files with 713336 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
import { Disposable } from './disposable';
/**
* Provides credentials asynchronously.
*/
export interface AsyncCredentialsProvider {
readonly type: 'async-credentials-provider';
credentials: () => Promise<BasicAuth>;
}
/**
* Provides credentials asynchronously with support for continuous updates via a subscription model.
* This is useful for environments where credentials are frequently rotated or updated or can be revoked.
*/
export interface StreamingCredentialsProvider {
readonly type: 'streaming-credentials-provider';
/**
* Provides initial credentials and subscribes to subsequent updates. This is used internally by the node-redis client
* to handle credential rotation and re-authentication.
*
* Note: The node-redis client manages the subscription lifecycle automatically. Users only need to implement
* onReAuthenticationError if they want to be notified about authentication failures.
*
* Error handling:
* - Errors received via onError indicate a fatal issue with the credentials stream
* - The stream is automatically closed(disposed) when onError occurs
* - onError typically mean the provider failed to fetch new credentials after retrying
*
* @example
* ```ts
* const provider = getStreamingProvider();
* const [initialCredentials, disposable] = await provider.subscribe({
* onNext: (newCredentials) => {
* // Handle credential update
* },
* onError: (error) => {
* // Handle fatal stream error
* }
* });
*
* @param listener - Callbacks to handle credential updates and errors
* @returns A Promise resolving to [initial credentials, cleanup function]
*/
subscribe: (listener: StreamingCredentialsListener<BasicAuth>) => Promise<[BasicAuth, Disposable]>;
/**
* Called when authentication fails or credentials cannot be renewed in time.
* Implement this to handle authentication errors in your application.
*
* @param error - Either a CredentialsError (invalid/expired credentials) or
* UnableToObtainNewCredentialsError (failed to fetch new credentials on time)
*/
onReAuthenticationError: (error: ReAuthenticationError) => void;
}
/**
* Type representing basic authentication credentials.
*/
export type BasicAuth = {
username?: string;
password?: string;
};
/**
* Callback to handle credential updates and errors.
*/
export type StreamingCredentialsListener<T> = {
onNext: (credentials: T) => void;
onError: (e: Error) => void;
};
/**
* Providers that can supply authentication credentials
*/
export type CredentialsProvider = AsyncCredentialsProvider | StreamingCredentialsProvider;
/**
* Errors that can occur during re-authentication.
*/
export type ReAuthenticationError = CredentialsError | UnableToObtainNewCredentialsError;
/**
* Thrown when re-authentication fails with provided credentials .
* e.g. when the credentials are invalid, expired or revoked.
*
*/
export declare class CredentialsError extends Error {
constructor(message: string);
}
/**
* Thrown when new credentials cannot be obtained before current ones expire
*/
export declare class UnableToObtainNewCredentialsError extends Error {
constructor(message: string);
}
//# sourceMappingURL=credentials-provider.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"credentials-provider.d.ts","sourceRoot":"","sources":["../../../lib/authx/credentials-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,4BAA4B,CAAC;IAC5C,WAAW,EAAE,MAAM,OAAO,CAAC,SAAS,CAAC,CAAA;CACtC;AAED;;;GAGG;AACH,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,IAAI,EAAE,gCAAgC,CAAC;IAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,SAAS,EAAE,CAAC,QAAQ,EAAE,4BAA4B,CAAC,SAAS,CAAC,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAA;IAElG;;;;;;OAMG;IACH,uBAAuB,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;CAEjE;AAED;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAEhE;;GAEG;AACH,MAAM,MAAM,4BAA4B,CAAC,CAAC,IAAI;IAC5C,MAAM,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,IAAI,CAAC;IACjC,OAAO,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;CAC7B,CAAA;AAGD;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,wBAAwB,GAAG,4BAA4B,CAAA;AAEzF;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,gBAAgB,GAAG,iCAAiC,CAAA;AAExF;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAK5B;AAED;;GAEG;AACH,qBAAa,iCAAkC,SAAQ,KAAK;gBAC9C,OAAO,EAAE,MAAM;CAI5B"}

View File

@@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.UnableToObtainNewCredentialsError = exports.CredentialsError = void 0;
/**
* Thrown when re-authentication fails with provided credentials .
* e.g. when the credentials are invalid, expired or revoked.
*
*/
class CredentialsError extends Error {
constructor(message) {
super(`Re-authentication with latest credentials failed: ${message}`);
this.name = 'CredentialsError';
}
}
exports.CredentialsError = CredentialsError;
/**
* Thrown when new credentials cannot be obtained before current ones expire
*/
class UnableToObtainNewCredentialsError extends Error {
constructor(message) {
super(`Unable to obtain new credentials : ${message}`);
this.name = 'UnableToObtainNewCredentialsError';
}
}
exports.UnableToObtainNewCredentialsError = UnableToObtainNewCredentialsError;
//# sourceMappingURL=credentials-provider.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"credentials-provider.js","sourceRoot":"","sources":["../../../lib/authx/credentials-provider.ts"],"names":[],"mappings":";;;AAgFA;;;;GAIG;AACH,MAAa,gBAAiB,SAAQ,KAAK;IACzC,YAAY,OAAe;QACzB,KAAK,CAAC,qDAAqD,OAAO,EAAE,CAAC,CAAC;QACtE,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CAEF;AAND,4CAMC;AAED;;GAEG;AACH,MAAa,iCAAkC,SAAQ,KAAK;IAC1D,YAAY,OAAe;QACzB,KAAK,CAAC,sCAAsC,OAAO,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC,IAAI,GAAG,mCAAmC,CAAC;IAClD,CAAC;CACF;AALD,8EAKC"}

View File

@@ -0,0 +1,7 @@
/**
* Represents a resource that can be disposed.
*/
export interface Disposable {
dispose(): void;
}
//# sourceMappingURL=disposable.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"disposable.d.ts","sourceRoot":"","sources":["../../../lib/authx/disposable.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,IAAI,IAAI,CAAC;CACjB"}

View File

@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=disposable.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"disposable.js","sourceRoot":"","sources":["../../../lib/authx/disposable.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,24 @@
/**
* An identity provider is responsible for providing a token that can be used to authenticate with a service.
*/
/**
* The response from an identity provider when requesting a token.
*
* note: "native" refers to the type of the token that the actual identity provider library is using.
*
* @type T The type of the native idp token.
* @property token The token.
* @property ttlMs The time-to-live of the token in epoch milliseconds extracted from the native token in local time.
*/
export type TokenResponse<T> = {
token: T;
ttlMs: number;
};
export interface IdentityProvider<T> {
/**
* Request a token from the identity provider.
* @returns A promise that resolves to an object containing the token and the time-to-live in epoch milliseconds.
*/
requestToken(): Promise<TokenResponse<T>>;
}
//# sourceMappingURL=identity-provider.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"identity-provider.d.ts","sourceRoot":"","sources":["../../../lib/authx/identity-provider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI;IAAE,KAAK,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC;;;OAGG;IACH,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;CAC3C"}

View File

@@ -0,0 +1,6 @@
"use strict";
/**
* An identity provider is responsible for providing a token that can be used to authenticate with a service.
*/
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=identity-provider.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"identity-provider.js","sourceRoot":"","sources":["../../../lib/authx/identity-provider.ts"],"names":[],"mappings":";AAAA;;GAEG"}

6
node_modules/@redis/client/dist/lib/authx/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,6 @@
export { TokenManager, TokenManagerConfig, TokenStreamListener, RetryPolicy, IDPError } from './token-manager';
export { CredentialsProvider, StreamingCredentialsProvider, UnableToObtainNewCredentialsError, CredentialsError, StreamingCredentialsListener, AsyncCredentialsProvider, ReAuthenticationError, BasicAuth } from './credentials-provider';
export { Token } from './token';
export { IdentityProvider, TokenResponse } from './identity-provider';
export { Disposable } from './disposable';
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/authx/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC/G,OAAO,EACL,mBAAmB,EACnB,4BAA4B,EAC5B,iCAAiC,EACjC,gBAAgB,EAChB,4BAA4B,EAC5B,wBAAwB,EACxB,qBAAqB,EACrB,SAAS,EACV,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEtE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA"}

12
node_modules/@redis/client/dist/lib/authx/index.js generated vendored Normal file
View File

@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Token = exports.CredentialsError = exports.UnableToObtainNewCredentialsError = exports.IDPError = exports.TokenManager = void 0;
var token_manager_1 = require("./token-manager");
Object.defineProperty(exports, "TokenManager", { enumerable: true, get: function () { return token_manager_1.TokenManager; } });
Object.defineProperty(exports, "IDPError", { enumerable: true, get: function () { return token_manager_1.IDPError; } });
var credentials_provider_1 = require("./credentials-provider");
Object.defineProperty(exports, "UnableToObtainNewCredentialsError", { enumerable: true, get: function () { return credentials_provider_1.UnableToObtainNewCredentialsError; } });
Object.defineProperty(exports, "CredentialsError", { enumerable: true, get: function () { return credentials_provider_1.CredentialsError; } });
var token_1 = require("./token");
Object.defineProperty(exports, "Token", { enumerable: true, get: function () { return token_1.Token; } });
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/authx/index.ts"],"names":[],"mappings":";;;AAAA,iDAA+G;AAAtG,6GAAA,YAAY,OAAA;AAAwD,yGAAA,QAAQ,OAAA;AACrF,+DASgC;AAN9B,yIAAA,iCAAiC,OAAA;AACjC,wHAAA,gBAAgB,OAAA;AAMlB,iCAAgC;AAAvB,8FAAA,KAAK,OAAA"}

View File

@@ -0,0 +1,164 @@
import { IdentityProvider } from './identity-provider';
import { Token } from './token';
import { Disposable } from './disposable';
/**
* The configuration for retrying token refreshes.
*/
export interface RetryPolicy {
/**
* The maximum number of attempts to retry token refreshes.
*/
maxAttempts: number;
/**
* The initial delay in milliseconds before the first retry.
*/
initialDelayMs: number;
/**
* The maximum delay in milliseconds between retries.
* The calculated delay will be capped at this value.
*/
maxDelayMs: number;
/**
* The multiplier for exponential backoff between retries.
* @example
* A value of 2 will double the delay each time:
* - 1st retry: initialDelayMs
* - 2nd retry: initialDelayMs * 2
* - 3rd retry: initialDelayMs * 4
*/
backoffMultiplier: number;
/**
* The percentage of jitter to apply to the delay.
* @example
* A value of 0.1 will add or subtract up to 10% of the delay.
*/
jitterPercentage?: number;
/**
* Function to classify errors from the identity provider as retryable or non-retryable.
* Used to determine if a token refresh failure should be retried based on the type of error.
*
* The default behavior is to retry all types of errors if no function is provided.
*
* Common use cases:
* - Network errors that may be transient (should retry)
* - Invalid credentials (should not retry)
* - Rate limiting responses (should retry)
*
* @param error - The error from the identity provider3
* @param attempt - Current retry attempt (0-based)
* @returns `true` if the error is considered transient and the operation should be retried
*
* @example
* ```typescript
* const retryPolicy: RetryPolicy = {
* maxAttempts: 3,
* initialDelayMs: 1000,
* maxDelayMs: 5000,
* backoffMultiplier: 2,
* isRetryable: (error) => {
* // Retry on network errors or rate limiting
* return error instanceof NetworkError ||
* error instanceof RateLimitError;
* }
* };
* ```
*/
isRetryable?: (error: unknown, attempt: number) => boolean;
}
/**
* the configuration for the TokenManager.
*/
export interface TokenManagerConfig {
/**
* Represents the ratio of a token's lifetime at which a refresh should be triggered.
* For example, a value of 0.75 means the token should be refreshed when 75% of its lifetime has elapsed (or when
* 25% of its lifetime remains).
*/
expirationRefreshRatio: number;
retry?: RetryPolicy;
}
/**
* IDPError indicates a failure from the identity provider.
*
* The `isRetryable` flag is determined by the RetryPolicy's error classification function - if an error is
* classified as retryable, it will be marked as transient and the token manager will attempt to recover.
*/
export declare class IDPError extends Error {
readonly message: string;
readonly isRetryable: boolean;
constructor(message: string, isRetryable: boolean);
}
/**
* TokenStreamListener is an interface for objects that listen to token changes.
*/
export type TokenStreamListener<T> = {
/**
* Called each time a new token is received.
* @param token
*/
onNext: (token: Token<T>) => void;
/**
* Called when an error occurs while calling the underlying IdentityProvider. The error can be
* transient and the token manager will attempt to obtain a token again if retry policy is configured.
*
* Only fatal errors will terminate the stream and stop the token manager.
*
* @param error
*/
onError: (error: IDPError) => void;
};
/**
* TokenManager is responsible for obtaining/refreshing tokens and notifying listeners about token changes.
* It uses an IdentityProvider to request tokens. The token refresh is scheduled based on the token's TTL and
* the expirationRefreshRatio configuration.
*
* The TokenManager should be disposed when it is no longer needed by calling the dispose method on the Disposable
* returned by start.
*/
export declare class TokenManager<T> {
private readonly identityProvider;
private readonly config;
private currentToken;
private refreshTimeout;
private listener;
private retryAttempt;
constructor(identityProvider: IdentityProvider<T>, config: TokenManagerConfig);
/**
* Starts the token manager and returns a Disposable that can be used to stop the token manager.
*
* @param listener The listener that will receive token updates.
* @param initialDelayMs The initial delay in milliseconds before the first token refresh.
*/
start(listener: TokenStreamListener<T>, initialDelayMs?: number): Disposable;
calculateRetryDelay(): number;
private shouldRetry;
isRunning(): boolean;
private refresh;
private handleNewToken;
/**
* Creates a Token object from a native token and sets it as the current token.
*
* @param nativeToken - The raw token received from the identity provider
* @param ttlMs - Time-to-live in milliseconds for the token
*
* @returns A new Token instance containing the wrapped native token and expiration details
*
*/
wrapAndSetCurrentToken(nativeToken: T, ttlMs: number): Token<T>;
private scheduleNextRefresh;
/**
* Calculates the time in milliseconds when the token should be refreshed
* based on the token's TTL and the expirationRefreshRatio configuration.
*
* @param token The token to calculate the refresh time for.
* @param now The current time in milliseconds. Defaults to Date.now().
*/
calculateRefreshTime(token: Token<T>, now?: number): number;
private stop;
/**
* Returns the current token or null if no token is available.
*/
getCurrentToken(): Token<T> | null;
private notifyError;
}
//# sourceMappingURL=token-manager.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"token-manager.d.ts","sourceRoot":"","sources":["../../../lib/authx/token-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAiB,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAC;AAExC;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;;;;;;OAOG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAE1B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;CAC5D;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAEjC;;;;OAIG;IACH,sBAAsB,EAAE,MAAM,CAAC;IAG/B,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAED;;;;;GAKG;AACH,qBAAa,QAAS,SAAQ,KAAK;aACL,OAAO,EAAE,MAAM;aAAkB,WAAW,EAAE,OAAO;gBAArD,OAAO,EAAE,MAAM,EAAkB,WAAW,EAAE,OAAO;CAIlF;AAED;;GAEG;AACH,MAAM,MAAM,mBAAmB,CAAC,CAAC,IAAI;IACnC;;;OAGG;IACH,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAElC;;;;;;;OAOG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;CAEpC,CAAA;AAED;;;;;;;GAOG;AACH,qBAAa,YAAY,CAAC,CAAC;IAOvB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPzB,OAAO,CAAC,YAAY,CAAyB;IAC7C,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,QAAQ,CAAuC;IACvD,OAAO,CAAC,YAAY,CAAa;gBAGd,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,CAAC,EACrC,MAAM,EAAE,kBAAkB;IAU7C;;;;;OAKG;IACI,KAAK,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC,CAAC,EAAE,cAAc,GAAE,MAAU,GAAG,UAAU;IAe/E,mBAAmB,IAAI,MAAM;IAoBpC,OAAO,CAAC,WAAW;IAgBZ,SAAS,IAAI,OAAO;YAIb,OAAO;IAsBrB,OAAO,CAAC,cAAc,CAQrB;IAED;;;;;;;;OAQG;IACI,sBAAsB,CAAC,WAAW,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC;IAWtE,OAAO,CAAC,mBAAmB;IAa3B;;;;;;OAMG;IACI,oBAAoB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,GAAE,MAAmB,GAAG,MAAM;IAK9E,OAAO,CAAC,IAAI;IAYZ;;OAEG;IACI,eAAe,IAAI,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI;IAIzC,OAAO,CAAC,WAAW;CASpB"}

View File

@@ -0,0 +1,184 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TokenManager = exports.IDPError = void 0;
const token_1 = require("./token");
/**
* IDPError indicates a failure from the identity provider.
*
* The `isRetryable` flag is determined by the RetryPolicy's error classification function - if an error is
* classified as retryable, it will be marked as transient and the token manager will attempt to recover.
*/
class IDPError extends Error {
message;
isRetryable;
constructor(message, isRetryable) {
super(message);
this.message = message;
this.isRetryable = isRetryable;
this.name = 'IDPError';
}
}
exports.IDPError = IDPError;
/**
* TokenManager is responsible for obtaining/refreshing tokens and notifying listeners about token changes.
* It uses an IdentityProvider to request tokens. The token refresh is scheduled based on the token's TTL and
* the expirationRefreshRatio configuration.
*
* The TokenManager should be disposed when it is no longer needed by calling the dispose method on the Disposable
* returned by start.
*/
class TokenManager {
identityProvider;
config;
currentToken = null;
refreshTimeout = null;
listener = null;
retryAttempt = 0;
constructor(identityProvider, config) {
this.identityProvider = identityProvider;
this.config = config;
if (this.config.expirationRefreshRatio > 1) {
throw new Error('expirationRefreshRatio must be less than or equal to 1');
}
if (this.config.expirationRefreshRatio < 0) {
throw new Error('expirationRefreshRatio must be greater or equal to 0');
}
}
/**
* Starts the token manager and returns a Disposable that can be used to stop the token manager.
*
* @param listener The listener that will receive token updates.
* @param initialDelayMs The initial delay in milliseconds before the first token refresh.
*/
start(listener, initialDelayMs = 0) {
if (this.listener) {
this.stop();
}
this.listener = listener;
this.retryAttempt = 0;
this.scheduleNextRefresh(initialDelayMs);
return {
dispose: () => this.stop()
};
}
calculateRetryDelay() {
if (!this.config.retry)
return 0;
const { initialDelayMs, maxDelayMs, backoffMultiplier, jitterPercentage } = this.config.retry;
let delay = initialDelayMs * Math.pow(backoffMultiplier, this.retryAttempt - 1);
delay = Math.min(delay, maxDelayMs);
if (jitterPercentage) {
const jitterRange = delay * (jitterPercentage / 100);
const jitterAmount = Math.random() * jitterRange - (jitterRange / 2);
delay += jitterAmount;
}
let result = Math.max(0, Math.floor(delay));
return result;
}
shouldRetry(error) {
if (!this.config.retry)
return false;
const { maxAttempts, isRetryable } = this.config.retry;
if (this.retryAttempt >= maxAttempts) {
return false;
}
if (isRetryable) {
return isRetryable(error, this.retryAttempt);
}
return false;
}
isRunning() {
return this.listener !== null;
}
async refresh() {
if (!this.listener) {
throw new Error('TokenManager is not running, but refresh was called');
}
try {
await this.identityProvider.requestToken().then(this.handleNewToken);
this.retryAttempt = 0;
}
catch (error) {
if (this.shouldRetry(error)) {
this.retryAttempt++;
const retryDelay = this.calculateRetryDelay();
this.notifyError(`Token refresh failed (attempt ${this.retryAttempt}), retrying in ${retryDelay}ms: ${error}`, true);
this.scheduleNextRefresh(retryDelay);
}
else {
this.notifyError(error, false);
this.stop();
}
}
}
handleNewToken = async ({ token: nativeToken, ttlMs }) => {
if (!this.listener) {
throw new Error('TokenManager is not running, but a new token was received');
}
const token = this.wrapAndSetCurrentToken(nativeToken, ttlMs);
this.listener.onNext(token);
this.scheduleNextRefresh(this.calculateRefreshTime(token));
};
/**
* Creates a Token object from a native token and sets it as the current token.
*
* @param nativeToken - The raw token received from the identity provider
* @param ttlMs - Time-to-live in milliseconds for the token
*
* @returns A new Token instance containing the wrapped native token and expiration details
*
*/
wrapAndSetCurrentToken(nativeToken, ttlMs) {
const now = Date.now();
const token = new token_1.Token(nativeToken, now + ttlMs, now);
this.currentToken = token;
return token;
}
scheduleNextRefresh(delayMs) {
if (this.refreshTimeout) {
clearTimeout(this.refreshTimeout);
this.refreshTimeout = null;
}
if (delayMs === 0) {
this.refresh();
}
else {
this.refreshTimeout = setTimeout(() => this.refresh(), delayMs);
}
}
/**
* Calculates the time in milliseconds when the token should be refreshed
* based on the token's TTL and the expirationRefreshRatio configuration.
*
* @param token The token to calculate the refresh time for.
* @param now The current time in milliseconds. Defaults to Date.now().
*/
calculateRefreshTime(token, now = Date.now()) {
const ttlMs = token.getTtlMs(now);
return Math.floor(ttlMs * this.config.expirationRefreshRatio);
}
stop() {
if (this.refreshTimeout) {
clearTimeout(this.refreshTimeout);
this.refreshTimeout = null;
}
this.listener = null;
this.currentToken = null;
this.retryAttempt = 0;
}
/**
* Returns the current token or null if no token is available.
*/
getCurrentToken() {
return this.currentToken;
}
notifyError(error, isRetryable) {
const errorMessage = error instanceof Error ? error.message : String(error);
if (!this.listener) {
throw new Error(`TokenManager is not running but received an error: ${errorMessage}`);
}
this.listener.onError(new IDPError(errorMessage, isRetryable));
}
}
exports.TokenManager = TokenManager;
//# sourceMappingURL=token-manager.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"token-manager.js","sourceRoot":"","sources":["../../../lib/authx/token-manager.ts"],"names":[],"mappings":"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"}

15
node_modules/@redis/client/dist/lib/authx/token.d.ts generated vendored Normal file
View File

@@ -0,0 +1,15 @@
/**
* A token that can be used to authenticate with a service.
*/
export declare class Token<T> {
readonly value: T;
readonly expiresAtMs: number;
readonly receivedAtMs: number;
constructor(value: T, expiresAtMs: number, receivedAtMs: number);
/**
* Returns the time-to-live of the token in milliseconds.
* @param now The current time in milliseconds since the Unix epoch.
*/
getTtlMs(now: number): number;
}
//# sourceMappingURL=token.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../../lib/authx/token.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,KAAK,CAAC,CAAC;aAEA,KAAK,EAAE,CAAC;aAER,WAAW,EAAE,MAAM;aAEnB,YAAY,EAAE,MAAM;gBAJpB,KAAK,EAAE,CAAC,EAER,WAAW,EAAE,MAAM,EAEnB,YAAY,EAAE,MAAM;IAGtC;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;CAM9B"}

32
node_modules/@redis/client/dist/lib/authx/token.js generated vendored Normal file
View File

@@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Token = void 0;
/**
* A token that can be used to authenticate with a service.
*/
class Token {
value;
expiresAtMs;
receivedAtMs;
constructor(value,
//represents the token deadline - the time in milliseconds since the Unix epoch at which the token expires
expiresAtMs,
//represents the time in milliseconds since the Unix epoch at which the token was received
receivedAtMs) {
this.value = value;
this.expiresAtMs = expiresAtMs;
this.receivedAtMs = receivedAtMs;
}
/**
* Returns the time-to-live of the token in milliseconds.
* @param now The current time in milliseconds since the Unix epoch.
*/
getTtlMs(now) {
if (this.expiresAtMs < now) {
return 0;
}
return this.expiresAtMs - now;
}
}
exports.Token = Token;
//# sourceMappingURL=token.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"token.js","sourceRoot":"","sources":["../../../lib/authx/token.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,MAAa,KAAK;IAEE;IAEA;IAEA;IALlB,YACkB,KAAQ;IACxB,0GAA0G;IAC1F,WAAmB;IACnC,0FAA0F;IAC1E,YAAoB;QAJpB,UAAK,GAAL,KAAK,CAAG;QAER,gBAAW,GAAX,WAAW,CAAQ;QAEnB,iBAAY,GAAZ,YAAY,CAAQ;IACnC,CAAC;IAEJ;;;OAGG;IACH,QAAQ,CAAC,GAAW;QAClB,IAAI,IAAI,CAAC,WAAW,GAAG,GAAG,EAAE,CAAC;YAC3B,OAAO,CAAC,CAAC;QACX,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC;IAChC,CAAC;CACF;AAnBD,sBAmBC"}