From 3096148746c906105c4424352f5b5ad1bff0fd4f Mon Sep 17 00:00:00 2001
From: Alexander Akait <4567934+alexander-akait@users.noreply.github.com>
Date: Wed, 24 Apr 2024 17:48:41 +0300
Subject: [PATCH] feat: added the `app` option to setup any `connect`
 compatibility HTTP server framework

---
 lib/Server.js                                 | 245 +++--
 lib/options.json                              |   8 +
 package-lock.json                             | 454 ++++++----
 package.json                                  |   9 +-
 scripts/setupTest.js                          |   2 +-
 .../validate-options.test.js.snap.webpack5    |  14 +
 .../allowed-hosts.test.js.snap.webpack5       |  16 +-
 .../__snapshots__/app.test.js.snap.webpack5   | 253 ++++++
 .../built-in-routes.test.js.snap.webpack5     |  10 +-
 test/e2e/app.test.js                          | 103 +++
 test/e2e/on-listening.test.js                 |  18 +-
 test/e2e/setup-middlewares.test.js            |  30 +-
 test/ports-map.js                             |   1 +
 test/server/proxy-option.test.js              |  20 +-
 test/validate-options.test.js                 |  10 +
 types/lib/Server.d.ts                         | 834 +++++++++++++-----
 16 files changed, 1537 insertions(+), 490 deletions(-)
 create mode 100644 test/e2e/__snapshots__/app.test.js.snap.webpack5
 create mode 100644 test/e2e/app.test.js

diff --git a/lib/Server.js b/lib/Server.js
index 88a051d9cf..05c3c0ba82 100644
--- a/lib/Server.js
+++ b/lib/Server.js
@@ -18,9 +18,6 @@ const schema = require("./options.json");
 /** @typedef {import("webpack").Stats} Stats */
 /** @typedef {import("webpack").MultiStats} MultiStats */
 /** @typedef {import("os").NetworkInterfaceInfo} NetworkInterfaceInfo */
-/** @typedef {import("express").NextFunction} NextFunction */
-/** @typedef {import("express").RequestHandler} ExpressRequestHandler */
-/** @typedef {import("express").ErrorRequestHandler} ExpressErrorRequestHandler */
 /** @typedef {import("chokidar").WatchOptions} WatchOptions */
 /** @typedef {import("chokidar").FSWatcher} FSWatcher */
 /** @typedef {import("connect-history-api-fallback").Options} ConnectHistoryApiFallbackOptions */
@@ -37,11 +34,28 @@ const schema = require("./options.json");
 /** @typedef {import("http").IncomingMessage} IncomingMessage */
 /** @typedef {import("http").ServerResponse} ServerResponse */
 /** @typedef {import("open").Options} OpenOptions */
+/** @typedef {import("express").Application} ExpressApplication */
+/** @typedef {import("express").RequestHandler} ExpressRequestHandler */
+/** @typedef {import("express").ErrorRequestHandler} ExpressErrorRequestHandler */
+/** @typedef {import("express").Request} ExpressRequest */
+/** @typedef {import("express").Response} ExpressResponse */
+
+/** @typedef {(err?: any) => void} NextFunction */
+/** @typedef {(req: IncomingMessage, res: ServerResponse) => void} SimpleHandleFunction */
+/** @typedef {(req: IncomingMessage, res: ServerResponse, next: NextFunction) => void} NextHandleFunction */
+/** @typedef {(err: any, req: IncomingMessage, res: ServerResponse, next: NextFunction) => void} ErrorHandleFunction */
+/** @typedef {SimpleHandleFunction | NextHandleFunction | ErrorHandleFunction} HandleFunction */
 
 /** @typedef {import("https").ServerOptions & { spdy?: { plain?: boolean | undefined, ssl?: boolean | undefined, 'x-forwarded-for'?: string | undefined, protocol?: string | undefined, protocols?: string[] | undefined }}} ServerOptions */
 
-/** @typedef {import("express").Request} Request */
-/** @typedef {import("express").Response} Response */
+/**
+ * @template {BasicApplication} [T=ExpressApplication]
+ * @typedef {T extends ExpressApplication ? ExpressRequest : IncomingMessage} Request
+ */
+/**
+ * @template {BasicApplication} [T=ExpressApplication]
+ * @typedef {T extends ExpressApplication ? ExpressResponse : ServerResponse} Response
+ */
 
 /**
  * @template {Request} T
@@ -173,10 +187,16 @@ const schema = require("./options.json");
  */
 
 /**
- * @typedef {{ name?: string, path?: string, middleware: ExpressRequestHandler | ExpressErrorRequestHandler } | ExpressRequestHandler | ExpressErrorRequestHandler} Middleware
+ * @template {BasicApplication} [T=ExpressApplication]
+ * @typedef {T extends ExpressApplication ? ExpressRequestHandler | ExpressErrorRequestHandler : HandleFunction} MiddlewareHandler
+ */
+
+/**
+ * @typedef {{ name?: string, path?: string, middleware: MiddlewareHandler } | MiddlewareHandler } Middleware
  */
 
 /**
+ * @template {BasicApplication} [T=ExpressApplication]
  * @typedef {Object} Configuration
  * @property {boolean | string} [ipc]
  * @property {Host} [host]
@@ -191,16 +211,16 @@ const schema = require("./options.json");
  * @property {string | string[] | WatchFiles | Array<string | WatchFiles>} [watchFiles]
  * @property {boolean | string | Static | Array<string | Static>} [static]
  * @property {boolean | ServerOptions} [https]
- * @property {boolean} [http2]
  * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server]
+ * @property {() => Promise<T>} [app]
  * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer]
  * @property {ProxyConfigArray} [proxy]
  * @property {boolean | string | Open | Array<string | Open>} [open]
  * @property {boolean} [setupExitSignals]
  * @property {boolean | ClientConfiguration} [client]
  * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response>) => Headers)} [headers]
- * @property {(devServer: Server) => void} [onListening]
- * @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares]
+ * @property {(devServer: Server<T>) => void} [onListening]
+ * @property {(middlewares: Middleware[], devServer: Server<T>) => Middleware[]} [setupMiddlewares]
  */
 
 if (!process.env.WEBPACK_SERVE) {
@@ -245,10 +265,45 @@ const encodeOverlaySettings = (setting) =>
     ? encodeURIComponent(setting.toString())
     : setting;
 
+// Working for overload, because typescript doesn't support this yes
+/**
+ * @overload
+ * @param {NextHandleFunction} fn
+ * @returns {BasicApplication}
+ */
+/**
+ * @overload
+ * @param {HandleFunction} fn
+ * @returns {BasicApplication}
+ */
+/**
+ * @overload
+ * @param {string} route
+ * @param {NextHandleFunction} fn
+ * @returns {BasicApplication}
+ */
+/**
+ * @param {string} route
+ * @param {HandleFunction} fn
+ * @returns {BasicApplication}
+ */
+// eslint-disable-next-line no-unused-vars
+function useFn(route, fn) {
+  return /** @type {BasicApplication} */ ({});
+}
+
+/**
+ * @typedef {Object} BasicApplication
+ * @property {typeof useFn} use
+ */
+
+/**
+ * @template {BasicApplication} [T=ExpressApplication]
+ */
 class Server {
   /**
-   * @param {Configuration | Compiler | MultiCompiler} options
-   * @param {Compiler | MultiCompiler | Configuration} compiler
+   * @param {Configuration<T>} options
+   * @param {Compiler | MultiCompiler} compiler
    */
   constructor(options = {}, compiler) {
     validate(/** @type {Schema} */ (schema), options, {
@@ -256,12 +311,12 @@ class Server {
       baseDataPath: "options",
     });
 
-    this.compiler = /** @type {Compiler | MultiCompiler} */ (compiler);
+    this.compiler = compiler;
     /**
      * @type {ReturnType<Compiler["getInfrastructureLogger"]>}
      * */
     this.logger = this.compiler.getInfrastructureLogger("webpack-dev-server");
-    this.options = /** @type {Configuration} */ (options);
+    this.options = options;
     /**
      * @type {FSWatcher[]}
      */
@@ -1670,7 +1725,7 @@ class Server {
     }
 
     this.setupHooks();
-    this.setupApp();
+    await this.setupApp();
     this.setupHostHeaderCheck();
     this.setupDevMiddleware();
     // Should be after `webpack-dev-middleware`, otherwise other middlewares might rewrite response
@@ -1729,11 +1784,14 @@ class Server {
 
   /**
    * @private
-   * @returns {void}
+   * @returns {Promise<void>}
    */
-  setupApp() {
-    /** @type {import("express").Application | undefined}*/
-    this.app = new /** @type {any} */ (getExpress())();
+  async setupApp() {
+    /** @type {T | undefined}*/
+    this.app =
+      typeof this.options.app === "function"
+        ? await this.options.app()
+        : getExpress()();
   }
 
   /**
@@ -1788,29 +1846,22 @@ class Server {
    * @returns {void}
    */
   setupHostHeaderCheck() {
-    /** @type {import("express").Application} */
-    (this.app).all(
-      "*",
-      /**
-       * @param {Request} req
-       * @param {Response} res
-       * @param {NextFunction} next
-       * @returns {void}
-       */
-      (req, res, next) => {
-        if (
-          this.checkHeader(
-            /** @type {{ [key: string]: string | undefined }} */
-            (req.headers),
-            "host",
-          )
-        ) {
-          return next();
-        }
+    /** @type {T} */
+    (this.app).use((req, res, next) => {
+      if (
+        this.checkHeader(
+          /** @type {{ [key: string]: string | undefined }} */
+          (req.headers),
+          "host",
+        )
+      ) {
+        next();
+        return;
+      }
 
-        res.send("Invalid Host header");
-      },
-    );
+      res.statusCode = 403;
+      res.end("Invalid Host header");
+    });
   }
 
   /**
@@ -1834,45 +1885,103 @@ class Server {
   setupBuiltInRoutes() {
     const { app, middleware } = this;
 
-    /** @type {import("express").Application} */
-    (app).get("/__webpack_dev_server__/sockjs.bundle.js", (req, res) => {
-      res.setHeader("Content-Type", "application/javascript");
+    /** @type {T} */
+    (app).use("/__webpack_dev_server__/sockjs.bundle.js", (req, res, next) => {
+      if (req.method !== "GET" && req.method !== "HEAD") {
+        next();
+        return;
+      }
+
+      const clientPath = path.join(
+        __dirname,
+        "..",
+        "client/modules/sockjs-client/index.js",
+      );
+
+      // Express send Etag and other headers by default, so let's keep them for compatibility reasons
+      // @ts-ignore
+      if (typeof res.sendFile === "function") {
+        // @ts-ignore
+        res.sendFile(clientPath);
+        return;
+      }
+
+      let stats;
 
-      const clientPath = path.join(__dirname, "..", "client");
+      try {
+        // TODO implement `inputFileSystem.createReadStream` in webpack
+        stats = fs.statSync(clientPath);
+      } catch (err) {
+        next();
+        return;
+      }
 
-      res.sendFile(path.join(clientPath, "modules/sockjs-client/index.js"));
+      res.setHeader("Content-Type", "application/javascript; charset=UTF-8");
+      res.setHeader("Content-Length", stats.size);
+
+      if (req.method === "HEAD") {
+        res.end();
+        return;
+      }
+
+      fs.createReadStream(clientPath).pipe(res);
     });
 
-    /** @type {import("express").Application} */
-    (app).get("/webpack-dev-server/invalidate", (_req, res) => {
+    /** @type {T} */
+    (app).use("/webpack-dev-server/invalidate", (req, res, next) => {
+      if (req.method !== "GET" && req.method !== "HEAD") {
+        next();
+        return;
+      }
+
       this.invalidate();
 
       res.end();
     });
 
-    /** @type {import("express").Application} */
-    (app).get("/webpack-dev-server/open-editor", (req, res) => {
-      const fileName = req.query.fileName;
+    /** @type {T} */
+    (app).use("/webpack-dev-server/open-editor", (req, res, next) => {
+      if (req.method !== "GET" && req.method !== "HEAD") {
+        next();
+        return;
+      }
+
+      if (!req.url) {
+        next();
+        return;
+      }
+
+      const resolveUrl = new URL(req.url, `http://${req.headers.host}`);
+      const params = new URLSearchParams(resolveUrl.search);
+      const fileName = params.get("fileName");
 
       if (typeof fileName === "string") {
         // @ts-ignore
         const launchEditor = require("launch-editor");
+
         launchEditor(fileName);
       }
 
       res.end();
     });
 
-    /** @type {import("express").Application} */
-    (app).get("/webpack-dev-server", (req, res) => {
+    /** @type {T} */
+    (app).use("/webpack-dev-server", (req, res, next) => {
+      if (req.method !== "GET" && req.method !== "HEAD") {
+        next();
+        return;
+      }
+
       /** @type {import("webpack-dev-middleware").API<Request, Response>}*/
       (middleware).waitUntilValid((stats) => {
-        res.setHeader("Content-Type", "text/html");
+        res.setHeader("Content-Type", "text/html; charset=utf-8");
+
         // HEAD requests should not return body content
         if (req.method === "HEAD") {
           res.end();
           return;
         }
+
         res.write(
           '<!DOCTYPE html><html><head><meta charset="utf-8"/></head><body>',
         );
@@ -1975,7 +2084,6 @@ class Server {
     if (typeof this.options.headers !== "undefined") {
       middlewares.push({
         name: "set-headers",
-        path: "*",
         middleware: this.setHeaders.bind(this),
       });
     }
@@ -2104,8 +2212,8 @@ class Server {
 
           if (typeof bypassUrl === "boolean") {
             // skip the proxy
-            // @ts-ignore
-            req.url = null;
+            res.statusCode = 404;
+            req.url = "";
             next();
           } else if (typeof bypassUrl === "string") {
             // byPass to that url
@@ -2255,7 +2363,6 @@ class Server {
     // fallback when no other middleware responses.
     middlewares.push({
       name: "options-middleware",
-      path: "*",
       /**
        * @param {Request} req
        * @param {Response} res
@@ -2279,14 +2386,24 @@ class Server {
 
     middlewares.forEach((middleware) => {
       if (typeof middleware === "function") {
-        /** @type {import("express").Application} */
-        (this.app).use(middleware);
+        /** @type {T} */
+        (this.app).use(
+          /** @type {NextHandleFunction | HandleFunction} */
+          (middleware),
+        );
       } else if (typeof middleware.path !== "undefined") {
-        /** @type {import("express").Application} */
-        (this.app).use(middleware.path, middleware.middleware);
+        /** @type {T} */
+        (this.app).use(
+          middleware.path,
+          /** @type {SimpleHandleFunction | NextHandleFunction} */
+          (middleware.middleware),
+        );
       } else {
-        /** @type {import("express").Application} */
-        (this.app).use(middleware.middleware);
+        /** @type {T} */
+        (this.app).use(
+          /** @type {NextHandleFunction | HandleFunction} */
+          (middleware.middleware),
+        );
       }
     });
   }
@@ -2794,7 +2911,7 @@ class Server {
         headers = headers(
           req,
           res,
-          /** @type {import("webpack-dev-middleware").API<IncomingMessage, ServerResponse>}*/
+          /** @type {import("webpack-dev-middleware").API<Request, Response>}*/
           (this.middleware).context,
         );
       }
diff --git a/lib/options.json b/lib/options.json
index 567245ce4c..0951aefbcf 100644
--- a/lib/options.json
+++ b/lib/options.json
@@ -2,6 +2,11 @@
   "title": "Dev Server options",
   "type": "object",
   "definitions": {
+    "App": {
+      "instanceof": "Function",
+      "description": "Allows to use custom applications (i.e. 'connect', 'fastify' and etc).",
+      "link": " https://webpack.js.org/configuration/dev-server/#devserverapp"
+    },
     "AllowedHosts": {
       "anyOf": [
         {
@@ -997,6 +1002,9 @@
     "server": {
       "$ref": "#/definitions/Server"
     },
+    "app": {
+      "$ref": "#/definitions/App"
+    },
     "setupExitSignals": {
       "$ref": "#/definitions/SetupExitSignals"
     },
diff --git a/package-lock.json b/package-lock.json
index 76ed88542a..2dd73df4f8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -62,9 +62,10 @@
         "babel-jest": "^29.5.0",
         "babel-loader": "^9.1.0",
         "body-parser": "^1.19.2",
+        "connect": "^3.7.0",
         "core-js": "^3.31.0",
         "cspell": "^8.3.2",
-        "css-loader": "^6.8.1",
+        "css-loader": "^7.1.1",
         "eslint": "^8.43.0",
         "eslint-config-prettier": "^9.1.0",
         "eslint-config-webpack": "^1.2.5",
@@ -83,19 +84,19 @@
         "memfs": "^4.6.0",
         "npm-run-all": "^4.1.5",
         "prettier": "^3.2.4",
-        "puppeteer": "^22.1.0",
+        "puppeteer": "^22.6.5",
         "readable-stream": "^4.5.2",
         "require-from-string": "^2.0.2",
         "rimraf": "^5.0.5",
         "sockjs-client": "^1.6.1",
         "standard-version": "^9.3.0",
         "strip-ansi-v6": "npm:strip-ansi@^6.0.0",
-        "style-loader": "^3.3.1",
+        "style-loader": "^4.0.0",
         "supertest": "^6.1.3",
         "tcp-port-used": "^1.0.2",
         "typescript": "^5.3.3",
         "wait-for-expect": "^3.0.2",
-        "webpack": "^5.89.0",
+        "webpack": "^5.91.0",
         "webpack-cli": "^5.0.1",
         "webpack-merge": "^5.9.0"
       },
@@ -335,9 +336,9 @@
       }
     },
     "node_modules/@babel/helper-define-polyfill-provider": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.1.tgz",
-      "integrity": "sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==",
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz",
+      "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==",
       "dev": true,
       "dependencies": {
         "@babel/helper-compilation-targets": "^7.22.6",
@@ -1942,12 +1943,12 @@
       "dev": true
     },
     "node_modules/@commitlint/cli": {
-      "version": "19.2.2",
-      "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-19.2.2.tgz",
-      "integrity": "sha512-P8cbOHfg2PQRzfICLSrzUVOCVMqjEZ8Hlth6mtJ4yOEjT47Q5PbIGymgX3rLVylNw+3IAT2Djn9IJ2wHbXFzBg==",
+      "version": "19.3.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-19.3.0.tgz",
+      "integrity": "sha512-LgYWOwuDR7BSTQ9OLZ12m7F/qhNY+NpAyPBgo4YNMkACE7lGuUnuQq1yi9hz1KA4+3VqpOYl8H1rY/LYK43v7g==",
       "dev": true,
       "dependencies": {
-        "@commitlint/format": "^19.0.3",
+        "@commitlint/format": "^19.3.0",
         "@commitlint/lint": "^19.2.2",
         "@commitlint/load": "^19.2.0",
         "@commitlint/read": "^19.2.1",
@@ -2097,9 +2098,9 @@
       }
     },
     "node_modules/@commitlint/config-conventional": {
-      "version": "19.1.0",
-      "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-19.1.0.tgz",
-      "integrity": "sha512-KIKD2xrp6Uuk+dcZVj3++MlzIr/Su6zLE8crEDQCZNvWHNQSeeGbzOlNtsR32TUy6H3JbP7nWgduAHCaiGQ6EA==",
+      "version": "19.2.2",
+      "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-19.2.2.tgz",
+      "integrity": "sha512-mLXjsxUVLYEGgzbxbxicGPggDuyWNkf25Ht23owXIH+zV2pv1eJuzLK3t1gDY5Gp6pxdE60jZnWUY5cvgL3ufw==",
       "dev": true,
       "dependencies": {
         "@commitlint/types": "^19.0.3",
@@ -2149,9 +2150,9 @@
       }
     },
     "node_modules/@commitlint/format": {
-      "version": "19.0.3",
-      "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-19.0.3.tgz",
-      "integrity": "sha512-QjjyGyoiVWzx1f5xOteKHNLFyhyweVifMgopozSgx1fGNrGV8+wp7k6n1t6StHdJ6maQJ+UUtO2TcEiBFRyR6Q==",
+      "version": "19.3.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-19.3.0.tgz",
+      "integrity": "sha512-luguk5/aF68HiF4H23ACAfk8qS8AHxl4LLN5oxPc24H+2+JRPsNr1OS3Gaea0CrH7PKhArBMKBz5RX9sA5NtTg==",
       "dev": true,
       "dependencies": {
         "@commitlint/types": "^19.0.3",
@@ -2851,9 +2852,9 @@
       "dev": true
     },
     "node_modules/@cspell/dict-en_us": {
-      "version": "4.3.17",
-      "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.3.17.tgz",
-      "integrity": "sha512-CS0Tb2f2YwQZ4VZ6+WLAO5uOzb0iO/iYSRl34kX4enq6quXxLYzwdfGAwv85wSYHPdga8tGiZFP+p8GPsi2JEg==",
+      "version": "4.3.19",
+      "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.3.19.tgz",
+      "integrity": "sha512-tHcXdkmm0t9LlRct1vgu3+h0KW/wlXCInkTiR4D/rl730q1zu2qVEgiy1saMiTUSNmdu7Hiy+Mhb+1braVqnZQ==",
       "dev": true
     },
     "node_modules/@cspell/dict-en-common-misspellings": {
@@ -3040,9 +3041,9 @@
       "dev": true
     },
     "node_modules/@cspell/dict-software-terms": {
-      "version": "3.3.18",
-      "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-3.3.18.tgz",
-      "integrity": "sha512-LJZGGMGqS8KzgXJrSMs3T+6GoqHG9z8Bc+rqLzLzbtoR3FbsMasE9U8oP2PmS3q7jJLFjQkzmg508DrcuZuo2g==",
+      "version": "3.3.20",
+      "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-3.3.20.tgz",
+      "integrity": "sha512-KmPwCxYWEu7SGyT/0m/n6i6R4ZgxbmN3XcerzA6Z629Wm5iZTVfJaMWqDK2RKAyBawS7OMfxGz0W/wYU4FhJlA==",
       "dev": true
     },
     "node_modules/@cspell/dict-sql": {
@@ -3070,9 +3071,9 @@
       "dev": true
     },
     "node_modules/@cspell/dict-typescript": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.1.2.tgz",
-      "integrity": "sha512-lcNOYWjLUvDZdLa0UMNd/LwfVdxhE9rKA+agZBGjL3lTA3uNvH7IUqSJM/IXhJoBpLLMVEOk8v1N9xi+vDuCdA==",
+      "version": "3.1.4",
+      "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.1.4.tgz",
+      "integrity": "sha512-jUcPa0rsPca5ur1+G56DXnSc5hbbJkzvPHHvyQtkbPXBQd3CXPMNfrTVCgzex/7cY/7FONcpFCUwgwfni9Jqbw==",
       "dev": true
     },
     "node_modules/@cspell/dict-vue": {
@@ -3274,9 +3275,9 @@
       }
     },
     "node_modules/@humanwhocodes/object-schema": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
-      "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+      "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
       "dev": true
     },
     "node_modules/@hutson/parse-repository-url": {
@@ -4266,9 +4267,9 @@
       }
     },
     "node_modules/@leichtgewicht/ip-codec": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
-      "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A=="
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz",
+      "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw=="
     },
     "node_modules/@nicolo-ribaudo/chokidar-2": {
       "version": "2.1.8-no-fsevents.3",
@@ -4332,9 +4333,9 @@
       }
     },
     "node_modules/@puppeteer/browsers": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.0.tgz",
-      "integrity": "sha512-MC7LxpcBtdfTbzwARXIkqGZ1Osn3nnZJlm+i0+VqHl72t//Xwl9wICrXT8BwtgC6s1xJNHsxOpvzISUqe92+sw==",
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.2.tgz",
+      "integrity": "sha512-hZ/JhxPIceWaGSEzUZp83/8M49CoxlkuThfTR7t4AoCu5+ZvJ3vktLm60Otww2TXeROB5igiZ8D9oPQh6ckBVg==",
       "dev": true,
       "dependencies": {
         "debug": "4.3.4",
@@ -4525,9 +4526,9 @@
       "dev": true
     },
     "node_modules/@types/eslint": {
-      "version": "8.56.6",
-      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.6.tgz",
-      "integrity": "sha512-ymwc+qb1XkjT/gfoQwxIeHZ6ixH23A+tCT2ADSA/DPVKzAjwYkTXBMCQ/f6fe4wEa85Lhp26VPeUxI7wMhAi7A==",
+      "version": "8.56.10",
+      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz",
+      "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==",
       "devOptional": true,
       "dependencies": {
         "@types/estree": "*",
@@ -4562,9 +4563,9 @@
       }
     },
     "node_modules/@types/express-serve-static-core": {
-      "version": "4.17.43",
-      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz",
-      "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==",
+      "version": "4.19.0",
+      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz",
+      "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==",
       "dependencies": {
         "@types/node": "*",
         "@types/qs": "*",
@@ -4680,9 +4681,9 @@
       "dev": true
     },
     "node_modules/@types/qs": {
-      "version": "6.9.13",
-      "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.13.tgz",
-      "integrity": "sha512-iLR+1vTTJ3p0QaOUq6ACbY1mzKTODFDT/XedZI8BksOotFmL4ForwDfRQ/DZeuTHR7/2i4lI1D203gdfxuqTlA=="
+      "version": "6.9.15",
+      "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz",
+      "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg=="
     },
     "node_modules/@types/range-parser": {
       "version": "1.2.7",
@@ -5233,15 +5234,16 @@
       "dev": true
     },
     "node_modules/array-includes": {
-      "version": "3.1.7",
-      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz",
-      "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==",
+      "version": "3.1.8",
+      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz",
+      "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.2.0",
-        "es-abstract": "^1.22.1",
-        "get-intrinsic": "^1.2.1",
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2",
+        "es-object-atoms": "^1.0.0",
+        "get-intrinsic": "^1.2.4",
         "is-string": "^1.0.7"
       },
       "engines": {
@@ -5538,13 +5540,13 @@
       }
     },
     "node_modules/babel-plugin-polyfill-corejs2": {
-      "version": "0.4.10",
-      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz",
-      "integrity": "sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==",
+      "version": "0.4.11",
+      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz",
+      "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==",
       "dev": true,
       "dependencies": {
         "@babel/compat-data": "^7.22.6",
-        "@babel/helper-define-polyfill-provider": "^0.6.1",
+        "@babel/helper-define-polyfill-provider": "^0.6.2",
         "semver": "^6.3.1"
       },
       "peerDependencies": {
@@ -5565,12 +5567,12 @@
       }
     },
     "node_modules/babel-plugin-polyfill-regenerator": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.1.tgz",
-      "integrity": "sha512-JfTApdE++cgcTWjsiCQlLyFBMbTUft9ja17saCc93lgV33h4tuCVj7tlvu//qpLwaG+3yEz7/KhahGrUMkVq9g==",
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz",
+      "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==",
       "dev": true,
       "dependencies": {
-        "@babel/helper-define-polyfill-provider": "^0.6.1"
+        "@babel/helper-define-polyfill-provider": "^0.6.2"
       },
       "peerDependencies": {
         "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
@@ -5629,35 +5631,44 @@
       "optional": true
     },
     "node_modules/bare-fs": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.2.2.tgz",
-      "integrity": "sha512-X9IqgvyB0/VA5OZJyb5ZstoN62AzD7YxVGog13kkfYWYqJYcK0kcqLZ6TrmH5qr4/8//ejVcX4x/a0UvaogXmA==",
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.0.tgz",
+      "integrity": "sha512-TNFqa1B4N99pds2a5NYHR15o0ZpdNKbAeKTE/+G6ED/UeOavv8RY3dr/Fu99HW3zU3pXpo2kDNO8Sjsm2esfOw==",
       "dev": true,
       "optional": true,
       "dependencies": {
         "bare-events": "^2.0.0",
-        "bare-os": "^2.0.0",
         "bare-path": "^2.0.0",
-        "streamx": "^2.13.0"
+        "bare-stream": "^1.0.0"
       }
     },
     "node_modules/bare-os": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.2.1.tgz",
-      "integrity": "sha512-OwPyHgBBMkhC29Hl3O4/YfxW9n7mdTr2+SsO29XBWKKJsbgj3mnorDB80r5TiCQgQstgE5ga1qNYrpes6NvX2w==",
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.3.0.tgz",
+      "integrity": "sha512-oPb8oMM1xZbhRQBngTgpcQ5gXw6kjOaRsSWsIeNyRxGed2w/ARyP7ScBYpWR1qfX2E5rS3gBw6OWcSQo+s+kUg==",
       "dev": true,
       "optional": true
     },
     "node_modules/bare-path": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.0.tgz",
-      "integrity": "sha512-DIIg7ts8bdRKwJRJrUMy/PICEaQZaPGZ26lsSx9MJSwIhSrcdHn7/C8W+XmnG/rKi6BaRcz+JO00CjZteybDtw==",
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.1.tgz",
+      "integrity": "sha512-OHM+iwRDRMDBsSW7kl3dO62JyHdBKO3B25FB9vNQBPcGHMo4+eA8Yj41Lfbk3pS/seDY+siNge0LdRTulAau/A==",
       "dev": true,
       "optional": true,
       "dependencies": {
         "bare-os": "^2.1.0"
       }
     },
+    "node_modules/bare-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-1.0.0.tgz",
+      "integrity": "sha512-KhNUoDL40iP4gFaLSsoGE479t0jHijfYdIcxRn/XtezA2BaUD0NRf/JGRpsMq6dMNM+SrCrB0YSSo/5wBY4rOQ==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "streamx": "^2.16.1"
+      }
+    },
     "node_modules/base64-js": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -5941,9 +5952,9 @@
       }
     },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001599",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz",
-      "integrity": "sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==",
+      "version": "1.0.30001612",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz",
+      "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==",
       "devOptional": true,
       "funding": [
         {
@@ -6043,9 +6054,9 @@
       }
     },
     "node_modules/chromium-bidi": {
-      "version": "0.5.16",
-      "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.16.tgz",
-      "integrity": "sha512-IT5lnR44h/qZQ4GaCHvBxYIl4cQL2i9UvFyYeRyVdcpY04hx5H720HQfe/7Oz7ndxaYVLQFGpCO71J4X2Ye/Gw==",
+      "version": "0.5.17",
+      "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.17.tgz",
+      "integrity": "sha512-BqOuIWUgTPj8ayuBFJUYCCuwIcwjBsb3/614P7tt1bEPJ4i1M0kCdIl0Wi9xhtswBXnfO2bTpTMkHD71H8rJMg==",
       "dev": true,
       "dependencies": {
         "mitt": "3.0.1",
@@ -6492,6 +6503,21 @@
         "typedarray-to-buffer": "^3.1.5"
       }
     },
+    "node_modules/connect": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
+      "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==",
+      "dev": true,
+      "dependencies": {
+        "debug": "2.6.9",
+        "finalhandler": "1.1.2",
+        "parseurl": "~1.3.3",
+        "utils-merge": "1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.10.0"
+      }
+    },
     "node_modules/connect-history-api-fallback": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz",
@@ -6500,6 +6526,21 @@
         "node": ">=0.8"
       }
     },
+    "node_modules/connect/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/connect/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
     "node_modules/content-disposition": {
       "version": "0.5.4",
       "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@@ -7777,9 +7818,9 @@
       }
     },
     "node_modules/core-js-compat": {
-      "version": "3.36.1",
-      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz",
-      "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==",
+      "version": "3.37.0",
+      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz",
+      "integrity": "sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA==",
       "dev": true,
       "dependencies": {
         "browserslist": "^4.23.0"
@@ -8209,9 +8250,9 @@
       "dev": true
     },
     "node_modules/css-loader": {
-      "version": "6.11.0",
-      "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz",
-      "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==",
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.1.tgz",
+      "integrity": "sha512-OxIR5P2mjO1PSXk44bWuQ8XtMK4dpEqpIyERCx3ewOo3I8EmbcxMPUc5ScLtQfgXtOojoMv57So4V/C02HQLsw==",
       "dev": true,
       "dependencies": {
         "icss-utils": "^5.1.0",
@@ -8224,7 +8265,7 @@
         "semver": "^7.5.4"
       },
       "engines": {
-        "node": ">= 12.13.0"
+        "node": ">= 18.12.0"
       },
       "funding": {
         "type": "opencollective",
@@ -8232,7 +8273,7 @@
       },
       "peerDependencies": {
         "@rspack/core": "0.x || 1.x",
-        "webpack": "^5.0.0"
+        "webpack": "^5.27.0"
       },
       "peerDependenciesMeta": {
         "@rspack/core": {
@@ -8492,9 +8533,9 @@
       "dev": true
     },
     "node_modules/dedent": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz",
-      "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==",
+      "version": "1.5.3",
+      "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz",
+      "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==",
       "dev": true,
       "peerDependencies": {
         "babel-plugin-macros": "^3.1.0"
@@ -8665,9 +8706,9 @@
       "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="
     },
     "node_modules/devtools-protocol": {
-      "version": "0.0.1262051",
-      "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1262051.tgz",
-      "integrity": "sha512-YJe4CT5SA8on3Spa+UDtNhEqtuV6Epwz3OZ4HQVLhlRccpZ9/PAYk0/cy/oKxFKRrZPBUPyxympQci4yWNWZ9g==",
+      "version": "0.0.1273771",
+      "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1273771.tgz",
+      "integrity": "sha512-QDbb27xcTVReQQW/GHJsdQqGKwYBE7re7gxehj467kKP2DKuYBUj6i2k5LRiAC66J1yZG/9gsxooz/s9pcm0Og==",
       "dev": true
     },
     "node_modules/dezalgo": {
@@ -8906,9 +8947,9 @@
       "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
     },
     "node_modules/electron-to-chromium": {
-      "version": "1.4.711",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.711.tgz",
-      "integrity": "sha512-hRg81qzvUEibX2lDxnFlVCHACa+LtrCPIsWAxo161LDYIB3jauf57RGsMZV9mvGwE98yGH06icj3zBEoOkxd/w==",
+      "version": "1.4.747",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.747.tgz",
+      "integrity": "sha512-+FnSWZIAvFHbsNVmUxhEqWiaOiPMcfum1GQzlWCg/wLigVtshOsjXHyEFfmt6cFK6+HkS3QOJBv6/3OPumbBfw==",
       "devOptional": true
     },
     "node_modules/emittery": {
@@ -8981,9 +9022,9 @@
       }
     },
     "node_modules/envinfo": {
-      "version": "7.11.1",
-      "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.1.tgz",
-      "integrity": "sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==",
+      "version": "7.12.0",
+      "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.12.0.tgz",
+      "integrity": "sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg==",
       "dev": true,
       "bin": {
         "envinfo": "dist/cli.js"
@@ -9015,9 +9056,9 @@
       }
     },
     "node_modules/es-abstract": {
-      "version": "1.23.2",
-      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.2.tgz",
-      "integrity": "sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w==",
+      "version": "1.23.3",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
+      "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==",
       "dev": true,
       "dependencies": {
         "array-buffer-byte-length": "^1.0.1",
@@ -9059,11 +9100,11 @@
         "safe-regex-test": "^1.0.3",
         "string.prototype.trim": "^1.2.9",
         "string.prototype.trimend": "^1.0.8",
-        "string.prototype.trimstart": "^1.0.7",
+        "string.prototype.trimstart": "^1.0.8",
         "typed-array-buffer": "^1.0.2",
         "typed-array-byte-length": "^1.0.1",
         "typed-array-byte-offset": "^1.0.2",
-        "typed-array-length": "^1.0.5",
+        "typed-array-length": "^1.0.6",
         "unbox-primitive": "^1.0.2",
         "which-typed-array": "^1.1.15"
       },
@@ -9094,9 +9135,9 @@
       }
     },
     "node_modules/es-module-lexer": {
-      "version": "1.4.2",
-      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.2.tgz",
-      "integrity": "sha512-7nOqkomXZEaxUDJw21XZNtRk739QvrPSoZoRtbsEfcii00vdzZUh6zh1CQwHhrib8MdEtJfv5rJiGeb4KuV/vw==",
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz",
+      "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==",
       "devOptional": true
     },
     "node_modules/es-object-atoms": {
@@ -9956,6 +9997,23 @@
         "ms": "2.0.0"
       }
     },
+    "node_modules/express/node_modules/finalhandler": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+      "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+      "dependencies": {
+        "debug": "2.6.9",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "on-finished": "2.4.1",
+        "parseurl": "~1.3.3",
+        "statuses": "2.0.1",
+        "unpipe": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/express/node_modules/ms": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
@@ -10155,16 +10213,17 @@
       }
     },
     "node_modules/finalhandler": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
-      "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+      "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+      "dev": true,
       "dependencies": {
         "debug": "2.6.9",
         "encodeurl": "~1.0.2",
         "escape-html": "~1.0.3",
-        "on-finished": "2.4.1",
+        "on-finished": "~2.3.0",
         "parseurl": "~1.3.3",
-        "statuses": "2.0.1",
+        "statuses": "~1.5.0",
         "unpipe": "~1.0.0"
       },
       "engines": {
@@ -10175,6 +10234,7 @@
       "version": "2.6.9",
       "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
       "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
       "dependencies": {
         "ms": "2.0.0"
       }
@@ -10182,7 +10242,29 @@
     "node_modules/finalhandler/node_modules/ms": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
+    "node_modules/finalhandler/node_modules/on-finished": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+      "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
+      "dev": true,
+      "dependencies": {
+        "ee-first": "1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/finalhandler/node_modules/statuses": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+      "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
     },
     "node_modules/find-cache-dir": {
       "version": "4.0.0",
@@ -14856,13 +14938,10 @@
       }
     },
     "node_modules/log-update/node_modules/ansi-escapes": {
-      "version": "6.2.0",
-      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz",
-      "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==",
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz",
+      "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==",
       "dev": true,
-      "dependencies": {
-        "type-fest": "^3.0.0"
-      },
       "engines": {
         "node": ">=14.16"
       },
@@ -14913,18 +14992,6 @@
         "url": "https://github.com/chalk/slice-ansi?sponsor=1"
       }
     },
-    "node_modules/log-update/node_modules/type-fest": {
-      "version": "3.13.1",
-      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz",
-      "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==",
-      "dev": true,
-      "engines": {
-        "node": ">=14.16"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
     "node_modules/lower-case": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
@@ -15488,9 +15555,9 @@
       }
     },
     "node_modules/nwsapi": {
-      "version": "2.2.7",
-      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz",
-      "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==",
+      "version": "2.2.9",
+      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz",
+      "integrity": "sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==",
       "dev": true
     },
     "node_modules/object-inspect": {
@@ -15922,12 +15989,12 @@
       "dev": true
     },
     "node_modules/path-scurry": {
-      "version": "1.10.1",
-      "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz",
-      "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==",
+      "version": "1.10.2",
+      "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz",
+      "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==",
       "dev": true,
       "dependencies": {
-        "lru-cache": "^9.1.1 || ^10.0.0",
+        "lru-cache": "^10.2.0",
         "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
       },
       "engines": {
@@ -16065,9 +16132,9 @@
       }
     },
     "node_modules/postcss": {
-      "version": "8.4.37",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.37.tgz",
-      "integrity": "sha512-7iB/v/r7Woof0glKLH8b1SPHrsX7uhdO+Geb41QpF/+mWZHU3uxxSlN+UXGVit1PawOYDToO+AbZzhBzWRDwbQ==",
+      "version": "8.4.38",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
+      "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
       "dev": true,
       "funding": [
         {
@@ -16390,16 +16457,16 @@
       }
     },
     "node_modules/puppeteer": {
-      "version": "22.6.2",
-      "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.6.2.tgz",
-      "integrity": "sha512-3GMAJ9adPUSdIHGuYV1b1RqRB6D2UScjnq779uZsvpAP6HOWw2+9ezZiUZaAXVST+Ku7KWsxOjkctEvRasJClA==",
+      "version": "22.7.0",
+      "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.7.0.tgz",
+      "integrity": "sha512-s1ulKFZKW3lwWCtNu0VrRLfRaanFHxIv7F8UFYpLo8dPTZcI4wB4EAOD0sKT3SKP+1Rsjodb9WFsK78yKQ6i9Q==",
       "dev": true,
       "hasInstallScript": true,
       "dependencies": {
-        "@puppeteer/browsers": "2.2.0",
+        "@puppeteer/browsers": "2.2.2",
         "cosmiconfig": "9.0.0",
-        "devtools-protocol": "0.0.1262051",
-        "puppeteer-core": "22.6.2"
+        "devtools-protocol": "0.0.1273771",
+        "puppeteer-core": "22.7.0"
       },
       "bin": {
         "puppeteer": "lib/esm/puppeteer/node/cli.js"
@@ -16409,15 +16476,15 @@
       }
     },
     "node_modules/puppeteer-core": {
-      "version": "22.6.2",
-      "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.6.2.tgz",
-      "integrity": "sha512-Sws/9V2/7nFrn3MSsRPHn1pXJMIFn6FWHhoMFMUBXQwVvcBstRIa9yW8sFfxePzb56W1xNfSYzPRnyAd0+qRVQ==",
+      "version": "22.7.0",
+      "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.7.0.tgz",
+      "integrity": "sha512-9Q+L3VD7cfhXnxv6AqwTHsVb/+/uXENByhPrgvwQ49wvzQwtf1d6b7v6gpoG3tpRdwYjxoV1eHTD8tFahww09g==",
       "dev": true,
       "dependencies": {
-        "@puppeteer/browsers": "2.2.0",
-        "chromium-bidi": "0.5.16",
+        "@puppeteer/browsers": "2.2.2",
+        "chromium-bidi": "0.5.17",
         "debug": "4.3.4",
-        "devtools-protocol": "0.0.1262051",
+        "devtools-protocol": "0.0.1273771",
         "ws": "8.16.0"
       },
       "engines": {
@@ -16425,9 +16492,9 @@
       }
     },
     "node_modules/pure-rand": {
-      "version": "6.0.4",
-      "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz",
-      "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==",
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
+      "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==",
       "dev": true,
       "funding": [
         {
@@ -16966,16 +17033,16 @@
       }
     },
     "node_modules/rimraf/node_modules/glob": {
-      "version": "10.3.10",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
-      "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
+      "version": "10.3.12",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz",
+      "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==",
       "dev": true,
       "dependencies": {
         "foreground-child": "^3.1.0",
-        "jackspeak": "^2.3.5",
+        "jackspeak": "^2.3.6",
         "minimatch": "^9.0.1",
-        "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
-        "path-scurry": "^1.10.1"
+        "minipass": "^7.0.4",
+        "path-scurry": "^1.10.2"
       },
       "bin": {
         "glob": "dist/esm/bin.mjs"
@@ -16988,9 +17055,9 @@
       }
     },
     "node_modules/rimraf/node_modules/minimatch": {
-      "version": "9.0.3",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
-      "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+      "version": "9.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
+      "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
       "dev": true,
       "dependencies": {
         "brace-expansion": "^2.0.1"
@@ -17467,9 +17534,9 @@
       }
     },
     "node_modules/socks": {
-      "version": "2.8.1",
-      "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz",
-      "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==",
+      "version": "2.8.3",
+      "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
+      "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
       "dev": true,
       "dependencies": {
         "ip-address": "^9.0.5",
@@ -18083,14 +18150,15 @@
       }
     },
     "node_modules/string.prototype.padend": {
-      "version": "3.1.5",
-      "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.5.tgz",
-      "integrity": "sha512-DOB27b/2UTTD+4myKUFh+/fXWcu/UDyASIXfg+7VzoCNNGOfWvoyU/x5pvVHr++ztyt/oSYI1BcWBBG/hmlNjA==",
+      "version": "3.1.6",
+      "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz",
+      "integrity": "sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.2.0",
-        "es-abstract": "^1.22.1"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2",
+        "es-object-atoms": "^1.0.0"
       },
       "engines": {
         "node": ">= 0.4"
@@ -18132,14 +18200,17 @@
       }
     },
     "node_modules/string.prototype.trimstart": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz",
-      "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==",
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
+      "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.2.0",
-        "es-abstract": "^1.22.1"
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
       },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
@@ -18253,25 +18324,26 @@
       }
     },
     "node_modules/style-loader": {
-      "version": "3.3.4",
-      "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz",
-      "integrity": "sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz",
+      "integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==",
       "dev": true,
       "engines": {
-        "node": ">= 12.13.0"
+        "node": ">= 18.12.0"
       },
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/webpack"
       },
       "peerDependencies": {
-        "webpack": "^5.0.0"
+        "webpack": "^5.27.0"
       }
     },
     "node_modules/superagent": {
       "version": "8.1.2",
       "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz",
       "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==",
+      "deprecated": "Please upgrade to v9.0.0+ as we have fixed a public vulnerability with formidable dependency. Note that v9.0.0+ requires Node.js v14.18.0+. See https://github.com/ladjs/superagent/pull/1800 for insight. This project is supported and maintained by the team at Forward Email @ https://forwardemail.net",
       "dev": true,
       "dependencies": {
         "component-emitter": "^1.3.0",
@@ -18439,9 +18511,9 @@
       }
     },
     "node_modules/terser": {
-      "version": "5.29.2",
-      "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.2.tgz",
-      "integrity": "sha512-ZiGkhUBIM+7LwkNjXYJq8svgkd+QK3UUr0wJqY4MieaezBSAIPgbSPZyIx0idM6XWK5CMzSWa8MJIzmRcB8Caw==",
+      "version": "5.30.4",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.4.tgz",
+      "integrity": "sha512-xRdd0v64a8mFK9bnsKVdoNP9GQIKUAaJPTaqEQDL4w/J8WaW4sWXXoMZ+6SimPkfT5bElreXf8m9HnmPc3E1BQ==",
       "devOptional": true,
       "dependencies": {
         "@jridgewell/source-map": "^0.3.3",
@@ -18875,9 +18947,9 @@
       }
     },
     "node_modules/typed-array-length": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.5.tgz",
-      "integrity": "sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==",
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz",
+      "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==",
       "dev": true,
       "dependencies": {
         "call-bind": "^1.0.7",
@@ -18910,9 +18982,9 @@
       }
     },
     "node_modules/typescript": {
-      "version": "5.4.3",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz",
-      "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==",
+      "version": "5.4.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
+      "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
       "dev": true,
       "bin": {
         "tsc": "bin/tsc",
diff --git a/package.json b/package.json
index be846890f4..a53816ab29 100644
--- a/package.json
+++ b/package.json
@@ -96,9 +96,10 @@
     "babel-jest": "^29.5.0",
     "babel-loader": "^9.1.0",
     "body-parser": "^1.19.2",
+    "connect": "^3.7.0",
     "core-js": "^3.31.0",
     "cspell": "^8.3.2",
-    "css-loader": "^6.8.1",
+    "css-loader": "^7.1.1",
     "eslint": "^8.43.0",
     "eslint-config-prettier": "^9.1.0",
     "eslint-config-webpack": "^1.2.5",
@@ -117,19 +118,19 @@
     "memfs": "^4.6.0",
     "npm-run-all": "^4.1.5",
     "prettier": "^3.2.4",
-    "puppeteer": "^22.1.0",
+    "puppeteer": "^22.6.5",
     "readable-stream": "^4.5.2",
     "require-from-string": "^2.0.2",
     "rimraf": "^5.0.5",
     "sockjs-client": "^1.6.1",
     "standard-version": "^9.3.0",
     "strip-ansi-v6": "npm:strip-ansi@^6.0.0",
-    "style-loader": "^3.3.1",
+    "style-loader": "^4.0.0",
     "supertest": "^6.1.3",
     "tcp-port-used": "^1.0.2",
     "typescript": "^5.3.3",
     "wait-for-expect": "^3.0.2",
-    "webpack": "^5.89.0",
+    "webpack": "^5.91.0",
     "webpack-cli": "^5.0.1",
     "webpack-merge": "^5.9.0"
   },
diff --git a/scripts/setupTest.js b/scripts/setupTest.js
index f3dedf9551..99a74a59bf 100644
--- a/scripts/setupTest.js
+++ b/scripts/setupTest.js
@@ -2,4 +2,4 @@
 
 process.env.CHOKIDAR_USEPOLLING = true;
 
-jest.setTimeout(300000);
+jest.setTimeout(400000);
diff --git a/test/__snapshots__/validate-options.test.js.snap.webpack5 b/test/__snapshots__/validate-options.test.js.snap.webpack5
index 03cf17040e..60fa07786f 100644
--- a/test/__snapshots__/validate-options.test.js.snap.webpack5
+++ b/test/__snapshots__/validate-options.test.js.snap.webpack5
@@ -52,6 +52,20 @@ exports[`options validate should throw an error on the "allowedHosts" option wit
     * options.allowedHosts should be a non-empty string."
 `;
 
+exports[`options validate should throw an error on the "app" option with 'false' value 1`] = `
+"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
+ - options.app should be an instance of function.
+   -> Allows to use custom applications (i.e. 'connect', 'fastify' and etc).
+   -> Read more at  https://webpack.js.org/configuration/dev-server/#devserverapp"
+`;
+
+exports[`options validate should throw an error on the "app" option with 'test' value 1`] = `
+"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
+ - options.app should be an instance of function.
+   -> Allows to use custom applications (i.e. 'connect', 'fastify' and etc).
+   -> Read more at  https://webpack.js.org/configuration/dev-server/#devserverapp"
+`;
+
 exports[`options validate should throw an error on the "bonjour" option with '' value 1`] = `
 "ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
  - options.bonjour should be one of these:
diff --git a/test/e2e/__snapshots__/allowed-hosts.test.js.snap.webpack5 b/test/e2e/__snapshots__/allowed-hosts.test.js.snap.webpack5
index 84b2498b57..5ab1e22dec 100644
--- a/test/e2e/__snapshots__/allowed-hosts.test.js.snap.webpack5
+++ b/test/e2e/__snapshots__/allowed-hosts.test.js.snap.webpack5
@@ -262,15 +262,23 @@ exports[`allowed hosts should connect web socket client using localhost to web s
 
 exports[`allowed hosts should connect web socket client using localhost to web socket server with the "auto" value ("ws"): page errors 1`] = `[]`;
 
-exports[`allowed hosts should disconnect web client using localhost to web socket server with the "auto" value ("sockjs"): console messages 1`] = `[]`;
+exports[`allowed hosts should disconnect web client using localhost to web socket server with the "auto" value ("sockjs"): console messages 1`] = `
+[
+  "Failed to load resource: the server responded with a status of 403 (Forbidden)",
+]
+`;
 
-exports[`allowed hosts should disconnect web client using localhost to web socket server with the "auto" value ("sockjs"): html 1`] = `"<html><head></head><body>Invalid Host header</body></html>"`;
+exports[`allowed hosts should disconnect web client using localhost to web socket server with the "auto" value ("sockjs"): html 1`] = `"<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">Invalid Host header</pre></body></html>"`;
 
 exports[`allowed hosts should disconnect web client using localhost to web socket server with the "auto" value ("sockjs"): page errors 1`] = `[]`;
 
-exports[`allowed hosts should disconnect web client using localhost to web socket server with the "auto" value ("ws"): console messages 1`] = `[]`;
+exports[`allowed hosts should disconnect web client using localhost to web socket server with the "auto" value ("ws"): console messages 1`] = `
+[
+  "Failed to load resource: the server responded with a status of 403 (Forbidden)",
+]
+`;
 
-exports[`allowed hosts should disconnect web client using localhost to web socket server with the "auto" value ("ws"): html 1`] = `"<html><head></head><body>Invalid Host header</body></html>"`;
+exports[`allowed hosts should disconnect web client using localhost to web socket server with the "auto" value ("ws"): html 1`] = `"<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">Invalid Host header</pre></body></html>"`;
 
 exports[`allowed hosts should disconnect web client using localhost to web socket server with the "auto" value ("ws"): page errors 1`] = `[]`;
 
diff --git a/test/e2e/__snapshots__/app.test.js.snap.webpack5 b/test/e2e/__snapshots__/app.test.js.snap.webpack5
new file mode 100644
index 0000000000..9ac3495c9b
--- /dev/null
+++ b/test/e2e/__snapshots__/app.test.js.snap.webpack5
@@ -0,0 +1,253 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`app option should work using "connect (async)" application and "http" server should handle GET request to index route (/): console messages 1`] = `
+[
+  "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
+  "[HMR] Waiting for update signal from WDS...",
+  "Hey.",
+]
+`;
+
+exports[`app option should work using "connect (async)" application and "http" server should handle GET request to index route (/): page errors 1`] = `[]`;
+
+exports[`app option should work using "connect (async)" application and "http" server should handle GET request to index route (/): response status 1`] = `200`;
+
+exports[`app option should work using "connect (async)" application and "http" server should handle GET request to index route (/): response text 1`] = `
+"
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset='UTF-8'>
+    <title>webpack-dev-server</title>
+  </head>
+  <body>
+    <h1>webpack-dev-server is running...</h1>
+    <script type="text/javascript" charset="utf-8" src="/main.js"></script>
+  </body>
+</html>
+"
+`;
+
+exports[`app option should work using "connect (async)" application and "https" server should handle GET request to index route (/): console messages 1`] = `
+[
+  "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
+  "[HMR] Waiting for update signal from WDS...",
+  "Hey.",
+]
+`;
+
+exports[`app option should work using "connect (async)" application and "https" server should handle GET request to index route (/): page errors 1`] = `[]`;
+
+exports[`app option should work using "connect (async)" application and "https" server should handle GET request to index route (/): response status 1`] = `200`;
+
+exports[`app option should work using "connect (async)" application and "https" server should handle GET request to index route (/): response text 1`] = `
+"
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset='UTF-8'>
+    <title>webpack-dev-server</title>
+  </head>
+  <body>
+    <h1>webpack-dev-server is running...</h1>
+    <script type="text/javascript" charset="utf-8" src="/main.js"></script>
+  </body>
+</html>
+"
+`;
+
+exports[`app option should work using "connect (async)" application and "spdy" server should handle GET request to index route (/): console messages 1`] = `
+[
+  "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
+  "[HMR] Waiting for update signal from WDS...",
+  "Hey.",
+]
+`;
+
+exports[`app option should work using "connect (async)" application and "spdy" server should handle GET request to index route (/): page errors 1`] = `[]`;
+
+exports[`app option should work using "connect (async)" application and "spdy" server should handle GET request to index route (/): response status 1`] = `200`;
+
+exports[`app option should work using "connect (async)" application and "spdy" server should handle GET request to index route (/): response text 1`] = `
+"
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset='UTF-8'>
+    <title>webpack-dev-server</title>
+  </head>
+  <body>
+    <h1>webpack-dev-server is running...</h1>
+    <script type="text/javascript" charset="utf-8" src="/main.js"></script>
+  </body>
+</html>
+"
+`;
+
+exports[`app option should work using "connect" application and "http" server should handle GET request to index route (/): console messages 1`] = `
+[
+  "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
+  "[HMR] Waiting for update signal from WDS...",
+  "Hey.",
+]
+`;
+
+exports[`app option should work using "connect" application and "http" server should handle GET request to index route (/): page errors 1`] = `[]`;
+
+exports[`app option should work using "connect" application and "http" server should handle GET request to index route (/): response status 1`] = `200`;
+
+exports[`app option should work using "connect" application and "http" server should handle GET request to index route (/): response text 1`] = `
+"
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset='UTF-8'>
+    <title>webpack-dev-server</title>
+  </head>
+  <body>
+    <h1>webpack-dev-server is running...</h1>
+    <script type="text/javascript" charset="utf-8" src="/main.js"></script>
+  </body>
+</html>
+"
+`;
+
+exports[`app option should work using "connect" application and "https" server should handle GET request to index route (/): console messages 1`] = `
+[
+  "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
+  "[HMR] Waiting for update signal from WDS...",
+  "Hey.",
+]
+`;
+
+exports[`app option should work using "connect" application and "https" server should handle GET request to index route (/): page errors 1`] = `[]`;
+
+exports[`app option should work using "connect" application and "https" server should handle GET request to index route (/): response status 1`] = `200`;
+
+exports[`app option should work using "connect" application and "https" server should handle GET request to index route (/): response text 1`] = `
+"
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset='UTF-8'>
+    <title>webpack-dev-server</title>
+  </head>
+  <body>
+    <h1>webpack-dev-server is running...</h1>
+    <script type="text/javascript" charset="utf-8" src="/main.js"></script>
+  </body>
+</html>
+"
+`;
+
+exports[`app option should work using "connect" application and "spdy" server should handle GET request to index route (/): console messages 1`] = `
+[
+  "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
+  "[HMR] Waiting for update signal from WDS...",
+  "Hey.",
+]
+`;
+
+exports[`app option should work using "connect" application and "spdy" server should handle GET request to index route (/): page errors 1`] = `[]`;
+
+exports[`app option should work using "connect" application and "spdy" server should handle GET request to index route (/): response status 1`] = `200`;
+
+exports[`app option should work using "connect" application and "spdy" server should handle GET request to index route (/): response text 1`] = `
+"
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset='UTF-8'>
+    <title>webpack-dev-server</title>
+  </head>
+  <body>
+    <h1>webpack-dev-server is running...</h1>
+    <script type="text/javascript" charset="utf-8" src="/main.js"></script>
+  </body>
+</html>
+"
+`;
+
+exports[`app option should work using "express" application and "http" server should handle GET request to index route (/): console messages 1`] = `
+[
+  "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
+  "[HMR] Waiting for update signal from WDS...",
+  "Hey.",
+]
+`;
+
+exports[`app option should work using "express" application and "http" server should handle GET request to index route (/): page errors 1`] = `[]`;
+
+exports[`app option should work using "express" application and "http" server should handle GET request to index route (/): response status 1`] = `200`;
+
+exports[`app option should work using "express" application and "http" server should handle GET request to index route (/): response text 1`] = `
+"
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset='UTF-8'>
+    <title>webpack-dev-server</title>
+  </head>
+  <body>
+    <h1>webpack-dev-server is running...</h1>
+    <script type="text/javascript" charset="utf-8" src="/main.js"></script>
+  </body>
+</html>
+"
+`;
+
+exports[`app option should work using "express" application and "https" server should handle GET request to index route (/): console messages 1`] = `
+[
+  "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
+  "[HMR] Waiting for update signal from WDS...",
+  "Hey.",
+]
+`;
+
+exports[`app option should work using "express" application and "https" server should handle GET request to index route (/): page errors 1`] = `[]`;
+
+exports[`app option should work using "express" application and "https" server should handle GET request to index route (/): response status 1`] = `200`;
+
+exports[`app option should work using "express" application and "https" server should handle GET request to index route (/): response text 1`] = `
+"
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset='UTF-8'>
+    <title>webpack-dev-server</title>
+  </head>
+  <body>
+    <h1>webpack-dev-server is running...</h1>
+    <script type="text/javascript" charset="utf-8" src="/main.js"></script>
+  </body>
+</html>
+"
+`;
+
+exports[`app option should work using "express" application and "spdy" server should handle GET request to index route (/): console messages 1`] = `
+[
+  "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
+  "[HMR] Waiting for update signal from WDS...",
+  "Hey.",
+]
+`;
+
+exports[`app option should work using "express" application and "spdy" server should handle GET request to index route (/): page errors 1`] = `[]`;
+
+exports[`app option should work using "express" application and "spdy" server should handle GET request to index route (/): response status 1`] = `200`;
+
+exports[`app option should work using "express" application and "spdy" server should handle GET request to index route (/): response text 1`] = `
+"
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset='UTF-8'>
+    <title>webpack-dev-server</title>
+  </head>
+  <body>
+    <h1>webpack-dev-server is running...</h1>
+    <script type="text/javascript" charset="utf-8" src="/main.js"></script>
+  </body>
+</html>
+"
+`;
diff --git a/test/e2e/__snapshots__/built-in-routes.test.js.snap.webpack5 b/test/e2e/__snapshots__/built-in-routes.test.js.snap.webpack5
index 769c716c67..9fa4d94d12 100644
--- a/test/e2e/__snapshots__/built-in-routes.test.js.snap.webpack5
+++ b/test/e2e/__snapshots__/built-in-routes.test.js.snap.webpack5
@@ -16,7 +16,7 @@ exports[`Built in routes with multi config should handle GET request to director
 
 exports[`Built in routes with multi config should handle GET request to directory index and list all middleware directories: page errors 1`] = `[]`;
 
-exports[`Built in routes with multi config should handle GET request to directory index and list all middleware directories: response headers content-type 1`] = `"text/html"`;
+exports[`Built in routes with multi config should handle GET request to directory index and list all middleware directories: response headers content-type 1`] = `"text/html; charset=utf-8"`;
 
 exports[`Built in routes with multi config should handle GET request to directory index and list all middleware directories: response status 1`] = `200`;
 
@@ -34,7 +34,7 @@ exports[`Built in routes with simple config should handle GET request to directo
 
 exports[`Built in routes with simple config should handle GET request to directory index and list all middleware directories: page errors 1`] = `[]`;
 
-exports[`Built in routes with simple config should handle GET request to directory index and list all middleware directories: response headers content-type 1`] = `"text/html"`;
+exports[`Built in routes with simple config should handle GET request to directory index and list all middleware directories: response headers content-type 1`] = `"text/html; charset=utf-8"`;
 
 exports[`Built in routes with simple config should handle GET request to directory index and list all middleware directories: response status 1`] = `200`;
 
@@ -56,7 +56,7 @@ exports[`Built in routes with simple config should handle HEAD request to direct
 
 exports[`Built in routes with simple config should handle HEAD request to directory index: page errors 1`] = `[]`;
 
-exports[`Built in routes with simple config should handle HEAD request to directory index: response headers content-type 1`] = `"text/html"`;
+exports[`Built in routes with simple config should handle HEAD request to directory index: response headers content-type 1`] = `"text/html; charset=utf-8"`;
 
 exports[`Built in routes with simple config should handle HEAD request to directory index: response status 1`] = `200`;
 
@@ -70,7 +70,7 @@ exports[`Built in routes with simple config should handles GET request to sockjs
 
 exports[`Built in routes with simple config should handles GET request to sockjs bundle: page errors 1`] = `[]`;
 
-exports[`Built in routes with simple config should handles GET request to sockjs bundle: response headers content-type 1`] = `"application/javascript"`;
+exports[`Built in routes with simple config should handles GET request to sockjs bundle: response headers content-type 1`] = `"application/javascript; charset=UTF-8"`;
 
 exports[`Built in routes with simple config should handles GET request to sockjs bundle: response status 1`] = `200`;
 
@@ -78,6 +78,6 @@ exports[`Built in routes with simple config should handles HEAD request to sockj
 
 exports[`Built in routes with simple config should handles HEAD request to sockjs bundle: page errors 1`] = `[]`;
 
-exports[`Built in routes with simple config should handles HEAD request to sockjs bundle: response headers content-type 1`] = `"application/javascript"`;
+exports[`Built in routes with simple config should handles HEAD request to sockjs bundle: response headers content-type 1`] = `"application/javascript; charset=UTF-8"`;
 
 exports[`Built in routes with simple config should handles HEAD request to sockjs bundle: response status 1`] = `200`;
diff --git a/test/e2e/app.test.js b/test/e2e/app.test.js
new file mode 100644
index 0000000000..05e6c23a79
--- /dev/null
+++ b/test/e2e/app.test.js
@@ -0,0 +1,103 @@
+"use strict";
+
+const path = require("path");
+const webpack = require("webpack");
+const Server = require("../../lib/Server");
+const config = require("../fixtures/client-config/webpack.config");
+const runBrowser = require("../helpers/run-browser");
+const port = require("../ports-map").app;
+
+const staticDirectory = path.resolve(
+  __dirname,
+  "../fixtures/static-config/public",
+);
+
+const apps = [
+  ["express", () => require("express")()],
+  ["connect", () => require("connect")()],
+  ["connect (async)", async () => require("express")()],
+];
+
+const servers = ["http", "https", "spdy"];
+
+describe("app option", () => {
+  for (const [appName, app] of apps) {
+    for (const server of servers) {
+      let compiler;
+      let devServer;
+      let page;
+      let browser;
+      let pageErrors;
+      let consoleMessages;
+
+      describe(`should work using "${appName}" application and "${server}" server`, () => {
+        beforeEach(async () => {
+          compiler = webpack(config);
+
+          devServer = new Server(
+            {
+              static: {
+                directory: staticDirectory,
+                watch: false,
+              },
+              app,
+              server,
+              port,
+            },
+            compiler,
+          );
+
+          await devServer.start();
+
+          ({ page, browser } = await runBrowser());
+
+          pageErrors = [];
+          consoleMessages = [];
+        });
+
+        afterEach(async () => {
+          await browser.close();
+          await devServer.stop();
+        });
+
+        it("should handle GET request to index route (/)", async () => {
+          page
+            .on("console", (message) => {
+              consoleMessages.push(message);
+            })
+            .on("pageerror", (error) => {
+              pageErrors.push(error);
+            });
+
+          const pageUrl =
+            server === "https" || server === "spdy" || server === "http2"
+              ? `https://127.0.0.1:${port}/`
+              : `http://127.0.0.1:${port}/`;
+
+          const response = await page.goto(pageUrl, {
+            waitUntil: "networkidle0",
+          });
+
+          const HTTPVersion = await page.evaluate(
+            () => performance.getEntries()[0].nextHopProtocol,
+          );
+
+          const isSpdy = server === "spdy";
+
+          if (isSpdy) {
+            expect(HTTPVersion).toEqual("h2");
+          } else {
+            expect(HTTPVersion).toEqual("http/1.1");
+          }
+
+          expect(response.status()).toMatchSnapshot("response status");
+          expect(await response.text()).toMatchSnapshot("response text");
+          expect(
+            consoleMessages.map((message) => message.text()),
+          ).toMatchSnapshot("console messages");
+          expect(pageErrors).toMatchSnapshot("page errors");
+        });
+      });
+    }
+  }
+});
diff --git a/test/e2e/on-listening.test.js b/test/e2e/on-listening.test.js
index 6e97561b14..4a88d908e7 100644
--- a/test/e2e/on-listening.test.js
+++ b/test/e2e/on-listening.test.js
@@ -26,12 +26,18 @@ describe("onListening option", () => {
 
           onListeningIsRunning = true;
 
-          devServer.app.get("/listening/some/path", (_, response) => {
-            response.send("listening");
-          });
-
-          devServer.app.post("/listening/some/path", (_, response) => {
-            response.send("listening POST");
+          devServer.app.use("/listening/some/path", (req, res, next) => {
+            if (req.method === "GET") {
+              res.setHeader("Content-Type", "text/html; charset=utf-8");
+              res.end("listening");
+              return;
+            } else if (req.method === "POST") {
+              res.setHeader("Content-Type", "text/html; charset=utf-8");
+              res.end("listening POST");
+              return;
+            }
+
+            return next();
           });
         },
         port,
diff --git a/test/e2e/setup-middlewares.test.js b/test/e2e/setup-middlewares.test.js
index 5ed6fece62..5187aaa8a7 100644
--- a/test/e2e/setup-middlewares.test.js
+++ b/test/e2e/setup-middlewares.test.js
@@ -23,35 +23,43 @@ describe("setupMiddlewares option", () => {
             throw new Error("webpack-dev-server is not defined");
           }
 
-          devServer.app.get("/setup-middleware/some/path", (_, response) => {
-            response.send("setup-middlewares option GET");
-          });
-
-          devServer.app.post("/setup-middleware/some/path", (_, response) => {
-            response.send("setup-middlewares option POST");
+          devServer.app.use("/setup-middleware/some/path", (req, res, next) => {
+            if (req.method === "GET") {
+              res.setHeader("Content-Type", "text/html; charset=utf-8");
+              res.end("setup-middlewares option GET");
+              return;
+            } else if (req.method === "POST") {
+              res.setHeader("Content-Type", "text/html; charset=utf-8");
+              res.end("setup-middlewares option POST");
+              return;
+            }
+
+            return next();
           });
 
           middlewares.push({
             name: "hello-world-test-two",
             middleware: (req, res, next) => {
-              if (req.path !== "/foo/bar/baz") {
+              if (req.url !== "/foo/bar/baz") {
                 next();
-
                 return;
               }
 
-              res.send("Hello World without path!");
+              res.setHeader("Content-Type", "text/html; charset=utf-8");
+              res.end("Hello World without path!");
             },
           });
           middlewares.push({
             name: "hello-world-test-one",
             path: "/foo/bar",
             middleware: (req, res) => {
-              res.send("Hello World with path!");
+              res.setHeader("Content-Type", "text/html; charset=utf-8");
+              res.end("Hello World with path!");
             },
           });
           middlewares.push((req, res) => {
-            res.send("Hello World as function!");
+            res.setHeader("Content-Type", "text/html; charset=utf-8");
+            res.end("Hello World as function!");
           });
 
           return middlewares;
diff --git a/test/ports-map.js b/test/ports-map.js
index c43004298c..00eb84a7dd 100644
--- a/test/ports-map.js
+++ b/test/ports-map.js
@@ -80,6 +80,7 @@ const listOfTests = {
   "normalize-option": 1,
   "setup-middlewares-option": 1,
   "options-request-response": 2,
+  app: 1,
 };
 
 let startPort = 8089;
diff --git a/test/server/proxy-option.test.js b/test/server/proxy-option.test.js
index d894fdae08..e77824a371 100644
--- a/test/server/proxy-option.test.js
+++ b/test/server/proxy-option.test.js
@@ -27,7 +27,7 @@ const proxyOptionPathsAsProperties = [
   {
     context: "/foo",
     bypass(req) {
-      if (/\.html$/.test(req.path)) {
+      if (/\.html$/.test(req.path || req.url)) {
         return "/index.html";
       }
 
@@ -37,7 +37,7 @@ const proxyOptionPathsAsProperties = [
   {
     context: "proxyfalse",
     bypass(req) {
-      if (/\/proxyfalse$/.test(req.path)) {
+      if (/\/proxyfalse$/.test(req.path || req.url)) {
         return false;
       }
     },
@@ -45,7 +45,7 @@ const proxyOptionPathsAsProperties = [
   {
     context: "/proxy/async",
     bypass(req, res) {
-      if (/\/proxy\/async$/.test(req.path)) {
+      if (/\/proxy\/async$/.test(req.path || req.url)) {
         return new Promise((resolve) => {
           setTimeout(() => {
             res.end("proxy async response");
@@ -61,7 +61,7 @@ const proxyOptionPathsAsProperties = [
     changeOrigin: true,
     secure: false,
     bypass(req) {
-      if (/\.(html)$/i.test(req.url)) {
+      if (/\.(html)$/i.test(req.path || req.url)) {
         return req.url;
       }
     },
@@ -95,10 +95,16 @@ const proxyOptionOfArray = [
       target: `http://localhost:${port2}`,
       pathRewrite: { "^/api": "" },
       bypass: () => {
-        if (req && req.query.foo) {
-          res.end(`foo+${next.name}+${typeof next}`);
+        if (req) {
+          const resolveUrl = new URL(req.url, `http://${req.headers.host}`);
+          const params = new URLSearchParams(resolveUrl.search);
+          const foo = params.get("foo");
 
-          return false;
+          if (foo) {
+            res.end(`foo+${next.name}+${typeof next}`);
+
+            return false;
+          }
         }
       },
     };
diff --git a/test/validate-options.test.js b/test/validate-options.test.js
index 72bf4c933e..bc170f3dc3 100644
--- a/test/validate-options.test.js
+++ b/test/validate-options.test.js
@@ -437,6 +437,16 @@ const tests = {
       },
     ],
   },
+  app: {
+    success: [
+      () => require("connect")(),
+      async () =>
+        new Promise((resolve) => {
+          resolve(require("connect")());
+        }),
+    ],
+    failure: ["test", false],
+  },
   static: {
     success: [
       "path",
diff --git a/types/lib/Server.d.ts b/types/lib/Server.d.ts
index b9eee28278..5742ee0b33 100644
--- a/types/lib/Server.d.ts
+++ b/types/lib/Server.d.ts
@@ -1,90 +1,71 @@
 /// <reference types="node" />
 export = Server;
-declare class Server {
+/**
+ * @typedef {Object} BasicApplication
+ * @property {typeof useFn} use
+ */
+/**
+ * @template {BasicApplication} [T=ExpressApplication]
+ */
+declare class Server<
+  T extends BasicApplication = import("express").Application,
+> {
   static get schema(): {
     title: string;
     type: string;
     definitions: {
-      AllowedHosts: {
-        anyOf: (
-          | {
-              type: string;
-              minItems: number;
-              items: {
-                $ref: string;
-              };
-              enum?: undefined;
-              $ref?: undefined;
-            }
-          | {
-              enum: string[];
-              type?: undefined;
-              minItems?: undefined;
-              items?: undefined;
-              $ref?: undefined;
-            }
-          | {
-              $ref: string;
-              type?: undefined;
-              minItems?: undefined;
-              items?: undefined;
-              enum?: undefined;
-            }
-        )[];
-        description: string;
-        link: string;
-      };
-      AllowedHostsItem: {
-        type: string;
-        minLength: number;
-      };
-      Bonjour: {
-        anyOf: (
-          | {
-              type: string;
-              cli: {
-                negatedDescription: string;
-              };
-              description?: undefined;
-              link?: undefined;
-            }
-          | {
-              type: string /** @typedef {import("express").ErrorRequestHandler} ExpressErrorRequestHandler */;
-              description: string;
-              link: string;
-              cli?: undefined;
-            }
-        )[];
+      App: {
+        instanceof: string;
         description: string;
         link: string;
       };
-      Client: {
-        description: string;
-        link: string;
+      AllowedHosts: {
         anyOf: (
-          | {
-              enum: boolean[];
-              cli: {
-                negatedDescription: string;
-              };
-              type?: undefined;
-              additionalProperties?: undefined;
-              properties?: undefined;
-            }
           | {
               type: string;
-              additionalProperties: boolean;
-              properties: {
-                logging: {
-                  $ref: string;
-                };
+              minItems: number;
+              items: {
+                /** @typedef {import("webpack").Configuration} WebpackConfiguration */
+                /** @typedef {import("webpack").StatsOptions} StatsOptions */
+                /** @typedef {import("webpack").StatsCompilation} StatsCompilation */
+                /** @typedef {import("webpack").Stats} Stats */
+                /** @typedef {import("webpack").MultiStats} MultiStats */
+                /** @typedef {import("os").NetworkInterfaceInfo} NetworkInterfaceInfo */
+                /** @typedef {import("chokidar").WatchOptions} WatchOptions */
+                /** @typedef {import("chokidar").FSWatcher} FSWatcher */
+                /** @typedef {import("connect-history-api-fallback").Options} ConnectHistoryApiFallbackOptions */
+                /** @typedef {import("bonjour-service").Bonjour} Bonjour */
+                /** @typedef {import("bonjour-service").Service} BonjourOptions */
+                /** @typedef {import("http-proxy-middleware").RequestHandler} RequestHandler */
+                /** @typedef {import("http-proxy-middleware").Options} HttpProxyMiddlewareOptions */
+                /** @typedef {import("http-proxy-middleware").Filter} HttpProxyMiddlewareOptionsFilter */
+                /** @typedef {import("serve-index").Options} ServeIndexOptions */
+                /** @typedef {import("serve-static").ServeStaticOptions} ServeStaticOptions */
+                /** @typedef {import("ipaddr.js").IPv4} IPv4 */
+                /** @typedef {import("ipaddr.js").IPv6} IPv6 */
                 /** @typedef {import("net").Socket} Socket */
                 /** @typedef {import("http").IncomingMessage} IncomingMessage */
                 /** @typedef {import("http").ServerResponse} ServerResponse */
                 /** @typedef {import("open").Options} OpenOptions */
+                /** @typedef {import("express").Application} ExpressApplication */
+                /** @typedef {import("express").RequestHandler} ExpressRequestHandler */
+                /** @typedef {import("express").ErrorRequestHandler} ExpressErrorRequestHandler */
+                /** @typedef {import("express").Request} ExpressRequest */
+                /** @typedef {import("express").Response} ExpressResponse */
+                /** @typedef {(err?: any) => void} NextFunction */
+                /** @typedef {(req: IncomingMessage, res: ServerResponse) => void} SimpleHandleFunction */
+                /** @typedef {(req: IncomingMessage, res: ServerResponse, next: NextFunction) => void} NextHandleFunction */
+                /** @typedef {(err: any, req: IncomingMessage, res: ServerResponse, next: NextFunction) => void} ErrorHandleFunction */
+                /** @typedef {SimpleHandleFunction | NextHandleFunction | ErrorHandleFunction} HandleFunction */
                 /** @typedef {import("https").ServerOptions & { spdy?: { plain?: boolean | undefined, ssl?: boolean | undefined, 'x-forwarded-for'?: string | undefined, protocol?: string | undefined, protocols?: string[] | undefined }}} ServerOptions */
-                /** @typedef {import("express").Request} Request */
-                /** @typedef {import("express").Response} Response */
+                /**
+                 * @template {BasicApplication} [T=ExpressApplication]
+                 * @typedef {T extends ExpressApplication ? ExpressRequest : IncomingMessage} Request
+                 */
+                /**
+                 * @template {BasicApplication} [T=ExpressApplication]
+                 * @typedef {T extends ExpressApplication ? ExpressResponse : ServerResponse} Response
+                 */
                 /**
                  * @template {Request} T
                  * @template {Response} U
@@ -193,9 +174,14 @@ declare class Server {
                  * @typedef {Array<{ key: string; value: string }> | Record<string, string | string[]>} Headers
                  */
                 /**
-                 * @typedef {{ name?: string, path?: string, middleware: ExpressRequestHandler | ExpressErrorRequestHandler } | ExpressRequestHandler | ExpressErrorRequestHandler} Middleware
+                 * @template {BasicApplication} [T=ExpressApplication]
+                 * @typedef {T extends ExpressApplication ? ExpressRequestHandler | ExpressErrorRequestHandler : HandleFunction} MiddlewareHandler
+                 */
+                /**
+                 * @typedef {{ name?: string, path?: string, middleware: MiddlewareHandler } | MiddlewareHandler } Middleware
                  */
                 /**
+                 * @template {BasicApplication} [T=ExpressApplication]
                  * @typedef {Object} Configuration
                  * @property {boolean | string} [ipc]
                  * @property {Host} [host]
@@ -210,17 +196,84 @@ declare class Server {
                  * @property {string | string[] | WatchFiles | Array<string | WatchFiles>} [watchFiles]
                  * @property {boolean | string | Static | Array<string | Static>} [static]
                  * @property {boolean | ServerOptions} [https]
-                 * @property {boolean} [http2]
                  * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server]
+                 * @property {() => Promise<T>} [app]
                  * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer]
                  * @property {ProxyConfigArray} [proxy]
                  * @property {boolean | string | Open | Array<string | Open>} [open]
                  * @property {boolean} [setupExitSignals]
                  * @property {boolean | ClientConfiguration} [client]
                  * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response>) => Headers)} [headers]
-                 * @property {(devServer: Server) => void} [onListening]
-                 * @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares]
+                 * @property {(devServer: Server<T>) => void} [onListening]
+                 * @property {(middlewares: Middleware[], devServer: Server<T>) => Middleware[]} [setupMiddlewares]
                  */
+                $ref: string;
+              };
+              enum?: undefined;
+              $ref?: undefined;
+            }
+          | {
+              enum: string[];
+              type?: undefined;
+              minItems?: undefined;
+              items?: undefined;
+              $ref?: undefined;
+            }
+          | {
+              $ref: string;
+              type?: undefined;
+              minItems?: undefined;
+              items?: undefined;
+              enum?: undefined;
+            }
+        )[];
+        description: string;
+        link: string;
+      };
+      AllowedHostsItem: {
+        type: string;
+        minLength: number;
+      };
+      Bonjour: {
+        anyOf: (
+          | {
+              type: string;
+              cli: {
+                negatedDescription: string;
+              };
+              description?: undefined;
+              link?: undefined;
+            }
+          | {
+              type: string;
+              description: string;
+              link: string;
+              cli?: undefined;
+            }
+        )[];
+        description: string;
+        link: string;
+      };
+      Client: {
+        description: string;
+        link: string;
+        anyOf: (
+          | {
+              enum: boolean[];
+              cli: {
+                negatedDescription: string;
+              };
+              type?: undefined;
+              additionalProperties?: undefined;
+              properties?: undefined;
+            }
+          | {
+              type: string;
+              additionalProperties: boolean;
+              properties: {
+                logging: {
+                  $ref: string;
+                };
                 overlay: {
                   $ref: string;
                 };
@@ -234,6 +287,157 @@ declare class Server {
                   $ref: string;
                 };
                 webSocketURL: {
+                  /** @typedef {SimpleHandleFunction | NextHandleFunction | ErrorHandleFunction} HandleFunction */
+                  /** @typedef {import("https").ServerOptions & { spdy?: { plain?: boolean | undefined, ssl?: boolean | undefined, 'x-forwarded-for'?: string | undefined, protocol?: string | undefined, protocols?: string[] | undefined }}} ServerOptions */
+                  /**
+                   * @template {BasicApplication} [T=ExpressApplication]
+                   * @typedef {T extends ExpressApplication ? ExpressRequest : IncomingMessage} Request
+                   */
+                  /**
+                   * @template {BasicApplication} [T=ExpressApplication]
+                   * @typedef {T extends ExpressApplication ? ExpressResponse : ServerResponse} Response
+                   */
+                  /**
+                   * @template {Request} T
+                   * @template {Response} U
+                   * @typedef {import("webpack-dev-middleware").Options<T, U>} DevMiddlewareOptions
+                   */
+                  /**
+                   * @template {Request} T
+                   * @template {Response} U
+                   * @typedef {import("webpack-dev-middleware").Context<T, U>} DevMiddlewareContext
+                   */
+                  /**
+                   * @typedef {"local-ip" | "local-ipv4" | "local-ipv6" | string} Host
+                   */
+                  /**
+                   * @typedef {number | string | "auto"} Port
+                   */
+                  /**
+                   * @typedef {Object} WatchFiles
+                   * @property {string | string[]} paths
+                   * @property {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [options]
+                   */
+                  /**
+                   * @typedef {Object} Static
+                   * @property {string} [directory]
+                   * @property {string | string[]} [publicPath]
+                   * @property {boolean | ServeIndexOptions} [serveIndex]
+                   * @property {ServeStaticOptions} [staticOptions]
+                   * @property {boolean | WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [watch]
+                   */
+                  /**
+                   * @typedef {Object} NormalizedStatic
+                   * @property {string} directory
+                   * @property {string[]} publicPath
+                   * @property {false | ServeIndexOptions} serveIndex
+                   * @property {ServeStaticOptions} staticOptions
+                   * @property {false | WatchOptions} watch
+                   */
+                  /**
+                   * @typedef {Object} ServerConfiguration
+                   * @property {"http" | "https" | "spdy" | string} [type]
+                   * @property {ServerOptions} [options]
+                   */
+                  /**
+                   * @typedef {Object} WebSocketServerConfiguration
+                   * @property {"sockjs" | "ws" | string | Function} [type]
+                   * @property {Record<string, any>} [options]
+                   */
+                  /**
+                   * @typedef {(import("ws").WebSocket | import("sockjs").Connection & { send: import("ws").WebSocket["send"], terminate: import("ws").WebSocket["terminate"], ping: import("ws").WebSocket["ping"] }) & { isAlive?: boolean }} ClientConnection
+                   */
+                  /**
+                   * @typedef {import("ws").WebSocketServer | import("sockjs").Server & { close: import("ws").WebSocketServer["close"] }} WebSocketServer
+                   */
+                  /**
+                   * @typedef {{ implementation: WebSocketServer, clients: ClientConnection[] }} WebSocketServerImplementation
+                   */
+                  /**
+                   * @callback ByPass
+                   * @param {Request} req
+                   * @param {Response} res
+                   * @param {ProxyConfigArrayItem} proxyConfig
+                   */
+                  /**
+                   * @typedef {{ path?: HttpProxyMiddlewareOptionsFilter | undefined, context?: HttpProxyMiddlewareOptionsFilter | undefined } & { bypass?: ByPass } & HttpProxyMiddlewareOptions } ProxyConfigArrayItem
+                   */
+                  /**
+                   * @typedef {(ProxyConfigArrayItem | ((req?: Request | undefined, res?: Response | undefined, next?: NextFunction | undefined) => ProxyConfigArrayItem))[]} ProxyConfigArray
+                   */
+                  /**
+                   * @typedef {Object} OpenApp
+                   * @property {string} [name]
+                   * @property {string[]} [arguments]
+                   */
+                  /**
+                   * @typedef {Object} Open
+                   * @property {string | string[] | OpenApp} [app]
+                   * @property {string | string[]} [target]
+                   */
+                  /**
+                   * @typedef {Object} NormalizedOpen
+                   * @property {string} target
+                   * @property {import("open").Options} options
+                   */
+                  /**
+                   * @typedef {Object} WebSocketURL
+                   * @property {string} [hostname]
+                   * @property {string} [password]
+                   * @property {string} [pathname]
+                   * @property {number | string} [port]
+                   * @property {string} [protocol]
+                   * @property {string} [username]
+                   */
+                  /**
+                   * @typedef {boolean | ((error: Error) => void)} OverlayMessageOptions
+                   */
+                  /**
+                   * @typedef {Object} ClientConfiguration
+                   * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"} [logging]
+                   * @property {boolean  | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions }} [overlay]
+                   * @property {boolean} [progress]
+                   * @property {boolean | number} [reconnect]
+                   * @property {"ws" | "sockjs" | string} [webSocketTransport]
+                   * @property {string | WebSocketURL} [webSocketURL]
+                   */
+                  /**
+                   * @typedef {Array<{ key: string; value: string }> | Record<string, string | string[]>} Headers
+                   */
+                  /**
+                   * @template {BasicApplication} [T=ExpressApplication]
+                   * @typedef {T extends ExpressApplication ? ExpressRequestHandler | ExpressErrorRequestHandler : HandleFunction} MiddlewareHandler
+                   */
+                  /**
+                   * @typedef {{ name?: string, path?: string, middleware: MiddlewareHandler } | MiddlewareHandler } Middleware
+                   */
+                  /**
+                   * @template {BasicApplication} [T=ExpressApplication]
+                   * @typedef {Object} Configuration
+                   * @property {boolean | string} [ipc]
+                   * @property {Host} [host]
+                   * @property {Port} [port]
+                   * @property {boolean | "only"} [hot]
+                   * @property {boolean} [liveReload]
+                   * @property {DevMiddlewareOptions<Request, Response>} [devMiddleware]
+                   * @property {boolean} [compress]
+                   * @property {"auto" | "all" | string | string[]} [allowedHosts]
+                   * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback]
+                   * @property {boolean | Record<string, never> | BonjourOptions} [bonjour]
+                   * @property {string | string[] | WatchFiles | Array<string | WatchFiles>} [watchFiles]
+                   * @property {boolean | string | Static | Array<string | Static>} [static]
+                   * @property {boolean | ServerOptions} [https]
+                   * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server]
+                   * @property {() => Promise<T>} [app]
+                   * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer]
+                   * @property {ProxyConfigArray} [proxy]
+                   * @property {boolean | string | Open | Array<string | Open>} [open]
+                   * @property {boolean} [setupExitSignals]
+                   * @property {boolean | ClientConfiguration} [client]
+                   * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response>) => Headers)} [headers]
+                   * @property {(devServer: Server<T>) => void} [onListening]
+                   * @property {(middlewares: Middleware[], devServer: Server<T>) => Middleware[]} [setupMiddlewares]
+                   */
                   $ref: string;
                 };
               };
@@ -286,15 +490,125 @@ declare class Server {
                     | {
                         description: string;
                         type: string;
+                        /**
+                         * @typedef {Object} NormalizedStatic
+                         * @property {string} directory
+                         * @property {string[]} publicPath
+                         * @property {false | ServeIndexOptions} serveIndex
+                         * @property {ServeStaticOptions} staticOptions
+                         * @property {false | WatchOptions} watch
+                         */
+                        /**
+                         * @typedef {Object} ServerConfiguration
+                         * @property {"http" | "https" | "spdy" | string} [type]
+                         * @property {ServerOptions} [options]
+                         */
+                        /**
+                         * @typedef {Object} WebSocketServerConfiguration
+                         * @property {"sockjs" | "ws" | string | Function} [type]
+                         * @property {Record<string, any>} [options]
+                         */
+                        /**
+                         * @typedef {(import("ws").WebSocket | import("sockjs").Connection & { send: import("ws").WebSocket["send"], terminate: import("ws").WebSocket["terminate"], ping: import("ws").WebSocket["ping"] }) & { isAlive?: boolean }} ClientConnection
+                         */
+                        /**
+                         * @typedef {import("ws").WebSocketServer | import("sockjs").Server & { close: import("ws").WebSocketServer["close"] }} WebSocketServer
+                         */
+                        /**
+                         * @typedef {{ implementation: WebSocketServer, clients: ClientConnection[] }} WebSocketServerImplementation
+                         */
+                        /**
+                         * @callback ByPass
+                         * @param {Request} req
+                         * @param {Response} res
+                         * @param {ProxyConfigArrayItem} proxyConfig
+                         */
+                        /**
+                         * @typedef {{ path?: HttpProxyMiddlewareOptionsFilter | undefined, context?: HttpProxyMiddlewareOptionsFilter | undefined } & { bypass?: ByPass } & HttpProxyMiddlewareOptions } ProxyConfigArrayItem
+                         */
+                        /**
+                         * @typedef {(ProxyConfigArrayItem | ((req?: Request | undefined, res?: Response | undefined, next?: NextFunction | undefined) => ProxyConfigArrayItem))[]} ProxyConfigArray
+                         */
+                        /**
+                         * @typedef {Object} OpenApp
+                         * @property {string} [name]
+                         * @property {string[]} [arguments]
+                         */
+                        /**
+                         * @typedef {Object} Open
+                         * @property {string | string[] | OpenApp} [app]
+                         * @property {string | string[]} [target]
+                         */
+                        /**
+                         * @typedef {Object} NormalizedOpen
+                         * @property {string} target
+                         * @property {import("open").Options} options
+                         */
+                        /**
+                         * @typedef {Object} WebSocketURL
+                         * @property {string} [hostname]
+                         * @property {string} [password]
+                         * @property {string} [pathname]
+                         * @property {number | string} [port]
+                         * @property {string} [protocol]
+                         * @property {string} [username]
+                         */
+                        /**
+                         * @typedef {boolean | ((error: Error) => void)} OverlayMessageOptions
+                         */
+                        /**
+                         * @typedef {Object} ClientConfiguration
+                         * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"} [logging]
+                         * @property {boolean  | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions }} [overlay]
+                         * @property {boolean} [progress]
+                         * @property {boolean | number} [reconnect]
+                         * @property {"ws" | "sockjs" | string} [webSocketTransport]
+                         * @property {string | WebSocketURL} [webSocketURL]
+                         */
+                        /**
+                         * @typedef {Array<{ key: string; value: string }> | Record<string, string | string[]>} Headers
+                         */
+                        /**
+                         * @template {BasicApplication} [T=ExpressApplication]
+                         * @typedef {T extends ExpressApplication ? ExpressRequestHandler | ExpressErrorRequestHandler : HandleFunction} MiddlewareHandler
+                         */
+                        /**
+                         * @typedef {{ name?: string, path?: string, middleware: MiddlewareHandler } | MiddlewareHandler } Middleware
+                         */
+                        /**
+                         * @template {BasicApplication} [T=ExpressApplication]
+                         * @typedef {Object} Configuration
+                         * @property {boolean | string} [ipc]
+                         * @property {Host} [host]
+                         * @property {Port} [port]
+                         * @property {boolean | "only"} [hot]
+                         * @property {boolean} [liveReload]
+                         * @property {DevMiddlewareOptions<Request, Response>} [devMiddleware]
+                         * @property {boolean} [compress]
+                         * @property {"auto" | "all" | string | string[]} [allowedHosts]
+                         * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback]
+                         * @property {boolean | Record<string, never> | BonjourOptions} [bonjour]
+                         * @property {string | string[] | WatchFiles | Array<string | WatchFiles>} [watchFiles]
+                         * @property {boolean | string | Static | Array<string | Static>} [static]
+                         * @property {boolean | ServerOptions} [https]
+                         * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server]
+                         * @property {() => Promise<T>} [app]
+                         * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer]
+                         * @property {ProxyConfigArray} [proxy]
+                         * @property {boolean | string | Open | Array<string | Open>} [open]
+                         * @property {boolean} [setupExitSignals]
+                         * @property {boolean | ClientConfiguration} [client]
+                         * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response>) => Headers)} [headers]
+                         * @property {(devServer: Server<T>) => void} [onListening]
+                         * @property {(middlewares: Middleware[], devServer: Server<T>) => Middleware[]} [setupMiddlewares]
+                         */
                         cli: {
                           negatedDescription: string;
                         };
                         instanceof?: undefined;
                       }
                     | {
-                        instanceof: string /**
-                         * @typedef {import("ws").WebSocketServer | import("sockjs").Server & { close: import("ws").WebSocketServer["close"] }} WebSocketServer
-                         */;
+                        instanceof: string;
                         description: string;
                         type?: undefined;
                         cli?: undefined;
@@ -319,6 +633,91 @@ declare class Server {
                       }
                   )[];
                 };
+                /**
+                 * @callback ByPass
+                 * @param {Request} req
+                 * @param {Response} res
+                 * @param {ProxyConfigArrayItem} proxyConfig
+                 */
+                /**
+                 * @typedef {{ path?: HttpProxyMiddlewareOptionsFilter | undefined, context?: HttpProxyMiddlewareOptionsFilter | undefined } & { bypass?: ByPass } & HttpProxyMiddlewareOptions } ProxyConfigArrayItem
+                 */
+                /**
+                 * @typedef {(ProxyConfigArrayItem | ((req?: Request | undefined, res?: Response | undefined, next?: NextFunction | undefined) => ProxyConfigArrayItem))[]} ProxyConfigArray
+                 */
+                /**
+                 * @typedef {Object} OpenApp
+                 * @property {string} [name]
+                 * @property {string[]} [arguments]
+                 */
+                /**
+                 * @typedef {Object} Open
+                 * @property {string | string[] | OpenApp} [app]
+                 * @property {string | string[]} [target]
+                 */
+                /**
+                 * @typedef {Object} NormalizedOpen
+                 * @property {string} target
+                 * @property {import("open").Options} options
+                 */
+                /**
+                 * @typedef {Object} WebSocketURL
+                 * @property {string} [hostname]
+                 * @property {string} [password]
+                 * @property {string} [pathname]
+                 * @property {number | string} [port]
+                 * @property {string} [protocol]
+                 * @property {string} [username]
+                 */
+                /**
+                 * @typedef {boolean | ((error: Error) => void)} OverlayMessageOptions
+                 */
+                /**
+                 * @typedef {Object} ClientConfiguration
+                 * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"} [logging]
+                 * @property {boolean  | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions }} [overlay]
+                 * @property {boolean} [progress]
+                 * @property {boolean | number} [reconnect]
+                 * @property {"ws" | "sockjs" | string} [webSocketTransport]
+                 * @property {string | WebSocketURL} [webSocketURL]
+                 */
+                /**
+                 * @typedef {Array<{ key: string; value: string }> | Record<string, string | string[]>} Headers
+                 */
+                /**
+                 * @template {BasicApplication} [T=ExpressApplication]
+                 * @typedef {T extends ExpressApplication ? ExpressRequestHandler | ExpressErrorRequestHandler : HandleFunction} MiddlewareHandler
+                 */
+                /**
+                 * @typedef {{ name?: string, path?: string, middleware: MiddlewareHandler } | MiddlewareHandler } Middleware
+                 */
+                /**
+                 * @template {BasicApplication} [T=ExpressApplication]
+                 * @typedef {Object} Configuration
+                 * @property {boolean | string} [ipc]
+                 * @property {Host} [host]
+                 * @property {Port} [port]
+                 * @property {boolean | "only"} [hot]
+                 * @property {boolean} [liveReload]
+                 * @property {DevMiddlewareOptions<Request, Response>} [devMiddleware]
+                 * @property {boolean} [compress]
+                 * @property {"auto" | "all" | string | string[]} [allowedHosts]
+                 * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback]
+                 * @property {boolean | Record<string, never> | BonjourOptions} [bonjour]
+                 * @property {string | string[] | WatchFiles | Array<string | WatchFiles>} [watchFiles]
+                 * @property {boolean | string | Static | Array<string | Static>} [static]
+                 * @property {boolean | ServerOptions} [https]
+                 * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server]
+                 * @property {() => Promise<T>} [app]
+                 * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer]
+                 * @property {ProxyConfigArray} [proxy]
+                 * @property {boolean | string | Open | Array<string | Open>} [open]
+                 * @property {boolean} [setupExitSignals]
+                 * @property {boolean | ClientConfiguration} [client]
+                 * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response>) => Headers)} [headers]
+                 * @property {(devServer: Server<T>) => void} [onListening]
+                 * @property {(middlewares: Middleware[], devServer: Server<T>) => Middleware[]} [setupMiddlewares]
+                 */
                 trustedTypesPolicyName: {
                   description: string;
                   type: string;
@@ -357,35 +756,6 @@ declare class Server {
         )[];
       };
       ClientWebSocketTransport: {
-        /**
-         * @typedef {{ name?: string, path?: string, middleware: ExpressRequestHandler | ExpressErrorRequestHandler } | ExpressRequestHandler | ExpressErrorRequestHandler} Middleware
-         */
-        /**
-         * @typedef {Object} Configuration
-         * @property {boolean | string} [ipc]
-         * @property {Host} [host]
-         * @property {Port} [port]
-         * @property {boolean | "only"} [hot]
-         * @property {boolean} [liveReload]
-         * @property {DevMiddlewareOptions<Request, Response>} [devMiddleware]
-         * @property {boolean} [compress]
-         * @property {"auto" | "all" | string | string[]} [allowedHosts]
-         * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback]
-         * @property {boolean | Record<string, never> | BonjourOptions} [bonjour]
-         * @property {string | string[] | WatchFiles | Array<string | WatchFiles>} [watchFiles]
-         * @property {boolean | string | Static | Array<string | Static>} [static]
-         * @property {boolean | ServerOptions} [https]
-         * @property {boolean} [http2]
-         * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server]
-         * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer]
-         * @property {ProxyConfigArray} [proxy]
-         * @property {boolean | string | Open | Array<string | Open>} [open]
-         * @property {boolean} [setupExitSignals]
-         * @property {boolean | ClientConfiguration} [client]
-         * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response>) => Headers)} [headers]
-         * @property {(devServer: Server) => void} [onListening]
-         * @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares]
-         */
         anyOf: {
           $ref: string;
         }[];
@@ -465,10 +835,15 @@ declare class Server {
       };
       Compress: {
         type: string;
+        /**
+         * @template T
+         * @param fn {(function(): any) | undefined}
+         * @returns {function(): T}
+         */
         description: string;
         link: string;
         cli: {
-          negatedDescription: string;
+          negatedDescription: string /** @type {function(): any} */;
         };
       };
       DevMiddleware: {
@@ -479,9 +854,6 @@ declare class Server {
       };
       HeaderObject: {
         type: string;
-        /**
-         * @type {FSWatcher[]}
-         */
         additionalProperties: boolean;
         properties: {
           key: {
@@ -545,10 +917,17 @@ declare class Server {
       };
       Host: {
         description: string;
+        /**
+         * @private
+         * @type {RequestHandler[]}
+         */
         link: string;
         anyOf: (
           | {
               enum: string[];
+              /**
+               * @type {Socket[]}
+               */
               type?: undefined;
               minLength?: undefined;
             }
@@ -731,7 +1110,7 @@ declare class Server {
             }
         )[];
         description: string;
-        link: string /** @type {WebSocketURL} */;
+        link: string;
       };
       Proxy: {
         type: string;
@@ -743,7 +1122,6 @@ declare class Server {
               }
             | {
                 instanceof: string;
-                /** @type {{ type: WebSocketServerConfiguration["type"], options: NonNullable<WebSocketServerConfiguration["options"]> }} */
                 type?: undefined;
               }
           )[];
@@ -759,7 +1137,10 @@ declare class Server {
         description: string;
       };
       ServerType: {
-        enum: string[];
+        enum: string[] /**
+         * @private
+         * @param {Compiler} compiler
+         */;
       };
       ServerEnum: {
         enum: string[];
@@ -770,7 +1151,6 @@ declare class Server {
       ServerString: {
         type: string;
         minLength: number;
-        /** @type {string} */
         cli: {
           exclude: boolean;
         };
@@ -784,7 +1164,7 @@ declare class Server {
             }[];
           };
           options: {
-            $ref: string;
+            $ref: string /** @type {{ type: WebSocketServerConfiguration["type"], options: NonNullable<WebSocketServerConfiguration["options"]> }} */;
           };
         };
         additionalProperties: boolean;
@@ -795,13 +1175,14 @@ declare class Server {
         properties: {
           passphrase: {
             type: string;
+            /** @type {string} */
             description: string;
           };
           requestCert: {
             type: string;
             description: string;
             cli: {
-              negatedDescription: string;
+              negatedDescription: string /** @type {ServerConfiguration} */;
             };
           };
           ca: {
@@ -1104,7 +1485,7 @@ declare class Server {
                   $ref: string;
                 }[];
               };
-              $ref?: undefined;
+              /** @type {MultiCompiler} */ $ref?: undefined;
             }
           | {
               $ref: string;
@@ -1259,6 +1640,9 @@ declare class Server {
       server: {
         $ref: string;
       };
+      app: {
+        $ref: string;
+      };
       setupExitSignals: {
         $ref: string;
       };
@@ -1318,23 +1702,19 @@ declare class Server {
    */
   private static isWebTarget;
   /**
-   * @param {Configuration | Compiler | MultiCompiler} options
-   * @param {Compiler | MultiCompiler | Configuration} compiler
+   * @param {Configuration<T>} options
+   * @param {Compiler | MultiCompiler} compiler
    */
   constructor(
-    options:
-      | import("webpack").Compiler
-      | import("webpack").MultiCompiler
-      | Configuration
-      | undefined,
-    compiler: Compiler | MultiCompiler | Configuration,
+    options: Configuration<T> | undefined,
+    compiler: Compiler | MultiCompiler,
   );
   compiler: import("webpack").Compiler | import("webpack").MultiCompiler;
   /**
    * @type {ReturnType<Compiler["getInfrastructureLogger"]>}
    * */
   logger: ReturnType<Compiler["getInfrastructureLogger"]>;
-  options: Configuration;
+  options: Configuration<T>;
   /**
    * @type {FSWatcher[]}
    */
@@ -1395,11 +1775,11 @@ declare class Server {
   private initialize;
   /**
    * @private
-   * @returns {void}
+   * @returns {Promise<void>}
    */
   private setupApp;
-  /** @type {import("express").Application | undefined}*/
-  app: import("express").Application | undefined;
+  /** @type {T | undefined}*/
+  app: T | undefined;
   /**
    * @private
    * @param {Stats | MultiStats} statsObj
@@ -1575,9 +1955,6 @@ declare namespace Server {
     Stats,
     MultiStats,
     NetworkInterfaceInfo,
-    NextFunction,
-    ExpressRequestHandler,
-    ExpressErrorRequestHandler,
     WatchOptions,
     FSWatcher,
     ConnectHistoryApiFallbackOptions,
@@ -1594,6 +1971,16 @@ declare namespace Server {
     IncomingMessage,
     ServerResponse,
     OpenOptions,
+    ExpressApplication,
+    ExpressRequestHandler,
+    ExpressErrorRequestHandler,
+    ExpressRequest,
+    ExpressResponse,
+    NextFunction,
+    SimpleHandleFunction,
+    NextHandleFunction,
+    ErrorHandleFunction,
+    HandleFunction,
     ServerOptions,
     Request,
     Response,
@@ -1619,8 +2006,10 @@ declare namespace Server {
     OverlayMessageOptions,
     ClientConfiguration,
     Headers,
+    MiddlewareHandler,
     Middleware,
     Configuration,
+    BasicApplication,
   };
 }
 type Compiler = import("webpack").Compiler;
@@ -1641,9 +2030,6 @@ type StatsCompilation = import("webpack").StatsCompilation;
 type Stats = import("webpack").Stats;
 type MultiStats = import("webpack").MultiStats;
 type NetworkInterfaceInfo = import("os").NetworkInterfaceInfo;
-type NextFunction = import("express").NextFunction;
-type ExpressRequestHandler = import("express").RequestHandler;
-type ExpressErrorRequestHandler = import("express").ErrorRequestHandler;
 type WatchOptions = import("chokidar").WatchOptions;
 type ConnectHistoryApiFallbackOptions =
   import("connect-history-api-fallback").Options;
@@ -1659,6 +2045,28 @@ type IPv6 = import("ipaddr.js").IPv6;
 type IncomingMessage = import("http").IncomingMessage;
 type ServerResponse = import("http").ServerResponse;
 type OpenOptions = import("open").Options;
+type ExpressApplication = import("express").Application;
+type ExpressRequestHandler = import("express").RequestHandler;
+type ExpressErrorRequestHandler = import("express").ErrorRequestHandler;
+type ExpressRequest = import("express").Request;
+type ExpressResponse = import("express").Response;
+type NextFunction = (err?: any) => void;
+type SimpleHandleFunction = (req: IncomingMessage, res: ServerResponse) => void;
+type NextHandleFunction = (
+  req: IncomingMessage,
+  res: ServerResponse,
+  next: NextFunction,
+) => void;
+type ErrorHandleFunction = (
+  err: any,
+  req: IncomingMessage,
+  res: ServerResponse,
+  next: NextFunction,
+) => void;
+type HandleFunction =
+  | SimpleHandleFunction
+  | NextHandleFunction
+  | ErrorHandleFunction;
 type ServerOptions = import("https").ServerOptions & {
   spdy?: {
     plain?: boolean | undefined;
@@ -1668,8 +2076,10 @@ type ServerOptions = import("https").ServerOptions & {
     protocols?: string[] | undefined;
   };
 };
-type Request = import("express").Request;
-type Response = import("express").Response;
+type Request<T extends BasicApplication = import("express").Application> =
+  T extends ExpressApplication ? ExpressRequest : IncomingMessage;
+type Response<T extends BasicApplication = import("express").Application> =
+  T extends ExpressApplication ? ExpressResponse : ServerResponse;
 type DevMiddlewareOptions<
   T extends import("express").Request<
     import("express-serve-static-core").ParamsDictionary,
@@ -1811,72 +2221,102 @@ type Headers =
       value: string;
     }>
   | Record<string, string | string[]>;
+type MiddlewareHandler<
+  T extends BasicApplication = import("express").Application,
+> = T extends ExpressApplication
+  ? ExpressRequestHandler | ExpressErrorRequestHandler
+  : HandleFunction;
 type Middleware =
   | {
       name?: string;
       path?: string;
-      middleware: ExpressRequestHandler | ExpressErrorRequestHandler;
+      middleware: MiddlewareHandler;
     }
-  | ExpressRequestHandler
-  | ExpressErrorRequestHandler;
-type Configuration = {
-  ipc?: string | boolean | undefined;
-  host?: string | undefined;
-  port?: Port | undefined;
-  hot?: boolean | "only" | undefined;
-  liveReload?: boolean | undefined;
-  devMiddleware?:
-    | DevMiddlewareOptions<
-        import("express").Request<
-          import("express-serve-static-core").ParamsDictionary,
-          any,
-          any,
-          qs.ParsedQs,
-          Record<string, any>
-        >,
-        import("express").Response<any, Record<string, any>>
-      >
-    | undefined;
-  compress?: boolean | undefined;
-  allowedHosts?: string | string[] | undefined;
-  historyApiFallback?:
-    | boolean
-    | import("connect-history-api-fallback").Options
-    | undefined;
-  bonjour?:
-    | boolean
-    | Record<string, never>
-    | import("bonjour-service").Service
-    | undefined;
-  watchFiles?:
-    | string
-    | string[]
-    | WatchFiles
-    | (string | WatchFiles)[]
-    | undefined;
-  static?: string | boolean | Static | (string | Static)[] | undefined;
-  https?: boolean | ServerOptions | undefined;
-  http2?: boolean | undefined;
-  server?: string | ServerConfiguration | undefined;
-  webSocketServer?: string | boolean | WebSocketServerConfiguration | undefined;
-  proxy?: ProxyConfigArray | undefined;
-  open?: string | boolean | Open | (string | Open)[] | undefined;
-  setupExitSignals?: boolean | undefined;
-  client?: boolean | ClientConfiguration | undefined;
-  headers?:
-    | Headers
-    | ((
-        req: Request,
-        res: Response,
-        context: DevMiddlewareContext<Request, Response>,
-      ) => Headers)
-    | undefined;
-  onListening?: ((devServer: Server) => void) | undefined;
-  setupMiddlewares?:
-    | ((middlewares: Middleware[], devServer: Server) => Middleware[])
-    | undefined;
+  | MiddlewareHandler;
+type Configuration<T extends BasicApplication = import("express").Application> =
+  {
+    ipc?: string | boolean | undefined;
+    host?: string | undefined;
+    port?: Port | undefined;
+    hot?: boolean | "only" | undefined;
+    liveReload?: boolean | undefined;
+    devMiddleware?:
+      | DevMiddlewareOptions<
+          import("express").Request<
+            import("express-serve-static-core").ParamsDictionary,
+            any,
+            any,
+            qs.ParsedQs,
+            Record<string, any>
+          >,
+          import("express").Response<any, Record<string, any>>
+        >
+      | undefined;
+    compress?: boolean | undefined;
+    allowedHosts?: string | string[] | undefined;
+    historyApiFallback?:
+      | boolean
+      | import("connect-history-api-fallback").Options
+      | undefined;
+    bonjour?:
+      | boolean
+      | Record<string, never>
+      | import("bonjour-service").Service
+      | undefined;
+    watchFiles?:
+      | string
+      | string[]
+      | WatchFiles
+      | (string | WatchFiles)[]
+      | undefined;
+    static?: string | boolean | Static | (string | Static)[] | undefined;
+    https?: boolean | ServerOptions | undefined;
+    server?: string | ServerConfiguration | undefined;
+    app?: (() => Promise<T>) | undefined;
+    webSocketServer?:
+      | string
+      | boolean
+      | WebSocketServerConfiguration
+      | undefined;
+    proxy?: ProxyConfigArray | undefined;
+    open?: string | boolean | Open | (string | Open)[] | undefined;
+    setupExitSignals?: boolean | undefined;
+    client?: boolean | ClientConfiguration | undefined;
+    headers?:
+      | Headers
+      | ((
+          req: Request,
+          res: Response,
+          context: DevMiddlewareContext<Request, Response>,
+        ) => Headers)
+      | undefined;
+    onListening?: ((devServer: Server<T>) => void) | undefined;
+    setupMiddlewares?:
+      | ((middlewares: Middleware[], devServer: Server<T>) => Middleware[])
+      | undefined;
+  };
+type BasicApplication = {
+  use: typeof useFn;
 };
-import path = require("path");
+/**
+ * @overload
+ * @param {NextHandleFunction} fn
+ * @returns {BasicApplication}
+ */
+declare function useFn(fn: NextHandleFunction): BasicApplication;
+/**
+ * @overload
+ * @param {HandleFunction} fn
+ * @returns {BasicApplication}
+ */
+declare function useFn(fn: HandleFunction): BasicApplication;
+/**
+ * @overload
+ * @param {string} route
+ * @param {NextHandleFunction} fn
+ * @returns {BasicApplication}
+ */
+declare function useFn(route: string, fn: NextHandleFunction): BasicApplication;
 
 // DO NOT REMOVE THIS!
 type DevServerConfiguration = Configuration;