async function requestLocalFile(url, options = {}) {
  // only GET method is allowed for local files
  // headers is meaningless
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    /** @type {VMReq.Response} */
    const result = {
      headers: {
        get: name => xhr.getResponseHeader(name),
      },
      url,
    };
    const { [kResponseType]: responseType } = options;
    xhr.open('GET', url, true);
    if (binaryTypes.includes(responseType)) xhr[kResponseType] = responseType;
    xhr.onload = () => {
      // status for `file:` protocol will always be `0`
      result.status = xhr.status || 200;
      result.data = xhr[binaryTypes.includes(responseType) ? kResponse : kResponseText];
      if (responseType === 'json') {
        try {
          result.data = JSON.parse(result.data);
        } catch {
          // ignore invalid JSON
        }
      }
      resolve(result);
    };
    xhr.onerror = () => {
      result.status = -1;
      reject(result);
    };
    xhr.send();
  });
}
@param {string} url
@param {VMReq.Options} options
@return {Promise<VMReq.Response>}