<NME> base-scraper.ts
<BEF> import { EventEmitter } from 'events';

import { SCRAPE_PROGRESS_TYPES, LOGIN_RESULT, ERRORS } from '../constants';

const SCRAPE_PROGRESS = 'SCRAPE_PROGRESS';


export enum ScraperErrorTypes {
  InvalidPassword ='INVALID_PASSWORD',
  ChangePassword = 'CHANGE_PASSWORD',
  Timeout = 'TIMEOUT',
  AccountBlocked = 'ACCOUNT_BLOCKED',
  Generic = 'GENERIC',
  General = 'GENERAL_ERROR'
}

export interface ScaperLoginResult {
  success: boolean;
function createGenericError(errorMessage) {
  return createErrorResult(ERRORS.GENERIC, errorMessage);
}

class BaseScraper {
  constructor(options) {
    this.options = options;
    this.eventEmitter = new EventEmitter();
  }

  async initialize() {

export interface ScraperOptions {
  /**
   * The company you want to scrape
   */
  companyId: CompanyTypes;

  /**
    try {
      loginResult = await this.login(credentials);
    } catch (e) {
      loginResult = e.timeout ?
        createTimeoutError(e.message) :
        createGenericError(e.message);
    }
  startDate: Date;

  /**
   * shows the browser while scraping, good for debugging (default false)
        scrapeResult = await this.fetchData();
      } catch (e) {
        scrapeResult =
          e.timeout ?
            createTimeoutError(e.message) :
            createGenericError(e.message);
      }
  futureMonthsToScrape?: number;

  /**
   * option from init puppeteer browser instance outside the libary scope. you can get
   * browser diretly from puppeteer via `puppeteer.launch()`
   */
  browser?: any;

  /**
   * provide a patch to local chromium to be used by puppeteer. Relevant when using
   * `israeli-bank-scrapers-core` library
    return scrapeResult;
  }

  async login() {
    throw new Error(`login() is not created in ${this.options.companyId}`);
  }

  async fetchData() {
    throw new Error(`fetchData() is not created in ${this.options.companyId}`);
  }

   * https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options
   * https://peter.sh/experiments/chromium-command-line-switches/
   */
  args?: string[];

  /**
   * Maximum navigation time in milliseconds, pass 0 to disable timeout.
   * @default 30000
   */
  timeout?: number | undefined;

  /**
   * adjust the browser instance before it is being used
   *
  }
}

export { BaseScraper, LOGIN_RESULT };
  /**
   * adjust the page instance before it is being used.
   *
   * @param page
   */
  preparePage?: (page: Page) => Promise<void>;

  /**
   * if set, store a screenshot if failed to scrape. Used for debug purposes
   */
  storeFailureScreenShotPath?: string;

  /**
   * if set, will set the timeout in milliseconds of puppeteer's `page.setDefaultTimeout`.
   */
  defaultTimeout?: number;
}

export enum ScaperProgressTypes {
  Initializing = 'INITIALIZING',
  StartScraping = 'START_SCRAPING',
  LoggingIn = 'LOGGING_IN',
  LoginSuccess = 'LOGIN_SUCCESS',
  LoginFailed = 'LOGIN_FAILED',
  ChangePassword = 'CHANGE_PASSWORD',
  EndScraping = 'END_SCRAPING',
  Terminating = 'TERMINATING',
}

function createErrorResult(errorType: ScraperErrorTypes, errorMessage: string) {
  return {
    success: false,
    errorType,
    errorMessage,
  };
}

function createTimeoutError(errorMessage: string) {
  return createErrorResult(ScraperErrorTypes.Timeout, errorMessage);
}

function createGenericError(errorMessage: string) {
  return createErrorResult(ScraperErrorTypes.Generic, errorMessage);
}

export class BaseScraper {
  private eventEmitter = new EventEmitter();

  constructor(public options: ScraperOptions) {
  }

  // eslint-disable-next-line  @typescript-eslint/require-await
  async initialize() {
    this.emitProgress(ScaperProgressTypes.Initializing);
    moment.tz.setDefault('Asia/Jerusalem');
  }

  async scrape(credentials: ScraperCredentials): Promise<ScaperScrapingResult> {
    this.emitProgress(ScaperProgressTypes.StartScraping);
    await this.initialize();

    let loginResult;
    try {
      loginResult = await this.login(credentials);
    } catch (e) {
      loginResult = e instanceof TimeoutError ?
        createTimeoutError(e.message) :
        createGenericError(e.message);
    }

    let scrapeResult;
    if (loginResult.success) {
      try {
        scrapeResult = await this.fetchData();
      } catch (e) {
        scrapeResult =
          e instanceof TimeoutError ?
            createTimeoutError(e.message) :
            createGenericError(e.message);
      }
    } else {
      scrapeResult = loginResult;
    }

    try {
      const success = scrapeResult && scrapeResult.success === true;
      await this.terminate(success);
    } catch (e) {
      scrapeResult = createGenericError(e.message);
    }
    this.emitProgress(ScaperProgressTypes.EndScraping);

    return scrapeResult;
  }

  // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/require-await
  async login(_credentials: Record<string, string>): Promise<ScaperLoginResult> {
    throw new Error(`login() is not created in ${this.options.companyId}`);
  }

  // eslint-disable-next-line  @typescript-eslint/require-await
  async fetchData(): Promise<ScaperScrapingResult> {
    throw new Error(`fetchData() is not created in ${this.options.companyId}`);
  }

  // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/require-await
  async terminate(_success: boolean) {
    this.emitProgress(ScaperProgressTypes.Terminating);
  }

  emitProgress(type: ScaperProgressTypes) {
    this.emit(SCRAPE_PROGRESS, { type });
  }

  emit(eventName: string, payload: Record<string, any>) {
    this.eventEmitter.emit(eventName, this.options.companyId, payload);
  }

  onProgress(func: (...args: any[]) => void) {
    this.eventEmitter.on(SCRAPE_PROGRESS, func);
  }
}

<MSG> update scrapers to use new enums

<DFF> @@ -1,6 +1,8 @@
 import { EventEmitter } from 'events';
 
-import { SCRAPE_PROGRESS_TYPES, LOGIN_RESULT, ERRORS } from '../constants';
+import { SCRAPE_PROGRESS_TYPES, LoginResults, ERRORS } from '../constants';
+import { TimeoutError } from '@core/waiting';
+import { LegacyLoginResult, LegacyScrapingResult } from '../types';
 
 const SCRAPE_PROGRESS = 'SCRAPE_PROGRESS';
 
@@ -19,11 +21,20 @@ function createTimeoutError(errorMessage) {
 function createGenericError(errorMessage) {
   return createErrorResult(ERRORS.GENERIC, errorMessage);
 }
+// TODO es consider browser type
+export interface BaseScraperOptions {
+  companyId: string;
+  verbose: boolean;
+  startDate: Date;
+  showBrowser: boolean;
+  browser: any;
+  executablePath?: string;
+}
 
 class BaseScraper {
-  constructor(options) {
-    this.options = options;
-    this.eventEmitter = new EventEmitter();
+  private eventEmitter = new EventEmitter();
+
+  constructor(public options: BaseScraperOptions) {
   }
 
   async initialize() {
@@ -38,7 +49,7 @@ class BaseScraper {
     try {
       loginResult = await this.login(credentials);
     } catch (e) {
-      loginResult = e.timeout ?
+      loginResult = e instanceof TimeoutError ?
         createTimeoutError(e.message) :
         createGenericError(e.message);
     }
@@ -49,7 +60,7 @@ class BaseScraper {
         scrapeResult = await this.fetchData();
       } catch (e) {
         scrapeResult =
-          e.timeout ?
+          e instanceof TimeoutError  ?
             createTimeoutError(e.message) :
             createGenericError(e.message);
       }
@@ -67,11 +78,11 @@ class BaseScraper {
     return scrapeResult;
   }
 
-  async login() {
+  async login(credentials: Record<string, string>): Promise<LegacyLoginResult> {
     throw new Error(`login() is not created in ${this.options.companyId}`);
   }
 
-  async fetchData() {
+  async fetchData(): Promise<LegacyScrapingResult> {
     throw new Error(`fetchData() is not created in ${this.options.companyId}`);
   }
 
@@ -92,4 +103,4 @@ class BaseScraper {
   }
 }
 
-export { BaseScraper, LOGIN_RESULT };
+export { BaseScraper, LoginResults };

update scrapers to use new enums