Source: request.js

/** The reviewer API behind https://mangrove.reviews */
export const ORIGINAL_API = 'https://api.mangrove.reviews'

/** The signer behind https://mangrove.reviews */
export const ORIGINAL_SIGNER = 'https://signer.mangrove.reviews'

/** The Fediverse bridge behind https://mangrove.reviews */
export const ORIGINAL_FEDIVERSE = 'https://social.mangrove.reviews'

/**
 * Error for a response a Mangrove server refused.
 * `status` is the HTTP status and `body` the response text, which names the
 * reason, such as the field of a review that is wrong.
 */
export class ApiError extends Error {
  /**
   * @param {number} status
   * @param {string} body
   */
  constructor(status, body) {
    super(
      body
        ? `Request refused with status ${status}: ${body}`
        : `Request refused with status ${status}`
    )
    this.name = 'ApiError'
    this.status = status
    this.body = body
  }
}

/**
 * Fetch a JSON response, or throw an {@link ApiError} for a refused request.
 * An empty body, as in a 204 answer, resolves to null.
 * @param {string} url
 * @param {object} [options]
 * @returns {Promise<any>}
 */
export async function request(url, options = {}) {
  const response = await fetch(url, options)
  const text = await response.text()
  if (!response.ok) {
    throw new ApiError(response.status, text)
  }
  return text ? JSON.parse(text) : null
}