"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var network_exports = {};
__export(network_exports, {
  NET_DEFAULT_TIMEOUT: () => NET_DEFAULT_TIMEOUT,
  createHttp2Server: () => createHttp2Server,
  createHttpServer: () => createHttpServer,
  createHttpsServer: () => createHttpsServer,
  createProxyAgent: () => createProxyAgent,
  fetchData: () => fetchData,
  httpRequest: () => httpRequest,
  isURLAvailable: () => isURLAvailable
});
module.exports = __toCommonJS(network_exports);
var import_http = __toESM(require("http"));
var import_http2 = __toESM(require("http2"));
var import_https = __toESM(require("https"));
var import_url = __toESM(require("url"));
var import_utilsBundle = require("../../utilsBundle");
var import_happyEyeballs = require("./happyEyeballs");
const NET_DEFAULT_TIMEOUT = 3e4;
function httpRequest(params, onResponse, onError) {
  const parsedUrl = import_url.default.parse(params.url);
  let options = {
    ...parsedUrl,
    agent: parsedUrl.protocol === "https:" ? import_happyEyeballs.httpsHappyEyeballsAgent : import_happyEyeballs.httpHappyEyeballsAgent,
    method: params.method || "GET",
    headers: params.headers
  };
  if (params.rejectUnauthorized !== void 0)
    options.rejectUnauthorized = params.rejectUnauthorized;
  const proxyURL = (0, import_utilsBundle.getProxyForUrl)(params.url);
  if (proxyURL) {
    const parsedProxyURL = import_url.default.parse(proxyURL);
    if (params.url.startsWith("http:")) {
      options = {
        path: parsedUrl.href,
        host: parsedProxyURL.hostname,
        port: parsedProxyURL.port,
        headers: options.headers,
        method: options.method
      };
    } else {
      parsedProxyURL.secureProxy = parsedProxyURL.protocol === "https:";
      options.agent = new import_utilsBundle.HttpsProxyAgent(parsedProxyURL);
      options.rejectUnauthorized = false;
    }
  }
  let cancelRequest;
  const requestCallback = (res) => {
    const statusCode = res.statusCode || 0;
    if (statusCode >= 300 && statusCode < 400 && res.headers.location) {
      request.destroy();
      cancelRequest = httpRequest({ ...params, url: new URL(res.headers.location, params.url).toString() }, onResponse, onError).cancel;
    } else {
      onResponse(res);
    }
  };
  const request = options.protocol === "https:" ? import_https.default.request(options, requestCallback) : import_http.default.request(options, requestCallback);
  request.on("error", onError);
  if (params.socketTimeout !== void 0) {
    request.setTimeout(params.socketTimeout, () => {
      onError(new Error(`Request to ${params.url} timed out after ${params.socketTimeout}ms`));
      request.abort();
    });
  }
  cancelRequest = (e) => request.destroy(e);
  request.end(params.data);
  return { cancel: (e) => cancelRequest(e) };
}
function fetchData(progress, params, onError) {
  const promise = new Promise((resolve, reject) => {
    const { cancel } = httpRequest(params, async (response) => {
      if (response.statusCode !== 200) {
        const error = onError ? await onError(params, response) : new Error(`fetch failed: server returned code ${response.statusCode}. URL: ${params.url}`);
        reject(error);
        return;
      }
      let body = "";
      response.on("data", (chunk) => body += chunk);
      response.on("error", (error) => reject(error));
      response.on("end", () => resolve(body));
    }, reject);
    progress?.cleanupWhenAborted(cancel);
  });
  return progress ? progress.race(promise) : promise;
}
function shouldBypassProxy(url2, bypass) {
  if (!bypass)
    return false;
  const domains = bypass.split(",").map((s) => {
    s = s.trim();
    if (!s.startsWith("."))
      s = "." + s;
    return s;
  });
  const domain = "." + url2.hostname;
  return domains.some((d) => domain.endsWith(d));
}
function createProxyAgent(proxy, forUrl) {
  if (!proxy)
    return;
  if (forUrl && proxy.bypass && shouldBypassProxy(forUrl, proxy.bypass))
    return;
  let proxyServer = proxy.server.trim();
  if (!/^\w+:\/\//.test(proxyServer))
    proxyServer = "http://" + proxyServer;
  const proxyOpts = import_url.default.parse(proxyServer);
  if (proxyOpts.protocol?.startsWith("socks")) {
    return new import_utilsBundle.SocksProxyAgent({
      host: proxyOpts.hostname,
      port: proxyOpts.port || void 0
    });
  }
  if (proxy.username)
    proxyOpts.auth = `${proxy.username}:${proxy.password || ""}`;
  if (forUrl && ["ws:", "wss:"].includes(forUrl.protocol)) {
    return new import_utilsBundle.HttpsProxyAgent(proxyOpts);
  }
  return new import_utilsBundle.HttpsProxyAgent(proxyOpts);
}
function createHttpServer(...args) {
  const server = import_http.default.createServer(...args);
  decorateServer(server);
  return server;
}
function createHttpsServer(...args) {
  const server = import_https.default.createServer(...args);
  decorateServer(server);
  return server;
}
function createHttp2Server(...args) {
  const server = import_http2.default.createSecureServer(...args);
  decorateServer(server);
  return server;
}
async function isURLAvailable(url2, ignoreHTTPSErrors, onLog, onStdErr) {
  let statusCode = await httpStatusCode(url2, ignoreHTTPSErrors, onLog, onStdErr);
  if (statusCode === 404 && url2.pathname === "/") {
    const indexUrl = new URL(url2);
    indexUrl.pathname = "/index.html";
    statusCode = await httpStatusCode(indexUrl, ignoreHTTPSErrors, onLog, onStdErr);
  }
  return statusCode >= 200 && statusCode < 404;
}
async function httpStatusCode(url2, ignoreHTTPSErrors, onLog, onStdErr) {
  return new Promise((resolve) => {
    onLog?.(`HTTP GET: ${url2}`);
    httpRequest({
      url: url2.toString(),
      headers: { Accept: "*/*" },
      rejectUnauthorized: !ignoreHTTPSErrors
    }, (res) => {
      res.resume();
      const statusCode = res.statusCode ?? 0;
      onLog?.(`HTTP Status: ${statusCode}`);
      resolve(statusCode);
    }, (error) => {
      if (error.code === "DEPTH_ZERO_SELF_SIGNED_CERT")
        onStdErr?.(`[WebServer] Self-signed certificate detected. Try adding ignoreHTTPSErrors: true to config.webServer.`);
      onLog?.(`Error while checking if ${url2} is available: ${error.message}`);
      resolve(0);
    });
  });
}
function decorateServer(server) {
  const sockets = /* @__PURE__ */ new Set();
  server.on("connection", (socket) => {
    sockets.add(socket);
    socket.once("close", () => sockets.delete(socket));
  });
  const close = server.close;
  server.close = (callback) => {
    for (const socket of sockets)
      socket.destroy();
    sockets.clear();
    return close.call(server, callback);
  };
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  NET_DEFAULT_TIMEOUT,
  createHttp2Server,
  createHttpServer,
  createHttpsServer,
  createProxyAgent,
  fetchData,
  httpRequest,
  isURLAvailable
});
