function koaWrapper(compiler, options) {
  const devMiddleware = wdm(compiler, options);

  // eslint-disable-next-line jsdoc/no-restricted-syntax
  /**
   * @param {{req: RequestInternal, res: ResponseInternal & import("./utils/compatibleAPI").ExpectedServerResponse, status: number, body: string | Buffer | import("fs").ReadStream | {message: string}, state: object}} ctx context
   * @param {Function} next next
   * @returns {Promise<void>}
   */
  async function webpackDevMiddleware(ctx, next) {
    const { req, res } = ctx;

    res.locals = ctx.state;

    let { status } = ctx;

    /**
     * @returns {number} code
     */
    res.getStatusCode = () => status;

    /**
     * @param {number} statusCode status code
     */
    res.setStatusCode = (statusCode) => {
      status = statusCode;

      ctx.status = statusCode;
    };

    res.getReadyReadableStreamState = () => "open";

    try {
      await new Promise(
        /**
         * @param {(value: void) => void} resolve resolve
         * @param {(reason?: Error) => void} reject reject
         */
        (resolve, reject) => {
          /**
           * @param {import("fs").ReadStream} stream readable stream
           */
          res.stream = (stream) => {
            ctx.body = stream;
          };
          /**
           * @param {string | Buffer} data data
           */
          res.send = (data) => {
            ctx.body = data;
          };

          /**
           * @param {(string | Buffer)=} data data
           */
          res.finish = (data) => {
            ctx.status = status;
            res.end(data);
          };

          devMiddleware(req, res, (err) => {
            if (err) {
              reject(err);
              return;
            }

            resolve();
          });
        },
      );
    } catch (err) {
      ctx.status =
        /** @type {Error & { statusCode: number }} */ (err).statusCode ||
        /** @type {Error & { status: number }} */ (err).status ||
        500;

      ctx.body = {
        message: /** @type {Error} */ (err).message,
      };
    }

    await next();
  }

  webpackDevMiddleware.devMiddleware = devMiddleware;

  return webpackDevMiddleware;
}
@template {IncomingMessage} [RequestInternal=IncomingMessage]
@template {ServerResponse} [ResponseInternal=ServerResponse]
@param {Compiler | MultiCompiler} compiler compiler
@param {Options<RequestInternal, ResponseInternal>=} options options
@returns {(ctx: any, next: Function) => Promise<void> | void} kow wrapper