repo_description: A fast, local first, reactive Database for JavaScript Applications https://rxdb.info/
repo_topics: angular browser-database couchdb crdt database firebase graphql indexeddb ionic local-first localstorage nodejs nosql postgres pouchdb react-native realtime realtime-database rxdb sqlite
code: /**
   * here we use custom errors with the additional field 'parameters'
   */
  
  import { overwritable } from './overwritable.ts';
  import type {
      RxErrorParameters,
      RxErrorKey,
      RxStorageWriteError,
      RxStorageWriteErrorConflict
  } from './types/index.d.ts';
  
  /**
   * transform an object of parameters to a presentable string
   */
  function parametersToString(parameters: any): string {
      let ret = '';
      if (Object.keys(parameters).length === 0)
          return ret;
      ret += '-'.repeat(20) + '\n';
      ret += 'Parameters:\n';
      ret += Object.keys(parameters)
          .map(k => {
              let paramStr = '[object Object]';
              try {
                  if (k === 'errors') {
                      paramStr = parameters[k].map((err: any) => JSON.stringify(err, Object.getOwnPropertyNames(err)));
                  } else {
                      paramStr = JSON.stringify(parameters[k], function (_k, v) {
                          return v === undefined ? null : v;
                      }, 2);
                  }
              } catch (e) { }
              return k + ': ' + paramStr;
          })
          .join('\n');
      ret += '\n';
      return ret;
  }
  
  function messageForError(
      message: string,
      code: string,
      parameters: any
  ): string {
      return '' + '\n' +
          message + '\n' +
          parametersToString(parameters);
  }
  
  export class RxError extends Error {
      public code: RxErrorKey;
      public message: string;
      public url: string;
      public parameters: RxErrorParameters;
      // always true, use this to detect if it's an rxdb-error
      public rxdb: true;
      constructor(
          code: RxErrorKey,
          message: string,
          parameters: RxErrorParameters = {}
      ) {
          const mes = messageForError(message, code, parameters);
          super(mes);
          this.code = code;
          this.message = mes;
          this.url = getErrorUrl(code);
          this.parameters = parameters;
          this.rxdb = true; // tag them as internal
      }
      get name(): string {
          return 'RxError (' + this.code + ')';
      }
      toString(): string {
          return this.message;
      }
      get typeError(): boolean {
          return false;
      }
  }
  
  export class RxTypeError extends TypeError {
      public code: RxErrorKey;
      public message: string;
      public url: string;
      public parameters: RxErrorParameters;
      // always true, use this to detect if it's an rxdb-error
      public rxdb: true;
      constructor(
          code: RxErrorKey,
          message: string,
          parameters: RxErrorParameters = {}
      ) {
          const mes = messageForError(message, code, parameters);
          super(mes);
          this.code = code;
          this.message = mes;
          this.url = getErrorUrl(code);
          this.parameters = parameters;
          this.rxdb = true; // tag them as internal
      }
      get name(): string {
          return 'RxTypeError (' + this.code + ')';
      }
      toString(): string {
          return this.message;
      }
      get typeError(): boolean {
          return true;
      }
  }
  
  
  export function getErrorUrl(code: RxErrorKey) {
      return 'https://rxdb.info/errors.html?console=errors#' + code;
  }
  
  export function errorUrlHint(code: RxErrorKey) {
      return '\nFind out more about this error here: ' + getErrorUrl(code) + ' \n';
  }
  
  export function newRxError(
      code: RxErrorKey,
      parameters?: RxErrorParameters
  ): RxError {
      return new RxError(
          code,
          overwritable.tunnelErrorMessage(code) + errorUrlHint(code),
          parameters
      );
  }
  
  export function newRxTypeError(
      code: RxErrorKey,
      parameters?: RxErrorParameters
  ): RxTypeError {
      return new RxTypeError(
          code,
          overwritable.tunnelErrorMessage(code) + errorUrlHint(code),
          parameters
      );
  }
  
  
  /**
   * Returns the error if it is a 409 conflict,
   * return false if it is another error.
   */
  export function isBulkWriteConflictError<RxDocType>(
      err?: RxStorageWriteError<RxDocType> | any
  ): RxStorageWriteErrorConflict<RxDocType> | false {
      if (
          err &&
          err.status === 409
      ) {
          return err;
      } else {
          return false;
      }
  }
  
  
  const STORAGE_WRITE_ERROR_CODE_TO_MESSAGE: { [k: number]: string; } = {
      409: 'document write conflict',
      422: 'schema validation error',
      510: 'attachment data missing'
  };
  
  export function rxStorageWriteErrorToRxError(err: RxStorageWriteError<any>): RxError {
      return newRxError('COL20', {
          name: STORAGE_WRITE_ERROR_CODE_TO_MESSAGE[err.status],
          document: err.documentId,
          writeError: err
      });
  }
  
  export async function newRxFetchError(
      input: Response,
      additionalParameters?: RxErrorParameters
  ): Promise<RxError> {
      const errorText = await input.text().catch(() => '');
      const parameters: RxErrorParameters = {
          ...additionalParameters,
          ...(input.url ? { url: input.url } : {}),
          ...(input.status ? { status: input.status } : {}),
          ...(input.statusText ? { statusText: input.statusText } : {}),
          ...(errorText ? { errorText } : {})
      };
      return newRxError('FETCH', parameters);
  }
  