import { serializeError as serializeError$1, deserializeError as deserializeError$1 } from 'serialize-error';

function isError(value) {
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
    return false;
  }
  const maybe = value;
  if (typeof maybe.name !== "string" || maybe.name === "") {
    return false;
  }
  if (typeof maybe.message !== "string") {
    return false;
  }
  return true;
}
function assertError(value) {
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
    throw new Error(`Encountered invalid error, not an object, got '${value}'`);
  }
  const maybe = value;
  if (typeof maybe.name !== "string" || maybe.name === "") {
    throw new Error(`Encountered error object without a name, got '${value}'`);
  }
  if (typeof maybe.message !== "string") {
    throw new Error(
      `Encountered error object without a message, got '${value}'`
    );
  }
}

function serializeError(error, options) {
  const serialized = serializeError$1(error);
  const result = {
    name: "Unknown",
    message: "<no reason given>",
    ...serialized
  };
  if (!(options == null ? void 0 : options.includeStack)) {
    delete result.stack;
  }
  return result;
}
function deserializeError(data) {
  const result = deserializeError$1(data);
  if (!data.stack) {
    result.stack = void 0;
  }
  return result;
}
function stringifyError(error) {
  if (isError(error)) {
    const str = String(error);
    return str !== "[object Object]" ? str : `${error.name}: ${error.message}`;
  }
  return `unknown error '${error}'`;
}

var __defProp$2 = Object.defineProperty;
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField$2 = (obj, key, value) => {
  __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
  return value;
};
class CustomErrorBase extends Error {
  constructor(message, cause) {
    var _a;
    let fullMessage = message;
    if (cause !== void 0) {
      const causeStr = stringifyError(cause);
      if (fullMessage) {
        fullMessage += `; caused by ${causeStr}`;
      } else {
        fullMessage = `caused by ${causeStr}`;
      }
    }
    super(fullMessage);
    /**
     * An inner error that caused this error to be thrown, if any.
     */
    __publicField$2(this, "cause");
    (_a = Error.captureStackTrace) == null ? void 0 : _a.call(Error, this, this.constructor);
    if (!this.name || this.name === "Error") {
      const baseName = this.constructor.name;
      if (baseName !== "Error") {
        this.name = this.constructor.name;
      }
    }
    this.cause = isError(cause) ? cause : void 0;
  }
}

var __defProp$1 = Object.defineProperty;
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField$1 = (obj, key, value) => {
  __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
  return value;
};
class InputError extends CustomErrorBase {
  constructor() {
    super(...arguments);
    __publicField$1(this, "name", "InputError");
  }
}
class AuthenticationError extends CustomErrorBase {
  constructor() {
    super(...arguments);
    __publicField$1(this, "name", "AuthenticationError");
  }
}
class NotAllowedError extends CustomErrorBase {
  constructor() {
    super(...arguments);
    __publicField$1(this, "name", "NotAllowedError");
  }
}
class NotFoundError extends CustomErrorBase {
  constructor() {
    super(...arguments);
    __publicField$1(this, "name", "NotFoundError");
  }
}
class ConflictError extends CustomErrorBase {
  constructor() {
    super(...arguments);
    __publicField$1(this, "name", "ConflictError");
  }
}
class NotModifiedError extends CustomErrorBase {
  constructor() {
    super(...arguments);
    __publicField$1(this, "name", "NotModifiedError");
  }
}
class NotImplementedError extends CustomErrorBase {
  constructor() {
    super(...arguments);
    __publicField$1(this, "name", "NotImplementedError");
  }
}
class ServiceUnavailableError extends CustomErrorBase {
}
class ForwardedError extends CustomErrorBase {
  constructor(message, cause) {
    super(message, cause);
    this.name = isError(cause) ? cause.name : "Error";
  }
}

async function parseErrorResponseBody(response) {
  var _a;
  try {
    const text = await response.text();
    if (text) {
      if ((_a = response.headers.get("content-type")) == null ? void 0 : _a.startsWith("application/json")) {
        try {
          const body = JSON.parse(text);
          if (body.error && body.response) {
            return body;
          }
        } catch {
        }
      }
      return {
        error: {
          name: "Error",
          message: `Request failed with status ${response.status} ${response.statusText}, ${text}`
        },
        response: {
          statusCode: response.status
        }
      };
    }
  } catch {
  }
  return {
    error: {
      name: "Error",
      message: `Request failed with status ${response.status} ${response.statusText}`
    },
    response: {
      statusCode: response.status
    }
  };
}

var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  return value;
};
class ResponseError extends Error {
  constructor(props) {
    super(props.message);
    /**
     * The actual response, as seen by the client.
     *
     * Note that the body of this response is always consumed. Its parsed form is
     * in the `body` field.
     */
    __publicField(this, "response");
    /**
     * The parsed JSON error body, as sent by the server.
     */
    __publicField(this, "body");
    /**
     * The Error cause, as seen by the remote server. This is parsed out of the
     * JSON error body.
     *
     * This error always has the plain Error constructor, however all
     * serializable enumerable fields on the remote error including its name are
     * preserved. Therefore, if you want to check the error type, use its name
     * property rather than checking typeof or its constructor or prototype.
     */
    __publicField(this, "cause");
    this.name = "ResponseError";
    this.response = props.response;
    this.body = props.data;
    this.cause = props.cause;
  }
  /**
   * Constructs a ResponseError based on a failed response.
   *
   * Assumes that the response has already been checked to be not ok. This
   * function consumes the body of the response, and assumes that it hasn't
   * been consumed before.
   */
  static async fromResponse(response) {
    const data = await parseErrorResponseBody(response);
    const status = data.response.statusCode || response.status;
    const statusText = data.error.name || response.statusText;
    const message = `Request failed with ${status} ${statusText}`;
    const cause = deserializeError(data.error);
    return new ResponseError({
      message,
      response,
      data,
      cause
    });
  }
}

export { AuthenticationError, ConflictError, CustomErrorBase, ForwardedError, InputError, NotAllowedError, NotFoundError, NotImplementedError, NotModifiedError, ResponseError, ServiceUnavailableError, assertError, deserializeError, isError, parseErrorResponseBody, serializeError, stringifyError };
//# sourceMappingURL=index.esm.js.map
