coveo-search-ui
Version: 
Coveo JavaScript Search Framework
81 lines (69 loc) • 2.54 kB
text/typescript
import { Logger } from '../misc/Logger';
import { debounce } from 'underscore';
export type onTokenRefreshed = (newToken: string) => void;
export enum ACCESS_TOKEN_ERRORS {
  NO_RENEW_FUNCTION = 'NO_RENEW_FUNCTION',
  REPEATED_FAILURES = 'REPEATED_FAILURES'
}
export class AccessToken {
  private subscribers: onTokenRefreshed[] = [];
  private logger: Logger = new Logger(this);
  private triedRenewals: number = 0;
  private resetRenewalTriesAfterDelay;
  constructor(public token: string, public renew?: () => Promise<string>) {
    this.resetRenewalTriesAfterDelay = debounce(
      () => {
        this.triedRenewals = 0;
      },
      500,
      false
    );
  }
  public updateToken(token: string) {
    this.token = token;
    this.notifySubscribers();
  }
  public async doRenew(onError?: (error: Error) => void): Promise<Boolean> {
    this.triedRenewals++;
    this.resetRenewalTriesAfterDelay();
    try {
      this.verifyRenewSetup();
      this.logger.info('Renewing expired access token');
      this.token = await this.renew();
      this.logger.info('Access token renewed', this.token);
      this.notifySubscribers();
      return true;
    } catch (err) {
      switch (err.message) {
        case ACCESS_TOKEN_ERRORS.REPEATED_FAILURES:
          this.logger.error('AccessToken tried to renew itself extremely fast in a short period of time');
          this.logger.error('There is most probably an authentication error, or a bad implementation of the custom renew function');
          this.logger.error('Inspect the developer console of your browser to find out the root cause');
          break;
        case ACCESS_TOKEN_ERRORS.NO_RENEW_FUNCTION:
          this.logger.error(`AccessToken tried to renew, but no function is configured on initialization to provide acess token renewal`);
          this.logger.error('The option name is renewAccessToken on the SearchEndpoint class');
          break;
      }
      this.logger.error('Failed to renew access token', err);
      if (onError) {
        onError(err);
      }
      return false;
    }
  }
  public subscribeToRenewal(onTokenRefreshed: onTokenRefreshed) {
    this.subscribers.push(onTokenRefreshed);
  }
  private verifyRenewSetup() {
    if (this.renew == null) {
      throw new Error(ACCESS_TOKEN_ERRORS.NO_RENEW_FUNCTION);
    }
    if (this.triedRenewals >= 5) {
      throw new Error(ACCESS_TOKEN_ERRORS.REPEATED_FAILURES);
    }
  }
  private notifySubscribers() {
    this.subscribers.forEach(subscriber => subscriber(this.token));
  }
}