Repository: octokit/webhooks.js
Pull request #502 (2021-03-21 19:22:18)

ci: update PR body text to reflect npm package name
Small change to the body text to use the npm package name instead of `@octokit/webhooks` which could lead to confusion between the npm package published from this repo and `@octokit/webhooks-definitions`


Patch:
diff --git a/.github/workflows/update.yml b/.github/workflows/update.yml
index 4628b31..e1a2e61 100644
--- a/.github/workflows/update.yml
+++ b/.github/workflows/update.yml
@@ -23,7 +23,7 @@ jobs:
           GITHUB_TOKEN: "${{ secrets.OCTOKITBOT_PAT }}"
         with:
           title: "\U0001F6A7 \U0001F916\U0001F4EF Webhooks changed"
-          body: "A new release of [@octokit/webhooks](https://github.com/octokit/webhooks) was just released \U0001F44B\U0001F916\n\nThis pull request updates the TypeScript definitions derived from `@octokit/webhooks`. I can't tell if the changes are fixes, features or breaking, you'll have to figure that out on yourself and adapt the commit messages accordingly to trigger the right release, see [our commit message conventions](https://github.com/octokit/openapi/blob/main/CONTRIBUTING.md#merging-the-pull-request--releasing-a-new-version).\n"
+          body: "A new release of [@octokit/webhooks-definitions](https://github.com/octokit/webhooks) was just released \U0001F44B\U0001F916\n\nThis pull request updates the TypeScript definitions derived from `@octokit/webhooks-definitions`. I can't tell if the changes are fixes, features or breaking, you'll have to figure that out on yourself and adapt the commit messages accordingly to trigger the right release, see [our commit message conventions](https://github.com/octokit/openapi/blob/main/CONTRIBUTING.md#merging-the-pull-request--releasing-a-new-version).\n"
           branch: "update-octokit-webhooks"
           author: Octokit Bot <octokitbot@martynus.net>
           commit-message: "WIP: Webhooks changed - please review"
diff --git a/README.md b/README.md
index cbc6359..6054872 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@
   - [webhooks.onAny()](#webhooksonany)
   - [webhooks.onError()](#webhooksonerror)
   - [webhooks.removeListener()](#webhooksremovelistener)
-  - [webhooks.middleware()](#webhooksmiddleware)
+  - [createNodeMiddleware()](#createnodemiddleware)
   - [Webhook events](#webhook-events)
 - [TypeScript](#typescript)
   - [`EmitterWebhookEventName`](#emitterwebhookeventname)
@@ -42,7 +42,7 @@ Note that while setting a secret is optional on GitHub, it is required to be set
 
 ```js
 // install with: npm install @octokit/webhooks
-const { Webhooks } = require("@octokit/webhooks");
+const { Webhooks, createNodeMiddleware } = require("@octokit/webhooks");
 const webhooks = new Webhooks({
   secret: "mysecret",
 });
@@ -51,8 +51,8 @@ webhooks.onAny(({ id, name, payload }) => {
   console.log(name, "event received");
 });
 
-require("http").createServer(webhooks.middleware).listen(3000);
-// can now receive webhook events at port 3000
+require("http").createServer(createNodeMiddleware(webhooks)).listen(3000);
+// can now receive webhook events at /api/github/webhooks
 ```
 
 ## Local development
@@ -93,52 +93,54 @@ source.onmessage = (event) => {
 7. [webhooks.onAny()](#webhooksonany)
 8. [webhooks.onError()](#webhooksonerror)
 9. [webhooks.removeListener()](#webhooksremoveListener)
-10. [webhooks.middleware()](#webhooksmiddleware)
-11. [Webhook events](#webhook-events)
+10. [Webhook events](#webhook-events)
 
 ### Constructor
 
 ```js
-new Webhooks({secret[, path, transform]})
+new Webhooks({ secret /*, transform */ });
 ```
 
 <table width="100%">
-  <tr>
-    <td>
-      <code>
-        secret
-      </code>
-      <em>(String)</em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      Secret as configured in GitHub Settings.
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <code>
-        path
-      </code>
-      <em>(String)</em>
-    </td>
-    <td>
-      Only relevant for <a href="#webhooksmiddleware"><code>webhooks.middleware</code></a>.
-      Custom path to match requests against. Defaults to <code>/</code>.
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <code>
-        transform
-      </code>
-      <em>(Function)</em>
+  <tbody valign="top">
+    <tr>
+      <td>
+        <code>
+          secret
+        </code>
+        <em>(String)</em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+        Secret as configured in GitHub Settings.
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <code>
+          transform
+        </code>
+        <em>(Function)</em>
+      </td>
+      <td>
+        Only relevant for <a href="#webhookson"><code>webhooks.on</code></a>.
+        Transform emitted event before calling handlers. Can be asynchronous.
+      </td>
+    </tr>
+    <tr>
+    <td>
+      <code>log</code>
+      <em>
+        object
+      </em>
     </td>
     <td>
-      Only relevant for <a href="#webhookson"><code>webhooks.on</code></a>.
-      Transform emitted event before calling handlers. Can be asynchronous.
-    </td>
-  </tr>
+
+Used for internal logging. Defaults to [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console) with `debug` and `info` doing nothing.
+
+</td>
+    </tr>
+  </tbody>
 </table>
 
 Returns the `webhooks` API.
@@ -150,20 +152,22 @@ webhooks.sign(eventPayload);
 ```
 
 <table width="100%">
-  <tr>
-    <td>
-      <code>
-        eventPayload
-      </code>
-      <em>
-        (Object)
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      Webhook request payload as received from GitHub
-    </td>
-  </tr>
+  <tbody valign="top">
+    <tr>
+      <td>
+        <code>
+          eventPayload
+        </code>
+        <em>
+          (Object)
+        </em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+        Webhook request payload as received from GitHub
+      </td>
+    </tr>
+  </tbody>
 </table>
 
 Returns a `signature` string. Throws error if `eventPayload` is not passed.
@@ -177,34 +181,36 @@ webhooks.verify(eventPayload, signature);
 ```
 
 <table width="100%">
-  <tr>
-    <td>
-      <code>
-        eventPayload
-      </code>
-      <em>
-        (Object)
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      Webhook event request payload as received from GitHub.
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <code>
-        signature
-      </code>
-      <em>
-        (String)
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      Signature string as calculated by <code><a href="#webhookssign">webhooks.sign()</a></code>.
-    </td>
-  </tr>
+  <tbody valign="top">
+    <tr>
+      <td>
+        <code>
+          eventPayload
+        </code>
+        <em>
+          (Object)
+        </em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+        Webhook event request payload as received from GitHub.
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <code>
+          signature
+        </code>
+        <em>
+          (String)
+        </em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+        Signature string as calculated by <code><a href="#webhookssign">webhooks.sign()</a></code>.
+      </td>
+    </tr>
+  </tbody>
 </table>
 
 Returns `true` or `false`. Throws error if `eventPayload` or `signature` not passed.
@@ -218,62 +224,64 @@ webhooks.verifyAndReceive({ id, name, payload, signature });
 ```
 
 <table width="100%">
-  <tr>
-    <td>
-      <code>
-        id
-      </code>
-      <em>
-        String
-      </em>
-    </td>
-    <td>
-      Unique webhook event request id
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <code>
-        name
-      </code>
-      <em>
-        String
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      Name of the event. (Event names are set as <a href="https://docs.github.com/developers/webhooks-and-events/webhook-events-and-payloads#delivery-headers"><code>X-GitHub-Event</code> header</a>
-      in the webhook event request.)
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <code>
-        payload
-      </code>
-      <em>
-        Object
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      Webhook event request payload as received from GitHub.
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <code>
-        signature
-      </code>
-      <em>
-        (String)
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      Signature string as calculated by <code><a href="#webhookssign">webhooks.sign()</a></code>.
-    </td>
-  </tr>
+  <tbody valign="top">
+    <tr>
+      <td>
+        <code>
+          id
+        </code>
+        <em>
+          String
+        </em>
+      </td>
+      <td>
+        Unique webhook event request id
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <code>
+          name
+        </code>
+        <em>
+          String
+        </em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+        Name of the event. (Event names are set as <a href="https://docs.github.com/developers/webhooks-and-events/webhook-events-and-payloads#delivery-headers"><code>X-GitHub-Event</code> header</a>
+        in the webhook event request.)
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <code>
+          payload
+        </code>
+        <em>
+          Object
+        </em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+        Webhook event request payload as received from GitHub.
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <code>
+          signature
+        </code>
+        <em>
+          (String)
+        </em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+        Signature string as calculated by <code><a href="#webhookssign">webhooks.sign()</a></code>.
+      </td>
+    </tr>
+  </tbody>
 </table>
 
 Returns a promise.
@@ -309,48 +317,50 @@ webhooks.receive({ id, name, payload });
 ```
 
 <table width="100%">
-  <tr>
-    <td>
-      <code>
-        id
-      </code>
-      <em>
-        String
-      </em>
-    </td>
-    <td>
-      Unique webhook event request id
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <code>
-        name
-      </code>
-      <em>
-        String
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      Name of the event. (Event names are set as <a href="https://docs.github.com/developers/webhooks-and-events/webhook-events-and-payloads#delivery-headers"><code>X-GitHub-Event</code> header</a>
-      in the webhook event request.)
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <code>
-        payload
-      </code>
-      <em>
-        Object
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      Webhook event request payload as received from GitHub.
-    </td>
-  </tr>
+  <tbody valign="top">
+    <tr>
+      <td>
+        <code>
+          id
+        </code>
+        <em>
+          String
+        </em>
+      </td>
+      <td>
+        Unique webhook event request id
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <code>
+          name
+        </code>
+        <em>
+          String
+        </em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+        Name of the event. (Event names are set as <a href="https://docs.github.com/developers/webhooks-and-events/webhook-events-and-payloads#delivery-headers"><code>X-GitHub-Event</code> header</a>
+        in the webhook event request.)
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <code>
+          payload
+        </code>
+        <em>
+          Object
+        </em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+        Webhook event request payload as received from GitHub.
+      </td>
+    </tr>
+  </tbody>
 </table>
 
 Returns a promise. Runs all handlers set with [`webhooks.on()`](#webhookson) in parallel and waits for them to finish. If one of the handlers rejects or throws an error, then `webhooks.receive()` rejects. The returned error has an `.errors` property which holds an array of all errors caught from the handlers. If no errors occur, `webhooks.receive()` resolves without passing any value.
@@ -365,50 +375,52 @@ webhooks.on(eventNames, handler);
 ```
 
 <table width="100%">
-  <tr>
-    <td>
-      <code>
-        eventName
-      </code>
-      <em>
-        String
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      Name of the event. One of <a href="https://docs.github.com/developers/webhooks-and-events/webhook-events-and-payloads">GitHub's supported event names</a>.
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <code>
-        eventNames
-      </code>
-      <em>
-        Array
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      Array of event names.
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <code>
-        handler
-      </code>
-      <em>
-        Function
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      Method to be run each time the event with the passed name is received.
-      the <code>handler</code> function can be an async function, throw an error or
-      return a Promise. The handler is called with an event object: <code>{id, name, payload}</code>.
-    </td>
-  </tr>
+  <tbody valign="top">
+    <tr>
+      <td>
+        <code>
+          eventName
+        </code>
+        <em>
+          String
+        </em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+        Name of the event. One of <a href="https://docs.github.com/developers/webhooks-and-events/webhook-events-and-payloads">GitHub's supported event names</a>.
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <code>
+          eventNames
+        </code>
+        <em>
+          Array
+        </em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+        Array of event names.
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <code>
+          handler
+        </code>
+        <em>
+          Function
+        </em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+        Method to be run each time the event with the passed name is received.
+        the <code>handler</code> function can be an async function, throw an error or
+        return a Promise. The handler is called with an event object: <code>{id, name, payload}</code>.
+      </td>
+    </tr>
+  </tbody>
 </table>
 
 The `.on()` method belongs to the `event-handler` module which can be used [standalone](src/event-handler/).
@@ -420,22 +432,24 @@ webhooks.onAny(handler);
 ```
 
 <table width="100%">
-  <tr>
-    <td>
-      <code>
-        handler
-      </code>
-      <em>
-        Function
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      Method to be run each time any event is received.
-      the <code>handler</code> function can be an async function, throw an error or
-      return a Promise. The handler is called with an event object: <code>{id, name, payload}</code>.
-    </td>
-  </tr>
+  <tbody valign="top">
+    <tr>
+      <td>
+        <code>
+          handler
+        </code>
+        <em>
+          Function
+        </em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+        Method to be run each time any event is received.
+        the <code>handler</code> function can be an async function, throw an error or
+        return a Promise. The handler is called with an event object: <code>{id, name, payload}</code>.
+      </td>
+    </tr>
+  </tbody>
 </table>
 
 The `.onAny()` method belongs to the `event-handler` module which can be used [standalone](src/event-handler/).
@@ -451,22 +465,24 @@ If a webhook event handler throws an error or returns a promise that rejects, an
 Asynchronous `error` event handler are not blocking the `.receive()` method from completing.
 
 <table width="100%">
-  <tr>
-    <td>
-      <code>
-        handler
-      </code>
-      <em>
-        Function
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      Method to be run each time a webhook event handler throws an error or returns a promise that rejects.
-      The <code>handler</code> function can be an async function,
-      return a Promise. The handler is called with an error object that has a .event property which has all the information on the event: <code>{id, name, payload}</code>.
-    </td>
-  </tr>
+  <tbody valign="top">
+    <tr>
+      <td>
+        <code>
+          handler
+        </code>
+        <em>
+          Function
+        </em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+        Method to be run each time a webhook event handler throws an error or returns a promise that rejects.
+        The <code>handler</code> function can be an async function,
+        return a Promise. The handler is called with an error object that has a .event property which has all the information on the event: <code>{id, name, payload}</code>.
+      </td>
+    </tr>
+  </tbody>
 </table>
 
 The `.onError()` method belongs to the `event-handler` module which can be used [standalone](src/event-handler/).
@@ -479,105 +495,135 @@ webhooks.removeListener(eventNames, handler);
 ```
 
 <table width="100%">
-  <tr>
-    <td>
-      <code>
-        eventName
-      </code>
-      <em>
-        String
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      Name of the event. One of <a href="https://docs.github.com/developers/webhooks-and-events/webhook-events-and-payloads">GitHub’s supported event names</a>, or '*' for the <code>onAny()</code> method or 'error' for the <code>onError()</code> method.
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <code>
-        eventNames
-      </code>
-      <em>
-        Array
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      Array of event names.
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <code>
-        handler
-      </code>
-      <em>
-        Function
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      Method which was previously passed to <code><a href="webhookson">webhooks.on()</a></code>. If the same handler was registered multiple times for the same event, only the most recent handler gets removed.
-    </td>
-  </tr>
+  <tbody valign="top">
+    <tr>
+      <td>
+        <code>
+          eventName
+        </code>
+        <em>
+          String
+        </em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+        Name of the event. One of <a href="https://docs.github.com/developers/webhooks-and-events/webhook-events-and-payloads">GitHub’s supported event names</a>, or '*' for the <code>onAny()</code> method or 'error' for the <code>onError()</code> method.
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <code>
+          eventNames
+        </code>
+        <em>
+          Array
+        </em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+        Array of event names.
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <code>
+          handler
+        </code>
+        <em>
+          Function
+        </em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+        Method which was previously passed to <code><a href="webhookson">webhooks.on()</a></code>. If the same handler was registered multiple times for the same event, only the most recent handler gets removed.
+      </td>
+    </tr>
+  </tbody>
 </table>
 
 The `.removeListener()` method belongs to the `event-handler` module which can be used [standalone](src/event-handler/).
 
-### webhooks.middleware()
+### createNodeMiddleware()
 
 ```js
-webhooks.middleware(request, response[, next])
+const { createServer } = require("http");
+const { Webhooks, createNodeMiddleware } = require("@octokit/webhooks");
+
+const webhooks = new Webhooks({
+  secret: "mysecret",
+});
+
+const middleware = createNodeMiddleware(webhooks, { path: "/" });
+
+createServer(middleware).listen(3000);
+// can now receive user authorization callbacks at POST /
 ```
 
 <table width="100%">
-  <tr>
-    <td>
-      <code>
-        request
-      </code>
-      <em>
-        Object
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      A Node.js <a href="https://nodejs.org/docs/latest/api/http.html#http_class_http_clientrequest">http.ClientRequest</a>.
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <code>
-        response
-      </code>
-      <em>
-        Object
-      </em>
-    </td>
-    <td>
-      <strong>Required.</strong>
-      A Node.js <a href="https://nodejs.org/docs/latest/api/http.html#http_class_http_serverresponse">http.ServerResponse</a>.
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <code>
-        next
-      </code>
-      <em>
-        Function
-      </em>
-    </td>
-    <td>
-      Optional function which invokes the next middleware, as used by <a href="https://github.com/senchalabs/connect">Connect</a> and <a href="http://expressjs.com/">Express</a>.
-    </td>
-  </tr>
-</table>
+  <tbody valign="top">
+    <tr>
+      <td>
+        <code>webhooks</code>
+        <em>
+          Webhooks instance
+        </em>
+      </td>
+      <td>
+        <strong>Required.</strong>
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <code>path</code>
+        <em>
+          string
+        </em>
+      </td>
+      <td>
+        Custom path to match requests against. Defaults to <code>/api/github/webhooks</code>.
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <code>log</code>
+        <em>
+          object
+        </em>
+      </td>
+      <td>
+
+Used for internal logging. Defaults to [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console) with `debug` and `info` doing nothing.
+
+</td>
+    </tr>
+    <tr>
+      <td>
+        <code>onUnhandledRequest</code>
+        <em>
+          function
+        </em>
+      </td>
+      <td>
+
+Defaults to
 
-Returns a `requestListener` (or _middleware_) method which can be directly passed to [`http.createServer()`](https://nodejs.org/docs/latest/api/http.html#http_http_createserver_requestlistener), <a href="http://expressjs.com/">Express</a> and other compatible Node.js server frameworks.
+```js
+function onUnhandledRequest(request, response) {
+  response.writeHead(400, {
+    "content-type": "application/json",
+  });
+  response.end(
+    JSON.stringify({
+      error: error.message,
+    })
+  );
+}
+```
 
-Can also be used [standalone](src/middleware/).
+</td>
+    </tr>
+  <tbody>
+</table>
 
 ### Webhook events
 
diff --git a/package-lock.json b/package-lock.json
index f765b58..a75de9b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,26 +14,26 @@
       }
     },
     "@babel/compat-data": {
-      "version": "7.13.8",
-      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.8.tgz",
-      "integrity": "sha512-EaI33z19T4qN3xLXsGf48M2cDqa6ei9tPZlfLdb2HC+e/cFtREiRd8hdSqDbwdLB0/+gLwqJmCYASH0z2bUdog==",
+      "version": "7.13.12",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.12.tgz",
+      "integrity": "sha512-3eJJ841uKxeV8dcN/2yGEUy+RfgQspPEgQat85umsE1rotuquQ2AbIub4S6j7c50a2d+4myc+zSlnXeIHrOnhQ==",
       "dev": true
     },
     "@babel/core": {
-      "version": "7.13.10",
-      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.10.tgz",
-      "integrity": "sha512-bfIYcT0BdKeAZrovpMqX2Mx5NrgAckGbwT982AkdS5GNfn3KMGiprlBAtmBcFZRUmpaufS6WZFP8trvx8ptFDw==",
+      "version": "7.13.13",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.13.tgz",
+      "integrity": "sha512-1xEs9jZAyKIouOoCmpsgk/I26PoKyvzQ2ixdRpRzfbcp1fL+ozw7TUgdDgwonbTovqRaTfRh50IXuw4QrWO0GA==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "^7.12.13",
         "@babel/generator": "^7.13.9",
-        "@babel/helper-compilation-targets": "^7.13.10",
-        "@babel/helper-module-transforms": "^7.13.0",
+        "@babel/helper-compilation-targets": "^7.13.13",
+        "@babel/helper-module-transforms": "^7.13.12",
         "@babel/helpers": "^7.13.10",
-        "@babel/parser": "^7.13.10",
+        "@babel/parser": "^7.13.13",
         "@babel/template": "^7.12.13",
-        "@babel/traverse": "^7.13.0",
-        "@babel/types": "^7.13.0",
+        "@babel/traverse": "^7.13.13",
+        "@babel/types": "^7.13.13",
         "convert-source-map": "^1.7.0",
         "debug": "^4.1.0",
         "gensync": "^1.0.0-beta.2",
@@ -74,21 +74,21 @@
       }
     },
     "@babel/helper-compilation-targets": {
-      "version": "7.13.10",
-      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.10.tgz",
-      "integrity": "sha512-/Xju7Qg1GQO4mHZ/Kcs6Au7gfafgZnwm+a7sy/ow/tV1sHeraRUHbjdat8/UvDor4Tez+siGKDk6zIKtCPKVJA==",
+      "version": "7.13.13",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.13.tgz",
+      "integrity": "sha512-q1kcdHNZehBwD9jYPh3WyXcsFERi39X4I59I3NadciWtNDyZ6x+GboOxncFK0kXlKIv6BJm5acncehXWUjWQMQ==",
       "dev": true,
       "requires": {
-        "@babel/compat-data": "^7.13.8",
+        "@babel/compat-data": "^7.13.12",
         "@babel/helper-validator-option": "^7.12.17",
         "browserslist": "^4.14.5",
         "semver": "^6.3.0"
       }
     },
     "@babel/helper-create-class-features-plugin": {
-      "version": "7.13.10",
-      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.13.10.tgz",
-      "integrity": "sha512-YV7r2YxdTUaw84EwNkyrRke/TJHR/UXGiyvACRqvdVJ2/syV2rQuJNnaRLSuYiop8cMRXOgseTGoJCWX0q2fFg==",
+      "version": "7.13.11",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.13.11.tgz",
+      "integrity": "sha512-ays0I7XYq9xbjCSvT+EvysLgfc3tOkwCULHjrnscGT3A9qD4sk3wXnJ3of0MAWsWGjdinFvajHU2smYuqXKMrw==",
       "dev": true,
       "requires": {
         "@babel/helper-function-name": "^7.12.13",
@@ -164,38 +164,37 @@
       }
     },
     "@babel/helper-member-expression-to-functions": {
-      "version": "7.13.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.0.tgz",
-      "integrity": "sha512-yvRf8Ivk62JwisqV1rFRMxiSMDGnN6KH1/mDMmIrij4jztpQNRoHqqMG3U6apYbGRPJpgPalhva9Yd06HlUxJQ==",
+      "version": "7.13.12",
+      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz",
+      "integrity": "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.13.0"
+        "@babel/types": "^7.13.12"
       }
     },
     "@babel/helper-module-imports": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.13.tgz",
-      "integrity": "sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g==",
+      "version": "7.13.12",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz",
+      "integrity": "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.12.13"
+        "@babel/types": "^7.13.12"
       }
     },
     "@babel/helper-module-transforms": {
-      "version": "7.13.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.0.tgz",
-      "integrity": "sha512-Ls8/VBwH577+pw7Ku1QkUWIyRRNHpYlts7+qSqBBFCW3I8QteB9DxfcZ5YJpOwH6Ihe/wn8ch7fMGOP1OhEIvw==",
+      "version": "7.13.12",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.12.tgz",
+      "integrity": "sha512-7zVQqMO3V+K4JOOj40kxiCrMf6xlQAkewBB0eu2b03OO/Q21ZutOzjpfD79A5gtE/2OWi1nv625MrDlGlkbknQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-module-imports": "^7.12.13",
-        "@babel/helper-replace-supers": "^7.13.0",
-        "@babel/helper-simple-access": "^7.12.13",
+        "@babel/helper-module-imports": "^7.13.12",
+        "@babel/helper-replace-supers": "^7.13.12",
+        "@babel/helper-simple-access": "^7.13.12",
         "@babel/helper-split-export-declaration": "^7.12.13",
         "@babel/helper-validator-identifier": "^7.12.11",
         "@babel/template": "^7.12.13",
         "@babel/traverse": "^7.13.0",
-        "@babel/types": "^7.13.0",
-        "lodash": "^4.17.19"
+        "@babel/types": "^7.13.12"
       }
     },
     "@babel/helper-optimise-call-expression": {
@@ -225,24 +224,24 @@
       }
     },
     "@babel/helper-replace-supers": {
-      "version": "7.13.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.0.tgz",
-      "integrity": "sha512-Segd5me1+Pz+rmN/NFBOplMbZG3SqRJOBlY+mA0SxAv6rjj7zJqr1AVr3SfzUVTLCv7ZLU5FycOM/SBGuLPbZw==",
+      "version": "7.13.12",
+      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz",
+      "integrity": "sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==",
       "dev": true,
       "requires": {
-        "@babel/helper-member-expression-to-functions": "^7.13.0",
+        "@babel/helper-member-expression-to-functions": "^7.13.12",
         "@babel/helper-optimise-call-expression": "^7.12.13",
         "@babel/traverse": "^7.13.0",
-        "@babel/types": "^7.13.0"
+        "@babel/types": "^7.13.12"
       }
     },
     "@babel/helper-simple-access": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.13.tgz",
-      "integrity": "sha512-0ski5dyYIHEfwpWGx5GPWhH35j342JaflmCeQmsPWcrOQDtCN6C1zKAVRFVbK53lPW2c9TsuLLSUDf0tIGJ5hA==",
+      "version": "7.13.12",
+      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz",
+      "integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.12.13"
+        "@babel/types": "^7.13.12"
       }
     },
     "@babel/helper-skip-transparent-expression-wrappers": {
@@ -362,11 +361,22 @@
       }
     },
     "@babel/parser": {
-      "version": "7.13.10",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.10.tgz",
-      "integrity": "sha512-0s7Mlrw9uTWkYua7xWr99Wpk2bnGa0ANleKfksYAES8LpWH4gW1OUr42vqKNf0us5UQNfru2wPqMqRITzq/SIQ==",
+      "version": "7.13.13",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.13.tgz",
+      "integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==",
       "dev": true
     },
+    "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
+      "version": "7.13.12",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.13.12.tgz",
+      "integrity": "sha512-d0u3zWKcoZf379fOeJdr1a5WPDny4aOFZ6hlfKivgK0LY7ZxNfoaHL2fWwdGtHyVvra38FC+HVYkO+byfSA8AQ==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.13.0",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1",
+        "@babel/plugin-proposal-optional-chaining": "^7.13.12"
+      }
+    },
     "@babel/plugin-proposal-async-generator-functions": {
       "version": "7.13.8",
       "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.8.tgz",
@@ -472,9 +482,9 @@
       }
     },
     "@babel/plugin-proposal-optional-chaining": {
-      "version": "7.13.8",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.13.8.tgz",
-      "integrity": "sha512-hpbBwbTgd7Cz1QryvwJZRo1U0k1q8uyBmeXOSQUjdg/A2TASkhR/rz7AyqZ/kS8kbpsNA80rOYbxySBJAqmhhQ==",
+      "version": "7.13.12",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.13.12.tgz",
+      "integrity": "sha512-fcEdKOkIB7Tf4IxrgEVeFC4zeJSTr78no9wTdBuZZbqF64kzllU0ybo2zrzm7gUQfxGhBgq4E39oRs8Zx/RMYQ==",
       "dev": true,
       "requires": {
         "@babel/helper-plugin-utils": "^7.13.0",
@@ -961,15 +971,16 @@
       }
     },
     "@babel/preset-env": {
-      "version": "7.13.10",
-      "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.13.10.tgz",
-      "integrity": "sha512-nOsTScuoRghRtUsRr/c69d042ysfPHcu+KOB4A9aAO9eJYqrkat+LF8G1yp1HD18QiwixT2CisZTr/0b3YZPXQ==",
+      "version": "7.13.12",
+      "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.13.12.tgz",
+      "integrity": "sha512-JzElc6jk3Ko6zuZgBtjOd01pf9yYDEIH8BcqVuYIuOkzOwDesoa/Nz4gIo4lBG6K861KTV9TvIgmFuT6ytOaAA==",
       "dev": true,
       "requires": {
-        "@babel/compat-data": "^7.13.8",
+        "@babel/compat-data": "^7.13.12",
         "@babel/helper-compilation-targets": "^7.13.10",
         "@babel/helper-plugin-utils": "^7.13.0",
         "@babel/helper-validator-option": "^7.12.17",
+        "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.13.12",
         "@babel/plugin-proposal-async-generator-functions": "^7.13.8",
         "@babel/plugin-proposal-class-properties": "^7.13.0",
         "@babel/plugin-proposal-dynamic-import": "^7.13.8",
@@ -980,7 +991,7 @@
         "@babel/plugin-proposal-numeric-separator": "^7.12.13",
         "@babel/plugin-proposal-object-rest-spread": "^7.13.8",
         "@babel/plugin-proposal-optional-catch-binding": "^7.13.8",
-        "@babel/plugin-proposal-optional-chaining": "^7.13.8",
+        "@babel/plugin-proposal-optional-chaining": "^7.13.12",
         "@babel/plugin-proposal-private-methods": "^7.13.0",
         "@babel/plugin-proposal-unicode-property-regex": "^7.12.13",
         "@babel/plugin-syntax-async-generators": "^7.8.4",
@@ -1028,7 +1039,7 @@
         "@babel/plugin-transform-unicode-escapes": "^7.12.13",
         "@babel/plugin-transform-unicode-regex": "^7.12.13",
         "@babel/preset-modules": "^0.1.4",
-        "@babel/types": "^7.13.0",
+        "@babel/types": "^7.13.12",
         "babel-plugin-polyfill-corejs2": "^0.1.4",
         "babel-plugin-polyfill-corejs3": "^0.1.3",
         "babel-plugin-polyfill-regenerator": "^0.1.2",
@@ -1081,26 +1092,25 @@
       }
     },
     "@babel/traverse": {
-      "version": "7.13.0",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz",
-      "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==",
+      "version": "7.13.13",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.13.tgz",
+      "integrity": "sha512-CblEcwmXKR6eP43oQGG++0QMTtCjAsa3frUuzHoiIJWpaIIi8dwMyEFUJoXRLxagGqCK+jALRwIO+o3R9p/uUg==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "^7.12.13",
-        "@babel/generator": "^7.13.0",
+        "@babel/generator": "^7.13.9",
         "@babel/helper-function-name": "^7.12.13",
         "@babel/helper-split-export-declaration": "^7.12.13",
-        "@babel/parser": "^7.13.0",
-        "@babel/types": "^7.13.0",
+        "@babel/parser": "^7.13.13",
+        "@babel/types": "^7.13.13",
         "debug": "^4.1.0",
-        "globals": "^11.1.0",
-        "lodash": "^4.17.19"
+        "globals": "^11.1.0"
       }
     },
     "@babel/types": {
-      "version": "7.13.0",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz",
-      "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==",
+      "version": "7.13.13",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.13.tgz",
+      "integrity": "sha512-kt+EpC6qDfIaqlP+DIbIJOclYy/A1YXs9dAf/ljbi+39Bcbc073H6jKVpXEr/EoIh5anGn5xq/yRVzKl+uIc9w==",
       "dev": true,
       "requires": {
         "@babel/helper-validator-identifier": "^7.12.11",
@@ -1484,9 +1494,9 @@
       }
     },
     "@octokit/core": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.3.0.tgz",
-      "integrity": "sha512-GGMpjaodCBY7JrtOwfolMocwZw9Pj5NxuQqfaJhGau4tkyonm0JRV9D6juQYLMb1Kl261++4Q980o0FlAtg8jg==",
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.3.1.tgz",
+      "integrity": "sha512-Dc5NNQOYjgZU5S1goN6A/E500yXOfDUFRGQB8/2Tl16AcfvS3H9PudyOe3ZNE/MaVyHPIfC0htReHMJb1tMrvw==",
       "dev": true,
       "requires": {
         "@octokit/auth-token": "^2.4.4",
@@ -1529,14 +1539,14 @@
       }
     },
     "@octokit/openapi-types": {
-      "version": "5.3.2",
-      "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-5.3.2.tgz",
-      "integrity": "sha512-NxF1yfYOUO92rCx3dwvA2onF30Vdlg7YUkMVXkeptqpzA3tRLplThhFleV/UKWFgh7rpKu1yYRbvNDUtzSopKA=="
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-6.0.0.tgz",
+      "integrity": "sha512-CnDdK7ivHkBtJYzWzZm7gEkanA7gKH6a09Eguz7flHw//GacPJLmkHA3f3N++MJmlxD1Fl+mB7B32EEpSCwztQ=="
     },
     "@octokit/plugin-paginate-rest": {
-      "version": "2.13.2",
-      "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.2.tgz",
-      "integrity": "sha512-mjfBcla00UNS4EI/NN7toEbUM45ow3kk4go+LxsXAFLQodsrXcIZbftUhXTqi6ZKd+r6bcqMI+Lv4dshLtFjww==",
+      "version": "2.13.3",
+      "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.3.tgz",
+      "integrity": "sha512-46lptzM9lTeSmIBt/sVP/FLSTPGx6DCzAdSX3PfeJ3mTf4h9sGC26WpaQzMEq/Z44cOcmx8VsOhO+uEgE3cjYg==",
       "dev": true,
       "requires": {
         "@octokit/types": "^6.11.0"
@@ -1549,12 +1559,12 @@
       "dev": true
     },
     "@octokit/plugin-rest-endpoint-methods": {
-      "version": "4.13.5",
-      "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.13.5.tgz",
-      "integrity": "sha512-kYKcWkFm4Ldk8bZai2RVEP1z97k1C/Ay2FN9FNTBg7JIyKoiiJjks4OtT6cuKeZX39tqa+C3J9xeYc6G+6g8uQ==",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.0.0.tgz",
+      "integrity": "sha512-Jc7CLNUueIshXT+HWt6T+M0sySPjF32mSFQAK7UfAg8qGeRI6OM1GSBxDLwbXjkqy2NVdnqCedJcP1nC785JYg==",
       "dev": true,
       "requires": {
-        "@octokit/types": "^6.12.2",
+        "@octokit/types": "^6.13.0",
         "deprecation": "^2.3.1"
       }
     },
@@ -1593,15 +1603,15 @@
       }
     },
     "@octokit/rest": {
-      "version": "18.3.5",
-      "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.3.5.tgz",
-      "integrity": "sha512-ZPeRms3WhWxQBEvoIh0zzf8xdU2FX0Capa7+lTca8YHmRsO3QNJzf1H3PcuKKsfgp91/xVDRtX91sTe1kexlbw==",
+      "version": "18.5.2",
+      "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.5.2.tgz",
+      "integrity": "sha512-Kz03XYfKS0yYdi61BkL9/aJ0pP2A/WK5vF/syhu9/kY30J8He3P68hv9GRpn8bULFx2K0A9MEErn4v3QEdbZcw==",
       "dev": true,
       "requires": {
         "@octokit/core": "^3.2.3",
         "@octokit/plugin-paginate-rest": "^2.6.2",
         "@octokit/plugin-request-log": "^1.0.2",
-        "@octokit/plugin-rest-endpoint-methods": "4.13.5"
+        "@octokit/plugin-rest-endpoint-methods": "5.0.0"
       }
     },
     "@octokit/tsconfig": {
@@ -1611,17 +1621,17 @@
       "dev": true
     },
     "@octokit/types": {
-      "version": "6.12.2",
-      "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.12.2.tgz",
-      "integrity": "sha512-kCkiN8scbCmSq+gwdJV0iLgHc0O/GTPY1/cffo9kECu1MvatLPh9E+qFhfRIktKfHEA6ZYvv6S1B4Wnv3bi3pA==",
+      "version": "6.13.0",
+      "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.13.0.tgz",
+      "integrity": "sha512-W2J9qlVIU11jMwKHUp5/rbVUeErqelCsO5vW5PKNb7wAXQVUz87Rc+imjlEvpvbH8yUb+KHmv8NEjVZdsdpyxA==",
       "requires": {
-        "@octokit/openapi-types": "^5.3.2"
+        "@octokit/openapi-types": "^6.0.0"
       }
     },
     "@octokit/webhooks-definitions": {
-      "version": "3.64.2",
-      "resolved": "https://registry.npmjs.org/@octokit/webhooks-definitions/-/webhooks-definitions-3.64.2.tgz",
-      "integrity": "sha512-CEEYgbSOWST0Y26bKNY2u3AWh6IeFKthoKE5wHDzpT6+bI+byB83wAR5uByW40IVAGmOzlJ/Hci1guKZPCTIzg=="
+      "version": "3.65.5",
+      "resolved": "https://registry.npmjs.org/@octokit/webhooks-definitions/-/webhooks-definitions-3.65.5.tgz",
+      "integrity": "sha512-cQxHFYIrOHINEaw/dE8qrZKCmrJ7h8OOj8ZKeMq9KtP9ueBr9VdHKddbG4OMYEVHtylGSlGsvYT6GZBPYJe8OQ=="
     },
     "@pika/babel-plugin-esm-import-rewrite": {
       "version": "0.6.1",
@@ -1891,9 +1901,9 @@
           "dev": true
         },
         "globby": {
-          "version": "11.0.2",
-          "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz",
-          "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==",
+          "version": "11.0.3",
+          "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz",
+          "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==",
           "dev": true,
           "requires": {
             "array-union": "^2.1.0",
@@ -1996,9 +2006,9 @@
           }
         },
         "semver": {
-          "version": "7.3.4",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
-          "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
+          "version": "7.3.5",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+          "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
           "dev": true,
           "requires": {
             "lru-cache": "^6.0.0"
@@ -2070,9 +2080,9 @@
       "dev": true
     },
     "@types/babel__core": {
-      "version": "7.1.12",
-      "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz",
-      "integrity": "sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ==",
+      "version": "7.1.14",
+      "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz",
+      "integrity": "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==",
       "dev": true,
       "requires": {
         "@babel/parser": "^7.1.0",
@@ -2117,9 +2127,9 @@
       "dev": true
     },
     "@types/estree": {
-      "version": "0.0.46",
-      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz",
-      "integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==",
+      "version": "0.0.47",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.47.tgz",
+      "integrity": "sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg==",
       "dev": true
     },
     "@types/glob": {
@@ -2166,9 +2176,9 @@
       }
     },
     "@types/jest": {
-      "version": "26.0.20",
-      "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.20.tgz",
-      "integrity": "sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA==",
+      "version": "26.0.22",
+      "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.22.tgz",
+      "integrity": "sha512-eeWwWjlqxvBxc4oQdkueW5OF/gtfSceKk4OnOAGlUSwS/liBRtZppbJuz1YkgbrbfGOoeBHun9fOvXnjNwrSOw==",
       "dev": true,
       "requires": {
         "jest-diff": "^26.0.0",
@@ -2182,9 +2192,9 @@
       "dev": true
     },
     "@types/minimatch": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
-      "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==",
       "dev": true
     },
     "@types/minimist": {
@@ -2194,11 +2204,34 @@
       "dev": true
     },
     "@types/node": {
-      "version": "14.14.34",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.34.tgz",
-      "integrity": "sha512-dBPaxocOK6UVyvhbnpFIj2W+S+1cBTkHQbFQfeeJhoKFbzYcVUGHvddeWPSucKATb3F0+pgDq0i6ghEaZjsugA==",
+      "version": "14.14.37",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz",
+      "integrity": "sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==",
       "dev": true
     },
+    "@types/node-fetch": {
+      "version": "2.5.8",
+      "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.8.tgz",
+      "integrity": "sha512-fbjI6ja0N5ZA8TV53RUqzsKNkl9fv8Oj3T7zxW7FGv1GSH7gwJaNF8dzCjrqKaxKeUpTz4yT1DaJFq/omNpGfw==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*",
+        "form-data": "^3.0.0"
+      },
+      "dependencies": {
+        "form-data": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
+          "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
+          "dev": true,
+          "requires": {
+            "asynckit": "^0.4.0",
+            "combined-stream": "^1.0.8",
+            "mime-types": "^2.1.12"
+          }
+        }
+      }
+    },
     "@types/normalize-package-data": {
       "version": "2.4.0",
       "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
@@ -2212,9 +2245,9 @@
       "dev": true
     },
     "@types/prettier": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.2.tgz",
-      "integrity": "sha512-i99hy7Ki19EqVOl77WplDrvgNugHnsSjECVR/wUrzw2TJXz1zlUfT2ngGckR6xN7yFYaijsMAqPkOLx9HgUqHg==",
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz",
+      "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==",
       "dev": true
     },
     "@types/retry": {
@@ -2260,6 +2293,16 @@
       "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==",
       "dev": true
     },
+    "accepts": {
+      "version": "1.3.7",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+      "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+      "dev": true,
+      "requires": {
+        "mime-types": "~2.1.24",
+        "negotiator": "0.6.2"
+      }
+    },
     "acorn": {
       "version": "7.4.1",
       "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
@@ -2347,12 +2390,12 @@
       }
     },
     "ansi-escapes": {
-      "version": "4.3.1",
-      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
-      "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==",
+      "version": "4.3.2",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+      "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
       "dev": true,
       "requires": {
-        "type-fest": "^0.11.0"
+        "type-fest": "^0.21.3"
       }
     },
     "ansi-regex": {
@@ -2437,6 +2480,12 @@
       "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
       "dev": true
     },
+    "array-flatten": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+      "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
+      "dev": true
+    },
     "array-ify": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz",
@@ -2731,6 +2780,47 @@
       "integrity": "sha512-jH6rKQIfroBbhEXVmI7XmXe3ix5S/PgJqpzdDPnR8JGLHWNYLsYZ6tK5iWOF/Ra3oqEX0NobXGlzbiylIzVphQ==",
       "dev": true
     },
+    "body-parser": {
+      "version": "1.19.0",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
+      "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+      "dev": true,
+      "requires": {
+        "bytes": "3.1.0",
+        "content-type": "~1.0.4",
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "http-errors": "1.7.2",
+        "iconv-lite": "0.4.24",
+        "on-finished": "~2.3.0",
+        "qs": "6.7.0",
+        "raw-body": "2.4.0",
+        "type-is": "~1.6.17"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        },
+        "qs": {
+          "version": "6.7.0",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+          "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
+          "dev": true
+        }
+      }
+    },
     "bottleneck": {
       "version": "2.19.5",
       "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
@@ -2908,6 +2998,12 @@
       "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=",
       "dev": true
     },
+    "bytes": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+      "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
+      "dev": true
+    },
     "cache-base": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
@@ -3008,9 +3104,9 @@
       }
     },
     "caniuse-lite": {
-      "version": "1.0.30001200",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001200.tgz",
-      "integrity": "sha512-ic/jXfa6tgiPBAISWk16jRI2q8YfjxHnSG7ddSL1ptrIP8Uy11SayFrjXRAk3NumHpDb21fdTkbTxb/hOrFrnQ==",
+      "version": "1.0.30001204",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001204.tgz",
+      "integrity": "sha512-JUdjWpcxfJ9IPamy2f5JaRDCaqJOxDzOSKtbdx4rH9VivMd1vIzoPumsJa9LoMIi4Fx2BV2KZOxWhNkBjaYivQ==",
       "dev": true
     },
     "capture-exit": {
@@ -3116,9 +3212,9 @@
       }
     },
     "cli-table": {
-      "version": "0.3.5",
-      "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.5.tgz",
-      "integrity": "sha512-7uo2+RMNQUZ13M199udxqwk1qxTOS53EUak4gmu/aioUpdH5RvBz0JkJslcWz6ABKedZNqXXzikMZgHh+qF16A==",
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.6.tgz",
+      "integrity": "sha512-ZkNZbnZjKERTY5NwC2SeMeLeifSPq/pubeRoTpdr3WchLlnZg6hEgvHkK5zL7KNFdd9PmHN8lxrENUwI3cE8vQ==",
       "dev": true,
       "requires": {
         "colors": "1.0.3"
@@ -3342,6 +3438,21 @@
         "xdg-basedir": "^3.0.0"
       }
     },
+    "content-disposition": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
+      "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "5.1.2"
+      }
+    },
+    "content-type": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+      "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+      "dev": true
+    },
     "conventional-changelog-angular": {
       "version": "5.0.12",
       "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.12.tgz",
@@ -3382,9 +3493,9 @@
           }
         },
         "hosted-git-info": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.0.tgz",
-          "integrity": "sha512-fqhGdjk4av7mT9fU/B01dUtZ+WZSc/XEXMoLXDVZukiQRXxeHSSz3AqbeWRJHtF8EQYHlAgB1NSAHU0Cm7aqZA==",
+          "version": "4.0.2",
+          "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz",
+          "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==",
           "dev": true,
           "requires": {
             "lru-cache": "^6.0.0"
@@ -3427,21 +3538,21 @@
           }
         },
         "normalize-package-data": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.1.tgz",
-          "integrity": "sha512-D/ttLdxo71msR4FF3VgSwK4blHfE3/vGByz1NCeE7/Dh8reQOKNJJjk5L10mLq9jxa+ZHzT1/HLgxljzbXE7Fw==",
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz",
+          "integrity": "sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==",
           "dev": true,
           "requires": {
-            "hosted-git-info": "^4.0.0",
-            "resolve": "^1.17.0",
-            "semver": "^7.3.2",
+            "hosted-git-info": "^4.0.1",
+            "resolve": "^1.20.0",
+            "semver": "^7.3.4",
             "validate-npm-package-license": "^3.0.1"
           },
           "dependencies": {
             "semver": {
-              "version": "7.3.4",
-              "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
-              "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
+              "version": "7.3.5",
+              "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+              "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
               "dev": true,
               "requires": {
                 "lru-cache": "^6.0.0"
@@ -3531,9 +3642,9 @@
           }
         },
         "hosted-git-info": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.0.tgz",
-          "integrity": "sha512-fqhGdjk4av7mT9fU/B01dUtZ+WZSc/XEXMoLXDVZukiQRXxeHSSz3AqbeWRJHtF8EQYHlAgB1NSAHU0Cm7aqZA==",
+          "version": "4.0.2",
+          "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz",
+          "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==",
           "dev": true,
           "requires": {
             "lru-cache": "^6.0.0"
@@ -3576,14 +3687,14 @@
           }
         },
         "normalize-package-data": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.1.tgz",
-          "integrity": "sha512-D/ttLdxo71msR4FF3VgSwK4blHfE3/vGByz1NCeE7/Dh8reQOKNJJjk5L10mLq9jxa+ZHzT1/HLgxljzbXE7Fw==",
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz",
+          "integrity": "sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==",
           "dev": true,
           "requires": {
-            "hosted-git-info": "^4.0.0",
-            "resolve": "^1.17.0",
-            "semver": "^7.3.2",
+            "hosted-git-info": "^4.0.1",
+            "resolve": "^1.20.0",
+            "semver": "^7.3.4",
             "validate-npm-package-license": "^3.0.1"
           }
         },
@@ -3604,9 +3715,9 @@
           }
         },
         "semver": {
-          "version": "7.3.4",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
-          "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
+          "version": "7.3.5",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+          "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
           "dev": true,
           "requires": {
             "lru-cache": "^6.0.0"
@@ -3650,6 +3761,18 @@
         "safe-buffer": "~5.1.1"
       }
     },
+    "cookie": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
+      "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
+      "dev": true
+    },
+    "cookie-signature": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+      "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
+      "dev": true
+    },
     "copy-descriptor": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
@@ -3927,11 +4050,23 @@
       "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
       "dev": true
     },
+    "depd": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+      "dev": true
+    },
     "deprecation": {
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
       "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
     },
+    "destroy": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+      "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
+      "dev": true
+    },
     "detect-indent": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz",
@@ -4050,10 +4185,16 @@
         "safer-buffer": "^2.1.0"
       }
     },
+    "ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
+      "dev": true
+    },
     "electron-to-chromium": {
-      "version": "1.3.687",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.687.tgz",
-      "integrity": "sha512-IpzksdQNl3wdgkzf7dnA7/v10w0Utf1dF2L+B4+gKrloBrxCut+au+kky3PYvle3RMdSxZP+UiCZtLbcYRxSNQ==",
+      "version": "1.3.701",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.701.tgz",
+      "integrity": "sha512-Zd9ofdIMYHYhG1gvnejQDvC/kqSeXQvtXF0yRURGxgwGqDZm9F9Fm3dYFnm5gyuA7xpXfBlzVLN1sz0FjxpKfw==",
       "dev": true
     },
     "elegant-spinner": {
@@ -4074,6 +4215,12 @@
       "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
       "dev": true
     },
+    "encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+      "dev": true
+    },
     "end-of-stream": {
       "version": "1.4.4",
       "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
@@ -4136,6 +4283,12 @@
       "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
       "dev": true
     },
+    "escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+      "dev": true
+    },
     "escape-string-regexp": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@@ -4188,10 +4341,16 @@
       "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
       "dev": true
     },
+    "etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
+      "dev": true
+    },
     "exec-sh": {
-      "version": "0.3.4",
-      "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz",
-      "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==",
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz",
+      "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==",
       "dev": true
     },
     "execa": {
@@ -4281,6 +4440,67 @@
         "jest-regex-util": "^26.0.0"
       }
     },
+    "express": {
+      "version": "4.17.1",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
+      "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+      "dev": true,
+      "requires": {
+        "accepts": "~1.3.7",
+        "array-flatten": "1.1.1",
+        "body-parser": "1.19.0",
+        "content-disposition": "0.5.3",
+        "content-type": "~1.0.4",
+        "cookie": "0.4.0",
+        "cookie-signature": "1.0.6",
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "finalhandler": "~1.1.2",
+        "fresh": "0.5.2",
+        "merge-descriptors": "1.0.1",
+        "methods": "~1.1.2",
+        "on-finished": "~2.3.0",
+        "parseurl": "~1.3.3",
+        "path-to-regexp": "0.1.7",
+        "proxy-addr": "~2.0.5",
+        "qs": "6.7.0",
+        "range-parser": "~1.2.1",
+        "safe-buffer": "5.1.2",
+        "send": "0.17.1",
+        "serve-static": "1.14.1",
+        "setprototypeof": "1.1.1",
+        "statuses": "~1.5.0",
+        "type-is": "~1.6.18",
+        "utils-merge": "1.0.1",
+        "vary": "~1.1.2"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        },
+        "qs": {
+          "version": "6.7.0",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+          "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
+          "dev": true
+        }
+      }
+    },
     "extend": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@@ -4464,6 +4684,38 @@
         "to-regex-range": "^5.0.1"
       }
     },
+    "finalhandler": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+      "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+      "dev": true,
+      "requires": {
+        "debug": "2.6.9",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "on-finished": "~2.3.0",
+        "parseurl": "~1.3.3",
+        "statuses": "~1.5.0",
+        "unpipe": "~1.0.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        }
+      }
+    },
     "find-up": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
@@ -4511,6 +4763,12 @@
         "mime-types": "^2.1.12"
       }
     },
+    "forwarded": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
+      "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
+      "dev": true
+    },
     "fragment-cache": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
@@ -4520,6 +4778,12 @@
         "map-cache": "^0.2.2"
       }
     },
+    "fresh": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
+      "dev": true
+    },
     "from2": {
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
@@ -5002,6 +5266,27 @@
       "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
       "dev": true
     },
+    "http-errors": {
+      "version": "1.7.2",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+      "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+      "dev": true,
+      "requires": {
+        "depd": "~1.1.2",
+        "inherits": "2.0.3",
+        "setprototypeof": "1.1.1",
+        "statuses": ">= 1.5.0 < 2",
+        "toidentifier": "1.0.0"
+      },
+      "dependencies": {
+        "inherits": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+          "dev": true
+        }
+      }
+    },
     "http-proxy-agent": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
@@ -5374,6 +5659,12 @@
       "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==",
       "dev": true
     },
+    "ipaddr.js": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+      "dev": true
+    },
     "is-accessor-descriptor": {
       "version": "0.1.6",
       "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
@@ -6193,9 +6484,9 @@
       },
       "dependencies": {
         "semver": {
-          "version": "7.3.4",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
-          "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
+          "version": "7.3.5",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+          "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
           "dev": true,
           "requires": {
             "lru-cache": "^6.0.0"
@@ -6288,13 +6579,13 @@
       "dev": true
     },
     "jsdom": {
-      "version": "16.5.1",
-      "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.5.1.tgz",
-      "integrity": "sha512-pF73EOsJgwZekbDHEY5VO/yKXUkab/DuvrQB/ANVizbr6UAHJsDdHXuotZYwkJSGQl1JM+ivXaqY+XBDDL4TiA==",
+      "version": "16.5.2",
+      "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.5.2.tgz",
+      "integrity": "sha512-JxNtPt9C1ut85boCbJmffaQ06NBnzkQY/MWO3YxPW8IWS38A26z+B1oBvA9LwKrytewdfymnhi4UNH3/RAgZrg==",
       "dev": true,
       "requires": {
         "abab": "^2.0.5",
-        "acorn": "^8.0.5",
+        "acorn": "^8.1.0",
         "acorn-globals": "^6.0.0",
         "cssom": "^0.4.4",
         "cssstyle": "^2.3.0",
@@ -6316,7 +6607,7 @@
         "webidl-conversions": "^6.1.0",
         "whatwg-encoding": "^1.0.5",
         "whatwg-mimetype": "^2.3.0",
-        "whatwg-url": "^8.0.0",
+        "whatwg-url": "^8.5.0",
         "ws": "^7.4.4",
         "xml-name-validator": "^3.0.0"
       },
@@ -6779,12 +7070,6 @@
       "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=",
       "dev": true
     },
-    "lodash.sortby": {
-      "version": "4.7.0",
-      "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
-      "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
-      "dev": true
-    },
     "lodash.toarray": {
       "version": "4.4.0",
       "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
@@ -7033,6 +7318,12 @@
         "supports-hyperlinks": "^2.1.0"
       }
     },
+    "media-typer": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+      "dev": true
+    },
     "mem": {
       "version": "4.3.0",
       "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz",
@@ -7098,6 +7389,12 @@
         }
       }
     },
+    "merge-descriptors": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
+      "dev": true
+    },
     "merge-stream": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -7110,6 +7407,12 @@
       "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
       "dev": true
     },
+    "methods": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
+      "dev": true
+    },
     "micromatch": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
@@ -7256,6 +7559,12 @@
       "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
       "dev": true
     },
+    "negotiator": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+      "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
+      "dev": true
+    },
     "neo-async": {
       "version": "2.6.2",
       "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
@@ -7317,9 +7626,9 @@
       },
       "dependencies": {
         "semver": {
-          "version": "7.3.4",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
-          "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
+          "version": "7.3.5",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+          "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -7459,9 +7768,9 @@
       }
     },
     "npm": {
-      "version": "6.14.11",
-      "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.11.tgz",
-      "integrity": "sha512-1Zh7LjuIoEhIyjkBflSSGzfjuPQwDlghNloppjruOH5bmj9midT9qcNT0tRUZRR04shU9ekrxNy9+UTBrqeBpQ==",
+      "version": "6.14.12",
+      "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.12.tgz",
+      "integrity": "sha512-La0TNNm1TLYaSeOyit+p3xGTRYYRsHae6/RG69MVXurZsWna9jccPP7FOi/u7V9WdiCV5OOojrfMD+WstO5MZQ==",
       "dev": true,
       "requires": {
         "JSONStream": "^1.3.5",
@@ -10874,7 +11183,7 @@
           "dev": true
         },
         "y18n": {
-          "version": "4.0.0",
+          "version": "4.0.1",
           "bundled": true,
           "dev": true
         },
@@ -11102,6 +11411,15 @@
         "isobject": "^3.0.1"
       }
     },
+    "on-finished": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+      "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+      "dev": true,
+      "requires": {
+        "ee-first": "1.1.1"
+      }
+    },
     "once": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -11323,6 +11641,12 @@
       "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
       "dev": true
     },
+    "parseurl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+      "dev": true
+    },
     "pascalcase": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
@@ -11359,6 +11683,12 @@
       "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
       "dev": true
     },
+    "path-to-regexp": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
+      "dev": true
+    },
     "path-type": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
@@ -11549,6 +11879,16 @@
         "sisteransi": "^1.0.5"
       }
     },
+    "proxy-addr": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
+      "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
+      "dev": true,
+      "requires": {
+        "forwarded": "~0.1.2",
+        "ipaddr.js": "1.9.1"
+      }
+    },
     "pseudomap": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
@@ -11590,9 +11930,9 @@
       "dev": true
     },
     "queue-microtask": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.2.tgz",
-      "integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg==",
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
       "dev": true
     },
     "quick-lru": {
@@ -11601,6 +11941,24 @@
       "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=",
       "dev": true
     },
+    "range-parser": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+      "dev": true
+    },
+    "raw-body": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
+      "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+      "dev": true,
+      "requires": {
+        "bytes": "3.1.0",
+        "http-errors": "1.7.2",
+        "iconv-lite": "0.4.24",
+        "unpipe": "1.0.0"
+      }
+    },
     "rc": {
       "version": "1.2.8",
       "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
@@ -11614,9 +11972,9 @@
       }
     },
     "react-is": {
-      "version": "17.0.1",
-      "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz",
-      "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==",
+      "version": "17.0.2",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+      "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
       "dev": true
     },
     "read-pkg": {
@@ -11847,9 +12205,9 @@
       "dev": true
     },
     "regjsparser": {
-      "version": "0.6.7",
-      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.7.tgz",
-      "integrity": "sha512-ib77G0uxsA2ovgiYbCVGx4Pv3PSttAx2vIwidqQzbL2U5S4Q+j00HdSAneSBuyVcMvEnTXMjiGgB+DlXozVhpQ==",
+      "version": "0.6.9",
+      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.9.tgz",
+      "integrity": "sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==",
       "dev": true,
       "requires": {
         "jsesc": "~0.5.0"
@@ -12100,9 +12458,9 @@
       }
     },
     "rxjs": {
-      "version": "6.6.6",
-      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.6.tgz",
-      "integrity": "sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg==",
+      "version": "6.6.7",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+      "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
       "dev": true,
       "requires": {
         "tslib": "^1.9.0"
@@ -12463,9 +12821,9 @@
           "dev": true
         },
         "hosted-git-info": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.0.tgz",
-          "integrity": "sha512-fqhGdjk4av7mT9fU/B01dUtZ+WZSc/XEXMoLXDVZukiQRXxeHSSz3AqbeWRJHtF8EQYHlAgB1NSAHU0Cm7aqZA==",
+          "version": "4.0.2",
+          "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz",
+          "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==",
           "dev": true,
           "requires": {
             "lru-cache": "^6.0.0"
@@ -12523,9 +12881,9 @@
           "dev": true
         },
         "semver": {
-          "version": "7.3.4",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
-          "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
+          "version": "7.3.5",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+          "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
           "dev": true,
           "requires": {
             "lru-cache": "^6.0.0"
@@ -12626,6 +12984,70 @@
       "integrity": "sha512-bXWyL6EAKOJa81XG1OZ/Yyuq+oT0b2YLlxx7c+mrdYPaPbnj6WgVULXhinMIeZGufuUBu/eVRqXEhiv4imfwxA==",
       "dev": true
     },
+    "send": {
+      "version": "0.17.1",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
+      "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+      "dev": true,
+      "requires": {
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "destroy": "~1.0.4",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "fresh": "0.5.2",
+        "http-errors": "~1.7.2",
+        "mime": "1.6.0",
+        "ms": "2.1.1",
+        "on-finished": "~2.3.0",
+        "range-parser": "~1.2.1",
+        "statuses": "~1.5.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          },
+          "dependencies": {
+            "ms": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+              "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+              "dev": true
+            }
+          }
+        },
+        "mime": {
+          "version": "1.6.0",
+          "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+          "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+          "dev": true
+        },
+        "ms": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+          "dev": true
+        }
+      }
+    },
+    "serve-static": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
+      "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+      "dev": true,
+      "requires": {
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "parseurl": "~1.3.3",
+        "send": "0.17.1"
+      }
+    },
     "set-blocking": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
@@ -12655,6 +13077,12 @@
         }
       }
     },
+    "setprototypeof": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+      "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
+      "dev": true
+    },
     "shebang-command": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -13186,6 +13614,12 @@
         }
       }
     },
+    "statuses": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+      "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+      "dev": true
+    },
     "stealthy-require": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
@@ -13229,9 +13663,9 @@
       }
     },
     "string-length": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz",
-      "integrity": "sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw==",
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
+      "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==",
       "dev": true,
       "requires": {
         "char-regex": "^1.0.2",
@@ -13373,9 +13807,9 @@
       "dev": true
     },
     "tempy": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.0.tgz",
-      "integrity": "sha512-eLXG5B1G0mRPHmgH2WydPl5v4jH35qEn3y/rA/aahKhIa91Pn119SsU7n7v/433gtT9ONzC8ISvNHIh2JSTm0w==",
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.1.tgz",
+      "integrity": "sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==",
       "dev": true,
       "requires": {
         "del": "^6.0.0",
@@ -13414,9 +13848,9 @@
           }
         },
         "globby": {
-          "version": "11.0.2",
-          "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz",
-          "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==",
+          "version": "11.0.3",
+          "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz",
+          "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==",
           "dev": true,
           "requires": {
             "array-union": "^2.1.0",
@@ -13627,9 +14061,9 @@
       }
     },
     "tlds": {
-      "version": "1.218.0",
-      "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.218.0.tgz",
-      "integrity": "sha512-JpD3eSrYaIFlU/OvtI5WTEK+v5qXZSeUifz4hT2bJsJKx5ykjZvg6i5yXVBJNjoN3XbTCtryc7H5v8B16yHfMg==",
+      "version": "1.219.0",
+      "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.219.0.tgz",
+      "integrity": "sha512-o4g9c8kXCmTDwUnK/9HpTT9o/GNH85KCvs+S5SgUw5yILdECvMmTGzK7ngoWMp97P5tfYr8fZeF16YhgV/l90A==",
       "dev": true
     },
     "tmp": {
@@ -13700,6 +14134,12 @@
         "is-number": "^7.0.0"
       }
     },
+    "toidentifier": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+      "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
+      "dev": true
+    },
     "tough-cookie": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz",
@@ -13739,9 +14179,9 @@
       "dev": true
     },
     "ts-jest": {
-      "version": "26.5.3",
-      "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.3.tgz",
-      "integrity": "sha512-nBiiFGNvtujdLryU7MiMQh1iPmnZ/QvOskBbD2kURiI1MwqvxlxNnaAB/z9TbslMqCsSbu5BXvSSQPc5tvHGeA==",
+      "version": "26.5.4",
+      "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.4.tgz",
+      "integrity": "sha512-I5Qsddo+VTm94SukBJ4cPimOoFZsYTeElR2xy6H2TOVs+NsvgYglW8KuQgKoApOKuaU/Ix/vrF9ebFZlb5D2Pg==",
       "dev": true,
       "requires": {
         "bs-logger": "0.x",
@@ -13763,9 +14203,9 @@
           "dev": true
         },
         "semver": {
-          "version": "7.3.4",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
-          "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
+          "version": "7.3.5",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+          "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
           "dev": true,
           "requires": {
             "lru-cache": "^6.0.0"
@@ -13830,11 +14270,21 @@
       "dev": true
     },
     "type-fest": {
-      "version": "0.11.0",
-      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz",
-      "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==",
+      "version": "0.21.3",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+      "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
       "dev": true
     },
+    "type-is": {
+      "version": "1.6.18",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+      "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+      "dev": true,
+      "requires": {
+        "media-typer": "0.3.0",
+        "mime-types": "~2.1.24"
+      }
+    },
     "typedarray-to-buffer": {
       "version": "3.1.5",
       "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
@@ -13851,9 +14301,9 @@
       "dev": true
     },
     "uglify-js": {
-      "version": "3.13.1",
-      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.1.tgz",
-      "integrity": "sha512-EWhx3fHy3M9JbaeTnO+rEqzCe1wtyQClv6q3YWq0voOj4E+bMZBErVS1GAHPDiRGONYq34M1/d8KuQMgvi6Gjw==",
+      "version": "3.13.3",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.3.tgz",
+      "integrity": "sha512-otIc7O9LyxpUcQoXzj2hL4LPWKklO6LJWoJUzNa8A17Xgi4fOeDC8FBDOLHnC/Slo1CQgsZMcM6as0M76BZaig==",
       "dev": true,
       "optional": true
     },
@@ -13918,6 +14368,12 @@
       "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
       "dev": true
     },
+    "unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+      "dev": true
+    },
     "unset-value": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
@@ -14110,6 +14566,12 @@
       "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
       "dev": true
     },
+    "utils-merge": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+      "dev": true
+    },
     "uuid": {
       "version": "8.3.2",
       "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
@@ -14155,6 +14617,12 @@
         "builtins": "^1.0.3"
       }
     },
+    "vary": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
+      "dev": true
+    },
     "verror": {
       "version": "1.10.0",
       "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
@@ -14215,12 +14683,12 @@
       "dev": true
     },
     "whatwg-url": {
-      "version": "8.4.0",
-      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz",
-      "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==",
+      "version": "8.5.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.5.0.tgz",
+      "integrity": "sha512-fy+R77xWv0AiqfLl4nuGUlQ3/6b5uNfQ4WAbGQVMYshCTCCPK9psC1nWh3XHuxGVCtlcDDQPQW1csmmIQo+fwg==",
       "dev": true,
       "requires": {
-        "lodash.sortby": "^4.7.0",
+        "lodash": "^4.7.0",
         "tr46": "^2.0.2",
         "webidl-conversions": "^6.1.0"
       }
diff --git a/package.json b/package.json
index 767512c..339e485 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,7 @@
   "prettier": {},
   "dependencies": {
     "@octokit/request-error": "^2.0.2",
-    "@octokit/webhooks-definitions": "3.64.2",
+    "@octokit/webhooks-definitions": "3.65.5",
     "aggregate-error": "^3.1.0",
     "debug": "^4.0.0"
   },
@@ -33,10 +33,13 @@
     "@types/jest": "^26.0.9",
     "@types/json-schema": "^7.0.7",
     "@types/node": "^14.0.14",
+    "@types/node-fetch": "^2.5.8",
     "@types/prettier": "^2.0.0",
     "axios": "^0.21.0",
+    "express": "^4.17.1",
     "get-port": "^5.0.0",
     "jest": "^26.2.2",
+    "node-fetch": "^2.6.1",
     "prettier": "^2.0.1",
     "prettier-plugin-packagejson": "^2.2.9",
     "semantic-release": "^17.0.0",
diff --git a/src/createLogger.ts b/src/createLogger.ts
index 8529966..e86d953 100644
--- a/src/createLogger.ts
+++ b/src/createLogger.ts
@@ -1,8 +1,8 @@
 export interface Logger {
-  debug: (message: string) => unknown;
-  info: (message: string) => unknown;
-  warn: (message: string) => unknown;
-  error: (message: string) => unknown;
+  debug: (...data: any[]) => void;
+  info: (...data: any[]) => void;
+  warn: (...data: any[]) => void;
+  error: (...data: any[]) => void;
 }
 
 export const createLogger = (logger?: Partial<Logger>): Logger => ({
diff --git a/src/index.ts b/src/index.ts
index 12ac19d..98e4d1a 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,9 +1,9 @@
 import { IncomingMessage, ServerResponse } from "http";
 import { createLogger } from "./createLogger";
 import { createEventHandler } from "./event-handler/index";
-import { createMiddleware } from "./middleware/index";
-import { middleware } from "./middleware/middleware";
-import { verifyAndReceive } from "./middleware/verify-and-receive";
+import { createMiddleware } from "./middleware-legacy/index";
+import { middleware } from "./middleware-legacy/middleware";
+import { verifyAndReceive } from "./middleware-legacy/verify-and-receive";
 import { sign } from "./sign/index";
 import {
   EmitterWebhookEvent,
@@ -16,8 +16,10 @@ import {
 } from "./types";
 import { verify } from "./verify/index";
 
+export { createNodeMiddleware } from "./middleware/node/index";
+
 // U holds the return value of `transform` function in Options
-class Webhooks<TTransformed> {
+class Webhooks<TTransformed = unknown> {
   public sign: (payload: string | object) => string;
   public verify: (eventPayload: string | object, signature: string) => boolean;
   public on: <E extends EmitterWebhookEventName>(
@@ -31,14 +33,18 @@ class Webhooks<TTransformed> {
     callback: HandlerFunction<E, TTransformed>
   ) => void;
   public receive: (event: EmitterWebhookEvent) => Promise<void>;
+  public verifyAndReceive: (
+    options: EmitterWebhookEvent & { signature: string }
+  ) => Promise<void>;
+
+  /**
+   * @deprecated use `createNodeMiddleware(webhooks)` instead
+   */
   public middleware: (
     request: IncomingMessage,
     response: ServerResponse,
     next?: (err?: any) => void
   ) => void | Promise<void>;
-  public verifyAndReceive: (
-    options: EmitterWebhookEvent & { signature: string }
-  ) => Promise<void>;
 
   constructor(options: Options<TTransformed>) {
     if (!options || !options.secret) {
@@ -53,6 +59,12 @@ class Webhooks<TTransformed> {
       log: createLogger(options.log),
     };
 
+    if ("path" in options) {
+      state.log.warn(
+        "[@octokit/webhooks] `path` option is deprecated and will be removed in a future release of `@octokit/webhooks`. Please use `createNodeMiddleware(webhooks, { path })` instead"
+      );
+    }
+
     this.sign = sign.bind(null, options.secret);
     this.verify = verify.bind(null, options.secret);
     this.on = state.eventHandler.on;
@@ -60,12 +72,29 @@ class Webhooks<TTransformed> {
     this.onError = state.eventHandler.onError;
     this.removeListener = state.eventHandler.removeListener;
     this.receive = state.eventHandler.receive;
-    this.middleware = middleware.bind(null, state);
     this.verifyAndReceive = verifyAndReceive.bind(null, state);
+
+    this.middleware = function deprecatedMiddleware(
+      request: IncomingMessage,
+      response: ServerResponse,
+      next?: (err?: any) => void
+    ) {
+      state.log.warn(
+        "[@octokit/webhooks] `webhooks.middleware` is deprecated and will be removed in a future release of `@octokit/webhooks`. Please use `createNodeMiddleware(webhooks)` instead"
+      );
+      return middleware(state, request, response, next);
+    };
   }
 }
 
-const createWebhooksApi = Webhooks.prototype.constructor;
+/** @deprecated `createWebhooksApi()` is deprecated and will be removed in a future release of `@octokit/webhooks`, please use the `Webhooks` class instead */
+const createWebhooksApi = <TTransformed>(options: Options<TTransformed>) => {
+  const log = createLogger(options.log);
+  log.warn(
+    "[@octokit/webhooks] `createWebhooksApi()` is deprecated and will be removed in a future release of `@octokit/webhooks`, please use the `Webhooks` class instead"
+  );
+  return new Webhooks<TTransformed>(options);
+};
 
 export {
   createEventHandler,
diff --git a/src/middleware/README.md b/src/middleware-legacy/README.md
similarity index 65%
rename from src/middleware/README.md
rename to src/middleware-legacy/README.md
index 654045f..b7478db 100644
--- a/src/middleware/README.md
+++ b/src/middleware-legacy/README.md
@@ -3,15 +3,15 @@
 If you only need the middleware with access to the `.sign()`, `.verify()` or the receiver’s `.receive()` method, you can use the webhooks middleware directly
 
 ```js
-const { createMiddleware } = require('@octokit/webhooks')
+const { createMiddleware } = require("@octokit/webhooks");
 const middleware = createMiddleware({
-  secret: 'mysecret',
-  path: '/github-webhooks'
-})
+  secret: "mysecret",
+  path: "/github-webhooks",
+});
 
-middleware.on('installation', asyncInstallationHook)
+middleware.on("installation", asyncInstallationHook);
 
-require('http').createServer(middleware).listen(3000)
+require("http").createServer(middleware).listen(3000);
 ```
 
 ## API
diff --git a/src/middleware/get-missing-headers.ts b/src/middleware-legacy/get-missing-headers.ts
similarity index 100%
rename from src/middleware/get-missing-headers.ts
rename to src/middleware-legacy/get-missing-headers.ts
diff --git a/src/middleware/get-payload.ts b/src/middleware-legacy/get-payload.ts
similarity index 100%
rename from src/middleware/get-payload.ts
rename to src/middleware-legacy/get-payload.ts
diff --git a/src/middleware/index.ts b/src/middleware-legacy/index.ts
similarity index 100%
rename from src/middleware/index.ts
rename to src/middleware-legacy/index.ts
diff --git a/src/middleware/isnt-webhook.ts b/src/middleware-legacy/isnt-webhook.ts
similarity index 100%
rename from src/middleware/isnt-webhook.ts
rename to src/middleware-legacy/isnt-webhook.ts
diff --git a/src/middleware/middleware.ts b/src/middleware-legacy/middleware.ts
similarity index 100%
rename from src/middleware/middleware.ts
rename to src/middleware-legacy/middleware.ts
diff --git a/src/middleware/verify-and-receive.ts b/src/middleware-legacy/verify-and-receive.ts
similarity index 100%
rename from src/middleware/verify-and-receive.ts
rename to src/middleware-legacy/verify-and-receive.ts
diff --git a/src/middleware/node/get-missing-headers.ts b/src/middleware/node/get-missing-headers.ts
new file mode 100644
index 0000000..6b25de8
--- /dev/null
+++ b/src/middleware/node/get-missing-headers.ts
@@ -0,0 +1,12 @@
+import { IncomingMessage } from "http";
+
+const WEBHOOK_HEADERS = [
+  "x-github-event",
+  "x-hub-signature-256",
+  "x-github-delivery",
+];
+
+// https://docs.github.com/en/developers/webhooks-and-events/webhook-events-and-payloads#delivery-headers
+export function getMissingHeaders(request: IncomingMessage) {
+  return WEBHOOK_HEADERS.filter((header) => !(header in request.headers));
+}
diff --git a/src/middleware/node/get-payload.ts b/src/middleware/node/get-payload.ts
new file mode 100644
index 0000000..f764d38
--- /dev/null
+++ b/src/middleware/node/get-payload.ts
@@ -0,0 +1,36 @@
+import { WebhookEvent } from "@octokit/webhooks-definitions/schema";
+// @ts-ignore to address #245
+import AggregateError from "aggregate-error";
+import { IncomingMessage } from "http";
+
+declare module "http" {
+  interface IncomingMessage {
+    body?: WebhookEvent;
+  }
+}
+
+export function getPayload(request: IncomingMessage): Promise<WebhookEvent> {
+  // If request.body already exists we can stop here
+  // See https://github.com/octokit/webhooks.js/pull/23
+
+  if (request.body) return Promise.resolve(request.body);
+
+  return new Promise((resolve, reject) => {
+    let data = "";
+
+    request.setEncoding("utf8");
+
+    // istanbul ignore next
+    request.on("error", (error) => reject(new AggregateError([error])));
+    request.on("data", (chunk) => (data += chunk));
+    request.on("end", () => {
+      try {
+        resolve(JSON.parse(data));
+      } catch (error) {
+        error.message = "Invalid JSON";
+        error.status = 400;
+        reject(new AggregateError([error]));
+      }
+    });
+  });
+}
diff --git a/src/middleware/node/index.ts b/src/middleware/node/index.ts
new file mode 100644
index 0000000..06312ba
--- /dev/null
+++ b/src/middleware/node/index.ts
@@ -0,0 +1,20 @@
+import { createLogger } from "../../createLogger";
+import { Webhooks } from "../../index";
+import { middleware } from "./middleware";
+import { onUnhandledRequestDefault } from "./on-unhandled-request-default";
+import { MiddlewareOptions } from "./types";
+
+export function createNodeMiddleware(
+  webhooks: Webhooks,
+  {
+    path = "/api/github/webhooks",
+    onUnhandledRequest = onUnhandledRequestDefault,
+    log = createLogger(),
+  }: MiddlewareOptions = {}
+) {
+  return middleware.bind(null, webhooks, {
+    path,
+    onUnhandledRequest,
+    log,
+  } as Required<MiddlewareOptions>);
+}
diff --git a/src/middleware/node/middleware.ts b/src/middleware/node/middleware.ts
new file mode 100644
index 0000000..499a1c7
--- /dev/null
+++ b/src/middleware/node/middleware.ts
@@ -0,0 +1,81 @@
+import { IncomingMessage, ServerResponse } from "http";
+
+import { WebhookEventName } from "@octokit/webhooks-definitions/schema";
+
+import { Webhooks } from "../../index";
+import { WebhookEventHandlerError } from "../../types";
+import { MiddlewareOptions } from "./types";
+import { onUnhandledRequestDefault } from "./on-unhandled-request-default";
+import { getMissingHeaders } from "./get-missing-headers";
+import { getPayload } from "./get-payload";
+
+export async function middleware(
+  webhooks: Webhooks,
+  options: Required<MiddlewareOptions>,
+  request: IncomingMessage,
+  response: ServerResponse,
+  next?: Function
+) {
+  const { pathname } = new URL(request.url as string, "http://localhost");
+
+  const isUnknownRoute = request.method !== "POST" || pathname !== options.path;
+  const isExpressMiddleware = typeof next === "function";
+  if (!isExpressMiddleware && isUnknownRoute) {
+    options.log.debug(`not found: ${request.method} ${request.url}`);
+    return onUnhandledRequestDefault(request, response);
+  }
+
+  const missingHeaders = getMissingHeaders(request).join(", ");
+
+  if (missingHeaders) {
+    response.writeHead(400, {
+      "content-type": "application/json",
+    });
+    response.end(
+      JSON.stringify({
+        error: `Required headers missing: ${missingHeaders}`,
+      })
+    );
+
+    return;
+  }
+
+  const eventName = request.headers["x-github-event"] as WebhookEventName;
+  const signatureSHA256 = request.headers["x-hub-signature-256"] as string;
+  const id = request.headers["x-github-delivery"] as string;
+
+  options.log.debug(`${eventName} event received (id: ${id})`);
+
+  // GitHub will abort the request if it does not receive a response within 10s
+  // See https://github.com/octokit/webhooks.js/issues/185
+  let didTimeout = false;
+  const timeout = setTimeout(() => {
+    didTimeout = true;
+    response.statusCode = 202;
+    response.end("still processing\n");
+  }, 9000).unref();
+
+  try {
+    const payload = await getPayload(request);
+
+    await webhooks.verifyAndReceive({
+      id: id,
+      name: eventName as any,
+      payload: payload as any,
+      signature: signatureSHA256,
+    });
+    clearTimeout(timeout);
+
+    if (didTimeout) return;
+
+    response.end("ok\n");
+  } catch (error) {
+    clearTimeout(timeout);
+
+    if (didTimeout) return;
+
+    const statusCode = Array.from(error as WebhookEventHandlerError)[0].status;
+    response.statusCode = typeof statusCode !== "undefined" ? statusCode : 500;
+    response.end(error.toString());
+  }
+}
diff --git a/src/middleware/node/on-unhandled-request-default.ts b/src/middleware/node/on-unhandled-request-default.ts
new file mode 100644
index 0000000..c32ef7a
--- /dev/null
+++ b/src/middleware/node/on-unhandled-request-default.ts
@@ -0,0 +1,15 @@
+import { IncomingMessage, ServerResponse } from "http";
+
+export function onUnhandledRequestDefault(
+  request: IncomingMessage,
+  response: ServerResponse
+) {
+  response.writeHead(404, {
+    "content-type": "application/json",
+  });
+  response.end(
+    JSON.stringify({
+      error: `Unknown route: ${request.method} ${request.url}`,
+    })
+  );
+}
diff --git a/src/middleware/node/types.ts b/src/middleware/node/types.ts
new file mode 100644
index 0000000..c114ce2
--- /dev/null
+++ b/src/middleware/node/types.ts
@@ -0,0 +1,12 @@
+import { IncomingMessage, ServerResponse } from "http";
+
+import { Logger } from "../../createLogger";
+
+export type MiddlewareOptions = {
+  path?: string;
+  log?: Logger;
+  onUnhandledRequest?: (
+    request: IncomingMessage,
+    response: ServerResponse
+  ) => void;
+};
diff --git a/src/verify/index.ts b/src/verify/index.ts
index 09ce118..0f1655e 100644
--- a/src/verify/index.ts
+++ b/src/verify/index.ts
@@ -19,6 +19,7 @@ export function verify(
 
   const signatureBuffer = Buffer.from(signature);
   const algorithm = getAlgorithm(signature);
+
   const verificationBuffer = Buffer.from(
     sign({ secret, algorithm }, eventPayload)
   );


Test patch:
diff --git a/test/integration/middleware-test.ts b/test/integration/middleware-test.ts
index b5da700..51e5b71 100644
--- a/test/integration/middleware-test.ts
+++ b/test/integration/middleware-test.ts
@@ -1,6 +1,6 @@
 import { EventEmitter } from "events";
 import { Buffer } from "buffer";
-import { createMiddleware } from "../../src/middleware";
+import { createMiddleware } from "../../src/middleware-legacy";
 
 enum RequestMethodType {
   POST = "POST",
diff --git a/test/integration/node-middleware.test.ts b/test/integration/node-middleware.test.ts
new file mode 100644
index 0000000..737bbff
--- /dev/null
+++ b/test/integration/node-middleware.test.ts
@@ -0,0 +1,321 @@
+import { createServer } from "http";
+
+import fetch from "node-fetch";
+
+// import without types
+const express = require("express");
+
+import { Webhooks, createNodeMiddleware, sign } from "../../src";
+import { pushEventPayload } from "../fixtures";
+
+const signatureSha256 = sign(
+  { secret: "mySecret", algorithm: "sha256" },
+  JSON.stringify(pushEventPayload)
+);
+
+describe("createNodeMiddleware(webhooks)", () => {
+  test("README example", async () => {
+    expect.assertions(3);
+
+    const webhooks = new Webhooks({
+      secret: "mySecret",
+    });
+
+    webhooks.on("push", (event) => {
+      expect(event.id).toBe("123e4567-e89b-12d3-a456-426655440000");
+    });
+
+    const server = createServer(createNodeMiddleware(webhooks)).listen();
+
+    // @ts-expect-error complains about { port } although it's included in returned AddressInfo interface
+    const { port } = server.address();
+
+    const response = await fetch(
+      `http://localhost:${port}/api/github/webhooks`,
+      {
+        method: "POST",
+        headers: {
+          "X-GitHub-Delivery": "123e4567-e89b-12d3-a456-426655440000",
+          "X-GitHub-Event": "push",
+          "X-Hub-Signature-256": signatureSha256,
+        },
+        body: JSON.stringify(pushEventPayload),
+      }
+    );
+
+    expect(response.status).toEqual(200);
+    await expect(response.text()).resolves.toBe("ok\n");
+
+    server.close();
+  });
+
+  test("request.body already parsed (e.g. Lambda)", async () => {
+    expect.assertions(3);
+
+    const webhooks = new Webhooks({
+      secret: "mySecret",
+    });
+    const dataChunks: any[] = [];
+    const middleware = createNodeMiddleware(webhooks);
+
+    const server = createServer((req, res) => {
+      req.once("data", (chunk) => dataChunks.push(chunk));
+      req.once("end", () => {
+        req.body = JSON.parse(Buffer.concat(dataChunks).toString());
+        middleware(req, res);
+      });
+    }).listen();
+
+    webhooks.on("push", (event) => {
+      expect(event.id).toBe("123e4567-e89b-12d3-a456-426655440000");
+    });
+
+    // @ts-expect-error complains about { port } although it's included in returned AddressInfo interface
+    const { port } = server.address();
+
+    const response = await fetch(
+      `http://localhost:${port}/api/github/webhooks`,
+      {
+        method: "POST",
+        headers: {
+          "X-GitHub-Delivery": "123e4567-e89b-12d3-a456-426655440000",
+          "X-GitHub-Event": "push",
+          "X-Hub-Signature-256": signatureSha256,
+        },
+        body: JSON.stringify(pushEventPayload),
+      }
+    );
+
+    expect(response.status).toEqual(200);
+    expect(await response.text()).toEqual("ok\n");
+
+    server.close();
+  });
+
+  test("Handles invalid JSON", async () => {
+    const webhooks = new Webhooks({
+      secret: "mySecret",
+    });
+
+    const server = createServer(createNodeMiddleware(webhooks)).listen();
+
+    // @ts-expect-error complains about { port } although it's included in returned AddressInfo interface
+    const { port } = server.address();
+
+    const response = await fetch(
+      `http://localhost:${port}/api/github/webhooks`,
+      {
+        method: "POST",
+        headers: {
+          "X-GitHub-Delivery": "123e4567-e89b-12d3-a456-426655440000",
+          "X-GitHub-Event": "push",
+          "X-Hub-Signature-256": signatureSha256,
+        },
+        body: "invalid",
+      }
+    );
+
+    expect(response.status).toEqual(400);
+
+    await expect(response.text()).resolves.toMatch(/SyntaxError: Invalid JSON/);
+
+    server.close();
+  });
+
+  test("Handles non POST request", async () => {
+    const webhooks = new Webhooks({
+      secret: "mySecret",
+    });
+
+    const server = createServer(createNodeMiddleware(webhooks)).listen();
+
+    // @ts-expect-error complains about { port } although it's included in returned AddressInfo interface
+    const { port } = server.address();
+
+    const response = await fetch(
+      `http://localhost:${port}/api/github/webhooks`,
+      {
+        method: "PUT",
+        headers: {
+          "X-GitHub-Delivery": "123e4567-e89b-12d3-a456-426655440000",
+          "X-GitHub-Event": "push",
+          "X-Hub-Signature-256": signatureSha256,
+        },
+        body: "invalid",
+      }
+    );
+
+    expect(response.status).toEqual(404);
+
+    await expect(response.text()).resolves.toMatch(
+      /Unknown route: PUT \/api\/github\/webhooks/
+    );
+
+    server.close();
+  });
+
+  test("Handles missing headers", async () => {
+    const webhooks = new Webhooks({
+      secret: "mySecret",
+    });
+
+    const server = createServer(createNodeMiddleware(webhooks)).listen();
+
+    // @ts-expect-error complains about { port } although it's included in returned AddressInfo interface
+    const { port } = server.address();
+
+    const response = await fetch(
+      `http://localhost:${port}/api/github/webhooks`,
+      {
+        method: "POST",
+        headers: {
+          "X-GitHub-Delivery": "123e4567-e89b-12d3-a456-426655440000",
+          // "X-GitHub-Event": "push",
+          "X-Hub-Signature-256": signatureSha256,
+        },
+        body: "invalid",
+      }
+    );
+
+    expect(response.status).toEqual(400);
+
+    await expect(response.text()).resolves.toMatch(
+      /Required headers missing: x-github-event/
+    );
+
+    server.close();
+  });
+
+  test("Handles non-request errors", async () => {
+    const webhooks = new Webhooks({
+      secret: "mySecret",
+    });
+
+    webhooks.on("push", () => {
+      throw new Error("boom");
+    });
+
+    const server = createServer(createNodeMiddleware(webhooks)).listen();
+
+    // @ts-expect-error complains about { port } although it's included in returned AddressInfo interface
+    const { port } = server.address();
+
+    const response = await fetch(
+      `http://localhost:${port}/api/github/webhooks`,
+      {
+        method: "POST",
+        headers: {
+          "X-GitHub-Delivery": "123e4567-e89b-12d3-a456-426655440000",
+          "X-GitHub-Event": "push",
+          "X-Hub-Signature-256": signatureSha256,
+        },
+        body: JSON.stringify(pushEventPayload),
+      }
+    );
+
+    await expect(response.text()).resolves.toMatch(/boom/);
+    expect(response.status).toEqual(500);
+
+    server.close();
+  });
+
+  test("Handles timeout", async () => {
+    jest.useFakeTimers();
+
+    const webhooks = new Webhooks({
+      secret: "mySecret",
+    });
+
+    webhooks.on("push", async () => {
+      jest.advanceTimersByTime(10000);
+      server.close();
+    });
+
+    const server = createServer(createNodeMiddleware(webhooks)).listen();
+
+    // @ts-expect-error complains about { port } although it's included in returned AddressInfo interface
+    const { port } = server.address();
+
+    const response = await fetch(
+      `http://localhost:${port}/api/github/webhooks`,
+      {
+        method: "POST",
+        headers: {
+          "X-GitHub-Delivery": "123e4567-e89b-12d3-a456-426655440000",
+          "X-GitHub-Event": "push",
+          "X-Hub-Signature-256": signatureSha256,
+        },
+        body: JSON.stringify(pushEventPayload),
+      }
+    );
+
+    await expect(response.text()).resolves.toMatch(/still processing/);
+    expect(response.status).toEqual(202);
+  });
+
+  test("Handles timeout with error", async () => {
+    jest.useFakeTimers();
+
+    const webhooks = new Webhooks({
+      secret: "mySecret",
+    });
+
+    webhooks.on("push", async () => {
+      jest.advanceTimersByTime(10000);
+      server.close();
+      throw new Error("oops");
+    });
+
+    const server = createServer(createNodeMiddleware(webhooks)).listen();
+
+    // @ts-expect-error complains about { port } although it's included in returned AddressInfo interface
+    const { port } = server.address();
+
+    const response = await fetch(
+      `http://localhost:${port}/api/github/webhooks`,
+      {
+        method: "POST",
+        headers: {
+          "X-GitHub-Delivery": "123e4567-e89b-12d3-a456-426655440000",
+          "X-GitHub-Event": "push",
+          "X-Hub-Signature-256": signatureSha256,
+        },
+        body: JSON.stringify(pushEventPayload),
+      }
+    );
+
+    await expect(response.text()).resolves.toMatch(/still processing/);
+    expect(response.status).toEqual(202);
+  });
+
+  test("express middleware 404", async () => {
+    const app = express();
+    const webhooks = new Webhooks({
+      secret: "mySecret",
+    });
+
+    app.post("/test", createNodeMiddleware(webhooks));
+    app.all("*", (_request: any, response: any) =>
+      response.status(404).send("Dafuq")
+    );
+
+    const server = app.listen();
+
+    const { port } = server.address();
+
+    const response = await fetch(`http://localhost:${port}/test`, {
+      method: "POST",
+      headers: {
+        "X-GitHub-Delivery": "123e4567-e89b-12d3-a456-426655440000",
+        "X-GitHub-Event": "push",
+        "X-Hub-Signature-256": signatureSha256,
+      },
+      body: JSON.stringify(pushEventPayload),
+    });
+
+    await expect(response.text()).resolves.toBe("ok\n");
+    expect(response.status).toEqual(200);
+
+    server.close();
+  });
+});
diff --git a/test/integration/server-test.ts b/test/integration/server-test.ts
index f9fbbfb..2c97955 100644
--- a/test/integration/server-test.ts
+++ b/test/integration/server-test.ts
@@ -29,6 +29,9 @@ describe("server-test", () => {
   test("GET /", (t) => {
     const api = new Webhooks({
       secret: "mysecret",
+      log: {
+        warn: () => {},
+      },
     });
     const server = http.createServer(api.middleware);
 
@@ -55,6 +58,9 @@ describe("server-test", () => {
 
     const api = new Webhooks({
       secret: "mysecret",
+      log: {
+        warn: () => {},
+      },
     });
     const server = http.createServer(api.middleware);
 
@@ -94,6 +100,9 @@ describe("server-test", () => {
 
     const api = new Webhooks({
       secret: "mysecret",
+      log: {
+        warn: () => {},
+      },
     });
     const server = http.createServer(api.middleware);
 
@@ -132,6 +141,9 @@ describe("server-test", () => {
 
     const api = new Webhooks({
       secret: "mysecret",
+      log: {
+        warn: () => {},
+      },
     });
     const server = http.createServer(api.middleware);
 
@@ -172,6 +184,9 @@ describe("server-test", () => {
 
     const api = new Webhooks({
       secret: "mysecret",
+      log: {
+        warn: () => {},
+      },
     });
     const dataChunks: any[] = [];
     let timeout: NodeJS.Timeout;
@@ -224,6 +239,9 @@ describe("server-test", () => {
   test("POST / with push event payload (no signature)", (t) => {
     const api = new Webhooks({
       secret: "mysecret",
+      log: {
+        warn: () => {},
+      },
     });
     const server = http.createServer(api.middleware);
     const errorHandler = jest.fn();
@@ -262,6 +280,9 @@ describe("server-test", () => {
   test("POST / with push event payload (invalid signature)", (t) => {
     const api = new Webhooks({
       secret: "mysecret",
+      log: {
+        warn: () => {},
+      },
     });
     const server = http.createServer(api.middleware);
     const errorHandler = jest.fn();
@@ -302,6 +323,9 @@ describe("server-test", () => {
   test("POST / with hook error", (t) => {
     const api = new Webhooks({
       secret: "mysecret",
+      log: {
+        warn: () => {},
+      },
     });
     const server = http.createServer(api.middleware);
 
@@ -345,6 +369,9 @@ describe("server-test", () => {
 
     const api = new Webhooks({
       secret: "mysecret",
+      log: {
+        warn: () => {},
+      },
     });
     const server = http.createServer(api.middleware);
     const tenSecondsInMs = 10 * 1000;
diff --git a/test/typescript-validate.ts b/test/typescript-validate.ts
index 400dbb2..19731e6 100644
--- a/test/typescript-validate.ts
+++ b/test/typescript-validate.ts
@@ -2,7 +2,6 @@ import {
   Webhooks,
   createEventHandler,
   createMiddleware,
-  createWebhooksApi,
   sign,
   verify,
   EmitterWebhookEvent,
@@ -78,11 +77,6 @@ export default async function () {
     },
   });
 
-  // Check named exports of new API work
-  createWebhooksApi({
-    secret: "blah",
-  });
-
   createEventHandler({ secret: "blah" });
 
   createMiddleware({
diff --git a/test/unit/deprecation.test.ts b/test/unit/deprecation.test.ts
new file mode 100644
index 0000000..359c39c
--- /dev/null
+++ b/test/unit/deprecation.test.ts
@@ -0,0 +1,67 @@
+import { createWebhooksApi, Webhooks } from "../../src";
+
+describe("Deprecated methods", () => {
+  test("createWebhooksApi", () => {
+    const warn = jest.fn();
+
+    createWebhooksApi({
+      secret: "foo",
+      log: {
+        debug: () => {},
+        info: () => {},
+        warn: warn,
+        error: () => {},
+      },
+    });
+    expect(warn).toBeCalledWith(
+      "[@octokit/webhooks] `createWebhooksApi()` is deprecated and will be removed in a future release of `@octokit/webhooks`, please use the `Webhooks` class instead"
+    );
+    warn.mockClear();
+  });
+
+  test("path parameter", () => {
+    const warn = jest.fn();
+    new Webhooks({
+      secret: "secret",
+      path: "/test",
+      log: {
+        debug: () => {},
+        info: () => {},
+        warn: warn,
+        error: () => {},
+      },
+    });
+
+    expect(warn).toHaveBeenCalledWith(
+      "[@octokit/webhooks] `path` option is deprecated and will be removed in a future release of `@octokit/webhooks`. Please use `createNodeMiddleware(webhooks, { path })` instead"
+    );
+  });
+
+  test("webhooks.middleware", () => {
+    expect.assertions(2);
+
+    const warn = jest.fn();
+    const webhooks = new Webhooks({
+      secret: "secret",
+      log: {
+        debug: () => {},
+        info: () => {},
+        warn: warn,
+        error: () => {},
+      },
+    });
+
+    try {
+      // @ts-expect-error
+      webhooks.middleware();
+    } catch (error) {
+      expect(error.message).toEqual(
+        "Cannot read property 'method' of undefined"
+      );
+    }
+
+    expect(warn).toHaveBeenCalledWith(
+      "[@octokit/webhooks] `webhooks.middleware` is deprecated and will be removed in a future release of `@octokit/webhooks`. Please use `createNodeMiddleware(webhooks)` instead"
+    );
+  });
+});
diff --git a/test/unit/middleware-constructor-test.ts b/test/unit/middleware-constructor-test.ts
index e3403cc..70eac39 100644
--- a/test/unit/middleware-constructor-test.ts
+++ b/test/unit/middleware-constructor-test.ts
@@ -1,4 +1,4 @@
-import { createMiddleware as Middleware } from "../../src/middleware";
+import { createMiddleware as Middleware } from "../../src/middleware-legacy";
 
 test("options: none", () => {
   expect(() => Middleware({})).toThrow();
diff --git a/test/unit/middleware-test.ts b/test/unit/middleware-test.ts
index e18147b..2ade1f4 100644
--- a/test/unit/middleware-test.ts
+++ b/test/unit/middleware-test.ts
@@ -1,10 +1,10 @@
 import { IncomingMessage, ServerResponse } from "http";
-import { middleware } from "../../src/middleware/middleware";
-import { getPayload } from "../../src/middleware/get-payload";
-import { verifyAndReceive } from "../../src/middleware/verify-and-receive";
+import { middleware } from "../../src/middleware-legacy/middleware";
+import { getPayload } from "../../src/middleware-legacy/get-payload";
+import { verifyAndReceive } from "../../src/middleware-legacy/verify-and-receive";
 
-jest.mock("../../src/middleware/get-payload");
-jest.mock("../../src/middleware/verify-and-receive");
+jest.mock("../../src/middleware-legacy/get-payload");
+jest.mock("../../src/middleware-legacy/verify-and-receive");
 
 const mockGetPayload = getPayload as jest.Mock;
 const mockVerifyAndReceive = verifyAndReceive as jest.Mock;