async function request(url, options = {}) {
  // fetch supports file:// since Chrome 99 but we use XHR for consistency
  if (url.startsWith('file:')) return requestLocalFile(url, options);
  const { body, headers, [kResponseType]: responseType } = options;
  const isBodyObj = body && body::({}).toString() === '[object Object]';
  const [, scheme, auth, hostname, urlTail] = url.match(/^([-\w]+:\/\/)([^@/]*@)?([^/]*)(.*)|$/);
  // Avoiding LINK header prefetch of js in 404 pages which cause CSP violations in our console
  // TODO: toggle a webRequest/declarativeNetRequest rule to strip LINK headers
  const accept = (hostname === 'greasyfork.org' || hostname === 'sleazyfork.org')
    && 'application/javascript, text/plain, text/css';
  const init = Object.assign({}, !isRemote(url) && NO_CACHE, options, {
    body: isBodyObj ? JSON.stringify(body) : body,
    headers: isBodyObj || accept || auth
      ? Object.assign({},
        headers,
        isBodyObj && { 'Content-Type': 'application/json' },
        auth && { Authorization: `Basic ${btoa(decodeURIComponent(auth.slice(0, -1)))}` },
        accept && { accept })
      : headers,
  });
  let result = { url, status: -1 };
  try {
    const urlNoAuth = auth ? scheme + hostname + urlTail : url;
    const resp = await fetch(urlNoAuth, init);
    const loadMethod = {
      arraybuffer: 'arrayBuffer',
      blob: 'blob',
      json: 'json',
    }[responseType] || 'text';
    // status for `file:` protocol will always be `0`
    result.status = resp.status || 200;
    result.headers = resp.headers;
    result.data = await resp[loadMethod]();
  } catch (err) {
    result = Object.assign(err, result);
    result.message += '\n' + url;
  }
  if (result.status < 0 || result.status > 300) throw result;
  return result;
}
Make a request.
@param {string} url
@param {VMReq.Options} options
@return {Promise<VMReq.Response>}